docs(i18n): core-docs batch — five bilingual pairs via the committed pipeline

architecture / cordis-primer / defensive-patterns / glossary / testing
五篇核心文档配对,译文由进仓流水线产出(committed renderer + 金标
few-shot + 严格 XML 协议),并经二遍校验(逐句对照原文复述核查 +
注入 architecture/glossary 仓库上下文的一致性修复)。五篇生成文档
(agent-lifecycle、capability-seams、event-producer-consumer、
graph-atlas、tool-execution-pipeline 均为 gen-doc-graphs 产物)列入
排除清单——手写译文会在再生成时失效,与既有生成目录排除策略一致。
This commit is contained in:
Ziya
2026-07-15 23:01:43 -07:00
parent b045b553a9
commit ec47f2e40f
16 changed files with 348 additions and 0 deletions

View File

@@ -0,0 +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
architecture.md: 32b9700b9aece988985ff932e597b537872f12c3
architecture.zh.md: 1adb0111fb67c6e252153e2500732a320de44523

View File

@@ -1,5 +1,7 @@
# DeepSeek Harness Architecture
English | [中文](architecture.zh.md)
The **DeepSeek Harness SDK** builds agent harnesses on Cordis. The principle is simple: **everything is a plugin**. The shipped loop is one plugin, not a privileged kernel.
## Overview

171
docs/architecture.zh.md Normal file
View File

