UNPKG

@openai/agents-core

Version:

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

1,679 lines • 82.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.selectRunItemIndexesForBlockedOutput = void 0;
exports.getSessionCompactionState = getSessionCompactionState;
exports.bindSessionCompactionState = bindSessionCompactionState;
exports.prepareSessionCompactionExchange = prepareSessionCompactionExchange;
exports.prepareResumedSessionWrite = prepareResumedSessionWrite;
exports.acquireResumedSessionWriteOperation = acquireResumedSessionWriteOperation;
exports.reconcilePendingSessionWriteBeforeRun = reconcilePendingSessionWriteBeforeRun;
exports.selectRunItemsForBlockedOutput = selectRunItemsForBlockedOutput;
exports.canPersistBlockedOutputToSession = canPersistBlockedOutputToSession;
exports.prepareSessionHistoryTransactionsForRun = prepareSessionHistoryTransactionsForRun;
exports.captureSessionHistoryTransactionInputItems = captureSessionHistoryTransactionInputItems;
exports.markSessionHistoryTransactionInputPersisted = markSessionHistoryTransactionInputPersisted;
exports.releaseUnusedSessionHistoryTransactionBinding = releaseUnusedSessionHistoryTransactionBinding;
exports.releaseProvisionalSessionHistoryTransactionBinding = releaseProvisionalSessionHistoryTransactionBinding;
exports.createSessionPersistenceTracker = createSessionPersistenceTracker;
exports.mapOwnedInputItemsAfterContextProcessing = mapOwnedInputItemsAfterContextProcessing;
exports.saveToSession = saveToSession;
exports.saveStreamInputToSession = saveStreamInputToSession;
exports.saveStreamResultToSession = saveStreamResultToSession;
exports.reconcileLegacyCompactionSessionBeforeResume = reconcileLegacyCompactionSessionBeforeResume;
exports.prepareInputItemsWithSession = prepareInputItemsWithSession;
const errors_1 = require("../errors.js");
const session_1 = require("../memory/session.js");
const runState_1 = require("../runState.js");
const protocol_1 = require("../types/protocol.js");
const usage_1 = require("../usage.js");
const items_1 = require("./items.js");
const logger_1 = __importStar(require("../logger.js"));
const usageTracking_1 = require("./usageTracking.js");
const blockedOutputPersistence_1 = require("./blockedOutputPersistence.js");
const sessionItems_1 = require("./sessionItems.js");
var blockedOutputPersistence_2 = require("./blockedOutputPersistence.js");
Object.defineProperty(exports, "selectRunItemIndexesForBlockedOutput", { enumerable: true, get: function () { return blockedOutputPersistence_2.selectRunItemIndexesForBlockedOutput; } });
const SESSION_LIMIT_UNSET = Symbol('sessionLimitUnset');
// Ownership survives same-live resume, but never RunState serialization or a different session.
const sessionCompactionStates = new WeakMap();
function getSessionCompactionState(session, state) {
    if (!(0, session_1.isOpenAIResponsesCompactionOwnershipAwareSession)(session)) {
        return undefined;
    }
    const existing = state && sessionCompactionStates.get(state);
    if (existing?.session === session) {
        return existing;
    }
    const binding = { session, ownership: null };
    if (state) {
        sessionCompactionStates.set(state, binding);
    }
    return binding;
}
function bindSessionCompactionState(state, binding) {
    if (binding) {
        sessionCompactionStates.set(state, binding);
    }
}
/** Capture final input now, but authorize compaction only after the response succeeds. */
function prepareSessionCompactionExchange(session, state, input) {
    const binding = getSessionCompactionState(session, state);
    if (!binding) {
        return () => { };
    }
    binding.modelExchange = undefined;
    const snapshot = structuredClone(input);
    const reasoningItemIdPolicy = state._reasoningItemIdPolicy;
    return (output, responseId) => {
        binding.modelExchange = {
            items: [...snapshot, ...structuredClone(output)],
            responseId,
            reasoningItemIdPolicy,
        };
    };
}
async function getSessionItems(session, runContext, limit = SESSION_LIMIT_UNSET) {
    if (runContext && (0, session_1.isRunContextAwareSession)(session)) {
        return session.getItems(limit === SESSION_LIMIT_UNSET ? undefined : limit, runContext);
    }
    return limit === SESSION_LIMIT_UNSET
        ? session.getItems()
        : session.getItems(limit);
}
async function addSessionItems(session, items, runContext, compactionState) {
    if ((0, session_1.isOpenAIResponsesCompactionOwnershipAwareSession)(session)) {
        await session.addItemsWithCompactionOwnership(items, compactionState?.session === session ? compactionState.ownership : null, runContext);
        return;
    }
    if (runContext && (0, session_1.isRunContextAwareSession)(session)) {
        await session.addItems(items, runContext);
        return;
    }
    await session.addItems(items);
}
async function clearSession(session, runContext) {
    if (runContext && (0, session_1.isRunContextAwareSession)(session)) {
        await session.clearSession(runContext);
        return;
    }
    await session.clearSession();
}
function canonicalizeSessionHistoryTransaction(transaction) {
    let decoded;
    try {
        const encoded = JSON.stringify(transaction);
        if (encoded === undefined) {
            throw new Error('Missing JSON transaction.');
        }
        decoded = JSON.parse(encoded);
    }
    catch {
        throw new errors_1.UserError('Session history transaction cannot be represented in durable RunState JSON.');
    }
    if (!decoded || typeof decoded !== 'object') {
        throw new errors_1.UserError('Session history transaction is invalid.');
    }
    const record = decoded;
    const parseItems = (value) => {
        if (!Array.isArray(value)) {
            throw new errors_1.UserError('Session history transaction items are invalid.');
        }
        return value.map((item) => protocol_1.ModelItem.parse(item));
    };
    if (record.type === 'append_items') {
        return {
            type: record.type,
            items: parseItems(record.items),
        };
    }
    if (record.type === 'replace_suffix') {
        return {
            type: record.type,
            expectedSuffix: parseItems(record.expectedSuffix),
            replacement: parseItems(record.replacement),
        };
    }
    throw new errors_1.UserError('Session history transaction is invalid.');
}
function getRunItemIndexesForPendingTransaction(state, runItems) {
    const indexes = runItems.map((item) => state._generatedItems.indexOf(item));
    if (indexes.some((index) => index < 0) ||
        new Set(indexes).size !== indexes.length) {
        throw new errors_1.UserError('Session history transaction run items do not belong to the current RunState.');
    }
    return indexes;
}
function getSessionHistoryTransactionOperationId(state, transactionKind, alreadyPersistedCount, persistedItemCount) {
    return [
        state._sessionHistoryTransactionId,
        state._currentTurn,
        transactionKind,
        alreadyPersistedCount,
        persistedItemCount,
    ].join(':');
}
function buildPendingSessionHistoryTransaction(state) {
    const pending = state._pendingSessionHistoryTransaction;
    if (!pending) {
        throw new errors_1.UserError('Session history transaction state is missing.');
    }
    const reasoningItemIdPolicy = state._currentTurnSessionReasoningItemIdPolicy;
    if (reasoningItemIdPolicy === undefined) {
        throw new errors_1.UserError('Session history transaction reasoning-item policy is missing.');
    }
    const runItems = pending.runItemIndexes.map((index) => state._generatedItems[index]);
    const replacementItems = pending.replaceRunItemIndexes.map((index) => state._generatedItems[index]);
    const items = (0, sessionItems_1.normalizeItemsForSessionPersistence)([
        ...(state._currentTurnSessionHistoryTransactionInputItems ?? []),
        ...(0, items_1.extractOutputItemsFromRunItems)(runItems, reasoningItemIdPolicy),
    ]);
    if (pending.transactionKind === 'blocked_append') {
        if (items.length === 0) {
            throw new errors_1.UserError('Pending blocked session history transaction cannot be empty.');
        }
        return canonicalizeSessionHistoryTransaction({
            type: 'append_items',
            items,
        });
    }
    const expectedSuffix = (0, sessionItems_1.normalizeItemsForSessionPersistence)((0, items_1.extractOutputItemsFromRunItems)(replacementItems, reasoningItemIdPolicy));
    if (expectedSuffix.length === 0 || items.length === 0) {
        throw new errors_1.UserError('Pending accepted session history transaction requires a non-empty suffix and replacement.');
    }
    return canonicalizeSessionHistoryTransaction({
        type: 'replace_suffix',
        expectedSuffix,
        replacement: items,
    });
}
function getEffectiveSessionReasoningItemIdPolicy(session, state) {
    return session.preserveReasoningItemIdsForPersistence?.() === true
        ? 'preserve'
        : (state._reasoningItemIdPolicy ?? 'preserve');
}
function getComparableSessionItems(session, items) {
    const detachedItems = structuredClone(items);
    return structuredClone(session.prepareHistoryItemsForPersistenceComparison?.(detachedItems) ??
        detachedItems);
}
async function prepareResumedSessionWrite(session, state) {
    if (state._pendingSessionWrite !== undefined) {
        throw new errors_1.UserError('A pending Session write must be reconciled before another append is prepared.');
    }
    if (!state._resumedSessionWriteInProgress) {
        throw new errors_1.UserError('A resumed Session append requires exclusive ownership of its RunState.');
    }
    if (state._currentStep?.type !== 'next_step_interruption') {
        throw new errors_1.UserError('Only interrupted tool work can prepare a resumed Session append.');
    }
    const sessionId = await session.getSessionId();
    if (sessionId.length === 0) {
        throw new errors_1.UserError('Cannot prepare a Session append without a session ID.');
    }
    return {
        session,
        state,
        sessionId,
        reasoningItemIdPolicy: getEffectiveSessionReasoningItemIdPolicy(session, state),
    };
}
function acquireResumedSessionWriteOperation(state) {
    if (state._resumedSessionWriteInProgress) {
        throw new errors_1.UserError('The same RunState cannot resume or reconcile a Session write concurrently.');
    }
    state._resumedSessionWriteInProgress = true;
    let released = false;
    return () => {
        if (!released) {
            released = true;
            state._resumedSessionWriteInProgress = false;
        }
    };
}
function checkpointPreparedResumedSessionWrite(options) {
    const { session, state, preparation, items, alreadyPersistedCount, persistedItemCount, reasoningItemIdPolicy, } = options;
    if (!state._resumedSessionWriteInProgress) {
        throw new errors_1.UserError('A resumed Session append requires exclusive ownership of its RunState.');
    }
    if (preparation.session !== session || preparation.state !== state) {
        throw new errors_1.UserError('Resumed Session write preparation belongs to a different runtime operation.');
    }
    if (state._pendingSessionWrite !== undefined ||
        state._generatedItems.length !== persistedItemCount ||
        persistedItemCount <= alreadyPersistedCount ||
        items.length === 0 ||
        preparation.reasoningItemIdPolicy !== reasoningItemIdPolicy) {
        throw new errors_1.UserError('Resumed Session write preparation is stale.');
    }
    if (state._currentStep?.type !== 'next_step_run_again' &&
        state._currentStep?.type !== 'next_step_interruption' &&
        !(0, blockedOutputPersistence_1.hasTerminalToolOutputSource)(state)) {
        throw new errors_1.UserError('Only resumed tool work awaiting another model turn, approval, or terminal tool finalization can checkpoint a Session append.');
    }
    const pendingItems = {
        sessionId: preparation.sessionId,
        alreadyPersistedCount,
        persistedItemCount,
        reasoningItemIdPolicy,
    };
    const reconstructedItems = (0, runState_1.getPendingSessionWriteAppendItems)(state, pendingItems);
    if (reconstructedItems.length !== items.length ||
        !(0, sessionItems_1.agentItemRangeMatches)(reconstructedItems, items, 0)) {
        throw new errors_1.UserError('Resumed Session write items do not match their canonical RunState owners.');
    }
    const pending = {
        phase: 'prepared',
        ...pendingItems,
        handoffInput: preparation.handoffInput,
        terminalToolFinalization: (0, runState_1.capturePendingSessionWriteTerminalFinalization)(state),
    };
    state._pendingSessionWrite = structuredClone(pending);
    (0, runState_1.assertPendingSessionWriteOwnership)(state, pending);
    return pending;
}
function promotePreparedSessionWrite(session, state, storedItems) {
    const pending = state._pendingSessionWrite;
    if (pending?.phase !== 'prepared') {
        throw new errors_1.UserError('Prepared Session write state is missing.');
    }
    (0, runState_1.assertPendingSessionWriteOwnership)(state, pending);
    const appendItems = (0, runState_1.getPendingSessionWriteAppendItems)(state, pending);
    const beforeItems = getComparableSessionItems(session, storedItems);
    const comparableAppendItems = getComparableSessionItems(session, appendItems);
    const combinedItems = getComparableSessionItems(session, [
        ...storedItems,
        ...appendItems,
    ]);
    const expectedCombinedItems = [...beforeItems, ...comparableAppendItems];
    if (beforeItems.length !== storedItems.length ||
        comparableAppendItems.length !== appendItems.length ||
        combinedItems.length !== storedItems.length + appendItems.length) {
        throw new errors_1.UserError('Session persistence comparison must preserve stored item boundaries.');
    }
    if (!(0, sessionItems_1.sessionItemArraysMatch)(combinedItems, expectedCombinedItems)) {
        throw new errors_1.UserError('Session history changed before a prepared resumed write could be completed safely.');
    }
    const appendReady = {
        ...pending,
        phase: 'append_ready',
        beforeItems,
        comparableAppendItems,
    };
    state._pendingSessionWrite = structuredClone(appendReady);
    (0, runState_1.assertPendingSessionWriteOwnership)(state, appendReady);
    return appendReady;
}
async function appendPreparedResumedSessionWrite(options) {
    const { session, state, preparation } = options;
    const sessionId = await session.getSessionId();
    if (sessionId !== preparation.sessionId) {
        throw new errors_1.UserError('A prepared Session write belongs to a different session and cannot be resumed safely.');
    }
    const storedItems = await getSessionItems(session, state._context);
    const pending = promotePreparedSessionWrite(session, state, storedItems);
    await addSessionItems(session, (0, runState_1.getPendingSessionWriteAppendItems)(state, pending), state._context, getSessionCompactionState(session, state));
}
async function reconcilePendingSessionWriteBeforeRun(session, state, options) {
    const pending = state._pendingSessionWrite;
    if (pending === undefined) {
        return false;
    }
    if (options.operationAlreadyOwned === true &&
        !state._resumedSessionWriteInProgress) {
        throw new errors_1.UserError('Pending Session write reconciliation lost exclusive RunState ownership.');
    }
    const releaseOperation = options.operationAlreadyOwned === true
        ? undefined
        : acquireResumedSessionWriteOperation(state);
    try {
        (0, runState_1.assertPendingSessionWriteOwnership)(state, pending);
        if (options.serverManagesConversation || session === undefined) {
            throw new errors_1.UserError('A pending Session write requires the same ordinary local Session to resume safely.');
        }
        if (pending.phase === 'compaction_pending') {
            await completePendingApprovedToolInputCompaction(session, state);
            return true;
        }
        if (getEffectiveSessionReasoningItemIdPolicy(session, state) !==
            pending.reasoningItemIdPolicy) {
            throw new errors_1.UserError('Session persistence policy changed while a resumed write was pending.');
        }
        if (state._currentTurnSessionHistoryTransactionSessionId !== undefined &&
            !(0, session_1.isSessionHistoryTransactionAwareSession)(session)) {
            throw new errors_1.UserError('A pending transaction-aware Session write requires the same transaction-aware local Session to resume safely.');
        }
        const appendItems = (0, runState_1.getPendingSessionWriteAppendItems)(state, pending);
        if (pending.phase === 'append_ready') {
            const comparableAppendItems = getComparableSessionItems(session, appendItems);
            if (pending.comparableAppendItems.length !== appendItems.length ||
                comparableAppendItems.length !== appendItems.length ||
                !(0, sessionItems_1.sessionItemArraysMatch)(comparableAppendItems, pending.comparableAppendItems)) {
                throw new errors_1.UserError('RunState pending Session write comparison evidence does not match the runtime Session.');
            }
        }
        const sessionId = await session.getSessionId();
        if (sessionId !== pending.sessionId) {
            throw new errors_1.UserError('A pending Session write belongs to a different session and cannot be resumed safely.');
        }
        const storedItems = await getSessionItems(session, state._context);
        const currentItems = getComparableSessionItems(session, storedItems);
        if (currentItems.length !== storedItems.length) {
            throw new errors_1.UserError('Session persistence comparison must preserve stored item boundaries.');
        }
        const appendReady = pending.phase === 'prepared'
            ? promotePreparedSessionWrite(session, state, storedItems)
            : pending;
        const expectedAfterItems = [
            ...appendReady.beforeItems,
            ...appendReady.comparableAppendItems,
        ];
        if ((0, sessionItems_1.sessionItemArraysMatch)(currentItems, appendReady.beforeItems)) {
            await addSessionItems(session, appendItems, state._context, getSessionCompactionState(session, state));
        }
        else if (!(0, sessionItems_1.sessionItemArraysMatch)(currentItems, expectedAfterItems)) {
            throw new errors_1.UserError('Session history changed while a resumed write was unacknowledged and cannot be reconciled safely.');
        }
        commitSessionPersistenceState({
            state,
            persistedItemCount: pending.persistedItemCount,
            deferredRunItemIndexes: [],
        });
        markPendingApprovedToolInputCompaction(state);
        await completePendingApprovedToolInputCompaction(session, state);
        return true;
    }
    finally {
        releaseOperation?.();
    }
}
function selectRunItemsForBlockedOutput(items, unpersistedStartIndex = 0) {
    return (0, blockedOutputPersistence_1.selectRunItemIndexesForBlockedOutput)(items, unpersistedStartIndex).map((index) => items[index]);
}
function canPersistBlockedOutputToSession(session, state) {
    return ((0, session_1.isSessionHistoryTransactionAwareSession)(session) &&
        (0, blockedOutputPersistence_1.selectRunItemIndexesForBlockedOutput)(state._generatedItems, state._currentTurnPersistedItemCount).length > 0);
}
async function prepareSessionHistoryTransactionsForRun(session, state, options) {
    const boundSessionId = state._currentTurnSessionHistoryTransactionSessionId;
    const hasTransactionAuthority = boundSessionId !== undefined ||
        state._pendingSessionHistoryTransaction !== undefined ||
        state._currentTurnDeferredSessionItemIndexes.size > 0;
    if (hasTransactionAuthority &&
        state._pendingLegacyCompactionSessionItems !== undefined) {
        throw new errors_1.UserError('RunState cannot combine legacy compaction reconciliation with output guardrail transaction authority.');
    }
    if (!hasTransactionAuthority) {
        await reconcileLegacyCompactionSessionBeforeResume(session, state);
    }
    if (options.serverManagesConversation ||
        !(0, session_1.isSessionHistoryTransactionAwareSession)(session)) {
        if (hasTransactionAuthority) {
            throw new errors_1.UserError('Output guardrail session persistence must resume with the same transaction-aware local session.');
        }
        return;
    }
    const sessionId = await session.getSessionId();
    if (boundSessionId !== undefined && boundSessionId !== sessionId) {
        throw new errors_1.UserError('Output guardrail session persistence belongs to a different session and cannot be resumed safely.');
    }
    state._currentTurnSessionHistoryTransactionSessionId = sessionId;
    state._currentTurnSessionReasoningItemIdPolicy ??=
        getEffectiveSessionReasoningItemIdPolicy(session, state);
    state._currentTurnSessionHistoryTransactionInputItems ??= [];
    await flushPendingSessionHistoryTransaction(session, state);
    await assertBlockedSessionSuffixMatches(session, state);
}
function captureSessionHistoryTransactionInputItems(session, state, items) {
    if (session === undefined) {
        state._currentTurnSessionHistoryTransactionInputItems =
            (0, sessionItems_1.normalizeItemsForSessionPersistence)(items ?? []);
        return;
    }
    if (!(0, session_1.isSessionHistoryTransactionAwareSession)(session)) {
        return;
    }
    if (state._currentTurnSessionHistoryTransactionSessionId === undefined) {
        return;
    }
    state._currentTurnSessionHistoryTransactionInputItems =
        (0, sessionItems_1.normalizeItemsForSessionPersistence)(items ?? []);
}
function markSessionHistoryTransactionInputPersisted(state) {
    if (state._currentTurnSessionHistoryTransactionInputItems !== undefined) {
        state._currentTurnSessionHistoryTransactionInputItems = [];
    }
}
function releaseUnusedSessionHistoryTransactionBinding(state) {
    if (state._pendingSessionHistoryTransaction !== undefined ||
        state._currentTurnBlockedSessionStartIndex !== undefined ||
        state._currentTurnDeferredSessionItemIndexes.size > 0 ||
        (0, blockedOutputPersistence_1.hasBlockedOutputExecutionEffect)(state._generatedItems, state._currentTurnPersistedItemCount)) {
        return;
    }
    clearSessionHistoryTransactionBinding(state);
}
function releaseProvisionalSessionHistoryTransactionBinding(state, provisionalSessionId, portableInputItems) {
    if (provisionalSessionId === undefined ||
        state._currentTurnSessionHistoryTransactionSessionId !==
            provisionalSessionId ||
        state._pendingSessionHistoryTransaction !== undefined ||
        state._currentTurnBlockedSessionStartIndex !== undefined ||
        state._currentTurnDeferredSessionItemIndexes.size > 0) {
        return;
    }
    clearSessionHistoryTransactionBinding(state);
    state._currentTurnSessionHistoryTransactionInputItems = portableInputItems;
}
function clearSessionHistoryTransactionBinding(state) {
    state._currentTurnSessionHistoryTransactionSessionId = undefined;
    state._currentTurnSessionReasoningItemIdPolicy = undefined;
    state._currentTurnSessionHistoryTransactionInputItems = undefined;
    state._currentTurnSessionHistoryTransactionCanReplaceAcceptedOutput =
        undefined;
}
function commitSessionPersistenceState(options) {
    const { state, persistedItemCount, deferredRunItemIndexes } = options;
    state._currentTurnPersistedItemCount = persistedItemCount;
    if (state._currentTurnSessionWriteCompactedItemCount !== persistedItemCount) {
        state._currentTurnSessionWriteCompactedItemCount = undefined;
    }
    state._currentTurnDeferredSessionItemIndexes = new Set(deferredRunItemIndexes);
    if (deferredRunItemIndexes.length === 0) {
        state._currentTurnBlockedSessionStartIndex = undefined;
        clearSessionHistoryTransactionBinding(state);
    }
}
function markPendingApprovedToolInputCompaction(state) {
    const pending = state._pendingSessionWrite;
    if (pending?.phase !== 'append_ready') {
        throw new errors_1.UserError('A settled resumed Session append is missing its compaction authority.');
    }
    const { beforeItems: _beforeItems, comparableAppendItems: _comparableAppendItems, ...ownedCompaction } = pending;
    state._currentTurnSessionWriteCompactedItemCount = undefined;
    state._pendingSessionWrite = {
        ...ownedCompaction,
        phase: 'compaction_pending',
    };
    (0, runState_1.assertPendingSessionWriteOwnership)(state, state._pendingSessionWrite);
}
function commitApprovedToolInputCompaction(state, persistedItemCount) {
    const handoffInput = state._pendingSessionWrite?.handoffInput;
    if (handoffInput) {
        const input = state._deserializeHandoffInput(handoffInput);
        state._originalInput = input.originalInput;
        state._replaceGeneratedItems(input.generatedItems);
        state._currentTurnPersistedItemCount = input.generatedItems.length;
    }
    state._currentTurnSessionWriteCompactedItemCount = handoffInput
        ? state._generatedItems.length
        : persistedItemCount;
    state._pendingSessionWrite = undefined;
    (0, runState_1.clearPendingSessionWriteTerminalProducer)(state);
}
async function completePendingApprovedToolInputCompaction(session, state) {
    const pending = state._pendingSessionWrite;
    if (pending?.phase !== 'compaction_pending') {
        throw new errors_1.UserError('Pending Session compaction authority is missing.');
    }
    (0, runState_1.assertPendingSessionWriteOwnership)(state, pending);
    if (getEffectiveSessionReasoningItemIdPolicy(session, state) !==
        pending.reasoningItemIdPolicy) {
        throw new errors_1.UserError('Session persistence policy changed while compaction was pending.');
    }
    if ((await session.getSessionId()) !== pending.sessionId) {
        throw new errors_1.UserError('A pending Session compaction belongs to a different session and cannot be resumed safely.');
    }
    await runCompactionOnSession(session, undefined, state, 'input');
    commitApprovedToolInputCompaction(state, pending.persistedItemCount);
}
async function assertBlockedSessionSuffixMatches(session, state) {
    const blockedStartIndex = state._currentTurnBlockedSessionStartIndex;
    if (blockedStartIndex === undefined) {
        return;
    }
    const canReplaceAcceptedOutput = state._currentTurnSessionHistoryTransactionCanReplaceAcceptedOutput;
    if (canReplaceAcceptedOutput !== true) {
        throw new errors_1.UserError('Accepted output cannot replace a sparse session suffix created from a serialized final step. Start a new run from the persisted session history.');
    }
    const reasoningItemIdPolicy = state._currentTurnSessionReasoningItemIdPolicy;
    if (reasoningItemIdPolicy === undefined) {
        throw new errors_1.UserError('Blocked session history replacement authority is incomplete.');
    }
    const hasDeferredItems = state._currentTurnDeferredSessionItemIndexes.size > 0;
    const plan = hasDeferredItems
        ? buildRunItemPersistencePlan(state, state._generatedItems, false, true)
        : undefined;
    if (hasDeferredItems && plan?.transactionKind !== 'accepted_replace') {
        throw new errors_1.UserError('Blocked session history replacement authority is incomplete.');
    }
    const suffixRunItems = hasDeferredItems
        ? plan.runItemsToReplace
        : state._generatedItems.slice(blockedStartIndex, state._currentTurnPersistedItemCount);
    const expectedSuffix = (0, sessionItems_1.normalizeItemsForSessionPersistence)((0, items_1.extractOutputItemsFromRunItems)(suffixRunItems, reasoningItemIdPolicy));
    const currentItems = await getSessionItems(session, state._context);
    const comparableCurrentItems = session.prepareHistoryItemsForPersistenceComparison?.(currentItems) ??
        currentItems;
    const comparableExpectedSuffix = session.prepareHistoryItemsForPersistenceComparison?.(expectedSuffix) ??
        expectedSuffix;
    if (comparableExpectedSuffix.length === 0 ||
        !(0, sessionItems_1.agentItemRangeMatches)(comparableCurrentItems, comparableExpectedSuffix, comparableCurrentItems.length - comparableExpectedSuffix.length)) {
        throw new errors_1.UserError('Session history suffix no longer matches the transaction precondition.');
    }
}
function buildRunItemPersistencePlan(state, items, outputBlocked, canUseHistoryTransactions) {
    const blockedSnapshot = outputBlocked
        ? (0, blockedOutputPersistence_1.getBlockedOutputSessionSnapshotRunItems)(state)
        : [];
    const blockedSnapshotStart = state._generatedItems.length - blockedSnapshot.length;
    return (0, blockedOutputPersistence_1.buildRunItemPersistencePlan)({
        items,
        alreadyPersistedCount: state._currentTurnPersistedItemCount ?? 0,
        currentDeferredIndexes: state._currentTurnDeferredSessionItemIndexes,
        outputBlocked,
        canUseHistoryTransactions,
        blockedSnapshot: blockedSnapshot.length > 0 ||
            (outputBlocked &&
                canUseHistoryTransactions &&
                items.length === (state._currentTurnPersistedItemCount ?? 0))
            ? {
                items: canUseHistoryTransactions
                    ? state._generatedItems.slice(blockedSnapshotStart)
                    : blockedSnapshot,
                startIndex: blockedSnapshotStart,
                alreadyPersistedCount: state._currentTurnBlockedSessionStartIndex ??
                    state._currentTurnPersistedItemCount,
            }
            : undefined,
    });
}
async function persistSessionRunItemPlan(options) {
    const { session, state, persistencePlan, sessionInputItems, lastResponseId, persistenceOptions, } = options;
    if (persistenceOptions.outputBlocked === true &&
        persistencePlan.useHistoryTransaction &&
        persistencePlan.runItemsToPersist.length === 0 &&
        (sessionInputItems?.length ?? 0) === 0) {
        await prepareSessionHistoryTransactionsForRun(session, state, {
            serverManagesConversation: false,
        });
        return;
    }
    await persistRunItemsToSession({
        session,
        state,
        newRunItems: persistencePlan.runItemsToPersist,
        runItemsToReplace: persistencePlan.runItemsToReplace,
        processedRunItemCount: persistencePlan.processedRunItemCount,
        deferredRunItemIndexes: persistencePlan.deferredRunItemIndexes,
        useHistoryTransaction: persistencePlan.useHistoryTransaction,
        transactionKind: persistencePlan.transactionKind,
        extraInputItems: sessionInputItems,
        lastResponseId: persistenceOptions.outputBlocked
            ? undefined
            : lastResponseId,
        alreadyPersistedCount: persistencePlan.alreadyPersistedCount,
        runCompaction: persistenceOptions.outputBlocked === true
            ? false
            : (persistenceOptions.runCompaction ?? true),
        compactionMode: persistenceOptions.compactionMode,
        resumedSessionWritePreparation: persistenceOptions.resumedSessionWritePreparation,
        deferResumedSessionWrite: persistenceOptions.deferResumedSessionWrite === true,
    });
}
class SessionReconciliationRecoveryError extends Error {
    primaryError;
    rollbackError;
    errors;
    cause;
    constructor(primaryError, rollbackError) {
        super('Failed to reconcile legacy compaction session history and restore the previous session contents.');
        this.primaryError = primaryError;
        this.rollbackError = rollbackError;
        this.name = 'SessionReconciliationRecoveryError';
        this.errors = [primaryError, rollbackError];
        this.cause = primaryError;
    }
}
function createSessionPersistenceTracker(options) {
    class SessionPersistenceTrackerImpl {
        session;
        runContext;
        hasCallModelInputFilter;
        persistInput;
        originalSnapshot;
        filteredSnapshot;
        preparedSources;
        initialPreparedItems;
        initialSourcePositions;
        ownedFilteredItems = new Map();
        persistedInputOrder = [];
        persistedInput = false;
        constructor() {
            this.session = options.session;
            this.runContext = options.runContext;
            this.hasCallModelInputFilter = options.hasCallModelInputFilter;
            this.persistInput = options.persistInput;
            this.originalSnapshot = options.resumingFromState
                ? cloneItems(options.resumedSessionInputItems ?? [])
                : undefined;
            this.filteredSnapshot = options.resumedSessionInputItems
                ? cloneItems(options.resumedSessionInputItems)
                : undefined;
            this.preparedSources = options.resumingFromState ? [] : undefined;
            this.initialPreparedItems = options.resumingFromState ? [] : undefined;
            this.initialSourcePositions = options.resumingFromState ? [] : undefined;
        }
        setPreparedItems = (items, preparedInput) => {
            const sessionItems = items ??
                (this.session === undefined && preparedInput !== undefined
                    ? (0, items_1.toAgentInputList)(preparedInput)
                    : []);
            this.originalSnapshot = cloneItems((0, items_1.deduplicateAgentInputItemsPreferringLatest)(sessionItems));
            if (Array.isArray(preparedInput)) {
                this.preparedSources = undefined;
                this.initialPreparedItems = preparedInput;
                this.initialSourcePositions = findOwnedItemIndexes(preparedInput, sessionItems);
            }
            else if (typeof preparedInput === 'string') {
                this.preparedSources = undefined;
                this.initialPreparedItems = sessionItems;
                this.initialSourcePositions = findOwnedItemIndexes(sessionItems, sessionItems);
            }
            else {
                this.preparedSources = sessionItems.map((item, ownerIndex) => ({
                    item,
                    ownerIndex,
                }));
                this.initialPreparedItems = undefined;
                this.initialSourcePositions = undefined;
            }
            this.ownedFilteredItems.clear();
            this.persistedInputOrder = [];
        };
        setPreparedTurnItems = (preparedItems, processedItems) => {
            if (!this.initialPreparedItems || !this.initialSourcePositions) {
                return;
            }
            const preparedSources = mapPreparedSourcesAfterContextProcessing(this.initialPreparedItems, preparedItems, this.initialSourcePositions, { validateReplacements: false });
            this.preparedSources = mapPreparedSourcesAfterContextProcessing(preparedItems, processedItems, findPreparedSourcePositions(preparedItems, preparedSources));
        };
        recordTurnItems = (sourceItems, filteredItems) => {
            if (filteredItems !== undefined) {
                if (!this.preparedSources) {
                    this.filteredSnapshot = cloneItems(filteredItems);
                    return;
                }
                const next = reconcilePersistableFilteredItems({
                    preparedSources: this.preparedSources,
                    sourceItems,
                    filteredItems,
                    ownedFilteredItems: this.ownedFilteredItems,
                    persistedInputOrder: this.persistedInputOrder,
                });
                this.ownedFilteredItems = next.ownedFilteredItems;
                this.persistedInputOrder = next.persistedInputOrder;
                this.filteredSnapshot = next.filteredSnapshot;
                return;
            }
            this.filteredSnapshot = buildSnapshotForUnfilteredItems({
                preparedSourceCounts: this.preparedSources
                    ? countItemReferences(this.preparedSources.map((source) => source.item))
                    : undefined,
                sourceItems,
                existingSnapshot: this.filteredSnapshot,
            });
        };
        getItemsForPersistence = () => {
            if (this.filteredSnapshot !== undefined) {
                return this.filteredSnapshot;
            }
            if (this.hasCallModelInputFilter) {
                return undefined;
            }
            return this.originalSnapshot;
        };
        buildPersistInputOnce = (serverManagesConversation) => {
            if (!this.session || serverManagesConversation) {
                return undefined;
            }
            const persistInput = this.persistInput ?? saveStreamInputToSession;
            return async () => {
                if (this.persistedInput) {
                    return;
                }
                const itemsToPersist = this.getItemsForPersistence();
                if (!itemsToPersist || itemsToPersist.length === 0) {
                    return;
                }
                this.persistedInput = true;
                if (options.compactionState) {
                    await persistInput(this.session, itemsToPersist, this.runContext, options.compactionState);
                }
                else {
                    await persistInput(this.session, itemsToPersist, this.runContext);
                }
            };
        };
    }
    return new SessionPersistenceTrackerImpl();
}
function cloneItems(items) {
    return items.map((item) => structuredClone(item));
}
function countItemReferences(items) {
    const counts = new Map();
    for (const item of items) {
        counts.set(item, (counts.get(item) ?? 0) + 1);
    }
    return counts;
}
function findOwnedItemIndexes(preparedInput, ownedItems) {
    const remainingOwnerIndexes = new Map();
    for (const [ownerIndex, item] of ownedItems.entries()) {
        const indexes = remainingOwnerIndexes.get(item) ?? [];
        indexes.push(ownerIndex);
        remainingOwnerIndexes.set(item, indexes);
    }
    const positions = [];
    for (const [index, item] of preparedInput.entries()) {
        const ownerIndex = remainingOwnerIndexes.get(item)?.shift();
        if (ownerIndex === undefined) {
            continue;
        }
        positions.push({ preparedIndex: index, ownerIndex });
    }
    return positions;
}
function findPreparedSourcePositions(preparedItems, preparedSources) {
    const remainingOwnerIndexes = new Map();
    for (const source of preparedSources) {
        const indexes = remainingOwnerIndexes.get(source.item) ?? [];
        indexes.push(source.ownerIndex);
        remainingOwnerIndexes.set(source.item, indexes);
    }
    const positions = [];
    for (const [preparedIndex, item] of preparedItems.entries()) {
        const ownerIndex = remainingOwnerIndexes.get(item)?.shift();
        if (ownerIndex !== undefined) {
            positions.push({ preparedIndex, ownerIndex });
        }
    }
    return positions;
}
function mapPreparedSourcesAfterContextProcessing(preparedItems, processedItems, preparedSourcePositions, options = {}) {
    const ownerIndexByPreparedIndex = new Map(preparedSourcePositions.map(({ preparedIndex, ownerIndex }) => [
        preparedIndex,
        ownerIndex,
    ]));
    const preparedIndexesByReference = new Map();
    const preparedIndexesByKey = new Map();
    for (const [index, item] of preparedItems.entries()) {
        const referenceIndexes = preparedIndexesByReference.get(item) ?? [];
        referenceIndexes.push(index);
        preparedIndexesByReference.set(item, referenceIndexes);
        const key = (0, items_1.getAgentInputItemKey)(item);
        const keyIndexes = preparedIndexesByKey.get(key) ?? [];
        keyIndexes.push(index);
        preparedIndexesByKey.set(key, keyIndexes);
    }
    const mappedPreparedIndexes = new Array(processedItems.length);
    const usedPreparedIndexes = new Set();
    const ambiguousKeys = new Set();
    const ambiguousProcessedIndexes = new Set();
    const mapOccurrences = (processedIndexesByIdentity, preparedIndexesByIdentity) => {
        for (const [identity, processedIndexes] of processedIndexesByIdentity) {
            const availablePreparedIndexes = (preparedIndexesByIdentity.get(identity) ?? []).filter((index) => !usedPreparedIndexes.has(index));
            const availableProcessedIndexes = processedIndexes.filter((index) => mappedPreparedIndexes[index] === undefined);
            for (let index = 0; index <
                Math.min(availableProcessedIndexes.length, availablePreparedIndexes.length); index++) {
                const processedIndex = availableProcessedIndexes[index];
                const preparedIndex = availablePreparedIndexes[index];
                if (processedIndex === undefined || preparedIndex === undefined) {
                    continue;
                }
                mappedPreparedIndexes[processedIndex] = preparedIndex;
                usedPreparedIndexes.add(preparedIndex);
            }
        }
    };
    const processedIndexesByReference = new Map();
    for (const [index, item] of processedItems.entries()) {
        const indexes = processedIndexesByReference.get(item) ?? [];
        indexes.push(index);
        processedIndexesByReference.set(item, indexes);
    }
    mapOccurrences(processedIndexesByReference, preparedIndexesByReference);
    const referenceMappedPreparedIndexes = new Set(usedPreparedIndexes);
    for (const [item, processedIndexes] of processedIndexesByReference) {
        const preparedIndexes = preparedIndexesByReference.get(item);
        if (preparedIndexes === undefined) {
            continue;
        }
        const preparedCount = preparedIndexes.length;
        for (const processedIndex of processedIndexes.slice(preparedCount)) {
            ambiguousKeys.add((0, items_1.getAgentInputItemKey)(item));
            ambiguousProcessedIndexes.add(processedIndex);
        }
    }
    const processedIndexesByKey = new Map();
    for (const [index, item] of processedItems.entries()) {
        if (mappedPreparedIndexes[index] !== undefined ||
            ambiguousProcessedIndexes.has(index)) {
            continue;
        }
        const key = (0, items_1.getAgentInputItemKey)(item);
        const indexes = processedIndexesByKey.get(key) ?? [];
        indexes.push(index);
        processedIndexesByKey.set(key, indexes);
    }
    const availablePreparedCountByKey = new Map();
    for (const [key, indexes] of preparedIndexesByKey) {
        availablePreparedCountByKey.set(key, indexes.filter((index) => !usedPreparedIndexes.has(index)).length);
    }
    for (const [key, indexes] of processedIndexesByKey) {
        const availablePreparedCount = availablePreparedCountByKey.get(key) ?? 0;
        if (preparedIndexesByKey.has(key) &&
            indexes.length > availablePreparedCount) {
            ambiguousKeys.add(key);
            indexes.forEach((index) => ambiguousProcessedIndexes.add(index));
        }
    }
    // Reserve unchanged positional clones before matching equal-content occurrences globally.
    // Otherwise, an earlier removed occurrence can steal a later clone's prepared position and
    // cause an injected replacement to inherit the clone's Session ownership. Equal-sized key
    // groups retain forward occurrence matching because unrelated insertions may shift the group.
    for (const [index, item] of processedItems.entries()) {
        const preparedItem = preparedItems[index];
        const key = (0, items_1.getAgentInputItemKey)(item);
        if (mappedPreparedIndexes[index] !== undefined ||
            ambiguousProcessedIndexes.has(index) ||
            preparedItem === undefined ||
            usedPreparedIndexes.has(index) ||
            key !== (0, items_1.getAgentInputItemKey)(preparedItem) ||
            (processedIndexesByKey.get(key)?.length ?? 0) >=
                (availablePreparedCountByKey.get(key) ?? 0)) {
            continue;
        }
        mappedPreparedIndexes[index] = index;
        usedPreparedIndexes.add(index);
    }
    // Public capabilities may return clones. Resolve remaining occurrences against the complete
    // prepared sequence so callback reordering and equal-content history retain their ownership.
    const matchableProcessedIndexesByKey = new Map([...processedIndexesByKey].filter(([, indexes]) => indexes.every((index) => !ambiguousProcessedIndexes.has(index))));
    mapOccurrences(matchableProcessedIndexesByKey, preparedIndexesByKey);
    const remainingProcessedIndexes = processedItems
        .map((_, index) => index)
        .filter((index) => mappedPreparedIndexes[index] === undefined &&
        !ambiguousProcessedIndexes.has(index));
    const remainingPreparedIndexes = preparedItems
        .map((_, index) => index)
        .filter((index) => !usedPreparedIndexes.has(index) &&
        !ambiguousKeys.has((0, items_1.getAgentInputItemKey)(preparedItems[index])));
    // Preserve the explicitly supported whole-context single-item rewrite. Once any surrounding
    // occurrence exists, an unmatched item could instead be a deletion plus an injection, so leave
    // it unowned rather than assigning Session provenance from matching residual cardinality alone.
    if (options.validateReplacements !== false &&
        preparedItems.length === 1 &&
        processedItems.length === 1 &&
        remainingProcessedIndexes.length === 1 &&
        remainingPreparedIndexes.length === 1) {
        const processedIndex = remainingProcessedIndexes[0];
        const preparedIndex = remainingPreparedIndexes[0];
        if (processedIndex !== undefined && preparedIndex !== undefined) {
            mappedPreparedIndexes[processedIndex] = preparedIndex;
            usedPreparedIndexes.add(preparedIndex);
        }
    }
    const hasUnmatchedProcessedItem = remainingProcessedIndexes.some((index) => mappedPreparedIndexes[index] === undefined);
    const hasUnmatchedOwnedItem = remainingPreparedIndexes.some((index) => !usedPreparedIndexes.has(index) && ownerIndexByPreparedIndex.has(index));
    const hasUnprovenOwnedClone = [...preparedIndexesByKey.values()].some((indexes) => indexes.some((index) => ownerIndexByPreparedIndex.has(index)) &&
        indexes.some((index) => !ownerIndexByPreparedIndex.has(index)) &&
        indexes.some((index) => ownerIndexByPreparedIndex.has(index) &&
            usedPreparedIndexes.has(index) &&
            !referenceMappedPreparedIndexes.has(index)) &&
        indexes.some((index) => !usedPreparedIndexes.has(index)));
    if (options.validateReplacements !== false &&
        hasUnmatchedProcessedItem &&
        (hasUnmatchedOwnedItem || hasUnprovenOwnedClone)) {
        throw new errors_1.UserError('Capability.processContext() cannot replace Session-owned input without preserving its identity. Use callModelInputFilter for persistence-aware input replacement.');
    }
    return processedItems.flatMap((item, index) => {
        const preparedIndex = mappedPreparedIndexes[index];
        const ownerIndex = preparedIndex === undefined
            ? undefined
            : ownerIndexByPreparedIndex.get(preparedIndex);
        return ownerIndex === undefined ? [] : [{ item, ownerIndex }];
    });
}
/**
 * Maps selected input occurrences through sandbox capability context processing.
 */
