From 42840394c4bb0601bf65b5708ce1de1ca0c55e72 Mon Sep 17 00:00:00 2001 From: j-xiang Date: Wed, 29 Jul 2026 15:29:38 +0800 Subject: [PATCH] docs(i18n): proofread README translations 81-100 --- packages/llm/README.zh.md | 12 +++--- packages/llm/llm-deepseek/README.zh.md | 38 ++++++++--------- packages/llm/llm-pi-ai/README.zh.md | 34 +++++++-------- packages/llm/llm-retry/README.zh.md | 10 ++--- packages/llm/llm/README.zh.md | 44 ++++++++++---------- packages/llm/token-meter/README.zh.md | 18 ++++---- packages/lsp/README.zh.md | 8 ++-- packages/lsp/lsp-local/README.zh.md | 18 ++++---- packages/lsp/lsp/README.zh.md | 16 +++---- packages/lsp/tool-lsp/README.zh.md | 16 +++---- packages/mcp/mcp-client/README.zh.md | 20 ++++----- packages/plan/README.zh.md | 4 +- packages/pty/README.zh.md | 8 ++-- packages/pty/pty-local/README.zh.md | 14 +++---- packages/pty/pty/README.zh.md | 20 ++++----- packages/pty/tool-pty/README.zh.md | 10 ++--- packages/sandbox/README.zh.md | 12 +++--- packages/sandbox/sandbox-local/README.zh.md | 22 +++++----- packages/sandbox/sandbox-policy/README.zh.md | 22 +++++----- packages/sandbox/sandbox/README.zh.md | 18 ++++---- 20 files changed, 182 insertions(+), 182 deletions(-) diff --git a/packages/llm/README.zh.md b/packages/llm/README.zh.md index 48c54358ce..1913db5f34 100644 --- a/packages/llm/README.zh.md +++ b/packages/llm/README.zh.md @@ -1,15 +1,15 @@ -# llm/:LLM 能力家族 +# llm/:LLM(大语言模型)能力家族 [English](README.md) | 中文 -LLM seam 及其提供方适配器。接口包(`llm`)拥有抽象服务、内容块词汇和流分片组装器;适配器是在 `ctx.llm` 上注册的具体实现。这些全是**产品** 包。 +LLM seam 及其提供方适配器。接口包(`llm`)拥有抽象服务、内容块词汇和流分片组装器;适配器是在 `ctx.llm` 上注册的具体实现。这些全是**产品**包(package)。 | 包 | 职责 | ctx key | |---|---|---| | `llm/` | 抽象 LLM 服务 + 内容块词汇 + 分片组装器 | `ctx.llm` | -| `token-meter/` | 感知回放的请求与表层 token 测量 | `ctx.tokenMeter` | -| `llm-retry/` | 确切提供方的 normal 或无界请求重试策略 | (监听 `agent/request-error`) | -| `llm-deepseek/` | DeepSeek API 适配器(直接 fetch + eventsource-parser SSE) | (注册到 `ctx.llm`) | +| `token-meter/` | 感知回放的请求 token 与表层 token 测量 | `ctx.tokenMeter` | +| `llm-retry/` | 确切提供方的常规或无界请求重试策略 | (监听 `agent/request-error`) | +| `llm-deepseek/` | DeepSeek API 适配器(直接 fetch + eventsource-parser SSE(Server-Sent Events)) | (注册到 `ctx.llm`) | | `llm-pi-ai/` | 通过 `@earendil-works/pi-ai` 实现的多提供方适配器 | (注册到 `ctx.llm`) | -接口位于 `llm/llm/`;适配器、重试策略和可复用的 token 计量器都是该分组下的扁平兄弟包。请求按 `provider` 路由,而 `model` 会原样传给选中的适配器。拥有路由的适配器提供重试策略,并解析可用的确切模型身份、上下文容量和推理元数据;重试执行器与 token 计量器仍与提供方无关。新的提供方适配器只需在 `ctx.llm` 上注册一个或多个提供方路由,无需改动消费方。两个已交付实现见[双生 LLM 适配器](../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md),测量归属见[回放 token 计量器 Agent Note](../../.agents/notes/implemented/architecture/2026-07-15-replay-token-meter-service.md),容量与压缩策略归属见[路由模型上下文 Agent Note](../../.agents/notes/implemented/architecture/2026-07-20-routed-model-context-and-compaction-policy.md)。 +接口位于 `llm/llm/`;适配器、重试策略和可复用的 token 计量器以扁平结构并列在该分组下。请求按 `provider` 路由,而 `model` 会原样传给选中的适配器。负责该路由的适配器提供重试策略,并解析可用的确切模型身份、上下文容量和推理元数据;重试执行器与 token 计量器仍与提供方无关。新的提供方适配器只需在 `ctx.llm` 上注册一个或多个提供方路由,无需改动消费方。两个已交付实现见[双生 LLM 适配器](../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md),测量归属见[回放 token 计量器 Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-15-replay-token-meter-service.md),容量与 compaction(上下文压缩)策略归属见[路由模型上下文 Agent Note](../../.agents/notes/implemented/architecture/2026-07-20-routed-model-context-and-compaction-policy.md)。 diff --git a/packages/llm/llm-deepseek/README.zh.md b/packages/llm/llm-deepseek/README.zh.md index 523bbbfd29..7f80b1055f 100644 --- a/packages/llm/llm-deepseek/README.zh.md +++ b/packages/llm/llm-deepseek/README.zh.md @@ -2,11 +2,11 @@ [English](README.md) | 中文 -harness LLM seam 的 DeepSeek chat-completions 适配器:直接 `fetch` + SSE(由 `eventsource-parser` 分帧),将官方协议格式(真源:API 文档 guides/thinking_mode、guides/tool_calls、api/create-chat-completion)转换为 `StreamChunk` 协议。 +harness LLM(大语言模型)seam 的 DeepSeek chat-completions 适配器:直接 `fetch` + SSE(Server-Sent Events,由 `eventsource-parser` 分帧),将官方协议格式(wire format;真源:API 文档 guides/thinking_mode、guides/tool_calls、api/create-chat-completion)转换为 `StreamChunk` 协议。 -同一 seam 的第二个库支持实现位于 `@deepseek-ai/dsh-llm-pi-ai`。本包始终拥有 `deepseek` 提供方路由;在同一上下文中装载 `provider: deepseek` 的 pi-ai profile 会按设计抛出 `LlmError('DUPLICATE_ADAPTER')`。 +同一 seam 的第二个基于库的实现位于 `@deepseek-ai/dsh-llm-pi-ai`。本包(package)始终负责 `deepseek` 提供方路由;在同一上下文中装载 `provider: deepseek` 的 pi-ai profile 会按设计抛出 `LlmError('DUPLICATE_ADAPTER')`。 -包根目录公开 Cordis 插件契约与 `DeepSeekAdapter`;协议序列化、SSE 解析与 chunk 转换 helper 不属于该根契约。 +包根入口导出 Cordis 插件契约与 `DeepSeekAdapter`;协议序列化、SSE 解析与 分片转换 helper 不属于该根契约。 ## 配置 @@ -36,33 +36,33 @@ harness LLM seam 的 DeepSeek chat-completions 适配器:直接 `fetch` + SSE 该插件注册唯一提供方路由 `deepseek`,同时注册解析后的 `retryPolicy`。请求使用 `provider: deepseek` 选择该路由;其 `model` 会作为协议 `model` 字符串原样传递,因此更改 DeepSeek 模型不需要生命周期时注册。省略 `models` 会公布 `deepseek-v4-flash`(名称为 `DeepSeek-V4-Flash`)和 `deepseek-v4-pro`(名称为 `DeepSeek-V4-Pro`),两者的上下文窗口均为 256,000 token;显式列表会替换这些默认值,`models: []` 则不公布任何模型。Catalog 配置项通过 `ctx.llm.listModels('deepseek')` 公开给 ACP(Agent Client Protocol)编辑器和 Web 选择器等客户端,但仍只提供建议:未列出模型 id 仍原样传递。省略配置项 name 默认为其 id。 -`contextWindow` 对每个已配置模型都可选,不会通过建议 catalog 公开。`ctx.llm.resolveModelInfo('deepseek', model).context` 先返回精确模型值,再对不含容量的配置项或未列出原样传递 id 返回 `defaultContextWindow`。两者都不存在时,`context` 字段缺失但不会使路由失效。因此,压力敏感插件可以获得部署拥有的容量,不会将模型 selector 视为权威。为 `deepseek` 注册另一个适配器会抛出 `LlmError('DUPLICATE_ADAPTER')`。 +`contextWindow` 对每个已配置模型都可选,不会通过建议 catalog 公开。`ctx.llm.resolveModelInfo('deepseek', model).context` 先返回精确模型值,再对不含容量的配置项或未列出原样传递 id 返回 `defaultContextWindow`。两者都不存在时,`context` 字段缺失但不会使路由失效。因此,压力敏感插件可以获得由部署决定的容量,不会将模型 selector 视为权威。为 `deepseek` 注册另一个适配器会抛出 `LlmError('DUPLICATE_ADAPTER')`。 -同一确切模型结果会在部署策略允许思考时,为每个原样传递模型在 `reasoning` 下公开有序的 `off`、`high` 和 `max` 推理强度。`reasoningEffort` 选择部署默认值,省略时回退为 `high`。`agent/request` 可以在每个会话步骤替换它;解析后的值会记录在 `request/header`。`high` 和 `max` 会启用思考,并序列化为官方顶层 `reasoning_effort`;适配器持有的 `off` 则序列化为 `thinking.type: disabled`,且省略 `reasoning_effort`。不支持的值会在网络 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 +同一确切模型结果会在部署策略允许思考时,为每个原样传递模型在 `reasoning` 下公开有序的 `off`、`high` 和 `max` 推理(reasoning)强度。`reasoningEffort` 选择部署默认值,省略时回退为 `high`。`agent/request` 可以在每个会话步骤替换它;解析后的值会记录在 `request/header`。`high` 和 `max` 会启用思考,并序列化为官方顶层 `reasoning_effort`;适配器持有的 `off` 则序列化为 `thinking.type: disabled`,且省略 `reasoning_effort`。不支持的值会在网络 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 -`thinking: disabled` 是部署锁定:它只公布 `off`,并以 `off` 为默认值。省略 `reasoningEffort` 或将其配置为 `off` 均有效;配置 `high` 或 `max` 会使插件加载失败,直接按请求启用思考也会在网络 I/O 前失败。携带 `GenerateOptions.purpose: 'session-title'` 的请求也会强制禁用思考并省略已解析的推理强度,将有界输出保留给可见标题文本,不改变会话或压缩默认值。 +`thinking: disabled` 是部署锁定:它只公布 `off`,并以 `off` 为默认值。省略 `reasoningEffort` 或将其配置为 `off` 均有效;配置 `high` 或 `max` 会使插件加载失败,直接按请求启用思考也会在网络 I/O 前失败。携带 `GenerateOptions.purpose: 'session-title'` 的请求也会强制禁用思考并省略已解析的推理强度,将有界输出保留给可见标题文本,不改变会话或 compaction(上下文压缩)默认值。 -`streamIdleTimeoutMs` 会限制每次未完成提供方读取,包括初始 `fetch`,但不计入消费方在 chunk 间花费的时间。一个稳定 abort 信号会在整个调用中达到请求与 body reader;过期会停止传输并抛出 `LlmError('TIMEOUT')`,较早的调用方 abort 则抛出 `LlmError('ABORTED')`。适配器每次 `stream()` 调用精确发起一次提供方请求;它把已配置策略注册为提供方元数据,再由 `dsh-llm-retry` 在持久 agent 步骤边界单独执行该策略。 +`streamIdleTimeoutMs` 会限制每次未完成提供方读取,包括初始 `fetch`,但不计入消费方在分片间花费的时间。同一个稳定的 abort 信号会在整个调用期间传递给请求与 body reader;过期会停止传输并抛出 `LlmError('TIMEOUT')`,较早的调用方 abort 则抛出 `LlmError('ABORTED')`。适配器每次 `stream()` 调用恰好发起一次提供方请求;它把已配置策略注册为提供方元数据,再由 `dsh-llm-retry` 在持久化的 agent(智能体)步骤边界单独执行该策略。 ## 应用归因 -每个请求都携带 dsh-llm `attributionHeaders()` 的共享归因标头,即用于识别 harness 的必需 `User-Agent` 基线(见 [dsh-llm § 应用归因](../llm/README.md#app-attribution-attributionts))。在该适配器契约下,直接 DeepSeek 请求与 OpenAI 兼容 gateway 请求都不会获得提供方特定应用归因标头;OpenRouter 应用归因暂缓到未来的显式 OpenRouter 适配器或模式。`GenerateOptions.purpose` 为 `compaction` 的请求(dsh-compact-basic 的辅助摘要调用)还会携带 `x-deepseek-harness-compact: 1`,让宿主可以将压缩流量与会话请求分开。 +每个请求都携带 dsh-llm `attributionHeaders()` 的共享归因标头,即用于识别 harness 的必需 `User-Agent` 基线(见 [dsh-llm § 应用归因](../llm/README.md#app-attribution-attributionts))。在该适配器契约(adapter contract)下,直接 DeepSeek 请求与 OpenAI 兼容 gateway 请求都不会获得提供方特定应用归因标头;OpenRouter 应用归因暂缓到未来的显式 OpenRouter 适配器或模式。`GenerateOptions.purpose` 为 `compaction` 的请求(dsh-compact-basic 的辅助摘要调用)还会携带 `x-deepseek-harness-compact: 1`,让宿主可以将压缩流量与会话请求分开。 ## 协议格式说明(已通过实时请求与官方文档验证) -- 只支持流式输出(`stream_options.include_usage` 始终开启)。`usage` 可能附着在 finish chunk 上,也可能作为尾随仅 usage chunk 到达;转换器会将两者都延迟到 `[DONE]`,因此 `usage` 始终位于 `finish` 之前,`finish` 之后不会出现任何内容。 -- 适配器持有的 `off` 推理强度映射为 `thinking: {type: 'disabled'}`,绝不会以 `reasoning_effort: 'off'` 跨越协议。 -- 第一个 thinking 模式 chunk 携带 `reasoning_content: ""`,系统会处理它(不会产生多余 reasoning 块)。 -- **Reasoning 回传规则**:对携带工具调用的 assistant 轮次,会将 `reasoning_content` 序列化回历史(thinking 模式 API 必需);对不含工具调用的轮次,它会被丢弃(不会使用,可节省 token)。 +- 只支持流式输出(`stream_options.include_usage` 始终开启)。`usage` 可能附着在 finish 分片上,也可能作为尾随的纯 usage 分片到达;转换器会将两者都延迟到 `[DONE]`,因此 `usage` 始终位于 `finish` 之前,`finish` 之后不会出现任何内容。 +- 适配器持有的 `off` 推理强度映射为 `thinking: {type: 'disabled'}`,绝不会以 `reasoning_effort: 'off'` 通过协议发送。 +- 第一个思考模式分片 携带 `reasoning_content: ""`,系统会处理它(不会产生多余 reasoning 块)。 +- **推理回传规则**:对携带工具调用的 assistant 轮次,会将 `reasoning_content` 序列化回历史(思考模式 API 必需);对不含工具调用的轮次,它会被丢弃(不会使用,可节省 token)。 - Cache 计量:`cacheReadTokens` ← `prompt_cache_hit_tokens` / `prompt_tokens_details.cached_tokens`;DeepSeek 不报告 cache-write 指标。 ## 错误 -非 2xx 响应会抛出稳定 code 的 `LlmError`:`AUTH`(401/403)、`QUOTA`(提供方详细信息标识配额、余额或点数耗尽的响应)、`RATE_LIMIT`(其他 429)、`CONTEXT_WINDOW_EXCEEDED`(提供方 code、type 或 message 标识上下文溢出的 400)、`INVALID_REQUEST`(其他 400)、`SERVER`(5xx),其他情况为 `HTTP_`。其可序列化 `failure` 保留 HTTP 状态,以及有效的正 `Retry-After` 秒数/日期延迟和存在时的 `x-request-id` / `x-deepseek-request-id`。响应前传输失败(DNS、连接被拒绝、TLS、proxy)会抛出命名已配置端点的 `TRANSPORT`,并将原始拒绝链接为 `cause`;调用方 abort 抛出 `ABORTED`,loop 的取消信号仍最具权威。协议违例抛出 `STREAM_CLOSED`(没有 `[DONE]`)或 `MALFORMED_RESPONSE`(JSON payload 错误)。未知协议 `finish_reason`(例如 `content_filter`、`insufficient_system_resource`)会变为 `finish {kind: 'error', failure}` chunk;已完成流如果使用 `stop`(或缺失)finish 但没有开启内容块,就会变为 `finish {kind: 'error'}`,code 为 `EMPTY_RESPONSE`(默认策略会重试)。 +非 2xx 响应会抛出稳定 code 的 `LlmError`:`AUTH`(401/403)、`QUOTA`(提供方详细信息标识配额、余额或点数耗尽的响应)、`RATE_LIMIT`(其他 429)、`CONTEXT_WINDOW_EXCEEDED`(提供方 code、type 或 message 标识上下文溢出的 400)、`INVALID_REQUEST`(其他 400)、`SERVER`(5xx),其他情况为 `HTTP_`。其可序列化 `failure` 保留 HTTP 状态,以及有效的正 `Retry-After` 秒数/日期延迟和存在时的 `x-request-id` / `x-deepseek-request-id`。响应前传输失败(DNS、连接被拒绝、TLS、proxy)会抛出命名已配置端点的 `TRANSPORT`,并将原始拒绝作为 `cause`;调用方 abort 抛出 `ABORTED`,仍以 loop 的取消信号为准。协议违例抛出 `STREAM_CLOSED`(没有 `[DONE]`)或 `MALFORMED_RESPONSE`(JSON payload 格式错误)。未知协议 `finish_reason`(例如 `content_filter`、`insufficient_system_resource`)会变为 `finish {kind: 'error', failure}` 分片;已完成流如果使用 `stop`(或缺失)finish 但没有开启内容块,就会变为 `finish {kind: 'error'}`,code 为 `EMPTY_RESPONSE`(默认策略会重试)。 ## 测试 -单元套件使用本地 `node:http` mock SSE 服务器(无网络),覆盖动态 `high`/`off`/`max` 选择、结构化 HTTP 事实、格式错误/截断流、调用方 abort、连接失败,以及 idle 超时确实会 abort 实际 body 的证明。真实 API 覆盖位于 `tests/adapter.e2e.ts`(`pnpm run test:e2e`,由 key 调节):V4 Flash + V4 Pro,覆盖 thinking 启用/禁用与两种官方 effort 级别,包括 thinking + 工具往返与 reasoning 回传。 +单元套件使用本地 `node:http` mock SSE 服务器(无网络),覆盖动态 `high`/`off`/`max` 选择、结构化 HTTP 事实、格式错误/截断流、调用方 abort、连接失败,以及 idle 超时确实会 abort 实际 body 的证明。真实 API 覆盖位于 `tests/adapter.e2e.ts`(`pnpm run test:e2e`,需有 key 才会运行):V4 Flash + V4 Pro,覆盖 思考启用/禁用与两种官方 effort 级别,包括思考 + 工具往返与推理回传。 ## 模型体验 @@ -70,21 +70,21 @@ harness LLM seam 的 DeepSeek chat-completions 适配器:直接 `fetch` + SSE #### 模型看到的内容 -所选 DeepSeek 模型会收到 harness 系统提示词、消息历史、工具 schema、stop sequence 和调用配置,不含适配器撰写的提示词文本。当之前的 assistant 轮次包含工具调用时,会按要求回传其 reasoning 内容;不含工具调用的轮次会省略 reasoning。 +所选 DeepSeek 模型会收到 harness 系统提示词、消息历史、工具 schema、stop sequence 和调用配置,不含适配器撰写的提示词文本。当之前的 assistant 轮次包含工具调用时,会按要求回传其推理内容;不含工具调用的轮次会省略推理。 #### Token 影响 -精确输入取决于提供方 tokenization。有条件 reasoning 回传会增加工具往返上下文,丢弃其他 reasoning 则避免再次支付这些 token;可用时会报告 cache-read 用量。 +精确输入取决于提供方 tokenization。有条件推理回传会增加工具往返上下文,丢弃其他推理 则避免再次支付这些 token;可用时会报告 cache-read 用量。 #### KV Cache 影响 -未更改的已组装前缀可使用 DeepSeek cache 复用,适配器会在 usage 中报告它。模型路由变更,或任何上游提示词、schema、前缀或历史变更,都可能使从第一个改变 token 起的复用失效;reasoning 回传会在工具往返期间追加。 +未更改的已组装前缀可使用 DeepSeek cache 复用,适配器会在 usage 中报告它。模型路由变更,或任何上游提示词、schema、前缀或历史变更,都可能使从首个发生变化的 token 起的复用失效;推理回传会在工具往返期间追加。 ### DeepSeek 响应 #### 模型看到的内容 -Reasoning、文本与原始字符串工具参数会转换为 harness chunk,供 loop 记录和组装。 +推理、文本与原始字符串工具参数会转换为 harness 分片,供 loop 记录和组装。 #### Token 影响 @@ -98,4 +98,4 @@ loop 保留的响应块会追加到下一个请求,并保留其较早可复用 - **未映射 `tool_choice`**:它不属于核心词汇(MVP 取舍,与 pi-ai twin 共享)。 - **请求使用原始 `fetch`,而非 `@cordisjs/plugin-http`**:没有共享 proxy/拦截配置;采用暂缓到第二个适配器需要该功能时(`TODO(http)`)。 -- **序列化会将 user 与工具结果内容展平为文本块**:会跳过插件添加的块类型,空工具输出会以字面 `(no output)` 跨越协议。 +- **序列化会将 user 与工具结果内容展平为文本块**:会跳过插件添加的块类型,空工具输出会以字面 `(no output)` 通过协议发送。 diff --git a/packages/llm/llm-pi-ai/README.zh.md b/packages/llm/llm-pi-ai/README.zh.md index a3d864ed90..c940751e91 100644 --- a/packages/llm/llm-pi-ai/README.zh.md +++ b/packages/llm/llm-pi-ai/README.zh.md @@ -2,9 +2,9 @@ [English](README.md) | 中文 -基于 [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) 的 harness LLM seam 通用多提供方适配器。一个插件实例拥有显式提供方 profile 列表;每个请求使用 `GenerateOptions.provider` 选择 profile,并从 pi-ai 已安装 catalog 中动态解析 `GenerateOptions.model`。 +基于 [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) 的 harness LLM(大语言模型)seam 通用多提供方适配器。一个插件实例拥有显式提供方 profile 列表;每个请求使用 `GenerateOptions.provider` 选择 profile,并从 pi-ai 已安装 catalog 中动态解析 `GenerateOptions.model`。 -包根目录公开 Cordis 插件契约与 `PiAiAdapter`;profile 解析、模型构造、回放转换和流转换保留在包内部。 +包(package)根入口导出 Cordis 插件契约与 `PiAiAdapter`;profile 解析、模型构造、回放转换和流转换保留在包内部。 ## 配置 @@ -39,39 +39,39 @@ 适配器通过 `ctx.llm.listModels(provider)` 公开每个已配置提供方已安装的 pi-ai 模型。这是从 `getModels(provider)` 派生的提供方无关 selector 元数据;请求时解析仍会执行权威 catalog 查找,因此发现不会创建第二个模型注册表。`ctx.llm.resolveModelInfo(provider, model)` 会执行一次精确 descriptor 查找,并返回其身份、上下文窗口和可选思考级别,让权威元数据保留在拥有路由的适配器上,而非消费方。 -`reasoning.efforts` 列表是 pi-ai 有序的 `getSupportedThinkingLevels(model)` 结果,不经筛选或规范化,其中包括 `off`,以及模型对 `xhigh` 或 `max` 的特定支持。Harness 将每个规范 pi-ai 级别公开为不透明 ID;提供方/模型协议拼写仍保留在 pi-ai 的 `thinkingLevelMap` 中。因此,不具备推理(reasoning)能力的模型也会公开 pi-ai 的 `off` 选项。配置 profile 的 `reasoning` 值(包括 `off`)在存在时是部署默认值;省略它会保留提供方默认值。每次请求的 `GenerateOptions.reasoningEffort` 优先;任何未出现在确切模型能力中的显式值都会在网络 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败,而不会被自动调整。pi-ai 的通用流选项通过省略 `reasoning` 表示 `off`。 +`reasoning.efforts` 列表是 pi-ai 有序的 `getSupportedThinkingLevels(model)` 结果,不经筛选或规范化,其中包括 `off`,以及模型对 `xhigh` 或 `max` 的特定支持。Harness 将每个规范 pi-ai 级别公开为不透明 ID;提供方/模型在协议格式中的表示仍保留在 pi-ai 的 `thinkingLevelMap` 中。因此,不具备推理(reasoning)能力的模型也会公开 pi-ai 的 `off` 选项。配置 profile 的 `reasoning` 值(包括 `off`)在存在时是部署默认值;省略它会保留提供方默认值。每次请求的 `GenerateOptions.reasoningEffort` 优先;任何未出现在确切模型能力中的显式值都会在网络 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败,而不会被自动调整。pi-ai 的通用流选项通过省略 `reasoning` 表示 `off`。 -受支持的 profile 字段是 `provider`、`apiKey`、`baseURL`、`headers`、`reasoning`、`thinkingBudgets`、`cacheRetention`、`transport`、`timeoutMs`、`websocketConnectTimeoutMs`、`streamIdleTimeoutMs` 和 `retryPolicy`。每个 profile 的可选重试策略都会与该提供方路由一同捕获;省略时使用有界的 normal 默认值。流 idle 间隔必须是正的有限 Node 定时器延迟,默认为五分钟,且只覆盖未完成提供方读取,不包括消费方思考时间。Harness 应用归因会胜过名称冲突的已配置标头。 +受支持的 profile 字段是 `provider`、`apiKey`、`baseURL`、`headers`、`reasoning`、`thinkingBudgets`、`cacheRetention`、`transport`、`timeoutMs`、`websocketConnectTimeoutMs`、`streamIdleTimeoutMs` 和 `retryPolicy`。每个 profile 的可选重试策略都会与该提供方路由一同捕获;省略时使用有界的常规默认值。流空闲间隔必须是正的有限 Node 定时器延迟,默认为五分钟,且只覆盖未完成提供方读取,不包括消费方思考时间。若已配置标头中有同名项,则以 Harness 应用归因为准。 -适配器强制 pi-ai SDK `maxRetries` 为零,因此一次 `stream()` 调用只会发起一次提供方请求。已移除 profile 字段 `maxRetries` 和 `maxRetryDelayMs` 会使加载失败,而不是静默倍增或隐藏单独组合的 agent 级重试预算。Idle 过期会 abort SDK 的稳定请求信号,并以 `TIMEOUT` 呈现;较早的调用方 abort 仍为 `ABORTED`。 +适配器强制 pi-ai SDK `maxRetries` 为零,因此一次 `stream()` 调用只会发起一次提供方请求。已移除 profile 字段 `maxRetries` 和 `maxRetryDelayMs` 会使加载失败,而不是静默倍增或隐藏单独组合的 agent(智能体)级重试预算。空闲超时会 abort SDK 的稳定请求信号,并以 `TIMEOUT` 呈现;较早的调用方 abort 仍为 `ABORTED`。 ## 提供方/模型路由与回放 所选 pi-ai catalog descriptor 提供协议实现。这包括原生 API 差异,例如 descriptor 使用 Responses API 而非 Chat Completions 的 OpenAI 模型;harness 适配器不会按模型名称硬编码端点选择。 -成功的 assistant 响应会在自身持久提供方/模型溯源旁存储经版本化的无损 JSON 回放状态。请求时,`LlmService` 只有在历史提供方路由与目标提供方路由当前由同一个 `PiAiAdapter` 实例拥有时,才会传递回放状态。即使目标提供方或模型改变,适配器也会验证状态并恢复 pi-ai 响应 id 与提供方 signature;随后由 pi-ai 判定目标 API 可以复用哪些元数据。没有回放状态的历史会被转换为外来提供方无关内容,绝不伪装为原生 pi-ai 响应。 +成功的 assistant 响应会在自身持久提供方/模型溯源旁存储经版本化的无损 JSON 回放状态。请求时,`LlmService` 只有在历史提供方路由与目标提供方路由当前由同一个 `PiAiAdapter` 实例拥有时,才会传递回放状态。即使目标提供方或模型改变,适配器也会验证状态并恢复 pi-ai 响应 id 与提供方 signature;随后由 pi-ai 判定目标 API 可以复用哪些元数据。没有回放状态的历史会被转换为外部的提供方无关内容,绝不伪装为原生 pi-ai 响应。 如果 listener 改写已组装 assistant 内容,loop 会在记录消息前丢弃回放状态,因为其提供方元数据不再描述该内容。无效版本、格式错误元数据、溯源提供方/模型不匹配,以及内容/块不匹配都会显式以 `LlmError('INVALID_REPLAY_STATE')` 失败。 ## 词汇差异 - pi-ai 工具调用参数是已解析对象;harness 存储原始 JSON 字符串。适配器会解析输入,并将输出重新字符串化。 -- pi-ai 将失败报告为流内错误事件;它们会映射到 `finish {kind:'error'|'aborted', failure}` chunk。提供方特定错误文本会区分终端 `QUOTA` 与短暂 `RATE_LIMIT`,针对已解析模型上下文窗口评估的文本与 usage 信号则将溢出规范化为 `CONTEXT_WINDOW_EXCEEDED`。携带零个内容块消息的终止 `stop` 会映射为 `finish {kind:'error'}`,code 为 `EMPTY_RESPONSE`(默认策略会重试),而非成功空消息。 -- pi-ai 将 reasoning token 折叠到输出 usage 中;没有可映射的独立 reasoning 计数。 -- pi-ai 的 `off` thinking 级别会原样穿过 Harness 能力 seam,并在分派时变为被省略的 pi-ai 通用 `reasoning` 选项。 -- `GenerateOptions.stop` 会以 `UNSUPPORTED_OPTION` 被拒绝,因为 pi-ai 的通用流式输出表层无法保证所有提供方都支持它。 +- pi-ai 将失败报告为流内错误事件;它们会映射到 `finish {kind:'error'|'aborted', failure}` 分片。提供方特定错误文本会区分终止型 `QUOTA` 与暂时型 `RATE_LIMIT`,针对已解析模型上下文窗口评估的文本与 usage 信号则将溢出规范化为 `CONTEXT_WINDOW_EXCEEDED`。终止时的 `stop` 若消息不含内容块 会映射为 `finish {kind:'error'}`,code 为 `EMPTY_RESPONSE`(默认策略会重试),而非成功空消息。 +- pi-ai 将 推理 token 折叠到输出 usage 中;没有可映射的独立推理计数。 +- pi-ai 的 `off` 思考级别会原样穿过 Harness 能力 seam,并在分派时变为被省略的 pi-ai 通用 `reasoning` 选项。 +- `GenerateOptions.stop` 会以 `UNSUPPORTED_OPTION` 被拒绝,因为 pi-ai 的通用流式输出接口无法保证所有提供方都支持它。 ## 应用归因 每个请求都携带 dsh-llm `attributionHeaders()` 的共享归因标头,并通过 pi-ai `headers` 流选项合并。不会合成提供方特定应用归因标头。详见 [dsh-llm § 应用归因](../llm/README.md#app-attribution-attributionts)。 -## 依赖重量 +## 依赖体量 -pi-ai 会安装多个提供方 SDK,并延迟加载 catalog 模型所选的 SDK。依赖重量隔离在该可选适配器包中。 +pi-ai 会安装多个提供方 SDK,并延迟加载 catalog 模型所选的 SDK。该可选适配器包将依赖体量隔离在自身范围内。 ## 测试 -单元测试使用重定向到本地 mock 服务器的 pi-ai catalog 模型,覆盖提供方/profile 路由、每次适配器调用一次协议请求、idle-timeout 响应终止、调用方 abort、原生 API 选择、端点覆盖、归因、转换、回放状态验证,以及一个适配器实例内的跨提供方/模型回放。真实 API 覆盖仍位于由 key 调节的 `pnpm run test:e2e` 下。 +单元测试使用重定向到本地 mock 服务器的 pi-ai catalog 模型,覆盖提供方/profile 路由、每次适配器调用只发起一个协议请求、idle-timeout 响应终止、调用方 abort、原生 API 选择、端点覆盖、归因、转换、回放状态验证,以及一个适配器实例内的跨提供方/模型回放。真实 API 覆盖仍需 key 才会启用,并通过 `pnpm run test:e2e` 运行。 ## 模型体验 @@ -87,17 +87,17 @@ pi-ai 会安装多个提供方 SDK,并延迟加载 catalog 模型所选的 SDK #### KV Cache 影响 -转换保留逻辑请求顺序,不添加文本;复用取决于所选提供方的序列化与回放状态。更改适配器实例、提供方、模型或任何上游请求 token,都可能使从第一个差异起的复用失效。 +转换保留逻辑请求顺序,不添加文本;复用取决于所选提供方的序列化与回放状态。更改适配器实例、提供方、模型或任何上游请求 token,都可能使复用从首个出现差异的 token 起失效。 ### 提供方响应 #### 模型看到的内容 -pi-ai 事件会变为 harness reasoning、文本、工具调用、usage 与 finish chunk。已解析工具参数以原始 JSON 字符串形式跨越 harness 边界。 +pi-ai 事件会变为 harness 推理、文本、工具调用、usage 与 finish 分片。已解析工具参数以原始 JSON 字符串形式通过 harness 边界传递。 #### Token 影响 -只有在 loop 记录生成内容后,它才会影响后续输入。提供方不单独报告 reasoning token 时,pi-ai 会将其折叠到输出 usage 中。 +只有在 loop 记录生成内容后,它才会影响后续输入。提供方不单独报告 推理 token 时,pi-ai 会将其折叠到输出 usage 中。 #### KV Cache 影响 @@ -109,4 +109,4 @@ pi-ai 事件会变为 harness reasoning、文本、工具调用、usage 与 fini - **不支持 `GenerateOptions.stop`**:pi-ai 的通用流选项无法保证所有提供方都支持 stop sequence,因此适配器会拒绝该字段。 - **历史中的 `system` 消息使用 pi-ai 通用上下文转换**:提供方特定位置由 pi-ai 决定,而非由 harness 拥有的协议覆盖决定。 - **无法获取提供方 HTTP 状态**:pi-ai 错误事件不会在所有提供方上公开稳定 HTTP 状态;失败只公开稳定 harness 错误 code。 -- **重试策略由提供方持有,而不是 SDK 重试**:每个提供方 profile 都可以配置嵌套的 `retryPolicy`,由 `dsh-llm-retry` 在 agent 的失败步骤 seam 上执行;pi-ai SDK 重试仍保持禁用,因此持久 agent 步骤与 `llm/retry` 事件拥有每次可见尝试,直接 `ctx.llm.stream()` 调用仍只尝试一次。 +- **重试策略由提供方持有,而不是 SDK 重试**:每个提供方 profile 都可以配置嵌套的 `retryPolicy`,由 `dsh-llm-retry` 在 agent 的失败步骤 seam 上执行;pi-ai SDK 重试仍保持禁用,因此持久化的 agent 步骤与 `llm/retry` 事件记录每次可见尝试,直接 `ctx.llm.stream()` 调用仍只尝试一次。 diff --git a/packages/llm/llm-retry/README.zh.md b/packages/llm/llm-retry/README.zh.md index 6255cca8c3..92772faf6a 100644 --- a/packages/llm/llm-retry/README.zh.md +++ b/packages/llm/llm-retry/README.zh.md @@ -4,13 +4,13 @@ 一个函数插件,通过 agent loop(智能体循环)在已关闭步骤上触发的 `agent/request-error` waterfall(瀑布式事件)应用确切提供方重试策略。它不包装 `ctx.llm.stream()`:每次适配器调用仍是一次提供方尝试,每次重试都会开启新的编号轮次。 -每个提供方适配器都拥有可选的嵌套 `retryPolicy`;路由在 `ctx.llm` 上注册时会捕获该策略,任何到达该注册最终适配器边界的调用都会携带它。如果之后释放或替换路由,进行中的失败仍会保留为其提供服务的策略;在选中任何最终适配器前发生的失败没有提供方策略,会继续委托。省略策略时使用 normal mode:为 `EMPTY_RESPONSE`、`RATE_LIMIT`、`SERVER`、`TIMEOUT` 和 `TRANSPORT` 重试两次,并采用从 500 ms 到 10 秒的有界指数退避与 10% jitter。`EMPTY_RESPONSE` 是适配器对未产生任何持久内容的退化提供方完成所作的分类,因此可安全重复。normal 策略可以更改其有限预算、合格 code 和退避配置。always mode 会先请求下游恢复,再无次数上限地重试每个模型请求失败;成功、取消或插件 dispose(资源释放)会在活跃的委托恢复完全停稳后终止它。 +每个提供方适配器都拥有可选的嵌套 `retryPolicy`;路由在 `ctx.llm` 上注册时会捕获该策略,任何到达该注册最终适配器边界的调用都会携带它。如果之后释放或替换路由,进行中的失败仍会保留当时为其提供服务的策略;在选中任何最终适配器前发生的失败没有提供方策略,会继续委托。省略策略时使用 normal mode:为 `EMPTY_RESPONSE`、`RATE_LIMIT`、`SERVER`、`TIMEOUT` 和 `TRANSPORT` 重试两次,并采用从 500 ms 到 10 秒的有界指数退避与 10% jitter。`EMPTY_RESPONSE` 是适配器对未产生任何持久内容的退化提供方完成所作的分类,因此可安全重复。normal 策略可以更改其有限预算、符合条件的 code 和退避配置。always mode 会先请求下游恢复,再无次数上限地重试每个模型请求失败;成功、取消或插件 dispose(资源释放)会在活跃的委托恢复完全停稳后终止它。 两种 mode 都使用带对称 jitter 的有界指数退避。有效 `providerRetryAfterMs` 不超过 `maxDelayMs` 时会替换本地退避,并且不加 jitter。超出上限的提供方延迟会使 normal mode 继续委托;always mode 则改用已配置的本地退避,避免该指令终止重试。 -等待前,插件会追加一条不进入表层的 `llm/retry` 事件,其中包含提供方、mode、规范的解析策略 key、失败和计划延迟。该 key 包含所有影响行为的字段,并对 normal mode 的 code 排序,因为合格性采用集合成员关系判断。只有提供方与完整策略 key 都相同的事件才会延续重试编号;因此,用限制、code 成员关系或退避不同的路由替换后,会开始自己的历史。normal 事件包含有限上限;always 事件省略该上限,UI 会渲染 `∞`。等待结束后,监听器返回 `{ kind: 'retry' }`,循环关闭失败轮次,并在同一持久历史上开启重试轮次。取消与插件 dispose 会中止活跃退避,在应用中止前排空活跃的委托恢复,并使 dispose 前捕获的 callback 只能以失败结束。 +等待前,插件会追加一条不进入表层的 `llm/retry` 事件,其中包含提供方、mode、已解析策略的规范 key、失败和计划延迟。该 key 包含所有影响行为的字段,并对 normal mode 的 code 排序,因为合格性采用集合成员关系判断。只有提供方与完整策略 key 都相同的事件才会延续重试编号;因此,用限制、code 成员关系或退避不同的路由替换后,会开始自己的历史。normal 事件包含有限上限;always 事件省略该上限,UI 会渲染 `∞`。等待结束后,监听器返回 `{ kind: 'retry' }`,循环关闭失败轮次,并在同一持久历史上开启重试轮次。取消与插件 dispose 会中止活跃退避,在应用中止前排空活跃的委托恢复,并使 dispose 前捕获的 callback 只能以失败结束。 -单独发布的 `./invariant` 配套模块会检查每个重试记录是否指向当前开启轮次及其最新已关闭步骤,是否与失败请求的持久提供方匹配,是否携带非空的提供方与策略身份,是否满足 mode 特定边界,是否拥有唯一步骤记录和正确的提供方策略重试编号,以及是否携带有界定时器延迟。完整 jitter 可以在下界调度为零毫秒。 +单独发布的 `./invariant` 配套模块会检查每个重试记录是否指向当前开启轮次及其最新已关闭步骤,是否与失败请求的持久提供方匹配,是否携带非空的提供方与策略标识,是否满足 mode 特定边界,是否拥有唯一步骤记录和正确的提供方策略重试编号,以及是否携带有界定时器延迟。完整 jitter 可以在下界调度为零毫秒。 ```yaml - name: '@deepseek-ai/dsh-llm-deepseek' @@ -46,8 +46,8 @@ ## 已知限制与暂缓事项 -- **Agent 轮次是唯一重试边界**:直接 `ctx.llm.stream()` 消费方仍只尝试一次,因为原始流无法将已发出 chunk 持久分隔为不同尝试。 +- **agent 轮次是唯一重试边界**:直接 `ctx.llm.stream()` 消费方仍只尝试一次,因为原始流无法将已发出分片 持久分隔为不同尝试。 - **always mode 会重试永久性失败**:身份验证、配额、无效请求、协议和无法恢复的上下文错误都会继续重试,直至成功、取消或 dispose;部署负责提供方特定的成本与延迟控制。 -- **有限插件预算可叠加**:normal mode 只统计已配置 code 和确切提供方策略,上下文溢出压缩则拥有独立预算。未来如有重叠策略,必须记录并测试注册顺序行为。 +- **有限插件预算可叠加**:normal mode 只统计已配置 code 和确切提供方策略,上下文溢出压缩(compaction)则拥有独立预算。未来如有重叠策略,必须记录并测试注册顺序行为。 - **恢复策略按 waterfall 顺序组合**:always mode 会先接受下游重试,再应用自己的回退。后续策略如果忽略取消且永不结算,也会阻止回退、轮次完全停稳和插件 dispose 完成。 - **`llm/retry` 记录调度,不是完成**:后续步骤与轮次事件用于确立成功、耗尽或取消。 diff --git a/packages/llm/llm/README.zh.md b/packages/llm/llm/README.zh.md index 6ac57b1e60..4dc4a0ca06 100644 --- a/packages/llm/llm/README.zh.md +++ b/packages/llm/llm/README.zh.md @@ -2,30 +2,30 @@ [English](README.md) | 中文 -提供方无关的 LLM 词汇与抽象服务。本包定义 agent loop、会话日志和每个插件使用的规范语言。 +提供方无关的 LLM(大语言模型)词汇与抽象服务。本包(package)定义 agent loop(智能体循环)、会话日志和每个插件使用的规范语言。 ## 服务:`LlmService`(ctx key:`llm`) -一个适配器注册表加单一流式调用表层,可通过 waterfall 事件拦截。 +一个适配器注册表加单一流式调用接口,可通过 waterfall(瀑布式事件)拦截。 ### 公开 API -- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): () => void` 为给定提供方路由注册一个适配器实例。注册要么全部成功,要么全部不生效,并且会随调用 fiber dispose。 +- `ctx.llm.registerAdapter(providers: string[], adapter: LlmAdapter): () => void` 为给定提供方路由注册一个适配器实例。注册要么全部成功,要么全部不生效,并且会随调用 fiber 一起 dispose(资源释放)。 - `ctx.llm.listProviders(): LlmProviderInfo[]` 按注册顺序描述已注册提供方路由。 - `ctx.llm.providerRetryPolicy(provider: string): ResolvedRetryPolicy` 返回注册时捕获的提供方重试策略,并解析 normal 默认值。 - `ctx.llm.listModels(provider: string): Promise` 发现某个已注册提供方当前公布的模型。 - `ctx.llm.resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise` 从拥有精确路由的适配器解析经校验的确切模型身份、可用上下文和推理(reasoning)元数据;异步适配器可选地支持取消。 - `ctx.llm.resolveCallConfig(config: LlmCallConfig, signal?: AbortSignal): Promise` 校验显式推理强度,并填入适配器配置的默认值,但不自动调整。 - `ctx.llm.prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise` 解析配置并将其当前适配器注册捕获为一次可取消、一次性调用。 -- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` 将一次模型调用流式输出为原始 chunk(token 级 delta)。消费方使用 `BlockAssembler` 将 chunk 组装为块/消息。 +- `ctx.llm.stream(options: GenerateOptions): AsyncIterable` 将一次模型调用流式输出为原始分片(token 级增量)。消费方使用 `BlockAssembler` 将分片组装为块/消息。 -`LlmService` 保留来自最终适配器选择、同步 dispatch、iterator 构造与迭代的错误,并将其溯源绑定到该次模型调用返回的精确流句柄。`isLlmAdapterFailure(stream, value)` 只报告该调用最终适配器边界的错误;`llmFailureOf(stream, value)` 返回相邻的不可变 `LlmFailure`;`llmRetryPolicyOf(stream)` 返回在该边界选中的确切注册所对应的不可变策略,即使之后释放或替换路由也不变。未到达最终适配器的调用没有服务策略。嵌套模型调用、`llm/stream` middleware 和下游消费方失败对外层调用仍未分类。分类绝不替换或更改适配器的原始编码 `Error`。 +`LlmService` 保留来自最终适配器选择、同步 dispatch、iterator 构造与迭代的错误,并将其溯源绑定到该次模型调用返回的精确流句柄。`isLlmAdapterFailure(stream, value)` 只报告该调用最终适配器边界的错误;`llmFailureOf(stream, value)` 返回关联的不可变 `LlmFailure`;`llmRetryPolicyOf(stream)` 返回在该边界选中的确切注册所对应的不可变策略,即使之后释放或替换路由也不变。未到达最终适配器的调用没有服务策略。嵌套模型调用、`llm/stream` middleware 和下游消费方失败对外层调用仍未分类。分类绝不替换或更改适配器原有的带代码 `Error`。 -提供方与模型元数据是发现表层,不是路由白名单。`registerAdapter()` 仍拥有提供方排他性,并为每条路由捕获适配器的重试策略;适配器则可以接受 `listModels()` 中不存在的模型 id,消费方禁止因模型未列出而拒绝请求。返回的 selector 元数据与输入脱离,无效或重复适配器配置项会以 `INVALID_ADAPTER` 或 `INVALID_CATALOG` 失败。 +提供方与模型元数据是发现接口,不是路由白名单。`registerAdapter()` 仍拥有提供方排他性,并为每条路由捕获适配器的重试策略;适配器则可以接受 `listModels()` 中不存在的模型 id,消费方禁止因模型未列出而拒绝请求。返回的 selector 元数据与输入脱离,无效或重复适配器配置项会以 `INVALID_ADAPTER` 或 `INVALID_CATALOG` 失败。 确切模型元数据是独立的正确性查询,不是 catalog 装饰或全局 LLM 设置。`resolveModelInfo()` 会向拥有精确提供方/模型路由的适配器查询一次;适配器可以描述未列出的动态模型,缺少 `context` 或 `reasoning` 字段只表示相应能力不可用。无效的身份、上下文或推理元数据会以 `INVALID_MODEL_INFO`、`INVALID_MODEL_CONTEXT` 或 `INVALID_MODEL_REASONING` 失败。 -推理标识符是由适配器持有的不透明字符串,而非核心枚举。适配器会公布有序可选列表;模型能力 API 提供 `off` id 时,列表也会包含它。`resolveCallConfig()` 只接受与已公布标识符完全一致的值,在存在 `defaultEffort` 时填入它,否则保留提供方默认值。异步模型解析器会接收调用方的 signal,并且必须在取消后迅速完成结算。`prepareCall()` 还会让精确适配器注册跨越请求头记录和最终分派,因此 HMR(热模块替换)不会将一个适配器的能力结果与另一个适配器的请求混用;复用其一次性句柄或更改调用配置字段会以 `INVALID_PREPARED_CALL` 失败。不支持的显式或配置推理强度会在提供方 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 +推理标识符是由适配器持有的不透明字符串,而非核心枚举。适配器会公布有序可选列表;模型能力 API 提供 `off` id 时,列表也会包含它。`resolveCallConfig()` 只接受与已公布标识符完全一致的值,在存在 `defaultEffort` 时填入它,否则保留提供方默认值。异步模型解析器会接收调用方的 signal,并且必须在取消后迅速结束。`prepareCall()` 还会让精确适配器注册跨越请求头记录和最终分派,因此 HMR(热模块替换)不会将一个适配器的能力结果与另一个适配器的请求混用;复用其一次性句柄或更改调用配置字段会以 `INVALID_PREPARED_CALL` 失败。不支持的显式或配置推理强度会在提供方 I/O 前以 `UNSUPPORTED_REASONING_EFFORT` 失败。 ### 事件 @@ -36,42 +36,42 @@ ### 扩展点 - 继承 `LlmAdapter` 并调用 `ctx.llm.registerAdapter(providers, adapter)`,添加一条或多条提供方路由。`GenerateOptions.provider` 选择适配器;`GenerateOptions.model` 属于适配器,可以动态解析。覆盖 `providerRetryPolicy()` 以提供由提供方持有的恢复配置,覆盖 `providerInfo()` 和异步 `listModels()` 以公开 selector 元数据;精确身份、容量或可选推理强度可用时,实现 `resolveModel()`;异步解析器必须响应其可选的取消 signal。默认实现使用有界的 normal 重试策略,将路由和模型 id 用作名称,不公布模型,也不返回容量或推理元数据。 -- 包装 `llm/stream` 时,通过 `ctx.on()` waterfall listener 实现缓存、日志或路由。发出 chunk 后重试的包装层没有持久尝试边界;因此已发布 agent 重试策略改用 `agent/request-error`。 +- 包装 `llm/stream` 时,通过 `ctx.on()` waterfall listener 实现缓存、日志或路由。发出分片后重试的包装层没有持久尝试边界;因此已发布 agent 重试策略改用 `agent/request-error`。 ### 消息(`message.ts`)与内容块(`types.ts`) `Message` 是投递、持久历史和模型请求共享的不可变值。每条消息从创建起都必须具有 `MessageId`、角色、内容和带类型的来源。`createMessage(input)` 生成标识,并返回与输入分离且深度冻结的值;`createUserMessage({ content, source })` 固定 user 角色;`createAssistantMessage({ content, source })` 固定 assistant 角色与模型来源类别;`createToolResultMessage({ callId, content, isError })` 固定 user 角色,并将工具来源与其结果块耦合;`freezeMessage(message)` 导入已有标识,绝不将其替换。改写消息时会保留标识,并产生另一个冻结值。浏览器端代码会从依赖最少的 `@deepseek-ai/dsh-llm/message` 入口导入这些值构造函数,而不是从包含服务的包根入口导入。 -消息内容是类型化内容块数组:`text`、`reasoning`、`tool-call`、`tool-result`。联合从可合并扩展的 `ContentBlockMap` 派生,因此插件可以通过 declaration merging 添加块类型。assistant 消息使用模型来源,其中携带提供方/模型溯源与可选适配器私有回放状态。dispatch 前,`LlmService` 只在历史提供方路由与目标提供方路由当前由完全相同的适配器实例拥有时才保留该状态;随后由适配器判定能否在模型/提供方间恢复或转换该状态。核心块集只包含每条已发布路径都支持的块。多模态内容(图像、音频等)没有核心块类型;需要它的功能会通过 map 添加,并一并添加支持它的适配器/UI/压缩实现。 +消息内容是类型化内容块数组:`text`、`reasoning`、`tool-call`、`tool-result`。联合从可合并扩展的 `ContentBlockMap` 派生,因此插件可以通过 declaration merging 添加块类型。assistant 消息使用模型来源,其中携带提供方/模型溯源与可选适配器私有回放状态。dispatch 前,`LlmService` 只在历史提供方路由与目标提供方路由当前由完全相同的适配器实例拥有时才保留该状态;随后由适配器判定能否在模型/提供方间恢复或转换该状态。核心块集只包含每条已发布路径都支持的块。多模态内容(图像、音频等)没有核心块类型;需要它的功能会通过 map 添加,并一并添加相应的适配器/UI/压缩(compaction)支持。 -流式输出是原始 chunk 协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)。`BlockAssembler` 是将 chunk 组装为块/消息的唯一共享实现。 +流式输出是原始分片协议(`block-start`、`text-delta`、`reasoning-delta`、`tool-call-delta`、`block-end`、`usage`、`finish`)。`BlockAssembler` 是将分片组装为块/消息的唯一共享实现。 ### 调用配置(`call-config.ts`) -`LlmCallConfig` 是一个会话请求的提供方、模型、可选的适配器持有推理强度和采样标量(`provider`、`model`、`reasoningEffort`、`temperature`、`maxTokens`、`stop`,每个都与同名 `GenerateOptions` 字段 1:1 映射)。它是作为请求标头一部分记录在会话日志中的每会话状态(见 dsh-session `request/header` 事件),绝不是可静默调整的每次调用旋钮:`agent/request` waterfall 会提议替换,`prepareCall()` 在轮次 signal 控制下校验并填入默认值,loop 随后记录生效值,再使用准备完成调用的注册绑定流。`callConfigEquals(a, b)` 是逐字段真实变更检测器;`deepFreeze(value)` 是 loop 在 dispatch 前对每个已构建请求应用的所有权 helper(`llm/stream` listener 与适配器只读,绝不改写)。`markAgentLoopRequest()` 为该精确对象添加进程本地 loop 溯源,`isAgentLoopRequest()` 让观测方可以将其与同样可能冻结并关联会话、但独立记录的辅助调用区分。`GenerateOptions.purpose` 对已记录辅助压缩与会话标题调用分类,让适配器可以应用目的特定传输策略,而不改变普通会话请求。 +`LlmCallConfig` 是一个会话中各次请求的提供方、模型、可选的适配器持有推理强度和采样标量(`provider`、`model`、`reasoningEffort`、`temperature`、`maxTokens`、`stop`,每个都与同名 `GenerateOptions` 字段 1:1 映射)。它是作为请求标头一部分记录在会话日志中的每会话状态(见 dsh-session `request/header` 事件),绝不是可静默调整的每次调用旋钮:`agent/request` waterfall 会提议替换,`prepareCall()` 在轮次 signal 控制下校验并填入默认值,loop 随后记录生效值,再使用已准备调用中与注册绑定的流。`callConfigEquals(a, b)` 是逐字段真实变更检测器;`deepFreeze(value)` 是 loop 在 dispatch 前对每个已构建请求应用的所有权 helper(`llm/stream` listener 与适配器只读,绝不改写)。`markAgentLoopRequest()` 为该精确对象添加进程本地 loop 溯源,`isAgentLoopRequest()` 让观测方可以将其与同样可能冻结并关联会话、但独立记录的辅助调用区分。`GenerateOptions.purpose` 对已记录辅助压缩与会话标题调用分类,让适配器可以应用目的特定传输策略,而不改变普通会话请求。 ### 应用归因(`attribution.ts`) -每个产品适配器都会在提供方 HTTP 请求上发送应用身份。`attributionHeaders(identity?)` 构建标准 `User-Agent`,默认为公开 `APP_IDENTITY`;白标部署可以替换它,但不能抑制它。适配器会直接验证 wire 标头,或通过自身库 hook 验证。详见 [归因 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 +每个产品适配器都会在提供方 HTTP 请求上发送应用身份。`attributionHeaders(identity?)` 构建标准 `User-Agent`,默认为公开 `APP_IDENTITY`;白标部署可以替换它,但不能抑制它。适配器会直接验证 wire 标头,或通过自身库 hook 验证。详见 [归因 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/architecture/2026-06-21-mandatory-app-attribution-headers.md)。 ### 类 - `LlmAdapter`:提供方适配器的抽象基类。唯一必需方法是 `stream()`。 -- `BlockAssembler`:将原始 chunk 逐步组装为完整内容块,并能据此创建带标识且冻结的 assistant 消息。agent loop 向它提供原始 chunk(同时记录以供回放),并读取已组装块以构建历史。 -- `HarnessError`:harness 错误分类体系的基类,包含稳定 `code` 字符串(与面向人的 `message` 不同)加 `cause` 链接。它位于所有其他包都导入的叶子包中,因此可以共享单一基类,无需新的依赖边。每包错误(`LlmError`、`ToolArgsError`、`InvariantError` 等)都会扩展它。`isHarnessError(value)` 在 seam 处收窄类型。 -- `LlmError`:扩展 `HarnessError`;其稳定 `code` 字符串(`NO_ADAPTER`、`DUPLICATE_ADAPTER` 与 `AUTH`/`RATE_LIMIT` 等适配器 code)与冻结可序列化 `failure.code` 匹配。Payload 还可以保留已验证状态、`Retry-After` 和品牌化提供方请求 id 事实;策略位于错误之外。 +- `BlockAssembler`:将原始分片逐步组装为完整内容块,并能据此创建带标识且冻结的 assistant 消息。agent loop 向它提供原始分片(同时记录以供回放),并读取已组装块以构建历史。 +- `HarnessError`:harness 错误分类体系的基类,包含稳定 `code` 字符串(与面向人的 `message` 不同)加 `cause` 链接。它位于所有其他包都从中导入的叶子包中,因此可以共享单一基类,无需新的依赖边。各包的错误(`LlmError`、`ToolArgsError`、`InvariantError` 等)都继承自它。`isHarnessError(value)` 在 seam 处收窄类型。 +- `LlmError`:继承自 `HarnessError`;其稳定 `code` 字符串(`NO_ADAPTER`、`DUPLICATE_ADAPTER` 与 `AUTH`/`RATE_LIMIT` 等适配器 code)与冻结可序列化 `failure.code` 匹配。Payload 还可以保留已验证状态、`Retry-After` 和品牌化提供方请求 id 事实;策略位于错误之外。 - `errorChain(value)`:渲染抛出值的完整 `cause` 链与 AggregateError 成员,供诊断表层使用,包括 UI 通知、logger 行和持久 `turn/end` 消息。因此 undici 的 `TypeError: fetch failed` 等传输包装层会显示底层 `ECONNREFUSED`/DNS/TLS 详细信息,而不是将其遮蔽。该函数只负责渲染:请按 `code` 路由,绝不解析结果。 -- `CONTEXT_WINDOW_EXCEEDED_CODE`:当请求超过模型上下文窗口时,无论通过抛出 HTTP 还是带内 finish 交付,两个 DeepSeek 适配器都使用的提供方无关 code。`isContextWindowExceededError(detail)` 是它们针对 OpenAI 兼容提供方详细信息的共享保守分类器。 +- `CONTEXT_WINDOW_EXCEEDED_CODE`:当请求超过模型上下文窗口时,无论通过 HTTP 异常抛出还是带内 finish 交付,两个 DeepSeek 适配器都使用的提供方无关 code。`isContextWindowExceededError(detail)` 是它们针对 OpenAI 兼容提供方详细信息的共享保守分类器。 - `QUOTA_EXCEEDED_CODE`:帐户配额、余额、点数、预算或用量限制耗尽时使用的非短暂提供方无关 code。`isQuotaExceededError(detail)` 使这些失败与请求速率限制保持区分。 -- `EMPTY_RESPONSE_CODE`:对退化提供方完成使用的提供方无关 code,两个适配器均使用:一个不携带任何内容块的终止 `stop`。它会被分类为错误 finish(而非成功空消息),因为尝试未产生持久内容;`dsh-llm-retry` 默认重试它。 +- `EMPTY_RESPONSE_CODE`:两个适配器都使用的提供方无关 code,用于表示退化的提供方生成结果:一个未携带任何内容块的终止 `stop`。它会被分类为错误 finish(而非成功空消息),因为尝试未产生持久内容;`dsh-llm-retry` 默认重试它。 ### 真实适配器 -两个适配器使用不同内部机制实现 `LlmAdapter`:[`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) 针对 `deepseek` 路由使用直接 fetch 加 `eventsource-parser` SSE 分帧,[`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) 则通过 `@earendil-works/pi-ai` 动态解析已配置提供方/模型对。两者都遵循 `StreamChunk` 约定,定义见 `types.ts`:usage 先于 finish,工具参数保持原始字符串,错误使用两种已批准路径之一。设计理由见 [双 LLM 适配器](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md)。 +两个适配器使用不同内部机制实现 `LlmAdapter`:[`@deepseek-ai/dsh-llm-deepseek`](../llm-deepseek) 针对 `deepseek` 路由使用直接 fetch 加 `eventsource-parser` SSE(Server-Sent Events)分帧,[`@deepseek-ai/dsh-llm-pi-ai`](../llm-pi-ai) 则通过 `@earendil-works/pi-ai` 动态解析已配置提供方/模型对。两者都遵循 `StreamChunk` 约定,定义见 `types.ts`:usage 先于 finish,工具参数保持原始字符串,错误使用两种已批准路径之一。设计理由见 [双 LLM 适配器](../../../.agents/notes/implemented/architecture/2026-06-13-twin-llm-adapters.md)。 ## 模型体验 -无。服务不添加或更改任何模型边界文本、schema 或消息;它只会填入并记录适配器配置的推理强度。 +无。服务不添加任何与模型绑定的文本、schema 或消息;它只会填入并记录适配器配置的推理强度。 #### KV Cache 影响 @@ -79,9 +79,9 @@ ## 已知限制与暂缓事项 -- **本服务不执行重试、缓存或速率限制**:提供方注册会存储重试策略,但 `llm/stream` 仍是单次尝试调用包装 seam。agent loop 会将已验证模型请求失败单独提供给 `agent/request-error`,其默认行为是保留原始失败;`@deepseek-ai/dsh-llm-retry` 是共享示例 spine 加载的可选执行器。 +- **本服务不执行重试、缓存或速率限制**:提供方注册会存储重试策略,但 `llm/stream` 仍是单次尝试调用包装 seam。agent loop 会将已验证模型请求失败单独提供给 `agent/request-error`,其默认行为是保留原始失败;`@deepseek-ai/dsh-llm-retry` 是共享示例主干加载的可选执行器。 - **`GenerateOptions` 采样只包含 `temperature`/`maxTokens`/`stop`**:没有 `tool_choice`、`top_p` 或 penalty 字段;有产生方落地时词汇才会增长(见 [已删除惰性旋钮](../../../.agents/notes/archived/simplification/2026-07-04-drop-inert-request-knobs.md))。 -- **由产生方调节的变体在实际产生前保持在外**:`prefill`、每工具 `strict`、块 `cache` 提示与 `agent` 消息源变体因没有产生方而被剪除(见 [Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md))。 -- **`BlockAssembler` 只处理核心块 kind**:如果插件添加块类型的流从未由 `block-end` 关闭,`blocks()` 会抛出异常。 +- **受产生方约束的变体在实际产生前不会加入**:`prefill`、每工具 `strict`、块 `cache` 提示与 `agent` 消息源变体因没有产生方而被剪除(见 [Agent Note](../../../.agents/notes/archived/simplification/2026-07-04-prune-producerless-vocabulary-variants.md))。 +- **`BlockAssembler` 只处理核心块类型**:如果插件添加块类型的流从未由 `block-end` 关闭,`blocks()` 会抛出异常。 - **`APP_IDENTITY.url` 指向一个尚不存在的仓库**:`FIXME`:创建公开 `deepseek-ai/deepseek-harness-sdk` 仓库是首次发布的前置条件。 - **`GenerateOptions.sessionId` 是本地声明的品牌类型**:导入 dsh-session 的 `SessionId` 会产生循环;未来拥有 id 的包可以消除该权宜之计。 diff --git a/packages/llm/token-meter/README.zh.md b/packages/llm/token-meter/README.zh.md index 51518e98c4..9d54ddb479 100644 --- a/packages/llm/token-meter/README.zh.md +++ b/packages/llm/token-meter/README.zh.md @@ -2,11 +2,11 @@ [English](README.md) | 中文 -通过单例 `ctx.tokenMeter` 服务进行感知回放的 token 测量。它从持久日志为每个会话推进一个隔离 fold,因此压缩与其他压力敏感插件可以共享计量,无需依赖 `CompactService`。 +通过单例 `ctx.tokenMeter` 服务进行具备回放感知能力的 token 测量。它从持久日志为每个会话推进一个隔离 fold,因此压缩(compaction)与其他压力敏感插件可以共享计量,无需依赖 `CompactService`。 ## 配置 -估算器没有设置。它有意使用一项固定启发式规则:每个 token 按四个字符估算,再加上角色、块与请求 envelope 字段的结构开销。任何 key 都会被拒绝,包括已废弃的全局 `contextWindow`;模型容量属于拥有精确提供方/模型路由的适配器,可通过 `ctx.llm.resolveModelInfo().context` 获取。 +估算器没有配置项。它有意使用一项固定启发式规则:每个 token 按四个字符估算,再加上角色、块与请求 envelope 字段的结构开销。任何配置键都会被拒绝,包括已废弃的全局 `contextWindow`;模型容量属于拥有精确提供方/模型路由的适配器,可通过 `ctx.llm.resolveModelInfo().context` 获取。 ## 测量契约 @@ -15,11 +15,11 @@ - `measure(session, requestHeader?)` 在同一个已消费日志 revision 上返回请求压力与当前已计价表层。 - `estimateMessage(message)` 使用固定启发式规则为一条消息计价。 -`measure()` 会同步一次,返回一个与输入脱离、深度不可变的快照。`totalTokens` 是请求与响应压力,`surfaceTokens` 是仅表层启发式总量,等于 `nodes[].tokens` 之和。`requestHeader` 覆盖只影响压力字段;表层字段仍描述当前会话。每次调用都会克隆带位置的节点,因此测量是 O(surface)。 +`measure()` 会同步一次,并返回一个独立且深度不可变的快照。`totalTokens` 是请求与响应压力,`surfaceTokens` 是仅表层启发式总量,等于 `nodes[].tokens` 之和。`requestHeader` 覆盖只影响压力字段;表层字段仍描述当前会话。每次调用都会克隆带位置的节点,因此测量是 O(surface)。 -fold 跟踪完整请求标头快照、步骤边界、表层追加与替换、成功 assistant 消息、提供方用量和 assistant chunk 溯源。只有当最新成功调用的规范请求 envelope 与已测量 envelope 匹配,且其总量不低于该调用的完整启发式锚点时,才会复用提供方用量;后续成功会替换较早锚点。否则估算完整当前 envelope 与表层。表层变更保持相对于匹配锚点的带符号值,包括缩减替换后的负 delta。 +fold 跟踪完整请求标头快照、步骤边界、表层追加与替换、成功 assistant 消息、提供方用量和 assistant 分片溯源。只有当最新成功调用的规范请求 envelope 与已测量 envelope 匹配,且其总量不低于该调用的完整启发式锚点时,才会复用提供方用量;后续成功会替换较早锚点。否则会对当前 envelope 与表层进行完整估算。表层变更保持相对于匹配锚点的带符号值,包括缩减替换后的负 delta。 -用量计量会求和不重叠的输入、cache-read、cache-write 与输出 bucket;不会再次添加 reasoning。每次成功调用都会记录一个 assistant 锚点,包括无内容调用。显式空溯源列表表示已知空提供方流,而缺失的遗留溯源会保守地将持久 assistant 输出视为提供方输出。 +用量计量会求和不重叠的输入、cache-read、cache-write 与输出 bucket;不会再次添加推理(reasoning)。每次成功调用都会记录一个 assistant 锚点,包括无内容调用。显式空溯源列表表示已知空提供方流,而遗留溯源缺失时,fold 会保守地将持久 assistant 输出视为提供方输出。 ## 组合 @@ -28,7 +28,7 @@ fold 跟踪完整请求标头快照、步骤边界、表层追加与替换、成 - name: '@deepseek-ai/dsh-compact-basic' ``` -两个插件都有可用默认值。meter 保持与模型路由和可选压缩无关。部署会在 LLM 适配器上配置容量,并在 `dsh-compact-basic` 上配置压缩策略。 +两个插件都有可用默认值。meter 保持与模型路由和可选压缩无关。部署会在 LLM(大语言模型)适配器上配置容量,并在 `dsh-compact-basic` 上配置压缩策略。 ## 模型体验 @@ -36,11 +36,11 @@ fold 跟踪完整请求标头快照、步骤边界、表层追加与替换、成 #### KV Cache 影响 -不会直接失效;请求前缀变更由具名消费方负责。 +不会直接失效;请求前缀变更由上述消费方负责。 ## 已知限制与暂缓事项 - **固定启发式规则是近似值**:没有可复用提供方用量的内容按字符数加结构开销计价,而不是使用精确提供方 tokenizer 或请求 serializer。 -- **每次测量都会克隆当前表层**:连贯不可变快照使读取成为 O(surface),包括低于阈值的压力检查。 +- **每次测量都会克隆当前表层**:一致且不可变的快照使读取成为 O(surface),包括低于阈值的压力检查。 - **提供方用量只能为完全相同的规范 envelope 复用**:提示词、前缀、工具、提供方、模型或调用配置变更都会有意回退到完整启发式估算。 -- **遗留溯源采取保守策略**:没有 `sourceEventSeqs` 的 assistant 消息无法区分提供方输出与 listener 改写,因此 fold 不会声称已知空流或精确 chunk 流。 +- **遗留溯源采取保守策略**:没有 `sourceEventSeqs` 的 assistant 消息无法区分提供方输出与 listener 改写,因此 fold 不会声称已知空流或精确分片流。 diff --git a/packages/lsp/README.zh.md b/packages/lsp/README.zh.md index 9b4dbb9f3a..0d068b2a78 100644 --- a/packages/lsp/README.zh.md +++ b/packages/lsp/README.zh.md @@ -2,14 +2,14 @@ [English](README.md) | 中文 -语言服务器能力 seam:抽象 LSP 接口、通用 stdio 提供方,以及面向模型的 `lsp` 工具。这些全是**产品** 包。 +语言服务器能力 seam:抽象 LSP 接口、通用 stdio 提供方,以及面向模型的 `lsp` 工具。这些全是**产品**包。 | 包 | 职责 | ctx key | |---|---|---| | `lsp/` | 抽象 LSP seam(按品牌化 id + 扩展名映射组织的提供方注册表、逐查询选择、词汇、`LspError`) | `ctx.lsp` | -| `lsp-local/` | 通用多服务器本地后端(spawn、JSON-RPC、临时打开查询) | (在 `ctx.lsp` 上注册提供方) | +| `lsp-local/` | 通用多服务器本地后端(spawn、JSON-RPC、查询时临时打开文档) | (在 `ctx.lsp` 上注册提供方) | | `tool-lsp/` | 面向模型的 `lsp` 工具(四种操作、从 1 开始的 UTF-16 光标坐标) | (注册到 `ctx.tools`) | -接口位于 `lsp/lsp/`。该 seam 恰好公开四种语义操作:`goToDefinition`、`findReferences`、`goToImplementation`、`hover`,且不提供通用 JSON-RPC 逃生口;因此,替换提供方不会改变模型请求导航的方式,也不会让协议载荷或未经评审的修改进入模型契约。提供方注册的是**能力** 而非工具;`tool-lsp` 是面向模型名称、schema、提示词指引和呈现的唯一 owner。 +接口位于 `lsp/lsp/`。该 seam 恰好公开四种语义操作:`goToDefinition`、`findReferences`、`goToImplementation`、`hover`,且不提供通用 JSON-RPC 逃生口;因此,替换提供方不会改变模型请求导航的方式,也不会让协议载荷或未经评审的修改进入模型契约。提供方注册的是**能力**而非工具;`tool-lsp` 是面向模型名称、schema、提示词指引和呈现的唯一 owner。 -设计原理见 [LSP 能力 seam Agent Note](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md),其中也解释了文档为何在每次查询时临时打开、本地主机为何通过 Node API 而非 `ctx.fs` 读取,以及扩展名归属为何在同一运行时内互斥。 +设计原理见 [LSP 能力 seam Agent Note(agent 决策记录)](../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md),其中也解释了文档为何在每次查询时临时打开、本地主机为何通过 Node API 而非 `ctx.fs` 读取,以及扩展名归属为何在同一运行时内互斥。 diff --git a/packages/lsp/lsp-local/README.zh.md b/packages/lsp/lsp-local/README.zh.md index 290601d455..2390b02371 100644 --- a/packages/lsp/lsp-local/README.zh.md +++ b/packages/lsp/lsp-local/README.zh.md @@ -2,17 +2,17 @@ [English](README.md) | 中文 -`ctx.lsp` 的**通用本地 stdio 语言服务器后端**。一个插件实例接受一张命名服务器表,并逐配置项注册一个隔离的提供方。这是通用主机,而不是语言服务器目录或安装器:部署需要显式配置命令与映射,preset 应放在 `cordis.yml` overlay 中。 +`ctx.lsp` 的**通用本地 stdio 语言服务器后端**。一个插件实例接受一张命名服务器表,并逐配置项注册一个隔离的提供方。这是通用主机,而不是语言服务器目录或安装器:部署需要显式配置命令与映射,预设应放在 `cordis.yml` overlay 中。 Namespace 插件(`name`/`inject`/`Config`/`apply`,无默认导出)。 ## 功能 - 在注册前解析每项服务器局部设置;无效映射或注册冲突会回滚较早配置项,因此加载失败不会留下提供方路由。 -- 每个 `(server id, canonical workspace realpath)` 惰性 single-flight 一个服务器进程。存活服务器错误不会回放;如果选中的池化传输在只读查询之前或期间失败,提供方会等待其释放,并在新进程上重试该查询一次。 -- 每次查询都使用兼容性优先的**临时打开** 序列:通过 Node API 规范化并读取源文件、`textDocument/didOpen`(版本 1、完整文本)、所请求操作,然后执行 `textDocument/didClose`,该操作位于 `finally` 中。写入 `didOpen` 失败或取消时,会先终止实例再允许池复用。文档在每次调用后关闭,因此第一版不需要 `didChange`、内容 cache 或文档 LRU。 +- 每个 `(server id, canonical workspace realpath)` 惰性 single-flight 一个服务器进程。存活服务器错误不会回放;如果选中的池化传输在只读查询之前或期间失败,提供方会等待其 dispose(资源释放)完成,并在新进程上重试该查询一次。 +- 每次查询都使用兼容性优先的**临时打开**序列:通过 Node API 规范化并读取源文件、`textDocument/didOpen`(版本 1、完整文本)、所请求操作,然后执行 `textDocument/didClose`,该操作位于 `finally` 中。写入 `didOpen` 失败或取消时,会在池复用该实例前将其终止。文档在每次调用后关闭,因此第一版不需要 `didChange`、内容 cache 或文档 LRU。 - 通过一条逐 Workspace、可中止的队列,串行执行每个源读取/打开/查询/关闭生命周期,因此排队调用只会在轮到自身时读取当前源;不同 Workspace 并行运行。 -- 协议 shutdown 失败后,经由进程管理器 seam 终止服务器后代树(POSIX 进程组信号;Windows `taskkill /T /F`)。树终止的投递结果与所有进程组信号一样被就地吸收,不向外抛出(投递与服务器退出存在竞态);服务器是否完全停稳,由句柄的进程树存活等待确认,而非由这次终止自身的结果确认。 +- 协议 shutdown 失败后,经由子进程 seam 终止服务器后代树(POSIX 进程组信号;Windows `taskkill /T /F`)。树终止的投递结果与所有进程组信号一样被就地吸收,不向外抛出(投递与服务器退出存在竞态);服务器是否完全停稳,由句柄的进程树存活等待确认,而非由这次终止自身的结果确认。 - 通过子进程 host namespace 中的 Node 文件系统 API 读取源文件,绝不使用 `ctx.fs`,也不发出 `fs/observed`:只有 LSP 结果对模型可见,因此查询不满足先读后写策略。 ## 配置 @@ -29,7 +29,7 @@ Namespace 插件(`name`/`inject`/`Config`/`apply`,无默认导出) | `configuration` | `null` | 每个 `workspace/configuration` 配置项的静态答案。 | | `maxMessageBytes` | `16000000` | 从服务器接受的单条 framed 消息最大大小。 | | `maxStderrBytes` | `1000000` | 为诊断保留的 stderr 尾部最大大小。 | -| `maxDocumentBytes` | `4000000` | 该主机可打开的最大源文件。 | +| `maxDocumentBytes` | `4000000` | 该主机可打开的源文件大小上限。 | | `shutdownTimeoutMs` | `5000` | 升级前用于优雅 `shutdown`/`exit` 的预算。 | | `killGraceMs` | `2000` | 请求取消及 SIGTERM→SIGKILL 升级的宽限期。 | @@ -37,11 +37,11 @@ Namespace 插件(`name`/`inject`/`Config`/`apply`,无默认导出) ## 协议行为 -初始化会声明 `general.positionEncodings: ['utf-16']`、`workspace: { workspaceFolders: true, configuration: true }`、`textDocument.hover.contentFormat: ['markdown', 'plaintext']`,以及定义与实现使用的 `linkSupport: true`,且不进行动态注册。服务器返回的能力具有最终决定权:不受支持的操作,或缺少临时打开/关闭的同步方式,会使查询失败。服务器省略 `positionEncoding` 时默认为 `utf-16`;其他值都属于协议错误。客户端通过静态配置回答 `workspace/configuration`,接受生命周期记账请求,并拒绝 `workspace/applyEdit`:它绝不应用编辑或运行命令。导航直接映射 `Location`,并从 `LocationLink` 的 `targetUri` + `targetSelectionRange` 映射;hover 规范化会取得有效的 `MarkupContent.value`,保留 string `MarkedString`,把带 language tag 的值渲染为围栏代码,并用一个空行连接数组。缺失结果、格式错误的范围或位置,以及格式错误的 hover 编码,都会作为结构化 `LSP_MALFORMED_RESPONSE` 错误失败。 +初始化会声明 `general.positionEncodings: ['utf-16']`、`workspace: { workspaceFolders: true, configuration: true }`、`textDocument.hover.contentFormat: ['markdown', 'plaintext']`,以及定义与实现使用的 `linkSupport: true`,且不进行动态注册。服务器返回的能力具有最终决定权:不受支持的操作,或缺少临时打开/关闭的同步方式,会使查询失败。服务器省略 `positionEncoding` 时默认为 `utf-16`;其他值都属于协议错误。客户端通过静态配置回答 `workspace/configuration`,接受生命周期记账请求,并拒绝 `workspace/applyEdit`:它绝不应用编辑或运行命令。导航直接映射 `Location`,并从 `LocationLink` 的 `targetUri` + `targetSelectionRange` 映射;hover 规范化会取得有效的 `MarkupContent.value`,保留 string `MarkedString`,把带 language tag 的值渲染为围栏代码,并用一个空行连接数组。缺失结果、格式错误的范围或位置,以及格式错误的 hover 编码,都会以结构化 `LSP_MALFORMED_RESPONSE` 错误的形式失败。 ## 安全边界 -提供方信任其配置的服务器,不声明任何沙箱限制。它通过 Node API 规范化并读取源文件,拒绝缺失、非普通文件、非 UTF-8、过大,或规范路径位于规范 Workspace 外部的源文件(符号链接别名共享一个实例)。结果位置可以在外部,但外部路径不能成为查询源。因此,第一版要求可信的主机本地部署;受限、远程或虚拟 Workspace 需要另一个提供方。 +提供方信任其配置的服务器,不提供任何沙箱隔离。它通过 Node API 规范化并读取源文件,拒绝缺失、非普通文件、非 UTF-8、过大,或规范路径位于规范 Workspace 外部的源文件(符号链接别名共享一个实例)。结果位置可以在外部,但外部路径不能成为查询源。因此,第一版要求可信的主机本地部署;受限、远程或虚拟 Workspace 需要另一个提供方。 ## 模型体验 @@ -53,6 +53,6 @@ Namespace 插件(`name`/`inject`/`Config`/`apply`,无默认导出) ## 已知限制与暂缓事项 -- **仅限可信主机本地环境**:没有沙箱限制,也没有私有 cache/temp 写入契约;支持不受信任 binary 或受限/远程/虚拟 Workspace,需要后续的进程/文件系统契约及不同提供方(见 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。限制逻辑先解析 `realpath`,再通过一个带 `O_NOFOLLOW | O_NONBLOCK` 的 handle 打开源文件(最终组件符号链接防护,并以非阻塞方式拒绝 FIFO),同时进行有界读取;并发修改方如果在解析与打开之间把*祖先*目录替换为符号链接,会造成残余 TOCTOU。在该可信部署模型下接受此风险,不使用不可移植的 `openat` 逐 segment 遍历来封闭。 +- **仅限可信主机本地环境**:没有沙箱隔离,也没有私有 cache/temp 写入契约;支持不受信任 binary 或受限/远程/虚拟 Workspace,需要后续的进程/文件系统契约及不同提供方(见 [seam Agent Note(agent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。限制逻辑先解析 `realpath`,再通过一个带 `O_NOFOLLOW | O_NONBLOCK` 的 handle 打开源文件(最终组件符号链接防护,并以非阻塞方式拒绝 FIFO),同时进行有界读取;并发修改方如果在解析与打开之间把*祖先*目录替换为符号链接,会造成残余 TOCTOU。在该可信部署模型下接受此风险,不使用不可移植的 `openat` 逐 segment 遍历来封闭。 - **临时打开兼容性下限**:同步能力省略打开/关闭(或声明 `None`)的服务器不受支持,即使关闭文档查询能够工作;固定的 TypeScript e2e 只建立一项兼容性下限,不代表跨语言承诺。 -- **逐服务器/Workspace 串行化延迟**:共享同一个服务器与 Workspace 的并行 agent 会在一个进程后排队;长生命周期 Workspace 进程会占用内存直到释放。 +- **逐服务器/Workspace 串行化延迟**:共享同一个服务器与 Workspace 的并行 agent(智能体)会在一个进程后排队;长生命周期 Workspace 进程会占用内存直到 dispose。 diff --git a/packages/lsp/lsp/README.zh.md b/packages/lsp/lsp/README.zh.md index 13ae9700e2..ea018ae34c 100644 --- a/packages/lsp/lsp/README.zh.md +++ b/packages/lsp/lsp/README.zh.md @@ -4,11 +4,11 @@ **LSP 能力 seam**:抽象 `LspService`(`ctx.lsp`)定义 harness 具备哪些语义代码导航能力(转到定义、查找引用、查找实现、悬停),并通过语言服务器提供方实现,不把模型契约绑定到本地子进程。 -该包是 LSP 能力中负责接口的三分之一: +该包(package)是 LSP 能力中负责接口的三分之一: | 包 | 职责 | |---|---| -| `@deepseek-ai/dsh-lsp`(本包) | 接口:服务、以品牌化 id + 扩展名映射为 key 的提供方注册表、逐查询选择、请求/结果词汇、`LspError` 分类体系 | +| `@deepseek-ai/dsh-lsp`(本包) | 接口:服务、以带品牌类型的 id 和扩展名映射为键的提供方注册表、逐查询选择、请求/结果词汇、`LspError` 分类体系 | | `@deepseek-ai/dsh-lsp-local` | 通用本地后端,注册已配置的 stdio 语言服务器提供方 | | `@deepseek-ai/dsh-tool-lsp` | 面向模型的 `lsp` 工具,基于 `ctx.lsp` | @@ -18,16 +18,16 @@ | 成员 | 语义 | |---|---| -| `registerProvider(provider)` | 注册后端,以原子方式保留其品牌化 `id` 与每个规范化文件扩展名。任何无效输入或冲突都不会发布内容,并抛出 `LspError`(`LSP_INVALID_PROVIDER`/`LSP_CONFLICT`)。返回释放所有保留项的 disposer。随调用 fiber 释放。 | +| `registerProvider(provider)` | 注册后端,以原子方式保留其带品牌类型的 `id` 与每个规范化文件扩展名。任何无效输入或冲突都不会发布内容,并抛出 `LspError`(`LSP_INVALID_PROVIDER`/`LSP_CONFLICT`)。返回释放所有保留项的 disposer。随调用 fiber 一同 dispose(资源释放)。 | | `query(request, signal?)` | 按文件最终扩展名选择提供方,从该提供方的映射派生 `languageId`,并运行一次查询。没有匹配项时抛出 `LspError` `LSP_UNAVAILABLE`。 | -选择逐查询进行且与顺序无关:一个提供方独占一组扩展名,因此注册和 HMR 顺序绝不会改变路由。扩展名 key 规范化为小写且以点开头;`languageId` 只用于同步临时文档,绝不参与选择。第一版没有 glob、language-id 或显式路由 selector。 +选择逐查询进行且与顺序无关:一个提供方独占一组扩展名,因此注册和 HMR(热模块替换)顺序绝不会改变路由。扩展名 key 规范化为小写且以点开头;`languageId` 只用于同步临时文档,绝不参与选择。第一版没有 glob、language-id 或显式路由 selector。 -提供方注册的是**能力** 而非工具。`dsh-tool-lsp` 是面向模型名称、描述、提示词指引、schema 和呈现的唯一 owner。 +提供方注册的是**能力**,而非工具。`dsh-tool-lsp` 是面向模型名称、描述、提示词指引、schema 和呈现的唯一 owner。 ## 词汇 -`LspQueryRequest`(`operation`、`filePath`、`position`、`workspaceRoot`):每个字段都必填,因此没有字段需要实现默认值,也不存在 `resolve()` 步骤。位置与范围使用从零开始的 UTF-16,与协议一致;工具拥有从 1 开始的光标约定。`findReferences` 始终包含声明,提供方在内部强制执行,因此调用方没有 flag。`LspQueryResult` 是封闭的判别联合:导航使用 `{ kind: 'locations'; locations; resolvedWorkspaceRoot }`,悬停使用 `{ kind: 'hover'; hover }`(内容或 `null`);消费方通过 `switch` 实现穷尽检查,因此新增分支会使编译失败,直到完成处理。`resolvedWorkspaceRoot` 是提供方对请求 `workspaceRoot` 的规范形式,也是其 `file:` URI 所相对的根;调用方把显示路径相对化时使用该值,而非可能含符号链接的请求根。完整契约见 `src/types.ts`;`src/index.ts` 给出 `LspError` code,包括 `LSP_DISPOSED` 和 `LSP_MALFORMED_RESPONSE`。 +`LspQueryRequest`(`operation`、`filePath`、`position`、`workspaceRoot`):每个字段都必填,因此没有字段需要实现默认值,也不存在 `resolve()` 步骤。位置与范围使用从零开始的 UTF-16,与协议一致;工具负责从 1 开始的光标约定。`findReferences` 始终包含声明,提供方在内部强制执行,因此调用方没有 flag。`LspQueryResult` 是封闭的判别联合:导航使用 `{ kind: 'locations'; locations; resolvedWorkspaceRoot }`,悬停使用 `{ kind: 'hover'; hover }`(内容或 `null`);消费方通过 `switch` 实现穷尽检查,因此新增分支会使编译失败,直到完成处理。`resolvedWorkspaceRoot` 是提供方对请求 `workspaceRoot` 的规范形式,也是其 `file:` URI 所相对的根;调用方把显示路径相对化时使用该值,而非可能含符号链接的请求根。完整契约见 `src/types.ts`;`src/index.ts` 给出 `LspError` 代码,包括 `LSP_DISPOSED` 和 `LSP_MALFORMED_RESPONSE`。 ## 模型体验 @@ -39,6 +39,6 @@ ## 已知限制与暂缓事项 -- **同一运行时内扩展名归属互斥**:两个提供方不能同时声明 `.ts`,即使 language id 不同;重叠会使注册失败。预期扩展是在注册之上增加部署配置的 selector;它可以放宽互斥保留,而无需把提供方选择加入模型输入(见 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。 +- **同一运行时内扩展名归属互斥**:两个提供方不能同时声明 `.ts`,即使语言 ID 不同;重叠会使注册失败。预期扩展是在注册之上增加部署配置的 selector;它可以放宽互斥保留,而无需把提供方选择加入模型输入(见 [seam Agent Note(agent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。 - **仅四种操作**:symbol 与 call hierarchy 暂缓(它们需要不同 schema);diagnostics 需要独立的新鲜度/累积规则;修改操作(rename、code action、formatting)需要独立工具,并集成预览、权限和写入策略。 -- **没有观测表层**:可用性只能通过运行 `query()` 并按抛出的 `LspError` code 路由来观测;没有提供方变更事件或能力状态查询。 +- **没有观测接口**:可用性只能通过运行 `query()` 并按抛出的 `LspError` 代码 路由来观测;没有提供方变更事件或能力状态查询。 diff --git a/packages/lsp/tool-lsp/README.zh.md b/packages/lsp/tool-lsp/README.zh.md index e08ffcef0f..570fd353a3 100644 --- a/packages/lsp/tool-lsp/README.zh.md +++ b/packages/lsp/tool-lsp/README.zh.md @@ -8,13 +8,13 @@ Namespace 插件(`name`/`inject`/`Config`/`apply`,无默认导出) ## 工具 -`lsp` 接受 `operation`(`goToDefinition` | `findReferences` | `goToImplementation` | `hover`)、`file_path`、`line` 和 `character`。`line` 与 `character` 是正的、从 1 开始的 UTF-16 光标坐标;工具将其转换为 seam 从零开始的位置,并把渲染位置转换回来。`findReferences` 包含声明,因此影响分析不会遗漏定义位置。提供方、language id、Workspace 根、限制、超时、初始化和可执行文件均不进入模型输入。 +`lsp` 接受 `operation`(`goToDefinition` | `findReferences` | `goToImplementation` | `hover`)、`file_path`、`line` 和 `character`。`line` 与 `character` 是正的、从 1 开始的 UTF-16 光标坐标;工具将其转换为 seam 从零开始的位置,并把渲染位置转换回来。`findReferences` 包含声明,因此影响分析不会遗漏定义位置。提供方、语言 ID、工作区根目录、限制、超时、初始化和可执行文件均不进入模型输入。 -该工具要求从会话 `header.cwd` 取得 Workspace 根,没有回退值:缺失时会在查询前以 `LSP_WORKSPACE_REQUIRED` 失败。其规范结果是完整的已规范化 seam 联合:`{ kind: "locations", locations, resolvedWorkspaceRoot }` 或 `{ kind: "hover", hover }`;Code Mode 可以直接检查每个已取得的位置和从零开始的范围。原生渲染随后投影按文件稳定分组的 `path:line:character` 配置项,并相对于结果的 `resolvedWorkspaceRoot`(提供方的规范根)而非会话 cwd;因此,即使 cwd 包含符号链接,Workspace 内结果仍渲染为相对路径。`file:` URI 在内部时成为 Workspace 相对路径,在外部时成为绝对路径,其他 URI 保持原样。空位置和 `null` hover 都是成功的无结果响应;格式错误的提供方载荷仍是结构化错误。 +该工具要求从会话 `header.cwd` 取得工作区根目录,没有回退值:缺失时会在查询前以 `LSP_WORKSPACE_REQUIRED` 失败。其规范结果是完整的已规范化 seam 联合:`{ kind: "locations", locations, resolvedWorkspaceRoot }` 或 `{ kind: "hover", hover }`;Code Mode 可以直接检查每个已取得的位置和从零开始的范围。Native 渲染随后投影出稳定的、按文件分组的 `path:line:character` 条目,并相对于结果的 `resolvedWorkspaceRoot`(提供方的规范根目录)而非会话 cwd;因此,即使 cwd 包含符号链接,工作区内的结果仍渲染为相对路径。`file:` URI 位于工作区内时成为工作区相对路径,位于工作区外时成为绝对路径,其他 URI 保持原样。空位置和 `null` hover 都是成功的无结果响应;格式错误的提供方载荷仍是结构化错误。 ## 配置 -| Key | 默认值 | 含义 | +| 配置键 | 默认值 | 含义 | |---|---|---| | `maxLocations` | `100` | 出现省略标记前可渲染位置的最大数量。 | | `maxResultChars` | `16000` | 完整渲染结果的最大长度,包括截断元数据。 | @@ -40,7 +40,7 @@ Use search/read for ordinary navigation. Use lsp when textual matches are ambigu #### KV Cache 影响 -只要插件 scope 与指引文本不变,前缀就保持稳定;激活或释放可能使从该区段起的复用失效。 +只要插件作用域与指引文本不变,前缀就保持稳定;激活或 dispose(资源释放)可能使从该区段起的复用失效。 ### 工具 schema @@ -54,13 +54,13 @@ Use search/read for ordinary navigation. Use lsp when textual matches are ambigu #### KV Cache 影响 -只要可见工具定义与顺序不变,前缀就保持稳定;注册生命周期或 scope 限制可能使从第一个变化的 schema token 起的复用失效。 +只要可见工具定义与顺序不变,前缀就保持稳定;注册生命周期或作用域限制可能使从第一个变化的 schema token 起的复用失效。 ### 结果 #### 模型看到的内容 -按文件分组的 `path:line:character` 位置行或规范化 hover 文本,先由 `maxLocations` 限制,再由 `maxResultChars` 限制;省略与截断标记计入完整字符上限。这些上限只影响原生/模型呈现,不影响规范值。空结果使用不同的 `No results.`/`No hover information.` 行。 +按文件分组的 `path:line:character` 位置行或规范化 hover 文本,先由 `maxLocations` 限制,再由 `maxResultChars` 限制;省略与截断标记计入完整字符上限。这些上限只影响 Native/模型呈现,不影响规范值。空结果使用不同的 `No results.`/`No hover information.` 行。 #### Token 影响 @@ -74,7 +74,7 @@ Use search/read for ordinary navigation. Use lsp when textual matches are ambigu #### 模型看到的内容 -无。客户端渲染通用搜索卡片:`{ card: 'generic', kind: 'search', title, locations: [{ path, line }] }`;从 args 派生的标题携带操作与从 1 开始的光标,跟随焦点对准查询行,标题则保留列号。 +无。客户端渲染通用搜索卡片:`{ card: 'generic', kind: 'search', title, locations: [{ path, line }] }`;从 args 派生的标题携带操作与从 1 开始的光标,编辑器跟随定位会聚焦所查询的行,标题则保留列号。 #### Token 影响 @@ -86,5 +86,5 @@ Use search/read for ordinary navigation. Use lsp when textual matches are ambigu ## 已知限制与暂缓事项 -- **UTF-16 光标坐标**:列坐标与协议精确一致,但模型难以在非 BMP 字符周围计数;非 symbol 位置可能返回空结果,因此提示词解释了该约定,但不会鼓励宽泛使用 LSP(见 [seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。 +- **UTF-16 光标坐标**:列坐标与协议精确一致,但模型难以在非 BMP 字符周围计数;不在符号上的位置可能返回空结果,因此提示词解释了该约定,但不会鼓励宽泛使用 LSP(见 [seam Agent Note(agent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md))。 - **不承诺跨服务器完整性**:受支持的服务器仍可能根据索引就绪情况返回空或部分结果;该工具不承诺跨语言或服务器的完整性。 diff --git a/packages/mcp/mcp-client/README.zh.md b/packages/mcp/mcp-client/README.zh.md index 006e662ad6..e687c62015 100644 --- a/packages/mcp/mcp-client/README.zh.md +++ b/packages/mcp/mcp-client/README.zh.md @@ -29,7 +29,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc Authorization: !!js '`Bearer ${process.env.MCP_TOKEN}`' ``` -模型会看到 `mcp__github__create_issue`、`mcp__web__search` 等工具,这与 Claude Code 和 Codex 使用的服务器限定形状相同。HMR 会热替换:编辑配置项会触发断开 + 重新连接,无需重启进程;`serverName` 不变时会生成完全相同的工具名称。 +模型会看到 `mcp__github__create_issue`、`mcp__web__search` 等工具,这与 Claude Code 和 Codex 使用的服务器限定形状相同。HMR(热模块替换)支持热替换:编辑配置项会触发断开 + 重新连接,无需重启进程;`serverName` 不变时会生成完全相同的工具名称。 ## 配置 @@ -39,7 +39,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc | `serverName` | 两者 | 是 | 该服务器面向模型工具名称的 namespace;`[A-Za-z0-9_-]{1,32}`,在存活实例中唯一 | | `command` | stdio | 是 | 要 spawn 的可执行文件 | | `args` | stdio | 否 | 传给命令的参数 | -| `env` | stdio | 否 | 合并到已清理环境之上的额外环境变量 | +| `env` | stdio | 否 | 合并到已清理环境中的额外环境变量 | | `cwd` | stdio | 否 | 子进程工作目录 | | `url` | http | 是 | MCP 服务器 URL | | `headers` | http | 否 | 额外标头(例如认证 token) | @@ -52,7 +52,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc - 发布相同原始名称(例如 `search`)的两个服务器会在各自 namespace 下共存。 - 存活实例中的重复 `serverName` 会使后加载的插件实例失败。 - 服务器在工具列表中两次列出同一工具名称时,该列表会作为无效工具列表被拒绝。 -- 外部注册抢占该服务器 namespace 时,会回滚整个世代(绝不保留部分集合),并高声报错。 +- 外部注册抢占该服务器 namespace 时,会回滚整个世代(绝不保留部分集合),并明确报错。 ## 行为 @@ -60,7 +60,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc - 监听 `notifications/tools/list_changed` → 重新同步;同步失败时保留上一世代的注册。 - 工具执行:`client.callTool({ name: rawName, arguments }, { signal })`,支持超时 + 中止;公开名称绝不会发给服务器。 - 规范成功值是 `{ content: JsonValue[], structuredContent? }`;完整的 JSON MCP 块会保留给编程调用方。受支持且已声明的 `outputSchema` 会验证 `structuredContent`;不受支持的 schema 词汇会回退为不受约束的 `JsonValue`。 -- 原生/模型渲染保留现有文本投影:文本块以换行连接,图片、音频、资源和不受支持的块会变成占位符。 +- Native/模型渲染保留现有文本投影:文本块以换行连接,图片、音频、资源和不受支持的块会变成占位符。 - 断开/崩溃时:注销所有工具;不自动重新连接。 ## 消费的服务 @@ -75,7 +75,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc #### 模型看到的内容 -初始发现成功后,每个已声明的 MCP 工具都会显示为名为 `mcp____`(或其确定性规范化形式)的原生工具,并携带服务器提供的描述和输入 schema。成功的重新同步会替换整个世代;插件释放会移除它。 +初始发现成功后,每个已声明的 MCP 工具都会显示为名为 `mcp____`(或其确定性规范化形式)的原生工具,并携带服务器提供的描述和输入 schema。成功的重新同步会替换整个世代;对插件执行 dispose(资源释放)会移除该世代。 #### Token 影响 @@ -89,20 +89,20 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc #### 模型看到的内容 -公开工具名称和 JSON 参数会保留在 assistant 历史中。文本结果块会以换行连接为一个保留的原生文本结果;图片、音频、资源和不受支持的块在其中变为简短占位符。它们的完整 JSON 块及可选结构化内容保留在执行局部的规范值中;MCP `isError` 会通过注册表的错误路径拒绝调用。 +公开工具名称和 JSON 参数会保留在 assistant 历史中。文本结果块会以换行连接为一个保留的 Native 文本结果;图片、音频、资源和不受支持的块在其中变为简短占位符。它们的完整 JSON 块及可选结构化内容保留在执行局部的规范值中;MCP `isError` 会通过注册表的错误路径拒绝调用。 #### Token 影响 -参数和映射后的文本会保留到压缩发生时。二进制与资源载荷会被丢弃,而不会加入上下文。 +参数和映射后的文本会保留到压缩(compaction)发生时。二进制与资源载荷会被丢弃,而不会加入上下文。 #### KV Cache 影响 -仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 配置项失效。 +仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。 ## 已知限制与暂缓事项 - **初始发现是异步的**:插件加载不会等待连接和 `listTools()`,因此在启动或 HMR 后立即开始的轮次可能在 MCP 工具注册前完成组装。 -- **只桥接 MCP 的工具能力**:资源和提示词没有 harness 消费表层,暂缓实现。 +- **只桥接 MCP 的工具能力**:资源和提示词没有 harness 消费接口,暂缓实现。 - **崩溃恢复需要手动触发**:传输关闭会注销服务器工具,但重新连接需要 HMR 重载或重启 harness。 -- **原生非文本渲染有损**:图片、音频与资源载荷在模型上下文中会变成占位符,即使执行局部的规范值保留了其 JSON 块。更丰富的原生多媒体投影暂缓实现。 +- **Native 非文本渲染有损**:图片、音频与资源载荷在模型上下文中会变成占位符,即使执行局部的规范值保留了其 JSON 块。更丰富的 Native 多媒体投影暂缓实现。 - **不强制执行不受支持的 MCP 输出 schema**:已声明 schema 使用 harness 子集之外的词汇时,`structuredContent` 会回退到 `JsonValue`。 diff --git a/packages/plan/README.zh.md b/packages/plan/README.zh.md index cedb8dac13..4afe39e0eb 100644 --- a/packages/plan/README.zh.md +++ b/packages/plan/README.zh.md @@ -2,10 +2,10 @@ [English](README.md) | 中文 -Plan mode 是一种按 agent 分开记录到日志的协作状态。它是单一 **产品** 包(package),而非通用 mode 注册表或能力 seam 三包组合。 +Plan mode 是一种按 agent(智能体)分开记录到日志的协作状态。它是单一**产品**包(package),而非通用模式注册表或能力 seam 三包组合。 | 包 | 职责 | ctx 键 | |---|---|---| | `plan-mode/` | `plan/mode` 词汇与折叠、在边界生效的状态、`plan:policy` 引导段、`/plan [message]` 进入命令与 `/plan off` 退出命令,以及面向模型的 `exit_plan_mode` 评审工具 | `ctx.planMode` | -活跃状态是会话日志的纯函数,因此恢复和 fork 无需额外机制即可还原该状态。部署通过 Cordis 配置提供 plan 指令,而 `exit_plan_mode` 在 plan mode 未激活时仍保持注册,以稳定请求工具目录。交互式适配器使用插件拥有的 `/plan` 命令;沙箱模式和批准策略仍是独立的强制执行设置。设计详见 [plan 专用协作状态](../../.agents/notes/implemented/simplification/2026-07-22-plan-specific-collaboration-state.md)。 +活跃状态是会话日志的纯函数,因此恢复和 fork 无需额外机制即可还原该状态。部署通过 Cordis 配置提供 plan 引导内容,而 `exit_plan_mode` 在 Plan mode 未激活时仍保持注册,以稳定请求工具目录。交互式适配器使用插件拥有的 `/plan` 命令;沙箱模式和审批策略仍是独立的强制执行设置。设计详见 [plan 专用协作状态](../../.agents/notes/implemented/simplification/2026-07-22-plan-specific-collaboration-state.md)。 diff --git a/packages/pty/README.zh.md b/packages/pty/README.zh.md index 9fc262787b..4e36ef934d 100644 --- a/packages/pty/README.zh.md +++ b/packages/pty/README.zh.md @@ -2,12 +2,12 @@ [English](README.md) | 中文 -`PTY` 的全称是 **Pseudo-Terminal(伪终端)**。这项能力提供持久且限定所有者范围的终端会话,适用于需要跨工具调用保留状态或使用交互式 stdin 的工作流。PTY 是单次 bash 与文件系统工具的补充,不会取代后两者更严格的逐操作契约。 +`PTY` 的全称是 **Pseudo-Terminal**(伪终端)。这项能力提供持久且限定所有者范围的终端会话,适用于需要跨工具调用保留状态或使用交互式 stdin 的工作流。PTY 是单次 bash 与文件系统工具的补充,不会取代后两者更严格的逐操作契约。 | 包 | 职责 | ctx 键 | |---|---|---| -| [`pty`](pty/README.md)(`@deepseek-ai/dsh-pty`) | 后端注册表、品牌化 id、精确的 Agent 所有权、会话操作与等待完成的清理 | `ctx.pty` | +| [`pty`](pty/README.md)(`@deepseek-ai/dsh-pty`) | 后端注册表、品牌化 id、精确到 agent(智能体)的所有权、会话操作与等待清理完成的机制 | `ctx.pty` | | `pty-local`(`@deepseek-ai/dsh-pty-local`) | 本地 `node-pty` 后端、就绪检测、有界终端状态、沙箱与进程会话监管 | 注册到 `ctx.pty` | -| `tool-pty`(`@deepseek-ai/dsh-tool-pty`) | 6 个面向模型的工具,并为后台发送集成通用任务 | 注册到 `ctx.tools` | +| `tool-pty`(`@deepseek-ai/dsh-tool-pty`) | 6 个面向模型的工具,以及用于后台发送的通用任务集成 | 注册到 `ctx.tools` | -设计与暂缓边界记录在[持久 PTY Agent Note](../../.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md) 中。 +设计与暂缓边界记录在[持久 PTY Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.md) 中。 diff --git a/packages/pty/pty-local/README.zh.md b/packages/pty/pty-local/README.zh.md index c417828a44..fc71c419a5 100644 --- a/packages/pty/pty-local/README.zh.md +++ b/packages/pty/pty-local/README.zh.md @@ -6,11 +6,11 @@ ## 插件(`pty-local`) -该插件注入 `pty`、`sandbox` 和 `sandboxPolicy`,然后注册所配置的后端类型(`shell`)。`danger-full-access` 会直接启动 shell;受限模式则通过 `ctx.sandbox` 包装确切的 shell argv。系统在 spawn 时解析会话的实际模式。当某个所有者存在开放的 PTY 或正在进行 spawn 时,如果配置变更会得到不同的实际模式,系统会在对应 `sandbox/mode` 事件提交前拒绝该变更。该限制绑定到确切所有者,因此即使本地提供方重新加载并保留现有会话,它仍然有效。更改模式前,请等待创建结算并关闭会话,避免以更宽权限打开的终端在权限降级后继续存在。 +该插件注入 `pty`、`sandbox` 和 `sandboxPolicy`,然后注册所配置的后端类型(`shell`)。`danger-full-access` 会直接启动 shell;受限模式则通过 `ctx.sandbox` 包装确切的 shell argv。系统在 spawn 时解析会话的实际模式。当某个所有者存在开放的 PTY 或正在进行 spawn 时,如果配置变更会得到不同的实际模式,系统会在对应 `sandbox/mode` 事件提交前拒绝该变更。该限制绑定到确切所有者,因此即使本地提供方重新加载并保留现有会话,它仍然有效。更改模式前,请等待创建完成并关闭会话,避免以更宽权限打开的终端在权限降级后继续存在。 -Linux 的就绪检测结合以下机制:由前台状态验证的私有 bash 提示符标记、前台进程组 syscall 检查、静默回退和绝对超时。macOS 没有 `/proc` syscall 接口,因此使用经过验证的提示符标记以及静默/超时。当可打印的提示符文本尚未到达时,即使 OSC 标记和 `PS1` 被拆到多个数据回调中,系统也不会把标记视为就绪。如果 bash 在内核发布其重新取得前台进程组的状态前打印标记,轮询会在普通静默上限之后再保留该候选状态 `handoffGraceMs`,使恰好同时发生的前台交接有机会胜出;该宽限至少要覆盖一个 `pollIntervalMs`,否则加载时即被拒绝。因此,继承 `PROMPT_COMMAND` 的交互式子进程无法持续压制推断空闲就绪,最多只能延续到绝对超时。无法识别或读取的进程状态绝不会作为精确空闲的正向信号。同样,一次 send 之前就已存在的前台进程组 stdin 等待并不代表写入后就绪:必须先观察到同一进程组脱离该等待,之后再次进入等待才能使该次 send 完成;前台进程组发生变化则构成新的证据。尚未发布的启动过程中,回退路径要求已经观察到输出;零输出静默不能发布空会话,超时则拒绝 spawn。取消操作会关闭尚未发布的 shell,并以调用方提供的确切中止原因拒绝,即使当时还无法观察其前台进程组。如果关闭失败,`PtyBackendCleanupError` 会单独保留清理失败,供注册表释放资源时处理。未完成的终端控制序列受 `maxReadBytes` 限制;超过上限后,系统会丢弃内容直到其终止符。末尾的回车会跨回调保留,使拆分的 CRLF 合并为一个换行。 +Linux 的就绪检测结合以下机制:由前台状态验证的私有 bash 提示符标记、前台进程组 syscall 检查、静默回退和绝对超时。macOS 没有 `/proc` syscall 接口,因此使用经过验证的提示符标记以及静默/超时。当可打印的提示符文本尚未到达时,即使 OSC 标记和 `PS1` 被拆到多个数据回调中,系统也不会把标记视为就绪。如果 bash 在内核发布其重新取得前台进程组的状态前打印标记,轮询会在普通静默上限之后再保留该候选状态 `handoffGraceMs`,使恰好同时发生的前台交接有机会胜出;该宽限至少要覆盖一个 `pollIntervalMs`,否则加载时即被拒绝。因此,继承 `PROMPT_COMMAND` 的交互式子进程无法一直抑制推断空闲就绪直至绝对超时。无法识别或读取的进程状态绝不会作为精确空闲的正向信号。同样,一次 send 之前就已存在的前台进程组 stdin 等待并不代表写入后就绪:必须先观察到同一进程组脱离该等待,之后再次进入等待才能使该次 send 完成;前台进程组发生变化则构成新的证据。尚未发布的启动过程中,回退路径要求已经观察到输出;零输出静默不能发布空会话,超时则拒绝 spawn。取消操作会关闭尚未发布的 shell,并以调用方提供的确切中止原因拒绝,即使当时还无法观察其前台进程组。如果关闭失败,`PtyBackendCleanupError` 会单独保留清理失败,供注册表 dispose(资源释放)时处理。未完成的终端控制序列受 `maxReadBytes` 限制;超过上限后,系统会丢弃内容直到其终止符。末尾的回车会跨回调保留,使拆分的 CRLF 合并为一个换行。 -取消发送时,系统会解析当前前台进程组并发送真正的 `SIGINT`;它绝不会通过写入 `\x03` 模拟中断,因此原始模式程序仍可取消。关闭操作先向后代发送 `SIGTERM` 并等待,再向已捕获的存活进程与新扫描到的后代之并集发送 `SIGKILL`,防止进程通过重新设定父进程而逃避清理。系统确认每个保留的进程身份都已消失;在 Linux 上,非执行中的僵尸进程也视为完全停稳,并会随 shell 退出而回收。如果仍有进程存活,失败结果不会缓存成永久拒绝的关闭操作;后续关闭仍会重试清理。 +取消发送时,系统会解析当前前台进程组并发送真正的 `SIGINT`;它绝不会通过写入 `\x03` 模拟中断,因此raw 模式程序仍可取消。关闭操作先向后代发送 `SIGTERM` 并等待,再向已捕获的存活进程与新扫描到的后代之并集发送 `SIGKILL`,防止进程通过重新设定父进程而逃避清理。在停止 shell 前,系统会确认每个保留的进程身份都已消失,或者在 Linux 上已成为不再执行的僵尸进程;僵尸进程条目视为完全停稳,并会随 shell 退出而回收。如果仍有进程存活,失败结果不会缓存成永久拒绝的关闭操作;后续关闭仍会重试清理。 ## 模型体验 @@ -22,15 +22,15 @@ Linux 的就绪检测结合以下机制:由前台状态验证的私有 bash #### Token 影响 -消费方返回有界的后端输出前没有影响。此包不会把保留的 PTY scrollback 放入模型历史。 +消费方返回有界的后端输出前没有影响。此包(package)不会把保留的 PTY scrollback 放入模型历史。 #### KV Cache 影响 -不会直接失效;提示词、schema 与追加结果由消费方负责。 +不会直接使 KV Cache 失效;提示词、schema 与追加结果由消费方负责。 -## 已知限制与暂缓工作 +## 已知限制与暂缓事项 - 输出按行规范化;不支持全屏备用缓冲区交互。 - Linux 精确探针支持 x64 与 arm64 UAPI 表;其他架构使用提示符标记和静默/超时就绪机制。 - 如果后代进程在清理前守护化并重新设定父进程,它会脱离已捕获的进程树;清理绝不会扩大到启动器 PID 所属的整个 POSIX 会话,因为其中可能包含无关进程。 -- 会话无法跨 harness 进程退出保留。 +- harness 进程退出后,会话无法继续存在。 diff --git a/packages/pty/pty/README.zh.md b/packages/pty/pty/README.zh.md index 9158afd6a7..95c6345a80 100644 --- a/packages/pty/pty/README.zh.md +++ b/packages/pty/pty/README.zh.md @@ -2,20 +2,20 @@ [English](README.md) | 中文 -限定所有者范围的持久 PTY seam。`PtyService` 注册为 `ctx.pty`,生成不透明的会话 id,通过具名后端路由创建操作,将每个操作限制在完全相同的活跃 `Agent` 内,并在该 agent 或服务释放资源时等待后端完全停稳。 +限定所有者范围的持久 PTY seam。`PtyService` 注册为 `ctx.pty`,生成不透明的会话 id,通过具名后端路由创建操作,将每个操作限制在完全相同的活跃 `Agent` 内,并在该 agent(智能体)或服务 dispose(资源释放)时等待后端完全停稳。 ## 契约 -- 后端注册一个稳定的 `type`,并返回尚未发布的 `PtyBackendSession`;失败或取消的设置过程必须清理部分资源。若清理失败,则以 `PtyBackendCleanupError` 拒绝,使注册表能在取消之后继续保留该资源。 -- spawn 取消会保留调用方提供的确切中止原因。后端设置完成后,服务资源释放与所有者消失仍分别对应可供机器路由的不同失败。 -- 所有者与服务的资源释放会通过服务所有的信号中止尚未发布的设置,并等待后端结算和回滚后才返回。 -- 如果回滚关闭失败,或后端报告启动清理失败,资源释放生命周期会以拒绝结束,不会声称已经完全停稳。调用方触发的取消仍收到其确切原因;生命周期触发的回滚失败也会拒绝待完成的 spawn。 -- 调用方取消后发生的后端清理失败仍算作所有者活动,直到所有者或服务释放资源并消费、报告该失败,避免生命周期策略把失败的清理误判为完全停稳。 +- 后端注册一个稳定的 `type`,并返回尚未发布的 `PtyBackendSession`;失败或取消的设置过程必须清理部分资源。若清理失败,则以 `PtyBackendCleanupError` 拒绝,使注册表能在取消后继续保留该清理失败。 +- spawn 取消会保留调用方提供的确切中止原因。后端设置完成后,服务 dispose 与所有者消失仍分别对应可供机器路由的不同失败。 +- 所有者与服务的 dispose 会通过服务持有的信号中止尚未发布的设置,并等待后端结算和回滚后才返回。 +- 如果回滚关闭失败,或后端报告启动清理失败,dispose 生命周期会以拒绝结束,不会声称已经完全停稳。调用方触发的取消仍收到其确切原因;生命周期触发的回滚失败也会拒绝待完成的 spawn。 +- 调用方取消后发生的后端清理失败仍算作所有者活动,直到所有者或服务 dispose 并消费、报告该失败,避免生命周期策略把失败的清理误判为完全停稳。 - `hasOwnerActivity(owner)` 覆盖从尚未发布的设置到最终关闭的全过程,使生命周期策略能精确限制对应所有者,不受发布竞态影响。 - 成功的 spawn 会发布一个 `PtySessionId`。可选的 `name` 只是所有者本地的显示元数据,绝不代表权限。 - 一个会话最多接受一个活跃的发送操作。读取和信号操作可以观察该发送;在当前操作结算前,另一项发送会失败。 - `PtySendResult.waitReason` 与 `sessionStatus` 相互独立。`session_exit` 描述顶层 PTY 进程,而不是任意前台命令。 -- `kill()` 与资源释放只会在后端捕获的进程树完全停稳后完成。清理失败会以拒绝结束,而非声称成功;同时它会清除匹配的后端和注册表限制,使后续关闭能够重试,且不会干扰较新的尝试。 +- `kill()` 与 dispose 只会在后端捕获的进程树完全停稳后完成。清理失败会以拒绝结束,而非声称成功;同时它会清除匹配的后端和注册表限制,使后续关闭能够重试,且不会干扰较新的尝试。 该 seam 不包含 `node-pty`、沙箱、工具 schema、提示词、任务或终端渲染策略。实现负责终端机制;消费方负责模型呈现和可选的后台任务注册。 @@ -25,7 +25,7 @@ #### 模型看到的内容 -没有直接可见内容。此包不注册提示词或工具;可见 schema 和结果文本由 `@deepseek-ai/dsh-tool-pty` 负责。 +没有直接可见内容。此包(package)不注册提示词或工具;可见 schema 和结果文本由 `@deepseek-ai/dsh-tool-pty` 负责。 #### Token 影响 @@ -33,9 +33,9 @@ #### KV Cache 影响 -不会直接失效;由具名消费方负责请求前缀变更。 +不会直接失效;请求前缀变更由上述消费方负责。 -## 已知限制与暂缓工作 +## 已知限制与暂缓事项 - 会话只存在于进程本地,harness 重启后不会恢复。 - 系统有意不支持跨 agent 共享;未来的共享会话设计需要独立的权限契约。 diff --git a/packages/pty/tool-pty/README.zh.md b/packages/pty/tool-pty/README.zh.md index cdce3c25a6..72eb13957c 100644 --- a/packages/pty/tool-pty/README.zh.md +++ b/packages/pty/tool-pty/README.zh.md @@ -2,9 +2,9 @@ [English](README.md) | 中文 -基于 `ctx.pty` 提供 6 个面向模型的工具:`terminal_open`、`terminal_send`、`terminal_read`、`terminal_signal`、`terminal_close` 和 `terminal_list`。每项操作都要求提供完全相同的发起 `Agent`,因此即使模型获知另一个 agent 的 id,也无法操作其终端。 +基于 `ctx.pty` 提供 6 个面向模型的工具:`terminal_open`、`terminal_send`、`terminal_read`、`terminal_signal`、`terminal_close` 和 `terminal_list`。每项操作都要求提供完全相同的发起 `Agent`,因此即使模型获知另一个 agent(智能体)的 id,也无法操作其终端。 -`terminal_send(run_in_background: true)` 会复用 `ctx.tasks`;任务预检和 PTY 服务对每会话发送的独占预留都发生在返回 task id 之前。系统通过 `task_output` 收集完成结果,`task_kill` 则向前台进程组发送 `SIGINT`。前台发送使用终端调用/结果卡片。后台发送使用通用执行卡片;打开、读取、发送信号、关闭和列出操作则分别使用通用 `execute`、`read`、`execute`、`delete` 和 `read` 卡片。所有操作都不声明源位置。 +`terminal_send(run_in_background: true)` 会复用 `ctx.tasks`;任务预检和 PTY 服务对每个会话的独占发送预留都发生在返回 task id 之前。系统通过 `task_output` 收集完成结果,`task_kill` 则向前台进程组发送 `SIGINT`。前台发送使用终端调用/结果卡片。后台发送使用通用执行卡片;打开、读取、发送信号、关闭和列出操作则分别使用通用 `execute`、`read`、`execute`、`delete` 和 `read` 卡片。所有操作都不声明源位置。 ## 配置 @@ -13,7 +13,7 @@ | `enableRunInBackground` | `true` | 公开并接受 `run_in_background`;设为 false 时,schema 会省略该字段,并拒绝强行传入未声明的参数 | | `maxResultBytes` | `262144` | 每个完整终端结果或 PTY 任务输出的 UTF-8 上限(最小值 `64`);在等待、会话、分页、截断和任务状态元数据全部加入后计算 | -两个值都会在加载时验证。最小结果上限可保证注册表签发的每个会话或 task id 都能出现在创建确认中。结果超过 `maxResultBytes` 时,只要空间允许,渲染会为控制元数据和截断标记预留空间;截断会保留 UTF-8 边界。每个终端定义的最终内容回调都会应用同一个上限,涵盖经过规范化的 pre-execute、around-execute 与 post-execute 策略失败、拒绝、短路、替换或阻止;结构化的多块策略结果保留其形状。 +两个值都会在加载时验证。最小结果上限可保证注册表签发的每个会话或 task id 都能出现在创建确认中。结果超过 `maxResultBytes` 时,只要空间允许,渲染会为控制元数据和截断标记预留空间;截断会保留 UTF-8 边界。每个终端定义的最终内容回调都会应用同一个上限,涵盖经过规范化的 pre-execute、around-execute 与 post-execute 策略失败、拒绝、短路、替换或阻止;结构化的多块策略结果保留其结构。 ## 模型体验 @@ -55,7 +55,7 @@ Use a terminal session only when work needs persistent terminal state or interac #### 模型看到的内容 -spawn 会返回 id 和有界 MOTD。发送/读取会返回有界终端文本以及就绪/历史标记。后台模式返回通用 task id。所有终端自身或策略产生的单文本结果,在经过规范化的工具或流水线错误、拒绝、短路、替换、阻止与通用任务状态文本之后,都受 `maxResultBytes` 限制。结构化的多块策略结果保留其形状。结果会保留在会话历史中直到压缩;增量任务读取不会重复已经消费的输出。编程调用方会收到带类型的会话快照、有界的提供方读取/发送 DTO、信号与关闭结果,或 `{ kind: "background", taskId }`;Native 渲染会应用上述呈现上限。 +spawn 会返回 id 和有界 MOTD。发送/读取会返回有界终端文本以及就绪/历史标记。后台模式返回通用 task id。所有终端自身或策略产生的单文本结果,在经过规范化的工具或流水线错误、拒绝、短路、替换、阻止与通用任务状态文本之后,都受 `maxResultBytes` 限制。结构化的多块策略结果保留其结构。结果会保留在会话历史中直到压缩(compaction);增量任务读取不会重复已经消费的输出。编程调用方会收到带类型的会话快照、有界的提供方读取/发送 DTO、信号与关闭结果,或 `{ kind: "background", taskId }`;Native 渲染会应用上述呈现上限。 #### Token 影响 @@ -65,7 +65,7 @@ spawn 会返回 id 和有界 MOTD。发送/读取会返回有界终端文本 仅追加;新结果位于可复用请求前缀之后。 -## 已知限制与暂缓工作 +## 已知限制与暂缓事项 - 不公开具名按键序列、TUI、BEL、调整大小、自动启动或跨 agent 共享 schema。 - 后台模式同时依赖 `@deepseek-ai/dsh-tasks` 及其面向模型的控制接口。 diff --git a/packages/sandbox/README.zh.md b/packages/sandbox/README.zh.md index 63eaef2488..d782d1b639 100644 --- a/packages/sandbox/README.zh.md +++ b/packages/sandbox/README.zh.md @@ -2,14 +2,14 @@ [English](README.md) | 中文 -[能力 seam 拆分](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)中负责限制的一半:抽象提供方接口、平台后端和共享策略归属位置。消费方把即将 spawn 的精确 argv 交给 `ctx.sandbox`,改为 spawn 返回的已包装 argv;完整的 `SandboxExecutionPolicy`(模式 + Workspace 根)随每次能力调用传递,其中受限制的子集成为提供方的 `SandboxPolicy`。因此,不同会话与消费方可以同时按不同策略施加限制。这些全是**产品** 包。 +[能力 seam 拆分](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)中负责限制的一半:抽象提供方接口、平台后端和共享策略归属位置。消费方把即将 spawn 的精确 argv 交给 `ctx.sandbox`,改为 spawn 返回的已包装 argv;完整的 `SandboxExecutionPolicy`(模式 + 工作区根目录)随每次能力调用传递,其中受限制的子集成为提供方的 `SandboxPolicy`。因此,不同会话与消费方可以同时按不同策略施加限制。这些均为**产品**包(package)。 | 包 | 职责 | ctx key | |---|---|---| -| `sandbox/` | 抽象进程沙箱 seam(`SandboxProvider` 契约 + 模式/强制执行/策略词汇),加共享 ESCALATION 工具包(`approveEscalation`、严格变宽的阶梯、拒绝/提示标记),以及所有强制执行方言共享的 `writableRoots` 派生 | `ctx.sandbox` | -| `sandbox-local/` | 按平台链选择的本地后端:Linux 使用 `bwrap`,否则使用 `landlock-run` launcher(通过 npm 分发的 [`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run) 家族,在自身仓库构建发布);darwin 使用 `sandbox-exec`/Seatbelt。多候选链会执行功能探测,唯一候选项直接选择,结论缓存,快速失败 | (注册 `ctx.sandbox`) | -| `sandbox-policy/` | 策略解析器:部署回退值,加每个会话的持久模式与不可变 cwd 根。两个强制执行家族都消费完整的逐调用结果,因此 bash 与 fs 不会限制到不同根目录 | `ctx.sandboxPolicy` | +| `sandbox/` | 抽象进程沙箱 seam(`SandboxProvider` 契约 + 模式/强制执行/策略词汇),加共享 ESCALATION 工具包(`approveEscalation`、权限逐级严格扩大的阶梯、拒绝/提示标记),以及所有强制执行方言共享的 `writableRoots` 派生 | `ctx.sandbox` | +| `sandbox-local/` | 按平台链选择的本地后端:Linux 使用 `bwrap`,否则使用 `landlock-run` launcher(通过 npm 分发的 [`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run) 家族,在自身仓库构建发布);darwin 使用 `sandbox-exec`/Seatbelt。多候选链会执行功能探测,唯一候选项直接选择,结论缓存,失败时默认拒绝 | (注册 `ctx.sandbox`) | +| `sandbox-policy/` | 策略解析器:部署回退值,加每个会话的持久模式与不可变 cwd 根目录。两个强制执行家族都消费完整的逐调用结果,因此 bash 与 fs 不会限制到不同根目录 | `ctx.sandboxPolicy` | -该 seam 只限制与宿主共享文件系统和内核的子进程。容器、microVM 和远程执行器都不是这里的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash`、`ctx.fs`);边界记录在[沙箱 Agent Note](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md) 中。 +该 seam 只限制与宿主共享文件系统和内核的子进程。容器、microVM 和远程执行器都不是这里的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash`、`ctx.fs`);边界记录在[沙箱 Agent Note(agent 决策记录)](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)中。 -当前消费方:[`bash/bash-sandbox`](../bash/bash-sandbox/)(包装 `['bash', '-c', command]` 并通过 `ctx.sandbox` 执行)和 [`fs/fs-sandbox`](../fs/fs-sandbox/)(进程内路径隔离,而非 argv 包装层;读取 `ctx.sandboxPolicy`,对写入/编辑强制执行共享模式)。跨家族边界是沙箱 Agent Note 的[跨家族 fs 沙箱](../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)阶段;共享词汇使两个家族可以向模型传授同一种拒绝标记与升权流程。 +当前消费方:[`bash/bash-sandbox`](../bash/bash-sandbox/)(包装 `['bash', '-c', command]` 时会调用 `ctx.sandbox`)和 [`fs/fs-sandbox`](../fs/fs-sandbox/)(进程内路径隔离,而非 argv 包装层;读取 `ctx.sandboxPolicy`,对写入/编辑强制执行共享模式)。跨家族边界是沙箱 Agent Note 的[跨家族 fs 沙箱](../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)阶段;共享词汇使两个家族可以向模型传授同一种拒绝标记与升权流程。 diff --git a/packages/sandbox/sandbox-local/README.zh.md b/packages/sandbox/sandbox-local/README.zh.md index 9c5a79ed8d..5c02b0ce3f 100644 --- a/packages/sandbox/sandbox-local/README.zh.md +++ b/packages/sandbox/sandbox-local/README.zh.md @@ -4,17 +4,17 @@ [`dsh-sandbox`](../sandbox/) seam 的本地实现。它选择并缓存一个平台 runner:Linux 优先选择可工作的 `bwrap`,否则选择 Landlock;macOS 使用 Seatbelt。多个候选项会按顺序探测,只有一个候选项时则直接选择。 -包根导出默认及命名的 `LocalSandboxProvider` 插件、`Config` 和公共测试注入 seam;平台 profile builder 保持内部状态。 +包(package)根目录导出默认及命名的 `LocalSandboxProvider` 插件、`Config` 和公共测试注入 seam;平台 profile builder 仍为内部实现。 -不受支持的平台和不可用 runner 会以 `SANDBOX_UNAVAILABLE` 快速失败;执行绝不会静默回退为不受限制。每次包装都携带 runner 失败签名,使消费方能够区分损坏的沙箱与命令失败。[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)拥有选择原理与 profile 差异。 +不受支持的平台和不可用 runner 会以 `SANDBOX_UNAVAILABLE` 拒绝执行;执行绝不会静默回退为不受限制。每次包装都携带 runner 失败签名,使消费方能够区分损坏的沙箱与命令失败。[沙箱 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)负责说明选择依据与 profile 差异。 -策略逐调用传入;提供方只存储机制与缓存的 runner 结论。每次包装都会报告强制执行完整度,以及后端专用的拒绝和 runner 失败签名。`runnerCommand` 是操作方对 bwrap 形状 runner 的断言,会跳过探测;但命令缺失或不可执行时,执行仍会快速失败。由于其机制未知,它会同时携带两种 Linux 拒绝方言。`probeTimeoutMs` 限制功能探测。[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)拥有选择与失败语义。 +策略逐调用传入;提供方只存储机制与缓存的 runner 结论。每次包装都会报告强制执行完整度,以及后端专用的拒绝和 runner 失败签名。`runnerCommand` 是操作方对 bwrap 形式 runner 的断言,会跳过探测;但命令缺失或不可执行时,执行仍会被拒绝。由于其机制未知,它会同时携带两种 Linux 拒绝方言。`probeTimeoutMs` 限制功能探测。[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)负责说明选择与失败语义。 -Seatbelt profile 默认允许,但带 `(deny file-write*)` 和写入 allow-list,因此恰好治理对应模式承诺的文件 effect:`read-only` 只授予 `/dev/null` 字面路径;`workspace-write` 另加 Workspace 根、`/tmp` 和逐用户 darwin 临时目录(`os.tmpdir()`,即平台供 mkstemp 家族工具使用的真实临时区域)。每个根都经过规范化,因为 Seatbelt 匹配解析后的路径(`/tmp` 就是 `/private/tmp`)。Apple 将 `sandbox-exec` CLI 标为 deprecated,但每个 macOS 仍会提供它;若情况发生变化,功能探测会快速失败。 +Seatbelt profile 默认允许,但带 `(deny file-write*)` 和写入 allow-list,因此恰好约束相应模式承诺的文件操作:`read-only` 只授予 `/dev/null` 字面路径;`workspace-write` 另加工作区根目录、`/tmp` 和逐用户 darwin 临时目录(`os.tmpdir()`,即平台供 mkstemp 家族工具使用的真实临时区域)。每个根目录都经过规范化,因为 Seatbelt 匹配解析后的路径(`/tmp` 就是 `/private/tmp`)。Apple 将 `sandbox-exec` CLI(命令行界面)标为 deprecated,但所有 macOS 系统仍会提供它;若情况发生变化,功能探测会使执行被拒绝。 -[`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run)提供平台 launcher、功能探测和 CLI 参数词汇。该提供方只拥有模式到授权的映射与 runner 选择。把路径解析和探测解析保留在带版本的 binary 中,可防止契约漂移。 +[`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run)提供平台 launcher、功能探测和 CLI 参数词汇。该提供方只负责模式到授权的映射与 runner 选择。把路径解析和探测解析保留在带版本的 binary 中,可防止契约漂移。 -每个阶梯都有会自行跳过的无密钥 world-effect 测试;CI 在真实内核上运行平台 job,并拒绝所有测试静默跳过。打包安装测试通过纯 Node 消费方运行 registry launcher 与可执行模式。 +每个权限层级都有会自行跳过的无密钥 world-effect 测试;CI 在真实内核上运行平台 job,并拒绝所有测试静默跳过。打包安装测试通过纯 Node 消费方运行注册表 launcher 与可执行模式。 ```yaml - id: sandbox @@ -25,16 +25,16 @@ Seatbelt profile 默认允许,但带 `(deny file-write*)` 和写入 allow-list ## 模型体验 -通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md) 间接影响;它们渲染该提供方的强制执行与拒绝事实,而 [`dsh-sandbox`](../sandbox/README.md) seam 拥有 `SANDBOX_UNAVAILABLE` 文本,runner 选择与 profile 则不进入上下文。 +通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md) 间接影响;它们渲染该提供方的强制执行与拒绝事实,而 [`dsh-sandbox`](../sandbox/README.md) seam 负责定义 `SANDBOX_UNAVAILABLE` 文本,runner 选择与 profile 则不进入上下文。 #### KV Cache 影响 -不会直接失效;请求前缀变更由命名消费方负责。 +不会直接使 KV Cache 失效;请求前缀变更由上述消费方负责。 ## 已知限制与暂缓事项 -- **Windows 没有 runner**:`win32` 以 `SANDBOX_UNAVAILABLE` 快速失败;AppContainer 家族后端暂缓实现。 +- **Windows 没有 runner**:`win32` 以 `SANDBOX_UNAVAILABLE` 拒绝执行;AppContainer 家族后端暂缓实现。 - **Landlock 可能只实现部分强制执行**:较旧且受支持的内核 ABI 只能限制自身公开的访问类别,因此报告 `enforcement: 'partial'`,不会夸大为完整强制执行。 -- **Seatbelt 依赖 deprecated 的 `sandbox-exec`**:macOS 仍会提供它,但若 Apple 移除该私有策略引擎,该提供方无法替换或探测。 +- **Seatbelt 依赖已弃用的 `sandbox-exec`**:macOS 仍会提供它,但若 Apple 移除该私有策略引擎,该提供方无法替换或探测。 - **runner 选择在提供方生命周期内缓存**:安装、移除或修复 runner 后,必须重载插件才能改变选择。 -- **`runnerCommand` 是操作方断言**:配置的自定义 runner 会跳过功能探测,并假定它诚实实现 bwrap 形状 profile。 +- **`runnerCommand` 是操作方断言**:配置的自定义 runner 会跳过功能探测,并假定它诚实实现 bwrap 形式的 profile。 diff --git a/packages/sandbox/sandbox-policy/README.zh.md b/packages/sandbox/sandbox-policy/README.zh.md index abf2d9fb88..a201d48c81 100644 --- a/packages/sandbox/sandbox-policy/README.zh.md +++ b/packages/sandbox/sandbox-policy/README.zh.md @@ -2,30 +2,30 @@ [English](README.md) | 中文 -沙箱策略解析的唯一 owner:部署默认 [`SandboxMode`](../sandbox/README.md) 与回退根目录,加上每个会话的持久模式覆盖和不可变 Workspace 根。每个执行强制限制的能力家族在每次调用时收到一项解析完成的模式与根策略。 +沙箱策略解析的唯一归属位置:部署默认 [`SandboxMode`](../sandbox/README.md) 与回退根目录,加上每个会话的持久模式覆盖和不可变工作区根目录。每个强制执行策略的能力家族在每次调用时都会收到一项解析完成的模式与根目录策略。 ## 为何需要共享归属位置 -两个家族强制执行同一套模式词汇:沙箱化 bash 执行器(`@deepseek-ai/dsh-bash-sandbox`)与沙箱化文件系统提供方(`@deepseek-ai/dsh-fs-sandbox`)。如果两者各自解析 `mode` + `workspaceRoot`,就可能漂移成分裂世界:bash 限制在一个根目录,fs 却隔离另一个根目录,正是[沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)所警告的情况。两个工具层都通过 `ctx.sandboxPolicy` 解析策略,两个执行后端也都消费完整的逐调用结果。[跨家族 fs 沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)记录了共享策略决策。 +两个家族强制执行同一套模式词汇:沙箱化 bash 执行器(`@deepseek-ai/dsh-bash-sandbox`)与沙箱化文件系统提供方(`@deepseek-ai/dsh-fs-sandbox`)。如果两者各自解析 `mode` + `workspaceRoot`,就可能漂移成分裂世界:bash 限制在一个根目录,fs 却隔离另一个根目录,正是[沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)所警告的情况。两个工具层都通过 `ctx.sandboxPolicy` 解析策略,两个强制执行后端也都消费完整的逐调用结果。[跨家族 fs 沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)记录了共享策略决策。 ## 配置 - `mode`:部署默认 `SandboxMode`(`read-only`/`workspace-write`/`danger-full-access`),加载时验证。默认为 `read-only`(故障安全)。 -- `workspaceRoot`:agentless 调用或没有 cwd 的会话在 `workspace-write` 下可写入的回退目录。默认为 `process.cwd()`,两种情况下都会解析为其绝对文件系统标识。普通 agent 调用改用其会话头中不可变的 `cwd`。 +- `workspaceRoot`:无 agent(智能体)的调用或没有 cwd 的会话在 `workspace-write` 下可写入的回退目录。默认为 `process.cwd()`;无论显式配置还是采用默认值,都会解析为其绝对文件系统标识。普通 agent 调用改用其会话头中不可变的 `cwd`。 -## 表层 +## 接口 - `ctx.sandboxPolicy.resolve({ session?, mode? })`:解析一项完整的逐调用策略。显式批准的模式优先于会话最后一条 `sandbox/mode` 事件,后者又优先于 `defaultMode`;会话不可变的 `cwd` 会先按文件系统语义规范化,再成为 `workspaceRoot`,否则使用配置的回退值。规范化先于词法归一化,因此 `symlink/..` 与进程工作目录解析保持一致。 -- `ctx.sandboxPolicy.defaultMode`/`ctx.sandboxPolicy.workspaceRoot`:`resolve()` 使用的部署默认值与回退根。 +- `ctx.sandboxPolicy.defaultMode`/`ctx.sandboxPolicy.workspaceRoot`:`resolve()` 使用的部署默认值与回退根目录。 - `effectiveSandboxMode(events)`:会话 `sandbox/mode` 事件的纯 fold(最后一次切换胜出,没有则为 `undefined`),在 `resolve()` 内使用。 - `setSandboxMode(session, mode)`:逐会话覆盖的唯一写入路径:恰好追加一条 `sandbox/mode` 事件。切换本身就是事件;不会在带外修改模式。 - `SANDBOX_MODES`:所有模式,用于选项展示与运行时验证。 -可选的 `./invariant` 配套组件会拒绝伪造的持久 `sandbox/mode` 事件,只要其值不在该封闭词汇中;Session 与其配套组件拥有周围的存储与核心执行封闭规则。 +可选的 `./invariant` 配套组件会拒绝伪造的持久 `sandbox/mode` 事件,只要其值不在该封闭词汇中;Session 与其配套组件负责相关存储与核心执行封闭规则。 -## 逐会话 store +## 逐会话存储 -运行时切换是在对应会话日志中追加的一条 `sandbox/mode` 事件。`effective = explicit grant ?? fold(events) ?? deployment default`,因此覆盖会通过回放跨重启保留,两个会话也绝不会看到彼此状态。Workspace 标识无需另一条事件:创建时记录的不可变 `SessionHeader.cwd` 是该会话每次调用使用的根。该事件只进入日志(沿用 `approval/*` 先例):模型通过强制执行工具的拒绝标记获知模式,绝不会从事件获知。 +运行时切换是在对应会话日志中追加的一条 `sandbox/mode` 事件。`effective = explicit grant ?? fold(events) ?? deployment default`,因此覆盖会通过回放跨重启保留,两个会话也绝不会看到彼此状态。工作区标识无需另一条事件:创建时记录的不可变 `SessionHeader.cwd` 是该会话每次调用使用的根。该事件只进入日志(沿用 `approval/*` 先例):模型通过强制执行工具的拒绝标记获知模式,绝不会从事件获知。 ## 模型体验 @@ -33,9 +33,9 @@ #### KV Cache 影响 -不会直接失效;请求前缀变更由命名消费方负责,且提示词有意不包含模式。 +不会直接使 KV Cache 失效;请求前缀变更由上述消费方负责,且提示词有意不包含模式。 ## 已知限制与暂缓事项 -- **每个会话只有一个主要 Workspace 根**:策略解析 `SessionHeader.cwd`;额外可写根不属于 `SandboxExecutionPolicy`。 -- **只有文件 effect 模式**:`SandboxMode` 治理文件 effect;网络和进程策略不在其词汇中,因此这里没有限制它们的旋钮。 +- **每个会话只有一个主要工作区根目录**:策略解析 `SessionHeader.cwd`;额外可写根目录不属于 `SandboxExecutionPolicy`。 +- **仅限文件操作模式**:`SandboxMode` 管控文件操作;网络和进程策略不在其词汇中,因此这里没有限制它们的旋钮。 diff --git a/packages/sandbox/sandbox/README.zh.md b/packages/sandbox/sandbox/README.zh.md index 402c241353..1dad006622 100644 --- a/packages/sandbox/sandbox/README.zh.md +++ b/packages/sandbox/sandbox/README.zh.md @@ -2,15 +2,15 @@ [English](README.md) | 中文 -抽象进程沙箱 seam。拥有 `ctx.sandbox` 服务契约([`SandboxProvider`](src/index.ts))与 harness 共享的限制词汇:`SandboxMode`(`read-only`/`workspace-write`/`danger-full-access`,仅限文件 effect)、`SandboxEnforcement`(`full`/`partial`,逐内核 ABI)、`SandboxExecutionPolicy`(完整的逐调用模式 + Workspace 根)、`SandboxPolicy`(其中受限制的子集),以及快速失败的 `SANDBOX_UNAVAILABLE` 错误。它是[能力 seam 拆分](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)的接口包:只依赖 cordis(及 harness 错误基类),绝不依赖后端。 +抽象进程沙箱 seam。负责定义 `ctx.sandbox` 服务契约([`SandboxProvider`](src/index.ts))与 harness 共享的限制词汇:`SandboxMode`(`read-only`/`workspace-write`/`danger-full-access`,仅限文件操作)、`SandboxEnforcement`(`full`/`partial`,针对每种内核 ABI)、`SandboxExecutionPolicy`(每次调用的完整模式及工作区根目录)、`SandboxPolicy`(其中受限制的子集),以及故障时拒绝放行的 `SANDBOX_UNAVAILABLE` 错误。它是[能力 seam 拆分](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)的接口包(package):只依赖 cordis(及 harness 错误基类),绝不依赖后端。 -用一句话概括契约:`ctx.sandbox.confine(argv, policy)` 返回应当取代自有 argv 用于 spawn 的 argv。返回值经过包装,使进程及其 spawn 的一切都在限制下运行;另附所选后端的两个事实:它达到的强制执行完整度,以及拒绝方言(`denialSignatures`,即内核在文件 effect 被拒绝时打印到 stderr 的子字符串;通过 stderr 推断的消费方会匹配这些字符串,而不是跨后端联合)。没有可用后端时,它会抛出异常,绝不会原样传递 argv 使其不受限制地运行。 +用一句话概括契约:`ctx.sandbox.confine(argv, policy)` 返回用于 spawn、应当取代调用方原始 argv 的 argv。返回值经过包装,使进程及其派生的所有进程都在限制下运行;另附所选后端的两个事实:它达到的强制执行完整度,以及拒绝方言(`denialSignatures`,即内核在文件操作被拒绝时打印到 stderr 的子字符串;通过 stderr 推断的消费方会匹配这些字符串,而不是统一的跨后端签名集合)。没有可用后端时,它会抛出异常,绝不会原样传递 argv 使其不受限制地运行。 -策略随调用传递,而不属于提供方:两个消费方可以同时按不同策略施加限制(bash 使用 `read-only`,而受限制子 agent 保持其状态目录可写);获批的升权重试只是使用更宽策略发起的新调用。 +策略随调用传递,而不属于提供方:两个消费方可以同时按不同策略施加限制(bash 使用 `read-only`,而受限制的子 agent(智能体)保持其状态目录可写);获批的升权重试只是使用更宽策略发起的新调用。 -**只支持与宿主共享文件系统和内核的限制。** 后端与宿主共享文件系统和内核(`bwrap`、Landlock、Seatbelt);`workspaceRoot` 指向文件系统规范化后的真实主机目录。系统先解析 Workspace 标识,再做词法规范化,因此包含 `symlink/..` 的有效 cwd 会授权 `chdir` 实际到达的目录,而非无关的词法父目录。容器、microVM 与远程执行器都不是该 seam 的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash`、`ctx.fs`)。边界及其原理见[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 +**只支持与宿主共享文件系统和内核的限制。** 后端与宿主共享文件系统和内核(`bwrap`、Landlock、Seatbelt);`workspaceRoot` 指向文件系统规范化后的真实主机目录。系统先解析工作区所指的目录,再做词法规范化,因此包含 `symlink/..` 的有效 cwd 会授权 `chdir` 实际到达的目录,而非无关的词法父目录。容器、microVM 与远程执行器都不是该 seam 的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash`、`ctx.fs`)。边界及其设计理由见[沙箱 Agent Note(agent 决策记录)](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。 -实现:[`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/)(Linux:`bwrap`,否则使用逐平台 Landlock launcher;macOS:`sandbox-exec`/Seatbelt)。消费方:[`@deepseek-ai/dsh-bash-sandbox`](../../bash/bash-sandbox/)(包装 `['bash', '-c', command]`)。 +实现:[`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/)(Linux:`bwrap`,否则使用相应平台的 Landlock launcher;macOS:`sandbox-exec`/Seatbelt)。消费方:[`@deepseek-ai/dsh-bash-sandbox`](../../bash/bash-sandbox/)(包装 `['bash', '-c', command]`)。 ## 模型体验 @@ -18,7 +18,7 @@ #### 模型看到的内容 -通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md),无法强制执行所请求模式时会生成 code `SANDBOX_UNAVAILABLE` 及以下精确错误。执行期 runner 失败会追加 ` Runner failure: `。 +通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md),无法强制执行所请求模式时会产生错误码 `SANDBOX_UNAVAILABLE` 及以下精确错误。执行期 runner 失败会追加 ` Runner failure: `。 ##### 精确错误 @@ -28,15 +28,15 @@ sandbox mode "" is requested but no sandbox backend is usable on this host #### Token 影响 -条件性错误文本对该次调用可见,并保留在历史中直到压缩。 +条件性错误文本对该次调用可见,并保留在历史中直到 compaction(上下文压缩)。 #### KV Cache 影响 -仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 配置项失效。 +仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。 ## 已知限制与暂缓事项 -- **文件 effect 是完整的策略词汇**:该 seam 不表达网络、进程、syscall、设备或 credential 限制。 +- **文件操作是完整的策略词汇**:该 seam 不表达网络、进程、系统调用、设备或凭据限制。 - **只支持与宿主共享文件系统和内核的限制**:容器、microVM 与远程执行需要替换能力实现,而不是在此处增加提供方。 - **拒绝报告是一种 stderr 方言**:该 seam 返回后端签名,而非类型化运行时拒绝通道,因此需要分类的消费方必须从子进程输出推断。 - **每个上下文只有一个提供方**:同时组合不同沙箱机制需要提供方级阶梯或独立 Cordis 上下文;调用方逐调用选择策略,而非后端标识。