/** * Record/Replay — capture real API sessions, replay them deterministically. * * Record: brain that forwards requests to the real API, parses responses, * stores them as a transcript. The transcript doubles as a hand-writable * scenario format. * * Replay: brain that loads a transcript and plays back responses by index. * * const rec = createRecorder({ model: "claude-sonnet-4-20250514" }); * const mock = await createMock({ brain: rec.brain, network: { default: "allow" } }); * await mock.run("do something"); * await rec.save("./session.json"); * * const mock2 = await createMock({ brain: replay("./session.json") }); * await mock2.run("do something"); // deterministic, free, fast */ import { type Brain, type BrainResponse, type ResponseBlock } from "./anthropic.js"; export interface TranscriptUsage { input_tokens: number; output_tokens: number; cache_read_tokens?: number; cache_write_tokens?: number; } /** Request fingerprint for divergence detection (not the full request). */ export interface RequestFingerprint { model: string; messageCount: number; lastUserPrefix: string; toolCount?: number; } export interface TranscriptTurn { response: ResponseBlock[]; usage?: TranscriptUsage; /** Optional request fingerprint — included in recordings, omitted in hand-written scenarios. */ request?: RequestFingerprint; } export interface Transcript { version: 1; recorded?: string; meta?: { provider?: string; model?: string; prompt?: string; }; turns: TranscriptTurn[]; } type RecordProvider = "anthropic" | "openai"; export interface RecorderOptions { /** Real model ID to forward to (e.g. "claude-sonnet-4-20250514"). */ model: string; /** Provider. Auto-detected from model name if not specified. */ provider?: RecordProvider; /** API key. Default: reads from ANTHROPIC_API_KEY / OPENAI_API_KEY. */ apiKey?: string; /** Include request fingerprints for divergence detection. Default: true */ includeRequests?: boolean; /** Called after each turn is recorded. */ onTurn?: (turn: TranscriptTurn, index: number) => void; } export interface Recorder { /** The brain function — pass to createMock({ brain: rec.brain }). */ brain: Brain; /** The accumulated transcript. */ transcript: Transcript; /** Save transcript to a JSON file. */ save(path: string): Promise; } /** * Create a recording brain that forwards requests to a real API. * * ```typescript * const rec = createRecorder({ model: "claude-sonnet-4-20250514" }); * const mock = await createMock({ * brain: rec.brain, * network: { default: "allow" }, // extensions need real network * }); * await mock.run("implement a todo app"); * await rec.save("./session.json"); * await mock.close(); * ``` */ export declare function createRecorder(options: RecorderOptions): Recorder; /** * Load a transcript and replay responses by index. * * Accepts two formats: * * 1. **Full transcript** (from recording or hand-written): * ```json * { "version": 1, "turns": [{ "response": [...] }, ...] } * ``` * * 2. **Simple array** (hand-written shorthand): * ```json * [ * [{ "type": "tool_call", "name": "bash", "input": { "command": "ls" } }], * [{ "type": "text", "text": "Done." }] * ] * ``` * * ```typescript * const mock = await createMock({ * brain: replay("./session.json"), * extensions: ["./ext.ts"], * sandbox: true, * }); * ``` */ export declare function replay(pathOrTranscript: string | Transcript | TranscriptTurn[] | BrainResponse[], options?: { /** Warn on request fingerprint divergence. Default: true */ warnOnDivergence?: boolean; /** Called when a request diverges from the recorded fingerprint. */ onDivergence?: (index: number, expected: RequestFingerprint, actual: RequestFingerprint) => void; }): Brain; export {}; //# sourceMappingURL=record.d.ts.map