@@ -0,0 +1,171 @@
# DeepSeek Harness 架构
[English](architecture.md) | 中文
**DeepSeek Harness SDK** 基于 Cordis 构建 agent harness智能体框架。原则很简单**一切皆插件**。内置的循环只是一个插件,不是特权内核。
## 概览
一个 harness 就是一个 [Cordis](cordis-primer.md) 上下文。各包package贡献服务键、类型化事件和可 dispose资源释放的注册服务暴露稳定的调用`ctx.llm``ctx.tools``ctx.sessions`),事件提供拦截与通知(`agent/request``tools/pre-execute``session/event`),注册则安装提示词段、工具、提供方、适配器或监听器。
`packages/core/` 组织了默认的 agent 流程;周边能力同样是一等的 Cordis 插件。
### 默认服务
| ctx 键 | 包 | 职责 |
|---|---|---|
| — | [`dsh-scope`](../packages/core/scope/README.md) | 作用域上下文注册原语(库) |
| `ctx.sessions` | `dsh-session` | 内存中事件溯源的会话 |
| `ctx.systemPrompt` | `dsh-system-prompt` | 有序提示词段、工具 schema 与提示词变量 |
| `ctx.tools` | `dsh-tools` | 工具注册表与[执行流水线](tool-execution-pipeline.md) |
| `ctx.agents` | `dsh-agent` | 活跃 agent 注册表、公开 `Agent` 句柄、`agent/*` 事件 |
| `ctx.agentLoop` | `dsh-agent-loop` | 内置 `ReactLoopAgent` 驱动器 |
### 能力服务
| ctx 键 | 包族 | 职责 |
|---|---|---|
| `ctx.llm` | [`llm/`](../packages/llm/README.md) | 适配器注册表与流式模型调用 |
| `ctx.bash` | [`bash/`](../packages/bash/README.md) | 前台/后台命令执行 |
| `ctx.sandbox` | [`sandbox/`](../packages/sandbox/README.md) | 同世界进程隔离argv 包装、逐调用策略) |
| `ctx.codeRuntime` | [`code-runtime/`](../packages/code-runtime/README.md) | 模型编写的程序执行 |
| `ctx.fs` | [`fs/`](../packages/fs/README.md) | 文件系统提供方原语与策略事件 |
| `ctx.skills` | [`skill/`](../packages/skill/README.md) | skill技能提供方注册表与渐进式披露 |
| `ctx.web` | [`web/`](../packages/web/README.md) | 搜索/抓取提供方注册表 |
| `ctx.compact` | [`compact/`](../packages/compact/README.md) | 会话日志压缩compaction |
| `ctx.subagents` | [`subagent/`](../packages/subagent/README.md) | 命名委托提供方 |
| `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | 脚本驱动的多 agent 编排 |
| `ctx.sessionPersistence` | [`session-persistence/`](../packages/session-persistence/README.md) | 会话日志的持久化存储 |
| `ctx.sessionQuery` | [`session-query/`](../packages/session-query/README.md) | 活跃优先的逻辑语料库与精确事件读取 |
## 事件
事件构成服务扩展 API详见完整的[事件目录](cordis-catalog/events.md)与[生产者/消费方映射](event-producer-consumer.md)。
### 事件域
- **会话事件**是持久的、可回放的事实。轮次与步骤边界、用户输入、助手输出、工具调用、工具结果、steering中途引导、压缩记录以及工具拥有的持久事实追加到会话日志并流经 `session/event`
- **Agent 事件**携带活跃的 `Agent` 句柄用于状态、诊断、prompt 准入、调用配置塑形、结果校验与续行策略。
- **能力事件**归属于拥有该动作的 seam。`tools/*``llm/*``system-prompt/*``fs/*``subagent/*` 让策略和适配器无需导入循环即可接入。
### 拦截语义
waterfall瀑布式事件的行为类似 around 中间件:监听器通过调用 `next()` 委托下游;不调用 `next()` 直接返回即为否决或接管。完整规则见 [Cordis waterfall 语义](cordis-primer.md#cordis-waterfall-semantics)。
## 默认循环生命周期
内置循环消耗工作队列、组装请求、流式接收模型回答、执行工具、应用续行策略并持久化检查点。每一个暂停点都是一个服务调用或事件,可供插件介入。
**会话**是一个 agent 的仅追加事件日志。**轮次turn**消耗一批排队消息,运行到模型不再请求工具且没有插件要求续行为止。**步骤step**是一次模型请求加上该响应引发的工具执行。下面的流程中([时序图伴侣文档](agent-lifecycle.md)),带引号的名称是持久化的会话事件,事件名称是扩展点。
### 轮次流程
```text
prepare private session + agent.ctx -> await unpublished setup
-> enter session + agent -> session/created -> agent/created
-> enable driving -> agent/session-start(source) -> start driver
forever:
wait for queued messages
emit agent/status(running)
TURN:
'turn/start'
each queued message -> agent/prompt-submit
allowed prompt -> 'user/message' plus injected context
every prompt blocked -> 'turn/end'(rejected)
STEP loop:
drain steering
assemble system prompt and tool schemas
agent/session-prefix (first step)
agent/pre-step
'step/start'
snapshot the derived messages (the reconstruction boundary)
agent/request (config only) -> log request/header -> llm/stream (frozen)
'assistant/chunk'
agent/step-result
'assistant/message'
each tool call:
'tool/call'
tools/pre-execute -> monotonic guards -> tools/execute -> tools/post-execute -> tools/result
'tool/result'
append post-tool context and steering
'step/end'
agent/turn-continuation
agent/turn-stop (terminal policy)
stop unless tools or continuation policy ask for another step
'turn/end'
checkpoint persistence and notify idle/running status
```
循环每步骤渲染一次 prompt 组装。插件贡献有序段、工具 schema 与 `{{name}}` 变量;未知或无值的引用会使轮次失败,而非带着空洞发送。`dsh-system-prompt` 拥有 harness 身份与默认部署人格agent 作用域的人格可以遮蔽默认值。循环提供 `model``cwd`。见 [prompt 所有权 RFC](rfc/implemented/architecture/2026-07-05-prompt-variables-and-tool-guidance-ownership.md)。
Post-tool 上下文在所有工具结果之后落入,以保持 tool-call/result 的邻接稳定。steering 在步骤之间排空;轮次结束后的普通剩余 steering 作为输入重新入队。终止性的 `agent/turn-stop` 是显式例外:它在普通续行与 steering 折叠之后运行,然后在轮次关闭和刷新期间保持权威,因此这些后续监听器产生的 steering 被丢弃而非成为新的步骤或轮次;普通排队的 prompt 则被保留。
### 失败边界
轮次是容错边界。抛出异常的监听器、适配器错误结束或失败的步骤会以错误原因结束当前轮次,并通过 `agent/error` 报告实时诊断;它不会杀死驱动循环。`cancel()` 清除排队与 steering 工作,在可能时中止活跃的模型/工具边界并记录相应的轮次结束。dispose 停止循环、等待静默、注销 agent并让服务 disposer 排空。
每个会话事件都被轮次包围。重新加载崩溃的会话时,系统保留中断的尾部并以合成的 `interrupted` 轮次结束关闭它。持久化轮次已关闭后的失败仅通过 `agent/error` 报告,因为已没有安全的轮次内位置。轮次以一个 `TurnEndReason` 结束(`completed``aborted``error``disposed``max-tokens``rejected``interrupted`);各变体的语义见 [session.md § TurnEndReasonMap](core-data-structures/session.md#why-a-turn-ended-turnendreasonmap)。
### Agent 句柄
`ctx.agents` 拥有活跃 agent 并返回 `AgentHandle { agent, dispose() }``Agent` 是其他插件驱动的 API`send()` 入队工作,`steer()` 注入轮次中内容,`inject()` 追加上下文并在空闲时开启一次性注入轮次,`cancel()` 是公开的停止原语,`whenIdle()` 观察静默状态。调用方 fiber 与具体工厂提供方在结构上共同拥有编程式生命周期;消费方句柄是唯一的非结构性拆卸能力,且每个所有者到达同一个被 await 的 disposer。
### Agent 作用域
每个活跃 agent 拥有一个作用域化的 `agent.ctx`。其注册遮蔽同名全局注册,只接收该 agent 的派发,并随 agent 一起解除。`CreateAgentOptions.setup(agentCtx)` 在发布前组合作用域。[语义门禁 RFC](rfc/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.md) 定义了类型化解析器,从合并的 `Events` 签名与 `scopeTarget` 派生载体检查,消除了手写事件表。见 [agent 作用域 RFC](rfc/implemented/architecture/2026-07-08-agent-scope-contexts.md)subagent 组合控制另行记录于[](rfc/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)。
## 状态
### 会话日志
会话日志是真源。`deriveMessages()` 将会话事件投影为发送给模型的 `Message[]`;原始 `assistant/chunk` 事件留在日志中用于回放和 UI 保真。回放、fork、恢复、transcript文本记录渲染、遥测和持久化都从同一事件流派生。
**模型可见 ⟺ 已记录**:日志能重建每次请求——`step/start` 处的消息前置 header 的会话前缀header 通过折叠 `request/header` 得出——开发不变式对此做断言([可重建性 RFC](rfc/implemented/architecture/2026-07-05-reconstructable-requests.md))。
持久性是插件关注点。持久化后端缓冲同步的 `session/event` 通知,循环在轮次结束检查点完成后才继续。`SessionPersistence` seam 直接存储 `SessionEvent`,元数据在 `SessionHeader`JSONL 与 SQLite 共享同一套契约测试。
### 模型内容
消息是类型化内容块(`text``reasoning``tool-call``tool-result`)的数组。联合类型派生自可合并扩展的 `ContentBlockMap`;同一模式也用于 `MessageSource``FinishReason``TurnTrigger``TurnEndReason`。新的块类型需要跨适配器、UI 桥接、压缩计价与持久化协调,因此块类型仍是仓库级契约。
流式输出是原始分片协议(从 `block-start``finish``BlockAssembler` 是共享的 chunk 到 block 组装器。循环在组装分片以供派发的同时记录原始 chunk。`LlmAdapter` 是提供方 seam继承它、实现 `stream()`、用 `ctx.llm.registerAdapter(models, adapter)` 注册。StreamChunk 约定见 [llm-streaming.md](core-data-structures/llm-streaming.md)。
## 扩展与组合
### 能力模式
一个可替换的能力通常拆分为**接口 / 实现 / 消费方**:接口拥有其 `ctx` 键与事件,实现注册后端,消费方通过工具或 prompt 暴露模型行为。Bash 是参考实现;[能力图](capability-seams.md)展示了每个族。
部分 seam 有意偏离模板。LLM大语言模型将接口与消费方词汇放在一起因为适配器就是实现。文件系统在提供方原语周围添加策略门禁。Web 是一个服务加搜索/抓取两个提供方注册表因此提供方替换不会重命名模型工具。skill 与 subagent 使用命名提供方注册表;本地 skill 扫描项目/用户根目录,其他提供方可以在不改动注册表/工具的情况下添加嵌入式或远程目录。subagent 可以全新 spawn、从父级已完成轮次的前缀 fork或使用 ACP 子进程([subagent.md](core-data-structures/subagent.md))。
### Bundle 与应用
`dsh-agent-spine-demo` 是默认的组合 bundle一个插件加载共享主干[README](../packages/examples/agent-spine-demo/README.md))。应用包将其与前端入口和启动 `bin` 组合:`dsh-stdio-demo` 用于终端 REPL`dsh-acp-demo` 用于基于 JSON-RPC stdio 的 ACP无 stdout logger[ui/](../packages/ui/README.md))。`dsh-jsonrpc-agent` 则启动外部 `cordis.yml`Python SDK 在未设置显式配置通道时注入包默认值,并通过行分隔的 stdio JSON-RPC 驱动 `dsh-jsonrpc`[Python SDK](../python/README.md))。一个部署就是一片薄薄的 `cordis.yml` 叶子:可替换的后端、一个应用入口和可选的产品工具([examples/](../examples/AGENTS.md)、[可运行接线](cookbook/extension-cookbook.md#runnable-wirings)、[关系图索引](graph-atlas.md))。
### 新行为的归属
新行为应接入已记录的扩展点;修改内置循环需要同步更新本映射。
| 目标 | 机制 |
|---|---|
| 添加模型提供方 | 在 `ctx.llm` 上注册适配器 |
| 添加面向模型的能力 | 在 `ctx.tools` 上注册工具schema 流入 prompt 组装 |
| 添加命令执行 | 实现并注册 `ctx.bash` 后端 |
| 添加文件系统访问或策略 | 实现 `ctx.fs` 提供方或监听 `fs/*` 策略事件 |
| 隔离 spawn 的进程 | 一个 `ctx.sandbox` 后端;消费方在 spawn 前包装 argv |
| 拦截 prompt、请求、工具使用或续行 | 监听相关的 `agent/*``tools/*` waterfall使用串行 `agent/turn-stop` 实现单调终止 |
| 添加历史之外的会话稳定请求前缀 | 在 `agent/session-prefix` 上组合,每个循环实例一次;记录在请求 header 上 |
| 添加 UI 或编辑器集成 | 驱动 `ctx.agents` 并从 `session/event` 渲染 |
| 添加持久化会话状态 | 添加 `SessionEventMap` 成员并从日志渲染/回放 |
| fork 活跃会话 | 使用 `ctx.sessions.fork(source, boundary?, childSessionId?)` |
| 将工具、prompt 段或监听器限定到单个 agent | 通过该 agent 的 `agent.ctx` 注册(见 Agent 作用域) |
[扩展实操手册cookbook](cookbook/extension-cookbook.md)提供插件骨架与功能到 seam 的映射;分步指南覆盖[](cookbook/adding-a-package.md)、[工具](cookbook/adding-a-tool.md)、[LLM 适配器](cookbook/adding-an-llm-adapter.md)与[vendor 包](cookbook/adding-a-vendored-package.md)。
## 快速参考
- 领域术语见[术语表](glossary.md)
- 类型定义见 [core-data-structures/](core-data-structures/core.md)
- 精确的事件与服务签名见[事件目录](cordis-catalog/events.md)
- [服务目录](cordis-catalog/services.md)
- 包契约见[包映射](../packages/README.md)
- [RFC](rfc/README.md)

View File

@@ -0,0 +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
cordis-primer.md: 39d3d97b9ac43fec50cb0c832af449fc8bc6232f
cordis-primer.zh.md: 4915f665cae51b44f89190d43d147e5cda0df146

View File

@@ -1,5 +1,7 @@
# Cordis Primer
English | [中文](cordis-primer.zh.md)
Cordis is the vendored plugin framework underneath the DeepSeek Harness SDK. This primer teaches the Cordis ideas a harness plugin author needs before reading the generated [events](cordis-catalog/events.md) and [services](cordis-catalog/services.md) catalogs. The vendored source and sync procedure live in [vendor/README.md](../vendor/README.md).
## Cordis In Five Ideas

44
docs/cordis-primer.zh.md Normal file
View File

@@ -0,0 +1,44 @@
# Cordis 入门
[English](cordis-primer.md) | 中文
Cordis 是 DeepSeek Harness SDK 底层以 vendor 方式引入的插件框架。本入门文档讲解 harness 插件作者在阅读生成的[事件](cordis-catalog/events.md)与[服务](cordis-catalog/services.md)目录之前需要了解的 Cordis 核心概念。vendor 源码与同步流程见 [vendor/README.md](../vendor/README.md)。
## Cordis 五大理念
- **插件是实现了 Service 的对象。** 它可以是一个带有可选 `inject``apply(ctx)` 字段的函数,也可以是一个 `Service` 子类,其生命周期由 Cordis 挂载到当前上下文中。
- **上下文是服务的注册表。** 一个服务在上下文中声明一个稳定的 `ctx.<key>`(如 `ctx.tools``ctx.llm``ctx.sessions`);其他插件通过 key 查找服务,而非导入具体实现。
- **通过 `inject` 声明服务依赖。** 插件声明所需的服务后,会等待这些服务就绪;加载顺序通过服务依赖表达,而非手动编排启动序列。
- **类型化事件用于通信。** 服务通过 TypeScript 声明合并定义事件名,然后以 `emit``waterfall`(瀑布式事件)、`parallel``serial` 方式分发,分别对应监听者观察、包装、并行扇出或按序执行。
- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()``ctx.on()` 安装,因此重载和拆卸能可预测地回退它们。
## 分发模式
每个事件具有以下分发模式之一,且只能通过对应的方法分发。
| 模式 | 是否 await | 分发顺序 | 是否有返回值? |
|---|---|---|---|
| `emit` | 否 | 监听器按注册顺序观察 | 否 |
| `waterfall` | 否 | 监听器按注册顺序观察 | 是 |
| `parallel` | 是 | 所有监听器并行观察事件 | 否 |
| `serial` | 是 | 监听器按注册顺序观察 | 是 |
分发模式是事件公开契约的一部分。新的 harness 事件通过 `@mode` 标签记录它,以便生成的目录能将声明与分发站点进行交叉校验。
## Cordis Waterfall 语义
`ctx.waterfall` 是环绕中间件。监听器接收 `(...args, next)`。调用 `next()` 将可能经过包装的结果委托给下一个服务;不调用 `next()` 直接返回则短路。值通过 `next()` 的返回值向下传播。
协作式监听器通常修改一个共享的请求或决策对象,然后委托。监听器也可以选择完全替换结果,下游监听器只会看到替换后的结果。仅当监听器必须在普通注册之前运行时才使用 `prepend: true`
对于单决策事件,短路是设计意图。策略监听器在拥有决策权时可以不调用 `next()` 直接返回,而仅做标注或观察的监听器必须委托。
## Loader 配置
`@cordisjs/plugin-include``!!js` 解析为表达式节点,但 Loader 仅在挂载插件前对条目的 `config` 进行插值。条目元数据(`id``name``group``disabled``inject``intercept``isolate`)保持字面值;因此 `disabled: !!js ...` 是一个真值对象,总是会禁用该条目。当需要根据环境选择挂载哪些插件时,请使用显式的配置覆盖。
## 实践规则
将行为封装到插件中:工具流水线事件属于 `ctx.tools`,模型流式输出属于 `ctx.llm`,实时 agent 协调属于 `ctx.agents`。拦截和策略优先使用事件;直接能力调用优先使用服务方法。
每个注册都应有对应的 dispose资源释放要么从 `ctx.effect()` 返回一个,要么使用 Cordis 提供的辅助函数自动处理。如果拆卸顺序有要求,请将相关工作放在同一个 effect 中,以确保 dispose 按预期顺序回退。

View File

@@ -0,0 +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
defensive-patterns.md: fda0be0d2d3b7fa099162123b3d219673eebd07d
defensive-patterns.zh.md: 60d7389db50c30e2b85fd88b320f04b43e22d84d

View File

@@ -1,5 +1,7 @@
# Defensive patterns
English | [中文](defensive-patterns.zh.md)
Hard-won bug-class rules: each pattern below is a class of defect that actually shipped or nearly shipped here, stated as the rule that prevents its recurrence. Read this before writing lifecycle, concurrency, subprocess, or teardown code. Test-tier counterparts (real entry path, world-verification, resource ownership) are in [testing.md](testing.md).
## Report orthogonal outcomes independently

View File

@@ -0,0 +1,29 @@
# 防御性模式
[English](defensive-patterns.md) | 中文
来之不易的缺陷类别规则以下每条模式都是本项目中实际发布或险些发布的一类缺陷以防止其复发的规则形式陈述。在编写生命周期、并发、子进程或清理代码之前请先阅读本文。测试层面的对应规则真实入口路径、world 验证、资源归属)见 [testing.md](testing.md)。
## 正交结果独立上报
一个结果可以同时具有多重性质:进程可能既超时又以 exit 0 退出,因为它捕获了信号。每个独立事实(`timedOut``signal``exitCode`)都应独立暴露;永远不要把一个 flag 的上报嵌套在另一个 flag 的分支内,否则调用方会把一次被截断的运行误读为正常成功。
## 在接口两侧都遵守跨 seam 契约
当接口文档记录了两种有效的信号方式时——例如适配器可以通过从 `stream()` 抛出异常来报告失败,也可以通过以 `finish {kind:'error'|'aborted'}` 分片结束流来报告——消费方必须两种都处理,而不只是第一个实现碰巧使用的那种。基于库的适配器在流中途无法抛出异常,只能依赖带内路径;如果 agent loop 只捕获 throw就会把提供方的 401 变成一个正常完成的轮次。请在类型定义处记录契约;通过真实消费方测试每个分支。
## 异步状态不是同步状态
`agent.send()` 不会在返回前翻转状态;后台任务的完成与轮次边界存在竞态;`reader.close()` 在 EOF 和 dispose资源释放两种情况下都会触发。永远不要基于一个你刚刚请求的状态来控制流程——应当基于实际触发的事件/promise 来驱动生命周期(`agent/status``task.done`),并观察状态转换(先看到 `running` 再看到 `idle`),而不是假设你发出的动作与轮次 1:1 对应循环会批量处理排队的消息。这条守则是双向的如果等待的转换永远不会发生EOF 且没有提交过工作 → 永远不会进入 `running`),等待就会挂起——请显式处理「无需等待」的分支。
## dispose 必须达到静止,而非仅仅请求停止
一个只发出 kill/abort 就返回的清理逻辑会留下孤儿进程。请让清理逻辑异步化并 await 子进程退出kill → await `done`),并在 kill 之前关闭监听器/通知注册表,使迟到的完成事件保持静默。测试应证明 dispose 确实等到了进程退出(`await fiber.dispose()` 之后 pid 已不存在),而非仅仅证明进程最终会死。
## 在边界处包容回调异常
用户提供的监听器抛出异常时,不得导致它所在的 promise 被 reject也不得饿死排在它之后的监听器。请在分发循环中用 try/catch 包裹并记录日志;一个有问题的订阅者永远不能破坏核心生命周期。
## 永远不要把环境变量或可预测路径暴露给不可信输出
spawn 的命令应获得一个经过清洗的 env移除 `*KEY*`/`*SECRET*`/`*TOKEN*`),确保 harness 凭证不会泄漏到输出、`env` 或溢出文件中。临时/溢出文件应使用私有0700目录、随机文件名和排他的仅所有者可打开模式`'wx'``0o600`)——可预测的全局可读路径会招致符号链接竞态和信息泄露。

6
docs/glossary.i18n.yaml Normal file
View File

@@ -0,0 +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
glossary.md: 23eebc5793e8232482a796f5bde1e794f0556208
glossary.zh.md: 7163015eeed71c96743b9cae491db206585a70b2

View File

@@ -1,5 +1,7 @@
# Glossary
English | [中文](glossary.zh.md)
Domain vocabulary for the DeepSeek Harness SDK uses one canonical term per concept. Terms link to their entries with standard Markdown anchors; implementation detail stays in package READMEs and RFCs.
FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope.

19
docs/glossary.zh.md Normal file
View File

@@ -0,0 +1,19 @@
# 术语表
[English](glossary.md) | 中文
DeepSeek Harness SDK 的领域词汇对每个概念使用唯一的规范术语。各术语通过标准 Markdown 锚点互相链接;实现细节留在各 package README 和 RFC 中。
FIXME(glossary-completeness): Expand this glossary before the first release so it covers the SDK's other core and capability subsystems, not only agent scope.
## agent 作用域
- **scope作用域**:按 agent智能体注册的单位。一项贡献工具、prompt 段落、变量、限制、监听器)要么是*全局*的(对所有 agent 可见),要么是*有作用域*的(归属于恰好一个 [scope key](#scope-key))。只有两层,扁平结构:有作用域的注册不会向下继承给 subagent子树行为通过[血统](#lineage)数据表达,从不通过作用域结构。
- **scope key作用域键**作用域的不透明标识按对象同一性比较。harness 约定:一个活跃的 agent 就是其自身作用域的 key。<a id="scope-key"></a>
- **agent context`agent.ctx`**agent 的有作用域上下文;通过它进行的注册既是作用域可见的,也是作用域生命周期的(一个事实同时驱动两者),其上的监听器参与该 agent 的作用域过滤分发。注册表主体事件可以在其自身的事件契约下有意保持不过滤。
- **scope carrier作用域载体**:作用域过滤分发所携带的 `thisArg`(由 `scopeTarget` 构建);其过滤器放行无标签监听器加上主体自身的监听器。*无主体*的载体(没有 key只放行无标签监听器。
- **scoped dispatch作用域分发**:规则是:关于某个 agent 活动的事件以该 agent 的载体进行分发。关于注册表本身的事件(如「一个工具被添加」)属于*注册表主体*事件,保持不过滤。
- **shadowing遮蔽**:最具体者胜出的名称解析:一个有作用域的工具/段落/变量仅在该作用域内替代其同名的全局副本。这是按 agent 定制人设和按 agent 定制工具变体的机制。
- **restriction / scope-local registration限制 / 作用域局部注册)**:限制(`tools.restrict`)为单个作用域过滤全局工具面(按交集组合);作用域局部注册在过滤之后合并。被过滤掉的全局工具既不出现在 prompt 中,也拒绝执行,与不存在的工具无法区分。
- **setup window设置窗口**:创建者组装 agent 有作用域世界的创建时隙(`CreateAgentOptions.setup`):在作用域和 agent 对象已存在、但 agent 或会话尚未发布、`agent/session-start` 尚未触发、首次 prompt 尚未组装之前。设置窗口只做注册,从不驱动 agent。
- **lineage血统**:以数据形式携带的父子关系(`parentSession``subagentDepth`);从不影响可见性。<a id="lineage"></a>

6
docs/testing.i18n.yaml Normal file
View File

@@ -0,0 +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
testing.md: ddb9da0b38e5dc9cc75ede81ec157c4744fd11c2
testing.zh.md: 6d21a37b175c8052fbc34db0fc5a9b522c27f7ec

View File

@@ -1,5 +1,7 @@
# Testing policy
English | [中文](testing.zh.md)
How this repo tests, tier by tier, and the rules that keep a green suite meaningful. Commands live in root [AGENTS.md](../AGENTS.md); linked RFCs carry the rationale.
## Tiers

35
docs/testing.zh.md Normal file
View File

@@ -0,0 +1,35 @@
# 测试策略
[English](testing.md) | 中文
本文说明本仓库如何逐层测试,以及保持绿色测试套件有意义的规则。命令见根目录 [AGENTS.md](../AGENTS.md);关联 RFC 承载设计动机。
## 层级
- **单元测试**`pnpm run test`vitest 运行 `packages|examples/*/tests/**/*.spec.ts`,与被测代码同目录。每个注册表都有一个 HMR热模块替换安全测试dispose 贡献该注册的 fiber断言清理完成。优先覆盖边界情况、错误路径、事件顺序、并发竞态与永久契约回归`packages/core/agent-loop/tests/contract-regressions.spec.ts`)。
- **覆盖率门禁**`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,绝非充分条件:它证明代码行被执行过,不证明功能按交付预期工作。
- **真实 API e2e**`pnpm run test:e2e`):带密钥测试,对接真实提供方 API——DeepSeek 模型加各提供方独立冒烟测试(各自依赖自己的密钥:`EXA_API_KEY``PERPLEXITY_API_KEY` 等);每个套件在缺少对应密钥时自动跳过,确保无密钥 CI 保持绿色([真实 API e2e RFC](rfc/implemented/testing/2026-06-19-real-api-e2e-ci.md))。
- **快照测试**`pnpm run test:snapshot`):启动真实示例子进程,无密钥回放录制的会话,将归一化后的 stdout 与重新持久化的日志同已提交的 golden 文件做 diff[快照 RFC](rfc/implemented/testing/2026-06-19-acp-snapshot-tests.md))。当模型 transcript文本记录需要变更时使用 `pnpm run test:snapshot:record`;当已提交的 transcript 仍是正确的 mock LLM大语言模型输入、只需无密钥重写回放 golden 时使用 `pnpm run test:snapshot:refresh`。请评审 golden diff。系统提示词/工具 schema 内容由一个场景(`text-turn`)固定,其余 fixture测试前置数据中以 token 化形式引用,因此 prompt 或 schema 的修改只变动一行已提交内容([pinned-header RFC](rfc/implemented/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。
## 带密钥策略:推理在这里很便宜
我们是 DeepSeek不要吝惜真实 API 测试。无密钥测试证明管道通了;只有带密钥运行才能证明 agent 对接真实模型时能正常工作。多写:文件写入 prompt、多轮对话、工具调用、流中取消。价值最高的是**冒烟测试**:启动真实示例、发送一条真实 prompt、检查外部世界的状态。它们能捕获「单元测试全绿、产品却坏了」这类 mock 在结构上无法发现的问题([事后分析 0001](postmortem/0001-acp-default-export-drops-inject.md))。自动跳过机制的存在仅仅是为了不阻塞无密钥 CI 和无密钥贡献者,它不是成本信号。每个示例都附带一个无密钥冒烟测试,以及(除非本身就不需要密钥)一个带密钥冒烟测试([examples/AGENTS.md](../examples/AGENTS.md))。
## 优先使用真实实现而非 mock
只 mock 真正昂贵或不确定的边界LLM 适配器、网络、时钟下游一切保持真实。手写的替身只能证明桥接层在搬运字节不能证明交付的工具行为符合断言——两者会漂移而测试仍然绿着。示例bridge 工具调用测试运行脚本化的 mock 模型,但使用真实的 tool + 真实的执行器(`makeBridgeHarness({ withBash: true })` 接入 `dsh-bash-local` + `dsh-tool-bash`,执行真正的 `echo`)。
## 验证外部世界,而非自我报告
e2e 断言应重新运行命令或从外部重新读取文件;仅对 agent 自身输出做关键词探测会让作弊的 agent 通过。断言未改动的文件字节相同。e2e 测试拥有自己的资源:在测试中创建 harness`afterEach` 中 dispose即使失败/重试/超时);共享 fixture 放在普通的 `tests/harness.ts` 中,绝不放在另一个 `*.e2e.ts`import 一个 spec 会重新注册其 `describe`,导致真实 API 调用重复)。
## 测试真实入口路径
- 产品可见的插件需要一个非单元的真实组合测试。手工搭建的 `ctx.plugin(...)` 套件不够:通过 Loader 和 app/process 启动仅用于测试的 `cordis.yml`,只 mock 外部/不确定边界,断言模型可见的请求/日志、持久状态或用户可见输出。不要把 opt-in 混入默认交付。
- 一个守卫只有在回归真正让它失败时才算守卫。对于没有 `inject` 的插件bundle/组合插件Loader 冒烟测试在导出形状损坏时仍然绿——需要加一个显式的 `expect('default' in mod).toBe(false)``unwrapExports` 往返断言,并证明它有效:引入回归、观察变红、还原。
- 「真实入口路径」指已发布的产物package 的 `bin` 指向构建出的 `lib/bin.js`,在原生 `node` 下运行tsx 会掩盖竞态、模块解析问题以及静默以 0 退出的加载失败。同理适用于构建后 package 在运行时解析的任何非 index 运行时入口worker-thread 运行时的兄弟文件 `lib/worker.cjs`)。保持构建产物冒烟测试绿色(`packages/ui/*/tests/built-bin.e2e.ts``packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts`),并断言真正缺失的配置以非零退出。
- 从临时 cwd spawn 示例的 e2e 测试需要设置 `TSX_TSCONFIG_PATH` 指向仓库根 tsconfig否则会静默回退到陈旧的构建 `lib/`[examples/AGENTS.md](../examples/AGENTS.md))。
## 何时需要快照测试
任何影响编辑器侧 transcript 或端到端 agent 用户体验的变更——ACP bridge、agent loop智能体循环的可观测输出、工具呈现——都应在所属示例的快照套件中添加或更新场景`examples/<name>/tests/snapshots/`,基于 [`dsh-acp-snapshot`](../packages/support/acp-snapshot/README.md) 套件工厂的场景表;`examples/acp-agent` 是主套件),或在 PR 中说明为何不适用。新的能力 seam、生命周期形态或 transcript 表面在计划阶段就要标明各层的覆盖方式,并验证 harness 能表达它——harness 的缺口是排期工作,不是构建中途的意外。

