Files
deepseek-harness/packages/support/llm-replay
Tianyi Cui b0422f2a50 fix review findings: bump session format version + restore late turn-end warn
Codex review of the trace-event fold found two merge-blockers.

Blocker #1 — format version. Folding usage onto assistant/message and removing
the standalone usage/error events changed the persisted SessionEventMap shape,
which per the AGENTS.md "bump the version and reject — don't migrate" policy
requires a backend to reject any non-current log. Centralize the version in an
exported SESSION_FORMAT_VERSION constant (dsh-session), read by both write sites
(Session constructor default, SessionStore.prepare header) and the coordinator's
load-time assertVersion check. The constant is pinned at 0: while unreleased the
on-disk format is unstable/pre-release, so breaking shape churn is absorbed at v0
(no monotonic bump until the first tagged release) and any non-0 log is rejected
on load — no migration. Update every test/fixture/doc that stamps a
currently-written header to the constant, bump the ACP snapshot fixture + golden
headers to v0, and keep the version-rejection test meaningful by switching its
bad value to a clearly non-current 99. AGENTS.md documents both the monotonic
(SQLite SCHEMA_VERSION) and pinned-0 (session log) pre-release stances.

Blocker #2 — restore the late turn-end warn. failTurn now sets the error reason
only while the turn is still open; once turn/end is appended (a throwing
agent/turn-end listener after closeTurn) the reason can no longer reach the
durable log, so the late throw is logged via ctx.logger.warn instead of
vanishing into a futile post-close assignment. A regression test asserts the
warn fires.

Also guard the normal-step assistant/message append with the same
content-or-usage condition as the max-tokens branch (a content-less, usage-less
step records no trace-only row), with a covering test.
2026-06-21 11:08:10 +08:00
..

@deepseek-ai/dsh-llm-replay

A replay LLM plugin for keyless snapshot tests. It installs a single llm/stream waterfall listener that short-circuits the waterfall (never calls next()) and yields model streams reconstructed from a recorded session JSONL fixture — so a test can boot the real agent against a fixed model transcript with no API key.

Its consumer is the ACP snapshot harness in examples/acp-agent, which loads this plugin (via cordis.snapshot.yml) in place of a real LLM adapter. The package exists so its derive/parse/replay logic falls under the per-file 100% coverage gate on packages/*/src (the same logic, while it lived under examples/, was outside the gate).

How the fixture works

The fixture IS the persisted session log (<scenario>/session.jsonl). Its assistant/chunk events carry every StreamChunk, so grouping them by (turn, step) reconstructs each stream() call's chunk sequence (one model call per loop step). Recording is therefore "run the real agent once and harvest the .jsonl", done by the snapshot harness — this plugin does not record.

Two failure modes are not reconstructable from assistant/chunk alone — a pure throw before any chunk (e.g. an HTTP 401, where the log holds only a turn/end {error} and no chunks) and a cancel/hang (timing, not chunk content). A scenario that needs those supplies an optional sidecar (<scenario>/replay.override.json: a ReplayEntry[]) that REPLACES the derived script.

Config

Key Type Default Notes
file string $DSH_SNAPSHOT_FILE Path to the per-scenario session.jsonl fixture. Required (config or env).
overrideFile string $DSH_SNAPSHOT_OVERRIDE Optional path to a ReplayEntry[] sidecar that replaces the derived script.
- id: llm-replay
  name: '@deepseek-ai/dsh-llm-replay'
  # file/overrideFile default to $DSH_SNAPSHOT_FILE / $DSH_SNAPSHOT_OVERRIDE,
  # set by the snapshot harness per scenario.

Exports

  • installLlmReplay(ctx, config) — install the llm/stream listener; returns the disposer (HMR safety). Use this in tests to drive replay without the Loader or env vars.
  • loadReplayScript(config) — resolve the ReplayEntry[] for a scenario (sidecar override if present, else derived from the JSONL; fail-loud if the fixture is missing).
  • deriveReplayScript(events) / parseSessionLog(text) — the pure helpers that turn a recorded session log into a script. A derived group must end in a finish chunk; a group without one is the fingerprint of a thrown stream() and must instead be expressed via an override sidecar.
  • Types ReplayEntry / ReplayConfig / Config.

Plugin export shape

Named name / inject / Config / apply, with no default export: the cordis Loader's unwrapExports does exports.default ?? exports, so a stray default would collapse the module to the bare function and drop the inject namespace (see docs/postmortem/0001).