@ai-sdk/code-mode 1.0.77 → 1.0.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval-continuation.js +48 -74
- package/dist/approval-continuation.js.map +1 -1
- package/dist/approval.js +12 -23
- package/dist/approval.js.map +1 -1
- package/dist/code-mode-tool.js +39 -51
- package/dist/code-mode-tool.js.map +1 -1
- package/dist/continuation-capability.js +74 -105
- package/dist/continuation-capability.js.map +1 -1
- package/dist/direct-tool-call.js +9 -3
- package/dist/direct-tool-call.js.map +1 -1
- package/dist/errors.js +109 -96
- package/dist/errors.js.map +1 -1
- package/dist/host-interrupt.js +7 -12
- package/dist/host-interrupt.js.map +1 -1
- package/dist/index.d.ts +172 -163
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -61
- package/dist/interrupt-continuation.js +54 -90
- package/dist/interrupt-continuation.js.map +1 -1
- package/dist/run-code-mode.js +292 -494
- package/dist/run-code-mode.js.map +1 -1
- package/dist/tool-invocation.js +98 -176
- package/dist/tool-invocation.js.map +1 -1
- package/dist/tool-prompt.js +254 -392
- package/dist/tool-prompt.js.map +1 -1
- package/dist/types.js +1 -1
- package/dist/utils/serialization.js +23 -39
- package/dist/utils/serialization.js.map +1 -1
- package/package.json +6 -6
- package/dist/index.js.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/run-code-mode.js
CHANGED
|
@@ -1,549 +1,347 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
createRunner,
|
|
5
|
-
createSignedContinuationCodec,
|
|
6
|
-
getHostFunctionContext,
|
|
7
|
-
RunError
|
|
8
|
-
} from "run";
|
|
9
|
-
import {
|
|
10
|
-
isCodeModeApprovalInterruptPayload,
|
|
11
|
-
normalizeApprovalResolution
|
|
12
|
-
} from "./approval.js";
|
|
13
|
-
import {
|
|
14
|
-
resolveCodeModeContinuationSecurity,
|
|
15
|
-
signCodeModeContinuation,
|
|
16
|
-
verifyCodeModeContinuation
|
|
17
|
-
} from "./continuation-capability.js";
|
|
18
|
-
import {
|
|
19
|
-
CodeModeAbortedError,
|
|
20
|
-
CodeModeBridgeLimitError,
|
|
21
|
-
CodeModeConcurrencyError,
|
|
22
|
-
CodeModeDetachedBridgeRequestError,
|
|
23
|
-
CodeModeError,
|
|
24
|
-
CodeModeProtocolError,
|
|
25
|
-
CodeModeSourceTooLargeError,
|
|
26
|
-
CodeModeTimeoutError,
|
|
27
|
-
CodeModeToolApprovalDeniedError
|
|
28
|
-
} from "./errors.js";
|
|
29
|
-
import { invokeHostTool } from "./tool-invocation.js";
|
|
1
|
+
import { CodeModeAbortedError, CodeModeBridgeLimitError, CodeModeConcurrencyError, CodeModeDetachedBridgeRequestError, CodeModeError, CodeModeProtocolError, CodeModeSourceTooLargeError, CodeModeTimeoutError, CodeModeToolApprovalDeniedError } from "./errors.js";
|
|
2
|
+
import { isCodeModeApprovalInterruptPayload, normalizeApprovalResolution } from "./approval.js";
|
|
3
|
+
import { resolveCodeModeContinuationSecurity, signCodeModeContinuation, verifyCodeModeContinuation } from "./continuation-capability.js";
|
|
30
4
|
import { fromJsonPayload, toJsonPayload } from "./utils/serialization.js";
|
|
5
|
+
import { invokeHostTool } from "./tool-invocation.js";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { Buffer } from "node:buffer";
|
|
8
|
+
import { RunError, createRunner, createSignedContinuationCodec, getHostFunctionContext } from "run";
|
|
9
|
+
//#region src/run-code-mode.ts
|
|
31
10
|
const SOURCE_LINE_OFFSET = 1;
|
|
32
11
|
const MAX_RUN_LIMIT = 2147483647;
|
|
33
12
|
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
34
|
-
const DEFAULT_MEMORY_LIMIT_BYTES =
|
|
35
|
-
const DEFAULT_STACK_LIMIT_BYTES =
|
|
36
|
-
const DEFAULT_MAX_RESULT_BYTES =
|
|
37
|
-
const DEFAULT_MAX_CONSOLE_OUTPUT_BYTES =
|
|
38
|
-
const DEFAULT_MAX_SOURCE_BYTES =
|
|
39
|
-
const DEFAULT_MAX_TOOL_INPUT_BYTES =
|
|
40
|
-
const DEFAULT_MAX_TOOL_OUTPUT_BYTES =
|
|
13
|
+
const DEFAULT_MEMORY_LIMIT_BYTES = 67108864;
|
|
14
|
+
const DEFAULT_STACK_LIMIT_BYTES = 2097152;
|
|
15
|
+
const DEFAULT_MAX_RESULT_BYTES = 1048576;
|
|
16
|
+
const DEFAULT_MAX_CONSOLE_OUTPUT_BYTES = 65536;
|
|
17
|
+
const DEFAULT_MAX_SOURCE_BYTES = 262144;
|
|
18
|
+
const DEFAULT_MAX_TOOL_INPUT_BYTES = 1048576;
|
|
19
|
+
const DEFAULT_MAX_TOOL_OUTPUT_BYTES = 4194304;
|
|
41
20
|
const DEFAULT_MAX_BRIDGE_REQUESTS = 256;
|
|
42
21
|
const DEFAULT_MAX_IN_FLIGHT_BRIDGE_REQUESTS = 32;
|
|
43
22
|
let invocationCounter = 0;
|
|
23
|
+
/**
|
|
24
|
+
* Runs one code-mode invocation directly without wrapping it as an AI SDK tool.
|
|
25
|
+
*
|
|
26
|
+
* The source is executed in a fresh QuickJS context with the provided host tools
|
|
27
|
+
* and execution limits.
|
|
28
|
+
*
|
|
29
|
+
* @param input - Source code, host tools, forwarded tool execution options, and code-mode options.
|
|
30
|
+
* @returns The JSON-serializable value returned by the sandboxed program.
|
|
31
|
+
*/
|
|
44
32
|
async function runCodeMode(input) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
toolNames,
|
|
102
|
-
token: result.continuation,
|
|
103
|
-
pendingInterruptions,
|
|
104
|
-
resolutions: []
|
|
105
|
-
},
|
|
106
|
-
continuationSecurity
|
|
107
|
-
);
|
|
108
|
-
return toCodeModeInterrupt(continuation, 0);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
const preserved = findPreservedCodeModeError(error, codeModeErrors);
|
|
111
|
-
if (preserved !== void 0) {
|
|
112
|
-
throw translateSourceStack(preserved);
|
|
113
|
-
}
|
|
114
|
-
throw translateSourceStack(toCodeModeRuntimeError(error));
|
|
115
|
-
}
|
|
33
|
+
const policy = resolveExecutionPolicy(input.options?.executionPolicy);
|
|
34
|
+
assertSourceSize(input.js, policy.maxSourceBytes);
|
|
35
|
+
const toolNames = Object.keys(input.tools).sort();
|
|
36
|
+
const continuationState = prepareContinuation(input, toolNames, policy.maxToolOutputBytes);
|
|
37
|
+
if (continuationState.nextInterrupt !== void 0) return continuationState.nextInterrupt;
|
|
38
|
+
const outerToolCallId = input.toolExecutionOptions?.toolCallId ?? input.continuation?.outerToolCallId ?? `code-mode-${++invocationCounter}`;
|
|
39
|
+
const source = createCodeModeSource(input.js, toolNames);
|
|
40
|
+
const codeModeErrors = [];
|
|
41
|
+
const hostFunctions = createHostFunctions({
|
|
42
|
+
codeModeErrors,
|
|
43
|
+
input,
|
|
44
|
+
outerToolCallId,
|
|
45
|
+
policy,
|
|
46
|
+
toolNames
|
|
47
|
+
});
|
|
48
|
+
const continuationSecurity = resolveCodeModeContinuationSecurity(input.options?.continuationSecurity);
|
|
49
|
+
const runner = createRunner({
|
|
50
|
+
continuationAudience: "@ai-sdk/code-mode/v2",
|
|
51
|
+
continuationCodec: createSignedContinuationCodec({
|
|
52
|
+
maxAgeMs: continuationSecurity.maxAgeMs,
|
|
53
|
+
secret: createHash("sha256").update(continuationSecurity.signingKey).digest()
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
const result = await runner.run({
|
|
58
|
+
source,
|
|
59
|
+
hostFunctions,
|
|
60
|
+
limits: toRunLimits(policy, source, input.js),
|
|
61
|
+
continuationContext: {
|
|
62
|
+
outerToolCallId,
|
|
63
|
+
toolNames
|
|
64
|
+
},
|
|
65
|
+
...input.toolExecutionOptions?.abortSignal === void 0 ? {} : { abortSignal: input.toolExecutionOptions.abortSignal },
|
|
66
|
+
...continuationState.token === void 0 ? {} : { continuation: continuationState.token },
|
|
67
|
+
...continuationState.resolutions === void 0 ? {} : { resolutions: continuationState.resolutions }
|
|
68
|
+
});
|
|
69
|
+
if (result.status === "completed") return fromJsonPayload(toJsonPayload(result.value, policy.maxResultBytes, "Code mode result"));
|
|
70
|
+
const pendingInterruptions = toPendingInterruptions({
|
|
71
|
+
interruptions: result.interruptions,
|
|
72
|
+
outerToolCallId,
|
|
73
|
+
toolNames
|
|
74
|
+
});
|
|
75
|
+
return toCodeModeInterrupt(signCodeModeContinuation({
|
|
76
|
+
version: 2,
|
|
77
|
+
js: input.js,
|
|
78
|
+
outerToolCallId,
|
|
79
|
+
toolNames,
|
|
80
|
+
token: result.continuation,
|
|
81
|
+
pendingInterruptions,
|
|
82
|
+
resolutions: []
|
|
83
|
+
}, continuationSecurity), 0);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const preserved = findPreservedCodeModeError(error, codeModeErrors);
|
|
86
|
+
if (preserved !== void 0) throw translateSourceStack(preserved);
|
|
87
|
+
throw translateSourceStack(toCodeModeRuntimeError(error));
|
|
88
|
+
}
|
|
116
89
|
}
|
|
117
90
|
function resolveExecutionPolicy(policy = {}) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
91
|
+
return {
|
|
92
|
+
timeoutMs: policy.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
93
|
+
memoryLimitBytes: policy.memoryLimitBytes ?? DEFAULT_MEMORY_LIMIT_BYTES,
|
|
94
|
+
maxStackSizeBytes: policy.maxStackSizeBytes ?? DEFAULT_STACK_LIMIT_BYTES,
|
|
95
|
+
maxResultBytes: policy.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES,
|
|
96
|
+
maxConsoleOutputBytes: policy.maxConsoleOutputBytes ?? DEFAULT_MAX_CONSOLE_OUTPUT_BYTES,
|
|
97
|
+
maxSourceBytes: policy.maxSourceBytes ?? DEFAULT_MAX_SOURCE_BYTES,
|
|
98
|
+
maxToolInputBytes: policy.maxToolInputBytes ?? DEFAULT_MAX_TOOL_INPUT_BYTES,
|
|
99
|
+
maxToolOutputBytes: policy.maxToolOutputBytes ?? DEFAULT_MAX_TOOL_OUTPUT_BYTES,
|
|
100
|
+
maxBridgeRequests: policy.maxBridgeRequests ?? DEFAULT_MAX_BRIDGE_REQUESTS,
|
|
101
|
+
maxInFlightBridgeRequests: policy.maxInFlightBridgeRequests ?? DEFAULT_MAX_IN_FLIGHT_BRIDGE_REQUESTS
|
|
102
|
+
};
|
|
130
103
|
}
|
|
131
104
|
function assertSourceSize(source, maxBytes) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const bytes = Buffer.byteLength(source);
|
|
136
|
-
if (bytes > maxBytes) {
|
|
137
|
-
throw new CodeModeSourceTooLargeError(bytes, maxBytes);
|
|
138
|
-
}
|
|
105
|
+
if (!isValidRunLimit(maxBytes)) return;
|
|
106
|
+
const bytes = Buffer.byteLength(source);
|
|
107
|
+
if (bytes > maxBytes) throw new CodeModeSourceTooLargeError(bytes, maxBytes);
|
|
139
108
|
}
|
|
140
109
|
function createCodeModeSource(js, toolNames) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
);
|
|
144
|
-
const bindingSource = Object.entries(bindings).map(([name, reference]) => `${JSON.stringify(name)}:${reference}`).join(",");
|
|
145
|
-
return `const __codeModeBindings={${bindingSource}};const tools=new Proxy(Object.create(null),{get(_target,name){const binding=__codeModeBindings[name];return typeof binding==="function"?(input)=>binding(input):(input)=>__codeMode.missing(String(name),input);}});const __codeModeResult=await(async()=>{
|
|
146
|
-
${js}
|
|
147
|
-
})();if(__codeModeResult===undefined)return undefined;return JSON.parse(JSON.stringify(__codeModeResult));`;
|
|
110
|
+
const bindings = Object.fromEntries(toolNames.map((toolName, index) => [toolName, `__codeMode.tool${index}`]));
|
|
111
|
+
return `const __codeModeBindings={${Object.entries(bindings).map(([name, reference]) => `${JSON.stringify(name)}:${reference}`).join(",")}};const tools=new Proxy(Object.create(null),{get(_target,name){const binding=__codeModeBindings[name];return typeof binding==="function"?(input)=>binding(input):(input)=>__codeMode.missing(String(name),input);}});const __codeModeResult=await(async()=>{\n${js}\n})();if(__codeModeResult===undefined)return undefined;return JSON.parse(JSON.stringify(__codeModeResult));`;
|
|
148
112
|
}
|
|
149
|
-
function createHostFunctions({
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
codeModeErrors,
|
|
169
|
-
input,
|
|
170
|
-
outerToolCallId,
|
|
171
|
-
policy,
|
|
172
|
-
toolInput,
|
|
173
|
-
toolName: String(toolName)
|
|
174
|
-
});
|
|
175
|
-
return { __codeMode: group };
|
|
113
|
+
function createHostFunctions({ codeModeErrors, input, outerToolCallId, policy, toolNames }) {
|
|
114
|
+
const group = {};
|
|
115
|
+
for (const [index, toolName] of toolNames.entries()) group[`tool${index}`] = async (toolInput) => await invokeCodeModeTool({
|
|
116
|
+
codeModeErrors,
|
|
117
|
+
input,
|
|
118
|
+
outerToolCallId,
|
|
119
|
+
policy,
|
|
120
|
+
toolInput,
|
|
121
|
+
toolName
|
|
122
|
+
});
|
|
123
|
+
group.missing = async (toolName, toolInput) => await invokeCodeModeTool({
|
|
124
|
+
codeModeErrors,
|
|
125
|
+
input,
|
|
126
|
+
outerToolCallId,
|
|
127
|
+
policy,
|
|
128
|
+
toolInput,
|
|
129
|
+
toolName: String(toolName)
|
|
130
|
+
});
|
|
131
|
+
return { __codeMode: group };
|
|
176
132
|
}
|
|
177
|
-
async function invokeCodeModeTool({
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
inputJson,
|
|
228
|
-
tools: input.tools,
|
|
229
|
-
baseExecutionOptions,
|
|
230
|
-
codeModeOptions: input.options ?? {},
|
|
231
|
-
maxToolInputBytes: policy.maxToolInputBytes,
|
|
232
|
-
maxToolOutputBytes: policy.maxToolOutputBytes,
|
|
233
|
-
toolCallId,
|
|
234
|
-
...codeModeInterrupt === void 0 ? {} : { codeModeInterrupt },
|
|
235
|
-
skipApproval
|
|
236
|
-
});
|
|
237
|
-
if (outcome.type === "interrupted") {
|
|
238
|
-
return context.interrupt(outcome.payload);
|
|
239
|
-
}
|
|
240
|
-
return fromJsonPayload(outcome.valueJson);
|
|
241
|
-
} catch (error) {
|
|
242
|
-
if (error instanceof CodeModeError) {
|
|
243
|
-
codeModeErrors.push(error);
|
|
244
|
-
throw new RunError(error.message, error.code, error.details);
|
|
245
|
-
}
|
|
246
|
-
if (RunError.isInstance(error) || error instanceof Error && error.name === "HostFunctionInterruptSignal") {
|
|
247
|
-
throw error;
|
|
248
|
-
}
|
|
249
|
-
throw new RunError("Host tool failed.", "CODE_MODE_HOST_TOOL_ERROR");
|
|
250
|
-
}
|
|
133
|
+
async function invokeCodeModeTool({ codeModeErrors, input, outerToolCallId, policy, toolInput, toolName }) {
|
|
134
|
+
const context = getHostFunctionContext();
|
|
135
|
+
const toolCallId = `${outerToolCallId}:tool-${context.requestIndex}`;
|
|
136
|
+
const forwardedContext = input.toolExecutionOptions?.context ?? input.toolExecutionOptions?.experimental_context;
|
|
137
|
+
const forwardedExperimentalContext = input.toolExecutionOptions?.experimental_context ?? input.toolExecutionOptions?.context;
|
|
138
|
+
const baseExecutionOptions = {
|
|
139
|
+
toolCallId: outerToolCallId,
|
|
140
|
+
messages: input.toolExecutionOptions?.messages ?? [],
|
|
141
|
+
abortSignal: context.abortSignal,
|
|
142
|
+
...forwardedContext === void 0 ? {} : { context: forwardedContext },
|
|
143
|
+
...forwardedExperimentalContext === void 0 ? {} : { experimental_context: forwardedExperimentalContext }
|
|
144
|
+
};
|
|
145
|
+
let codeModeInterrupt;
|
|
146
|
+
let skipApproval = false;
|
|
147
|
+
if (context.resume !== void 0) {
|
|
148
|
+
const payload = assertInterruptPayload(context.resume.payload);
|
|
149
|
+
if (isCodeModeApprovalInterruptPayload(payload)) {
|
|
150
|
+
const decision = normalizeApprovalResolution(context.resume.resolution);
|
|
151
|
+
if (!decision.approved) throw new CodeModeToolApprovalDeniedError(toolName, toolInput, toolCallId, decision.reason);
|
|
152
|
+
skipApproval = true;
|
|
153
|
+
} else codeModeInterrupt = {
|
|
154
|
+
interruptId: `${toolCallId}:interrupt`,
|
|
155
|
+
payload,
|
|
156
|
+
resolution: context.resume.resolution
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const inputJson = toJsonPayload(toolInput, policy.maxToolInputBytes, `Tool "${toolName}" input`);
|
|
161
|
+
const outcome = await invokeHostTool({
|
|
162
|
+
toolName,
|
|
163
|
+
inputJson,
|
|
164
|
+
tools: input.tools,
|
|
165
|
+
baseExecutionOptions,
|
|
166
|
+
codeModeOptions: input.options ?? {},
|
|
167
|
+
maxToolInputBytes: policy.maxToolInputBytes,
|
|
168
|
+
maxToolOutputBytes: policy.maxToolOutputBytes,
|
|
169
|
+
toolCallId,
|
|
170
|
+
...codeModeInterrupt === void 0 ? {} : { codeModeInterrupt },
|
|
171
|
+
skipApproval
|
|
172
|
+
});
|
|
173
|
+
if (outcome.type === "interrupted") return context.interrupt(outcome.payload);
|
|
174
|
+
return fromJsonPayload(outcome.valueJson);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (error instanceof CodeModeError) {
|
|
177
|
+
codeModeErrors.push(error);
|
|
178
|
+
throw new RunError(error.message, error.code, error.details);
|
|
179
|
+
}
|
|
180
|
+
if (RunError.isInstance(error) || error instanceof Error && error.name === "HostFunctionInterruptSignal") throw error;
|
|
181
|
+
throw new RunError("Host tool failed.", "CODE_MODE_HOST_TOOL_ERROR");
|
|
182
|
+
}
|
|
251
183
|
}
|
|
252
184
|
function assertInterruptPayload(value) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"Code mode interruption payload is malformed."
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
return value;
|
|
185
|
+
if (typeof value !== "object" || value === null || Array.isArray(value) || typeof value.kind !== "string") throw new CodeModeProtocolError("Code mode interruption payload is malformed.");
|
|
186
|
+
return value;
|
|
259
187
|
}
|
|
260
188
|
function toRunLimits(policy, source, userSource) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
),
|
|
274
|
-
maxHostFunctionOutputBytes: expandedSerializationLimit(
|
|
275
|
-
policy.maxToolOutputBytes
|
|
276
|
-
),
|
|
277
|
-
maxBridgeRequests: policy.maxBridgeRequests,
|
|
278
|
-
maxInFlightBridgeRequests: policy.maxInFlightBridgeRequests
|
|
279
|
-
};
|
|
189
|
+
return {
|
|
190
|
+
timeoutMs: policy.timeoutMs,
|
|
191
|
+
memoryLimitBytes: policy.memoryLimitBytes,
|
|
192
|
+
maxStackSizeBytes: policy.maxStackSizeBytes,
|
|
193
|
+
maxResultBytes: expandedSerializationLimit(policy.maxResultBytes),
|
|
194
|
+
maxConsoleOutputBytes: policy.maxConsoleOutputBytes,
|
|
195
|
+
maxSourceBytes: withSerializationOverhead(policy.maxSourceBytes, Buffer.byteLength(source) - Buffer.byteLength(userSource)),
|
|
196
|
+
maxHostFunctionArgumentsBytes: expandedSerializationLimit(policy.maxToolInputBytes),
|
|
197
|
+
maxHostFunctionOutputBytes: expandedSerializationLimit(policy.maxToolOutputBytes),
|
|
198
|
+
maxBridgeRequests: policy.maxBridgeRequests,
|
|
199
|
+
maxInFlightBridgeRequests: policy.maxInFlightBridgeRequests
|
|
200
|
+
};
|
|
280
201
|
}
|
|
281
202
|
function expandedSerializationLimit(value) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
return Math.min(MAX_RUN_LIMIT, Math.max(4096, value * 2 + 1024));
|
|
203
|
+
if (!isValidRunLimit(value)) return value;
|
|
204
|
+
return Math.min(MAX_RUN_LIMIT, Math.max(4096, value * 2 + 1024));
|
|
286
205
|
}
|
|
287
206
|
function withSerializationOverhead(value, overhead) {
|
|
288
|
-
|
|
207
|
+
return isValidRunLimit(value) ? Math.min(MAX_RUN_LIMIT, value + overhead) : value;
|
|
289
208
|
}
|
|
290
209
|
function isValidRunLimit(value) {
|
|
291
|
-
|
|
210
|
+
return Number.isInteger(value) && value > 0 && value <= MAX_RUN_LIMIT;
|
|
292
211
|
}
|
|
293
212
|
function prepareContinuation(input, toolNames, maxToolOutputBytes) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const pending = input.continuation.pendingInterruptions[resolutionIndex];
|
|
323
|
-
if (pending === void 0 || pending.interruptId !== input.interruptResolution.interruptId) {
|
|
324
|
-
throw new CodeModeProtocolError(
|
|
325
|
-
"Interrupt resolution does not match the next pending code-mode interruption.",
|
|
326
|
-
{ interruptId: input.interruptResolution.interruptId }
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
const resolutionValue = normalizeResolutionForPending(
|
|
330
|
-
pending,
|
|
331
|
-
input.interruptResolution.resolution,
|
|
332
|
-
maxToolOutputBytes
|
|
333
|
-
);
|
|
334
|
-
const resolutions = [
|
|
335
|
-
...input.continuation.resolutions,
|
|
336
|
-
{
|
|
337
|
-
runInterruptionId: pending.runInterruptionId,
|
|
338
|
-
value: resolutionValue
|
|
339
|
-
}
|
|
340
|
-
];
|
|
341
|
-
if (resolutions.length < input.continuation.pendingInterruptions.length) {
|
|
342
|
-
const continuation = signCodeModeContinuation(
|
|
343
|
-
{
|
|
344
|
-
...withoutAuth(input.continuation),
|
|
345
|
-
resolutions
|
|
346
|
-
},
|
|
347
|
-
resolveCodeModeContinuationSecurity(input.options?.continuationSecurity)
|
|
348
|
-
);
|
|
349
|
-
return {
|
|
350
|
-
nextInterrupt: toCodeModeInterrupt(continuation, resolutions.length)
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
assertNoDeniedApproval(input.continuation.pendingInterruptions, resolutions);
|
|
354
|
-
return {
|
|
355
|
-
token: input.continuation.token,
|
|
356
|
-
resolutions: resolutions.map((resolution) => ({
|
|
357
|
-
interruptionId: resolution.runInterruptionId,
|
|
358
|
-
value: resolution.value
|
|
359
|
-
}))
|
|
360
|
-
};
|
|
213
|
+
if (input.continuation === void 0) {
|
|
214
|
+
if (input.interruptResolution !== void 0) throw new CodeModeProtocolError("A code-mode interrupt resolution was provided without continuation state.");
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
verifyCodeModeContinuation(input.continuation, input.options?.continuationSecurity);
|
|
218
|
+
if (input.continuation.js !== input.js) throw new CodeModeProtocolError("Code mode continuation source does not match the resumed source.");
|
|
219
|
+
if (!stringArraysEqual(input.continuation.toolNames, toolNames)) throw new CodeModeProtocolError("Code mode continuation tool names do not match the resumed tools.");
|
|
220
|
+
if (input.interruptResolution === void 0) throw new CodeModeProtocolError("A code-mode continuation requires an interrupt resolution.");
|
|
221
|
+
const resolutionIndex = input.continuation.resolutions.length;
|
|
222
|
+
const pending = input.continuation.pendingInterruptions[resolutionIndex];
|
|
223
|
+
if (pending === void 0 || pending.interruptId !== input.interruptResolution.interruptId) throw new CodeModeProtocolError("Interrupt resolution does not match the next pending code-mode interruption.", { interruptId: input.interruptResolution.interruptId });
|
|
224
|
+
const resolutionValue = normalizeResolutionForPending(pending, input.interruptResolution.resolution, maxToolOutputBytes);
|
|
225
|
+
const resolutions = [...input.continuation.resolutions, {
|
|
226
|
+
runInterruptionId: pending.runInterruptionId,
|
|
227
|
+
value: resolutionValue
|
|
228
|
+
}];
|
|
229
|
+
if (resolutions.length < input.continuation.pendingInterruptions.length) return { nextInterrupt: toCodeModeInterrupt(signCodeModeContinuation({
|
|
230
|
+
...withoutAuth(input.continuation),
|
|
231
|
+
resolutions
|
|
232
|
+
}, resolveCodeModeContinuationSecurity(input.options?.continuationSecurity)), resolutions.length) };
|
|
233
|
+
assertNoDeniedApproval(input.continuation.pendingInterruptions, resolutions);
|
|
234
|
+
return {
|
|
235
|
+
token: input.continuation.token,
|
|
236
|
+
resolutions: resolutions.map((resolution) => ({
|
|
237
|
+
interruptionId: resolution.runInterruptionId,
|
|
238
|
+
value: resolution.value
|
|
239
|
+
}))
|
|
240
|
+
};
|
|
361
241
|
}
|
|
362
242
|
function normalizeResolutionForPending(pending, resolution, maxToolOutputBytes) {
|
|
363
|
-
|
|
364
|
-
toJsonPayload(
|
|
365
|
-
resolution,
|
|
366
|
-
maxToolOutputBytes,
|
|
367
|
-
`Resolution "${pending.interruptId}"`
|
|
368
|
-
)
|
|
369
|
-
);
|
|
243
|
+
return isCodeModeApprovalInterruptPayload(pending.payload) ? normalizeApprovalResolution(resolution) : fromJsonPayload(toJsonPayload(resolution, maxToolOutputBytes, `Resolution "${pending.interruptId}"`));
|
|
370
244
|
}
|
|
371
245
|
function assertNoDeniedApproval(pendingInterruptions, resolutions) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (!decision.approved) {
|
|
378
|
-
throw new CodeModeToolApprovalDeniedError(
|
|
379
|
-
pending.toolName,
|
|
380
|
-
pending.input,
|
|
381
|
-
pending.toolCallId,
|
|
382
|
-
decision.reason
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
246
|
+
for (const [index, pending] of pendingInterruptions.entries()) {
|
|
247
|
+
if (!isCodeModeApprovalInterruptPayload(pending.payload)) continue;
|
|
248
|
+
const decision = normalizeApprovalResolution(resolutions[index]?.value);
|
|
249
|
+
if (!decision.approved) throw new CodeModeToolApprovalDeniedError(pending.toolName, pending.input, pending.toolCallId, decision.reason);
|
|
250
|
+
}
|
|
386
251
|
}
|
|
387
252
|
function withoutAuth(continuation) {
|
|
388
|
-
|
|
389
|
-
|
|
253
|
+
const { auth: _auth, ...unsigned } = continuation;
|
|
254
|
+
return unsigned;
|
|
390
255
|
}
|
|
391
|
-
function toPendingInterruptions({
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
input: interruption.hostFunctionName === "__codeMode.missing" ? interruption.arguments[1] : interruption.arguments[0],
|
|
406
|
-
payload: assertInterruptPayload(interruption.payload)
|
|
407
|
-
};
|
|
408
|
-
});
|
|
256
|
+
function toPendingInterruptions({ interruptions, outerToolCallId, toolNames }) {
|
|
257
|
+
return interruptions.map((interruption) => {
|
|
258
|
+
const requestIndex = interruptionIndex(interruption.id);
|
|
259
|
+
const toolName = toolNameForInterruption(interruption, toolNames);
|
|
260
|
+
const toolCallId = `${outerToolCallId}:tool-${requestIndex}`;
|
|
261
|
+
return {
|
|
262
|
+
runInterruptionId: interruption.id,
|
|
263
|
+
interruptId: `${toolCallId}:interrupt`,
|
|
264
|
+
toolName,
|
|
265
|
+
toolCallId,
|
|
266
|
+
input: interruption.hostFunctionName === "__codeMode.missing" ? interruption.arguments[1] : interruption.arguments[0],
|
|
267
|
+
payload: assertInterruptPayload(interruption.payload)
|
|
268
|
+
};
|
|
269
|
+
});
|
|
409
270
|
}
|
|
410
271
|
function interruptionIndex(interruptionId) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
`Run returned malformed interruption id "${interruptionId}".`
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
return Number(match[1]);
|
|
272
|
+
const match = /^interrupt-(\d+)$/u.exec(interruptionId);
|
|
273
|
+
if (match === null) throw new CodeModeProtocolError(`Run returned malformed interruption id "${interruptionId}".`);
|
|
274
|
+
return Number(match[1]);
|
|
418
275
|
}
|
|
419
276
|
function toolNameForInterruption(interruption, toolNames) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (toolName === void 0) {
|
|
426
|
-
throw new CodeModeProtocolError(
|
|
427
|
-
`Run returned an unknown code-mode host function "${interruption.hostFunctionName}".`
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
return toolName;
|
|
277
|
+
if (interruption.hostFunctionName === "__codeMode.missing") return String(interruption.arguments[0]);
|
|
278
|
+
const match = /^__codeMode\.tool(\d+)$/u.exec(interruption.hostFunctionName);
|
|
279
|
+
const toolName = match === null ? void 0 : toolNames[Number(match[1])];
|
|
280
|
+
if (toolName === void 0) throw new CodeModeProtocolError(`Run returned an unknown code-mode host function "${interruption.hostFunctionName}".`);
|
|
281
|
+
return toolName;
|
|
431
282
|
}
|
|
432
283
|
function toCodeModeInterrupt(continuation, index) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
input: structuredClone(pending.input),
|
|
446
|
-
payload: structuredClone(pending.payload),
|
|
447
|
-
continuation
|
|
448
|
-
};
|
|
284
|
+
const pending = continuation.pendingInterruptions[index];
|
|
285
|
+
if (pending === void 0) throw new CodeModeProtocolError("Code mode continuation has no pending interruption at the requested index.");
|
|
286
|
+
return {
|
|
287
|
+
type: "code-mode-interrupt",
|
|
288
|
+
interruptId: pending.interruptId,
|
|
289
|
+
toolName: pending.toolName,
|
|
290
|
+
toolCallId: pending.toolCallId,
|
|
291
|
+
outerToolCallId: continuation.outerToolCallId,
|
|
292
|
+
input: structuredClone(pending.input),
|
|
293
|
+
payload: structuredClone(pending.payload),
|
|
294
|
+
continuation
|
|
295
|
+
};
|
|
449
296
|
}
|
|
450
297
|
function stringArraysEqual(left, right) {
|
|
451
|
-
|
|
298
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
452
299
|
}
|
|
453
300
|
function findPreservedCodeModeError(error, errors) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
457
|
-
return errors.find((candidate) => candidate.code === error.code);
|
|
301
|
+
if (!RunError.isInstance(error)) return;
|
|
302
|
+
return errors.find((candidate) => candidate.code === error.code);
|
|
458
303
|
}
|
|
459
304
|
function toCodeModeRuntimeError(error) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
return copyStack(
|
|
475
|
-
new CodeModeTimeoutError(Number(details?.timeoutMs ?? 0)),
|
|
476
|
-
error
|
|
477
|
-
);
|
|
478
|
-
case "RUN_CONCURRENCY_LIMIT":
|
|
479
|
-
return copyStack(
|
|
480
|
-
new CodeModeConcurrencyError(Number(details?.maxWorkers ?? 0)),
|
|
481
|
-
error
|
|
482
|
-
);
|
|
483
|
-
case "RUN_SOURCE_TOO_LARGE":
|
|
484
|
-
return copyStack(
|
|
485
|
-
new CodeModeSourceTooLargeError(
|
|
486
|
-
Number(details?.bytes ?? 0),
|
|
487
|
-
Number(details?.maxBytes ?? 0)
|
|
488
|
-
),
|
|
489
|
-
error
|
|
490
|
-
);
|
|
491
|
-
case "RUN_BRIDGE_LIMIT":
|
|
492
|
-
return copyStack(
|
|
493
|
-
new CodeModeBridgeLimitError(error.message, error.details),
|
|
494
|
-
error
|
|
495
|
-
);
|
|
496
|
-
case "RUN_DETACHED_BRIDGE_REQUEST":
|
|
497
|
-
return copyStack(
|
|
498
|
-
new CodeModeDetachedBridgeRequestError(error.message, error.details),
|
|
499
|
-
error
|
|
500
|
-
);
|
|
501
|
-
case "RUN_PROTOCOL_ERROR":
|
|
502
|
-
return copyStack(
|
|
503
|
-
new CodeModeProtocolError(error.message, error.details),
|
|
504
|
-
error
|
|
505
|
-
);
|
|
506
|
-
default:
|
|
507
|
-
return error;
|
|
508
|
-
}
|
|
305
|
+
if (error instanceof TypeError) error.message = translateLimitPath(error.message);
|
|
306
|
+
if (error instanceof Error && error.name === "SyntaxError" && !/syntax|unexpected|expression expected/iu.test(error.message)) error.message = `Syntax error: ${error.message}`;
|
|
307
|
+
if (!RunError.isInstance(error)) return error;
|
|
308
|
+
const details = error.details;
|
|
309
|
+
switch (error.code) {
|
|
310
|
+
case "RUN_ABORTED": return copyStack(new CodeModeAbortedError(), error);
|
|
311
|
+
case "RUN_TIMEOUT": return copyStack(new CodeModeTimeoutError(Number(details?.timeoutMs ?? 0)), error);
|
|
312
|
+
case "RUN_CONCURRENCY_LIMIT": return copyStack(new CodeModeConcurrencyError(Number(details?.maxWorkers ?? 0)), error);
|
|
313
|
+
case "RUN_SOURCE_TOO_LARGE": return copyStack(new CodeModeSourceTooLargeError(Number(details?.bytes ?? 0), Number(details?.maxBytes ?? 0)), error);
|
|
314
|
+
case "RUN_BRIDGE_LIMIT": return copyStack(new CodeModeBridgeLimitError(error.message, error.details), error);
|
|
315
|
+
case "RUN_DETACHED_BRIDGE_REQUEST": return copyStack(new CodeModeDetachedBridgeRequestError(error.message, error.details), error);
|
|
316
|
+
case "RUN_PROTOCOL_ERROR": return copyStack(new CodeModeProtocolError(error.message, error.details), error);
|
|
317
|
+
default: return error;
|
|
318
|
+
}
|
|
509
319
|
}
|
|
510
320
|
function translateLimitPath(message) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
if (message.includes(runPath)) {
|
|
525
|
-
return message.replace(runPath, codeModePath);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
return message;
|
|
321
|
+
for (const [runPath, codeModePath] of Object.entries({
|
|
322
|
+
"limits.timeoutMs": "executionPolicy.timeoutMs",
|
|
323
|
+
"limits.memoryLimitBytes": "executionPolicy.memoryLimitBytes",
|
|
324
|
+
"limits.maxStackSizeBytes": "executionPolicy.maxStackSizeBytes",
|
|
325
|
+
"limits.maxResultBytes": "executionPolicy.maxResultBytes",
|
|
326
|
+
"limits.maxConsoleOutputBytes": "executionPolicy.maxConsoleOutputBytes",
|
|
327
|
+
"limits.maxSourceBytes": "executionPolicy.maxSourceBytes",
|
|
328
|
+
"limits.maxHostFunctionArgumentsBytes": "executionPolicy.maxToolInputBytes",
|
|
329
|
+
"limits.maxHostFunctionOutputBytes": "executionPolicy.maxToolOutputBytes",
|
|
330
|
+
"limits.maxBridgeRequests": "executionPolicy.maxBridgeRequests",
|
|
331
|
+
"limits.maxInFlightBridgeRequests": "executionPolicy.maxInFlightBridgeRequests"
|
|
332
|
+
})) if (message.includes(runPath)) return message.replace(runPath, codeModePath);
|
|
333
|
+
return message;
|
|
529
334
|
}
|
|
530
335
|
function copyStack(target, source) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
534
|
-
return target;
|
|
336
|
+
if (source.stack !== void 0) target.stack = source.stack;
|
|
337
|
+
return target;
|
|
535
338
|
}
|
|
536
339
|
function translateSourceStack(error) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
error.stack = error.stack.replaceAll(
|
|
541
|
-
/run\.js:(\d+):(\d+)/gu,
|
|
542
|
-
(_match, line, column) => `code-mode.js:${Math.max(1, Number(line) - SOURCE_LINE_OFFSET)}:${column}`
|
|
543
|
-
);
|
|
544
|
-
return error;
|
|
340
|
+
if (!(error instanceof Error) || error.stack === void 0) return error;
|
|
341
|
+
error.stack = error.stack.replaceAll(/run\.js:(\d+):(\d+)/gu, (_match, line, column) => `code-mode.js:${Math.max(1, Number(line) - SOURCE_LINE_OFFSET)}:${column}`);
|
|
342
|
+
return error;
|
|
545
343
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
344
|
+
//#endregion
|
|
345
|
+
export { runCodeMode };
|
|
346
|
+
|
|
549
347
|
//# sourceMappingURL=run-code-mode.js.map
|