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