UNPKG

@openai/agents-core

Version:

The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.

2,344 lines • 143 kB
"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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Runner = exports.getTurnInput = exports.selectModel = exports.getTracing = void 0;
exports.run = run;
const agentToolStream_1 = require("./runner/agentToolStream.js");
const agent_1 = require("./agent.js");
const events_1 = require("./events.js");
const errors_1 = require("./errors.js");
const guardrail_1 = require("./guardrail.js");
const lifecycle_1 = require("./lifecycle.js");
const logger_1 = __importStar(require("./logger.js"));
const providers_1 = require("./providers.js");
const runContext_1 = require("./runContext.js");
const result_1 = require("./result.js");
const runState_1 = require("./runState.js");
const context_1 = require("./tracing/context.js");
const config_1 = require("./tracing/config.js");
const usage_1 = require("./usage.js");
const tools_1 = require("./utils/tools.js");
const rawUsage_1 = require("./utils/rawUsage.js");
const constants_1 = require("./runner/constants.js");
const protocol_1 = require("./types/protocol.js");
const runtime_1 = require("./sandbox/runtime/index.js");
const conversation_1 = require("./runner/conversation.js");
const guardrails_1 = require("./runner/guardrails.js");
const modelSettings_1 = require("./runner/modelSettings.js");
const modelRetry_1 = require("./runner/modelRetry.js");
const modelOutputs_1 = require("./runner/modelOutputs.js");
const streaming_1 = require("./runner/streaming.js");
const sessionPersistence_1 = require("./runner/sessionPersistence.js");
const turnResolution_1 = require("./runner/turnResolution.js");
const blockedOutputPersistence_1 = require("./runner/blockedOutputPersistence.js");
const outputGuardrailBlockedMessage_1 = require("./runner/outputGuardrailBlockedMessage.js");
const turnPreparation_1 = require("./runner/turnPreparation.js");
const pendingInput_1 = require("./runner/pendingInput.js");
const modelPreparation_1 = require("./runner/modelPreparation.js");
const runLoop_1 = require("./runner/runLoop.js");
const tracing_1 = require("./runner/tracing.js");
const usageTracking_1 = require("./runner/usageTracking.js");
const invocationContext_1 = require("./runner/invocationContext.js");
const traces_1 = require("./tracing/traces.js");
const utils_1 = require("./tracing/utils.js");
const items_1 = require("./runner/items.js");
const errorHandlers_1 = require("./runner/errorHandlers.js");
const sandbox_1 = require("./runner/sandbox.js");
const streamReconciliation_1 = require("./runner/streamReconciliation.js");
const runConfig_1 = require("./runner/runConfig.js");
function hasRetainableBlockedOutputEffect(state) {
    return (0, blockedOutputPersistence_1.hasBlockedOutputExecutionEffect)(state._generatedItems, state._currentTurnPersistedItemCount);
}
function commitDeferredRunErrorItemAfterPartialPersistence(state, preparedErrorOutput) {
    if (preparedErrorOutput?.deferredItem &&
        state._currentTurnPersistedItemCount > state._generatedItems.length) {
        state._generatedItems.push(preparedErrorOutput.deferredItem);
        return true;
    }
    return false;
}
var tracing_2 = require("./runner/tracing.js");
Object.defineProperty(exports, "getTracing", { enumerable: true, get: function () { return tracing_2.getTracing; } });
var modelSettings_2 = require("./runner/modelSettings.js");
Object.defineProperty(exports, "selectModel", { enumerable: true, get: function () { return modelSettings_2.selectModel; } });
var items_2 = require("./runner/items.js");
Object.defineProperty(exports, "getTurnInput", { enumerable: true, get: function () { return items_2.getTurnInput; } });
class LazyDefaultModelProvider {
    #modelProvider;
    getModel(modelName) {
        const modelProvider = this.#modelProvider ?? (0, providers_1.getDefaultModelProvider)();
        this.#modelProvider = modelProvider;
        return modelProvider.getModel(modelName);
    }
}
function isNoopTrace(trace) {
    return trace instanceof traces_1.NoopTrace || trace?.traceId === utils_1.NOOP_TRACE_OR_SPAN_ID;
}
function rollbackUnstartedTurn(state, snapshot) {
    if (!snapshot) {
        return false;
    }
    state._currentTurn = snapshot.currentTurn;
    state._currentTurnInProgress = snapshot.currentTurnInProgress;
    return true;
}
function recordModelFailureUsage(usage, state, recordUsage) {
    state.usage.add(usage);
    recordUsage(usage);
}
function assertPendingInputServerOwnership(state, conversationId, previousResponseId) {
    const serverManagesConversation = Boolean(conversationId || previousResponseId);
    if (state._pendingInput.length === 0 ||
        !serverManagesConversation ||
        (0, conversation_1.getServerConversationOwner)(conversationId, previousResponseId)) {
        return;
    }
    throw new errors_1.UserError('Pending RunState input requires exactly one server-managed conversation owner', state);
}
async function run(agent, input, options) {
    const runner = getDefaultRunner();
    if (options?.stream) {
        return await runner.run(agent, input, options);
    }
    else {
        return await runner.run(agent, input, options);
    }
}
/**
 * Orchestrates agent execution, including guardrails, tool calls, session persistence, and
 * tracing. Reuse a `Runner` instance when you want consistent configuration across multiple runs.
 */
