diff --git a/dist-electron/main/main.js b/dist-electron/main/main.js index 9f6ba8f..19437d3 100644 --- a/dist-electron/main/main.js +++ b/dist-electron/main/main.js @@ -1,6 +1,6 @@ "use strict"; require("electron"); -require("./main-CYkgmH75.js"); +require("./main-Cg0vBGtL.js"); require("electron-squirrel-startup"); require("electron-log"); require("bytenode"); diff --git a/dist/index.html b/dist/index.html index ac3ddba..2f7a431 100644 --- a/dist/index.html +++ b/dist/index.html @@ -8,8 +8,8 @@ http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn" /> - - + +
diff --git a/docs/ClawX-Chat-Skill-Runtime-Migration-Checklist.md b/docs/ClawX-Chat-Skill-Runtime-Migration-Checklist.md new file mode 100644 index 0000000..8c88b2b --- /dev/null +++ b/docs/ClawX-Chat-Skill-Runtime-Migration-Checklist.md @@ -0,0 +1,1386 @@ +# zn-ai 对齐 ClawX 的聊天 Skill 运行时迁移清单 + +## 1. 目标 + +让 `zn-ai` 的聊天运行时具备与 `ClawX` 同方向的能力: + +- 用户在聊天中提到某个已启用的 skill 时,模型能把它当成可规划、可调用、可回传结果的运行时能力,而不是只把它当成设置页里的开关。 +- 用户上传文件、引用网页、请求执行动作时,运行时能根据当前已启用 skills 自动规划合适的 skill/tool 链路。 +- 聊天链路能产生真实的 `thinking / tool_use / tool_result / final answer`。 +- 用户能在 UI 中看到执行过程、失败原因和最终结果。 + +首个样板场景仍然是: + +- 用户发送:`使用 minimax-xlsx 这个 skill,帮我分析下` +- 如果会话里已有 `.xlsx/.csv/.tsv` 附件,运行时能识别并把文件交给表格类 skill + +但这份文档的目标已经调整为: + +- 架构上按“所有已启用 skills 都能接入聊天运行时”来设计 +- `xlsx/minimax-xlsx` 只是第一条落地样板,不再作为唯一目标 + +## 2. 范围定义 + +### 2.1 最终目标范围 + +最终目标不是只支持 `minimax-xlsx`,而是支持: + +- 所有已启用 skills 在聊天时可见 +- 所有已启用 skills 可被模型规划 +- 所有已启用 skills 可被运行时调用 +- 所有已启用 skills 的结果可回传给模型并写入会话历史 +- 所有已启用 skills 的执行结果可被 renderer 展示 + +### 2.2 首批交付范围 + +首批交付不要求把每一个 skill 都逐个深度适配,但要求: + +- 运行时架构必须按“全量 skills 通用接入”设计 +- 第一批用 `xlsx/minimax-xlsx` 完成端到端验收 +- 第二批逐步覆盖其他 skill 类型,而不是继续新增特判分支 + +### 2.3 明确不再采用的方向 + +不采用下面这种方案: + +- 只为 `minimax-xlsx` 单独写一条聊天特判链路 +- 只为少数 skill 手工写 prompt 注入和执行代码 +- 让不同 skill 分别走不同的 ad-hoc 执行协议 + +## 3. 全量 skills 通用接入边界与阶段化策略 + +这一节单独回答一个关键问题: + +- 这次迁移是不是要把“所有 skills 都接进聊天运行时”考虑进去? + +答案是: + +- 要考虑进去 +- 但不是要求第一批把每一个 skill 都做成同等质量的深度适配 +- 而是要求从第一天起,架构必须按“全量 skills 可接入”来设计 + +### 3.1 通用接入边界 + +本次迁移的“全量 skills 通用接入”边界如下: + +- 所有已启用 skills 都必须能进入聊天运行时的 capability 列表 +- 所有已启用 skills 都必须能被 planner 看见并参与候选规划 +- 所有已启用 skills 都必须能映射到统一 executor 协议 +- 所有 skills 的执行结果都必须能落入统一的 `tool_result` 结构 +- 所有 skills 的执行过程都必须能被 transcript 和 renderer 消费 + +本次迁移不承诺的边界如下: + +- 不承诺首批就为每一个 skill 做专门的高质量 UI 定制 +- 不承诺首批就为每一个 skill 做类型专属优化 +- 不承诺首批就覆盖所有外部依赖复杂、权限要求高的 skills + +换句话说: + +- 首批必须做到“都能接” +- 但不要求首批“都接得一样深、一样好看、一样聪明” + +### 3.2 `SKILL.md -> runtime capability` 通用抽取规则 + +这是第一项必须补进文档的内容。 + +目标: + +- 不能把 `SKILL.md` 原文直接塞给模型 +- 需要抽成稳定、短小、可规划的 runtime capability + +通用抽取规则建议如下: + +1. 基础身份字段 + - `skillKey` + - `displayName` + - `description` + +2. 能力字段 + - `inputKinds` + - `outputKinds` + - `triggerHints` + - `supportedFileTypes` + +3. 约束字段 + - `requiresFiles` + - `requiresEnv` + - `requiresRuntime` + - `riskLevel` + +4. 执行字段 + - `defaultEntrypoint` + - `callPattern` + - `resultShape` + +抽取优先级建议: + +1. 先读显式元数据 +2. 再读 `SKILL.md` 的标题、description、usage、limitations +3. 最后使用默认推断规则兜底 + +兜底策略: + +- 如果 skill 没有足够结构化信息,也必须能生成最小 capability +- 不能因为 metadata 不完整就把 skill 排除出聊天运行时 + +### 3.3 Skill 分类分层策略 + +这是第二项必须补进文档的内容。 + +目标: + +- 不同 skill 的输入输出模式不同 +- 不能要求所有 skill 共用完全相同的 planner 提示和 executor 适配方式 + +首版推荐分层如下: + +1. 文档/文件类 + - 例:`xlsx`、`minimax-xlsx`、`pdf`、`docx` + - 典型输入:文件、路径、sheet、段落、页码 + - 典型输出:结构化数据、文件、摘要 + +2. 浏览器/网页类 + - 例:browser automation、web browse + - 典型输入:URL、页面元素、交互动作 + - 典型输出:页面快照、DOM 结果、提取数据 + +3. 搜索/检索类 + - 例:web search、knowledge search + - 典型输入:query、filters、time range + - 典型输出:候选结果、摘要、来源 + +4. 命令/脚本类 + - 例:shell、uv、脚本执行型 skill + - 典型输入:命令参数、工作目录、文件引用 + - 典型输出:stdout、stderr、产物文件、退出状态 + +5. 外部 API / 服务类 + - 例:需要第三方 API key 的 skill + - 典型输入:结构化参数、凭据引用、速率限制 + - 典型输出:API 响应、结构化记录、失败状态 + +分层原则: + +- planner 先按 skill type 缩小候选范围 +- executor 再按该 type 的 adapter 执行 +- UI 先展示通用结果,再逐步补 skill type 专属展示 + +### 3.4 Skill 前置检查策略 + +这是第三项必须补进文档的内容。 + +目标: + +- 不是 skill 已启用就一定可执行 +- 聊天运行时必须在规划前或执行前做前置检查 + +每个 skill 的前置检查至少包括: + +1. 依赖检查 + - 本地二进制是否存在 + - Python/Node/uv 运行时是否可用 + - 所需脚本是否存在 + +2. 环境变量检查 + - 必需 env 是否已配置 + - API key 是否存在 + - 敏感变量是否允许在当前运行环境使用 + +3. 权限检查 + - 是否需要文件访问 + - 是否需要网络访问 + - 是否需要 shell/命令执行权限 + - 是否需要浏览器自动化权限 + +4. 输入检查 + - 文件是否存在 + - 文件类型是否受支持 + - 参数是否齐全 + +前置检查的输出必须标准化为: + +- `ready` +- `blocked_missing_dependency` +- `blocked_missing_env` +- `blocked_missing_permission` +- `blocked_invalid_input` + +这一步的意义是: + +- 避免模型盲目调用 skill +- 避免把“权限没给”误判成“skill 不会用” +- 避免用户只看到一句模糊失败文案 + +### 3.5 通用 `tool_result` 标准化与 UI 渲染协议 + +这是第四项必须补进文档的内容。 + +目标: + +- 所有 skill 返回结果必须进入统一 `tool_result` +- renderer 先消费统一协议,再渐进增强不同 skill 类型的展示 + +建议统一结果结构: + +- `ok` +- `summary` +- `structuredData` +- `artifacts` +- `logs` +- `error` +- `retryable` +- `skillType` +- `renderHints` + +其中: + +- `structuredData` 用于模型继续推理 +- `artifacts` 用于文件、图片、表格结果回传 +- `logs` 用于调试和错误诊断 +- `renderHints` 用于 UI 做轻量差异化展示 + +UI 渲染协议建议分两层: + +1. 通用层 + - 所有 skills 都显示状态、摘要、错误、耗时、输入概览 + +2. 类型增强层 + - 文档类显示文件、sheet、提取结果摘要 + - 搜索类显示来源列表和摘要 + - 浏览器类显示页面结果与操作轨迹 + - 命令类显示输出日志与产物 + +原则: + +- 没有类型增强时,通用层也必须完整可用 +- UI 不得依赖某个单 skill 的私有字段才能渲染 + +### 3.6 阶段化策略 + +“全量 skills 通用接入”建议按 4 个阶段推进: + +#### Phase A:通用协议冻结 + +目标: + +- 冻结 capability schema +- 冻结 skill type taxonomy +- 冻结 preflight check 输出 +- 冻结 `tool_result` 标准结构 + +产出: + +- skill registry 契约 +- planner 输入输出契约 +- renderer 消费契约 + +#### Phase B:样板链路落地 + +目标: + +- 用 `xlsx/minimax-xlsx` 跑通文件类样板 +- 验证“启用 -> 可见 -> 可规划 -> 可执行 -> 可回传 -> 可展示” + +要求: + +- 代码实现必须走通用协议 +- 不允许新增只服务于 `minimax-xlsx` 的永久特判 + +#### Phase C:扩展到多 skill 类型 + +目标: + +- 选至少 1 个搜索类 skill +- 选至少 1 个浏览器或命令类 skill +- 验证通用架构不是只对文件类有效 + +要求: + +- 不改聊天主链路,只增加 registry/parser/adapter 配置 + +#### Phase D:规模化接入与收敛 + +目标: + +- 把更多已启用 skills 纳入 capability 列表 +- 补前置检查、错误模型、UI 增强 +- 补自动化回归 + +验收口径: + +- 新增 skill 时,原则上不需要再改 `chat.send` 主编排 +- 如果新增 skill 还需要改主编排,说明架构仍未真正通用 +## 4. 当前主结论 + +当前 `zn-ai` 的主阻塞不是 `minimax-xlsx` 没启用,而是: + +- 聊天运行时没有把已启用 skills 注入成可用能力 +- 聊天主链路仍是“文本 provider 直连”,不是通用 tool/skill runtime +- 附件虽然能进入聊天,但没有稳定进入“技能可消费输入链路” +- renderer 能显示少量工具状态,但没有完整执行闭环 +- 现有设计更接近“个别功能特判”,还不是“所有 skills 通用接入聊天运行时” + +## 5. 验收标准 + +迁移完成后,至少要通过这 6 个场景: + +1. 已启用 `minimax-xlsx`,用户发送 `使用 minimax-xlsx 这个 skill,帮我分析下`,模型不会只返回空泛文本,而会进入 skill/tool 执行链路。 +2. 用户上传 `.xlsx/.csv/.tsv` 后发送同一句话,运行时能把附件作为分析输入,而不是只把文件路径当普通文本。 +3. 用户启用任意其他文档类或搜索类 skill 后,聊天运行时能把该 skill 暴露为能力,而不是只在 Skills 页显示“已启用”。 +4. 聊天中能看到工具执行状态、结果摘要、失败信息;失败时能明确是“文件缺失 / skill 不可见 / provider 不支持 / runtime 执行失败 / skill 依赖未满足”。 +5. 多轮对话里,tool 结果能回灌到后续推理,不会出现“执行过了但模型下一轮不知道结果”。 +6. 新增一个符合规范的 skill 时,不需要再给聊天链路补新的特判代码,只需通过注册/抽取机制接入。 + +## 6. 通用接入原则 + +这一节是本次调整的核心。 + +### 5.1 所有 skills 都必须经过同一条能力链路 + +统一链路: + +1. Skill 发现 +2. Skill 元数据抽取 +3. Runtime capability 注入 +4. Planner 选择 skill/tool +5. Executor 调用 skill/tool +6. Tool result 标准化 +7. Transcript 写回 +8. Renderer 展示 + +任何 skill 都不应该绕过这条链路单独接入聊天。 + +### 5.2 `xlsx/minimax-xlsx` 只是样板,不是特例 + +首批先用它验收,是因为它最能暴露当前缺口: + +- 附件输入 +- 文件访问 +- tool loop +- 结果回灌 +- UI 展示 + +但一旦链路建好,其他 skills 也必须复用同一套机制。 + +### 5.3 先做“通用协议”,再做“具体 skill 适配” + +顺序必须是: + +1. 先冻结通用 skill capability schema +2. 先冻结通用 planner/executor/tool_result 协议 +3. 再做 `xlsx/minimax-xlsx` 样板接入 +4. 再扩展到更多 skills + +不能反过来先做某一个 skill 的特例实现,再倒推通用架构。 + +## 7. 通用能力模型 + +### 6.1 Skill capability schema + +每个已启用 skill 在聊天运行时至少要暴露这些字段: + +- `skillKey` +- `displayName` +- `description` +- `inputKinds` +- `outputKinds` +- `triggerHints` +- `requiresFiles` +- `supportedFileTypes` +- `requiresEnv` +- `requiresRuntime` +- `riskLevel` + +说明: + +- 这里不是把整个 `SKILL.md` 原样塞给模型 +- 而是把它抽成稳定的、可规划的最小能力描述 + +### 6.2 Tool execution schema + +所有 skills 在执行层至少统一到这些结构: + +- `toolName` +- `toolCallId` +- `input` +- `status` +- `result` +- `error` +- `artifacts` +- `summary` + +### 6.3 Tool result schema + +所有 skill/tool 返回结果都要能映射成统一结构: + +- `ok` +- `summary` +- `structuredData` +- `files` +- `logs` +- `error` +- `retryable` + +### 6.4 Transcript schema + +所有 skills 的执行都要进入统一会话记录: + +- `thinking` +- `tool_use` +- `tool_result` +- `assistant final` + +### 6.5 Skills 通用接入数据流图 + +下面这张文字版流程图,定义的是 `registry -> planner -> executor -> tool_result -> transcript -> renderer` 的标准主链路: + +```text +[已启用 skills / 内建 tools / SKILL.md metadata / adapter manifest] + | + v + [Registry] + 产出统一 capability list / tool registry entries / preflight metadata + | + v +[用户消息 / 附件 / 会话历史 / runtime context / capability list] + | + v + [Planner] + 选择 skill/tool,产出 thinking + tool_use plan + 如果当前无需调用 tool,则直接走 assistant final + | + v + [Executor] + 执行 preflight check + 把附件、参数、上下文转成 adapter 可消费输入 + 调用具体 skill/tool adapter,拿到 raw result / artifacts / logs / error + | + v + [tool_result Normalize] + 统一映射成 ok / summary / structuredData / files / logs / error / retryable / renderHints + | + +-------------+-------------+ + | | + v v + [Transcript] [模型续推] + 写回 thinking / tool_use / 把 tool_result 回灌给模型, + tool_result / assistant final 决定继续下一次 tool_use 或输出 final + | + v + [Renderer] + 渲染执行状态、结果卡片、错误原因、产物入口、最终回答 +``` + +实现约束: + +- `registry` 只负责暴露能力,不负责替模型做最终决策 +- `planner` 只负责选什么能力、传什么输入,不直接承担具体执行 +- `executor` 只负责执行与标准化,不负责私自改写会话历史 +- `tool_result` 必须同时服务两条链路:一条给模型续推,一条给 transcript / renderer 展示 +- `transcript` 是多轮续接的唯一可信记录,不能只在 UI 本地保留工具结果 +- `renderer` 优先消费统一协议,再按 skill type 做渐进增强 + +落地时最容易漏掉的环节: + +- 只做了 `registry -> planner -> executor`,但没有把 `tool_result` 回灌模型 +- 只做了 `tool_result -> renderer`,但没有把 `tool_use / tool_result` 写回 transcript +- 只让 `minimax-xlsx` 走这条链路,其他 enabled skills 仍然走特判分支 +- 让 provider 直接内嵌 planner / executor 逻辑,导致通用 runtime 无法复用 + +### 6.6 Skills 通用接入代码文件映射图 + +下面这张图把上一节的数据流,直接映射到当前 `zn-ai` 里已经存在或建议新增的关键文件: + +```text +[Registry capability 装配入口] + runtime-context.ts + 说明:当前这里是 runtime capability 注入边界; + 后续可把真正的 registry 生成下沉到 skill-capability-registry.ts, + 但对 chat.send 的上游入口仍然是这里。 + | + v +[聊天主编排入口] + handlers/chat.ts + 说明:接收用户消息、附件、会话历史,串联 planner / executor / transcript + | + +---------+---------+ + | | + v v +[规划层] [执行层] + skill-planner.ts tool-runtime.ts + 说明: 说明: + - 消费 message - 执行 preflight check + / attachments - 调用 skill/tool adapter + / history - 生成标准化 tool_result + / runtime context - 产出 tool status / artifacts / logs + - 产出 thinking + / tool_use plan + / no-tool decision + | | + +---------+---------+ + | + v +[共享协议层] + chat-model.ts + 说明:定义 thinking / tool_use / tool_result / assistant final + 的 transcript schema 与共享消息结构 + | + v +[渲染层] + ChatMessageList.tsx + 说明:消费 transcript、toolStatuses、attachments、tool_result, + 渲染执行状态、结果摘要、错误信息和最终回答 +``` + +按职责拆到文件后的推荐边界如下: + +- `runtime-context.ts` + - 负责把当前 enabled skills、内建 tools、session 信息装配成模型可见的 runtime context + - 不负责直接决定“这次该调用哪个 skill” + - 不负责写死某个 skill 的执行分支 + +- `handlers/chat.ts` + - 负责主编排,是 `chat.send` 的唯一入口 + - 负责把用户消息、附件、历史、runtime context 串起来 + - 负责调用 `skill-planner.ts` 和 `tool-runtime.ts` + - 负责把 `thinking / tool_use / tool_result / final` 写回 transcript + - 不负责继续堆 `if user says x then call y` 的特判 + +- `skill-planner.ts` + - 负责根据 capability list、附件类型、用户意图、历史上下文决定是否调用 skill/tool + - 输出统一的 planner decision,而不是直接在这里执行 tool + - 如果模型无需调 tool,也要能明确返回 `assistant-final-only` 这类决策 + +- `tool-runtime.ts` + - 负责 preflight check、adapter dispatch、错误归一化、`tool_result` 标准化 + - 负责把 raw result 转成 transcript 和 renderer 都能消费的结构 + - 不负责挑选哪个 tool;那是 planner 的职责 + +- `chat-model.ts` + - 负责冻结共享协议,避免 gateway 和 renderer 各自维护一套 message shape + - 这里必须成为 `thinking / tool_use / tool_result / tool status / attachments` 的统一来源 + - 如果协议扩展,不应该只改 UI 或只改 gateway 单边 + +- `ChatMessageList.tsx` + - 负责把通用 transcript 协议渲染出来 + - 先支持通用 `tool_result` 卡片,再渐进增强不同 skill type 的专属展示 + - 不应该依赖某个 skill 的私有字段才能完成基础渲染 + +这张映射图对应的实施顺序建议是: + +1. 先冻结 `chat-model.ts` 的共享 schema +2. 再补 `skill-planner.ts` 和 `tool-runtime.ts` +3. 然后让 `handlers/chat.ts` 接管主编排 +4. 再把 `runtime-context.ts` 从“固定两三个 tool 描述”升级成“全量 enabled skills capability 注入” +5. 最后让 `ChatMessageList.tsx` 完整消费新的 transcript / tool_result 协议 + +如果后面要继续往下拆实现任务,这 6 个文件基本就能直接映射成 6 条主工作流,不容易再把 registry、planner、executor、renderer 的职责混到一起。 + +## 8. 优先级清单 + +状态回填基线(2026-04-24): + +- 已完成:当前阶段目标已经落地,后续只做增强,不再影响本阶段是否达标 +- 部分完成:主链路已接入或已有样板,但仍有明显缺口,暂不能视为该项收口 +- 未开始:还停留在文档/设计层,或尚未形成有效实现 + +### P0 阻塞项 + +这些必须先补,不补就很难达到目标效果。 + +#### P0-1 建立“全量 enabled skills -> runtime capabilities”注入机制 + +状态:部分完成 + +现状: + +- 已有 capability registry 和 runtime context 注入链路,首批样板能把已启用 skill 暴露给聊天运行时 +- 但“依赖/环境不满足”的统一降级提示还没有完全收口,新增 skill 也还没有做到真正零补丁接入 + +目标: + +- 聊天发送前,运行时拿到当前所有已启用 skills 的能力描述 +- 不是只暴露 `browser.open_url`、`skills.install` +- 首批先验证 `xlsx/minimax-xlsx`,但实现必须支持所有 skills + +当前涉及文件: + +- `zn-ai/electron/gateway/runtime-context.ts` +- `zn-ai/electron/gateway/handlers/chat.ts` +- `zn-ai/electron/gateway/handlers/skills.ts` + +清单: + +- [ ] 在聊天发送前读取当前 enabled skills +- [ ] 为 enabled skills 生成通用 runtime capability 描述 +- [ ] 首批先支持 `xlsx/minimax-xlsx` 样板注入 +- [ ] 确保后续 skill 接入不需要再改聊天主链路 +- [ ] 明确“已启用但依赖/环境不满足”时的降级提示 + +#### P0-2 建立通用 skill metadata 抽取机制 + +状态:已完成 + +现状: + +- capability schema、默认抽取规则、`SKILL.md` 降级抽取和 registry 入口都已落地 +- 更细的 skill type 扩展仍会继续增强,但不影响这一阶段的 metadata 抽取主目标 + +目标: + +- 从 skill 配置和 `SKILL.md` 提取统一 capability schema +- 为所有 skills 提供同一套抽取入口 + +当前涉及文件: + +- `zn-ai/electron/gateway/handlers/skills.ts` +- 新增建议文件:`zn-ai/electron/gateway/skill-capability-registry.ts` +- 新增建议文件:`zn-ai/electron/gateway/skill-capability-parser.ts` + +清单: + +- [ ] 定义 capability schema +- [ ] 定义默认抽取规则 +- [ ] 为缺少结构化元数据的 skill 提供降级抽取策略 +- [ ] 支持后续按 skill 类型扩展抽取器 + +#### P0-3 从“文本 provider”升级到“可执行 tool 的聊天运行时” + +状态:部分完成 + +现状: + +- tool-capable provider/runtime 契约和 planner-first 执行链路已接入,`tool_result` 也能回灌后续回答 +- 但 provider 原生 tool loop 还没有完整打通,`tools/toolChoice` 仍未成为统一主路径 + +目标: + +- 聊天主链路不能只调用 `provider.chat(messages, model)` +- 必须支持模型发起工具调用,运行时执行后再把结果回给模型 + +当前涉及文件: + +- `zn-ai/electron/providers/BaseProvider.ts` +- `zn-ai/electron/providers/OpenAIProvider.ts` +- `zn-ai/electron/gateway/handlers/chat.ts` + +清单: + +- [ ] 设计统一 tool-capable provider/runtime 接口 +- [ ] 支持模型输出 `tool_use` 或等价调用结构 +- [ ] 运行时执行 skill/tool 后生成 `tool_result` +- [ ] 把 `tool_result` 回灌给模型,继续完成最终回答 +- [ ] 保留现有文本流式输出作为降级路径 + +#### P0-4 建立通用 planner / registry,而不是继续堆特判 + +状态:部分完成 + +现状: + +- tool registry、planner、tool runtime 已建立统一入口,`skills.install`、浏览器、`xlsx/minimax-xlsx` 已纳入同一条链路 +- 但新增 skill 仍需要补 adapter,尚未做到“任意已启用 skill 都能直接执行” + +目标: + +- skill 调用不能再靠“遇到某句提示词就手工分支” +- 所有 skills 和内建 tools 都通过统一 registry 暴露给 planner + +当前涉及文件: + +- `zn-ai/electron/gateway/handlers/chat.ts` +- 新增建议文件:`zn-ai/electron/gateway/tool-runtime.ts` +- 新增建议文件:`zn-ai/electron/gateway/tool-registry.ts` +- 新增建议文件:`zn-ai/electron/gateway/skill-planner.ts` + +清单: + +- [ ] 抽象通用 tool registry +- [ ] skill/tool 共用一套注册与调度模型 +- [ ] 把 `skills.install`、浏览器、`xlsx/minimax-xlsx` 纳入统一 planner +- [ ] 后续 skill 不再新增聊天特判 + +#### P0-5 把附件真正接入“通用 skill 输入链路” + +状态:部分完成 + +现状: + +- 文件类样板已能把附件作为结构化输入交给表格分析链路,`.xls` 也已补上本地 fallback +- 但附件输入 schema 还没有沉淀成所有文件类 skill 共用的公共层 + +目标: + +- 对 `.xlsx/.csv/.tsv`,不能只把 `[media attached: ...]` 拼到文本里 +- 附件要变成 planner/executor 可消费的标准输入 +- 设计要对所有“需要文件输入”的 skills 通用 + +当前涉及文件: + +- `zn-ai/src/stores/chat.ts` +- `zn-ai/electron/api/routes/files.ts` +- `zn-ai/electron/gateway/handlers/chat.ts` + +清单: + +- [ ] 为文件类 skill 建立统一附件输入 schema +- [ ] 首批先验证表格类输入 +- [ ] tool/skill 执行时能拿到稳定文件路径或句柄信息 +- [ ] 附件缺失、路径失效时返回结构化错误 + +#### P0-6 把 tool 结果写回会话历史 + +状态:部分完成 + +现状: + +- `tool_use / tool_result` 已写回 transcript,并能参与后续轮次的推理 +- 但大结果摘要、上下文膨胀控制和进一步的历史裁剪策略还没有完全收口 + +目标: + +- 执行过的 skill 结果必须成为会话上下文的一部分 +- 下一轮问“继续分析第 2 个 sheet”时,模型能接上 + +当前涉及文件: + +- `zn-ai/electron/gateway/handlers/chat.ts` +- `zn-ai/src/stores/chat.ts` +- `zn-ai/runtime-shared/shared/chat-model.ts` + +清单: + +- [ ] 在 transcript/session history 中保留 `tool_use / tool_result` +- [ ] 重新定义发送下一轮时的 history flatten 规则 +- [ ] 避免把关键 tool 结果过滤掉 +- [ ] 对大结果做摘要,避免上下文膨胀 + +### P1 重要项 + +这些不一定是第一批 blocker,但会直接影响可用性和稳定性。 + +#### P1-1 建立“聊天 runtime 与 Skills 页”的同步机制 + +状态:部分完成 + +现状: + +- `skills.update/install` 后已能广播 runtime refresh,Skills 页也已经接到这类变化 +- 但聊天 runtime/store 侧还没有完整消费这些变更,热更新边界仍不够清晰 + +当前涉及文件: + +- `zn-ai/electron/gateway/handlers/skills.ts` +- `zn-ai/electron/gateway/types.ts` +- `zn-ai/src/lib/skills-api.ts` + +清单: + +- [ ] `skills.update` 后广播 runtime refresh +- [ ] 聊天 runtime 监听 skills 变化并刷新能力缓存 +- [ ] 明确“需要重启 gateway”与“可热更新”的边界 + +#### P1-2 补齐聊天 UI 的执行可视化 + +状态:部分完成 + +现状: + +- 通用 tool-only 消息和结果卡片已经具备,`browser.open_url`、`skills.install` 有专项展示 +- 但表格分析专项卡片、失败重试和查看详情入口还没有补齐 + +当前涉及文件: + +- `zn-ai/src/stores/chat.ts` +- `zn-ai/src/components/chat/ChatMessageList.tsx` +- `zn-ai/src/pages/Home/index.tsx` + +清单: + +- [ ] 区分普通 assistant 文本和 tool-only 消息 +- [ ] 增加通用 tool 结果展示结构 +- [ ] 首批先做好表格分析类结果卡片 +- [ ] 为失败结果增加重试或查看详情入口 + +#### P1-3 对齐 ClawX 的 workspace/context 注入机制 + +状态:未开始 + +现状: + +- 目前仍以现有 runtime context 注入为主 +- workspace/context 资源目录、统一说明文件和启动期上下文装配还没有正式开工 + +当前参考文件: + +- `ClawX/electron/utils/openclaw-workspace.ts` +- `ClawX/resources/context/AGENTS.clawx.md` +- `ClawX/resources/context/TOOLS.clawx.md` + +清单: + +- [ ] 为 `zn-ai` 增加运行时 context 资源目录 +- [ ] 定义 skill/tool 使用约束说明 +- [ ] 让 agent/workspace 在 gateway 启动后获得一致上下文 + +#### P1-4 明确 provider 能力矩阵 + +状态:未开始 + +现状: + +- provider 契约已经开始具备 tool-capable 方向的定义 +- 但支持矩阵、白名单和成体系的降级策略还没有形成可执行结果 + +清单: + +- [ ] 列出支持 tool loop 的 provider/model 白名单 +- [ ] 不支持时给出明确降级策略 +- [ ] 区分“模型不支持”与“skill 执行失败” + +### P2 增强项 + +这些会提高稳定性、可维护性和长期对齐度。 + +#### P2-1 Skill 类型分层 + +状态:部分完成 + +现状: + +- capability parser 已有轻量分类能力 +- 但 taxonomy 冻结、分类专属 adapter 和跨类型接入标准还没有全部完成 + +目标: + +- 不是所有 skill 都有相同输入输出模式 +- 需要按类型建立统一接入层 + +推荐分类: + +- 文档/文件类 +- 浏览器/网页类 +- 搜索/检索类 +- 命令/脚本类 +- 外部 API 类 + +清单: + +- [ ] 定义 skill type taxonomy +- [ ] 为每类定义默认 input/output adapter +- [ ] 首批至少覆盖文档类与浏览器类 + +#### P2-2 回归测试与 smoke + +状态:部分完成 + +现状: + +- 已有 runtime context、planner、shortcut、chat-tooling 等聚焦单测 +- 但非 `xlsx` skill 回归、`tool_use -> tool_result -> final` 集成测试,以及开发态/打包态 smoke 还未补齐 + +清单: + +- [ ] 单测:已启用 skill 会出现在 runtime context +- [ ] 单测:上传 `.xlsx` 后进入表格分析链路 +- [ ] 单测:新增一个非 `xlsx` skill 也能进入通用 registry +- [ ] 集成测试:`tool_use -> tool_result -> final` +- [ ] smoke:开发态和打包态都验证一次 + +#### P2-3 错误模型和日志分层 + +状态:部分完成 + +现状: + +- shared schema 已具备基础的 tool error/result 结构 +- 但授权、provider、tool、skill、附件的统一错误模型和 UI 提示映射仍未收口 + +清单: + +- [ ] 区分授权错误、provider 错误、tool 错误、skill 错误、附件错误 +- [ ] transcript 中保留最小必要诊断字段 +- [ ] UI 侧映射成用户能理解的提示 + +## 9. 推荐推进顺序 + +当前进度判断: + +- 第一阶段:已基本完成 +- 第二阶段:部分完成 +- 第三阶段:未完成 + +### 第一阶段 + +- P0-1 全量 enabled skills 注入 runtime +- P0-2 通用 skill metadata 抽取 +- P0-3 tool-capable 聊天运行时 +- P0-4 通用 planner / registry +- P0-5 附件进入通用 skill 输入链路 + +完成标志: + +- 架构上已经不再依赖单个 skill 特判 +- `xlsx/minimax-xlsx` 成为第一条跑通的样板链路 + +### 第二阶段 + +- P0-6 tool 结果回灌历史 +- P1-1 runtime 与 Skills 页同步 +- P1-2 聊天 UI 执行可视化 + +完成标志: + +- 用户能稳定看到执行过程,且多轮能接续 + +### 第三阶段 + +- P1-3 workspace/context 对齐 +- P1-4 provider 能力矩阵 +- P2 全部增强项 + +完成标志: + +- 新增 skill 时,聊天运行时不再需要新增 ad-hoc 接入代码 + +## 10. 推荐 sub-agent 编制 + +### 9.1 推荐数量 + +- 推荐:`7` 个 sub-agent +- 最小可行:`5` 个 sub-agent +- 稳妥完整:`8` 个 sub-agent + +解释: + +- 因为这次目标已经从“单个 skill 样板”升级为“全量 skills 通用接入架构” +- 需要单独有人负责 skill metadata/registry,不适合继续塞进原有分工里 + +默认建议采用: + +- `7 个 worker sub-agent + 1 个主协调 agent` + +说明: + +- 主协调 agent 不计入上面的 `sub-agent` 数量 +- 主协调 agent 负责冻结接口、安排波次、收敛冲突、做最终集成 + +### 9.2 7 个 sub-agent 分工 + +#### SA-1 Skill Capability Registry + +职责: + +- 把所有 enabled skills 注入聊天 runtime context +- 定义通用 capability schema +- 负责 skill metadata 抽取与 registry + +主要文件归属: + +- `zn-ai/electron/gateway/runtime-context.ts` +- `zn-ai/electron/gateway/handlers/skills.ts` +- `zn-ai/electron/gateway/types.ts` +- 新增 `zn-ai/electron/gateway/skill-capability-registry.ts` +- 新增 `zn-ai/electron/gateway/skill-capability-parser.ts` + +验收: + +- 任何已启用 skill 都能进入 runtime capability 列表 + +#### SA-2 Provider 与 Tool Runtime + +职责: + +- 把文本 provider 升级为可执行 tool 的聊天运行时 +- 定义 tool call / tool result / resume 推理接口 + +主要文件归属: + +- `zn-ai/electron/providers/BaseProvider.ts` +- `zn-ai/electron/providers/OpenAIProvider.ts` +- 新增 `zn-ai/electron/gateway/tool-runtime.ts` + +验收: + +- 模型能发起真实 tool 调用,不再只有文本流 + +#### SA-3 Planner / Tool Registry + +职责: + +- 设计通用 planner +- 统一 skill/tool 注册与调度 +- 去掉继续堆特判的趋势 + +主要文件归属: + +- 新增 `zn-ai/electron/gateway/tool-registry.ts` +- 新增 `zn-ai/electron/gateway/skill-planner.ts` +- 必要时补 `zn-ai/electron/gateway/types.ts` + +验收: + +- `skills.install`、浏览器、`xlsx/minimax-xlsx` 都通过统一 registry 接入 + +#### SA-4 Chat Orchestration / Transcript + +职责: + +- 负责 `chat.send` 主编排 +- 把 `tool_use / tool_result / final` 写回会话历史 +- 处理 history flatten 和多轮续接 + +主要文件归属: + +- `zn-ai/electron/gateway/handlers/chat.ts` +- `zn-ai/electron/gateway/session-store.ts` +- `zn-ai/runtime-shared/shared/chat-model.ts` + +验收: + +- 多轮对话能接上前一轮 tool 结果 + +#### SA-5 Attachment / File Skill Input + +职责: + +- 把 `.xlsx/.csv/.tsv` 等文件变成通用 skill 输入 +- 先打通文件类 skill 输入适配层 + +主要文件归属: + +- `zn-ai/src/stores/chat.ts` +- `zn-ai/electron/api/routes/files.ts` + +验收: + +- 文件类 skill 拿到稳定输入,不再只依赖文本路径猜测 + +#### SA-6 Renderer Tool UI + +职责: + +- 聊天 UI 展示 tool 卡片、状态、结果摘要、失败详情 +- 对齐 `pendingFinal`、tool-only 消息和分析过程可视化 + +主要文件归属: + +- `zn-ai/src/components/chat/ChatMessageList.tsx` +- `zn-ai/src/pages/Home/index.tsx` +- 新增聊天执行可视化组件时归此 agent + +验收: + +- 用户能在聊天页看清楚“何时开始分析、分析了什么、结果是什么” + +#### SA-7 Testing / Smoke / Rollout + +职责: + +- 为前 6 个 agent 的改动补回归测试 +- 增加最小集成测试和开发态 smoke +- 记录“新增 skill 是否零特判接入”的验收结果 + +主要文件归属: + +- `zn-ai/tests/chat-runtime-context.test.ts` +- `zn-ai/tests/gateway-rpc-dispatch.test.ts` +- 新增与 skill registry、planner、tool_result 相关测试 +- 需要时补充 `docs/` 中的验收记录 + +验收: + +- 至少有 1 条覆盖“已启用 skill + planner + tool_result + final”的集成链路 +- 至少有 1 条覆盖“新增非 xlsx skill 无需新增聊天特判”的回归验证 + +### 9.3 6 个核心文件实施任务拆解表 + +这张表只聚焦最容易互相卡住的 6 个核心文件。 + +- 辅助文件仍然跟随主责 `sub-agent` 所在分支推进 +- 任何辅助文件的改动,都不应绕开对应核心文件的 owner +- `chat-model.ts` 虽然归 `SA-4` 主责,但必须以“共享契约先冻结”方式提前进入 Wave 1 + +| 核心文件 | 主要实施任务 | 主责 sub-agent | 主要协作方 | 前置冻结 / 依赖 | 推荐合并顺序 | +| --- | --- | --- | --- | --- | --- | +| `zn-ai/runtime-shared/shared/chat-model.ts` | 冻结 `thinking / tool_use / tool_result / assistant final / tool status / attachments` 的共享 schema,统一 gateway、store、UI 的消息结构 | `SA-4` | `SA-1` `SA-2` `SA-6` | 先评审 schema,再允许其他链路接入;这是后续 `handlers/chat.ts` 和 `ChatMessageList.tsx` 的共同前置 | `0` | +| `zn-ai/electron/gateway/runtime-context.ts` | 把当前 enabled skills、内建 tools、session 信息装配成 runtime capability 注入入口;从“固定工具说明”升级成“全量能力注入” | `SA-1` | `SA-3` `SA-4` | 依赖 capability schema 冻结;与 `skill-capability-registry.ts`、`skill-capability-parser.ts` 一起推进 | `1` | +| `zn-ai/electron/gateway/tool-runtime.ts` | 定义 preflight check、adapter dispatch、raw result -> `tool_result` 标准化、resume 推理接口 | `SA-2` | `SA-3` `SA-4` | 依赖 `chat-model.ts` 的 `tool_result` 结构;需要先冻结 provider / runtime contract | `2` | +| `zn-ai/electron/gateway/skill-planner.ts` | 根据 capability list、附件、历史、用户意图产出统一 planner decision,去掉继续堆特判的趋势 | `SA-3` | `SA-1` `SA-2` `SA-4` | 依赖 runtime capability shape 与 tool runtime contract;与 `tool-registry.ts` 同分支推进 | `3` | +| `zn-ai/electron/gateway/handlers/chat.ts` | 接管 `chat.send` 主编排,串联 runtime context、planner、executor、transcript 写回与多轮续接 | `SA-4` | `SA-2` `SA-3` `SA-5` | 必须等 `runtime-context.ts`、`tool-runtime.ts`、`skill-planner.ts` 的契约稳定后再合并;其他 agent 不直接改这个文件 | `4` | +| `zn-ai/src/components/chat/ChatMessageList.tsx` | 消费统一 transcript / `tool_result` / `toolStatuses`,渲染 tool 卡片、错误、摘要、最终回答 | `SA-6` | `SA-4` `SA-7` | 必须等 `chat-model.ts` 与 `handlers/chat.ts` 稳定后接入;优先做通用渲染,再做类型增强 | `5` | + +推荐按下面的节奏合并: + +1. 先合并 `chat-model.ts` 的 schema 冻结 PR。 +2. 再并行推进 `runtime-context.ts`、`tool-runtime.ts`、`skill-planner.ts`,但以契约评审通过为合并门槛。 +3. 然后由 `SA-4` 合并 `handlers/chat.ts`,把前三者正式编排进主链路。 +4. 最后由 `SA-6` 合并 `ChatMessageList.tsx`,避免 UI 反向驱动协议。 + +这 6 个文件对应的辅助文件跟随关系建议如下: + +- `runtime-context.ts` + 对应辅助文件:`skill-capability-registry.ts`、`skill-capability-parser.ts`、必要时 `handlers/skills.ts` +- `tool-runtime.ts` + 对应辅助文件:`BaseProvider.ts`、`OpenAIProvider.ts` +- `skill-planner.ts` + 对应辅助文件:`tool-registry.ts`、必要时 `gateway/types.ts` +- `handlers/chat.ts` + 对应辅助文件:`session-store.ts`、必要时 `src/stores/chat.ts` +- `ChatMessageList.tsx` + 对应辅助文件:`src/pages/Home/index.tsx`、新增 tool result 展示组件 + +如果要把冲突降到最低,可以把这张表当成 branch / PR 边界: + +- `SA-1` 不直接改 `handlers/chat.ts`,而是通过 capability schema 和 registry 模块接入 +- `SA-2` 不在 provider 内重做 planner,而是只冻结 runtime contract +- `SA-3` 不直接改 UI,只输出 planner decision 与 registry 结构 +- `SA-4` 只在前三项契约稳定后改 `handlers/chat.ts` +- `SA-6` 只消费共享协议,不反向决定 gateway 数据结构 + +## 11. 波次安排 + +### Wave 1 + +当前状态:已完成 + +现状: + +- 核心契约、registry、planner 和 tool runtime 已经冻结并落地 +- 第一条样板链路已经跑通,不再停留在纯设计阶段 + +- `SA-1` Skill Capability Registry +- `SA-2` Provider 与 Tool Runtime +- `SA-3` Planner / Tool Registry + +目标: + +- 先冻结最核心接口:skill capability schema、tool runtime contract、planner contract + +### Wave 2 + +当前状态:部分完成 + +现状: + +- transcript 回写和样板附件链路已经进入主聊天编排 +- 但 runtime 与 Skills 页的同步,以及表格专项 UI 可视化还没有全部完成 + +- `SA-5` Attachment / File Skill Input +- `SA-4` Chat Orchestration / Transcript + +目标: + +- 在已冻结契约上,把样板链路接入主聊天编排 + +### Wave 3 + +当前状态:部分完成 + +现状: + +- 通用 tool UI 和一部分回归验证已经启动 +- 但 provider 能力矩阵、完整 smoke 和 rollout 收口还没有完成 + +- `SA-6` Renderer Tool UI +- `SA-7` Testing / Smoke / Rollout + +目标: + +- 把用户体验和回归验证补齐 + +## 12. 协作约束 + +为避免冲突,建议遵守这 5 条: + +1. 每个 sub-agent 只改自己负责的文件,不跨写别人的主文件。 +2. `zn-ai/electron/gateway/handlers/chat.ts` 只归 `SA-4`,其他人不要直接改。 +3. `zn-ai/src/stores/chat.ts` 只归 `SA-5`,UI agent 不要同时改这个文件。 +4. `zn-ai/electron/gateway/types.ts` 由 `SA-1` 牵头冻结,其他 agent 只在评审后接入。 +5. 主协调 agent 统一做接口冻结、合并、回归验证,不让多个 agent 反复改同一入口。 + +## 13. 功能交叉与冲突清单 + +这一节把真正会互相卡住的交叉点单独列出来。 + +### 12.1 冲突 A:`chat.send` 是所有能力的汇合点 + +交叉功能: + +- skill 可见性 +- planner 结果接入 +- tool runtime 执行 +- 附件输入 +- transcript 写回 +- final answer 回传 + +核心文件: + +- `zn-ai/electron/gateway/handlers/chat.ts` + +处理规则: + +- 只允许 `SA-4` 直接修改 +- `SA-1`、`SA-2`、`SA-3`、`SA-5` 通过契约和辅助模块接入 + +### 12.2 冲突 B:`src/stores/chat.ts` 同时承担“附件状态”和“聊天执行状态” + +交叉功能: + +- 附件 staging +- tool 状态消费 +- pendingFinal 状态 +- UI 展示状态 + +核心文件: + +- `zn-ai/src/stores/chat.ts` + +处理规则: + +- `SA-5` 主责 store shape +- `SA-6` 尽量通过 selector 和 helper 消费,不重写 store 结构 + +### 12.3 冲突 C:事件协议同时影响 runtime、store、UI + +交叉功能: + +- `tool:status` +- `chat:final` +- 未来的 `tool_use / tool_result / thinking` +- runtime refresh + +核心文件: + +- `zn-ai/electron/gateway/types.ts` +- `zn-ai/runtime-shared/shared/chat-model.ts` + +处理规则: + +- 先冻结 gateway event contract +- 再冻结 transcript/chat-model contract +- UI 最后接入,不反向驱动协议改名 + +### 12.4 冲突 D:provider 能力和 planner/runtime 边界容易混淆 + +交叉功能: + +- provider 是否支持 tool loop +- runtime 如何继续二次调用模型 +- planner 与 executor 谁负责决策 + +核心文件: + +- `zn-ai/electron/providers/BaseProvider.ts` +- `zn-ai/electron/providers/OpenAIProvider.ts` +- `zn-ai/electron/gateway/tool-runtime.ts` +- `zn-ai/electron/gateway/skill-planner.ts` + +处理规则: + +- `SA-2` 先冻结 provider/runtime 边界 +- `SA-3` 再实现 planner,不在 provider 内重复做编排 + +### 12.5 冲突 E:skill metadata 抽取与 renderer 展示不要耦合 + +交叉功能: + +- `SKILL.md` 抽取 +- capability schema +- UI 上如何显示 skill 名称、说明、输入输出 + +处理规则: + +- `SA-1` 负责 runtime capability schema +- `SA-6` 只能消费 schema,不反过来决定抽取字段 + +## 14. 最小落地建议 + +如果本轮只做最小可行闭环,优先只做这 6 件事: + +1. 聊天发送前读取 enabled skills,并把它们注入 runtime context。 +2. 建立通用 skill capability registry,而不是只处理 `minimax-xlsx`。 +3. 为聊天 runtime 增加最小 tool loop,不再只走纯文本 provider。 +4. 让文件类附件进入统一 skill 输入链路。 +5. 把 `tool_result` 写回 session history,保证多轮可续接。 +6. 在聊天 UI 里把执行过程展示成 tool 卡片,而不是只显示最终一句话。 + +## 15. 非目标 + +这一版清单默认不把下面内容作为首批阻塞项: + +- skill 市场页样式优化 +- 为每一个 skill 都单独做精细化 UI 定制 +- 完整复刻 ClawX 的所有 execution graph 细节 +- 与 skill 运行时无关的 channel/plugin 改造 + +注意: + +- “所有 skills 一次性通用化接入聊天运行时”不再是非目标 +- 但“所有 skills 一次性都达到同等体验质量”仍然不是首批目标 + +## 16. 建议先开工的代码入口 + +- `zn-ai/electron/gateway/handlers/chat.ts` +- `zn-ai/electron/gateway/runtime-context.ts` +- `zn-ai/electron/gateway/handlers/skills.ts` +- `zn-ai/electron/providers/BaseProvider.ts` +- `zn-ai/electron/providers/OpenAIProvider.ts` +- `zn-ai/src/stores/chat.ts` +- `zn-ai/src/components/chat/ChatMessageList.tsx` +- `zn-ai/electron/api/routes/files.ts` +- 新增 `zn-ai/electron/gateway/skill-capability-registry.ts` +- 新增 `zn-ai/electron/gateway/skill-capability-parser.ts` +- 新增 `zn-ai/electron/gateway/tool-registry.ts` +- 新增 `zn-ai/electron/gateway/skill-planner.ts` +## 17. Progress Update (2026-04-24) + +This checkpoint extends the "first batch of real generic skill execution adapters" +beyond `xlsx/minimax-xlsx` and lands the first reusable document-family, +search-family, browser-family, and command-family runtimes. + +Completed in this round: +- `zn-ai/electron/gateway/chat-tooling.ts` + - Added a real document adapter for enabled `docx`, `pptx`, and `pdf` skills. + - Added Node-side analyzers for `.docx`, `.pptx`, and `.pdf`. + - Added real search adapters for `brave-web-search` and `tavily-search`. + - Added a browser-category adapter so browser-capable skills can reuse the managed `browser.open_url` runtime. + - Added a command-category adapter that keeps `find-skills` on the safe ClawHub path and also executes generic command-style skills from safe manifest command templates or a single local `scripts/` entrypoint. + - Reads skill credentials from saved skill config (`apiKey` / `env`) instead of relying only on process env. + - Normalizes Brave and Tavily responses into shared `search-results` payloads and URL artifacts. + - Reused the same `tool_runtime -> tool_result -> transcript` path as spreadsheet analysis. + - Kept unsupported generic skills on capability-aware blocked results instead of silently falling through. +- `zn-ai/src/components/chat/ChatMessageList.tsx` + - Added a dedicated search-result card for query, provider, answer, ranked results, and install commands. + - Reused the same card for command-style discovery results such as `find-skills`. +- `zn-ai/electron/gateway/skill-capability-parser.ts` + - Tightened file-extension inference so URL-like fragments such as `.search` or `.results` no longer become fake input extensions. + - Tightened auth detection to prefer explicit auth/env signals and avoid substring false positives. + - Promoted office-style document skills into the shared `document-analysis` render shape. +- `zn-ai/tests/chat-tooling.test.ts` + - Added execution regressions for `.docx`, `.pptx`, and `.pdf`. + - Added execution regressions for `brave-web-search` and `tavily-search`. + - Added execution regressions for browser-capable skills, `find-skills`, and generic command-style skills that run from manifest command templates or local script entrypoints. + - Kept `.xls` fallback coverage and generic blocked-state coverage. +- `zn-ai/tests/chat-message-list.test.tsx` + - Added UI regressions for dedicated search cards and command-style install-command rendering. +- `zn-ai/tests/skill-capability-parser.test.ts` + - Added parser regressions for document capability classification, URL-like extension filtering, and auth detection. + +Current first-batch runtime coverage: +- Spreadsheet execution: `.xls`, `.xlsx`, `.xlsm`, `.csv`, `.tsv` +- Document execution: `.docx`, `.pptx`, `.pdf` +- Search execution: `brave-web-search`, `tavily-search` +- Browser execution: browser-capable skills that map to explicit URL open flows +- Command execution: `find-skills` through ClawHub search, plus generic command-style skills that expose a safe single-command template or one local `scripts/` entrypoint +- Generic non-document skills without a real adapter: still blocked with explicit reasons such as `missing_required_env`, `user_authorization_required`, or `skill_runtime_not_implemented` + +What is still not done: +- Browser/search/command category executors now exist, but multi-step shell flows, install/login/setup commands, and other unsafe command patterns are still intentionally blocked. Generic command execution is limited to safe single-command templates and local script entrypoints. +- Cross-type adapter manifesting and large-scale skill onboarding are still follow-up work after this checkpoint. + +Verification for this checkpoint: +- `pnpm typecheck` +- `pnpm exec vitest run tests/skill-capability-parser.test.ts tests/chat-tooling.test.ts` +- `pnpm exec vitest run tests/chat-provider-tool-loop.test.ts tests/chat-store-runtime-refresh.test.ts tests/chat-runtime-context.test.ts tests/runtime-context-capabilities.test.ts tests/skill-planner.test.ts tests/chat-tooling.test.ts tests/skill-capability-parser.test.ts tests/chat-message-list.test.tsx` diff --git a/docs/prompt-history.md b/docs/prompt-history.md index 0e53aaa..398b6c3 100644 --- a/docs/prompt-history.md +++ b/docs/prompt-history.md @@ -18,4 +18,8 @@ - 重构KnowLedge/index.tsx渲染层、主进程,产品需求如下:上传文件按钮,上传到zn-ai/docs目录,文件列表显示内容:文件名称,文件大小、修改日期、文件类型,操作:删除,视觉UI沿用当前的风格。规划重构计划,估算sub-agent数量,安排sub-agent分工推进工作 -- 在ClawX项目中,通过对话,https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md,帮我安装这个skill,能正确安装。在zn-ai项目中,是否也能有同样的功能呢?帮我对比下,如果zn-ai项目没有安装skill的功能,就规划功能迁移计划到zn-ai/docs目录下,估算sub-agent数量,安排sub-agent分工推进迁移安装skill功能,跟安装skill无关的功能先不考虑修改调整。 \ No newline at end of file +- 在ClawX项目中,通过对话,https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md,帮我安装这个skill,能正确安装。在zn-ai项目中,是否也能有同样的功能呢?帮我对比下,如果zn-ai项目没有安装skill的功能,就规划功能迁移计划到zn-ai/docs目录下,估算sub-agent数量,安排sub-agent分工推进迁移安装skill功能,跟安装skill无关的功能先不考虑修改调整。 + +- 在ClawX发起对话,对话内容:"使用minimax-xlsx这个skill,帮我分析下。",它能正确的思考做出数据分析,同样在zn-ai中发起同样的对话内容,就做不到思考做出数据分析,对比一下,zn-ai是缺少了哪些功能,跟用户授权有关系吗?安排多个sub-agent分工对比工作。 + +- 直接给我补一版迁移清单,按优先级列出 zn-ai 要补哪些点,才能接近 ClawX 这种“在聊天里直接调用 minimax-xlsx做分析”的效果。 \ No newline at end of file diff --git a/electron/gateway/browser-shortcut.ts b/electron/gateway/browser-shortcut.ts index 916dfa9..259af0d 100644 --- a/electron/gateway/browser-shortcut.ts +++ b/electron/gateway/browser-shortcut.ts @@ -1,7 +1,7 @@ import logManager from '@electron/service/logger'; import { extractBrowserOpenIntent, openUrlInBrowser } from '@electron/service/browser-open-service'; import { appendTranscriptLine } from '@electron/utils/token-usage-writer'; -import type { RawMessage, ToolStatus } from '@runtime/shared/chat-model'; +import type { RawMessage, ToolResultPayload, ToolStatus } from '@runtime/shared/chat-model'; import { sessionStore } from './session-store'; import type { GatewayEvent } from './types'; @@ -25,6 +25,7 @@ async function processBrowserOpen( const toolCallId = `browser.open_url:${runId}`; const startedAt = Date.now(); let finalToolStatus: ToolStatus | null = null; + let finalToolResult: ToolResultPayload | null = null; broadcast({ type: 'tool:status', @@ -44,6 +45,15 @@ async function processBrowserOpen( return; } assistantText = buildBrowserOpenResponseText(result); + finalToolResult = { + ok: true, + summary: assistantText, + structuredData: result, + renderHints: { + card: 'browser-step', + }, + raw: result, + }; finalToolStatus = { id: toolCallId, toolCallId, @@ -73,6 +83,18 @@ async function processBrowserOpen( return; } assistantText = buildBrowserOpenErrorText(error); + finalToolResult = { + ok: false, + summary: assistantText, + error: error instanceof Error ? error.message : String(error), + retryable: true, + renderHints: { + card: 'browser-step', + }, + raw: { + error: error instanceof Error ? error.message : String(error), + }, + }; finalToolStatus = { id: toolCallId, toolCallId, @@ -107,6 +129,7 @@ async function processBrowserOpen( role: 'assistant', content: assistantText, timestamp: Date.now(), + toolResult: finalToolResult, _toolStatuses: finalToolStatus ? [finalToolStatus] : undefined, }; sessionStore.appendMessage(sessionKey, finalMessage); diff --git a/electron/gateway/chat-tooling.ts b/electron/gateway/chat-tooling.ts new file mode 100644 index 0000000..64aa3ab --- /dev/null +++ b/electron/gateway/chat-tooling.ts @@ -0,0 +1,3571 @@ +import { + createToolRuntime, + type ToolRuntime, + type ToolRuntimeAdapter, + type ToolRuntimeContext, + type ToolRuntimeExecutionResult, + type ToolRuntimeInvocation, + type ToolRuntimePreflightResult, +} from './tool-runtime'; +import type { GatewayToolDefinition } from '@electron/providers/BaseProvider'; +import type { SkillCapability } from './skill-capability-parser'; +import type { ToolRegistryCapabilityInput, ToolRegistryEntry } from './tool-registry'; +import type { AttachedFileMeta, ToolArtifact, ToolCallPayload } from '@runtime/shared/chat-model'; + +type NodeFsDirentLike = { + name: string; + isFile(): boolean; +}; + +type NodeFsLike = { + existsSync(path: string): boolean; + readdirSync(path: string, options: { withFileTypes: true }): NodeFsDirentLike[]; +}; + +type NodePathLike = { + join(...parts: string[]): string; +}; + +type NodeChildProcessLike = { + spawn( + command: string, + args?: string[], + options?: { + cwd?: string; + env?: NodeJS.ProcessEnv; + windowsHide?: boolean; + signal?: AbortSignal; + } + ): { + stdout: { + on(event: 'data', listener: (chunk: unknown) => void): void; + }; + stderr: { + on(event: 'data', listener: (chunk: unknown) => void): void; + }; + on(event: 'error', listener: (error: Error) => void): void; + on(event: 'close', listener: (code: number | null) => void): void; + }; +}; + +function getBuiltinNodeModule| + {header} + | + ))} +
|---|
| + {formatStructuredValue(row[header], locale, labels)} + | + ))} +
| + {prettifyKey(header)} + | + ))} +
|---|
| + {value} + | + ))} +