UNPKG

@openai/agents-core

Version:

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

547 lines • 21.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.CompactionItemValidationError = void 0; exports.toAgentInputList = toAgentInputList; exports.assertValidCompactionItems = assertValidCompactionItems; exports.getAgentInputItemKey = getAgentInputItemKey; exports.buildAgentInputPool = buildAgentInputPool; exports.takeAgentInputFromPool = takeAgentInputFromPool; exports.removeAgentInputFromPool = removeAgentInputFromPool; exports.deduplicateAgentInputItemsPreferringLatest = deduplicateAgentInputItemsPreferringLatest; exports.agentInputSerializationReplacer = agentInputSerializationReplacer; exports.invalidateOutputItemNormalization = invalidateOutputItemNormalization; exports.stripReasoningItemIdForPolicy = stripReasoningItemIdForPolicy; exports.extractOutputItemsFromRunItems = extractOutputItemsFromRunItems; exports.dropOrphanToolCalls = dropOrphanToolCalls; exports.prepareModelInputItems = prepareModelInputItems; exports.getRunOutput = getRunOutput; exports.getTurnInput = getTurnInput; exports.trimToLatestCompaction = trimToLatestCompaction; const errors_1 = require("../errors.js"); const tooling_1 = require("../tooling.js"); const protocol = __importStar(require("../types/protocol.js")); const binary_1 = require("../utils/binary.js"); const toolResultCorrelation_1 = require("./toolResultCorrelation.js"); class CompactionItemValidationError extends errors_1.UserError { } exports.CompactionItemValidationError = CompactionItemValidationError; // Normalizes user-provided input into the structure the model expects. Strings become user messages, // arrays are kept as-is so downstream loops can treat both scenarios uniformly. function toAgentInputList(originalInput) { if (typeof originalInput === 'string') { return [{ type: 'message', role: 'user', content: originalInput }]; } return [...originalInput]; } function assertValidCompactionItems(items) { for (const item of items) { if (item.type === 'compaction' && !protocol.CompactionItem.safeParse(item).success) { throw new CompactionItemValidationError('Compaction item missing encrypted_content'); } } } function getAgentInputItemKey(item) { return JSON.stringify(item, agentInputSerializationReplacer); } function buildAgentInputPool(items) { const pool = new Map(); for (const item of items) { const key = getAgentInputItemKey(item); const existing = pool.get(key); if (existing) { existing.push(item); } else { pool.set(key, [item]); } } return pool; } function takeAgentInputFromPool(pool, key) { const candidates = pool.get(key); if (!candidates || candidates.length === 0) { return undefined; } const [first] = candidates; candidates.shift(); if (candidates.length === 0) { pool.delete(key); } return first; } function removeAgentInputFromPool(pool, item) { const key = getAgentInputItemKey(item); const candidates = pool.get(key); if (!candidates || candidates.length === 0) { return false; } const index = candidates.findIndex((candidate) => candidate === item); if (index === -1) { return false; } candidates.splice(index, 1); if (candidates.length === 0) { pool.delete(key); } return true; } function getAgentInputItemDeduplicationKey(item) { if (!item || typeof item !== 'object') { return undefined; } const candidate = item; const itemType = candidate.type; if (typeof candidate.role === 'string' || itemType === 'message') { return undefined; } if (typeof itemType !== 'string') { return undefined; } if (itemType === 'tool_search_call' || itemType === 'tool_search_output') { const callId = (0, tooling_1.getToolSearchProviderCallId)(item); if (callId) { return JSON.stringify(['call', itemType, callId]); } } const callCorrelation = (0, toolResultCorrelation_1.getToolResultCorrelationForCall)(item); if (callCorrelation && callCorrelation.id.length > 0) { return JSON.stringify([ 'call', itemType, (0, toolResultCorrelation_1.getToolResultCorrelationKey)(callCorrelation), ]); } const resultCorrelation = (0, toolResultCorrelation_1.getToolResultCorrelationForResult)(item); if (resultCorrelation && resultCorrelation.id.length > 0) { return JSON.stringify([ 'result', itemType, (0, toolResultCorrelation_1.getToolResultCorrelationKey)(resultCorrelation), ]); } if (typeof candidate.id === 'string' && candidate.id.length > 0) { return JSON.stringify(['item', itemType, candidate.id]); } return undefined; } function isCausalPrecursorItem(item) { if (!item || typeof item !== 'object') { return false; } return (item.type === 'tool_search_call' || (item.type === 'hosted_tool_call' && (0, toolResultCorrelation_1.getToolResultCorrelationForResult)(item) === undefined) || item.type === 'compaction' || item.type === 'reasoning' || (0, toolResultCorrelation_1.getToolResultCorrelationForCall)(item) !== undefined); } /** * Deduplicates provider-identified items while preserving causal ordering. * * The latest payload wins. Calls, compaction, reasoning, and approval requests stay at their * earliest occurrence so they cannot move behind a required follower; other identified items * stay at their latest occurrence so stale outputs are not moved earlier. Items without stable * provider identity, including ordinary messages, remain untouched. */ function deduplicateAgentInputItemsPreferringLatest(items) { const latestByKey = new Map(); const anchorIndexByKey = new Map(); for (const [index, item] of items.entries()) { const key = getAgentInputItemDeduplicationKey(item); if (!key) { continue; } latestByKey.set(key, item); if (!anchorIndexByKey.has(key) || !isCausalPrecursorItem(item)) { anchorIndexByKey.set(key, index); } } const deduplicated = []; for (const [index, item] of items.entries()) { const key = getAgentInputItemDeduplicationKey(item); if (!key) { deduplicated.push(item); } else if (anchorIndexByKey.get(key) === index) { deduplicated.push(latestByKey.get(key)); } } return deduplicated; } function agentInputSerializationReplacer(_key, value) { const serialized = (0, binary_1.serializeBinary)(value); if (serialized) { return serialized; } return value; } // Keep each model-input normalization stable for one generated item so identity-preserving // filters can reuse caches across turns without mutating the provider item. const normalizedOutputItemByRunItem = new WeakMap(); function invalidateOutputItemNormalization(items) { for (const item of items) { normalizedOutputItemByRunItem.delete(item); } } function shouldOmitReasoningItemIds(reasoningItemIdPolicy) { return reasoningItemIdPolicy === 'omit'; } function stripReasoningItemIdForPolicy(item, reasoningItemIdPolicy) { if (!shouldOmitReasoningItemIds(reasoningItemIdPolicy) || !item || typeof item !== 'object' || item.type !== 'reasoning' || !('id' in item)) { return item; } const { id: _id, ...withoutId } = item; return withoutId; } // Extracts model-ready output items from run items, excluding approval placeholders. function extractOutputItemsFromRunItems(items, reasoningItemIdPolicy) { return items .filter((item) => item.type !== 'tool_approval_item') .map((item) => { const normalizationKey = item.type === 'reasoning_item' && shouldOmitReasoningItemIds(reasoningItemIdPolicy) ? 'omit' : 'preserve'; const cached = normalizedOutputItemByRunItem.get(item)?.[normalizationKey]; if (cached) { return cached; } const withoutOutputOnlyMetadata = stripOutputOnlyCreatedBy(item.rawItem); const withoutNullStatusItem = withoutNullStatus(withoutOutputOnlyMetadata); const normalizedItem = normalizationKey === 'omit' ? stripReasoningItemIdForPolicy(withoutNullStatusItem, reasoningItemIdPolicy) : withoutNullStatusItem; const cachedByPolicy = normalizedOutputItemByRunItem.get(item) ?? {}; cachedByPolicy[normalizationKey] = normalizedItem; normalizedOutputItemByRunItem.set(item, cachedByPolicy); return normalizedItem; }); } function stripOutputOnlyCreatedBy(item) { if (!item || typeof item !== 'object') { return item; } const candidate = item; const hasTopLevelCreatedBy = Object.prototype.hasOwnProperty.call(candidate, 'created_by'); const output = candidate.output; const hasShellOutputCreatedBy = candidate.type === 'shell_call_output' && Array.isArray(output) && output.some((entry) => entry !== null && typeof entry === 'object' && Object.prototype.hasOwnProperty.call(entry, 'created_by')); if (!hasTopLevelCreatedBy && !hasShellOutputCreatedBy) { return item; } const { created_by: _createdBy, ...withoutCreatedBy } = candidate; const normalized = withoutCreatedBy; if (hasShellOutputCreatedBy) { normalized.output = output.map((entry) => { if (entry === null || typeof entry !== 'object' || !Object.prototype.hasOwnProperty.call(entry, 'created_by')) { return entry; } const { created_by: _chunkCreatedBy, ...withoutChunkCreatedBy } = entry; return withoutChunkCreatedBy; }); } return normalized; } function withoutNullStatus(item) { if (!item || typeof item !== 'object' || !('status' in item) || item.status !== null) { return item; } const { status: _status, ...withoutStatus } = item; return withoutStatus; } function collectCompletedCallIdsByResultType(items) { const completed = new Map(); for (const item of items) { if (!item || typeof item !== 'object') { continue; } const type = item.type; const callId = item.callId; if (typeof type !== 'string' || typeof callId !== 'string') { continue; } if (!(0, toolResultCorrelation_1.isSimpleToolResultType)(type)) { continue; } const existing = completed.get(type); if (existing) { existing.add(callId); } else { completed.set(type, new Set([callId])); } } return completed; } function collectProgramCallIds(items) { const callIds = new Set(); for (const item of items) { if (!item || typeof item !== 'object' || item.type !== 'program') { continue; } if (typeof item.callId === 'string') { callIds.add(item.callId); } } return callIds; } function isPendingHostedShellCall(item) { if (!item || typeof item !== 'object' || item.type !== 'shell_call') { return false; } const status = item.status; return status === undefined || status === 'in_progress'; } function getProgramCallerId(item) { if (!item || typeof item !== 'object' || !('caller' in item)) { return undefined; } const caller = item.caller; if (!caller || typeof caller !== 'object') { return undefined; } const candidate = caller; return candidate.type === 'program' && typeof candidate.callerId === 'string' ? candidate.callerId : undefined; } function getProgramOwnedCorrelationKey(programCallId, correlation) { return correlation ? JSON.stringify([programCallId, (0, toolResultCorrelation_1.getToolResultCorrelationKey)(correlation)]) : undefined; } function collectProgramOwnedCallKeys(items) { const callKeys = new Set(); for (const item of items) { const programCallId = getProgramCallerId(item); if (!programCallId) { continue; } const key = getProgramOwnedCorrelationKey(programCallId, (0, toolResultCorrelation_1.getToolResultCorrelationForCall)(item)); if (key) { callKeys.add(key); } } return callKeys; } function hasRetainedProgramOwnedItem(items, programCallId, pruningIndexes) { const retainedCallKeys = new Set(); const retainedResultKeys = new Set(); for (const [index, item] of items.entries()) { if (getProgramCallerId(item) !== programCallId) { continue; } const result = (0, toolResultCorrelation_1.getToolResultCorrelationForResult)(item); if (!(pruningIndexes?.has(index) ?? false) && (isPendingHostedShellCall(item) || (item && typeof item === 'object' && item.type === 'hosted_tool_call' && !result))) { return true; } const call = (0, toolResultCorrelation_1.getToolResultCorrelationForCall)(item); if (call) { retainedCallKeys.add((0, toolResultCorrelation_1.getToolResultCorrelationKey)(call)); } if (result) { retainedResultKeys.add((0, toolResultCorrelation_1.getToolResultCorrelationKey)(result)); } } return [...retainedCallKeys].some((key) => retainedResultKeys.has(key)); } function dropOrphanToolCalls(items, options) { const pruningIndexes = options?.pruningIndexes; const completedByResultType = collectCompletedCallIdsByResultType(items); const programCallIds = collectProgramCallIds(items); const programOwnedCallKeys = collectProgramOwnedCallKeys(items); const droppedIndexes = new Set(); const activeProgramCallIds = new Set(); const orphanProgramCallIds = new Set(); for (const [index, item] of items.entries()) { if (pruningIndexes && !pruningIndexes.has(index)) { continue; } if (!item || typeof item !== 'object' || item.type !== 'program') { continue; } if (completedByResultType.get('program_output')?.has(item.callId) ?? false) { continue; } const hasRetainedOwnedItem = hasRetainedProgramOwnedItem(items, item.callId, pruningIndexes); if (hasRetainedOwnedItem) { activeProgramCallIds.add(item.callId); } else { orphanProgramCallIds.add(item.callId); } } const filtered = items.filter((item, index) => { if (!item || typeof item !== 'object') { return true; } const programCallerId = getProgramCallerId(item); if (programCallerId) { if (!programCallIds.has(programCallerId) || orphanProgramCallIds.has(programCallerId)) { droppedIndexes.add(index); return false; } const resultKey = getProgramOwnedCorrelationKey(programCallerId, (0, toolResultCorrelation_1.getToolResultCorrelationForResult)(item)); if (resultKey && !programOwnedCallKeys.has(resultKey)) { droppedIndexes.add(index); return false; } } if (pruningIndexes && !pruningIndexes.has(index)) { return true; } const type = item.type; const callId = item.callId; if (typeof type !== 'string' || typeof callId !== 'string') { return true; } if (type === 'program_output' && !programCallIds.has(callId)) { droppedIndexes.add(index); return false; } const resultType = (0, toolResultCorrelation_1.getSimpleToolResultTypeForCall)(type); if (!resultType) { return true; } if (isPendingHostedShellCall(item)) { return true; } if (type === 'program' && activeProgramCallIds.has(callId)) { return true; } if (completedByResultType.get(resultType)?.has(callId) ?? false) { return true; } droppedIndexes.add(index); return false; }); if (droppedIndexes.size === 0) { return filtered; } return dropReasoningItemsPrecedingDroppedCalls(items, droppedIndexes, pruningIndexes); } function dropReasoningItemsPrecedingDroppedCalls(items, droppedIndexes, pruningIndexes) { const dropReasoning = new Set(); for (let index = items.length - 1; index >= 0; index -= 1) { if (pruningIndexes && !pruningIndexes.has(index)) { continue; } const item = items[index]; if (!item || typeof item !== 'object' || item.type !== 'reasoning' || droppedIndexes.has(index)) { continue; } for (let nextIndex = index + 1; nextIndex < items.length; nextIndex += 1) { if (dropReasoning.has(nextIndex)) { continue; } const nextItem = items[nextIndex]; if (nextItem && typeof nextItem === 'object' && nextItem.type === 'reasoning') { continue; } if (droppedIndexes.has(nextIndex)) { dropReasoning.add(index); } break; } } const excluded = new Set([...droppedIndexes, ...dropReasoning]); return items.filter((_item, index) => !excluded.has(index)); } function prepareModelInputItems(originalInput, generatedItems, reasoningItemIdPolicy) { const callerItems = toAgentInputList(originalInput); const preparedGeneratedItems = getContinuationOutputItems(generatedItems, reasoningItemIdPolicy); return trimToLatestCompaction([...callerItems, ...preparedGeneratedItems]); } function getContinuationOutputItems(generatedItems, reasoningItemIdPolicy) { const generatedOutputItems = trimToLatestCompaction(extractOutputItemsFromRunItems(generatedItems, reasoningItemIdPolicy)); return dropOrphanToolCalls(generatedOutputItems); } /** * Extracts generated output without including input admitted while resuming a run. */ function getRunOutput(generatedItems, reasoningItemIdPolicy) { return getContinuationOutputItems(generatedItems.filter((item) => item.type !== 'input_item'), reasoningItemIdPolicy); } /** * Constructs the model input array for the current turn by combining the original turn input with * any new run items (excluding tool approval placeholders). This helps ensure that repeated calls * to the Responses API only send newly generated content. * * See: https://platform.openai.com/docs/guides/conversation-state?api-mode=responses. */ function getTurnInput(originalInput, generatedItems, reasoningItemIdPolicy) { const outputItems = getContinuationOutputItems(generatedItems, reasoningItemIdPolicy); return trimToLatestCompaction([ ...toAgentInputList(originalInput), ...outputItems, ]); } function trimToLatestCompaction(items) { for (let index = items.length - 1; index >= 0; index -= 1) { const item = items[index]; const rawItem = item && 'rawItem' in item ? item.rawItem : item; if (rawItem?.type === 'compaction') { return items.slice(index); } } return items; } //# sourceMappingURL=items.js.map