@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
2,142 lines • 95 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
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