Skip to main content

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

LifecycleWhat it meansExamples
inputSet once by the caller at turn startmessage, user_id, channel
reducerAnnotated with a reducer; survives the turn and accumulates across turns via the checkpointerhistory, session_progress, exercise_state, diagnostics
loadedRe-fetched each turn from the memory storeworking_memory, procedural_profile.*
turn-scopedFresh each turn, last-write-winscrisis, 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

inputSet once by the caller at turn start.reducerAnnotated with a reducer — accumulates across turns via the checkpointer.turn-scopedFresh each turn. Last-write-wins.loadedRe-fetched each turn from the memory store.
messagestr

Current user message being processed.

inputset by caller
channelChannel

Transport surface: TEST, WEB, VOICE.

inputset by caller
user_idstr | None

Persistent owner. resolve_owner_id() namespaces memory by this; mandatory if session_id is absent.

inputset by caller
session_idstr | None

Thread identifier used by persistence and as a fallback memory owner.

inputset by caller
installed_skillslist[str]

Skill names resolved into prompt behavior by the runtime.

inputset by caller
historyAnnotated[list[dict], operator.add]

build_initial_state emits [user_turn]; turn finalization emits [assistant_turn]. The checkpointer accumulates prior turns automatically.

reduceroperator.addset by build_initial_state + turn finalization
transcriptAnnotated[list[dict], operator.add]

Full durable conversation record. Same reducer as history — never reconstructs from scratch.

reduceroperator.addset by build_initial_state + finalize_turn
working_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.

loadedset by turn memory context
session_memoryAnnotated[SessionMemoryState, _merge_dicts]

Prompt-visible session continuity: summary, active_concerns, open_loops, current_goal.

reducer_merge_dictsset by turn memory context
procedural_profile.procedural_ruleslist[str]

Style directives that shape every reply. Always applied — the recall toggle is content-recall only.

reducerset by turn memory context
procedural_profile.proactive_recall_enabledbool

Whether the agent may proactively reference recalled content. Procedural rules apply regardless.

reducerset by turn memory context
session_progressAnnotated[SessionProgressState, _merge_dicts]

Turn-count continuity. The merge reducer preserves checkpointed counters and sibling flags.

reducer_merge_dictsset by build_initial_state
session_progress.turn_countint

Persistent callers derive from checkpoint; one-shot callers count from history.

reducerset by build_initial_state
exercise_stateAnnotated[ExerciseState, _merge_dicts]

Active guided-exercise continuity. Cleared by runtime logic when the user exits or the exercise completes.

reducer_merge_dictsset by guided exercise flow + triage
exercise_state.exercise_typestr | None

Active exercise identifier (e.g., "grounding_5_4_3_2_1").

reducerset by guided exercise flow
exercise_state.exercise_stepint | None

Current step index. Cleared when the exercise completes or the user exits.

reducerset by guided exercise flow
exercise_state.exercise_therapeutic_approachstr | None

Approach 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.

reducerset by guided exercise flow + triage
memory_control.pending_actiondict | None

Carries a destructive memory action across turns so the next reply can confirm or cancel without LLM inference.

reducer_merge_dictsset by memory-control service
crisisCrisisAssessment

level (0–3), confidence, reason, needs_crisis_response, needs_clarification.

turn-scopedset by crisis gate
crisis_auditCrisisAuditState

Classifier provenance: override_kind, classifier_path (llm_primary), llm_failure_occurred. Read by crisis logging.

turn-scopedset by crisis gate
routestr

"crisis" / "therapeutic" / "memory_control" / "grounded_lookup". Drives extractor skip logic.

turn-scopedset by crisis_gate + turn_dispatch
response_textstr

Generated reply for the turn.

turn-scopedset by reply node (response style / crisis_response / memory_control / grounded_answer)
response_stylestr

supportive · reflective · clarifying · psychoeducation · technique · guided_exercise · closing · safety_check · crisis_response · memory_control · grounded_lookup

