docs(i18n): proofread README translations 121-140

This commit is contained in:
j-xiang
2026-07-29 15:29:38 +08:00
parent f6c8fe4dcb
commit 57b01e68d3
20 changed files with 193 additions and 193 deletions
+3 -3
View File
@@ -1,8 +1,8 @@
# skill/ - skill 功能家族
# skill/ - skill(技能)能力家族
[English](README.md) | 中文
可复用 agent 指令的规范三包功能 seam:提供方注册表、本地实现,以及面向模型的目录/加载器消费方。全部都是**产品** 包。
可复用 agent(智能体)指令的规范能 seam 由三个包(package)组成:提供方注册表、本地实现,以及面向模型的目录loader 消费方。全部均为**产品**包。
| 包 | 职责 | ctx 键 |
|---|---|---|
@@ -10,4 +10,4 @@
| `skill-local/` | 项目/自定义/用户文件系统提供方 | (注册到 `ctx.skills` |
| `tool-skill/` | 会话前缀目录和面向模型的 `skill` 加载器 | (注册到 `ctx.tools` |
接口位于 `skill/skill/`。提供方同步注册,并通过 `ctx.skills` 执行异步发现;`tool-skill` 只消费该接口,因此嵌入式或远程提供方可替换或补充 `skill-local`,无需改变面向模型的契约。`agent-core` 默认加载该家族,但它仍然是核心控制主干之外的能,与 [`bash/`](../bash/README.md)、[`fs/`](../fs/README.md)、[`web/`](../web/README.md) 和 [`subagent/`](../subagent/README.md) 并列。
接口位于 `skill/skill/`。提供方同步注册,并通过 `ctx.skills` 执行异步发现;`tool-skill` 只消费该接口,因此嵌入式或远程提供方可替换或补充 `skill-local`,无需改变面向模型的契约。`agent-core` 默认加载该家族,但它仍然是核心控制主干之外的能,与 [`bash/`](../bash/README.md)、[`fs/`](../fs/README.md)、[`web/`](../web/README.md) 和 [`subagent/`](../subagent/README.md) 并列。
+13 -13
View File
@@ -4,19 +4,19 @@
`ctx.skills` 注册表的本地文件系统提供方。
该包实现一个 skill 来源。它扫描本地项目、自定义和用户 skill 根,解析 `SKILL.md` 或平铺 Markdown skill 文件,并将提供方注册到 `ctx.skills`。注册表仍位于 `@deepseek-ai/dsh-skill`;会话前缀目录和面向模型的加载器工具仍位于 `@deepseek-ai/dsh-tool-skill`
该包package实现一个 skill(技能)来源。它扫描本地项目、自定义和用户 skill 根目录,解析 `SKILL.md` 或平铺 Markdown skill 文件,并将提供方注册到 `ctx.skills`。注册表仍位于 `@deepseek-ai/dsh-skill`;会话前缀目录和面向模型的 loader 工具仍位于 `@deepseek-ai/dsh-tool-skill`
## 插件
需要 `ctx.skills` `inject: ['skills']`)。
需要 `ctx.skills``inject: ['skills']`)。
### 配置
| 字段 | 默认值 | 含义 |
|---|---|---|
| `dshHome` | `$DSH_HOME` or `~/.dsh` | 由 [`@deepseek-ai/dsh-paths`](../../util/paths/README.md) 解析的 DeepSeek Harness 配置根;扫描该目录下的 `skills`。 |
| `agentsHome` | `$DSH_AGENTS_HOME` or `~/.agents` | 为兼容 skill 扫描的共享 agent 配置根。 |
| `customSkillDirs` | `[]` | 在项目根之后、用户根之前扫描的其他本地 skill 根。 |
| `dshHome` | `$DSH_HOME` `~/.dsh` | 由 [`@deepseek-ai/dsh-paths`](../../util/paths/README.md) 解析的 DeepSeek Harness 配置根目录;扫描该目录下的 `skills`。 |
| `agentsHome` | `$DSH_AGENTS_HOME` `~/.agents` | 为兼容 skill 扫描的共享 agent(智能体)配置根目录。 |
| `customSkillDirs` | `[]` | 在项目根目录之后、用户根目录之前扫描的其他本地 skill 根目录。 |
## 发现
@@ -30,25 +30,25 @@
| 400 | `user-dsh` | `<dshHome>/skills` |
| 500 | `user-agents` | `<agentsHome>/skills` |
项目根是包含 `.git` 的最近祖先;如果不存在,则使用当前 cwd。用户 DSH 根会跳过其 `.system`,因此系统所有目录不会被当作普通用户 skill。该提供方提供项目和用户 skill;其他提供方可提供内置系统 skill。
项目根目录是包含 `.git` 的最近祖先目录;如果不存在,则使用当前 cwd。用户 DSH 根目录会跳过其 `.system`目录,因此系统所有目录不会被当作普通用户 skill。该提供方提供项目和用户 skill;其他提供方可提供内置系统 skill。
`ctx.fs` 可用时,发现通过 `ctx.fs.listDir` 列出根,通过 `ctx.fs.readText` 读取 skill 文件,并通过文件系统服务探测 `.git`。完整 skill 加载会将查找中止信号转发给文件系统元数据和内容读取。如果没有文件系统服务,提供方回退到可中止的 Node 文件系统 I/O,使最小本地上下文仍能加载 skill。缺失、不可读或格式错误的 skill 文件会警告并跳过,而不会使整个请求失败。
## Skill 格式
Skill 可以是单层目录 bundle`<name>/SKILL.md`),也可以是平铺 Markdown 文件(`<name>.md`)。v1 刻意不包含嵌套 `**/SKILL.md` 发现。Frontmatter 使用 `yaml` 包解析为 YAML;它要求 `name``description`,而 `whenToUse``disableModelInvocation``metadata` 可选。名称必须使用 kebab-case。
Skill 可以是单层目录 bundle`<name>/SKILL.md`),也可以是平铺 Markdown 文件(`<name>.md`)。v1 刻意不支持发现嵌套 `**/SKILL.md`。Frontmatter 使用 `yaml` 包解析为 YAML;它要求 `name``description`,而 `whenToUse``disableModelInvocation``metadata` 可选。名称必须使用 kebab-case。
## 模型体验
通过 `dsh-tool-skill` 间接影响模型。它将该提供方的可调用名称和有上限描述渲染到会话前缀目录中,并将所选指令正文与资源基底指引渲染到保留工具历史中;路径、提供方 rank 和已禁用 skill 仍被隐藏。
通过 `dsh-tool-skill` 间接影响模型。它将该提供方的可调用名称和有长度上限描述渲染到会话前缀目录中,并将所选指令正文与资源基底指引渲染到保留工具历史中;路径、提供方 rank 和已禁用 skill 仍被隐藏。
#### KV 缓存影响
#### KV Cache 影响
不直接导致失效;指定的消费方负责其引起的任何请求前缀变更
直接导致 KV Cache 失效;请求前缀变更由上述消费方负责
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **发现深度为一层**:只识别 `<root>/<name>/SKILL.md``<root>/<name>.md`;忽略嵌套 skill 树和包 manifest。
- **发现深度为一层**:只识别 `<root>/<name>/SKILL.md``<root>/<name>.md`;忽略嵌套 skill 树和包 manifest(元数据清单)
- **项目范围为最近 `.git` 祖先**:没有该标记的工作区回退到提供的 cwd,不支持其他项目根标记或 monorepo 子项目选择。
- **不可读或格式错误的条目会随警告消失**:模型目录不会收到每个 skill 的诊断,无法区分缺失的 skill 与被跳过的 skill。
- **无文件系统 watcher**先前已收集 cwd 重新发现之前,编辑操作依赖注册表缓存被驱逐,或因提供方重新加载而失效。
- **无文件系统监听**:在重新发现先前已收集 cwd 之前,编辑内容能否生效取决于注册表缓存是否被淘汰,或是否因提供方重新加载而失效。
+13 -13
View File
@@ -2,15 +2,15 @@
[English](README.md) | 中文
纯 agent skill 提供方注册表。
纯 agent skill(智能体技能)提供方注册表。
该包负责 `ctx.skills` 接口。它不知道 skill 来自本地文件、嵌入式插件数据、HTTP 还是其他后端;提供方通过 `ctx.skills.registerProvider(...)` 注册这些来源。已发布的本地实现是 [`@deepseek-ai/dsh-skill-local`](../skill-local)。
该包package负责 `ctx.skills` 接口。它不知道 skill 来自本地文件、嵌入式插件数据、HTTP 还是其他后端;提供方通过 `ctx.skills.registerProvider(...)` 注册这些来源。已发布的本地实现是 [`@deepseek-ai/dsh-skill-local`](../skill-local)。
## 服务:`SkillService`ctx 键:`skills`
### 公开 API
- `ctx.skills.registerProvider(provider): () => void` 使用唯一 `provider.name` 注册只读提供方。重复提供方名称会抛错,`runtime` 保留给 `ctx.skills.register(...)`。注册表借用提供方对象,并直接调用其方法。注册作用域绑定到 effect,可安全用于 HMR;精确的 Cordis disposer 支持有序组合拆卸。
- `ctx.skills.registerProvider(provider): () => void` 使用唯一 `provider.name` 注册只读提供方。重复提供方名称会抛错,`runtime` 保留给 `ctx.skills.register(...)`。注册表借用提供方对象,并直接调用其方法。注册作用域绑定到 effect,可安全用于 HMR(热模块替换);Cordis 返回的原始 disposer 支持有序组合拆卸。
- `ctx.skills.list({ cwd?, signal? })` 借用只读查找选项,然后返回当前工作区中模型可调用的摘要;这些摘要跨提供方合并,并按名称排序。
- `ctx.skills.get(name, { cwd?, signal? })` 在发现和加载中使用同一组只读选项和胜出候选项;在发现或缓存命中后重新检查取消,让提供方加载与信号竞速,验证已加载定义,然后将其返回,包括已对模型禁用的 skill。
- `ctx.skills.register(skill): () => void` 注册只读运行时嵌入式 skill,省略时添加 `provider: "runtime"`。同名运行时注册使用先到先得:重复项会记录警告,并获得无操作 disposer。成功注册会返回精确的 Cordis disposer,以供有序组合拆卸。
@@ -23,15 +23,15 @@
## 提供方契约
提供方同步注册,并在等待的 `list(options)` 调用中执行远程设置、身份验证和发现。提供方对象、查找选项、候选项和定义都以只读方式借用,而不是克隆或重新绑定。提供方应遵守 `options.signal`;取消后,注册表也会停止等待不协作的发现或加载。
提供方同步注册,并在等待的 `list(options)` 调用中执行远程设置、身份验证和发现。提供方对象、查找选项、候选项和定义都以只读方式借用,而不是克隆或重新绑定。提供方应遵守 `options.signal`;取消后,注册表也会停止等待不协作的发现或加载。
注册表在缓存前验证候选项,在返回前验证定义。胜出提供方会收到同一候选项和不透明 `locator`,两者都是它从 `list()` 返回的内容,从而支持后端专用文件、URL、id 或版本句柄。调用方和提供方必须保持只读契约。
契约违反会快速失败。被拒绝的 `list()` 视为瞬时来源失败:系统记录它、跳过它,并且不缓存。只缓存已完成目录;提供方或运行时修订变更会丢弃正在进行的结果并重试。重复名称按 rank、提供方注册顺序,然后按提供方本地顺序解。摘要按 skill 名称排序。
违反契约时会快速失败。`list()` 返回的 Promise 被拒绝会被视为瞬时来源失败:系统记录并跳过该失败,且不缓存结果。只缓存已完成目录;提供方或运行时修订发生变化时,会丢弃正在进行的结果并重试。重复名称依次按 rank、提供方注册顺序提供方本地顺序解决冲突。摘要按 skill 名称排序。
## 运行时 Skill
## 运行时 skill
`ctx.skills.register(...)` 是嵌入式运行时 skill 的便利接口。运行时 skill 使用 rank `250`:项目提供方可覆盖它们,它们则覆盖已发布本地提供方的自定义根和用户根。运行时定义和嵌套资源元数据均以只读方式借用;服务只实体化提供默认 `provider` 所需的顶层定义。运行时贡献内的注册使用先到先得,因此重复贡献无法通过其 disposer 移除活动项
`ctx.skills.register(...)` 是嵌入式运行时 skill 的便利接口。运行时 skill 使用 rank `250`:项目提供方可覆盖它们,它们则覆盖已发布本地提供方的自定义根目录和用户根目录。运行时定义和嵌套资源元数据均以只读方式借用;服务只化提供默认 `provider` 所需的顶层定义。运行时贡献内的注册使用先到先得,因此重复贡献无法通过其 disposer 移除当前生效的贡献
## 消费方边界
@@ -41,13 +41,13 @@
通过 `dsh-tool-skill` 间接影响模型;该包将提供方摘要渲染到会话前缀中,并将已加载指令渲染到已保留工具结果中。
#### KV 缓存影响
#### KV Cache 影响
不直接导致失效;指定的消费方负责其引起的任何请求前缀变更
直接导致 KV Cache 失效;请求前缀变更由上述消费方负责
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **已完成目录没有 TTL 或 watcher 失效机制**:提供方的底层文件或远程数据可在注册修订不变的情况下更改,因此已缓存 cwd 会保持陈旧,直到被驱逐或重新加载提供方/运行时。
- **提供方依次查询**:一个缓慢的协作提供方会延迟之后注册的所有提供方;取消会停止调用方等待,但无法终止不协作提供方持续运行的工作。
- **提供方列表失败会移除该请求整个来源**:注册表会记录并跳过,不提供模型可见诊断或部分目录恢复契约。
- **已完成目录没有 TTL 或监听失效机制**:提供方的底层文件或远程数据可在注册修订不变的情况下更改,因此已缓存 cwd 会保持陈旧,直到缓存条目被淘汰或提供方运行时重新加载
- **提供方依次查询**:一个响应取消但速度缓慢的提供方会延迟之后注册的所有提供方;取消会停止调用方等待,但无法终止不响应取消的提供方持续运行的工作。
- **提供方列表失败会使该请求无法使用整个来源**:注册表会记录并跳过该来源,不提供模型可见诊断或部分目录恢复契约。
- **重复解析使用先到先得**:系统会记录并隐藏较晚出现的低优先级候选项;不提供检查全部被遮蔽定义的 API。
+18 -18
View File
@@ -2,13 +2,13 @@
[English](README.md) | 中文
面向模型的 skill 目录和 `skill` 工具。
面向模型的 skill(技能)目录和 `skill` 工具。
需要 `ctx.tools``ctx.skills` `inject: ['tools', 'skills']`)。
需要 `ctx.tools``ctx.skills``inject: ['tools', 'skills']`)。
## 会话目录
该插件在实时会话的第一个 `agent/step` 注入一条持久的用户角色 `<system-reminder>` 目录。它为调用会话的 cwd 解析 skill,将步骤中止信号转发到发现,并只列出已排序的 `name``description` 条目;skill 正文、路径、来源、提供方和 `whenToUse` 提示仍位于目录之外。如果没有模型可调用 skill,则省略目录;如果该 agent 的工具视图排除已发布`skill` 工具,或解析出一个同名作用域遮蔽,也会省略目录。这项精确定义检查使提示词指引、模型可见 schema 和可执行分派保持对齐。
该插件在活动会话的第一个 `agent/step` 注入一条持久的用户角色 `<system-reminder>` 目录。它为调用会话的 cwd 解析 skill,将步骤中止信号转发到发现流程,并只列出已排序的 `name``description` 条目;skill 正文、路径、来源、提供方和 `whenToUse` 提示仍位于目录之外。如果没有模型可调用 skill,则省略目录;如果该 agent(智能体)的工具视图排除了随附`skill` 工具,或解析出同名作用域遮蔽,也会省略目录。这项对工具定义的精确匹配检查使提示词指引、模型可见 schema 和可执行分派保持对齐。
`catalogDescriptionMaxLength` 控制规范化且经 XML 转义的目录描述。其默认值是 `500`,且必须是不小于 `3` 的整数,以便为截断省略号保留空间。目录是一条带来源的 `user/message`,在第一个请求前注入,并保留在普通会话历史中。
@@ -18,9 +18,9 @@
|---|---|---|
| `name` | string(必填) | 可用 skill 列表中精确的 kebab-case skill 名称。 |
执行使用调用 agent 的 `session.header.cwd`,使工作区敏感提供方解析胜出 skill。成功调用返回规范 `{ name, provider, resourceBase?, content }`排除目录 rank 和提供方内部机制;其 Native 渲染器产生一个文本结果,其中包含 `<skill_content name="...">``<skill_resources>``<skill_instructions>`
执行使用调用 agent 的 `session.header.cwd`,使结果随工作区变化的提供方能够解析胜出 skill。成功调用返回规范形式的 `{ name, provider, resourceBase?, content }`其中不包含目录排名和提供方内部机制;其 Native 渲染器会生成一个文本结果,其中包含 `<skill_content name="...">``<skill_resources>``<skill_instructions>`
资源指引只会根据 `resourceBase` 解析指令显式引用的路径或 URL;脚本、参考资料和产物按需加载,结果不会列举 skill 目录。本地提供方可以提供目录,而远程或嵌入式提供方可以提供 URL 或不透明加载指引。
资源指引只会根据 `resourceBase` 解析指令显式引用的路径或 URL;脚本、参考资料和资源文件按需加载,结果不会列举 skill 目录。本地提供方可以提供目录,而远程或嵌入式提供方可以提供 URL 或不透明加载指引。
无法解析的名称会报告 skill 未知或已不可用。无效名称和 `disableModelInvocation: true` skill 产生不同的错误结果。
@@ -32,7 +32,7 @@
#### 模型所见
如果存在模型可调用 skill,且该精确 `skill` 工具可见,agent 会收到下方目录模板,其中包含每个已排序 skill 的一条数据依赖条目。该目录是一条持久的用户角色消息。
如果存在模型可调用 skill,且可见的正是这个 `skill` 工具,agent 会收到下方目录模板,其中包含每个已排序 skill 的一条数据而定的条目。该目录是一条持久的用户角色消息。
##### Skill 目录模板
@@ -52,7 +52,7 @@ If the user names a skill, or the task clearly matches a skill's description, ca
重复输入成本随 skill 数量和 `catalogDescriptionMaxLength` 增长;当列表为空或工具被隐藏或遮蔽时,不会发送目录 token。
#### KV 缓存影响
#### KV Cache 影响
仅追加,位于现有可重用前缀之后。如果新建或恢复的实例具有不同提供方、skill、描述、可见性或目录上限,则可能从新追加的目录位置起影响缓存重用。
@@ -64,9 +64,9 @@ If the user names a skill, or the task clearly matches a skill's description, ca
#### Token 影响
工具可见时,每次请求都有固定 schema 成本
工具可见时,每次请求都有固定 schema token 开销
#### KV 缓存影响
#### KV Cache 影响
工具定义和可见性不变时,前缀稳定。遮蔽、限制或插件生命周期变更可能从该 schema 起使重用失效。
@@ -74,7 +74,7 @@ If the user names a skill, or the task clearly matches a skill's description, ca
#### 模型所见
成功调用使用下方结果模板,以及提供方管理、目录、URL 或不透明资源指引。
成功调用使用下方结果模板,以及提供方管理的资源指引、目录资源指引、URL 资源指引或不透明资源指引。
##### Skill 结果模板
@@ -120,11 +120,11 @@ Load referenced resources only as needed.
#### Token 影响
已加载指令是取决于数据的工具结果 token,并在后续步骤中重新发送,直到压缩;不会制作重复的 `agent.inject()` 副本。
已加载指令是取决于数据的工具结果 token,并在后续步骤中重新发送,直到压缩compaction;不会制作重复的 `agent.inject()` 副本。
#### KV 缓存影响
#### KV Cache 影响
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV 缓存条目失效。
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV Cache 条目失效。
### 工具错误
@@ -136,13 +136,13 @@ Load referenced resources only as needed.
只有失败调用会添加这些已保留 token。
#### KV 缓存影响
#### KV Cache 影响
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV 缓存条目失效。
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **目录省略 `whenToUse`、来源和提供方元数据**:路由只基于名称和有上限描述;`whenToUse` 仍是提供方元数据,加载后的包装层也不渲染它。
- **目录省略 `whenToUse`、来源和提供方元数据**:路由只基于名称和有长度上限描述;`whenToUse` 仍是提供方元数据,加载后的包装层也不渲染它。
- **已加载指令正文没有大小上限**:提供方可返回足以占用大量下一步上下文的 skill;只有目录描述会被截断。
- **资源是指引,而非附件**:工具报告基础目录/URL/不透明提示,但既不列举也不为模型获取引用文件。
- **加载是一次性文本**:远程提供方缓慢或 skill 正文很大时,不提供部分、流式或缓存内容句柄。
- **加载是一次性文本**:远程提供方缓慢或 skill 正文很大时,不提供部分内容、流式输出或缓存内容句柄。
+4 -4
View File
@@ -1,15 +1,15 @@
# spill/ - spill 存储能家族
# spill/ - spill 存储能家族
[English](README.md) | 中文
工具输出 spill 的能 seam:一个抽象存储接口、一个本地文件系统实现,以及一个使用该实现的工具结果策略。全部都是**产品** 包。
工具输出 spill 的能 seam:一个抽象存储接口、一个本地文件系统实现,以及一个使用该实现的工具结果策略。全部均为**产品**包package
| 包 | 职责 | ctx 键 |
|---|---|---|
| `spill/` | 抽象 spill 存储 seam`saveText`:持久化过大的工具文本,返回定位信息与取回指引) | `ctx.spillStore` |
| `spill-local/` | 本地文件系统后端:使用防路径遍历名称的私有会话级文件 | (注册到 `ctx.spillStore` |
| `spill-local/` | 本地文件系统后端:名称可防止路径遍历的私有会话级文件 | (注册到 `ctx.spillStore` |
| `spill-policy/` | `tools/post-execute` 策略:将过大的纯文本结果替换为预览和 spill 定位信息 | (无服务接口) |
接口位于 `spill/spill/`。这种拆分方式与 bash/fs 相同:seam 只负责存储,`spill-local` 负责文件系统机制,`spill-policy` 负责决定何时 spill 以及面向模型的通知。预览机制位于 [`util/retention`](../util/README.md);策略只组合两者,不会让任何一方承担对方的职责。
设计原理见[工具输出 spill Agent Note](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),其中说明了为什么最终结果 spill 要与工具自行提前 spillbash 流、subagent rollout)分离,以及为什么创建操作应由运行时 spill seam 而非面向模型的 `write` 工具承担。
设计原理见[工具输出 spill Agent Noteagent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),其中说明了为什么最终结果 spill 要与工具自行提前 spillbash 流、subagent rollout)分离,以及为什么创建操作应由运行时 spill seam 而非面向模型的 `write` 工具承担。
+9 -9
View File
@@ -2,33 +2,33 @@
[English](README.md) | 中文
[`@deepseek-ai/dsh-spill`](../spill) 存储 seam 的**本地文件系统** 实现。它注册为 `ctx.spillStore`,将工具过大文本持久化到私有的会话级文件;定位信息是文件路径,取回指引会告诉模型对该路径使用 `read``grep`
[`@deepseek-ai/dsh-spill`](../spill) 存储 seam 的**本地文件系统**实现。它注册为 `ctx.spillStore`,将工具产生的过大文本持久化到私有的会话级文件;定位信息是文件路径,取回指引会告诉模型对该路径使用 `read``grep`
## 存储布局
文件存放在 `<root>/session-<hash>/<random>-<safeName>`
- **`root`**:使用配置中的 `root`(解析为绝对路径);如果省略,则在操作系统临时目录下延迟创建每进程私有(0700)目录。可预测且全球可读的根目录会让其他本地用户读取 spill 工具输出,或在其中预置符号链接。
- **`session-<hash>`** `sha256(sessionId)` 前缀,用于将一会话的 spill 文件归,以便未来的清理操作可按会话删除。
- **`<random>-<safeName>`**:不可预测的十六进制前缀(防止在共享根目录中预置符号链接),加上经过清理的调用方 `suggestedName`,使其成为单个安全路径段(防路径遍历;与 JSONL 持久化后端的 `encodeSegment` 一致)。写入操作为排他且仅所有者可读写`open(path, 'wx', 0o600)`):如果路径已经存在,无论是否为符号链接,操作都会失败,因此预置的目标无法重定向写入。
- **`root`**:使用配置中的 `root`(解析为绝对路径);如果省略,则在操作系统临时目录下延迟创建每进程私有(0700)目录。可预测且任何用户均可读的根目录会让其他本地用户读取 spill 工具输出,或在其中预置符号链接。
- **`session-<hash>`**截短的 `sha256(sessionId)` 前缀,用于将一会话的 spill 文件归在一起,以便未来的清理操作可按会话删除。
- **`<random>-<safeName>`**:不可预测的十六进制前缀(防止在共享根目录中预置符号链接),加上经过清理的调用方 `suggestedName`,使其成为单个安全路径段(防路径遍历;与 JSONL 持久化后端的 `encodeSegment` 一致)。写入操作采用排他方式,且权限仅限所有者`open(path, 'wx', 0o600)`):如果路径已经存在,无论是否为符号链接,操作都会失败,因此预置的目标无法重定向写入。
## 配置
| 键 | 默认值 | 含义 |
|---|---|---|
| `root` | 私有 0700 临时目录 | spill 文件的根目录。进行设置可将它们保存在已知位置。 |
| `root` | 私有 0700 临时目录 | spill 文件的根目录。设置可将这些文件保存在已知位置。 |
`saveText` 在发生真实存储故障(权限、ENOSPC)时拒绝;spill 策略会将该拒绝作为尽力而为的失败,并保留内联结果。词汇见 seam README,设计见[工具输出 spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md)。
`saveText` 在发生真实存储故障(权限、ENOSPC)时返回拒绝;spill 策略会按尽力而为原则处理该拒绝,并保留内联结果。词汇见 seam README,设计见[工具输出 spill Agent Noteagent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md)。
## 模型体验
通过渲染本地路径以及 `read`/`grep` 取回指引的 spill 消费方间接影响模型。
#### KV 缓存影响
#### KV Cache 影响
不直接导致失效;指定的消费方负责其引起的任何请求前缀变更
直接导致 KV Cache 失效;请求前缀变更由上述消费方负责
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **本地 spill 文件会持续存在,直到外部清理为止**:该后端不提供会话生命周期删除或按时间保留的策略,因为已持久化、已恢复和 fork 后的会话可能仍在引用某个路径。
- **定位信息需要与其位于同一文件系统的消费方**:远程或虚拟部署需要另一个 `SpillStore` 后端,其定位信息和取回指引在该环境中有明确含义。
+13 -13
View File
@@ -4,18 +4,18 @@
**工具结果 spill 策略**:一个 `tools/post-execute` 转换器,用于防止过大的纯文本工具结果进入模型上下文。当最终结果超过 `maxInlineBytes` 时,它会通过 [`ctx.spillStore`](../spill) 保存完整文本,并将面向模型的结果替换为有界的首尾预览、后端定位信息与取回指引。
该插件**不注册任何服务**,也不负责存储或预览机制:预览由 [`@deepseek-ai/dsh-retention`](../../util/retention) `TextRetainer`)负责,存储由 `ctx.spillStore` 负责。它只决定何时 spill,并组合通知。
该插件**不注册任何服务**,也不负责存储或预览机制:预览由 [`@deepseek-ai/dsh-retention`](../../util/retention)`TextRetainer`)负责,存储由 `ctx.spillStore` 负责。它只决定何时 spill,并组合通知。
## 配置
| 键 | 默认值 | 含义 |
|---|---|---|
| `maxInlineBytes` | *(省略)* | 面向模型的纯文本结果上下文上限,以 UTF-8 字节数计(在加载时验证为非负整数)。**省略时完全禁用该策略**(插件不注册任何内容)。设置后,较大的结果会被 spill,并替换为从同一预算派生的预览(首尾拆分)。 |
| `maxInlineBytes` | *(省略)* | 面向模型的纯文本结果上下文上限,以 UTF-8 字节数计(在加载时验证为非负整数)。**省略时完全禁用该策略**(插件不注册任何内容)。设置后,超过该上限的结果会被 spill,并替换为从同一预算派生的预览(首尾拆分)。 |
## 行为
1. 允许工具运行(通过 `next()` 委托,因此可以限制任何下游钩子接受的内容)。
2. 跳过嵌套执行(存在 `exec.parent`——其持久副本由下方的 dispatch-log 分支设界)、已接受的值替换(注册表必须重新验证并渲染它们)、`read`(避免 `read → spill → read again` 循环)以及任何非 `accept``block` 的纠正反馈会原样通过)。
1. 允许工具运行(通过 `next()` 委托,因此可以限制任何下游钩子接受的结果)。
2. 跳过嵌套执行(存在 `exec.parent`——其持久副本由下方的 dispatch-log 分支设界)、已接受的值替换(注册表必须重新验证并重新渲染它们)、`read`(避免 `read → spill → read again` 循环)以及任何非 `accept``block` 的纠正反馈会原样通过)。
3. 仅在已接受的内容为**纯文本**(全部都是 `text` 块)时才将其展平;包含任何非文本块的结果都保持不变。
4. 如果 UTF-8 大小为 `≤ maxInlineBytes`,则保持不变。
5. 否则,保存完整文本,并将结果替换为预览和以下通知。系统会调整大小,使整个替换内容(预览、空行和通知)不超过 `maxInlineBytes`:先从预算中保留通知所需字节,再缩小预览以适配剩余空间,因此面向模型的结果绝不会超过上限:
@@ -28,13 +28,13 @@
当通知本身已占满预算时(上限极小或定位信息很长),预览为空,只返回通知。如果仅通知的替换内容仍会超过 `maxInlineBytes`,策略将保留内联结果;它绝不会发出超过上限的替换内容(而且上限内的替换内容总比原结果更小,因此这也意味着 spill 绝不会增加字节数)。
**尽力而为**:没有会话 owner、没有 `ctx.spillStore` 后端,或 `saveText` 拒绝 ⇒ 策略记录警告并返回原始结果。spill 失败绝不会将成功调用变为 `isError`,也不会隐藏内联结果。成功替换时只会更改 `content`;规范程序值保持不变。
**尽力而为**:没有会话所有者、没有 `ctx.spillStore` 后端,或 `saveText` 返回拒绝 ⇒ 策略记录警告并返回原始结果。spill 失败绝不会将成功调用变为 `isError`,也不会隐藏内联结果。成功替换时只会更改 `content`;规范程序值保持不变。
**dispatch-log 分支:**注册在 `tools/code-dispatch-log` 上的第二个监听器,把同一套上限、替换流水线与尽力而为的回退应用到每个 `run_code` 子调用结果的持久副本上(工件标签为 `dispatch`,按子调用 id 归档)。程序取得的值不受影响——它早已完整跨过 worker 边界;`read` 子调用同样设界:日志副本不是模型上下文,因此不会发生 read-again 循环,而 `read` 恰恰是最容易产生巨型日志的工具([原理](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md))。
**dispatch-log 分支:**注册在 `tools/code-dispatch-log` 上的第二个监听器,把同一套上限、替换流水线与尽力而为的回退应用到每个 `run_code` 子调用结果的持久副本上(产物标签为 `dispatch`,按子调用 id 归档)。程序的值不受影响,因为它早已完整跨过 worker 边界;`read` 子调用同样设界:日志副本不是模型上下文,因此不会发生 read-again 循环,而 `read` 恰恰是最容易产生巨型日志的工具([原理](../../../.agents/notes/implemented/feature/2026-07-26-code-dispatch-log-spill.md))。
## 范围
该策略只能看到最终格式化接口结果,看不到工具的内部资源或规范值。如果提供方已经截断内容(例如 `web-fetch-local.maxBodyChars`),spill 产物保存的是工具返回的完整格式化结果,而非完整原始源。提供方/资源上限仍必须存在,并且与该策略分离。`glob`/`grep` 负责对项级接口结果执行 spill,因为渲染前仍然存在完整的已获取值;bash 流负责在获取时 spill。通用策略预先注册自己的 waterfall 监听器,然后再委托,因此无论插件加载顺序如何,普通工具拥有的异步投影都会在通用字节限制之前完成。详见[工具输出 spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md)。
该策略只能看到最终格式化的呈现结果,看不到工具的内部资源或规范值。如果提供方已经截断内容(例如 `web-fetch-local.maxBodyChars`),spill 产物保存的是工具返回的完整格式化结果,而非完整原始源。提供方资源上限仍然是必需的,并且与该策略相互独立。`glob`/`grep` 负责对项级呈现结果执行 spill,因为渲染前仍然存在完整的已获取值;bash 流负责在获取时 spill。通用策略预先注册自己的 waterfall(瀑布式事件)监听器,然后再委托,因此无论插件加载顺序如何,普通工具自身的异步投影都会在通用字节限制之前完成。详见[工具输出 spill Agent Noteagent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md)。
## 模型体验
@@ -42,17 +42,17 @@
#### 模型所见
大小不超过 `maxInlineBytes` 的结果、嵌套结果、`read` 结果、阻止的决和包含非文本块的结果都保持不变。过大的纯文本接口结果会变为有界的首尾预览,后面附加 `(Omitted <bytes> bytes. Full formatted result stored at: <locator>. <retrievalHint>)`;存储或 owner 失败时,原始结果仍然可见。
大小不超过 `maxInlineBytes` 的结果、嵌套结果、`read` 结果、阻止的决和包含非文本块的结果都保持不变。过大的纯文本呈现结果会变为有界的首尾预览,后面附加 `(Omitted <bytes> bytes. Full formatted result stored at: <locator>. <retrievalHint>)`;存储失败或没有会话所有者时,原始结果仍然可见。
#### Token 影响
成功替换后的内容最多为 `maxInlineBytes` 个 UTF-8 字节,并会保留在历史中直到压缩;完整 spill 文本不会重新发送给模型。
成功替换后的内容最多为 `maxInlineBytes` 个 UTF-8 字节,并会保留在历史中直到压缩compaction;完整 spill 文本不会重新发送给模型。
#### KV 缓存影响
#### KV Cache 影响
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV 缓存条目失效。
仅追加;新可见内容位于可重用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **只能对最终纯文本结果执行 spill**:混合内容结果、阻止反馈和 `read` 会原样通过;无法在此恢复先前已经发生的提供方截断或工具自有保留
- **只能对最终纯文本结果执行 spill**:混合内容结果、阻止反馈和 `read` 会原样通过;无法在此恢复先前已经发生的提供方截断或工具自身执行的保留处理
- **通知无法容纳时,该次调用的替换功能会禁用**:当上限极小或定位信息很长时,后端已经保存了无引用的 spill,但过大的原始结果仍会保留在内联位置。
+8 -8
View File
@@ -4,11 +4,11 @@
**spill 存储 seam**:抽象的 `SpillStore` 服务(`ctx.spillStore`)定义 spill 后端做什么,即持久化某个工具过大的文本,并返回面向模型的定位信息与取回指引;它不规定如何实现。
该包是 spill 能的三个组成部分之一。拆分后,各项关注点可独立演进和替换:
该包package是 spill 能的三个组成部分之一。拆分后,各项关注点可独立演进和替换:
| 包 | 职责 |
|---|---|
| `@deepseek-ai/dsh-spill` (本包) | 接口:抽象服务与词汇类型 |
| `@deepseek-ai/dsh-spill`(本包) | 接口:抽象服务与词汇类型 |
| `@deepseek-ai/dsh-spill-local` | 实现:位于宿主文件系统中的私有会话级文件 |
| `@deepseek-ai/dsh-spill-policy` | 对过大最终结果执行 spill 的工具结果策略 |
@@ -18,25 +18,25 @@
| 成员 | 语义 |
|---|---|
| `saveText(input)` | 逐字保存 `input.content`解析并返回 `SpillRef`(不透明定位信息、写入的精确字节数和取回指引)。如果出现真实存储故障(权限、ENOSPC、后端不可用),则**拒绝**;由调用方决定如何降级。 |
| `saveText(input)` | 逐字保存 `input.content`成功时返回 `SpillRef`(不透明定位信息、写入的精确字节数和取回指引)。**如果出现真实存储故障,则返回拒绝**(权限、ENOSPC、后端不可用);由调用方决定如何降级。 |
存储操作以请求的 `owner` 会话作为保存时命名空间进行分组;后端自行选择私有表示,并可以从调用方的 `suggestedName` 派生名称,但绝不能将其当作可信路径。该 seam 只负责存储:不提供保留策略(由 [`@deepseek-ai/dsh-retention`](../../util/retention) 负责),不替换工具结果(由 `@deepseek-ai/dsh-spill-policy` 负责),也不提供取回/搜索 API(后端的 `retrievalHint` 会告诉模型如何使用定位信息)。
## 词汇
`SaveTextSpill` owner、source、suggestedName、content)是请求;`SpillRef` locator、bytes、retrievalHint)是结果。`SpillLocator` 已经[品牌](../../util/brand),并以不透明字符串的形式呈现给模型;对 `dsh-spill-local` 而言它是本地路径,但未来的后端可以返回 URI、键或命令 token,无需修改策略/工具消费方。`SpillOwner.sessionId` 是保存时存储命名空间:fork 后的会话会从种子日志继承现有定位信息,无需复制文件或更改其归属;fork 后新产生的 spill 使用子会话 id。`SpillSource` toolName、callId、label)是供后端命名和检查使用的描述性来源信息,而非访问控制信息。完整契约见 `src/types.ts`
`SaveTextSpill`owner、source、suggestedName、content)是请求;`SpillRef`locator、bytes、retrievalHint)是结果。`SpillLocator` [品牌类型](../../util/brand)的值,并以不透明字符串的形式呈现给模型;对 `dsh-spill-local` 而言它是本地路径,但未来的后端可以返回 URI、键或命令 token,无需修改策略工具消费方。`SpillOwner.sessionId` 是保存时存储命名空间:fork 后的会话会从种子日志继承现有定位信息,无需复制文件或更改其归属;fork 后新产生的 spill 使用子会话 id。`SpillSource`toolName、callId、label)是供后端命名和检查使用的描述性来源信息,而非访问控制信息。完整契约见 `src/types.ts`
设计原理见[工具输出 spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),其中说明了为什么创建操作应由运行时 spill seam 而非面向模型的 `write` 工具承担。
设计原理见[工具输出 spill Agent Noteagent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md),其中说明了为什么创建操作应由运行时 spill seam 而非面向模型的 `write` 工具承担。
## 模型体验
通过渲染后端定位信息和取回指引的 spill 消费方间接影响模型。
#### KV 缓存影响
#### KV Cache 影响
不直接导致失效;指定的消费方负责其引起的任何请求前缀变更
直接导致 KV Cache 失效;请求前缀变更由上述消费方负责
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **该 seam 没有取回或删除 API**:消费方只能渲染后端的定位信息与指引;生命周期和访问语义仍由后端自行决定。
- **存储不等于访问控制**`SpillOwner` 会区分写入命名空间,但不会授予定位信息的读取权限;每个后端和取回消费方都必须自行强制执行访问边界。
+4 -4
View File
@@ -2,13 +2,13 @@
[English](README.md) | 中文
存储家族持久化会话事件日志之外的一切数据:命名后端与类型化数据形式在一个中心相接。设计记录:[领域 KV 存储 Agent Note](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
存储家族持久化会话事件日志之外的一切数据:命名后端与类型化数据形式在一个中心相接。设计记录:[领域 KV 存储 Agent Noteagent 决策记录)](../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
| 包 | 职责 | ctx key |
| 包package | 职责 | ctx key |
|---|---|---|
| `storage/` | 中心:命名后端注册表 + 可合并扩展的数据形式挂载、后端 facet 词汇、共享一致性测试套件 | `ctx.storage` |
| `storage/` | 中心:命名后端注册表 + 可通过合并扩展的数据形式挂载、后端分面词汇、共享一致性测试套件 | `ctx.storage` |
| `storage-json/` | JSON 后端:每个单元一个人类可读文件,以原子方式重写整个文件 | 注册后端 `json` |
| `storage-sqlite/` | SQLite 后端:一个数据库承载所有已路由单元,每行一个文档 | 注册后端 `sqlite` |
| `domain/` | 领域数据形式:经 zod 验证的记录、逐领域写入链、`domain/changed` 事件、按配置路由后端 | `ctx.storageDomain` + `ctx.storage.domain` |
每个后端拥有一种介质,并公开数据形状 **facet**(目前为 `kv`;为未来的会话后端迁移预留 append-log facet)。每个后端插件都会在注册后发布内部生命周期服务;领域插件在公开自身服务前注入每个已配置的后端 key,因此配置树中的行序不携带启动语义。消费方绝不直接接触后端,而是注入 `storageDomain` 并通过它打开已声明的领域。
每个后端拥有一种介质,并公开数据形状**分面**(目前为 `kv`;为未来的会话后端迁移预留追加日志分面)。每个后端插件都会在注册后发布内部生命周期服务;领域插件在公开自身服务前注入每个已配置的后端 key,因此配置树中的条目顺序不影响启动顺序。消费方绝不直接接触后端,而是注入 `storageDomain` 并通过它打开已声明的领域。
+7 -7
View File
@@ -2,15 +2,15 @@
[English](README.md) | 中文
DeepSeek Harness 存储中心的领域数据形式:在每个已配置后端注册后,公开可注入的 `ctx.storageDomain` 服务及对应的 `ctx.storage.domain` 投影。一个领域通过 `defineDomain`zod 记录 schema、从 `z.infer` 派生的类型)声明一次,通过 `DomainFacility.open` 打开,并由具有最终决定权的内存状态提供服务:读取同步执行;写入在一条逐领域链上串行化,先在已路由后端达到持久状态,再更新内存并发出 `domain/changed`。打开消费方拥有 handle 的生命周期,并通过 `Domain.close()` 释放它(幂等;通常作为其自身的 `ctx.effect` disposer);插件卸载时,facility 会关闭仍处于打开状态的领域。
DeepSeek Harness 存储中心的领域数据形式:在所有已配置后端注册后,公开可注入的 `ctx.storageDomain` 服务及对应的 `ctx.storage.domain` 投影。一个领域通过 `defineDomain`zod 记录 schema、从 `z.infer` 派生的类型)声明一次,通过 `DomainFacility.open` 打开,并由具有最终决定权的内存状态提供服务:读取同步执行;写入在每个领域各自的一条链上串行化,先在已路由后端达到持久状态,再更新内存并发出 `domain/changed`。打开领域的消费方负责管理句柄的生命周期,并通过 `Domain.close()` 释放它(幂等;通常作为其自身的 `ctx.effect` 资源释放函数);插件卸载时,该设施会关闭仍处于打开状态的领域。
设计原理、打开语义和存储/领域分层见 [Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
设计原理、打开语义和存储/领域分层见 [Agent Noteagent 决策记录)](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
## 配置
| key | 含义 |
| --- | --- |
| `backend` | 每个领域的默认后端名称(必填;不存在普遍正确的介质)。 |
| `backend` | 每个领域的默认后端名称(必填;不存在普遍适用的存储介质)。 |
| `routes` | 逐领域覆盖:领域名称 → 后端名称。 |
## 模型体验
@@ -19,7 +19,7 @@ DeepSeek Harness 存储中心的领域数据形式:在每个已配置后端注
#### 模型看到的内容
无。该包不注册工具、不注入提示词,也不追加会话事件;它在 `ctx.storageDomain` 后面存储非会话数据(Workspace 记录、未来的会话伴随数据),只发出进程内 `domain/changed` 事件。只有消费方包通过自身已记录的表层渲染该事件时,它才会到达模型。
无。该包package不注册工具、不注入提示词,也不追加会话事件;它在 `ctx.storageDomain` 后面存储非会话数据(工作区记录、未来的会话伴随数据),只发出进程内 `domain/changed` 事件。只有消费方包通过自身有文档说明的接口呈现该事件时,它才会到达模型。
#### Token 影响
@@ -27,9 +27,9 @@ DeepSeek Harness 存储中心的领域数据形式:在每个已配置后端注
#### KV Cache 影响
相互独立:领域读写绝不触碰请求前缀,因此这里没有任何内容能使提供方 cache 复用失效。
相互独立:领域读写绝不触碰请求前缀,因此这里没有任何内容能使提供方缓存复用失效。
## 已知限制与暂缓事项
- **变更只在单进程内可见**`domain/changed` 是进程内事件;在 Agent Note 暂缓的跨进程 revision 模式落地前,第二个主机进程或重新连接的 GUI 无法观察变更。
- **没有跨表事务、二级索引或多 segment key**:每次写入只触碰一条记录;这些扩展的 trigger 和返工点列在 Agent Note 的暂缓工作清单中。
- **变更只在单进程内可见**`domain/changed` 是进程内事件;在 Agent Note 暂缓的跨进程修订模式落地前,第二个主机进程或重新连接的 GUI 无法观察变更。
- **没有跨表事务、二级索引或多段键**:每次写入只触碰一条记录;这些扩展的触发点和返工点列在 Agent Note 的暂缓工作清单中。
+7 -7
View File
@@ -2,13 +2,13 @@
[English](README.md) | 中文
[存储中心](../storage/README.md)的 JSON 后端:配置根目录下每个单元使用一个人类可读的 `<unit>.json` 文件,注册为后端 `json`。设计见[领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
[存储中心](../storage/README.md)的 JSON 后端:配置根目录下每个单元使用一个人类可读的 `<unit>.json` 文件,注册为后端 `json`。设计见[领域 KV 存储 Agent Noteagent 决策记录)](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
## 模型
- 内存中的单元状态具有最终决定权;每个写入原语都会通过临时写入 + fsync + 原子 `rename()` 替换重新发布整个文件。单元文件始终是完整的当前状态:可读性是该后端存在的理由,规模问题则属于 SQLite 后端。
- 缺失文件会作为空单元打开,并在第一次写入时物化。外或无法解析的文件以 `malformed-medium` 拒绝;已存版本与 descriptor 不同时以 `version-mismatch` 拒绝(预发布立场,不迁移)。
- 跨调用的写入顺序属于调用方(领域层的写入链);每个单独调用具备原子性,并在 resolve 后持久
- 内存中的单元状态具有最终决定权;每个写入原语都会通过临时文件写入 + fsync + 原子 `rename()` 替换重新发布整个文件。单元文件始终是完整的当前状态:可读性是该后端存在的理由,规模问题则属于 SQLite 后端。
- 缺失文件会作为空单元打开,并在第一次写入时物化。外或无法解析的文件以 `malformed-medium` 拒绝;已存版本与描述符不同时以 `version-mismatch` 拒绝(预发布立场,不迁移)。
- 跨调用的写入顺序属于调用方(领域层的写入链);每调用具备原子性,并在完成时已达到持久状态
## 配置
@@ -22,7 +22,7 @@
#### 模型看到的内容
无。该后端不贡献提示词、工具或 schema;它在 `ctx.storage` 后面持久化非会话领域数据,只供主侧消费方使用。
无。该后端不贡献提示词、工具或 schema;它在 `ctx.storage` 后面持久化非会话领域数据,只供宿主侧消费方使用。
#### Token 影响
@@ -34,5 +34,5 @@
## 已知限制与暂缓事项
- Windows 持久性依赖 libuv 的 `rename()`使用替换的 `MoveFileExW`),没有显式 write-through 标志;append-log facet 落地时,计划把会话日志后端更严格的 Win32 write-through 发布辅助函数下移到此处(见 Agent Note 的迁移章节)。
- 没有跨进程写锁:两个进程写入同一根目录时,可能交错执行整文件替换(最后写入者胜出)。当前消费方采用单主进程部署;多进程方案按 Agent Note 的范围外表暂缓。
- Windows 持久性依赖 libuv 的 `rename()`调用 `MoveFileExW` 并启用替换),没有显式 write-through 标志;追加日志分面 落地时,计划把会话日志后端更严格的 Win32 write-through 发布辅助函数下移到此处(见 Agent Note 的迁移章节)。
- 没有跨进程写锁:两个进程写入同一根目录时,可能交错执行整文件替换(最后写入者胜出)。当前消费方采用单一宿主进程部署;多进程方案按 Agent Note 的范围外事项表暂缓。
+6 -6
View File
@@ -2,13 +2,13 @@
[English](README.md) | 中文
[存储中心](../storage/README.md)的 SQLite 后端:注册为后端 `sqlite`,通过一个数据库文件提供 `kv` facet;该文件使用 `node:sqlite`(也可以是 `:memory:`)。设计与取舍见[领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
[存储中心](../storage/README.md)的 SQLite 后端:注册为后端 `sqlite`,通过一个数据库文件提供 `kv` facet;该文件使用 `node:sqlite`(也可以是 `:memory:`)。设计与取舍见[领域 KV 存储 Agent Noteagent 决策记录)](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
## 存储模型
每行一个文档:每个单元表都会成为一个物理 STRICT 表 `"u_<unit>_<table>" (key TEXT PRIMARY KEY, value TEXT)`,其中 `value` 是记录的 JSON 文本,因此一个 key 只更新一行(高频变更领域路由到这里而非 JSON 后端的原因)。单元标识位于两个元数据表中:`units` 在单元首次打开时标记其格式版本,descriptor 不同时以 `version-mismatch` 拒绝;`unit_globals` 保存每个单元的全局 singleton 行。物理布局版本位于 `PRAGMA user_version`;其他任何标记值都会被拒绝(未发布格式,不迁移)。单元名和表名在进入 DDL 之前依据中心的 `UNIT_NAME_RE` 接受验证,因此不会把外部输入插值到 SQL 标识符中。
每行一个文档:每个单元表都会成为一个物理 STRICT 表 `"u_<unit>_<table>" (key TEXT PRIMARY KEY, value TEXT)`,其中 `value` 是记录的 JSON 文本,因此一个 key 只更新一行(高频变更领域路由到这里而非 JSON 后端的原因)。单元标识位于两个元数据表中:`units` 在单元首次打开时标记其格式版本,描述符不同时以 `version-mismatch` 拒绝;`unit_globals` 保存每个单元的全局单例行。物理布局版本位于 `PRAGMA user_version`;其他任何标记值都会被拒绝(未发布格式,不迁移)。单元名和表名在进入 DDL 之前依据中心的 `UNIT_NAME_RE` 进行验证,因此不会把外部输入插值到 SQL 标识符中。
每个写入原语都是一条 prepared statement:SQLite 的逐语句原子性无需显式事务即可满足 KV 契约,写入顺序仍由调用方负责(领域层写入链)。缺失目录和数据库文件会以仅 owner 可访问的权限创建(`0o700``0o600`),与 session-persistence SQLite 后端一致;在计划的介质层提取完成前,该包逐字复用了后者的打开顺序。
每个写入原语都是一条预处理语句:SQLite 的逐语句原子性无需显式事务即可满足 KV 契约,写入顺序仍由调用方负责(领域层写入链)。缺失目录和数据库文件会以仅所有者可访问的权限创建(`0o700``0o600`),与 session-persistence SQLite 后端一致;在计划的介质层提取完成前,该包package逐字复用了后者的打开顺序。
## 配置(schemastery
@@ -25,7 +25,7 @@ interface Config {
#### 模型看到的内容
无。该后端不贡献提示词、工具或 schema;它在 `ctx.storage` 后面持久化非会话领域数据(Workspace 记录、未来的会话伴随元数据),只供主机侧消费方使用。
无。该后端不贡献提示词、工具或 schema;它在 `ctx.storage` 后面持久化非会话领域数据(工作区记录、未来的会话伴随元数据),只供主机侧消费方使用。
#### Token 影响
@@ -37,7 +37,7 @@ interface Config {
## 已知限制与暂缓事项
- **`DatabaseSync` 是同步的**:每次写入会在其持续时间内阻塞事件循环(一条语句);在领域数据规模下可以接受。
- **没有 busy-wait 或重试策略**:另一个连接持有写事务时,该操作会立即被拒绝;多进程写入保护列在设计的未来工作清单中。
- **`DatabaseSync` 是同步的**:每次写入会在单条语句执行期间阻塞事件循环;在领域数据规模下可以接受。
- **没有忙等待或重试策略**:另一个连接持有写事务时,该操作会立即被拒绝;多进程写入保护列在设计文档的未来工作清单中。
- **只打开当前的 `STORAGE_SQLITE_SCHEMA_VERSION`**:其他任何已标记版本都会被拒绝而不是迁移(预发布立场)。
- **`openDatabase` 重复了 session-persistence SQLite 打开顺序**:提取到共享介质层的工作暂缓至计划的会话后端迁移(见 Agent Note 的复用审计)。
+9 -9
View File
@@ -2,17 +2,17 @@
[English](README.md) | 中文
非会话数据的存储中心(`ctx.storage`):命名后端注册表加已挂载的数据形式 facility。中心自身不执行 IO:后端拥有介质,数据形式拥有语义。设计与取舍见[领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
非会话数据的存储中心(`ctx.storage`):命名后端注册表加已挂载的数据形式设施。中心自身不执行 IO:后端拥有介质,数据形式拥有语义。设计与取舍见[领域 KV 存储 Agent Noteagent 决策记录)](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)。
## 形状
## 结构
- `ctx.storage.backend`:名称 → 后端表。多个后端并排保持挂载(`json``sqlite`);为消费方提供服务的后端由该消费方自身的配置决定(领域层的路由表),绝非中心的全局选择。`register()` 返回 disposer;重复名称和未知 lookup 会高声失败
- `ctx.storage.mount(form, facility)``ctx.storage.form(form)`:数据形式挂载。`StorageForms` 可合并扩展;领域层合并 `domain`,并通过 `ctx.storage.domain` 访问。
- 后端拥有一种介质(文件树根、数据库文件),并公开可选的数据形状 **facet**:目前为 `kv`;为未来的会话后端迁移预留 append-log facet`src/backend.ts` 是规范契约文本;`tests/contract.ts` 导出每个后端都会运行的共享一致性测试套件。
- `ctx.storage.backend`:名称 → 后端表。多个后端并排保持挂载(`json``sqlite`);为消费方提供服务的后端由该消费方自身的配置决定(领域层的路由表),绝非中心的全局选择。`register()` 返回资源释放函数;注册重复名称或查找未知名称时都会明确报错
- `ctx.storage.mount(form, facility)``ctx.storage.form(form)`:数据形式挂载。`StorageForms`通过合并扩展;领域层合并 `domain`,并通过 `ctx.storage.domain` 访问。
- 后端拥有一种介质(文件树根、数据库文件),并公开可选的数据形状**分面**:目前为 `kv`;为未来的会话后端迁移预留追加日志分面`src/backend.ts` 是规范契约文本;`tests/contract.ts` 导出每个后端都会运行的共享一致性测试套件。
## 该分组中的包
| 包 | 职责 |
| 包package | 职责 |
| --- | --- |
| `dsh-storage` | 中心服务 + 后端词汇 + 共享一致性测试套件 |
| `dsh-storage-json` | JSON 后端:每个单元一个人类可读文件,以原子方式重写整个文件 |
@@ -29,13 +29,13 @@
#### Token 影响
每次请求的直接 token 为零
每次请求都不会直接增加 token。
#### KV Cache 影响
与实时请求相互独立:中心绝不触碰请求前缀,因此无法使提供方 cache 复用失效。
与实时请求相互独立:中心绝不触碰请求前缀,因此无法使提供方缓存复用失效。
## 已知限制与暂缓事项
- **`kv` 是唯一的数据形状**:设计记录为未来的会话后端迁移预留了 append-log facet,但尚未定义;后端目前恰好只有一个 facet 需要实现。
- **形式惰性解析**:在领域插件挂载前读取 `ctx.storage.domain` 会抛出 `form-not-mounted`;组装会按相应顺序排列插件(错误配置会高声失败,而不是静默等待)。
- **数据形式按需解析**:在领域插件挂载前读取 `ctx.storage.domain` 会抛出 `form-not-mounted`;组装会按相应顺序排列插件(错误配置会明确报错,而不是静默推迟处理)。
+7 -7
View File
@@ -1,19 +1,19 @@
# subagent/subagent 能力族
# subagent/subagent 能力
[English](README.md) | 中文
subagent seam 允许 agent(智能体)把工作委派给子 agent。与 [bash](../bash/README.md) 和 [llm](../llm/README.md) 能力族一样,这也是一种能力 seam(见[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)),但有一个关键差异:**多个提供方实现在同一上下文中共存,并按名称注册**,而不是采用 bash 的单实现形态。该注册表仿照 LLM大语言模型)适配器注册表。
subagent(子 agentseam 允许 agent(智能体)把工作委派给子 agent。与 [bash](../bash/README.md) 和 [llm](../llm/README.md) 能力族一样,这也是一种能力 seam(见[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)),但有一个关键差异:**多个提供方实现在同一上下文中共存,并按名称注册**,而不是采用 bash 的单实现形态。该注册表仿照大语言模型LLM)适配器注册表。
| 包 | 角色 | ctx 键 |
| 包package | 角色 | ctx 键 |
|---|---|---|
| `subagent/` | 抽象 subagent seam:具名提供方注册表与词汇 | `ctx.subagents` |
| `subagent-inprocess/` | 共享进程内运行驱动器(不提供提供方;每次运行使用一个清理 effect) | 无 |
| `subagent-inprocess/` | 共享进程内运行驱动器(不提供方;每次运行使用一个清理 effect) | 无 |
| `subagent-spawn/` | 进程内后端:全新的子 agent | (注册到 `ctx.subagents` |
| `subagent-fork/` | 进程内后端:以父 agent 已完成轮次的前缀作为初始内容的子 agent | (注册到 `ctx.subagents` |
| `subagent-acp/` | 进程外后端:在派生子进程中运行并通过 ACPAgent Client Protocol)驱动的子 agent | (注册到 `ctx.subagents` |
| `subagent-dsh-sdk/` | 进程外后端:在派生子进程中运行的子 harness 运行时,经 TypeScript SDK 客户端走 stdio JSON-RPC 驱动 | (注册到 `ctx.subagents` |
| `subagent-acp/` | 进程外后端:在 spawn 的子进程中运行并通过 ACPAgent Client Protocol)驱动的子 agent | (注册到 `ctx.subagents` |
| `subagent-dsh-sdk/` | 进程外后端:在 spawn 的子进程中运行的子 harness 运行时,经 TypeScript SDK 客户端走 stdio JSON-RPC 驱动 | (注册到 `ctx.subagents` |
| `tool-subagent/` | 面向模型的 `subagent` 委派工具,基于 `ctx.subagents` | (注册到 `ctx.tools` |
接口位于 `subagent/subagent/`。进程内 `subagent-spawn` / `subagent-fork` 后端共享 `subagent-inprocess` 驱动器(一个自身不提供提供方的库:两者都依赖它,彼此不依赖),进程外 `subagent-acp` / `subagent-dsh-sdk` 后端则经由 [`subprocess/`](../subprocess/README.md) seam spawn 其子进程(共享的凭据清除、以进程树为范围的拆卸、dispose(资源释放)阶梯)。测试只用包内 fixture(测试前置数据)替换子 agent 边界。
接口位于 `subagent/subagent/`。进程内 `subagent-spawn` / `subagent-fork` 后端共享 `subagent-inprocess` 驱动器(一个自身不提供方的库:两者都依赖它,彼此不依赖),进程外 `subagent-acp` / `subagent-dsh-sdk` 后端则经由 [`subprocess/`](../subprocess/README.md) seam spawn 其子进程(共享的凭据清除、以进程树为范围的拆卸、dispose(资源释放)阶梯)。测试只用包内 fixture(测试前置数据)替换子 agent 边界。
提案与设计理由见 [.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)。
+10 -10
View File
@@ -6,15 +6,15 @@ ACPAgent Client Protocol)提供方会在全新的子进程中运行每个 s
## 启动与所有权
`start(request)` 先解析子 agent 的工作目录,再依次执行 `spawn` → ACP `initialize``newSession`,然后才兑现。因此,兑现表示远程会话已就绪,所有权也已转移给调用方。派生、初始化、新建会话或发布前取消失败时,只有在子进程已回收后才会拒绝;工作目录解析失败则会在派生任何内容拒绝。
`start(request)` 先解析子 agent 的工作目录,再依次执行 `spawn` → ACP `initialize``newSession`,然后才兑现。因此,兑现表示远程会话已就绪,所有权也已转移给调用方。spawn、初始化、新建会话或发布前取消失败时,只有在子进程已回收后才会拒绝;工作目录解析失败则会在尚未 spawn 任何内容拒绝。
工作目录优先使用已配置的 `cwd` 覆盖值,否则使用执行委派的父会话 cwd,绝不使用服务器进程自身的 cwd,因为同一个服务器进程会服务来自多个工作区的会话。从父级取得的值必须是绝对路径,指向 harness 可以进入的目录(具备搜索权限,这是子进程 cwd 的要求);解析后的同一路径同时作为子进程 cwd 和 ACP `session/new` 工作区。
返回的运行 id 在父级命名空间中生成。子服务器的会话 id 只用于 ACP 协议调用,因为 ACP 只保证它在该全新子进程中唯一;若将其用作父级生命周期 id,可能与另一个远程运行或本地 agent 冲突。
发布后,提供方发送提示词,并把流式 `agent_message_chunk` 文本收集到 `SubagentResult.output`。提示词/传输失败会以 `stopReason: 'error'` 兑现;如果必需的请求信号或 dispose 请求了取消,则以 `aborted` 兑现。
发布后,提供方发送提示词,并把流式 `agent_message_chunk` 文本收集到 `SubagentResult.output`。提示词/传输失败会以 `stopReason: 'error'` 兑现;如果必需的请求信号或 dispose(资源释放)请求了取消,则以 `aborted` 兑现。
`dispose()` 是幂等的。它会移除信号监听器,在可行时请求 ACP 取消,然后经由该 seam 的动词运行本后端自有的拆卸阶梯(`disposeAcpChild`):先关闭 stdin 并等待 `disposeEofGraceMs` 让子进程协作停稳,再触发句柄的 `terminate()` 升级(SIGTERM、spawn 宽限期、SIGKILL——Windows 直接强制终止),最后进行有界的整树退出等待;若仍有存活进程,则拒绝。每次运行都使用全新进程;尚未实现进程池。
`dispose()` 是幂等的。它会移除信号监听器,在可行时请求 ACP 取消,然后经由该 seam 的动词运行本后端自有的拆卸阶梯(`disposeAcpChild`):先关闭 stdin 并等待 `disposeEofGraceMs` 让子进程协作式完全停稳,再触发句柄的 `terminate()` 升级(SIGTERM、spawn 宽限期、SIGKILL——Windows 直接强制终止),最后进行有界的整树退出等待;若仍有存活进程,则拒绝。每次运行都使用全新进程;尚未实现进程池。
## 能力与上下文
@@ -25,7 +25,7 @@ ACP 不声明任何启动时能力,因为当前进程无法强制执行远程
| 键 | 默认值 | 含义 |
|---|---|---|
| `providerName` | `acp` | `ctx.subagents` 上的注册表名称。 |
| `command` | 必填 | 每次运行时派生的可执行文件。 |
| `command` | 必填 | 每次运行时 spawn 的可执行文件。 |
| `args` | `[]` | 命令参数。 |
| `cwd` | 父会话 cwd | 子进程及其 ACP 会话的工作目录覆盖值;不得为空。相对值会在加载时以 harness 启动目录为基准解析,结果必须指向 harness 可以进入的目录。 |
| `permission` | `reject` | 自动回答权限请求:拒绝,或选择第一个允许形态的选项。 |
@@ -57,9 +57,9 @@ ACP 不声明任何启动时能力,因为当前进程无法强制执行远程
## 进程边界
子进程经由 [`dsh-subprocess`](../../subprocess/subprocess/README.md) seam spawn:共享的凭据清除先移除名称形似凭据的环境变量和环境中已有的 `DSH_*` 名称,显式 `config.env` 值在清除之后合并(有意转发的 `DEEPSEEK_API_KEY` 会保留下来,`DSH_PERMISSION_MODE` 这类 `DSH_*` 部署事实也以同样的方式到达子进程——清除只丢弃其陈旧的同名环境值),stderr 以 inherit 方式直通父进程自身的流,dispose 则以本插件配置的宽限期运行该 seam 的协作式 stdin EOF→SIGTERM→SIGKILL 阶梯。ACP 协议是真正的序列化边界;同进程 subagent 值不会为防御目的而克隆。
子进程经由 [`dsh-subprocess`](../../subprocess/subprocess/README.md) seam spawn:共享的凭据清除先移除似凭据的环境变量和环境中已有的 `DSH_*` 名称,显式 `config.env` 值在清除之后合并(有意转发的 `DEEPSEEK_API_KEY` 会保留下来,`DSH_PERMISSION_MODE` 这类 `DSH_*` 部署事实也以同样的方式到达子进程——清除只丢弃其陈旧的同名环境值),stderr 会继承到父进程自身的流,dispose 则以本插件配置的宽限期运行该 seam 的协作式 stdin EOF→SIGTERM→SIGKILL 阶梯。ACP 协议格式是真正的序列化边界;同进程 subagent 值不会为防御目的而克隆。
本包没有默认导出。否则 Cordis loader 的解包会隐藏具名 `inject` 元数据;见[事故复盘 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
本包package没有默认导出。否则 Cordis loader 的解包会隐藏具名 `inject` 元数据;见[事故复盘 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
无密钥测试通过真实 stdio 驱动脚本化 ACP 子进程,其中包括一个由 Loader 组合的 stdio 应用,用于端到端证明父会话 cwd 继承。带密钥 e2e 会驱动仓库中的真实 ACP agent;没有 `DEEPSEEK_API_KEY` 时自行跳过。
@@ -87,17 +87,17 @@ ACP 不声明任何启动时能力,因为当前进程无法强制执行远程
#### Token 影响
父级输入只增加最终结果或错误,其内容依赖数据,并保留到上下文压缩为止。该提供方自身不会添加父级 schema。
父级输入只增加最终结果或错误,其内容依赖数据,并保留到 compaction上下文压缩为止。该提供方自身不会添加父级 schema。
#### KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
## 已知限制与延期工作
## 已知限制与暂缓事项
- **每次运行使用全新进程**:持久进程池属于后续优化(见 [seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md))。
- **每次运行使用全新进程**:持久进程池属于后续优化(见 [seam Agent Noteagent 决策记录)](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md))。
- **仅支持本地工作区**:解析后的 cwd 是交给同一台机器上子进程的本地路径;远程 ACP agent 的工作区映射需要独立的后端能力,本包尚未设计。
- **不支持可选启动时能力**:该提供方无法在远程进程内应用本地 harness 的 `outputSchema`、深度上限、工具过滤器或 persona,因此不会声明这些能力;服务会拒绝需要它们的请求。
- **只收集已提交的 `agent_message_chunk` 文本**:自动化服务器把推理、工具活动、计划和其他 trace 数据保留在子 agent 会话日志中,不通过 ACP 发出。
- **只收集已提交的 `agent_message_chunk` 文本**:自动化服务器把推理reasoning、工具活动、计划和其他 trace 数据保留在子 agent 会话日志中,不通过 ACP 发出。
- **权限提示自动回答**`permission: allow | reject`):当前版本不会把子 agent 的 `session/request_permission` 呈现给人。
- **没有快照层回放覆盖率**`TODO(acp-subagent-replay)`):ACP 子 agent 拥有独立进程和独立回放形态,该工作延期处理。
+32 -32
View File
@@ -2,21 +2,21 @@
[English](README.md) | 中文
SDK provider 把每个子代理作为一个完整的 DeepSeek Harness 运行时跑在全新子进程里,经由 [TypeScript SDK 客户端](../../sdk/sdk-client/README.md) stdio JSON-RPC 驱动。它是 [`subagent-acp`](../subagent-acp/README.md) 之外的第二个进程外后端,差异在线协议与子进程契约:ACP 后端能驱动任何 Agent Client Protocol 代理;本后端专门驱动 harness SDK 运行时(`dsh-jsonrpc-agent` bin 或打包可执行文件),因此子进程是一个完整的对等 harness——自有 `cordis.yml` 决定的组、会话持久化、模型路由工具。
SDK 提供方会在全新的子进程中把每个 subagent 作为完整的 DeepSeek Harness 运行时运行,并经由 [TypeScript SDK 客户端](../../sdk/sdk-client/README.md) 通过 stdio JSON-RPC 驱动。它是 [`subagent-acp`](../subagent-acp/README.md) 之外的第二个进程外后端,差异在协议格式(wire format)和子进程契约:ACPAgent Client Protocol后端能驱动任何 Agent Client Protocol agent(智能体);本后端专门驱动 harness SDK 运行时(`dsh-jsonrpc-agent` bin 或打包后的可执行文件),因此子进程是一个完整的对等 harness,拥有由 `cordis.yml` 决定的组、会话持久化、模型路由工具。
## 启动与所有权
`start(request)` 先解析子进程工作目录, `DeepSeekHarness` 生成运行时,并在履行前完成 `initialize` 握手(携带配置的 `provider`/`model` 路由及可选的 `maxTokens` 输出上限)。因此履行意味着子运行时已就绪、所有权已移交调用方。生成、握手或发布前取消失败在子进程被收割之后拒绝;工作目录解析失败在生成任何东西之前拒绝。
`start(request)` 先解析子进程工作目录,通过 `DeepSeekHarness` spawn 运行时,并在履行前完成 `initialize` 握手(携带配置的 `provider`/`model` 路由及可选的 `maxTokens` 输出上限)。因此履行意味着子运行时已就绪、所有权已移交调用方。spawn、握手或发布前取消失败时,只会在子进程被收后拒绝;工作目录解析失败则会在尚未 spawn 任何内容时拒绝。
工作目录的解析与 ACP 后端完全一致,经由接缝共享的进程外助手[`dsh-subagent`](../subagent/README.md)):设置了 `cwd` 覆盖则用之(加载时校验一次),否则用发起委的父会话 cwd——绝不用服务器进程自的 cwd。解析出的路径同时成为子进程 cwd 其 SDK 会话的工作区 cwd。
工作目录的解析与 ACP 后端完全一致,并使用 seam 共享的进程外辅助工具[`dsh-subagent`](../subagent/README.md)):设置了 `cwd` 覆盖值时使用该值(加载时校验一次),否则使用发起委的父会话 cwd绝不使用服务器进程自的 cwd。解析出的路径同时成为子进程 cwd 其 SDK 会话的工作区 cwd。
返回的 run id 铸造于父命名空间;子运行时的会话 id 只存在于子进程内部。发布后,provider 跑一个 SDK 回合,并从子会话事件中读取答案:最后一条完整 `assistant/message`,或回合被截断时已累积的 `text-delta`——部分答案在取消错误路径上都得以保留。
返回的 run id 在父级命名空间中生成;子运行时的会话 id 只存在于子进程内部。发布后,提供方运行一个 SDK 轮次,并从子会话事件中读取答案:最后一条完整 `assistant/message`,或轮次被截断时已累积的 `text-delta`部分答案在取消错误路径上都得以保留。
`dispose()` 幂等:先把结果就地定格`aborted`线上没有 prompt 取消方法),再关闭运行时——一次有界的协议 `shutdown` 请求,随后共享的 stdin-EOF → SIGTERM → SIGKILL 阶梯直到真正退出。
`dispose()`(资源释放)是幂等:先在本地把结果确定`aborted`协议层面没有提示词取消机制),再关闭运行时,即先发出一次有界的协议 `shutdown` 请求,随后通过共享的 stdin-EOF → SIGTERM → SIGKILL 阶梯使进程实际退出。
## 停止原因映射
子进程在 `session.finished` 上以结构化 `TurnEndReason` 报告回合结局;provider 把它映射进接缝词汇`completed``completed``max-tokens``max-tokens``aborted``aborted`;其余一切——`error``interrupted``disposed`、未来变体或根本没跑回合——映射为 `error`不洁终止绝不报告为成功。发布后的传输层失败 `onError` 诊断汇(接到 `ctx.logger.warn`)压平为 `stopReason: 'error'`接缝契约禁止 `result` 拒绝。
子进程在 `session.finished` 上以结构化 `TurnEndReason` 报告轮次结果;提供方将其映射为 seam 词汇。`completed``completed``max-tokens``max-tokens``aborted``aborted`;其余情况,包括 `error``interrupted``disposed`、未来变体或根本未运行轮次,均映射为 `error`因此非正常停止绝不报告为成功。发布后的传输层失败会通过 `onError` 诊断接收器(连接到 `ctx.logger.warn`)压平为 `stopReason: 'error'`seam 契约禁止 `result` 拒绝。
## 能力与上下文
@@ -27,14 +27,14 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
| 键 | 默认 | 含义 |
|---|---|---|
| `providerName` | `dsh-sdk` | `ctx.subagents` 上的注册名。 |
| `command` | 必填 | 每次 run 生成的可执行文件(子运行时 bin 或打包 exe)。 |
| `command` | 必填 | 每次运行时 spawn 的可执行文件(子运行时 bin 或打包后的可执行文件)。 |
| `args` | `[]` | 命令参数(通常是子进程的 `cordis.yml` 路径)。 |
| `cwd` | 父会话 cwd | 工作目录覆盖;校验规则与 [`subagent-acp`](../subagent-acp/README.md) 相同。 |
| `provider` | `deepseek` | 写入子进程 `initialize` provider 路由。 |
| `provider` | `deepseek` | 写入子进程 `initialize`提供方路由。 |
| `model` | `deepseek-v4-flash` | 写入子进程 `initialize` 的模型。 |
| `maxTokens` | provider 默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限;对子根 Agent 及其进程内后代生效。 |
| `maxTokens` | 提供方默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限;对子运行时的agent 及其进程内后代生效。 |
| `env` | `{}` | 在凭据擦除后的父环境之上叠加的显式子环境(例如子进程自己的 `DEEPSEEK_API_KEY`,或 `DSH_CORDIS_CONFIG`)。 |
| `shutdownTimeoutMs` | `1000` | 处置期间协议 `shutdown` 交换的时限。 |
| `shutdownTimeoutMs` | `1000` | dispose 期间协议 `shutdown` 交换的时限。 |
| `disposeEofGraceMs` | `6000` | stdin EOF 之后、平台终止之前的宽限。 |
| `disposeGraceMs` | `3000` | 终止后的退出确认窗口;POSIX 在 SIGTERM 之后、SIGKILL 之前也等待同样时长。 |
@@ -55,45 +55,45 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
## 进程边界
子环境以 [`dsh-subprocess`](../../subprocess/README.md) 接缝`scrubbedParentEnv()` 为基底——移除似凭据 `DSH_*` 的环境变量——再在擦除之后合并显式 `config.env` 值。子进程由 SDK 客户端生成而非经 `ctx.subprocess`subprocess README 记载的 SDK 托管传输例外),因此本后端自行应用该擦除。JSON-RPC 线就是真的序列化边界。
进程环境以 [`dsh-subprocess`](../../subprocess/README.md) seam `scrubbedParentEnv()` 为基础,先移除似凭据和名称为 `DSH_*` 的环境变量,再合并显式 `config.env` 值。子进程由 SDK 客户端 spawn,而不是经由 `ctx.subprocess` spawn(这是 subprocess README 中记录的 SDK 托管传输例外),因此本后端自行执行环境清理。JSON-RPC 协议格式才是真的序列化边界。
本包没有默认导出。否则 Cordis loader 解包会隐藏具名 `inject` 元数据;见[后分析 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
本包package没有默认导出。否则 Cordis loader 解包会隐藏具名 `inject` 元数据;见[故复盘 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
免密钥测试通过真实 stdio 驱动 SDK 客户端包的脚本化伪运行时,还包括一个 Loader 组合 e2e:子进程是真实的第二个 harness 运行时,端到端证明父会话 cwd 继承(`tests/loader-composition.e2e.ts`)。
## Model Experience
## 模型体验
### Child-agent request
### 子 agent 请求
#### What the model sees
#### 模型看到的内容
子运行时的模型收到独立任务作为用户消息,加上该运行时自配置的系统提示、工具全新会话。它收不到任何父对话。本 provider 不宣告可选启动能力,因此本地服务会拒绝要 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略。
子运行时的模型收到作为用户消息的独立任务,以及该运行时自配置的系统提示、工具全新会话。它不会收到父级对话。本提供方不声明可选启动能力,因此本地服务会拒绝要 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略这些要求
#### Token effect
#### Token 影响
进程支付一份独立的完整上下文与自己的多步历史。这些 token 绝不进入父上下文。
运行时会为独立的完整上下文及其多步历史消耗 token。这些 token 绝不进入父上下文。
#### KV Cache effect
#### KV Cache 影响
独立于父请求缓存。每个 SDK 子进程只能复用其自身 provider、模型、组成与历史下完全相同的前缀;子步骤在此之外只增不改
与父级请求缓存相互独立。每个 SDK 子进程只能复用其自身提供方、模型、组合和历史均相同的前缀;除此之外,子 agent 的步骤仅追加增长
### Parent tool result, indirectly
### 父级工具结果(间接)
#### What the model sees
#### 模型看到的内容
经由 `dsh-tool-subagent`,父方只收到子进程的最终助手文本(或累积的部分文本),或该消费精确停止原因错误——收不到中间消息工具流量。
经由 `dsh-tool-subagent`,父级只会收到子运行时最终的 assistant 文本(或累积的部分文本),或该消费方给出的精确停止原因错误;不会收到中间消息工具流量。
#### Token effect
#### Token 影响
父输入只增最终结果或错误,其大小依数据而定,保留至压缩。本 provider 自身不给父方增加任何 schema。
输入只增最终结果或错误,其大小取决于数据,并保留到 compaction(上下文压缩)为止。本提供方自身不会向父级添加任何 schema。
#### KV Cache effect
#### KV Cache 影响
追加;新可见内容跟在可复用请求前缀之后,不使既有 KV 缓存条目失效。
追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## Known Limitations and Deferred Work
## 已知限制与暂缓事项
- **每次 run 一个全新运行时进程** —— 无池化;harness 运行时要启动完整插件树,单次生成成本高于 ACP 后端的典型子进程。
- **可选启动能力** —— 父方无法在子进程内强制 `outputSchema`、深度、工具过滤或 persona改为配置子进程自`cordis.yml`
- **子进程的转录留在其自的会话根** —— 父日志只记录委工具调用/结果(接缝的子隔离规则);流式 `session.event` 通道只用于提取输出,不桥接进父日志。
- **仅本地子进程** —— 解析出的 cwd 是本地路径;远程运行时需要自己的后端。
- **每次运行都使用全新运行时进程**:不使用进程池harness 运行时要启动完整插件树,因此每次运行的 spawn 成本高于 ACP 后端通常使用的子进程。
- **不支持可选启动能力**:父级无法在子进程内强制执行 `outputSchema`、深度限制、工具过滤或 persona改为配置子进程自`cordis.yml`
- **子进程的 transcript(文本记录)保留在其自的会话根目录中**:父级日志只记录委工具调用结果(seam 的子隔离规则);流式 `session.event` 通道只用于提取输出,不桥接到父级日志
- **仅支持本地子进程**解析出的 cwd 是本地路径;远程运行时需要独立的后端。
+4 -4
View File
@@ -31,7 +31,7 @@ fork 声明 `{ outputSchema: true, depthLimit: true, toolFilter: true, persona:
#### 模型看到的内容
子 agent 先接收父 agent 平衡的已完成轮次界面前缀,再逐字接收新的任务内容。配置的 persona 会在子 agent 的全新作用域中遮蔽提示词文本;工具限制会过滤其全局协议 schema、可执行工具查找和 Code Mode SDK 绑定,但不影响独立注册的指导内容。父 agent 的工具视图与权限不会被继承。可选的结构化输出请求会添加仅属于子 agent 的契约。父 agent 当前进行中的轮次会被排除。
子 agent 先接收父 agent 已配平的完整轮次表层前缀,再逐字接收新的任务内容。配置的 persona 会在子 agent 的全新作用域中遮蔽提示词文本;工具限制会过滤其全局协议 schema、可执行工具查找和 Code Mode SDK 绑定,但不影响独立的指导内容。父 agent 的工具视图与权限不会被继承。可选的结构化输出请求会添加仅属于子 agent 的契约。父 agent 当前进行中的轮次会被排除。
#### Token 影响
@@ -49,13 +49,13 @@ fork 会把保留的已完成历史复制到独立的子 agent 请求中;随
#### Token 影响
父 agent 输入增加一个依赖数据的最终结果,并保留到上下文压缩(compaction)为止。
父 agent 输入增加一个取决于数据的最终结果,并保留到 compaction(上下文压缩)为止。
#### KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与延期工作
## 已知限制与暂缓事项
- **运行不公开 `sendMessage`/`resume`**:进程内运行不具备这些可选运行时能力。
- **初始内容是一次性快照**:子 agent 只能看到 fork 时父 agent 已完成的轮次,看不到父 agent 此后记录的任何内容;不会实时共享上下文。
@@ -6,9 +6,9 @@ spawn 提供方会在当前进程中创建一个全新的子 `Agent`。子 agent
## 行为
`start(request)`提供初始内容,直接委托给 [`startInProcessRun`](../subagent-inprocess/README.md),并在子 agent 发布后才返回。子 agent 获得父 agent 的工作目录/会话谱系,并默认继承父 agent 模型(除非覆盖),但以空对话开始运行。
`start(request)`传入 seed,直接委托给 [`startInProcessRun`](../subagent-inprocess/README.md),并在子 agent 发布后才返回。子 agent 获得父 agent 的工作目录/会话谱系,并默认继承父 agent 模型(除非覆盖),但以空对话开始运行。
共享驱动器负责深度检查、persona 与工具过滤器设置、结构化输出、必需信号取消、单次执行、结果读取和完全停稳后的 dispose(资源释放)。启动失败不会留下已发布的子 agent;提供方插件在完成后卸载,也不会撤销由持有方拥有的运行。
共享驱动器负责深度检查、persona 与工具过滤器设置、结构化输出、通过必需信号执行取消、单次执行、结果读取和完全停稳后的 dispose(资源释放)。启动遭拒不会留下已发布的子 agent启动调用兑现后卸载提供方,也不会撤销由持有方拥有的运行。
## 能力
@@ -30,7 +30,7 @@ spawn 声明 `{ outputSchema: true, depthLimit: true, toolFilter: true, persona:
#### Token 影响
子 agent 为全新的独立上下文和历史支付 token 成本;不会复制父 agent 历史 token。persona 会改变该子 agent 的重复提示词成本,过滤则会改变其 schema 或生成 SDK 的成本。
子 agent 为全新的独立上下文和历史消耗 token;不会复制父 agent 历史 token。persona 会改变该子 agent 反复使用的提示词成本,过滤则会改变其 schema 或生成 SDK 的成本。
#### KV Cache 影响
@@ -48,9 +48,9 @@ spawn 声明 `{ outputSchema: true, depthLimit: true, toolFilter: true, persona:
#### KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与延期工作
## 已知限制与暂缓事项
- **运行不公开 `sendMessage`/`resume`**:进程内运行不具备这些可选运行时能力。
- **全新表示不含父 agent transcript**:子 agent 会继承 cwd、谱系、模型及显式配置的 persona/工具限制,但不继承父 agent 的任何对话;需要已完成轮次上下文时,请使用 fork 提供方。
- **全新表示不含父 agent transcript(文本记录)**:子 agent 会继承 cwd、谱系、模型及显式配置的 persona/工具限制,但不继承父 agent 的任何对话;需要已完成轮次上下文时,请使用 fork 提供方。
+12 -12
View File
@@ -2,11 +2,11 @@
[English](README.md) | 中文
subagent seam 允许一个 agent(智能体)通过具名提供方把工作委派给子 agent。调用方使用统一的服务 API(`ctx.subagents`);提供方决定子 agent 在当前进程、另一进程还是未来的传输之上运行。
subagent seam 允许一个 agent(智能体)通过具名提供方把工作委派给子 agent。调用方使用统一的服务 API(`ctx.subagents`);提供方决定子 agent 在当前进程、另一进程中,还是通过未来的传输机制运行。
## 包角色
## 包package)的角色
能力族把稳定接口与实现、面向模型的工具分开:
系列包把稳定接口与实现、面向模型的工具分开:
| 包 | 角色 |
|---|---|
@@ -24,12 +24,12 @@ subagent seam 允许一个 agent(智能体)通过具名提供方把工作委
| 成员 | 含义 |
|---|---|
| `registerProvider(provider)` | 按名称注册一个可信的同进程实现。注册受 effect 作用域约束;移除注册会阻止新的启动,但不会撤销已返回给调用方的运行。重复名称会立即失败。 |
| `registerProvider(provider)` | 按名称注册一个可信的同进程实现。注册受 effect 作用域约束;移除注册会阻止新的启动,但不会撤销已返回给调用方的运行。重复名称会明确报错。 |
| `getProvider(name)` | 返回提供方;不存在时返回 `undefined`。 |
| `list()` | 按插入顺序返回提供方名称。 |
| `start(name, request)` | 校验请求的能力和语义值,然后等待提供方,直到真实子 agent 就绪。兑现时返回由持有方拥有的 `SubagentRun`;拒绝表示提供方已清理所有部启动资源。 |
| `start(name, request)` | 校验请求的能力和语义值,然后等待提供方,直到真实子 agent 就绪。兑现时返回由持有方拥有的 `SubagentRun`;拒绝表示提供方已清理所有部启动资源。 |
`SubagentStartRequest.signal` 是必填项,也是规范取消通道。发布前中止会使 `start()` 在回滚后拒绝;发布后中止会取消实时子 agent。请求还可以选择模型、要求结构化输出、限制委派深度、约束子 agent 工具或设置子 agent persona。
`SubagentStartRequest.signal` 是必填项,也是规范取消通道。发布前中止会使 `start()` 在回滚后拒绝;发布后中止会取消正在运行的子 agent。请求还可以选择模型、要求结构化输出、限制委派深度、约束子 agent 工具或设置子 agent persona。
同进程请求、描述符、结果和事件 payload 都是以不可变方式借用的可信类型值。服务不会克隆或冻结它们;序列化和不可信输入校验属于真实的进程、worker、持久化和模型边界。
@@ -46,17 +46,17 @@ subagent seam 允许一个 agent(智能体)通过具名提供方把工作委
该 seam 拥有实现和消费方共享的深度词汇:`AgentOptions.subagentDepth` 声明、`assertSubagentMaxDepth``delegationDepthOf(agent)`。持久化的 `SessionHeader.delegationDepth` 具有权威性且单调:运行时选项可以加深计数,但绝不能降低它,因此恢复后的子 agent 不会被重新计为顶层。
运行时功能是 `SubagentRun` 上的可选方法:`sendMessage?` 会引导实时子 agent`resume?` 则异步创建延续运行。方法是否存在就是能力检查。
运行时功能是 `SubagentRun` 上的可选方法:`sendMessage?` 可对正在运行的子 agent 进行 steering(中途引导)`resume?` 则异步创建延续运行。方法是否存在就是能力检查。
`inheritsParentContext` 只用于描述,不能强制执行。它仅说明子 agent 是否能看到父级已完成的对话历史(`fork` 可以;`spawn` 和 ACP 不可以),不表示是否继承工具、服务或权限。
## 所有权与生命周期
`provider.start(request): Promise<SubagentRun>` 是所有权转移边界。兑现前,提供方拥有设置过程,并且每次失败时都必须取消、回滚并使部资源完全停稳。兑现后,调用方拥有该运行,并且必须在每条路径上调用 `dispose()`
`provider.start(request): Promise<SubagentRun>` 是所有权转移边界。兑现前,提供方拥有设置过程,并且每次失败时都必须取消、回滚并使部资源完全停稳。兑现后,调用方拥有该运行,并且必须在每条路径上调用 `dispose()`
`SubagentRun.result` 兑现为 `{ output, structured?, stopReason }`。子 agent 级失败会以非 `completed` 原因兑现;只有 seam 无法表示的基础设施故障才可以拒绝。`dispose()` 是幂等的,会取消剩余工作,并等待子 agent 资源完全停稳。
本地运行会在 `start()` 兑现前发布普通的子 agent/会话,把该共享会话 id 作为 `SubagentRun.id` 返回,以 `SubagentRun.localAgent` 公开准确的子 agent,并把 `request.parent.session.id` 记录到子 agent 的 `parentSession` header。远程提供方则生成父级作用域的生命周期 id,并返回 `localAgent: undefined`
本地运行会在 `start()` 兑现前发布普通的子 agent/会话,把该共享会话 id 作为 `SubagentRun.id` 返回,以 `SubagentRun.localAgent` 公开子 agent 本身,并把 `request.parent.session.id` 记录到子 agent 的 `parentSession` header。远程提供方则生成父级作用域的生命周期 id,并返回 `localAgent: undefined`
服务只会发出 `subagent/start`,而且是在 `start()` 兑现后。它在同步通知前附加结果观察器,因此即使子 agent 已经结算,也仍会先产生 `subagent/start`,再产生 `subagent/end`。这对事件共享服务生成的 `runId`;其 `local` 标志取自提供方准确 `localAgent` 的快照,因此观察器绝不会从可复用的提供方/会话名称推断运行身份或本地性。
@@ -66,7 +66,7 @@ subagent seam 允许一个 agent(智能体)通过具名提供方把工作委
## 收集模型
面向模型的工具默认同步收集:先等待子 agent 结果,再 dispose 运行,然后才返回。后台委派不会改变该 seam;消费方把启动过程和最终运行注册到通用 `ctx.tasks` 运行时,随后使用共享任务工具进行收集和取消。完整契约见[后台 subagent 任务 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)、[能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)和 `src/types.ts`
面向模型的工具默认同步收集:先等待子 agent 结果,再对运行执行 dispose(资源释放),然后才返回。后台委派不会改变该 seam;消费方把启动过程和最终运行注册到通用 `ctx.tasks` 运行时,随后使用共享任务工具进行收集和取消。完整契约见[后台 subagent 任务 Agent Noteagent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)、[能力 seam Agent Note](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)和 `src/types.ts`
## 模型体验
@@ -76,7 +76,7 @@ subagent seam 允许一个 agent(智能体)通过具名提供方把工作委
不会直接使缓存失效;具名消费方负责请求前缀的任何变化。
## 已知限制与延期工作
## 已知限制与暂缓事项
- **运行时引导和延续只是 seam 能力**:当前工具中没有消费 `sendMessage``resume` 的面向模型消费方。
- **运行时 steering 和延续只是 seam 能力**:当前工具中没有消费 `sendMessage``resume` 的面向模型消费方。
- **生命周期事件只供观察**:影响运行的 `subagent/end` 延续或决策接口仍需等待具体消费方。
+8 -8
View File
@@ -10,7 +10,7 @@
前台调用会让执行信号贯穿启动和执行,等待 `run.result`,并且在返回前总会等待 `run.dispose()`。只有 `completed` 会返回规范值 `{ kind: 'foreground', runId, output: JsonValue[] }`,并渲染为相同的最终文本;中止、拒绝、token 上限和其他失败都会变成出错的工具结果,不包含局部输出。
设置 `run_in_background: true` 后,工具会在启动提供方前注册父级拥有的任务,并返回规范值 `{ kind: 'background', taskId }`,渲染为 `started background subagent task <id>`。任务拥有的信号覆盖待处理的启动阶段,以及启动调用返回后的子 agent。`task_kill` 和所有者 dispose(资源释放)会中止它。结算会等待启动回滚或子 agent dispose,然后把完成的最终文本映射为完成、中止映射为 `killed`、其他失败映射为 `failed`。任务不提供增量读取;通用任务工具负责后续状态、收集、取消和通知。见[后台 subagent Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)。
设置 `run_in_background: true` 后,工具会在启动提供方前注册父级拥有的任务,并返回规范值 `{ kind: 'background', taskId }`,渲染为 `started background subagent task <id>`。任务拥有的信号覆盖待处理的启动阶段,以及启动调用返回后的子 agent。`task_kill` 和所有者 dispose(资源释放)会中止它。结算会等待启动回滚或子 agent dispose,然后把完成的最终文本映射为完成、中止映射为 `killed`、其他失败映射为 `failed`。任务不提供增量读取;通用任务工具负责后续状态、收集、取消和通知。见[后台 subagent Agent Noteagent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-08-background-subagent-tasks.md)。
`toolFilter` 会改变子 agent 的全局工具层,但不是从父级派生的权限上限。见 [agent 作用域的安全非目标](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。
@@ -21,14 +21,14 @@
| `provider`(必填) | 提供方名称(`spawn``fork``acp` 等)。 |
| `toolName` | 面向模型的名称,默认 `subagent`;每个已加载实例必须不同。 |
| `enableRunInBackground` | 公开后台模式,默认 `true`;禁用时也会拒绝强制后台调用。 |
| `agentOptions` | 传给具体 provider 的子 agent `provider``model` 和正整数 `maxTokens`;进程内 provider 会用显式值覆盖继承的父级选项。 |
| `agentOptions` | 传给具体提供方的子 agent `provider``model` 和正整数 `maxTokens`;进程内提供方会用显式值覆盖继承的父级选项。 |
| `persona` | 每个子 agent 独立的 persona;要求提供方具备 `persona` 能力。 |
| `toolFilter` | 每个子 agent 独立的全局工具限制;要求提供方具备 `toolFilter` 能力。 |
| `maxDepth` | 绝对委派深度上限,默认 `3``0` 禁止委派);数值上限要求 `depthLimit` 能力,缺失时挂载失败。对于预算由子 harness 拥有的进程外提供方,`'provider-managed'` 不发送上限。工具在达到上限时仍然可见;每次尝试启动都会检查调用 agent 的当前深度,被拒绝时返回出错的工具结果。 |
## 并发
前台调用后台调用互斥。子 agent 可能共享父级工作区或外部资源,一元分类器无法证明同级委派的效果彼此不相交。见[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md)。
前台调用后台调用互斥。子 agent 可能共享父级工作区或外部资源,一元分类器无法证明同级委派的效果彼此不相交。见[并行工具调用 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-parallel-tool-call-execution.md)。
## 模型体验
@@ -40,7 +40,7 @@
#### Token 影响
每个父级请求支付固定 schema 成本;每个提供方实例增加一个 schema。
每个父级请求都会产生固定 schema token 开销;每个提供方实例增加一个 schema。
#### KV Cache 影响
@@ -58,13 +58,13 @@
#### KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
### 后台任务结果
#### 模型看到的内容
启动时精确返回 `started background subagent task <id>`。通用任务接口提供后续状态、最终输出、取消响应和通知。
启动时原样返回 `started background subagent task <id>`。通用任务接口提供后续状态、最终输出、取消响应和通知。
#### Token 影响
@@ -72,9 +72,9 @@
#### KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与延期工作
## 已知限制与暂缓事项
- **后台运行只公开最终输出**:子 agent 中间步骤留在子 agent 会话中。
- **等待中实例的重复名称发现较晚**(`TODO(subagent-dup-toolname)`):若要阻止提供方注册回滚,需要一份预期名称注册表。