UNPKG

@openai/agents-core

Version:

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

1,710 lines • 84.8 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.SandboxRuntimeManager = void 0;
const agentToolConfiguration_1 = require("../../agentToolConfiguration.js");
const logger_1 = __importStar(require("../../logger.js"));
const errors_1 = require("../../errors.js");
const memory_1 = require("../capabilities/memory.js");
const errors_2 = require("../errors.js");
const manifest_1 = require("../manifest.js");
const mountSecurity_1 = require("../mountSecurity.js");
const remoteMountCommandAllowlist_1 = require("../shared/remoteMountCommandAllowlist.js");
const environment_1 = require("../shared/environment.js");
const stableJson_1 = require("../shared/stableJson.js");
const generation_1 = require("../memory/generation.js");
const agentPreparation_1 = require("./agentPreparation.js");
const agentKeys_1 = require("./agentKeys.js");
const livePreservedSessions_1 = require("./livePreservedSessions.js");
const providedSessionManifest_1 = require("./providedSessionManifest.js");
const sessionSerialization_1 = require("./sessionSerialization.js");
const manifestPersistence_1 = require("../sandboxes/shared/manifestPersistence.js");
const sessionLifecycle_1 = require("./sessionLifecycle.js");
const sessionState_1 = require("./sessionState.js");
const spans_1 = require("./spans.js");
const runAsManifest_1 = require("./runAsManifest.js");
const workspacePaths_1 = require("../workspacePaths.js");
const sandboxAgentIdentitiesByRunState = new WeakMap();
class SandboxRuntimeManager {
    sandboxConfig;
    workspaceScope;
    runState;
    agentKeys;
    agentsByKey;
    acquiredAgents = new Map();
    sessionsByAgent = new Map();
    sessionsByAgentKey = new Map();
    sessionAgentNamesByKey = new Map();
    preparedAgents = new Map();
    preparedSessions = new Map();
    preparedManifestSignatures = new Map();
    ownedSessionAgentKeys = new Set();
    sessionStartPromises = new WeakMap();
    activeMemory;
    currentAgentId;
    constructor(args) {
        this.sandboxConfig = args.sandboxConfig;
        this.workspaceScope = new workspacePaths_1.SandboxWorkspaceScope(args.sandboxConfig?.cwd);
        this.runState = args.runState;
        const existingIdentityRegistry = args.runState
            ? sandboxAgentIdentitiesByRunState.get(args.runState)
            : undefined;
        if (existingIdentityRegistry) {
            this.agentKeys = existingIdentityRegistry.agentKeys;
            this.agentsByKey = existingIdentityRegistry.agentsByKey;
        }
        else {
            this.agentKeys = (0, agentKeys_1.allocateAgentKeys)(args.startingAgent);
            this.agentsByKey = (0, agentKeys_1.indexAgentsByKey)(args.startingAgent, this.agentKeys);
            if (args.runState) {
                sandboxAgentIdentitiesByRunState.set(args.runState, {
                    agentKeys: this.agentKeys,
                    agentsByKey: this.agentsByKey,
                });
            }
        }
    }
    async prepareAgent(args) {
        const { currentAgent, turnInput, runConfigModel, tracingParent } = args;
        if (!(0, agentKeys_1.isSandboxAgent)(currentAgent)) {
            this.activeMemory = undefined;
            return {
                executionAgent: currentAgent,
                turnInput,
            };
        }
        if (!this.sandboxConfig) {
            throw new errors_1.UserError('SandboxAgent execution requires `RunConfig.sandbox`.');
        }
        return await (0, spans_1.withSandboxSpan)('sandbox.prepare_agent', {
            agent_name: currentAgent.name,
        }, async (prepareSpan) => {
            this.acquireAgent(currentAgent);
            const session = await this.ensureSession(currentAgent, prepareSpan);
            await this.ensureWorkspaceScopeAccessible(session, (0, runAsManifest_1.sandboxRunAsName)(currentAgent.runAs));
            // Bind a clone to the live session so capability tools and instructions can carry
            // per-session state without mutating the public SandboxAgent instance.
            const executionAgent = this.getPreparedAgent(currentAgent, session, runConfigModel, tracingParent);
            const memory = executionAgent.capabilities.find(memory_1.isMemoryCapability);
            if (memory) {
                this.activeMemory = {
                    session,
                    memory,
                    runAs: (0, runAsManifest_1.sandboxRunAsName)(currentAgent.runAs),
                };
            }
            else {
                this.activeMemory = undefined;
            }
            return {
                executionAgent,
                turnInput: executionAgent.capabilities.reduce((input, capability) => capability.processContext(input), turnInput),
            };
        }, tracingParent);
    }
    async cleanup(state, options = {}) {
        const preserveOwnedSessions = options.preserveOwnedSessions ?? false;
        const runCleanup = async (cleanupSpan) => {
            let preserveCleanupHandles = false;
            try {
                const cleanupPlan = await this.planCleanup(state, { preserveOwnedSessions }, cleanupSpan);
                await this.executeCleanupPlan(state, cleanupPlan, {
                    onCloseError: () => {
                        preserveCleanupHandles = true;
                    },
                    tracingParent: cleanupSpan,
                });
            }
            finally {
                if ((0, sessionState_1.hasPreservedOwnedSessions)((0, sessionState_1.getSerializedSandboxState)(state))) {
                    sandboxAgentIdentitiesByRunState.set(state, {
                        agentKeys: this.agentKeys,
                        agentsByKey: this.agentsByKey,
                    });
                }
                else {
                    sandboxAgentIdentitiesByRunState.delete(state);
                }
                this.releaseAgents();
                this.sessionsByAgent.clear();
                if (!preserveCleanupHandles) {
                    this.sessionsByAgentKey.clear();
                    this.sessionAgentNamesByKey.clear();
                    this.ownedSessionAgentKeys.clear();
                }
                this.preparedAgents.clear();
                this.preparedSessions.clear();
                this.preparedManifestSignatures.clear();
                this.activeMemory = undefined;
                this.currentAgentId = undefined;
            }
        };
        if (this.sessionsByAgentKey.size === 0 &&
            this.preparedAgents.size === 0 &&
            this.ownedSessionAgentKeys.size === 0) {
            await runCleanup(options.tracingParent);
            return;
        }
        await (0, spans_1.withSandboxSpan)('sandbox.cleanup', {}, runCleanup, options.tracingParent);
    }
    async planCleanup(state, options, tracingParent) {
        if (this.sessionsByAgentKey.size > 0) {
            return await this.planCleanupForActiveSessions(state, options);
        }
        return await this.planCleanupForSerializedStateOnly(state, options, tracingParent);
    }
    async planCleanupForActiveSessions(state, options) {
        const cleanupPlan = options.preserveOwnedSessions
            ? {}
            : {
                ownedSessionCloseTarget: 'all',
                afterOwnedSessionClose: {
                    forgetLivePreservedSessions: true,
                },
            };
        const { closeErrors: rejectedCloseErrors } = await this.closeLivePreservedOwnedSessions(state, {
            rejectedOnly: true,
        });
        if (rejectedCloseErrors.length > 0) {
            cleanupPlan.deferredError = lifecycleErrorForCloseErrors('Failed to close one or more rejected live sandbox sessions.', rejectedCloseErrors);
        }
        try {
            await this.runPreStopHooksBeforeRelease();
            const serializedState = await this.serializeState({
                includeOwnedSessions: options.preserveOwnedSessions,
            });
            state._sandbox = serializedState;
            if (options.preserveOwnedSessions && serializedState) {
                (0, livePreservedSessions_1.rememberLivePreservedOwnedSessions)({
                    state,
                    serializedState,
                    sessionsByAgentKey: this.sessionsByAgentKey,
                });
                const serializedOnlySessionAgentKeys = (0, livePreservedSessions_1.preservedOwnedSessionAgentKeysWithoutLiveReuse)(serializedState);
                if (serializedOnlySessionAgentKeys.size > 0) {
                    cleanupPlan.ownedSessionCloseTarget = serializedOnlySessionAgentKeys;
                    cleanupPlan.afterOwnedSessionClose = {
                        removeFreshCreationSessionsFromSandboxState: true,
                    };
                }
            }
            if (options.preserveOwnedSessions &&
                !serializedState &&
                this.ownedSessionAgentKeys.size > 0) {
                cleanupPlan.ownedSessionCloseTarget = 'all';
                cleanupPlan.afterOwnedSessionClose = {
                    forgetLivePreservedSessions: true,
                };
            }
        }
        catch (error) {
            cleanupPlan.deferredError = cleanupPlan.deferredError
                ? new errors_2.SandboxLifecycleError('Failed to clean up rejected live sessions and serialize active sandbox sessions.', { errors: [cleanupPlan.deferredError, error] })
                : error;
            if (this.ownedSessionAgentKeys.size > 0) {
                cleanupPlan.ownedSessionCloseTarget = 'all';
                cleanupPlan.afterOwnedSessionClose = {
                    forgetLivePreservedSessions: true,
                    removeClosedSessionsFromSandboxState: true,
                };
            }
        }
        return cleanupPlan;
    }
    async planCleanupForSerializedStateOnly(state, options, tracingParent) {
        const cleanupPlan = options.preserveOwnedSessions
            ? {}
            : {
                ownedSessionCloseTarget: 'all',
                afterOwnedSessionClose: {
                    forgetLivePreservedSessions: true,
                },
            };
        let sandboxState = (0, sessionState_1.getSerializedSandboxState)(state);
        if (((0, sessionState_1.hasPreservedOwnedSessions)(sandboxState) ||
            (0, livePreservedSessions_1.hasRejectedLivePreservedOwnedSessions)(state)) &&
            !options.preserveOwnedSessions) {
            const { closedAgentKeys, closeErrors } = await this.closeLivePreservedOwnedSessions(state);
            if (closedAgentKeys.size > 0) {
                if (sandboxState &&
                    !removeClosedPreservedOwnedSessions(sandboxState, closedAgentKeys)) {
                    state._sandbox = undefined;
                    sandboxState = undefined;
                }
            }
            if (closeErrors.length === 1) {
                throw closeErrors[0];
            }
            if (closeErrors.length > 1) {
                throw new errors_2.SandboxLifecycleError('Failed to close one or more live preserved owned sandbox sessions.', { errors: closeErrors });
            }
            if ((0, sessionState_1.hasPreservedOwnedSessions)(sandboxState)) {
                if (this.sandboxConfig?.client) {
                    try {
                        await this.adoptPreservedOwnedSessions(tracingParent);
                        if (this.ownedSessionAgentKeys.size > 0) {
                            cleanupPlan.ownedSessionCloseTarget = 'all';
                            cleanupPlan.afterOwnedSessionClose = {
                                clearSandboxState: true,
                                forgetLivePreservedSessions: true,
                            };
                        }
                        else {
                            cleanupPlan.ownedSessionCloseTarget = undefined;
                            cleanupPlan.afterOwnedSessionClose = undefined;
                        }
                    }
                    catch (error) {
                        cleanupPlan.deferredError = error;
                    }
                }
                else {
                    state._sandbox = undefined;
                    (0, livePreservedSessions_1.forgetLivePreservedOwnedSessions)(state);
                    cleanupPlan.ownedSessionCloseTarget = undefined;
                    cleanupPlan.afterOwnedSessionClose = undefined;
                }
            }
            else if (closedAgentKeys.size > 0) {
                state._sandbox = undefined;
            }
        }
        else if (!(0, sessionState_1.hasPreservedOwnedSessions)(sandboxState)) {
            state._sandbox = undefined;
            (0, livePreservedSessions_1.forgetLivePreservedOwnedSessions)(state);
        }
        return cleanupPlan;
    }
    async executeCleanupPlan(state, plan, options) {
        if (plan.ownedSessionCloseTarget) {
            let closeResult;
            try {
                closeResult = await this.closeOwnedSessions(plan.ownedSessionCloseTarget === 'all'
                    ? undefined
                    : plan.ownedSessionCloseTarget, {
                    removeClosedSessionsFromSandboxState: Boolean(plan.afterOwnedSessionClose
                        ?.removeClosedSessionsFromSandboxState ||
                        plan.afterOwnedSessionClose?.clearSandboxState),
                    tracingParent: options.tracingParent,
                });
            }
            catch (error) {
                options.onCloseError();
                throw error;
            }
            const { closedAgentKeys: closedSessionAgentKeys, closeErrors } = closeResult;
            if (plan.afterOwnedSessionClose?.forgetLivePreservedSessions) {
                (0, livePreservedSessions_1.forgetLivePreservedOwnedSessions)(state);
            }
            if (plan.afterOwnedSessionClose?.removeFreshCreationSessionsFromSandboxState) {
                const sandboxState = (0, sessionState_1.getSerializedSandboxState)(state);
                const freshCreationAgentKeys = new Set([...closedSessionAgentKeys].filter((agentKey) => sandboxState?.sessionsByAgent[agentKey]?.requiresFreshCreation ===
                    true));
                if (freshCreationAgentKeys.size > 0) {
                    this.invalidateSerializedSessions(freshCreationAgentKeys);
                }
            }
            if (plan.afterOwnedSessionClose?.removeClosedSessionsFromSandboxState) {
                const sandboxState = (0, sessionState_1.getSerializedSandboxState)(state);
                if (sandboxState &&
                    !removeClosedSerializedSessions(sandboxState, closedSessionAgentKeys)) {
                    state._sandbox = undefined;
                }
            }
            if (closeErrors.length > 0) {
                options.onCloseError();
                throw lifecycleErrorForCloseErrors('Failed to close one or more owned sandbox sessions.', closeErrors);
            }
            if (plan.afterOwnedSessionClose?.clearSandboxState) {
                state._sandbox = undefined;
            }
        }
        if (plan.deferredError) {
            throw plan.deferredError;
        }
    }
    async closeLivePreservedOwnedSessions(state, options = {}) {
        const sessionAgentKeys = new Map();
        for (const entry of (0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(state)) {
            if (options.rejectedOnly && !entry.reuseRejected) {
                continue;
            }
            const agentKeys = sessionAgentKeys.get(entry.session) ?? [];
            agentKeys.push(entry.agentKey);
            sessionAgentKeys.set(entry.session, agentKeys);
        }
        const closedAgentKeys = new Set();
        const closeErrors = [];
        for (const [session, agentKeys] of sessionAgentKeys) {
            (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({ state, session });
            this.detachSessionAliases(session);
            try {
                await (0, sessionLifecycle_1.cleanupSandboxSession)(session);
                (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({ state, session });
                for (const agentKey of agentKeys) {
                    closedAgentKeys.add(agentKey);
                }
            }
            catch (error) {
                closeErrors.push(error);
            }
        }
        const agentKeysWithLiveHandles = new Set((0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(state).map((entry) => entry.agentKey));
        for (const agentKey of agentKeysWithLiveHandles) {
            closedAgentKeys.delete(agentKey);
        }
        return { closedAgentKeys, closeErrors };
    }
    async runPreStopHooksBeforeRelease() {
        const shouldRunForOwnedSessions = Boolean(this.sandboxConfig?.client?.serializeSessionState);
        const sessionsForPreStop = new Set();
        const sessionsForHooks = new Set();
        for (const [agentKey, session] of this.sessionsByAgentKey) {
            if (!this.ownedSessionAgentKeys.has(agentKey)) {
                sessionsForPreStop.add(session);
                continue;
            }
            // Owned sessions without serialization run hooks through the close lifecycle.
            if (shouldRunForOwnedSessions) {
                sessionsForHooks.add(session);
            }
        }
        for (const session of sessionsForPreStop) {
            await (0, sessionLifecycle_1.runSandboxSessionPreStop)(session);
        }
        for (const session of sessionsForHooks) {
            if (!sessionsForPreStop.has(session)) {
                await (0, sessionLifecycle_1.runSandboxSessionPreStopHooks)(session);
            }
        }
    }
    async enqueueMemoryGeneration(state, args) {
        if (!this.activeMemory || this.activeMemory.memory.generate === null) {
            return;
        }
        try {
            const manager = (0, generation_1.getOrCreateSandboxMemoryGenerationManager)({
                session: this.activeMemory.session,
                memory: this.activeMemory.memory,
                runAs: this.activeMemory.runAs,
                runAgent: args.runAgent,
                tracingParent: args.tracingParent,
            });
            await manager.enqueueState(state, {
                exception: args.exception,
                inputOverride: args.inputOverride,
                rolloutIdentity: {
                    conversationId: state._conversationId ?? undefined,
                    sdkSessionId: await args.sdkSessionId?.(),
                    groupId: args.groupId,
                },
            });
        }
        catch (error) {
            (0, logger_1.logModelAndToolActionWarning)(logger_1.default, 'Failed to enqueue sandbox memory generation:', error);
        }
    }
    async adoptPreservedOwnedSessions(tracingParent) {
        // An explicit state replaces any preserved RunState entry. Do not inspect
        // or resume that stale envelope before the replacement is processed. Signal
        // callers to rehydrate any live tool closures against the explicit state.
        if (this.sandboxConfig?.sessionState !== undefined) {
            return true;
        }
        const sandboxState = (0, sessionState_1.getSerializedSandboxState)(this.runState);
        if (!(0, sessionState_1.hasPreservedOwnedSessions)(sandboxState)) {
            return false;
        }
        const client = this.sandboxConfig?.client;
        if (!client) {
            throw new errors_1.UserError('Sandbox client must be configured to restore preserved sandbox sessions.');
        }
        if (sandboxState && sandboxState.backendId !== client.backendId) {
            throw new errors_1.UserError('RunState sandbox backend does not match the configured sandbox client.');
        }
        const preservedEntries = Object.entries((0, sessionState_1.getPreviousSerializedSessionsByAgent)(sandboxState, client)).filter(([, entry]) => entry.preservedOwnedSession);
        let resumedSession = false;
        for (const [agentKey] of preservedEntries) {
            if (this.sessionsByAgentKey.has(agentKey)) {
                continue;
            }
            const entry = (0, sessionState_1.getSerializedSessionEntryForAgent)((0, sessionState_1.getSerializedSandboxState)(this.runState), agentKey);
            if (!entry?.preservedOwnedSession) {
                continue;
            }
            (0, sessionState_1.assertSessionStateEnvelope)(client, entry.sessionState);
            const trustedManifest = this.resolveTrustedManifestForAgentKey(agentKey);
            const clientPreparesEnvironment = client.environmentPreparation === 'client';
            const resumeTrustedManifest = clientPreparesEnvironment
                ? (0, sessionState_1.resolveTrustedManifestForResume)(client, trustedManifest, this.sandboxConfig?.options)
                : trustedManifest;
            if (clientPreparesEnvironment && !resumeTrustedManifest) {
                throw new errors_1.UserError('Client-owned environment preparation requires a current trusted manifest before resuming a preserved sandbox session.');
            }
            const liveDecision = await this.inspectLivePreservedOwnedSessionReuse({
                client,
                agentKey,
                serializedEntry: entry,
                trustedManifest: resumeTrustedManifest,
                trustedManifestAlreadyResolved: clientPreparesEnvironment,
            });
            if (entry.requiresFreshCreation === true) {
                if (liveDecision) {
                    await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
                    continue;
                }
                throw serializedOwnedSessionReplacementError(client);
            }
            if (liveDecision?.reusable) {
                this.sessionsByAgentKey.set(agentKey, liveDecision.entry.session);
                this.sessionAgentNamesByKey.set(agentKey, liveDecision.entry.currentAgentName);
                this.ownedSessionAgentKeys.add(agentKey);
                continue;
            }
            if (liveDecision?.mountAuthorityChanged) {
                await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
                continue;
            }
            if (client.serializedSessionStateRequiresFreshCreation ||
                (0, sessionState_1.serializedSessionEntryRequiresFreshMountAuthority)(entry) ||
                (resumeTrustedManifest &&
                    ((0, mountSecurity_1.manifestHasInContainerMounts)(resumeTrustedManifest) ||
                        (0, mountSecurity_1.manifestHasNonResumableMountAuthority)(resumeTrustedManifest)))) {
                if (liveDecision) {
                    await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
                }
                else {
                    this.invalidateSerializedSession(agentKey);
                }
                continue;
            }
            if (!client.resume) {
                throw new errors_1.UserError('Sandbox client must implement resume() to restore preserved sandbox sessions.');
            }
            const serializedState = await (0, sessionState_1.deserializeSandboxSessionStateEntry)(client, entry, resumeTrustedManifest, {
                clientOptions: this.sandboxConfig?.options,
                snapshot: this.sandboxConfig?.snapshot,
            }, { trustedManifestAlreadyResolved: clientPreparesEnvironment });
            if (!serializedState) {
                continue;
            }
            if (await serializedSessionStateRequiresFreshCreationForOptions(client, serializedState, {
                archiveLimits: this.sandboxConfig?.archiveLimits,
                clientOptions: this.sandboxConfig?.options,
                ...(clientPreparesEnvironment
                    ? { trustedManifest: resumeTrustedManifest }
                    : {}),
            })) {
                if (liveDecision) {
                    await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
                }
                else {
                    throw serializedOwnedSessionReplacementError(client);
                }
                continue;
            }
            const rejectedLiveEntry = await this.prepareRejectedLiveSessionReplacement(client, liveDecision);
            let session = await (0, spans_1.withSandboxSpan)('sandbox.resume_session', {
                agent_name: entry.currentAgentName,
                backend_id: client.backendId,
            }, async () => await resumeSandboxSession(client, serializedState, {
                archiveLimits: this.sandboxConfig?.archiveLimits,
                clientOptions: this.sandboxConfig?.options,
                ...(clientPreparesEnvironment
                    ? { trustedManifest: resumeTrustedManifest }
                    : {}),
            }), tracingParent);
            session = await this.replaceRejectedLiveSession(rejectedLiveEntry, session);
            this.applyArchiveLimits(session);
            this.sessionsByAgentKey.set(agentKey, session);
            this.sessionAgentNamesByKey.set(agentKey, entry.currentAgentName);
            this.ownedSessionAgentKeys.add(agentKey);
            resumedSession = true;
        }
        return resumedSession;
    }
    acquireAgent(agent) {
        const agentId = (0, agentKeys_1.getObjectId)(agent);
        if (this.acquiredAgents.has(agentId)) {
            return;
        }
        (0, agentKeys_1.acquireSandboxAgent)(agent);
        this.acquiredAgents.set(agentId, agent);
    }
    async ensureSession(agent, tracingParent) {
        const agentId = (0, agentKeys_1.getObjectId)(agent);
        const agentKey = this.agentKey(agent);
        const existing = this.sessionsByAgent.get(agentId);
        if (existing) {
            (0, mountSecurity_1.assertSandboxSessionStateUsable)(existing.state);
            this.currentAgentId = agentId;
            return existing;
        }
        const existingByKey = this.sessionsByAgentKey.get(agentKey);
        if (existingByKey) {
            (0, mountSecurity_1.assertSandboxSessionStateUsable)(existingByKey.state);
            this.applyArchiveLimits(existingByKey);
            await this.ensureSessionStarted(existingByKey, agent, 'resume', {
                oncePerSession: true,
                tracingParent,
            });
            this.currentAgentId = agentId;
            this.sessionsByAgent.set(agentId, existingByKey);
            this.sessionAgentNamesByKey.set(agentKey, agent.name);
            return existingByKey;
        }
        if (this.sandboxConfig?.session) {
            const session = this.sandboxConfig.session;
            (0, mountSecurity_1.assertSandboxSessionStateUsable)(session.state);
            this.applyArchiveLimits(session);
            const configuredManifest = this.resolveConfiguredManifest(agent, {
                providedSession: session,
            });
            if (this.sandboxConfig.client?.environmentPreparation === 'client' &&
                (manifestHasDeferredEnvironmentValues(configuredManifest.manifest) ||
                    manifestHasDeferredEnvironmentValues(session.state.manifest))) {
                throw new errors_1.UserError('Client-owned environment preparation cannot revalidate deferred environment values for an already-running provided session. Resume the session through the client instead.');
            }
            // Provided sessions are already running, so only a safe additive manifest delta can
            // be applied instead of reprovisioning root, env, users, groups, or mounts.
            await (0, providedSessionManifest_1.applyManifestToProvidedSession)(session, configuredManifest.manifest, (0, runAsManifest_1.sandboxRunAsName)(agent.runAs));
            await this.ensureSessionStarted(session, agent, 'provided', {
                oncePerSession: true,
                tracingParent,
            });
            this.registerSessionForAgent(agent, session);
            return session;
        }
        const configuredManifest = this.resolveConfiguredManifest(agent);
        (0, mountSecurity_1.validateMountCredentialBoundaries)(configuredManifest.manifest);
        const client = this.requireClient();
        const resumed = await this.resumeSessionForAgent(client, agent, configuredManifest.manifest, tracingParent);
        if (resumed) {
            this.applyArchiveLimits(resumed);
            await this.ensureSessionStarted(resumed, agent, 'resume', {
                tracingParent,
            });
            this.registerSessionForAgent(agent, resumed, { owned: true });
            return resumed;
        }
        if (!client.create) {
            throw new errors_1.UserError('Sandbox execution requires a sandbox client with create() support.');
        }
        const clientPreparesEnvironment = client.environmentPreparation === 'client';
        if (clientPreparesEnvironment) {
            (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(configuredManifest.manifest, {}, { preserveDeferredValuePresence: true });
        }
        const createManifest = clientPreparesEnvironment
            ? (0, manifest_1.cloneManifest)(configuredManifest.manifest)
            : await (0, mountSecurity_1.resolveAndValidateMountEnvironment)(configuredManifest.manifest);
        const createSession = client.create.bind(client);
        const createArgs = {
            snapshot: this.resolveSnapshotSpec(client),
            options: this.sandboxConfig?.options,
            concurrencyLimits: this.sandboxConfig?.concurrencyLimits,
            archiveLimits: this.sandboxConfig?.archiveLimits,
        };
        if (configuredManifest.passToCreate) {
            createArgs.manifest = createManifest;
        }
        const session = await (0, spans_1.withSandboxSpan)('sandbox.create_session', {
            agent_name: agent.name,
            backend_id: client.backendId,
        }, async () => await createSession(createArgs), tracingParent);
        if (clientPreparesEnvironment) {
            bindClientPreparedTrustedManifest(session, configuredManifest.manifest);
        }
        else if (configuredManifest.passToCreate) {
            session.state.environment = {
                ...(session.state.environment ?? {}),
                ...(await createManifest.resolveEnvironment()),
            };
            const manifestWithTrustedPolicies = manifestWithTrustedRuntimePolicies(session.state.manifest, configuredManifest.manifest);
            (0, mountSecurity_1.recordLiveMountCredentialAuthority)(manifestWithTrustedPolicies, session.state.manifest);
            session.state.manifest = manifestWithTrustedPolicies;
        }
        this.applyArchiveLimits(session);
        await this.ensureSessionStarted(session, agent, 'create', {
            tracingParent,
        });
        this.registerSessionForAgent(agent, session, { owned: true });
        return session;
    }
    applyArchiveLimits(session) {
        if (this.sandboxConfig?.archiveLimits === undefined) {
            return;
        }
        session.setArchiveLimits?.(this.sandboxConfig.archiveLimits);
    }
    registerSessionForAgent(agent, session, options = {}) {
        const agentId = (0, agentKeys_1.getObjectId)(agent);
        const agentKey = this.agentKey(agent);
        this.currentAgentId = agentId;
        this.sessionsByAgent.set(agentId, session);
        this.sessionsByAgentKey.set(agentKey, session);
        this.sessionAgentNamesByKey.set(agentKey, agent.name);
        if (options.owned) {
            this.ownedSessionAgentKeys.add(agentKey);
            (0, mountSecurity_1.captureLiveMountCredentialAuthorityIfAbsent)(session.state.manifest, session.state.environment);
        }
    }
    async ensureSessionStarted(session, agent, reason, options = {}) {
        if (!session.start) {
            return;
        }
        if (options.oncePerSession) {
            // Provided and resumed sessions may be shared by multiple agents in one run; keep
            // their provider-specific start hook idempotent.
            const started = this.sessionStartPromises.get(session);
            if (started) {
                await started;
                return;
            }
        }
        if (session.running && (await session.running())) {
            if (options.oncePerSession) {
                this.sessionStartPromises.set(session, Promise.resolve());
            }
            return;
        }
        const startPromise = (0, spans_1.withSandboxSpan)('sandbox.start', {
            agent_name: agent.name,
        }, async () => {
            await session.start({ reason });
        }, options.tracingParent);
        if (options.oncePerSession) {
            this.sessionStartPromises.set(session, startPromise);
        }
        try {
            await startPromise;
        }
        catch (error) {
            if (options.oncePerSession) {
                this.sessionStartPromises.delete(session);
            }
            throw error;
        }
    }
    getPreparedAgent(agent, session, runConfigModel, tracingParent) {
        const agentId = (0, agentKeys_1.getObjectId)(agent);
        const manifestSignature = getManifestSignature(session.state.manifest);
        const cached = this.preparedAgents.get(agentId);
        if (cached &&
            this.preparedSessions.get(agentId) === session &&
            this.preparedManifestSignatures.get(agentId) === manifestSignature) {
            const cachedSandboxAgent = cached;
            for (const capability of cachedSandboxAgent.capabilities) {
                capability.bindTracingParent(tracingParent);
            }
            (0, agentToolConfiguration_1.refreshPreparedAgentTools)(cachedSandboxAgent);
            return cachedSandboxAgent;
        }
        // Capability instructions include a rendered filesystem view, so a manifest change
        // invalidates the prepared-agent cache even when the live session object is unchanged.
        const prepared = (0, agentPreparation_1.prepareSandboxAgent)({
            agent,
            session,
            capabilities: (0, agentPreparation_1.cloneSandboxCapabilities)(agent.capabilities),
            runConfigModel,
            processManifest: false,
            tracingParent,
            workspaceScope: this.workspaceScope,
        });
        this.preparedAgents.set(agentId, prepared);
        this.preparedSessions.set(agentId, session);
        this.preparedManifestSignatures.set(agentId, manifestSignature);
        return prepared;
    }
    async ensureWorkspaceScopeAccessible(session, runAs) {
        const cwd = this.workspaceScope.cwd;
        if (cwd === undefined) {
            return;
        }
        if (!session.directoryExists) {
            throw new errors_1.UserError('Sandbox sessions used with sandbox.cwd must provide directoryExists().');
        }
        const accessible = await session.directoryExists(cwd, runAs);
        if (!accessible) {
            throw new errors_1.UserError(`Sandbox working directory "${cwd}" does not exist or is not accessible.`);
        }
    }
    async resumeSessionForAgent(client, agent, trustedManifest, tracingParent) {
        const agentKey = this.agentKey(agent);
        const serializedEntry = (0, sessionState_1.getSerializedSessionEntryForAgent)((0, sessionState_1.getSerializedSandboxState)(this.runState), agentKey);
        const explicitSessionStateInput = this.sandboxConfig?.sessionState;
        const hasExplicitSessionState = explicitSessionStateInput !== undefined;
        if (!hasExplicitSessionState && serializedEntry) {
            (0, sessionState_1.assertSessionStateEnvelope)(client, serializedEntry.sessionState);
        }
        const clientPreparesEnvironment = client.environmentPreparation === 'client';
        const resumeTrustedManifest = clientPreparesEnvironment &&
            (hasExplicitSessionState || serializedEntry !== undefined)
            ? (0, sessionState_1.resolveTrustedManifestForResume)(client, trustedManifest, this.sandboxConfig?.options)
            : trustedManifest;
        const explicitTrustedManifest = explicitSessionStateInput
            ? resumeTrustedManifest
            : trustedManifest;
        if (explicitSessionStateInput) {
            client.validateSessionStateForResume?.({ source: 'explicit', state: explicitSessionStateInput }, {
                archiveLimits: this.sandboxConfig?.archiveLimits,
                clientOptions: this.sandboxConfig?.options,
                ...(clientPreparesEnvironment
                    ? { trustedManifest: explicitTrustedManifest }
                    : {}),
            });
        }
        const explicitResume = hasExplicitSessionState
            ? await this.prepareExplicitSessionStateForResume(client, trustedManifest, clientPreparesEnvironment ? explicitTrustedManifest : undefined)
            : undefined;
        const explicitSessionState = explicitResume?.state;
        if (explicitSessionState && !client.resume) {
            throw new errors_1.UserError('Sandbox client must implement resume() to restore sandbox session state.');
        }
        const explicitClientPreparedLiveEntry = hasExplicitSessionState && clientPreparesEnvironment
            ? (0, livePreservedSessions_1.livePreservedOwnedSession)({
                runState: this.runState,
                client,
                agentKey,
                serializedEntry,
            })
            : undefined;
        const liveDecision = hasExplicitSessionState && clientPreparesEnvironment
            ? explicitClientPreparedLiveEntry
                ? { entry: explicitClientPreparedLiveEntry, reusable: false }
                : undefined
            : await this.inspectLivePreservedOwnedSessionReuse({
                client,
                agentKey,
                serializedEntry,
                trustedManifest: resumeTrustedManifest,
                trustedManifestAlreadyResolved: clientPreparesEnvironment,
            });
        if (!hasExplicitSessionState &&
            serializedEntry?.requiresFreshCreation === true) {
            if (liveDecision) {
                await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
                return undefined;
            }
            throw serializedOwnedSessionReplacementError(client);
        }
        if (!hasExplicitSessionState && liveDecision?.reusable) {
            return liveDecision.entry.session;
        }
        if (!hasExplicitSessionState && liveDecision?.mountAuthorityChanged) {
            await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
            return undefined;
        }
        if (!hasExplicitSessionState &&
            (client.serializedSessionStateRequiresFreshCreation ||
                (0, mountSecurity_1.manifestHasInContainerMounts)(resumeTrustedManifest) ||
                (0, mountSecurity_1.manifestHasNonResumableMountAuthority)(resumeTrustedManifest) ||
                (0, sessionState_1.serializedSessionEntryRequiresFreshMountAuthority)(serializedEntry))) {
            if (liveDecision) {
                await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
            }
            else {
                this.invalidateSerializedSession(agentKey);
            }
            return undefined;
        }
        if (!client.resume) {
            if (this.sandboxConfig?.sessionState || serializedEntry) {
                throw new errors_1.UserError('Sandbox client must implement resume() to restore sandbox session state.');
            }
            return undefined;
        }
        if (explicitSessionState) {
            const rejectedLiveEntry = await this.prepareRejectedLiveSessionReplacement(client, liveDecision ? { ...liveDecision, reusable: false } : undefined);
            const session = await (0, spans_1.withSandboxSpan)('sandbox.resume_session', {
                agent_name: agent.name,
                backend_id: client.backendId,
            }, async () => await resumeSandboxSession(client, explicitSessionState, {
                archiveLimits: this.sandboxConfig?.archiveLimits,
                clientOptions: this.sandboxConfig?.options,
                ...(clientPreparesEnvironment
                    ? { trustedManifest: explicitResume?.trustedManifest }
                    : {}),
            }), tracingParent);
            return await this.replaceRejectedLiveSession(rejectedLiveEntry, session);
        }
        const serializedState = await (0, sessionState_1.deserializeSandboxSessionStateEntry)(client, serializedEntry, resumeTrustedManifest, {
            clientOptions: this.sandboxConfig?.options,
            snapshot: this.sandboxConfig?.snapshot,
        }, { trustedManifestAlreadyResolved: clientPreparesEnvironment });
        if (!serializedState) {
            return undefined;
        }
        if (await serializedSessionStateRequiresFreshCreationForOptions(client, serializedState, {
            archiveLimits: this.sandboxConfig?.archiveLimits,
            clientOptions: this.sandboxConfig?.options,
            ...(clientPreparesEnvironment
                ? { trustedManifest: resumeTrustedManifest }
                : {}),
        })) {
            if (liveDecision) {
                await this.discardLiveSessionWithChangedMountAuthority(liveDecision);
            }
            else {
                throw serializedOwnedSessionReplacementError(client);
            }
            return undefined;
        }
        const rejectedLiveEntry = await this.prepareRejectedLiveSessionReplacement(client, liveDecision);
        const session = await (0, spans_1.withSandboxSpan)('sandbox.resume_session', {
            agent_name: agent.name,
            backend_id: client.backendId,
        }, async () => await resumeSandboxSession(client, serializedState, {
            archiveLimits: this.sandboxConfig?.archiveLimits,
            clientOptions: this.sandboxConfig?.options,
            ...(clientPreparesEnvironment
                ? { trustedManifest: resumeTrustedManifest }
                : {}),
        }), tracingParent);
        return await this.replaceRejectedLiveSession(rejectedLiveEntry, session);
    }
    async prepareExplicitSessionStateForResume(client, trustedManifest, preResolvedTrustedManifest) {
        const persistedState = this.sandboxConfig.sessionState;
        const trustedManifestForPolicy = preResolvedTrustedManifest ?? trustedManifest;
        if (client.serializedSessionStateRequiresFreshCreation ||
            (0, mountSecurity_1.manifestHasInContainerMounts)(trustedManifestForPolicy) ||
            (0, mountSecurity_1.manifestHasNonResumableMountAuthority)(trustedManifestForPolicy) ||
            (0, mountSecurity_1.manifestHasInContainerMounts)(persistedState.manifest) ||
            (0, mountSecurity_1.manifestHasNonResumableMountAuthority)(persistedState.manifest)) {
            throw new errors_1.UserError(client.serializedSessionStateRequiresFreshCreation
                ? 'This sandbox provider cannot safely resume persisted session state. Create a fresh sandbox from current trusted configuration.'
                : 'Sandbox session state with in-container mounts cannot be resumed safely. Create a fresh sandbox from the current trusted manifest.');
        }
        const resolvedTrustedManifest = preResolvedTrustedManifest ??
            (0, sessionState_1.resolveTrustedManifestForResume)(client, trustedManifest, this.sandboxConfig?.options);
        if (client.backendId === 'docker' &&
            client.environmentPreparation !== 'client' &&
            Object.keys(persistedState.manifest.environment).some((key) => !(key in trustedManifestForPolicy.environment))) {
            throw new errors_1.UserError('Docker sandbox session state cannot be resumed because the current trusted manifest removes an environment variable. Start a fresh session from a snapshot instead.');
        }
        const topologyReboundState = (0, manifestPersistence_1.rebindPersistedMountCredentials)(persistedState, resolvedTrustedManifest);
        (0, manifestPersistence_1.assertMountCredentialsRebound)(topologyReboundState);
        if (!(0, mountSecurity_1.liveMountCredentialAuthorityMatches)(persistedState.manifest, resolvedTrustedManifest)) {
            throw new errors_2.SandboxMountError('Sandbox session state mount authority does not match the current trusted manifest. Create a fresh sandbox from current trusted configuration.', undefined, 'mount_config_invalid');
        }
        if (client.environmentPreparation === 'client') {
            (0, mountSecurity_1.validateMountCredentialBoundaries)(resolvedTrustedManifest);
            (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(resolvedTrustedManifest, {}, { preserveDeferredValuePresence: true });
            const pathReboundState = (0, manifestPersistence_1.rebindPersistedPathGrants)(topologyReboundState, resolvedTrustedManifest, {
                replaceWithTrustedManifest: client.backendId === 'docker',
            });
            (0, manifestPersistence_1.assertMountCredentialsRebound)(pathReboundState);
            (0, manifestPersistence_1.assertHostPathGrantsRebound)(pathReboundState);
            return {
                state: persistedState,
                trustedManifest: resolvedTrustedManifest,
            };
        }
        const materializedTrustedManifest = await (0, mountSecurity_1.resolveAndValidateMountEnvironment)(resolvedTrustedManifest);
        const credentialReboundState = (0, manifestPersistence_1.rebindPersistedMountCredentials)(topologyReboundState, materializedTrustedManifest);
        const sessionState = (0, manifestPersistence_1.rebindPersistedPathGrants)(credentialReboundState, materializedTrustedManifest, {
            replaceWithTrustedManifest: client.backendId === 'docker',
        });
        if (client.backendId === 'docker') {
            sessionState.environment = {
                ...(sessionState.environment ?? {}),
                ...(await materializedTrustedManifest.resolveEnvironment()),
            };
        }
        (0, manifestPersistence_1.assertMountCredentialsRebound)(sessionState);
        (0, mountSecurity_1.validateMountCredentialBoundaries)(sessionState.manifest);
        (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(sessionState.manifest, sessionState.environment ?? {});
        (0, manifestPersistence_1.assertHostPathGrantsRebound)(sessionState);
        return {
            state: sessionState,
            trustedManifest: materializedTrustedManifest,
        };
    }
    async inspectLivePreservedOwnedSessionReuse(args) {
        const liveEntry = (0, livePreservedSessions_1.livePreservedOwnedSession)({
            runState: this.runState,
            client: args.client,
            agentKey: args.agentKey,
            serializedEntry: args.serializedEntry,
        });
        if (!liveEntry) {
            return undefined;
        }
        const trustedManifest = args.trustedManifestAlreadyResolved
            ? args.trustedManifest
            : (0, sessionState_1.resolveTrustedManifestForResume)(args.client, args.trustedManifest, this.sandboxConfig?.options);
        (0, sessionState_1.assertTrustedManifestForDockerRunState)(args.client, trustedManifest);
        return await (0, providedSessionManifest_1.withExclusiveProvidedSessionManifestMutation)(liveEntry.session.state, async () => await (0, mountSecurity_1.withExclusiveSandboxStateInspection)(liveEntry.session.state, async () => {
            if (liveEntry.reuseRejected) {
                await serializedSessionStateRequiresFreshCreationForOptions(args.client, liveEntry.session.state, {
                    archiveLimits: this.sandboxConfig?.archiveLimits,
                    clientOptions: this.sandboxConfig?.options,
                    ...(args.client.environmentPreparation === 'client'
                        ? { trustedManifest }
                        : {}),
                });
                return {
                    entry: liveEntry,
                    reusable: false,
                    ...(args.client
                        .preservedOwnedSessionReuseRejectionRequiresFreshCreation ===
                        true
                        ? { mountAuthorityChanged: true }
                        : {}),
                };
            }
            if ((0, mountSecurity_1.isSandboxSessionStateUnsafe)(liveEntry.session.state)) {
                (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: liveEntry.session,
                });
                return {
                    entry: liveEntry,
                    reusable: false,
                    mountAuthorityChanged: true,
                };
            }
            if (!trustedManifest ||
                (0, mountSecurity_1.manifestHasNonResumableMountAuthority)(trustedManifest) ||
                !(0, mountSecurity_1.liveMountCredentialAuthorityMatches)(liveEntry.session.state.manifest, trustedManifest)) {
                (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: liveEntry.session,
                });
                return {
                    entry: liveEntry,
                    reusable: false,
                    mountAuthorityChanged: true,
                };
            }
            const canReuse = args.client.canReusePreservedOwnedSession;
            const clientPreparesEnvironment = args.client.environmentPreparation === 'client';
            if (args.client.backendId === 'docker' &&
                !clientPreparesEnvironment &&
                Object.keys(liveEntry.session.state.manifest.environment).some((key) => !(key in trustedManifest.environment))) {
                (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: liveEntry.session,
                });
                return { entry: liveEntry, reusable: false };
            }
            const hasDeferredEnvironmentValues = manifestHasDeferredEnvironmentValues(trustedManifest) ||
                manifestHasDeferredEnvironmentValues(liveEntry.session.state.manifest);
            if (clientPreparesEnvironment) {
                (0, mountSecurity_1.validateMountCredentialBoundaries)(trustedManifest);
                (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(trustedManifest, {}, {
                    preserveDeferredValuePresence: true,
                });
                const hasOtherMappedAlias = [...this.sessionsByAgentKey].some(([mappedAgentKey, mappedSession]) => mappedAgentKey !== args.agentKey &&
                    mappedSession === liveEntry.session);
                if (hasOtherMappedAlias &&
                    !(0, sessionState_1.clientPreparedManifestAuthoritiesMatch)(liveEntry.session.state.manifest, liveEntry.session.state.manifest, trustedManifest)) {
                    const requiresFreshCreation = args.client
                        .preservedOwnedSessionReuseRejectionRequiresFreshCreation ===
                        true;
                    (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                        state: this.runState,
                        session: liveEntry.session,
                    });
                    return {
                        entry: liveEntry,
                        reusable: false,
                        ...(requiresFreshCreation
                            ? { mountAuthorityChanged: true }
                            : {}),
                    };
                }
                if (!canReuse) {
                    const authorityMatches = !hasDeferredEnvironmentValues &&
                        (0, sessionState_1.clientPreparedManifestAuthoritiesMatch)(liveEntry.session.state.manifest, liveEntry.session.state.manifest, trustedManifest);
                    if (!authorityMatches) {
                        const requiresFreshCreation = args.client
                            .preservedOwnedSessionReuseRejectionRequiresFreshCreation ===
                            true;
                        (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                            state: this.runState,
                            session: liveEntry.session,
                        });
                        return {
                            entry: liveEntry,
                            reusable: false,
                            ...(requiresFreshCreation
                                ? { mountAuthorityChanged: true }
                                : {}),
                        };
                    }
                }
                else {
                    const reusable = await canReuse.call(args.client, liveEntry.session.state, {
                        clientOptions: this.sandboxConfig?.options,
                        revalidateManifestEntries: true,
                        trustedManifest,
                    });
                    if (!reusable) {
                        const requiresFreshCreation = args.client
                            .preservedOwnedSessionReuseRejectionRequiresFreshCreation ===
                            true;
                        (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                            state: this.runState,
                            session: liveEntry.session,
                        });
                        return {
                            entry: liveEntry,
                            reusable: false,
                            ...(requiresFreshCreation
                                ? { mountAuthorityChanged: true }
                                : {}),
                        };
                    }
                }
                args.client.rebindPreservedOwnedSessionState?.(liveEntry.session.state, {
                    clientOptions: this.sandboxConfig?.options,
                    revalidateManifestEntries: true,
                    trustedManifest,
                });
                bindClientPreparedTrustedManifest(liveEntry.session, trustedManifest);
                return { entry: liveEntry, reusable: true };
            }
            const candidateState = (0, manifestPersistence_1.rebindPersistedPathGrants)(liveEntry.session.state, trustedManifest, {
                replaceWithTrustedManifest: args.client.backendId === 'docker',
            });
            (0, manifest_1.replaceManifestMountCredentialExposurePolicy)(candidateState.manifest, trustedManifest);
            (0, mountSecurity_1.recordLiveMountCredentialAuthority)(candidateState.manifest, liveEntry.session.state.manifest);
            (0, mountSecurity_1.validateMountCredentialBoundaries)(trustedManifest);
            if (args.client.backendId === 'docker') {
                candidateState.environment = {
                    ...(liveEntry.session.state.environment ?? {}),
                    ...(await trustedManifest.resolveEnvironment()),
                };
            }
            if (!canReuse) {
                const trustedEnvironment = await trustedManifest.resolveEnvironment();
                if (!(0, mountSecurity_1.liveMountEnvironmentAuthorityMatches)(liveEntry.session.state.manifest, trustedManifest, trustedEnvironment)) {
                    (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                        state: this.runState,
                        session: liveEntry.session,
                    });
                    return {
                        entry: liveEntry,
                        reusable: false,
                        mountAuthorityChanged: true,
                    };
                }
                await refreshLiveEnvironmentReferences(candidateState, trustedManifest, trustedEnvironment);
            }
            else {
                const reusable = await canReuse.call(args.client, candidateState, {
                    clientOptions: this.sandboxConfig?.options,
                    revalidateManifestEntries: true,
                    trustedManifest,
                });
                if (!reusable) {
                    const requiresFreshCreation = args.client
                        .preservedOwnedSessionReuseRejectionRequiresFreshCreation ===
                        true;
                    (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                        state: this.runState,
                        session: liveEntry.session,
                    });
                    return {
                        entry: liveEntry,
                        reusable: false,
                        ...(requiresFreshCreation
                            ? { mountAuthorityChanged: true }
                            : {}),
                    };
                }
                if (args.client.backendId !== 'docker') {
                    await refreshLiveEnvironmentReferences(candidateState, trustedManifest);
                }
            }
            args.client.rebindPreservedOwnedSessionState?.(liveEntry.session.state, {
                clientOptions: this.sandboxConfig?.options,
                revalidateManifestEntries: true,
                trustedManifest,
            });
            // Rebind only after the backend has verified that its live authority still
            // matches the current trusted manifest.
            const reboundManifest = args.client.backendId === 'docker'
                ? manifestWithTrustedRuntimePolicies((0, manifestPersistence_1.rebindPersistedPathGrants)(liveEntry.session.state, trustedManifest, {
                    replaceWithTrustedGrantSet: true,
                }).manifest, trustedManifest)
                : candidateState.manifest;
            (0, mountSecurity_1.recordLiveMountCredentialAuthority)(reboundManifest, candidateState.manifest);
            liveEntry.session.state.manifest = reboundManifest;
            liveEntry.session.state.environment = candidateState.environment;
            return { entry: liveEntry, reusable: true };
        }));
    }
    async discardLiveSessionWithChangedMountAuthority(decision) {
        const session = decision.entry.session;
        const agentKeys = new Set([decision.entry.agentKey]);
        for (const entry of (0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(this.runState)) {
            if (entry.session === session) {
                agentKeys.add(entry.agentKey);
            }
        }
        for (const agentKey of this.detachSessionAliases(session)) {
            agentKeys.add(agentKey);
        }
        this.markSerializedSessionsRequireFreshCreation(agentKeys);
        for (const agentKey of agentKeys) {
            this.sessionsByAgentKey.delete(agentKey);
            this.sessionAgentNamesByKey.delete(agentKey);
            this.ownedSessionAgentKeys.delete(agentKey);
        }
        await (0, sessionLifecycle_1.cleanupSandboxSession)(decision.entry.session);
        (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
            state: this.runState,
            session,
        });
        this.invalidateSerializedSessions(agentKeys);
    }
    detachSessionAliases(session) {
        const detachedAgentKeys = new Set();
        for (const [agentKey, mappedSession] of this.sessionsByAgentKey) {
            if (mappedSession !== session) {
                continue;
            }
            detachedAgentKeys.add(agentKey);
            this.sessionsByAgentKey.delete(agentKey);
            this.sessionAgentNamesByKey.delete(agentKey);
            this.ownedSessionAgentKeys.delete(agentKey);
        }
        for (const [agentId, mappedSession] of this.sessionsByAgent) {
            if (mappedSession !== session) {
                continue;
            }
            this.sessionsByAgent.delete(agentId);
            if (this.currentAgentId === agentId) {
                this.currentAgentId = undefined;
            }
        }
        for (const [agentId, preparedSession] of this.preparedSessions) {
            if (preparedSession !== session) {
                continue;
            }
            this.preparedSessions.delete(agentId);
            this.preparedAgents.delete(agentId);
            this.preparedManifestSignatures.delete(agentId);
        }
        if (this.activeMemory?.session === session) {
            this.activeMemory = undefined;
        }
        return detachedAgentKeys;
    }
    invalidateSerializedSession(agentKey) {
        this.invalidateSerializedSessions(new Set([agentKey]));
    }
    markSerializedSessionsRequireFreshCreation(agentKeys) {
        const sandboxState = (0, sessionState_1.getSerializedSandboxState)(this.runState);
        if (!sandboxState) {
            return;
        }
        for (const agentKey of agentKeys) {
            const entry = sandboxState.sessionsByAgent[agentKey];
            if (!entry) {
                continue;
            }
            entry.preservedOwnedSession = true;
            entry.reuseLiveSession = false;
            entry.requiresFreshCreation = true;
        }
    }
    invalidateSerializedSessions(agentKeys) {
        const sandboxState = (0, sessionState_1.getSerializedSandboxState)(this.runState);
        const agentKeysWithLiveHandles = new Set(this.runState
            ? (0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(this.runState).map((entry) => entry.agentKey)
            : []);
        const removableAgentKeys = new Set([...agentKeys].filter((agentKey) => !agentKeysWithLiveHandles.has(agentKey)));
        if (sandboxState &&
            removableAgentKeys.size > 0 &&
            !removeClosedSerializedSessions(sandboxState, removableAgentKeys)) {
            this.runState._sandbox = undefined;
        }
    }
    async prepareRejectedLiveSessionReplacement(client, decision) {
        if (!decision || decision.reusable) {
            return undefined;
        }
        (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
            state: this.runState,
            session: decision.entry.session,
        });
        if (client.backendId === 'docker') {
            return decision.entry;
        }
        this.detachSessionAliases(decision.entry.session);
        await (0, sessionLifecycle_1.cleanupSandboxSession)(decision.entry.session);
        (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
            state: this.runState,
            session: decision.entry.session,
        });
        return undefined;
    }
    async replaceRejectedLiveSession(rejectedEntry, replacement) {
        if (!rejectedEntry) {
            return replacement;
        }
        (0, livePreservedSessions_1.rememberRejectedLivePreservedOwnedSessionHandle)({
            state: this.runState,
            source: rejectedEntry,
            session: replacement,
        });
        this.detachSessionAliases(rejectedEntry.session);
        try {
            await (0, sessionLifecycle_1.cleanupSandboxSession)(rejectedEntry.session);
        }
        catch (rejectedCleanupError) {
            try {
                await (0, sessionLifecycle_1.cleanupSandboxSession)(replacement);
                (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: replacement,
                });
            }
            catch (replacementCleanupError) {
                throw new errors_2.SandboxLifecycleError('Failed to close the rejected live sandbox session and its replacement.', {
                    errors: [rejectedCleanupError, replacementCleanupError],
                });
            }
            throw rejectedCleanupError;
        }
        (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
            state: this.runState,
            session: rejectedEntry.session,
        });
        const siblingRejectedSessions = new Set(this.runState
            ? (0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(this.runState)
                .filter((entry) => entry.reuseRejected &&
                entry.agentKey === rejectedEntry.agentKey &&
                entry.session !== replacement)
                .map((entry) => entry.session)
            : []);
        const siblingCleanupErrors = [];
        for (const siblingSession of siblingRejectedSessions) {
            this.detachSessionAliases(siblingSession);
            try {
                await (0, sessionLifecycle_1.cleanupSandboxSession)(siblingSession);
                (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: siblingSession,
                });
            }
            catch (error) {
                siblingCleanupErrors.push(error);
            }
        }
        if (siblingCleanupErrors.length > 0) {
            try {
                await (0, sessionLifecycle_1.cleanupSandboxSession)(replacement);
                (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
                    state: this.runState,
                    session: replacement,
                });
            }
            catch (replacementCleanupError) {
                siblingCleanupErrors.push(replacementCleanupError);
            }
            throw lifecycleErrorForCloseErrors('Failed to close rejected live sandbox session handles and their replacement.', siblingCleanupErrors);
        }
        (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
            state: this.runState,
            session: replacement,
        });
        return replacement;
    }
    async serializeState(args = {}) {
        const currentAgent = this.currentAgentId
            ? this.acquiredAgents.get(this.currentAgentId)
            : undefined;
        const sandboxState = (0, sessionState_1.getSerializedSandboxState)(this.runState);
        const preferredCurrentAgentKey = currentAgent
            ? this.agentKey(currentAgent)
            : sandboxState?.currentAgentKey;
        const retainedRejectedAgentKeys = new Set(this.runState
            ? (0, livePreservedSessions_1.livePreservedOwnedSessionEntries)(this.runState)
                .filter((entry) => entry.reuseRejected)
                .map((entry) => entry.agentKey)
            : []);
        return await (0, sessionSerialization_1.serializeSandboxRuntimeState)({
            client: this.sandboxConfig?.client,
            sandboxState,
            sessionsByAgentKey: this.sessionsByAgentKey,
            sessionAgentNamesByKey: this.sessionAgentNamesByKey,
            ownedSessionAgentKeys: this.ownedSessionAgentKeys,
            trustedManifestForAgentKey: (agentKey) => (0, sessionState_1.resolveTrustedManifestForResume)(this.sandboxConfig.client, this.resolveTrustedManifestForAgentKey(agentKey, this.ownedSessionAgentKeys.has(agentKey)
                ? undefined
                : this.sessionsByAgentKey.get(agentKey)), this.sandboxConfig?.options),
            clientOptions: this.sandboxConfig?.options,
            includeOwnedSessions: args.includeOwnedSessions,
            preferredCurrentAgentKey,
            retainedPreservedOwnedSessionAgentKeys: retainedRejectedAgentKeys,
        });
    }
    requireClient() {
        if (!this.sandboxConfig?.client) {
            throw new errors_1.UserError('Sandbox execution requires `RunConfig.sandbox.client` unless a live session is provided.');
        }
        return this.sandboxConfig.client;
    }
    resolveSnapshotSpec(client) {
        if (this.sandboxConfig?.snapshot) {
            return this.sandboxConfig.snapshot;
        }
        if (!client.supportsDefaultOptions) {
            return undefined;
        }
        return { type: 'local' };
    }
    agentKey(agent) {
        const agentId = (0, agentKeys_1.getObjectId)(agent);
        const existing = this.agentKeys.get(agentId);
        if (existing) {
            this.agentsByKey.set(existing, agent);
            return existing;
        }
        const agentKey = this.allocateRuntimeAgentKey(agent.name);
        this.agentKeys.set(agentId, agentKey);
        this.agentsByKey.set(agentKey, agent);
        return agentKey;
    }
    allocateRuntimeAgentKey(agentName) {
        const usedKeys = new Set(this.agentKeys.values());
        if (!usedKeys.has(agentName)) {
            return agentName;
        }
        let suffix = 2;
        while (usedKeys.has(`${agentName}_${suffix}`)) {
            suffix += 1;
        }
        return `${agentName}_${suffix}`;
    }
    resolveConfiguredManifest(agent, options = {}) {
        const baseManifest = this.sandboxConfig?.manifest ??
            agent.defaultManifest ??
            options.providedSession?.state.manifest;
        const initialManifest = baseManifest
            ? (0, manifest_1.cloneManifest)(baseManifest)
            : new manifest_1.Manifest();
        const manifestWithIdentity = options.providedSession
            ? initialManifest
            : (0, runAsManifest_1.manifestWithRunAsUser)(initialManifest, agent.runAs);
        const configuredManifest = (0, agentPreparation_1.cloneSandboxCapabilities)(agent.capabilities).reduce((manifest, capability) => capability.processManifest(manifest), manifestWithIdentity);
        // Passing a truly default manifest to providers can override their natural root
        // defaults, so create() receives a manifest only when configuration changed it.
        return {
            manifest: configuredManifest,
            passToCreate: baseManifest !== undefined || !isDefaultManifest(configuredManifest),
        };
    }
    resolveTrustedManifestForAgentKey(agentKey, providedSession) {
        const agent = this.agentsByKey.get(agentKey);
        if (!agent || !(0, agentKeys_1.isSandboxAgent)(agent)) {
            return undefined;
        }
        return this.resolveConfiguredManifest(agent, { providedSession }).manifest;
    }
    async closeOwnedSessions(agentKeys, options = {}) {
        const keysToClose = [...(agentKeys ?? this.ownedSessionAgentKeys)].filter((agentKey) => this.ownedSessionAgentKeys.has(agentKey));
        const sessionsToClose = new Map();
        for (const agentKey of keysToClose) {
            const session = this.sessionsByAgentKey.get(agentKey);
            if (!session || !(0, sessionLifecycle_1.hasSessionCleanup)(session)) {
                continue;
            }
            const existing = sessionsToClose.get(session);
            if (existing) {
                existing.agentKeys.push(agentKey);
            }
            else {
                sessionsToClose.set(session, {
                    agentKeys: [agentKey],
                    agentName: this.sessionAgentNamesByKey.get(agentKey),
                });
            }
        }
        if (sessionsToClose.size === 0) {
            return { closedAgentKeys: new Set(), closeErrors: [] };
        }
        const closedAgentKeys = new Set();
        const closeErrors = [];
        await (0, spans_1.withSandboxSpan)('sandbox.cleanup_sessions', {
            session_count: sessionsToClose.size,
        }, async (cleanupSessionsSpan) => {
            const sessions = [...sessionsToClose];
            const results = await Promise.allSettled(sessions.map(async ([session, { agentName }]) => {
                await (0, spans_1.withSandboxSpan)('sandbox.shutdown', {
                    agent_name: agentName,
                }, async () => {
                    (0, livePreservedSessions_1.rejectLivePreservedOwnedSessionHandle)({
                        state: this.runState,
                        session,
                    });
                    await (0, sessionLifecycle_1.cleanupSandboxSession)(session);
                    (0, livePreservedSessions_1.forgetLivePreservedOwnedSessionHandle)({
                        state: this.runState,
                        session,
                    });
                }, cleanupSessionsSpan);
            }));
            for (const [index, result] of results.entries()) {
                const [session, { agentKeys }] = sessions[index];
                if (result.status === 'rejected') {
                    closeErrors.push(result.reason);
                    continue;
                }
                const closedKeys = new Set(agentKeys);
                if (options.removeClosedSessionsFromSandboxState) {
                    this.invalidateSerializedSessions(closedKeys);
                }
                for (const agentKey of closedKeys) {
                    this.sessionsByAgentKey.delete(agentKey);
                    this.sessionAgentNamesByKey.delete(agentKey);
                    this.ownedSessionAgentKeys.delete(agentKey);
                    closedAgentKeys.add(agentKey);
                }
                for (const [agentId, mappedSession] of this.sessionsByAgent) {
                    if (mappedSession === session) {
                        this.sessionsByAgent.delete(agentId);
                        if (this.currentAgentId === agentId) {
                            this.currentAgentId = undefined;
                        }
                    }
                }
                for (const [agentId, preparedSession] of this.preparedSessions) {
                    if (preparedSession === session) {
                        this.preparedSessions.delete(agentId);
                        this.preparedAgents.delete(agentId);
                        this.preparedManifestSignatures.delete(agentId);
                    }
                }
                if (this.activeMemory?.session === session) {
                    this.activeMemory = undefined;
                }
            }
        }, options.tracingParent);
        return { closedAgentKeys, closeErrors };
    }
    releaseAgents() {
        (0, agentKeys_1.releaseSandboxAgents)(this.acquiredAgents.values());
        this.acquiredAgents.clear();
    }
}
exports.SandboxRuntimeManager = SandboxRuntimeManager;
function getManifestSignature(manifest) {
    return (0, stableJson_1.stableJsonStringify)({
        version: manifest.version,
        root: manifest.root,
        entries: manifest.entries,
        environment: (0, environment_1.serializeManifestEnvironment)(manifest),
        users: manifest.users,
        groups: manifest.groups,
        extraPathGrants: manifest.extraPathGrants,
        remoteMountCommandAllowlist: manifest.remoteMountCommandAllowlist,
        mountCredentialExposure: manifest.mountTargets().map(({ mountPath }) => ({
            mountPath,
            mountScoped: (0, manifest_1.manifestAcknowledgesInContainerMountCredentialExposure)(manifest, mountPath, 'mount_scoped'),
            broad: (0, manifest_1.manifestAcknowledgesInContainerMountCredentialExposure)(manifest, mountPath, 'broad'),
        })),
    });
}
function isDefaultManifest(manifest) {
    const defaultManifest = new manifest_1.Manifest();
    return (manifest.version === defaultManifest.version &&
        manifest.root === defaultManifest.root &&
        Object.keys(manifest.entries).length === 0 &&
        Object.keys(manifest.environment).length === 0 &&
        manifest.users.length === 0 &&
        manifest.groups.length === 0 &&
        manifest.extraPathGrants.length === 0 &&
        (0, remoteMountCommandAllowlist_1.isDefaultRemoteMountCommandAllowlist)(manifest.remoteMountCommandAllowlist));
}
function manifestWithTrustedRuntimePolicies(manifest, trustedManifest) {
    const merged = new manifest_1.Manifest({
        version: manifest.version,
        root: manifest.root,
        entries: structuredClone(manifest.entries),
        environment: Object.fromEntries(Object.entries(trustedManifest.environment).map(([key, value]) => [
            key,
            value.init(),
        ])),
        users: structuredClone(manifest.users),
        groups: structuredClone(manifest.groups),
        extraPathGrants: structuredClone(manifest.extraPathGrants),
        remoteMountCommandAllowlist: [
            ...trustedManifest.remoteMountCommandAllowlist,
        ],
    });
    (0, manifest_1.replaceManifestMountCredentialExposurePolicy)(merged, trustedManifest);
    return merged;
}
function manifestHasDeferredEnvironmentValues(manifest) {
    return Object.values(manifest.environment).some((value) => (0, manifest_1.isEnvValueReference)(value) || value.resolver !== undefined);
}
async function resumeSandboxSession(client, state, options) {
    if (client.environmentPreparation !== 'client') {
        return await client.resume(state, options);
    }
    const session = await (0, providedSessionManifest_1.withExclusiveProvidedSessionManifestMutation)(state, () => (0, mountSecurity_1.withExclusiveSandboxStateInspection)(state, async () => {
        const previousManifest = state.manifest;
        const rebound = (0, manifestPersistence_1.rebindPersistedPathGrants)((0, manifestPersistence_1.rebindPersistedMountCredentials)(state, options.trustedManifest), options.trustedManifest, { replaceWithTrustedManifest: client.backendId === 'docker' });
        (0, manifestPersistence_1.assertMountCredentialsRebound)(rebound);
        (0, manifestPersistence_1.assertHostPathGrantsRebound)(rebound);
        // Preserve branded provider state while restoring SDK-owned authority before
        // the provider can use it. A failed resume must leave the input retryable.
        state.manifest = rebound.manifest;
        try {
            const resumed = await client.resume(state, options);
            if (resumed.state === state) {
                bindClientPreparedTrustedManifest(resumed, options.trustedManifest);
            }
            return resumed;
        }
        catch (error) {
            state.manifest = previousManifest;
            throw error;
        }
    }));
    if (session.state !== state) {
        // Do not hold the input lock while acquiring a distinct returned-state lock.
        await (0, providedSessionManifest_1.withExclusiveProvidedSessionManifestMutation)(session.state, () => (0, mountSecurity_1.withExclusiveSandboxStateInspection)(session.state, async () => {
            bindClientPreparedTrustedManifest(session, options.trustedManifest);
        }));
    }
    return session;
}
function bindClientPreparedTrustedManifest(session, trustedManifest) {
    const runnerManifest = (0, sessionState_1.mergeClientPreparedManifestAuthority)(session.state.manifest, trustedManifest);
    (0, mountSecurity_1.recordLiveMountCredentialAuthority)(runnerManifest, trustedManifest);
    session.state.manifest = runnerManifest;
}
async function refreshLiveEnvironmentReferences(state, trustedManifest, resolvedTrustedEnvironment) {
    if (!trustedManifest) {
        return;
    }
    const referenceKeys = new Set([
        ...Object.entries(state.manifest.environment)
            .filter(([, value]) => (0, manifest_1.isEnvValueReference)(value))
            .map(([key]) => key),
        ...Object.entries(trustedManifest.environment)
            .filter(([, value]) => (0, manifest_1.isEnvValueReference)(value))
            .map(([key]) => key),
    ]);
    if (referenceKeys.size === 0) {
        return;
    }
    const resolvedEnvironment = Object.fromEntries((await Promise.all([...referenceKeys].map(async (key) => {
        const value = trustedManifest.environment[key];
        return value
            ? [
                key,
                resolvedTrustedEnvironment?.[key] ?? (await value.resolve()),
            ]
            : undefined;
    }))).filter((entry) => entry !== undefined));
    const environment = { ...(state.environment ?? {}) };
    const manifestEnvironment = Object.fromEntries(Object.entries(state.manifest.environment)
        .filter(([key]) => !referenceKeys.has(key))
        .map(([key, value]) => [key, value.init()]));
    for (const key of referenceKeys) {
        delete environment[key];
        const value = trustedManifest.environment[key];
        if (value) {
            manifestEnvironment[key] = value.init();
        }
    }
    const manifest = new manifest_1.Manifest({
        version: state.manifest.version,
        root: state.manifest.root,
        entries: structuredClone(state.manifest.entries),
        environment: manifestEnvironment,
        users: structuredClone(state.manifest.users),
        groups: structuredClone(state.manifest.groups),
        extraPathGrants: structuredClone(state.manifest.extraPathGrants),
        remoteMountCommandAllowlist: [
            ...state.manifest.remoteMountCommandAllowlist,
        ],
    });
    (0, manifest_1.replaceManifestMountCredentialExposurePolicy)(manifest, state.manifest);
    (0, mountSecurity_1.recordLiveMountCredentialAuthority)(manifest, state.manifest);
    state.environment = {
        ...environment,
        ...resolvedEnvironment,
    };
    state.manifest = manifest;
}
function removeClosedPreservedOwnedSessions(sandboxState, agentKeys) {
    return removeClosedSerializedSessions(sandboxState, agentKeys, {
        requirePreservedSession: true,
    });
}
async function serializedSessionStateRequiresFreshCreationForOptions(client, state, options = {}) {
    return ((await client.serializedSessionStateRequiresFreshCreationForOptions?.(state, options)) ?? false);
}
function serializedOwnedSessionReplacementError(client) {
    return new errors_1.UserError(`Sandbox client "${client.backendId}" cannot safely replace an owned sandbox from untrusted serialized state because remote ownership cannot be verified. Reconnect through a caller-managed sandbox selection, or explicitly clean up the old sandbox before starting a new run.`);
}
function lifecycleErrorForCloseErrors(message, errors) {
    return errors.length === 1
        ? errors[0]
        : new errors_2.SandboxLifecycleError(message, { errors });
}
function removeClosedSerializedSessions(sandboxState, agentKeys, options = {}) {
    for (const agentKey of agentKeys) {
        delete sandboxState.sessionsByAgent[agentKey];
    }
    const remainingEntries = Object.values(sandboxState.sessionsByAgent);
    if (options.requirePreservedSession &&
        !remainingEntries.some((entry) => entry.preservedOwnedSession)) {
        return false;
    }
    const currentEntry = sandboxState.sessionsByAgent[sandboxState.currentAgentKey];
    if (currentEntry) {
        sandboxState.currentAgentName = currentEntry.currentAgentName;
        sandboxState.sessionState = currentEntry.sessionState;
        return true;
    }
    const nextEntry = options.requirePreservedSession
        ? remainingEntries.find((entry) => entry.preservedOwnedSession)
        : remainingEntries[0];
    if (!nextEntry) {
        return false;
    }
    sandboxState.currentAgentKey = nextEntry.currentAgentKey;
    sandboxState.currentAgentName = nextEntry.currentAgentName;
    sandboxState.sessionState = nextEntry.sessionState;
    return true;
}
//# sourceMappingURL=manager.js.map