Files
social-app/.trellis/tasks/04-20-refactor-tool-cli-skill-ui-schema/prd.md
T

739 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AgentScope Skill + CLI Tool Protocol Refactor PRD
## 1. Goal
本次重构的目标不是发明一套新的 agent 工具体系,而是把当前项目的工具执行、skill 使用、UI 生成这三条链路收敛到一条一致的协议路径上:
1. 以 AgentScope 原生 `tools``skills` 能力为基础。
2. 将当前项目工具包装为符合 AgentScope 工具协议的 CLI 工具。
3. skill 不负责执行工具,而是负责向 agent 渐进式披露"有哪些能力、什么时候用、怎么用"。
4. CLI 工具的 runtime 认证边界以用户登录 token 为主,默认通过受控环境变量注入,而不是直接注入数据库 session / owner_id。
5. worker agent output 不再输出 `ui_hints`
6. tool output 继续保留独立结构化协议对象,并可携带 `ui_hints` 给前端渲染使用。
7. worker 在 ReAct loop 中消费的工具信息应收敛为 tool message `content`,而不是完整 `ToolAgentOutput` 元数据对象。
8. `message.content` 继续保持文本投影,不升级为通用 schema 字段;结构化结果进入 `ToolAgentOutput.result`
9. `ToolResponse` 只返回 `result` 文本投影;再由 tool 后处理器把 `result` 解析/补全为完整 `ToolAgentOutput`,包括 `ui_hints` 等字段。
本次改造的核心收益:
- 减少 worker 输出 token 成本
- 消除 UI 在 worker / backend compiler / frontend renderer 三处漂移
- 让工具边界对 AgentScope、skill、前端渲染都更稳定
## 2. Corrected Design Principles
以下原则是本 PRD 的前提,必须严格遵守:
1. AgentScope 原生支持 `skills`
- 官方 README 明确列出 built-in support for `tools, skills`
- 官方示例提供 `toolkit.register_agent_skill(...)`
2. skill 是给 agent 的能力说明与工作流知识,不是业务执行 transport。
3. 如果工具改成 CLICLI 仍然必须服从 AgentScope 的工具协议,而不是项目自己随意定义。
4. preset/runtime 参数应该以认证凭证为边界,当前项目应使用 Bearer token,并默认通过受控环境变量注入 CLI 执行环境,而不是把 DB session 直接暴露给工具调用接口。
5. worker output 和 tool output 的协议职责必须分离,不能混成同一套字段语义。
6. 协议文档先行,`docs/protocols/**` 仍是项目单一协议真源。
7. 本项目的"CLI"是受限命令行工具,不是通用 bash/shell 执行能力。
## 3. Confirmed External Facts
### 3.1 AgentScope 对 Skills 的官方支持
已确认的外部事实:
- AgentScope 官方 README 明确写有 built-in support for `skills`
- 官方示例 `examples/functionality/agent_skill/main.py` 使用:
- `toolkit.register_agent_skill(...)`
- 官方示例同时说明:
- 使用 agent skill 时,agent 需要具备查看文本文件等基础工具能力
- skill 目录通过 `SKILL.md` 进行渐进式披露
已确认的 skill 示例结构:
- `SKILL.md` 包含 frontmatter`name``description`
- skill 内容描述:
- 适用场景
- 推荐工作流
- 需要执行的脚本/命令
- 何时读取补充材料
结论:本项目不应绕开 AgentScope skill 能力自行设计一套"伪 skill"机制。
### 3.2 AgentScope 工具协议的确认边界
已确认的 AgentScope 工具使用方式:
- `Toolkit.register_tool_function(...)` 注册 callable function
- tool 返回 `ToolResponse`
- `ToolResponse.content` 可承载 `TextBlock`
- toolkit 支持 `preset_kwargs`
这意味着如果本项目改成 CLI 路径,落点应是:
- 对 agent 来说,固定暴露为单一 AgentScope tool`project_cli`
- 对 tool 的内部实现来说,它可以调用 CLI
- CLI 的输入输出要能被稳定转换为 AgentScope `ToolResponse`
## 4. Confirmed Repository Facts
### 4.1 当前工具执行方式
当前项目仍然是 Python 函数直接注册多个工具:
- `backend/src/core/agentscope/tools/toolkit.py`
- `TOOL_FUNCTIONS` 直接绑定:
- `calendar_read`
- `calendar_write`
- `calendar_share`
- `user_lookup`
- `memory_write`
- `memory_forget`
- `build_toolkit()` 通过 `toolkit.register_tool_function(...)` 注册这些函数
- `backend/src/core/agentscope/tools/tool_config.py`
- 现统一使用 `enabled_skills``calendar|contacts|memory`)做能力白名单
- `backend/src/core/agentscope/runtime/runner.py`
- `_build_toolkit()` 根据 `enabled_skills` 选择技能白名单
结论:当前实现尚未接入 AgentScope skill,也尚未接入 CLI 工具边界。
### 4.2 当前项目中的认证边界
当前项目已有明确的 Bearer token 用户解析路径:
- `backend/src/v1/users/dependencies.py`
- `get_current_user()``Authorization: Bearer <token>` 解析 token
- 先走 JWT verifier,再 fallback 到 Supabase user lookup
- 最终产出 `CurrentUser`
- `backend/src/core/auth/models.py`
- `CurrentUser` 当前字段:`id``phone``role`
结论:如果工具改为 CLI,runtime 的合理边界应是 token 或 auth credential,而不是 DB session / owner_id。token 默认通过受控环境变量注入 CLI 运行环境,CLI 内部再根据 token 推导用户身份和数据访问上下文。
补充约束:
- 不能仅凭 `owner_id` 直接构造用户 Bearer token`owner_id` 不是签名凭证。
- automation 场景由当前 Bearer token 的签发方负责基于 `automation_jobs.owner_id` 签发短期受控凭证;若现有签发链路不支持,则补一个服务端签发函数。
- 当前假设该签发方与用户登录 Bearer token 的签发体系一致;现有若仅支持"邮箱 + 验证码"登录签发,则在同一信任边界下新增 automation 凭证签发能力。
- automation 受控凭证生命周期目标为 5-10 分钟,只覆盖 agent 调用工具所需窗口。
- 该凭证的签发方式、有效期、权限边界和审计规则必须在协议文档中写清。
### 4.3 当前 worker output 与 UI 路径
当前 worker output 仍然包含 UI 描述:
- `backend/src/schemas/agent/runtime_models.py`
- `WorkerAgentOutputRich.ui_hints`
当前 runtime 会把 `ui_hints` 带入最终文本事件:
- `backend/src/core/agentscope/runtime/stage_emitter.py`
- `emit_final_text_end()``ui_hints` 写入 payload
当前对外 AG-UI payload 会把 `ui_hints` 编译为 `ui_schema`
- `backend/src/core/agentscope/events/agui_codec.py`
- `TEXT_MESSAGE_END` 上执行 `compile_ui_hints(...)`
当前 history 回放同样依赖 `ui_hints -> ui_schema`
- `backend/src/v1/agent/utils.py`
- `backend/src/v1/agent/schemas.py`
结论:当前 `ui_schema` 的真源是 worker 自身输出的 `ui_hints`。本次改造将把 `ui_hints` 的来源从 worker output 改为 tool output`ui_hints → ui_schema` 的编译链路保持不变。
### 4.4 当前前端消费方式
前端当前消费的是后端下发的编译后 `ui_schema`
- `apps/lib/core/chat/ag_ui_event.dart`
- `apps/lib/core/chat/chat_history_repository.dart`
- `apps/lib/shared/widgets/ui_schema/ui_schema_renderer.dart`
- `apps/lib/features/home/presentation/widgets/home_chat_item_renderer.dart`
结论:前端目前理解的是后端已编译好的 `ui_schema`。本次改造目标不是改变前端消费方式,而是改变 `ui_hints` 的来源(从 worker 改为 tool),`ui_hints → ui_schema` 编译链路保持不变。
### 4.5 当前 tool result 结构
当前 tool result 已经走 machine-oriented 路线,但结构还不完整:
- `backend/src/core/agentscope/tools/utils/tool_response_builder.py`
- tool 最终返回 `ToolResponse`
- 当前 `ToolResponse` 中仍混入完整 tool 结构,不符合目标边界
- `backend/src/core/agentscope/utils/parsing.py`
- 从 ToolResponse text block 中恢复 `ToolAgentOutput`
- `backend/src/core/agentscope/runtime/stage_emitter.py`
- `TOOL_CALL_RESULT` payload 包含 `tool_name``tool_call_args``status``result`
当前仓库已经存在"给 agent 的文本内容"和"给事件/持久化的完整结构化对象"分离的模式:
- `backend/src/core/agentscope/events/store.py`
- tool 消息持久化时:`content = tool_output.result`
- 完整结构化对象进入 `metadata.tool_agent_output`
- `backend/tests/unit/core/agentscope/events/test_store.py`
- 明确校验 tool message `content` 等于文本结果
- 同时完整 `tool_agent_output` 保存在 metadata 中
结论:当前仓库已经证明一个正确的职责分层:
- worker/上下文消费的应是 tool message `content`
- AG-UI 事件、持久化和前端渲染可以保留完整 `ToolAgentOutput`
但当前仍有三个缺口:
- `ToolAgentOutput` 还没有承载前端所需 `ui_hints`
- `ToolAgentOutput.result` 仍是字符串,还没有升级为结构化对象字段
- `ToolResponse` 还没有收敛为只承载 `result` 文本投影,再交给 tool 后处理器生成完整 `ToolAgentOutput`
此外,history/replay 的正确恢复方向也已经比较明确:
- 可以像 worker output 一样,从 `message.metadata` 中恢复结构化对象
- 对 tool 来说,恢复源应是 `metadata.tool_agent_output.ui_hints`
## 5. Problem Statement
当前实现存在 5 个核心问题:
1. 工具实现直接耦合在 Python runtime 函数注册层,缺少独立协议边界。
2. skill 尚未成为 agent 的原生能力入口,工具知识仍主要依赖 prompt 和函数 docstring。
3. worker 仍承担 UI 描述职责,导致 `ui_hints` 占 token,且与前后端实现容易漂移。
4. tool result 已经拥有独立结构化对象,但没有成为 UI 渲染主路径。
5. 当前 tool output 协议没有明确区分"给 worker 推理的 content"和"给前端渲染的完整结构化输出"。
6. 当前 CLI 工具边界尚未定义为受限命令行工具,容易和通用 shell 执行概念混淆。
## 6. Target Architecture
### 6.1 总体方向
目标架构应遵循下面的职责分层:
1. AgentScope skill
- 负责告诉 agent
- 有哪些工具能力
- 什么时候调用
- 调用前后如何决策
- 不直接承担业务执行
2. AgentScope tool
- agent 固定只看到一个工具入口:`project_cli`
- 内部执行方式为结构化 `command + subcommand + args` -> 调用项目 CLI -> 适配回 ToolResponse
3. CLI tool
- 是业务执行边界
- 输入输出必须稳定、结构化、可验证
- 采用经典命令树:`command + subcommand + args`
- 不按 `skill + action` 建模 CLI
- 必须符合 AgentScope 工具协议适配需要
- 必须是受限项目命令行工具,不提供通用 bash/shell 能力
4. Tool output protocol
- 保留独立的 `ToolAgentOutput` 类协议对象
- 对 AG-UI 事件、持久化元数据、前端渲染负责
- 可包含 `ui_hints` 这类前端渲染字段
5. UI contract
- 由 tool output 中的 `ui_hints` 编译生成 `ui_schema`
- `ui_schema` 成为前端渲染的输入
- worker output 不再输出 `ui_hints`
### 6.2 Token / 受控凭证作为 runtime 注入参数
本项目要求将 Bearer token 或受控服务端凭证作为 tool runtime 注入参数,而不是 DB 级参数。
目标边界:
- AgentScope tool 被调用时,runtime 将认证 token 或受控服务端凭证注入 CLI 执行环境
- CLI 接收到 token 后:
- 验证 token
- 解析用户身份
- 推导可访问数据范围
- 再进入 service / repository / DB 层
禁止继续扩大的错误边界:
- 不应把 `AsyncSession` 直接暴露到 CLI 工具调用边界
- 不应把 `owner_id` 当作唯一可信的输入
- 不应让 agent 直接控制数据库上下文对象
当前优先方案:
- token 不作为模型可见的业务参数字段进入 tool args schema
- token 由 runtime 以默认环境变量方式注入到 CLI 子进程
- CLI 只读取受控环境变量,不从自然语言或 tool args 中接受任意 token 字符串
- automation 不直接伪造用户 Bearer token;由当前 token 签发方基于 `automation_jobs.owner_id` 获取或签发 5-10 分钟短期受控凭证后注入
### 6.3 ToolResponse 与 ToolAgentOutput 的边界
本次协议边界明确如下:
- CLI/Tool 原始执行结果先产出结构化 `result`
- AgentScope `ToolResponse` 只承载给 agent 使用的 `result` 文本投影
- 不再把完整 `ToolAgentOutput` 直接塞进 `ToolResponse.content`
- runtime 内增加 tool 后处理器:基于 `result` 解析/补全完整 `ToolAgentOutput`
- 该后处理器负责补齐:
- `tool_name`
- `tool_call_id`
- `tool_call_args`
- `status`
- `result`
- `error`
- `ui_hints`
这样职责分层固定为:
- agent 只看到 `message.content` / `ToolResponse` 中的 `result` 文本投影
- runtime / SSE / history / persistence 使用完整 `ToolAgentOutput`
### 6.4 Worker 与 Tool 输出职责分离
根据当前仓库已存在的运行时与持久化逻辑,本次重构必须明确保持以下分层:
1. worker output
- 面向 worker 最终回答
- 不再包含 `ui_hints`
2. tool output
- 使用 `ToolAgentOutput` 作为结构化协议对象
- 面向 AG-UI 事件、历史持久化、前端渲染
- 可以包含 `ui_hints`
3. tool message content
- 面向 agent ReAct loop 上下文
- 应是工具结构化结果的稳定文本投影
- 不应把完整 `ToolAgentOutput` 字段直接作为下一轮 worker 输入上下文
当前仓库中的支持证据:
- `backend/src/core/agentscope/events/store.py`
- tool message `content = tool_output.result`
- metadata 保留完整 `tool_agent_output`
因此正确方向不是删除 `ToolAgentOutput`,而是:
- 保留 `ToolAgentOutput` 作为独立 tool 协议对象
- 只让 worker 主要消费 tool message `content`
### 6.4 `message.content` 字段策略
本次不建议把 `message.content` 从文本改成通用 schema 字段。
原因:
1. AgentScope/Msg 本身是通用消息抽象,不同 role 的 content 类型已经存在差异,但当前项目的 worker 推理、历史持久化、事件处理都默认把文本内容当作主信息载体。
2. 当前仓库已经有一条可工作的分层:
- `message.content` 给 worker 推理
- `metadata.tool_agent_output` 给结构化消费
3. 若把 `message.content` 直接升级为 schema,会把:
- ReAct loop
- memory/context assembly
- event store
- history replay
- frontend parsing
一起拉进大范围协议改动,收益不成比例。
因此推荐策略是:
- `message.content` 继续保持文本
- 文本内容由 `ToolAgentOutput.result` 结构化对象稳定投影生成
- 结构化真源放在 `ToolAgentOutput.result`
也就是说,后续语义应变成:
- `message.content`: 给 worker 的完整 JSON 文本投影
- `ToolAgentOutput.result`: 给系统使用的结构化对象真源
### 6.5 UI 真源迁移方向
本次改造的目标不是"前端直接裸渲染任意 CLI 参数 schema",而是:
1. 先把 tool output 协议收敛为稳定的结构化 schema
2. 在 tool output 协议中保留前端所需 `ui_hints`
3. 再从该协议导出 AG-UI / history / frontend 统一 contract
4. AG-UI 传输时:后端 codec 将 `ui_hints` 编译为 `ui_schema` 后传输
5. 前端渲染 `ui_schema`(复用现有 `UiSchemaRenderer`
**关键设计决策**
- `ui_hints` 是 tool 输出的描述性 UI 表示(真源)
- `ui_schema` 是编译后的渲染性 UI 表示(传输格式)
- 编译链路 `ui_hints → ui_schema` 保持不变,仅改变 `ui_hints` 的来源
- 前端继续使用现有 `UiSchemaRenderer` 渲染 `ui_schema`
因此本次必须避免两个错误方向:
1. 继续保留 `worker -> ui_hints -> ui_schema`(应改为 `tool -> ui_hints -> ui_schema`
2. 让前端直接绑定 `ui_hints` 而不是 `ui_schema`
3. 把完整 `ToolAgentOutput` 直接塞回 worker 推理输入,而不是让 worker 主要消费 tool message `content`
4. 把"项目 CLI"实现成可执行任意 shell 的通用命令入口
## 7. Required Refactor Requirements
### 7.1 Skill 接入要求
必须:
- 基于 AgentScope 原生 `register_agent_skill(...)` 接入 skill
- 提供项目内 skill 目录与 `SKILL.md`
- skill 内容必须包含:
- 工具能力说明
- 何时调用哪个工具
- 参数构造规则
- 组合调用规则
- 失败后的恢复策略
不允许:
- 用单纯 prompt 文本替代 skill
- 自定义一套与 AgentScope skill 不兼容的 skill 机制
### 7.2 CLI Tool Protocol 要求
CLI 工具必须满足:
- 能被 AgentScope tool wrapper 稳定调用
- 输入参数可从当前 AgentScope tool schema 映射得到
- 输出结果可稳定映射回 `ToolResponse`
- 输出至少包含:
- 状态
- 结构化结果
- 错误信息
- 前端渲染所需的稳定字段
CLI 输出在进入 AgentScope tool wrapper 后,最终需要映射成两层信息:
1. `message.content`
- 给 worker ReAct loop 使用
- 应为结构化 `result` 的稳定文本投影
- 由结构化 `result` 稳定投影生成
- 默认保留完整 JSON 文本投影,不做阉割式摘要裁剪
2. `ToolAgentOutput`
- 给 AG-UI 事件、持久化、前端渲染使用
- 至少包含 `tool_name``tool_call_id``tool_call_args``status``result``error`
- 本次应扩展支持 `ui_hints`
这里的实现约束已经确定:
- `ToolResponse` 只返回 `result` 文本投影
- 完整 `ToolAgentOutput` 由 tool 后处理器在 runtime 内生成
- `ui_hints` 由 tool 后处理器生成并写入 `ToolAgentOutput`
- `ui_hints` 经后端 codec 编译为 `ui_schema` 后传输给前端
- worker 不参与 tool UI 生成
需要显式设计:
- stdin / argv / env 何者承载输入
- token 放在哪个输入通道
- stdout 返回 JSON 的格式
- 非 0 exit code 的错误语义
当前已确认的输入通道策略:
- CLI 输入通道采用"两者结合"
- 默认以 `argv` 为主、`stdin` 为辅
- token 继续通过受控环境变量注入,不进入模型可控参数
### 7.3 Tool Configuration 保留要求
以下配置能力必须保留:
- `enabled_skills` from system agents config
- `enabled_skills` from automation jobs config
允许变化的部分:
- `enabled_skills` 不再映射到 Python 函数名
- 改为映射到 CLI-backed tool capability
### 7.4 Worker Output 精简要求
worker output 必须移除:
- `ui_hints`
worker output 保留:
- `status`
- `answer`
- `suggested_actions`
- `error`
是否增加新的结构化字段,必须以协议文档先定义为前提;禁止再次引入新的"隐式 UI 描述字段"。
### 7.5 Tool Output 协议重构要求
`ToolAgentOutput` 不应被删除,而应被重构为更完整的 tool 协议对象。
至少应满足:
- 保留当前已有字段:
- `tool_name`
- `tool_call_id`
- `tool_call_args`
- `status`
- `result`
- `error`
- 扩展支持:
- `ui_hints`
其中 `result` 应升级为结构化对象字段,不再以字符串为真源。
同时需要新增一条投影规则:
- 从结构化 `result` 生成稳定文本投影,写入 tool message `content`
- 默认使用完整 JSON 投影,保持与 `result` 信息量一致,避免因摘要裁剪削弱模型对结构化数据的读取能力
同时需要固定 tool 后处理规则:
- 后处理器以 tool 原始 `result` 为真源
- 根据 result 解析/补齐 `ToolAgentOutput`
- `ui_hints` 由后处理器生成并写入 `ToolAgentOutput`
- worker 不参与 tool UI 生成
这样可以满足两条不同消费链路:
- worker 继续消费由 `result` 投影生成的 `message.content`
- AG-UI / history / frontend 消费完整 `ToolAgentOutput`
### 7.6 UI Contract 重构要求
必须完成:
- `TEXT_MESSAGE_END` 不再依赖 worker `ui_hints` 编译
- history assistant message 不再依赖 `metadata.agent_output.ui_hints` 编译
- tool result 成为 UI 合约的主要输入之一
- `TOOL_CALL_RESULT` / tool metadata / history replay 能保留 tool `ui_hints`
AG-UI 传递策略调整为:
- tool 事件内部携带 `ui_hints`
- 后端 codec 将 `ui_hints` 编译为 `ui_schema`
- AG-UI 对前端传输 `ui_schema`
- 前端继续复用现有 UI 渲染器渲染 `ui_schema`
- history 恢复时优先从 `message.metadata.tool_agent_output.ui_hints` 读取并编译为 `ui_schema` 后渲染
这里的设计结论已经确定:
- `ui_hints` 是 tool 输出的 UI 描述(真源)
- `ui_schema` 是编译后的渲染格式(传输格式)
- 编译链路 `ui_hints → ui_schema` 保持不变
- 前端继续使用现有 `UiSchemaRenderer` 渲染 `ui_schema`
## 8. Scope Of Changes
### 8.1 Protocol Docs
必须更新:
- `docs/protocols/ui/ui-schema.md`
- `docs/protocols/ui/data-flow.md`
- `docs/protocols/agent/sse-events.md`
- `docs/protocols/agent/run-agent-input.md`
- `docs/protocols/agent/api-endpoints.md`
建议新增:
- 一个工具协议文档,明确:
- CLI 输入输出约定
- token preset 约定
- tool result 到 UI contract 的映射边界
### 8.2 Backend
主要改动点:
- `backend/src/core/agentscope/tools/toolkit.py`
- `backend/src/core/agentscope/tools/tool_config.py`
- `backend/src/core/agentscope/runtime/runner.py`
- `backend/src/core/agentscope/runtime/stage_emitter.py`
- `backend/src/core/agentscope/events/agui_codec.py`
- `backend/src/core/agentscope/events/store.py`
- `backend/src/core/agentscope/runtime/tasks.py`
- `backend/src/core/agentscope/utils/parsing.py`
- `backend/src/schemas/agent/runtime_models.py`
- `backend/src/v1/agent/utils.py`
- `backend/src/v1/agent/schemas.py`
- 新增 skill 资产与 CLI adapter
- 新增 Python console entrypoint 与内嵌 command router
skill 资产目录精确落点:
- `backend/src/core/agentscope/tools/custom`
skill 部署方式:
- 参考 AgentScope skill 提供的原生装载/注册方法进入运行时与部署产物
- 现有 `custom/*.py` 不再保留为最终工具实现,后续由 CLI handler / router 重写替换
### 8.3 Cleanup / 收尾清理
本次改造完成后,必须明确收尾清理以下代码与路径,避免旧协议残留:
1. 删除或下线 worker `ui_hints` 主路径
- `backend/src/schemas/agent/runtime_models.py` 中 worker rich output 的旧定义
- `backend/src/core/agentscope/runtime/stage_emitter.py` 中向 `TEXT_MESSAGE_END` 写入 worker `ui_hints` 的逻辑
- `backend/src/core/agentscope/events/agui_codec.py``TEXT_MESSAGE_END``compile_ui_hints(...)` 主路径
- `backend/src/v1/agent/utils.py` 中 assistant history 读取 worker `ui_hints` 并编译的逻辑
2. 清理旧文档语义
- `docs/protocols/ui/data-flow.md` 中"worker ui_hints 是 UI 真源"的描述
- `docs/protocols/ui/ui-schema.md` 中把 UI compiler 绑定到 worker `ui_hints` 的描述
- `docs/protocols/agent/sse-events.md` / `api-endpoints.md` / `run-agent-input.md` 中与旧 worker UI 路径冲突的描述
3. 清理测试中的旧假设
- 依赖 worker `ui_hints` 的 runtime/event/history 单测
- 依赖 `ToolAgentOutput.result` 为字符串真源的测试
4. 清理旧前端假设
- 只接受 assistant `ui_schema` 而不理解 tool `ui_schema` 的渲染逻辑
- 历史/事件解析中把 assistant UI 当唯一 UI 来源的路径
5. 清理旧工具调用边界
- 继续把 Python runtime 函数当作唯一稳定工具边界的 registry 代码
- 任何会把 DB session / owner_id 直接注入到 CLI 边界的适配代码
-`custom/*.py` 直接工具实现
6. 清理第二条 runtime 冷路径
- `backend/src/core/agentscope/runtime/tasks.py` 中与新 tool output/context rebuild 不一致的旧序列化路径
- 所有会导致热路径、冷路径看到不同 tool 上下文的兼容逻辑
### 8.4 Frontend
主要改动点:
- `apps/lib/core/chat/ag_ui_event.dart`
- `apps/lib/core/chat/chat_history_repository.dart`
- `apps/lib/shared/widgets/ui_schema/ui_schema_renderer.dart`(保持不变,继续渲染 `ui_schema`
- `apps/lib/features/home/presentation/widgets/home_chat_item_renderer.dart`
## 9. Phased Plan
### Phase 1. Protocol Correction
先修正文档中的错误前提:
- 明确 AgentScope skill 是原生能力
- 明确 CLI 是工具实现载体,不是替代 AgentScope tool/skill
- 明确 token 环境变量注入边界
- 明确仅 worker `ui_hints` 将被移除,tool `ui_hints` 保留在独立协议中
- 明确 `ui_hints → ui_schema` 编译链路保持不变
### Phase 2. Skill And Tool Boundary Refactor
- 接入项目内 skill
- 定义单一 `project_cli` AgentScope tool wrapper
- 使用 Pydantic 化的 `enabled_skills` 作为唯一配置字段
- CLI 输入通道采用"两者结合",默认 `argv` 为主、`stdin` 为辅
- 定义 Python console entrypoint 作为外部 CLI 入口
- 定义内嵌 command router 作为唯一分发核心
- router 只注册白名单 `command + subcommand`
- 每个命令绑定 Python handler
- handler 只调用允许的内部能力
- 默认不开放 shell 执行能力
- 移除旧多工具暴露实现,改为 skills 手册 + 单一 CLI 入口
### Phase 3. Auth-Preset Refactor
- 将 tool preset 从 runtime DB context 改为 auth token / 受控凭证
- CLI 内部完成身份解析与数据作用域推导
- token 默认通过受控环境变量进入 CLI,而不是模型可控参数
- automation 基于 `automation_jobs.owner_id` 获取或签发受控凭证,不直接伪造用户 Bearer token
### Phase 4. UI Source Refactor
- 删除 worker `ui_hints` 输出
- 删除 worker `ui_hints -> ui_schema` 编译主路径
- 将 tool `ui_hints` 纳入 `ToolAgentOutput` 协议
-`ToolAgentOutput.result` 升级为结构化对象
- 建立 `result -> message.content` 的稳定完整 JSON 文本投影规则
- 建立 tool output `ui_hints → ui_schema` 的编译路径
### Phase 4.5 Runtime Path Unification
- 改造 `backend/src/core/agentscope/runtime/tasks.py`
- 确保热路径、冷路径、context rebuild 都使用同一套:
- `ToolAgentOutput.result` 结构化对象真源
- `message.content` 完整 JSON 文本投影
- `metadata.tool_agent_output` 作为历史恢复真源
- 移除第二条旧路径,避免同一线程在不同路径下看到不同 tool 上下文
### Phase 5. Frontend Alignment
- 调整事件解析和 history 解析,从 `TOOL_CALL_RESULT.ui_schema` 读取
- 渲染逻辑保持不变,继续使用 `UiSchemaRenderer` 渲染 `ui_schema`
## 10. Acceptance Criteria
- [ ] PRD 与协议文档不再错误描述 AgentScope skill 能力
- [ ] skill 通过 AgentScope 原生能力接入,而不是自定义伪 skill 机制
- [ ] 单一 `project_cli` 能通过 AgentScope tool protocol 被稳定调用
- [ ] 工具 runtime 以 Bearer token / 受控服务端凭证为边界
- [ ] token/凭证 默认以受控环境变量注入 CLI 执行环境
- [ ] CLI 能基于 token/凭证 解析用户身份与数据访问范围
- [ ] automation 能基于 `owner_id` 由当前 token 签发方签发 5-10 分钟受控凭证,但不直接伪造用户 Bearer token
- [ ] `enabled_skills` 能驱动技能手册和允许命令域配置
- [ ] worker output 不再包含 `ui_hints`
- [ ] `ToolAgentOutput` 保留为独立 tool 协议对象,并支持 `ui_hints`
- [ ] worker 在上下文中主要消费 tool message `content/result`,而不是完整 `ToolAgentOutput`
- [ ] `message.content` 保持文本,不升级为通用 schema 字段
- [ ] `ToolAgentOutput.result` 升级为结构化对象真源
- [ ] `message.content` 采用完整 JSON 文本投影,而不是裁剪摘要
- [ ] `ToolResponse` 只承载 `result` 文本投影
- [ ] tool 后处理器能基于 `result` 生成完整 `ToolAgentOutput`(含 `ui_hints`
- [ ] `TEXT_MESSAGE_END` 和 assistant history 不再依赖 worker `ui_hints` 编译 UI
- [ ] history 能直接从 `metadata.tool_agent_output.ui_hints` 恢复 tool UI
- [ ] `runtime/tasks.py` 等冷/热路径已统一,不再存在第二条旧路径
- [ ] 前端继续通过现有 UI 渲染器消费 `ui_schema` 渲染内容
- [ ] `ui_hints → ui_schema` 编译链路保持不变,仅改变 `ui_hints` 来源
- [ ] skill 资产目录已落在 `backend/src/core/agentscope/tools/skills`
- [ ] skill 部署/装载方式与 AgentScope 原生方法保持一致
- [ ] CLI 输入通道已按 `argv` 主、`stdin` 辅的组合模式落地
- [ ]`custom/*.py` 直接工具实现已被 CLI handler / router 替换
## 11. Open Questions
当前 open questions 已收口,不再保留架构级未决项。
已确认结论:
1. `ui_hints` 是 tool 输出的 UI 描述(真源),`ui_schema` 是编译后的渲染格式(传输格式)
2. skill 资产目录最终精确落点为 `backend/src/core/agentscope/tools/custom`
3. skill 部署方式参考 AgentScope skill 提供的原生方法
4. CLI 输入通道采用"两者结合",默认 `argv` 为主、`stdin` 为辅
5. history route 的 tool UI 回放从 `metadata.tool_agent_output.ui_hints` 读取并编译为 `ui_schema`
6.`custom/*.py` 不再保留,工具实现改为 CLI handler / router
7. `ToolResponse` 只返回 `result` 文本投影,完整 `ToolAgentOutput` 由 tool 后处理器生成
## 12. Risks
1. 如果只把工具换成 CLI,但不先定义稳定工具协议,最终仍会把旧耦合问题原样搬过去。
2. 如果前端直接消费 `ui_hints` 而不是 `ui_schema`,会破坏现有渲染链路。
3. 如果把"项目 CLI"误实现为通用 shell/命令执行器,会引入提示词注入和越权风险。
4. 如果 token/凭证 注入边界设计不严谨,容易把认证逻辑散落到多个工具实现中。
5. 当前代码里仍有多处 broad catch,迁移时错误可能被掩盖:
- `backend/src/core/agentscope/events/agui_codec.py`
- `backend/src/v1/agent/utils.py`
- `apps/lib/core/chat/ag_ui_service.dart`
## 13. Definition Of Done
当以下条件全部满足时,本任务完成:
1. 协议文档修正完毕并成为实现依据。
2. AgentScope skill 已在项目内落地并承担工具使用知识披露。
3. 当前工具已切换为单一 `project_cli` + skills 手册架构。
4. token/受控凭证 已通过受控环境变量成为 CLI runtime 的认证边界。
5. worker output 已移除 `ui_hints`
6. `ToolAgentOutput` 已成为独立完整的 tool 协议对象,并承载前端所需 UI hints。
7. `ToolAgentOutput.result` 已升级为结构化对象真源。
8. worker 仅通过完整 JSON 文本投影的 tool message `content` 获取工具结果主信息。
9. history 能通过 `metadata.tool_agent_output.ui_hints` 编译为 `ui_schema` 恢复 tool UI。
10. `runtime/tasks.py` 等冷/热路径已统一,不再存在第二条旧路径。
11. AG-UI 对 tool UI 编译 `ui_hints → ui_schema` 后传输,前端继续复用现有 UI 渲染器。
12. 旧 worker UI 编译路径和相关清理项已完成收尾。
13. 前后端事件/history/渲染链路验证通过。
14. `ui_hints → ui_schema` 编译链路保持不变,仅改变 `ui_hints` 来源。
15. skill 资产已按约定落在 `backend/src/core/agentscope/tools/skills`,并按 AgentScope 原生方式装载。
16. CLI 输入通道已按 `argv` 主、`stdin` 辅的组合模式落地。
17. history route 已从 `metadata.tool_agent_output.ui_hints` 编译为 `ui_schema` 回放 tool UI。
18.`custom/*.py` 直接工具实现已被 CLI handler / router 替换。
19. `ToolResponse` 已收敛为只返回 `result` 文本投影,完整 `ToolAgentOutput` 由 tool 后处理器生成。