"""Side channel for what a backend learned during one turn. Frontends pass ``capture=TurnCapture()`` through ``Backend.complete``'s ``**options``. Backends that keep state per conversation (the Claude SDK adapter) fill it in after the stream closes; backends that don't (anthropic, raycast) drop the kwarg and the frontend falls back to a text-only history. """ from __future__ import annotations from dataclasses import dataclass, field from typing import Any __all__ = ["TurnCapture", "TurnUsage"] @dataclass(frozen=True, slots=True) class TurnUsage: input_tokens: int = 0 output_tokens: int = 0 cache_read_tokens: int = 0 cache_creation_tokens: int = 0 cost_usd: float | None = None duration_ms: int | None = None num_turns: int | None = None model_usage: dict[str, Any] | None = None """``ResultMessage.model_usage`` verbatim: per-model tokens, cost, web searches.""" context_tokens: int = 0 """Input of the last API call in the turn (fresh + cached + written to cache) - the context size the model actually ran with, what Claude Code shows as the context. The token fields above are sums over every API call of the turn and grow with the number of tool calls.""" @dataclass class TurnCapture: synthesized_messages: list[dict[str, Any]] = field(default_factory=list) """The assistant/tool_result cycle of the turn as Anthropic messages.""" session_id: str | None = None """Backend session that ran the turn; persist and pass back as ``session_id``.""" usage: TurnUsage | None = None interrupted: bool = False """The turn was cut by ``interrupt()`` (urgent inject), not by an error."""