UNPKG

@openai/agents-core

Version:

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

183 lines • 7.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getModelVisibleSessionItems = getModelVisibleSessionItems; exports.hasCompleteApprovalGroups = hasCompleteApprovalGroups; exports.normalizeItemsForSessionPersistence = normalizeItemsForSessionPersistence; exports.sessionItemArraysMatch = sessionItemArraysMatch; exports.agentItemRangeMatches = agentItemRangeMatches; const base64_1 = require("../utils/base64.js"); const binary_1 = require("../utils/binary.js"); const items_1 = require("./items.js"); const toolResultCorrelation_1 = require("./toolResultCorrelation.js"); /** Return model-visible representations only when every stored occurrence is covered in order. */ function getModelVisibleSessionItems(session, stored, exchange) { const comparable = (items) => { // Normalize each record separately: persistence's whole-array deduplication would lose counts. const normalized = items.map((item) => normalizeItemsForSessionPersistence([item])[0]); return (session.prepareHistoryItemsForPersistenceComparison?.(structuredClone(normalized)) ?? normalized); }; const history = comparable(stored); const modelItems = comparable(exchange.items); if (history.length !== stored.length || modelItems.length !== exchange.items.length) { return undefined; } const visible = []; let cursor = 0; for (const item of history) { const replayItem = (0, items_1.stripReasoningItemIdForPolicy)(item, exchange.reasoningItemIdPolicy); while (cursor < modelItems.length && !sessionItemArraysMatch([item], [modelItems[cursor]]) && !sessionItemArraysMatch([replayItem], [modelItems[cursor]]) && !sessionItemArraysMatch([item], [ (0, items_1.stripReasoningItemIdForPolicy)(modelItems[cursor], exchange.reasoningItemIdPolicy), ])) { cursor++; } if (cursor === modelItems.length) return undefined; visible.push(exchange.items[cursor++]); } return visible; } /** Check the covered history before automatically compacting an approval group. */ function hasCompleteApprovalGroups(items) { const pending = new Map(); for (const item of items) { if (item.type !== 'function_call' && item.type !== 'function_call_result' && item.type !== 'hosted_tool_call') { continue; } const call = (0, toolResultCorrelation_1.getToolResultCorrelationForCall)(item); const correlation = call ?? (0, toolResultCorrelation_1.getToolResultCorrelationForResult)(item); if (!correlation) continue; const key = (0, toolResultCorrelation_1.getToolResultCorrelationKey)(correlation); const count = pending.get(key) ?? 0; if (call) { pending.set(key, count + 1); } else if (count === 0) { return false; } else if (count === 1) { pending.delete(key); } else { pending.set(key, count - 1); } } return pending.size === 0; } function normalizeItemsForSessionPersistence(items) { return (0, items_1.deduplicateAgentInputItemsPreferringLatest)(items.map((item) => sanitizeValueForSession(stripTransientCallIds(item)))); } function sessionItemArraysMatch(items, expected) { return (items.length === expected.length && agentItemRangeMatches(items, expected, 0)); } function agentItemRangeMatches(items, expected, start) { if (start < 0 || start + expected.length > items.length) { return false; } return expected.every((item, offset) => getSessionReconciliationItemKey(items[start + offset]) === getSessionReconciliationItemKey(item)); } function sanitizeValueForSession(value, context = {}) { if (value === null || value === undefined) { return value; } const binary = (0, binary_1.toUint8ArrayFromBinary)(value); if (binary) { return toDataUrlFromBytes(binary, context.mediaType); } if (Array.isArray(value)) { return value.map((entry) => sanitizeValueForSession(entry, context)); } if (!isPlainObject(value)) { return value; } const record = value; const result = {}; const mediaType = typeof record.mediaType === 'string' && record.mediaType.length > 0 ? record.mediaType : context.mediaType; for (const [key, entry] of Object.entries(record)) { const nextContext = key === 'data' || key === 'fileData' ? { mediaType } : context; result[key] = sanitizeValueForSession(entry, nextContext); } return result; } function toDataUrlFromBytes(bytes, mediaType) { const base64 = (0, base64_1.encodeUint8ArrayToBase64)(bytes); const type = mediaType && !mediaType.startsWith('data:') ? mediaType : 'text/plain'; return `data:${type};base64,${base64}`; } function stripTransientCallIds(value) { if (value === null || value === undefined) { return value; } if (Array.isArray(value)) { return value.map((entry) => stripTransientCallIds(entry)); } if (!isPlainObject(value)) { return value; } const record = value; const result = {}; const isProtocolItem = typeof record.type === 'string' && record.type.length > 0; const shouldStripId = isProtocolItem && shouldStripIdForProtocolItem(record); for (const [key, entry] of Object.entries(record)) { if (shouldStripId && key === 'id') { continue; } result[key] = stripTransientCallIds(entry); } return result; } function shouldStripIdForProtocolItem(record) { switch (record.type) { case 'function_call': case 'function_call_result': return true; case 'tool_search_call': case 'tool_search_output': return hasToolSearchCallId(record); default: return false; } } function hasToolSearchCallId(record) { const topLevelCallId = record.call_id ?? record.callId; if (typeof topLevelCallId === 'string' && topLevelCallId.length > 0) { return true; } const providerData = isPlainObject(record.providerData) ? record.providerData : undefined; const providerCallId = providerData?.call_id ?? providerData?.callId; return typeof providerCallId === 'string' && providerCallId.length > 0; } function getSessionReconciliationItemKey(item) { return JSON.stringify(sortSessionReconciliationValue(item)); } function sortSessionReconciliationValue(value) { if (Array.isArray(value)) { return value.map(sortSessionReconciliationValue); } if (!isPlainObject(value)) { return value; } return Object.fromEntries(Object.keys(value) .sort() .map((key) => [key, sortSessionReconciliationValue(value[key])])); } function isPlainObject(value) { if (typeof value !== 'object' || value === null) { return false; } const proto = Object.getPrototypeOf(value); return proto === Object.prototype || proto === null; } //# sourceMappingURL=sessionItems.js.map