core/generate/result.py
Shay 216a789808
Fix identity gating and vault telemetry
- calibrate identity threshold and per-axis telemetry
- keep walk surfaces visible when identity flags are telemetry
- report real vault recall hits through generation/runtime logs
- record selected surface in TurnEvent
- fix async chat persona reference
- add regression coverage for chat telemetry
2026-05-14 15:44:01 -07:00

42 lines
1.7 KiB
Python

"""
GenerationResult — the complete output of one generation pass.
Generate() must return the evolved field state, not only surface tokens.
The field state after generation is semantically different from the
field state before generation; discarding it means the vault stores
the prompt field, not the assistant response field.
Contracts:
tokens — the decoded token sequence in emission order
final_state — FieldState after the last propagation step
trajectory — optional ordered list of intermediate FieldStates;
None unless the caller explicitly requests it (expensive)
vault_hits — exact number of vault recall hits applied during generation
identity_score — IdentityScore from IdentityCheck; None if not evaluated
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
from field.state import FieldState
@dataclass(frozen=True, slots=True)
class GenerationResult:
tokens: tuple # decoded token sequence, immutable
final_state: FieldState
trajectory: tuple | None = None # (FieldState, ...) or None
salience_top_k: int | None = None
candidates_used: int | None = None
vault_hits: int = 0
identity_score: Optional[object] = None # IdentityScore | None
def __post_init__(self) -> None:
# Coerce list inputs to tuple for immutability.
object.__setattr__(self, "tokens", tuple(self.tokens))
if self.trajectory is not None:
object.__setattr__(self, "trajectory", tuple(self.trajectory))
def text(self, sep: str = " ") -> str:
"""Join tokens into a string for display."""
return sep.join(self.tokens)