d060962a5f
- Replace command/subcommand/args with module/method/input envelope - Calendar handler uses discriminated union (mode) for read operations - Strict Pydantic models with extra='forbid' for all calendar methods - Worker max_iters=7, router prompt simplified (removed project_cli_defaults) - Skill index cards + per-action files for progressive disclosure - Frontend/AG-UI aligned to module/method dispatch - Protocol docs updated to module/method/input contract WIP: action cards need envelope fix, 2 tests need update, memory handler needs Pydantic models.
8.8 KiB
8.8 KiB
Agent Tool Protocol
本文件定义当前项目中 AgentScope tool、项目 CLI、tool post-processor、SSE/history/persistence 之间的协议边界。
1. Scope
本协议覆盖:
- AgentScope tool wrapper
- 项目内受限 CLI tool
- runtime tool post-processor
ToolResponseToolAgentOutput- tool message
content - tool 结果的 SSE/history/persistence 表达
本协议不覆盖:
- 前端视觉实现细节
- worker answer 文案格式
- 非 tool 的普通 assistant 文本输出
2. Core Principles
- 项目 CLI 是受限工具执行边界,不是通用 shell。
- agent 只暴露一个 AgentScope tool:
project_cli。 - skills 只负责向 agent 披露如何使用
project_cli,不承担执行 transport、分发或权限决策。 - Router 是 CLI 的唯一动作分发核心,只允许白名单
module + method。 - 每个 CLI method 绑定 Python handler 或 action dispatcher。
- handler 只能调用允许的内部能力,不开放任意系统命令执行。
6.1
project_cli权限由 runtime 的 module 白名单与 CLI router 白名单共同约束,不能由 skills 可见性隐式放开。 ToolAgentOutput.result是 canonical machine-oriented tool result。ToolResponse不承载完整ToolAgentOutput,只承载给 agent 使用的文本投影。- tool UI 只来自
ToolAgentOutput.ui_hints,不再经过 workerui_hints -> ui_schema链路。
3. Execution Flow
一次 tool 调用按如下顺序执行:
- AgentScope tool
project_cli接收到模型生成的 tool call。 - wrapper 将
module + method + input映射为项目 CLI 输入。 - runtime 将受控认证凭证通过环境变量注入 CLI 子进程。
- CLI router 将
(module, method)分发给对应 Python handler。 - handler 执行业务逻辑并返回结构化
result。 - wrapper 将
result投影为文本,写入ToolResponse.content。 - runtime tool post-processor 基于
result和 runtime 上下文生成完整ToolAgentOutput。 ToolAgentOutput进入:TOOL_CALL_RESULTmetadata.tool_agent_output- history replay
- context rebuild
4. Input Channels
Agent -> project_cli 的结构化入参:
{
"module": "calendar",
"method": "read",
"input": {
"mode": "range",
"start_at": "2026-04-21T00:00:00+08:00",
"end_at": "2026-04-22T00:00:00+08:00"
}
}
补充说明:
project_cli对模型暴露的 schema 保持薄封装,只保证存在module、method、input三层。- method 级别的严格字段校验由服务端 dispatch 到对应 Pydantic model 后执行。
- 对日期/时间字段使用强类型约束:
date使用 Pydanticdate,时间区间使用带时区的datetime。 - 不再把完整 action matrix 直接注入工具 schema,以保留渐进式披露和较低 token 成本。
CLI 运行时输入通道采用“两者结合”:
argv为主:- module
- method
- mode / formatting flags
stdin为辅:- 较大的 JSON payload
- 复杂对象参数
- 多步批量操作负载
- environment variables:
- controlled credential
- runtime-only internal context
约束:
- 模型不可见的认证信息不得进入 tool args。
- CLI 不接受来自自然语言/模型参数的任意 token 字符串。
- backend runtime 只能通过受控环境变量注入认证凭证。
权限边界:
enabled_skills仅控制 skill 文档可见性与注册。- runtime 白名单控制
project_cli可执行的 module/method 集合。 - 两者职责解耦,避免“技能可见即动作授权”的隐式耦合。
5. CLI Output Contract
CLI handler 的原始成功输出必须是统一结构化结果。
示例:
{
"ok": true,
"module": "calendar",
"method": "read",
"data": {
"items": [
{
"id": "evt_123",
"title": "Project sync",
"startAt": "2026-04-21T10:00:00+08:00"
}
],
"count": 1
}
}
失败时,CLI handler 必须返回结构化错误结果。
6. ToolResponse Contract
ToolResponse 只用于给 agent 提供 tool 结果文本投影。
规则:
ToolResponse.content只包含result的完整 JSON 文本投影。- 不再把完整
ToolAgentOutput序列化后塞进ToolResponse.content。 - 文本投影必须与
result保持等价信息量,不做摘要裁剪。
示例:
{"status":"success","items":[{"id":"evt_123","title":"Project sync","startAt":"2026-04-21T10:00:00+08:00"}],"count":1}
7. Tool Post-Processor Contract
runtime 必须在 tool 调用完成后运行 tool post-processor。
post-processor 负责生成完整 ToolAgentOutput,至少包括:
tool_name(固定为project_cli)tool_call_idtool_call_argsstatusresulterrorui_hints
规则:
result是真源。result应保留module、method和data。ui_hints由 post-processor 生成,不由 worker 生成。- tool 失败时
error必须为结构化对象。 status必须是success | failure | partial。
ui_hints 输出范围(当前协议):
- 输出:当前业务 action 中适合稳定结构化展示的调用
calendar.readcalendar.createcalendar.updatecalendar.deletecalendar.sharecalendar.accept_invitecalendar.reject_invitecontacts.readmemory.update
- 若某 action 暂无稳定 UI 模板,可不输出
ui_hints,但不能回退为 worker 生成 UI。
8. ToolAgentOutput Contract
ToolAgentOutput 用于系统内部和前端消费,不直接作为模型上下文主输入。
消费位置:
TOOL_CALL_RESULT- 数据库存储
metadata.tool_agent_output /historytool UI replay- cold-path context rebuild
规则:
tool_name固定为project_cli。result必须是 JSON-native、machine-oriented 结构。- 必须包含后续链式调用所需的 ID/outcome/status/count 等事实。
ui_hints是 tool UI 的唯一真源。
推荐的 result 形状:
{
"module": "calendar",
"method": "read",
"data": {
"id": "evt_123",
"title": "Project sync"
}
}
失败时应返回结构化、可纠正的错误对象,而不是只返回泛化文案:
{
"status": "failure",
"error": {
"code": "INVALID_ACTION_INPUT",
"message": "calendar.read input does not match method schema",
"module": "calendar",
"method": "read",
"input_schema": {
"mode": "string enum(day|range|event)"
}
}
}
9. History Replay Contract
/history 必须支持 tool UI 回放。
规则:
- history 对外返回 tool message。
- tool message 的 UI 恢复从
metadata.tool_agent_output.ui_hints读取,编译为ui_schema后返回。 - tool message
content仍是result的 JSON 文本投影。
9.1 messages.content 存储类型决策
- 当前决策:
messages.content继续保持text,不迁移到jsonb。 - 原因:
messages表承担多角色消息(user/assistant/tool),content统一作为文本载荷更稳定;- tool 的结构化数据已经由
metadata.tool_agent_output.result与metadata.tool_agent_output.ui_hints承载; /history、SSE、context rebuild 当前都按“content文本 + metadata 结构化字段”工作,避免双轨 schema 演进;- 实测出现过 dict 直接写入
messages.content导致驱动类型错误(expected str, got dict),保持text可减少写入歧义。
- 约束:凡写入
messages.content的数据必须是字符串;结构化对象必须进入metadata。
10. SSE Contract
规则:
TEXT_MESSAGE_END不再包含 workerui_hints或ui_schema。TOOL_CALL_RESULT携带ui_schema(由后端 codec 从ui_hints编译而来)。- tool UI 前端消费基于
ui_schema(由ui_hints编译)。
11. Controlled Credential Contract
tool runtime 的认证边界使用 controlled credential。
规则:
- chat 与 automation 都不得把
owner_id当作凭证。 - controlled credential 由当前 bearer token 签发方在同一信任边界内签发。
- TTL 目标为 5-10 分钟。
- 该凭证只覆盖 tool runtime 所需权限窗口。
- 凭证仅通过 backend-controlled env 注入 CLI。
- 日志、错误响应、history、SSE 中不得暴露原始凭证。
12. Security Constraints
- 不开放 shell 执行能力。
- 不允许通过 tool args 传任意 token。
- 不允许通过
owner_id伪造用户 Bearer token。 - 不允许把 DB session 直接注入 CLI 边界。
13. Compatibility Strategy
- 策略:
migration。 ui_schema作为 wire format 保留,由后端 codec 从ui_hints编译而来。- 前端 renderer 继续消费
ui_schema。 ui_hints作为内部字段,不直接传输给前端。- 模型侧
command/subcommand/args输入协议废弃并移除,不保留广义别名兼容。