Agent State
One AgentState dict is the app-owned turn snapshot. Runtime stages
read from it and return partial deltas; reducer-backed fields
accumulate across turns, while ordinary fields are last-write-wins.
Mental model
| Lifecycle | What it means | Examples |
|---|---|---|
| input | Set once by the caller at turn start | message, user_id, channel |
| reducer | Annotated with a reducer; survives the turn and accumulates across turns via the checkpointer | history, session_progress, exercise_state, diagnostics |
| loaded | Re-fetched each turn from the memory store | working_memory, procedural_profile.* |
| turn-scoped | Fresh each turn, last-write-wins | crisis, route, response_text |
That's the whole story. The interactive table below splits the schema into nine groups and tags every field with one of these four labels — click a section to expand it.
Field reference
messagestrCurrent user message being processed.
callerchannelChannelTransport surface: TEST, WEB, VOICE.
calleruser_idstr | NonePersistent owner. resolve_owner_id() namespaces memory by this; mandatory if session_id is absent.
callersession_idstr | NoneThread identifier used by persistence and as a fallback memory owner.
callerinstalled_skillslist[str]Skill names resolved into prompt behavior by the runtime.
callerhistoryAnnotated[list[dict], operator.add]build_initial_state emits [user_turn]; turn finalization emits [assistant_turn]. The checkpointer accumulates prior turns automatically.
build_initial_state + turn finalizationtranscriptAnnotated[list[dict], operator.add]Full durable conversation record. Same reducer as history — never reconstructs from scratch.
build_initial_state + finalize_turnworking_memorylist[WorkingMemoryEntry]SemanticWorkingMemoryEntry (category/subject/predicate/object + evidence_quote) and EpisodicWorkingMemoryEntry (summary, themes, is_catch_up, approach_used). Formatted on demand at prompt-build time.
turn memory contextsession_memoryAnnotated[SessionMemoryState, _merge_dicts]Prompt-visible session continuity: summary, active_concerns, open_loops, current_goal.
turn memory contextprocedural_profile.procedural_ruleslist[str]Style directives that shape every reply. Always applied — the recall toggle is content-recall only.
turn memory contextprocedural_profile.proactive_recall_enabledboolWhether the agent may proactively reference recalled content. Procedural rules apply regardless.
turn memory contextsession_progressAnnotated[SessionProgressState, _merge_dicts]Turn-count continuity. The merge reducer preserves checkpointed counters and sibling flags.
build_initial_statesession_progress.turn_countintPersistent callers derive from checkpoint; one-shot callers count from history.
build_initial_stateexercise_stateAnnotated[ExerciseState, _merge_dicts]Active guided-exercise continuity. Cleared by runtime logic when the user exits or the exercise completes.
guided exercise flow + triageexercise_state.exercise_typestr | NoneActive exercise identifier (e.g., "grounding_5_4_3_2_1").
guided exercise flowexercise_state.exercise_stepint | NoneCurrent step index. Cleared when the exercise completes or the user exits.
guided exercise flowexercise_state.exercise_therapeutic_approachstr | NoneApproach pinned at exercise start. Reused when guidance resumes and for narrow clarifying side-turns; psychoeducation side-turns keep the exercise active but may use a fresh top-level approach.
guided exercise flow + triagememory_control.pending_actiondict | NoneCarries a destructive memory action across turns so the next reply can confirm or cancel without LLM inference.
memory-control servicecrisisCrisisAssessmentlevel (0–3), confidence, reason, needs_crisis_response, needs_clarification.
crisis gatecrisis_auditCrisisAuditStateClassifier provenance: override_kind, classifier_path (llm_primary), llm_failure_occurred. Read by crisis logging.
crisis gateroutestr"crisis" / "therapeutic" / "memory_control" / "grounded_lookup". Drives extractor skip logic.
crisis_gate + turn_dispatchresponse_textstrGenerated reply for the turn.
reply node (response style / crisis_response / memory_control / grounded_answer)response_stylestrsupportive · reflective · clarifying · psychoeducation · technique · guided_exercise · closing · safety_check · crisis_response · memory_control · grounded_lookup
reply node + gatestherapeutic_approachstr | Nonemotivational_interviewing · cbt · act · dbt_skills · grief_support · interpersonal_therapy · pfa · none
TherapeuticAgentshould_persist_memoryboolSet on exercise completion as a hint that the turn is worth summarizing.
guided exercise flowmemory_control.actiondictDetected memory command (kind, args). Consumed by the memory-control service.
turn triagegrounded_lookup.querystrFactual query extracted by triage. Consumed by the grounded lookup tool.
turn triagegrounded_lookup.statusstranswered · no_verified_answer · not_attempted
grounded lookup toolinferred_locationstrRegion extracted from recent context for hotline lookup.
crisis resource lookupfound_resourceslist[dict]Verified hotlines (name / phone / website / region). Empty on failure or missing location.
crisis resource lookupresource_lookup_statusstrfound · no_location · location_refused · no_verified_results · not_attempted
crisis resource lookupdiagnosticsAnnotated[dict, _merge_dicts]Timing, routing, and retrieval metadata.
runtime stages + servicesdiagnostics.crisis_gate_ms · crisis_classifier_pathfloat · strTime spent classifying + which path decided it.
crisis gatediagnostics.load_memory_ms · retrieval_pathfloat · strRetrieval time + which path ran (hybrid_rrf / token_recall / token_recall_after_embed_error).
turn memory contextdiagnostics.turn_total_msfloatTotal turn wall-clock, stamped outside the graph.
runtimeWorking memory
working_memory is a list of structured dicts, not pre-formatted
strings. Two entry types:
| Type | Key fields | Renders as |
|---|---|---|
SemanticWorkingMemoryEntry | evidence_quote, category, subject, predicate, object | [relationship] User WORRIES_ABOUT work — "my boss is terrible" |
EpisodicWorkingMemoryEntry | summary, primary_themes, is_catch_up, approach_used, approach_context | Last session (grief): talked about loss after my dog died. |
Formatting via format_working_memory_entries() happens at three
surfaces only: the therapeutic prompt builder, the dispatcher
prompt, and the CLI's context panel. Legacy str entries from
older checkpoints pass through unchanged.
Public contract
The external API only sees AgentInput and AgentOutput — the
state itself is internal to the runtime.
| Model | Public fields |
|---|---|
AgentInput | message, channel, user_id, session_id, history, working_memory, installed_skills |
AgentOutput | response_text, response_type, crisis, response_style, response_style_type, response_style_source, therapeutic_approach, should_persist_memory, diagnostics |
CrisisAssessment | level (0–3), confidence, reason, needs_crisis_response, needs_clarification |
Message | role, content, response_style (optional — stamped onto assistant turns by turn finalization) |
Runtime context
Runtime dependencies live on WorkflowContext, not on the
state. It's a frozen dataclass injected via runtime.context —
attribute access only.
| Field | Type | Default |
|---|---|---|
llm_client | BaseLLMClient | None | required |
memory_store | MemoryStore | required |
crisis_log_backend | CrisisLogBackend | required |
memory_mode | MemoryMode | required |
response_llm | BaseLLMClient | None | None |
embedding_provider | EmbeddingProvider | None | None |
session_memory_buffer | SessionMemoryBuffer | None | None |
session_memory_buffer is set by PersistentAgentRuntime so that
session-end candidates can be carried in a per-thread buffer that
persists across restarts.
Schema implementation detail
The schema is built from six TypedDict fragments — AgentIdentityState,
AgentConversationState, AgentPersistentState, AgentCrisisState,
AgentGraphOutputState, and AgentPrivateState. The runtime declares
three views over them:
| Schema | Used as |
|---|---|
AgentGraphInputState | Input — what build_initial_state() emits |
AgentState | Internal — the full union, used by every node |
AgentGraphOutputState | Output — what state_to_output() reads back |
You don't need to think about the fragments to use the agent — they exist so the runtime can keep input, internal state, and public output boundaries explicit.
Key files
| File | Defines |
|---|---|
agent/state.py | All TypedDict fragments and the AgentGraphInputState / AgentState / AgentGraphOutputState schemas |
agent/memory/entries.py | WorkingMemoryEntry types and format_working_memory_entry/entries() |
agent/models.py | AgentInput, AgentOutput, Message, CrisisAssessment, Channel, MessageRole, ResponseCategory, ResponseStyleType, stream events, STAGE_LABELS |
agent/audit/models.py | CrisisOverrideOutcome and CrisisClassifierPath (used inside CrisisAuditState), plus CrisisLogRecord and feedback types |
agent/runtime/turn.py | build_initial_state() (input → state) and state_to_output() (state → output) |
agent/runtime/workflow_context.py | WorkflowContext frozen dataclass — runtime dependencies via runtime.context |