docs(i18n): apply reviewed Chinese proofreading updates

This commit is contained in:
xjt
2026-08-12 09:59:19 +08:00
parent 82d21ab3c3
commit 7b450d121e
258 changed files with 535 additions and 535 deletions

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-20-error-cause-chain-diagnostics.md
2026-07-20-error-cause-chain-diagnostics.md: d1944b3b435f2e1c64e1612adf0e61dd8e7401ff
2026-07-20-error-cause-chain-diagnostics.zh.md: 914e983d7ea81eef8bca8fd5aa3791f2f44d4080
2026-07-20-error-cause-chain-diagnostics.zh.md: 054397f1a5902ef9121856e63c13637f84fe9768

View File

@@ -13,7 +13,7 @@ TUI 连接不可达的 DeepSeek 端点时,失败只显示一条 `fetch failed`
## 决策
- `dsh-llm` 导出 `errorChain(value)`:渲染抛出值及其完整 `cause` 链(`outer: inner: …`)与 AggregateError 成员(`msg [m1; m2]`),并容错循环 cause 和恶意强制转换。它只是用于诊断界面的渲染器;路由仍然基于 `HarnessError.code`
- `dsh-llm` 导出 `errorChain(value)`:渲染抛出值及其完整 `cause` 链(`outer: inner: …`)与 AggregateError 成员(`msg [m1; m2]`),并容错循环 cause 和恶意强制转换。它只是用于诊断输出的渲染器;路由仍然基于 `HarnessError.code`
- DeepSeek 适配器把拿到响应之前的传输失败包装成 `LlmError('TRANSPORT')`,写明配置的 `baseURL` 并将原始拒绝值作为 `cause` 串入错误链。被中止的请求变为 `LlmError('ABORTED')`由于轮次信号已处于中止状态agent loop智能体循环仍将该轮次归类为取消而非恢复。
- 每个诊断边界改用 `errorChain` 而非 `error.message`/`String(error)`agent-loop 的持久化 `turn/end` 错误消息(`errorData`、其日志警告、TUI 的 `agent/error` 通知与启动失败行、以及 `dsh-stdio` 的启动失败日志行。实时 `agent/error` 事件与 `SettleReason``unknown` 原样保留抛出值;各诊断 Consumer 自行渲染,而不是由循环把它包装成另一个错误。`dsh-agent-loop``dsh-stdio``dsh-tui` 里各自的 `renderThrown` 副本被删除,统一使用这一个共享渲染器。
- `dsh-stdio` 渲染失败的 `turn/end` reason`[turn failed <code>] <message>``[turn aborted] <reason>``[turn rejected] <reason>``[turn interrupted by a previous process exit]` 以及输出 token 上限通知。通过声明合并扩展出的未知 kind 按普通 turn 结束处理。
@@ -24,7 +24,7 @@ TUI 连接不可达的 DeepSeek 端点时,失败只显示一条 `fetch failed`
**在每个错误的构造函数里渲染链(把 cause 写入 `message`)。** 否决:当消费方同时遍历 `cause` 时会双重渲染(适配器修复的第一版产出了 `… fetch failed: bad port: fetch failed: bad port`),并且破坏了想按内层错误路由的消费方所需的结构化链。
**只做一个感知 `cause` 的日志导出器。** 否决:持久化的 `turn/end` reason 和 TUI 通知不是日志行;被掩盖的消息会留在会话日志——轮次内失败的唯一持久记录——以及主要 UI 表面里
**只做一个感知 `cause` 的日志导出器。** 否决:持久化的 `turn/end` reason 和 TUI 通知不是日志行;被掩盖的消息会留在会话日志——轮次内失败的唯一持久记录——以及主要 UI
**逐包升级 `renderThrown`。** 否决:三个包已经各自持有几乎相同的私有副本;分别升级只会固化共享渲染器所要消除的重复。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-24-empty-model-response-is-retryable.md
2026-07-24-empty-model-response-is-retryable.md: 16e4a79ec64a1abb5489690f5e064ccb104ec5bc
2026-07-24-empty-model-response-is-retryable.zh.md: 2573ef66d9ca1e6c0610686d0051c738774af588
2026-07-24-empty-model-response-is-retryable.zh.md: a6bd3ed5a5f98a1f617be984cea1c9b1a847cfb4

View File

@@ -31,6 +31,6 @@ Status: implemented
## 后果
- 一个偶发异常的提供方会消耗一次有界重试,而不是一个没有输出的轮次;一个持续返回空内容的模型则会暴露为用户可据以行动的 `EMPTY_RESPONSE` 轮次失败。
- 一个偶发异常的提供方会消耗一次有界重试,而不是一个没有输出的轮次;一个持续返回空内容的模型则会产生用户可据以行动的 `EMPTY_RESPONSE` 轮次失败。
- 一个确实打算什么都不说的模型(罕见,但在一次工具结果之后有可能出现)会被重试,若始终为空,则该轮次失败。这个取舍是经过审慎权衡后接受的:一条空的 assistant 消息与提供方缺陷无法区分,且对用户毫无价值。
- `empty-response-retry` ACPAgent Client Protocol快照一个人工编写的无密钥场景配有确定性的 1 ms 零抖动重试 overlay`examples/acp-agent/retry.cordis.yml`)钉住了产品可见的行为:持久的 `llm/retry` 事件、被丢弃的尝试不产生任何 ACP 输出、恢复后的回复,以及一次正常完成的轮次。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-30-bounded-overwrite-diff-basis.md
2026-07-30-bounded-overwrite-diff-basis.md: 7a09934bd1798059de43a092f338d37aa9ccbd9a
2026-07-30-bounded-overwrite-diff-basis.zh.md: 1d6bdd1068d119aae859132d9f8216ca29d0dc11
2026-07-30-bounded-overwrite-diff-basis.zh.md: 761c0e6e5591ba8d31f7a43ac555d4b10b97659a

