UNPKG

@openai/agents-core

Version:

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

248 lines • 8.69 kB
import { cloneManifest, Manifest } from "../sandbox/manifest.mjs"; import { snapshotTestingValue } from "../utils/testingSnapshot.mjs"; export class InvalidScriptedSandboxStepError extends Error { reason; /** The zero-based position of the invalid factory input. */ inputIndex; method; constructor(options) { super(options.message); this.name = 'InvalidScriptedSandboxStepError'; this.reason = options.reason; this.inputIndex = options.inputIndex; this.method = options.method; } } export class UnexpectedSandboxCallError extends Error { /** The zero-based position of the call in `calls`. */ callIndex; actualMethod; expectedMethod; remainingSteps; constructor(options) { const expectation = options.expectedMethod ? `; expected ${options.expectedMethod}` : '; no scripted steps remain'; super(`Scripted sandbox session received unexpected ${options.actualMethod} call #${displayIndex(options.callIndex)}${expectation}.`); this.name = 'UnexpectedSandboxCallError'; this.callIndex = options.callIndex; this.actualMethod = options.actualMethod; this.expectedMethod = options.expectedMethod; this.remainingSteps = options.remainingSteps; } } export class SandboxCallMatcherError extends Error { /** The zero-based position of the call in `calls`. */ callIndex; method; constructor(call) { super(`Scripted sandbox session matcher rejected ${call.method} call #${displayIndex(call.index)}.`); this.name = 'SandboxCallMatcherError'; this.callIndex = call.index; this.method = call.method; } } export class UnconsumedSandboxStepsError extends Error { remainingSteps; pendingMethods; constructor(pendingMethods) { super(`Scripted sandbox session has ${pendingMethods.length} unconsumed step${pendingMethods.length === 1 ? '' : 's'}: ${pendingMethods.join(', ')}.`); this.name = 'UnconsumedSandboxStepsError'; this.remainingSteps = pendingMethods.length; this.pendingMethods = Object.freeze([...pendingMethods]); } } const sandboxMethodModes = { start: 'async', running: 'async', registerPreStopHook: 'sync', runPreStopHooks: 'async', preStop: 'async', stop: 'async', shutdown: 'async', delete: 'async', createEditor: 'sync', exec: 'async', execCommand: 'async', writeStdin: 'async', viewImage: 'async', readFile: 'async', listDir: 'async', pathExists: 'async', directoryExists: 'async', materializeEntry: 'async', applyManifest: 'async', persistWorkspace: 'async', hydrateWorkspace: 'async', setArchiveLimits: 'sync', resolveExposedPort: 'async', supportsPty: 'sync', close: 'async', }; export function scriptedSandboxSession(inputs = []) { const steps = Array.from(inputs, (input, index) => normalizeInput(input, index)); const calls = []; const configuredMethods = new Set(steps.map((step) => step.method)); const state = { manifest: new Manifest() }; const session = { state }; const invoke = (method, args) => { const call = Object.freeze({ index: calls.length, method, args: Object.freeze(snapshotSandboxCallArgs(method, args)), }); calls.push(call); const step = steps.shift(); if (!step || step.method !== method) { throw new UnexpectedSandboxCallError({ callIndex: call.index, actualMethod: method, expectedMethod: step?.method, remainingSteps: steps.length, }); } if (step.match) { const matchArgs = snapshotSandboxCallArgs(method, call.args); if (step.match(...matchArgs) === false) { throw new SandboxCallMatcherError(call); } } if (step.type === 'error') { throw step.error; } if (step.type === 'responder') { return step.respond(snapshotRecordedCall(call)); } return step.result; }; for (const method of configuredMethods) { const scriptedMethod = (...args) => { if (sandboxMethodModes[method] === 'sync') { return invoke(method, args); } try { return Promise.resolve(invoke(method, args)); } catch (error) { return Promise.reject(error); } }; Object.defineProperty(session, method, { configurable: false, enumerable: true, value: scriptedMethod, writable: true, }); } Object.defineProperties(session, { calls: { configurable: false, enumerable: true, get: () => Object.freeze(calls.map(snapshotRecordedCall)), }, remainingSteps: { configurable: false, enumerable: true, get: () => steps.length, }, assertComplete: { configurable: false, enumerable: true, value: () => { if (steps.length > 0) { throw new UnconsumedSandboxStepsError(steps.map((step) => step.method)); } }, writable: false, }, }); return session; } function normalizeInput(input, inputIndex) { if (!isRecord(input)) { throw new InvalidScriptedSandboxStepError({ reason: 'invalid_input', inputIndex, message: `Scripted sandbox step #${displayIndex(inputIndex)} must be an object.`, }); } const method = input.method; if (typeof method !== 'string' || !Object.prototype.hasOwnProperty.call(sandboxMethodModes, method)) { throw new InvalidScriptedSandboxStepError({ reason: 'unknown_method', inputIndex, method: typeof method === 'string' ? method : undefined, message: `Scripted sandbox step #${displayIndex(inputIndex)} has an unknown method.`, }); } if (typeof input.match !== 'undefined' && typeof input.match !== 'function') { throw new InvalidScriptedSandboxStepError({ reason: 'invalid_matcher', inputIndex, method, message: `Scripted sandbox step #${displayIndex(inputIndex)} for ${method} must use a function matcher.`, }); } const hasResult = Object.prototype.hasOwnProperty.call(input, 'result'); const hasResponder = Object.prototype.hasOwnProperty.call(input, 'respond'); const hasError = Object.prototype.hasOwnProperty.call(input, 'error'); if (Number(hasResult) + Number(hasResponder) + Number(hasError) !== 1) { throw new InvalidScriptedSandboxStepError({ reason: 'invalid_outcome', inputIndex, method, message: `Scripted sandbox step #${displayIndex(inputIndex)} for ${method} must define exactly one of result, respond, or error.`, }); } const base = { method: method, ...(typeof input.match === 'function' ? { match: input.match } : {}), }; if (hasResponder) { if (typeof input.respond !== 'function') { throw new InvalidScriptedSandboxStepError({ reason: 'invalid_outcome', inputIndex, method, message: `Scripted sandbox step #${displayIndex(inputIndex)} for ${method} must use a function responder.`, }); } return { ...base, type: 'responder', respond: input.respond, }; } if (hasError) { return { ...base, type: 'error', error: input.error }; } return { ...base, type: 'result', result: snapshotTestingValue(input.result), }; } function displayIndex(index) { return index + 1; } function snapshotRecordedCall(call) { return Object.freeze({ index: call.index, method: call.method, args: Object.freeze(snapshotSandboxCallArgs(call.method, call.args)), }); } function snapshotSandboxCallArgs(method, args) { const snapshot = snapshotTestingValue([...args]); if (method === 'applyManifest' && snapshot[0] instanceof Manifest) { snapshot[0] = cloneManifest(snapshot[0]); } return snapshot; } function isRecord(value) { return typeof value === 'object' && value !== null; } //# sourceMappingURL=scriptedSandboxSession.mjs.map