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.