symfonic.agent.backend.provider_history¶
provider_history ¶
What one completed round leaves on the wire for the provider's next call.
turn.payload is the round as the provider produced it, and reply receipts
bind it by identity (Transcript._record_successful_reply). So nothing here
mutates or replaces it: the wire gets its own message, and only when the
provider's object is not already the one legacy would replay.
Two things differ from the payload, both toward what the legacy body sends:
- A streamed round aggregates to an
AIMessageChunk. Legacy replays theAIMessageLangChain'sgenerate_from_streambuilds from that same aggregate, through the same :func:message_chunk_to_message. - A tool observation carries
name=<tool>, as LangGraph'sToolNodewrites it. Some serializers read it (Gemini names itsFunctionResponsefromToolMessage.namefirst). The name is correlated from the assistant reply's tool call with the same id, never stored onMessage.
names_by_call_id ¶
Tool name per call id, from LangChain call dicts or facade ToolCalls.
Source code in src/symfonic/agent/backend/provider_history.py
replayed_reply ¶
The assistant reply as the provider history carries it.
call_ids remaps tool call ids onto the facade's; None is a round
that requested no tool. A payload that is not a chunk is returned as is
when its ids already match, so an invoked reply stays the same object.
Source code in src/symfonic/agent/backend/provider_history.py
tool_observations ¶
Each tool outcome as the ToolMessage the provider is handed back.
name comes from reply's call with the outcome's id; an outcome no
call names keeps None, which is what it carried before. Failed or
refused calls remain errors on the provider wire.