mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
test(snapshot): centralize SDK session corpus
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/testing.md
|
||||
testing.md: 9b0ed0a103b1ca9f149d289cabcc2b0ba9bc909f
|
||||
testing.zh.md: 18e72deed19b7ecd981123e933f23cbbf7ba2c87
|
||||
testing.md: 1d9f50e3d593e41ca0823e9b6a8182b573db5feb
|
||||
testing.zh.md: dbe6bd4fedb779584998003587c71f5846d52c1c
|
||||
|
||||
+1
-1
@@ -46,4 +46,4 @@ An e2e assertion re-runs the command or re-reads the file externally; a keyword
|
||||
|
||||
## When a snapshot test is required
|
||||
|
||||
Every non-trivial model-, protocol-, or human-visible change adds or updates a keyless scenario in the same PR through its owning recorded-session suite. Package tests, e2e assertions, mock/test-only compositions, and PR rationale do not replace the assembled transcript; extend the harness when needed. ACP automation scenarios live under `snapshots/acp/`, driven by the [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.md) ACP adapter; `examples/headless-agent` owns the internal canonical-event JSONL snapshots and replay fixtures. The `pwsh-tool-turn` ACP scenario boots real `pwsh` and skips where it is absent. Completed interactive-terminal journeys use JSONL-driven scenarios under `apps/cli/tests/snapshots/`; transient presentation uses the package-local semantic matrix, with a PTY case when input, Loader selection, or terminal teardown changes. Browser-rendered web GUI journeys use `apps/web/tests/snapshots/`. The two SDKs project the agent loop, session lifecycle, and `SessionEventMap` independently, so changing any of those updates both: `examples/python-sdk-agent/tests/snapshots/` owns the TypeScript client; `scripts/snapshots/python-sdk-single-exe/` owns the Python client, which only the required `python-runtime` CI job runs. New capability seams, lifecycle variants, or transcript surfaces name every coverage tier at plan time and verify the harness can express it before implementation.
|
||||
Every non-trivial model-, protocol-, or human-visible change adds or updates a keyless scenario in the same PR through its owning recorded-session suite. Package tests, e2e assertions, mock/test-only compositions, and PR rationale do not replace the assembled transcript; extend the harness when needed. ACP automation scenarios live under `snapshots/acp/`, driven by the [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.md) ACP adapter; `examples/headless-agent` owns the internal canonical-event JSONL snapshots and replay fixtures. The `pwsh-tool-turn` ACP scenario boots real `pwsh` and skips where it is absent. Completed interactive-terminal journeys use JSONL-driven scenarios under `apps/cli/tests/snapshots/`; transient presentation uses the package-local semantic matrix, with a PTY case when input, Loader selection, or terminal teardown changes. Browser-rendered web GUI journeys use `apps/web/tests/snapshots/`. The two SDKs project the agent loop, session lifecycle, and `SessionEventMap` independently, so changing any of those updates both: `snapshots/sdk/` owns the TypeScript client; `scripts/snapshots/python-sdk-single-exe/` owns the Python client, which only the required `python-runtime` CI job runs. New capability seams, lifecycle variants, or transcript surfaces name every coverage tier at plan time and verify the harness can express it before implementation.
|
||||
|
||||
+1
-1
@@ -46,4 +46,4 @@ e2e 断言应重新运行命令或从外部重新读取文件;对 agent 自身
|
||||
|
||||
## 何时需要快照测试
|
||||
|
||||
每项非平凡的模型可见、协议可见或人类可见变更,都必须在同一 PR 中,通过所属录制会话套件添加或更新无密钥场景。包测试、e2e 断言、mock 与仅测试组合、PR 理由都不能取代组装后的 transcript;必要时应扩展 harness。ACP 自动化场景位于 `snapshots/acp/`,由 [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.zh.md) ACP 适配器驱动;`examples/headless-agent` 拥有内部规范事件 JSONL 快照与回放 fixture。`pwsh-tool-turn` ACP 场景启动真实 `pwsh`,在无 `pwsh` 的主机上跳过。已完成的交互式终端旅程使用 `apps/cli/tests/snapshots/` 下由 JSONL 驱动的场景;瞬态呈现使用包内语义矩阵,输入、Loader 选择或终端清理发生变化时还要添加 PTY 用例。浏览器渲染的 Web GUI 旅程使用上述 Web 应用快照套件。两个 SDK 各自独立地投影 agent loop、会话生命周期与 `SessionEventMap`,因此改动其中任何一项都要同时更新两者:`examples/python-sdk-agent/tests/snapshots/` 拥有 TypeScript 客户端;`scripts/snapshots/python-sdk-single-exe/` 拥有 Python 客户端,且只有必需的 `python-runtime` CI 作业会运行它。新的能力 seam、生命周期变体或 transcript 呈现接口在计划阶段就要列出每个覆盖层级,并在实现前验证 harness 能够表达它们。
|
||||
每项非平凡的模型可见、协议可见或人类可见变更,都必须在同一 PR 中,通过所属录制会话套件添加或更新无密钥场景。包测试、e2e 断言、mock 与仅测试组合、PR 理由都不能取代组装后的 transcript;必要时应扩展 harness。ACP 自动化场景位于 `snapshots/acp/`,由 [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.zh.md) ACP 适配器驱动;`examples/headless-agent` 拥有内部规范事件 JSONL 快照与回放 fixture。`pwsh-tool-turn` ACP 场景启动真实 `pwsh`,在无 `pwsh` 的主机上跳过。已完成的交互式终端旅程使用 `apps/cli/tests/snapshots/` 下由 JSONL 驱动的场景;瞬态呈现使用包内语义矩阵,输入、Loader 选择或终端清理发生变化时还要添加 PTY 用例。浏览器渲染的 Web GUI 旅程使用上述 Web 应用快照套件。两个 SDK 各自独立地投影 agent loop、会话生命周期与 `SessionEventMap`,因此改动其中任何一项都要同时更新两者:`snapshots/sdk/` 拥有 TypeScript 客户端;`scripts/snapshots/python-sdk-single-exe/` 拥有 Python 客户端,且只有必需的 `python-runtime` CI 作业会运行它。新的能力 seam、生命周期变体或 transcript 呈现接口在计划阶段就要列出每个覆盖层级,并在实现前验证 harness 能够表达它们。
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
normalizeSessionLog,
|
||||
normalizeSessionSnapshot,
|
||||
normalizeStdout,
|
||||
parseSnapshotManifest,
|
||||
refreshFixtureReplacements,
|
||||
scrubRequestHeaders,
|
||||
scrubSessionSnapshot,
|
||||
@@ -31,7 +32,7 @@ import {
|
||||
import { DeepSeekHarness, type HarnessNotification, type RunResult } from '@deepseek-ai/dsh-sdk-client'
|
||||
|
||||
const testsDir = dirOf(import.meta.url)
|
||||
const snapshotsDir = join(testsDir, 'snapshots')
|
||||
const snapshotsDir = fileURLToPath(new URL('../../../snapshots/sdk/', import.meta.url))
|
||||
const liveConfig = join(testsDir, '..', 'typescript-sdk.cordis.yml')
|
||||
const replayConfig = join(testsDir, '..', 'typescript-sdk.cordis.snapshot.yml')
|
||||
const minimalLiveConfig = join(testsDir, '..', 'typescript-sdk-minimal.cordis.yml')
|
||||
@@ -65,7 +66,7 @@ function dirOf(url: string): string {
|
||||
}
|
||||
|
||||
interface SdkScenario {
|
||||
/** Scenario name; the snapshots/<name> fixture directory. */
|
||||
/** Scenario name; the `snapshots/sdk/<name>` fixture directory. */
|
||||
name: string
|
||||
/** The user prompt for the single SDK turn. */
|
||||
prompt: string
|
||||
@@ -370,6 +371,11 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
|
||||
for (const scenario of SCENARIOS) {
|
||||
it(`replays ${scenario.name} through the SDK`, async () => {
|
||||
const scenarioDir = join(snapshotsDir, scenario.name)
|
||||
const manifest = parseSnapshotManifest(
|
||||
await readFile(join(scenarioDir, 'snapshot.yml'), 'utf8'),
|
||||
join(scenarioDir, 'snapshot.yml'),
|
||||
)
|
||||
expect(manifest).toEqual({ version: 1, profile: 'sdk' })
|
||||
const notificationsExpectedPath = join(scenarioDir, 'notifications.expected.jsonl')
|
||||
const resultExpectedPath = join(scenarioDir, 'result.expected.json')
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
version: 1
|
||||
profile: sdk
|
||||
@@ -0,0 +1,2 @@
|
||||
version: 1
|
||||
profile: sdk
|
||||
@@ -0,0 +1,2 @@
|
||||
version: 1
|
||||
profile: sdk
|
||||
@@ -0,0 +1,2 @@
|
||||
version: 1
|
||||
profile: sdk
|
||||
Reference in New Issue
Block a user