Skip to content

feat(adapters): mock + recording + replay adapters [closes #119]#293

Merged
EmersonBraun merged 1 commit intomainfrom
phase1/dry-run
Apr 15, 2026
Merged

feat(adapters): mock + recording + replay adapters [closes #119]#293
EmersonBraun merged 1 commit intomainfrom
phase1/dry-run

Conversation

@EmersonBraun
Copy link
Copy Markdown
Owner

Summary

Phase 1 #119. Three testing primitives for adapters — write fast, deterministic tests without burning tokens.

import {
  mockAdapter, recordingAdapter, replayAdapter, inMemorySink,
} from '@agentskit/adapters'

mockAdapter — deterministic stub

Three call shapes:

// 1. Static chunks
mockAdapter({ response: [
  { type: 'text', content: 'hello' },
  { type: 'done' },
]})

// 2. Request-aware
mockAdapter({ response: req => [
  { type: 'text', content: 'echo: ' + req.messages[0].content },
  { type: 'done' },
]})

// 3. Sequenced — different output per call
mockAdapter({ response: [
  [{ type: 'text', content: 'first' },  { type: 'done' }],
  [{ type: 'text', content: 'second' }, { type: 'done' }],
]})

Conforms to ADR 0001 — auto-appends terminal done if the response doesn't include one, pure factory, abort-safe.

recordingAdapter + replayAdapter — capture once, replay forever

import { openai, recordingAdapter, replayAdapter, inMemorySink } from '@agentskit/adapters'

// Dev: record real sessions
const sink = inMemorySink()
const adapter = recordingAdapter(
  openai({ apiKey: KEY, model: 'gpt-4o' }),
  sink,
)
// ... run the agent ...
// sink.fixture is JSON-serializable — save to disk

// Test: replay
const replay = replayAdapter(savedFixture)

RecordedTurn includes recordedAt, original request, and every chunk yielded.

This is the substrate for the deterministic-replay feature tracked in #134 (Phase 2).

Use cases unlocked

  • Unit-test agent flows without API keys or rate limits
  • Snapshot-test prompts: record a real session, replay forever in CI
  • Demo apps that need deterministic output for screenshots
  • Cost-free CI runs of @agentskit/eval test suites

Tests

12 new cases — 75 / 75 passing on @agentskit/adapters (was 63):

  • Static / request-aware / sequenced response shapes
  • Auto-done append behavior
  • Error termination (no double done)
  • Pure factory invariant (no work until stream())
  • Request history capture
  • Abort cooperation
  • recordingAdapter end-to-end
  • replay determinism
  • Empty fixture error

Test plan

  • Build succeeds
  • All 75 tests pass
  • All exports threaded through src/index.ts
  • No type leaks — RecordedTurn is JSON-serializable
  • Reviewer: try recording a real session and replaying it

Refs #119 #134 #211

Phase 1, story #119. Three first-class testing primitives that let
consumers test agent code without burning tokens or hitting real APIs.

mockAdapter — deterministic adapter
- Three call shapes: static chunks, request-aware function, or
  sequenced (different output per turn, looping when exhausted)
- ADR 0001 compliant: pure factory (A1), auto-appends terminal 'done'
  if response doesn't include one (A3), abort safe (A6), no input
  mutation (A7)
- Optional delayMs between chunks for streaming-UX testing
- Optional history sink to capture every request received

recordingAdapter — wrap a real adapter, capture every turn
- Records {recordedAt, request, chunks} per stream
- Pushes to a sink (in-memory or custom)
- Drains the inner stream completely so partial recordings are
  impossible — fixtures are always whole

replayAdapter — feed a fixture back as an adapter
- Maps call N to fixture[N % fixture.length]
- Throws on empty fixture (clear error vs silent misbehavior)

inMemorySink — convenience for tests + ephemeral capture

Use cases unlocked:
- Unit-test agent flows without API keys or rate limits
- Snapshot-test prompts: record a real session, replay forever in CI
- Demo apps that need deterministic output for screenshots
- Foundation for the deterministic-replay feature tracked in #134

Tests:
- 12 new cases on @agentskit/adapters covering: static / request-aware /
  sequenced response, auto-done append, error termination (no double
  done), pure factory invariant, request history capture, abort
  cooperation, recordingAdapter end-to-end, replay determinism, empty
  fixture error
- Total: 75 / 75 passing on @agentskit/adapters (was 63)

Refs #119 #134 #211
@EmersonBraun EmersonBraun merged commit dc32c9d into main Apr 15, 2026
1 of 4 checks passed
@EmersonBraun EmersonBraun deleted the phase1/dry-run branch April 15, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant