UNPKG

@openai/agents-core

Version:

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

2,142 lines • 95 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getToolCallOutputItem = getToolCallOutputItem;
exports.executeFunctionToolCalls = executeFunctionToolCalls;
exports.executeShellActions = executeShellActions;
exports.executeApplyPatchOperations = executeApplyPatchOperations;
exports.executeComputerActions = executeComputerActions;
exports.executeHandoffCalls = executeHandoffCalls;
exports.collectInterruptions = collectInterruptions;
exports.checkForFinalOutputFromTools = checkForFinalOutputFromTools;
const functionToolApproval_1 = require("../utils/functionToolApproval.js");
const toolInvocation_1 = require("../toolInvocation.js");
const agentToolRunConfig_1 = require("../agentToolRunConfig.js");
const agentToolRunResults_1 = require("../agentToolRunResults.js");
const errors_1 = require("../errors.js");
const toolInputError_1 = require("../toolInputError.js");
const toolOutputError_1 = require("../toolOutputError.js");
const handoff_1 = require("../handoff.js");
const items_1 = require("../items.js");
const message_1 = require("../helpers/message.js");
const logger_1 = __importStar(require("../logger.js"));
const tool_1 = require("../tool.js");
const functionToolTracing_1 = require("../functionToolTracing.js");
const abortSignals_1 = require("../utils/abortSignals.js");
const standardSchema_1 = require("../utils/standardSchema.js");
const smartString_1 = require("../utils/smartString.js");
const createSpans_1 = require("../tracing/createSpans.js");
const context_1 = require("../tracing/context.js");
const runState_1 = require("../runState.js");
const toolIdentity_1 = require("../toolIdentity.js");
const toolOutputNormalization_1 = require("./toolOutputNormalization.js");
const toolGuardrails_1 = require("../utils/toolGuardrails.js");
const customData_1 = require("../utils/customData.js");
const approvalRejection_1 = require("./approvalRejection.js");
const steps_1 = require("./steps.js");
const usageTracking_1 = require("./usageTracking.js");
const invocationContext_1 = require("./invocationContext.js");
const streamReconciliation_1 = require("./streamReconciliation.js");
const siblingCancellation_1 = require("./siblingCancellation.js");
const items_2 = require("./items.js");
function getFunctionToolIdentity(toolRun) {
    return (0, toolIdentity_1.getFunctionToolQualifiedName)(toolRun.tool) ?? toolRun.tool.name;
}
function cloneForCustomDataContext(value) {
    try {
        return structuredClone(value);
    }
    catch {
        return value;
    }
}
function getFunctionToolCallbackToolCall(toolCall, redactArguments) {
    if (!redactArguments) {
        return toolCall;
    }
    return {
        type: 'function_call',
        callId: toolCall.callId,
        name: toolCall.name,
        arguments: '',
        ...(toolCall.id ? { id: toolCall.id } : {}),
        ...(toolCall.namespace ? { namespace: toolCall.namespace } : {}),
        ...(toolCall.status ? { status: toolCall.status } : {}),
        ...(toolCall.caller ? { caller: toolCall.caller } : {}),
    };
}
function getFunctionToolTraceName(toolRun) {
    return getFunctionToolIdentity(toolRun);
}
function getFunctionToolApprovalStateKey(toolRun) {
    return ((0, toolIdentity_1.getFunctionToolStateKey)(toolRun.tool) ?? getFunctionToolIdentity(toolRun));
}
function getFunctionToolPendingStateKeys(toolRun) {
    const availableTools = toolRun.availableFunctionTools ?? [toolRun.tool];
    return (0, toolIdentity_1.getFunctionToolStateKeys)(toolRun.tool, availableTools);
}
const COMPUTER_TRACE_NAME = 'computer';
function getComputerToolActions(toolCall) {
    if (Array.isArray(toolCall.actions) && toolCall.actions.length > 0) {
        return toolCall.actions;
    }
    return toolCall.action ? [toolCall.action] : [];
}
function getComputerTraceInputPayload(toolCall) {
    const actions = getComputerToolActions(toolCall);
    if (Array.isArray(toolCall.actions) && toolCall.actions.length > 0) {
        return actions;
    }
    return actions[0];
}
/**
 * @internal
 * Normalizes tool outputs once so downstream code works with fully structured protocol items.
 * Doing this here keeps API surface stable even when providers add new shapes.
 */
function getToolCallOutputItem(toolCall, output, options) {
    const hasOutputSchema = typeof options?.outputSchema !== 'undefined';
    const maybeStructuredOutputs = hasOutputSchema
        ? null
        : (0, toolOutputNormalization_1.normalizeStructuredToolOutputs)(output);
    if (maybeStructuredOutputs) {
        const structuredItems = maybeStructuredOutputs.map(toolOutputNormalization_1.convertStructuredToolOutputToInputItem);
        return {
            type: 'function_call_result',
            name: toolCall.name,
            ...(typeof toolCall.namespace === 'string'
                ? { namespace: toolCall.namespace }
                : {}),
            callId: toolCall.callId,
            status: 'completed',
            output: structuredItems,
            ...(toolCall.caller ? { caller: toolCall.caller } : {}),
        };
    }
    let textOutput;
    if (hasOutputSchema) {
        try {
            const serializedOutput = JSON.stringify(output);
            if (typeof serializedOutput !== 'string') {
                throw new Error('The output is not a JSON value.');
            }
            textOutput = serializedOutput;
        }
        catch (error) {
            throw (0, toolOutputError_1.createInvalidToolOutputError)(`Function tool '${toolCall.name}' outputSchema requires a JSON-serializable output.`, error, { output });
        }
    }
    else {
        textOutput = (0, smartString_1.toSmartString)(output);
    }
    return {
        type: 'function_call_result',
        name: toolCall.name,
        ...(typeof toolCall.namespace === 'string'
            ? { namespace: toolCall.namespace }
            : {}),
        callId: toolCall.callId,
        status: 'completed',
        output: {
            type: 'text',
            text: textOutput,
        },
        ...(toolCall.caller ? { caller: toolCall.caller } : {}),
    };
}
/**
 * @internal
 * Runs every function tool call requested by the model and returns their outputs alongside
 * the `RunItem` instances that should be appended to history.
 */
