# LineUp — 协议定义 ## 一、工具协议定义 工具协议定义 App 端可以向 Agent 暴露哪些能力,以及每个能力长什么样。 ### 1.1 工具定义结构 所有工具使用统一的结构模板,通过 `type` 区分结构差异。 | type | 含义 | 定义结构 | |------|------|---------| | `app` | 有状态应用,有生命周期 | `{ name, type, description, actions[] }` | | `toolset` | 无状态工具集,多个动作 | `{ name, type, description, actions[] }` | | `action` | 单指令工具,一个动作 | `{ name, type, description, inputSchema }` | app 和 toolset 包含多个动作,用 `actions` 数组描述。action 只有一个操作,直接用 `inputSchema`,不需要数组包一层。 ### 1.2 三类工具的完整定义 #### type: app — 有状态应用 需要生命周期管理,先 open 创建实例,执行动作,最后 close 释放。 ```json { "name": "canvas", "type": "app", "description": "画板应用,支持绘制、撤销、清空等操作", "actions": [ { "name": "open", "description": "创建画板实例,返回 instance_id", "inputSchema": { "type": "object", "properties": { "width": { "type": "integer", "description": "画板宽度" }, "height": { "type": "integer", "description": "画板高度" } }, "required": ["width", "height"] } }, { "name": "draw", "description": "在画板上绘制路径", "inputSchema": { "type": "object", "properties": { "instance_id": { "type": "string", "description": "画板实例 ID" }, "path": { "type": "string", "description": "SVG 路径数据" }, "color": { "type": "string", "description": "线条颜色" }, "width": { "type": "integer", "description": "线条粗细" } }, "required": ["instance_id", "path"] } }, { "name": "undo", "description": "撤销上一步操作", "inputSchema": { "type": "object", "properties": { "instance_id": { "type": "string", "description": "画板实例 ID" } }, "required": ["instance_id"] } }, { "name": "clear", "description": "清空画板内容", "inputSchema": { "type": "object", "properties": { "instance_id": { "type": "string", "description": "画板实例 ID" } }, "required": ["instance_id"] } }, { "name": "close", "description": "关闭画板释放资源", "inputSchema": { "type": "object", "properties": { "instance_id": { "type": "string", "description": "画板实例 ID" } }, "required": ["instance_id"] } } ] } ``` #### type: toolset — 无状态工具集 多个动作,无生命周期。每次调用独立,动作间不共享状态。 ```json { "name": "calculator", "type": "toolset", "description": "基础计算器,无状态,每次调用独立", "actions": [ { "name": "add", "description": "两个数相加", "inputSchema": { "type": "object", "properties": { "a": { "type": "number" }, "b": { "type": "number" } }, "required": ["a", "b"] } }, { "name": "subtract", "description": "两个数相减", "inputSchema": { "type": "object", "properties": { "a": { "type": "number" }, "b": { "type": "number" } }, "required": ["a", "b"] } }, { "name": "multiply", "description": "两个数相乘", "inputSchema": { "type": "object", "properties": { "a": { "type": "number" }, "b": { "type": "number" } }, "required": ["a", "b"] } }, { "name": "divide", "description": "两个数相除", "inputSchema": { "type": "object", "properties": { "a": { "type": "number" }, "b": { "type": "number" } }, "required": ["a", "b"] } } ] } ``` #### type: action — 单指令工具 只有一个动作,最简结构。 ```json { "name": "choice", "type": "action", "description": "向用户提供一组选项让其选择", "inputSchema": { "type": "object", "properties": { "question": { "type": "string", "description": "问题描述" }, "options": { "type": "array", "items": { "type": "string" }, "description": "可选列表" } }, "required": ["question", "options"] } } ``` ### 1.3 三类工具对比 | | app | toolset | action | |--|-----|---------|--------| | 定义字段 | name + type + description + actions[] | name + type + description + actions[] | name + type + description + inputSchema | | 适用场景 | 需要维护内部状态的应用 | 多个独立功能可归类 | 单个独立功能 | | 生命周期 | open → use → close | 无 | 无 | | instance_id | 需要 | 不需要 | 不需要 | | 调用指定动作 | 每次调用需 action | 每次调用需 action | action 字段仍需传 | | 示例 | canvas | calculator | choice / confirm / input | --- ## 二、消息协议定义 消息协议定义 Agent 和 App 之间交换的所有消息格式。 ### 2.1 统一信封 所有消息使用同一个信封格式。 ```json { "v": 1, "id": "消息唯一 ID,用于去重和配对", "type": "消息类型", "payload": { } } ``` | 字段 | 类型 | 说明 | |------|------|------| | v | integer | 协议版本号 | | id | string | 消息唯一 ID,全局唯一 | | type | string | 消息类型 | | payload | object | 消息内容,按 type 决定结构 | ### 2.2 消息类型 | type | 方向 | 说明 | |------|------|------| | `system.hello` | 双向 | 连接握手,交换身份 | | `system.ping` / `system.pong` | 双向 | 心跳保活 | | `text` | 双向 | 普通文本消息 | | `image` | Agent → App | 展示图片 | | `tool.list` | 双向 | 查询或返回工具列表 | | `tool.call` | Agent → App | 调用 App 端工具 / 动作 | | `tool.result` | App → Agent | 返回工具执行结果 | ### 2.3 各类型消息格式 #### system.hello 连接建立后,双方通过 hello 交换身份。 Agent → App: ```json { "v": 1, "id": "msg_hello_agent", "type": "system.hello", "payload": { "name": "我的 AI 助手", "token": "预设的配对 Token", "agent": "Hermes", "version": "0.19.0" } } ``` App → Agent: ```json { "v": 1, "id": "msg_hello_app", "type": "system.hello", "payload": { "name": "我的手机", "platform": "web", "version": "1.0.0" } } ``` #### text 两边都可以发送。 ```json { "v": 1, "id": "msg_001", "type": "text", "payload": { "content": "帮我查一下下周的天气" } } ``` #### image Agent 展示图片给用户。 ```json { "v": 1, "id": "msg_002", "type": "image", "payload": { "url": "http://192.168.1.100:9527/files/screenshot.png", "alt": "系统架构图", "caption": "这是当前项目的架构图" } } ``` #### tool.list 查询 App 端支持哪些工具。 ```json { "v": 1, "id": "msg_003", "type": "tool.list", "payload": {} } ``` App 返回含工具列表。 ```json { "v": 1, "id": "msg_004", "type": "tool.list", "payload": { "tools": [ ] } } ``` #### tool.call Agent 触发 App 端的一个工具动作。 ```json { "v": 1, "id": "msg_005", "type": "tool.call", "payload": { "name": "工具名", "action": "动作名", "call_id": "本次调用的唯一 ID", "arguments": { } } } ``` #### tool.result App 返回工具执行结果给 Agent。 ```json { "v": 1, "id": "msg_006", "type": "tool.result", "payload": { "name": "工具名", "action": "动作名", "call_id": "对应的调用 ID", "result": { "message": "用户操作结果" } } } ``` V1 简化约定:App 返回的用户操作结果统一放在 `result.message` 字段。后续工具需要更丰富的返回格式时(如文件路径、选择详情),再按工具定义扩展 `result` 结构。 --- ## 三、协议分层关系 ``` 通讯协议层(WebSocket 连接、心跳、重连、鉴权) ↓ 消息协议层(信封 + 消息类型) ↓ 工具协议层(工具定义 + 工具调用流程) ``` 三层独立不耦合。通讯层换了,上面两层不用改。消息层升版本号,工具层不受影响。工具层加新工具,上面两层不需要动。 --- ## 四、与 MCP 的对应关系 ``` MCP LineUp ────────────────────────────────────── MCP Server ────────────── Tool(画板 / 计算器 / 选择框) │ │ ├─ MCP Tool A ├─ Action(open / draw / add / select) ├─ MCP Tool B ├─ Action └─ MCP Tool C └─ Action ``` MCP 里每一个 Tool 是无状态的一次性调用单元。LineUp 里 Tool 多了一层容器层。app 类型让有状态工具在逻辑上是一个整体,Agent 看到 canvas 就知道这是一个画板应用,再看 actions 就知道具体可以做什么。