|
|
@@ -2,21 +2,21 @@
|
|
|
|
|
|
[English](README.md) | 中文
|
|
|
|
|
|
-SDK provider 把每个子代理作为一个完整的 DeepSeek Harness 运行时跑在全新子进程里,经由 [TypeScript SDK 客户端](../../sdk/sdk-client/README.md)走 stdio JSON-RPC 驱动。它是 [`subagent-acp`](../subagent-acp/README.md) 之外的第二个进程外后端,差异在线协议与子进程契约:ACP 后端能驱动任何 Agent Client Protocol 代理;本后端专门驱动 harness SDK 运行时(`dsh-jsonrpc-agent` bin 或打包可执行文件),因此子进程是一个完整的对等 harness——自有 `cordis.yml` 决定的组成、会话持久化、模型路由与工具。
|
|
|
+SDK 提供方会在全新的子进程中把每个 subagent 作为完整的 DeepSeek Harness 运行时运行,并经由 [TypeScript SDK 客户端](../../sdk/sdk-client/README.md) 通过 stdio JSON-RPC 驱动。它是 [`subagent-acp`](../subagent-acp/README.md) 之外的第二个进程外后端,差异在协议格式(wire format)和子进程契约:ACP(Agent Client Protocol)后端能驱动任何 Agent Client Protocol agent(智能体);本后端专门驱动 harness SDK 运行时(`dsh-jsonrpc-agent` bin 或打包后的可执行文件),因此子进程是一个完整的对等 harness,拥有由 `cordis.yml` 决定的组合、会话持久化、模型路由和工具。
|
|
|
|
|
|
## 启动与所有权
|
|
|
|
|
|
-`start(request)` 先解析子进程工作目录,经 `DeepSeekHarness` 生成运行时,并在履行前完成 `initialize` 握手(携带配置的 `provider`/`model` 路由及可选的 `maxTokens` 输出上限)。因此履行意味着子运行时已就绪、所有权已移交调用方。生成、握手或发布前取消的失败只在子进程被收割之后拒绝;工作目录解析失败在生成任何东西之前拒绝。
|
|
|
+`start(request)` 先解析子进程工作目录,通过 `DeepSeekHarness` spawn 运行时,并在履行前完成 `initialize` 握手(携带配置的 `provider`/`model` 路由及可选的 `maxTokens` 输出上限)。因此,履行意味着子运行时已就绪、所有权已移交给调用方。spawn、握手或发布前取消失败时,只会在子进程被回收后拒绝;工作目录解析失败则会在尚未 spawn 任何内容时拒绝。
|
|
|
|
|
|
-工作目录的解析与 ACP 后端完全一致,经由接缝共享的进程外助手([`dsh-subagent`](../subagent/README.md)):设置了 `cwd` 覆盖则用之(加载时校验一次),否则用发起委托的父会话 cwd——绝不用服务器进程自己的 cwd。解析出的路径同时成为子进程 cwd 与其 SDK 会话的工作区 cwd。
|
|
|
+工作目录的解析与 ACP 后端完全一致,并使用 seam 共享的进程外辅助工具([`dsh-subagent`](../subagent/README.md)):设置了 `cwd` 覆盖值时使用该值(加载时校验一次),否则使用发起委派的父会话 cwd,绝不使用服务器进程自身的 cwd。解析出的路径同时成为子进程 cwd 和其 SDK 会话的工作区 cwd。
|
|
|
|
|
|
-返回的 run id 铸造于父命名空间;子运行时的会话 id 只存在于子进程内部。发布之后,provider 跑一个 SDK 回合,并从子会话事件中读取答案:最后一条完整 `assistant/message`,或回合被截断时已累积的 `text-delta` 流——部分答案在取消与错误路径上都得以保留。
|
|
|
+返回的 run id 在父级命名空间中生成;子运行时的会话 id 只存在于子进程内部。发布后,提供方运行一个 SDK 轮次,并从子会话事件中读取答案:最后一条完整的 `assistant/message`,或轮次被截断时已累积的 `text-delta` 流;部分答案在取消和错误路径上都得以保留。
|
|
|
|
|
|
-`dispose()` 幂等:先把结果就地定格为 `aborted`(线上没有 prompt 取消方法),再关闭运行时——一次有界的协议 `shutdown` 请求,随后是共享的 stdin-EOF → SIGTERM → SIGKILL 阶梯直到真正退出。
|
|
|
+`dispose()`(资源释放)是幂等的:先在本地把结果确定为 `aborted`(协议层面没有提示词取消机制),再关闭运行时,即先发出一次有界的协议 `shutdown` 请求,随后通过共享的 stdin-EOF → SIGTERM → SIGKILL 阶梯使进程实际退出。
|
|
|
|
|
|
## 停止原因映射
|
|
|
|
|
|
-子进程在 `session.finished` 上以结构化 `TurnEndReason` 报告回合结局;provider 把它映射进接缝词汇表。`completed` → `completed`,`max-tokens` → `max-tokens`,`aborted` → `aborted`;其余一切——`error`、`interrupted`、`disposed`、未来变体、或根本没跑回合——映射为 `error`,不洁终止绝不报告为成功。发布后的传输层失败经 `onError` 诊断汇(接到 `ctx.logger.warn`)压平为 `stopReason: 'error'`;接缝契约禁止 `result` 拒绝。
|
|
|
+子进程在 `session.finished` 上以结构化 `TurnEndReason` 报告轮次结果;提供方将其映射为 seam 词汇。`completed` → `completed`,`max-tokens` → `max-tokens`,`aborted` → `aborted`;其余情况,包括 `error`、`interrupted`、`disposed`、未来变体或根本未运行轮次,均映射为 `error`,因此非正常停止绝不会报告为成功。发布后的传输层失败会通过 `onError` 诊断接收器(连接到 `ctx.logger.warn`)压平为 `stopReason: 'error'`;seam 契约禁止 `result` 被拒绝。
|
|
|
|
|
|
## 能力与上下文
|
|
|
|
|
|
@@ -27,14 +27,14 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
|
|
|
| 键 | 默认 | 含义 |
|
|
|
|---|---|---|
|
|
|
| `providerName` | `dsh-sdk` | `ctx.subagents` 上的注册名。 |
|
|
|
-| `command` | 必填 | 每次 run 生成的可执行文件(子运行时 bin 或打包 exe)。 |
|
|
|
+| `command` | 必填 | 每次运行时 spawn 的可执行文件(子运行时 bin 或打包后的可执行文件)。 |
|
|
|
| `args` | `[]` | 命令参数(通常是子进程的 `cordis.yml` 路径)。 |
|
|
|
| `cwd` | 父会话 cwd | 工作目录覆盖;校验规则与 [`subagent-acp`](../subagent-acp/README.md) 相同。 |
|
|
|
-| `provider` | `deepseek` | 写入子进程 `initialize` 的 provider 路由。 |
|
|
|
+| `provider` | `deepseek` | 写入子进程 `initialize` 的提供方路由。 |
|
|
|
| `model` | `deepseek-v4-flash` | 写入子进程 `initialize` 的模型。 |
|
|
|
-| `maxTokens` | provider 默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限;对子根 Agent 及其进程内后代生效。 |
|
|
|
+| `maxTokens` | 提供方默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限;对子运行时的根 agent 及其进程内后代生效。 |
|
|
|
| `env` | `{}` | 在凭据擦除后的父环境之上叠加的显式子环境(例如子进程自己的 `DEEPSEEK_API_KEY`,或 `DSH_CORDIS_CONFIG`)。 |
|
|
|
-| `shutdownTimeoutMs` | `1000` | 处置期间协议 `shutdown` 交换的时限。 |
|
|
|
+| `shutdownTimeoutMs` | `1000` | dispose 期间协议 `shutdown` 交换的时限。 |
|
|
|
| `disposeEofGraceMs` | `6000` | stdin EOF 之后、平台终止之前的宽限。 |
|
|
|
| `disposeGraceMs` | `3000` | 终止后的退出确认窗口;POSIX 在 SIGTERM 之后、SIGKILL 之前也等待同样时长。 |
|
|
|
|
|
|
@@ -55,45 +55,45 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
|
|
|
|
|
|
## 进程边界
|
|
|
|
|
|
-子环境以 [`dsh-subprocess`](../../subprocess/README.md) 接缝的 `scrubbedParentEnv()` 为基底——移除形似凭据与 `DSH_*` 的环境变量——再在擦除之后合并显式 `config.env` 值。子进程由 SDK 客户端生成而非经 `ctx.subprocess`(subprocess README 记载的 SDK 托管传输例外),因此本后端自行应用该擦除。JSON-RPC 线就是真实的序列化边界。
|
|
|
+子进程环境以 [`dsh-subprocess`](../../subprocess/README.md) seam 的 `scrubbedParentEnv()` 为基础,先移除疑似凭据和名称为 `DSH_*` 的环境变量,再合并显式 `config.env` 值。子进程由 SDK 客户端 spawn,而不是经由 `ctx.subprocess` spawn(这是 subprocess README 中记录的 SDK 托管传输例外),因此本后端会自行执行环境清理。JSON-RPC 协议格式才是真正的序列化边界。
|
|
|
|
|
|
-本包没有默认导出。否则 Cordis loader 解包会隐藏具名 `inject` 元数据;见[事后分析 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
|
|
|
+本包(package)没有默认导出。否则 Cordis loader 解包会隐藏具名 `inject` 元数据;见[事故复盘 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md)。
|
|
|
|
|
|
免密钥测试通过真实 stdio 驱动 SDK 客户端包的脚本化伪运行时,还包括一个 Loader 组合 e2e:子进程是真实的第二个 harness 运行时,端到端证明父会话 cwd 继承(`tests/loader-composition.e2e.ts`)。
|
|
|
|
|
|
-## Model Experience
|
|
|
+## 模型体验
|
|
|
|
|
|
-### Child-agent request
|
|
|
+### 子 agent 请求
|
|
|
|
|
|
-#### What the model sees
|
|
|
+#### 模型看到的内容
|
|
|
|
|
|
-子运行时的模型收到独立任务作为其用户消息,加上该运行时自己配置的系统提示、工具与全新会话。它收不到任何父对话。本 provider 不宣告可选启动期能力,因此本地服务会拒绝需要 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略。
|
|
|
+子运行时的模型会收到作为用户消息的独立任务,以及该运行时自身配置的系统提示词、工具和全新会话。它不会收到父级对话。本提供方不声明可选的启动时能力,因此本地服务会拒绝要求 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略这些要求。
|
|
|
|
|
|
-#### Token effect
|
|
|
+#### Token 影响
|
|
|
|
|
|
-子进程支付一份独立的完整上下文与自己的多步历史。这些 token 绝不进入父上下文。
|
|
|
+子运行时会为独立的完整上下文及其多步骤历史消耗 token。这些 token 绝不会进入父级上下文。
|
|
|
|
|
|
-#### KV Cache effect
|
|
|
+#### KV Cache 影响
|
|
|
|
|
|
-独立于父请求缓存。每个 SDK 子进程只能复用在其自身 provider、模型、组成与历史下完全相同的前缀;子步骤在此之外只增不改。
|
|
|
+与父级请求缓存相互独立。每个 SDK 子进程只能复用其自身提供方、模型、组合和历史均相同时的前缀;除此之外,子 agent 的步骤仅追加增长。
|
|
|
|
|
|
-### Parent tool result, indirectly
|
|
|
+### 父级工具结果(间接)
|
|
|
|
|
|
-#### What the model sees
|
|
|
+#### 模型看到的内容
|
|
|
|
|
|
-经由 `dsh-tool-subagent`,父方只收到子进程的最终助手文本(或累积的部分文本),或该消费者精确的停止原因错误——收不到中间消息与工具流量。
|
|
|
+经由 `dsh-tool-subagent`,父级只会收到子运行时最终的 assistant 文本(或累积的部分文本),或该消费方给出的精确停止原因错误;不会收到中间消息或工具流量。
|
|
|
|
|
|
-#### Token effect
|
|
|
+#### Token 影响
|
|
|
|
|
|
-父输入只增长最终结果或错误,其大小依数据而定,保留至压缩。本 provider 自身不给父方增加任何 schema。
|
|
|
+父级输入只增加最终结果或错误,其大小取决于数据,并保留到 compaction(上下文压缩)为止。本提供方自身不会向父级添加任何 schema。
|
|
|
|
|
|
-#### KV Cache effect
|
|
|
+#### KV Cache 影响
|
|
|
|
|
|
-只追加;新可见内容跟在可复用请求前缀之后,不使既有 KV 缓存条目失效。
|
|
|
+仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
|
|
|
|
|
|
-## Known Limitations and Deferred Work
|
|
|
+## 已知限制与暂缓事项
|
|
|
|
|
|
-- **每次 run 一个全新运行时进程** —— 无池化;harness 运行时要启动完整插件树,单次生成成本高于 ACP 后端的典型子进程。
|
|
|
-- **无可选启动期能力** —— 父方无法在子进程内强制 `outputSchema`、深度、工具过滤或 persona;请改为配置子进程自己的 `cordis.yml`。
|
|
|
-- **子进程的转录留在其自己的会话根** —— 父日志只记录委托工具调用/结果(接缝的子隔离规则);流式 `session.event` 通道只用于提取输出,不桥接进父日志。
|
|
|
-- **仅限本地子进程** —— 解析出的 cwd 是本地路径;远程运行时需要自己的后端。
|
|
|
+- **每次运行都使用全新的运行时进程**:不使用进程池;harness 运行时需要启动完整的插件树,因此每次运行的 spawn 成本高于 ACP 后端通常使用的子进程。
|
|
|
+- **不支持可选的启动时能力**:父级无法在子进程内强制执行 `outputSchema`、深度限制、工具过滤或 persona;应改为配置子进程自身的 `cordis.yml`。
|
|
|
+- **子进程的 transcript(文本记录)保留在其自身的会话根目录中**:父级日志只记录委派工具调用/结果(seam 的子级隔离规则);流式 `session.event` 通道只用于提取输出,不会桥接到父级日志中。
|
|
|
+- **仅支持本地子进程**:解析出的 cwd 是本地路径;远程运行时需要独立的后端。
|