async function executeFunctionToolCalls(agent, toolRuns, runner, state, toolErrorFormatter, agentToolParentRunConfig, signal, onFatalFailure) {
    const startedInvalidInputFailures = [];
    const startedInvalidOutputFailures = [];
    const trackInvalidOutputFailure = (failure) => {
        if (!startedInvalidOutputFailures.includes(failure)) {
            startedInvalidOutputFailures.push(failure);
        }
    };
    const trackInvalidOutputError = (error) => {
        const failure = (0, toolOutputError_1.getInvalidToolOutputFailure)(error);
        if (failure) {
            trackInvalidOutputFailure(failure);
        }
    };
    const deps = {
        agent,
        runner,
        state,
        toolErrorFormatter,
        agentToolParentRunConfig,
        signal,
        onInvalidOutputFailure: trackInvalidOutputFailure,
    };
    const executePreparedToolRun = async (toolRun, executionSignal = signal) => {
        const executionDeps = executionSignal === deps.signal
            ? deps
            : { ...deps, signal: executionSignal };
        if (executionSignal?.aborted) {
            return buildFunctionCancellationResult(executionDeps, toolRun);
        }
        if (!(0, toolIdentity_1.matchesFunctionToolRecipient)(toolRun.mcpToolBinding ?? null, toolRun.tool)) {
            // Rejection is safe even when the original recipient is unavailable. Do not
            // parse input or invoke output-schema callbacks belonging to a replacement.
            const rejected = state._context.isToolApproved({
                toolName: getFunctionToolApprovalStateKey(toolRun),
                callId: toolRun.toolCall.callId,
                functionTool: false,
                agent,
            }) === false;
            if (!rejected) {
                throw new errors_1.UserError('Cannot resume a function tool call with a missing or different MCP recipient binding. Restore the original MCP configuration and tool listing, or start a new run.', state);
            }
            for (const stateKey of getFunctionToolPendingStateKeys(toolRun)) {
                state.clearPendingAgentToolRun(stateKey, toolRun.toolCall.callId);
            }
            return buildApprovalRejectionResult(executionDeps, {
                ...toolRun,
                availableFunctionTools: toolRun.availableFunctionTools,
                tool: { ...toolRun.tool, outputSchema: undefined },
            });
        }
        const pending = state._pendingFunctionToolApprovals
            .get(agent)
            ?.get(toolRun.toolCall.callId);
        const invocation = (0, toolInvocation_1.getToolInvocationFingerprint)(getFunctionToolIdentity(toolRun), toolRun.toolCall);
        const retainedInput = pending?.invocation === invocation &&
            pending.invoke === toolRun.tool.invoke
            ? pending.preparedInput
            : undefined;
        const parseResult = parseToolArguments(toolRun, retainedInput);
        let failure;
        if (!parseResult.success) {
            failure = (0, toolInputError_1.createInvalidToolInputFailure)({
                message: `Invalid input for function tool '${getFunctionToolIdentity(toolRun)}'.`,
                state: deps.state,
                originalError: parseResult.error,
                toolInvocation: {
                    runContext: deps.state._context,
                    input: toolRun.toolCall.arguments,
                    details: { toolCall: toolRun.toolCall },
                },
                disposition: parseResult.preparedInput?.disposition,
                fatal: (0, standardSchema_1.isAsyncStandardSchemaValidationError)(parseResult.error),
            });
            startedInvalidInputFailures.push(failure);
            if (failure.fatal) {
                throw failure.error;
            }
        }
        const dynamicApprovalPolicy = (0, tool_1.hasDynamicFunctionToolApprovalPolicy)(toolRun.tool);
        // Handle parse errors gracefully instead of crashing.
        if (!parseResult.success) {
            if (parseResult.preparedInput) {
                const approvalOutcome = await handlePreparedFunctionApproval(executionDeps, toolRun, parseResult, false, failure);
                if (approvalOutcome !== 'approved') {
                    return approvalOutcome;
                }
                if (executionSignal?.aborted) {
                    return buildFunctionCancellationResult(executionDeps, toolRun);
                }
                try {
                    return await runApprovedFunctionTool(executionDeps, toolRun, parseResult.approvalArgs, parseResult.preparedInput, failure, trackInvalidOutputFailure);
                }
                catch (error) {
                    trackInvalidOutputError(error);
                    if (executionSignal?.aborted &&
                        (error === executionSignal.reason || (0, abortSignals_1.isAbortError)(error))) {
                        return buildFunctionCancellationResult(executionDeps, toolRun);
                    }
                    throw error;
                }
            }
            else if (dynamicApprovalPolicy) {
                const approvalOutcome = await handlePreparedFunctionApproval(executionDeps, toolRun, parseResult, true, failure);
                if (approvalOutcome !== 'approved') {
                    return approvalOutcome;
                }
                if (executionSignal?.aborted) {
                    return buildFunctionCancellationResult(executionDeps, toolRun);
                }
            }
            return buildParseErrorResult(executionDeps, toolRun, failure);
        }
        const approvalOutcome = await handlePreparedFunctionApproval(executionDeps, toolRun, parseResult, dynamicApprovalPolicy &&
            !(0, tool_1.hasInspectableFunctionToolArguments)(parseResult.approvalArgs));
        if (approvalOutcome !== 'approved') {
            return approvalOutcome;
        }
        if (executionSignal?.aborted) {
            return buildFunctionCancellationResult(executionDeps, toolRun);
        }
        try {
            return await runApprovedFunctionTool(executionDeps, toolRun, parseResult.approvalArgs, parseResult.preparedInput, undefined, trackInvalidOutputFailure);
        }
        catch (error) {
            trackInvalidOutputError(error);
            if (executionSignal?.aborted &&
                (error === executionSignal.reason || (0, abortSignals_1.isAbortError)(error))) {
                return buildFunctionCancellationResult(executionDeps, toolRun);
            }
            throw error;
        }
    };
    const executeToolRun = async (toolRun, executionSignal = signal) => {
        const result = await executePreparedToolRun(toolRun, executionSignal);
        if (result.type !== 'function_approval' &&
            (result.type !== 'function_output' || !result.interruptions?.length)) {
            const records = state._pendingFunctionToolApprovals.get(agent);
            records?.delete(toolRun.toolCall.callId);
            if (records?.size === 0)
                state._pendingFunctionToolApprovals.delete(agent);
        }
        return result;
    };
    try {
        const results = await executeToolRunsWithConcurrency(toolRuns, getMaxFunctionToolConcurrency(agentToolParentRunConfig?.toolExecution ?? runner.config.toolExecution), executeToolRun, signal, onFatalFailure);
        return results;
    }
    catch (e) {
        // A failed batch cannot publish newly collected interruptions. Keep only
        // records owned by an existing interruption or a surviving nested run.
        const interruptions = state.getInterruptions();
        const records = state._pendingFunctionToolApprovals.get(agent);
        for (const toolRun of toolRuns) {
            const callId = toolRun.toolCall.callId;
            const pending = interruptions.some((item) => item.agent === agent &&
                item.rawItem.type === 'function_call' &&
                item.rawItem.callId === callId) ||
                getFunctionToolPendingStateKeys(toolRun).some((key) => state.hasPendingAgentToolRun(key, callId));
            if (!pending)
                records?.delete(callId);
        }
        if (records?.size === 0)
            state._pendingFunctionToolApprovals.delete(agent);
        const redactInvalidInputFailure = startedInvalidInputFailures.some((failure) => (0, toolInputError_1.refreshInvalidToolInputFailure)(failure));
        const invalidOutputFailure = (0, toolOutputError_1.getInvalidToolOutputFailure)(e);
        const redactStartedInvalidOutputFailure = startedInvalidOutputFailures.some((failure) => (0, toolOutputError_1.refreshInvalidToolOutputFailure)(failure));
        const redactSurfacedInvalidOutputFailure = invalidOutputFailure
            ? (0, toolOutputError_1.refreshInvalidToolOutputFailure)(invalidOutputFailure)
            : (0, toolOutputError_1.isRedactedInvalidToolOutputError)(e);
        const redactInvalidOutputFailure = redactStartedInvalidOutputFailure || redactSurfacedInvalidOutputFailure;
        if (redactInvalidInputFailure || redactInvalidOutputFailure) {
            (0, errors_1.clearToolErrorState)(e, state);
        }
        if ((0, errors_1.isToolTimeoutError)(e)) {
            if (redactInvalidInputFailure || redactInvalidOutputFailure) {
                e.state = undefined;
            }
            else {
                e.state ??= state;
            }
            throw e;
        }
        const surfacedError = (invalidOutputFailure?.error ?? e);
        throw new errors_1.ToolCallError(`Failed to run function tools: ${surfacedError}`, surfacedError, redactInvalidInputFailure ||
            (0, toolInputError_1.isRedactedInvalidToolInputError)(e) ||
            redactInvalidOutputFailure
            ? undefined
            : state);
    }
}
function getMaxFunctionToolConcurrency(toolExecution) {
    return toolExecution?.maxFunctionToolConcurrency ?? undefined;
}
function shouldRunPreApprovalInputGuardrails(deps) {
    return ((deps.agentToolParentRunConfig?.toolExecution ??
        deps.runner.config.toolExecution)?.preApprovalInputGuardrails === true);
}
async function executeToolRunsWithConcurrency(toolRuns, maxConcurrency, executeToolRun, parentSignal, onFatalFailure) {
    if (maxConcurrency === undefined ||
        maxConcurrency >= toolRuns.length ||
        toolRuns.length <= 1) {
        return (0, siblingCancellation_1.runWithSiblingCancellation)(toolRuns.map((toolRun) => (signal) => executeToolRun(toolRun, signal)), parentSignal, onFatalFailure);
    }
    const results = [];
    let nextIndex = 0;
    const worker = async (signal, reserveFailure) => {
        while (nextIndex < toolRuns.length &&
            (!signal?.aborted ||
                (parentSignal?.aborted && !(0, abortSignals_1.isSiblingCancellationSignal)(parentSignal)))) {
            const currentIndex = nextIndex;
            nextIndex += 1;
            try {
                const result = await executeToolRun(toolRuns[currentIndex], signal);
                results[currentIndex] = result;
            }
            catch (error) {
                reserveFailure?.();
                throw error;
            }
        }
    };
    const workerCount = Math.min(maxConcurrency, toolRuns.length);
    // Drain every started worker before returning so no function tool retains
    // ownership after the run surfaces an error or cancellation.
    await (0, siblingCancellation_1.runWithSiblingCancellation)(Array.from({ length: workerCount }, () => (signal, reserveFailure) => worker(signal, reserveFailure)), parentSignal, onFatalFailure);
    return results;
}
function parseToolArguments(toolRun, retainedInput) {
    const toolName = getFunctionToolIdentity(toolRun);
    try {
        let approvalArgs = toolRun.toolCall.arguments;
        if (toolRun.tool.parameters) {
            approvalArgs = JSON.parse(toolRun.toolCall.arguments);
        }
        const preparedInput = retainedInput ??
            (0, tool_1.prepareFunctionToolInput)(toolRun.tool, toolRun.toolCall.arguments);
        if (preparedInput && !preparedInput.result.success) {
            return {
                success: false,
                error: preparedInput.result.error,
                approvalArgs,
                preparedInput,
            };
        }
        if (preparedInput?.result.success) {
            if ((0, tool_1.hasDynamicFunctionToolApprovalPolicy)(toolRun.tool)) {
                approvalArgs = (0, functionToolApproval_1.getFunctionToolApprovalInput)(preparedInput.result.value);
            }
            else if (preparedInput.validationMode === 'standard') {
                approvalArgs = preparedInput.result.value;
            }
        }
        return { success: true, approvalArgs, preparedInput };
    }
    catch (error) {
        if (error instanceof functionToolApproval_1.FunctionToolApprovalInputError)
            throw error;
        if (logger_1.default.dontLogToolData) {
            logger_1.default.debug(`Failed to parse tool arguments for ${toolName}`);
        }
        else {
            logger_1.default.debug(`Failed to parse tool arguments for ${toolName}: ${error}`);
        }
        return { success: false, error };
    }
}
function buildApprovalRequestResult(deps, toolRun) {
    return {
        type: 'function_approval',
        tool: toolRun.tool,
        runItem: new items_1.RunToolApprovalItem(toolRun.toolCall, deps.agent, getFunctionToolIdentity(toolRun), (0, toolIdentity_1.getFunctionToolStateKey)(toolRun.tool)),
    };
}
function buildFunctionFailureResult(deps, toolRun, output) {
    let rawItem;
    try {
        rawItem = getToolCallOutputItem(toolRun.toolCall, output, {
            outputSchema: toolRun.tool.outputSchema,
        });
    }
    catch (error) {
        const invalidOutputFailure = (0, toolOutputError_1.getInvalidToolOutputFailure)(error);
        if (invalidOutputFailure) {
            deps.onInvalidOutputFailure?.(invalidOutputFailure);
        }
        throw error;
    }
    return {
        type: 'function_output',
        tool: toolRun.tool,
        output,
        runItem: new items_1.RunToolCallOutputItem(rawItem, deps.agent, output),
    };
}
function buildFunctionCancellationResult(deps, toolRun) {
    const output = 'aborted';
    const rawItem = (0, streamReconciliation_1.buildFunctionAbortResult)(toolRun.toolCall);
    return {
        type: 'function_output',
        tool: toolRun.tool,
        output,
        runItem: new items_1.RunToolCallOutputItem(rawItem, deps.agent, output),
    };
}
async function resolveFunctionFailureOutput(deps, toolRun, error, legacyOutput, redactionBoundary) {
    const redactedBeforeCallback = redactionBoundary
        ? (0, toolInputError_1.refreshInvalidToolInputFailure)(redactionBoundary.failure)
        : (0, toolInputError_1.isRedactedInvalidToolInputError)(error);
    const callbackError = redactedBeforeCallback
        ? (redactionBoundary?.failure.error ?? error)
        : error;
    const effectiveLegacyOutput = redactedBeforeCallback
        ? (redactionBoundary?.redactedLegacyOutput ?? legacyOutput)
        : legacyOutput;
    if (!toolRun.tool.outputSchema) {
        return effectiveLegacyOutput;
    }
    if (!toolRun.tool.errorFunction) {
        throw callbackError;
    }
    const details = redactedBeforeCallback
        ? undefined
        : { toolCall: toolRun.toolCall };
    try {
        const output = await toolRun.tool.errorFunction(deps.state._context, callbackError, details);
        if (redactionBoundary &&
            !redactedBeforeCallback &&
            (0, toolInputError_1.refreshInvalidToolInputFailure)(redactionBoundary.failure)) {
            throw redactionBoundary.failure.error;
        }
        let validatedOutput;
        try {
            validatedOutput = (0, tool_1.validateFunctionToolOutput)({
                tool: toolRun.tool,
                output,
                runContext: deps.state._context,
                details,
            });
        }
        catch (error) {
            const invalidOutputFailure = (0, toolOutputError_1.getInvalidToolOutputFailure)(error);
            if (invalidOutputFailure) {
                deps.onInvalidOutputFailure?.(invalidOutputFailure);
            }
            throw error;
        }
        if (redactionBoundary &&
            !redactedBeforeCallback &&
            (0, toolInputError_1.refreshInvalidToolInputFailure)(redactionBoundary.failure)) {
            throw redactionBoundary.failure.error;
        }
        return validatedOutput;
    }
    catch (callbackFailure) {
        if (redactionBoundary &&
            (0, toolInputError_1.refreshInvalidToolInputFailure)(redactionBoundary.failure)) {
            throw redactionBoundary.failure.error;
        }
        throw callbackFailure;
    }
}
async function buildParseErrorResult(deps, toolRun, failure) {
    const traceToolName = getFunctionToolTraceName(toolRun);
    return withRunStateToolFunctionSpan(deps, traceToolName, async (span) => {
        (0, toolInputError_1.refreshInvalidToolInputFailure)(failure);
        if (span &&
            deps.runner.config.traceIncludeSensitiveData &&
            !failure.redacted) {
            span.spanData.input = toolRun.toolCall.arguments;
        }
        span?.setError({
            message: 'Error running tool (non-fatal)',
            data: {
                tool_name: traceToolName,
                error: toolRun.tool.outputSchema &&
                    toolRun.tool.errorFunction &&
                    deps.runner.config.traceIncludeSensitiveData &&
                    !failure.redacted
                    ? failure.error.toString()
                    : functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE,
            },
        });
        const baseMessage = 'An error occurred while parsing tool arguments. Please try again with valid JSON.';
        let output;
        try {
            output = await resolveFunctionFailureOutput(deps, toolRun, failure.error, baseMessage, { failure, redactedLegacyOutput: baseMessage });
        }
        finally {
            (0, toolInputError_1.refreshInvalidToolInputFailure)(failure);
            if (failure.redacted && span) {
                span.spanData.input = '';
            }
        }
        if (span && deps.runner.config.traceIncludeSensitiveData) {
            span.spanData.output = (0, smartString_1.toSmartString)(output);
        }
        return buildFunctionFailureResult(deps, toolRun, output);
    });
}
async function buildApprovalRejectionResult(deps, toolRun, invalidInputFailure) {
    const { runner, state, toolErrorFormatter } = deps;
    const toolName = getFunctionToolIdentity(toolRun);
    const approvalToolNames = [getFunctionToolApprovalStateKey(toolRun)];
    const traceToolName = getFunctionToolTraceName(toolRun);
    return withRunStateToolFunctionSpan(deps, traceToolName, async (span) => {
        const response = await (0, approvalRejection_1.resolveApprovalRejectionMessage)({
            runContext: state._context,
            toolType: 'function',
            toolName,
            approvalToolNames,
            approvalAgent: deps.agent,
            callId: toolRun.toolCall.callId,
            toolErrorFormatter,
        });
        if ((0, abortSignals_1.isSiblingCancellationSignal)(deps.signal)) {
            return buildFunctionCancellationResult(deps, toolRun);
        }
        const redactDetails = invalidInputFailure
            ? (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure)
            : false;
        const traceErrorMessage = runner.config.traceIncludeSensitiveData && !redactDetails
            ? response
            : approvalRejection_1.TOOL_APPROVAL_REJECTION_MESSAGE;
        let output;
        let rejectionFallbackFailed = false;
        let rejectionFallbackError;
        try {
            output = await resolveFunctionFailureOutput(deps, toolRun, new Error(response), response, invalidInputFailure
                ? {
                    failure: invalidInputFailure,
                    redactedLegacyOutput: approvalRejection_1.TOOL_APPROVAL_REJECTION_MESSAGE,
                }
                : undefined);
        }
        catch (error) {
            rejectionFallbackFailed = true;
            rejectionFallbackError = error;
        }
        if ((0, abortSignals_1.isSiblingCancellationSignal)(deps.signal)) {
            return buildFunctionCancellationResult(deps, toolRun);
        }
        span?.setError({
            message: traceErrorMessage,
            data: {
                tool_name: traceToolName,
                error: `Tool execution for ${toolRun.toolCall.callId} was manually rejected by user.`,
            },
        });
        if (rejectionFallbackFailed) {
            throw rejectionFallbackError;
        }
        if (invalidInputFailure &&
            (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure) &&
            span) {
            span.spanData.input = '';
        }
        if (span && runner.config.traceIncludeSensitiveData) {
            span.spanData.output = (0, smartString_1.toSmartString)(output);
        }
        return buildFunctionFailureResult(deps, toolRun, output);
    });
}
async function handlePreparedFunctionApproval(deps, toolRun, parsed, forceApproval, invalidInputFailure) {
    if (!(0, tool_1.hasDynamicFunctionToolApprovalPolicy)(toolRun.tool)) {
        return handleFunctionApproval(deps, toolRun, parsed.approvalArgs, forceApproval, invalidInputFailure);
    }
    const { state, agent } = deps;
    const callId = toolRun.toolCall.callId;
    const invocation = (0, toolInvocation_1.getToolInvocationFingerprint)(getFunctionToolIdentity(toolRun), toolRun.toolCall);
    const records = state._pendingFunctionToolApprovals.get(agent);
    const pending = records?.get(callId);
    const approval = state._context.isToolApproved({
        toolName: getFunctionToolApprovalStateKey(toolRun),
        callId,
        functionTool: false,
        agent,
    });
    if (approval === true && pending) {
        if (pending.invocation !== invocation) {
            throw new errors_1.UserError('The approved function tool invocation has changed.');
        }
        if (parsed.success &&
            parsed.preparedInput &&
            (pending.preparedInput?.result !== parsed.preparedInput.result ||
                pending.invoke !== toolRun.tool.invoke)) {
            const approvalArgs = parsed.approvalArgs;
            if (!(0, tool_1.hasInspectableFunctionToolArguments)(approvalArgs)) {
                throw new errors_1.UserError('Cannot re-evaluate conditional approval for this normalized input. Return a plain object or use needsApproval: true for durable manual approval.');
            }
            // Manual approval is bound to the unchanged model invocation. Re-evaluate
            // the policy against refreshed normalized input before honoring it. Either
            // result is satisfied by the existing approval; a thrown policy stops the
            // call. The handler below re-reads decisions after this await.
            await toolRun.tool.needsApproval(state._context, parsed.approvalArgs, callId);
            if (deps.signal?.aborted) {
                return buildFunctionCancellationResult(deps, toolRun);
            }
        }
    }
    const outcome = await handleFunctionApproval(deps, toolRun, parsed.approvalArgs, forceApproval, invalidInputFailure);
    if (outcome === 'approved' || outcome.type === 'function_approval') {
        const pendingRecords = state._pendingFunctionToolApprovals.get(agent) ?? new Map();
        state._pendingFunctionToolApprovals.set(agent, pendingRecords);
        pendingRecords.set(callId, {
            invocation,
            preparedInput: parsed.preparedInput,
            invoke: toolRun.tool.invoke,
        });
    }
    return outcome;
}
async function handleFunctionApproval(deps, toolRun, parsedArgs, forceApproval = false, invalidInputFailure) {
    const { agent, state } = deps;
    const approvalStateKey = getFunctionToolApprovalStateKey(toolRun);
    const pendingStateKeys = getFunctionToolPendingStateKeys(toolRun);
    const approval = state._context.isToolApproved({
        toolName: approvalStateKey,
        callId: toolRun.toolCall.callId,
        functionTool: false,
        agent,
    });
    if (approval === false) {
        for (const stateKey of pendingStateKeys) {
            state.clearPendingAgentToolRun(stateKey, toolRun.toolCall.callId);
        }
        return await buildApprovalRejectionResult(deps, toolRun, invalidInputFailure);
    }
    if (approval === true) {
        return 'approved';
    }
    let needsApproval = forceApproval;
    if (!needsApproval) {
        try {
            needsApproval = await toolRun.tool.needsApproval(state._context, parsedArgs, toolRun.toolCall.callId);
        }
        catch (error) {
            if (invalidInputFailure &&
                (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure)) {
                throw invalidInputFailure.error;
            }
            throw error;
        }
    }
    if (deps.signal?.aborted) {
        return buildFunctionCancellationResult(deps, toolRun);
    }
    if (!needsApproval) {
        return 'approved';
    }
    if (shouldRunPreApprovalInputGuardrails(deps)) {
        const redactedBeforeGuardrails = invalidInputFailure
            ? (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure)
            : false;
        const guardrailResults = [];
        let inputGuardrailResult = { type: 'allow' };
        let guardrailFailed = false;
        let guardrailError;
        try {
            inputGuardrailResult = await runFunctionToolInputGuardrails({
                guardrails: toolRun.tool.inputGuardrails,
                context: state._context,
                agent,
                toolCall: getFunctionToolCallbackToolCall(toolRun.toolCall, redactedBeforeGuardrails),
                onResult: (result) => {
                    guardrailResults.push(result);
                },
            });
        }
        catch (error) {
            guardrailFailed = true;
            guardrailError = error;
        }
        const redactedAfterGuardrails = invalidInputFailure
            ? (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure)
            : false;
        if (redactedBeforeGuardrails || !redactedAfterGuardrails) {
            state._toolInputGuardrailResults.push(...guardrailResults);
        }
        if ((0, abortSignals_1.isSiblingCancellationSignal)(deps.signal)) {
            return buildFunctionCancellationResult(deps, toolRun);
        }
        if (guardrailFailed) {
            const sdkTripwire = guardrailResults.some((result) => result.output.behavior?.type === 'throwException');
            if (invalidInputFailure &&
                redactedAfterGuardrails &&
                (!redactedBeforeGuardrails || !sdkTripwire)) {
                throw invalidInputFailure.error;
            }
            throw guardrailError;
        }
        if (inputGuardrailResult.type === 'reject') {
            return buildInputGuardrailRejectionResult(deps, toolRun, inputGuardrailResult.message, invalidInputFailure);
        }
    }
    return buildApprovalRequestResult(deps, toolRun);
}
async function buildInputGuardrailRejectionResult(deps, toolRun, message, invalidInputFailure) {
    const output = await resolveFunctionFailureOutput(deps, toolRun, new Error(message), message, invalidInputFailure
        ? {
            failure: invalidInputFailure,
            redactedLegacyOutput: functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE,
        }
        : undefined);
    return buildFunctionFailureResult(deps, toolRun, output);
}
async function runFunctionToolInputGuardrails({ guardrails, context, agent, toolCall, onResult, }) {
    return (0, toolGuardrails_1.runToolInputGuardrails)({
        guardrails,
        context,
        agent,
        toolCall,
        onResult,
    });
}
async function runApprovedFunctionTool(deps, toolRun, approvalArgs, preparedInput, invalidInputFailure, onInvalidOutputFailure) {
    const { agent, runner, state, agentToolParentRunConfig, signal } = deps;
    const toolName = getFunctionToolIdentity(toolRun);
    const stateKeys = getFunctionToolPendingStateKeys(toolRun);
    const traceToolName = getFunctionToolTraceName(toolRun);
    return withRunStateToolFunctionSpan(deps, traceToolName, async (span) => {
        let preservedLifecycleError;
        const refreshRedaction = () => {
            const redacted = invalidInputFailure
                ? (0, toolInputError_1.refreshInvalidToolInputFailure)(invalidInputFailure)
                : false;
            if (redacted && span) {
                span.spanData.input = '';
            }
            return redacted;
        };
        const throwIfRedactionPromoted = (redactedBefore) => {
            if (!redactedBefore && refreshRedaction() && invalidInputFailure) {
                throw invalidInputFailure.error;
            }
        };
        if (span &&
            runner.config.traceIncludeSensitiveData &&
            !refreshRedaction()) {
            span.spanData.input = toolRun.toolCall.arguments;
        }
        let toolStarted = false;
        let invocationPending = false;
        let cancellationFinalizationAttempted = false;
        let committedOutputOnFailure = false;
        const buildSiblingCancellationResult = () => {
            if (toolStarted) {
                toolStarted = false;
                cancellationFinalizationAttempted = true;
                if (span && runner.config.traceIncludeSensitiveData) {
                    span.spanData.output = 'aborted';
                }
                emitFunctionToolEnd(runner, state._context, agent, toolRun.tool, 'aborted', toolRun.toolCall, refreshRedaction, true);
            }
            return buildFunctionCancellationResult(deps, toolRun);
        };
        try {
            const redactedBeforeInputGuardrails = refreshRedaction();
            const inputGuardrailResults = [];
            let inputGuardrailResult = {
                type: 'allow',
            };
            let inputGuardrailFailed = false;
            let inputGuardrailError;
            try {
                inputGuardrailResult = await runFunctionToolInputGuardrails({
                    guardrails: toolRun.tool.inputGuardrails,
                    context: state._context,
                    agent,
                    toolCall: getFunctionToolCallbackToolCall(toolRun.toolCall, redactedBeforeInputGuardrails),
                    onResult: (result) => {
                        inputGuardrailResults.push(result);
                    },
                });
            }
            catch (error) {
                inputGuardrailFailed = true;
                inputGuardrailError = error;
                if (inputGuardrailResults.some((result) => result.output.behavior?.type === 'throwException')) {
                    preservedLifecycleError = error;
                }
            }
            const redactedAfterInputGuardrails = refreshRedaction();
            if (redactedBeforeInputGuardrails || !redactedAfterInputGuardrails) {
                state._toolInputGuardrailResults.push(...inputGuardrailResults);
            }
            if (signal?.aborted) {
                return buildFunctionCancellationResult(deps, toolRun);
            }
            if (inputGuardrailFailed) {
                if (!redactedBeforeInputGuardrails &&
                    redactedAfterInputGuardrails &&
                    invalidInputFailure) {
                    throw invalidInputFailure.error;
                }
                throw inputGuardrailError;
            }
            const redactedBeforeToolStart = refreshRedaction();
            try {
                emitFunctionToolStart(runner, state._context, agent, toolRun.tool, toolRun.toolCall, refreshRedaction);
            }
            catch (hookError) {
                if (!redactedBeforeToolStart &&
                    refreshRedaction() &&
                    invalidInputFailure) {
                    throw invalidInputFailure.error;
                }
                throw hookError;
            }
            refreshRedaction();
            toolStarted = true;
            let toolOutput;
            let executedInput = approvalArgs;
            let toolDetails = { toolCall: toolRun.toolCall };
            let shouldValidateToolOutput = false;
            let executionStatus;
            if (inputGuardrailResult.type === 'reject') {
                try {
                    toolOutput = await resolveFunctionFailureOutput(deps, toolRun, new Error(inputGuardrailResult.message), inputGuardrailResult.message, invalidInputFailure
                        ? {
                            failure: invalidInputFailure,
                            redactedLegacyOutput: functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE,
                        }
                        : undefined);
                }
                catch (error) {
                    if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                        return buildSiblingCancellationResult();
                    }
                    throw error;
                }
                if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                    return buildSiblingCancellationResult();
                }
            }
            else {
                const resumeState = stateKeys
                    .map((stateKey) => state.getPendingAgentToolRun(stateKey, toolRun.toolCall.callId))
                    .find((pendingState) => typeof pendingState !== 'undefined');
                const redactedBeforeInvocation = refreshRedaction();
                toolDetails = {
                    toolCall: getFunctionToolCallbackToolCall(toolRun.toolCall, redactedBeforeInvocation),
                    resumeState,
                    ...(signal ? { signal } : {}),
                    [tool_1.FUNCTION_TOOL_PARSED_INPUT_CALLBACK]: (input) => {
                        executedInput = cloneForCustomDataContext(input);
                    },
                    [tool_1.FUNCTION_TOOL_INVALID_OUTPUT_FAILURE_CALLBACK]: onInvalidOutputFailure,
                };
                if (preparedInput) {
                    let executionInput = preparedInput;
                    if ((0, tool_1.hasDynamicFunctionToolApprovalPolicy)(toolRun.tool) &&
                        preparedInput.result.success) {
                        const value = (0, functionToolApproval_1.getFunctionToolApprovalInput)(preparedInput.result.value);
                        // Keep the retained preparation pristine across nested execution.
                        executionInput = {
                            ...preparedInput,
                            result: { success: true, value },
                        };
                    }
                    (0, tool_1.setFunctionToolPreparedInput)(toolDetails, executionInput);
                }
                (0, usageTracking_1.setToolUsageRecorder)(toolDetails, (0, usageTracking_1.getRunStateUsageRecorder)(state));
                (0, agentToolRunConfig_1.setAgentToolParentRunConfigOnDetails)(toolDetails, agentToolParentRunConfig ?? runner.config);
                (0, agentToolRunConfig_1.setToolCallParentSpanOnDetails)(toolDetails, span);
                (0, functionToolTracing_1.setFunctionToolTracePolicy)(toolDetails, runner.config.traceIncludeSensitiveData);
                invocationPending = true;
                signal?.throwIfAborted();
                const invokedToolOutput = await (0, tool_1.invokeFunctionTool)({
                    tool: toolRun.tool,
                    runContext: state._context,
                    input: toolRun.toolCall.arguments,
                    details: toolDetails,
                });
                executionStatus = 'executed';
                invocationPending = false;
                throwIfRedactionPromoted(redactedBeforeInvocation);
                if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                    return buildSiblingCancellationResult();
                }
                const redactedBeforeOutputGuardrails = refreshRedaction();
                const outputGuardrailResults = [];
                try {
                    toolOutput = await (0, toolGuardrails_1.runToolOutputGuardrails)({
                        guardrails: toolRun.tool.outputGuardrails,
                        context: state._context,
                        agent,
                        toolCall: getFunctionToolCallbackToolCall(toolRun.toolCall, redactedBeforeOutputGuardrails),
                        toolOutput: invokedToolOutput,
                        onResult: (result) => {
                            outputGuardrailResults.push(result);
                        },
                    });
                }
                catch (guardrailError) {
                    if (outputGuardrailResults.some((result) => result.output.behavior?.type === 'throwException')) {
                        preservedLifecycleError = guardrailError;
                    }
                    throw guardrailError;
                }
                finally {
                    throwIfRedactionPromoted(redactedBeforeOutputGuardrails);
                    state._toolOutputGuardrailResults.push(...outputGuardrailResults);
                }
                if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                    return buildSiblingCancellationResult();
                }
                shouldValidateToolOutput = toolOutput !== invokedToolOutput;
            }
            if (shouldValidateToolOutput) {
                const redactedBeforeOutputValidation = refreshRedaction();
                toolOutput = (0, tool_1.validateFunctionToolOutput)({
                    tool: toolRun.tool,
                    output: toolOutput,
                    runContext: state._context,
                    details: toolDetails,
                });
                throwIfRedactionPromoted(redactedBeforeOutputValidation);
            }
            const stringResult = (0, smartString_1.toSmartString)(toolOutput);
            const rawItem = getToolCallOutputItem(toolRun.toolCall, toolOutput, {
                outputSchema: toolRun.tool.outputSchema,
            });
            if (refreshRedaction()) {
                executedInput = undefined;
            }
            const redactedBeforeCustomData = refreshRedaction();
            let customData;
            let customDataFailed = false;
            let customDataError;
            try {
                customData = await (0, customData_1.maybeExtractToolOutputCustomData)(toolRun.tool.customDataExtractor, {
                    runContext: state._context,
                    tool: toolRun.tool,
                    toolCall: cloneForCustomDataContext(getFunctionToolCallbackToolCall(toolRun.toolCall, redactedBeforeCustomData)),
                    input: cloneForCustomDataContext(executedInput),
                    output: cloneForCustomDataContext(toolOutput),
                    rawItem: cloneForCustomDataContext(rawItem),
                });
            }
            catch (error) {
                customDataFailed = true;
                customDataError = error;
            }
            finally {
                try {
                    throwIfRedactionPromoted(redactedBeforeCustomData);
                }
                catch (error) {
                    customDataFailed = true;
                    customDataError = error;
                }
            }
            if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                return buildSiblingCancellationResult();
            }
            if (customDataFailed) {
                throw customDataError;
            }
            const committedRunItem = new items_1.RunToolCallOutputItem(rawItem, agent, toolOutput, customData, executionStatus);
            const redactedBeforeToolEnd = refreshRedaction();
            try {
                emitFunctionToolEnd(runner, state._context, agent, toolRun.tool, stringResult, toolRun.toolCall, refreshRedaction);
                throwIfRedactionPromoted(redactedBeforeToolEnd);
            }
            catch (hookError) {
                if (state._currentStep?.type !== 'next_step_interruption' ||
                    state._currentStep.data?.responseAccepted !== true) {
                    throwIfRedactionPromoted(redactedBeforeToolEnd);
                    throw hookError;
                }
                const callRunItem = new items_1.RunToolCallItem(toolRun.toolCall, agent);
                const checkpointItems = state._generatedItems.some((item) => item instanceof items_1.RunToolCallItem &&
                    item.agent === agent &&
                    item.rawItem.type === 'function_call' &&
                    item.rawItem.callId === toolRun.toolCall.callId)
                    ? [committedRunItem]
                    : [callRunItem, committedRunItem];
                state._generatedItems.push(...checkpointItems);
                state._commitToolInvocations(checkpointItems);
                committedOutputOnFailure = true;
                throw hookError;
            }
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.output = stringResult;
            }
            const functionResult = {
                type: 'function_output',
                tool: toolRun.tool,
                output: toolOutput,
                runItem: committedRunItem,
            };
            const nestedRunResult = (0, agentToolRunResults_1.consumeAgentToolRunResult)(toolRun.toolCall);
            if (nestedRunResult) {
                functionResult.agentRunResult = nestedRunResult;
                const nestedInterruptions = nestedRunResult.interruptions;
                if (nestedInterruptions.length > 0) {
                    functionResult.interruptions = nestedInterruptions;
                    const nestedRunStateJson = nestedRunResult.state.toJSON();
                    const [stateKey, ...aliases] = stateKeys.length > 0 ? stateKeys : [toolName];
                    state.setPendingAgentToolRun(stateKey, toolRun.toolCall.callId, JSON.stringify(nestedRunStateJson), aliases);
                }
                else {
                    for (const stateKey of stateKeys) {
                        state.clearPendingAgentToolRun(stateKey, toolRun.toolCall.callId);
                    }
                }
            }
            return functionResult;
        }
        catch (error) {
            const invalidOutputFailure = (0, toolOutputError_1.getInvalidToolOutputFailure)(error);
            if (invalidOutputFailure) {
                onInvalidOutputFailure?.(invalidOutputFailure);
            }
            if (committedOutputOnFailure) {
                throw error;
            }
            if (cancellationFinalizationAttempted) {
                throw error;
            }
            if ((0, abortSignals_1.isSiblingCancellationSignal)(signal) && invocationPending) {
                return buildSiblingCancellationResult();
            }
            const redacted = refreshRedaction();
            const errorResult = redacted
                ? functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE
                : String(error);
            span?.setError({
                message: 'Error running tool',
                data: {
                    tool_name: traceToolName,
                    error: errorResult,
                },
            });
            try {
                emitFunctionToolEnd(runner, state._context, agent, toolRun.tool, errorResult, toolRun.toolCall, refreshRedaction);
            }
            catch (hookError) {
                if (refreshRedaction() && invalidInputFailure) {
                    throw invalidInputFailure.error;
                }
                throw hookError;
            }
            if (refreshRedaction() &&
                invalidInputFailure &&
                !(0, errors_1.isToolTimeoutError)(error) &&
                error !== preservedLifecycleError) {
                throw invalidInputFailure.error;
            }
            throw error;
        }
    });
}
/**
 * @internal
 */
