# fnr-cli **Repository Path**: suthinks/fnr-cli ## Basic Information - **Project Name**: fnr-cli - **Description**: agent cli 模式工具调用 局限于公司内部使用。 外部无法使用。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-02 - **Last Updated**: 2026-04-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # FNR CLI ---- 轩辕传媒 通用任务执行服务框架 - 客户端 + 服务端 ## 概述 FNR CLI 是一个通用的任务执行工具,包含两部分: | 组件 | 说明 | |------|------| | **fnr-cli** | 本地 CLI 客户端 | | **fnr-cli-server** | 远程服务(部署在服务器) | ### 架构 ``` ┌─────────────┐ HTTP ┌─────────────┐ ┌─────────────┐ │ Agent │ ────────────▶ │ fnr-cli │ ◀───────────── │ fnr-cli- │ │ (Skill) │ │ (本地CLI) │ 查询/结果 │ server │ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌────────────────────┘ ▼ ┌─────────────────┐ │ 工具配置扫描 │ │ (tools/*/config.json) └─────────────────┘ ``` --- ## 快速开始 ### 1. 启动服务器 ```bash cd /opt/fnr-cli-server ./fnr-cli-server ``` ### 2. 配置客户端 ```bash # 初始化配置(首次使用) fnr-cli init # 设置服务器地址 fnr-cli config set base_url http://192.168.5.224:8877 ``` ### 3. 查看工具列表 ```bash fnr-cli tools list ``` --- ## 使用手册 ### 工具列表 ```bash # 查看服务器上有哪些工具 $ fnr-cli tools list 📦 可用工具 (版本: 1.0) 🛠 campaign_builder - 广告系列构建工具 └── build: 提交广告构建任务 - cid (string) [必填]: 模板 ID - drama (string) [必填]: 剧名(多个用换行分隔) - link_cols (string) [必填]: 链接列(多个用换行分隔) - ad_count (int): 广告数量 └── login: 保存登录 Cookie └── download: 下载构建结果 └── status: 检查服务器状态 🛠 task - 通用任务管理 └── submit: 提交通用任务 └── status: 查看任务状态 └── get: 获取任务结果 ``` ### 提交任务 ```bash # 使用 campaign_builder 工具构建广告 fnr-cli campaign build \ --cid 759119024 \ --drama "剧名1 剧名2" \ --link-cols "链接列1 链接列2" # 输出 ✅ 任务已提交 📋 任务 ID: 1775792892597908224 ⏳ 使用以下命令等待完成: fnr-cli task wait -t 1775792892597908224 ``` ### 查看任务状态 ```bash # 查看任务当前状态 fnr-cli task status -t # 输出示例 📋 任务 ID: 1775792892597908224 📊 状态: running 📈 进度: 45% 📝 日志: 正在处理第 45 个... # 失败时 📋 任务 ID: xxx 📊 状态: failed 📈 进度: 10% ❌ 错误: 执行失败: run_ad.py not found ``` ### 等待任务完成 ```bash # 自动轮询直到任务完成 fnr-cli task wait -t # 输出 ⏳ 等待任务完成: 1775792892597908224 📝 正在构建广告数据... ⏳ 进度: 10% ... ✅ 任务完成! ``` ### 获取任务结果 ```bash # 获取已完成任务的结果 fnr-cli task get -t ``` ### 其他命令 ```bash # 保存登录 Cookie fnr-cli campaign login --cookie '' # 下载构建结果 fnr-cli campaign download --file "广告数据_759119024_*.xlsx" # 检查服务器状态 fnr-cli campaign status # 查看当前配置 fnr-cli config view ``` --- ## 错误处理 | 场景 | 处理方式 | |------|----------| | **任务失败** | `task status` 显示 `❌ 错误: {error}` | | **任务失败** | `task wait` 返回 `❌ 任务失败: {error}` | | **获取结果失败** | `task get` 返回 `获取失败: {message}` | | **查询失败** | `task status/wait` 返回 `查询失败: {err}` | --- ## 新增工具(服务器端) ### 方式一:配置驱动(推荐) 1. 在服务器的 `tools/` 目录下创建工具目录 2. 添加 `config.json` 配置文件 3. 重启服务器 ```bash # 示例:添加 hello_world 工具 mkdir -p /opt/fnr-cli-server/tools/hello_world cat > /opt/fnr-cli-server/tools/hello_world/config.json << 'EOF' { "name": "hello_world", "description": "Hello World 示例工具", "commands": [ { "name": "say", "description": "打招呼", "params": [ {"name": "name", "type": "string", "required": true, "description": "姓名"} ], "task_type": "hello_world_say" } ] } EOF # 重启服务器 pkill -f fnr-cli-server cd /opt/fnr-cli-server nohup ./fnr-cli-server > nohup.out 2>&1 & # 验证 fnr-cli tools list ``` ### config.json 格式 ```json { "name": "tool_name", "description": "工具描述", "commands": [ { "name": "command_name", "description": "命令描述", "params": [ {"name": "param1", "type": "string", "required": true, "description": "参数说明"}, {"name": "param2", "type": "int", "required": false, "default": "1", "description": "可选参数"} ], "task_type": "tool_name_command_name" } ] } ``` | 字段 | 必填 | 说明 | |------|------|------| | name | 是 | 工具名称 | | description | 是 | 工具描述 | | commands | 是 | 命令列表 | | commands[].name | 是 | 命令名称 | | commands[].params | 否 | 参数列表 | | commands[].task_type | 否 | 任务类型(默认:`{tool_name}_{command_name}`) | ### 方式二:自定义 Handler 如果工具需要特殊逻辑(非简单脚本调用),可实现自定义 Handler: 1. 在 `handlers/` 下创建 `my_tool.go` 2. 实现 `TaskHandler` 接口 3. 在 `main.go` 注册 ```go // handlers/my_tool.go type MyToolHandler struct { mgr *task.Manager } func (h *MyToolHandler) Submit(t *task.Task) error { go h.execute(t) return nil } func (h *MyToolHandler) Execute(t *task.Task) (string, error) { // 自定义逻辑 return result, nil } ``` ```go // main.go taskMgr.RegisterHandler("my_tool_run", &handlers.MyToolHandler{mgr: taskMgr}) ``` --- ## API 接口(服务端) ### 工具列表 ```bash GET /api/tools ``` ### 任务提交 ```bash POST /api/task/submit Content-Type: application/json { "type": "campaign_builder_build", "params": "{\"cid\":\"759119024\",\"dramas\":[\"剧名1\"],\"link_cols\":[\"链接列1\"],\"ad_count\":1}" } ``` ### 任务状态 ```bash GET /api/task/status?task_id= ``` 响应: ```json { "success": true, "task_id": "1775792892597908224", "message": "running", "progress": 45, "logs": "正在处理第 45 个...", "error": "" } ``` ### 任务结果 ```bash GET /api/task/result?task_id= ``` ### 健康检查 ```bash GET /health ``` --- ## 目录结构 ### 服务端 ``` fnr-cli-server/ ├── main.go # 入口 ├── server.go # HTTP 服务(动态加载工具) ├── task/ │ └── task.go # 任务管理器 ├── handlers/ │ └── campaign_builder.go # campaign_builder handler ├── tools/ # 工具目录(配置驱动) │ ├── loader.go # 配置加载器 │ ├── campaign_builder/ │ │ └── config.json │ └── task/ │ └── config.json └── data/ # 数据目录 └── tasks/ # 任务存储 ``` ### 客户端 ``` fnr-cli/ ├── main.go # 入口 ├── cmd/ │ ├── campaign/ # campaign 命令 │ ├── task/ # task 命令 │ ├── tools/ # tools 命令 │ └── config/ # config 命令 └── internal/ └── cmdutil/ # 工具函数 ``` --- ## 环境变量 ### 服务端 | 变量 | 说明 | 默认值 | |------|------|--------| | PORT | 服务端口 | 8877 | | TOOLS_PATH | 工具目录 | `./tools` | | WORKSPACE_PATH | 输出文件目录 | `~/.openclaw/workspace` | | CAMPAIGN_BUILDER_PATH | campaign_builder 路径 | `/Users/suthinks/Code/ai_code/coder_code/campaign_builder` | ### 客户端 | 变量 | 说明 | 默认值 | |------|------|--------| | FNR_CLI_BASE_URL | 服务器地址 | http://localhost:8877 | | FNR_CLI_TIMEOUT | 请求超时 | 30s | --- ## 任务状态 | 状态 | 说明 | |------|------| | pending | 等待执行 | | running | 执行中 | | done | 执行完成 | | failed | 执行失败 | --- ## 轮询策略 `task wait` 命令使用渐进式轮询间隔: | 进度范围 | 间隔 | |----------|------| | 0-30% | 5 秒 | | 30-60% | 10 秒 | | 60-90% | 20 秒 | | 90-100% | 30 秒 | --- ## License MIT