@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
109 lines • 5.08 kB
JavaScript
import { UserError } from "../errors.mjs";
import { RunInputItem } from "../items.mjs";
import { getAgentInputItemKey } from "./items.mjs";
import { mapOwnedInputItemsAfterContextProcessing } from "./sessionPersistence.mjs";
/**
* Resolves which staged occurrences reached the model after filtering.
*/
export function selectPendingInputForAdmission(pendingItems, preparation) {
if (pendingItems.length === 0) {
return [];
}
const pendingByRawItem = new Map();
for (const item of pendingItems) {
pendingByRawItem.set(item.rawItem, item);
}
for (const [index, sourceItem] of preparation.sourceItems.entries()) {
if (sourceItem &&
pendingByRawItem.has(sourceItem) &&
preparation.sourceMatchKinds[index] === 'fallback') {
throw new UserError('callModelInputFilter cannot safely associate a reconstructed item with pending RunState input. Preserve the input item object, return an unchanged copy, or omit the pending item.');
}
}
const pendingKeys = new Set(pendingItems.map((item) => getAgentInputItemKey(item.rawItem)));
for (const key of pendingKeys) {
const candidates = preparation.turnInput.filter((item) => getAgentInputItemKey(item) === key);
const reconstructedMatches = preparation.sourceItems.flatMap((sourceItem, index) => sourceItem &&
getAgentInputItemKey(sourceItem) === key &&
preparation.sourceMatchKinds[index] === 'content'
? [sourceItem]
: []);
const hasPendingCandidate = candidates.some((candidate) => pendingByRawItem.has(candidate));
const hasNonPendingCandidate = candidates.some((candidate) => !pendingByRawItem.has(candidate));
if (reconstructedMatches.length > 0 &&
reconstructedMatches.length < candidates.length &&
hasPendingCandidate &&
hasNonPendingCandidate) {
throw new UserError('callModelInputFilter cannot safely associate a reconstructed item with pending RunState input. Preserve the input item object, return an unchanged copy, or omit the pending item.');
}
}
const admitted = [];
const acceptedIds = new Set();
for (const [index, sourceItem] of preparation.sourceItems.entries()) {
if (!sourceItem) {
continue;
}
const pendingItem = pendingByRawItem.get(sourceItem);
if (!pendingItem || acceptedIds.has(pendingItem.inputId)) {
continue;
}
const persistedItem = preparation.persistedItems[index];
if (!persistedItem) {
continue;
}
acceptedIds.add(pendingItem.inputId);
const preservesPreparedItem = preparation.preserveInputIdentity &&
preparation.sourceMatchKinds[index] === 'identity' &&
getAgentInputItemKey(pendingItem.rawItem) ===
getAgentInputItemKey(persistedItem);
admitted.push(preservesPreparedItem
? pendingItem
: new RunInputItem(structuredClone(persistedItem), pendingItem.agent, pendingItem.inputId));
}
return admitted;
}
/**
* Preserves staged occurrence identity through sandbox capability processing.
*/
export function mapPendingInputAfterContextProcessing(pendingItems, preparedItems, processedItems) {
if (pendingItems.length === 0 || preparedItems === processedItems) {
return pendingItems;
}
return mapOwnedInputItemsAfterContextProcessing(preparedItems, processedItems, pendingItems.map((item) => item.rawItem)).map(({ item, ownerIndex }) => {
const pendingItem = pendingItems[ownerIndex];
return new RunInputItem(item, pendingItem.agent, pendingItem.inputId);
});
}
/**
* Commits accepted occurrences to RunState and leaves omitted occurrences pending.
*/
export function commitPendingInput(state, preparedItems, admittedItems, sourceItems) {
if (preparedItems.length === 0) {
return;
}
const admittedIds = new Set(admittedItems.map((item) => item.inputId));
const sourceItemSet = new Set(sourceItems);
const preparedQueueIsIntact = sourceItems.every((item, index) => state._pendingInput[index] === item);
const newlyStagedItems = preparedQueueIsIntact
? state._pendingInput.slice(sourceItems.length)
: state._pendingInput.filter((item) => !sourceItemSet.has(item));
state._generatedItems.push(...admittedItems);
state._pendingInput = [
...(preparedQueueIsIntact
? preparedItems
.filter((item) => !admittedIds.has(item.inputId))
.map((item) => item.rawItem)
: []),
...structuredClone(newlyStagedItems),
];
}
/**
* Returns whether a committed input occurrence still belongs to the unpersisted
* suffix for the current local-session turn.
*/
export function hasUnpersistedRunInput(state) {
return state._generatedItems
.slice(state._currentTurnPersistedItemCount)
.some((item) => item instanceof RunInputItem);
}
//# sourceMappingURL=pendingInput.mjs.map