// Internal helper: dispatch a computer action and return a screenshot (sync/async)
async function _runComputerActionAndScreenshot(computer, toolCall, runContext, signal) {
    for (const action of getComputerToolActions(toolCall)) {
        if (signal?.aborted) {
            return { type: 'cancelled' };
        }
        switch (action.type) {
            case 'click':
                await computer.click(action.x, action.y, action.button, runContext);
                break;
            case 'double_click':
                await computer.doubleClick(action.x, action.y, runContext);
                break;
            case 'drag':
                await computer.drag(action.path.map((p) => [p.x, p.y]), runContext);
                break;
            case 'keypress':
                await computer.keypress(action.keys, runContext);
                break;
            case 'move':
                await computer.move(action.x, action.y, runContext);
                break;
            case 'screenshot':
                // Screenshot actions are no-ops; capture the final state after the batch.
                break;
            case 'scroll':
                await computer.scroll(action.x, action.y, action.scroll_x, action.scroll_y, runContext);
                break;
            case 'type':
                await computer.type(action.text, runContext);
                break;
            case 'wait':
                await computer.wait(runContext);
                break;
            default:
                action;
                break;
        }
        if (signal?.aborted) {
            return { type: 'cancelled' };
        }
    }
    if (signal?.aborted) {
        return { type: 'cancelled' };
    }
    if (typeof computer.screenshot === 'function') {
        const screenshot = await computer.screenshot(runContext);
        if (signal?.aborted) {
            return { type: 'cancelled' };
        }
        if (typeof screenshot !== 'undefined') {
            return { type: 'completed', output: screenshot };
        }
    }
    throw new Error('Computer does not implement screenshot()');
}
function toErrorMessage(error) {
    if (error instanceof Error) {
        return error.message || error.toString();
    }
    try {
        return JSON.stringify(error);
    }
    catch {
        return String(error);
    }
}
function getTraceToolError(traceIncludeSensitiveData, errorMessage) {
    return traceIncludeSensitiveData ? errorMessage : functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE;
}
async function withToolFunctionSpan(runner, toolName, fn, parent) {
    if (runner.config.tracingDisabled || (!(0, context_1.getCurrentTrace)() && !parent)) {
        return fn();
    }
    return (0, createSpans_1.withFunctionSpan)(async (span) => {
        try {
            return await fn(span);
        }
        catch (error) {
            // Escaping callbacks must not fall through to generic error capture.
            if (!runner.config.traceIncludeSensitiveData && span.error === null) {
                span.setError({
                    message: 'Error running tool',
                    data: {
                        tool_name: toolName,
                        error: functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE,
                    },
                });
            }
            throw error;
        }
    }, {
        data: {
            name: toolName,
        },
    }, parent);
}
async function withRunStateToolFunctionSpan(deps, toolName, fn) {
    return withToolFunctionSpan(deps.runner, toolName, fn, (0, invocationContext_1.getRunStateTurnSpanParent)(deps.state) ?? deps.state._currentAgentSpan);
}
async function resolveToolApproval(options) {
    const { runContext, toolName, approvalItem, needsApproval, onApproval, isCancelled, } = options;
    const existingApproval = runContext._resolveToolInvocationApproval(approvalItem.agent, toolName, approvalItem.rawItem);
    if (existingApproval === true) {
        return 'approved';
    }
    if (existingApproval === false) {
        return 'rejected';
    }
    let approvalRequired;
    try {
        approvalRequired = await needsApproval();
    }
    catch (error) {
        if (isCancelled?.()) {
            return 'cancelled';
        }
        throw error;
    }
    if (isCancelled?.()) {
        return 'cancelled';
    }
    if (!approvalRequired) {
        return 'approved';
    }
    if (onApproval) {
        const decision = await onApproval(runContext, approvalItem);
        if (isCancelled?.()) {
            return 'cancelled';
        }
        if (decision.approve === true) {
            runContext.approveTool(approvalItem);
        }
        else if (decision.approve === false) {
            const reason = typeof decision.reason === 'string' && decision.reason.length > 0
                ? decision.reason
                : undefined;
            runContext.rejectTool(approvalItem, reason === undefined ? undefined : { message: reason });
        }
    }
    const approval = runContext._resolveToolInvocationApproval(approvalItem.agent, toolName, approvalItem.rawItem);
    if (approval === true) {
        return 'approved';
    }
    if (approval === false) {
        return 'rejected';
    }
    return 'pending';
}
async function handleToolApprovalDecision(options) {
    const { runContext, toolName, approvalItem, needsApproval, onApproval, buildRejectionItem, isCancelled, buildCancellationItem, } = options;
    const approvalState = await resolveToolApproval({
        runContext,
        toolName,
        approvalItem,
        needsApproval,
        onApproval,
        isCancelled,
    });
    if (isCancelled?.()) {
        return {
            status: 'cancelled',
            item: buildCancellationItem?.() ?? approvalItem,
        };
    }
    if (approvalState === 'cancelled') {
        return {
            status: 'cancelled',
            item: buildCancellationItem?.() ?? approvalItem,
        };
    }
    if (approvalState === 'rejected') {
        return { status: 'rejected', item: await buildRejectionItem() };
    }
    if (approvalState === 'pending') {
        return { status: 'pending', item: approvalItem };
    }
    return { status: 'approved' };
}
function emitToolStart(runner, runContext, agent, tool, toolCall) {
    runner.emit('agent_tool_start', runContext, agent, tool, { toolCall });
    if (typeof agent.emit === 'function') {
        agent.emit('agent_tool_start', runContext, tool, { toolCall });
    }
}
function emitToolEnd(runner, runContext, agent, tool, output, toolCall) {
    runner.emit('agent_tool_end', runContext, agent, tool, output, { toolCall });
    if (typeof agent.emit === 'function') {
        agent.emit('agent_tool_end', runContext, tool, output, { toolCall });
    }
}
function emitFunctionToolStart(runner, runContext, agent, tool, toolCall, refreshRedaction) {
    runner.emit('agent_tool_start', runContext, agent, tool, {
        toolCall: getFunctionToolCallbackToolCall(toolCall, refreshRedaction()),
    });
    if (typeof agent.emit === 'function') {
        agent.emit('agent_tool_start', runContext, tool, {
            toolCall: getFunctionToolCallbackToolCall(toolCall, refreshRedaction()),
        });
    }
}
function emitFunctionToolEnd(runner, runContext, agent, tool, output, toolCall, refreshRedaction, redactionSafeOutput = false) {
    const redactedBeforeRunnerHook = refreshRedaction();
    runner.emit('agent_tool_end', runContext, agent, tool, output, {
        toolCall: getFunctionToolCallbackToolCall(toolCall, redactedBeforeRunnerHook),
    });
    if (typeof agent.emit === 'function') {
        const redactedBeforeAgentHook = refreshRedaction();
        agent.emit('agent_tool_end', runContext, tool, !redactionSafeOutput &&
            !redactedBeforeRunnerHook &&
            redactedBeforeAgentHook
            ? functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE
            : output, {
            toolCall: getFunctionToolCallbackToolCall(toolCall, redactedBeforeAgentHook),
        });
    }
}
function getToolCallKey(toolCall) {
    if ('callId' in toolCall && typeof toolCall.callId === 'string') {
        return toolCall.callId;
    }
    if ('id' in toolCall && typeof toolCall.id === 'string') {
        return toolCall.id;
    }
    return undefined;
}
async function executeShellActions(agent, actions, runner, runContext, customLogger = undefined, toolErrorFormatter) {
    const _logger = customLogger ?? logger_1.default;
    const results = [];
    for (const action of actions) {
        const shellTool = action.shell;
        const toolCall = action.toolCall;
        const toolCallKey = getToolCallKey(toolCall) ?? toolCall.callId;
        if (!shellTool.shell) {
            _logger.warn(`Skipping shell action for tool "${shellTool.name}" because no local shell implementation is configured.`);
            continue;
        }
        const approvalItem = new items_1.RunToolApprovalItem(toolCall, agent, shellTool.name);
        const approvalDecision = await handleToolApprovalDecision({
            runContext,
            toolName: shellTool.name,
            approvalItem,
            needsApproval: () => shellTool.needsApproval(runContext, toolCall.action, toolCallKey),
            onApproval: shellTool.onApproval,
            buildRejectionItem: async () => {
                const response = await (0, approvalRejection_1.resolveApprovalRejectionMessage)({
                    runContext,
                    toolType: 'shell',
                    toolName: shellTool.name,
                    callId: toolCallKey,
                    toolErrorFormatter,
                });
                const rejectionOutput = {
                    stdout: '',
                    stderr: response,
                    outcome: { type: 'exit', exitCode: null },
                };
                return new items_1.RunToolCallOutputItem({
                    type: 'shell_call_output',
                    callId: toolCallKey,
                    output: [rejectionOutput],
                    ...(toolCall.caller ? { caller: toolCall.caller } : {}),
                }, agent, response);
            },
        });
        if (approvalDecision.status !== 'approved') {
            results.push(approvalDecision.item);
            continue;
        }
        const shellItem = await withToolFunctionSpan(runner, shellTool.name, async (span) => {
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.input = JSON.stringify(toolCall.action);
            }
            emitToolStart(runner, runContext, agent, shellTool, toolCall);
            let shellOutputs;
            const providerMeta = {};
            let maxOutputLength;
            try {
                const shellResult = await shellTool.shell.run(toolCall.action);
                shellOutputs = shellResult.output ?? [];
                if (shellResult.providerData) {
                    Object.assign(providerMeta, shellResult.providerData);
                }
                if (typeof shellResult.maxOutputLength === 'number') {
                    maxOutputLength = shellResult.maxOutputLength;
                }
            }
            catch (err) {
                const errorText = toErrorMessage(err);
                const traceError = getTraceToolError(runner.config.traceIncludeSensitiveData, errorText);
                shellOutputs = [
                    {
                        stdout: '',
                        stderr: errorText,
                        outcome: { type: 'exit', exitCode: null },
                    },
                ];
                span?.setError({
                    message: 'Error running tool',
                    data: {
                        tool_name: shellTool.name,
                        error: traceError,
                    },
                });
                (0, logger_1.logToolActionError)(_logger, 'Failed to execute shell action:', err);
            }
            shellOutputs = shellOutputs ?? [];
            const output = JSON.stringify(shellOutputs);
            emitToolEnd(runner, runContext, agent, shellTool, output, toolCall);
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.output = output;
            }
            const rawItem = {
                type: 'shell_call_output',
                callId: toolCallKey,
                output: shellOutputs ?? [],
                ...(toolCall.caller ? { caller: toolCall.caller } : {}),
            };
            if (typeof maxOutputLength === 'number') {
                rawItem.maxOutputLength = maxOutputLength;
            }
            if (Object.keys(providerMeta).length > 0) {
                rawItem.providerData = providerMeta;
            }
            return new items_1.RunToolCallOutputItem(rawItem, agent, rawItem.output, undefined, 'executed');
        });
        results.push(shellItem);
    }
    return results;
}
async function executeApplyPatchOperations(agent, actions, runner, runContext, customLogger = undefined, toolErrorFormatter) {
    const _logger = customLogger ?? logger_1.default;
    const results = [];
    for (const action of actions) {
        const applyPatchTool = action.applyPatch;
        const toolCall = action.toolCall;
        const toolCallKey = getToolCallKey(toolCall) ?? toolCall.callId;
        const editorContext = { runContext };
        const approvalItem = new items_1.RunToolApprovalItem(toolCall, agent, applyPatchTool.name);
        const approvalDecision = await handleToolApprovalDecision({
            runContext,
            toolName: applyPatchTool.name,
            approvalItem,
            needsApproval: () => applyPatchTool.needsApproval(runContext, toolCall.operation, toolCallKey),
            onApproval: applyPatchTool.onApproval,
            buildRejectionItem: async () => {
                const response = await (0, approvalRejection_1.resolveApprovalRejectionMessage)({
                    runContext,
                    toolType: 'apply_patch',
                    toolName: applyPatchTool.name,
                    callId: toolCallKey,
                    toolErrorFormatter,
                });
                return new items_1.RunToolCallOutputItem({
                    type: 'apply_patch_call_output',
                    callId: toolCallKey,
                    status: 'failed',
                    output: response,
                    ...(toolCall.caller ? { caller: toolCall.caller } : {}),
                }, agent, response);
            },
        });
        if (approvalDecision.status !== 'approved') {
            results.push(approvalDecision.item);
            continue;
        }
        const applyPatchItem = await withToolFunctionSpan(runner, applyPatchTool.name, async (span) => {
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.input = JSON.stringify(toolCall.operation);
            }
            emitToolStart(runner, runContext, agent, applyPatchTool, toolCall);
            let status = 'completed';
            let output = '';
            try {
                let result;
                switch (toolCall.operation.type) {
                    case 'create_file':
                        result = await applyPatchTool.editor.createFile(toolCall.operation, editorContext);
                        break;
                    case 'update_file':
                        result = await applyPatchTool.editor.updateFile(toolCall.operation, editorContext);
                        break;
                    case 'delete_file':
                        result = await applyPatchTool.editor.deleteFile(toolCall.operation, editorContext);
                        break;
                    default:
                        throw new Error('Unsupported apply_patch operation');
                }
                if (result && typeof result.status === 'string') {
                    status = result.status;
                }
                if (result && typeof result.output === 'string') {
                    output = result.output;
                }
            }
            catch (err) {
                status = 'failed';
                output = toErrorMessage(err);
                const traceError = getTraceToolError(runner.config.traceIncludeSensitiveData, output);
                span?.setError({
                    message: 'Error running tool',
                    data: {
                        tool_name: applyPatchTool.name,
                        error: traceError,
                    },
                });
                (0, logger_1.logToolActionError)(_logger, 'Failed to execute apply_patch operation:', err);
            }
            const rawItem = {
                type: 'apply_patch_call_output',
                callId: toolCallKey,
                status,
                ...(toolCall.caller ? { caller: toolCall.caller } : {}),
            };
            if (output) {
                rawItem.output = output;
            }
            const customData = await (0, customData_1.maybeExtractToolOutputCustomData)(applyPatchTool.customDataExtractor, {
                runContext,
                tool: applyPatchTool,
                operation: cloneForCustomDataContext(toolCall.operation),
                output,
                status,
                rawItem: cloneForCustomDataContext(rawItem),
            });
            emitToolEnd(runner, runContext, agent, applyPatchTool, output, toolCall);
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.output = output;
            }
            return new items_1.RunToolCallOutputItem(rawItem, agent, output, customData, 'executed');
        });
        results.push(applyPatchItem);
    }
    return results;
}
/**
 * @internal
 * Executes any computer-use actions emitted by the model and returns the resulting items so
 * the run history reflects the computer session.
 */
async function executeComputerActions(agent, actions, runner, runContext, customLogger = undefined, toolErrorFormatter, signal, onFatalFailure) {
    const _logger = customLogger ?? logger_1.default;
    const results = [];
    for (const action of actions) {
        const toolCall = action.toolCall;
        const computerTool = action.computer;
        if (signal?.aborted) {
            results.push(buildComputerCancellationItem(agent, toolCall));
            continue;
        }
        const computerActions = getComputerToolActions(toolCall);
        let cachedRejectionMessage;
        const getRejectionMessage = async () => {
            if (typeof cachedRejectionMessage === 'string') {
                return cachedRejectionMessage;
            }
            cachedRejectionMessage = await (0, approvalRejection_1.resolveApprovalRejectionMessage)({
                runContext,
                toolType: 'computer',
                toolName: computerTool.name,
                callId: toolCall.callId,
                toolErrorFormatter,
            });
            return cachedRejectionMessage;
        };
        const buildRejectionItem = (rejectionMessage) => {
            const rejectionOutput = {
                type: 'computer_screenshot',
                data: streamReconciliation_1.COMPUTER_FALLBACK_SCREENSHOT_DATA_URL,
                providerData: {
                    approvalStatus: 'rejected',
                    message: rejectionMessage,
                },
            };
            const rawItem = {
                type: 'computer_call_result',
                callId: toolCall.callId,
                output: rejectionOutput,
            };
            return new items_1.RunToolCallOutputItem(rawItem, agent, streamReconciliation_1.COMPUTER_FALLBACK_SCREENSHOT_DATA_URL);
        };
        const pendingSafetyChecks = getPendingSafetyChecks(toolCall);
        const approvalItem = new items_1.RunToolApprovalItem(toolCall, agent, computerTool.name);
        const needsApprovalCandidate = computerTool
            .needsApproval;
        const approvalDecision = await handleToolApprovalDecision({
            runContext,
            toolName: computerTool.name,
            approvalItem,
            needsApproval: async () => {
                if (typeof needsApprovalCandidate !== 'function') {
                    return typeof needsApprovalCandidate === 'boolean'
                        ? needsApprovalCandidate
                        : false;
                }
                let firstError;
                const approvalResults = await Promise.allSettled(computerActions.map(async (computerAction) => {
                    try {
                        return await needsApprovalCandidate(runContext, computerAction, toolCall.callId);
                    }
                    catch (error) {
                        if (!firstError) {
                            firstError = { value: error };
                            onFatalFailure?.(error);
                        }
                        throw error;
                    }
                }));
                if (firstError) {
                    throw firstError.value;
                }
                return approvalResults.some((result) => result.status === 'fulfilled' && result.value);
            },
            buildRejectionItem: async () => buildRejectionItem(await getRejectionMessage()),
            isCancelled: () => (0, abortSignals_1.isSiblingCancellationSignal)(signal),
            buildCancellationItem: () => buildComputerCancellationItem(agent, toolCall),
        });
        if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
            results.push(buildComputerCancellationItem(agent, toolCall));
            continue;
        }
        if (approvalDecision.status === 'rejected') {
            const rejectionMessage = await getRejectionMessage();
            if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                results.push(buildComputerCancellationItem(agent, toolCall));
                continue;
            }
            results.push(approvalDecision.item);
            results.push(new items_1.RunMessageOutputItem((0, message_1.assistant)(rejectionMessage), agent));
            continue;
        }
        if (approvalDecision.status === 'pending') {
            results.push(approvalDecision.item);
            continue;
        }
        if (approvalDecision.status === 'cancelled') {
            results.push(approvalDecision.item);
            continue;
        }
        const computerItem = await withToolFunctionSpan(runner, COMPUTER_TRACE_NAME, async (span) => {
            if (span && runner.config.traceIncludeSensitiveData) {
                const traceInput = getComputerTraceInputPayload(toolCall);
                span.spanData.input =
                    typeof traceInput === 'undefined' ? '' : JSON.stringify(traceInput);
            }
            if (signal?.aborted) {
                return buildComputerCancellationItem(agent, toolCall);
            }
            // Hooks: on_tool_start (global + agent)
            emitToolStart(runner, runContext, agent, computerTool, toolCall);
            let cancellationFinalizationAttempted = false;
            const buildStartedCancellationItem = () => {
                const item = buildComputerCancellationItem(agent, toolCall);
                cancellationFinalizationAttempted = true;
                if (span && runner.config.traceIncludeSensitiveData) {
                    span.spanData.output = 'aborted';
                }
                emitToolEnd(runner, runContext, agent, computerTool, 'aborted', toolCall);
                return item;
            };
            let acknowledgedSafetyChecks;
            try {
                acknowledgedSafetyChecks =
                    pendingSafetyChecks && pendingSafetyChecks.length > 0
                        ? await resolveSafetyCheckAcknowledgements({
                            runContext,
                            toolCall,
                            pendingSafetyChecks,
                            onSafetyCheck: computerTool.onSafetyCheck,
                        })
                        : undefined;
            }
            catch (error) {
                if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                    return buildStartedCancellationItem();
                }
                if (!runner.config.traceIncludeSensitiveData) {
                    span?.setError({
                        message: 'Error running tool',
                        data: {
                            tool_name: COMPUTER_TRACE_NAME,
                            error: functionToolTracing_1.REDACTED_TOOL_ERROR_MESSAGE,
                        },
                    });
                }
                throw error;
            }
            if (signal?.aborted) {
                return buildStartedCancellationItem();
            }
            if (acknowledgedSafetyChecks === false) {
                const rejectionMessage = await getRejectionMessage();
                if (signal?.aborted) {
                    return buildStartedCancellationItem();
                }
                const rejectionItem = buildRejectionItem(rejectionMessage);
                emitToolEnd(runner, runContext, agent, computerTool, rejectionMessage, toolCall);
                if (span && runner.config.traceIncludeSensitiveData) {
                    span.spanData.output = rejectionMessage;
                }
                return [
                    rejectionItem,
                    new items_1.RunMessageOutputItem((0, message_1.assistant)(rejectionMessage), agent),
                ];
            }
            // Run the action and get screenshot.
            let output;
            try {
                const computer = await (0, tool_1.resolveComputer)({
                    tool: computerTool,
                    runContext,
                });
                if (signal?.aborted) {
                    return buildStartedCancellationItem();
                }
                const actionResult = await _runComputerActionAndScreenshot(computer, toolCall, runContext, signal);
                if (signal?.aborted || actionResult.type === 'cancelled') {
                    return buildStartedCancellationItem();
                }
                output = actionResult.output;
            }
            catch (err) {
                if (cancellationFinalizationAttempted) {
                    throw err;
                }
                if (signal?.aborted) {
                    return buildStartedCancellationItem();
                }
                (0, logger_1.logToolActionError)(_logger, 'Failed to execute computer action:', err);
                output = '';
                const errorText = toErrorMessage(err);
                const traceError = getTraceToolError(runner.config.traceIncludeSensitiveData, errorText);
                span?.setError({
                    message: 'Error running tool',
                    data: {
                        tool_name: COMPUTER_TRACE_NAME,
                        error: traceError,
                    },
                });
            }
            // Return the screenshot as a data URL when available; fall back to an empty string on failures.
            const imageUrl = output ? `data:image/png;base64,${output}` : '';
            const rawItem = {
                type: 'computer_call_result',
                callId: toolCall.callId,
                output: { type: 'computer_screenshot', data: imageUrl },
            };
            if (acknowledgedSafetyChecks && acknowledgedSafetyChecks.length > 0) {
                rawItem.providerData = {
                    acknowledgedSafetyChecks,
                };
            }
            let customData;
            let customDataFailed = false;
            let customDataError;
            try {
                customData = await (0, customData_1.maybeExtractToolOutputCustomData)(computerTool.customDataExtractor, {
                    runContext,
                    tool: computerTool,
                    toolCall: cloneForCustomDataContext(toolCall),
                    output: imageUrl,
                    rawItem: cloneForCustomDataContext(rawItem),
                });
            }
            catch (error) {
                customDataFailed = true;
                customDataError = error;
            }
            if ((0, abortSignals_1.isSiblingCancellationSignal)(signal)) {
                return buildStartedCancellationItem();
            }
            if (customDataFailed) {
                throw customDataError;
            }
            // Hooks: on_tool_end (global + agent)
            emitToolEnd(runner, runContext, agent, computerTool, output, toolCall);
            if (span && runner.config.traceIncludeSensitiveData) {
                span.spanData.output = imageUrl;
            }
            return new items_1.RunToolCallOutputItem(rawItem, agent, imageUrl, customData, 'executed');
        });
        results.push(...(Array.isArray(computerItem) ? computerItem : [computerItem]));
    }
    return results;
}
function buildComputerCancellationItem(agent, toolCall) {
    const rawItem = (0, streamReconciliation_1.buildComputerAbortResult)(toolCall);
    return new items_1.RunToolCallOutputItem(rawItem, agent, 'aborted');
}
/**
 * @internal
 * Drives handoff calls by invoking the downstream agent and capturing any generated items so
 * the current agent can continue with the new context.
 */