turn-scopedset by reply node + gates
therapeutic_approachstr | None

motivational_interviewing · cbt · act · dbt_skills · grief_support · interpersonal_therapy · pfa · none

turn-scopedset by TherapeuticAgent
should_persist_memorybool

Set on exercise completion as a hint that the turn is worth summarizing.

turn-scopedset by guided exercise flow
memory_control.actiondict

Detected memory command (kind, args). Consumed by the memory-control service.

turn-scopedset by turn triage
grounded_lookup.querystr

Factual query extracted by triage. Consumed by the grounded lookup tool.

turn-scopedset by turn triage
grounded_lookup.statusstr

answered · no_verified_answer · not_attempted

turn-scopedset by grounded lookup tool
inferred_locationstr

Region extracted from recent context for hotline lookup.

turn-scopedset by crisis resource lookup
found_resourceslist[dict]

Verified hotlines (name / phone / website / region). Empty on failure or missing location.

turn-scopedset by crisis resource lookup
resource_lookup_statusstr

found · no_location · location_refused · no_verified_results · not_attempted

turn-scopedset by crisis resource lookup
diagnosticsAnnotated[dict, _merge_dicts]

Timing, routing, and retrieval metadata.

reducer_merge_dictsset by runtime stages + services
diagnostics.crisis_gate_ms · crisis_classifier_pathfloat · str

Time spent classifying + which path decided it.

reducerset by crisis gate
diagnostics.load_memory_ms · retrieval_pathfloat · str

Retrieval time + which path ran (hybrid_rrf / token_recall / token_recall_after_embed_error).

reducerset by turn memory context
diagnostics.turn_total_msfloat

Total turn wall-clock, stamped outside the graph.

reducerset by runtime

Working memory

working_memory is a list of structured dicts, not pre-formatted strings. Two entry types:

TypeKey fieldsRenders as
SemanticWorkingMemoryEntryevidence_quote, category, subject, predicate, object[relationship] User WORRIES_ABOUT work — "my boss is terrible"
EpisodicWorkingMemoryEntrysummary, primary_themes, is_catch_up, approach_used, approach_contextLast 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.

ModelPublic fields
AgentInputmessage, channel, user_id, session_id, history, working_memory, installed_skills
AgentOutputresponse_text, response_type, crisis, response_style, response_style_type, response_style_source, therapeutic_approach, should_persist_memory, diagnostics
CrisisAssessmentlevel (0–3), confidence, reason, needs_crisis_response, needs_clarification
Messagerole, 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.

FieldTypeDefault
llm_clientBaseLLMClient | Nonerequired
memory_storeMemoryStorerequired
crisis_log_backendCrisisLogBackendrequired
memory_modeMemoryModerequired
response_llmBaseLLMClient | NoneNone
embedding_providerEmbeddingProvider | NoneNone
session_memory_bufferSessionMemoryBuffer | NoneNone

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:

SchemaUsed as
AgentGraphInputStateInput — what build_initial_state() emits
AgentStateInternal — the full union, used by every node
AgentGraphOutputStateOutput — 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

FileDefines
agent/state.pyAll TypedDict fragments and the AgentGraphInputState / AgentState / AgentGraphOutputState schemas
agent/memory/entries.pyWorkingMemoryEntry types and format_working_memory_entry/entries()
agent/models.pyAgentInput, AgentOutput, Message, CrisisAssessment, Channel, MessageRole, ResponseCategory, ResponseStyleType, stream events, STAGE_LABELS
agent/audit/models.pyCrisisOverrideOutcome and CrisisClassifierPath (used inside CrisisAuditState), plus CrisisLogRecord and feedback types
agent/runtime/turn.pybuild_initial_state() (input → state) and state_to_output() (state → output)
agent/runtime/workflow_context.pyWorkflowContext frozen dataclass — runtime dependencies via runtime.context