Skip to main content
Keep your existing model/tool loop. Add Mirrors where you record history, assemble the next model request, and finish the turn. Complete SDK setup first; these TypeScript examples use mirrors-sdk@0.7.0. The Python quickstart shows the same hooks in Python.

1. Capture original history

Give each user turn a fresh execution ID. Keep it through all model calls, tools, and retries in that turn. Map your stored history to a CanonicalTrace, including the original system prompt. At your existing history logging point:
Send the full snapshot, not just new messages. Capture runs in the background; do not await it before calling the model. Keep injected context out of stored history so later captures contain only original instructions, messages, and results.

2. Add context before the first model call

Here, originalTrace is that turn’s current canonical snapshot. request and model.complete stand for your existing provider request and call; they are application code, not Mirrors APIs.
This copies the request without changing its original system prompt. Empty context uses the baseline prompt; it is normal in shadow/off mode, on no match, or during a fallback. Retrieval carries its own snapshot, independently of capture delivery. Use context immediately. If dispatch is delayed, check selected.freshness.expiresAt; if history changes, retrieve again. This pattern adds one bounded wait at turn entry. Later tool steps use the base prompt unless you explicitly retrieve fresh context for their updated history. Each retrieval can add up to 1,000 ms.

3. Finalize when the whole turn ends

After recording the last response and tool results, capture the final originals:
For streaming, this belongs in the actual completion hook, after stream consumption and all tool work finish. Returning a stream handle is too early. On failure or cancellation, capture the available originals with terminal: "failed" or "canceled", preserving your existing error handling. If no final evidence is available, use mirrors.releaseTrace(traceId) for local cleanup. The next turn gets a new execution ID. To connect turns in one chat, follow the conversation identity rules.

Delivery and shutdown

Inspect ticket.receipt or await ticket.done outside model execution. An accepted final capture with ingestion queued means analysis is pending, not finished. Reuse the client across turns. At application shutdown, stop admitting turns, let active turns finish, then drain pending captures:
Inspect delivery.dropped, unconfirmed, and pending; complete only means the covered tickets settled. Capture queues are in memory. Short-lived hosts need a supported post-response lifetime hook to allow flushing.

Verify the integration

  • Active match: context reaches the outgoing prompt while stored originals stay unchanged.
  • Tools and streaming: final capture includes original call/result pairs and the final response.
  • Failure, cancellation, and outage: native error/abort handling still works; empty context uses the base prompt.
Start in shadow mode. Inspect final capture receipts and the resulting conversation in Mirrors. See troubleshooting for empty context or missing traces.