async function executeHandoffCalls(agent, originalInput, preStepItems, newStepItems, newResponse, runHandoffs, runner, runContext, parent, validateHandoffAgent, beforeInputFilter, signal) {
    newStepItems = [...newStepItems];
    if (runHandoffs.length === 0) {
        logger_1.default.warn('Incorrectly called executeHandoffCalls with no handoffs. This should not happen. Moving on.');
        return new steps_1.SingleStepResult(originalInput, newResponse, preStepItems, newStepItems, { type: 'next_step_run_again' });
    }
    if (runHandoffs.length > 1) {
        const ignoredCallIds = new Set(runHandoffs.slice(1).map((handoff) => handoff.toolCall.callId));
        // Drop ignored handoff requests from the step so they never persist to history.
        newStepItems = newStepItems.filter((item) => !(item instanceof items_1.RunHandoffCallItem &&
            ignoredCallIds.has(item.rawItem.callId)));
    }
    const actualHandoff = runHandoffs[0];
    return (0, createSpans_1.withHandoffSpan)(async (handoffSpan) => {
        const handoff = actualHandoff.handoff;
        const inputFilter = handoff.inputFilter ?? runner.config.handoffInputFilter;
        if (inputFilter != null && typeof inputFilter !== 'function') {
            throw Object.assign(new errors_1.UserError('Invalid handoff input filter: not callable'), {
                data: {
                    details: 'not callable',
                },
            });
        }
        validateHandoffAgent?.(handoff.agent);
        let newAgent;
        try {
            newAgent = await handoff.onInvokeHandoff(runContext, actualHandoff.toolCall.arguments);
        }
        catch (error) {
            if (!handoff.errorFunction || (0, abortSignals_1.isAbortError)(error)) {
                throw error;
            }
            signal?.throwIfAborted();
            const fatalInputError = (0, handoff_1.getFatalHandoffInputError)(error);
            if (fatalInputError !== undefined)
                throw fatalInputError;
            handoffSpan.setError({
                message: 'Handoff invocation failed',
                data: {},
            });
            const feedback = await handoff.errorFunction(runContext, error);
            signal?.throwIfAborted();
            newStepItems.push(new items_1.RunToolCallOutputItem(getToolCallOutputItem(actualHandoff.toolCall, feedback), agent, feedback, undefined, 'executed'));
            return new steps_1.SingleStepResult(originalInput, newResponse, preStepItems, newStepItems, {
                type: 'next_step_run_again',
            });
        }
        validateHandoffAgent?.(newAgent);
        handoffSpan.spanData.to_agent = newAgent.name;
        if (runHandoffs.length > 1) {
            const requestedAgents = runHandoffs.map((h) => h.handoff.agentName);
            handoffSpan.setError({
                message: 'Multiple handoffs requested',
                data: {
                    requested_agents: requestedAgents,
                },
            });
        }
        newStepItems.push(new items_1.RunHandoffOutputItem(getToolCallOutputItem(actualHandoff.toolCall, (0, handoff_1.getTransferMessage)(newAgent)), agent, newAgent));
        runner.emit('agent_handoff', runContext, agent, newAgent);
        agent.emit('agent_handoff', runContext, newAgent);
        const toolInvocationCommitItems = [...newStepItems];
        if (inputFilter != null) {
            logger_1.default.debug('Filtering inputs for handoff');
            const handoffInputData = {
                inputHistory: Array.isArray(originalInput)
                    ? [...originalInput]
                    : originalInput,
                preHandoffItems: [...preStepItems],
                newItems: [...newStepItems],
                runContext,
            };
            beforeInputFilter?.(handoffInputData);
            const filtered = inputFilter(handoffInputData);
            (0, items_2.invalidateOutputItemNormalization)([
                ...handoffInputData.preHandoffItems,
                ...handoffInputData.newItems,
            ]);
            originalInput = filtered.inputHistory;
            preStepItems = filtered.preHandoffItems;
            newStepItems = filtered.newItems;
        }
        return new steps_1.SingleStepResult(originalInput, newResponse, preStepItems, newStepItems, { type: 'next_step_handoff', newAgent }, undefined, toolInvocationCommitItems);
    }, {
        data: {
            from_agent: agent.name,
        },
    }, parent);
}
const NOT_FINAL_OUTPUT = {
    isFinalOutput: false,
    isInterrupted: undefined,
};
/**
 * Collects approval interruptions from tool execution results and any additional
 * RunItems (e.g., shell/apply_patch approval placeholders).
 */