View File

@@ -2,31 +2,41 @@
"requiredSince": "2026-07-14",
"required": [
"README.md",
"docs/architecture.md",
"docs/cookbook/adding-a-package.md",
"docs/cookbook/adding-a-tool.md",
"docs/cookbook/adding-a-vendored-package.md",
"docs/cookbook/adding-an-llm-adapter.md",
"docs/cookbook/extension-cookbook.md",
"docs/cookbook/responding-to-pr-review-on-a-stack.md",
"docs/cordis-primer.md",
"docs/defensive-patterns.md",
"docs/development.md",
"docs/glossary.md",
"docs/i18n/README.md",
"docs/i18n/translation-rules.md",
"docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md",
"docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md",
"docs/testing.md",
"python/README.md",
"python/sdk-runtime/README.md",
"python/sdk/README.md"
],
"excluded": [
"docs/AGENTS.md",
"docs/agent-lifecycle.md",
"docs/capability-seams.md",
"docs/config-catalog.md",
"docs/cordis-catalog/",
"docs/event-producer-consumer.md",
"docs/graph-atlas.md",
"docs/i18n/style-samples.md",
"docs/i18n/terminology.md",
"docs/i18n/translation-prompt.md",
"docs/module-graph.md",
"docs/persistence-catalog.md",
"docs/tool-catalog.md",
"docs/tool-execution-pipeline.md",
"python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/"
]
}