function mapOwnedInputItemsAfterContextProcessing(preparedItems, processedItems, ownedItems) {
    return mapPreparedSourcesAfterContextProcessing(preparedItems, processedItems, findOwnedItemIndexes(preparedItems, ownedItems));
}
function reconcilePersistableFilteredItems(options) {
    const { preparedSources, sourceItems, filteredItems, ownedFilteredItems, persistedInputOrder, } = options;
    const sourceOwnerIndexes = new Map();
    for (const source of preparedSources) {
        const ownerIndexes = sourceOwnerIndexes.get(source.item) ?? [];
        ownerIndexes.push(source.ownerIndex);
        sourceOwnerIndexes.set(source.item, ownerIndexes);
    }
    const sourceOccurrences = new Map();
    const representedOwnedIndexes = new Set();
    const currentOrder = [];
    const nextOwnedFilteredItems = new Map(ownedFilteredItems);
    for (let i = 0; i < filteredItems.length; i++) {
        const filteredItem = filteredItems[i];
        if (!filteredItem) {
            continue;
        }
        const source = sourceItems[i];
        if (source && typeof source === 'object') {
            const occurrence = sourceOccurrences.get(source) ?? 0;
            sourceOccurrences.set(source, occurrence + 1);
            const ownedIndex = sourceOwnerIndexes.get(source)?.[occurrence];
            if (ownedIndex !== undefined) {
                representedOwnedIndexes.add(ownedIndex);
                nextOwnedFilteredItems.set(ownedIndex, structuredClone(filteredItem));
                currentOrder.push({ type: 'owned', index: ownedIndex });
            }
            continue;
        }
        // Items without a source were injected by the callback. Preserve them without attempting
        // content-based identity matching, which could collapse ordinary messages.
        currentOrder.push({
            type: 'injected',
            item: structuredClone(filteredItem),
        });
    }
    const nextPersistedInputOrder = persistedInputOrder.filter((occurrence) => occurrence.type === 'owned' &&
        !representedOwnedIndexes.has(occurrence.index));
    nextPersistedInputOrder.push(...currentOrder);
    return {
        ownedFilteredItems: nextOwnedFilteredItems,
        persistedInputOrder: nextPersistedInputOrder,
        filteredSnapshot: nextPersistedInputOrder.flatMap((occurrence) => {
            if (occurrence.type === 'injected') {
                return [structuredClone(occurrence.item)];
            }
            const item = nextOwnedFilteredItems.get(occurrence.index);
            return item ? [structuredClone(item)] : [];
        }),
    };
}
function buildSnapshotForUnfilteredItems(options) {
    const { preparedSourceCounts, sourceItems, existingSnapshot } = options;
    if (!preparedSourceCounts) {
        const filtered = sourceItems
            .filter((item) => Boolean(item))
            .map((item) => structuredClone(item));
        return filtered.length > 0
            ? filtered
            : existingSnapshot === undefined
                ? []
                : existingSnapshot;
    }
    const filtered = [];
    const includedSourceCounts = new Map();
    for (const item of sourceItems) {
        if (!item) {
            continue;
        }
        const preparedOccurrences = preparedSourceCounts.get(item) ?? 0;
        const includedOccurrences = includedSourceCounts.get(item) ?? 0;
        if (includedOccurrences >= preparedOccurrences) {
            continue;
        }
        includedSourceCounts.set(item, includedOccurrences + 1);
        filtered.push(structuredClone(item));
    }
    if (filtered.length > 0) {
        return filtered;
    }
    return existingSnapshot === undefined ? [] : existingSnapshot;
}
async function saveToSession(session, sessionInputItems, result, options = {}) {
    const state = result.state;
    const additionalRunItems = options.additionalRunItems ?? [];
    if (additionalRunItems.length > 0) {
        const { additionalRunItems: _additionalRunItems, ...baseOptions } = options;
        await saveToSession(session, sessionInputItems, result, {
            ...baseOptions,
            runCompaction: false,
        });
        await persistRunItemsToSession({
            session,
            state,
            newRunItems: additionalRunItems,
            runItemsToReplace: [],
            processedRunItemCount: additionalRunItems.length,
            deferredRunItemIndexes: [],
            useHistoryTransaction: false,
            extraInputItems: [],
            lastResponseId: result.lastResponseId,
            alreadyPersistedCount: state._currentTurnPersistedItemCount,
            runCompaction: options.runCompaction ?? true,
            compactionMode: options.compactionMode,
        });
        return;
    }
    const persistencePlan = buildRunItemPersistencePlan(state, result.newItems, options.outputBlocked === true, (0, session_1.isSessionHistoryTransactionAwareSession)(session));
    if (typeof process !== 'undefined' &&
        process.env?.OPENAI_AGENTS__DEBUG_SAVE_SESSION) {
        console.debug('saveToSession:newRunItems', persistencePlan.runItemsToPersist.map((item) => item.type));
    }
    await persistSessionRunItemPlan({
        session,
        state,
        persistencePlan,
        sessionInputItems,
        lastResponseId: result.lastResponseId,
        persistenceOptions: options,
    });
}
async function saveStreamInputToSession(session, sessionInputItems, runContext, compactionState) {
    if (!session) {
        return;
    }
    if (!sessionInputItems || sessionInputItems.length === 0) {
        return;
    }
    const sanitizedInput = (0, sessionItems_1.normalizeItemsForSessionPersistence)(sessionInputItems);
    const compactedInput = (0, items_1.trimToLatestCompaction)(sanitizedInput);
    assertPersistableCompactionBoundary(compactedInput);
    if (compactedInput[0]?.type === 'compaction') {
        const previousItems = await getSessionItems(session, runContext);
        await replaceSessionItemsWithRecovery(session, previousItems, compactedInput, runContext);
        return;
    }
    await addSessionItems(session, sanitizedInput, runContext, compactionState);
}
async function saveStreamResultToSession(session, result, options = {}, sessionInputItems) {
    const state = result.state;
    const additionalRunItems = options.additionalRunItems ?? [];
    if (additionalRunItems.length > 0) {
        const { additionalRunItems: _additionalRunItems, ...baseOptions } = options;
        await saveStreamResultToSession(session, result, {
            ...baseOptions,
            runCompaction: false,
        }, sessionInputItems);
        await persistRunItemsToSession({
            session,
            state,
            newRunItems: additionalRunItems,
            runItemsToReplace: [],
            processedRunItemCount: additionalRunItems.length,
            deferredRunItemIndexes: [],
            useHistoryTransaction: false,
            extraInputItems: [],
            lastResponseId: result.lastResponseId,
            alreadyPersistedCount: state._currentTurnPersistedItemCount,
            runCompaction: options.runCompaction ?? true,
            compactionMode: options.compactionMode,
        });
        return;
    }
    const persistencePlan = buildRunItemPersistencePlan(state, result.newItems, options.outputBlocked === true, (0, session_1.isSessionHistoryTransactionAwareSession)(session));
    await persistSessionRunItemPlan({
        session,
        state,
        persistencePlan,
        sessionInputItems,
        lastResponseId: result.lastResponseId,
        persistenceOptions: options,
    });
}
async function reconcileLegacyCompactionSessionBeforeResume(session, state) {
    const pendingLegacyItems = state._pendingLegacyCompactionSessionItems;
    if (pendingLegacyItems === undefined) {
        return;
    }
    const normalizedPendingItems = (0, sessionItems_1.normalizeItemsForSessionPersistence)(pendingLegacyItems);
    assertPersistableCompactionBoundary(normalizedPendingItems);
    assertPendingLegacyCompactionItemsMatchState(state, normalizedPendingItems, undefined);
    if (!session) {
        throwLegacyCompactionReconciliationError();
    }
    const reasoningItemIdPolicy = session.preserveReasoningItemIdsForPersistence?.() === true
        ? undefined
        : state._reasoningItemIdPolicy;
    const sanitizedPendingItems = (0, sessionItems_1.normalizeItemsForSessionPersistence)(pendingLegacyItems.map((item) => (0, items_1.stripReasoningItemIdForPolicy)(item, reasoningItemIdPolicy)));
    assertPendingLegacyCompactionItemsMatchState(state, sanitizedPendingItems, reasoningItemIdPolicy);
    await reconcileLegacyCompactionSessionItems(session, sanitizedPendingItems, state._context);
    state._pendingLegacyCompactionSessionItems = undefined;
}
function assertPendingLegacyCompactionItemsMatchState(state, pendingItems, reasoningItemIdPolicy) {
    if (pendingItems.length < 2 || pendingItems[0]?.type !== 'compaction') {
        throwLegacyCompactionReconciliationError();
    }
    const persistedItemCount = state._currentTurnPersistedItemCount;
    if (!Number.isInteger(persistedItemCount) ||
        persistedItemCount < 1 ||
        persistedItemCount > state._generatedItems.length) {
        throwLegacyCompactionReconciliationError();
    }
    let matchingCandidates = 0;
    for (let index = 0; index < persistedItemCount; index += 1) {
        if (state._generatedItems[index]?.type !== 'compaction_item') {
            continue;
        }
        const candidateItems = (0, sessionItems_1.normalizeItemsForSessionPersistence)((0, items_1.extractOutputItemsFromRunItems)(state._generatedItems.slice(index, persistedItemCount), reasoningItemIdPolicy));
        if (candidateItems.length > 1 &&
            (0, sessionItems_1.agentItemRangeMatches)(candidateItems, pendingItems, 0) &&
            candidateItems.length === pendingItems.length) {
            matchingCandidates += 1;
        }
    }
    if (matchingCandidates !== 1) {
        throwLegacyCompactionReconciliationError();
    }
}
async function prepareInputItemsWithSession(input, session, sessionInputCallback, options, runContext, compactionState) {
    const newInputItems = (0, items_1.toAgentInputList)(input);
    (0, items_1.assertValidCompactionItems)(newInputItems);
    if (!session) {
        return {
            preparedInput: input,
            sessionItems: undefined,
        };
    }
    const includeHistoryInPreparedInput = options?.includeHistoryInPreparedInput ?? true;
    const preserveDroppedNewItems = options?.preserveDroppedNewItems ?? false;
    const reasoningItemIdPolicy = options?.reasoningItemIdPolicy;
    let storedItems;
    if (compactionState?.session === session &&
        (0, session_1.isOpenAIResponsesCompactionOwnershipAwareSession)(session)) {
        const snapshot = await session.getItemsWithCompactionOwnership(runContext);
        compactionState.ownership = snapshot.ownership;
        storedItems = snapshot.items;
    }
    else {
        storedItems = await getSessionItems(session, runContext);
    }
    const history = (0, items_1.trimToLatestCompaction)(storedItems);
    assertPersistableCompactionBoundary(history);
    if (!sessionInputCallback) {
        const historyForModelInput = history.map((item) => prepareHistoryItemForModelInput(session, item, reasoningItemIdPolicy));
        const preparedInput = includeHistoryInPreparedInput
            ? (0, items_1.dropOrphanToolCalls)([...historyForModelInput, ...newInputItems], {
                pruningIndexes: new Set(history.map((_, index) => index)),
            })
            : newInputItems;
        return {
            preparedInput,
            sessionItems: newInputItems,
        };
    }
    const historySnapshot = history.slice();
    const newInputSnapshot = newInputItems.slice();
    // Keep the original history objects alive so their identities remain valid even if the
    // callback removes them from the list it receives.
    const originalHistoryItems = new Set(historySnapshot);
    const combined = await sessionInputCallback(history, newInputItems);
    if (!Array.isArray(combined)) {
        throw new errors_1.UserError('Session input callback must return an array of AgentInputItem objects.');
    }
    (0, items_1.assertValidCompactionItems)(combined);
    const historyCounts = buildItemFrequencyMap(historySnapshot, {
        session,
        prepareForModelInput: true,
        reasoningItemIdPolicy,
    });
    const newInputCounts = buildItemFrequencyMap(newInputSnapshot);
    const historyRefs = (0, items_1.buildAgentInputPool)(historySnapshot);
    const newInputRefs = (0, items_1.buildAgentInputPool)(newInputSnapshot);
    const historyIndexes = new Set();
    const appended = [];
    for (const [index, item] of combined.entries()) {
        const historyKey = getHistoryItemModelInputKey(session, item, reasoningItemIdPolicy);
        const newInputKey = (0, items_1.getAgentInputItemKey)(item);
        if (originalHistoryItems.has(item)) {
            if ((0, items_1.removeAgentInputFromPool)(historyRefs, item)) {
                decrementCount(historyCounts, historyKey);
            }
            if ((0, items_1.removeAgentInputFromPool)(newInputRefs, item)) {
                decrementCount(newInputCounts, newInputKey);
            }
            historyIndexes.add(index);
            continue;
        }
        if ((0, items_1.removeAgentInputFromPool)(newInputRefs, item)) {
            decrementCount(newInputCounts, newInputKey);
            appended.push(item);
            continue;
        }
        if ((0, items_1.removeAgentInputFromPool)(historyRefs, item)) {
            decrementCount(historyCounts, historyKey);
            historyIndexes.add(index);
            continue;
        }
        const historyRemaining = historyCounts.get(historyKey) ?? 0;
        if (historyRemaining > 0) {
            historyCounts.set(historyKey, historyRemaining - 1);
            historyIndexes.add(index);
            continue;
        }
        const newRemaining = newInputCounts.get(newInputKey) ?? 0;
        if (newRemaining > 0) {
            newInputCounts.set(newInputKey, newRemaining - 1);
            appended.push(item);
            continue;
        }
        appended.push(item);
    }
    const preparedItems = includeHistoryInPreparedInput
        ? combined
        : appended.length > 0
            ? appended
            : preserveDroppedNewItems
                ? newInputSnapshot
                : [];
    if (preserveDroppedNewItems &&
        appended.length === 0 &&
        newInputSnapshot.length > 0) {
        // In server-managed conversations we cannot drop the turn delta; restore it and warn callers.
        logger_1.default.warn('sessionInputCallback dropped all new inputs in a server-managed conversation; original turn inputs were restored to avoid losing the API delta. Keep at least one new item or omit conversationId if you intended to drop them.');
    }
    const prunedPreparedItems = includeHistoryInPreparedInput
        ? (0, items_1.dropOrphanToolCalls)(prepareHistoryItemsForModelInput(session, preparedItems, historyIndexes, reasoningItemIdPolicy), { pruningIndexes: historyIndexes })
        : preparedItems;
    return {
        preparedInput: prunedPreparedItems,
        sessionItems: appended,
    };
}
function prepareHistoryItemsForModelInput(session, items, historyIndexes, reasoningItemIdPolicy) {
    if (historyIndexes.size === 0) {
        return items;
    }
    return items.map((item, index) => historyIndexes.has(index)
        ? prepareHistoryItemForModelInput(session, item, reasoningItemIdPolicy)
        : item);
}
function prepareHistoryItemForModelInput(session, item, reasoningItemIdPolicy) {
    const prepared = session.prepareHistoryItemForModelInput?.(item) ?? item;
    return (0, items_1.stripReasoningItemIdForPolicy)(prepared, reasoningItemIdPolicy);
}
function getHistoryItemModelInputKey(session, item, reasoningItemIdPolicy) {
    return (0, items_1.getAgentInputItemKey)(prepareHistoryItemForModelInput(session, item, reasoningItemIdPolicy));
}
async function persistRunItemsToSession(options) {
    const { session, state, newRunItems, runItemsToReplace, processedRunItemCount, deferredRunItemIndexes, useHistoryTransaction, transactionKind, extraInputItems = [], lastResponseId, alreadyPersistedCount, runCompaction, compactionMode, resumedSessionWritePreparation, deferResumedSessionWrite = false, } = options;
    if (!session) {
        return;
    }
    if (state._pendingLegacyCompactionSessionItems !== undefined &&
        resumedSessionWritePreparation === undefined) {
        await prepareSessionHistoryTransactionsForRun(session, state, {
            serverManagesConversation: false,
        });
    }
    const effectiveReasoningItemIdPolicy = resumedSessionWritePreparation?.reasoningItemIdPolicy ??
        getEffectiveSessionReasoningItemIdPolicy(session, state);
    const frozenReasoningItemIdPolicy = useHistoryTransaction || transactionKind === 'blocked_append'
        ? (state._currentTurnSessionReasoningItemIdPolicy ??
            effectiveReasoningItemIdPolicy)
        : effectiveReasoningItemIdPolicy;
    if (useHistoryTransaction &&
        transactionKind === 'accepted_replace' &&
        (state._currentTurnBlockedSessionStartIndex === undefined ||
            state._currentTurnSessionReasoningItemIdPolicy === undefined)) {
        throw new errors_1.UserError('Accepted session history replacement is missing its blocked-output persistence authority.');
    }
    const itemsToSave = [
        ...extraInputItems,
        ...(0, items_1.extractOutputItemsFromRunItems)(newRunItems, frozenReasoningItemIdPolicy),
    ];
    const sanitizedItems = (0, sessionItems_1.normalizeItemsForSessionPersistence)(itemsToSave);
    const compactedItems = (0, items_1.trimToLatestCompaction)(sanitizedItems);
    if (resumedSessionWritePreparation &&
        !useHistoryTransaction &&
        compactedItems[0]?.type !== 'compaction') {
        checkpointPreparedResumedSessionWrite({
            session,
            state,
            preparation: resumedSessionWritePreparation,
            items: sanitizedItems,
            alreadyPersistedCount,
            persistedItemCount: alreadyPersistedCount + processedRunItemCount,
            reasoningItemIdPolicy: frozenReasoningItemIdPolicy,
        });
        if (deferResumedSessionWrite) {
            return;
        }
        if (getEffectiveSessionReasoningItemIdPolicy(session, state) !==
            resumedSessionWritePreparation.reasoningItemIdPolicy) {
            throw new errors_1.UserError('Session persistence policy changed after resumed tool execution.');
        }
    }
    const hadPendingHistoryTransaction = state._pendingSessionHistoryTransaction !== undefined;
    await prepareSessionHistoryTransactionsForRun(session, state, {
        serverManagesConversation: false,
    });
    if (hadPendingHistoryTransaction &&
        state._pendingSessionHistoryTransaction === undefined) {
        if (runCompaction) {
            await runCompactionOnSession(session, lastResponseId, state, compactionMode);
        }
        return;
    }
    const persistedItemCount = alreadyPersistedCount + processedRunItemCount;
    const commitPersistenceState = () => {
        commitSessionPersistenceState({
            state,
            persistedItemCount,
            deferredRunItemIndexes,
        });
    };
    if (itemsToSave.length === 0) {
        const pendingApprovedToolInputCompaction = (0, blockedOutputPersistence_1.hasPendingApprovedToolInputCompaction)(state);
        if (pendingApprovedToolInputCompaction) {
            if (!runCompaction || compactionMode !== 'input') {
                throw new errors_1.UserError('Pending Session compaction must settle before other persistence work.');
            }
            await completePendingApprovedToolInputCompaction(session, state);
            return;
        }
        commitPersistenceState();
        if (runCompaction) {
            await runCompactionOnSession(session, lastResponseId, state, compactionMode);
        }
        return;
    }
    if (useHistoryTransaction) {
        if (!(0, session_1.isSessionHistoryTransactionAwareSession)(session) ||
            transactionKind === undefined ||
            state._currentTurnSessionHistoryTransactionSessionId === undefined ||
            state._currentTurnSessionReasoningItemIdPolicy === undefined) {
            throw new errors_1.UserError('Session history transaction capability was lost while persisting run items.');
        }
        const normalizedInputItems = (0, sessionItems_1.normalizeItemsForSessionPersistence)(extraInputItems);
        const frozenInputItems = state._currentTurnSessionHistoryTransactionInputItems;
        if (frozenInputItems === undefined ||
            frozenInputItems.length !== normalizedInputItems.length ||
            !(0, sessionItems_1.agentItemRangeMatches)(normalizedInputItems, frozenInputItems, 0)) {
            throw new errors_1.UserError('Session history transaction input no longer matches the pre-execution snapshot.');
        }
        const persistedItemCount = alreadyPersistedCount + processedRunItemCount;
        state._currentTurnSessionHistoryTransactionCanReplaceAcceptedOutput ??=
            state._serializedCurrentStep === undefined ||
                state._currentStep !== state._serializedCurrentStep;
        const operationId = getSessionHistoryTransactionOperationId(state, transactionKind, alreadyPersistedCount, persistedItemCount);
        if (newRunItems.length > 0 || deferredRunItemIndexes.length > 0) {
            state._currentTurnBlockedSessionStartIndex ??= alreadyPersistedCount;
        }
        state._pendingSessionHistoryTransaction = structuredClone({
            operationId,
            transactionKind,
            runItemIndexes: getRunItemIndexesForPendingTransaction(state, newRunItems),
            replaceRunItemIndexes: getRunItemIndexesForPendingTransaction(state, runItemsToReplace),
            alreadyPersistedCount,
            persistedItemCount,
            deferredItemIndexes: deferredRunItemIndexes,
        });
        await flushPendingSessionHistoryTransaction(session, state);
        if (runCompaction) {
            await runCompactionOnSession(session, lastResponseId, state, compactionMode);
        }
        return;
    }
    assertPersistableCompactionBoundary(compactedItems);
    if (compactedItems[0]?.type === 'compaction') {
        const previousItems = await getSessionItems(session, state._context);
        await replaceSessionItemsWithRecovery(session, previousItems, compactedItems, state._context);
    }
    else {
        if (resumedSessionWritePreparation) {
            await appendPreparedResumedSessionWrite({
                session,
                state,
                preparation: resumedSessionWritePreparation,
            });
        }
        else {
            await addSessionItems(session, sanitizedItems, state._context, getSessionCompactionState(session, state));
        }
    }
    if (resumedSessionWritePreparation) {
        commitPersistenceState();
        if (runCompaction) {
            markPendingApprovedToolInputCompaction(state);
            await completePendingApprovedToolInputCompaction(session, state);
        }
        else {
            state._pendingSessionWrite = undefined;
            (0, runState_1.clearPendingSessionWriteTerminalProducer)(state);
        }
        return;
    }
    commitPersistenceState();
    if (runCompaction) {
        await runCompactionOnSession(session, lastResponseId, state, compactionMode);
    }
}
async function flushPendingSessionHistoryTransaction(session, state) {
    const pending = state._pendingSessionHistoryTransaction;
    if (!pending) {
        return;
    }
    if (!(0, session_1.isSessionHistoryTransactionAwareSession)(session)) {
        throw new errors_1.UserError('A pending session history transaction requires the same transaction-aware session to resume safely.');
    }
    const boundSessionId = state._currentTurnSessionHistoryTransactionSessionId;
    if (boundSessionId === undefined) {
        throw new errors_1.UserError('A pending session history transaction is missing its session binding.');
    }
    const sessionId = await session.getSessionId();
    if (sessionId !== boundSessionId) {
        throw new errors_1.UserError('A pending session history transaction belongs to a different session and cannot be resumed safely.');
    }
    if (state._currentTurnSessionHistoryTransactionCanReplaceAcceptedOutput ===
        undefined) {
        throw new errors_1.UserError('A pending session history transaction is missing its accepted-output replacement authority.');
    }
    const transactionArgs = {
        operationId: pending.operationId,
        transaction: buildPendingSessionHistoryTransaction(state),
    };
    if ((0, session_1.isRunContextAwareSession)(session)) {
        await session.applyHistoryTransaction(transactionArgs, state._context);
    }
    else {
        await session.applyHistoryTransaction(transactionArgs);
    }
    state._currentTurnPersistedItemCount = pending.persistedItemCount;
    state._currentTurnDeferredSessionItemIndexes = new Set(pending.deferredItemIndexes);
    state._pendingSessionHistoryTransaction = undefined;
    state._currentTurnSessionHistoryTransactionInputItems = [];
    if (pending.transactionKind === 'accepted_replace') {
        state._currentTurnBlockedSessionStartIndex = undefined;
        state._currentTurnSessionHistoryTransactionSessionId = undefined;
        state._currentTurnSessionReasoningItemIdPolicy = undefined;
        state._currentTurnSessionHistoryTransactionInputItems = undefined;
        state._currentTurnSessionHistoryTransactionCanReplaceAcceptedOutput =
            undefined;
    }
}
async function reconcileLegacyCompactionSessionItems(session, pendingItems, runContext) {
    if (pendingItems.length === 0 || pendingItems[0]?.type !== 'compaction') {
        throwLegacyCompactionReconciliationError();
    }
    assertPersistableCompactionBoundary(pendingItems);
    const previousItems = await getSessionItems(session, runContext);
    (0, items_1.assertValidCompactionItems)((0, items_1.trimToLatestCompaction)(previousItems));
    const comparablePreviousItems = session.prepareHistoryItemsForPersistenceComparison?.(previousItems) ??
        previousItems;
    const comparablePendingItems = session.prepareHistoryItemsForPersistenceComparison?.(pendingItems) ??
        pendingItems;
    const compactedComparablePreviousItems = (0, items_1.trimToLatestCompaction)(comparablePreviousItems);
    if (compactedComparablePreviousItems.length === comparablePendingItems.length &&
        (0, sessionItems_1.agentItemRangeMatches)(compactedComparablePreviousItems, comparablePendingItems, 0)) {
        return;
    }
    const previouslyPersistedSuffix = comparablePendingItems.slice(1);
    if (!(0, sessionItems_1.agentItemRangeMatches)(comparablePreviousItems, previouslyPersistedSuffix, comparablePreviousItems.length - previouslyPersistedSuffix.length)) {
        throwLegacyCompactionReconciliationError();
    }
    await replaceSessionItemsWithRecovery(session, previousItems, pendingItems, runContext);
}
function assertPersistableCompactionBoundary(items) {
    (0, items_1.assertValidCompactionItems)(items);
}
function throwLegacyCompactionReconciliationError() {
    throw new errors_1.UserError('Run state cannot safely reconcile its restored compaction item with session history.');
}
async function replaceSessionItemsWithRecovery(session, previousItems, replacementItems, runContext) {
    (0, items_1.assertValidCompactionItems)((0, items_1.trimToLatestCompaction)(previousItems));
    (0, items_1.assertValidCompactionItems)((0, items_1.trimToLatestCompaction)(replacementItems));
    if (replacementItems[0]?.type === 'compaction' &&
        session.replaceHistoryWithCompaction) {
        const comparablePreviousItems = session.prepareHistoryItemsForPersistenceComparison?.(previousItems) ??
            previousItems;
        const comparableReplacementItems = session.prepareHistoryItemsForPersistenceComparison?.(replacementItems) ??
            replacementItems;
        const compactedPreviousItems = (0, items_1.trimToLatestCompaction)(comparablePreviousItems);
        if (compactedPreviousItems.length === comparableReplacementItems.length &&
            (0, sessionItems_1.agentItemRangeMatches)(compactedPreviousItems, comparableReplacementItems, 0)) {
            return;
        }
        if (runContext && (0, session_1.isRunContextAwareSession)(session)) {
            await session.replaceHistoryWithCompaction(replacementItems, runContext);
        }
        else {
            await session.replaceHistoryWithCompaction(replacementItems);
        }
        return;
    }
    try {
        await clearSession(session, runContext);
        if (replacementItems.length > 0) {
            await addSessionItems(session, replacementItems, runContext);
        }
    }
    catch (error) {
        await restoreSessionItemsAfterFailedReplacement(session, previousItems, error, runContext);
        throw error;
    }
}
async function restoreSessionItemsAfterFailedReplacement(session, previousItems, replacementError, runContext) {
    try {
        const currentItems = await getSessionItems(session, runContext);
        if (currentItems.length === previousItems.length &&
            (0, sessionItems_1.agentItemRangeMatches)(currentItems, previousItems, 0)) {
            return;
        }
    }
    catch (inspectionError) {
        (0, logger_1.logModelAndToolActionWarning)(logger_1.default, 'Failed to inspect session history after compaction replacement failed.', inspectionError);
    }
    try {
        await clearSession(session, runContext);
        if (previousItems.length > 0) {
            await addSessionItems(session, previousItems, runContext);
        }
    }
    catch (restoreError) {
        (0, logger_1.logModelAndToolActionWarning)(logger_1.default, 'Failed to restore session history after compaction replacement failed.', restoreError);
        throw new SessionReconciliationRecoveryError(replacementError, restoreError);
    }
    (0, logger_1.logModelAndToolActionWarning)(logger_1.default, 'Restored session history after compaction replacement failed.', replacementError);
}
async function runCompactionOnSession(session, responseId, state, compactionMode) {
    if (!(0, session_1.isOpenAIResponsesCompactionAwareSession)(session)) {
        return;
    }
    const store = state._lastModelSettings?.store ?? state._currentAgent.modelSettings?.store;
    const compactionArgs = typeof responseId === 'undefined' &&
        typeof store === 'undefined' &&
        typeof compactionMode === 'undefined'
        ? undefined
        : {
            ...(typeof responseId === 'undefined' ? {} : { responseId }),
            ...(typeof store === 'undefined' ? {} : { store }),
            ...(typeof compactionMode === 'undefined' ? {} : { compactionMode }),
        };
    let compactionResult;
    try {
        compactionResult = (0, session_1.isOpenAIResponsesCompactionOwnershipAwareSession)(session)
            ? await session.runCompaction(compactionArgs, state._context, getSessionCompactionState(session, state)?.ownership ?? null, getSessionCompactionState(session, state)?.modelExchange)
            : (0, session_1.isRunContextAwareSession)(session)
                ? await session.runCompaction(compactionArgs, state._context)
                : await session.runCompaction(compactionArgs);
    }
    catch (error) {
        const usage = (0, usageTracking_1.consumeModelFailureUsage)(error);
        if (usage) {
            state._context.usage.add(usage);
            (0, usageTracking_1.getRunStateUsageRecorder)(state)?.(usage);
        }
        throw error;
    }
    if (!compactionResult) {
        return;
    }
    const usage = compactionResult.usage;
    const usageIncrement = new usage_1.Usage({
        requests: 1,
        inputTokens: usage.inputTokens,
        outputTokens: usage.outputTokens,
        totalTokens: usage.totalTokens,
        inputTokensDetails: usage.inputTokensDetails,
        outputTokensDetails: usage.outputTokensDetails,
        requestUsageEntries: [usage],
    });
    state._context.usage.add(usageIncrement);
    (0, usageTracking_1.getRunStateUsageRecorder)(state)?.(usageIncrement);
}
function buildItemFrequencyMap(items, options) {
    const counts = new Map();
    for (const item of items) {
        const key = options?.prepareForModelInput && options.session
            ? getHistoryItemModelInputKey(options.session, item, options.reasoningItemIdPolicy)
            : (0, items_1.getAgentInputItemKey)(item);
        counts.set(key, (counts.get(key) ?? 0) + 1);
    }
    return counts;
}
function decrementCount(map, key) {
    const remaining = (map.get(key) ?? 0) - 1;
    if (remaining <= 0) {
        map.delete(key);
    }
    else {
        map.set(key, remaining);
    }
}
//# sourceMappingURL=sessionPersistence.js.map