UNPKG

@openai/agents-core

Version:

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

160 lines • 6.15 kB
import { UserError } from "../errors.mjs"; import { SandboxInvalidManifestPathError } from "./errors.mjs"; import { normalizePathGrant, } from "./pathGrants.mjs"; import { hasBackslashPathSeparator, hasEscapingParentPathSegment, hasParentPathSegment, isUnderPosixPath, normalizePosixPath, relativePosixPathWithinRoot, } from "./shared/posixPath.mjs"; export class SandboxWorkspaceScope { cwd; constructor(cwd) { this.cwd = cwd === undefined ? undefined : normalizeSandboxCwd(cwd); } static fromCwd(cwd) { return new SandboxWorkspaceScope(cwd); } anchor(path) { if (this.cwd === undefined) { return path; } const trimmed = path?.trim() ?? ''; if (!trimmed) { return this.cwd; } if (trimmed.startsWith('/')) { return trimmed; } return `${this.cwd}/${trimmed}`; } modelResourcePath(workspaceRoot, path) { if (this.cwd === undefined) { return path; } const normalizedRoot = normalizeWorkspaceRoot(workspaceRoot); const normalizedPath = normalizeWorkspaceRelativeResourcePath(path); return normalizedPath ? joinPosixPath(normalizedRoot, normalizedPath) : normalizedRoot; } absoluteCwd(workspaceRoot) { return this.cwd === undefined ? undefined : this.modelResourcePath(workspaceRoot, this.cwd); } } export function normalizeSandboxCwd(cwd) { if (typeof cwd !== 'string') { throw new UserError('sandbox.cwd must be a string.'); } const trimmed = cwd.trim(); if (!trimmed) { throw new UserError('sandbox.cwd must be non-empty.'); } if (hasBackslashPathSeparator(cwd)) { throw new UserError('sandbox.cwd must use POSIX path separators.'); } if (trimmed.startsWith('/')) { throw new UserError('sandbox.cwd must be workspace-relative.'); } if (hasParentPathSegment(cwd)) { throw new UserError('sandbox.cwd must not contain parent segments.'); } const normalized = normalizePosixPath(trimmed); if (normalized === '.') { throw new UserError('sandbox.cwd must be non-empty.'); } return normalized; } export class WorkspacePathPolicy { root; extraPathGrants; constructor(options) { if (hasParentPathSegment(options.root)) { throw new UserError('Sandbox workspace root must not contain parent segments.'); } if (hasBackslashPathSeparator(options.root)) { throw new UserError(`Sandbox path "${options.root}" must use "/" separators.`); } const root = normalizePosixPath(options.root); if (!root.startsWith('/')) { throw new UserError('Sandbox workspace root must be absolute.'); } this.root = root; this.extraPathGrants = (options.extraPathGrants ?? []) .map((grant) => normalizePathGrant(grant)) .sort((left, right) => right.path.length - left.path.length); } resolve(path, options = {}) { const originalPath = path ?? ''; const trimmed = originalPath.trim(); const normalizedPath = trimmed.length === 0 ? this.root : trimmed.startsWith('/') ? normalizeSandboxPath(trimmed, originalPath) : joinPosixPath(this.root, normalizeSandboxPath(trimmed, originalPath)); const workspaceRelativePath = relativePosixPathWithinRoot(this.root, normalizedPath); if (workspaceRelativePath !== null) { return { path: normalizedPath, workspaceRelativePath, }; } const grant = this.matchingGrant(normalizedPath); if (grant) { if (options.forWrite && grant.readOnly) { throw new UserError(`Sandbox path "${originalPath}" uses read-only extra path grant "${grant.path}".`); } return { path: normalizedPath, grant, }; } throw new SandboxInvalidManifestPathError(`Sandbox path "${originalPath}" escapes the workspace root.`); } matchingGrant(path) { return this.extraPathGrants.find((grant) => isUnderPosixPath(path, grant.path)); } } function joinPosixPath(root, relativePath) { if (!relativePath) { return normalizePosixPath(root); } return normalizePosixPath(`${root.replace(/\/+$/u, '')}/${relativePath}`); } function normalizeWorkspaceRoot(root) { if (hasBackslashPathSeparator(root)) { throw new UserError('Sandbox workspace root must use POSIX path separators.'); } if (hasParentPathSegment(root)) { throw new UserError('Sandbox workspace root must not contain parent segments.'); } const normalized = normalizePosixPath(root); if (!normalized.startsWith('/')) { throw new UserError('Sandbox workspace root must be POSIX absolute.'); } return normalized; } function normalizeWorkspaceRelativeResourcePath(path) { const trimmed = path.trim(); if (!trimmed) { throw new UserError('Sandbox resource path must be non-empty.'); } if (hasBackslashPathSeparator(path)) { throw new UserError('Sandbox resource path must use POSIX path separators.'); } if (trimmed.startsWith('/')) { throw new UserError('Sandbox resource path must be workspace-relative.'); } if (hasParentPathSegment(path)) { throw new UserError('Sandbox resource path must not contain parent segments.'); } const normalized = normalizePosixPath(trimmed); return normalized === '.' ? '' : normalized; } function normalizeSandboxPath(path, originalPath) { if (hasBackslashPathSeparator(path)) { throw new UserError(`Sandbox path "${originalPath}" must use "/" separators.`); } if (hasEscapingParentPathSegment(path)) { throw new SandboxInvalidManifestPathError(`Sandbox path "${originalPath}" must not escape root.`); } return normalizePosixPath(path); } //# sourceMappingURL=workspacePaths.mjs.map