UNPKG

@openai/agents-openai

Version:

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

1,304 lines 57.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIResponsesModel = void 0; exports.getToolChoice = getToolChoice; exports.converTool = converTool; exports.getInputItems = getInputItems; exports.convertToOutputItem = convertToOutputItem; const agents_core_1 = require("@openai/agents-core"); const logger_1 = __importDefault(require("./logger.js")); const zod_1 = require("zod"); const defaults_1 = require("./defaults.js"); const tools_1 = require("./tools.js"); const providerData_1 = require("./utils/providerData.js"); const utils_1 = require("@openai/agents-core/utils"); const HostedToolChoice = zod_1.z.enum([ 'file_search', 'web_search', 'web_search_preview', 'code_interpreter', 'image_generation', 'mcp', // Specialized local tools 'computer_use_preview', 'shell', 'apply_patch', ]); const DefaultToolChoice = zod_1.z.enum(['auto', 'required', 'none']); function getToolChoice(toolChoice) { if (typeof toolChoice === 'undefined') { return undefined; } const resultDefaultCheck = DefaultToolChoice.safeParse(toolChoice); if (resultDefaultCheck.success) { return resultDefaultCheck.data; } const result = HostedToolChoice.safeParse(toolChoice); if (result.success) { return { type: result.data }; } return { type: 'function', name: toolChoice }; } function getResponseFormat(outputType, otherProperties) { if (outputType === 'text') { return otherProperties; } return { ...otherProperties, format: outputType, }; } function normalizeFunctionCallOutputForRequest(output) { if (typeof output === 'string') { return output; } if (Array.isArray(output)) { return output.map(convertStructuredOutputToRequestItem); } if (isRecord(output) && typeof output.type === 'string') { if (output.type === 'text' && typeof output.text === 'string') { return output.text; } if (output.type === 'image' || output.type === 'file') { const structuredItems = convertLegacyToolOutputContent(output); return structuredItems.map(convertStructuredOutputToRequestItem); } } return String(output); } /** * Older tool integrations (and the Python SDK) still return their own `ToolOutput*` objects. * Translate those into the protocol `input_*` structures so the rest of the pipeline can stay * agnostic about who produced the data. */ function convertLegacyToolOutputContent(output) { if (output.type === 'text') { const structured = { type: 'input_text', text: output.text, }; if (output.providerData) { structured.providerData = output.providerData; } return [structured]; } if (output.type === 'image') { const structured = { type: 'input_image', }; if (output.detail) { structured.detail = output.detail; } const legacyImageUrl = output.imageUrl; const legacyFileId = output.fileId; const dataValue = output.data; if (typeof output.image === 'string' && output.image.length > 0) { structured.image = output.image; } else if (isRecord(output.image)) { const imageObj = output.image; const inlineMediaType = getImageInlineMediaType(imageObj); if (typeof imageObj.url === 'string' && imageObj.url.length > 0) { structured.image = imageObj.url; } else if (typeof imageObj.data === 'string' && imageObj.data.length > 0) { structured.image = formatInlineData(imageObj.data, inlineMediaType); } else if (imageObj.data instanceof Uint8Array && imageObj.data.length > 0) { structured.image = formatInlineData(imageObj.data, inlineMediaType); } else { const referencedId = (typeof imageObj.fileId === 'string' && imageObj.fileId.length > 0 && imageObj.fileId) || (typeof imageObj.id === 'string' && imageObj.id.length > 0 ? imageObj.id : undefined); if (referencedId) { structured.image = { id: referencedId }; } } } else if (typeof legacyImageUrl === 'string' && legacyImageUrl.length > 0) { structured.image = legacyImageUrl; } else if (typeof legacyFileId === 'string' && legacyFileId.length > 0) { structured.image = { id: legacyFileId }; } else { let base64Data; if (typeof dataValue === 'string' && dataValue.length > 0) { base64Data = dataValue; } else if (dataValue instanceof Uint8Array && dataValue.length > 0) { base64Data = (0, utils_1.encodeUint8ArrayToBase64)(dataValue); } if (base64Data) { structured.image = base64Data; } } if (output.providerData) { structured.providerData = output.providerData; } return [structured]; } if (output.type === 'file') { const structured = { type: 'input_file', }; const fileValue = output.file ?? output.file; if (typeof fileValue === 'string') { structured.file = fileValue; } else if (isRecord(fileValue)) { if (typeof fileValue.data === 'string' && fileValue.data.length > 0) { structured.file = formatInlineData(fileValue.data, fileValue.mediaType ?? 'text/plain'); } else if (fileValue.data instanceof Uint8Array && fileValue.data.length > 0) { structured.file = formatInlineData(fileValue.data, fileValue.mediaType ?? 'text/plain'); } else if (typeof fileValue.url === 'string' && fileValue.url.length > 0) { structured.file = { url: fileValue.url }; } else { const referencedId = (typeof fileValue.id === 'string' && fileValue.id.length > 0 && fileValue.id) || (typeof fileValue.fileId === 'string' && fileValue.fileId.length > 0 ? fileValue.fileId : undefined); if (referencedId) { structured.file = { id: referencedId }; } } if (typeof fileValue.filename === 'string' && fileValue.filename.length > 0) { structured.filename = fileValue.filename; } } if (!structured.file) { const legacy = normalizeLegacyFileFromOutput(output); if (legacy.file) { structured.file = legacy.file; } if (legacy.filename) { structured.filename = legacy.filename; } } if (output.providerData) { structured.providerData = output.providerData; } return [structured]; } throw new agents_core_1.UserError(`Unsupported tool output type: ${JSON.stringify(output)}`); } /** * Converts the protocol-level structured output into the exact wire format expected by the * Responses API. Be careful to keep the snake_case property names the service requires here. */ function convertStructuredOutputToRequestItem(item) { if (item.type === 'input_text') { return { type: 'input_text', text: item.text, }; } if (item.type === 'input_image') { const result = { type: 'input_image' }; const imageValue = item.image ?? item.imageUrl; if (typeof imageValue === 'string') { result.image_url = imageValue; } else if (isRecord(imageValue) && typeof imageValue.id === 'string') { result.file_id = imageValue.id; } const legacyFileId = item.fileId; if (typeof legacyFileId === 'string') { result.file_id = legacyFileId; } if (item.detail) { result.detail = item.detail; } return result; } if (item.type === 'input_file') { const result = { type: 'input_file' }; if (typeof item.file === 'string') { const value = item.file.trim(); if (value.startsWith('data:')) { result.file_data = value; } else if (value.startsWith('http://') || value.startsWith('https://')) { result.file_url = value; } else if (/^[A-Za-z0-9+/=]+$/.test(value)) { result.file_data = value; } else { result.file_url = value; } } else if (item.file && typeof item.file === 'object' && 'id' in item.file && typeof item.file.id === 'string') { result.file_id = item.file.id; } else if (item.file && typeof item.file === 'object' && 'url' in item.file && typeof item.file.url === 'string') { result.file_url = item.file.url; } const legacyFileData = item.fileData; if (typeof legacyFileData === 'string') { result.file_data = legacyFileData; } const legacyFileUrl = item.fileUrl; if (typeof legacyFileUrl === 'string') { result.file_url = legacyFileUrl; } const legacyFileId = item.fileId; if (typeof legacyFileId === 'string') { result.file_id = legacyFileId; } if (item.filename) { result.filename = item.filename; } return result; } throw new agents_core_1.UserError(`Unsupported structured tool output: ${JSON.stringify(item)}`); } function convertResponseFunctionCallOutputItemToStructured(item) { if (item.type === 'input_text') { return { type: 'input_text', text: item.text, }; } if (item.type === 'input_image') { const structured = { type: 'input_image' }; if (typeof item.image_url === 'string' && item.image_url.length > 0) { structured.image = item.image_url; } else if (typeof item.file_id === 'string' && item.file_id.length > 0) { structured.image = { id: item.file_id }; } else { // As of 2025-10-30, conversations retrieval API may not include // data url in image_url property; so skipping this pattern logger_1.default.debug(`Skipped the "input_image" output item from a tool call result because the OpenAI Conversations API response didn't include the required property (image_url or file_id).`); return null; } if (item.detail) { structured.detail = item.detail; } return structured; } if (item.type === 'input_file') { const structured = { type: 'input_file' }; if (typeof item.file_id === 'string' && item.file_id.length > 0) { structured.file = { id: item.file_id }; } else if (typeof item.file_url === 'string' && item.file_url.length > 0) { structured.file = { url: item.file_url }; } else if (typeof item.file_data === 'string' && item.file_data.length > 0) { structured.file = item.file_data; } if (item.filename) { structured.filename = item.filename; } return structured; } const exhaustive = item; throw new agents_core_1.UserError(`Unsupported structured tool output: ${JSON.stringify(exhaustive)}`); } function convertFunctionCallOutputToProtocol(output) { if (typeof output === 'string') { return output; } if (Array.isArray(output)) { return output .map(convertResponseFunctionCallOutputItemToStructured) .filter((s) => s !== null); } return ''; } function normalizeLegacyFileFromOutput(value) { const filename = typeof value.filename === 'string' && value.filename.length > 0 ? value.filename : undefined; const referencedId = (typeof value.id === 'string' && value.id.length > 0 && value.id) ?? (typeof value.fileId === 'string' && value.fileId.length > 0 ? value.fileId : undefined); if (referencedId) { return { file: { id: referencedId }, filename }; } if (typeof value.fileUrl === 'string' && value.fileUrl.length > 0) { return { file: { url: value.fileUrl }, filename }; } if (typeof value.fileData === 'string' && value.fileData.length > 0) { return { file: formatInlineData(value.fileData, value.mediaType ?? 'text/plain'), filename, }; } if (value.fileData instanceof Uint8Array && value.fileData.length > 0) { return { file: formatInlineData(value.fileData, value.mediaType ?? 'text/plain'), filename, }; } return {}; } function isRecord(value) { return typeof value === 'object' && value !== null; } function getImageInlineMediaType(source) { if (typeof source.mediaType === 'string' && source.mediaType.length > 0) { return source.mediaType; } return undefined; } function formatInlineData(data, mediaType) { const base64 = typeof data === 'string' ? data : (0, utils_1.encodeUint8ArrayToBase64)(data); return mediaType ? `data:${mediaType};base64,${base64}` : base64; } function getTools(tools, handoffs) { const openaiTools = []; const include = []; for (const tool of tools) { const { tool: openaiTool, include: openaiIncludes } = converTool(tool); openaiTools.push(openaiTool); if (openaiIncludes && openaiIncludes.length > 0) { for (const item of openaiIncludes) { include.push(item); } } } return { tools: [...openaiTools, ...handoffs.map(getHandoffTool)], include, }; } function converTool(tool) { if (tool.type === 'function') { return { tool: { type: 'function', name: tool.name, description: tool.description, parameters: tool.parameters, strict: tool.strict, }, include: undefined, }; } else if (tool.type === 'computer') { return { tool: { type: 'computer_use_preview', environment: tool.environment, display_width: tool.dimensions[0], display_height: tool.dimensions[1], }, include: undefined, }; } else if (tool.type === 'shell') { return { tool: { type: 'shell', }, include: undefined, }; } else if (tool.type === 'apply_patch') { return { tool: { type: 'apply_patch', }, include: undefined, }; } else if (tool.type === 'hosted_tool') { if (tool.providerData?.type === 'web_search') { return { tool: { type: 'web_search', user_location: tool.providerData.user_location, filters: tool.providerData.filters, search_context_size: tool.providerData.search_context_size, }, include: undefined, }; } else if (tool.providerData?.type === 'web_search_preview') { return { tool: { type: 'web_search_preview', user_location: tool.providerData.user_location, search_context_size: tool.providerData.search_context_size, }, include: undefined, }; } else if (tool.providerData?.type === 'file_search') { return { tool: { type: 'file_search', vector_store_ids: tool.providerData.vector_store_ids || // for backwards compatibility (typeof tool.providerData.vector_store_id === 'string' ? [tool.providerData.vector_store_id] : tool.providerData.vector_store_id), max_num_results: tool.providerData.max_num_results, ranking_options: tool.providerData.ranking_options, filters: tool.providerData.filters, }, include: tool.providerData.include_search_results ? ['file_search_call.results'] : undefined, }; } else if (tool.providerData?.type === 'code_interpreter') { return { tool: { type: 'code_interpreter', container: tool.providerData.container, }, include: undefined, }; } else if (tool.providerData?.type === 'image_generation') { return { tool: { type: 'image_generation', background: tool.providerData.background, input_fidelity: tool.providerData.input_fidelity, input_image_mask: tool.providerData.input_image_mask, model: tool.providerData.model, moderation: tool.providerData.moderation, output_compression: tool.providerData.output_compression, output_format: tool.providerData.output_format, partial_images: tool.providerData.partial_images, quality: tool.providerData.quality, size: tool.providerData.size, }, include: undefined, }; } else if (tool.providerData?.type === 'mcp') { return { tool: { type: 'mcp', server_label: tool.providerData.server_label, server_url: tool.providerData.server_url, connector_id: tool.providerData.connector_id, authorization: tool.providerData.authorization, allowed_tools: tool.providerData.allowed_tools, headers: tool.providerData.headers, require_approval: convertMCPRequireApproval(tool.providerData.require_approval), }, include: undefined, }; } else if (tool.providerData) { return { tool: tool.providerData, include: undefined, }; } } throw new Error(`Unsupported tool type: ${JSON.stringify(tool)}`); } function convertMCPRequireApproval(requireApproval) { if (requireApproval === 'never' || requireApproval === undefined) { return 'never'; } if (requireApproval === 'always') { return 'always'; } return { never: { tool_names: requireApproval.never?.tool_names }, always: { tool_names: requireApproval.always?.tool_names }, }; } function getHandoffTool(handoff) { return { name: handoff.toolName, description: handoff.toolDescription, parameters: handoff.inputJsonSchema, strict: handoff.strictJsonSchema, type: 'function', }; } function getInputMessageContent(entry) { if (entry.type === 'input_text') { return { type: 'input_text', text: entry.text, ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData), }; } else if (entry.type === 'input_image') { const imageEntry = { type: 'input_image', detail: (entry.detail ?? 'auto'), }; if (typeof entry.image === 'string') { imageEntry.image_url = entry.image; } else if (entry.image && 'id' in entry.image) { imageEntry.file_id = entry.image.id; } else if (typeof entry.imageUrl === 'string') { imageEntry.image_url = entry.imageUrl; } else if (typeof entry.fileId === 'string') { imageEntry.file_id = entry.fileId; } return { ...imageEntry, ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData), }; } else if (entry.type === 'input_file') { const fileEntry = { type: 'input_file', }; if (typeof entry.file === 'string') { if (entry.file.startsWith('data:')) { fileEntry.file_data = entry.file; } else if (entry.file.startsWith('https://')) { fileEntry.file_url = entry.file; } else { throw new agents_core_1.UserError(`Unsupported string data for file input. If you're trying to pass an uploaded file's ID, use an object with the ID property instead.`); } } else if (entry.file && typeof entry.file === 'object' && 'id' in entry.file) { fileEntry.file_id = entry.file.id; } else if (entry.file && typeof entry.file === 'object' && 'url' in entry.file) { fileEntry.file_url = entry.file.url; } const legacyFileData = entry.fileData; if (typeof legacyFileData === 'string') { fileEntry.file_data = legacyFileData; } const legacyFileUrl = entry.fileUrl; if (typeof legacyFileUrl === 'string') { fileEntry.file_url = legacyFileUrl; } const legacyFileId = entry.fileId; if (typeof legacyFileId === 'string') { fileEntry.file_id = legacyFileId; } if (entry.filename) { fileEntry.filename = entry.filename; } return { ...fileEntry, ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData), }; } throw new agents_core_1.UserError(`Unsupported input content type: ${JSON.stringify(entry)}`); } function getOutputMessageContent(entry) { if (entry.type === 'output_text') { return { type: 'output_text', text: entry.text, annotations: [], ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData), }; } if (entry.type === 'refusal') { return { type: 'refusal', refusal: entry.refusal, ...(0, providerData_1.camelOrSnakeToSnakeCase)(entry.providerData), }; } throw new agents_core_1.UserError(`Unsupported output content type: ${JSON.stringify(entry)}`); } function getMessageItem(item) { if (item.role === 'system') { return { id: item.id, role: 'system', content: item.content, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; } if (item.role === 'user') { if (typeof item.content === 'string') { return { id: item.id, role: 'user', content: item.content, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; } return { id: item.id, role: 'user', content: item.content.map(getInputMessageContent), ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; } if (item.role === 'assistant') { const assistantMessage = { type: 'message', id: item.id, role: 'assistant', content: item.content.map(getOutputMessageContent), status: item.status, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return assistantMessage; } throw new agents_core_1.UserError(`Unsupported item ${JSON.stringify(item)}`); } function isMessageItem(item) { if (item.type === 'message') { return true; } if (typeof item.type === 'undefined' && typeof item.role === 'string') { return true; } return false; } function getPrompt(prompt) { if (!prompt) { return undefined; } const transformedVariables = {}; for (const [key, value] of Object.entries(prompt.variables ?? {})) { if (typeof value === 'string') { transformedVariables[key] = value; } else if (typeof value === 'object') { transformedVariables[key] = getInputMessageContent(value); } } return { id: prompt.promptId, version: prompt.version, variables: transformedVariables, }; } function getInputItems(input) { if (typeof input === 'string') { return [ { role: 'user', content: input, }, ]; } return input.map((item) => { if (isMessageItem(item)) { return getMessageItem(item); } if (item.type === 'function_call') { const entry = { id: item.id, type: 'function_call', name: item.name, call_id: item.callId, arguments: item.arguments, status: item.status, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return entry; } if (item.type === 'function_call_result') { const normalizedOutput = normalizeFunctionCallOutputForRequest(item.output); const entry = { type: 'function_call_output', id: item.id, call_id: item.callId, output: normalizedOutput, status: item.status, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return entry; } if (item.type === 'reasoning') { const entry = { id: item.id, type: 'reasoning', summary: item.content.map((content) => ({ type: 'summary_text', text: content.text, ...(0, providerData_1.camelOrSnakeToSnakeCase)(content.providerData), })), encrypted_content: item.providerData?.encryptedContent, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return entry; } if (item.type === 'computer_call') { const entry = { type: 'computer_call', call_id: item.callId, id: item.id, action: item.action, status: item.status, pending_safety_checks: [], ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return entry; } if (item.type === 'computer_call_result') { const entry = { type: 'computer_call_output', id: item.id, call_id: item.callId, output: buildResponseOutput(item), status: item.providerData?.status, acknowledged_safety_checks: item.providerData?.acknowledgedSafetyChecks, ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), }; return entry; } if (item.type === 'shell_call') { const action = { commands: item.action.commands, timeout_ms: typeof item.action.timeoutMs === 'number' ? item.action.timeoutMs : null, max_output_length: typeof item.action.maxOutputLength === 'number' ? item.action.maxOutputLength : null, }; const entry = { type: 'shell_call', id: item.id, call_id: item.callId, status: item.status ?? 'in_progress', action, }; return entry; } if (item.type === 'shell_call_output') { const shellOutputs = item.output; const sanitizedOutputs = shellOutputs.map((entry) => { const outcome = entry?.outcome; const exitCode = outcome?.type === 'exit' ? outcome.exitCode : null; return { stdout: typeof entry?.stdout === 'string' ? entry.stdout : '', stderr: typeof entry?.stderr === 'string' ? entry.stderr : '', outcome: outcome?.type === 'timeout' ? { type: 'timeout' } : { type: 'exit', exit_code: exitCode ?? 0 }, }; }); const entry = { type: 'shell_call_output', call_id: item.callId, output: sanitizedOutputs, id: item.id ?? undefined, }; if (typeof item.maxOutputLength === 'number') { entry.max_output_length = item.maxOutputLength; } return entry; } if (item.type === 'apply_patch_call') { if (!item.operation) { throw new agents_core_1.UserError('apply_patch_call missing operation'); } const entry = { type: 'apply_patch_call', id: item.id ?? undefined, call_id: item.callId, status: item.status ?? 'in_progress', operation: item.operation, }; return entry; } if (item.type === 'apply_patch_call_output') { const entry = { type: 'apply_patch_call_output', id: item.id ?? undefined, call_id: item.callId, status: item.status ?? 'completed', output: item.output ?? undefined, }; return entry; } if (item.type === 'hosted_tool_call') { if (item.providerData?.type === 'web_search_call' || item.providerData?.type === 'web_search' // for backward compatibility ) { const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields type: 'web_search_call', id: item.id, status: tools_1.WebSearchStatus.parse(item.status ?? 'failed'), }; return entry; } if (item.providerData?.type === 'file_search_call' || item.providerData?.type === 'file_search' // for backward compatibility ) { const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields type: 'file_search_call', id: item.id, status: tools_1.FileSearchStatus.parse(item.status ?? 'failed'), queries: item.providerData?.queries ?? [], results: item.providerData?.results, }; return entry; } if (item.providerData?.type === 'code_interpreter_call' || item.providerData?.type === 'code_interpreter' // for backward compatibility ) { const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields type: 'code_interpreter_call', id: item.id, code: item.providerData?.code ?? '', // This property used to be results, so keeping both for backward compatibility // That said, this property cannot be passed from a user, so it's just API's internal data. outputs: item.providerData?.outputs ?? item.providerData?.results ?? [], status: tools_1.CodeInterpreterStatus.parse(item.status ?? 'failed'), container_id: item.providerData?.container_id, }; return entry; } if (item.providerData?.type === 'image_generation_call' || item.providerData?.type === 'image_generation' // for backward compatibility ) { const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields type: 'image_generation_call', id: item.id, result: item.providerData?.result ?? null, status: tools_1.ImageGenerationStatus.parse(item.status ?? 'failed'), }; return entry; } if (item.providerData?.type === 'mcp_list_tools' || item.name === 'mcp_list_tools') { const providerData = item.providerData; const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), type: 'mcp_list_tools', id: item.id, tools: (0, providerData_1.camelOrSnakeToSnakeCase)(providerData.tools), server_label: providerData.server_label, error: providerData.error, }; return entry; } else if (item.providerData?.type === 'mcp_approval_request' || item.name === 'mcp_approval_request') { const providerData = item.providerData; const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields type: 'mcp_approval_request', id: providerData.id ?? item.id, name: providerData.name, arguments: providerData.arguments, server_label: providerData.server_label, }; return entry; } else if (item.providerData?.type === 'mcp_approval_response' || item.name === 'mcp_approval_response') { const providerData = item.providerData; const entry = { ...(0, providerData_1.camelOrSnakeToSnakeCase)(providerData), type: 'mcp_approval_response', id: providerData.id, approve: providerData.approve, approval_request_id: providerData.approval_request_id, reason: providerData.reason, }; return entry; } else if (item.providerData?.type === 'mcp_call' || item.name === 'mcp_call') { const providerData = item.providerData; const entry = { // output, which can be a large text string, is optional here, so we don't include it // output: item.output, ...(0, providerData_1.camelOrSnakeToSnakeCase)(providerData), // place here to prioritize the below fields type: 'mcp_call', id: providerData.id ?? item.id, name: providerData.name, arguments: providerData.arguments, server_label: providerData.server_label, error: providerData.error, }; return entry; } throw new agents_core_1.UserError(`Unsupported built-in tool call type: ${JSON.stringify(item)}`); } if (item.type === 'compaction') { const encryptedContent = item.encrypted_content ?? item.encryptedContent; if (typeof encryptedContent !== 'string') { throw new agents_core_1.UserError('Compaction item missing encrypted_content'); } return { type: 'compaction', id: item.id ?? undefined, encrypted_content: encryptedContent, }; } if (item.type === 'unknown') { return { ...(0, providerData_1.camelOrSnakeToSnakeCase)(item.providerData), // place here to prioritize the below fields id: item.id, }; } const exhaustive = item; throw new agents_core_1.UserError(`Unsupported item ${JSON.stringify(exhaustive)}`); }); } // As of May 29, the output is always screenshot putput function buildResponseOutput(item) { return { type: 'computer_screenshot', image_url: item.output.data, }; } function convertToMessageContentItem(item) { if (item.type === 'output_text') { const { type, text, ...remainingItem } = item; return { type, text, ...remainingItem, }; } if (item.type === 'refusal') { const { type, refusal, ...remainingItem } = item; return { type, refusal, ...remainingItem, }; } throw new Error(`Unsupported message content type: ${JSON.stringify(item)}`); } function convertToOutputItem(items) { return items.map((item) => { if (item.type === 'message') { const { id, type, role, content, status, ...providerData } = item; return { id, type, role, content: content.map(convertToMessageContentItem), status, providerData, }; } else if (item.type === 'file_search_call' || item.type === 'web_search_call' || item.type === 'image_generation_call' || item.type === 'code_interpreter_call') { const { status, ...remainingItem } = item; let outputData = undefined; if ('result' in remainingItem && remainingItem.result !== null) { // type: "image_generation_call" outputData = remainingItem.result; delete remainingItem.result; } const output = { type: 'hosted_tool_call', id: item.id, name: item.type, status, output: outputData, providerData: remainingItem, }; return output; } else if (item.type === 'function_call') { const { call_id, name, status, arguments: args, ...providerData } = item; const output = { type: 'function_call', id: item.id, callId: call_id, name, status, arguments: args, providerData, }; return output; } else if (item.type === 'function_call_output') { const { call_id, status, output: rawOutput, name: toolName, function_name: functionName, ...providerData } = item; const output = { type: 'function_call_result', id: item.id, callId: call_id, name: toolName ?? functionName ?? call_id, status: status ?? 'completed', output: convertFunctionCallOutputToProtocol(rawOutput), providerData, }; return output; } else if (item.type === 'computer_call') { const { call_id, status, action, ...providerData } = item; const output = { type: 'computer_call', id: item.id, callId: call_id, status, action, providerData, }; return output; } else if (item.type === 'shell_call') { const { call_id, status, action, ...providerData } = item; const shellAction = { commands: Array.isArray(action?.commands) ? action.commands : [], }; const timeout = action?.timeout_ms; if (typeof timeout === 'number') { shellAction.timeoutMs = timeout; } const maxOutputLength = action?.max_output_length; if (typeof maxOutputLength === 'number') { shellAction.maxOutputLength = maxOutputLength; } const output = { type: 'shell_call', id: item.id ?? undefined, callId: call_id, status: status ?? 'in_progress', action: shellAction, providerData, }; return output; } else if (item.type === 'shell_call_output') { const { call_id, output: responseOutput, max_output_length, ...providerData } = item; let normalizedOutput = []; if (Array.isArray(responseOutput)) { normalizedOutput = responseOutput.map((entry) => ({ stdout: typeof entry?.stdout === 'string' ? entry.stdout : '', stderr: typeof entry?.stderr === 'string' ? entry.stderr : '', outcome: entry?.outcome?.type === 'timeout' ? { type: 'timeout' } : { type: 'exit', exitCode: typeof entry?.outcome?.exit_code === 'number' ? entry.outcome.exit_code : null, }, })); } const output = { type: 'shell_call_output', id: item.id ?? undefined, callId: call_id, output: normalizedOutput, providerData, }; if (typeof max_output_length === 'number') { output.maxOutputLength = max_output_length; } return output; } else if (item.type === 'apply_patch_call') { const { call_id, status, operation, ...providerData } = item; if (!operation) { throw new agents_core_1.UserError('apply_patch_call missing operation'); } let normalizedOperation; switch (operation.type) { case 'create_file': normalizedOperation = { type: 'create_file', path: operation.path, diff: operation.diff, }; break; case 'delete_file': normalizedOperation = { type: 'delete_file', path: operation.path, }; break; case 'update_file': normalizedOperation = { type: 'update_file', path: operation.path, diff: operation.diff, }; break; default: throw new agents_core_1.UserError('Unknown apply_patch operation type'); } const output = { type: 'apply_patch_call', id: item.id ?? undefined, callId: call_id, status: status ?? 'in_progress', operation: normalizedOperation, providerData, }; return output; } else if (item.type === 'apply_patch_call_output') { const { call_id, status, output: responseOutput, ...providerData } = item; const output = { type: 'apply_patch_call_output', id: item.id ?? undefined, callId: call_id, status, output: typeof responseOutput === 'string' ? responseOutput : undefined, providerData, }; return output; } else if (item.type === 'mcp_list_tools') { const { ...providerData } = item; const output = { type: 'hosted_tool_call', id: item.id, name: item.type, status: 'completed', output: undefined, providerData, }; return output; } else if (item.type === 'mcp_approval_request') { const { ...providerData } = item; const output = { type: 'hosted_tool_call', id: item.id, name: 'mcp_approval_request', status: 'completed', output: undefined, providerData, }; return output; } else if (item.type === 'mcp_call') { // Avoiding to duplicate potentially large output data const { output: outputData, ...providerData } = item; const output = { type: 'hosted_tool_call', id: item.id, name: item.type, status: 'completed', output: outputData || undefined, providerData, }; return output; } else if (item.type === 'reasoning') { // Avoiding to duplicate potentially large summary data const { summary, ...providerData } = item; const output = { type: 'reasoning', id: item.id, content: summary.map((content) => { // Avoiding to duplicate potentially large text const { text, ...remainingContent } = content; return { type: 'input_text', text, providerData: remainingContent, }; }), providerData, }; return output; } else if (item.type === 'compaction') { const { encrypted_content, created_by, ...providerData } = item; if (typeof encrypted_content !== 'string') { throw new agents_core_1.UserError('Compaction item missing encrypted_content'); } const output = { type: 'compaction', id: item.id ?? undefined, encrypted_content, created_by, providerData, }; return output; } return { type: 'unknown', id: item.id, providerData: item, }; }); } /** * Model implementation that uses OpenAI's Responses API to generate responses. */ class OpenAIResponsesModel { #client; #model; constructor(client, model) { this.#client = client; this.#model = model; } async #fetchResponse(request, stream) { const input = getInputItems(request.input); const { tools, include } = getTools(request.tools, request.handoffs); const toolChoice = getToolChoice(request.modelSettings.toolChoice); const { text, ...restOfProviderData } = request.modelSettings.providerData ?? {}; if (request.modelSettings.reasoning) { // Merge top-level reasoning settings with provider data restOfProviderData.reasoning = { ...request.modelSettings.reasoning, ...restOfProviderData.reasoning, }; } let mergedText = text; if (request.modelSettings.text) { // Merge top-level text settings with provider data mergedText = { ...request.modelSettings.text, ...text }; } const responseFormat = getResponseFormat(request.outputType, mergedText); const prompt = getPrompt(request.prompt); let parallelToolCalls = undefined; if (typeof request.modelSettings.parallelToolCalls === 'boolean') { if (request.modelSettings.parallelToolCalls && tools.length === 0) { throw new Error('Parallel tool calls are not supported without tools'); } parallelToolCalls = request.modelSettings.parallelToolCalls; } // When a prompt template already declares a model, skip sending the agent's default model. // If the caller explicitly requests an override, include the resolved model name in the request. const shouldSendModel = !request.prompt || request.overridePromptModel === true; const shouldSendTools = tools.length > 0 || request.toolsExplicitlyProvided === true || !request.prompt; const requestData = { ...(shouldSendModel ? { model: this.#model } : {}), instructio