Log and transcript fields
A stateful agent needs more than slots. It needs a transcript of what has been said, plus a stage label that describes where the conversation is right now. Both live inside the same TypedDict, and together they make the graph observable and testable.
def _append_message(state: BookingState, role: str, content: str) -> None:
messages = state.get("messages") or []
messages.append({"role": role, "content": content})
state["messages"] = messagesThe transcript is a list of role/content dicts, exactly the shape most chat completion APIs already expect. Appending is a helper so every node reads and writes it the same way.
Flashcards: Flashcards
Loading practice…
async def chat(self, thread_id: str, user_message: str) -> Dict[str, Any]:
"""Run one turn through the graph. MemorySaver resumes prior state."""
config = {"configurable": {"thread_id": thread_id}}
turn_input: Dict[str, Any] = {
"user_message": user_message,
"thread_id": thread_id,
}
# Append the user message to running transcript.
prior = self._graph.get_state(config)
prior_messages = []
if prior and prior.values:
prior_messages = list(prior.values.get("messages") or [])
prior_messages.append({"role": "user", "content": user_message})
turn_input["messages"] = prior_messages
result = await self._graph.ainvoke(turn_input, config=config)Every chat turn pulls the prior transcript from the checkpointer, appends the new user message, invokes the graph, and lets the nodes write their reply back into state.
Quiz: Quiz
Loading practice…