State And Public Types
The most important types are the ones your application reads, persists, or reacts to. This page focuses on those surfaces.
SmartState
SmartState is the main runtime state surface for smart agents.
type SmartState = {
messages: Message[];
toolHistory?: ToolExecution[];
toolHistoryArchived?: ToolExecution[];
summaries?: string[];
summaryRecords?: SummaryRecord[];
memoryFacts?: MemoryFact[];
plan?: {
version: number;
steps: PlanStepRecord[];
lastUpdated?: string;
adherenceScore?: number;
} | null;
planVersion?: number;
reflections?: ReflectionRecord[];
pendingApprovals?: PendingToolApproval[];
pendingUserQuestions?: PendingUserQuestion[];
ctx?: Record<string, any>;
}PendingUserQuestion
Populated when the model calls the built-in ask_user_question tool (enabled via humanInTheLoop.askUser). The run pauses with ctx.__awaitingUserQuestion set.
type UserQuestionOption = {
label: string;
value?: string; // defaults to label
description?: string;
preview?: string;
};
type UserQuestionItem = {
question: string;
header?: string; // short chip (max ~12 chars recommended)
multiSelect?: boolean; // default false
placeholder?: string;
options?: UserQuestionOption[];
required?: boolean; // default true
};
type PendingUserQuestion = {
id: string;
toolCallId: string;
toolName: "ask_user_question";
questions: UserQuestionItem[];
status: "pending" | "answered" | "cancelled" | "executed";
requestedAt: string;
answeredAt?: string;
answeredBy?: string;
answers?: UserQuestionAnswerSet;
cancelled?: boolean;
notes?: string;
allowFreeText?: boolean; // snapshot of the global flag at request time
metadata?: Record<string, any>;
};UserQuestionResolution
Passed to agent.resolveUserQuestion(state, resolution):
type UserQuestionAnswer = {
values: string[]; // selected option values; single-select questions get one entry
freeText?: string; // only valid when allowFreeText is true
notes?: string;
};
type UserQuestionAnswerSet = Record<string /* question text */, UserQuestionAnswer>;
type UserQuestionResolution = {
id: string; // PendingUserQuestion.id or toolCallId
answers?: UserQuestionAnswerSet;
answeredBy?: string;
notes?: string;
cancelled?: boolean;
};UserQuestionEvent
Emitted by the runtime when the model invokes ask_user_question. Subscribe through invoke({ onEvent }) or the humanInTheLoop.askUser.onQuestion shortcut.
type UserQuestionEvent = {
type: "user_question";
status: "pending" | "answered" | "cancelled";
id: string;
toolCallId: string;
questions?: UserQuestionItem[];
answers?: UserQuestionAnswerSet;
answeredBy?: string;
allowFreeText?: boolean;
};ReasoningConfig
Both createAgent(...) and createSmartAgent(...) accept a unified reasoning surface:
type ReasoningConfig = {
enabled?: boolean;
level?: "low" | "medium" | "high";
native?: {
effort?: "minimal" | "low" | "medium" | "high";
budgetTokens?: number;
includeThoughts?: boolean;
providerExtras?: Record<string, any>;
} | false;
reflection?: {
enabled?: boolean;
cadence?: "off" | "every_turn" | "after_tool" | "on_branch";
mode?: "piggyback" | "separate";
maxTokens?: number;
maxChars?: number;
keepLast?: number;
summarize?: boolean;
promptTemplate?: string;
emitEvents?: boolean;
maxPerRun?: number; // cap total reflections in a single invoke
everyNTurns?: number; // minimum tool turns between reflections (default 1)
} | false;
}nativeconfigures provider-specific reasoning/thinking fields.reflectioncreates short post-tool text notes without adding normal assistant turns.reflection.maxPerRunandreflection.everyNTurnscap reflection cost in long tool-heavy invokes.- Explicit sub-fields always win over
levelpresets.
ReflectionRecord
type ReflectionRecord = {
id: string;
turn: number;
text: string;
createdAt: string;
durationMs?: number;
anchorMessageIndex?: number;
trigger?: "off" | "every_turn" | "after_tool" | "on_branch";
usage?: {
inputTokens?: number;
outputTokens?: number;
cachedInputTokens?: number;
totalTokens?: number;
reasoningTokens?: number;
};
toolCallIds?: string[];
}Reflection records live on state.reflections. They are intended for persistence, timelines, and operator review rather than direct user rendering.
ReflectionEvent
type ReflectionEvent = {
type: "reflection";
id: string;
turn: number;
text: string;
trigger?: "off" | "every_turn" | "after_tool" | "on_branch";
durationMs?: number;
usage?: {
inputTokens?: number;
outputTokens?: number;
cachedInputTokens?: number;
totalTokens?: number;
reasoningTokens?: number;
};
toolCallIds?: string[];
}SmartAgentEvent includes ReflectionEvent alongside plan, tool-call, summarization, handoff, and final-answer events.
PlanStepRecord
type PlanStepRecord = {
id: number;
step: string;
owner: "agent" | "user" | "tool" | string;
exitCriteria: string;
evidence?: string;
status: "not-started" | "in-progress" | "completed" | "blocked";
title?: string;
description?: string;
}The smart runtime stores the current plan on state.plan. The event payload still uses todoList for compatibility.
PlanEvent
type PlanEvent = {
type: "plan";
source: "manage_todo_list" | "system";
operation?: "read" | "write" | "update";
todoList?: PlanStepRecord[];
version?: number;
adherenceScore?: number;
}Remember the distinction:
state.planis durable runtime stateevent.todoListis an event payload
Profiles and limits
type BuiltInRuntimeProfile = "fast" | "balanced" | "deep" | "research";
type RuntimeProfile = BuiltInRuntimeProfile | "custom";
type AgentLimits = {
maxToolCalls?: number; // tool budget for the whole invoke
maxParallelTools?: number; // concurrent non-approval tools per turn
maxContextTokens?: number; // approx ceiling for model-facing context
maxTotalOutputTokens?: number; // cumulative model output token budget
maxCostUsd?: number; // cumulative USD cost — needs costEstimator
maxWallClockMs?: number; // total wall-clock budget for the invoke
}AgentOptions and SmartAgentOptions additionally expose:
type AgentOptions = {
// ... model, tools, limits, tracing, reasoning, ...
tokenCounter?: (text: string) => number;
costEstimator?: (args: {
modelName?: string;
inputTokens: number;
outputTokens: number;
cachedInputTokens?: number;
reasoningTokens?: number;
}) => number;
};tokenCounterswaps the built-in character heuristic for a real tokenizer (tiktoken,@anthropic-ai/tokenizer, …) for the duration of a singleinvoke(...).costEstimatoris required formaxCostUsdto take effect. The SDK has no built-in pricing table.
If you are building a configurable product, these are usually the first types you expose to your own application config layer.
Snapshot and restore
Snapshots matter if your agents pause, resume, or move through human approval workflows.
At a conceptual level:
snapshot(...)captures serializable runtime stateresume(...)restores and continues execution- disallowed callback-like keys are stripped from
ctx
Tracing config
type TracingConfig = {
enabled: boolean;
mode?: "batched" | "streaming";
threadId?: string;
logData?: boolean;
sink?: TraceSinkConfig;
}Supported sink families:
- file
- http
- cognipeer
- otlp
- custom
Degraded trace runs may finalize as status: "partial" when one or more sinks fail but the session still completes.