symfonic.kernel.contracts.values¶
values ¶
Kernel-native invocation values — the vocabulary the loop actually speaks.
Everything here is a frozen dataclass built from the standard library alone.
That is the whole point of the module: the invocation loop is written against
these types, so it never learns a wire format, a provider SDK, or a
serialization library. LangChain messages, pydantic results, and provider
responses live on the far side of the ports in :mod:.ports, and the adapter
that implements those ports is the only code that knows both vocabularies.
InvocationOutcome
dataclass
¶
InvocationOutcome(text: str, output: Any = None, messages: tuple[Any, ...] = (), tool_outcomes: tuple[Any, ...] = (), usage: UsageDelta = UsageDelta(), run_id: str = '', duration_ms: float = 0.0, stop_reason: str | None = None)
Everything one invocation produced, before result-shape adaptation.
messages and tool_outcomes are opaque to the kernel: it collects
and orders them, and the bound response port decides what they look like to
an adopter. That split is why T2.3.3 can change the public result shape
without touching the loop.
KernelEvent
dataclass
¶
KernelEvent(kind: str, index: int, run_id: str, text: str | None = None, tool_request: ToolRequest | None = None, tool_outcome: Any = None, outcome: InvocationOutcome | None = None, error: str | None = None, stage_id: str | None = None, phase: str | None = None, capability: str | None = None, stage_outcome: str | None = None, stage_reason: str | None = None, counts: Mapping[str, int] = (lambda: EMPTY_COUNTS)(), dropped_kind: str | None = None, dropped_count: int = 0, first_dropped_index: int | None = None, last_dropped_index: int | None = None, termination: str | None = None, interrupt: PendingInterrupt | None = None)
One event on the single internal pipeline (CADR-10, EVT-1…EVT-10).
index is dense and monotonic within a run, and the kernel is the only
thing that assigns it — an adapter that renumbered events would break the
ordering guarantee every consumer joins on.
ModelTurn
dataclass
¶
ModelTurn(text: str = '', tool_requests: tuple[ToolRequest, ...] = (), usage: UsageDelta = UsageDelta(), stop_reason: str | None = None, payload: Any = None)
One completed provider round, in kernel vocabulary.
payload is the adapter's own object — the raw provider message, or
whatever else it needs back when the kernel asks it to record the round.
The kernel carries it and never reads it: a field the loop cannot inspect
is a field the loop cannot come to depend on.
PromptAssembly
dataclass
¶
PromptAssembly(instructions: str | None, prompt: str, attachments: tuple[Any, ...] = (), history: tuple[Any, ...] = (), system_blocks: tuple[Any, ...] = ())
The output of the prompt-assembly phase (STG-7: a pure function).
It is a value, not a side effect, precisely so the phase stays pure and the assembled prompt is reproducible from the plan and the request alone.
ToolRequest
dataclass
¶
ToolRequest(call_id: str, name: str, arguments: Mapping[str, Any] = (lambda: MappingProxyType({}))())
One tool the model asked for, with a kernel-owned join key.
call_id is assigned by the kernel, not trusted from the provider:
providers omit ids and reuse them across rounds, and an ambiguous join key
between a tool_call and its tool_result is not a defect a consumer
can work around (RES-3).
TurnRequest
dataclass
¶
TurnRequest(prompt: str, attachments: tuple[Any, ...] = (), history: tuple[Any, ...] = (), run_id: str = '', root_run_id: str = '', parent_run_id: str | None = None, session_id: str = '', scope: Any = None, properties: Mapping[str, Any] = (lambda: EMPTY_PROPERTIES)())
The caller's half of an invocation: prompt, attachments, history.
Instructions are deliberately absent. They are a plan decision (the
kernel-owned kernel.prompt stage carries them), so a caller cannot
change the system prompt per call without recompiling — which is IPL-1's
compile-once rule expressed in a signature.
UsageDelta
dataclass
¶
UsageDelta(input_tokens: int = 0, output_tokens: int = 0, total_tokens: int = 0, cache_read_tokens: int = 0, cache_creation_tokens: int = 0, reasoning_tokens: int = 0, cache_ttl: str | None = None)
What one provider round reported (RES-4).
0 means unreported, never free: the kernel adds what it is told and
estimates nothing, so a silent provider leaves the zero value standing.