function collectInterruptions(toolResults, additionalItems = []) {
    const interruptions = [];
    for (const item of additionalItems) {
        if (item instanceof items_1.RunToolApprovalItem) {
            interruptions.push(item);
        }
    }
    for (const result of toolResults) {
        if (result.runItem instanceof items_1.RunToolApprovalItem) {
            interruptions.push(result.runItem);
        }
        if (result.type === 'function_output') {
            if (Array.isArray(result.interruptions)) {
                interruptions.push(...result.interruptions);
            }
            else if (result.agentRunResult) {
                const nestedInterruptions = result.agentRunResult.interruptions;
                if (nestedInterruptions.length > 0) {
                    interruptions.push(...nestedInterruptions);
                }
            }
        }
    }
    return interruptions;
}
/**
 * @internal
 * Determines whether tool executions produced a final agent output, triggered an interruption,
 * or whether the agent loop should continue collecting more responses.
 */
async function checkForFinalOutputFromTools(agent, toolResults, state, additionalInterruptions = []) {
    (0, runState_1.recordPendingSessionWriteTerminalProducer)(state, undefined);
    if (toolResults.length === 0 && additionalInterruptions.length === 0) {
        return NOT_FINAL_OUTPUT;
    }
    const interruptions = collectInterruptions(toolResults, additionalInterruptions);
    if (interruptions.length > 0) {
        return {
            isFinalOutput: false,
            isInterrupted: true,
            interruptions,
        };
    }
    const finalizationResults = toolResults.filter((result) => {
        const rawItem = result.runItem.rawItem;
        return !(rawItem &&
            'caller' in rawItem &&
            rawItem.caller?.type === 'program');
    });
    const isIncompleteFunctionResult = (result) => {
        const rawItem = result.runItem.rawItem;
        return (result.type === 'function_output' &&
            rawItem?.type === 'function_call_result' &&
            rawItem.status === 'incomplete');
    };
    if (finalizationResults.length === 0 ||
        finalizationResults.some(isIncompleteFunctionResult)) {
        return NOT_FINAL_OUTPUT;
    }
    if (agent.toolUseBehavior === 'run_llm_again') {
        return NOT_FINAL_OUTPUT;
    }
    const firstToolResult = finalizationResults[0];
    if (agent.toolUseBehavior === 'stop_on_first_tool') {
        if (firstToolResult?.type === 'function_output') {
            const stringOutput = (0, smartString_1.toSmartString)(firstToolResult.output);
            const callId = firstToolResult.runItem.rawItem?.callId;
            const functionOutputs = finalizationResults.flatMap((result) => result.type === 'function_output' ? [result] : []);
            const resultCallIds = functionOutputs.flatMap((result) => result.runItem.rawItem?.callId ? [result.runItem.rawItem.callId] : []);
            if (callId && resultCallIds.length === finalizationResults.length) {
                (0, runState_1.recordPendingSessionWriteTerminalProducer)(state, {
                    behavior: agent.toolUseBehavior,
                    resultCallIds,
                    resultItems: functionOutputs.map((result) => result.runItem),
                    selectedCallId: callId,
                    finalOutput: stringOutput,
                });
            }
            return {
                isFinalOutput: true,
                isInterrupted: undefined,
                finalOutput: stringOutput,
            };
        }
        return NOT_FINAL_OUTPUT;
    }
    const toolUseBehavior = agent.toolUseBehavior;
    if (typeof toolUseBehavior === 'object') {
        const stoppingTool = finalizationResults.find((r) => {
            return toolUseBehavior.stopAtToolNames.some((toolName) => (0, toolIdentity_1.matchesFunctionToolName)(r.tool, toolName));
        });
        if (stoppingTool?.type === 'function_output') {
            const stringOutput = (0, smartString_1.toSmartString)(stoppingTool.output);
            const callId = stoppingTool.runItem.rawItem?.callId;
            if (callId) {
                (0, runState_1.recordPendingSessionWriteTerminalProducer)(state, {
                    behavior: toolUseBehavior,
                    resultCallIds: [callId],
                    resultItems: [stoppingTool.runItem],
                    selectedCallId: callId,
                    finalOutput: stringOutput,
                });
            }
            return {
                isFinalOutput: true,
                isInterrupted: undefined,
                finalOutput: stringOutput,
            };
        }
        return NOT_FINAL_OUTPUT;
    }
    if (typeof toolUseBehavior === 'function') {
        const outcome = await toolUseBehavior(state._context, finalizationResults);
        if (outcome.isFinalOutput) {
            const resultCallIds = finalizationResults.flatMap((result) => result.type === 'function_output' && result.runItem.rawItem?.callId
                ? [result.runItem.rawItem.callId]
                : []);
            if (resultCallIds.length === finalizationResults.length) {
                (0, runState_1.recordPendingSessionWriteTerminalProducer)(state, {
                    behavior: toolUseBehavior,
                    resultCallIds,
                    resultItems: finalizationResults.flatMap((result) => result.type === 'function_output' ? [result.runItem] : []),
                    finalOutput: outcome.finalOutput,
                });
            }
        }
        return outcome;
    }
    throw new errors_1.UserError(`Invalid toolUseBehavior: ${toolUseBehavior}`, state);
}
function normalizeSafetyChecks(checks) {
    if (!Array.isArray(checks)) {
        return undefined;
    }
    const normalized = [];
    for (const entry of checks) {
        if (!isRecord(entry)) {
            continue;
        }
        const id = entry.id;
        const code = entry.code;
        if (!isNonEmptyString(id) || !isNonEmptyString(code)) {
            continue;
        }
        const message = 'message' in entry && isNonEmptyString(entry.message)
            ? entry.message
            : undefined;
        const normalizedEntry = { ...entry, id, code };
        if (message) {
            normalizedEntry.message = message;
        }
        normalized.push(normalizedEntry);
    }
    return normalized.length > 0 ? normalized : undefined;
}
function normalizeSafetyCheckResult(result) {
    if (!result) {
        return undefined;
    }
    if (!isRecord(result)) {
        return undefined;
    }
    if ('acknowledgedSafetyChecks' in result) {
        return normalizeSafetyChecks(result.acknowledgedSafetyChecks);
    }
    if ('acknowledged_safety_checks' in result) {
        return normalizeSafetyChecks(result.acknowledged_safety_checks);
    }
    return undefined;
}
async function resolveSafetyCheckAcknowledgements(options) {
    const { runContext, toolCall, pendingSafetyChecks, onSafetyCheck } = options;
    if (!onSafetyCheck) {
        logger_1.default.warn('Computer call has pending safety checks, but no onSafetyCheck handler is configured. ' +
            'The action will proceed without acknowledging the checks. ' +
            'Configure computerTool({ onSafetyCheck }) to review or reject them.');
        return undefined;
    }
    const result = await onSafetyCheck({
        runContext,
        pendingSafetyChecks,
        toolCall,
    });
    if (result === true) {
        return pendingSafetyChecks;
    }
    if (result === false) {
        return false;
    }
    return normalizeSafetyCheckResult(result);
}
function getPendingSafetyChecks(toolCall) {
    const providerData = toolCall.providerData;
    if (!isRecord(providerData)) {
        return undefined;
    }
    if ('pending_safety_checks' in providerData) {
        return normalizeSafetyChecks(providerData.pending_safety_checks);
    }
    if ('pendingSafetyChecks' in providerData) {
        return normalizeSafetyChecks(providerData.pendingSafetyChecks);
    }
    return undefined;
}
function isRecord(value) {
    return typeof value === 'object' && value !== null;
}
function isNonEmptyString(value) {
    return typeof value === 'string' && value.length > 0;
}
//# sourceMappingURL=toolExecution.js.map