View File

@@ -4,11 +4,11 @@ Status: implemented
[English](2026-07-30-bounded-overwrite-diff-basis.md) | 中文
## Problem
## 问题
`dsh-fs-local` 会在 `FsWriteOutcome.before` 中返回完整旧文件,供消费方生成覆写上下文 diff。这个仅用于展示的预读没有上限大文件覆写可能分配整个旧文件而仅检查较早的路径 stat 也无法真正实施上限,因为外部进程可以在 stat 与读取之间替换文件或扩大文件。即使旧文件很小,大替换内容也会使上下文 hunk 接近替换内容本身的大小。本改动关闭了 [result-time applied-hunk diff](../../archived/architecture/2026-07-02-result-time-applied-hunk-diffs.md) 中记录的暂缓上限事项。
## Decision
## 决策
`LocalFileSystem.Config.diffBasisMaxBytes` 是一个不超过运行时 Buffer 分配和字符串解码上限的正安全整数部署配置,默认 10 MiB。只有当 UTF-8 替换内容严格低于该上限,且为生成基础而打开的旧文件最终也低于该上限时,覆写才提供 `before`。旧文件读取会打开文件描述符、检查该描述符,并按可响应取消的分块最多读取配置的字节数;一旦到达边界便返回 `null`。描述符 stat 后发生大小变化时同样返回 `null`,即使最终大小仍低于上限,因为部分前缀会成为错误的 diff 基础。旧内容为二进制或无效 UTF-8 时也返回 `null`;描述符阶段的任何 errno 同样如此——旧文件在调用方预检之后、基础读取打开之前被删除或变得不可读,不能让调用方已经提交的写入失败;只有取消和非 errno 故障会继续向上传播。这些结果都不会阻止原子写入。
@@ -16,7 +16,7 @@ Status: implemented
`before: null` 要求消费方使用既有的整文件回退。该上限只限制额外获取旧内容的成本,以及上下文内容对是否合格;它不限制调用方持有的替换内容、返回的 `after` 值或消费方的回退渲染。
## Alternatives considered
## 考虑过的替代方案
**保留一个与读取工具流式阈值相等的硬编码阈值。** 否决,因为读取阈值可由部署配置,且归消费方所有。两个同值常量会形成无法强制的一致性耦合,而覆写基础本身也是部署层面的内存与展示选择。
@@ -26,6 +26,6 @@ Status: implemented
**为任意大的内容对流式生成上下文 diff。** 本次缺陷修复不采用,因为当前文件系统 seam 返回完整的 `before`/`after` 字符串,当前 diff 实现也消费这两个字符串。流式 diff 需要独立的跨包协议与展示设计。
## Consequences
## 后果
部署可以调整额外的覆写基础成本,而不改变读取路由。达到或超过排他上限时,覆写仍会成功,并通过整文件回退保持可见,但不再提供上下文 hunk。低于上限时除调用方的替换内容外提供方仍可能持有接近 `diffBasisMaxBytes` 的旧文本。对于合格覆写,有上限的描述符读取会增加一次 open/stat/read 序列,同时防止陈旧路径探测把该序列变成无上限分配。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-06-list-agents-residency-vocabulary.md
2026-08-06-list-agents-residency-vocabulary.md: 01fff958921465909f5cd300dc355fdac6ec0772
2026-08-06-list-agents-residency-vocabulary.zh.md: d68b9857de23ccb0b68f0bfafba153fde63303a7
2026-08-06-list-agents-residency-vocabulary.zh.md: ba528ade01a5adf6302511735168d292fe3aee89

