UNPKG

@openai/agents-core

Version:

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

892 lines • 42.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processModelResponse = processModelResponse; exports.processModelResponseAsync = processModelResponseAsync; const errors_1 = require("../errors.js"); const items_1 = require("../items.js"); const tool_1 = require("../tool.js"); const context_1 = require("../tracing/context.js"); const toolIdentity_1 = require("../toolIdentity.js"); const utils_1 = require("../utils/index.js"); const types_1 = require("./types.js"); const toolSearch_1 = require("./toolSearch.js"); const toolCaller_1 = require("./toolCaller.js"); const items_2 = require("./items.js"); const toolSearchAttribution_1 = require("./toolSearchAttribution.js"); function ensureToolAvailable(tool, message, data) { if (!tool) { (0, context_1.addErrorToCurrentSpan)({ message, data, }); throw new errors_1.ModelBehaviorError(message); } return tool; } function ensureProgrammaticToolCallingAvailable(output, tools, agent, options) { const programmaticTool = tools.find((tool) => tool.type === 'hosted_tool' && tool.providerData?.type === 'programmatic_tool_calling'); if (programmaticTool || options.allowPromptSuppliedTools === true) { return; } ensureToolAvailable(programmaticTool, `Model produced a program item without programmaticToolCallingTool() in Agent (${agent.name}).`, { agent_name: agent.name, tool_call_id: output.callId, }); } const MCP_HOSTED_CALL_TYPES = new Set([ 'mcp_call', 'mcp_list_tools', 'mcp_approval_request', 'mcp_approval_response', ]); function ensureHostedToolCallAllowed(output, tools, mcpToolMap, loadedState, agent) { const providerType = output.providerData?.type; const isCodeInterpreterCall = providerType === 'code_interpreter_call' || providerType === 'code_interpreter' || output.name === 'code_interpreter_call' || output.name === 'code_interpreter'; if (isCodeInterpreterCall) { const codeInterpreterTool = tools.find((tool) => tool.type === 'hosted_tool' && tool.providerData?.type === 'code_interpreter'); if (!codeInterpreterTool) { return; } (0, toolCaller_1.ensureToolCallerAllowed)(output, codeInterpreterTool.providerData?.allowed_callers, codeInterpreterTool.name, agent); return; } if (!MCP_HOSTED_CALL_TYPES.has(providerType) && !MCP_HOSTED_CALL_TYPES.has(output.name)) { return; } const serverLabel = output.providerData?.server_label; if (typeof serverLabel !== 'string') { return; } const mcpTool = mcpToolMap.get(serverLabel); if (!mcpTool) { return; } (0, toolCaller_1.ensureToolCallerAllowed)(output, mcpTool.providerData.allowed_callers, serverLabel, agent); // Hosted MCP discovery can be reported before the tool-search result. // Listing tools does not execute them or mark the server as loaded. if (providerType === 'mcp_list_tools' || output.name === 'mcp_list_tools') { return; } if (mcpTool.providerData.defer_loading !== true || [ ...loadedState.keyedToolSearchOutputsByKey.values(), ...loadedState.anonymousToolSearchOutputs, ].some((searchOutput) => (0, toolSearch_1.toolSearchOutputLoadsHostedMcpTool)(searchOutput, serverLabel, output.providerData?.name))) { return; } const message = `Model produced deferred MCP call ${serverLabel} before it was loaded via tool_search.`; (0, context_1.addErrorToCurrentSpan)({ message, data: { agent_name: agent.name, mcp_server_label: serverLabel, tool_call_id: output.id, }, }); throw new errors_1.ModelBehaviorError(message); } function handleToolCallAction({ output, tool, agent, errorMessage, errorData, items, toolsUsed, actions, buildAction, }) { const resolvedTool = ensureToolAvailable(tool, errorMessage, errorData); (0, toolCaller_1.ensureToolCallerAllowed)(output, resolvedTool.allowedCallers, resolvedTool.name, agent); items.push(new items_1.RunToolCallItem(output, agent)); toolsUsed.push(resolvedTool.name); actions.push(buildAction(resolvedTool)); } function recordHandoffRequest(output, handoff, agent, items, toolsUsed, handoffs, completedInvocations) { toolsUsed.push(output.name); const request = { toolCall: output, handoff }; if (completedInvocations?.has(output.callId) || (handoffs.length > 0 && !completedInvocations?.has(handoffs[0].toolCall.callId))) { handoffs.push(request); return; } // Keep the first fresh request first for execution and managed continuation. // Preflight still validates the identity of every request, including replays. handoffs.unshift(request); items.push(new items_1.RunHandoffCallItem(output, agent)); } function resolveFunctionOrHandoff(toolCall, handoffMap, functionMap) { const namespace = (0, toolIdentity_1.getToolCallNamespace)(toolCall); if (!namespace) { const handoff = handoffMap.get(toolCall.name); if (handoff) { return { type: 'handoff', handoff }; } } const functionTool = (0, toolIdentity_1.resolveFunctionToolCall)(toolCall, functionMap); if (!functionTool) { return { type: 'not_found', toolName: (0, toolIdentity_1.getToolCallNamespace)(toolCall) && (0, toolIdentity_1.getToolCallNamespace)(toolCall) !== toolCall.name ? `${(0, toolIdentity_1.getToolCallNamespace)(toolCall)}.${toolCall.name}` : toolCall.name, }; } return { type: 'function', tool: functionTool }; } function throwFunctionToolNotFound(toolName, agent) { const message = `Tool ${toolName} not found in agent ${agent.name}.`; (0, context_1.addErrorToCurrentSpan)({ message, data: { tool_name: toolName, agent_name: agent.name, }, }); throw new errors_1.ModelBehaviorError(message); } function recordMissingFunctionTool(output, toolName, agent, items, toolsUsed, functionToolsNotFound, reason) { toolsUsed.push(toolName); items.push(new items_1.RunToolCallItem(output, agent)); functionToolsNotFound.push({ toolCall: output, toolName, ...(reason ? { reason } : {}), }); } function normalizeFunctionToolCallForStorage(toolCall, tool) { const namespace = (0, toolIdentity_1.getToolCallNamespace)(toolCall); const explicitNamespace = (0, toolIdentity_1.getFunctionToolNamespace)(tool); const qualifiedToolName = (0, toolIdentity_1.getFunctionToolQualifiedName)(tool); if (namespace || !explicitNamespace || !qualifiedToolName || toolCall.name !== qualifiedToolName) { return toolCall; } return { ...toolCall, name: tool.name, namespace: explicitNamespace, }; } function getRawAgentInputItem(item) { if (item && typeof item === 'object' && 'rawItem' in item && item.rawItem && typeof item.rawItem === 'object') { return item.rawItem; } return item; } function refreshLoadedDeferredToolNames(state) { state.loadedToolNames.clear(); for (const toolSearchOutput of state.keyedToolSearchOutputsByKey.values()) { (0, toolSearch_1.addLoadedToolNamesFromToolSearchOutput)(toolSearchOutput, state.loadedToolNames); } for (const toolSearchOutput of state.anonymousToolSearchOutputs) { (0, toolSearch_1.addLoadedToolNamesFromToolSearchOutput)(toolSearchOutput, state.loadedToolNames); } } function recordLoadedToolSearchOutput(state, toolSearchOutput) { const replacementKey = (0, utils_1.getToolSearchOutputReplacementKey)(toolSearchOutput); if (replacementKey) { state.keyedToolSearchOutputsByKey.set(replacementKey, toolSearchOutput); } else { state.anonymousToolSearchOutputs.push(toolSearchOutput); } refreshLoadedDeferredToolNames(state); } function collectLoadedDeferredToolStateFromHistory(items, agent, agentName) { const state = { anonymousToolSearchOutputs: [], keyedToolSearchOutputsByKey: new Map(), loadedToolNames: new Set(), }; // Use the active history boundary without discarding the surviving item owners. for (const item of (0, items_2.trimToLatestCompaction)(items)) { if ((item instanceof items_1.RunToolSearchOutputItem || item instanceof items_1.RunInputItem) && item.agent !== agent) { continue; } const rawItem = getRawAgentInputItem(item); if (rawItem?.type !== 'tool_search_output') { continue; } // Raw history has no live owner; only an unambiguous recorded name can restore discovery. if (!(item instanceof items_1.RunToolSearchOutputItem) && (typeof agentName !== 'string' || rawItem.toolSearchAgentName !== agentName)) { continue; } const replacementKey = (0, utils_1.getToolSearchOutputReplacementKey)(rawItem); if (replacementKey) { state.keyedToolSearchOutputsByKey.set(replacementKey, rawItem); } else { state.anonymousToolSearchOutputs.push(rawItem); } } refreshLoadedDeferredToolNames(state); return state; } function seedHostedMcpToolsFromLoadedDeferredToolState(state, mcpToolMap, preserveExistingServerLabels) { for (const toolSearchOutput of state.keyedToolSearchOutputsByKey.values()) { (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(toolSearchOutput, mcpToolMap, { preserveExistingServerLabels, }); } for (const toolSearchOutput of state.anonymousToolSearchOutputs) { (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(toolSearchOutput, mcpToolMap, { preserveExistingServerLabels, }); } } function buildFunctionToolMap(tools) { return (0, toolIdentity_1.buildFunctionToolLookupMap)(tools.filter((t) => t.type === 'function')); } function getUnresolvedClientToolSearchCalls(modelResponse, hasClientToolSearchTool) { const clientToolSearchCalls = []; const pendingCalls = []; const latestCallByMatchKey = new Map(); const resolvedCalls = new Set(); for (const output of modelResponse.output) { if (output.type === 'tool_search_call') { const execution = (0, utils_1.getToolSearchExecution)(output); if (execution === 'client' || (typeof execution === 'undefined' && hasClientToolSearchTool)) { clientToolSearchCalls.push(output); pendingCalls.push(output); const matchKey = (0, utils_1.getToolSearchMatchKey)(output); if (matchKey) { latestCallByMatchKey.set(matchKey, output); } } continue; } if (output.type !== 'tool_search_output' || (0, utils_1.getToolSearchExecution)(output) === 'server') { continue; } const explicitCallId = (0, utils_1.getToolSearchProviderCallId)(output); const matchedCall = explicitCallId ? latestCallByMatchKey.get(explicitCallId) : pendingCalls.shift(); if (!matchedCall) { continue; } resolvedCalls.add(matchedCall); const pendingIndex = pendingCalls.indexOf(matchedCall); if (pendingIndex >= 0) { pendingCalls.splice(pendingIndex, 1); } } return clientToolSearchCalls.filter((call) => !resolvedCalls.has(call)); } function buildGeneratedClientToolSearchOutputMap(modelResponse, tools, hasClientToolSearchTool) { const clientToolSearchCalls = getUnresolvedClientToolSearchCalls(modelResponse, hasClientToolSearchTool); const generatedOutputs = new Map(); for (const toolSearchCall of clientToolSearchCalls) { generatedOutputs.set(toolSearchCall, (0, toolSearch_1.createBuiltInClientToolSearchOutput)(toolSearchCall, tools)); } return generatedOutputs; } async function buildGeneratedClientToolSearchOutputMapAsync(args) { const { agent, handoffs, modelResponse, replaceableRuntimeToolKeys, runContext, tools, } = args; const clientToolSearchTool = (0, toolSearch_1.getClientToolSearchHelper)(tools); const hasClientToolSearchTool = typeof clientToolSearchTool !== 'undefined'; const executionTools = [...tools]; const validationAvailableTools = [...tools]; const validationFunctionMap = buildFunctionToolMap(tools); const validationHandoffMap = new Map(handoffs.map((handoff) => [handoff.toolName, handoff])); const validationMcpToolMap = new Map(tools .filter((tool) => tool.type === 'hosted_tool' && tool.providerData?.type === 'mcp') .map((tool) => [tool.providerData.server_label, tool])); const validationReplaceableRuntimeToolKeys = new Set(replaceableRuntimeToolKeys); const clientToolSearchCalls = getUnresolvedClientToolSearchCalls(modelResponse, hasClientToolSearchTool); const generatedOutputs = new Map(); for (const toolSearchCall of clientToolSearchCalls) { if (clientToolSearchTool && (0, tool_1.getClientToolSearchExecutor)(clientToolSearchTool)) { const generatedOutput = await (0, toolSearch_1.executeCustomClientToolSearch)({ agent, runContext, toolSearchCall, toolSearchTool: clientToolSearchTool, tools: executionTools, }); (0, toolSearch_1.registerRuntimeToolSearchTools)({ availableTools: validationAvailableTools, functionMap: validationFunctionMap, handoffMap: validationHandoffMap, mcpToolMap: validationMcpToolMap, replaceableRuntimeToolKeys: validationReplaceableRuntimeToolKeys, runtimeTools: generatedOutput.runtimeTools, }); generatedOutputs.set(toolSearchCall, generatedOutput); executionTools.push(...generatedOutput.callbackRuntimeTools); continue; } generatedOutputs.set(toolSearchCall, { output: (0, toolSearch_1.createBuiltInClientToolSearchOutput)(toolSearchCall, executionTools), runtimeTools: [], callbackRuntimeTools: [], }); } return generatedOutputs; } function checkDeferredFunctionToolLoaded(toolCall, tool, loadedToolNames, agent, behavior) { if (tool.deferLoading !== true) { return true; } const explicitNamespace = (0, toolIdentity_1.getFunctionToolNamespace)(tool); const qualifiedName = (0, toolIdentity_1.getFunctionToolQualifiedName)(tool); const isLoaded = (qualifiedName ? loadedToolNames.has(qualifiedName) : false) || ((!explicitNamespace || explicitNamespace === tool.name) && loadedToolNames.has(tool.name)); if (isLoaded) { return true; } if (behavior === 'return_error_to_model') { return false; } const toolName = qualifiedName ?? tool.name; const message = `Model produced deferred function call ${toolName} before it was loaded via tool_search.`; (0, context_1.addErrorToCurrentSpan)({ message, data: { agent_name: agent.name, tool_name: toolName, tool_call_id: toolCall.callId, }, }); throw new errors_1.ModelBehaviorError(message); } function parseShellCallStatus(status) { if (status === 'in_progress' || status === 'completed' || status === 'incomplete') { return status; } return undefined; } function isShellCallPendingStatus(status) { if (typeof status === 'undefined') { return true; } return parseShellCallStatus(status) === 'in_progress'; } function hasPendingShellOutputStatus(output) { const outputStatus = output.status ?? output.providerData?.status; if (typeof outputStatus !== 'string') { return false; } return isShellCallPendingStatus(outputStatus); } /** * Walks a raw model response and classifies each item so the runner can schedule follow-up work. * Returns both the serializable RunItems (for history/streaming) and the actionable tool metadata. */ function processModelResponse(modelResponse, agent, tools, handoffs, priorItems = [], toolNotFoundBehavior = 'raise_error', processingOptions = {}) { (0, items_2.assertValidCompactionItems)(modelResponse.output); const items = []; const runHandoffs = []; const runFunctions = []; const functionToolsNotFound = []; const runComputerActions = []; const runShellActions = []; let hasHostedShellCall = false; const runApplyPatchActions = []; const runMCPApprovalRequests = []; const toolsUsed = []; const handoffMap = new Map(handoffs.map((h) => [h.toolName, h])); // Resolve tools upfront so we can look up the concrete handler in O(1) while iterating outputs. const functionMap = buildFunctionToolMap(tools); const computerTool = tools.find((t) => t.type === 'computer'); const shellTool = tools.find((t) => t.type === 'shell'); const applyPatchTool = tools.find((t) => t.type === 'apply_patch'); const mcpToolMap = new Map(tools .filter((t) => t.type === 'hosted_tool' && t.providerData?.type === 'mcp') .map((t) => t) .map((t) => [t.providerData.server_label, t])); const originalMcpServerLabels = new Set(mcpToolMap.keys()); const hasClientToolSearchTool = tools.some((tool) => tool.type === 'hosted_tool' && tool.providerData?.type === 'tool_search' && tool.providerData.execution === 'client'); const loadedDeferredToolState = collectLoadedDeferredToolStateFromHistory(priorItems, agent, processingOptions.toolSearchAgentName); seedHostedMcpToolsFromLoadedDeferredToolState(loadedDeferredToolState, mcpToolMap, originalMcpServerLabels); const generatedClientToolSearchOutputsByCall = buildGeneratedClientToolSearchOutputMap(modelResponse, tools, hasClientToolSearchTool); let hasGeneratedClientToolSearchOutputs = false; for (const output of modelResponse.output) { if (output.type === 'message') { if (output.role === 'assistant') { items.push(new items_1.RunMessageOutputItem(output, agent)); } } else if (output.type === 'tool_search_call') { items.push(new items_1.RunToolSearchCallItem(output, agent)); toolsUsed.push('tool_search'); const generatedOutput = generatedClientToolSearchOutputsByCall.get(output); if (generatedOutput) { items.push(new items_1.RunToolSearchOutputItem((0, toolSearchAttribution_1.attributeToolSearchOutput)(generatedOutput, processingOptions.toolSearchAgentName), agent)); recordLoadedToolSearchOutput(loadedDeferredToolState, generatedOutput); (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(generatedOutput, mcpToolMap, { preserveExistingServerLabels: originalMcpServerLabels, }); hasGeneratedClientToolSearchOutputs = true; } } else if (output.type === 'tool_search_output') { const recordedOutput = (0, toolSearch_1.recordHostedMcpDiscovery)(output, [ ...agent.tools, ...tools, ]); items.push(new items_1.RunToolSearchOutputItem((0, toolSearchAttribution_1.attributeToolSearchOutput)(recordedOutput, processingOptions.toolSearchAgentName), agent)); recordLoadedToolSearchOutput(loadedDeferredToolState, recordedOutput); (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(output, mcpToolMap, { preserveExistingServerLabels: originalMcpServerLabels, }); } else if (output.type === 'program') { ensureProgrammaticToolCallingAvailable(output, tools, agent, processingOptions); items.push(new items_1.RunToolCallItem(output, agent)); toolsUsed.push('programmatic_tool_calling'); } else if (output.type === 'program_output') { items.push(new items_1.RunToolCallOutputItem(output, agent, output.output)); } else if (output.type === 'hosted_tool_call') { ensureHostedToolCallAllowed(output, tools, mcpToolMap, loadedDeferredToolState, agent); items.push(new items_1.RunToolCallItem(output, agent)); const toolName = output.name; toolsUsed.push(toolName); if (output.providerData?.type === 'mcp_approval_request' || output.name === 'mcp_approval_request') { // Hosted remote MCP server's approval process const providerData = output.providerData; const mcpServerLabel = providerData.server_label; const mcpServerTool = mcpToolMap.get(mcpServerLabel); if (typeof mcpServerTool === 'undefined') { const message = `MCP server (${mcpServerLabel}) not found in Agent (${agent.name})`; (0, context_1.addErrorToCurrentSpan)({ message, data: { mcp_server_label: mcpServerLabel }, }); throw new errors_1.ModelBehaviorError(message); } // Do this approval later: // We support both onApproval callback (like the Python SDK does) and HITL patterns. const approvalItem = new items_1.RunToolApprovalItem({ type: 'hosted_tool_call', // We must use this name to align with the name sent from the servers name: providerData.name, id: providerData.id, status: 'in_progress', providerData, ...(output.caller ? { caller: output.caller } : {}), }, agent); runMCPApprovalRequests.push({ requestItem: approvalItem, mcpTool: mcpServerTool, }); if (!mcpServerTool.providerData.on_approval) { // When onApproval function exists, it confirms the approval right after this. // Thus, this approval item must be appended only for the next turn interruption patterns. items.push(approvalItem); } } } else if (output.type === 'reasoning') { items.push(new items_1.RunReasoningItem(output, agent)); } else if (output.type === 'compaction') { items.push(new items_1.RunCompactionItem(output, agent)); } else if (output.type === 'computer_call') { handleToolCallAction({ output, tool: computerTool, agent, errorMessage: 'Model produced computer action without a computer tool.', errorData: { agent_name: agent.name }, items, toolsUsed, actions: runComputerActions, buildAction: (resolvedTool) => ({ toolCall: output, computer: resolvedTool, }), }); } else if (output.type === 'shell_call') { const resolvedShellTool = ensureToolAvailable(shellTool, 'Model produced shell action without a shell tool.', { agent_name: agent.name }); (0, toolCaller_1.ensureToolCallerAllowed)(output, resolvedShellTool.allowedCallers, resolvedShellTool.name, agent); items.push(new items_1.RunToolCallItem(output, agent)); toolsUsed.push(resolvedShellTool.name); const shellEnvironmentType = resolvedShellTool.environment?.type ?? 'local'; // Hosted container shell is executed by the API provider, so no local action is queued. if (shellEnvironmentType !== 'local') { if (isShellCallPendingStatus(output.status)) { hasHostedShellCall = true; } continue; } if (!resolvedShellTool.shell) { const message = 'Model produced local shell action without a local shell implementation.'; (0, context_1.addErrorToCurrentSpan)({ message, data: { agent_name: agent.name }, }); throw new errors_1.ModelBehaviorError(message); } runShellActions.push({ toolCall: output, shell: resolvedShellTool, }); } else if (output.type === 'shell_call_output') { items.push(new items_1.RunToolCallOutputItem(output, agent, output.output)); if (hasPendingShellOutputStatus(output)) { hasHostedShellCall = true; } } else if (output.type === 'apply_patch_call') { handleToolCallAction({ output, tool: applyPatchTool, agent, errorMessage: 'Model produced apply_patch action without an apply_patch tool.', errorData: { agent_name: agent.name }, items, toolsUsed, actions: runApplyPatchActions, buildAction: (resolvedTool) => ({ toolCall: output, applyPatch: resolvedTool, }), }); } /* * Intentionally skip returning here so function_call processing can still * run when output.type matches other tool call types. */ if (output.type !== 'function_call') { continue; } const resolved = resolveFunctionOrHandoff(output, handoffMap, functionMap); if (resolved.type === 'not_found') { if (toolNotFoundBehavior !== 'return_error_to_model') { throwFunctionToolNotFound(resolved.toolName, agent); } recordMissingFunctionTool(output, resolved.toolName, agent, items, toolsUsed, functionToolsNotFound); } else if (resolved.type === 'handoff') { (0, toolCaller_1.ensureToolCallerAllowed)(output, undefined, resolved.handoff.toolName, agent); recordHandoffRequest(output, resolved.handoff, agent, items, toolsUsed, runHandoffs, processingOptions.completedInvocations); } else { (0, toolCaller_1.ensureToolCallerAllowed)(output, resolved.tool.allowedCallers, (0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name, agent); if (!checkDeferredFunctionToolLoaded(output, resolved.tool, loadedDeferredToolState.loadedToolNames, agent, toolNotFoundBehavior)) { recordMissingFunctionTool(normalizeFunctionToolCallForStorage(output, resolved.tool), (0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name, agent, items, toolsUsed, functionToolsNotFound, 'not_loaded'); continue; } const normalizedToolCall = normalizeFunctionToolCallForStorage(output, resolved.tool); toolsUsed.push((0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name); items.push(new items_1.RunToolCallItem(normalizedToolCall, agent, !(0, toolIdentity_1.getToolCallNamespace)(normalizedToolCall) && (0, toolIdentity_1.isDeferredTopLevelFunctionTool)(resolved.tool) ? (0, toolIdentity_1.getFunctionToolStateKey)(resolved.tool) : undefined)); runFunctions.push((0, types_1.createToolRunFunction)({ toolCall: normalizedToolCall, tool: resolved.tool, availableFunctionTools: [...new Set(functionMap.values())], })); } } return { newItems: items, handoffs: runHandoffs, functions: runFunctions, functionToolsNotFound, computerActions: runComputerActions, shellActions: runShellActions, applyPatchActions: runApplyPatchActions, mcpApprovalRequests: runMCPApprovalRequests, toolsUsed: toolsUsed, hasToolsOrApprovalsToRun() { return (runHandoffs.length > 0 || runFunctions.length > 0 || functionToolsNotFound.length > 0 || runMCPApprovalRequests.length > 0 || runComputerActions.length > 0 || runShellActions.length > 0 || hasHostedShellCall || runApplyPatchActions.length > 0 || hasGeneratedClientToolSearchOutputs); }, }; } async function processModelResponseAsync(modelResponse, agent, tools, handoffs, state, priorItems = [], toolNotFoundBehavior = 'raise_error', processingOptions = {}) { (0, items_2.assertValidCompactionItems)(modelResponse.output); processingOptions = { ...processingOptions, toolSearchAgentName: state._getToolSearchAgentName(agent), completedInvocations: state._completedToolInvocations.get(agent), }; const clientToolSearchTool = (0, toolSearch_1.getClientToolSearchHelper)(tools); const hasCustomClientToolSearchExecutor = Boolean(clientToolSearchTool && (0, tool_1.getClientToolSearchExecutor)(clientToolSearchTool)); const hasRelevantClientToolSearchCall = modelResponse.output.some((output) => output.type === 'tool_search_call' && ((0, utils_1.getToolSearchExecution)(output) === 'client' || (typeof (0, utils_1.getToolSearchExecution)(output) === 'undefined' && typeof clientToolSearchTool !== 'undefined'))); if (!hasCustomClientToolSearchExecutor || !hasRelevantClientToolSearchCall) { return processModelResponse(modelResponse, agent, tools, handoffs, priorItems, toolNotFoundBehavior, processingOptions); } processingOptions.beforeClientToolSearch?.(); const items = []; const runHandoffs = []; const runFunctions = []; const functionToolsNotFound = []; const runComputerActions = []; const runShellActions = []; let hasHostedShellCall = false; const runApplyPatchActions = []; const runMCPApprovalRequests = []; const toolsUsed = []; const handoffMap = new Map(handoffs.map((h) => [h.toolName, h])); const functionMap = buildFunctionToolMap(tools); const computerTool = tools.find((t) => t.type === 'computer'); const shellTool = tools.find((t) => t.type === 'shell'); const applyPatchTool = tools.find((t) => t.type === 'apply_patch'); const mcpToolMap = new Map(tools .filter((t) => t.type === 'hosted_tool' && t.providerData?.type === 'mcp') .map((t) => t) .map((t) => [t.providerData.server_label, t])); const originalMcpServerLabels = new Set(mcpToolMap.keys()); const replaceableRuntimeToolKeys = new Set(state .getToolSearchRuntimeTools(agent) .map((tool) => (0, tool_1.getToolSearchRuntimeRoutingKey)(tool)) .filter((key) => typeof key === 'string')); const loadedDeferredToolState = collectLoadedDeferredToolStateFromHistory(priorItems, agent, processingOptions.toolSearchAgentName); seedHostedMcpToolsFromLoadedDeferredToolState(loadedDeferredToolState, mcpToolMap, originalMcpServerLabels); const generatedClientToolSearchOutputsByCall = await buildGeneratedClientToolSearchOutputMapAsync({ agent, handoffs, modelResponse, replaceableRuntimeToolKeys, runContext: state._context, tools, }); let hasGeneratedClientToolSearchOutputs = false; const availableTools = [...tools]; for (const output of modelResponse.output) { if (output.type === 'message') { if (output.role === 'assistant') { items.push(new items_1.RunMessageOutputItem(output, agent)); } } else if (output.type === 'tool_search_call') { items.push(new items_1.RunToolSearchCallItem(output, agent)); toolsUsed.push('tool_search'); const generatedOutput = generatedClientToolSearchOutputsByCall.get(output); if (generatedOutput) { items.push(new items_1.RunToolSearchOutputItem((0, toolSearchAttribution_1.attributeToolSearchOutput)(generatedOutput.output, processingOptions.toolSearchAgentName), agent)); recordLoadedToolSearchOutput(loadedDeferredToolState, generatedOutput.output); (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(generatedOutput.output, mcpToolMap, { preserveExistingServerLabels: originalMcpServerLabels, }); const replacedRuntimeTools = state.getToolSearchRuntimeToolsForOutput(agent, generatedOutput.output); const registeredRuntimeTools = (0, toolSearch_1.registerRuntimeToolSearchTools)({ availableTools, functionMap, handoffMap, mcpToolMap, replaceableRuntimeToolKeys, replacedRuntimeTools, runtimeTools: generatedOutput.runtimeTools, }); state.recordToolSearchRuntimeTools(agent, generatedOutput.output, registeredRuntimeTools); hasGeneratedClientToolSearchOutputs = true; } } else if (output.type === 'tool_search_output') { const recordedOutput = (0, toolSearch_1.recordHostedMcpDiscovery)(output, [ ...agent.tools, ...availableTools, ]); items.push(new items_1.RunToolSearchOutputItem((0, toolSearchAttribution_1.attributeToolSearchOutput)(recordedOutput, processingOptions.toolSearchAgentName), agent)); recordLoadedToolSearchOutput(loadedDeferredToolState, recordedOutput); (0, toolSearch_1.addHostedMcpToolsFromToolSearchOutput)(output, mcpToolMap, { preserveExistingServerLabels: originalMcpServerLabels, }); } else if (output.type === 'program') { ensureProgrammaticToolCallingAvailable(output, availableTools, agent, processingOptions); items.push(new items_1.RunToolCallItem(output, agent)); toolsUsed.push('programmatic_tool_calling'); } else if (output.type === 'program_output') { items.push(new items_1.RunToolCallOutputItem(output, agent, output.output)); } else if (output.type === 'hosted_tool_call') { ensureHostedToolCallAllowed(output, availableTools, mcpToolMap, loadedDeferredToolState, agent); items.push(new items_1.RunToolCallItem(output, agent)); const toolName = output.name; toolsUsed.push(toolName); if (output.providerData?.type === 'mcp_approval_request' || output.name === 'mcp_approval_request') { const providerData = output.providerData; const mcpServerLabel = providerData.server_label; const mcpServerTool = mcpToolMap.get(mcpServerLabel); if (typeof mcpServerTool === 'undefined') { const message = `MCP server (${mcpServerLabel}) not found in Agent (${agent.name})`; (0, context_1.addErrorToCurrentSpan)({ message, data: { mcp_server_label: mcpServerLabel }, }); throw new errors_1.ModelBehaviorError(message); } const approvalItem = new items_1.RunToolApprovalItem({ type: 'hosted_tool_call', name: providerData.name, id: providerData.id, status: 'in_progress', providerData, ...(output.caller ? { caller: output.caller } : {}), }, agent); runMCPApprovalRequests.push({ requestItem: approvalItem, mcpTool: mcpServerTool, }); if (!mcpServerTool.providerData.on_approval) { items.push(approvalItem); } } } else if (output.type === 'reasoning') { items.push(new items_1.RunReasoningItem(output, agent)); } else if (output.type === 'compaction') { items.push(new items_1.RunCompactionItem(output, agent)); } else if (output.type === 'computer_call') { handleToolCallAction({ output, tool: computerTool, agent, errorMessage: 'Model produced computer action without a computer tool.', errorData: { agent_name: agent.name }, items, toolsUsed, actions: runComputerActions, buildAction: (resolvedTool) => ({ toolCall: output, computer: resolvedTool, }), }); } else if (output.type === 'shell_call') { const resolvedShellTool = ensureToolAvailable(shellTool, 'Model produced shell action without a shell tool.', { agent_name: agent.name }); (0, toolCaller_1.ensureToolCallerAllowed)(output, resolvedShellTool.allowedCallers, resolvedShellTool.name, agent); items.push(new items_1.RunToolCallItem(output, agent)); toolsUsed.push(resolvedShellTool.name); const shellEnvironmentType = resolvedShellTool.environment?.type ?? 'local'; if (shellEnvironmentType !== 'local') { if (isShellCallPendingStatus(output.status)) { hasHostedShellCall = true; } continue; } if (!resolvedShellTool.shell) { const message = 'Model produced local shell action without a local shell implementation.'; (0, context_1.addErrorToCurrentSpan)({ message, data: { agent_name: agent.name }, }); throw new errors_1.ModelBehaviorError(message); } runShellActions.push({ toolCall: output, shell: resolvedShellTool, }); } else if (output.type === 'shell_call_output') { items.push(new items_1.RunToolCallOutputItem(output, agent, output.output)); if (hasPendingShellOutputStatus(output)) { hasHostedShellCall = true; } } else if (output.type === 'apply_patch_call') { handleToolCallAction({ output, tool: applyPatchTool, agent, errorMessage: 'Model produced apply_patch action without an apply_patch tool.', errorData: { agent_name: agent.name }, items, toolsUsed, actions: runApplyPatchActions, buildAction: (resolvedTool) => ({ toolCall: output, applyPatch: resolvedTool, }), }); } if (output.type !== 'function_call') { continue; } const resolved = resolveFunctionOrHandoff(output, handoffMap, functionMap); if (resolved.type === 'not_found') { if (toolNotFoundBehavior !== 'return_error_to_model') { throwFunctionToolNotFound(resolved.toolName, agent); } recordMissingFunctionTool(output, resolved.toolName, agent, items, toolsUsed, functionToolsNotFound); } else if (resolved.type === 'handoff') { (0, toolCaller_1.ensureToolCallerAllowed)(output, undefined, resolved.handoff.toolName, agent); recordHandoffRequest(output, resolved.handoff, agent, items, toolsUsed, runHandoffs, processingOptions.completedInvocations); } else { (0, toolCaller_1.ensureToolCallerAllowed)(output, resolved.tool.allowedCallers, (0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name, agent); if (!checkDeferredFunctionToolLoaded(output, resolved.tool, loadedDeferredToolState.loadedToolNames, agent, toolNotFoundBehavior)) { recordMissingFunctionTool(normalizeFunctionToolCallForStorage(output, resolved.tool), (0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name, agent, items, toolsUsed, functionToolsNotFound, 'not_loaded'); continue; } const normalizedToolCall = normalizeFunctionToolCallForStorage(output, resolved.tool); toolsUsed.push((0, toolIdentity_1.getFunctionToolQualifiedName)(resolved.tool) ?? resolved.tool.name); items.push(new items_1.RunToolCallItem(normalizedToolCall, agent, !(0, toolIdentity_1.getToolCallNamespace)(normalizedToolCall) && (0, toolIdentity_1.isDeferredTopLevelFunctionTool)(resolved.tool) ? (0, toolIdentity_1.getFunctionToolStateKey)(resolved.tool) : undefined)); runFunctions.push((0, types_1.createToolRunFunction)({ toolCall: normalizedToolCall, tool: resolved.tool, availableFunctionTools: [...new Set(functionMap.values())], })); } } return { newItems: items, handoffs: runHandoffs, functions: runFunctions, functionToolsNotFound, computerActions: runComputerActions, shellActions: runShellActions, applyPatchActions: runApplyPatchActions, mcpApprovalRequests: runMCPApprovalRequests, toolsUsed, hasToolsOrApprovalsToRun() { return (runHandoffs.length > 0 || runFunctions.length > 0 || functionToolsNotFound.length > 0 || runMCPApprovalRequests.length > 0 || runComputerActions.length > 0 || runShellActions.length > 0 || hasHostedShellCall || runApplyPatchActions.length > 0 || hasGeneratedClientToolSearchOutputs); }, }; } //# sourceMappingURL=modelOutputs.js.map