UNPKG

@openai/agents-core

Version:

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

240 lines • 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.applyManifestToProvidedSession = applyManifestToProvidedSession; exports.withExclusiveProvidedSessionManifestMutation = withExclusiveProvidedSessionManifestMutation; const errors_1 = require("../../errors.js"); const entries_1 = require("../entries/index.js"); const manifest_1 = require("../manifest.js"); const compare_1 = require("../shared/compare.js"); const environment_1 = require("../shared/environment.js"); const manifestCollections_1 = require("../shared/manifestCollections.js"); const remoteMountCommandAllowlist_1 = require("../shared/remoteMountCommandAllowlist.js"); const manifestPersistence_1 = require("../sandboxes/shared/manifestPersistence.js"); const mountSecurity_1 = require("../mountSecurity.js"); const providedSessionManifestMutationTails = new WeakMap(); async function applyManifestToProvidedSession(session, manifest, runAs) { return await withExclusiveProvidedSessionManifestMutation(session.state, async () => applyManifestToProvidedSessionExclusive(session, manifest, runAs)); } async function applyManifestToProvidedSessionExclusive(session, manifest, runAs) { (0, mountSecurity_1.assertSandboxSessionStateUsable)(session.state); const currentManifest = session.state.manifest; const currentManifestSnapshot = (0, manifest_1.cloneManifest)(currentManifest); const currentEnvironment = { ...(0, environment_1.materializeStaticEnvironment)(currentManifest), ...(session.state.environment ?? {}), }; (0, mountSecurity_1.validateMountCredentialBoundaries)(currentManifest); (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(currentManifest, currentEnvironment); // A provided session may already have long-lived processes, mounts, or provider // state, so only additive file materialization is allowed after validation. validateProvidedSessionManifestUpdate(currentManifest, manifest); const manifestDelta = buildProvidedSessionManifestDelta(currentManifest, manifest); const nextManifest = (0, manifestPersistence_1.mergeManifestDelta)(currentManifest, manifestDelta); if (currentManifest.mountTargets().length > 0) { const nextTrustedManifest = mergeProvidedMountAuthority(nextManifest, currentManifest, manifest); (0, mountSecurity_1.assertLiveMountCredentialAuthorityMatches)(currentManifest, nextTrustedManifest); const trustedEnvironment = await nextTrustedManifest.resolveEnvironment(); (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(nextTrustedManifest, trustedEnvironment); (0, mountSecurity_1.assertLiveMountEnvironmentAuthorityMatches)(currentManifest, nextTrustedManifest, trustedEnvironment); } if (isManifestDeltaEmpty(manifestDelta)) { return; } const nextEnvironment = { ...(0, environment_1.materializeStaticEnvironment)(nextManifest), ...(session.state.environment ?? {}), }; (0, mountSecurity_1.validateMountCredentialBoundaries)(nextManifest); (0, mountSecurity_1.validateMountEnvironmentCredentialBoundaries)(nextManifest, nextEnvironment); if (session.applyManifest) { await session.applyManifest(manifestDelta, runAs); } else { if (Object.keys(manifestDelta.entries).length > 0) { if (!session.materializeEntry) { throw new errors_1.UserError('Provided sandbox sessions must support applyManifest() or materializeEntry() when the agent declares manifest entries.'); } for (const [path, entry] of Object.entries(manifestDelta.entries)) { await session.materializeEntry({ path, entry, runAs, }); } } } // The helper owns the logical state commit after provider effects succeed. // Merge through the latest provider-visible state so released side-effect-only // implementations and concurrent additive provider updates remain supported, // while entries present before the callback cannot be dropped by a stale or // destructive provider commit. const committedManifest = (0, manifestPersistence_1.mergeManifestDelta)((0, manifestPersistence_1.mergeManifestDelta)(currentManifestSnapshot, session.state.manifest), manifestDelta); (0, mountSecurity_1.recordLiveMountCredentialAuthority)(committedManifest, session.state.manifest); session.state.manifest = committedManifest; } function mergeProvidedMountAuthority(nextManifest, currentManifest, targetManifest) { const currentMountPaths = new Set(currentManifest.mountTargets().map(({ logicalPath }) => logicalPath)); let trustedManifest = nextManifest; for (const { logicalPath, entry } of targetManifest.iterEntries()) { if ((0, entries_1.isMount)(entry) && currentMountPaths.has(logicalPath)) { trustedManifest = (0, manifestPersistence_1.mergeManifestEntryDelta)(trustedManifest, logicalPath, entry); } } (0, manifest_1.copyManifestMountCredentialExposurePolicy)(trustedManifest, nextManifest, targetManifest); return trustedManifest; } async function withExclusiveProvidedSessionManifestMutation(state, operation) { const previous = providedSessionManifestMutationTails.get(state) ?? Promise.resolve(); let release; const turn = new Promise((resolve) => { release = resolve; }); const tail = previous.catch(() => { }).then(() => turn); providedSessionManifestMutationTails.set(state, tail); await previous.catch(() => { }); try { return await operation(); } finally { release(); if (providedSessionManifestMutationTails.get(state) === tail) { providedSessionManifestMutationTails.delete(state); } } } function validateProvidedSessionManifestUpdate(current, target) { if (current.root !== target.root) { throw new errors_1.UserError('Live sandbox sessions cannot change manifest.root. Create or resume a session with the desired root instead.'); } validateNoEnvironmentDelta(current, target); validateNoAddedOrChangedNamedObjects('users', current.users, target.users); validateNoAddedOrChangedNamedObjects('groups', current.groups, target.groups); validateProvidedEntryUpdates(current, target); } function validateNoEnvironmentDelta(current, target) { const currentEnvironment = (0, environment_1.serializeManifestEnvironment)(current); const targetEnvironment = (0, environment_1.serializeManifestEnvironment)(target); const hasDelta = Object.entries(targetEnvironment).some(([key, value]) => !(0, compare_1.jsonEqual)(currentEnvironment[key], value)); if (hasDelta) { throw new errors_1.UserError('Live sandbox sessions cannot change manifest environment variables. Create or resume a session with the desired environment instead.'); } } function validateNoAddedOrChangedNamedObjects(label, current, target) { if ((0, manifestCollections_1.addedOrChangedNamedObjects)(current, target).length > 0) { throw new errors_1.UserError(`Live sandbox sessions cannot change manifest ${label}. Create or resume a session with the desired ${label} instead.`); } } function validateProvidedEntryUpdates(current, target) { const activeMountAuthorityMatches = (0, mountSecurity_1.liveMountCredentialAuthorityMatches)(current, target); const currentEntriesByPath = new Map([...current.iterEntries()].map(({ logicalPath, entry }) => [ logicalPath, entry, ])); for (const { logicalPath, entry } of target.iterEntries()) { const existingEntry = currentEntriesByPath.get(logicalPath); if (!existingEntry) { if ((0, entries_1.isMount)(entry)) { throw new errors_1.UserError(`Live sandbox sessions cannot add mount entries: ${logicalPath || '.'}`); } continue; } if (existingEntry.type !== entry.type) { throw new errors_1.UserError(`Live sandbox sessions cannot replace manifest entry types: ${logicalPath || '.'}`); } if ((0, entries_1.isMount)(existingEntry) || (0, entries_1.isMount)(entry)) { if (!(0, compare_1.jsonEqual)(existingEntry, entry) && !activeMountAuthorityMatches) { throw new errors_1.UserError(`Live sandbox sessions cannot change mount entries: ${logicalPath || '.'}`); } continue; } if ((0, entries_1.isDir)(existingEntry) && (0, entries_1.isDir)(entry)) { if (!(0, compare_1.jsonEqual)(manifestEntryWithoutDirChildren(existingEntry), manifestEntryWithoutDirChildren(entry))) { throw new errors_1.UserError(`Live sandbox sessions cannot change manifest entries: ${logicalPath || '.'}`); } continue; } if (!(0, compare_1.jsonEqual)(existingEntry, entry)) { throw new errors_1.UserError(`Live sandbox sessions cannot change manifest entries: ${logicalPath || '.'}`); } } } function manifestEntryWithoutDirChildren(entry) { if (!(0, entries_1.isDir)(entry)) { return entry; } const { children: _children, ...rest } = entry; return rest; } function buildProvidedSessionManifestDelta(current, target) { const currentEntriesByPath = new Map([...current.iterEntries()].map(({ logicalPath, entry }) => [ logicalPath, entry, ])); const currentExistingPaths = new Set(); for (const path of currentEntriesByPath.keys()) { addManifestPathAndParents(currentExistingPaths, path); } const entries = {}; for (const [path, entry] of Object.entries(target.entries)) { visitProvidedSessionTargetEntry(entries, currentEntriesByPath, currentExistingPaths, (0, manifest_1.normalizeRelativePath)(path), entry); } const users = (0, manifestCollections_1.addedOrChangedNamedObjects)(current.users, target.users); const groups = (0, manifestCollections_1.addedOrChangedNamedObjects)(current.groups, target.groups); const extraPathGrants = (0, manifestCollections_1.addedOrChangedPathKeyedObjects)(current.extraPathGrants, target.extraPathGrants); const hasRemoteMountCommandAllowlistDelta = !(0, remoteMountCommandAllowlist_1.isDefaultRemoteMountCommandAllowlist)(target.remoteMountCommandAllowlist) && !(0, compare_1.arraysEqual)(current.remoteMountCommandAllowlist, target.remoteMountCommandAllowlist); // Avoid sending the default allowlist as a delta because doing so would overwrite a // provider's existing customized allowlist on an already-running session. return new manifest_1.Manifest({ root: current.root, entries, users, groups, extraPathGrants, ...(hasRemoteMountCommandAllowlistDelta ? { remoteMountCommandAllowlist: [...target.remoteMountCommandAllowlist], } : {}), }); } function visitProvidedSessionTargetEntry(entries, currentEntriesByPath, currentExistingPaths, logicalPath, entry) { if (!currentExistingPaths.has(logicalPath)) { entries[logicalPath] = structuredClone(entry); return; } // Existing directories are containers for additive children; their own metadata was // already checked by validateProvidedEntryUpdates(). if (!(0, entries_1.isDir)(entry) || !entry.children) { return; } const currentEntry = currentEntriesByPath.get(logicalPath); if (currentEntry && !(0, entries_1.isDir)(currentEntry)) { return; } for (const [childPath, childEntry] of Object.entries(entry.children)) { const normalizedChildPath = (0, manifest_1.normalizeRelativePath)(childPath); const childLogicalPath = logicalPath ? `${logicalPath}/${normalizedChildPath}` : normalizedChildPath; visitProvidedSessionTargetEntry(entries, currentEntriesByPath, currentExistingPaths, childLogicalPath, childEntry); } } function addManifestPathAndParents(paths, logicalPath) { if (!logicalPath) { return; } const segments = logicalPath.split('/'); for (let index = 1; index <= segments.length; index += 1) { paths.add(segments.slice(0, index).join('/')); } } function isManifestDeltaEmpty(manifest) { return (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)); } //# sourceMappingURL=providedSessionManifest.js.map