Merge commit 'ecbf75a5e70f662b6420375140cf12eb6bac7860' into worktree/retarget-pr831-20260729

# Conflicts:
#	packages/context/workspace-context/README.i18n.yaml
#	packages/context/workspace-context/README.zh.md
This commit is contained in:
Tianyi Cui
2026-07-29 21:25:44 +08:00
780 changed files with 17727 additions and 4467 deletions

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
# pnpm run verify-translation-pairing --write packages/support/README.md
README.md: b9550fd54feb36448227faae8485fe8b6dbf4fb0
README.zh.md: dc017c5f6544e29533f14600deb5b9261e351536
README.zh.md: 8eec9b96f621724e1ddc9a70abed069f11cb7fdc

View File

@@ -2,15 +2,15 @@
[English](README.md) | 中文
这些包用于开发、测试和示例,而非作为产品 API 发布。它们是实工作区包(类型、经过测试受覆盖率门禁约束),但具有**较低的兼容性预期**:当其背后的开发需求变化时,它们可以改变或被移除,无需像产品包那样谨慎执行弃用流程。
这些包package用于开发、测试和示例,而非作为产品 API 发布。它们是实际的工作区包(具备类型、经过测试,并受覆盖率门禁约束),但具有**较低的兼容性预期**:当其背后的开发需求变化时,它们可以改变或被移除,无需像产品包那样谨慎执行弃用流程。
| 包 | 职责 | ctx 键 |
|---|---|---|
| `acp-snapshot/` | ACP 测试工具包:共享子进程/客户端启动器、快照 harness、规范化器和套件工厂 | (库:由 ACP e2e 和 `*.snapshot.ts` 套件导入) |
| `agent-loop-testkit/` | 为测试具体 agent loop 的测试挂载共享先决条件 | (库:由 AgentLoop 集成测试导入) |
| `acp-snapshot/` | ACPAgent Client Protocol测试工具包:共享子进程/客户端启动器、快照 harness、规范化器和套件工厂 | (库:由 ACP e2e 和 `*.snapshot.ts` 套件导入) |
| `agent-loop-testkit/` | 为验证具体 agent loop(智能体循环)的测试挂载共享先决条件 | (库:由 AgentLoop 集成测试导入) |
| `invariants/` | 用于开发诊断的运行时事件契约断言 | (监听 `session/*``agent/*` |
| `loader-smoke/` | 共享的真实 Loader 子进程 harness用于无密钥示例冒烟测试 | (库:由示例 e2e 套件导入) |
| `llm-mock-server/` | 可编脚本的 OpenAI 兼容 HTTP/SSE 故障服务器与 CLI用于 LLM 恢复测试 | (独立服务器和测试库) |
| `llm-replay/` | 录制/回放适配器:已记录的会话 JSONL 短路 `llm/stream`(无密钥快照测试) | (监听 `llm/stream` |
| `llm-mock-server/` | 可编的 OpenAI 兼容 HTTP/SSEServer-Sent Events故障服务器与 CLI命令行界面用于 LLM大语言模型恢复测试 | (独立服务器和测试库) |
| `llm-replay/` | 录制/回放适配器:通过已记录的会话 JSONL `llm/stream` 进行短路处理(无密钥快照测试) | (监听 `llm/stream` |
`invariants` 是开发支持,但没有环境保护:无论在何处注册,它都会运行;默认 `dsh-agent-spine-demo` bundle 无条件挂载它。`agent-loop-testkit` 为手工构建的 AgentLoop 测试集中管理必需服务主干,而不负责其 loop 或场景。`llm-replay` 支撑演示和受文件覆盖率门禁约束的快照测试层,`llm-mock-server` 则通过确定性 HTTP/SSE 故障驱动真实提供方适配器。`acp-snapshot` 包含 ACP 子进程/客户端边界以及快照 harness、规范化器和套件机制`loader-smoke` 负责无密钥示例 e2e 套件使用的并列真实 Loader 启动边界。只有当某个包获得已记录的产品消费方时,它才会从 `support/` 升级到产品分组。
`invariants` 是开发支持,但没有环境条件限制:无论在何处注册,它都会运行;默认 `dsh-agent-spine-demo` bundle 无条件挂载它。`agent-loop-testkit` 为手工构建的 AgentLoop 测试集中管理必需服务主干,而不负责其 agent loop 或场景。`llm-replay` 支撑演示和受文件覆盖率门禁约束的快照测试层,`llm-mock-server` 则通过确定性 HTTP/SSE 故障驱动真实提供方适配器。`acp-snapshot` 包含 ACP 子进程/客户端边界以及快照 harness、规范化器和套件机制`loader-smoke` 负责无密钥示例 e2e 套件使用的并列真实 Loader 启动边界。只有当某个包获得文档记载的产品消费方时,它才会从 `support/` 转入产品分组。

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
# pnpm run verify-translation-pairing --write packages/support/agent-loop-testkit/README.md
README.md: 18c46069d3cfd402c83b5ecab68458667738163b
README.zh.md: 93af58a279558007c252ef0734cc95b2ad79a5a5
README.zh.md: 2151591154899094fe33f9c25c9b9144e6d02a22

View File

@@ -2,9 +2,9 @@
[English](README.md) | 中文
测试具体 `AgentLoop` 的测试挂载共享先决条件`mountAgentLoopTestDependencies(ctx, options?)` 按依赖顺序安装 LLM、会话、系统提示词、工具和 agent 服务,然后在 loop 挂载前返回。
运行具体 `AgentLoop` 的测试共享挂载先决依赖`mountAgentLoopTestDependencies(ctx, options?)` 按依赖顺序安装 LLM(大语言模型)、会话、系统提示词、工具和 agent(智能体)服务,然后在 agent loop 挂载前返回。
调用方注册适配器和可选插件,使用待测配置挂载 `AgentLoop`,并 dispose 自己的 Context。系统提示词和工具注册表配置可通过 `options` 转发;辅助工具不提供超出服务自有默认值的测试默认值。插件加载失败会拒绝辅助工具调用,而顺序中较早激活的服务仍归调用方的 Context 所有。
调用方注册适配器和可选插件,使用待测配置挂载 `AgentLoop`,并 dispose(资源释放)自己的 Context。系统提示词和工具注册表配置可通过 `options` 转发;辅助函数不提供超出服务自有默认值的测试默认值。插件加载失败会使辅助函数调用被拒绝,而顺序中较早激活的服务仍归调用方的 Context 所有。
```ts
import { Context } from 'cordis'
@@ -18,16 +18,16 @@ await mountAgentLoopTestDependencies(ctx)
await ctx.plugin(AgentLoop, { agents: [] })
```
针对注入失败、部分拓扑、服务加载顺序或服务拆卸的测试会直接挂载其依赖,而不使用此辅助工具
针对注入失败、部分拓扑、服务加载顺序或服务清理的测试会直接挂载其依赖,而不使用此辅助函数
## 模型体验
无。该测试专用组合辅助工具既不驱动也不修改模型请求。
#### KV 缓存影响
#### KV Cache 影响
无;该包既不组装也不发送提供方请求。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **只共享必需的先决主干**:适配器、可选插件、`AgentLoop`、agent 和 Context 拆卸仍由调用方负责,以使场景专用顺序保持可见。
- **只共享必需的先决主干**:适配器、可选插件、`AgentLoop`、agent 和 Context 清理仍由调用方负责,以使特定场景的挂载顺序清晰可见。

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
# pnpm run verify-translation-pairing --write packages/support/invariants/README.md
README.md: 203dbd5ad09f5b1378061fbf9adcff885889eae2
README.zh.md: e101a30046c6b1ac18870c268ea6a2c960cb5d90
README.zh.md: 841e7a32f8e2605c25aadef35862a0223046933f

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
用于包自有运行时不变量检查的可配置注册表服务。根插件注册 `ctx.invariants`;它不包含产品检查或产品包导入。每个工作区包都发布一个 `./invariant` 配套入口,用于注册其精确 NPM 包名。
用于包package自有运行时不变量检查的可配置注册表服务。根插件注册 `ctx.invariants`;它不包含产品检查或产品包导入。每个工作区包都发布一个 `./invariant` 配套入口,用于注册其精确 NPM 包名。
## 服务:`InvariantService``ctx.invariants`
@@ -16,19 +16,19 @@ interface Config {
默认值为 `enabled: true``package_allowlist: []``package_blocklist: []`。只有在服务启用、allowlist 为空或至少一个 allowlist pattern 匹配完整 NPM 名称,且没有 blocklist pattern 匹配时包才被选中。因此blocklist 匹配优先于 allowlist 匹配。
每个条目都是区分大小写的 JavaScript 正则表达式源,使用 `new RegExp(pattern)` 编译。除非源提供 `^``$`,否则匹配不锚定;不解析 `/pattern/flags` 语法。同一列表中的空白、带前后空白、无效或重复条目会使服务启动失败。有效 pattern 可以不匹配任何当前已加载包,以使后续加载和 HMR 保持确定性。
每个条目都是区分大小写的 JavaScript 正则表达式源,使用 `new RegExp(pattern)` 编译。除非源提供 `^``$`,否则匹配不锚定;不解析 `/pattern/flags` 语法。同一列表中的空白、带前后空白、无效或重复条目会使服务启动失败。有效 pattern 可以不匹配任何当前已加载包,以使后续加载和 HMR(热模块替换)保持确定性。
`ctx.invariants.register(packageName, installer)` 为完整 NPM 包名保留一个活动注册,即使过滤器使其 installer 保持非活动,并返回 disposer。已启用贡献在专用子 Cordis fiber 中运行。Installer 可以通过 `installer.inject` 声明所需服务接口,并收到 `fail(message)`;后者抛出绑定到注册包的 `InvariantError`。在注册成功前,系统会等待同步或异步 installer 完成;失败会 dispose 子级,并原子释放归属。
`ctx.invariants.register(packageName, installer)` 为完整 NPM 包名保留一个活动注册,即使过滤器使其 installer 保持非活动,并返回 disposer。已启用贡献在专用子 Cordis fiber 中运行。installer 可以通过 `installer.inject` 声明所需服务接口,并收到 `fail(message)`;后者抛出绑定到注册包的 `InvariantError`。在注册成功前,系统会等待同步或异步 installer 完成;失败会原子地 dispose(资源释放)子级并释放归属。
服务拥有每个注册 fiber返回的 disposer 同时属于配套 fiber。卸载任一侧都会移除监听器、跟踪状态和保留。因此配套入口可以重新加载并注册同一包名而不保留旧状态。由会话支撑的配套入口从持久事件重建 baseline仅实时配套入口观察重新加载后开始的操作。
`InvariantError` 扩展 `Error`,携带稳定 `code: 'INVARIANT'`,并公开所属 `packageName`,而不向服务添加产品依赖。
在每个组合中Session 自身负责不可变且接口有效的日志存储:它对每个候选项制作一份无损 JSON 快照,验证完整来源和位置替换,将 `tool/result` 替换限制为一个当前结果的 `content`,深度冻结已接受记录,并通过不可变数组快照公开日志。`dsh-session` 不变量配套入口检查 Session 不负责的其余跨记录规则。
在每个组合中Session 自身负责不可变且通过对外接口校验的日志存储:它对每个候选项制作一份无损 JSON 快照,验证完整来源和位置替换,将 `tool/result` 替换限制为一个当前结果的 `content`,深度冻结已接受记录,并通过不可变数组快照公开日志。`dsh-session` 不变量配套入口检查 Session 不负责的其余跨记录规则。
## 包配套入口
发布和注册覆盖全部包;运行时断言刻意不使用合成内容。只有当包拥有可观察事件关系或相关可变数据关系时配套入口才安装检查。确认必需方法、插件名称、注入、effect 或固定纯函数结果属于类型、加载或单元测试关注点,而非运行时不变量。
发布和注册覆盖全部包;但不会为了覆盖全部包而人为编造运行时断言。只有当包拥有可观察事件关系或相关可变数据关系时配套入口才安装检查。确认必需方法、插件名称、注入、effect 或固定纯函数结果属于类型、加载或单元测试关注点,而非运行时不变量。
如果不存在合理的运行时关系,配套入口使用空 installer并以包专用的前置 `No runtime invariant:` 注释说明原因。纯工具、行为已通过 seam 观察的薄实现、仅组合包、二进制程序、契约需要崩溃/往返测试的持久化适配器和测试支持包通常属于此类。当 owner 获得可变状态或事件协议时,必须重新审视该说明。
@@ -36,18 +36,18 @@ interface Config {
| 配套入口 | 检查 |
|---|---|
| `dsh-session`, `dsh-agent`, `dsh-scope`, `dsh-agent-loop` | 会话包含关系和调用/结果跟踪、agent 状态转换、inbox FIFO 守恒、作用域 subject 和模型请求重建。 |
| `dsh-session`, `dsh-agent`, `dsh-scope`, `dsh-agent-loop` | 会话包含关系和调用/结果跟踪、agent(智能体)状态转换、inbox FIFO 守恒、作用域 subject 和模型请求重建。 |
| `dsh-llm`, `dsh-llm-retry`, `dsh-tools`, `dsh-system-prompt` | 流语法、持久重试位置和边界、工具流水线阶段与冻结结果,以及权威提示词组装数据。 |
| `dsh-compact`, `dsh-hook-protocol`, `dsh-sandbox-policy` | 持久压缩与钩子配对、压缩元数据和沙箱 mode 词汇。 |
| `dsh-compact`, `dsh-hook-protocol`, `dsh-sandbox-policy` | 持久压缩compaction与钩子配对、压缩元数据和沙箱 mode 词汇。 |
| `dsh-fs`, `dsh-subagent`, `dsh-workflow` | 文件系统事件身份、提供方/子级配对和工作流/agent 生命周期身份。 |
| `dsh-goal`, `dsh-goal-session` | 持久 goal 来源/内容一致性、修订和生命周期转换、时间戳、顺序接纳 Round 和重建的继续提示词。 |
| `dsh-goal`, `dsh-goal-session` | 持久 goal 来源/内容一致性、修订和生命周期转换、时间戳、依次获准的 Round 和重建的继续提示词。 |
| `dsh-permission`, `dsh-user-approval` | 活动 preset 引用和审批询问/决定审计配对。 |
| `dsh-tasks`, `dsh-tool-todo` | 任务快照生命周期/归属字段和持久整表 todo 结构。 |
| `dsh-time-context` | 持久时钟读数与会话开放轮次、下一步骤位置已用 baseline 一致;渲染时间可解析,且不晚于其事件。 |
| `dsh-time-context` | 持久时钟读数与会话中正在进行的轮次、下一步骤开始前的位置已用时间 baseline 一致;渲染时间可解析,且不晚于其事件。 |
每个 owner 的根入口仍与诊断独立。单独加载服务不会安装产品检查;在没有服务时加载配套入口,会等待其声明的 `invariants` 注入。
每个 owner 的根入口仍独立于诊断。单独加载服务不会安装产品检查;在没有服务时加载配套入口,会等待其声明的 `invariants` 注入。
`pnpm run verify-package-invariants` 发现全部工作区包。它拒绝生成标记、未说明的空 installer、省略或忽略 reporter 的非空 installer、错误注册名称以及不完整的导出、发布、依赖、TypeScript 引用或 bundle 接线。该源规则是最低归属检查;聚焦测试证明每个可执行配套入口的语义。
`pnpm run verify-package-invariants` 发现全部工作区包。它拒绝生成标记、未说明的空 installer、省略或忽略 reporter 的非空 installer、错误注册名称以及不完整的导出、发布、依赖、TypeScript 引用或 bundle 接线。该源规则是最低归属检查;聚焦测试证明每个可执行配套入口的语义。
## 组合
@@ -68,18 +68,18 @@ ctx.plugin(SessionInvariant)
标准 agent 主干挂载服务和 4 个核心有状态配套入口。自定义组合为希望检查其契约的其他已加载包显式添加配套入口;过滤器可以在不改变包入口的情况下禁用或选择注册。
每个普通 Vitest 拓扑都挂载显式启用的服务和当前测试包的配套入口。聚焦套件覆盖可执行配套入口的有效和无效观察,一个穷尽拓扑则挂载全部配套入口,以证明注册和 dispose 接线。
每个普通 Vitest 拓扑都挂载显式启用的服务和当前测试包的配套入口。聚焦套件覆盖可执行配套入口的合法与违规观测,一个穷尽拓扑则挂载全部配套入口,以证明注册和 dispose 接线。
## 模型体验
无。服务和配套入口观察运行时事件和可变快照不会更改提示词、消息、schema、流或工具结果。
#### KV 缓存影响
#### KV Cache 影响
无;不变量检查不组装或发送提供方请求。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- 请求重建覆盖 loop 在冻结前显式标记的请求;直接一次性 LLM 调用即使由调用方冻结或附加会话 id仍不在该标记契约内。
- 请求重建覆盖 loop 在冻结前显式标记的请求;直接一次性 LLM(大语言模型)调用即使由调用方冻结或附加会话 id仍不在该标记契约内。
- 仅实时生命周期配套入口无法重建自身重新加载前开始的操作。标准组合和测试组合会在相应操作开始前挂载它们。
- 正则表达式过滤器在服务生命周期内固定;更改它们需要执行普通 Cordis 插件重新加载。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/support/llm-replay/README.md
README.md: 6c934e01a5f13b94724d0e5435524d9d463adb2f
README.zh.md: 03309931d01957ef60aa65d5d9ba3c2a844b0a16
README.zh.md: d13d84ad95a6b63177ee0e2aa83965be19fdeeb8

View File

@@ -2,21 +2,21 @@
[English](README.md) | 中文
用于无密钥快照测试的回放 LLM 插件。它已记录的**会话 JSONL** fixture 重建模型流,使测试可以在无 API 密钥的情况下使用固定模型 transcript 启动真实 agent。配置 `providers` 后,它会注册仅回放适配器,其目录可供测试模型发现的场景使用;没有 `providers` 时,它会安装不需要发现的测试所用 catch-all `llm/stream` waterfall。
用于无密钥快照测试的大语言模型LLM回放插件。它根据已记录的**会话 JSONL** fixture(测试前置数据)重建模型流,使测试无 API 密钥即可针对固定模型 transcript(文本记录)启动真实 agent(智能体)。配置 `providers` 后,它会注册仅用于回放适配器,其模型目录可供测试模型发现功能的场景使用;未配置 `providers` 时,它会安装无需模型发现功能的测试所用 catch-all `llm/stream` waterfall(瀑布式事件)
其消费方 ACP、headless `stream-json` 和 TUI 快照套件,以及 web 浏览器 e2e lane。Loader 驱动套件使用此插件替真实 LLM 适配器;web lane 直接安装它,以保留拆卸消费句柄。将派生和回放逻辑保留在此处,可使其受 `packages/*/src` 上每文件 100% 覆盖率门禁约束。
其消费方包括 ACPAgent Client Protocol、headless `stream-json` 和 TUI 快照套件,以及 Web 浏览器 e2e 流水线。Loader 驱动套件使用此插件替真实 LLM 适配器;Web 流水线直接安装它,以保留清理阶段的消费检查句柄。将派生和回放逻辑在此处,可使其受 `packages/*/src` 的逐文件 100% 覆盖率门禁约束。
## Fixture 的工作方式
## fixture 的工作方式
Fixture 就是持久化会话日志(`<scenario>/session.jsonl`)。其 `assistant/chunk` 事件携带每个 `StreamChunk`,因此按 `(turn, step)` 对其分组可重建每次 `stream()` 调用的分片序列(每个 loop 步骤一次模型调用)。因此,录制操作是「运行一次真实 agent 并收集 `.jsonl`」,由快照 harness 完成;该插件不执行录制。Fixture 的 `request/header` 内容可能被 token 化为 `{{system}}`/`{{tools}}`harness 在一个场景中固定该内容,并除其余场景);回放对此并不关心,因为派生只读取 `assistant/chunk` 事件和第 0 行会话 header。
fixture 就是持久化会话日志(`<scenario>/session.jsonl`)。其 `assistant/chunk` 事件包含每个 `StreamChunk`,因此按 `(turn, step)` 分组可重建每次 `stream()` 调用的分片序列(每个循环步骤调用一次模型)。因此,录制是「运行一次真实 agent 并收集 `.jsonl`」,由快照 harness 完成;该插件本身不录制。fixture 的 `request/header` 内容可能被标记化为 `{{system}}`/`{{tools}}`harness 在一个场景中固定该内容,并除其余场景中的内容);回放不受影响,因为派生过程只读取 `assistant/chunk` 事件和第 0 行会话 header。
有两种失败 mode 无法仅 `assistant/chunk` 重建:在任何分片前纯抛出(例如 HTTP 401日志只包含 `turn/end {error}` 而没有分片),以及 cancel/hang时序,而非分片内容)。需要这些的场景提供可选 sidecar`<scenario>/replay.override.json`,它要么替换派生脚本(裸 `ReplayEntry[]`要么增补派生脚本(`{ patches: [{ at, entry }] }`:保留全部由 JSONL 派生的调用,仅在点名的调用索引处换入,索引从 0 计;`at` 等于派生长度时为追加,正是注入瞬态抛出之后那次重试尝试所占的槽位。Patch 索引必须互不重复。覆写文档、每个 patch 与每个条目,以及每个分片的判别字段都会在文件加载时接受校验`hang` 条目可以指定 `readyFile`在其前缀分片到达 loop 后、等待取消前,回放会写入空标记,使外部驱动器可以在不观察展示更新的情况下确定性取消。
有两种失败模式无法仅根据 `assistant/chunk` 重建:在产生任何分片前直接抛出异常(例如 HTTP 401此时日志只 `turn/end {error}` 而没有分片),以及取消或挂起(差异在时序,而非分片内容)。需要这些行为的场景提供伴随文件`<scenario>/replay.override.json`:它可以替换派生脚本(裸 `ReplayEntry[]`也可以增补派生脚本(`{ patches: [{ at, entry }] }`:保留所有从 JSONL 派生的调用,只替换指定的从 0 开始计数的调用索引;当 `at` 等于派生长度时,则在注入瞬态异常后的重试位置追加一次调用)。补丁索引不得重复。文件加载时会校验覆写文档、每个补丁和条目,以及每个分片的判别标签`hang` 条目可以指定 `readyFile`前缀分片到达循环后、开始等待取消前,回放会写入这个空标记,使外部驱动程序无需观察展示更新即可确定性取消。
## 嵌套 agent每会话键控
父 agent 委托给进程内 subagent 的场景会记录多个日志:父级(`session.jsonl`)和每个子级各一个`session.1.jsonl`等)。每个 agent 在同一上下文中作为自己`Session` 运行,因此回放必须为每个 agent 提供自的脚本。
父 agent 委托给进程内 subagent(子 agent的场景会记录多个日志:父会话使用 `session.jsonl`每个子会话各使用一个日志`session.1.jsonl` 等)。每个 agent 在同一上下文中作为独立`Session` 运行,因此回放必须为每个 agent 提供自的脚本。
回放调用会话 id 为每次调用建键(由 agent loop 标记的 `GenerateOptions.sessionId`)。实时会话 id 每次运行中都是新的随机值,绝不等于记录,因此实时会话通过**首次调用顺序** 绑定到已记录脚本:脚本按 header `createdAt` 排序(父在前,因为它必须先进行流式输出才能委托);第一个进行任何调用的实时会话取第一个脚本,下一个新会话取下一个,以此类推。然后,每个会话推进自己的游标。没有 `sessionId` 的调用绑定主脚本的单一匿名会话,因此单会话场景与以前完全相同。实时会话超过已记录脚本数时快速失败
回放根据发起调用会话 id 为每次调用建键(`GenerateOptions.sessionId` 由 agent loop 写入)。实时会话 id 每次运行时都会重新随机生成,绝不等于记录中的 id,因此实时会话**首次调用顺序**绑定到已记录脚本:脚本按 header 中的 `createdAt` 排序(父会话在前,因为它必须先开始流式输出才能委托);第一个发起调用的实时会话取第一个脚本,下一个新会话取下一个脚本,以此类推。此后每个会话分别推进自己的游标。没有 `sessionId` 的调用视为一个绑定主脚本的匿名会话,因此单会话场景的行为与以前完全相同。不同实时会话的数量超过已记录脚本数时会明确报错
## 配置
@@ -24,9 +24,9 @@ Fixture 就是持久化会话日志(`<scenario>/session.jsonl`)。其 `assis
|---|---|---|---|
| `file` | string | `$DSH_SNAPSHOT_FILE` | 主(父)`session.jsonl` fixture 的路径。必需(配置或 env。 |
| `overrideFile` | string | `$DSH_SNAPSHOT_OVERRIDE` | 主会话的可选 `ReplayOverrideDoc` sidecar`ReplayEntry[]` 替换其派生脚本,`{ patches }` 则按调用索引增补该脚本。 |
| `childFiles` | string[] | `$DSH_SNAPSHOT_CHILD_FILES` (path-delimited) | 嵌套场景中已记录的 subagent 子会话日志;单会话场景为空。 |
| `childFiles` | string[] | `$DSH_SNAPSHOT_CHILD_FILES`(以路径分隔符分隔) | 嵌套场景中已记录的 subagent 子会话日志;单会话场景为空。 |
| `providers` | `ReplayProviderConfig[]` | 无 | 可选的仅回放提供方和模型目录。每个提供方可以设置 `retryPolicy`,每个模型可以发布 `contextWindow`;已配置路由通过回放适配器分派,绝不执行提供方 I/O。 |
| `paceMs` | number | 无(突发) | 可选的每分片毫秒延迟,使下游传输(例如真实浏览器观察的 web SSE mux看到真正的增量传递。它只是仿真开关测试不得依赖它保证正确性。值必须是非负整数pace 等待期间中止会迅速取消流。 |
| `paceMs` | number | 无(突发) | 可选的每分片毫秒延迟,使下游传输(例如真实浏览器观察Web SSEServer-Sent Events多路复用器看到真正的增量传递。它只是仿真开关测试不得依赖它保证正确性。值必须是非负整数pace 等待期间中止会迅速取消流。 |
```yaml
- id: llm-replay
@@ -52,10 +52,10 @@ Fixture 就是持久化会话日志(`<scenario>/session.jsonl`)。其 `assis
## 导出项
- `installLlmReplay(ctx, config)`:安装已配置回放适配器或 catch-all `llm/stream` 监听器;返回 `ReplayHandle`(包含用于 HMR 安全的 `dispose()`,以及 `assertConsumed()` 拆卸检查;后者确保每个已记录脚本都绑定到实时会话,且每个已绑定游标都已耗尽,从而将场景静默驱动的模型调用少于记录数转换为明确诊断)。在测试中使用它,可以不通过 Loader 或 env var 驱动回放。
- `loadSessionScripts(config)`:解析场景的有序 `SessionScript[]` (主 + 子),准备按首次调用顺序绑定到实时会话。
- `loadReplayScript(config)`:只解析主会话的 `ReplayEntry[]` (如果存在则使用经校验的 sidecar 替换或 patch否则从 JSONL 派生fixture 缺失时快速失败)。
- `deriveReplayScript(events)` / `parseSessionLog(text)` / `parseSessionHeader(text)`:将已记录会话日志转换为脚本并读取其 header `id`/`createdAt` 的纯辅助工具。派生分组必须以 `finish` 分片结束;没有该分片的分组是已抛出 `stream()` 的指纹,必须改用 override sidecar 表达。
- `installLlmReplay(ctx, config)`:安装已配置回放适配器或 catch-all `llm/stream` 监听器;返回 `ReplayHandle`(包含用于保证 HMR(热模块替换)安全的 `dispose()`,以及清理阶段执行的 `assertConsumed()` 检查;后者确保每个已记录脚本都绑定到实时会话,且每个已绑定游标都已耗尽,从而将场景静默驱动的模型调用少于记录数转换为明确诊断)。在测试中使用它,可以不通过 Loader 或 env var 驱动回放。
- `loadSessionScripts(config)`:解析场景的有序 `SessionScript[]`(主会话 + 子会话),准备按首次调用顺序绑定到实时会话。
- `loadReplayScript(config)`:只解析主会话的 `ReplayEntry[]`(如果伴随文件存在则使用经校验的替换或补丁;否则从 JSONL 派生fixture 缺失时明确报错)。
- `deriveReplayScript(events)` / `parseSessionLog(text)` / `parseSessionHeader(text)`:将已记录会话日志转换为脚本并读取其 header `id`/`createdAt` 的纯辅助工具。派生分组必须以 `finish` 分片结束;没有该分片的分组是 `stream()` 抛出异常的指纹,必须改用 override sidecar 表达。
- 类型 `ReplayEntry` / `ReplayOverrideDoc` / `ReplayOverridePatch` / `SessionScript` / `ReplayConfig` / `ReplayProviderConfig` / `ReplayModelConfig` / `ReplayHandle` / `Config`
## 插件导出形态
@@ -66,11 +66,11 @@ Fixture 就是持久化会话日志(`<scenario>/session.jsonl`)。其 `assis
无。该无密钥测试适配器不向提供方模型发送请求,只将已记录 assistant 分片回放到测试 loop 中。
#### KV 缓存影响
#### KV Cache 影响
无;该包既不组装也不发送提供方请求。
无;该包package既不组装也不发送提供方请求。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **首次调用顺序脚本绑定假设串行委托**:并发运行同级 subagent 的 cut或运行中落地的压缩摘要调用)会非确定性地将实时会话绑定到已记录脚本;在这种场景出现前暂不实现更强的键控(`XXX(concurrent-subagents)`)。
- **只有生分片的调用派生**纯分片前抛出或 cancel/hang 场景需要 `replay.override.json` sidecar。替换和 patch 两种形式都只影响主会话;子会话脚本仍从各自日志派生。
- **首次调用顺序脚本绑定假设串行委托**:并发运行同级 subagent 的 cut或运行中发生的上下文压缩context compaction摘要调用)会非确定性地将实时会话绑定到已记录脚本;在这种场景出现前暂不实现更强的键控(`XXX(concurrent-subagents)`)。
- **只有会产生分片的调用才能派生**在产生分片前直接抛出异常或取消/挂起的场景需要 `replay.override.json` 伴随文件。替换和补丁两种形式都只影响主会话;子会话脚本仍从各自日志派生。

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
# pnpm run verify-translation-pairing --write packages/support/loader-smoke/README.md
README.md: 73610ce50ebac4c6fc7bb9135f7b41b347c60685
README.zh.md: 17f8481220136e8edf9fccd23fabfca5ccf41dfc
README.zh.md: 9254cd1592d4bf3f119d350f04165228db87b1cf

View File

@@ -4,20 +4,20 @@
用于测试通过 Cordis Loader 启动应用和 `cordis.yml` 的共享子进程 harness。`resolveExampleLaunch` 选择本地 `src` modetsx 和根 tsconfig 路径)或 CI `lib` mode普通 Node 和包导出);选择依据为显式 mode 或 `DSH_EXAMPLE_MODE`
`runLoaderSmoke` 接受 bin 和配置路径、可选的完整 bin 参数、环境覆盖、stdin、运行前设置和清理前检查。它负责隔离 cwd、DSH 主目录、诊断、deadline、终止、EOF 和清理;在零退出后返回两个流,失败时拒绝并带两个流。
`runLoaderSmoke` 接受可执行文件路径和配置路径、可选的完整可执行文件参数、环境变量覆盖、标准输入、运行前准备和清理前检查。它负责隔离工作目录、DSH 主目录、诊断、截止时间、终止、EOF 和清理;进程以零状态退出后返回两个流,失败时则返回拒绝并带两个流。
这是支持层测试基础设施,而非产品 API。
## 模型体验
无。该测试专用 harness 启动示例进程并检查它们的流,不会改变组装模型请求。
无。该测试专用 harness 启动示例进程并检查它们的流,不会改变组装后的模型请求。
#### KV 缓存影响
#### KV Cache 影响
无;该包既不组装也不发送提供方请求。
## 已知限制与待完成工作
## 已知限制与暂缓事项
- **构建 mode 需要事先构建**:配置还必须能够通过 `examples/node_modules` 向上解析每个命名包。
- **构建模式需要事先构建**:配置还必须能够通过 `examples/node_modules` 向上解析每个命名包。
- **捕获的 stdout 和 stderr 仅受 execa 默认 100 MB `maxBuffer` 约束**:失控子进程会在该上限处被终止,而不是在冒烟测试自选的预算处。
- **超时只终止直接子进程**:故障 fixture 生成的进程树可比冒烟测试存活更久,需要外部清理。
- **超时只终止直接子进程**故障 fixture测试前置数据spawn 的进程树可比冒烟测试存活更久,需要外部清理。