"""First-class Pydantic provenance stamp. Provenance is authoritative framework data — **independent** of MAF's ``Annotation`` type, which silently drops on the Python streaming path (#4316, research 02 Dim 2). A ``ProvenanceStamp`` is a Pydantic model that must carry at least one ``Citation`` (a ``min_length=1`` constraint), the model + role that produced the proposal, the validator's decision, and the token usage. ``to_annotations()`` maps to MAF ``Annotation`` dicts for DISPLAY only — never the source of truth. The locator type (``TextSpan``) is owned by ``retrieval.py`` (Step 5) and imported here, so a citation's span is the same exact object the retriever produced. """ from __future__ import annotations from typing import Literal from agent_framework import Annotation, TextSpanRegion from pydantic import BaseModel, Field from portfolio_optimiser.retrieval import TextSpan class Citation(BaseModel): """One exact-span citation into a source document (locator owned by retrieval.py).""" file: str locator: TextSpan snippet: str class ExternalCall(BaseModel): """One external service call a run actually made (Trekk B4). **What this is evidence of, and what it is not.** It records that ``tool`` was invoked and which configured ``server`` it belongs to. It is NOT evidence that the service's answer reached the proposal, and it is not a verified rendering of what the service returned — the framework hands the answer to the agent, and what the agent does with it is the agent's. Reading this as "the figure came from the price register" would claim more than the record supports. ``server`` is ``""`` when the tool name cannot be attributed to exactly one configured server. MEASURED against a real MCP stdio subprocess: MAF passes the BARE tool name to function middleware, with no server prefix, so two servers exposing one tool name are indistinguishable at this seam. Unattributed is the honest answer there; naming the first match would put a service in the record that may never have been contacted. """ server: str tool: str class ProvenanceStamp(BaseModel): """Authoritative provenance for one proposal — at least one citation is mandatory.""" citations: list[Citation] = Field(min_length=1) model: str role: str validator_decision: Literal["validated", "rejected"] token_usage: int #: External service calls the run made (B4). EMPTY is a positive statement — "nothing outside #: this process was contacted" — not an absent field, which is why it is always serialized. external_calls: list[ExternalCall] = Field(default_factory=list) def to_annotations(self) -> list[Annotation]: """Map to MAF ``Annotation`` dicts for display only (NOT the source of truth).""" return [ Annotation( type="citation", snippet=c.snippet, annotated_regions=[ TextSpanRegion( type="text_span", start_index=c.locator.start_index, end_index=c.locator.end_index, ) ], additional_properties={"file": c.file}, ) for c in self.citations ]