UNPKG

@openai/agents-core

Version:

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

2,303 lines • 139 kB
import { getAgentToolStreamBuffer } from "./runner/agentToolStream.mjs";
import { Agent } from "./agent.mjs";
import { RunAgentUpdatedStreamEvent, RunRawModelStreamEvent } from "./events.mjs";
import { AgentsError, ModelBehaviorError, ModelTimeoutError, UserError, } from "./errors.mjs";
import { defineInputGuardrail, defineOutputGuardrail, } from "./guardrail.mjs";
import { RunHooks } from "./lifecycle.mjs";
import logger, { logModelAndToolActionDebug } from "./logger.mjs";
import { getDefaultModelProvider } from "./providers.mjs";
import { RunContext } from "./runContext.mjs";
import { RunResult, StreamedRunResult } from "./result.mjs";
import { assertPendingSessionCompactionTerminalAuthority, RunState, } from "./runState.mjs";
import { getCurrentTrace, getCurrentTraceContext, resetCurrentSpan, setCurrentSpan, withNewSpanContext, withTrace, withTraceContext, } from "./tracing/context.mjs";
import { includeTaskAndTurnSpans, mergeTracingConfig } from "./tracing/config.mjs";
import { Usage } from "./usage.mjs";
import { convertAgentOutputTypeToSerializable } from "./utils/tools.mjs";
import { snapshotRawUsage } from "./utils/rawUsage.mjs";
import { DEFAULT_MAX_TURNS } from "./runner/constants.mjs";
import { StreamEvent, StreamEventResponseCompleted } from "./types/protocol.mjs";
import { SandboxRuntimeManager } from "./sandbox/runtime/index.mjs";
import { ServerConversationTracker, applyCallModelInputFilter, getServerConversationOwner, } from "./runner/conversation.mjs";
import { createGuardrailTracker, finalizeOutputGuardrails, } from "./runner/guardrails.mjs";
import { adjustModelSettingsForLegacyModel, mergeModelSettings, maybeResetToolChoice, selectModel, } from "./runner/modelSettings.mjs";
import { getResponseWithRetry, getStreamedResponseWithRetry, validateModelTimeoutMs, } from "./runner/modelRetry.mjs";
import { processModelResponseAsync } from "./runner/modelOutputs.mjs";
import { addStepToRunResult, streamStepItemsToRunResult, isAbortError, } from "./runner/streaming.mjs";
import { acquireResumedSessionWriteOperation, createSessionPersistenceTracker, getSessionCompactionState, bindSessionCompactionState, prepareSessionCompactionExchange, captureSessionHistoryTransactionInputItems, markSessionHistoryTransactionInputPersisted, prepareSessionHistoryTransactionsForRun, prepareResumedSessionWrite, reconcilePendingSessionWriteBeforeRun, releaseProvisionalSessionHistoryTransactionBinding, releaseUnusedSessionHistoryTransactionBinding, prepareInputItemsWithSession, saveStreamInputToSession, saveStreamResultToSession, saveToSession, } from "./runner/sessionPersistence.mjs";
import { filterSuppressedToolCallItems, preflightModelResponseToolInvocations, preflightToolInvocations, resolveTurnAfterModelResponse, } from "./runner/turnResolution.mjs";
import { assertResumedSessionOutputGuardrailSafety, captureCurrentResponseToolOutputGuardrailResultStart, normalizeSerializedOutputGuardrailBlockedMessage, hasBlockedOutputExecutionEffect, hasPendingApprovedToolInputCompaction, hasPersistedToolOutput, hasTerminalToolOutputSource, sanitizeBlockedTerminalToolOutput, redactCancelledResponseToolOutputs, shouldDeferInterruptedSessionItems, } from "./runner/blockedOutputPersistence.mjs";
import { createOutputGuardrailBlockedMessageResolver, OUTPUT_GUARDRAIL_BLOCKED_TOOL_OUTPUT, } from "./runner/outputGuardrailBlockedMessage.mjs";
import { prepareTurn } from "./runner/turnPreparation.mjs";
import { commitPendingInput, hasUnpersistedRunInput, mapPendingInputAfterContextProcessing, selectPendingInputForAdmission, } from "./runner/pendingInput.mjs";
import { prepareAgentArtifacts, trackDeferredToolRecovery, } from "./runner/modelPreparation.mjs";
import { applyTurnResult, assertAcceptedResponseContinuationAuthority, handleInterruptedOutcome, isAcceptedResponseCheckpoint, markAcceptedResponseProcessingStarted, markAcceptedResponseFinalizationStarted, resumeAcceptedModelResponse, resumeInterruptedTurn, } from "./runner/runLoop.mjs";
import { applyTraceOverrides, ensureActiveAgentSpanForInterruptedResume, ensureTurnSpan, finishRunnerSpan, getRunnerSpanErrorDetails, getTracing, setRunnerSpanError, startRunnerInvocationSpans, recordRunnerSpanUsage, } from "./runner/tracing.mjs";
import { getRunnerParentUsageRecorder, setRunStateUsageRecorder, } from "./runner/usageTracking.mjs";
import { getRunnerInvocationSpanParent, getRunStateTurnSpanParent, setRunStateTurnSpanParent, } from "./runner/invocationContext.mjs";
import { NoopTrace } from "./tracing/traces.mjs";
import { NOOP_TRACE_OR_SPAN_ID } from "./tracing/utils.mjs";
import { assertValidCompactionItems, CompactionItemValidationError, } from "./runner/items.mjs";
import { attachRunStateToError, invalidateAcceptedResponseReplayEvidence, prepareRunErrorFinalOutput, } from "./runner/errorHandlers.mjs";
import { finalizeSandboxRuntime, isSandboxRuntimeAgent, prepareSandboxInterruptedTurnResume, } from "./runner/sandbox.mjs";
import { buildAbortReconciliationInput, createStreamAbortReconciliationState, getAbortReconciliationPreviousResponseId, markAbortReconciliationComplete, recordStreamEventForAbortReconciliation, shouldReconcileStreamAbort, } from "./runner/streamReconciliation.mjs";
import { getImplicitModelSettingsForResolvedModel, validateToolExecutionConfig, validateToolNameCollisionPolicy, } from "./runner/runConfig.mjs";
function hasRetainableBlockedOutputEffect(state) {
    return 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;
}
export { getTracing } from "./runner/tracing.mjs";
export { selectModel } from "./runner/modelSettings.mjs";
export { getTurnInput } from "./runner/items.mjs";
class LazyDefaultModelProvider {
    #modelProvider;
    getModel(modelName) {
        const modelProvider = this.#modelProvider ?? getDefaultModelProvider();
        this.#modelProvider = modelProvider;
        return modelProvider.getModel(modelName);
    }
}
function isNoopTrace(trace) {
    return trace instanceof NoopTrace || trace?.traceId === 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 ||
        getServerConversationOwner(conversationId, previousResponseId)) {
        return;
    }
    throw new UserError('Pending RunState input requires exactly one server-managed conversation owner', state);
}
export 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.
 */