View File

@@ -4,13 +4,13 @@ Status: implemented
[English](2026-08-06-list-agents-residency-vocabulary.md) | 中文
## Problem
## 问题
`list_agents` 把可继续 child 的进程驻留状态投影为 `running | idle | complete``complete` 读起来像一项终态工作,且结果就在某处,但底层事实只表示没有驻留的 Activation对话完好无损`send_message` 可以继续它,而且它对 child 的结果不作任何断言。读到 `complete` 的模型会合理地寻找可收集结果,或向一个它以为已经结束的对话发送替代工作。
这个词与[由管理器负责的结算投递](../feature/2026-08-06-manager-owned-subagent-settlement-delivery.md)同时出现时尤其容易误导。完成会以通知到达 parent列表用于回忆持久化对话而不是轮询该通知。
## Decision
## 决策
面向模型的投影报告 `running | idle | ready`
@@ -22,7 +22,7 @@ Status: implemented
服务层不变。`SubagentListEntry.activity` 保留 `'running' | 'inactive'`,对 UI 等消费方而言,这准确描述了语料驻留状态。面向模型的适配器把 `inactive` 映射为 `ready`,因为这个词表达了模型可执行的操作,而没有虚构结果。
## Alternatives considered
## 考虑过的替代方案
**保留 `complete`,并在描述中限定它。** 一段解释 `complete` 不代表完成的描述,每次被读取时都在与渲染状态对抗。模型扫读的那一行必须自身表达正确区别。
@@ -32,7 +32,7 @@ Status: implemented
**重命名服务活动值。** `running | inactive` 在服务层是正确的,并且有非模型消费方。为了修复一个适配器的呈现而搅动通用契约并不合理;[持久化目录 Agent Note](../feature/2026-07-22-durable-subagent-catalog-and-list-agents.md) 继续拥有该服务词汇。
## Consequences
## 后果
- 渲染行使用 `<id> [running] — <label>``<id> [idle] — <label>``<id> [ready] — <label>`
- 输出 schema 的 `status` 枚举与渲染契约一同变化。生成的工具目录会带上新描述;它只渲染每个工具的 `parameters`,从来不收录输出 schema。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-09-broken-preset-roster-rows.md
2026-08-09-broken-preset-roster-rows.md: 069585957d4d99598cc38e4a7c6bc8c8d82490ca
2026-08-09-broken-preset-roster-rows.zh.md: d541292b59496464eb91bc03278e0800af16c4a3
2026-08-09-broken-preset-roster-rows.zh.md: 3f8a8b8fa7aeee04cf0d6dc05c398456b6c67bb3

View File

@@ -1,4 +1,4 @@
# Agent Note损坏的 preset 是名单行,不是空缺
# Agent Note: 损坏的 preset 是名单行,不是空缺
Status: implemented

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-10-child-agents-join-their-parent-preset.md
2026-08-10-child-agents-join-their-parent-preset.md: 4534004ad54df69822872b9595a29443fc3a990b
2026-08-10-child-agents-join-their-parent-preset.zh.md: bdf9928bea4b75e2915c8adf5c15f8a01c6583e4
2026-08-10-child-agents-join-their-parent-preset.zh.md: 550a952efefd2490924ed11f7a0e110694571855

