/** * PTC mode `run_code` transport. Programs call the registry's agent-visible * tools through nested executions scheduled under the native concurrency * contract; each sub-dispatch is logged for reconstruction, while only the * outer curated result enters model history. * @module */ import type { PtcDispatchLog } from './runtime-types.ts' import { symbols, type Context } from '@deepseek-ai/cordis' import { brandString } from '@deepseek-ai/dsh-brand' import { createUserMessage, HarnessError } from '@deepseek-ai/dsh-llm' import type { ContentBlock, ToolCallId, ToolSchema } from '@deepseek-ai/dsh-llm' import type { PtcBindingFunction, PtcRunResult, PtcRunSandbox, PtcRuntime } from '@deepseek-ai/dsh-ptc-runtime' import { approveEscalation, ESCALATION_TARGETS, validateEscalationArgs } from '@deepseek-ai/dsh-sandbox' import type { SandboxExecutionPolicy } from '@deepseek-ai/dsh-sandbox' import type {} from '@deepseek-ai/dsh-user-approval' import type {} from '@deepseek-ai/dsh-working-directory' import type {} from '@deepseek-ai/dsh-sandbox-policy' import { deepFreeze, snapshotJsonValue, type JsonValue } from '@deepseek-ai/dsh-util-values' import { defineTool, parameterSchemaSpecToJsonSchema, RUN_CODE_NAME, TOOL_ABORTED } from '@deepseek-ai/dsh-tools' import type { ToolExecutionPipeline } from '@deepseek-ai/dsh-tools/pipeline' import { toolErrorMessage } from '@deepseek-ai/dsh-tools/pipeline' import { scopeTarget } from '@deepseek-ai/dsh-scope' import { PtcCalls } from './ptc-calls.ts' import { CodeRunFailedError } from './errors.ts' import type { ToolDefinition, ToolExecutionResult, ToolRunContext } from '@deepseek-ai/dsh-tools' import type {} from './types.ts' /** The model-facing name of the PTC mode tool. */ export { RUN_CODE_NAME } /** Language-specific tool and code-parameter descriptions. */ interface RunCodeFlavor { /** The tool `description` the model sees for this language. */ readonly description: string /** The `code` parameter's description for this language. */ readonly codeDescription: string } /** Keep tool-call rules here; the runtime owns evaluation syntax and state retention. */ function runCodeFlavor(language: string, execution = { programDescription: 'the program to execute', outputInstruction: 'Curate the program output.', codeDescription: `The ${language} program to execute, following this tool's execution instructions.`, }): RunCodeFlavor { return { description: `Execute a ${language} program against the available tools. Takes two required arguments: ` + `\`code\`, ${execution.programDescription}, and \`description\`, a short summary of what the program does. ` + 'Call tools as `await tools.name(args)` per the declarations in the system prompt. ' + `${execution.outputInstruction} Image-bearing subtool results are attached after the run.`, codeDescription: execution.codeDescription, } } const TYPESCRIPT_FLAVOR = runCodeFlavor('TypeScript') const TYPESCRIPT_FUNCTION_FLAVOR = runCodeFlavor('TypeScript', { programDescription: 'the BODY of an async function (erasable syntax only; top-level `await` and `return` work)', outputInstruction: 'Only what you print or return is program output — curate it.', codeDescription: 'The program: the body of an async TypeScript function.', }) const PYTHON_FLAVOR = runCodeFlavor('Python') /** Languages with both a transport schema and an SDK renderer. */ export type PtcSdkLanguage = 'typescript' | 'python' type SupportedPtcRuntime = PtcRuntime & { readonly language: PtcSdkLanguage } const RUN_CODE_FLAVORS = { typescript: TYPESCRIPT_FLAVOR, python: PYTHON_FLAVOR, } satisfies Record /** * Read the active runtime, rejecting missing providers and unsupported languages. * @param ctx - executor context containing the runtime provider. * @returns the runtime with a supported SDK language. */ export function requirePtcRuntime(ctx: Context): SupportedPtcRuntime { const runtime = ctx.get('ptcRuntime') if (runtime === undefined) { throw new Error('dsh-tools: mode "ptc" requires a PTC runtime — load a ctx.ptcRuntime implementation (e.g. @deepseek-ai/dsh-ptc-runtime-node) or load @deepseek-ai/dsh-tool-executor-native') } if (!Object.hasOwn(RUN_CODE_FLAVORS, runtime.language)) { const known = Object.keys(RUN_CODE_FLAVORS).map(name => JSON.stringify(name)).join(', ') throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`) } return runtime as SupportedPtcRuntime } /** * The `description` parameter's model-facing description: language-independent * (the UI label contract is the same for every runtime), shared between the * static spec and the language-aware `parameters` getter so the two emissions * can never drift. */ const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = 'Clear, concise description of what this program does in active voice, ' + '5-10 words (shown in the UI). ' + 'Examples: "Count TODO markers across packages"; ' + '"Read failing test and its fixture"; "Rename config key in every cordis.yml".' const RUN_CODE_CONTROLS = { timeoutMs: { type: 'number', description: 'Positive elapsed-time budget in milliseconds, capped by the deployment maximum.' }, sandbox_permissions: { type: 'string', enum: [...ESCALATION_TARGETS], description: 'Wider sandbox mode for this complete program execution; requires justification and approval.' }, justification: { type: 'string', description: 'Reason this complete program needs wider access, shown to the user for approval. Use the language of the user’s current request.' }, } as const function controlParameters(runtime: PtcRuntime) { return { ...runtime.timeout === undefined ? {} : { timeoutMs: { ...RUN_CODE_CONTROLS.timeoutMs, description: `Positive elapsed-time budget in milliseconds, including nested tool and approval waits. Default ${runtime.timeout.defaultMs}; capped at ${runtime.timeout.maxMs}. Zero does not disable the deadline.` }, }, ...runtime.sandboxMode === undefined ? {} : { sandbox_permissions: RUN_CODE_CONTROLS.sandbox_permissions, justification: RUN_CODE_CONTROLS.justification, }, } } function escalationGuidance(mode: PtcRuntime['sandboxMode']): string { return mode === undefined ? '' : ' A sandbox escalation approves this complete program for one execution only. Nested tools retain their own policies and approvals. Request wider access only after evidence of a denial. Earlier effects may already have completed: inspect them before explicitly retrying. Programs are never replayed automatically.' } /** Match schema text to the runtime language and program syntax. */ function resolveFlavor(runtime: SupportedPtcRuntime): RunCodeFlavor { return runtime.language === 'typescript' && runtime.programFormat === 'function-body' ? TYPESCRIPT_FUNCTION_FLAVOR : RUN_CODE_FLAVORS[runtime.language] } /** * Snapshot one binding call's argument as lossless JSON, then snapshot that * detached value again so dispatch and logging stay independent without * reintroducing structured-clone's platform-specific nesting limit. */ function jsonNormalizeArgs(value: unknown): { dispatched: unknown; logged: unknown } { let snapshot: JsonValue | undefined try { snapshot = snapshotJsonValue(value) as JsonValue | undefined } catch (error: unknown) { throw new Error(`tool arguments must be lossless JSON: ${error instanceof Error ? error.message : String(error)}`) } if (snapshot === undefined) { throw new Error('tool arguments must be lossless JSON (call the tool with an arguments object, e.g. `{}`)') } const logged = snapshotJsonValue(snapshot) /* v8 ignore next -- snapshot is already a detached lossless JSON value. */ if (logged === undefined) { throw new Error('tool arguments could not be detached for durable logging') } return { dispatched: snapshot, logged } } /** Two-space JSON presentation, matching the existing shallow `run_code` text contract. */ const JSON_INDENT = ' ' /** * ECMAScript caps `JSON.stringify`'s `space` string at ten characters. The * renderer also caps TOTAL indentation there, compacting deeper subtrees, so * formatted output remains linear in the canonical JSON size. */ const MAX_JSON_INDENT_CHARS = 10 /** A pending fragment in the iterative JSON presentation traversal. */ type JsonRenderTask = | { kind: 'text'; text: string } | { kind: 'value'; value: JsonValue; depth: number; compact: boolean } /** Render one non-string JSON root without recursive traversal or unbounded indentation growth. */ function renderJsonValue(value: Exclude): string { const chunks: string[] = [] const tasks: JsonRenderTask[] = [{ kind: 'value', value, depth: 0, compact: false }] for (let task = tasks.pop(); task !== undefined; task = tasks.pop()) { if (task.kind === 'text') { chunks.push(task.text) continue } const current = task.value if (current === null || typeof current === 'boolean' || typeof current === 'number') { chunks.push(String(current)) continue } if (typeof current === 'string') { chunks.push(JSON.stringify(current)) continue } const compact = task.compact || (task.depth + 1) * JSON_INDENT.length > MAX_JSON_INDENT_CHARS const childDepth = task.depth + 1 if (Array.isArray(current)) { chunks.push('[') if (current.length === 0) { chunks.push(']') continue } tasks.push({ kind: 'text', text: compact ? ']' : `\n${JSON_INDENT.repeat(task.depth)}]` }) for (let index = current.length - 1; index >= 0; index--) { const item = current[index] /* v8 ignore next -- canonical JsonValue arrays are dense. */ if (item === undefined) throw new Error('cannot render a sparse JSON array') tasks.push({ kind: 'value', value: item, depth: childDepth, compact }) tasks.push({ kind: 'text', text: compact ? index === 0 ? '' : ',' : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}`, }) } continue } const keys = Object.keys(current) chunks.push('{') if (keys.length === 0) { chunks.push('}') continue } tasks.push({ kind: 'text', text: compact ? '}' : `\n${JSON_INDENT.repeat(task.depth)}}` }) for (let index = keys.length - 1; index >= 0; index--) { const key = keys[index] /* v8 ignore next -- the loop is bounded by the captured key count. */ if (key === undefined) throw new Error('cannot render a missing JSON object key') const item = current[key] /* v8 ignore next -- canonical JsonValue records contain no undefined properties. */ if (item === undefined) throw new Error('cannot render an undefined JSON object property') tasks.push({ kind: 'value', value: item, depth: childDepth, compact }) tasks.push({ kind: 'text', text: compact ? `${index === 0 ? '' : ','}${JSON.stringify(key)}:` : `${index === 0 ? '\n' : ',\n'}${JSON_INDENT.repeat(childDepth)}${JSON.stringify(key)}: `, }) } } return chunks.join('') } /** Render one present program completion value for the model-facing result text. */ function renderValue(value: JsonValue): string { return typeof value === 'string' ? value : renderJsonValue(value) } /** Canonical value returned by the outer PTC mode transport. */ type RunCodeOutput = { logs: string[]; result?: JsonValue; sandbox?: PtcRunSandbox } /** Unowned programs do not require Session directory state. */ async function resolveWorkingDirectory(ctx: Context, exec: ToolRunContext): Promise { if (exec.agent === undefined) return undefined const directories = ctx.get('workingDirectory') if (directories === undefined) throw new Error('dsh-tools: run_code with an Agent requires workingDirectory') return directories.ensure(exec.agent, exec.signal) } /** Resolve standing authority for a runtime that enforces file policy. */ function resolveSandboxPolicy(ctx: Context, exec: ToolRunContext): SandboxExecutionPolicy { const policy = ctx.get('sandboxPolicy') if (policy === undefined) throw new Error('dsh-tools: confined PTC runtime requires sandboxPolicy') return policy.resolve(exec.agent === undefined ? {} : { session: exec.agent.session }) } /** * Build the reserved `run_code` transport outside registered capabilities. * @param ctx - executor context owning policy listeners and active program cleanup. * @param executor - shared invocation pipeline for nested calls. * @param maxParallel - maximum overlapping concurrency-safe subcalls. * @returns the transport definition with runtime-dependent schema text. */ export function createRunCodeTool( ctx: Context, executor: ToolExecutionPipeline, maxParallel: number, ): ToolDefinition { // Retain services for log settlement after the executor context becomes inactive. const tools = ctx.tools const logger = ctx.logger /** A failed log-content listener preserves the settled content and cannot fail the dispatch. */ async function shapeDispatchLog(dispatch: PtcDispatchLog): Promise { try { return await ctx.waterfall( scopeTarget(tools, dispatch.agent), 'tools/ptc-dispatch-log', dispatch, () => Promise.resolve(dispatch.content), ) } catch (error: unknown) { logger.warn(`tools: ptc-dispatch-log listener failed for ${dispatch.name}: ${toolErrorMessage(error)}; logging the original settled content`) return dispatch.content } } const stateOwners = new WeakMap>() const calls = new PtcCalls(ctx) const definition = defineTool({ name: RUN_CODE_NAME, // The description and `code` parameter description are placeholders here: // the language-aware getters installed below replace both, resolving the // loaded runtime's flavor at schema-emission time so the schema the MODEL // sees matches the SDK section's language. Argument VALIDATION still keys // off this static spec (defineTool closes over it), which is language- // independent (one required string `code`). description: TYPESCRIPT_FLAVOR.description, parameters: { code: { type: 'string', required: true, description: TYPESCRIPT_FLAVOR.codeDescription }, description: { type: 'string', required: true, description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION, }, ...RUN_CODE_CONTROLS, }, output: { schema: { type: 'object', additionalProperties: false, properties: { logs: { type: 'array', required: true, items: { type: 'string' } }, result: { type: 'json' }, sandbox: { type: 'object', additionalProperties: false, properties: { mode: { type: 'string', required: true, enum: ['read-only', 'workspace-write', 'danger-full-access'] }, denied: { type: 'boolean', required: true }, enforcement: { type: 'string', enum: ['full', 'partial'] }, }, }, }, }, render: (_args, value) => { const rendered = value.result === undefined ? '' : renderValue(value.result) const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0) if (value.sandbox?.enforcement === 'partial') parts.push('File sandbox enforcement is partial on this host.') if (value.sandbox?.denied) parts.push(`The ${value.sandbox.mode} file sandbox denied an operation.${escalationGuidance(ctx.get('ptcRuntime')?.sandboxMode)}`) return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }] }, }, async execute(args, exec): Promise { if (args.description.trim().length === 0) { throw new Error('invalid description: expected a non-empty string') } const runtime = requirePtcRuntime(ctx) const run = async (callSignal: AbortSignal): Promise => { validateEscalationArgs(args.sandbox_permissions, args.justification) if (args.timeoutMs !== undefined && runtime.timeout === undefined) { throw new Error('timeoutMs is not available for this PTC runtime') } if (args.timeoutMs !== undefined && (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) { throw new Error('invalid timeoutMs: expected a positive finite number') } const standingPolicy = runtime.sandboxMode === undefined ? undefined : resolveSandboxPolicy(ctx, exec) let policy = standingPolicy if (args.sandbox_permissions !== undefined && args.justification !== undefined) { if (standingPolicy === undefined) throw new Error('sandbox_permissions is not available for this PTC runtime') const approvedMode = await approveEscalation({ requestedMode: args.sandbox_permissions, justification: args.justification, effectiveMode: standingPolicy.mode, subject: 'program', }, { approver: ctx.get('approval'), agent: exec.agent, callId: exec.callId, toolName: RUN_CODE_NAME, signal: callSignal, }) policy = { ...standingPolicy, mode: approvedMode } } const cwd = await resolveWorkingDirectory(ctx, { ...exec, signal: callSignal }) callSignal.throwIfAborted() // The run-scoped abort: follows the outer signal in, and fires when the // run settles for ANY reason, so an in-flight sub-dispatch is aborted // (its executor kills on this signal) instead of orphaned, and // queued-unstarted dispatches are abandoned. const runController = new AbortController() const onOuterAbort = (): void => { runController.abort(callSignal.reason) } callSignal.addEventListener('abort', onOuterAbort, { once: true }) let dispatches = 0 // The per-run scheduler uses the registry's staged interface and follows // the same concurrency rules as the native loop. It also follows the // native loop's SEQUENCING: every ordered stage (the dispatch-start // append, prepare = pre-execute/guards, complete = post-execute, // context deferral, the settle append) runs inside ONE driver lane, so // ordered policy stages never overlap each other and only the // around-dispatch/body stage runs concurrently. Starts are strictly // submission-ordered; results commit in submission order through the // head-of-line cursor. Consecutive parallel-classified calls overlap up // to maxParallel; an exclusive call waits for the pool to drain, runs // alone, and holds its barrier until its COMMIT (post-execute included) // completes, exactly like a native exclusive group. Classification is // re-read via executionMode() immediately before each start (a registry // mutation while queued can flip a call exclusive), matching the native // scheduler's lazy reclassification. interface PendingDispatch { /** Ordered stage: append the start event, await prepare (pre-execute/guards), launch the body into `flight`. */ start(): Promise classify(): 'parallel' | 'exclusive' abandon(): void /** Ordered stage: post-execute + context deferral + settle event, in submission order. */ commit(): Promise /** The launched around-dispatch/body stage; resolved until start() replaces it. */ flight: Promise /** True once the dispatch stage parked its outcome; the commit cursor waits on it. */ settled: boolean /** The classification this entry started under; an exclusive holds its barrier through commit(). */ mode?: 'parallel' | 'exclusive' } const pendingQueue: PendingDispatch[] = [] const inFlight = new Set>() /** Tracked settle-event side work (log-content listener + append), drained at run settlement. */ const logWork = new Set>() const commitQueue: PendingDispatch[] = [] let exclusiveActive = false let driving = false let driverRun: Promise = Promise.resolve() let wake: (() => void) | undefined const wakeup = (): void => { const release = wake wake = undefined release?.() } /** * The single ordered lane. Each pass commits the head-of-line settled * dispatch (ordered post-execute), then starts the next queued entry if * its slot is free (ordered pre-execute), and otherwise sleeps until a * body settles or a new submission arrives. One run reaching the * empty-queues/empty-pool state is quiescence. */ const drive = (): Promise => { if (driving) return driverRun driving = true driverRun = (async () => { try { for (;;) { // Create the wakeup promise before inspecting state so a settle or submission arriving // between the checks and the await below cannot be lost. const signal = new Promise((resolve) => { wake = resolve }) const commitHead = commitQueue[0] if (commitHead !== undefined && commitHead.settled) { commitQueue.shift() await commitHead.commit() // The barrier covers post-execute: later starts wait for the // exclusive call's full pipeline, as under the native loop. if (commitHead.mode === 'exclusive') exclusiveActive = false continue } const head = pendingQueue[0] if (head !== undefined) { if (runController.signal.aborted) { pendingQueue.shift() head.abandon() continue } // Reclassify at start time (fail-closed on registry changes). const mode = head.classify() const capacity = !exclusiveActive && (mode === 'exclusive' ? inFlight.size === 0 : inFlight.size < maxParallel) if (capacity) { if (mode === 'exclusive') exclusiveActive = true head.mode = mode pendingQueue.shift() // Joined before start() so the commit cursor sees submission // order; nothing commits it until `settled` flips. commitQueue.push(head) await head.start() const flight: Promise = head.flight.finally(() => { inFlight.delete(flight) wakeup() }) inFlight.add(flight) continue } } if (pendingQueue.length === 0 && commitQueue.length === 0 && inFlight.size === 0) return await signal } } finally { driving = false wake = undefined } })() return driverRun } /** Every dispatch settled AND committed; nothing can start (the run is aborted at call time). */ const drainDispatches = async (): Promise => { // The abort already fired: the driver abandons queued-unstarted // entries, awaits the live pool, and drains the ordered commit lane — // including a commit already in progress when the program returned. await drive() // Every settle event is appended inside the open run_code turn // (tasks self-remove on settlement). while (logWork.size > 0) await Promise.allSettled([...logWork]) } // Read through a call, not a bare property: the abort state genuinely // changes across awaits, and a direct `.aborted` re-check after one // would be narrowed away by control flow analysis. const runOver = (): boolean => runController.signal.aborted const binding = (schema: ToolSchema): PtcBindingFunction => async (rawArgs: unknown): Promise => { const { name } = schema if (runOver()) { throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`) } const normalized = jsonNormalizeArgs(rawArgs) const n = ++dispatches const subCallId = brandString(`${String(exec.callId)}:ptc:${n}`) const input = { callId: subCallId, rootCallId: exec.rootCallId, name, schema, arguments: normalized.dispatched, ...exec.agent ? { agent: exec.agent } : {}, ...exec.toolSet !== undefined ? { toolSet: exec.toolSet } : {}, parent: exec.token, signal: runController.signal, } type DispatchOutcome = { isError: true; message: string } | { isError: false; value: JsonValue } const outcome = await new Promise((resolve, reject) => { // Set by the dispatch stage (or start() for a pre-settled result): what commit() finalizes in submission order. let parked: | { kind: 'post-result' | 'final-result'; exec: ToolRunContext; result: ToolExecutionResult } | undefined const settle = (result: ToolExecutionResult): void => { // The program gets its value NOW: the log-content listener (for // example, a spill backend) must never delay the binding or occupy // a dispatch slot. The event append is tracked side work; the run's // settlement drains logWork so every settle event is still appended // inside the open turn (shapeDispatchLog is contained, so this // chain cannot reject). resolve(result.isError ? { isError: true, message: result.error.message } : { isError: false, value: result.value }) const agent = exec.agent if (agent === undefined) return const task: Promise = (async () => { // The listener may replace the durable copy with a preview and // locator; the program's value and model-visible result are // untouched. const logged = await shapeDispatchLog({ exec, agent, subCallId, name, isError: result.isError, // The registry deep-froze this projection at result // finalization; append snapshots the final copy again, so // the log stays detached. content: result.content, }) agent.session.append('tool/ptc-dispatch', { rootCallId: exec.rootCallId, parentCallId: exec.callId, subCallId, name, // The SIBLING parse of the dispatched value: byte-identical JSON, // but a separate object — a tool mutating its args cannot desync // this record from what it actually received. arguments: normalized.logged, isError: result.isError, ...result.error?.info === undefined ? {} : { error: result.error.info }, content: logged, ...result.meta === undefined ? {} : { meta: result.meta }, }) })().finally(() => { logWork.delete(task) }) logWork.add(task) } pendingQueue.push({ flight: Promise.resolve(), settled: false, // Re-read per driver pass against the same agent view the SDK // declared; fail-closed exclusive when undeclared/invalid. classify: () => executor.executionMode(input).kind, abandon: () => { reject(new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`)) }, async start(): Promise { exec.agent?.session.append('tool/ptc-dispatch-start', { rootCallId: exec.rootCallId, parentCallId: exec.callId, subCallId, name, arguments: normalized.logged, }) // Ordered prepare runs INSIDE the driver lane: the next entry's // pre-execute waits for this resolution, as under the native // scheduler. Only the launched body below overlaps. const prepared = await executor.prepare(input) if (prepared.kind === 'dispatch') { this.flight = executor.dispatch(prepared.exec).then((dispatchOutcome) => { parked = { kind: dispatchOutcome.kind, exec: prepared.exec, result: dispatchOutcome.result } this.settled = true }) return } parked = { kind: prepared.kind, exec: prepared.exec, result: prepared.result } this.settled = true }, async commit(): Promise { /* v8 ignore next -- commit() runs only after `settled` flipped, which set parked. */ if (parked === undefined) return const result = await executor.complete(parked.exec, parked) if (!result.isError && result.content.some(block => block.type === 'image')) { exec.deferContext(createUserMessage({ content: result.content, source: { kind: 'ptc-mode' }, })) } for (const context of result.additionalContexts ?? []) { exec.deferContext(context) } // The composite forwards `additionalContexts` above and // `concludesTurn` here from the nested result. Only a successful // nested result can carry the terminal marker // (ToolExecutionFailure types it never), so a policy-converted // failure cannot stop the turn through a recovering program. if (result.concludesTurn) exec.concludeTurn() settle(result) // Backpressure on pending event-append tasks: each task retains // a full result while a slow backend stores it, so the pool cap // bounds their count. Beyond the cap, the // ordered lane waits, so later sub-calls cannot start and // pending I/O/memory cannot grow without bound. while (logWork.size > maxParallel) await Promise.race(logWork) }, }) wakeup() void drive() }) // A budget expiry or outer cancel that occurs while this call was in // flight already aborted the dispatch; stop the program now rather // than hand it a result from a run that is over. if (runOver()) { throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} result discarded`) } // The worker turns a binding rejection into ToolCallError and adds // only the binding name. Native content and internal error metadata // stay outside the program-facing failure contract. if (outcome.isError) throw new Error(outcome.message) return outcome.value } // Null-prototype + defineProperty, mirroring the worker-side namespace // build: a registered tool named `__proto__` must become an ordinary // own key (a plain-object assignment would hit the prototype setter, // silently dropping the binding), and the runtime host resolves // binding names as own properties only. const functions: Record = Object.create(null) as Record // Enumerate the CALLING AGENT's visible set (scoped tools join, // restricted globals vanish) — the same view the SDK section declared, // so a program can bind exactly what its prompt promised; sub-dispatch // re-resolves per call through the same view (exec.agent threads down). for (const schema of tools.schemas(exec.agent, exec.toolSet)) { Object.defineProperty(functions, schema.name, { enumerable: true, value: binding(deepFreeze(schema)) }) } try { let result: PtcRunResult try { if (exec.agent !== undefined) { const agent = exec.agent let runtimes = stateOwners.get(agent) if (runtimes === undefined) stateOwners.set(agent, runtimes = new WeakSet()) // Cordis can wrap service returns repeatedly; cleanup belongs to the original provider. let provider: PtcRuntime = runtime for (;;) { const original = (provider as PtcRuntime & { [symbols.original]?: PtcRuntime })[symbols.original] if (original === undefined) break provider = original } if (!runtimes.has(provider)) { agent.ctx.effect(() => () => runtime.release(agent), 'PTC retained environment') runtimes.add(provider) } } result = await runtime.run(runtime.resolve({ program: args.code, ...exec.agent === undefined || policy?.mode !== standingPolicy?.mode ? {} : { stateOwner: exec.agent }, bindings: [{ global: 'tools', functions, errorClass: { name: 'ToolCallError', memberNameProperty: 'toolName' }, }], signal: runController.signal, ...cwd !== undefined ? { cwd } : {}, ...policy !== undefined ? { sandboxPolicy: policy } : {}, ...args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}, })) } finally { // Abort sub-dispatches and drain every in-flight dispatch before // closing the turn (queued-unstarted ones are abandoned unlogged). // Binding failures remain observable through their individual promises. runController.abort('run_code settled') await drainDispatches() } if (result.error) { if (result.error.kind === 'abort' && exec.signal.aborted) { const error = new HarnessError('tool call aborted', TOOL_ABORTED) error.name = 'AbortError' throw error } const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join('\n')}` : '' const sandboxText = result.sandbox === undefined ? '' : `\nFile sandbox: ${result.sandbox.mode}${result.sandbox.enforcement === undefined ? '' : `; enforcement: ${result.sandbox.enforcement}`}${result.sandbox.denied ? '; operation denied' : ''}.` throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}${sandboxText}${result.sandbox?.denied ? escalationGuidance(runtime.sandboxMode) : ''}`) } return { logs: result.logs, ...result.sandbox === undefined ? {} : { sandbox: result.sandbox }, ...result.value !== undefined ? { result: result.value } : {}, } } finally { callSignal.removeEventListener('abort', onOuterAbort) } } return runtime.sandboxMode === undefined || exec.agent === undefined ? run(exec.signal) : calls.run(exec.agent.session.id, exec.signal, () => resolveSandboxPolicy(ctx, exec).mode, run) }, // The model-authored description is the call's always-visible UI label // (the bash `description` precedent); the program itself rides rawInput. presentCall: args => ({ card: 'generic', title: args.description, kind: 'execute', rawInput: args.code, }), // Deliberately no presentResult: the generic card fallback keeps this // title and reads durable result content without duplicating a large raw // result into the host view payload. }) // Read current runtime instructions and controls whenever the schema is projected. Object.defineProperty(definition, 'description', { enumerable: true, get: () => { const runtime = requirePtcRuntime(ctx) const instructions = runtime.executionInstructions return resolveFlavor(runtime).description + (instructions ? ` ${instructions}` : '') + " Each program starts in the Session's current directory. Running programs keep their initial directory." + escalationGuidance(runtime.sandboxMode) }, }) Object.defineProperty(definition, 'parameters', { enumerable: true, // Recompile through the same spec→schema projection defineTool used, so // the emitted schema always matches the validated specification. get: () => { const runtime = requirePtcRuntime(ctx) return parameterSchemaSpecToJsonSchema({ code: { type: 'string', required: true, description: resolveFlavor(runtime).codeDescription }, description: { type: 'string', required: true, description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION }, ...controlParameters(runtime), }) }, }) return definition }