export class Runner extends 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: validateToolExecutionConfig(config.toolExecution),
            toolNotFoundBehavior: config.toolNotFoundBehavior ?? 'raise_error',
            toolNameCollisionPolicy: 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(defineInputGuardrail);
        this.outputGuardrailDefs = (config.outputGuardrails ?? []).map(defineOutputGuardrail);
    }
    async run(agent, input, options = {
        stream: false,
        context: undefined,
    }) {
        if (input instanceof RunState &&
            (input._currentTurn > 0 || input._pendingInput.length > 0) &&
            !input._initialInputGuardrailsCompleted) {
            throw new 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 ? input._currentAgent : agent);
        if (input instanceof RunState) {
            if (isNoopTrace(input._trace)) {
                input._trace = null;
            }
            if (input._currentAgentSpan?.spanId === NOOP_TRACE_OR_SPAN_ID) {
                input.setCurrentAgentSpan(undefined);
            }
        }
        const taskSpanName = this.#getTaskSpanName(input instanceof RunState ? input._trace?.name : undefined);
        const capturedInvocationTraceContext = getCurrentTraceContext();
        const invocationTraceContext = isNoopTrace(capturedInvocationTraceContext?.trace)
            ? undefined
            : capturedInvocationTraceContext;
        const configuredInvocationSpanParent = getRunnerInvocationSpanParent(this);
        const invocationSpanParent = configuredInvocationSpanParent ??
            (input instanceof 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 ? input._reasoningItemIdPolicy : undefined) ??
            this.config.reasoningItemIdPolicy;
        const toolExecution = validateToolExecutionConfig(resolvedOptions.toolExecution ?? this.config.toolExecution);
        const toolNotFoundBehavior = resolvedOptions.toolNotFoundBehavior ?? this.config.toolNotFoundBehavior;
        const toolNameCollisionPolicy = validateToolNameCollisionPolicy(resolvedOptions.toolNameCollisionPolicy === undefined
            ? this.config.toolNameCollisionPolicy
            : resolvedOptions.toolNameCollisionPolicy);
        const hasCallModelInputFilter = Boolean(callModelInputFilter);
        const tracingConfig = mergeTracingConfig(this.config.tracing, resolvedOptions.tracing);
        const runContext = input instanceof RunState
            ? input._context
            : resolvedOptions.context instanceof RunContext
                ? resolvedOptions.context
                : new 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 && includeTaskAndTurnSpans(tracingConfig);
        const resumingFromState = input instanceof 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 = getSessionCompactionState(session, input instanceof RunState ? input : undefined);
        const resumedState = resumingFromState
            ? input
            : undefined;
        if (resumedState?._resumedSessionWriteInProgress) {
            throw new UserError('The same RunState cannot resume or reconcile a Session write concurrently.');
        }
        const resumedStateRequiresInputCompaction = resumedState !== undefined &&
            hasPendingApprovedToolInputCompaction(resumedState);
        if (resumedStateRequiresInputCompaction) {
            if (serverManagesConversation || session === undefined) {
                throw new UserError('A pending Session compaction requires the same ordinary local Session to resume safely.');
            }
            assertPendingSessionCompactionTerminalAuthority(resumedState);
        }
        const releaseResumedSessionWriteOperation = resumedState &&
            (resumedState._pendingSessionWrite !== undefined ||
                resumedState._currentTurnSessionWriteCompactedItemCount !== undefined ||
                resumedStateRequiresInputCompaction ||
                resumedState._currentStep?.type === 'next_step_interruption')
            ? acquireResumedSessionWriteOperation(resumedState)
            : undefined;
        let releaseResumedSessionWriteOperationOnReturn = true;
        try {
            let provisionalSessionHistoryTransactionSessionId;
            let provisionalSessionHistoryTransactionInputItems;
            let pendingSessionWriteReconciled = false;
            if (resumingFromState) {
                assertAcceptedResponseContinuationAuthority(resumedState, effectiveOptions.conversationId, effectiveOptions.previousResponseId);
                const hadSessionBinding = resumedState._currentTurnSessionHistoryTransactionSessionId !==
                    undefined;
                const portableInputItems = resumedState._currentTurnSessionHistoryTransactionInputItems;
                assertResumedSessionOutputGuardrailSafety(resumedState, session, this.#agentHasOutputGuardrail(resumedState._currentAgent));
                pendingSessionWriteReconciled =
                    await reconcilePendingSessionWriteBeforeRun(session, resumedState, {
                        serverManagesConversation,
                        operationAlreadyOwned: releaseResumedSessionWriteOperation !== undefined,
                    });
                resumedState.setReasoningItemIdPolicy(reasoningItemIdPolicy);
                await prepareSessionHistoryTransactionsForRun(session, resumedState, {
                    serverManagesConversation,
                });
                if (!hadSessionBinding) {
                    provisionalSessionHistoryTransactionSessionId =
                        resumedState._currentTurnSessionHistoryTransactionSessionId;
                    provisionalSessionHistoryTransactionInputItems = portableInputItems;
                }
            }
            const sessionPersistence = createSessionPersistenceTracker({
                session,
                runContext,
                compactionState: sessionCompaction,
                hasCallModelInputFilter,
                persistInput: saveStreamInputToSession,
                resumingFromState,
                resumedSessionInputItems: resumingFromState
                    ? input
                        ._currentTurnSessionHistoryTransactionInputItems
                    : undefined,
            });
            let preparedInput = input;
            if (!(preparedInput instanceof RunState)) {
                const prepared = await 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 saveToSession(session, sessionPersistence.getItemsForPersistence(), result, persistenceOptions);
                    }
                    : undefined, pendingSessionWriteReconciled, sessionCompaction);
                return runResult;
            };
            if (this.config.tracingDisabled) {
                const disabledTrace = new NoopTrace();
                if (preparedInput instanceof RunState) {
                    preparedInput._currentAgentSpan?.end();
                    preparedInput._trace = null;
                    preparedInput.setCurrentAgentSpan(undefined);
                }
                return await withTrace(disabledTrace, async () => {
                    try {
                        const result = await executeRun(disabledTrace);
                        const clearDisabledTraceState = () => {
                            result.state._trace = null;
                            result.state.setCurrentAgentSpan(undefined);
                        };
                        if (result instanceof StreamedRunResult) {
                            void result.completed.then(clearDisabledTraceState, clearDisabledTraceState);
                        }
                        else {
                            clearDisabledTraceState();
                        }
                        return result;
                    }
                    catch (error) {
                        if (error instanceof AgentsError && error.state) {
                            error.state._trace = null;
                            error.state.setCurrentAgentSpan(undefined);
                        }
                        throw error;
                    }
                });
            }
            if (preparedInput instanceof RunState && preparedInput._trace) {
                const applied = applyTraceOverrides(preparedInput._trace, preparedInput._currentAgentSpan, traceOverrides);
                preparedInput._trace = applied.trace;
                preparedInput._currentAgentSpan = applied.currentSpan;
                return await withTrace(preparedInput._trace, async () => {
                    if (preparedInput._currentAgentSpan && !useTaskAndTurnSpans) {
                        setCurrentSpan(preparedInput._currentAgentSpan);
                    }
                    return executeRun();
                });
            }
            const executeInInvocationTrace = async (effectiveInvocationSpanParent = invocationSpanParent) => {
                if (preparedInput instanceof RunState && !preparedInput._trace) {
                    preparedInput._trace = getCurrentTrace();
                }
                return executeRun(effectiveInvocationSpanParent);
            };
            if (invocationTraceContext) {
                return await withTraceContext(invocationTraceContext, executeInInvocationTrace);
            }
            return await 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) {
        captureCurrentResponseToolOutputGuardrailResultStart(state, overwrite, this.#agentHasOutputGuardrail(state._currentAgent));
    }
    #shouldDeferInterruptedSessionItems(state) {
        return 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.DEFAULT_MODEL_PLACEHOLDER) ||
            (this.config.model !== undefined &&
                this.config.model !== Agent.DEFAULT_MODEL_PLACEHOLDER);
        const selectedModel = 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 (!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 withNewSpanContext(async () => {
            // if we have a saved state we use that one, otherwise we create a new one
            const isResumedState = input instanceof RunState;
            const state = isResumedState
                ? input
                : new RunState(options.context instanceof RunContext
                    ? options.context
                    : new RunContext(options.context), input, startingAgent, options.maxTurns === undefined
                    ? DEFAULT_MAX_TURNS
                    : options.maxTurns);
            bindSessionCompactionState(state, sessionCompaction);
            this.#validateModelTimeoutForAgent(state._currentAgent);
            if (isResumedState) {
                state._agentToolInvocation = undefined;
                if (options.maxTurns !== undefined) {
                    state._maxTurns = options.maxTurns;
                }
            }
            const sandboxRuntime = new 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 prepareSessionHistoryTransactionsForRun(options.session, state, {
                    serverManagesConversation,
                });
            }
            if (!isResumedState) {
                state.setConversationContext(resolvedConversationId, resolvedPreviousResponseId);
            }
            const serverConversationTracker = serverManagesConversation
                ? new 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 &&
                includeTaskAndTurnSpans(options.tracing);
            const resumingInterruptedTurn = isResumedState && state._currentStep?.type === 'next_step_interruption';
            const invocationSpans = useTaskAndTurnSpans
                ? startRunnerInvocationSpans({
                    name: taskSpanName,
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    resumeInterruptedTurn: resumingInterruptedTurn,
                    parent: invocationSpanParent,
                })
                : undefined;
            const taskSpan = invocationSpans?.taskSpan;
            const optOutResumeAgentSpan = resumingInterruptedTurn && !useTaskAndTurnSpans
                ? ensureActiveAgentSpanForInterruptedResume({
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    parent: invocationSpanParent ?? 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 = createGuardrailTracker();
            const parentUsageRecorder = getRunnerParentUsageRecorder(this);
            const recordUsage = (usage) => {
                recordRunnerSpanUsage(taskSpan, usage);
                recordRunnerSpanUsage(currentTurnSpan, usage);
                parentUsageRecorder?.(usage);
            };
            setRunStateUsageRecorder(state, recordUsage);
            let completedResult;
            let persistenceCheckpoint;
            let cancelledOutputRedacted = false;
            const resumedStateHasPersistedToolOutput = isResumedState && hasPersistedToolOutput(state);
            let approvedToolCheckpointCompacted = pendingSessionWriteReconciled ||
                state._currentTurnSessionWriteCompactedItemCount ===
                    state._currentTurnPersistedItemCount ||
                (resumedStateHasPersistedToolOutput &&
                    !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 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: getRunnerSpanErrorDetails(error, this.config.traceIncludeSensitiveData),
                        },
                    });
                }
                setRunnerSpanError(currentTurnSpan, error, this.config.traceIncludeSensitiveData);
                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 ModelBehaviorError('Expected a final output step while finalizing the run.', state);
                }
                markAcceptedResponseFinalizationStarted(state);
                normalizeSerializedOutputGuardrailBlockedMessage(state);
                const resolveBlockedMessage = createOutputGuardrailBlockedMessageResolver(outputGuardrailBlockedMessage, state);
                const outputGuardrailResultStart = state._outputGuardrailResults.length;
                let outputGuardrailBlocked = false;
                try {
                    await finalizeOutputGuardrails({
                        state,
                        runnerOutputGuardrails: this.outputGuardrailDefs,
                        output: currentStep.output,
                        redactedOutput: OUTPUT_GUARDRAIL_BLOCKED_TOOL_OUTPUT,
                        guardedTerminalToolOutput: hasTerminalToolOutputSource(state),
                        signal: options.signal,
                        sanitizeRejectedOutput: (...args) => sanitizeBlockedTerminalToolOutput(...args, resolveBlockedMessage, options.signal, () => {
                            outputGuardrailBlocked = true;
                        }),
                        persistBlockedOutput: persistResult
                            ? async () => persistResult(new RunResult(state), {
                                outputBlocked: true,
                            })
                            : undefined,
                        persistUnblockedFailure: async () => {
                            activateDeferredApprovedToolFinalSessionWrite();
                            await persistNonStreamingResult(new RunResult(state));
                            completedResultPersisted = true;
                        },
                        onBlockedOutput: () => {
                            outputGuardrailBlocked = true;
                        },
                        releaseBlockedOutputPersistence: 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 RunResult(state), { deferResumedSessionWrite: true });
                            }
                            catch (checkpointError) {
                                if (state._pendingSessionWrite === undefined) {
                                    throw checkpointError;
                                }
                            }
                        }
                    }
                    throw error;
                }
                if (state._serializedCurrentStep === currentStep &&
                    hasRetainableBlockedOutputEffect(state)) {
                    releaseProvisionalSessionHistoryTransactionBinding(state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                    throw new UserError('Accepted final output cannot be resumed directly from serialized terminal state. Start a new run from persisted session history.');
                }
                activateDeferredApprovedToolFinalSessionWrite();
                finishRunnerSpan(currentTurnSpan);
                setRunStateTurnSpanParent(state, undefined);
                currentTurnSpan = undefined;
                const result = new 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 (isAcceptedResponseCheckpoint(state)) {
                        this.#captureResponseGuardrailBoundary(state, false);
                        await resumeAcceptedModelResponse({
                            state,
                            runner: this,
                            toolErrorFormatter,
                            agentToolParentRunConfig,
                            signal: options.signal,
                            validateHandoffAgent: (handoffAgent) => {
                                this.#validateModelTimeoutForAgent(handoffAgent);
                            },
                        });
                    }
                    if (state._currentStep.type === 'next_step_interruption') {
                        await prepareSandboxInterruptedTurnResume({
                            startingAgent,
                            state,
                            sandboxRuntime,
                            runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(state._currentAgent),
                            toolNameCollisionPolicy: options.toolNameCollisionPolicy,
                            tracingParent: getRunStateTurnSpanParent(state) ?? state._currentAgentSpan,
                        });
                        if (useTaskAndTurnSpans) {
                            currentTurnSpan = ensureTurnSpan(currentTurnSpan, state._currentTurn, state._currentAgent.name, state._currentAgentSpan);
                            setRunStateTurnSpanParent(state, currentTurnSpan.span);
                        }
                        const { interruptedOutcome, approvedToolCheckpointDeferred } = await (async () => {
                            let resumedSessionWritePreparation;
                            this.#captureResponseGuardrailBoundary(state, false);
                            const outcome = await resumeInterruptedTurn({
                                state,
                                runner: this,
                                toolErrorFormatter,
                                agentToolParentRunConfig,
                                signal: options.signal,
                                validateHandoffAgent: (handoffAgent) => {
                                    this.#validateModelTimeoutForAgent(handoffAgent);
                                },
                                beforeResumedSideEffects: async () => {
                                    if (persistResult &&
                                        options.session &&
                                        !serverManagesConversation) {
                                        resumedSessionWritePreparation =
                                            await 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 RunResult(state);
                                approvedToolCheckpointRequiresLocalInputCompaction = true;
                                if (persistResult &&
                                    !this.#shouldDeferInterruptedSessionItems(state)) {
                                    if (options.session &&
                                        !serverManagesConversation &&
                                        !resumedSessionWritePreparation) {
                                        throw new 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 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 } = 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.
                        finishRunnerSpan(currentTurnSpan);
                        setRunStateTurnSpanParent(state, undefined);
                        currentTurnSpan = undefined;
                        if (shouldReturn) {
                            // we are still in an interruption, so we need to avoid an infinite loop
                            return completeResult(new RunResult(state));
                        }
                        if (shouldContinue) {
                            continue;
                        }
                    }
                    if (state._currentStep.type === 'next_step_run_again') {
                        this.#validateModelTimeoutForAgent(state._currentAgent);
                        if (approvedToolCheckpointCompacted &&
                            state._currentTurnSessionHistoryTransactionSessionId === undefined) {
                            await prepareSessionHistoryTransactionsForRun(options.session, state, { serverManagesConversation: false });
                        }
                        const wasContinuingInterruptedTurn = continuingInterruptedTurn;
                        continuingInterruptedTurn = false;
                        guardrailTracker = 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 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 = ensureTurnSpan(currentTurnSpan, turn, agentName, state._currentAgentSpan);
                                    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 = mapPendingInputAfterContextProcessing(pendingInputItems, sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                        const artifacts = await prepareAgentArtifacts(state, preparedSandboxAgent.executionAgent, options.toolNameCollisionPolicy);
                        const preparedCall = await this.#prepareModelCall(state, preparedSandboxAgent.executionAgent, options, artifacts, preparedSandboxAgent.turnInput, serverConversationTracker, sessionInputUpdate);
                        captureSessionHistoryTransactionInputItems(options.session, state, getSessionInputForPersistence?.());
                        await guardrailTracker.throwIfError();
                        const requiresPendingInputAdmissionCheckpoint = pendingInputItems.length > 0 ||
                            (!serverConversationTracker && hasUnpersistedRunInput(state));
                        if (requiresPendingInputAdmissionCheckpoint) {
                            options.signal?.throwIfAborted();
                        }
                        const admittedPendingInput = selectPendingInputForAdmission(processedPendingInputItems, preparedCall);
                        let localPendingInputCommitted = false;
                        const commitLocalPendingInput = async () => {
                            if (serverConversationTracker || localPendingInputCommitted) {
                                return;
                            }
                            localPendingInputCommitted = true;
                            commitPendingInput(state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                            if (hasUnpersistedRunInput(state)) {
                                await saveToSession(options.session, undefined, new 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: convertAgentOutputTypeToSerializable(state._currentAgent.outputType),
                            handoffs: preparedCall.serializedHandoffs,
                            tracing: 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,
                            });
                            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 = prepareSessionCompactionExchange(options.session, state, preparedCall.modelInput.input);
                        const pendingModelResponse = 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 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: () => preflightModelResponseToolInvocations(state._currentAgent, state, state._lastTurnResponse, preparedCall.tools, preparedCall.handoffs, this, options.signal),
                        });
                        serverConversationTracker?.trackServerItems(state._lastTurnResponse, processedResponse.newItems);
                        state._lastProcessedResponse = processedResponse;
                        trackDeferredToolRecovery(state, state._currentAgent, processedResponse);
                        const suppressedToolCalls = preflightToolInvocations(state._currentAgent, state, processedResponse);
                        await guardrailTracker.awaitCompletion();
                        markAcceptedResponseProcessingStarted(state);
                        this.#captureResponseGuardrailBoundary(state, true);
                        const turnResult = await 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);
                        }
                        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.
                                redactCancelledResponseToolOutputs(state, 'Tool output discarded because the run was cancelled before output validation.');
                                cancelledOutputRedacted = true;
                            }
                            if (!guardedFinalOutput || cancelledOutputRedacted) {
                                persistenceCheckpoint = new RunResult(state);
                            }
                            // Caller-owned RunState retains the candidate for validation on resume.
                        }
                        options.signal?.throwIfAborted();
                        if (turnResult.nextStep.type !== 'next_step_final_output') {
                            finishRunnerSpan(currentTurnSpan);
                            setRunStateTurnSpanParent(state, undefined);
                            currentTurnSpan = undefined;
                        }
                    }
                    const currentStep = state._currentStep;
                    if (!currentStep) {
                        logger.debug('Running next loop');
                        continue;
                    }
                    switch (currentStep.type) {
                        case 'next_step_final_output':
                            if (options.signal?.aborted) {
                                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();
                                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 RunResult(state));
                        case 'next_step_run_again':
                            state._currentTurnInProgress = false;
                            logger.debug('Running next loop');
                            break;
                        default:
                            logger.debug('Running next loop');
                    }
                }
            }
            catch (caughtError) {
                if (guardrailTracker.pending) {
                    await guardrailTracker.awaitCompletion({ suppressErrors: true });
                }
                const err = guardrailTracker.failed
                    ? guardrailTracker.error
                    : caughtError;
                if (guardrailTracker.failed) {
                    invalidateAcceptedResponseReplayEvidence(state);
                }
                const restoredPendingTurn = rollbackUnstartedTurn(state, turnPendingModelRequest);
                turnPendingModelRequest = undefined;
                if (!restoredPendingTurn) {
                    state._currentTurnInProgress = false;
                }
                attachRunStateToError(err, state);
                releaseUnusedSessionHistoryTransactionBinding(state);
                const errorHandled = state._pendingSessionWrite
                    ? undefined
                    : await prepareRunErrorFinalOutput({
                        error: err,
                        state,
                        errorHandlers: options.errorHandlers,
                        responseAccepted: isAcceptedResponseCheckpoint(state),
                        attemptedErrors: attemptedRunErrorHandlers,
                    });
                if (errorHandled) {
                    try {
                        return await finalizeCurrentOutput(errorHandled);
                    }
                    catch (finalizationError) {
                        recordNonStreamingError(finalizationError);
                        throw finalizationError;
                    }
                }
                recordNonStreamingError(err);
                throw err;
            }
            finally {
                finishRunnerSpan(currentTurnSpan);
                setRunStateTurnSpanParent(state, undefined);
                const preserveSandboxSessions = state._currentStep?.type === 'next_step_interruption';
                try {
                    try {
                        await 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) {
                        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) {
                            setRunnerSpanError(taskSpan, error, this.config.traceIncludeSensitiveData);
                            await Promise.reject(error);
                        }
                    }
                }
                finally {
                    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 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 = 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;
            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 && 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 && hasPersistedToolOutput(result.state);
        let approvedToolCheckpointCompacted = pendingSessionWriteReconciled ||
            result.state._currentTurnSessionWriteCompactedItemCount ===
                result.state._currentTurnPersistedItemCount ||
            (resumedStateHasPersistedToolOutput &&
                !hasPendingApprovedToolInputCompaction(result.state));
        let approvedToolCheckpointRequiresLocalInputCompaction = resumedStateHasPersistedToolOutput;
        let approvedToolCheckpointModelResponseCount = result.rawResponses.length;
        let approvedToolFinalSessionWritePreparation;
        let deferredApprovedToolFinalSessionWritePreparation;
        let currentTurnSpan;
        let turnPendingModelRequest;
        let commitDeferredLocalPendingInput;
        const parentUsageRecorder = getRunnerParentUsageRecorder(this);
        const recordUsage = (usage) => {
            recordRunnerSpanUsage(taskSpan, usage);
            recordRunnerSpanUsage(currentTurnSpan, usage);
            parentUsageRecorder?.(usage);
        };
        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 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 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: getRunnerSpanErrorDetails(error, this.config.traceIncludeSensitiveData),
                    },
                });
            }
            setRunnerSpanError(currentTurnSpan, error, this.config.traceIncludeSensitiveData);
            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 ModelBehaviorError('Expected a final output step while finalizing the run.', result.state);
            }
            markAcceptedResponseFinalizationStarted(result.state);
            result._hideFinalOutput();
            normalizeSerializedOutputGuardrailBlockedMessage(result.state);
            const resolveBlockedMessage = createOutputGuardrailBlockedMessageResolver(outputGuardrailBlockedMessage, result.state);
            const outputGuardrailResultStart = result.state._outputGuardrailResults.length;
            let outputGuardrailBlocked = false;
            try {
                await finalizeOutputGuardrails({
                    state: result.state,
                    runnerOutputGuardrails: this.outputGuardrailDefs,
                    output: currentStep.output,
                    redactedOutput: OUTPUT_GUARDRAIL_BLOCKED_TOOL_OUTPUT,
                    guardedTerminalToolOutput: hasTerminalToolOutputSource(result.state),
                    signal: options.signal,
                    sanitizeRejectedOutput: (...args) => 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: 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)) {
                releaseProvisionalSessionHistoryTransactionBinding(result.state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                throw new UserError('Accepted final output cannot be resumed directly from serialized terminal state. Start a new run from persisted session history.');
            }
            activateDeferredApprovedToolFinalSessionWrite();
            finishRunnerSpan(currentTurnSpan);
            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) {
                        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) {
                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') {
                        releaseProvisionalSessionHistoryTransactionBinding(result.state, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems);
                    }
                    return;
                }
                const currentAgent = result.state._currentAgent;
                result.state._currentStep = result.state._currentStep ?? {
                    type: 'next_step_run_again',
                };
                if (isAcceptedResponseCheckpoint(result.state)) {
                    this.#captureResponseGuardrailBoundary(result.state, false);
                    await resumeAcceptedModelResponse({
                        state: result.state,
                        runner: this,
                        toolErrorFormatter,
                        agentToolParentRunConfig,
                        signal: options.signal,
                        validateHandoffAgent: (handoffAgent) => {
                            this.#validateModelTimeoutForAgent(handoffAgent);
                        },
                        onStepItems: (turnResult) => {
                            addStepToRunResult(result, turnResult);
                        },
                    });
                }
                if (result.state._currentStep.type === 'next_step_interruption') {
                    await prepareSandboxInterruptedTurnResume({
                        startingAgent,
                        state: result.state,
                        sandboxRuntime,
                        runConfigModel: await this.#resolveSandboxRuntimeModelForAgent(result.state._currentAgent),
                        toolNameCollisionPolicy: options.toolNameCollisionPolicy,
                        tracingParent: getRunStateTurnSpanParent(result.state) ??
                            result.state._currentAgentSpan,
                    });
                    if (useTaskAndTurnSpans) {
                        currentTurnSpan = ensureTurnSpan(currentTurnSpan, result.state._currentTurn, result.state._currentAgent.name, result.state._currentAgentSpan);
                        setRunStateTurnSpanParent(result.state, currentTurnSpan.span);
                    }
                    const interruptedOutcome = await (async () => {
                        let resumedSessionWritePreparation;
                        this.#captureResponseGuardrailBoundary(result.state, false);
                        const outcome = await resumeInterruptedTurn({
                            state: result.state,
                            runner: this,
                            toolErrorFormatter,
                            agentToolParentRunConfig,
                            signal: options.signal,
                            validateHandoffAgent: (handoffAgent) => {
                                this.#validateModelTimeoutForAgent(handoffAgent);
                            },
                            onStepItems: (turnResult) => {
                                addStepToRunResult(result, turnResult);
                            },
                            onHandoff: (agent) => {
                                result._addItem(new RunAgentUpdatedStreamEvent(agent));
                            },
                            beforeResumedSideEffects: async () => {
                                if (options.session && !serverManagesConversation) {
                                    resumedSessionWritePreparation =
                                        await 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 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 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 } = 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.
                    finishRunnerSpan(currentTurnSpan);
                    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 prepareSessionHistoryTransactionsForRun(options.session, result.state, { serverManagesConversation: false });
                    }
                    guardrailTracker = 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 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 = ensureTurnSpan(currentTurnSpan, turn, agentName, result.state._currentAgentSpan);
                                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 = mapPendingInputAfterContextProcessing(pendingInputItems, sessionPreparedTurnInput, preparedSandboxAgent.turnInput);
                    const artifacts = await prepareAgentArtifacts(result.state, preparedSandboxAgent.executionAgent, options.toolNameCollisionPolicy);
                    const preparedCall = await this.#prepareModelCall(result.state, preparedSandboxAgent.executionAgent, options, artifacts, preparedSandboxAgent.turnInput, serverConversationTracker, sessionInputUpdate);
                    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 = selectPendingInputForAdmission(processedPendingInputItems, preparedCall);
                    let localPendingInputCommitted = false;
                    const commitLocalPendingInput = async () => {
                        if (serverConversationTracker || localPendingInputCommitted) {
                            return;
                        }
                        localPendingInputCommitted = true;
                        commitPendingInput(result.state, pendingInputItems, admittedPendingInput, pendingInputSourceItems);
                        if (hasUnpersistedRunInput(result.state)) {
                            await 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 = 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,
                            });
                            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 ||
                            !shouldReconcileStreamAbort(abortReconciliationState)) {
                            return;
                        }
                        const reconciliationInput = buildAbortReconciliationInput(abortReconciliationState);
                        try {
                            const reconciliationResponse = await getResponseWithRetry(preparedCall.model, {
                                systemInstructions: preparedCall.modelInput.instructions,
                                prompt: preparedCall.prompt,
                                ...(preparedCall.explicitlyModelSet
                                    ? { overridePromptModel: true }
                                    : {}),
                                input: reconciliationInput,
                                previousResponseId: getAbortReconciliationPreviousResponseId(abortReconciliationState, preparedCall),
                                conversationId: preparedCall.conversationId,
                                modelSettings: preparedCall.modelSettings,
                                _internal: preparedCall.modelRequestInternal,
                                tools: preparedCall.serializedTools,
                                toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
                                handoffs: preparedCall.serializedHandoffs,
                                outputType: convertAgentOutputTypeToSerializable(currentAgent.outputType),
                                tracing: getTracing(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
                            }, {
                                onModelFailureUsage: (usage) => recordModelFailureUsage(usage, result.state, recordUsage),
                            });
                            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) {
                            logModelAndToolActionDebug(logger, '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: convertAgentOutputTypeToSerializable(currentAgent.outputType),
                        tracing: 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 = prepareSessionCompactionExchange(options.session, result.state, preparedCall.modelInput.input);
                    try {
                        for await (const event of 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();
                            recordStreamEventForAbortReconciliation(abortReconciliationState, event);
                            if (event.type === 'response_done') {
                                assertValidCompactionItems(event.response.output);
                                let rawUsage;
                                if (modelRequest.modelSettings.preserveRawUsage === true) {
                                    try {
                                        rawUsage = snapshotRawUsage(event.response.rawUsage);
                                    }
                                    catch {
                                        rawUsage = undefined;
                                    }
                                }
                                const parsed = 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(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 RunRawModelStreamEvent(event));
                        }
                    }
                    catch (error) {
                        if (isAbortError(error)) {
                            if (sentInputToModel) {
                                markServerInputAccepted();
                            }
                            await awaitInputGuardrails();
                            await commitDeferredLocalPendingInput?.();
                            await reconcileStreamAbortIfNeeded();
                            return;
                        }
                        if (error instanceof 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 = StreamEvent.options.find((schema) => schema.shape.type.value === lastStreamEventType)?.shape.type.value ??
                            (streamEventCount > 0 ? 'unknown' : 'none');
                        throw new 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 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: () => 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;
                    trackDeferredToolRecovery(result.state, currentAgent, processedResponse);
                    const suppressedToolCalls = preflightToolInvocations(currentAgent, result.state, processedResponse);
                    const streamableItems = 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) {
                        streamStepItemsToRunResult(result, streamableItems);
                    }
                    markAcceptedResponseProcessingStarted(result.state);
                    this.#captureResponseGuardrailBoundary(result.state, true);
                    const turnResult = await 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);
                    }
                    applyTurnResult({
                        state: result.state,
                        turnResult,
                        agent: currentAgent,
                        toolsUsed: processedResponse.toolsUsed,
                        resetTurnPersistence: !isResumedState,
                        onStepItems: (step) => {
                            addStepToRunResult(result, step, { skipItems: preToolItems });
                        },
                    });
                    if (turnResult.nextStep.type !== 'next_step_final_output') {
                        finishRunnerSpan(currentTurnSpan);
                        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();
                            resetCurrentSpan();
                        }
                        result.state.setCurrentAgentSpan(undefined);
                        result._addItem(new 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.debug('Running next loop');
                        break;
                    default:
                        logger.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;
            }
            attachRunStateToError(error, result.state);
            releaseUnusedSessionHistoryTransactionBinding(result.state);
            suppressStreamInputPersistence =
                error instanceof CompactionItemValidationError;
            const errorHandled = result.state._pendingSessionWrite
                ? undefined
                : await prepareRunErrorFinalOutput({
                    error,
                    state: result.state,
                    errorHandlers: options.errorHandlers,
                    streamResult: result,
                    responseAccepted: isAcceptedResponseCheckpoint(result.state),
                    attemptedErrors: attemptedRunErrorHandlers,
                });
            if (errorHandled) {
                try {
                    await finalizeStreamOutput(errorHandled);
                    return;
                }
                catch (finalizationError) {
                    recordStreamingError(finalizationError);
                    throw finalizationError;
                }
            }
            recordStreamingError(error);
            throw error;
        }
        finally {
            finishRunnerSpan(currentTurnSpan);
            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 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) {
                    setRunnerSpanError(taskSpan, error, this.config.traceIncludeSensitiveData);
                    await Promise.reject(error);
                }
            }
            finally {
                finishRunnerSpan(taskSpan);
            }
        }
    }
    /**
     * @internal
     */
    async #runIndividualStream(agent, input, taskSpanName, options, ensureStreamInputPersisted, sessionTurnInputUpdate, sessionInputUpdate, getStreamInputForPersistence, preserveTurnPersistenceOnResume, provisionalSessionHistoryTransactionSessionId, provisionalSessionHistoryTransactionInputItems, sandboxMemoryRunContext, invocationSpanParent, pendingSessionWriteReconciled = false, sessionCompaction) {
        options = options ?? {};
        return withNewSpanContext(async () => {
            // Initialize or reuse existing state
            const isResumedState = input instanceof RunState;
            const state = isResumedState
                ? input
                : new RunState(options.context instanceof RunContext
                    ? options.context
                    : new RunContext(options.context), input, agent, options.maxTurns === undefined
                    ? DEFAULT_MAX_TURNS
                    : options.maxTurns);
            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 prepareSessionHistoryTransactionsForRun(options.session, state, {
                    serverManagesConversation: Boolean(resolvedConversationId || resolvedPreviousResponseId),
                });
            }
            const useTaskAndTurnSpans = !this.config.tracingDisabled &&
                includeTaskAndTurnSpans(options.tracing);
            const resumingInterruptedTurn = isResumedState && state._currentStep?.type === 'next_step_interruption';
            const invocationSpans = useTaskAndTurnSpans
                ? startRunnerInvocationSpans({
                    name: taskSpanName,
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    resumeInterruptedTurn: resumingInterruptedTurn,
                    parent: invocationSpanParent,
                })
                : undefined;
            const taskSpan = invocationSpans?.taskSpan;
            const optOutResumeAgentSpan = resumingInterruptedTurn && !useTaskAndTurnSpans
                ? ensureActiveAgentSpanForInterruptedResume({
                    agent: state._currentAgent,
                    restoredAgentSpan: isResumedState
                        ? state._currentAgentSpan
                        : undefined,
                    parent: invocationSpanParent ?? getCurrentTrace() ?? undefined,
                })
                : undefined;
            if (useTaskAndTurnSpans && isResumedState) {
                state.setCurrentAgentSpan(invocationSpans?.agentSpan);
            }
            else if (optOutResumeAgentSpan) {
                state.setCurrentAgentSpan(optOutResumeAgentSpan);
            }
            const sandboxRuntime = new 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 StreamedRunResult({
                signal: options.signal,
                state,
            });
            result._setAgentToolStreamBuffer(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;
        validateModelTimeoutMs(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
            : getImplicitModelSettingsForResolvedModel(explicitlyModelSet, resolvedModelName);
        let modelSettings = mergeModelSettings(implicitModelSettings, this.config.modelSettings);
        modelSettings = 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: getRunStateTurnSpanParent(state) ?? state._currentAgentSpan,
            toolNameCollisionPolicy: options.toolNameCollisionPolicy ?? 'warn',
        };
        modelSettings = adjustModelSettingsForLegacyModel(explicitlyModelSet, agentModelSettings ?? implicitModelSettings ?? {}, modelSettings, resolvedModelName);
        modelSettings = maybeResetToolChoice(state._currentAgent, state._toolUseTracker, modelSettings);
        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 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,
        };
    }
}
// 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.mjs.map