feat(acp-example): snapshot harness, normalizers, wiring, and handshake scenario
Adds the snapshot-test harness and the keyless replay pipeline end-to-end. - snapshot-harness.ts: boots the real acp-agent subprocess via the cordis Loader (preserving TSX_TSCONFIG_PATH so unbuilt dsh-* imports resolve from a temp cwd), tees raw stdout into an SDK ClientSideConnection, interprets a per-scenario input.json DSL (initialize / newSession capturing the random sessionId / prompt / cancel), closes stdin to trigger graceful shutdown, and harvests the persisted session.jsonl. Failure-safe: a finally block SIGKILLs a live child, awaits its exit, and removes both temp dirs even on a thrown step or harvest. Raw bytes are buffered and decoded once (no multibyte split). - snapshot-normalize.ts (+ spec): two pure normalizers (stdout frames + session JSONL) scrub cwd, session ids / UUIDs, and JSON-RPC ids, and zero time / createdAt — but keep `seq` (deterministic by contract). normalizeStdout throws on a non-JSON line (the stdout-purity check). - start.ts: selects cordis.snapshot.yml (replay, providerless) or cordis.snapshot-record.yml (record, real adapter) from DSH_SNAPSHOT, skips .env in replay, and disposes the ctx on stdin end so persistence flushes before exit (harvest-after-flush, not on the prompt response). - acp.snapshot.ts: asserts the normalized stdout golden (and, for model scenarios, the re-persisted JSONL golden) via toMatchFileSnapshot; record mode writes the harvested log back to the scenario fixture; an orphan-fixture guard fails on an unregistered scenario dir. - handshake scenario: initialize + session/new (no model call; a header-only session.jsonl, since session/new persists no events). - vitest.snapshot.config.ts, test:snapshot / test:snapshot:record scripts, a pre-push snapshot job, and the knip entry. Incorporates Codex review: record-fixture writeback, failure-safe teardown, seq-not-scrubbed, harvest-after-flush. Per docs/rfc/implemented/2026-06-19.
This commit is contained in:
43
examples/acp-agent/cordis.snapshot-record.yml
Normal file
43
examples/acp-agent/cordis.snapshot-record.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
# Snapshot-test RECORD config: a real run whose persisted session JSONL is
|
||||
# harvested into a scenario fixture. Identical to cordis.yml (real llm-deepseek
|
||||
# adapter + JSONL persistence) — recording must exercise the REAL model so the
|
||||
# recorded log is a genuine product of the system. Needs DEEPSEEK_API_KEY.
|
||||
#
|
||||
# It is a separate file (rather than reusing cordis.yml) only so the snapshot
|
||||
# harness selects it explicitly via $DSH_SNAPSHOT=record and so its persistence
|
||||
# root can be pointed at the harness's harvest directory by the same env the
|
||||
# replay path uses. The graceful-shutdown path in start.ts flushes persistence
|
||||
# before exit so the harvested log is complete.
|
||||
|
||||
- id: timer
|
||||
name: '@cordisjs/plugin-timer'
|
||||
|
||||
# Shared provider/tool core, INCLUDING the real llm-deepseek adapter.
|
||||
- id: base
|
||||
name: '@cordisjs/plugin-include'
|
||||
config:
|
||||
path: '../base.yml'
|
||||
|
||||
- id: agent-loop
|
||||
name: '@deepseek-ai/dsh-agent-loop'
|
||||
config:
|
||||
agents: []
|
||||
|
||||
- id: session-persistence
|
||||
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
||||
config:
|
||||
root: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT
|
||||
|
||||
- id: acp
|
||||
name: '@deepseek-ai/dsh-acp'
|
||||
config:
|
||||
model: deepseek-v4-flash
|
||||
systemPrompt: |
|
||||
You are a coding assistant driven over the Agent Client Protocol.
|
||||
|
||||
Your only tools are bash (plus bash_output/bash_kill for background
|
||||
tasks). Do ALL file operations through bash: read with cat/sed/head,
|
||||
search with grep, write with heredocs (cat <<'EOF' > file), edit with
|
||||
sed or a rewrite. Each bash call runs in a fresh shell — pass workdir
|
||||
instead of cd. Check the [exit code: N] marker; verify your work. Keep
|
||||
answers brief and factual.
|
||||
Reference in New Issue
Block a user