Merge branch 'feat/windows-pwsh-default' into feat/windows-acl-sandbox
# Conflicts: # .agents/notes/implemented/feature/2026-08-01-pwsh-tool-and-executor.i18n.yaml # .agents/notes/implemented/feature/2026-08-01-pwsh-tool-and-executor.zh.md # packages/bash/tool-pwsh/README.i18n.yaml # packages/bash/tool-pwsh/README.zh.md
This commit is contained in:
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/README.md
|
||||
README.md: 1c3d14aeb4fd11cbc45eaadd83f0b84de0dfda52
|
||||
README.zh.md: dda61d86c4d00117af851b4a55d16b97c6bc2f10
|
||||
README.zh.md: 04e07cc9c8b8b16c69bb09344e8533729525fe5c
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
| 页面 | 负责内容 |
|
||||
|---|---|
|
||||
| [core.md](core.md) | `packages/core` 控制主干:逐包循环地图、agent 创建与所有权(`AgentHandle`)、`Agent` 句柄及其投递/取消/拦截契约,以及全仓通用类型模式(`…Map → 派生联合`、品牌化 id) |
|
||||
| [llm-streaming.md](llm-streaming.md) | `packages/llm` 的对话词汇——`Message`/`ContentBlock`、组装完成的模型请求、`StreamChunk` 协议格式(wire format)+ 适配器契约(adapter contract)、`BlockAssembler`、`LlmAdapter` seam |
|
||||
| [core.md](core.md) | `packages/core` 控制主干:逐包循环地图、agent 创建与所有权(`AgentHandle`)、`Agent` 句柄及其投递/取消/拦截约定,以及全仓通用类型模式(`…Map → 派生联合`、品牌化 id) |
|
||||
| [llm-streaming.md](llm-streaming.md) | `packages/llm` 的对话词汇——`Message`/`ContentBlock`、组装完成的模型请求、`StreamChunk` 协议格式(wire format)+ 适配器约定(adapter contract)、`BlockAssembler`、`LlmAdapter` seam |
|
||||
| [token-meter.md](token-meter.md) | 不可变的标量与位置回放度量,附带已消费日志修订号 |
|
||||
| [scope.md](scope.md) | 作用域注册标识、dispatch 载体,以及拥有的 `Scope` 上下文 |
|
||||
| [typert.md](typert.md) | 远程调用描述符、lookup/Context 声明、TypeRT 注册表,以及 Host Gateway/Client API seam |
|
||||
@@ -18,15 +18,15 @@
|
||||
| [settings.md](settings.md) | 用户设置 seam:`SettingsNamespace` 注册、分层解析(默认值 → 组合 `base` → 用户文档)、owner scope、热提交 |
|
||||
| [credentials.md](credentials.md) | 凭据 seam:配置中的 `CredentialRef` 引用(绝不含值)、按操作解析、对 UI 安全的 `CredentialInfo`、provider 来源层 |
|
||||
| [session-query.md](session-query.md) | 逻辑记录、有界精确事件读取、关系追踪、语义筛选器/文档与全文检索结果页 |
|
||||
| [session-title.md](session-title.md) | 持久标题快照、来源 provenance 与异步提供方契约 |
|
||||
| [session-title.md](session-title.md) | 持久标题快照、来源 provenance 与异步提供方约定 |
|
||||
| [session-reference.md](session-reference.md) | 结构化跨会话引用:`SessionReferenceInput`/`Candidate`、prepared 消息上下文、稳定错误分类 |
|
||||
| [system-prompt.md](system-prompt.md) | 逐次组装的上下文、工具提供方结果、提示词段落与协作式组装 |
|
||||
| [tools.md](tools.md) | `ToolDefinition` 完整字段、schema DSL、`ToolExecution`/`ToolResult`、工具展示 UI 类型,以及受保护的执行流水线 |
|
||||
| [user-interaction.md](user-interaction.md) | UI 支持的人工问答 seam:`AskUserQuestionRequest`、answer/options 词汇、提供方 API、错误分类体系 |
|
||||
| [approval.md](approval.md) | 一次性用户审批 seam:`ApprovalRequest`、`ApprovalOutcome`、逐会话策略、审计与 answerer 契约 |
|
||||
| [approval.md](approval.md) | 一次性用户审批 seam:`ApprovalRequest`、`ApprovalOutcome`、逐会话策略、审计与 answerer 约定 |
|
||||
| [bash.md](bash.md) | bash 执行器 seam:`BashExecRequest`/`Spec`、`BashRunResult`、后台 `BashProcess` 句柄 |
|
||||
| [subprocess.md](subprocess.md) | 子进程 seam:完全显式的 `SubprocessSpawnSpec`、基于偏移的输出读取器、不含分类的 `SubprocessOutcome`,以及受管 `DSH_*` 环境词汇 |
|
||||
| [pty.md](pty.md) | 持久化终端 ID、后端/会话契约、发送就绪状态、有界读取与 owner 可见快照 |
|
||||
| [pty.md](pty.md) | 持久化终端 ID、后端/会话约定、发送就绪状态、有界读取与 owner 可见快照 |
|
||||
| [sandbox.md](sandbox.md) | 每会话策略解析与进程约束 seam:文件效果模式、执行/提供方策略、`ConfinedArgv`、强制执行与故障关闭错误 |
|
||||
| [code-runtime.md](code-runtime.md) | 代码执行 seam:`CodeRunRequest`/`Result`、绑定命名空间、捕获日志、`CodeRunFailure` 分类体系 |
|
||||
| [filesystem.md](filesystem.md) | 文件系统 seam:`FsTarget`、读/写/编辑结果、观测到的文件状态、`FsErrorCode` |
|
||||
@@ -37,15 +37,15 @@
|
||||
| [web.md](web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、提供方可用性、`WebError` |
|
||||
| [spill.md](spill.md) | spill 存储 seam:`SaveTextSpill`、`SpillOwner`/`SpillSource`、`SpillRef`、品牌类型 `SpillLocator` |
|
||||
| [workflow.md](workflow.md) | 工作流 seam:`WorkflowStartRequest`、`WorkflowMeta`、`WorkflowRun`/`Result`、`workflow/*` 事件载荷、`WorkflowError` 致命性 |
|
||||
| [tasks.md](tasks.md) | 后台任务运行时:品牌化 `TaskId`、producer 契约、consumer 视图、`ctx.tasks` 服务行为 |
|
||||
| [tasks.md](tasks.md) | 后台任务运行时:品牌化 `TaskId`、producer 约定、consumer 视图、`ctx.tasks` 服务行为 |
|
||||
| [permission.md](permission.md) | 权限预设层:`PresetSpec`/`PresetOption`、派生的 `custom` 状态、仅记日志的 `permission/preset` 事件 |
|
||||
| [plan.md](plan.md) | 计划模式:仅记日志的 `plan/mode` 状态、待定选择的冲刷、`PlanModeConfig`、`exit_plan_mode` 审阅流程 |
|
||||
| [invariants.md](invariants.md) | 运行时不变式注册表:选择配置 `Config`、`InvariantInstaller`/`InvariantFailure`、空配套插件契约 |
|
||||
| [invariants.md](invariants.md) | 运行时不变式注册表:选择配置 `Config`、`InvariantInstaller`/`InvariantFailure`、空配套插件约定 |
|
||||
| [http-server.md](http-server.md) | HTTP 载体:`WebRouteKind`/`WebRoute`、匹配顺序、可认领的回退席位、index 转换 |
|
||||
| [storage.md](storage.md) | 存储子系统:后端 seam(`StorageBackend`)、`StorageForms`、`DomainSpec`/`Domain`、`domain/changed` |
|
||||
| [workspace.md](workspace.md) | 工作区注册表:`Workspace`/`WorkspaceId`、注册与解析、与会话 `cwd` 的关系 |
|
||||
| [client-modules.md](client-modules.md) | Web 插件表:`dshClient` 声明、`WebBootGraph` 线上组合、bundle 路由与 index 转换 |
|
||||
| [session-projection.md](session-projection.md) | 投影 seam:`SessionProjectionMap`、纯函数 `ProjectionDefinition` 单元、`ProjectionSnapshot` 的一致切面、变更馈送 |
|
||||
| [telemetry.md](telemetry.md) | 对外上报 seam:`TelemetryRecord`/`TelemetrySeverity`、`TelemetryBackend` 契约、`telemetry/record` 脱敏 waterfall |
|
||||
| [telemetry.md](telemetry.md) | 对外上报 seam:`TelemetryRecord`/`TelemetrySeverity`、`TelemetryBackend` 约定、`telemetry/record` 脱敏 waterfall |
|
||||
|
||||
> 这些页面上的类型声明及其 JSDoc 与源码等价,并由 `pnpm run verify-type-equiv` 检查漂移(见 [development.md](../development.md#documenting-types-verbatim-ts-type-equiv))。普通块保留完整声明;`public-api` 块保留去除实现体的公开 class 声明。Cordis 服务与事件使用每页生成的 **Cordis surface** 小节。
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/bash.md
|
||||
bash.md: dd7649ce46bea5642270fa553eb3d82f2dc33e9b
|
||||
bash.zh.md: bba9ece2955cee66e941aa878299cff6c06a97a0
|
||||
bash.zh.md: e3c607cb1599da97cb69369a34135abc310387ed
|
||||
|
||||
@@ -218,7 +218,7 @@ interface BashProcessRead {
|
||||
|
||||
## 服务
|
||||
|
||||
`BashExecutor` 拥有 `resolve`、前台 `run`、后台进程 `start` 以及 `sandboxMode` 能力事实。`dsh-bash-local` 拥有命令默认值补全、超时/中止分类、终端环境以及后台读取合并;进程组、有界收集器、spill 文件、凭据清除与 dispose(资源释放)后完全停稳归[进程管理器](subprocess.md)所有。`dsh-tool-bash` 拥有面向模型的渲染,并将后台句柄适配到[通用任务运行时](tasks.md)。`dsh-bash` 拥有 shell 工具共享的退出状态契约:导出的 `parseExitStatus`/`ParsedExitStatus` 是 `dsh-tool-bash` 的 `renderResult` 与 `dsh-tool-pwsh` 的 `renderPwshResult` 所追加的 `[exit code: N]` / `[killed by signal: X]` 标记的逆解析,两个工具的 `presentResult` 都用它把渲染文本拆分为 terminal 卡的输出正文与退出状态 pill。
|
||||
`BashExecutor` 拥有 `resolve`、前台 `run`、后台进程 `start` 以及 `sandboxMode` 能力事实。`dsh-bash-local` 拥有命令默认值补全、超时/中止分类、终端环境以及后台读取合并;进程组、有界收集器、spill 文件、凭据清除与 dispose(资源释放)后完全停稳归[进程管理器](subprocess.md)所有。`dsh-tool-bash` 拥有面向模型的渲染,并将后台句柄适配到[通用任务运行时](tasks.md)。`dsh-bash` 拥有 shell 工具共享的退出状态约定:导出的 `parseExitStatus`/`ParsedExitStatus` 是 `dsh-tool-bash` 的 `renderResult` 与 `dsh-tool-pwsh` 的 `renderPwshResult` 所追加的 `[exit code: N]` / `[killed by signal: X]` 标记的逆解析,两个工具的 `presentResult` 都用它把渲染文本拆分为 terminal 卡的输出正文与退出状态 pill。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/code-runtime.md
|
||||
code-runtime.md: 12779f1aafc8930410ae0d695e3f617caafcf607
|
||||
code-runtime.zh.md: de563dd3430348f5cf3675d4bf124adeba170559
|
||||
code-runtime.zh.md: 0bb18aaafff5a9b390685ee4c93a67f3f15502d5
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](code-runtime.md) | 中文
|
||||
|
||||
代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread 后端与工具注册表消费方的契约见 [Code Mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 和[类型化返回契约](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)。
|
||||
代码执行 seam 是一个[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):其接口([dsh-code-runtime](../../packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread 后端与工具注册表消费方的约定见 [Code Mode 基础设计](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 和[类型化返回约定](../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)。
|
||||
|
||||
源码:[`packages/code-runtime/code-runtime/src/types.ts`](../../packages/code-runtime/code-runtime/src/types.ts)
|
||||
|
||||
@@ -36,7 +36,7 @@ interface CodeRunRequest {
|
||||
}
|
||||
```
|
||||
|
||||
结果将错误报告为一个**字段**,而不是让 `run()` 返回被拒绝的 Promise。报告程序失败是调用方的职责,不走异常路径(与 `BashExecutor.run` 失败时仍正常完成的契约一致):
|
||||
结果将错误报告为一个**字段**,而不是让 `run()` 返回被拒绝的 Promise。报告程序失败是调用方的职责,不走异常路径(与 `BashExecutor.run` 失败时仍正常完成的约定一致):
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/compaction.md
|
||||
compaction.md: 5aef839192ea6f67bb409622187fe65fed795e73
|
||||
compaction.zh.md: 63b28518e68f71cc648d2f4e78a82bc5beafb621
|
||||
compaction.zh.md: 20b4b2381f6e638e1d1b4db13ba98d53379b38db
|
||||
|
||||
@@ -81,7 +81,7 @@ type ManualCompactionErrorCode =
|
||||
|
||||
压力压缩在串行 `agent/pre-step` 中运行,先于请求推导。一旦压力或规范化溢出满足条件,compact-basic 会在选择范围前调用可选的 [`ctx.toolResultPrune`](../../packages/compact/compact-tool-result-prune/README.md),再通过 `ctx.tokenMeter` 重新测量,并且可以在不生成摘要的情况下推进 surface。失败请求的恢复在失败的步骤关闭后通过 `agent/request-error` 运行;仅当 surface replacement generation 前进时才返回重试动作,即便后续摘要工作在剪枝后抛异常亦如此;取消仍然优先。区域边界保持工具调用/结果配对,但不保持整个轮次,因此一个过大轮次中较早关闭的步骤可以被压缩。`dsh-compact-basic` 拥有阈值、保留尾部策略、溢出上限与失败处理。
|
||||
|
||||
该 seam 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`,用于这些边缘检查。两者都会验证当前 surface 成员关系,并拒绝缺失的 seq 与遗留结果;其缓存语义由[包契约](../../packages/compact/compact/README.md#tool-pairing-boundaries)规定。
|
||||
该 seam 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`,用于这些边缘检查。两者都会验证当前 surface 成员关系,并拒绝缺失的 seq 与遗留结果;其缓存语义由[包约定](../../packages/compact/compact/README.md#tool-pairing-boundaries)规定。
|
||||
|
||||
## 工具结果剪枝产出
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/core.md
|
||||
core.md: cc9cc30677b0b657492d8a5118489e8b801f3fd3
|
||||
core.zh.md: 6878300dc2cbd82d220e17d2d6f5e1009f41c48f
|
||||
core.md: b09e5b4f0a076a7f95a751a6204836a81a4c31e9
|
||||
core.zh.md: 9058e08854423c42d69d23284d719718fa0b445c
|
||||
|
||||
@@ -314,6 +314,30 @@ The two core IDs are `CallId` (correlates a tool call with its result; dsh-llm)
|
||||
|
||||
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` surface lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
||||
|
||||
<a id="ctxagentdefaultmodel--agentdefaultmodelservice"></a>
|
||||
|
||||
### `ctx.agentDefaultModel` — `AgentDefaultModelService`
|
||||
|
||||
Owns the default model selection independently of any Host or transport. The composition entry remains usable without a settings provider; when one is mounted, its user layer is read live.
|
||||
|
||||
```ts cordis-catalog
|
||||
/**
|
||||
* Read the current default model selection.
|
||||
* @returns a detached provider, model, and optional reasoning selection.
|
||||
*/
|
||||
currentSelection(): ModelSelection
|
||||
|
||||
/**
|
||||
* Save the complete default model selection. A deployment without a settings
|
||||
* provider keeps its composition entry.
|
||||
* @param next - resolved selection accepted by a front door.
|
||||
* @returns fulfillment after the optional settings write settles.
|
||||
*/
|
||||
async saveSelection(next: ModelSelection): Promise<void>
|
||||
```
|
||||
|
||||
Source: [`packages/core/agent-default-model/src/index.ts:64`](../../packages/core/agent-default-model/src/index.ts)
|
||||
|
||||
<a id="ctxagentloop--agentloop"></a>
|
||||
|
||||
### `ctx.agentLoop` — `AgentLoop`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](core.md) | 中文
|
||||
|
||||
**核心**子系统即 [`packages/core`](../../packages/core/README.md)——每个组合都会启动的控制主干:事件溯源的会话日志、系统提示词组装、工具注册表、agent 词汇,以及驱动它们的具体循环。本页拥有 `agent`/`agent-loop` 这对包所声明的内容——agent 如何被创建与拥有,以及 `Agent` 句柄及其投递、取消与拦截契约——外加每个子系统都遵循的两个类型模式;该组的专属页面与目录其余部分见[子系统 README](README.md)。
|
||||
**核心**子系统即 [`packages/core`](../../packages/core/README.md)——每个组合都会启动的控制主干:事件溯源的会话日志、系统提示词组装、工具注册表、agent 词汇,以及驱动它们的具体循环。本页拥有 `agent`/`agent-loop` 这对包所声明的内容——agent 如何被创建与拥有,以及 `Agent` 句柄及其投递、取消与拦截约定——外加每个子系统都遵循的两个类型模式;该组的专属页面与目录其余部分见[子系统 README](README.md)。
|
||||
|
||||
## 主干逐包速览
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
| `system-prompt/` | 提示词段落与工具 schema 组装(`ctx.systemPrompt`) | [system-prompt.md](system-prompt.md) |
|
||||
| `tools/` | 带作用域的工具注册表与受保护的执行流水线(`ctx.tools`) | [tools.md](tools.md) |
|
||||
| `agent/` | `Agent` 接口、实时注册表、发起者作用域与 `agent/*` 事件词汇(`ctx.agents`) | 本页 |
|
||||
| `agent-loop/` | 实现公开 `Agent` 契约的具体 driver(`ctx.agentLoop`) | 本页 |
|
||||
| `agent-loop/` | 实现公开 `Agent` 约定的具体 driver(`ctx.agentLoop`) | 本页 |
|
||||
| `scope/` | 注册表与循环用于构建按 agent 作用域的注册原语 | [scope.md](scope.md) |
|
||||
|
||||
`scope/` 是这里唯一的非服务包:一个零依赖库(`createScope`/`scopeOf`/`scopeTarget`),在模块图中位于 `session/` 与 `system-prompt/` 之下,正是为了让它们消费它而不形成环。`agent-loop` 是 `agent` seam 的唯一具体实现,放在这里因为它是 harness 的默认产品循环;它在 `ctx.agents.withInitiator()` 内运行每个 driver。扩展插件依赖 `agent`——包括需要发起 Agent 时——而绝不直接依赖 `agent-loop`,因此循环保持可替换。把这条主干接成可运行 agent 的默认组合是 [`examples/agent-spine-demo`](../../packages/examples/agent-spine-demo/README.md)。
|
||||
@@ -50,7 +50,7 @@ interface AgentHandle {
|
||||
|
||||
`CreateAgentOptions` 携带共享标识以及新 agent 发布前所需的一切:会话元数据(`meta`——已校验的 `cwd`、fork 谱系、seed 边界、来源分类、委派深度)、fork 用的可选 `seed` 回放前缀、按 agent 的 `AgentOptions`、仅创建期有效的取消 `signal`,以及 `setup`。`ResumeAgentOptions` 是持久标识的对应物:`resumeSessionId`、`agentOptions`、`signal` 与 `setup`。`setup` 回调(`AgentSetup`)在两个 id 都尚未发布时组装 agent 的作用域世界——凡经 `agentCtx` 注册的内容都先于 `agent/created` 与第一次提示词组装存在——并可返回一个在发布前一刻调用的同步 commit;setup 拒绝、commit 抛出或所有者 dispose 都会回滚事务,两个 id 均不发布。
|
||||
|
||||
`AgentFactory` 是注册表背后的创建 seam:循环经 `ctx.agents.setFactory()` 注册其工厂,因此消费方面向 `ctx.agents` 编程,无需依赖具体循环包。确切的 `create`/`resume` 签名及其回滚契约见下方[生成区块](#ctxagents--agentregistry)。
|
||||
`AgentFactory` 是注册表背后的创建 seam:循环经 `ctx.agents.setFactory()` 注册其工厂,因此消费方面向 `ctx.agents` 编程,无需依赖具体循环包。确切的 `create`/`resume` 签名及其回滚约定见下方[生成区块](#ctxagents--agentregistry)。
|
||||
|
||||
<a id="the-agent-handle"></a>
|
||||
|
||||
@@ -206,7 +206,7 @@ type AgentCancelCause =
|
||||
|
||||
cause 是由 TypeScript 强制约束的同进程输入。活跃的取消持有者会将它复制到仅运行时的 `AbortSignal.reason`;signal 不授予协作监听器任何分类权限。持久 `turn/end` 保留粗粒度 `{ kind: 'aborted' }` 结果;若需记录请求 provenance,应使用单独的持久事件,而不是让终态结果承担额外含义。
|
||||
|
||||
[事件分类](../architecture.md#event)拥有 `agent/*` 生命周期、检查点与 waterfall(瀑布式事件)契约。轮次和步骤边界是持久会话事件,而不是 agent emit。
|
||||
[事件分类](../architecture.md#event)拥有 `agent/*` 生命周期、检查点与 waterfall(瀑布式事件)约定。轮次和步骤边界是持久会话事件,而不是 agent emit。
|
||||
|
||||
<a id="initiating-agent"></a>
|
||||
|
||||
@@ -255,7 +255,7 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
|
||||
|
||||
## `ToolDefinition`
|
||||
|
||||
唯一属于核心的流水线编写类型:每个已注册工具*是什么*——一个面向模型的 `ToolSchema` 加上一个 `execute` 函数,以及可选的最终内容回调与 UI 回调。工具作者很少手动构造它(`defineTool` DSL 会用类型化参数构建),但它是注册表持有、循环分发所经过的契约。
|
||||
唯一属于核心的流水线编写类型:每个已注册工具*是什么*——一个面向模型的 `ToolSchema` 加上一个 `execute` 函数,以及可选的最终内容回调与 UI 回调。工具作者很少手动构造它(`defineTool` DSL 会用类型化参数构建),但它是注册表持有、循环分发所经过的约定。
|
||||
|
||||
其完整字段、`defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` 类型化 schema DSL、`ToolExecution`/`ToolExecutionResult` waterfall 形状,以及工具展示 UI 词汇在 **[tools.md](tools.md)** 中。
|
||||
|
||||
@@ -265,7 +265,7 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
|
||||
|
||||
### `…Map → derived-union` 模式
|
||||
|
||||
harness 中几乎所有可扩展的和类型都遵循同一形状:一个以判别标签为键的接口(`…Map`),联合类型由 `keyof` 派生。插件通过**声明合并**添加变体——无需修改拥有该类型的包(package)。
|
||||
harness 中几乎所有可扩展的和类型都遵循同一形状:一个以判别标签为键的接口(`…Map`),联合类型由 `keyof` 派生。插件通过**声明合并**添加变体——无需修改拥有该类型的包。
|
||||
|
||||
```ts ignore-check
|
||||
// The pattern, schematically:
|
||||
@@ -322,6 +322,30 @@ type Branded<B extends string> = string & { readonly [BRAND]: B }
|
||||
|
||||
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` surface lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
||||
|
||||
<a id="ctxagentdefaultmodel--agentdefaultmodelservice"></a>
|
||||
|
||||
### `ctx.agentDefaultModel` — `AgentDefaultModelService`
|
||||
|
||||
Owns the default model selection independently of any Host or transport. The composition entry remains usable without a settings provider; when one is mounted, its user layer is read live.
|
||||
|
||||
```ts cordis-catalog
|
||||
/**
|
||||
* Read the current default model selection.
|
||||
* @returns a detached provider, model, and optional reasoning selection.
|
||||
*/
|
||||
currentSelection(): ModelSelection
|
||||
|
||||
/**
|
||||
* Save the complete default model selection. A deployment without a settings
|
||||
* provider keeps its composition entry.
|
||||
* @param next - resolved selection accepted by a front door.
|
||||
* @returns fulfillment after the optional settings write settles.
|
||||
*/
|
||||
async saveSelection(next: ModelSelection): Promise<void>
|
||||
```
|
||||
|
||||
Source: [`packages/core/agent-default-model/src/index.ts:64`](../../packages/core/agent-default-model/src/index.ts)
|
||||
|
||||
<a id="ctxagentloop--agentloop"></a>
|
||||
|
||||
### `ctx.agentLoop` — `AgentLoop`
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/credentials.md
|
||||
credentials.md: 0bc2224ac039addc795d3806e8c85004f2bb84a7
|
||||
credentials.zh.md: 6f5ccd1572885434257d39eb0f659fcc7371ad1d
|
||||
credentials.zh.md: f236b0b2daef85784308f10dbcfc67db84c42234
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
[English](credentials.md) | 中文
|
||||
|
||||
[dsh-credentials](../../packages/credentials/credentials) 的凭据 seam 把机密挡在配置之外:settings 分节与 `cordis.yml` 条目携带的是*引用*(环境变量名),值归 [dsh-credentials-local](../../packages/credentials/credentials-local) 这类 provider 所有,消费方每个操作解析一次引用——LLM 适配器每次模型请求解析一次,因此轮换后的凭据无需任何重启即可作用于紧随其后的下一次请求。一条 seam 级规则约束每个 provider:空的存储值在任何地方都视为不存在。
|
||||
[dsh-credentials](../../packages/credentials/credentials) 的凭据 seam 把机密挡在配置之外:settings 分节与 `cordis.yml` 条目携带的是*引用*(环境变量名),值归 [dsh-credentials-local](../../packages/credentials/credentials-local) 这类提供方所有,消费方每个操作解析一次引用——LLM(大语言模型)适配器每次模型请求解析一次,因此轮换后的凭据无需任何重启即可作用于紧随其后的下一次请求。一条 seam 级规则约束每个提供方:空的存储值在任何地方都视为不存在。
|
||||
|
||||
Source: [`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts)
|
||||
来源:[`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts)
|
||||
|
||||
## 标识
|
||||
|
||||
@@ -17,7 +17,7 @@ type CredentialRef = Branded<'CredentialRef'>
|
||||
|
||||
## 解析
|
||||
|
||||
`resolve(ref)` 返回值,连同供出该值、由 provider 定义的来源层;未配置期间返回 `undefined`。消费方在每个操作中重新解析,绝不跨操作缓存——这次按操作进行的读取正是热更新机制。
|
||||
`resolve(ref)` 返回值,连同提供该值、由提供方定义的来源层;未配置期间返回 `undefined`。消费方在每个操作中重新解析,绝不跨操作缓存——这种按操作进行的读取正是热更新机制。
|
||||
|
||||
```ts type-equiv
|
||||
/** One resolved credential value and the source layer that supplied it. */
|
||||
@@ -31,7 +31,7 @@ interface ResolvedCredential {
|
||||
|
||||
## 描述
|
||||
|
||||
`describe(ref)` 在绝不暴露值的前提下回应配置界面:引用当前是否可解析、来自哪一层、`set` 当前能否成功。本地 provider 把由活跃进程环境供值的引用报告为 `writable: false`——那样的写入会表面成功而解析持续返回遮蔽值,因此 seam 直接拒绝,界面也得以提前把该引用渲染为只读。
|
||||
`describe(ref)` 在绝不暴露值的前提下回应配置界面:引用当前是否可解析、来自哪一层、`set` 当前能否成功。本地提供方把由当前进程环境供值的引用报告为 `writable: false`——那样的写入会表面成功而解析持续返回遮蔽值,因此 seam 直接拒绝,界面也得以提前把该引用渲染为只读。
|
||||
|
||||
```ts type-equiv
|
||||
/** Source and writability facts for one reference, safe for configuration UIs — never the value. */
|
||||
@@ -47,7 +47,7 @@ interface CredentialInfo {
|
||||
|
||||
## 变更提交
|
||||
|
||||
`credentials/updated (ref)` 在 provider 管理的来源发生已提交变更后触发——`set`、`unset` 或在存储中观察到的外部编辑。进程环境自身的变化不可观测,永不发出事件。消费方不需要该事件(它们按操作重新解析);它服务于配置界面刷新「已配置」徽标。
|
||||
`credentials/updated (ref)` 在提供方管理的来源发生已提交变更后触发——`set`、`unset` 或在存储中观察到的外部编辑。进程环境自身的变化不可观测,永不发出事件。消费方不需要该事件(它们按操作重新解析);它服务于配置界面刷新「已配置」徽标。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/goal.md
|
||||
goal.md: 6f54a5261cb44c3fda389e37cb689a00061ab241
|
||||
goal.zh.md: 043263f3231b4c727f21ca0b8fc07d8adffa0559
|
||||
goal.zh.md: ea5a0fe7923648aead5e6f54ab31162a7abdb954
|
||||
|
||||
@@ -142,7 +142,7 @@ interface GoalChanged {
|
||||
|
||||
## 服务行为
|
||||
|
||||
[`GoalService`](../../packages/goal/goal/src/index.ts) 解析创建默认值、从持久 `goal/change` 事件执行严格回放折叠、校验确切的活跃 agent 身份、以比较并设置方式执行变更,并发出 `goal/changed` 通知;监听器故障会被隔离。包 [README](../../packages/goal/goal/README.md) 负责记录可调用契约和面向模型的契约。
|
||||
[`GoalService`](../../packages/goal/goal/src/index.ts) 解析创建默认值、从持久 `goal/change` 事件执行严格回放折叠、校验确切的活跃 agent 身份、以比较并设置方式执行变更,并发出 `goal/changed` 通知;监听器故障会被隔离。包 [README](../../packages/goal/goal/README.md) 负责记录可调用约定和面向模型的约定。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/http-server.md
|
||||
http-server.md: b9795fe98b432b6ef5f7d01a4d3e115c809fe642
|
||||
http-server.zh.md: b84ea457bcd37eed361fde88fbf680d189aeebfb
|
||||
http-server.zh.md: 8d55c48ae2882bd471ca4e64e011c7d79c4ebb40
|
||||
|
||||
@@ -42,7 +42,7 @@ interface Config {
|
||||
|
||||
## 服务
|
||||
|
||||
`HttpServerService`(`ctx.httpServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会从 init 抛出,形成一个 FAILED fiber,由启动的大声失败 sweep 上报。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层契约,冲突即配置错误。`tapIndex(transform)` 添加一个纯的 html 到 html 转换,按注册顺序应用于每个 index 响应(`/` 和每次 SPA 回退);[dsh-client-modules](../../packages/client/modules) 用它注入启动 manifest(元数据清单)。`port` 读取监听端口,`config.port` 为 0 时读到的是操作系统分配的值。
|
||||
`HttpServerService`(`ctx.httpServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会从 init 抛出,形成一个 FAILED fiber,由启动的大声失败 sweep 上报。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。`tapIndex(transform)` 添加一个纯的 html 到 html 转换,按注册顺序应用于每个 index 响应(`/` 和每次 SPA 回退);[dsh-client-modules](../../packages/client/modules) 用它注入启动 manifest(元数据清单)。`port` 读取监听端口,`config.port` 为 0 时读到的是操作系统分配的值。
|
||||
|
||||
处理过程中抛出异常的请求(畸形的 % 转义撞上 `decodeURIComponent`、客户端在请求体中途断开)会记录为警告并应答 400(响应头已发出时则销毁 socket),绝不导致进程退出。dispose(资源释放)把 `close()` 与 `closeAllConnections()` 配对使用,因为处理器可能像 SSE(Server-Sent Events)那样保持响应打开,而这类连接永远不会自行结束;没有强制关闭,拆卸就会挂起。该包(package)从不打印输出:URL 行归 shell 所有。逐包运维细节(含开发模式的 bundle 监视流水线)留在 [README](../../packages/host/webserver/README.md) 中。
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/invariants.md
|
||||
invariants.md: 184d982bb27ab3ff98f715f0751c8bfcc1d08bea
|
||||
invariants.zh.md: bd2f83a018642832fe50ba5cca6dd82e2bd7d59b
|
||||
invariants.zh.md: e79b1c90a1c6284691404411ad9fa8ce62ef7e5e
|
||||
|
||||
@@ -54,9 +54,9 @@ interface InvariantInstaller {
|
||||
|
||||
`ctx.invariants.register(packageName, installer)` 为完整 npm 包名保留唯一一个活跃注册,并返回其绑定到 effect 的 disposer。即使过滤器使安装器保持不活跃,保留依然成立,因此两个插件绝不可能静默地认领同一个包名;重复、空白或含空白字符的名称会抛出异常。安装器失败会原子地 dispose(资源释放)子 fiber 并释放保留。服务拥有每个注册 fiber,而返回的 disposer 同时属于配套插件的 fiber:卸载任一侧都会移除监听器、trace 状态和保留项,因此配套插件可以重载并再次注册同一名称,不留残余状态。
|
||||
|
||||
## 配套插件契约
|
||||
## 配套插件约定
|
||||
|
||||
每个工作区包都拥有一个 `./invariant` 配套插件([包契约](../../packages/AGENTS.md));发布与注册是穷尽式的,但刻意不合成断言。只有当包对某个可观察事件或可变数据拥有所有权关系时,配套插件才安装检查;否则它导出一个空安装器,其起始注释以 `No runtime invariant:` 开头,针对该包具体解释为什么没有可检查项。`pnpm run verify-package-invariants` 机械地拒绝「生成文件」标记、无解释的空安装器、遗漏或忽略报告器的非空安装器、错误的注册名称,以及不完整的导出、发布、依赖或打包接线([机械规则 Agent Note](../../.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.md))。可执行配套插件的目录与标准组合方式见[包 README](../../packages/support/invariants/README.md)。
|
||||
每个工作区包都拥有一个 `./invariant` 配套插件([包约定](../../packages/AGENTS.md));发布与注册是穷尽式的,但刻意不合成断言。只有当包对某个可观察事件或可变数据拥有所有权关系时,配套插件才安装检查;否则它导出一个空安装器,其起始注释以 `No runtime invariant:` 开头,针对该包具体解释为什么没有可检查项。`pnpm run verify-package-invariants` 机械地拒绝「生成文件」标记、无解释的空安装器、遗漏或忽略报告器的非空安装器、错误的注册名称,以及不完整的导出、发布、依赖或打包接线([机械规则 Agent Note](../../.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.md))。可执行配套插件的目录与标准组合方式见[包 README](../../packages/support/invariants/README.md)。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/llm-streaming.md
|
||||
llm-streaming.md: c65416f449d1783f398cdd81b0d6987de83a6141
|
||||
llm-streaming.zh.md: ce79ecca53edf7213853df118489817451baa7b0
|
||||
llm-streaming.md: 1705c45697df98b51ba9f69c8c91b3a8a18dea76
|
||||
llm-streaming.zh.md: b47ae516e39cb6657ce5b6ada69d524d5f5ea174
|
||||
|
||||
@@ -623,7 +623,7 @@ interface LlmCallConfigAdapterDefaults {
|
||||
|
||||
## The seam
|
||||
|
||||
`LlmAdapter` is the provider seam: subclass, implement `stream()`, and register one adapter instance with `ctx.llm.registerAdapter(providers, adapter)`. `GenerateOptions.provider` selects the registered adapter; `GenerateOptions.model` is passed to that adapter and need not be registered at lifecycle start. Duplicate provider routes fail atomically. Optional `providerRetryPolicy()` is captured per route with normal defaults, while `providerInfo()` and asynchronous `listModels()` feed `LlmService.listProviders()` / `listModels()` with detached selector metadata. That catalog is advisory rather than a request whitelist: the adapter remains authoritative and may accept unlisted model ids. One asynchronous `resolveModel()` query returns exact model identity plus optional correctness-sensitive context capacity, an adapter-configured `defaultMaxTokens`, and ordered model-owned reasoning ids with an optional deployment default; absent fields mean unavailable metadata or provider-owned behavior, not invalid catalog membership. The resolver receives optional cancellation and must settle promptly after abort. `LlmService.resolveModelInfo()` validates and detaches the aggregate. At the final adapter boundary, `resolveCallConfig()` materializes the output default only when `maxTokens` is absent and validates and materializes reasoning, so direct calls cannot bypass either configured behavior; direct dispatch captures one registration before awaiting that resolution. The agent loop instead uses `prepareCall()` to keep the same registration across model resolution, durable header logging, and dispatch, retain detached context metadata from that exact lookup, and report which config fields the adapter defaulted. Adapter lookup happens at the terminal continuation of the `llm/stream` waterfall, so a listener may short-circuit the call or route a mutable one-shot request before lookup. AgentLoop observes a request attempt once the outer waterfall returns a stream handle; that limited boundary does not prove a lazy terminal adapter was constructed or began provider I/O. The `block-start` / `block-end` `index` correlation and the assembler together mean an adapter only has to emit well-formed chunks — block reassembly is not each adapter's problem. The consumer surface (`ctx.llm.stream()`) and the `llm/stream` waterfall are described in [architecture.md § Content blocks and streaming](../architecture.md#content-blocks-and-streaming-dsh-llm).
|
||||
`LlmAdapter` is the provider seam: subclass, implement `stream()`, and register one adapter instance with `ctx.llm.registerAdapter(providers, adapter)`. `GenerateOptions.provider` selects the registered adapter; `GenerateOptions.model` is passed to that adapter and need not be registered at lifecycle start. Duplicate provider routes fail atomically. Optional `providerRetryPolicy()` is captured per route with normal defaults, while `providerInfo()` and asynchronous `listModels()` feed `LlmService.listProviders()` / `listModels()` with detached selector metadata. That catalog is advisory rather than a request whitelist: the adapter remains authoritative and may accept unlisted model ids. One asynchronous `resolveModel()` query returns exact model identity plus optional correctness-sensitive context capacity, an adapter-configured `defaultMaxTokens`, and ordered model-owned reasoning ids with an optional deployment default; absent fields mean unavailable metadata or provider-owned behavior, not invalid catalog membership. The resolver receives optional cancellation and must settle promptly after abort. `LlmService.resolveModelInfo()` validates and detaches the aggregate. At the final adapter boundary, `resolveCallConfig()` materializes the output default only when `maxTokens` is absent and validates and materializes reasoning, so direct calls cannot bypass either configured behavior; direct dispatch captures one registration before awaiting that resolution. The agent loop instead uses `prepareCall()` to keep the same registration across model resolution, durable header logging, and dispatch, retain detached context metadata from that exact lookup, and report which config fields the adapter defaulted. Adapter lookup happens at the terminal continuation of the `llm/stream` waterfall, so a listener may short-circuit the call or route a mutable one-shot request before lookup. AgentLoop observes a request attempt once the outer waterfall returns a stream handle; that limited boundary does not prove a lazy terminal adapter was constructed or began provider I/O. The `block-start` / `block-end` `index` correlation and the assembler together mean an adapter only has to emit well-formed chunks — block reassembly is not each adapter's problem. The consumer surface (`ctx.llm.stream()`) and the `llm/stream` waterfall are described in [architecture.md § Content blocks and streaming](../architecture.md#model-content).
|
||||
|
||||
```ts type-equiv
|
||||
/** One model call whose config and adapter registration were resolved together. */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](llm-streaming.md) | 中文
|
||||
|
||||
[`packages/llm`](../../packages/llm/README.md) 的对话与流式输出词汇:每个请求与持久历史共享的 `Message`/`ContentBlock` 形状、完整组装的模型请求、原始 `StreamChunk` 协议、每个适配器必须遵守的适配器契约(adapter contract),以及共享的 assembler。[核心主干](core.md)在每个轮次持有并记录这些值;本页声明它们。
|
||||
[`packages/llm`](../../packages/llm/README.md) 的对话与流式输出词汇:每个请求与持久历史共享的 `Message`/`ContentBlock` 形状、完整组装的模型请求、原始 `StreamChunk` 协议、每个适配器必须遵守的适配器约定(adapter contract),以及共享的 assembler。[核心主干](core.md)在每个轮次持有并记录这些值;本页声明它们。
|
||||
|
||||
源码:[`packages/llm/llm/src/types.ts`](../../packages/llm/llm/src/types.ts)
|
||||
|
||||
@@ -202,7 +202,7 @@ interface LlmFailure {
|
||||
}
|
||||
```
|
||||
|
||||
## 适配器契约
|
||||
## 适配器约定
|
||||
|
||||
每个适配器必须遵守以下规则,每个消费方可以依赖它们:
|
||||
|
||||
@@ -216,7 +216,7 @@ interface LlmFailure {
|
||||
- **每个提供方 HTTP 请求都携带应用归属头。** 适配器发送 `attributionHeaders()`(见下文)作为 `User-Agent` 基线,并通过协议级测试加以证明(mock 服务器断言收到的 header,或对基于库的适配器使用库的 header 钩子)。
|
||||
- **回放状态归适配器所有。** 成功的 `finish` 可以携带重建提供方原生响应所需的无损 JSON 状态。循环会将其与组装后的 assistant 消息一起存储。后续请求中,仅当历史提供方与目标提供方当前注册到完全相同的适配器实例时,`LlmService` 才会传递该状态。该适配器负责校验状态并拥有所有跨模型或跨提供方转换;其他适配器只会收到提供方无关的内容与 provenance,不会收到私有状态。
|
||||
|
||||
该契约由两个有意保持独立的实现锁定:`dsh-llm-deepseek`(直接 fetch,SSE(Server-Sent Events)分帧经由 `eventsource-parser`)和 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 实现的通用多提供方适配器)。基于库的适配器覆盖 finish 分片错误路径,而传输边界测试证明每个空闲 watchdog 都会停止其实际请求。
|
||||
该约定由两个有意保持独立的实现锁定:`dsh-llm-deepseek`(直接 fetch,SSE(Server-Sent Events)分帧经由 `eventsource-parser`)和 `dsh-llm-pi-ai`(通过 `@earendil-works/pi-ai` 实现的通用多提供方适配器)。基于库的适配器覆盖 finish 分片错误路径,而传输边界测试证明每个空闲 watchdog 都会停止其实际请求。
|
||||
|
||||
## `ResolvedRetryPolicy`
|
||||
|
||||
@@ -224,7 +224,7 @@ interface LlmFailure {
|
||||
|
||||
## `AppIdentity`:应用归属
|
||||
|
||||
每个适配器都会向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 只把它映射到标准 `User-Agent` header;该契约有意不支持 OpenRouter 特有的应用归属 header。默认 `APP_IDENTITY` 从包(package) manifest(元数据清单)获取版本;每个字段都是公开产品事实——不含 secret、路径、会话 id 或逐用户标识,且任何逐请求信息都不得影响这些值。设计理由见[强制 `User-Agent` 归属](../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。
|
||||
每个适配器都会向提供方发送的静态公开应用标识([`packages/llm/llm/src/attribution.ts`](../../packages/llm/llm/src/attribution.ts))。`attributionHeaders(identity?)` 只把它映射到标准 `User-Agent` header;该约定有意不支持 OpenRouter 特有的应用归属 header。默认 `APP_IDENTITY` 从包(package) manifest(元数据清单)获取版本;每个字段都是公开产品事实——不含 secret、路径、会话 id 或逐用户标识,且任何逐请求信息都不得影响这些值。设计理由见[强制 `User-Agent` 归属](../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -504,7 +504,7 @@ interface GenerateOptions {
|
||||
}
|
||||
```
|
||||
|
||||
模型响应为何停止由可合并扩展的原因表示。提供方终态失败携带流式契约的 [`LlmFailure`](#llmfailure):
|
||||
模型响应为何停止由可合并扩展的原因表示。提供方终态失败携带流式约定的 [`LlmFailure`](#llmfailure):
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -631,7 +631,7 @@ interface LlmCallConfigAdapterDefaults {
|
||||
|
||||
## seam
|
||||
|
||||
`LlmAdapter` 是提供方 seam:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerRetryPolicy()` 会按路由捕获并填入 normal 默认值,`providerInfo()` 与异步 `listModels()` 方法则为 `LlmService.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单次异步 `resolveModel()` 查询返回确切模型身份,以及可选的对正确性敏感的上下文容量、适配器配置的 `defaultMaxTokens`、由模型持有的有序推理强度 ID 和部署默认值;字段缺失表示元数据不可用或保留提供方持有的行为,而不表示目录成员关系无效。解析器会接收可选的取消信号,并且必须在信号中止后迅速完成结算。`LlmService.resolveModelInfo()` 会校验聚合结果并返回分离值。在最终适配器边界,`resolveCallConfig()` 仅在 `maxTokens` 缺失时填入输出默认值,并校验和填入推理强度,因此直接调用也无法绕过任何一项已配置行为;直接分派会在等待解析前捕获一项适配器注册。agent loop 则使用 `prepareCall()`,使模型解析、请求头持久记录和分派全程使用同一项注册,保留来自同一次查询的分离上下文元数据,并报告适配器填入的配置字段。适配器查找发生在 `llm/stream` waterfall(瀑布式事件)的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。AgentLoop 在外层 waterfall 返回流句柄时观察到一次请求尝试;这个有限边界不能证明惰性终端适配器已构造完成或开始提供方 I/O。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的分片——块重组不是每个适配器各自的问题。消费方 surface(`ctx.llm.stream()`)与 `llm/stream` waterfall 见 [architecture.md § 内容块与流式传输](../architecture.md#content-blocks-and-streaming-dsh-llm)。
|
||||
`LlmAdapter` 是提供方 seam:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerRetryPolicy()` 会按路由捕获并填入 normal 默认值,`providerInfo()` 与异步 `listModels()` 方法则为 `LlmService.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单次异步 `resolveModel()` 查询返回确切模型身份,以及可选的对正确性敏感的上下文容量、适配器配置的 `defaultMaxTokens`、由模型持有的有序推理强度 ID 和部署默认值;字段缺失表示元数据不可用或保留提供方持有的行为,而不表示目录成员关系无效。解析器会接收可选的取消信号,并且必须在信号中止后迅速完成结算。`LlmService.resolveModelInfo()` 会校验聚合结果并返回分离值。在最终适配器边界,`resolveCallConfig()` 仅在 `maxTokens` 缺失时填入输出默认值,并校验和填入推理强度,因此直接调用也无法绕过任何一项已配置行为;直接分派会在等待解析前捕获一项适配器注册。agent loop 则使用 `prepareCall()`,使模型解析、请求头持久记录和分派全程使用同一项注册,保留来自同一次查询的分离上下文元数据,并报告适配器填入的配置字段。适配器查找发生在 `llm/stream` waterfall(瀑布式事件)的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。AgentLoop 在外层 waterfall 返回流句柄时观察到一次请求尝试;这个有限边界不能证明惰性终端适配器已构造完成或开始提供方 I/O。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的分片——块重组不是每个适配器各自的问题。消费方 surface(`ctx.llm.stream()`)与 `llm/stream` waterfall 见 [architecture.md § 内容块与流式传输](../architecture.md#model-content)。
|
||||
|
||||
```ts type-equiv
|
||||
/** One model call whose config and adapter registration were resolved together. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/core-data-structures/lsp.md
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/lsp.md
|
||||
lsp.md: 03d0ce2dbe246aadb6f6c9a702fa50e3e792eb09
|
||||
lsp.zh.md: d428f2b5f9568b231b0b50a13bd4a41f7ea81346
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/persistence.md
|
||||
persistence.md: 580ec250ebad3f2b51982f98a611268f26487321
|
||||
persistence.zh.md: 6676bf26e6eb0fb8f7dd9a94d17d4d70d1d1b271
|
||||
persistence.zh.md: 8785ca9c7dad562e6b27261920ab48c72c607121
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
事件日志的**持久性 seam**。[session.md](session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述如何使该日志持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一同存储的元数据头。日志承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐项列举。
|
||||
|
||||
该 seam 是典型的[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append、可复用的 Session 准备流程、逻辑 load/inspect、物理后缀读取,以及轻量的 list/snapshot 观察——**没有平行的持久化事件类型**——以及两个实现同一契约的可互换后端。见 [session-persistence Agent Note](../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)。
|
||||
该 seam 是典型的[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](../../packages/session/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append、可复用的 Session 准备流程、逻辑 load/inspect、物理后缀读取,以及轻量的 list/snapshot 观察——**没有平行的持久化事件类型**——以及两个实现同一约定的可互换后端。见 [session-persistence Agent Note](../../.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)。
|
||||
|
||||
## flush 检查点
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
修复仅适用于冷会话。对于活跃 id,`SessionPersistence.load(id)` 会等待权威内存快照完成持久化,并且只在日志平衡时返回;若活跃轮次仍未闭合,则拒绝操作,而不是添加合成的中断边界。HMR 会接管活跃前缀,而不会关闭其中正在进行的轮次。
|
||||
|
||||
`SessionPersistence.inspect(id)` 会构造一个不可变的逻辑 Session,但不发布它,也不写入恢复内容。冷检查会在内存中配平中断的 turn,同时保持撕裂的物理尾部不变;检查已经实时存在的 Session 则借用其当前不可变快照,因此可能包含打开的 turn。使用协调器的实现会在有界 LRU 中保留这个精确的冷未发布 Session,因此重复历史读取与后续 `prepare(id)` 可复用同一次读取、解压、验证、冻结及 Session 构造。`prepare(id)` 会预留该 Session、提交待处理修复并返回可 dispose 的发布句柄;`load(id)` 使用相同机制提交修复,但不会发布 Session。该生命周期由 [Session 准备阶段决策](../../.agents/notes/implemented/architecture/2026-08-05-session-preparation.md)定义。
|
||||
`SessionPersistence.inspect(id)` 会构造一个不可变的逻辑 Session,但不发布它,也不写入恢复内容。冷检查会在内存中配平中断的轮次,同时保持撕裂的物理尾部不变;检查已经实时存在的 Session 则借用其当前不可变快照,因此可能包含打开的 turn。使用协调器的实现会在有界 LRU 中保留这个精确的冷未发布 Session,因此重复历史读取与后续 `prepare(id)` 可复用同一次读取、解压、验证、冻结及 Session 构造。`prepare(id)` 会预留该 Session、提交待处理修复并返回可 dispose 的发布句柄;`load(id)` 使用相同机制提交修复,但不会发布 Session。该生命周期由 [Session 准备阶段决策](../../.agents/notes/implemented/architecture/2026-08-05-session-preparation.md)定义。
|
||||
|
||||
## `SessionLocation`——可选的逐会话产物目标
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/sandbox.md
|
||||
sandbox.md: 20e0f36a5edb211ea409208d4e5e4a9be2e91d46
|
||||
sandbox.zh.md: 0619046f2fa98a89275e2dad85f0eadaf8e4a231
|
||||
sandbox.zh.md: 5f5465af46aa88d72b4a39f728f18855156b24ba
|
||||
|
||||
@@ -151,7 +151,7 @@ interface ConfinedArgv {
|
||||
|
||||
## 提供方与 fail-closed 错误
|
||||
|
||||
`ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。消费方也可以在 spawn 或观察所返回的 argv 时对失败进行分类;该归因属于消费方契约。对于受限策略,静默的无隔离透传永远不合法。
|
||||
`ctx.sandbox.confine(argv, policy)` 返回一个 `ConfinedArgv`,或在没有可用后端时抛出 `SandboxUnavailableError`(错误码 `SANDBOX_UNAVAILABLE`)。消费方也可以在 spawn 或观察所返回的 argv 时对失败进行分类;该归因属于消费方约定。对于受限策略,静默的无隔离透传永远不合法。
|
||||
|
||||
提供方选择、探测、缓存和后端专有的强制执行报告归[本地提供方](../../packages/sandbox/sandbox-local/README.md)所有。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/core-data-structures/scope.md
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/scope.md
|
||||
scope.md: 73a697f2843293daffff85dabf4656346f7dcd04
|
||||
scope.zh.md: 06e2528eca958102110caa3a7d370e0778c0f7b2
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/session-projection.md
|
||||
session-projection.md: 64351195028c62f623b32cbeb80c952795c1e9e6
|
||||
session-projection.zh.md: cf9036e6db3f82d84ffa3b8aa809c5617409659a
|
||||
session-projection.zh.md: e4a03c6719095cc342d914612faf364fc48e4fa0
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](session-projection.md) | 中文
|
||||
|
||||
会话投影 seam 是一项[能力 seam](../capability-seams.md):领域 host 插件经由它向客户端载体供给按会话的日志派生状态的当前全量值;三方分别是接口与注册表([dsh-session-projection](../../packages/session/session-projection),`ctx.sessionProjections`)、领域贡献方(每个领域注册一个纯单元)与载体(今天是 [dsh-host-apiproxy](../../packages/host/apiproxy) 的历史尾页与 `session/projection` 推送帧)。它是一项可选能力,不属于 agent loop(智能体循环)主干。框架负责驱动,领域负责计算:注册表只订阅一次 `session/event`,并把每个已提交事件折叠进每个单元;领域不持有任何订阅,客户端也从不折叠领域事件——它们收到的是成品值。设计权威:[session-projection RFC](../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md);驱动、缓存与变更流契约:[包(package)README](../../packages/session/session-projection/README.md)。
|
||||
会话投影 seam 是一项[能力 seam](../capability-seams.md):领域 host 插件经由它向客户端载体供给按会话的日志派生状态的当前全量值;三方分别是接口与注册表([dsh-session-projection](../../packages/session/session-projection),`ctx.sessionProjections`)、领域贡献方(每个领域注册一个纯单元)与载体(今天是 [dsh-host-apiproxy](../../packages/host/apiproxy) 的历史尾页与 `session/projection` 推送帧)。它是一项可选能力,不属于 agent loop(智能体循环)主干。框架负责驱动,领域负责计算:注册表只订阅一次 `session/event`,并把每个已提交事件折叠进每个单元;领域不持有任何订阅,客户端也从不折叠领域事件——它们收到的是成品值。设计权威:[session-projection RFC](../../.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md);驱动、缓存与变更流约定:[包(package)README](../../packages/session/session-projection/README.md)。
|
||||
|
||||
源码:[`packages/session/session-projection/src/index.ts`](../../packages/session/session-projection/src/index.ts)
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/session-reference.md
|
||||
session-reference.md: f539a59b8d26182aff9746b6d6a39a86ba15cb45
|
||||
session-reference.zh.md: 82b6a6c5ec5c91372fc6a43b73ad1572fccf5b3a
|
||||
session-reference.zh.md: 1035614141936af1f94bdabe35b3104be319a762
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](session-reference.md) | 中文
|
||||
|
||||
结构化的跨会话引用请求与准备后的消息上下文。[包契约](../../packages/context/session-reference) 负责规范 URI、当前表层投影、标签安全的 JSON 与字节保留、稳定错误和不可信的模型提示词。宿主适配器使用这些类型,而不会把各自 UI 的提及语法传入 agent(智能体)核心。
|
||||
结构化的跨会话引用请求与准备后的消息上下文。[包约定](../../packages/context/session-reference) 负责规范 URI、当前表层投影、标签安全的 JSON 与字节保留、稳定错误和不可信的模型提示词。宿主适配器使用这些类型,而不会把各自 UI 的提及语法传入 agent(智能体)核心。
|
||||
|
||||
来源:[`packages/context/session-reference/src/types.ts`](../../packages/context/session-reference/src/types.ts)
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/session.md
|
||||
session.md: 7735e90807f6fce1b3645096437b3e86189dc8ec
|
||||
session.zh.md: 09f34ac19c2f685bf5f8e5b11355b4c642c584d0
|
||||
session.zh.md: 63eb460f7ef300decf3e32c0ace16b354606c271
|
||||
|
||||
@@ -177,7 +177,7 @@ interface EpochHeader {
|
||||
|
||||
### 路由容量事件:`request/context`
|
||||
|
||||
请求所解析到的路由的上下文元数据是独立的已记录状态,在同一步骤内紧随 `request/header` 追加,且仅在提供方、模型或容量与上一条记录不同时追加。它保持在 `EpochHeader` 之外,因为该类型是由 `headerEquals` 逐字段比较的重建契约:容量描述的是路由,不是请求输入,把它折叠进去会让一次容量变化被登记为请求信封的 `change`,也会把适配器元数据拉进 loop 的重建不变式。与 `request/header` 一样,它不是 `SurfaceEventType`,也不产生 LLM 消息。`session.requestContext()` 以增量方式归并最新一条记录。适配器不公布容量的路由会以缺失 `contextWindow` 的形式记录,因此新记录可以清除较早路由的容量。
|
||||
请求所解析到的路由的上下文元数据是独立的已记录状态,在同一步骤内紧随 `request/header` 追加,且仅在提供方、模型或容量与上一条记录不同时追加。它保持在 `EpochHeader` 之外,因为该类型是由 `headerEquals` 逐字段比较的重建约定:容量描述的是路由,不是请求输入,把它折叠进去会让一次容量变化被登记为请求信封的 `change`,也会把适配器元数据拉进 loop 的重建不变式。与 `request/header` 一样,它不是 `SurfaceEventType`,也不产生 LLM 消息。`session.requestContext()` 以增量方式归并最新一条记录。适配器不公布容量的路由会以缺失 `contextWindow` 的形式记录,因此新记录可以清除较早路由的容量。
|
||||
|
||||
```ts type-equiv
|
||||
/** Registration-bound metadata for one resolved model route. */
|
||||
@@ -585,11 +585,11 @@ interface TurnEndReasonMap {
|
||||
|
||||
钩子桥接层的 `hook/invoked` / `hook/result` 溯源对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。`UserPromptSubmit`、`PreToolUse`、`PostToolUse` 与 `Stop` 在 loop 已打开的轮次内触发,因此其 `hook/*` 记录天然位于轮次之内。`SessionStart` 不生成 `hook/*` 记录,因为它在轮次 1 之前运行;其上下文会在 inbox 中保持待处理,直到唤醒交付打开一个轮次(见[钩子桥接 Agent Note](../../.agents/notes/implemented/feature/2026-06-30-hook-bridges.md))。
|
||||
|
||||
## 持久性契约
|
||||
## 持久性约定
|
||||
|
||||
持久化后端依赖的契约如下:持久日志无损保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。后端可以为事件批次选择自己的存储编码,只要 `load` 返回与追加时完全一致的事件即可(JSONL 后端默认启用的打包分片行就是此类编码;见 [persistence.md](persistence.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.events` 始终与后端可持久化的内容一致。新增会携带不可序列化数据、破坏核心执行嵌套或违反事件所有方声明关系的事件类型,都会构成磁盘格式的破坏性变更。
|
||||
持久化后端依赖的约定如下:持久日志无损保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。后端可以为事件批次选择自己的存储编码,只要 `load` 返回与追加时完全一致的事件即可(JSONL 后端默认启用的打包分片行就是此类编码;见 [persistence.md](persistence.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.events` 始终与后端可持久化的内容一致。新增会携带不可序列化数据、破坏核心执行嵌套或违反事件所有方声明关系的事件类型,都会构成磁盘格式的破坏性变更。
|
||||
|
||||
消费此契约的后端见 [persistence.md](persistence.md)。
|
||||
消费此约定的后端见 [persistence.md](persistence.md)。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/settings.md
|
||||
settings.md: 9256bf9436d2e77093fc8c6a3728b62fc4e8d67f
|
||||
settings.zh.md: f6d662ebaf35eeb9d046353ea1087b0eb86e7068
|
||||
settings.zh.md: 720eb9c2718c1fa14a148cced806c224634dba69
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
[English](settings.md) | 中文
|
||||
|
||||
[dsh-settings](../../packages/settings/settings) 的用户设置 seam 持有一份按 namespace 分节的用户文档,并把每个已注册 namespace 解析为:schema 默认值,然后注册方的组合 `base`,最后用户分节。[dsh-settings-local](../../packages/settings/settings-local) 这类 provider 存储原始文档并推送外部编辑;消费插件注册 schema 后读取或观察解析值。组合配置仍留在 `cordis.yml`——namespace 只承载用户可编辑子集。
|
||||
[dsh-settings](../../packages/settings/settings) 的用户设置 seam 持有一份按 namespace 分节的用户文档,并把每个已注册 namespace 解析为:schema 默认值,然后注册方的组合 `base`,最后用户分节。[dsh-settings-local](../../packages/settings/settings-local) 这类提供方存储原始文档并推送外部编辑;消费方插件注册 schema 后读取或观察解析值。组合配置仍留在 `cordis.yml`——namespace 只承载用户可编辑子集。
|
||||
|
||||
Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts)
|
||||
来源:[`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts)
|
||||
|
||||
## 标识
|
||||
|
||||
namespace 命名用户文档中一个插件所有的分节。brand 使其不与其他跨边界 id 混用;构造时校验小写 kebab-case 形态。
|
||||
namespace 命名用户文档中一个归插件所有的分节。brand 使其不与其他跨边界 id 混用;构造时校验小写 kebab-case 形态。
|
||||
|
||||
```ts type-equiv
|
||||
/** Nominal id of one registered settings namespace. */
|
||||
@@ -17,7 +17,7 @@ type SettingsNamespace = Branded<'SettingsNamespace'>
|
||||
|
||||
## 注册
|
||||
|
||||
注册把 schemastery schema 绑定到调用方插件 fiber 上的 namespace——dispose 该 fiber 即移除 namespace 及其观察者。options 携带组合层、owner 的生效时机,以及一个可选的、用于校验 schema 表达不了的约束的钩子。
|
||||
注册把 schemastery schema 绑定到调用方插件 fiber 上的 namespace——dispose(资源释放)该 fiber 即移除 namespace 及其观察者。options 携带组合层、owner 的生效时机,以及一个可选的、用于校验 schema 表达不了的约束的钩子。
|
||||
|
||||
```ts type-equiv
|
||||
/** Registration options beyond the namespace schema. */
|
||||
@@ -49,7 +49,7 @@ interface SettingsRegisterOptions<T> {
|
||||
}
|
||||
```
|
||||
|
||||
`validate` 在 schema 接纳该值之后运行,因此它看到的默认值与组合 base 与 owner 将看到的完全一致。`dsh-llm-pi-ai` 用它在写入处拒绝自己无法服务的提供方 profile,而不是先存下来、再让该 namespace 下每条路由失效。
|
||||
`validate` 在 schema 接纳该值之后运行,因此它看到的默认值和组合 base 与 owner 实际看到的完全一致。`dsh-llm-pi-ai` 用它在写入处拒绝自己无法服务的提供方 profile,而不是先存下来、再让该 namespace 下每条路由失效。
|
||||
|
||||
`applies` 是 UI 提示而非机制:`restart` 的 owner 只是从不 watch,其值在构造期读取一次,配置界面可为待生效变更加标。
|
||||
|
||||
@@ -95,7 +95,7 @@ interface SettingsScope<T> {
|
||||
|
||||
## 描述符
|
||||
|
||||
`describe()` 为配置界面序列化每个已注册 namespace:schemastery 的 `toJSON()` 信封驱动 schema 渲染的表单,解析值填充表单,分离出的 `base`/`user` 层让表单按字段是否出现在 user 层标注「用户已覆盖」。`describe({ redactSecrets: true })`——每个 wire 面都必须传入——从三层剥离 `role('secret')` 字段并枚举其 `{path, set}` 槽位,页面因此能渲染只写输入框而永远收不到机密值。
|
||||
`describe()` 为配置界面序列化每个已注册 namespace:schemastery 的 `toJSON()` 封装结构驱动 schema 渲染的表单,解析值填充表单,分离出的 `base`/`user` 层让表单按字段是否出现在 user 层标注「用户已覆盖」。`describe({ redactSecrets: true })`——每个对外传输接口都必须传入——从三层剥离 `role('secret')` 字段并枚举其 `{path, set}` slot,页面因此能渲染只写输入框而永远收不到机密值。
|
||||
|
||||
```ts type-equiv
|
||||
/** One registered namespace as surfaced to configuration UIs. */
|
||||
@@ -154,7 +154,7 @@ interface SettingsDescribeOptions {
|
||||
|
||||
## 变更提交
|
||||
|
||||
每次提交的变更——进程内写入或 provider 观察到的外部编辑——在新值成为权威值之后发出 `settings/updated (ns, next, prev, source)`,解析值深相等时绝不发出。source 标记区分两条入口路径。
|
||||
每次提交的变更——进程内写入或提供方观察到的外部编辑——在新值成为权威值之后发出 `settings/updated (ns, next, prev, source)`,解析值深相等时绝不发出。source 标记区分两条入口路径。
|
||||
|
||||
```ts type-equiv
|
||||
/** Origin of one committed settings change. */
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/skills.md
|
||||
skills.md: 78d510fafca0017b9528a215270172a74e9b0de1
|
||||
skills.zh.md: e88c9f1ba190eb1e90966d35c7dcc2eb86ecd6cc
|
||||
skills.zh.md: 12e51c45a779e3ca0634db62ac9adfe69112d09f
|
||||
|
||||
@@ -211,7 +211,7 @@ interface Config {
|
||||
}
|
||||
```
|
||||
|
||||
## 会话目录与工具契约
|
||||
## 会话目录与工具约定
|
||||
|
||||
`dsh-tool-skill` 在存活会话中第一个观察到非空完整视图的 `agent/pre-step` 注入初始的持久 user-role `<system-reminder>`。目录只包含已排序的 skill `name` 和规范化、经 XML 转义的 `description`;不包含正文、路径、来源、提供方或路由提示。发现通过 `SkillLookupOptions` 转发该步骤的 abort signal。`catalogDescriptionMaxLength` 是消费方用于 description 上限的配置,默认值为 `500`,整数最小值为 `3`。
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/storage.md
|
||||
storage.md: 52dc84b699921e911276ce5214bc975abfd22fa4
|
||||
storage.zh.md: f614b77153e835264e1650515946a9d2acf70e57
|
||||
storage.zh.md: 89ff7f69ed43b55101be834c21d11cf74ca2340b
|
||||
|
||||
@@ -44,7 +44,7 @@ interface StorageBackend {
|
||||
}
|
||||
```
|
||||
|
||||
一个后端拥有一个介质(一棵文件树的根目录、一个数据库文件),并暴露可选的数据形状 facet;目前 `kv` 是唯一的 facet。`KvFacet.open(descriptor)` 打开一个具名 unit——`KvUnitDescriptor` 携带名称、格式版本、表名清单,以及是否存在全局单例槽位——并返回提供 `loadAll`、`putRecord`、`deleteRecord`、`setGlobal` 和 `close` 的 `KvUnit`。unit 名与表名必须匹配 `UNIT_NAME_RE`(既可安全用作文件名,也可安全用作 SQL 标识符片段);记录键是任意字符串,绝不进入文件路径。unit 不对并发写入做串行化——顺序由调用方负责——但每次单独调用在介质上都是原子的,且 resolve 后即已持久。介质上记录的版本与之不同时拒绝 `version-mismatch`;无法按该 unit 解析的介质拒绝 `malformed-medium`(不做迁移:预发布立场)。[`backend.ts`](../../packages/storage/storage/src/backend.ts) 是逐条款的规范性契约,[`tests/contract.ts`](../../packages/storage/storage/tests/contract.ts) 中的共享一致性套件对每个后端断言其中每一条款。[json 后端](../../packages/storage/storage-json/README.md)以原子方式为每个 unit 整文件重新发布一份人类可读文件;[sqlite 后端](../../packages/storage/storage-sqlite/README.md)在单个数据库中按一行一文档存储,是高频更新领域的路由选择。
|
||||
一个后端拥有一个介质(一棵文件树的根目录、一个数据库文件),并暴露可选的数据形状 facet;目前 `kv` 是唯一的 facet。`KvFacet.open(descriptor)` 打开一个具名 unit——`KvUnitDescriptor` 携带名称、格式版本、表名清单,以及是否存在全局单例槽位——并返回提供 `loadAll`、`putRecord`、`deleteRecord`、`setGlobal` 和 `close` 的 `KvUnit`。unit 名与表名必须匹配 `UNIT_NAME_RE`(既可安全用作文件名,也可安全用作 SQL 标识符片段);记录键是任意字符串,绝不进入文件路径。unit 不对并发写入做串行化——顺序由调用方负责——但每次单独调用在介质上都是原子的,且 resolve 后即已持久。介质上记录的版本与之不同时拒绝 `version-mismatch`;无法按该 unit 解析的介质拒绝 `malformed-medium`(不做迁移:预发布立场)。[`backend.ts`](../../packages/storage/storage/src/backend.ts) 是逐条款的规范性约定,[`tests/contract.ts`](../../packages/storage/storage/tests/contract.ts) 中的共享一致性套件对每个后端断言其中每一条款。[json 后端](../../packages/storage/storage-json/README.md)以原子方式为每个 unit 整文件重新发布一份人类可读文件;[sqlite 后端](../../packages/storage/storage-sqlite/README.md)在单个数据库中按一行一文档存储,是高频更新领域的路由选择。
|
||||
|
||||
## 声明领域
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/subagent.md
|
||||
subagent.md: 3bf3ac7c48bfa08be86314bb43263d4ee6198654
|
||||
subagent.zh.md: ddc3a715fbb6589dffc38f0e0c8b23bf35dddf6e
|
||||
subagent.md: a934c84835334cd6d31c79c4d52b4fb5ebfd722d
|
||||
subagent.zh.md: 65ea762fcddb0f7b4ef5ec977cc14f13c8bf4589
|
||||
|
||||
@@ -135,7 +135,7 @@ persisted Session
|
||||
|
||||
`running` means the Agent has an active admission or turn, or waking inbox work; `waiting` means it is quiescent but still owns at least one child Activation that has not completed disposal; `settled` means quiescent with every owned child disposed, at which point the manager disposes the [`AgentHandle`](core.md#creation-and-ownership) and removes the Activation. The manager derives these internal conditions from Agent quiescence and the owned-child set rather than maintaining a second execution state machine.
|
||||
|
||||
The Agent inbox is the only queue. Every continuation message becomes one `Agent.followup()` FIFO turn, so accepted messages have one observable order and a follow-up cannot redirect a turn already underway. Successful delivery returns the accepted `MessageId`; the existing `agent/inbox/enqueue`, `agent/inbox/dequeue`, and `agent/inbox/discard` events remain the message-lifecycle observations, and the continuation layer defines no subagent-specific delivery route.
|
||||
The Agent inbox is the only queue. Every continuation message becomes one `Agent.followup()` FIFO turn, so accepted messages have one observable order and a follow-up cannot redirect a turn already underway. Successful delivery returns the accepted `MessageId`; the existing `agent/inbox/inserted`, `agent/inbox/claimed`, and `agent/inbox/discarded` events remain the message-lifecycle observations, and the continuation layer defines no subagent-specific delivery route.
|
||||
|
||||
Follow-up authority comes from an exact live Agent tool context. The authenticated Agent must be the durable child's direct parent recorded in `SessionHeader.parentSession`. `MessageSource` and `senderSessionId` are durable provenance after admission and grant no authority; the optional model-facing tool uses `CoordinatorMessageSource`.
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
subagent seam:一个 agent(智能体)将工作委派给子 agent。与 [bash](bash.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](core.md) 中。但它在一个维度上与其他所有 seam 不同:**同一上下文中可共存多个提供方实现**,按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。注册表的形状参照 [LLM(大语言模型)适配器注册表](llm-streaming.md),而非单服务的 bash 执行器。
|
||||
|
||||
接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现为六个兄弟包(package):`dsh-subagent-spawn`、`-fork`、`-acp`、`-codex`、`-claude-code`、`-dsh-sdk`;面向模型的消费方包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)、[dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)和 [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report)(可选的 child 作用域 `report` 返回通道)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接从会话存储与可选的会话持久化负责只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md)、[report 工具 Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md)、[持久化目录 Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)和[服务合并 Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)。
|
||||
接口:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。实现为六个兄弟包:`dsh-subagent-spawn`、`-fork`、`-acp`、`-codex`、`-claude-code`、`-dsh-sdk`;面向模型的消费方包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)、[dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)和 [dsh-tool-subagent-report](../../packages/subagent/tool-subagent-report)(可选的 child 作用域 `report` 返回通道)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接基于会话存储和可选的会话持久化提供只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md)、[report 工具 Agent Note](../../.agents/notes/implemented/feature/2026-07-30-continuable-subagent-report-tool.md)、[持久化目录 Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md)、[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)和[服务合并 Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md)。
|
||||
|
||||
源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts)、[`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts)和 [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts)
|
||||
|
||||
## 两类能力,两种发现方式
|
||||
|
||||
提供方通过一个静态描述符公布其**启动时**特性,服务会在单次 run 存在之前即行检查;如果请求依赖提供方不具备的特性,会被大声拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会被接受后静默忽略。这些 flag 仅描述单次 [`start()`](#the-provider-seam-subagentprovider) 路径,即由提供方组合子 agent 的路径。**可继续**子 agent 由继续执行管理器自行组合,因此它们由唯一一个可选方法把关,方法存在即为能力,并以 TypeScript 的类型收窄作为发现机制:[`SubagentProvider.prepareContinuable`](#the-provider-seam-subagentprovider)。
|
||||
提供方通过一个静态描述符公布其**启动时**功能,服务会在单次 run 存在之前即行检查;如果请求依赖提供方不具备的功能,会被明确拒绝(`SubagentError('UNSUPPORTED_CAPABILITY')`),绝不会被接受后静默忽略。这些 flag 仅描述单次 [`start()`](#the-provider-seam-subagentprovider) 路径,即由提供方组合子 agent 的路径。**可继续**子 agent 由继续执行管理器自行组合,因此它们由唯一一个可选方法把关,方法存在即为能力,并以 TypeScript 的类型收窄作为发现机制:[`SubagentProvider.prepareContinuable`](#the-provider-seam-subagentprovider)。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -98,7 +98,7 @@ interface SubagentStartRequest {
|
||||
|
||||
`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 Agent Note](../../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)规定 persona、live 全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。
|
||||
|
||||
面向调用方的请求不携带目录格式细节或继续执行状态。`SubagentService.start()` 会在功能检查后解析分离的一次性描述符,再将以下面向提供方的请求传给所选传输;可继续子 agent 绝不会到达 `SubagentProvider.start()`:
|
||||
面向调用方的请求不携带目录格式细节或继续执行状态。`SubagentService.start()` 会在能力检查后解析分离的一次性描述符,再将以下面向提供方的请求传给所选传输;可继续子 agent 绝不会到达 `SubagentProvider.start()`:
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -123,7 +123,7 @@ persisted Session
|
||||
-> zero or more owned child Activations
|
||||
```
|
||||
|
||||
`SubagentService.startContinuable()` 会预留稳定的子 agent id,对版本化的 `subagent/descriptor` payload 建立快照,向指定提供方索取其分离的 `ContinuableCreateSpec`,通过私有的 activation-owner 作用域创建子 Agent,建立任何可继续父级的所有权,并提交初始 prompt。当收件箱(inbox)准入产出消息 id 时,它以 `{ childId, messageId }` resolve——无需等待轮次开始,也无需等待消息进入会话日志。在该准入之前的任何失败都会以两个 id 都不返回的方式 reject,并 dispose 任何已创建的 handle,回滚 Activation 与父级所有权。
|
||||
`SubagentService.startContinuable()` 会预留稳定的子 agent id,对版本化的 `subagent/descriptor` payload 建立快照,向指定提供方索取其分离的 `ContinuableCreateSpec`,通过私有的 activation-owner 作用域创建子 Agent,建立任何可继续父级的所有权,并提交初始提示词。当收件箱(inbox)准入产出消息 id 时,它以 `{ childId, messageId }` resolve——无需等待轮次开始,也无需等待消息进入会话日志。在该准入之前的任何失败都会以两个 id 都不返回的方式 reject,并 dispose(资源释放)任何已创建的 handle,回滚 Activation 与父级所有权。
|
||||
|
||||
`SubagentService.followup()` 是唯一的继续执行消息操作,其路由仅取决于 Activation 的驻留状态:
|
||||
|
||||
@@ -133,15 +133,15 @@ persisted Session
|
||||
| `waiting` | 唤醒同一 Activation |
|
||||
| 无 Activation | 冷恢复一个新的 Activation |
|
||||
|
||||
`running` 表示 Agent 拥有活跃的准入或轮次,或正在唤醒收件箱工作;`waiting` 表示它已停稳,但仍拥有至少一个尚未完成 dispose 的子 Activation;`settled` 表示已停稳且其拥有的每个子级都已 dispose,此时管理器会 dispose [`AgentHandle`](core.md#creation-and-ownership) 并移除该 Activation。管理器根据 Agent 的完全停稳状态与其拥有的子级集合推导这些内部条件,而非维护第二套执行状态机。
|
||||
`running` 表示 Agent 拥有活跃的准入或轮次,或正在唤醒收件箱工作;`waiting` 表示它已完全停稳,但仍拥有至少一个尚未完成 dispose 的子 Activation;`settled` 表示已完全停稳且其拥有的每个子级都已 dispose,此时管理器会 dispose [`AgentHandle`](core.md#creation-and-ownership) 并移除该 Activation。管理器根据 Agent 的完全停稳状态与其拥有的子级集合推导这些内部条件,而非维护第二套执行状态机。
|
||||
|
||||
Agent 收件箱是唯一的队列。每条继续执行消息都会成为一个 `Agent.followup()` FIFO 轮次,因此已接受的消息共享同一个可观测顺序,且后续消息无法改变已在进行中的轮次。投递成功会返回被接受的 `MessageId`;既有的 `agent/inbox/enqueue`、`agent/inbox/dequeue` 与 `agent/inbox/discard` 事件仍是消息生命周期的观测点,继续执行层不定义任何 subagent 专属的投递路由。
|
||||
Agent 收件箱是唯一的队列。每条继续执行消息都会成为一个 `Agent.followup()` FIFO 轮次,因此已接受的消息共享同一个可观测顺序,且后续消息无法改变已在进行中的轮次。投递成功会返回被接受的 `MessageId`;既有的 `agent/inbox/inserted`、`agent/inbox/claimed` 与 `agent/inbox/discarded` 事件仍是消息生命周期的观测点,继续执行层不定义任何 subagent 专属的投递路由。
|
||||
|
||||
后续操作的权限来自确切的在线 Agent 工具上下文。已认证的 Agent 必须是持久化子 agent 在 `SessionHeader.parentSession` 中记录的直接父级。`MessageSource` 与 `senderSessionId` 在准入之后是持久的来源凭据,不授予任何权限;可选的面向模型工具使用 `CoordinatorMessageSource`。
|
||||
|
||||
对于这两种操作,调用方 signal 仅在收件箱接受之前掌管查找、物化与准入。此后管理器独立掌管该 Activation:之后的调用方取消既不会取消已接受的轮次,也不会 dispose 子 agent,并且该 seam 不对外暴露任何 steering(中途引导)操作。
|
||||
|
||||
`SubagentService.interrupt(targetSessionId, authority)` 是唯一的公开停止操作:它同步完成鉴权,对在线目标发出 `Agent.cancel(cause, { keepInbox: true })`,然后不等待静止即返回。Activation、其尚未领取的待处理 inbox 工作与已发布的后代均不受影响;已被领取进入中断轮次的工作不会重新入队。被中断的 driver 进入 idle 后,一次唤醒发送会恢复被暂停的 FIFO 队列。不存在的目标——未知、一次性或已结算——以及未绑定管理器的组合是被接受的 no-op。对在线目标,错误的 parent 地址或不在其在线祖先链中的调用方会以 `UNAUTHORIZED` 拒绝;过期的 ancestor 对象和指向自身的 ancestor 请求会在查找目标前拒绝。
|
||||
`SubagentService.interrupt(targetSessionId, authority)` 是唯一的公开停止操作:它同步完成鉴权,对在线目标发出 `Agent.cancel(cause, { keepInbox: true })`,然后不等待完全停稳即返回。Activation、其尚未领取的待处理 inbox 工作与已发布的后代均不受影响;已被领取进入中断轮次的工作不会重新入队。被中断的 driver 进入 idle 后,一次唤醒发送会恢复被暂停的 FIFO 队列。不存在的目标——未知、一次性或已结算——以及未绑定管理器的组合是被接受的 no-op。对在线目标,错误的 parent 地址或不在其在线祖先链中的调用方会以 `UNAUTHORIZED` 拒绝;陈旧的 ancestor 对象和指向自身的 ancestor 请求会在查找目标前拒绝。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -154,7 +154,7 @@ type SubagentInterruptAuthority =
|
||||
| { readonly kind: 'ancestor'; readonly agent: Agent }
|
||||
```
|
||||
|
||||
每个 Activation 都拥有自己的 `AgentHandle` 和一个 `ownedChildren: Set<SessionId>`;由于一份会话至多有一个存活 Activation,子会话 id 无需另一个运行时化身引用即可标识存活的子 agent。启动子 agent 或提交源自 parent 的工作,会在子 agent 能够运行之前将其注册到受继续执行管理的父级集合中;只要该集合非空,该父级就无法 settle。顶层或其他非继续执行的 Agent 没有 Activation,处于 waiting 图之外。只有当子 Agent 已停稳、该子 agent 的每个子级都已 dispose、best-effort 的最终会话 flush 结算完毕,且子 agent 的 `AgentHandle` 完成 dispose 之后,才会释放子 agent。
|
||||
每个 Activation 都拥有自己的 `AgentHandle` 和一个 `ownedChildren: Set<SessionId>`;由于一份会话至多有一个存活 Activation,子会话 id 无需另一个运行时化身引用即可标识存活的子 agent。启动子 agent 或提交源自 parent 的工作,会在子 agent 能够运行之前将其注册到受继续执行管理的父级集合中;只要该集合非空,该父级就无法 settle。顶层或其他非继续执行的 Agent 没有 Activation,处于 waiting 图之外。只有当子 Agent 已完全停稳、该子 agent 的每个子级都已 dispose、best-effort 的最终会话 flush 结算完毕,且子 agent 的 `AgentHandle` 完成 dispose 之后,才会释放子 agent。
|
||||
|
||||
最终结算会等待 `ctx.sessions.flush(session)`,但会忽略其参与布尔值,因为任意 listener 都无法证明某个持久化后端已存储该状态。rejection 会被记录,但不会使 Activation 失败;管理器仍会 dispose 该 handle 并释放所有权,此后持久化的子 agent 状态在后续恢复时可能缺失或陈旧。管理器卸载会调用内部的管理器全局 drain,关闭准入并 dispose 每片在线森林;`drainContinuableDescendants(parents)` 只关闭由 host 确切拥有的在线 Agent 之下的准入,并 dispose 其可继续后代,而无关森林保持在线。两者都会等待各自作用域内已获准的物化过程,自顶向下传播取消,按 child-first 顺序释放 handle,并且即使个别分支失败也会等待所有选中分支。持久化子会话不受该进程内拆卸的影响。
|
||||
|
||||
@@ -219,7 +219,7 @@ interface SubagentReportOptions {
|
||||
}
|
||||
```
|
||||
|
||||
提供方只参与准备初始创建 spec,`spawn` 与 `fork` 在此有所不同。其返回的 spec 只携带分离的、提供方专属的创建输入——目前是可选的父级历史种子——不含 Agent、`AgentHandle`、prompt 投递、结果、dispose 或 resume 操作。冷恢复根本不经由提供方分发:管理器折叠通用描述符,通过同一个 activation-owner 作用域调用 `ctx.agents.resume()`,并提交等待中的轮次。
|
||||
提供方只参与准备初始创建 spec,`spawn` 与 `fork` 在此有所不同。其返回的 spec 只携带分离的、提供方专属的创建输入——目前是可选的父级历史种子——不含 Agent、`AgentHandle`、提示词投递、结果、dispose 或恢复操作。冷恢复根本不经由提供方分发:管理器折叠通用描述符,通过同一个 activation-owner 作用域调用 `ctx.agents.resume()`,并提交等待中的轮次。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -259,13 +259,13 @@ interface ContinuableCreateSpec {
|
||||
}
|
||||
```
|
||||
|
||||
描述符([descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts) 中的 `SubagentDescriptorData`)是每个由会话支撑的 subagent 所使用、按模式判别的持久化身份。两种模式都携带提供方名称。`one-shot` 描述符可以携带调用方拥有的可选显示 `label`;`continuable` 描述符要求以委派 `description` 作为持久化创建标签,并另外对已解析的子 agent `agentOptions.provider`/`model` 与可选的 `persona`/`toolFilter` 建立快照,用于冷恢复。它绝不会对可合并扩展的 `AgentOptions` 对象建立快照,因此无关的扩展值不会破坏继续执行,后续新增组合配置输入则是一次有意的版本更改。描述符省略 `subagentDepth`(冷恢复以持久化 header 中的 `delegationDepth` 作为单调下界)和 `outputSchema`(单次运行或 Activation 的结果契约,而非持久化身份)。
|
||||
描述符([descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts) 中的 `SubagentDescriptorData`)是每个由会话支撑的 subagent 所使用、按模式判别的持久化身份。两种模式都携带提供方名称。`one-shot` 描述符可以携带调用方拥有的可选显示 `label`;`continuable` 描述符要求以委派 `description` 作为持久化创建标签,并另外对已解析的子 agent `agentOptions.provider`/`model` 与可选的 `persona`/`toolFilter` 建立快照,用于冷恢复。它绝不会对可合并扩展的 `AgentOptions` 对象建立快照,因此无关的扩展值不会破坏继续执行,后续新增组合配置输入则是一次有意的版本更改。描述符省略 `subagentDepth`(冷恢复以持久化 header 中的 `delegationDepth` 作为单调下界)和 `outputSchema`(单次运行或 Activation 的结果约定,而非持久化身份)。
|
||||
|
||||
本地一次性提供方会在子 agent 的初始轮次内、首次请求前追加描述符。继续执行管理器会在任何提供方提供的谱系之后、初始 prompt 获准之前追加描述符;`header.seedLength` 仍是 fork 谱系边界:恢复时的描述符权威读取子 agent 自身的后缀,而供列表使用的身份投影以 last-wins 折叠 `subagent/descriptor`,子 agent 自己的描述符会覆盖 fork seed 中祖先的描述符。该事件只进入日志:不含 `surfaceOp`,绝不进入模型历史,并由仅追加日志跨压缩保留。格式错误的当前版本描述符属于损坏;本运行时无法对不受支持的版本进行分类。
|
||||
本地一次性提供方会在子 agent 的初始轮次内、首次请求前追加描述符。继续执行管理器会在任何提供方提供的谱系之后、初始提示词获准之前追加描述符;`header.seedLength` 仍是 fork 谱系边界:恢复时的描述符权威读取子 agent 自身的后缀,而供列表使用的身份投影以 last-wins 折叠 `subagent/descriptor`,子 agent 自己的描述符会覆盖 fork seed 中祖先的描述符。该事件只进入日志:不含 `surfaceOp`,绝不进入模型历史,并由仅追加日志跨压缩保留。格式错误的当前版本描述符属于损坏;本运行时无法对不受支持的版本进行分类。
|
||||
|
||||
## 持久化枚举:`listChildren()`、`listDescendants()` 与其条目
|
||||
|
||||
`SubagentService.listChildren(parentSessionId)` 从 `ctx.sessions.list()` 与可选 `ctx.sessionPersistence.list()` 的实时优先合并中枚举 parent 直接且由会话支撑的 subagent——不经查询 seam,也不会加载或恢复任何 Agent。候选是持久 header 携带 `origin: 'subagent'` 的直接 child;该标记只负责枚举分类与粗粒度的通用路由拒绝,不能证明描述符有效、child 可恢复或操作已获授权——身份由投影折叠负责,恢复由 Activation 契约负责。每行的 `mode`/`label` 是已注册 `subagent` projection unit 的值,经三级阶梯供值:存活 child 由注册表水位缓存供值(零日志读取);冷 child 先读可选的投影 checkpoint 缓存(`cachedSnapshot`——过 own-suffix seq 门的身份即定值,own descriptor 一经追加不可变);否则在一次 `persistence.inspect()` 读取上经注册表折叠(有界并发,每次列表重新计算)。该缓存是纯可选加速层:服务缺席、行里是 `null` 哨兵或 key 缺席、seq 门不过、读取出错,都静默落到权威重折。折叠规则是 `subagent/descriptor` last-wins 且没有失败通道:子 agent 自己的描述符覆盖 fork seed 中祖先的描述符,格式错误或版本不认识的载荷折叠为可序列化的 `null` 哨兵,视同无值。结果是按 `createdAt`、再按 id 排序的 `SubagentListEntry[]`:取到身份即生成带有 `mode: 'one-shot' | 'continuable'` 和 `activity: 'running' | 'inactive'` 的 `child` 条目;可继续条目始终携带 `label`,一次性条目则只在启动调用方提供展示元数据时携带该字段。已定局而折叠无身份的候选生成 `corrupt` diagnostic——缺失、格式错误与版本不认识的描述符有意不再细分,`unsupported` 为已按其路由的消费方保留在类型中但不再产出;运行中而无身份的候选被省略(描述符落盘前的创建窗口);冷检查失败生成一条 `unavailable` diagnostic 并在下次列表自然重试,因此一个损坏的 sibling 不会隐藏健康 child。`hasChildren` 标记存在持久 subagent origin 的直接后代,读取自同一份合并材料。活动状态只表示逻辑记录是否在 `ctx.sessions` 中存活,而不表示结果或可恢复性。缺少持久化时,枚举退化为仅存活枚举而不是报错——此时冷 child 本就无法恢复。缺少 `ctx.sessionProjections` 注册表时,`listChildren()` 抛出携带错误码 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 的 `SubagentError`,缺少会话存储时则抛出 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`,两者都在任何读取之前检查,因此零 child 的部署同样确定失败;列表工具在插件加载时要求 `ctx.subagents` 与 `ctx.agents`。UI 等服务消费方可以展示两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)则只保留可继续条目,并通过在线 Agent 注册表将状态细化为 `running`/`idle`/`complete` 词汇。枚举不会查询继续执行管理器的 Activation map、Agent 注册表或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的运行中可继续 child 仍可能因所有权冲突而拒绝投递。读路径的设计理由见[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)。
|
||||
`SubagentService.listChildren(parentSessionId)` 从 `ctx.sessions.list()` 与可选 `ctx.sessionPersistence.list()` 的实时优先合并中枚举 parent 直接且由会话支撑的 subagent——不经查询 seam,也不会加载或恢复任何 Agent。候选是持久 header 携带 `origin: 'subagent'` 的直接 child;该标记只负责枚举分类与粗粒度的通用路由拒绝,不能证明描述符有效、child 可恢复或操作已获授权——身份由投影折叠负责,恢复由 Activation 约定负责。每行的 `mode`/`label` 是已注册 `subagent` projection unit 的值,经三级阶梯供值:存活 child 由注册表水位缓存供值(零日志读取);冷 child 先读可选的投影 checkpoint 缓存(`cachedSnapshot`——过 own-suffix seq 门的身份即定值,own descriptor 一经追加不可变);否则在一次 `persistence.inspect()` 读取上经注册表折叠(有界并发,每次列表重新计算)。该缓存是纯可选加速层:服务缺席、行里是 `null` 哨兵或 key 缺席、seq 门不过、读取出错,都静默落到权威重折。折叠规则是 `subagent/descriptor` last-wins 且没有失败通道:子 agent 自己的描述符覆盖 fork seed 中祖先的描述符,格式错误或版本不认识的载荷折叠为可序列化的 `null` 哨兵,视同无值。结果是按 `createdAt`、再按 id 排序的 `SubagentListEntry[]`:取到身份即生成带有 `mode: 'one-shot' | 'continuable'` 和 `activity: 'running' | 'inactive'` 的 `child` 条目;可继续条目始终携带 `label`,一次性条目则只在启动调用方提供展示元数据时携带该字段。已定局而折叠无身份的候选生成 `corrupt` diagnostic——缺失、格式错误与版本不认识的描述符有意不再细分,`unsupported` 为已按其路由的消费方保留在类型中但不再产出;运行中而无身份的候选被省略(描述符落盘前的创建窗口);冷检查失败生成一条 `unavailable` diagnostic 并在下次列表自然重试,因此一个损坏的 sibling 不会隐藏健康 child。`hasChildren` 标记存在持久 subagent origin 的直接后代,读取自同一份合并材料。活动状态只表示逻辑记录是否在 `ctx.sessions` 中存活,而不表示结果或可恢复性。缺少持久化时,枚举退化为仅存活枚举而不是报错——此时冷 child 本就无法恢复。缺少 `ctx.sessionProjections` 注册表时,`listChildren()` 抛出携带错误码 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 的 `SubagentError`,缺少会话存储时则抛出 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`,两者都在任何读取之前检查,因此零 child 的部署同样确定失败;列表工具在插件加载时要求 `ctx.subagents` 与 `ctx.agents`。UI 等服务消费方可以展示两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)则只保留可继续条目,并通过在线 Agent 注册表将状态细化为 `running`/`idle`/`complete` 词汇。枚举不会查询继续执行管理器的 Activation map、Agent 注册表或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的运行中可继续 child 仍可能因所有权冲突而拒绝投递。读路径的设计理由见[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md)。
|
||||
|
||||
`SubagentService.listDescendants(rootSessionId)` 将同一份实时优先语料与基于投影的解释应用到根的完整后代树,并按稳定 pre-order 输出。普通会话和一次性 child 仍作为遍历节点,因此其下的可继续后代仍可发现;只有 `origin: 'subagent'` 的候选会生成条目。每个返回的 child 或 diagnostic 都从枚举所得的持久 header 附加树位置;冷检查在提供身份前还会重新校验完整生命周期:
|
||||
|
||||
@@ -333,7 +333,7 @@ interface SubagentStopReasonMap {
|
||||
|
||||
## 单次 run:`SubagentRun`
|
||||
|
||||
`SubagentRun` 是消费方持有的、指向一个已发布单次子 agent 的句柄——一次可 dispose 的前台委派,只有一个结果,绝不是持久化子 agent handle。发布后的提示词提交、轮次工作与基础设施故障归 `result` 所有。消费方 await 该结果并始终 dispose 该 run,直至完全停稳。子 agent 失败时以非 completed 的 stop reason resolve;只有无法表示的基础设施故障才会 reject。run 没有 steering,也没有 resume:可继续对话根本没有 run,因为继续执行管理器直接持有它们的 `AgentHandle`,并通过子 agent 自己的收件箱为每个轮次排序。
|
||||
`SubagentRun` 是消费方持有的、指向一个已发布单次子 agent 的句柄——一次可 dispose 的前台委派,只有一个结果,绝不是持久化子 agent handle。发布后的提示词提交、轮次工作与基础设施故障归 `result` 所有。消费方 await 该结果并始终 dispose 该 run,直至完全停稳。子 agent 失败时以非 completed 的 stop reason resolve;只有无法表示的基础设施故障才会 reject。run 没有 steering,也没有恢复:可继续对话根本没有 run,因为继续执行管理器直接持有它们的 `AgentHandle`,并通过子 agent 自己的收件箱为每个轮次排序。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/subprocess.md
|
||||
subprocess.md: 0bc2bf86518bcc60bef02554b94471425f2ac433
|
||||
subprocess.zh.md: 5d6425707edcf1952c25dbdc91dbf7aab3779350
|
||||
subprocess.zh.md: 7e27bf15dfe0cdde09459dbfb239ab25ccde126a
|
||||
|
||||
@@ -246,7 +246,7 @@ interface SubprocessOutcome {
|
||||
|
||||
## 服务行为
|
||||
|
||||
抽象的 [`SubprocessService`](../../packages/subprocess/subprocess/src/index.ts) seam 定义执行世界坐标、可执行文件查找、普通 `spawn` 与 `spawnTerminal`。[`LocalSubprocessService`](../../packages/subprocess/subprocess-local/src/index.ts) 以 detached 进程树、按处置方式接线、凭据清除、`node-pty`、平台进程检查,以及先终止再等待退出的资源释放实现这些能力。接口契约见 [`dsh-subprocess`](../../packages/subprocess/subprocess/README.md),本地机制见 [`dsh-subprocess-local`](../../packages/subprocess/subprocess-local/README.md)。
|
||||
抽象的 [`SubprocessService`](../../packages/subprocess/subprocess/src/index.ts) seam 定义执行世界坐标、可执行文件查找、普通 `spawn` 与 `spawnTerminal`。[`LocalSubprocessService`](../../packages/subprocess/subprocess-local/src/index.ts) 以 detached 进程树、按处置方式接线、凭据清除、`node-pty`、平台进程检查,以及先终止再等待退出的资源释放实现这些能力。接口约定见 [`dsh-subprocess`](../../packages/subprocess/subprocess/README.md),本地机制见 [`dsh-subprocess-local`](../../packages/subprocess/subprocess-local/README.md)。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/system-prompt.md
|
||||
system-prompt.md: 94ce40f8bf98dd4efe3514879c2527c2a7bd3b21
|
||||
system-prompt.zh.md: 37d366774089f91756433602a719e99b57747c17
|
||||
system-prompt.zh.md: c46ee6e2b70c6603500bd9061ed09b805ed61630
|
||||
|
||||
@@ -39,7 +39,7 @@ interface ToolProviderResult {
|
||||
|
||||
## 提示词段落
|
||||
|
||||
`PromptSection` 是一份只读的同进程注册契约。其文本可以是静态的,也可以从当前组装上下文动态解析。
|
||||
`PromptSection` 是一份只读的同进程注册约定。其文本可以是静态的,也可以从当前组装上下文动态解析。
|
||||
|
||||
```ts type-equiv
|
||||
/** One contributed section of the system prompt (registry input). */
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/tasks.md
|
||||
tasks.md: 6237607307cbab8511f968ed591e3e3b8b845c6a
|
||||
tasks.zh.md: 99a6fcc4f54c1b52e5c6fd393327cc768f064297
|
||||
tasks.zh.md: c73765b4d5ad0309f3473890557171af21527682
|
||||
|
||||
@@ -21,7 +21,7 @@ interface TaskKindMap {
|
||||
|
||||
`TaskStatus` 为 `'running' | 'stopping' | 'completed' | 'killed' | 'failed'`;生产方特有的事实归入 `TaskSnapshot.detail`。
|
||||
|
||||
## 生产方契约
|
||||
## 生产方约定
|
||||
|
||||
`TaskStart` 声明身份和启动器。运行时会在调用 `run()` 前完成预检,随后提交注册,不再执行可能失败的步骤。生产方拥有执行资源;运行时拥有身份、访问权限和生命周期状态。
|
||||
|
||||
@@ -151,7 +151,7 @@ interface TaskRead {
|
||||
|
||||
## 服务行为
|
||||
|
||||
抽象的 [`TaskService`](../../packages/tasks/tasks/src/index.ts) seam 定义原子 `start`、限定调用方作用域的 `get` 和 `list`、`read`、`kill`、有界 `wait`、故障隔离的 `onTaskDone` 监听器,以及 `attachSurface` 可用性防线;[`LocalTaskService`](../../packages/tasks/tasks-local/src/index.ts) 是其进程局部实现。授权会比较拥有者会话;拥有者清理会选择确切的已注册 `Agent` 实例。seam 契约见 [`dsh-tasks`](../../packages/tasks/tasks/README.md),注册表生命周期见 [`dsh-tasks-local`](../../packages/tasks/tasks-local/README.md),面向模型的接口见 [`dsh-tool-tasks`](../../packages/tasks/tool-tasks/README.md)。
|
||||
抽象的 [`TaskService`](../../packages/tasks/tasks/src/index.ts) seam 定义原子 `start`、限定调用方作用域的 `get` 和 `list`、`read`、`kill`、有界 `wait`、故障隔离的 `onTaskDone` 监听器,以及 `attachSurface` 可用性防线;[`LocalTaskService`](../../packages/tasks/tasks-local/src/index.ts) 是其进程局部实现。授权会比较拥有者会话;拥有者清理会选择确切的已注册 `Agent` 实例。seam 约定见 [`dsh-tasks`](../../packages/tasks/tasks/README.md),注册表生命周期见 [`dsh-tasks-local`](../../packages/tasks/tasks-local/README.md),面向模型的接口见 [`dsh-tool-tasks`](../../packages/tasks/tool-tasks/README.md)。
|
||||
|
||||
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/telemetry.md
|
||||
telemetry.md: 131c5814f29d70c356989e62fda1db5c1c5448d6
|
||||
telemetry.zh.md: 5d4a9d9994457bc06a9e4194c4807f88789a3cf0
|
||||
telemetry.zh.md: 147418000f240093f356fe9033612967f8e29ffb
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](telemetry.md) | 中文
|
||||
|
||||
对外的会话上报,拆分为一项[能力 seam](../capability-seams.md):seam 一侧([dsh-session-telemetry](../../packages/session/session-telemetry),`ctx.telemetry`)拥有捕获点、固定分片投影、`telemetry/record` 脱敏 waterfall(瀑布式事件)、handoff 游标与最小后端契约;部署方加载的后端([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel))则是原样配置的 OpenTelemetry JS SDK 日志流水线。它是一项可选能力,不属于 agent loop(智能体循环)主干,这里也没有任何内容会进入模型请求。边界公理(harness 的职责止于 `emit()`;批处理、重试、排队与丢失策略都属于上报 SDK)连同被否决的替代方案,均已在[复活 Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md)中定案;捕获点、游标与投影的契约见 [seam README](../../packages/session/session-telemetry/README.md)。
|
||||
对外的会话上报,拆分为一项[能力 seam](../capability-seams.md):seam 一侧([dsh-session-telemetry](../../packages/session/session-telemetry),`ctx.telemetry`)拥有捕获点、固定分片投影、`telemetry/record` 脱敏 waterfall(瀑布式事件)、handoff 游标与最小后端约定;部署方加载的后端([dsh-session-telemetry-otel](../../packages/session/session-telemetry-otel))则是原样配置的 OpenTelemetry JS SDK 日志流水线。它是一项可选能力,不属于 agent loop(智能体循环)主干,这里也没有任何内容会进入模型请求。边界公理(harness 的职责止于 `emit()`;批处理、重试、排队与丢失策略都属于上报 SDK)连同被否决的替代方案,均已在[复活 Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md)中定案;捕获点、游标与投影的约定见 [seam README](../../packages/session/session-telemetry/README.md)。
|
||||
|
||||
源码:[`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts)
|
||||
|
||||
@@ -56,7 +56,7 @@ interface TelemetryRecord {
|
||||
|
||||
每个 `(turn, step)` 只发出第一条 `assistant/chunk`,即「流已开始」的信号;其余分片在捕获时丢弃,因此导出流中的 `seq` 缺口是常态,绝不是丢失信号。其他所有[会话事件](session.md)类型都会完整透传,包括该 seam 从未听说过、由插件合并进来的事件类型。投递是尽力而为的:游标标记的是「已交接」而非「已送达」,记录可能丢失(崩溃、重载窗口)也可能重复(无游标的重新接管、SDK 重试),因此接收端对 ledger 记录基于 `(session.id, event.seq)` 去重;ops 记录刻意省略这类标识——它们是用于告警的信号,而非用于累加的条目,重复被容忍而非被去重。
|
||||
|
||||
## 后端契约
|
||||
## 后端约定
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -105,7 +105,7 @@ interface TelemetryBackend {
|
||||
}
|
||||
```
|
||||
|
||||
`Telemetry`(`ctx.telemetry`,[签名](#ctxtelemetry--telemetry-abstract-seam))是该契约的可加载形态:每个上下文只允许一个实现,重复加载会抛出异常;后端在其构造函数中组合 seam 的 `TelemetryCoordinator`,以此装配捕获侧。
|
||||
`Telemetry`(`ctx.telemetry`,[签名](#ctxtelemetry--telemetry-abstract-seam))是该约定的可加载形态:每个上下文只允许一个实现,重复加载会抛出异常;后端在其构造函数中组合 seam 的 `TelemetryCoordinator`,以此装配捕获侧。
|
||||
|
||||
## 脱敏 waterfall:`telemetry/record`
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/tools.md
|
||||
tools.md: 0551ee1c9dfa12b415c1f4575b5225f771cb53bc
|
||||
tools.zh.md: 50843b07f1d98b1c9d9222288b1273b34bee1e4a
|
||||
tools.zh.md: acdf10a0140e81dada9104653dee92dc9cb6f50d
|
||||
|
||||
@@ -148,7 +148,7 @@ type InferArgs<S> = InferProperties<S, []>
|
||||
|
||||
`defineTool({ name, description, parameters, output, execute, … })` 将参数推导与 `parameterSchemaSpecToJsonSchema()` 和 `validateArgs()` 绑定,并将 `execute`/`render`/`presentationMeta` 与 `InferValue<OutputSchema>` 绑定。Schema 记录只包含自有且可枚举的字符串键,schema 数组是稠密的内建数组,因此推导、编译与校验观察到的是同一份声明。精确推导保持到 16 层容器,之后放宽为 `JsonValue`;运行时校验仍会继续遍历完整 schema。`valueSchemaSpecToJsonSchema()` 通过同一套已强制执行的原始子集编译输出声明。参数不匹配时抛出 `ToolArgsError`(`INVALID_ARGS`);函数体或后置策略产生的值无效时抛出 `ToolOutputError`(`INVALID_TOOL_OUTPUT`)。两者都经由常规工具错误路径处理。原始 JSON Schema 默认保持开放;不支持的关键字会被拒绝,而不会在未强制执行的情况下获准进入。
|
||||
|
||||
注册是一个受信任的同进程契约。注册表以 readonly 输入借用类型化定义,要求它声明 `output`,校验其原始 schema,并检查 `timeoutMs` 必须为正有限值等语义要求;`schemas()` 在模型边界处物化显式的面向模型投影,使执行和展示共享同一份已解析定义,而不会将回调泄漏到协议上。
|
||||
注册是一个受信任的同进程约定。注册表以 readonly 输入借用类型化定义,要求它声明 `output`,校验其原始 schema,并检查 `timeoutMs` 必须为正有限值等语义要求;`schemas()` 在模型边界处物化显式的面向模型投影,使执行和展示共享同一份已解析定义,而不会将回调泄漏到协议上。
|
||||
|
||||
## `ToolRestriction` — 单个作用域的实时全局过滤器
|
||||
|
||||
@@ -243,7 +243,7 @@ type ToolExecutionMode =
|
||||
| { kind: 'exclusive' }
|
||||
```
|
||||
|
||||
Code Mode 的桥接层还会把每个已结算的子分派暴露给 `tools/code-dispatch-log` waterfall,该 waterfall 可以改写持久事件所存的内容副本(程序取得的值与模型契约均不受影响):
|
||||
Code Mode 的桥接层还会把每个已结算的子分派暴露给 `tools/code-dispatch-log` waterfall,该 waterfall 可以改写持久事件所存的内容副本(程序取得的值与模型约定均不受影响):
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -452,7 +452,7 @@ type ObjectJsonSchema = JsonSchemaNode & { type: 'object' }
|
||||
- `ToolCallView`(待执行):`{ card: 'generic', title, kind?, rawInput?, content?, locations? }`(默认卡片;`locations` 是 `{ path, line? }[]`,表示调用读取/修改的文件,供编辑器跟随)、`{ card: 'terminal', title, description?, cwd? }`(shell 命令→终端卡片)、或 `{ card: 'diff', title, diffs, locations? }`(文件创建/修改→行内 diff 卡片;`diffs` 是 `{ path, oldText, newText }[]`,新文件时 `oldText: null`)。
|
||||
- `ToolResultView`(已完成):`{ card: 'generic', title?, content? }`、`{ card: 'terminal', title?, output?, exitCode?, signal? }`(捕获的运行输出 + 退出状态;有能力的 UI 显示退出状态标签,其他 UI 可以派生围栏 ` ```console ` 回退)、`{ card: 'diff', title?, diffs }`(已完成的文件变更→要展示的变更,通常是从变更前后内容计算出带上下文行的已应用 hunk,或在没有前像时的整文件 diff)、`{ card: 'search', shape, title?, truncated, total, … }`(已完成的发现型搜索→`shape: 'matches'`(grep)为按文件分组的匹配,`shape: 'paths'`(glob)为扁平路径列表;`truncated`/`total` 报告内联结果是否被截断,使 UI 永不把部分结果当作完整结果呈现;该视图不携带结果文本——无 search 卡片的 UI 回退到原始结果内容)、`{ card: 'read', title?, path, offset, lines, totalLines, lang?, content? }`(已完成的文件读取→带行号、可选语法高亮的代码视图;`offset` 是窗口请求的 1-based 起始行,即使 `lines` 为空也保留;`lang` 是从扩展名推得的语言提示,`content` 是无读取能力的 UI 回退时使用的去信封文本)、或 `{ card: 'web', kind: 'search' | 'fetch', title?, … }`(已完成的 web 检索;`kind: 'search'` 携带结构化的 `sources`/`answer?`/`truncated`,`kind: 'fetch'` 携带 `url`/`statusCode`/`truncated`,不具备 `web` 能力的 UI 回退到原始结果内容——正文不会重复进视图)。已完成视图会替换待执行视图,因此变更工具即使与调用时的片段重复也要返回 diff 结果;搜索和 web 检索都没有 `card` 的调用时对应视图(其 pending 状态保持为 generic 卡片,因为结构化结果只在 `execute` 之后才存在)。
|
||||
|
||||
`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)用于为通用卡片选择图标。`FileLocation`(`{ path, line? }`)、`FileDiff`(`{ path, oldText, newText }`)与 `ReadFileLine`(`{ number, text }`,读取窗口中一行带 1-based 行号的内容)是共享的文件卡片词汇。该设计由[渲染意图联合类型 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md)固定;host/client 运行时将这套中性词汇投影为各自的视图。
|
||||
`ToolCallKind`(`'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'fetch' | 'other'`)用于为通用卡片选择图标。`FileLocation`(`{ path, line? }`)、`FileDiff`(`{ path, oldText, newText }`)与 `ReadFileLine`(`{ number, text }`,读取窗口中一行带 1-based 行号的内容)是共享的文件卡片词汇。该设计由[渲染意图联合类型 Agent Note](../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md)固定;host/client 运行时将这套中性词汇投影为各自的视图。
|
||||
|
||||
完整的展示字段文档见 [`packages/core/tools/src/presentation.ts`](../../packages/core/tools/src/presentation.ts)。`bash` schema 与执行器见 [bash.md](bash.md);通用后台控制见 [tasks.md](tasks.md)。
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/typert.md
|
||||
typert.md: 8ce52837ceee8e9c8c4a61de28f972912faa2cf0
|
||||
typert.zh.md: ff6b45a517c75392ee87fa348d72bfae6cdf1efb
|
||||
typert.zh.md: a025716dad9a9279a45530a0a9109a13a2c34b0c
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](typert.md) | 中文
|
||||
|
||||
以下类型由生成的 Remote 产物、Host Gateway 与消费方 API assembly 共用。[TypeRT Gateway Agent Note](../../.agents/notes/implemented/architecture/2026-08-02-typert-remote-method-calls.md) 负责架构与传输决策;本页记录 [`dsh-type-meta`](../../packages/typert/type-meta/src/types.ts) 和 [`dsh-api-gateway`](../../packages/api/gateway/src/types.ts) 中公共契约的字面定义。
|
||||
以下类型由生成的 Remote 产物、Host Gateway 与消费方 API assembly 共用。[TypeRT Gateway Agent Note](../../.agents/notes/implemented/architecture/2026-08-02-typert-remote-method-calls.md) 负责架构与传输决策;本页记录 [`dsh-type-meta`](../../packages/typert/type-meta/src/types.ts) 和 [`dsh-api-gateway`](../../packages/api/gateway/src/types.ts) 中公共约定的字面定义。
|
||||
|
||||
## Lookup 与 Context 声明
|
||||
## Lookup 与上下文声明
|
||||
|
||||
业务对象包通过声明合并扩展两个空 map。lookup 将一种 Host 对象类型与其 wire identity 关联;Context 声明将一种 scoped Context 类别与其 wire identity 关联。生成的 descriptor 引用这些 key,运行时提供方则提供活对象解析行为。
|
||||
业务对象包通过声明合并扩展两个空 map。lookup 将一种 Host 对象类型与其 wire identity 关联;上下文声明将一种作用域上下文类别与其 wire identity 关联。生成的 descriptor 引用这些 key,运行时提供方则提供活对象解析行为。
|
||||
|
||||
```ts type-equiv
|
||||
/** Merge-extensible Host object lookup declarations. */
|
||||
@@ -114,7 +114,7 @@ interface InvocationDescriptor {
|
||||
|
||||
## TypeRT 注册表
|
||||
|
||||
`ctx.typert` 分开保存当前环境的 descriptor、显式选择的 Remote contribution、lookup 提供方与 scoped Context 提供方。lookup 提供方拥有稳定 wire 声明和默认 resolver;Host 组合可以为同一个 key 配置 effect-scoped 同步或异步 resolver,配置卸载后恢复默认策略。各项注册都是由 Cordis 持有的 effect,并返回可等待的 disposer。
|
||||
`ctx.typert` 分开保存当前环境的 descriptor、显式选择的 Remote contribution、lookup 提供方与作用域上下文提供方。lookup 提供方拥有稳定 wire 声明和默认 resolver;Host 组合可以为同一个 key 配置 effect-scoped 同步或异步 resolver,配置卸载后恢复默认策略。各项注册都是由 Cordis 持有的 effect,并返回可等待的 disposer。
|
||||
|
||||
```ts type-equiv
|
||||
/** Minimal TypeRT runtime consumed through dependency inversion. */
|
||||
@@ -135,7 +135,7 @@ interface TypeRTRemoteNamespaceMap {}
|
||||
|
||||
## Host Gateway
|
||||
|
||||
Connection 会先解码 carrier envelope,再调用 `ctx.typertGateway`。请求将精确的具名 wire 字段与 carrier 的取消 signal 分开携带;基础设施与边界失败使用 Gateway 的进程内错误分类体系,普通异常由 RPC 适配器折叠为传输层的 `internal` 错误码,lookup 策略通过 `TypeRTLookupFailure` 携带的既有 RPC error 则原样返回。
|
||||
Connection 会先解码 carrier envelope,再调用 `ctx.typertGateway`。请求将精确的具名 wire 字段与 carrier 的取消 signal 分开携带;基础设施与边界失败使用 Gateway 的进程内错误分类体系,普通异常由 RPC 适配器归并为传输层的 `internal` 错误码,lookup 策略通过 `TypeRTLookupFailure` 携带的既有 RPC error 则原样返回。
|
||||
|
||||
```ts type-equiv
|
||||
/** One Remote method request after a carrier has decoded its envelope. */
|
||||
@@ -188,7 +188,7 @@ interface TypertGateway {
|
||||
|
||||
## 消费方 Remote
|
||||
|
||||
`ctx.remote` 只暴露由已导入 `/remote` 产物贡献的 namespace。`$mount()` 会把生成的 descriptor 与具体方法作为一项由 fiber 持有的操作统一注册。每个 namespace 都是可追踪的 `remote.<namespace>` Cordis 子 Service,其生命周期覆盖已挂载的方法;JavaScript Proxy 与 Host 业务 Service 类型都不会进入消费方。
|
||||
`ctx.remote` 只暴露由已导入 `/remote` 产物贡献的 namespace。`$mount()` 会把生成的 descriptor 与具体方法作为一项由 fiber 持有的操作统一注册。每个 namespace 都是可追踪的 `remote.<namespace>` Cordis 子服务,其生命周期覆盖已挂载的方法;JavaScript Proxy 与 Host 业务服务类型都不会进入消费方。
|
||||
|
||||
```ts type-equiv
|
||||
/** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/user-interaction.md
|
||||
user-interaction.md: a19155ae06af0133ae468c004b2e3b66f1de3fb8
|
||||
user-interaction.zh.md: dc5845a976068981b2761e26502eaf7dd95dcb01
|
||||
user-interaction.zh.md: c7aa9cafc9865191cda4089ad2beb214a33b00ef
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](user-interaction.md) | 中文
|
||||
|
||||
[dsh-user-interaction](../../packages/interaction/user-interaction) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。UI surface 提供活跃的 `UserInteractionProvider`;host 运行时把请求转发给它连接的客户端。
|
||||
[dsh-user-interaction](../../packages/interaction/user-interaction) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。UI 界面提供活跃的 `UserInteractionProvider`;host 运行时把请求转发给其连接的客户端。
|
||||
|
||||
源码:[`packages/interaction/user-interaction/src/index.ts`](../../packages/interaction/user-interaction/src/index.ts)
|
||||
|
||||
@@ -70,7 +70,7 @@ interface AskUserQuestionItem {
|
||||
|
||||
## 提问请求
|
||||
|
||||
`AskUserQuestionRequest` 是跨包(package)的请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。如提供 `agent`,它必须与存活调用方是同一实例;只有当当前注册表将该实例识别为运行时根时,交互 seam 才会接纳该 agent。
|
||||
`AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。如提供 `agent`,它必须与存活调用方是同一实例;只有当当前注册表将该实例识别为运行时根时,交互 seam 才会接纳该 agent。
|
||||
|
||||
```ts type-equiv
|
||||
/** Request for a human answer. */
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/subsystems/web.md
|
||||
web.md: f300bf2daef172fe4a69c00f36c804cf874c189d
|
||||
web.zh.md: 0c72e343c1b6ea5de8e7c296014da35b0291a33b
|
||||
web.zh.md: 36afee9a964a0ad185242d5ee8f4f91689b1d295
|
||||
|
||||
@@ -128,7 +128,7 @@ type WebFetchBody =
|
||||
|
||||
## 错误
|
||||
|
||||
`WebError extends HarnessError`([core.md](core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的错误代码,消费方必须容忍未知错误代码。错误代码按所有者划分。由 seam 统一定义的错误代码来自 `WebService` 的选择逻辑和共享契约:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmService` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障经 seam 暴露时使用的兜底代码,包括 DNS、连接被拒绝、TLS 等网络或传输故障)。抓取传输层错误代码由 `dsh-web-fetch-local` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。
|
||||
`WebError extends HarnessError`([core.md](core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的错误代码,消费方必须容忍未知错误代码。错误代码按所有者划分。由 seam 统一定义的错误代码来自 `WebService` 的选择逻辑和共享约定:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmService` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障经 seam 暴露时使用的兜底代码,包括 DNS、连接被拒绝、TLS 等网络或传输故障)。抓取传输层错误代码由 `dsh-web-fetch-local` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。
|
||||
|
||||
## 服务
|
||||
|
||||
|
||||
Reference in New Issue
Block a user