View File

@@ -4,7 +4,7 @@ Status: implemented
[English](2026-08-10-child-agents-join-their-parent-preset.md) | 中文
## Problem
## 问题
工具与提示段的可见性沿 `dsh-scope` 的父链继承,而 agent 的 scope key 铸造出来时没有父。[逐会话 agent preset](../architecture/2026-08-03-per-session-agent-presets.md) 把所有面向模型的行搬到了 agent 平面,并让 `AgentPresets.mount()` 成为绑定那条父链的唯一途径——调用点在 api-proxy 的会话创建、恢复与 fork 路径上。两个进程内 subagent 驱动通过 `applyChildComposition()` 组装子 agent而它只安装了逐子 agent 的 persona 与工具限制,于是子 agent 的 scope 链长度为一,其注册表视图只能解析到全局层。
@@ -12,7 +12,7 @@ Status: implemented
子 agent 的持久化 header 让问题更进一步。`childSessionMeta()` 不记录任何 preset于是冷读一个子会话解析到的是部署默认值——一套该子 agent 从未运行过的工具集,而这正是"模型可见 ⟺ 已记录"规则要杜绝的情形。
## Decision
## 决策
`AgentPresets.composeFrom(agentCtx, parentCtx)` 让一个 agent 加入另一个 agent 已在运行的常驻组装,并返回所加入的 preset id。它通过 `standingMountFor()` 定位父方的挂载——agent 的 key 认父到其 preset 的常驻 key正是 `serviceForAgent()` 读取的同一关系——再把子 agent 的 key 绑到同一个常驻 key 上,绑定句柄仍归 roster 独有的重链权威持有。未加入任何 preset 的父方不产生加入、也不报错,那就是无 roster 的部署:它面向模型的行位于宿主组装中,子 agent 已经能通过全局层解析到它们。
@@ -24,7 +24,7 @@ Status: implemented
把父方的工具交给子 agent 之后,暴露出同一次 agent 平面搬迁引入的第二个缺陷:`ToolRegistry` 把**作用域级**注册排除在限制之外、只过滤全局层,因此当所有面向模型的行都变成祖先贡献之后,子 agent 的 `toolFilter` 就不再约束任何东西——而且全局层为空时,`restrict()` 会把收到的每个名字都判为未知并直接让子 agent 创建失败。豁免集合应当是作用域**自己注册**的工具,而不是恰好位于全局层的工具;后一种读法只在这两个集合重合时才成立。`view()` 现在过滤作用域继承来的一切——全局层与每个祖先层——只豁免它自己那层。这条自身层豁免是承重的而非顺带的:委派运行时把子 agent 的 `report` 与结构化输出工具注册进子 agent 自己那层,而一个只点名子 agent 可用能力的过滤器绝不能把它回报所依赖的机制一并剥掉。
## Alternatives considered
## 考虑过的替代方案
**在子 agent 的 setup 里按 id 重新挂载父方的 preset。** 语义与机制两方面都不成立而被否决。它会重读 roster 并重新 stat 组装文件,因此父方启动后的一次编辑就会把子 agent 分叉到另一个代际,而此后被删除的 preset 会让子 agent 失败、父方却照常运行。`mount()` 还是异步的,同步的创建窗口无法在不重构两个驱动的前提下接受它。
@@ -38,7 +38,7 @@ Status: implemented
**只修活着的加入,不动持久化 header。** 否决,因为那样活着的子 agent 与冷读同一个子 agent 会对"哪份组装产出了这段历史"给出不同答案——同一类缺陷,只是被搬了个地方而不是被修掉。
## Testing
## 测试
`packages/preset/agent-presets/tests/mount.spec.ts` 用真实 fixture 组装覆盖该加入:子 agent 看到父方的工具与提示段、不会挂载出第二个代际、加入在父方 dispose 后依然成立(活得比父方久的后台子 agent、上报的 id 一致、没有 preset 的父方不产生加入、以及无 scope 的上下文被拒绝。
@@ -48,7 +48,7 @@ Status: implemented
组装记录这一层用的是真实 shipped Web 组装的 e2e而不是无密钥快照。本仓库所有可运行 example 都不组装 preset roster因此该缺陷在快照 harness 里根本不可观察:要做快照场景,得先有一个既挂载 roster 又发起委派的 example。Web e2e 启动的是真实的 `base` + `web-app` 补丁层与两个 shipped preset这正是测试政策要求的组装证据Web 浏览器 lane 的 subagent golden 承载了可见后果——记录了 preset 的子 agent 现在会显示与其父方相同的 preset 徽标。
## Consequences
## 后果
委派现在的成本是每个子 agent 一次 scope 认父,再无其他——没有额外的插件实例、没有 roster 读取、没有新的失败模式。子 agent 的能力恰好等于父方的能力,减去它自己的 `toolFilter` 所移除的部分;逐 subagent 的 preset"agent 类型")仍未构建,那会是一个新的请求字段,而不是对这次加入的改动。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-10-pre-plugin-theme-bootstrap.md
2026-08-10-pre-plugin-theme-bootstrap.md: 276d564dcef60e5130b4b2d0ef7cbc12eeb8b6d6
2026-08-10-pre-plugin-theme-bootstrap.zh.md: 7162b2d851b50f75b3af6320ad9348383933e50f
2026-08-10-pre-plugin-theme-bootstrap.zh.md: f9384df6e0ed5bf42c0671b70f484f57080060a0

