@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
1,028 lines • 42.4 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunState = exports.SerializedRunState = exports.CURRENT_SCHEMA_VERSION = void 0;
exports.buildAgentMap = buildAgentMap;
exports.deserializeSpan = deserializeSpan;
exports.deserializeModelResponse = deserializeModelResponse;
exports.deserializeItem = deserializeItem;
const zod_1 = require("zod");
const agent_1 = require("./agent.js");
const agentToolSourceRegistry_1 = require("./agentToolSourceRegistry.js");
const items_1 = require("./items.js");
const runContext_1 = require("./runContext.js");
const items_2 = require("./runner/items.js");
const toolUseTracker_1 = require("./runner/toolUseTracker.js");
const steps_1 = require("./runner/steps.js");
const errors_1 = require("./errors.js");
const provider_1 = require("./tracing/provider.js");
const usage_1 = require("./usage.js");
const tracing_1 = require("./tracing/index.js");
const logger_1 = __importDefault(require("./logger.js"));
const handoff_1 = require("./handoff.js");
const protocol = __importStar(require("./types/protocol.js"));
const safeExecute_1 = require("./utils/safeExecute.js");
/**
* The schema version of the serialized run state. This is used to ensure that the serialized
* run state is compatible with the current version of the SDK.
* If anything in this schema changes, the version will have to be incremented.
*
* Version history.
* - 1.0: Initial serialized RunState schema.
* - 1.1: Adds optional currentTurnInProgress, conversationId, and previousResponseId fields,
* plus broader tool_call_output_item rawItem variants for non-function tools. Older 1.0
* payloads remain readable but resumes may lack mid-turn or server-managed context precision.
* - 1.2: Adds pendingAgentToolRuns for nested agent tool resumption.
* - 1.3: Adds computer tool approval items to serialized tool_approval_item unions.
* - 1.4: Adds optional toolInput to serialized run context.
* - 1.5: Adds optional reasoningItemIdPolicy to preserve reasoning input policy across resume.
*/
exports.CURRENT_SCHEMA_VERSION = '1.5';
const SUPPORTED_SCHEMA_VERSIONS = [
'1.0',
'1.1',
'1.2',
'1.3',
'1.4',
exports.CURRENT_SCHEMA_VERSION,
];
const $schemaVersion = zod_1.z.enum(SUPPORTED_SCHEMA_VERSIONS);
const serializedAgentSchema = zod_1.z.object({
name: zod_1.z.string(),
});
const serializedSpanBase = zod_1.z.object({
object: zod_1.z.literal('trace.span'),
id: zod_1.z.string(),
trace_id: zod_1.z.string(),
parent_id: zod_1.z.string().nullable(),
started_at: zod_1.z.string().nullable(),
ended_at: zod_1.z.string().nullable(),
error: zod_1.z
.object({
message: zod_1.z.string(),
data: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
})
.nullable(),
span_data: zod_1.z.record(zod_1.z.string(), zod_1.z.any()),
});
const SerializedSpan = serializedSpanBase.extend({
previous_span: zod_1.z.lazy(() => SerializedSpan).optional(),
});
const requestUsageSchema = zod_1.z.object({
inputTokens: zod_1.z.number(),
outputTokens: zod_1.z.number(),
totalTokens: zod_1.z.number(),
inputTokensDetails: zod_1.z.record(zod_1.z.string(), zod_1.z.number()).optional(),
outputTokensDetails: zod_1.z.record(zod_1.z.string(), zod_1.z.number()).optional(),
endpoint: zod_1.z.string().optional(),
});
const usageSchema = zod_1.z.object({
requests: zod_1.z.number(),
inputTokens: zod_1.z.number(),
outputTokens: zod_1.z.number(),
totalTokens: zod_1.z.number(),
inputTokensDetails: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.number())).optional(),
outputTokensDetails: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.number())).optional(),
requestUsageEntries: zod_1.z.array(requestUsageSchema).optional(),
});
const modelResponseSchema = zod_1.z.object({
usage: usageSchema,
output: zod_1.z.array(protocol.OutputModelItem),
responseId: zod_1.z.string().optional(),
providerData: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
});
const itemSchema = zod_1.z.discriminatedUnion('type', [
zod_1.z.object({
type: zod_1.z.literal('message_output_item'),
rawItem: protocol.AssistantMessageItem,
agent: serializedAgentSchema,
}),
zod_1.z.object({
type: zod_1.z.literal('tool_call_item'),
rawItem: protocol.ToolCallItem.or(protocol.HostedToolCallItem),
agent: serializedAgentSchema,
}),
zod_1.z.object({
type: zod_1.z.literal('tool_call_output_item'),
rawItem: protocol.FunctionCallResultItem.or(protocol.ComputerCallResultItem)
.or(protocol.ShellCallResultItem)
.or(protocol.ApplyPatchCallResultItem),
agent: serializedAgentSchema,
output: zod_1.z.string(),
}),
zod_1.z.object({
type: zod_1.z.literal('reasoning_item'),
rawItem: protocol.ReasoningItem,
agent: serializedAgentSchema,
}),
zod_1.z.object({
type: zod_1.z.literal('handoff_call_item'),
rawItem: protocol.FunctionCallItem,
agent: serializedAgentSchema,
}),
zod_1.z.object({
type: zod_1.z.literal('handoff_output_item'),
rawItem: protocol.FunctionCallResultItem,
sourceAgent: serializedAgentSchema,
targetAgent: serializedAgentSchema,
}),
zod_1.z.object({
type: zod_1.z.literal('tool_approval_item'),
rawItem: protocol.FunctionCallItem.or(protocol.HostedToolCallItem)
.or(protocol.ComputerUseCallItem)
.or(protocol.ShellCallItem)
.or(protocol.ApplyPatchCallItem),
agent: serializedAgentSchema,
toolName: zod_1.z.string().optional(),
}),
]);
const serializedTraceSchema = zod_1.z.object({
object: zod_1.z.literal('trace'),
id: zod_1.z.string(),
workflow_name: zod_1.z.string(),
group_id: zod_1.z.string().nullable(),
metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.any()),
// Populated only if the trace was created with a per-run tracingApiKey (e.g., Runner.run({ tracing: { apiKey } }))
// and serialization opts in to include it. By default this is omitted to avoid persisting secrets.
tracing_api_key: zod_1.z.string().optional().nullable(),
});
const serializedProcessedResponseSchema = zod_1.z.object({
newItems: zod_1.z.array(itemSchema),
toolsUsed: zod_1.z.array(zod_1.z.string()),
handoffs: zod_1.z.array(zod_1.z.object({
toolCall: zod_1.z.any(),
handoff: zod_1.z.any(),
})),
functions: zod_1.z.array(zod_1.z.object({
toolCall: zod_1.z.any(),
tool: zod_1.z.any(),
})),
computerActions: zod_1.z.array(zod_1.z.object({
toolCall: zod_1.z.any(),
computer: zod_1.z.any(),
})),
shellActions: zod_1.z
.array(zod_1.z.object({
toolCall: zod_1.z.any(),
shell: zod_1.z.any(),
}))
.optional(),
applyPatchActions: zod_1.z
.array(zod_1.z.object({
toolCall: zod_1.z.any(),
applyPatch: zod_1.z.any(),
}))
.optional(),
mcpApprovalRequests: zod_1.z
.array(zod_1.z.object({
requestItem: zod_1.z.object({
// protocol.HostedToolCallItem
rawItem: zod_1.z.object({
type: zod_1.z.literal('hosted_tool_call'),
name: zod_1.z.string(),
arguments: zod_1.z.string().optional(),
status: zod_1.z.string().optional(),
output: zod_1.z.string().optional(),
// this always exists but marked as optional for early version compatibility; when releasing 1.0, we can remove the nullable and optional
providerData: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).nullable().optional(),
}),
}),
// HostedMCPTool
mcpTool: zod_1.z.object({
type: zod_1.z.literal('hosted_tool'),
name: zod_1.z.literal('hosted_mcp'),
providerData: zod_1.z.record(zod_1.z.string(), zod_1.z.any()),
}),
}))
.optional(),
});
const guardrailFunctionOutputSchema = zod_1.z.object({
tripwireTriggered: zod_1.z.boolean(),
outputInfo: zod_1.z.any(),
});
const toolGuardrailBehaviorSchema = zod_1.z.discriminatedUnion('type', [
zod_1.z.object({ type: zod_1.z.literal('allow') }),
zod_1.z.object({
type: zod_1.z.literal('rejectContent'),
message: zod_1.z.string(),
}),
zod_1.z.object({ type: zod_1.z.literal('throwException') }),
]);
const toolGuardrailFunctionOutputSchema = zod_1.z.object({
outputInfo: zod_1.z.any().optional(),
behavior: toolGuardrailBehaviorSchema,
});
const toolGuardrailMetadataSchema = zod_1.z.object({
type: zod_1.z.union([zod_1.z.literal('tool_input'), zod_1.z.literal('tool_output')]),
name: zod_1.z.string(),
});
const inputGuardrailResultSchema = zod_1.z.object({
guardrail: zod_1.z.object({
type: zod_1.z.literal('input'),
name: zod_1.z.string(),
}),
output: guardrailFunctionOutputSchema,
});
const outputGuardrailResultSchema = zod_1.z.object({
guardrail: zod_1.z.object({
type: zod_1.z.literal('output'),
name: zod_1.z.string(),
}),
agentOutput: zod_1.z.any(),
agent: serializedAgentSchema,
output: guardrailFunctionOutputSchema,
});
const toolInputGuardrailResultSchema = zod_1.z.object({
guardrail: toolGuardrailMetadataSchema.extend({
type: zod_1.z.literal('tool_input'),
}),
output: toolGuardrailFunctionOutputSchema,
});
const toolOutputGuardrailResultSchema = zod_1.z.object({
guardrail: toolGuardrailMetadataSchema.extend({
type: zod_1.z.literal('tool_output'),
}),
output: toolGuardrailFunctionOutputSchema,
});
exports.SerializedRunState = zod_1.z.object({
$schemaVersion,
currentTurn: zod_1.z.number(),
currentAgent: serializedAgentSchema,
originalInput: zod_1.z.string().or(zod_1.z.array(protocol.ModelItem)),
modelResponses: zod_1.z.array(modelResponseSchema),
context: zod_1.z.object({
usage: usageSchema,
approvals: zod_1.z.record(zod_1.z.string(), zod_1.z.object({
approved: zod_1.z.array(zod_1.z.string()).or(zod_1.z.boolean()),
rejected: zod_1.z.array(zod_1.z.string()).or(zod_1.z.boolean()),
})),
context: zod_1.z.record(zod_1.z.string(), zod_1.z.any()),
toolInput: zod_1.z.any().optional(),
}),
toolUseTracker: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())),
maxTurns: zod_1.z.number(),
currentAgentSpan: SerializedSpan.nullable().optional(),
noActiveAgentRun: zod_1.z.boolean(),
inputGuardrailResults: zod_1.z.array(inputGuardrailResultSchema),
outputGuardrailResults: zod_1.z.array(outputGuardrailResultSchema),
toolInputGuardrailResults: zod_1.z
.array(toolInputGuardrailResultSchema)
.optional()
.default([]),
toolOutputGuardrailResults: zod_1.z
.array(toolOutputGuardrailResultSchema)
.optional()
.default([]),
currentTurnInProgress: zod_1.z.boolean().optional(),
currentStep: steps_1.nextStepSchema.optional(),
lastModelResponse: modelResponseSchema.optional(),
generatedItems: zod_1.z.array(itemSchema),
pendingAgentToolRuns: zod_1.z.record(zod_1.z.string(), zod_1.z.string()).optional().default({}),
lastProcessedResponse: serializedProcessedResponseSchema.optional(),
currentTurnPersistedItemCount: zod_1.z.number().int().min(0).optional(),
conversationId: zod_1.z.string().optional(),
previousResponseId: zod_1.z.string().optional(),
reasoningItemIdPolicy: zod_1.z.enum(['preserve', 'omit']).optional(),
trace: serializedTraceSchema.nullable(),
});
/**
* Serializable snapshot of an agent's run, including context, usage and trace.
* While this class has publicly writable properties (prefixed with `_`), they are not meant to be
* used directly. To read these properties, use the `RunResult` instead.
*
* Manipulation of the state directly can lead to unexpected behavior and should be avoided.
* Instead, use the `approve` and `reject` methods to interact with the state.
*/
class RunState {
/**
* Current turn number in the conversation.
*/
_currentTurn = 0;
/**
* Whether the current turn has already been counted (useful when resuming mid-turn).
*/
_currentTurnInProgress = false;
/**
* The agent currently handling the conversation.
*/
_currentAgent;
/**
* Original user input prior to any processing.
*/
_originalInput;
/**
* Responses from the model so far.
*/
_modelResponses;
/**
* Conversation identifier when the server manages conversation history.
*/
_conversationId;
/**
* Latest response identifier returned by the server for server-managed conversations.
*/
_previousResponseId;
/**
* Runtime options that control how run items are converted into model turn input.
* This value is serialized so resumed runs keep the same turn-input behavior.
*/
_reasoningItemIdPolicy;
/**
* Effective model settings used for the most recent model call.
*/
_lastModelSettings;
/**
* Active tracing span for the current agent if tracing is enabled.
*/
_currentAgentSpan;
/**
* Run context tracking approvals, usage, and other metadata.
*/
_context;
/**
* The usage aggregated for this run. This includes per-request breakdowns when available.
*/
get usage() {
return this._context.usage;
}
/**
* Tracks what tools each agent has used.
*/
_toolUseTracker;
/**
* Serialized pending nested agent runs keyed by tool name and call id.
*/
_pendingAgentToolRuns;
/**
* Items generated by the agent during the run.
*/
_generatedItems;
/**
* Number of `_generatedItems` already flushed to session storage for the current turn.
*
* Persisting the entire turn on every save would duplicate responses and tool outputs.
* Instead, `saveToSession` appends only the delta since the previous write. This counter
* tracks how many generated run items from *this turn* were already written so the next
* save can slice off only the new entries. When a turn is interrupted (e.g., awaiting tool
* approval) and later resumed, we rewind the counter before continuing so the pending tool
* output still gets stored.
*/
_currentTurnPersistedItemCount;
/**
* Maximum allowed turns before forcing termination.
*/
_maxTurns;
/**
* Whether the run has an active agent step in progress.
*/
_noActiveAgentRun = true;
/**
* Last model response for the previous turn.
*/
_lastTurnResponse;
/**
* Results from input guardrails applied to the run.
*/
_inputGuardrailResults;
/**
* Results from output guardrails applied to the run.
*/
_outputGuardrailResults;
/**
* Results from tool input guardrails applied during tool execution.
*/
_toolInputGuardrailResults;
/**
* Results from tool output guardrails applied during tool execution.
*/
_toolOutputGuardrailResults;
/**
* Next step computed for the agent to take.
*/
_currentStep = undefined;
/**
* Indicates how the final output was produced for the current run.
* This value is not serialized.
*/
_finalOutputSource;
/**
* Parsed model response after applying guardrails and tools.
*/
_lastProcessedResponse = undefined;
/**
* Trace associated with this run if tracing is enabled.
*/
_trace = null;
constructor(context, originalInput, startingAgent, maxTurns) {
this._context = context;
this._originalInput = structuredClone(originalInput);
this._modelResponses = [];
this._currentAgentSpan = undefined;
this._currentAgent = startingAgent;
this._reasoningItemIdPolicy = undefined;
this._toolUseTracker = new toolUseTracker_1.AgentToolUseTracker();
this._pendingAgentToolRuns = new Map();
this._generatedItems = [];
this._currentTurnPersistedItemCount = 0;
this._maxTurns = maxTurns;
this._inputGuardrailResults = [];
this._outputGuardrailResults = [];
this._toolInputGuardrailResults = [];
this._toolOutputGuardrailResults = [];
this._trace = (0, tracing_1.getCurrentTrace)();
}
/**
* Updates server-managed conversation identifiers as a single operation.
*/
setConversationContext(conversationId, previousResponseId) {
this._conversationId = conversationId;
this._previousResponseId = previousResponseId;
}
/**
* Updates runtime options for converting run items into turn input.
*/
setReasoningItemIdPolicy(policy) {
this._reasoningItemIdPolicy = policy;
}
/**
* Updates the agent span associated with the current run.
*/
setCurrentAgentSpan(span) {
this._currentAgentSpan = span;
}
/**
* Switches the active agent handling the run.
*/
setCurrentAgent(agent) {
this._currentAgent = agent;
}
/**
* Returns the agent currently handling the run.
*/
get currentAgent() {
return this._currentAgent;
}
/**
* Resets the counter that tracks how many items were persisted for the current turn.
*/
resetTurnPersistence() {
this._currentTurnPersistedItemCount = 0;
}
/**
* Rewinds the persisted item counter when pending approvals require re-writing outputs.
*/
rewindTurnPersistence(count) {
if (count <= 0) {
return;
}
this._currentTurnPersistedItemCount = Math.max(0, this._currentTurnPersistedItemCount - count);
}
/**
* The history of the agent run. This includes the input items and the new items generated during the run.
*
* This can be used as inputs for the next agent run.
*/
get history() {
return (0, items_2.getTurnInput)(this._originalInput, this._generatedItems, this._reasoningItemIdPolicy);
}
/**
* Returns all interruptions if the current step is an interruption otherwise returns an empty array.
*/
getInterruptions() {
if (this._currentStep?.type !== 'next_step_interruption') {
return [];
}
const interruptions = this._currentStep.data.interruptions;
return Array.isArray(interruptions)
? interruptions
: [];
}
getPendingAgentToolRunKey(toolName, callId) {
return `${toolName}:${callId}`;
}
getPendingAgentToolRun(toolName, callId) {
return this._pendingAgentToolRuns.get(this.getPendingAgentToolRunKey(toolName, callId));
}
hasPendingAgentToolRun(toolName, callId) {
return this._pendingAgentToolRuns.has(this.getPendingAgentToolRunKey(toolName, callId));
}
setPendingAgentToolRun(toolName, callId, serializedState) {
this._pendingAgentToolRuns.set(this.getPendingAgentToolRunKey(toolName, callId), serializedState);
}
clearPendingAgentToolRun(toolName, callId) {
this._pendingAgentToolRuns.delete(this.getPendingAgentToolRunKey(toolName, callId));
}
/**
* Approves a tool call requested by the agent through an interruption and approval item request.
*
* To approve the request use this method and then run the agent again with the same state object
* to continue the execution.
*
* By default it will only approve the current tool call. To allow the tool to be used multiple
* times throughout the run, set the `alwaysApprove` option to `true`.
*
* @param approvalItem - The tool call approval item to approve.
* @param options - Options for the approval.
*/
approve(approvalItem, options = { alwaysApprove: false }) {
this._context.approveTool(approvalItem, options);
}
/**
* Rejects a tool call requested by the agent through an interruption and approval item request.
*
* To reject the request use this method and then run the agent again with the same state object
* to continue the execution.
*
* By default it will only reject the current tool call. To allow the tool to be used multiple
* times throughout the run, set the `alwaysReject` option to `true`.
*
* @param approvalItem - The tool call approval item to reject.
* @param options - Options for the rejection.
*/
reject(approvalItem, options = { alwaysReject: false }) {
this._context.rejectTool(approvalItem, options);
}
/**
* Serializes the run state to a JSON object.
*
* This method is used to serialize the run state to a JSON object that can be used to
* resume the run later.
*
* @returns The serialized run state.
*/
/**
* Serializes the run state. By default, tracing API keys are omitted to prevent
* accidental persistence of secrets. Pass `includeTracingApiKey: true` only when you
* intentionally need to migrate a run along with its tracing credentials (e.g., to
* rehydrate in a separate process that lacks the original environment variables).
*/
toJSON(options = {}) {
const includeTracingApiKey = options.includeTracingApiKey === true;
const output = {
$schemaVersion: exports.CURRENT_SCHEMA_VERSION,
currentTurn: this._currentTurn,
currentAgent: {
name: this._currentAgent.name,
},
originalInput: this._originalInput,
modelResponses: this._modelResponses.map((response) => {
return {
usage: {
requests: response.usage.requests,
inputTokens: response.usage.inputTokens,
outputTokens: response.usage.outputTokens,
totalTokens: response.usage.totalTokens,
inputTokensDetails: response.usage.inputTokensDetails,
outputTokensDetails: response.usage.outputTokensDetails,
...(response.usage.requestUsageEntries &&
response.usage.requestUsageEntries.length > 0
? {
requestUsageEntries: response.usage.requestUsageEntries.map((entry) => ({
inputTokens: entry.inputTokens,
outputTokens: entry.outputTokens,
totalTokens: entry.totalTokens,
inputTokensDetails: entry.inputTokensDetails,
outputTokensDetails: entry.outputTokensDetails,
...(entry.endpoint ? { endpoint: entry.endpoint } : {}),
})),
}
: {}),
},
output: response.output,
responseId: response.responseId,
providerData: response.providerData,
};
}),
context: this._context.toJSON(),
toolUseTracker: this._toolUseTracker.toJSON(),
maxTurns: this._maxTurns,
currentAgentSpan: this._currentAgentSpan?.toJSON(),
noActiveAgentRun: this._noActiveAgentRun,
currentTurnInProgress: this._currentTurnInProgress,
inputGuardrailResults: this._inputGuardrailResults,
outputGuardrailResults: this._outputGuardrailResults.map((r) => ({
...r,
agent: r.agent.toJSON(),
})),
toolInputGuardrailResults: this._toolInputGuardrailResults,
toolOutputGuardrailResults: this._toolOutputGuardrailResults,
currentStep: this._currentStep,
lastModelResponse: this._lastTurnResponse,
generatedItems: this._generatedItems.map((item) => item.toJSON()),
pendingAgentToolRuns: Object.fromEntries(this._pendingAgentToolRuns.entries()),
currentTurnPersistedItemCount: this._currentTurnPersistedItemCount,
lastProcessedResponse: this._lastProcessedResponse,
conversationId: this._conversationId,
previousResponseId: this._previousResponseId,
reasoningItemIdPolicy: this._reasoningItemIdPolicy,
trace: this._trace
? this._trace.toJSON({ includeTracingApiKey })
: null,
};
// parsing the schema to ensure the output is valid for reparsing
const parsed = exports.SerializedRunState.safeParse(output);
if (!parsed.success) {
throw new errors_1.SystemError(`Failed to serialize run state. ${parsed.error.message}`);
}
return parsed.data;
}
/**
* Serializes the run state to a string.
*
* This method is used to serialize the run state to a string that can be used to
* resume the run later.
*
* @returns The serialized run state.
*/
toString(options = {}) {
return JSON.stringify(this.toJSON(options));
}
/**
* Deserializes a run state from a string.
*
* This method is used to deserialize a run state from a string that was serialized using the
* `toString` method.
*/
static async fromString(initialAgent, str) {
return buildRunStateFromString(initialAgent, str);
}
static async fromStringWithContext(initialAgent, str, context, options = {}) {
return buildRunStateFromString(initialAgent, str, {
contextOverride: context,
contextStrategy: options.contextStrategy,
});
}
}
exports.RunState = RunState;
async function buildRunStateFromString(initialAgent, str, options = {}) {
const [parsingError, jsonResult] = await (0, safeExecute_1.safeExecute)(() => JSON.parse(str));
if (parsingError) {
throw new errors_1.UserError(`Failed to parse run state. ${parsingError instanceof Error ? parsingError.message : String(parsingError)}`);
}
const currentSchemaVersion = jsonResult.$schemaVersion;
if (!currentSchemaVersion) {
throw new errors_1.UserError('Run state is missing schema version');
}
if (!SUPPORTED_SCHEMA_VERSIONS.includes(currentSchemaVersion)) {
throw new errors_1.UserError(`Run state schema version ${currentSchemaVersion} is not supported. Please use version ${exports.CURRENT_SCHEMA_VERSION}.`);
}
const stateJson = exports.SerializedRunState.parse(JSON.parse(str));
return buildRunStateFromJson(initialAgent, stateJson, options);
}
async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
const agentMap = buildAgentMap(initialAgent);
const contextOverride = options.contextOverride;
const contextStrategy = options.contextStrategy ?? 'merge';
//
// Rebuild the context
//
const context = contextOverride ??
new runContext_1.RunContext(stateJson.context.context);
if (contextOverride) {
if (contextStrategy === 'merge') {
context._mergeApprovals(stateJson.context.approvals);
}
}
else {
context._rebuildApprovals(stateJson.context.approvals);
}
const shouldRestoreToolInput = !contextOverride || contextStrategy === 'merge';
if (shouldRestoreToolInput &&
typeof stateJson.context.toolInput !== 'undefined' &&
typeof context.toolInput === 'undefined') {
context.toolInput = stateJson.context.toolInput;
}
//
// Find the current agent from the initial agent
//
const currentAgent = agentMap.get(stateJson.currentAgent.name);
if (!currentAgent) {
throw new errors_1.UserError(`Agent ${stateJson.currentAgent.name} not found`);
}
const state = new RunState(context, '', currentAgent, stateJson.maxTurns);
state._currentTurn = stateJson.currentTurn;
state._currentTurnInProgress = stateJson.currentTurnInProgress ?? false;
state._conversationId = stateJson.conversationId ?? undefined;
state._previousResponseId = stateJson.previousResponseId ?? undefined;
state._reasoningItemIdPolicy = stateJson.reasoningItemIdPolicy ?? undefined;
// rebuild tool use tracker
state._toolUseTracker = new toolUseTracker_1.AgentToolUseTracker();
for (const [agentName, toolNames] of Object.entries(stateJson.toolUseTracker)) {
state._toolUseTracker.addToolUse(agentMap.get(agentName), toolNames, { allowEmpty: true });
}
state._pendingAgentToolRuns = new Map(Object.entries(stateJson.pendingAgentToolRuns ?? {}));
// rebuild current agent span
if (stateJson.currentAgentSpan) {
if (!stateJson.trace) {
logger_1.default.warn('Trace is not set, skipping tracing setup');
}
const trace = (0, provider_1.getGlobalTraceProvider)().createTrace({
traceId: stateJson.trace?.id,
name: stateJson.trace?.workflow_name,
groupId: stateJson.trace?.group_id ?? undefined,
metadata: stateJson.trace?.metadata,
tracingApiKey: stateJson.trace?.tracing_api_key ?? undefined,
});
state._currentAgentSpan = deserializeSpan(trace, stateJson.currentAgentSpan);
state._trace = trace;
}
state._noActiveAgentRun = stateJson.noActiveAgentRun;
state._inputGuardrailResults =
stateJson.inputGuardrailResults;
state._outputGuardrailResults = stateJson.outputGuardrailResults.map((r) => ({
...r,
agent: agentMap.get(r.agent.name),
}));
state._toolInputGuardrailResults =
stateJson.toolInputGuardrailResults;
state._toolOutputGuardrailResults =
stateJson.toolOutputGuardrailResults;
state._currentStep = stateJson.currentStep;
state._originalInput = stateJson.originalInput;
state._modelResponses = stateJson.modelResponses.map(deserializeModelResponse);
state._lastTurnResponse = stateJson.lastModelResponse
? deserializeModelResponse(stateJson.lastModelResponse)
: undefined;
state._generatedItems = stateJson.generatedItems.map((item) => deserializeItem(item, agentMap));
state._currentTurnPersistedItemCount =
stateJson.currentTurnPersistedItemCount ?? 0;
state._lastProcessedResponse = stateJson.lastProcessedResponse
? await deserializeProcessedResponse(agentMap, state._currentAgent, state._context, stateJson.lastProcessedResponse)
: undefined;
if (stateJson.currentStep?.type === 'next_step_handoff') {
state._currentStep = {
type: 'next_step_handoff',
newAgent: agentMap.get(stateJson.currentStep.newAgent.name),
};
}
else if (stateJson.currentStep?.type === 'next_step_interruption') {
state._currentStep = {
type: 'next_step_interruption',
data: {
...stateJson.currentStep.data,
interruptions: deserializeInterruptions(stateJson.currentStep.data?.interruptions, agentMap, state._currentAgent),
},
};
}
return state;
}
/**
* @internal
*/
function buildAgentMap(initialAgent) {
const map = new Map();
const queue = [initialAgent];
while (queue.length > 0) {
const currentAgent = queue.shift();
if (map.has(currentAgent.name)) {
continue;
}
map.set(currentAgent.name, currentAgent);
for (const handoff of currentAgent.handoffs) {
if (handoff instanceof agent_1.Agent) {
if (!map.has(handoff.name)) {
queue.push(handoff);
}
}
else if (handoff.agent) {
if (!map.has(handoff.agent.name)) {
queue.push(handoff.agent);
}
}
}
for (const tool of currentAgent.tools) {
const sourceAgent = (0, agentToolSourceRegistry_1.getAgentToolSourceAgent)(tool);
if (sourceAgent && !map.has(sourceAgent.name)) {
queue.push(sourceAgent);
}
}
}
return map;
}
/**
* @internal
*/
function deserializeSpan(trace, serializedSpan) {
const spanData = serializedSpan.span_data;
const previousSpan = serializedSpan.previous_span
? deserializeSpan(trace, serializedSpan.previous_span)
: undefined;
const span = (0, provider_1.getGlobalTraceProvider)().createSpan({
spanId: serializedSpan.id,
traceId: serializedSpan.trace_id,
parentId: serializedSpan.parent_id ?? undefined,
startedAt: serializedSpan.started_at ?? undefined,
endedAt: serializedSpan.ended_at ?? undefined,
data: spanData,
}, trace);
span.previousSpan = previousSpan;
return span;
}
/**
* @internal
*/
function deserializeModelResponse(serializedModelResponse) {
const usage = new usage_1.Usage(serializedModelResponse.usage);
return {
usage,
output: serializedModelResponse.output.map((item) => protocol.OutputModelItem.parse(item)),
responseId: serializedModelResponse.responseId,
providerData: serializedModelResponse.providerData,
};
}
/**
* @internal
*/
function deserializeItem(serializedItem, agentMap) {
switch (serializedItem.type) {
case 'message_output_item':
return new items_1.RunMessageOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
case 'tool_call_item':
return new items_1.RunToolCallItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
case 'tool_call_output_item':
return new items_1.RunToolCallOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name), serializedItem.output);
case 'reasoning_item':
return new items_1.RunReasoningItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
case 'handoff_call_item':
return new items_1.RunHandoffCallItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
case 'handoff_output_item':
return new items_1.RunHandoffOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.sourceAgent.name), agentMap.get(serializedItem.targetAgent.name));
case 'tool_approval_item':
return new items_1.RunToolApprovalItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name), serializedItem.toolName);
}
}
function deserializeInterruptionItem(serializedItem, agentMap, currentAgent) {
if (serializedItem instanceof items_1.RunToolApprovalItem) {
return serializedItem;
}
const parsed = itemSchema.safeParse(serializedItem);
if (parsed.success) {
if (parsed.data.type === 'tool_approval_item') {
const mappedAgent = agentMap.get(parsed.data.agent.name) ?? currentAgent;
return new items_1.RunToolApprovalItem(parsed.data.rawItem, mappedAgent, parsed.data.toolName);
}
const item = deserializeItem(parsed.data, agentMap);
return item instanceof items_1.RunToolApprovalItem ? item : undefined;
}
if (!serializedItem || typeof serializedItem !== 'object') {
return undefined;
}
const value = serializedItem;
if (!value.rawItem || typeof value.rawItem !== 'object') {
return undefined;
}
const rawItem = value.rawItem;
if (rawItem.type !== 'function_call' &&
rawItem.type !== 'hosted_tool_call' &&
rawItem.type !== 'computer_call' &&
rawItem.type !== 'shell_call' &&
rawItem.type !== 'apply_patch_call') {
return undefined;
}
const agentName = value.agent && typeof value.agent.name === 'string'
? value.agent.name
: undefined;
const mappedAgent = (agentName ? agentMap.get(agentName) : undefined) ?? currentAgent;
const toolName = typeof value.toolName === 'string'
? value.toolName
: typeof rawItem.name === 'string'
? rawItem.name
: undefined;
return new items_1.RunToolApprovalItem(value.rawItem, mappedAgent, toolName);
}
function deserializeInterruptions(serializedInterruptions, agentMap, currentAgent) {
if (!Array.isArray(serializedInterruptions)) {
return [];
}
return serializedInterruptions
.map((item) => deserializeInterruptionItem(item, agentMap, currentAgent))
.filter((item) => item instanceof items_1.RunToolApprovalItem);
}
/**
* @internal
*/
async function deserializeProcessedResponse(agentMap, currentAgent, context, serializedProcessedResponse) {
const allTools = await currentAgent.getAllTools(context);
const tools = new Map(allTools
.filter((tool) => tool.type === 'function')
.map((tool) => [tool.name, tool]));
const computerTools = new Map(allTools
.filter((tool) => tool.type === 'computer')
.map((tool) => [tool.name, tool]));
const shellTools = new Map(allTools
.filter((tool) => tool.type === 'shell')
.map((tool) => [tool.name, tool]));
const applyPatchTools = new Map(allTools
.filter((tool) => tool.type === 'apply_patch')
.map((tool) => [tool.name, tool]));
const handoffs = new Map(currentAgent.handoffs.map((entry) => {
if (entry instanceof agent_1.Agent) {
return [entry.name, (0, handoff_1.handoff)(entry)];
}
return [entry.toolName, entry];
}));
const result = {
newItems: serializedProcessedResponse.newItems.map((item) => deserializeItem(item, agentMap)),
toolsUsed: serializedProcessedResponse.toolsUsed,
handoffs: serializedProcessedResponse.handoffs.map((handoff) => {
if (!handoffs.has(handoff.handoff.toolName)) {
throw new errors_1.UserError(`Handoff ${handoff.handoff.toolName} not found`);
}
return {
toolCall: handoff.toolCall,
handoff: handoffs.get(handoff.handoff.toolName),
};
}),
functions: await Promise.all(serializedProcessedResponse.functions.map(async (functionCall) => {
if (!tools.has(functionCall.tool.name)) {
throw new errors_1.UserError(`Tool ${functionCall.tool.name} not found`);
}
return {
toolCall: functionCall.toolCall,
tool: tools.get(functionCall.tool.name),
};
})),
computerActions: serializedProcessedResponse.computerActions.map((computerAction) => {
const toolName = computerAction.computer.name;
if (!computerTools.has(toolName)) {
throw new errors_1.UserError(`Computer tool ${toolName} not found`);
}
return {
toolCall: computerAction.toolCall,
computer: computerTools.get(toolName),
};
}),
shellActions: (serializedProcessedResponse.shellActions ?? []).map((shellAction) => {
const toolName = shellAction.shell.name;
if (!shellTools.has(toolName)) {
throw new errors_1.UserError(`Shell tool ${toolName} not found`);
}
return {
toolCall: shellAction.toolCall,
shell: shellTools.get(toolName),
};
}),
applyPatchActions: (serializedProcessedResponse.applyPatchActions ?? []).map((applyPatchAction) => {
const toolName = applyPatchAction.applyPatch.name;
if (!applyPatchTools.has(toolName)) {
throw new errors_1.UserError(`Apply patch tool ${toolName} not found`);
}
return {
toolCall: applyPatchAction.toolCall,
applyPatch: applyPatchTools.get(toolName),
};
}),
mcpApprovalRequests: (serializedProcessedResponse.mcpApprovalRequests ?? []).map((approvalRequest) => ({
requestItem: new items_1.RunToolApprovalItem(approvalRequest.requestItem
.rawItem, currentAgent),
mcpTool: approvalRequest.mcpTool,
})),
};
return {
...result,
hasToolsOrApprovalsToRun() {
return (result.handoffs.length > 0 ||
result.functions.length > 0 ||
result.mcpApprovalRequests.length > 0 ||
result.computerActions.length > 0 ||
result.shellActions.length > 0 ||
result.applyPatchActions.length > 0);
},
};
}
//# sourceMappingURL=runState.js.map