class Runner extends lifecycle_1.RunHooks {
    config;
    traceOverrides;
    /**
     * Creates a runner with optional defaults that apply to every subsequent run invocation.
     *
     * @param config - Overrides for models, guardrails, tracing, or session behavior.
     */
    constructor(config = {}) {
        super();
        this.config = {
            modelProvider: config.modelProvider ?? new LazyDefaultModelProvider(),
            model: config.model,
            modelSettings: config.modelSettings,
            handoffInputFilter: config.handoffInputFilter,
            inputGuardrails: config.inputGuardrails,
            outputGuardrails: config.outputGuardrails,
            tracingDisabled: config.tracingDisabled ?? false,
            traceIncludeSensitiveData: config.traceIncludeSensitiveData ?? true,
            workflowName: config.workflowName ?? 'Agent workflow',
            traceId: config.traceId,
            groupId: config.groupId,
            traceMetadata: config.traceMetadata,
            tracing: config.tracing,
            sandbox: config.sandbox,
            toolExecution: (0, runConfig_1.validateToolExecutionConfig)(config.toolExecution),
            toolNotFoundBehavior: config.toolNotFoundBehavior ?? 'raise_error',
            toolNameCollisionPolicy: (0, runConfig_1.validateToolNameCollisionPolicy)(config.toolNameCollisionPolicy),
            sessionInputCallback: config.sessionInputCallback,
            callModelInputFilter: config.callModelInputFilter,
            toolErrorFormatter: config.toolErrorFormatter,
            outputGuardrailBlockedMessage: config.outputGuardrailBlockedMessage,
            reasoningItemIdPolicy: config.reasoningItemIdPolicy,
        };
        this.traceOverrides = {
            ...(config.traceId !== undefined ? { traceId: config.traceId } : {}),
            ...(config.workflowName !== undefined
                ? { workflowName: config.workflowName }
                : {}),
            ...(config.groupId !== undefined ? { groupId: config.groupId } : {}),
            ...(config.traceMetadata !== undefined
                ? { traceMetadata: config.traceMetadata }
                : {}),
            ...(config.tracing?.apiKey !== undefined
                ? { tracingApiKey: config.tracing.apiKey }
                : {}),
        };
        this.inputGuardrailDefs = (config.inputGuardrails ?? []).map(guardrail_1.defineInputGuardrail);
        this.outputGuardrailDefs = (config.outputGuardrails ?? []).map(guardrail_1.defineOutputGuardrail);
    }
    async run(agent, input, options = {
        stream: false,
        context: undefined,
    }) {
        if (input instanceof runState_1.RunState &&
            (input._currentTurn > 0 || input._pendingInput.length > 0) &&
            !input._initialInputGuardrailsCompleted) {
            throw new errors_1.UserError('Cannot resume this checkpoint because completion of initial input guardrails is unverified. Start a fresh run with the original input and context.', input);
        }
        this.#validateModelTimeoutForAgent(input instanceof runState_1.RunState ? input._currentAgent : agent);
        if (input instanceof runState_1.RunState) {
            if (isNoopTrace(input._trace)) {
                input._trace = null;
            }
            if (input._currentAgentSpan?.spanId === utils_1.NOOP_TRACE_OR_SPAN_ID) {
                input.setCurrentAgentSpan(undefined);
            }
        }
        const taskSpanName = this.#getTaskSpanName(input instanceof runState_1.RunState ? input._trace?.name : undefined);
        const capturedInvocationTraceContext = (0, context_1.getCurrentTraceContext)();
        const invocationTraceContext = isNoopTrace(capturedInvocationTraceContext?.trace)
            ? undefined
            : capturedInvocationTraceContext;
        const configuredInvocationSpanParent = (0, invocationContext_1.getRunnerInvocationSpanParent)(this);
        const invocationSpanParent = configuredInvocationSpanParent ??
            (input instanceof runState_1.RunState && input._trace
                ? input._trace
                : (invocationTraceContext?.span ?? invocationTraceContext?.trace));
        const resolvedOptions = options ?? { stream: false, context: undefined };
        // Per-run options take precedence over runner defaults for session memory behavior.
        const sessionInputCallback = resolvedOptions.sessionInputCallback ?? this.config.sessionInputCallback;
        // Likewise allow callers to override callModelInputFilter on individual runs.
        const callModelInputFilter = resolvedOptions.callModelInputFilter ?? this.config.callModelInputFilter;
        // Per-run callback can override runner-level tool error formatting defaults.
        const toolErrorFormatter = resolvedOptions.toolErrorFormatter ?? this.config.toolErrorFormatter;
        const outputGuardrailBlockedMessage = resolvedOptions.outputGuardrailBlockedMessage === undefined
            ? this.config.outputGuardrailBlockedMessage
            : resolvedOptions.outputGuardrailBlockedMessage;
        const reasoningItemIdPolicy = resolvedOptions.reasoningItemIdPolicy ??
            (input instanceof runState_1.RunState ? input._reasoningItemIdPolicy : undefined) ??
            this.config.reasoningItemIdPolicy;
        const toolExecution = (0, runConfig_1.validateToolExecutionConfig)(resolvedOptions.toolExecution ?? this.config.toolExecution);
        const toolNotFoundBehavior = resolvedOptions.toolNotFoundBehavior ?? this.config.toolNotFoundBehavior;
        const toolNameCollisionPolicy = (0, runConfig_1.validateToolNameCollisionPolicy)(resolvedOptions.toolNameCollisionPolicy === undefined
            ? this.config.toolNameCollisionPolicy
            : resolvedOptions.toolNameCollisionPolicy);
        const hasCallModelInputFilter = Boolean(callModelInputFilter);
        const tracingConfig = (0, config_1.mergeTracingConfig)(this.config.tracing, resolvedOptions.tracing);
        const runContext = input instanceof runState_1.RunState
            ? input._context
            : resolvedOptions.context instanceof runContext_1.RunContext
                ? resolvedOptions.context
                : new runContext_1.RunContext(resolvedOptions.context);
        const traceOverrides = {
            ...this.traceOverrides,
            ...(resolvedOptions.tracing?.apiKey !== undefined
                ? { tracingApiKey: resolvedOptions.tracing.apiKey }
                : {}),
        };
        const effectiveOptions = {
            ...resolvedOptions,
            context: runContext,
            sessionInputCallback,
            callModelInputFilter,
            toolErrorFormatter,
            outputGuardrailBlockedMessage,
            reasoningItemIdPolicy,
            toolExecution,
            toolNotFoundBehavior,
            toolNameCollisionPolicy,
            tracing: tracingConfig,
        };
        const useTaskAndTurnSpans = !this.config.tracingDisabled && (0, config_1.includeTaskAndTurnSpans)(tracingConfig);
        const resumingFromState = input instanceof runState_1.RunState;
        // A resumed turn may be inactive but already have persisted items.
        const preserveTurnPersistenceOnResume = resumingFromState &&
            (input._currentTurnInProgress === true ||
                input._currentTurnPersistedItemCount >
                    0);
        const resumedConversationId = resumingFromState
            ? input._conversationId
            : undefined;
        const resumedPreviousResponseId = resumingFromState
            ? input._previousResponseId
            : undefined;
        const serverManagesConversation = Boolean(effectiveOptions.conversationId ?? resumedConversationId) ||
            Boolean(effectiveOptions.previousResponseId ?? resumedPreviousResponseId);
        // When the server tracks conversation history we defer to it for previous turns so local session
        // persistence can focus solely on the new delta being generated in this process.
        const session = effectiveOptions.session;
        const sessionCompaction = (0, sessionPersistence_1.getSessionCompactionState)(session, input instanceof runState_1.RunState ? input : undefined);
        const resumedState = resumingFromState
            ? input
            : undefined;
        if (resumedState?._resumedSessionWriteInProgress) {
            throw new errors_1.UserError('The same RunState cannot resume or reconcile a Session write concurrently.');
        }
        const resumedStateRequiresInputCompaction = resumedState !== undefined &&
            (0, blockedOutputPersistence_1.hasPendingApprovedToolInputCompaction)(resumedState);
        if (resumedStateRequiresInputCompaction) {
            if (serverManagesConversation || session === undefined) {
                throw new errors_1.UserError('A pending Session compaction requires the same ordinary local Session to resume safely.');
            }
            (0, runState_1.assertPendingSessionCompactionTerminalAuthority)(resumedState);
        }
        const releaseResumedSessionWriteOperation = resumedState &&
            (resumedState._pendingSessionWrite !== undefined ||
                resumedState._currentTurnSessionWriteCompactedItemCount !== undefined ||
                resumedStateRequiresInputCompaction ||
                resumedState._currentStep?.type === 'next_step_interruption')
            ? (0, sessionPersistence_1.acquireResumedSessionWriteOperation)(resumedState)
            : undefined;
        let releaseResumedSessionWriteOperationOnReturn = true;
        try {
            let provisionalSessionHistoryTransactionSessionId;
            let provisionalSessionHistoryTransactionInputItems;
            let pendingSessionWriteReconciled = false;
            if (resumingFromState) {
                (0, runLoop_1.assertAcceptedResponseContinuationAuthority)(resumedState, effectiveOptions.conversationId, effectiveOptions.previousResponseId);
                const hadSessionBinding = resumedState._currentTurnSessionHistoryTransactionSessionId !==
                    undefined;
                const portableInputItems = resumedState._currentTurnSessionHistoryTransactionInputItems;
                (0, blockedOutputPersistence_1.assertResumedSessionOutputGuardrailSafety)(resumedState, session, this.#agentHasOutputGuardrail(resumedState._currentAgent));
                pendingSessionWriteReconciled =
                    await (0, sessionPersistence_1.reconcilePendingSessionWriteBeforeRun)(session, resumedState, {
                        serverManagesConversation,
                        operationAlreadyOwned: releaseResumedSessionWriteOperation !== undefined,
                    });
                resumedState.setReasoningItemIdPolicy(reasoningItemIdPolicy);
                await (0, sessionPersistence_1.prepareSessionHistoryTransactionsForRun)(session, resumedState, {
                    serverManagesConversation,
                });
                if (!hadSessionBinding) {
                    provisionalSessionHistoryTransactionSessionId =
                        resumedState._currentTurnSessionHistoryTransactionSessionId;
                    provisionalSessionHistoryTransactionInputItems = portableInputItems;
                }
            }
            const sessionPersistence = (0, sessionPersistence_1.createSessionPersistenceTracker)({
                session,
                runContext,
                compactionState: sessionCompaction,
                hasCallModelInputFilter,
                persistInput: sessionPersistence_1.saveStreamInputToSession,
                resumingFromState,
                resumedSessionInputItems: resumingFromState
                    ? input
                        ._currentTurnSessionHistoryTransactionInputItems
                    : undefined,
            });
            let preparedInput = input;
            if (!(preparedInput instanceof runState_1.RunState)) {
                const prepared = await (0, sessionPersistence_1.prepareInputItemsWithSession)(preparedInput, session, sessionInputCallback, {
                    // When the server tracks conversation state we only send the new turn inputs;
                    // previous messages are recovered via conversationId/previousResponseId.
                    includeHistoryInPreparedInput: !serverManagesConversation,
                    preserveDroppedNewItems: serverManagesConversation,
                    reasoningItemIdPolicy,
                }, runContext, sessionCompaction);
                if (serverManagesConversation && session) {
                    // When the server manages memory we only persist the new turn inputs locally so the
                    // conversation service stays the single source of truth for prior exchanges.
                    const sessionItems = prepared.sessionItems;
                    if (sessionItems && sessionItems.length > 0) {
                        preparedInput = sessionItems;
                    }
                    else {
                        preparedInput = prepared.preparedInput;
                    }
                }
                else {
                    preparedInput = prepared.preparedInput;
                }
                sessionPersistence?.setPreparedItems(prepared.sessionItems, prepared.preparedInput);
            }
            // Streaming runs persist the input asynchronously, so track a one-shot helper
            // that can be awaited from multiple branches without double-writing.
            const ensureStreamInputPersisted = sessionPersistence?.buildPersistInputOnce(serverManagesConversation);
            const executeRun = async (effectiveInvocationSpanParent = invocationSpanParent) => {
                if (effectiveOptions.stream) {
                    const streamResult = await this.#runIndividualStream(agent, preparedInput, taskSpanName, effectiveOptions, ensureStreamInputPersisted, sessionPersistence?.setPreparedTurnItems, sessionPersistence?.recordTurnItems, sessionPersistence?.getItemsForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, {
                        sdkSessionId: async () => await session?.getSessionId(),
                        inputOverride: () => session
                            ? sessionPersistence?.getItemsForPersistence()
                            : undefined,
                    }, effectiveInvocationSpanParent, pendingSessionWriteReconciled, sessionCompaction);
                    if (releaseResumedSessionWriteOperation) {
                        releaseResumedSessionWriteOperationOnReturn = false;
                        void streamResult.completed.then(releaseResumedSessionWriteOperation, releaseResumedSessionWriteOperation);
                    }
                    return streamResult;
                }
                const runResult = await this.#runIndividualNonStream(agent, preparedInput, effectiveOptions, taskSpanName, sessionPersistence?.setPreparedTurnItems, sessionPersistence?.recordTurnItems, sessionPersistence?.getItemsForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, {
                    sdkSessionId: async () => await session?.getSessionId(),
                    inputOverride: () => session
                        ? sessionPersistence?.getItemsForPersistence()
                        : undefined,
                }, effectiveInvocationSpanParent, session && sessionPersistence && !serverManagesConversation
                    ? async (result, persistenceOptions) => {
                        await (0, sessionPersistence_1.saveToSession)(session, sessionPersistence.getItemsForPersistence(), result, persistenceOptions);
                    }
                    : undefined, pendingSessionWriteReconciled, sessionCompaction);
                return runResult;
            };
            if (this.config.tracingDisabled) {
                const disabledTrace = new traces_1.NoopTrace();
                if (preparedInput instanceof runState_1.RunState) {
                    preparedInput._currentAgentSpan?.end();
                    preparedInput._trace = null;
                    preparedInput.setCurrentAgentSpan(undefined);
                }
                return await (0, context_1.withTrace)(disabledTrace, async () => {
                    try {
                        const result = await executeRun(disabledTrace);
                        const clearDisabledTraceState = () => {
                            result.state._trace = null;
                            result.state.setCurrentAgentSpan(undefined);
                        };
                        if (result instanceof result_1.StreamedRunResult) {
                            void result.completed.then(clearDisabledTraceState, clearDisabledTraceState);
                        }
                        else {
                            clearDisabledTraceState();
                        }
                        return result;
                    }
                    catch (error) {
                        if (error instanceof errors_1.AgentsError && error.state) {
                            error.state._trace = null;
                            error.state.setCurrentAgentSpan(undefined);
                        }
                        throw error;
                    }
                });
            }
            if (preparedInput instanceof runState_1.RunState && preparedInput._trace) {
                const applied = (0, tracing_1.applyTraceOverrides)(preparedInput._trace, preparedInput._currentAgentSpan, traceOverrides);
                preparedInput._trace = applied.trace;
                preparedInput._currentAgentSpan = applied.currentSpan;
                return await (0, context_1.withTrace)(preparedInput._trace, async () => {
                    if (preparedInput._currentAgentSpan && !useTaskAndTurnSpans) {
                        (0, context_1.setCurrentSpan)(preparedInput._currentAgentSpan);
                    }
                    return executeRun();
                });
            }
            const executeInInvocationTrace = async (effectiveInvocationSpanParent = invocationSpanParent) => {
                if (preparedInput instanceof runState_1.RunState && !preparedInput._trace) {
                    preparedInput._trace = (0, context_1.getCurrentTrace)();
                }
                return executeRun(effectiveInvocationSpanParent);
            };
            if (invocationTraceContext) {
                return await (0, context_1.withTraceContext)(invocationTraceContext, executeInInvocationTrace);
            }
            return await (0, context_1.withTrace)(this.config.workflowName ?? 'Agent workflow', async (trace) => executeInInvocationTrace(trace), {
                traceId: this.config.traceId,
                groupId: this.config.groupId,
                metadata: this.config.traceMetadata,
                // Per-run tracing config overrides exporter defaults such as environment API key.
                tracingApiKey: tracingConfig?.apiKey,
            });
        }
        finally {
            if (releaseResumedSessionWriteOperationOnReturn) {
                releaseResumedSessionWriteOperation?.();
            }
        }
    }
    // --------------------------------------------------------------
    //  Internals
    // --------------------------------------------------------------
    #getTaskSpanName(restoredWorkflowName) {
        return (this.traceOverrides.workflowName ??
            restoredWorkflowName ??
            this.config.workflowName ??
            'Agent workflow');
    }
    inputGuardrailDefs;
    outputGuardrailDefs;
    #agentHasOutputGuardrail(agent) {
        return Boolean(this.outputGuardrailDefs.length > 0 || agent.outputGuardrails.length > 0);
    }
    #captureResponseGuardrailBoundary(state, overwrite) {
        (0, blockedOutputPersistence_1.captureCurrentResponseToolOutputGuardrailResultStart)(state, overwrite, this.#agentHasOutputGuardrail(state._currentAgent));
    }
    #shouldDeferInterruptedSessionItems(state) {
        return (0, blockedOutputPersistence_1.shouldDeferInterruptedSessionItems)(state, this.#agentHasOutputGuardrail(state._currentAgent));
    }
    /**
     * @internal
     * Resolves the effective model once so both run loops obey the same precedence rules.
     */
    async #resolveModelForAgent(agent) {
        const explicitlyModelSet = (agent.model !== undefined &&
            agent.model !== agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER) ||
            (this.config.model !== undefined &&
                this.config.model !== agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER);
        const selectedModel = (0, modelSettings_1.selectModel)(agent.model, this.config.model);
        const resolvedModelName = typeof selectedModel === 'string' ? selectedModel : undefined;
        const resolvedModel = typeof selectedModel === 'string'
            ? await this.config.modelProvider.getModel(selectedModel)
            : selectedModel;
        return { model: resolvedModel, explicitlyModelSet, resolvedModelName };
    }
    async #resolveSandboxRuntimeModelForAgent(agent) {
        if (!(0, sandbox_1.isSandboxRuntimeAgent)(agent)) {
            return this.config.model;
        }
        const resolved = await this.#resolveModelForAgent(agent);
        if (resolved.resolvedModelName &&
            resolved.resolvedModelName.trim().length > 0) {
            return {
                model: resolved.resolvedModelName,
                modelInstance: resolved.model,
            };
        }
        return resolved.model;
    }
    #getAgentToolParentRunConfig(options) {
        const hasSandboxOverride = typeof options.sandbox !== 'undefined';
        const hasToolExecutionOverride = typeof options.toolExecution !== 'undefined';
        const hasToolNotFoundBehaviorOverride = typeof options.toolNotFoundBehavior !== 'undefined';
        const hasToolNameCollisionPolicyOverride = typeof options.toolNameCollisionPolicy !== 'undefined';
        const hasTracingOverride = typeof options.tracing !== 'undefined';
        if (!hasSandboxOverride &&
            !hasToolExecutionOverride &&
            !hasToolNotFoundBehaviorOverride &&
            !hasToolNameCollisionPolicyOverride &&
            !hasTracingOverride) {
            return this.config;
        }
        return {
            ...this.config,
            ...(hasSandboxOverride ? { sandbox: options.sandbox } : {}),
            ...(hasToolExecutionOverride
                ? { toolExecution: options.toolExecution }
                : {}),
            ...(hasToolNotFoundBehaviorOverride
                ? { toolNotFoundBehavior: options.toolNotFoundBehavior }
                : {}),
            ...(hasToolNameCollisionPolicyOverride
                ? { toolNameCollisionPolicy: options.toolNameCollisionPolicy }
                : {}),
            ...(hasTracingOverride ? { tracing: options.tracing } : {}),
        };
    }
    /**
     * @internal
     */
    async #runIndividualNonStream(startingAgent, input, options, taskSpanName, sessionTurnInputUpdate, 
    // sessionInputUpdate lets the caller adjust queued session items after filters run so we
    // persist exactly what we send to the model (e.g., after redactions or truncation).
    sessionInputUpdate, getSessionInputForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, sandboxMemoryRunContext, invocationSpanParent, persistResult, pendingSessionWriteReconciled = false, sessionCompaction) {
        return (0, context_1.withNewSpanContext)(async () => {
            // if we have a saved state we use that one, otherwise we create a new one
            const isResumedState = input instanceof runState_1.RunState;
            const state = isResumedState
                ? input
                : new runState_1.RunState(options.context instanceof runContext_1.RunContext
                    ? options.context
                    : new runContext_1.RunContext(options.context), input, startingAgent, options.maxTurns === undefined
                    ? constants_1.DEFAULT_MAX_TURNS
                    : options.maxTurns);
            (0, sessionPersistence_1.bindSessionCompactionState)(state, sessionCompaction);
            this.#validateModelTimeoutForAgent(state._currentAgent);
            if (isResumedState) {
                state._agentToolInvocation = undefined;
                if (options.maxTurns !== undefined) {
                    state._maxTurns = options.maxTurns;
                }
            }
            const sandboxRuntime = new runtime_1.SandboxRuntimeManager({
                startingAgent,
                sandboxConfig: options.sandbox ?? this.config.sandbox,
                runState: isResumedState
                    ? state
                    : undefined,
            });
            const agentToolParentRunConfig = this.#getAgentToolParentRunConfig(options);
            const resolvedReasoningItemIdPolicy = options.reasoningItemIdPolicy ??
                (isResumedState ? state._reasoningItemIdPolicy : undefined) ??
                this.config.reasoningItemIdPolicy;
            state.setReasoningItemIdPolicy(resolvedReasoningItemIdPolicy);
            const resolvedConversationId = options.conversationId ??
                (isResumedState ? state._conversationId : undefined);
            const resolvedPreviousResponseId = options.previousResponseId ??
                (isResumedState ? state._previousResponseId : undefined);
            const serverManagesConversation = Boolean(resolvedConversationId || resolvedPreviousResponseId);
            assertPendingInputServerOwnership(state, resolvedConversationId, resolvedPreviousResponseId);
            if (!isResumedState) {
                await (0, sessionPersistence_1.prepareSessionHistoryTransactionsForRun)(options.session, state, {
                    serverManagesConversation,
                });
            }
            if (!isResumedState) {
                state.setConversationContext(resolvedConversationId, resolvedPreviousResponseId);
            }
            const serverConversationTracker = serverManagesConversation
                ? new conversation_1.ServerConversationTracker({
                    conversationId: resolvedConversationId,
                    previousResponseId: resolvedPreviousResponseId,
                    reasoningItemIdPolicy: resolvedReasoningItemIdPolicy,
                })
                : undefined;
            if (serverConversationTracker && isResumedState) {
                serverConversationTracker.primeFromState({
                    originalInput: state._originalInput,
                    generatedItems: state._generatedItems,
                    modelResponses: state._modelResponses,
                });
                state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
            }
            const toolErrorFormatter = options.toolErrorFormatter ?? this.config.toolErrorFormatter;
            const outputGuardrailBlockedMessage = options.outputGuardrailBlockedMessage === undefined
                ? this.config.outputGuardrailBlockedMessage
                : options.outputGuardrailBlockedMessage;
            const useTaskAndTurnSpans = !this.config.tracingDisabled &&
                (0, config_1.includeTaskAndTurnSpans)(options.tracing);
            const resumingInterruptedTurn = isResumedState && state._currentStep?.type === 'next_step_interruption';
            const invocationSpans = useTaskAndTurnSpans
                ? (0, tracing_1.startRunnerInvocationSpans)({
                    name: taskSpanName,
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    resumeInterruptedTurn: resumingInterruptedTurn,
                    parent: invocationSpanParent,
                })
                : undefined;
            const taskSpan = invocationSpans?.taskSpan;
            const optOutResumeAgentSpan = resumingInterruptedTurn && !useTaskAndTurnSpans
                ? (0, tracing_1.ensureActiveAgentSpanForInterruptedResume)({
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    parent: invocationSpanParent ?? (0, context_1.getCurrentTrace)() ?? undefined,
                })
                : undefined;
            if (useTaskAndTurnSpans && isResumedState) {
                state.setCurrentAgentSpan(invocationSpans?.agentSpan);
            }
            else if (optOutResumeAgentSpan) {
                state.setCurrentAgentSpan(optOutResumeAgentSpan);
            }
            // Tracks when we resume an approval interruption so the next run-again step stays in the same turn.
            let continuingInterruptedTurn = false;
            let runError;
            const attemptedRunErrorHandlers = new WeakSet();
            let currentTurnSpan;
            let turnPendingModelRequest;
            let guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
            const parentUsageRecorder = (0, usageTracking_1.getRunnerParentUsageRecorder)(this);
            const recordUsage = (usage) => {
                (0, tracing_1.recordRunnerSpanUsage)(taskSpan, usage);
                (0, tracing_1.recordRunnerSpanUsage)(currentTurnSpan, usage);
                parentUsageRecorder?.(usage);
            };
            (0, usageTracking_1.setRunStateUsageRecorder)(state, recordUsage);
            let completedResult;
            let persistenceCheckpoint;
            let cancelledOutputRedacted = false;
            const resumedStateHasPersistedToolOutput = isResumedState && (0, blockedOutputPersistence_1.hasPersistedToolOutput)(state);
            let approvedToolCheckpointCompacted = pendingSessionWriteReconciled ||
                state._currentTurnSessionWriteCompactedItemCount ===
                    state._currentTurnPersistedItemCount ||
                (resumedStateHasPersistedToolOutput &&
                    !(0, blockedOutputPersistence_1.hasPendingApprovedToolInputCompaction)(state));
            let approvedToolCheckpointRequiresLocalInputCompaction = resumedStateHasPersistedToolOutput;
            let approvedToolCheckpointModelResponseCount = state._modelResponses.length;
            let approvedToolFinalSessionWritePreparation;
            let deferredApprovedToolFinalSessionWritePreparation;
            let completedResultPersisted = false;
            const completeResult = (result) => {
                completedResult = result;
                return result;
            };
            const persistNonStreamingResult = async (result, overrideOptions) => {
                if (this.#shouldDeferInterruptedSessionItems(result.state)) {
                    return;
                }
                const hasUnpersistedItems = result.newItems.length > state._currentTurnPersistedItemCount ||
                    (overrideOptions?.additionalRunItems?.length ?? 0) > 0;
                const modelResponseAdvanced = result.rawResponses.length > approvedToolCheckpointModelResponseCount;
                const compactionOptions = approvedToolCheckpointRequiresLocalInputCompaction
                    ? approvedToolCheckpointCompacted &&
                        !hasUnpersistedItems &&
                        !modelResponseAdvanced
                        ? { runCompaction: false }
                        : { compactionMode: 'input' }
                    : undefined;
                const persistenceOptions = {
                    ...compactionOptions,
                    ...overrideOptions,
                };
                const finalSessionWritePreparation = approvedToolFinalSessionWritePreparation;
                await persistResult?.(result, {
                    ...persistenceOptions,
                    resumedSessionWritePreparation: finalSessionWritePreparation ??
                        persistenceOptions.resumedSessionWritePreparation,
                });
                if (finalSessionWritePreparation) {
                    approvedToolFinalSessionWritePreparation = undefined;
                    if (persistenceOptions.deferResumedSessionWrite !== true) {
                        approvedToolCheckpointCompacted = true;
                        approvedToolCheckpointModelResponseCount =
                            result.rawResponses.length;
                    }
                }
            };
            const activateDeferredApprovedToolFinalSessionWrite = () => {
                const preparation = deferredApprovedToolFinalSessionWritePreparation;
                if (!preparation) {
                    return;
                }
                if (state._pendingSessionHistoryTransaction !== undefined ||
                    state._currentTurnDeferredSessionItemIndexes.size > 0 ||
                    state._currentTurnBlockedSessionStartIndex !== undefined) {
                    deferredApprovedToolFinalSessionWritePreparation = undefined;
                    return;
                }
                if (!options.session || serverManagesConversation) {
                    throw new errors_1.UserError('Resumed Session write preparation has no ordinary Session owner.');
                }
                deferredApprovedToolFinalSessionWritePreparation = undefined;
                approvedToolFinalSessionWritePreparation = preparation;
            };
            const recordNonStreamingError = (error) => {
                if (state._currentAgentSpan) {
                    state._currentAgentSpan.setError({
                        message: 'Error in agent run',
                        data: {
                            error: (0, tracing_1.getRunnerSpanErrorDetails)(error, this.config.traceIncludeSensitiveData),
                        },
                    });
                }
                (0, tracing_1.setRunnerSpanError)(currentTurnSpan, error, this.config.traceIncludeSensitiveData);
                (0, tracing_1.setRunnerSpanError)(taskSpan, error, this.config.traceIncludeSensitiveData);
                runError = error;
            };
            const finalizeCurrentOutput = async (preparedErrorOutput) => {
                const currentStep = state._currentStep;
                if (currentStep?.type !== 'next_step_final_output') {
                    throw new errors_1.ModelBehaviorError('Expected a final output step while finalizing the run.', state);
                }
                (0, runLoop_1.markAcceptedResponseFinalizationStarted)(state);
                (0, blockedOutputPersistence_1.normalizeSerializedOutputGuardrailBlockedMessage)(state);
                const resolveBlockedMessage = (0, outputGuardrailBlockedMessage_1.createOutputGuardrailBlockedMessageResolver)(outputGuardrailBlockedMessage, state);
                const outputGuardrailResultStart = state._outputGuardrailResults.length;
                let outputGuardrailBlocked = false;
                try {
                    await (0, guardrails_1.finalizeOutputGuardrails)({
                        state,
                        runnerOutputGuardrails: this.outputGuardrailDefs,
                        output: currentStep.output,
                        redactedOutput: outputGuardrailBlockedMessage_1.OUTPUT_GUARDRAIL_BLOCKED_TOOL_OUTPUT,
                        guardedTerminalToolOutput: (0, blockedOutputPersistence_1.hasTerminalToolOutputSource)(state),
                        signal: options.signal,
                        sanitizeRejectedOutput: (...args) => (0, blockedOutputPersistence_1.sanitizeBlockedTerminalToolOutput)(...args, resolveBlockedMessage, options.signal, () => {
                            outputGuardrailBlocked = true;
                        }),
                        persistBlockedOutput: persistResult
                            ? async () => persistResult(new result_1.RunResult(state), {
                                outputBlocked: true,
                            })
                            : undefined,
                        persistUnblockedFailure: async () => {
                            activateDeferredApprovedToolFinalSessionWrite();
                            await persistNonStreamingResult(new result_1.RunResult(state));
                            completedResultPersisted = true;
                        },
                        onBlockedOutput: () => {
                            outputGuardrailBlocked = true;
                        },
                        releaseBlockedOutputPersistence: sessionPersistence_1.releaseUnusedSessionHistoryTransactionBinding,
                    });
                }
                catch (error) {
                    if (!outputGuardrailBlocked &&
                        (deferredApprovedToolFinalSessionWritePreparation !== undefined ||
                            state._pendingSessionWrite !== undefined ||
                            approvedToolCheckpointCompacted)) {
                        state._outputGuardrailResults.splice(outputGuardrailResultStart);
                        if (deferredApprovedToolFinalSessionWritePreparation !== undefined &&
                            state._pendingSessionWrite === undefined) {
                            try {
                                activateDeferredApprovedToolFinalSessionWrite();
                                await persistNonStreamingResult(new result_1.RunResult(state), { deferResumedSessionWrite: true });
                            }
                            catch (checkpointError) {
                                if (state._pendingSessionWrite === undefined) {
                                    throw checkpointError;
                                }
                            }
                        }
                    }
                    throw error;
                }
                if (state._serializedCurrentStep === currentStep &&
                    hasRetainableBlockedOutputEffect(state)) {
                    (0, sessionPersistence_1.releaseProvisionalSessionHistoryTransactionBinding)(state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                    throw new errors_1.UserError('Accepted final output cannot be resumed directly from serialized terminal state. Start a new run from persisted session history.');
                }
                activateDeferredApprovedToolFinalSessionWrite();
                (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                (0, invocationContext_1.setRunStateTurnSpanParent)(state, undefined);
                currentTurnSpan = undefined;
                const result = new result_1.RunResult(state);
                try {
                    await persistNonStreamingResult(result, preparedErrorOutput?.deferredItem
                        ? { additionalRunItems: [preparedErrorOutput.deferredItem] }
                        : undefined);
                }
                catch (error) {
                    state._outputGuardrailResults.splice(outputGuardrailResultStart);
                    commitDeferredRunErrorItemAfterPartialPersistence(state, preparedErrorOutput);
                    throw error;
                }
                if (preparedErrorOutput?.deferredItem) {
                    state._generatedItems.push(preparedErrorOutput.deferredItem);
                }
                completedResultPersisted = true;
                state._currentTurnInProgress = false;
                this.emit('agent_end', state._context, state._currentAgent, currentStep.output);
                state._currentAgent.emit('agent_end', state._context, currentStep.output);
                return completeResult(result);
            };
            try {
                while (true) {
                    // if we don't have a current step, we treat this as a new run
                    state._currentStep = state._currentStep ?? {
                        type: 'next_step_run_again',
                    };
                    if ((0, runLoop_1.isAcceptedResponseCheckpoint)(state)) {
                        this.#captureResponseGuardrailBoundary(state, false);
                        await (0, runLoop_1.resumeAcceptedModelResponse)({
                            state,
                            runner: this,
                            toolErrorFormatter,
                            agentToolParentRunConfig,
                            signal: options.signal,
                            validateHandoffAgent: (handoffAgent) => {
                                this.#validateModelTimeoutForAgent(handoffAgent);
                            },
                        });
                    }
                    if (state._currentStep.type === 'next_step_interruption') {
                        await (0, sandbox_1.prepareSandboxInterruptedTurnResume)({
                            startingAgent,
                            state,
                            sandboxRuntime,
                            runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(state._currentAgent),
                            toolNameCollisionPolicy: options.toolNameCollisionPolicy,
                            tracingParent: (0, invocationContext_1.getRunStateTurnSpanParent)(state) ?? state._currentAgentSpan,
                        });
                        if (useTaskAndTurnSpans) {
                            currentTurnSpan = (0, tracing_1.ensureTurnSpan)(currentTurnSpan, state._currentTurn, state._currentAgent.name, state._currentAgentSpan);
                            (0, invocationContext_1.setRunStateTurnSpanParent)(state, currentTurnSpan.span);
                        }
                        const { interruptedOutcome, approvedToolCheckpointDeferred } = await (async () => {
                            let resumedSessionWritePreparation;
                            this.#captureResponseGuardrailBoundary(state, false);
                            const outcome = await (0, runLoop_1.resumeInterruptedTurn)({
                                state,
                                runner: this,
                                toolErrorFormatter,
                                agentToolParentRunConfig,
                                signal: options.signal,
                                validateHandoffAgent: (handoffAgent) => {
                                    this.#validateModelTimeoutForAgent(handoffAgent);
                                },
                                beforeResumedSideEffects: async () => {
                                    if (persistResult &&
                                        options.session &&
                                        !serverManagesConversation) {
                                        resumedSessionWritePreparation =
                                            await (0, sessionPersistence_1.prepareResumedSessionWrite)(options.session, state);
                                    }
                                    return resumedSessionWritePreparation;
                                },
                            });
                            const checkpointDeferred = outcome.resumedSideEffects &&
                                outcome.nextStep.type === 'next_step_final_output' &&
                                this.#agentHasOutputGuardrail(state._currentAgent);
                            if (outcome.resumedSideEffects) {
                                const approvedToolResult = new result_1.RunResult(state);
                                approvedToolCheckpointRequiresLocalInputCompaction = true;
                                if (persistResult &&
                                    !this.#shouldDeferInterruptedSessionItems(state)) {
                                    if (options.session &&
                                        !serverManagesConversation &&
                                        !resumedSessionWritePreparation) {
                                        throw new errors_1.UserError('Resumed Session write preparation is missing after approved tool execution.');
                                    }
                                    if (checkpointDeferred) {
                                        deferredApprovedToolFinalSessionWritePreparation =
                                            resumedSessionWritePreparation;
                                    }
                                    else if (outcome.nextStep.type === 'next_step_final_output') {
                                        approvedToolFinalSessionWritePreparation =
                                            resumedSessionWritePreparation;
                                    }
                                    if (outcome.nextStep.type !== 'next_step_final_output') {
                                        await persistResult(approvedToolResult, {
                                            compactionMode: 'input',
                                            resumedSessionWritePreparation,
                                        });
                                        approvedToolCheckpointCompacted = true;
                                        approvedToolCheckpointModelResponseCount =
                                            approvedToolResult.rawResponses.length;
                                    }
                                    else {
                                        approvedToolFinalSessionWritePreparation ??=
                                            checkpointDeferred
                                                ? undefined
                                                : resumedSessionWritePreparation;
                                    }
                                }
                            }
                            return {
                                interruptedOutcome: outcome,
                                approvedToolCheckpointDeferred: checkpointDeferred,
                            };
                        })();
                        if (options.signal?.aborted && !approvedToolCheckpointDeferred) {
                            persistenceCheckpoint = new result_1.RunResult(state);
                        }
                        options.signal?.throwIfAborted();
                        // Don't reset counter here - resolveInterruptedTurn already adjusted it via rewind logic
                        // The counter will be reset when _currentTurn is incremented (starting a new turn)
                        const { shouldReturn, shouldContinue } = (0, runLoop_1.handleInterruptedOutcome)({
                            state,
                            outcome: interruptedOutcome,
                            setContinuingInterruptedTurn: (value) => {
                                continuingInterruptedTurn = value;
                            },
                        });
                        // Approval resolution belongs to the previous turn; any next model call
                        // starts a new counted turn with its own span and usage.
                        (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                        (0, invocationContext_1.setRunStateTurnSpanParent)(state, undefined);
                        currentTurnSpan = undefined;
                        if (shouldReturn) {
                            // we are still in an interruption, so we need to avoid an infinite loop
                            return completeResult(new result_1.RunResult(state));
                        }
                        if (shouldContinue) {
                            continue;
                        }
                    }
                    if (state._currentStep.type === 'next_step_run_again') {
                        this.#validateModelTimeoutForAgent(state._currentAgent);
                        if (approvedToolCheckpointCompacted &&
                            state._currentTurnSessionHistoryTransactionSessionId === undefined) {
                            await (0, sessionPersistence_1.prepareSessionHistoryTransactionsForRun)(options.session, state, { serverManagesConversation: false });
                        }
                        const wasContinuingInterruptedTurn = continuingInterruptedTurn;
                        continuingInterruptedTurn = false;
                        guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
                        const previousTurn = state._currentTurn;
                        turnPendingModelRequest = {
                            currentTurn: previousTurn,
                            currentTurnInProgress: state._currentTurnInProgress,
                        };
                        const previousPersistedCount = state._currentTurnPersistedItemCount;
                        const previousGeneratedCount = state._generatedItems.length;
                        const { turnInput, pendingInputItems, pendingInputSourceItems } = await (0, turnPreparation_1.prepareTurn)({
                            state,
                            input: state._originalInput,
                            generatedItems: state._generatedItems,
                            isResumedState,
                            preserveTurnPersistenceOnResume,
                            continuingInterruptedTurn: wasContinuingInterruptedTurn,
                            serverConversationTracker,
                            inputGuardrailDefs: this.inputGuardrailDefs,
                            guardrailHandlers: {
                                onParallelPromise: guardrailTracker.setPromise,
                                onParallelError: guardrailTracker.setError,
                            },
                            emitAgentStart: (context, agent, inputItems) => {
                                this.emit('agent_start', context, agent, inputItems);
                            },
                            onAgentSpanReady: useTaskAndTurnSpans
                                ? (turn, agentName) => {
                                    currentTurnSpan = (0, tracing_1.ensureTurnSpan)(currentTurnSpan, turn, agentName, state._currentAgentSpan);
                                    (0, invocationContext_1.setRunStateTurnSpanParent)(state, currentTurnSpan.span);
                                }
                                : undefined,
                            agentSpanParent: taskSpan?.span ?? invocationSpanParent,
                        });
                        if (preserveTurnPersistenceOnResume &&
                            state._currentTurn > previousTurn &&
                            previousPersistedCount <= previousGeneratedCount) {
                            // Preserve persisted offsets from a resumed run to avoid re-saving prior items.
                            state._currentTurnPersistedItemCount = previousPersistedCount;
                        }
                        const sessionPreparedTurnInput = [...turnInput];
                        const preparedSandboxAgent = await sandboxRuntime.prepareAgent({
                            currentAgent: state._currentAgent,
                            turnInput,
                            runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(state._currentAgent),
                            tracingParent: currentTurnSpan?.span ?? state._currentAgentSpan,
                        });
                        sessionTurnInputUpdate?.(sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                        const processedPendingInputItems = (0, pendingInput_1.mapPendingInputAfterContextProcessing)(pendingInputItems, sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                        const artifacts = await (0, modelPreparation_1.prepareAgentArtifacts)(state, preparedSandboxAgent.executionAgent, options.toolNameCollisionPolicy);
                        const preparedCall = await this.#prepareModelCall(state, preparedSandboxAgent.executionAgent, options, artifacts, preparedSandboxAgent.turnInput, serverConversationTracker, sessionInputUpdate);
                        (0, sessionPersistence_1.captureSessionHistoryTransactionInputItems)(options.session, state, getSessionInputForPersistence?.());
                        await guardrailTracker.throwIfError();
                        const requiresPendingInputAdmissionCheckpoint = pendingInputItems.length > 0 ||
                            (!serverConversationTracker && (0, pendingInput_1.hasUnpersistedRunInput)(state));
                        if (requiresPendingInputAdmissionCheckpoint) {
                            options.signal?.throwIfAborted();
                        }
                        const admittedPendingInput = (0, pendingInput_1.selectPendingInputForAdmission)(processedPendingInputItems, preparedCall);
                        let localPendingInputCommitted = false;
                        const commitLocalPendingInput = async () => {
                            if (serverConversationTracker || localPendingInputCommitted) {
                                return;
                            }
                            localPendingInputCommitted = true;
                            (0, pendingInput_1.commitPendingInput)(state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                            if ((0, pendingInput_1.hasUnpersistedRunInput)(state)) {
                                await (0, sessionPersistence_1.saveToSession)(options.session, undefined, new result_1.RunResult(state), { runCompaction: false });
                            }
                            if (requiresPendingInputAdmissionCheckpoint) {
                                options.signal?.throwIfAborted();
                            }
                        };
                        const deferLocalPendingInputAdmission = !serverConversationTracker &&
                            pendingInputItems.length > 0 &&
                            guardrailTracker.pending;
                        if (!deferLocalPendingInputAdmission) {
                            await commitLocalPendingInput();
                        }
                        const modelRequest = {
                            systemInstructions: preparedCall.modelInput.instructions,
                            prompt: preparedCall.prompt,
                            // Explicit agent/run config models should take precedence over prompt defaults.
                            ...(preparedCall.explicitlyModelSet
                                ? { overridePromptModel: true }
                                : {}),
                            input: preparedCall.modelInput.input,
                            previousResponseId: preparedCall.previousResponseId,
                            conversationId: preparedCall.conversationId,
                            modelSettings: preparedCall.modelSettings,
                            _internal: preparedCall.modelRequestInternal,
                            tools: preparedCall.serializedTools,
                            toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
                            outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(state._currentAgent.outputType),
                            handoffs: preparedCall.serializedHandoffs,
                            tracing: (0, tracing_1.getTracing)(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
                            signal: options.signal,
                        };
                        turnPendingModelRequest = undefined;
                        let serverInputMarked = false;
                        const markServerInputAccepted = (responseAvailable = true) => {
                            if (serverInputMarked || !serverConversationTracker) {
                                return;
                            }
                            serverConversationTracker.markInputAsSent(preparedCall.filterApplied
                                ? preparedCall.sourceItems
                                : preparedCall.turnInput, {
                                filterApplied: preparedCall.filterApplied,
                                allTurnItems: preparedCall.turnInput,
                            });
                            (0, pendingInput_1.commitPendingInput)(state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                            if (pendingInputItems.length > 0) {
                                if (admittedPendingInput.length > 0) {
                                    serverConversationTracker.markInputAsSent(admittedPendingInput.map((item) => item.rawItem));
                                }
                            }
                            if (pendingInputItems.length > 0 || !responseAvailable) {
                                if (!responseAvailable) {
                                    state._lastTurnResponse = undefined;
                                }
                                state._lastProcessedResponse = undefined;
                                state._currentStep = {
                                    type: 'next_step_interruption',
                                    data: { interruptions: [], responseAccepted: true },
                                };
                            }
                            serverInputMarked = true;
                        };
                        const completeCompactionExchange = (0, sessionPersistence_1.prepareSessionCompactionExchange)(options.session, state, preparedCall.modelInput.input);
                        const pendingModelResponse = (0, modelRetry_1.getResponseWithRetry)(preparedCall.model, modelRequest, {
                            onModelFailureUsage: (usage) => recordModelFailureUsage(usage, state, recordUsage),
                            ...(serverConversationTracker
                                ? {
                                    onPossiblyAcceptedRequestFailure: () => markServerInputAccepted(false),
                                }
                                : {}),
                        });
                        if (deferLocalPendingInputAdmission) {
                            const modelResponseOutcome = pendingModelResponse.then((response) => ({ status: 'fulfilled', response }), (error) => ({ status: 'rejected', error }));
                            try {
                                await guardrailTracker.awaitCompletion();
                                await commitLocalPendingInput();
                            }
                            catch (error) {
                                // The request already started in parallel, so drain it before
                                // surfacing a guardrail or persistence failure.
                                await modelResponseOutcome;
                                throw error;
                            }
                            const outcome = await modelResponseOutcome;
                            if (outcome.status === 'rejected') {
                                throw outcome.error;
                            }
                            state._lastTurnResponse = outcome.response;
                        }
                        else {
                            state._lastTurnResponse = await pendingModelResponse;
                        }
                        if (serverConversationTracker) {
                            markServerInputAccepted();
                        }
                        completeCompactionExchange(state._lastTurnResponse.output, state._lastTurnResponse.responseId);
                        state._modelResponses.push(state._lastTurnResponse);
                        state._context.usage.add(state._lastTurnResponse.usage);
                        recordUsage(state._lastTurnResponse.usage);
                        state._noActiveAgentRun = false;
                        // After each turn record the items echoed by the server so future requests only
                        // include the incremental inputs that have not yet been acknowledged.
                        serverConversationTracker?.trackServerItems(state._lastTurnResponse);
                        if (serverConversationTracker) {
                            state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
                        }
                        const processedResponse = await (0, modelOutputs_1.processModelResponseAsync)(state._lastTurnResponse, state._currentAgent, preparedCall.tools, preparedCall.handoffs, state, 
                        // Loading authority retains the agent ownership lost in model input.
                        [
                            ...(Array.isArray(state._originalInput)
                                ? state._originalInput
                                : []),
                            ...state._generatedItems,
                        ], options.toolNotFoundBehavior, {
                            allowPromptSuppliedTools: preparedCall.allowPromptSuppliedTools,
                            beforeClientToolSearch: () => (0, turnResolution_1.preflightModelResponseToolInvocations)(state._currentAgent, state, state._lastTurnResponse, preparedCall.tools, preparedCall.handoffs, this, options.signal),
                        });
                        serverConversationTracker?.trackServerItems(state._lastTurnResponse, processedResponse.newItems);
                        state._lastProcessedResponse = processedResponse;
                        (0, modelPreparation_1.trackDeferredToolRecovery)(state, state._currentAgent, processedResponse);
                        const suppressedToolCalls = (0, turnResolution_1.preflightToolInvocations)(state._currentAgent, state, processedResponse);
                        await guardrailTracker.awaitCompletion();
                        (0, runLoop_1.markAcceptedResponseProcessingStarted)(state);
                        this.#captureResponseGuardrailBoundary(state, true);
                        const turnResult = await (0, turnResolution_1.resolveTurnAfterModelResponse)(state._currentAgent, state._originalInput, state._generatedItems, state._lastTurnResponse, state._lastProcessedResponse, this, state, toolErrorFormatter, agentToolParentRunConfig, options.errorHandlers, options.signal, suppressedToolCalls, attemptedRunErrorHandlers, (handoffAgent) => this.#validateModelTimeoutForAgent(handoffAgent));
                        if (turnResult.nextStep.type === 'next_step_handoff') {
                            this.#validateModelTimeoutForAgent(turnResult.nextStep.newAgent);
                        }
                        (0, runLoop_1.applyTurnResult)({
                            state,
                            turnResult,
                            agent: state._currentAgent,
                            toolsUsed: state._lastProcessedResponse?.toolsUsed ?? [],
                            resetTurnPersistence: !isResumedState,
                        });
                        if (options.signal?.aborted) {
                            const guardedFinalOutput = turnResult.nextStep.type === 'next_step_final_output' &&
                                this.#agentHasOutputGuardrail(state._currentAgent);
                            if (guardedFinalOutput && !isResumedState) {
                                // Ordinary callers cannot recover the runner-owned state from
                                // the original abort reason. Keep a replay-safe completion
                                // record without publishing the unchecked tool output.
                                (0, blockedOutputPersistence_1.redactCancelledResponseToolOutputs)(state, 'Tool output discarded because the run was cancelled before output validation.');
                                cancelledOutputRedacted = true;
                            }
                            if (!guardedFinalOutput || cancelledOutputRedacted) {
                                persistenceCheckpoint = new result_1.RunResult(state);
                            }
                            // Caller-owned RunState retains the candidate for validation on resume.
                        }
                        options.signal?.throwIfAborted();
                        if (turnResult.nextStep.type !== 'next_step_final_output') {
                            (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                            (0, invocationContext_1.setRunStateTurnSpanParent)(state, undefined);
                            currentTurnSpan = undefined;
                        }
                    }
                    const currentStep = state._currentStep;
                    if (!currentStep) {
                        logger_1.default.debug('Running next loop');
                        continue;
                    }
                    switch (currentStep.type) {
                        case 'next_step_final_output':
                            if (options.signal?.aborted) {
                                (0, sessionPersistence_1.releaseProvisionalSessionHistoryTransactionBinding)(state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                            }
                            options.signal?.throwIfAborted();
                            return await finalizeCurrentOutput();
                        case 'next_step_handoff':
                            this.#validateModelTimeoutForAgent(currentStep.newAgent);
                            state.setCurrentAgent(currentStep.newAgent);
                            if (state._currentAgentSpan) {
                                state._currentAgentSpan.end();
                                (0, context_1.resetCurrentSpan)();
                                state.setCurrentAgentSpan(undefined);
                            }
                            state._noActiveAgentRun = true;
                            state._currentTurnInProgress = false;
                            // We've processed the handoff, so we need to run the loop again.
                            state._currentStep = { type: 'next_step_run_again' };
                            break;
                        case 'next_step_interruption':
                            // Interrupted. Don't run any guardrails.
                            return completeResult(new result_1.RunResult(state));
                        case 'next_step_run_again':
                            state._currentTurnInProgress = false;
                            logger_1.default.debug('Running next loop');
                            break;
                        default:
                            logger_1.default.debug('Running next loop');
                    }
                }
            }
            catch (caughtError) {
                if (guardrailTracker.pending) {
                    await guardrailTracker.awaitCompletion({ suppressErrors: true });
                }
                const err = guardrailTracker.failed
                    ? guardrailTracker.error
                    : caughtError;
                if (guardrailTracker.failed) {
                    (0, errorHandlers_1.invalidateAcceptedResponseReplayEvidence)(state);
                }
                const restoredPendingTurn = rollbackUnstartedTurn(state, turnPendingModelRequest);
                turnPendingModelRequest = undefined;
                if (!restoredPendingTurn) {
                    state._currentTurnInProgress = false;
                }
                (0, errorHandlers_1.attachRunStateToError)(err, state);
                (0, sessionPersistence_1.releaseUnusedSessionHistoryTransactionBinding)(state);
                const errorHandled = state._pendingSessionWrite
                    ? undefined
                    : await (0, errorHandlers_1.prepareRunErrorFinalOutput)({
                        error: err,
                        state,
                        errorHandlers: options.errorHandlers,
                        responseAccepted: (0, runLoop_1.isAcceptedResponseCheckpoint)(state),
                        attemptedErrors: attemptedRunErrorHandlers,
                    });
                if (errorHandled) {
                    try {
                        return await finalizeCurrentOutput(errorHandled);
                    }
                    catch (finalizationError) {
                        recordNonStreamingError(finalizationError);
                        throw finalizationError;
                    }
                }
                recordNonStreamingError(err);
                throw err;
            }
            finally {
                (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                (0, invocationContext_1.setRunStateTurnSpanParent)(state, undefined);
                const preserveSandboxSessions = state._currentStep?.type === 'next_step_interruption';
                try {
                    try {
                        await (0, sandbox_1.finalizeSandboxRuntime)({
                            state: state,
                            sandboxRuntime,
                            preserveSessionsForInterruption: preserveSandboxSessions,
                            finishAgentSpanForInterruption: Boolean(taskSpan) || runError !== undefined,
                            runError,
                            groupId: this.config.groupId,
                            memoryContext: sandboxMemoryRunContext,
                            runAgent: async (agent, input, runOptions) => await this.run(agent, input, runOptions),
                            tracingParent: taskSpan?.span ??
                                state._currentAgentSpan ??
                                invocationSpanParent,
                        });
                    }
                    catch (error) {
                        (0, tracing_1.setRunnerSpanError)(taskSpan, error, this.config.traceIncludeSensitiveData);
                        await Promise.reject(error);
                    }
                    const resultToPersist = completedResult ?? persistenceCheckpoint;
                    if (resultToPersist && !completedResultPersisted) {
                        try {
                            await persistNonStreamingResult(resultToPersist, 
                            // The current response is already redacted; append the full
                            // suffix so earlier completed turns remain replayable.
                            cancelledOutputRedacted ? { runCompaction: false } : undefined);
                        }
                        catch (error) {
                            (0, tracing_1.setRunnerSpanError)(taskSpan, error, this.config.traceIncludeSensitiveData);
                            await Promise.reject(error);
                        }
                    }
                }
                finally {
                    (0, tracing_1.finishRunnerSpan)(taskSpan);
                }
            }
        });
    }
    /**
     * @internal
     */
    async #runStreamLoop(result, startingAgent, sandboxRuntime, options, isResumedState, ensureStreamInputPersisted, sessionTurnInputUpdate, sessionInputUpdate, getStreamInputForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, sandboxMemoryRunContext, taskSpan, invocationSpanParent, pendingSessionWriteReconciled = false) {
        const resolvedReasoningItemIdPolicy = options.reasoningItemIdPolicy ??
            (isResumedState ? result.state._reasoningItemIdPolicy : undefined) ??
            this.config.reasoningItemIdPolicy;
        result.state.setReasoningItemIdPolicy(resolvedReasoningItemIdPolicy);
        const resolvedConversationId = options.conversationId ?? result.state._conversationId;
        const resolvedPreviousResponseId = options.previousResponseId ?? result.state._previousResponseId;
        const serverManagesConversation = Boolean(resolvedConversationId) || Boolean(resolvedPreviousResponseId);
        assertPendingInputServerOwnership(result.state, resolvedConversationId, resolvedPreviousResponseId);
        const serverConversationTracker = serverManagesConversation
            ? new conversation_1.ServerConversationTracker({
                conversationId: resolvedConversationId,
                previousResponseId: resolvedPreviousResponseId,
                reasoningItemIdPolicy: resolvedReasoningItemIdPolicy,
            })
            : undefined;
        if (serverConversationTracker) {
            result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
        }
        let sentInputToModel = false;
        let streamInputPersisted = false;
        let guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
        const persistStreamInputIfNeeded = async () => {
            if (streamInputPersisted || !ensureStreamInputPersisted) {
                return;
            }
            // Both success and error paths call this helper, so guard against multiple writes.
            await ensureStreamInputPersisted();
            streamInputPersisted = true;
            (0, sessionPersistence_1.markSessionHistoryTransactionInputPersisted)(result.state);
        };
        const awaitInputGuardrails = async () => {
            await guardrailTracker.awaitCompletion();
            if (guardrailTracker.failed) {
                throw guardrailTracker.error;
            }
        };
        if (serverConversationTracker && isResumedState) {
            serverConversationTracker.primeFromState({
                originalInput: result.state._originalInput,
                generatedItems: result.state._generatedItems,
                modelResponses: result.state._modelResponses,
            });
            result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
        }
        const toolErrorFormatter = options.toolErrorFormatter ?? this.config.toolErrorFormatter;
        const outputGuardrailBlockedMessage = options.outputGuardrailBlockedMessage === undefined
            ? this.config.outputGuardrailBlockedMessage
            : options.outputGuardrailBlockedMessage;
        const agentToolParentRunConfig = this.#getAgentToolParentRunConfig(options);
        const useTaskAndTurnSpans = !this.config.tracingDisabled && (0, config_1.includeTaskAndTurnSpans)(options.tracing);
        // Tracks when we resume an approval interruption so the next run-again step stays in the same turn.
        let continuingInterruptedTurn = false;
        let runError;
        const attemptedRunErrorHandlers = new WeakSet();
        let suppressStreamInputPersistence = false;
        const resumedStateHasPersistedToolOutput = isResumedState && (0, blockedOutputPersistence_1.hasPersistedToolOutput)(result.state);
        let approvedToolCheckpointCompacted = pendingSessionWriteReconciled ||
            result.state._currentTurnSessionWriteCompactedItemCount ===
                result.state._currentTurnPersistedItemCount ||
            (resumedStateHasPersistedToolOutput &&
                !(0, blockedOutputPersistence_1.hasPendingApprovedToolInputCompaction)(result.state));
        let approvedToolCheckpointRequiresLocalInputCompaction = resumedStateHasPersistedToolOutput;
        let approvedToolCheckpointModelResponseCount = result.rawResponses.length;
        let approvedToolFinalSessionWritePreparation;
        let deferredApprovedToolFinalSessionWritePreparation;
        let currentTurnSpan;
        let turnPendingModelRequest;
        let commitDeferredLocalPendingInput;
        const parentUsageRecorder = (0, usageTracking_1.getRunnerParentUsageRecorder)(this);
        const recordUsage = (usage) => {
            (0, tracing_1.recordRunnerSpanUsage)(taskSpan, usage);
            (0, tracing_1.recordRunnerSpanUsage)(currentTurnSpan, usage);
            parentUsageRecorder?.(usage);
        };
        (0, usageTracking_1.setRunStateUsageRecorder)(result.state, recordUsage);
        const saveStreamResultWithCompactionOwnership = async (overrideOptions) => {
            if (this.#shouldDeferInterruptedSessionItems(result.state)) {
                return;
            }
            const hasUnpersistedItems = result.newItems.length > result.state._currentTurnPersistedItemCount ||
                (overrideOptions?.additionalRunItems?.length ?? 0) > 0;
            const modelResponseAdvanced = result.rawResponses.length > approvedToolCheckpointModelResponseCount;
            const compactionOptions = approvedToolCheckpointRequiresLocalInputCompaction
                ? approvedToolCheckpointCompacted &&
                    !hasUnpersistedItems &&
                    !modelResponseAdvanced
                    ? { runCompaction: false }
                    : { compactionMode: 'input' }
                : undefined;
            const persistenceOptions = {
                ...compactionOptions,
                ...overrideOptions,
            };
            const finalSessionWritePreparation = approvedToolFinalSessionWritePreparation;
            const sessionInputItems = streamInputPersisted
                ? undefined
                : getStreamInputForPersistence?.();
            // A remote session may commit addItems before rejecting, and compaction happens after the
            // append. Once the combined save starts, retrying the input is therefore unsafe.
            streamInputPersisted = true;
            await (0, sessionPersistence_1.saveStreamResultToSession)(options.session, result, {
                ...persistenceOptions,
                resumedSessionWritePreparation: finalSessionWritePreparation ??
                    persistenceOptions.resumedSessionWritePreparation,
            }, sessionInputItems);
            if (finalSessionWritePreparation) {
                approvedToolFinalSessionWritePreparation = undefined;
                if (persistenceOptions.deferResumedSessionWrite !== true) {
                    approvedToolCheckpointCompacted = true;
                    approvedToolCheckpointModelResponseCount = result.rawResponses.length;
                }
            }
        };
        const activateDeferredApprovedToolFinalSessionWrite = () => {
            const preparation = deferredApprovedToolFinalSessionWritePreparation;
            if (!preparation) {
                return;
            }
            if (result.state._pendingSessionHistoryTransaction !== undefined ||
                result.state._currentTurnDeferredSessionItemIndexes.size > 0 ||
                result.state._currentTurnBlockedSessionStartIndex !== undefined) {
                deferredApprovedToolFinalSessionWritePreparation = undefined;
                return;
            }
            if (!options.session || serverManagesConversation) {
                throw new errors_1.UserError('Resumed Session write preparation has no ordinary Session owner.');
            }
            deferredApprovedToolFinalSessionWritePreparation = undefined;
            approvedToolFinalSessionWritePreparation = preparation;
        };
        const recordStreamingError = (error) => {
            if (result.state._currentAgentSpan) {
                result.state._currentAgentSpan.setError({
                    message: 'Error in agent run',
                    data: {
                        error: (0, tracing_1.getRunnerSpanErrorDetails)(error, this.config.traceIncludeSensitiveData),
                    },
                });
            }
            (0, tracing_1.setRunnerSpanError)(currentTurnSpan, error, this.config.traceIncludeSensitiveData);
            (0, tracing_1.setRunnerSpanError)(taskSpan, error, this.config.traceIncludeSensitiveData);
            runError = error;
        };
        const finalizeStreamOutput = async (preparedErrorOutput) => {
            const currentStep = result.state._currentStep;
            if (currentStep?.type !== 'next_step_final_output') {
                throw new errors_1.ModelBehaviorError('Expected a final output step while finalizing the run.', result.state);
            }
            (0, runLoop_1.markAcceptedResponseFinalizationStarted)(result.state);
            result._hideFinalOutput();
            (0, blockedOutputPersistence_1.normalizeSerializedOutputGuardrailBlockedMessage)(result.state);
            const resolveBlockedMessage = (0, outputGuardrailBlockedMessage_1.createOutputGuardrailBlockedMessageResolver)(outputGuardrailBlockedMessage, result.state);
            const outputGuardrailResultStart = result.state._outputGuardrailResults.length;
            let outputGuardrailBlocked = false;
            try {
                await (0, guardrails_1.finalizeOutputGuardrails)({
                    state: result.state,
                    runnerOutputGuardrails: this.outputGuardrailDefs,
                    output: currentStep.output,
                    redactedOutput: outputGuardrailBlockedMessage_1.OUTPUT_GUARDRAIL_BLOCKED_TOOL_OUTPUT,
                    guardedTerminalToolOutput: (0, blockedOutputPersistence_1.hasTerminalToolOutputSource)(result.state),
                    signal: options.signal,
                    sanitizeRejectedOutput: (...args) => (0, blockedOutputPersistence_1.sanitizeBlockedTerminalToolOutput)(...args, resolveBlockedMessage, options.signal, () => {
                        outputGuardrailBlocked = true;
                    }),
                    persistBlockedOutput: !serverManagesConversation
                        ? async () => saveStreamResultWithCompactionOwnership({
                            outputBlocked: true,
                        })
                        : undefined,
                    persistUnblockedFailure: !serverManagesConversation
                        ? async () => {
                            activateDeferredApprovedToolFinalSessionWrite();
                            await saveStreamResultWithCompactionOwnership();
                        }
                        : undefined,
                    onBlockedOutput: () => {
                        outputGuardrailBlocked = true;
                    },
                    releaseBlockedOutputPersistence: sessionPersistence_1.releaseUnusedSessionHistoryTransactionBinding,
                });
            }
            catch (error) {
                if (!outputGuardrailBlocked &&
                    (deferredApprovedToolFinalSessionWritePreparation !== undefined ||
                        result.state._pendingSessionWrite !== undefined ||
                        approvedToolCheckpointCompacted)) {
                    result.state._outputGuardrailResults.splice(outputGuardrailResultStart);
                    if (deferredApprovedToolFinalSessionWritePreparation !== undefined &&
                        result.state._pendingSessionWrite === undefined) {
                        try {
                            activateDeferredApprovedToolFinalSessionWrite();
                            await saveStreamResultWithCompactionOwnership({
                                deferResumedSessionWrite: true,
                            });
                        }
                        catch (checkpointError) {
                            if (result.state._pendingSessionWrite === undefined) {
                                throw checkpointError;
                            }
                        }
                    }
                }
                throw error;
            }
            if (result.state._serializedCurrentStep === currentStep &&
                hasRetainableBlockedOutputEffect(result.state)) {
                (0, sessionPersistence_1.releaseProvisionalSessionHistoryTransactionBinding)(result.state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                throw new errors_1.UserError('Accepted final output cannot be resumed directly from serialized terminal state. Start a new run from persisted session history.');
            }
            activateDeferredApprovedToolFinalSessionWrite();
            (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
            (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, undefined);
            currentTurnSpan = undefined;
            result.state._currentTurnInProgress = false;
            // Guardrails must succeed before persisting session memory to avoid storing blocked outputs.
            if (!serverManagesConversation) {
                try {
                    await saveStreamResultWithCompactionOwnership(preparedErrorOutput?.deferredItem
                        ? { additionalRunItems: [preparedErrorOutput.deferredItem] }
                        : undefined);
                }
                catch (error) {
                    result.state._outputGuardrailResults.splice(outputGuardrailResultStart);
                    const itemCommitted = commitDeferredRunErrorItemAfterPartialPersistence(result.state, preparedErrorOutput);
                    if (itemCommitted && preparedErrorOutput?.deferredItem) {
                        (0, streaming_1.streamStepItemsToRunResult)(result, [
                            preparedErrorOutput.deferredItem,
                        ]);
                        recordStreamingError(error);
                        result._raiseError(error, { preserveQueuedItems: true });
                        return;
                    }
                    throw error;
                }
            }
            if (preparedErrorOutput?.deferredItem) {
                result.state._generatedItems.push(preparedErrorOutput.deferredItem);
            }
            if (preparedErrorOutput?.deferredItem) {
                (0, streaming_1.streamStepItemsToRunResult)(result, [preparedErrorOutput.deferredItem]);
                result._preserveQueuedItemsOnError();
            }
            result._revealFinalOutput();
            this.emit('agent_end', result.state._context, result.state._currentAgent, currentStep.output);
            result.state._currentAgent.emit('agent_end', result.state._context, currentStep.output);
        };
        try {
            while (true) {
                // Let the current action batch settle, but never start new work after
                // cancellation once a turn has already begun. Preserve the existing
                // first-request behavior for an initially aborted stream.
                if (result.cancelled &&
                    (result.state._currentTurn > 0 ||
                        result.state._currentStep?.type === 'next_step_final_output')) {
                    if (result.state._currentStep?.type === 'next_step_final_output') {
                        (0, sessionPersistence_1.releaseProvisionalSessionHistoryTransactionBinding)(result.state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                    }
                    return;
                }
                const currentAgent = result.state._currentAgent;
                result.state._currentStep = result.state._currentStep ?? {
                    type: 'next_step_run_again',
                };
                if ((0, runLoop_1.isAcceptedResponseCheckpoint)(result.state)) {
                    this.#captureResponseGuardrailBoundary(result.state, false);
                    await (0, runLoop_1.resumeAcceptedModelResponse)({
                        state: result.state,
                        runner: this,
                        toolErrorFormatter,
                        agentToolParentRunConfig,
                        signal: options.signal,
                        validateHandoffAgent: (handoffAgent) => {
                            this.#validateModelTimeoutForAgent(handoffAgent);
                        },
                        onStepItems: (turnResult) => {
                            (0, streaming_1.addStepToRunResult)(result, turnResult);
                        },
                    });
                }
                if (result.state._currentStep.type === 'next_step_interruption') {
                    await (0, sandbox_1.prepareSandboxInterruptedTurnResume)({
                        startingAgent,
                        state: result.state,
                        sandboxRuntime,
                        runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(result.state._currentAgent),
                        toolNameCollisionPolicy: options.toolNameCollisionPolicy,
                        tracingParent: (0, invocationContext_1.getRunStateTurnSpanParent)(result.state) ??
                            result.state._currentAgentSpan,
                    });
                    if (useTaskAndTurnSpans) {
                        currentTurnSpan = (0, tracing_1.ensureTurnSpan)(currentTurnSpan, result.state._currentTurn, result.state._currentAgent.name, result.state._currentAgentSpan);
                        (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, currentTurnSpan.span);
                    }
                    const interruptedOutcome = await (async () => {
                        let resumedSessionWritePreparation;
                        this.#captureResponseGuardrailBoundary(result.state, false);
                        const outcome = await (0, runLoop_1.resumeInterruptedTurn)({
                            state: result.state,
                            runner: this,
                            toolErrorFormatter,
                            agentToolParentRunConfig,
                            signal: options.signal,
                            validateHandoffAgent: (handoffAgent) => {
                                this.#validateModelTimeoutForAgent(handoffAgent);
                            },
                            onStepItems: (turnResult) => {
                                (0, streaming_1.addStepToRunResult)(result, turnResult);
                            },
                            onHandoff: (agent) => {
                                result._addItem(new events_1.RunAgentUpdatedStreamEvent(agent));
                            },
                            beforeResumedSideEffects: async () => {
                                if (options.session && !serverManagesConversation) {
                                    resumedSessionWritePreparation =
                                        await (0, sessionPersistence_1.prepareResumedSessionWrite)(options.session, result.state);
                                }
                                return resumedSessionWritePreparation;
                            },
                        });
                        if (outcome.resumedSideEffects) {
                            const checkpointDeferred = outcome.nextStep.type === 'next_step_final_output' &&
                                this.#agentHasOutputGuardrail(result.state._currentAgent);
                            approvedToolCheckpointRequiresLocalInputCompaction = true;
                            if (!serverManagesConversation &&
                                options.session &&
                                !this.#shouldDeferInterruptedSessionItems(result.state)) {
                                if (!resumedSessionWritePreparation) {
                                    throw new errors_1.UserError('Resumed Session write preparation is missing after approved tool execution.');
                                }
                                if (checkpointDeferred) {
                                    deferredApprovedToolFinalSessionWritePreparation =
                                        resumedSessionWritePreparation;
                                }
                                else if (outcome.nextStep.type === 'next_step_final_output') {
                                    approvedToolFinalSessionWritePreparation =
                                        resumedSessionWritePreparation;
                                }
                                else {
                                    await (0, sessionPersistence_1.saveStreamResultToSession)(options.session, result, {
                                        compactionMode: 'input',
                                        resumedSessionWritePreparation,
                                    });
                                    approvedToolCheckpointCompacted = true;
                                    approvedToolCheckpointModelResponseCount =
                                        result.rawResponses.length;
                                }
                            }
                        }
                        return outcome;
                    })();
                    // Don't reset counter here - resolveInterruptedTurn already adjusted it via rewind logic
                    // The counter will be reset when _currentTurn is incremented (starting a new turn)
                    const { shouldReturn, shouldContinue } = (0, runLoop_1.handleInterruptedOutcome)({
                        state: result.state,
                        outcome: interruptedOutcome,
                        setContinuingInterruptedTurn: (value) => {
                            continuingInterruptedTurn = value;
                        },
                    });
                    // Approval resolution belongs to the previous turn; any next model call
                    // starts a new counted turn with its own span and usage.
                    (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                    (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, undefined);
                    currentTurnSpan = undefined;
                    if (shouldReturn) {
                        // we are still in an interruption, so we need to avoid an infinite loop
                        return;
                    }
                    if (shouldContinue) {
                        continue;
                    }
                }
                if (result.state._currentStep.type === 'next_step_run_again') {
                    this.#validateModelTimeoutForAgent(result.state._currentAgent);
                    commitDeferredLocalPendingInput = undefined;
                    if (approvedToolCheckpointCompacted &&
                        result.state._currentTurnSessionHistoryTransactionSessionId ===
                            undefined) {
                        await (0, sessionPersistence_1.prepareSessionHistoryTransactionsForRun)(options.session, result.state, { serverManagesConversation: false });
                    }
                    guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
                    const wasContinuingInterruptedTurn = continuingInterruptedTurn;
                    continuingInterruptedTurn = false;
                    const previousTurn = result.state._currentTurn;
                    turnPendingModelRequest = {
                        currentTurn: previousTurn,
                        currentTurnInProgress: result.state._currentTurnInProgress,
                    };
                    const previousPersistedCount = result.state._currentTurnPersistedItemCount;
                    const previousGeneratedCount = result.state._generatedItems.length;
                    const preparedTurn = await (0, turnPreparation_1.prepareTurn)({
                        state: result.state,
                        input: result.input,
                        generatedItems: result.newItems,
                        isResumedState,
                        preserveTurnPersistenceOnResume,
                        continuingInterruptedTurn: wasContinuingInterruptedTurn,
                        serverConversationTracker,
                        inputGuardrailDefs: this.inputGuardrailDefs,
                        guardrailHandlers: {
                            onParallelPromise: guardrailTracker.setPromise,
                            onParallelError: (err) => {
                                guardrailTracker.setError(err);
                            },
                        },
                        emitAgentStart: (context, agent, inputItems) => {
                            this.emit('agent_start', context, agent, inputItems);
                        },
                        onAgentSpanReady: useTaskAndTurnSpans
                            ? (turn, agentName) => {
                                currentTurnSpan = (0, tracing_1.ensureTurnSpan)(currentTurnSpan, turn, agentName, result.state._currentAgentSpan);
                                (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, currentTurnSpan.span);
                            }
                            : undefined,
                        agentSpanParent: taskSpan?.span ?? invocationSpanParent,
                    });
                    if (preserveTurnPersistenceOnResume &&
                        result.state._currentTurn > previousTurn &&
                        previousPersistedCount <= previousGeneratedCount) {
                        // Preserve persisted offsets from a resumed run to avoid re-saving prior items.
                        result.state._currentTurnPersistedItemCount =
                            previousPersistedCount;
                    }
                    const { turnInput, pendingInputItems, pendingInputSourceItems } = preparedTurn;
                    // If guardrails are still running, defer input persistence until they finish.
                    const sessionPreparedTurnInput = [...turnInput];
                    const preparedSandboxAgent = await sandboxRuntime.prepareAgent({
                        currentAgent: result.state._currentAgent,
                        turnInput,
                        runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(result.state._currentAgent),
                        tracingParent: currentTurnSpan?.span ?? result.state._currentAgentSpan,
                    });
                    sessionTurnInputUpdate?.(sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                    const processedPendingInputItems = (0, pendingInput_1.mapPendingInputAfterContextProcessing)(pendingInputItems, sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                    const artifacts = await (0, modelPreparation_1.prepareAgentArtifacts)(result.state, preparedSandboxAgent.executionAgent, options.toolNameCollisionPolicy);
                    const preparedCall = await this.#prepareModelCall(result.state, preparedSandboxAgent.executionAgent, options, artifacts, preparedSandboxAgent.turnInput, serverConversationTracker, sessionInputUpdate);
                    (0, sessionPersistence_1.captureSessionHistoryTransactionInputItems)(options.session, result.state, getStreamInputForPersistence?.());
                    await guardrailTracker.throwIfError();
                    // Once a logical turn is established, do not start another model
                    // request if cancellation arrives during asynchronous preparation.
                    if ((sentInputToModel || isResumedState) && result.cancelled) {
                        rollbackUnstartedTurn(result.state, turnPendingModelRequest);
                        turnPendingModelRequest = undefined;
                        return;
                    }
                    const admittedPendingInput = (0, pendingInput_1.selectPendingInputForAdmission)(processedPendingInputItems, preparedCall);
                    let localPendingInputCommitted = false;
                    const commitLocalPendingInput = async () => {
                        if (serverConversationTracker || localPendingInputCommitted) {
                            return;
                        }
                        localPendingInputCommitted = true;
                        (0, pendingInput_1.commitPendingInput)(result.state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                        if ((0, pendingInput_1.hasUnpersistedRunInput)(result.state)) {
                            await (0, sessionPersistence_1.saveStreamResultToSession)(options.session, result, {
                                runCompaction: false,
                            });
                        }
                    };
                    const deferLocalPendingInputAdmission = !serverConversationTracker &&
                        pendingInputItems.length > 0 &&
                        guardrailTracker.pending;
                    if (deferLocalPendingInputAdmission) {
                        commitDeferredLocalPendingInput = async () => {
                            commitDeferredLocalPendingInput = undefined;
                            await commitLocalPendingInput();
                        };
                    }
                    else {
                        await commitLocalPendingInput();
                        if ((sentInputToModel || isResumedState) && result.cancelled) {
                            rollbackUnstartedTurn(result.state, turnPendingModelRequest);
                            turnPendingModelRequest = undefined;
                            return;
                        }
                    }
                    let finalResponse = undefined;
                    const abortReconciliationState = (0, streamReconciliation_1.createStreamAbortReconciliationState)();
                    let inputMarked = false;
                    let responseAcceptedCheckpointed = false;
                    let streamEventCount = 0;
                    let lastStreamEventType;
                    let timedOutModelCallFailed = false;
                    const markServerInputAccepted = (responseAvailable = true) => {
                        if (!serverConversationTracker) {
                            return;
                        }
                        if (!inputMarked) {
                            // Mark inputs after the first stream event, an explicit abort after
                            // request start, or provider advice that the failed request may have
                            // been accepted.
                            // Record the exact input that was sent so the server tracker can advance safely.
                            serverConversationTracker.markInputAsSent(preparedCall.filterApplied
                                ? preparedCall.sourceItems
                                : preparedCall.turnInput, {
                                filterApplied: preparedCall.filterApplied,
                                allTurnItems: preparedCall.turnInput,
                            });
                            (0, pendingInput_1.commitPendingInput)(result.state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                            if (pendingInputItems.length > 0) {
                                if (admittedPendingInput.length > 0) {
                                    serverConversationTracker.markInputAsSent(admittedPendingInput.map((item) => item.rawItem));
                                }
                            }
                            inputMarked = true;
                        }
                        if (!responseAcceptedCheckpointed &&
                            (pendingInputItems.length > 0 || !responseAvailable)) {
                            if (!responseAvailable) {
                                result.state._lastTurnResponse = undefined;
                            }
                            result.state._lastProcessedResponse = undefined;
                            result.state._currentStep = {
                                type: 'next_step_interruption',
                                data: { interruptions: [], responseAccepted: true },
                            };
                            responseAcceptedCheckpointed = true;
                        }
                    };
                    const reconcileStreamAbortIfNeeded = async () => {
                        if (!serverConversationTracker ||
                            !(0, streamReconciliation_1.shouldReconcileStreamAbort)(abortReconciliationState)) {
                            return;
                        }
                        const reconciliationInput = (0, streamReconciliation_1.buildAbortReconciliationInput)(abortReconciliationState);
                        try {
                            const reconciliationResponse = await (0, modelRetry_1.getResponseWithRetry)(preparedCall.model, {
                                systemInstructions: preparedCall.modelInput.instructions,
                                prompt: preparedCall.prompt,
                                ...(preparedCall.explicitlyModelSet
                                    ? { overridePromptModel: true }
                                    : {}),
                                input: reconciliationInput,
                                previousResponseId: (0, streamReconciliation_1.getAbortReconciliationPreviousResponseId)(abortReconciliationState, preparedCall),
                                conversationId: preparedCall.conversationId,
                                modelSettings: preparedCall.modelSettings,
                                _internal: preparedCall.modelRequestInternal,
                                tools: preparedCall.serializedTools,
                                toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
                                handoffs: preparedCall.serializedHandoffs,
                                outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(currentAgent.outputType),
                                tracing: (0, tracing_1.getTracing)(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
                            }, {
                                onModelFailureUsage: (usage) => recordModelFailureUsage(usage, result.state, recordUsage),
                            });
                            (0, streamReconciliation_1.markAbortReconciliationComplete)(abortReconciliationState, reconciliationResponse);
                            result.state._context.usage.add(reconciliationResponse.usage);
                            recordUsage(reconciliationResponse.usage);
                            serverConversationTracker.trackServerItems(reconciliationResponse);
                            result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
                        }
                        catch (error) {
                            (0, logger_1.logModelAndToolActionDebug)(logger_1.default, 'Failed to reconcile streamed tool calls after abort.', error);
                        }
                    };
                    const modelRequest = {
                        systemInstructions: preparedCall.modelInput.instructions,
                        prompt: preparedCall.prompt,
                        // Streaming requests should also honor explicitly chosen models.
                        ...(preparedCall.explicitlyModelSet
                            ? { overridePromptModel: true }
                            : {}),
                        input: preparedCall.modelInput.input,
                        previousResponseId: preparedCall.previousResponseId,
                        conversationId: preparedCall.conversationId,
                        modelSettings: preparedCall.modelSettings,
                        _internal: preparedCall.modelRequestInternal,
                        tools: preparedCall.serializedTools,
                        toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
                        handoffs: preparedCall.serializedHandoffs,
                        outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(currentAgent.outputType),
                        tracing: (0, tracing_1.getTracing)(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
                        signal: options.signal,
                    };
                    // Publish the turn only after the complete request is constructed,
                    // immediately before the model request starts.
                    turnPendingModelRequest = undefined;
                    result.currentTurn = result.state._currentTurn;
                    sentInputToModel = true;
                    const completeCompactionExchange = (0, sessionPersistence_1.prepareSessionCompactionExchange)(options.session, result.state, preparedCall.modelInput.input);
                    try {
                        for await (const event of (0, modelRetry_1.getStreamedResponseWithRetry)(preparedCall.model, modelRequest, {
                            onModelFailureUsage: (usage) => recordModelFailureUsage(usage, result.state, recordUsage),
                            onModelTimeout: () => {
                                timedOutModelCallFailed = true;
                            },
                            ...(serverConversationTracker
                                ? {
                                    onPossiblyAcceptedRequestFailure: () => markServerInputAccepted(false),
                                }
                                : {}),
                        })) {
                            streamEventCount++;
                            lastStreamEventType = event.type;
                            markServerInputAccepted(pendingInputItems.length === 0);
                            await guardrailTracker.throwIfError();
                            (0, streamReconciliation_1.recordStreamEventForAbortReconciliation)(abortReconciliationState, event);
                            if (event.type === 'response_done') {
                                (0, items_1.assertValidCompactionItems)(event.response.output);
                                let rawUsage;
                                if (modelRequest.modelSettings.preserveRawUsage === true) {
                                    try {
                                        rawUsage = (0, rawUsage_1.snapshotRawUsage)(event.response.rawUsage);
                                    }
                                    catch {
                                        rawUsage = undefined;
                                    }
                                }
                                const parsed = protocol_1.StreamEventResponseCompleted.parse({
                                    type: event.type,
                                    ...(event.providerData
                                        ? { providerData: event.providerData }
                                        : {}),
                                    response: {
                                        id: event.response.id,
                                        requestId: event.response.requestId,
                                        usage: event.response.usage,
                                        output: event.response.output,
                                        ...(event.response.providerData
                                            ? { providerData: event.response.providerData }
                                            : {}),
                                        ...(rawUsage !== undefined ? { rawUsage } : {}),
                                    },
                                });
                                finalResponse = {
                                    usage: new usage_1.Usage(parsed.response.usage),
                                    output: parsed.response.output,
                                    responseId: parsed.response.id,
                                    requestId: parsed.response.requestId,
                                    ...(rawUsage !== undefined ? { rawUsage } : {}),
                                };
                                result.state._lastTurnResponse = finalResponse;
                                result.state._context.usage.add(finalResponse.usage);
                                recordUsage(finalResponse.usage);
                            }
                            if (result.cancelled) {
                                // When the user's code exits a loop to consume the stream, we need to break
                                // this loop to prevent internal false errors and unnecessary processing
                                await awaitInputGuardrails();
                                await commitDeferredLocalPendingInput?.();
                                await reconcileStreamAbortIfNeeded();
                                return;
                            }
                            result._addItem(new events_1.RunRawModelStreamEvent(event));
                        }
                    }
                    catch (error) {
                        if ((0, streaming_1.isAbortError)(error)) {
                            if (sentInputToModel) {
                                markServerInputAccepted();
                            }
                            await awaitInputGuardrails();
                            await commitDeferredLocalPendingInput?.();
                            await reconcileStreamAbortIfNeeded();
                            return;
                        }
                        if (error instanceof errors_1.ModelTimeoutError || timedOutModelCallFailed) {
                            if (streamEventCount > 0) {
                                markServerInputAccepted(false);
                            }
                            await awaitInputGuardrails();
                            await commitDeferredLocalPendingInput?.();
                            await reconcileStreamAbortIfNeeded();
                        }
                        throw error;
                    }
                    if (finalResponse) {
                        markServerInputAccepted();
                    }
                    await awaitInputGuardrails();
                    await commitDeferredLocalPendingInput?.();
                    if (result.cancelled) {
                        return;
                    }
                    result.state._noActiveAgentRun = false;
                    if (!finalResponse) {
                        const lastEventKind = protocol_1.StreamEvent.options.find((schema) => schema.shape.type.value === lastStreamEventType)?.shape.type.value ??
                            (streamEventCount > 0 ? 'unknown' : 'none');
                        throw new errors_1.ModelBehaviorError(`Model did not produce a final response! Stream ended before response_done (event_count=${streamEventCount}, last_event_type=${lastEventKind}).`, result.state);
                    }
                    result.state._lastTurnResponse = finalResponse;
                    completeCompactionExchange(finalResponse.output, finalResponse.responseId);
                    // Keep the tracker in sync with the streamed response so reconnections remain accurate.
                    serverConversationTracker?.trackServerItems(finalResponse);
                    if (serverConversationTracker) {
                        result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
                    }
                    result.state._modelResponses.push(result.state._lastTurnResponse);
                    const processedResponse = await (0, modelOutputs_1.processModelResponseAsync)(result.state._lastTurnResponse, currentAgent, preparedCall.tools, preparedCall.handoffs, result.state, 
                    // Loading authority retains the agent ownership lost in model input.
                    [
                        ...(Array.isArray(result.state._originalInput)
                            ? result.state._originalInput
                            : []),
                        ...result.state._generatedItems,
                    ], options.toolNotFoundBehavior, {
                        allowPromptSuppliedTools: preparedCall.allowPromptSuppliedTools,
                        beforeClientToolSearch: () => (0, turnResolution_1.preflightModelResponseToolInvocations)(currentAgent, result.state, result.state._lastTurnResponse, preparedCall.tools, preparedCall.handoffs, this, options.signal),
                    });
                    serverConversationTracker?.trackServerItems(result.state._lastTurnResponse, processedResponse.newItems);
                    result.state._lastProcessedResponse = processedResponse;
                    (0, modelPreparation_1.trackDeferredToolRecovery)(result.state, currentAgent, processedResponse);
                    const suppressedToolCalls = (0, turnResolution_1.preflightToolInvocations)(currentAgent, result.state, processedResponse);
                    const streamableItems = (0, turnResolution_1.filterSuppressedToolCallItems)(processedResponse.newItems, suppressedToolCalls);
                    // Record the items emitted directly from the model response so we do not
                    // stream them again after tools and other side effects finish.
                    const preToolItems = new Set(streamableItems);
                    if (preToolItems.size > 0) {
                        (0, streaming_1.streamStepItemsToRunResult)(result, streamableItems);
                    }
                    (0, runLoop_1.markAcceptedResponseProcessingStarted)(result.state);
                    this.#captureResponseGuardrailBoundary(result.state, true);
                    const turnResult = await (0, turnResolution_1.resolveTurnAfterModelResponse)(currentAgent, result.state._originalInput, result.state._generatedItems, result.state._lastTurnResponse, result.state._lastProcessedResponse, this, result.state, toolErrorFormatter, agentToolParentRunConfig, options.errorHandlers, options.signal, suppressedToolCalls, attemptedRunErrorHandlers, (handoffAgent) => this.#validateModelTimeoutForAgent(handoffAgent));
                    if (turnResult.nextStep.type === 'next_step_handoff') {
                        this.#validateModelTimeoutForAgent(turnResult.nextStep.newAgent);
                    }
                    (0, runLoop_1.applyTurnResult)({
                        state: result.state,
                        turnResult,
                        agent: currentAgent,
                        toolsUsed: processedResponse.toolsUsed,
                        resetTurnPersistence: !isResumedState,
                        onStepItems: (step) => {
                            (0, streaming_1.addStepToRunResult)(result, step, { skipItems: preToolItems });
                        },
                    });
                    if (turnResult.nextStep.type !== 'next_step_final_output') {
                        (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
                        (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, undefined);
                        currentTurnSpan = undefined;
                    }
                }
                const currentStep = result.state._currentStep;
                switch (currentStep.type) {
                    case 'next_step_final_output':
                        await finalizeStreamOutput();
                        return;
                    case 'next_step_interruption':
                        // We are done for now. Don't run any output guardrails.
                        if (!serverManagesConversation) {
                            await saveStreamResultWithCompactionOwnership();
                        }
                        return;
                    case 'next_step_handoff':
                        this.#validateModelTimeoutForAgent(currentStep.newAgent);
                        result.state.setCurrentAgent(currentStep.newAgent);
                        if (result.state._currentAgentSpan) {
                            result.state._currentAgentSpan.end();
                            (0, context_1.resetCurrentSpan)();
                        }
                        result.state.setCurrentAgentSpan(undefined);
                        result._addItem(new events_1.RunAgentUpdatedStreamEvent(result.state._currentAgent));
                        result.state._noActiveAgentRun = true;
                        result.state._currentTurnInProgress = false;
                        // We've processed the handoff, so we need to run the loop again.
                        result.state._currentStep = {
                            type: 'next_step_run_again',
                        };
                        break;
                    case 'next_step_run_again':
                        result.state._currentTurnInProgress = false;
                        logger_1.default.debug('Running next loop');
                        break;
                    default:
                        logger_1.default.debug('Running next loop');
                }
            }
        }
        catch (caughtError) {
            if (guardrailTracker.pending) {
                await guardrailTracker.awaitCompletion({ suppressErrors: true });
            }
            if (!guardrailTracker.failed) {
                await commitDeferredLocalPendingInput?.();
            }
            const error = guardrailTracker.failed
                ? guardrailTracker.error
                : caughtError;
            const restoredPendingTurn = rollbackUnstartedTurn(result.state, turnPendingModelRequest);
            turnPendingModelRequest = undefined;
            if (!restoredPendingTurn) {
                result.state._currentTurnInProgress = false;
            }
            (0, errorHandlers_1.attachRunStateToError)(error, result.state);
            (0, sessionPersistence_1.releaseUnusedSessionHistoryTransactionBinding)(result.state);
            suppressStreamInputPersistence =
                error instanceof items_1.CompactionItemValidationError;
            const errorHandled = result.state._pendingSessionWrite
                ? undefined
                : await (0, errorHandlers_1.prepareRunErrorFinalOutput)({
                    error,
                    state: result.state,
                    errorHandlers: options.errorHandlers,
                    streamResult: result,
                    responseAccepted: (0, runLoop_1.isAcceptedResponseCheckpoint)(result.state),
                    attemptedErrors: attemptedRunErrorHandlers,
                });
            if (errorHandled) {
                try {
                    await finalizeStreamOutput(errorHandled);
                    return;
                }
                catch (finalizationError) {
                    recordStreamingError(finalizationError);
                    throw finalizationError;
                }
            }
            recordStreamingError(error);
            throw error;
        }
        finally {
            (0, tracing_1.finishRunnerSpan)(currentTurnSpan);
            (0, invocationContext_1.setRunStateTurnSpanParent)(result.state, undefined);
            if (guardrailTracker.pending) {
                await guardrailTracker.awaitCompletion({ suppressErrors: true });
            }
            if (sentInputToModel &&
                !streamInputPersisted &&
                !guardrailTracker.failed &&
                !suppressStreamInputPersistence) {
                await persistStreamInputIfNeeded();
            }
            const preserveSandboxSessions = result.state._currentStep?.type === 'next_step_interruption' ||
                (result.cancelled &&
                    result.state._currentStep?.type !== 'next_step_final_output' &&
                    runError === undefined);
            try {
                try {
                    await (0, sandbox_1.finalizeSandboxRuntime)({
                        state: result.state,
                        sandboxRuntime,
                        preserveSessionsForInterruption: preserveSandboxSessions,
                        finishAgentSpanForInterruption: Boolean(taskSpan) || runError !== undefined,
                        runError,
                        groupId: this.config.groupId,
                        memoryContext: sandboxMemoryRunContext,
                        runAgent: async (agent, input, runOptions) => await this.run(agent, input, runOptions),
                        tracingParent: taskSpan?.span ??
                            result.state._currentAgentSpan ??
                            invocationSpanParent,
                    });
                }
                catch (error) {
                    (0, tracing_1.setRunnerSpanError)(taskSpan, error, this.config.traceIncludeSensitiveData);
                    await Promise.reject(error);
                }
            }
            finally {
                (0, tracing_1.finishRunnerSpan)(taskSpan);
            }
        }
    }
    /**
     * @internal
     */
    async #runIndividualStream(agent, input, taskSpanName, options, ensureStreamInputPersisted, sessionTurnInputUpdate, sessionInputUpdate, getStreamInputForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, sandboxMemoryRunContext, invocationSpanParent, pendingSessionWriteReconciled = false, sessionCompaction) {
        options = options ?? {};
        return (0, context_1.withNewSpanContext)(async () => {
            // Initialize or reuse existing state
            const isResumedState = input instanceof runState_1.RunState;
            const state = isResumedState
                ? input
                : new runState_1.RunState(options.context instanceof runContext_1.RunContext
                    ? options.context
                    : new runContext_1.RunContext(options.context), input, agent, options.maxTurns === undefined
                    ? constants_1.DEFAULT_MAX_TURNS
                    : options.maxTurns);
            (0, sessionPersistence_1.bindSessionCompactionState)(state, sessionCompaction);
            this.#validateModelTimeoutForAgent(state._currentAgent);
            if (isResumedState) {
                state._agentToolInvocation = undefined;
                if (options.maxTurns !== undefined) {
                    state._maxTurns = options.maxTurns;
                }
            }
            const resolvedReasoningItemIdPolicy = options.reasoningItemIdPolicy ??
                (isResumedState ? state._reasoningItemIdPolicy : undefined) ??
                this.config.reasoningItemIdPolicy;
            state.setReasoningItemIdPolicy(resolvedReasoningItemIdPolicy);
            const resolvedConversationId = options.conversationId ??
                (isResumedState ? state._conversationId : undefined);
            const resolvedPreviousResponseId = options.previousResponseId ??
                (isResumedState ? state._previousResponseId : undefined);
            if (!isResumedState) {
                await (0, sessionPersistence_1.prepareSessionHistoryTransactionsForRun)(options.session, state, {
                    serverManagesConversation: Boolean(resolvedConversationId || resolvedPreviousResponseId),
                });
            }
            const useTaskAndTurnSpans = !this.config.tracingDisabled &&
                (0, config_1.includeTaskAndTurnSpans)(options.tracing);
            const resumingInterruptedTurn = isResumedState && state._currentStep?.type === 'next_step_interruption';
            const invocationSpans = useTaskAndTurnSpans
                ? (0, tracing_1.startRunnerInvocationSpans)({
                    name: taskSpanName,
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    resumeInterruptedTurn: resumingInterruptedTurn,
                    parent: invocationSpanParent,
                })
                : undefined;
            const taskSpan = invocationSpans?.taskSpan;
            const optOutResumeAgentSpan = resumingInterruptedTurn && !useTaskAndTurnSpans
                ? (0, tracing_1.ensureActiveAgentSpanForInterruptedResume)({
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    parent: invocationSpanParent ?? (0, context_1.getCurrentTrace)() ?? undefined,
                })
                : undefined;
            if (useTaskAndTurnSpans && isResumedState) {
                state.setCurrentAgentSpan(invocationSpans?.agentSpan);
            }
            else if (optOutResumeAgentSpan) {
                state.setCurrentAgentSpan(optOutResumeAgentSpan);
            }
            const sandboxRuntime = new runtime_1.SandboxRuntimeManager({
                startingAgent: agent,
                sandboxConfig: options.sandbox ?? this.config.sandbox,
                runState: isResumedState
                    ? state
                    : undefined,
            });
            if (!isResumedState) {
                state.setConversationContext(resolvedConversationId, resolvedPreviousResponseId);
            }
            // Initialize the streamed result with existing state
            const result = new result_1.StreamedRunResult({
                signal: options.signal,
                state,
            });
            result._setAgentToolStreamBuffer((0, agentToolStream_1.getAgentToolStreamBuffer)(this));
            const streamOptions = {
                ...options,
                signal: result._getAbortSignal(),
            };
            // Setup defaults
            result.maxTurns = state._maxTurns;
            // Continue the stream loop without blocking
            const streamLoopPromise = this.#runStreamLoop(result, agent, sandboxRuntime, streamOptions, isResumedState, ensureStreamInputPersisted, sessionTurnInputUpdate, sessionInputUpdate, getStreamInputForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, sandboxMemoryRunContext, taskSpan, invocationSpanParent, pendingSessionWriteReconciled).then(() => {
                result._done();
            }, (err) => {
                result._raiseError(err);
            });
            // Attach the stream loop promise so trace end waits for the loop to complete
            result._setStreamLoopPromise(streamLoopPromise);
            return result;
        });
    }
    /**
     * @internal
     * Validates timeout settings before turn preparation can run hooks, persist
     * input, or initialize sandbox resources.
     */
    #validateModelTimeoutForAgent(executionAgent) {
        const agentModelSettings = executionAgent.hasExplicitModelSettings()
            ? executionAgent.modelSettings
            : undefined;
        (0, modelRetry_1.validateModelTimeoutMs)((0, modelSettings_1.mergeModelSettings)(this.config.modelSettings, agentModelSettings));
    }
    /**
     * @internal
     * Applies call-level filters and merges session updates so the model request mirrors exactly
     * what we persisted for history.
     */
    async #prepareModelCall(state, executionAgent, options, artifacts, turnInput, serverConversationTracker, sessionInputUpdate) {
        const { model, explicitlyModelSet, resolvedModelName } = await this.#resolveModelForAgent(executionAgent);
        const hasExplicitAgentModelSettings = executionAgent.hasExplicitModelSettings();
        // Store is caller-owned even when reasoning/text settings are implicit defaults.
        const agentModelSettings = hasExplicitAgentModelSettings
            ? executionAgent.modelSettings
            : Object.prototype.hasOwnProperty.call(executionAgent.modelSettings, 'store')
                ? { store: executionAgent.modelSettings.store }
                : undefined;
        // Only adapters that honor prompt model selection can replace the default model.
        const promptOwnsModel = model.supportsPromptModelSelection === true &&
            executionAgent.prompt !== undefined &&
            !explicitlyModelSet;
        const implicitModelSettings = hasExplicitAgentModelSettings || promptOwnsModel
            ? undefined
            : (0, runConfig_1.getImplicitModelSettingsForResolvedModel)(explicitlyModelSet, resolvedModelName);
        let modelSettings = (0, modelSettings_1.mergeModelSettings)(implicitModelSettings, this.config.modelSettings);
        modelSettings = (0, modelSettings_1.mergeModelSettings)(modelSettings, agentModelSettings);
        // Record effort ownership before legacy model cleanup can remove an explicit choice.
        const hasReasoningEffort = modelSettings.reasoning?.effort !== undefined ||
            modelSettings.providerData?.reasoning_effort !== undefined;
        const modelRequestInternal = {
            reasoningEffortImplicit: hasReasoningEffort
                ? implicitModelSettings?.reasoning?.effort !== undefined &&
                    !hasExplicitTopLevelReasoningEffort(this.config.modelSettings) &&
                    !hasExplicitTopLevelReasoningEffort(agentModelSettings)
                : undefined,
            tracingParent: (0, invocationContext_1.getRunStateTurnSpanParent)(state) ?? state._currentAgentSpan,
            toolNameCollisionPolicy: options.toolNameCollisionPolicy ?? 'warn',
        };
        modelSettings = (0, modelSettings_1.adjustModelSettingsForLegacyModel)(explicitlyModelSet, agentModelSettings ?? implicitModelSettings ?? {}, modelSettings, resolvedModelName);
        modelSettings = (0, modelSettings_1.maybeResetToolChoice)(state._currentAgent, state._toolUseTracker, modelSettings);
        (0, modelRetry_1.validateModelTimeoutMs)(modelSettings);
        state._lastModelSettings = modelSettings;
        const systemInstructions = await executionAgent.getSystemPrompt(state._context);
        const prompt = await executionAgent.getPrompt(state._context);
        const allowPromptSuppliedTools = Boolean(prompt) &&
            !(artifacts.toolsExplicitlyProvided &&
                artifacts.serializedTools.length === 0 &&
                artifacts.serializedHandoffs.length === 0);
        const { modelInput, sourceItems, persistedItems, sourceMatchKinds, filterApplied, preserveInputIdentity, } = await (0, conversation_1.applyCallModelInputFilter)(state._currentAgent, options.callModelInputFilter, state._context, turnInput, systemInstructions);
        // Persist normalized clones so session history mirrors the exact model payload. An empty array
        // is intentional when a filter removes everything.
        sessionInputUpdate?.(sourceItems, persistedItems);
        const previousResponseId = serverConversationTracker?.previousResponseId ??
            options.previousResponseId;
        const conversationId = serverConversationTracker?.conversationId ?? options.conversationId;
        return {
            ...artifacts,
            model,
            explicitlyModelSet,
            modelRequestInternal,
            modelSettings,
            modelInput,
            prompt,
            allowPromptSuppliedTools,
            previousResponseId,
            conversationId,
            sourceItems,
            persistedItems,
            sourceMatchKinds,
            filterApplied,
            preserveInputIdentity,
            turnInput,
        };
    }
}
exports.Runner = Runner;
// internal helpers and constants
let defaultRunner;
function hasExplicitTopLevelReasoningEffort(settings) {
    return settings?.reasoning?.effort !== undefined;
}
const getDefaultRunner = () => {
    if (!defaultRunner) {
        defaultRunner = new Runner();
    }
    return defaultRunner;
};
//# sourceMappingURL=run.js.map