View File

@@ -4,13 +4,13 @@ Status: implemented
[English](2026-08-10-pre-plugin-theme-bootstrap.md) | 中文
## Problem
## 问题
Web 壳在浏览器侧插件树激活前呈现 `Loading plugins…`。主题 token 已随壳样式加载,但 `color-scheme``body[data-ds-dark-theme]` 要等 ui-theme 的 ThemeService 与 ui-layout 的 ThemePresenter 激活后才写入;持久化偏好为深色时,加载页因此先按浅色调色板绘制,再切为深色。
`dshClient.immediately` 只把 bundle 纳入第一阶段预取,不会让插件在 HTML 解析或壳首次渲染前执行。仅调整客户端插件的加载档位无法关闭这段时间窗口。
## Decision
## 决策
ui-theme 的主机侧通过 `ctx.httpServer.tapIndex()` 转换每份 index HTML`<body>` 起始标签后紧接一段同步内联脚本。该转换通过可选的 `httpServer` 注入注册,因此不含该服务的组合仍会激活 ui-theme但不会安装转换。HTML 解析器执行该脚本时body 已存在,而壳的模块脚本与 React 根节点尚未运行。
@@ -18,11 +18,11 @@ settings provider 存在时,主机侧会注册 [`ui-theme.preference` settings
引导逻辑只认识内建的 `light``dark``system` 语义,不注册监听器,也不解析第三方主题或 token 覆盖。浏览器侧插件树激活后ThemeService 仍是主题状态的权威来源ThemePresenter 会把完整解析结果重新写入同一组 DOM 状态并负责后续更新与释放。
## Verification
## 验证
ui-theme 的单元测试覆盖不含任一可选 Host 服务时的激活、脚本位置、Host 设置优先级、系统偏好、缺少 `matchMedia`、不含 body 的输入、实时读取 settings以及 Host 注册随插件 fiber 一同释放。真实 Web 组合的 Chromium 场景会选择持久化深色偏好并拦住插件 bundle 请求,使加载页保持可观察,再断言 index 响应产生了深色背景、body 属性和根元素 `color-scheme`。该变化不改变可访问性树,因此不产生新的页面 golden。
## Alternatives considered
## 考虑过的替代方案
**把逻辑固定写进 `apps/web/index.html`。** 这样能在相同时机执行,但静态 HTML 无法嵌入当前 Host 设置,还会复制 ui-theme 拥有的偏好解析和 DOM 字段Host 转换会跟随主题插件的生命周期,并让应用壳无需了解主题领域。
@@ -32,6 +32,6 @@ ui-theme 的单元测试覆盖不含任一可选 Host 服务时的激活、脚
**在 `<head>` 中执行并给 html 添加临时类。** body 此时尚不存在,还需要一套与正式调色板属性不同的临时选择器。紧接 `<body>` 是能够直接写正式 DOM 字段的最早解析位置。
## Consequences
## 后果
加载页首帧与持久化内建偏好一致;未组合 settings provider 时则默认采用系统偏好。index 转换会为每份响应读取 Host settings而内联脚本只包含选定的内建值与 `system` 解析逻辑。内建偏好语义或 ThemePresenter DOM 字段变化时,必须同时更新脚本与 ThemeService。自定义主题仍会在浏览器插件激活后才完整应用加载期间页面使用该主题解析后的浅色或深色基础调色板。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-10-slash-catalog-follows-preset-switch.md
2026-08-10-slash-catalog-follows-preset-switch.md: ec85d4a3a6a053e91c368f65ecb12f123c45287d
2026-08-10-slash-catalog-follows-preset-switch.zh.md: b68fa90e99c3597c61b3edcc03399bb7ea7844f4
2026-08-10-slash-catalog-follows-preset-switch.zh.md: 9b464dc54c125e2e15433871dc804981d916744d

View File

@@ -1,10 +1,10 @@
# Agent Note斜杠目录跟随空会话的 preset 切换
# Agent Note: 斜杠目录跟随空会话的 preset 切换
Status: implemented
[English](2026-08-10-slash-catalog-follows-preset-switch.md) | 中文
## Problem
## 问题
preset 把决定 `/` 菜单内容的那些行搬走了。Web 组装禁用了宿主面的 `skill-local``tool-skill``plan-mode``command-compact`,改由 preset 提供,因此一个会话有哪些命令和技能,是它自身组成的属性,而不是部署的属性。
@@ -12,7 +12,7 @@ preset 把决定 `/` 菜单内容的那些行搬走了。Web 组装禁用了宿
于是菜单继续提供会话已经不再运行的那套组成。向下切换后 `compact``plan` 和全部项目技能仍列在菜单里;向上切换后留在原地的是更窄的目录——四条宿主面行加客户端自己的 `model` 贡献——而且完全没有技能,这正是 bug 报告描述的现象。只有当某个无关的注册表变化或一次重连恰好使其失效时,目录才会自愈。
## Decision
## 决策
这次切换的提交点是落账的 `agent-preset/selected` 事件。preset owner 将该提交重新发为 client-safe 的 cordis owner 事件 `agent-preset/selected(sessionId, agentPreset)`,宿主流原样转发它,两份目录各自通过 `ctx.remote.$on` 直接订阅:`ui-command` 软刷新该键(新快照落地前,旧快照继续服务已打开的菜单),`ui-skill` 让它失效(并中止在途的预热,使一次与切换赛跑的 warm 无法发布过期目录)。
@@ -20,7 +20,7 @@ preset 把决定 `/` 菜单内容的那些行搬走了。Web 组装禁用了宿
从落账事件而不是 RPC 处理器的返回值派生 owner 事件,使「这个会话的组成变了」只有一个权威来源:每个已连接的客户端都能观察到这次切换,而不只是发起它的那个标签页;不是发起方的客户端也无需从一个根本不会到来的注册表信号里去推断。
## Alternatives considered
## 考虑过的替代方案
**在客户端自己的 `agentPresets.select` 回调里就地失效。** 改动最小,而且第一轮之后 preset 就锁定hero 上的 chip 是切换唯一可能的发起处。否决理由是失效逻辑会落在恰好发起 RPC 的那个界面上,而不是提交点:同一个空会话在第二个标签页里仍是过期菜单,将来任何宿主侧的重组也完全没有信号。
@@ -28,11 +28,11 @@ preset 把决定 `/` 菜单内容的那些行搬走了。Web 组装禁用了宿
**复用转发的 `commands/change`。** 它是既有的目录失效事件,但它是注册表级的、不带会话、也与技能无关;客户端会把每个会话的命令都重拉一遍,却依然永远刷不新技能目录。
## Consequences
## 后果
转发名单加入了 preset owner 的类型化事件,而每一份由 preset 决定的目录从此有了统一的订阅点将来任何从组成派生的按会话界面都在同一个信号上失效而不必再发明一个。owner 事件仍是落账事实的第二次发布,因此将来若出现一条不落账就重组的切换路径,它将无人宣告。`ui-command` 保持软失效(已打开的菜单不会变空),而 `ui-skill` 直接丢弃该项,因为技能目录没有「部分可服务」的状态;在重拉窗口内打开的菜单,那一瞬间显示的是没有技能,而不是错误的技能。
## Testing
## 测试
`api-proxy-agent-preset.spec.ts` 断言已提交的切换恰好转发一次,并带上会话与新 preset`ui-agent-preset``ui-command``ui-skill` 的 spec 断言直接 Remote 订阅会合并会话行或只重拉被重组的会话。`agent-preset-selection` web e2e 播种一个项目技能,并在 hero chip 应用 `minimal` 之后断言 `/` 菜单丢掉了 `compact``plan` 和该技能,同时保留宿主面的那几行——这是面板跟随组成的整装应用证据。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-11-preset-authoring-agent-validates-its-own-composition.md
2026-08-11-preset-authoring-agent-validates-its-own-composition.md: 6b9cdf32b70e3ab4adc9f3b0e20bb3d2245486c7
2026-08-11-preset-authoring-agent-validates-its-own-composition.zh.md: e6e8dabcd886a6331d294744b667552caa01e7b4
2026-08-11-preset-authoring-agent-validates-its-own-composition.zh.md: db2ed9c7758deef921272a976256bff56e5d359e

View File

@@ -4,7 +4,7 @@ Status: implemented
[English](2026-08-11-preset-authoring-agent-validates-its-own-composition.md) | 中文
## Problem
## 问题
`cordis` preset 随包发布 `editing-cordis-compositions`,它是 agent 创作 preset 时唯一的指导来源。其中四条陈述与事实不符,而分量最重的两条恰好指向该 skill 自称「最容易让人栽跟头的规则」。
@@ -18,7 +18,7 @@ Status: implemented
四条之下还压着一个能力断言agent「自己起不了会话」于是校验退化成肉眼核对 YAML 字段,再把结果经设置页的红色标记交给用户。那个标记是发现阶段的结构检查,远弱于这句话给人的印象。
## Decision
## 决策
skill 教 agent 通过 `ctx.agentPresets` 自行挂载校验其组装,其余每个示例都取自同一仓库中已发布的组装。
@@ -51,7 +51,7 @@ agent 按 `cordis_mount` 自身文档所述的方式够到 roster 服务:挂
skill 自带的 `cordis_mount` 代码片段经工具注册表逐字执行:它成功挂载,其 `preset_check` 工具在下一次读取时出现在组装该 agent 的目录中,对有效 preset 回答 `mounted OK`,对无效 preset 回答挂载拒绝原因。
## Alternatives considered
## 考虑过的替代方案
**把校验留给用户,只修四处错误。** 这些错误与那句能力断言同源——指导是按 preset 层的公开面写的,而不是按被组装出的 agent 实际够得到的东西写的——而无法自查的 agent 交出的组装,其缺陷设置页同样看不见。
@@ -59,7 +59,7 @@ skill 自带的 `cordis_mount` 代码片段经工具注册表逐字执行:它
**给 preset 加一个一等的 preset 校验工具。** 组合出的路径已经存在,且由 `cordis_mount` 自己的 schema 记载;专用工具会给一个「无需专用工具即可够到运行时」的 preset 再添一个面向模型的行。
## Consequences
## 后果
- 校验成功会留下一个永不回收的常驻代际,这是 roster 按代际本就承担的[常驻挂载](../architecture/2026-08-08-per-preset-standing-mounts.md)代价——由 agent 在编辑收尾时付一次,而不是由用户在首次会话时付。
- skill 现在依赖 `cordis_inspect` 生成的 API 目录对 `agentPresets` 保持最新;`doc-sync` 中的 `verify-cordis-api` 是守住这一点的门禁。