Skip to content

Replay

Record-and-replay for regression testing. Capture real agent interactions as JSON cassettes, then replay them deterministically.

Cassette

Cassette

Bases: BaseModel

A complete cassette file: metadata + ordered interactions.

Cassettes are JSON files stored at

cassettes/{test_id}/{short_hash}.json

The short_hash is derived from the content for git-friendliness (F2.8).

compute_content_hash()

SHA-256 hash of the interactions payload.

short_hash()

First 12 chars of content hash, used in filenames.

finalize()

Assign interaction IDs, sequence numbers, and content hash.

to_json(indent=2)

Serialize to JSON string.

Uses Pydantic's Rust-accelerated model_dump_json for speed.

from_json(data) classmethod

Deserialize from JSON string.

save(path)

Write cassette to a JSON file, creating parent dirs.

load(path) classmethod

Load a cassette from a JSON file.

Raises a warning if schema version is outdated.

verify_integrity()

Check that content hash matches stored hash.

cassette_path(base_dir, test_id, content_hash) staticmethod

Build a content-addressed cassette file path.

ReplayEngine

ReplayEngine(cassette, strategy=MatchStrategy.EXACT, *, block_unmatched=True)

Serves recorded responses from a cassette.

Usage::

engine = ReplayEngine(cassette)
response = engine.match(RecordedRequest(
    kind="llm",
    method="chat.completions.create",
    body={"messages": [...]},
))
# response is the RecordedResponse from the cassette

cassette property

The loaded cassette.

remaining property

Number of unused interactions.

all_used property

Whether all recorded interactions have been consumed.

match(request)

Find a matching recorded interaction for the given request.

Raises :class:CassetteMismatchError if no match is found and block_unmatched is True. Returns None when block_unmatched is False and no match exists, allowing the caller to pass the request through to the real service.

reset()

Reset the engine to replay the cassette from the beginning.