UNPKG

@openai/agents-core

Version:

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

328 lines • 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.normalizeStructuredToolOutputs = normalizeStructuredToolOutputs; exports.convertStructuredToolOutputToInputItem = convertStructuredToolOutputToInputItem; const base64_1 = require("../utils/base64.js"); const inlineData_1 = require("../utils/inlineData.js"); /** * Accepts whatever the tool returned and attempts to coerce it into the structured protocol * shapes we expose to downstream model adapters (input_text/input_image/input_file). Tools are * allowed to return either a single structured object or an array of them; anything else falls * back to the legacy string pipeline. */ function normalizeStructuredToolOutputs(output) { if (Array.isArray(output)) { if (output.length === 0) { return null; } const structured = []; for (const item of output) { const normalized = normalizeStructuredToolOutput(item); if (!normalized) { return null; } structured.push(normalized); } return structured; } const normalized = normalizeStructuredToolOutput(output); return normalized ? [normalized] : null; } /** * Best-effort normalization of a single tool output item. If the object already matches the * protocol shape we simply cast it; otherwise we copy the recognised fields into the canonical * structure. Returning null lets the caller know we should revert to plain-string handling. */ function normalizeStructuredToolOutput(value) { if (!isRecord(value)) { return null; } const type = value.type; if (type === 'text' && typeof value.text === 'string') { const output = { type: 'text', text: value.text }; if (isRecord(value.providerData)) { output.providerData = value.providerData; } return output; } if (type === 'image') { const output = { type: 'image' }; let imageString; let imageFileId; const fallbackImageMediaType = (0, inlineData_1.getInlineMediaType)(value); const imageField = value.image; if (typeof imageField === 'string' && imageField.length > 0) { imageString = imageField; } else if (isRecord(imageField)) { const imageObj = imageField; const inlineMediaType = (0, inlineData_1.getInlineMediaType)(imageObj) ?? fallbackImageMediaType; if (isNonEmptyString(imageObj.url)) { imageString = imageObj.url; } else if (isNonEmptyString(imageObj.data)) { imageString = (0, inlineData_1.formatInlineData)(imageObj.data, inlineMediaType); } else if (imageObj.data instanceof Uint8Array && imageObj.data.length > 0) { imageString = (0, inlineData_1.formatInlineData)(imageObj.data, inlineMediaType); } if (!imageString) { const candidateId = (isNonEmptyString(imageObj.fileId) && imageObj.fileId) || (isNonEmptyString(imageObj.id) && imageObj.id) || undefined; if (candidateId) { imageFileId = candidateId; } } } if (!imageString && typeof value.imageUrl === 'string' && value.imageUrl.length > 0) { imageString = value.imageUrl; } if (!imageFileId && typeof value.fileId === 'string' && value.fileId.length > 0) { imageFileId = value.fileId; } if (!imageString && typeof value.data === 'string' && value.data.length > 0) { imageString = fallbackImageMediaType ? (0, inlineData_1.formatInlineData)(value.data, fallbackImageMediaType) : value.data; } else if (!imageString && value.data instanceof Uint8Array && value.data.length > 0) { imageString = (0, inlineData_1.formatInlineData)(value.data, fallbackImageMediaType); } if (typeof value.detail === 'string' && value.detail.length > 0) { output.detail = value.detail; } if (imageString) { output.image = imageString; } else if (imageFileId) { output.image = { fileId: imageFileId }; } else { return null; } if (isRecord(value.providerData)) { output.providerData = value.providerData; } return output; } if (type === 'file') { const fileValue = normalizeFileValue(value); if (!fileValue) { return null; } const output = { type: 'file', file: fileValue }; if (isRecord(value.providerData)) { output.providerData = value.providerData; } return output; } return null; } /** * Translates the normalized tool output into the protocol `input_*` items. This is the last hop * before we hand the data to model-specific adapters, so we generate the exact schema expected by * the protocol definitions. */ function convertStructuredToolOutputToInputItem(output) { if (output.type === 'text') { const result = { type: 'input_text', text: output.text, }; if (output.providerData) { result.providerData = output.providerData; } return result; } if (output.type === 'image') { const result = { type: 'input_image' }; if (typeof output.detail === 'string' && output.detail.length > 0) { result.detail = output.detail; } if (typeof output.image === 'string' && output.image.length > 0) { result.image = output.image; } else if (isRecord(output.image)) { const imageObj = output.image; const inlineMediaType = (0, inlineData_1.getInlineMediaType)(imageObj); if (isNonEmptyString(imageObj.url)) { result.image = imageObj.url; } else if (isNonEmptyString(imageObj.data)) { result.image = inlineMediaType && !imageObj.data.startsWith('data:') ? asDataUrl(imageObj.data, inlineMediaType) : imageObj.data; } else if (imageObj.data instanceof Uint8Array && imageObj.data.length > 0) { const base64 = (0, base64_1.encodeUint8ArrayToBase64)(imageObj.data); result.image = asDataUrl(base64, inlineMediaType); } else { const referencedId = (isNonEmptyString(imageObj.fileId) && imageObj.fileId) || (isNonEmptyString(imageObj.id) && imageObj.id) || undefined; if (referencedId) { result.image = { id: referencedId }; } } } if (output.providerData) { result.providerData = output.providerData; } return result; } if (output.type === 'file') { const result = { type: 'input_file' }; const fileValue = output.file; if (typeof fileValue === 'string') { result.file = fileValue; } else if (fileValue && typeof fileValue === 'object') { const record = fileValue; if ('data' in record && record.data) { const mediaType = record.mediaType ?? 'text/plain'; if (typeof record.data === 'string') { result.file = asDataUrl(record.data, mediaType); } else { const base64 = (0, base64_1.encodeUint8ArrayToBase64)(record.data); result.file = asDataUrl(base64, mediaType); } } else if (typeof record.url === 'string' && record.url.length > 0) { result.file = { url: record.url }; } else { const referencedId = (typeof record.id === 'string' && record.id.length > 0 && record.id) || (typeof record.fileId === 'string' && record.fileId.length > 0 ? record.fileId : undefined); if (referencedId) { result.file = { id: referencedId }; } } if (typeof record.filename === 'string' && record.filename.length > 0) { result.filename = record.filename; } } if (output.providerData) { result.providerData = output.providerData; } return result; } const exhaustiveCheck = output; return exhaustiveCheck; } function normalizeFileValue(value) { const directFile = value.file; if (typeof directFile === 'string' && directFile.length > 0) { return directFile; } const normalizedObject = normalizeFileObjectCandidate(directFile); if (normalizedObject) { return normalizedObject; } const legacyValue = normalizeLegacyFileValue(value); if (legacyValue) { return legacyValue; } return null; } function normalizeFileObjectCandidate(value) { if (!isRecord(value)) { return null; } if ('data' in value && value.data !== undefined) { const dataValue = value.data; const hasStringData = typeof dataValue === 'string' && dataValue.length > 0; const hasBinaryData = dataValue instanceof Uint8Array && dataValue.length > 0; if (!hasStringData && !hasBinaryData) { return null; } if (!isNonEmptyString(value.mediaType) || !isNonEmptyString(value.filename)) { return null; } return { data: typeof dataValue === 'string' ? dataValue : new Uint8Array(dataValue), mediaType: value.mediaType, filename: value.filename, }; } if (isNonEmptyString(value.url)) { const result = { url: value.url }; if (isNonEmptyString(value.filename)) { result.filename = value.filename; } return result; } const referencedId = (isNonEmptyString(value.id) && value.id) || (isNonEmptyString(value.fileId) && value.fileId); if (referencedId) { const result = { id: referencedId }; if (isNonEmptyString(value.filename)) { result.filename = value.filename; } return result; } return null; } function normalizeLegacyFileValue(value) { const filename = typeof value.filename === 'string' && value.filename.length > 0 ? value.filename : undefined; const mediaType = typeof value.mediaType === 'string' && value.mediaType.length > 0 ? value.mediaType : undefined; if (typeof value.fileData === 'string' && value.fileData.length > 0) { if (!mediaType || !filename) { return null; } return { data: value.fileData, mediaType, filename }; } if (value.fileData instanceof Uint8Array && value.fileData.length > 0) { if (!mediaType || !filename) { return null; } return { data: new Uint8Array(value.fileData), mediaType, filename }; } if (typeof value.fileUrl === 'string' && value.fileUrl.length > 0) { const result = { url: value.fileUrl }; if (filename) { result.filename = filename; } return result; } if (typeof value.fileId === 'string' && value.fileId.length > 0) { const result = { id: value.fileId }; if (filename) { result.filename = filename; } return result; } return null; } function isRecord(value) { return typeof value === 'object' && value !== null; } function isNonEmptyString(value) { return typeof value === 'string' && value.length > 0; } function asDataUrl(base64, mediaType) { return mediaType ? `data:${mediaType};base64,${base64}` : base64; } //# sourceMappingURL=toolOutputNormalization.js.map