@ai-sdk/code-mode 1.0.20 → 1.0.22

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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/dist/continuation-capability.js +5 -0
  3. package/dist/continuation-capability.js.map +1 -1
  4. package/dist/errors.js +1 -136
  5. package/dist/errors.js.map +1 -1
  6. package/dist/host-interrupt.js +2 -14
  7. package/dist/host-interrupt.js.map +1 -1
  8. package/dist/index.d.ts +14 -44
  9. package/dist/index.js +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/interrupt-continuation.js +3 -8
  12. package/dist/interrupt-continuation.js.map +1 -1
  13. package/dist/run-code-mode.js +543 -2
  14. package/dist/run-code-mode.js.map +1 -1
  15. package/dist/tool-invocation.js +9 -23
  16. package/dist/tool-invocation.js.map +1 -1
  17. package/dist/utils/serialization.js +4 -0
  18. package/dist/utils/serialization.js.map +1 -1
  19. package/package.json +8 -7
  20. package/src/continuation-capability.ts +18 -0
  21. package/src/errors.ts +0 -190
  22. package/src/host-interrupt.ts +2 -31
  23. package/src/index.ts +1 -1
  24. package/src/interrupt-continuation.ts +13 -15
  25. package/src/run-code-mode.ts +706 -3
  26. package/src/tool-invocation.ts +9 -23
  27. package/src/types.ts +38 -68
  28. package/src/utils/serialization.ts +4 -0
  29. package/dist/runtime/guest-sources.js +0 -350
  30. package/dist/runtime/guest-sources.js.map +0 -1
  31. package/dist/runtime/manager.js +0 -794
  32. package/dist/runtime/manager.js.map +0 -1
  33. package/dist/runtime/max-workers.js +0 -40
  34. package/dist/runtime/max-workers.js.map +0 -1
  35. package/dist/runtime/protocol.js +0 -1
  36. package/dist/runtime/protocol.js.map +0 -1
  37. package/dist/runtime/worker-source.d.ts +0 -11
  38. package/dist/runtime/worker-source.js +0 -2
  39. package/dist/utils/options.js +0 -76
  40. package/dist/utils/options.js.map +0 -1
  41. package/dist/utils/source-cache.js +0 -77
  42. package/dist/utils/source-cache.js.map +0 -1
  43. package/src/runtime/guest-sources.ts +0 -351
  44. package/src/runtime/manager.ts +0 -963
  45. package/src/runtime/max-workers.ts +0 -65
  46. package/src/runtime/protocol.ts +0 -74
  47. package/src/runtime/worker-source.ts +0 -10
  48. package/src/runtime/worker.ts +0 -607
  49. package/src/utils/options.ts +0 -83
  50. package/src/utils/source-cache.ts +0 -91
@@ -1,794 +0,0 @@
1
- import { AsyncResource } from "node:async_hooks";
2
- import { Buffer } from "node:buffer";
3
- import { randomBytes } from "node:crypto";
4
- import { Worker } from "node:worker_threads";
5
- import {
6
- isCodeModeApprovalInterruptPayload,
7
- normalizeApprovalResolution
8
- } from "../approval.js";
9
- import {
10
- resolveCodeModeContinuationSecurity,
11
- signCodeModeContinuation,
12
- verifyCodeModeContinuation
13
- } from "../continuation-capability.js";
14
- import {
15
- CodeModeAbortedError,
16
- CodeModeBridgeLimitError,
17
- CodeModeConcurrencyError,
18
- CodeModeDetachedBridgeRequestError,
19
- CodeModeProtocolError,
20
- CodeModeTimeoutError,
21
- CodeModeToolApprovalDeniedError,
22
- deserializeError,
23
- serializeBridgeErrorForGuest
24
- } from "../errors.js";
25
- import { invokeHostTool } from "../tool-invocation.js";
26
- import { normalizeOptions } from "../utils/options.js";
27
- import { assertSourceSize, transformSource } from "../utils/source-cache.js";
28
- import { getMaxWorkers } from "./max-workers.js";
29
- import { INLINE_CODE_MODE_WORKER_SOURCE } from "./worker-source.js";
30
- let invocationCounter = 0;
31
- let activeInvocations = 0;
32
- let inlineWorkerUrl;
33
- const idleWorkers = [];
34
- async function runManagedCodeMode(input) {
35
- const normalizedOptions = normalizeOptions(input.options);
36
- const continuationSecurity = resolveCodeModeContinuationSecurity(
37
- input.options?.continuationSecurity
38
- );
39
- const maxWorkers = getMaxWorkers({
40
- memoryLimitBytes: normalizedOptions.memoryLimitBytes,
41
- activeWorkers: activeInvocations
42
- });
43
- if (activeInvocations >= maxWorkers) {
44
- throw new CodeModeConcurrencyError(maxWorkers);
45
- }
46
- activeInvocations++;
47
- try {
48
- if (input.toolExecutionOptions?.abortSignal?.aborted) {
49
- throw new CodeModeAbortedError();
50
- }
51
- assertSourceSize(input.js, normalizedOptions.maxSourceBytes);
52
- const js = transformSource(input.js);
53
- assertContinuationInput({
54
- js,
55
- continuation: input.continuation,
56
- interruptResolution: input.interruptResolution,
57
- continuationSecurity
58
- });
59
- const run = startWorkerRun({
60
- ...input,
61
- js,
62
- normalizedOptions,
63
- maxWorkers,
64
- continuationSecurity
65
- });
66
- return await run.result;
67
- } finally {
68
- releaseInvocationSlot(normalizedOptions.memoryLimitBytes);
69
- }
70
- }
71
- function startWorkerRun({
72
- js,
73
- tools,
74
- toolExecutionOptions,
75
- options,
76
- continuation,
77
- interruptResolution,
78
- normalizedOptions,
79
- maxWorkers,
80
- continuationSecurity
81
- }) {
82
- const invocationId = `code-mode-${++invocationCounter}`;
83
- const pooledWorker = acquireWorker(maxWorkers);
84
- const worker = pooledWorker.worker;
85
- const invocationContext = new AsyncResource("ai-sdk-code-mode:invocation");
86
- const bindInvocationContext = (handler) => {
87
- return (...args) => {
88
- invocationContext.runInAsyncScope(handler, void 0, ...args);
89
- };
90
- };
91
- const outerAbortSignal = toolExecutionOptions?.abortSignal;
92
- const invocationAbortController = new AbortController();
93
- let nestedToolCounter = getMaxNestedToolCounter(continuation?.ledger ?? []);
94
- const forwardedContext = toolExecutionOptions?.context ?? toolExecutionOptions?.experimental_context;
95
- const forwardedExperimentalContext = toolExecutionOptions?.experimental_context ?? toolExecutionOptions?.context;
96
- const baseExecutionOptions = {
97
- toolCallId: toolExecutionOptions?.toolCallId ?? continuation?.outerToolCallId ?? invocationId,
98
- messages: toolExecutionOptions?.messages ?? [],
99
- abortSignal: invocationAbortController.signal,
100
- ...forwardedExperimentalContext !== void 0 ? { experimental_context: forwardedExperimentalContext } : {},
101
- ...forwardedContext !== void 0 ? { context: forwardedContext } : {}
102
- };
103
- let resultMessage;
104
- let callerSettled = false;
105
- let terminalReached = false;
106
- let workerCleanedUp = false;
107
- let totalBridgeRequests = 0;
108
- let inFlightBridgeRequests = 0;
109
- let interruptEntryIndex;
110
- let interruptDrainCounter = 0;
111
- let pendingInterruptDrainId;
112
- let interruptResolutionConsumed = interruptResolution === void 0;
113
- const seenWorkerRequestIds = /* @__PURE__ */ new Set();
114
- const bridgeLedger = cloneLedger(continuation?.ledger ?? []);
115
- const determinism = continuation?.determinism ?? createDeterminismState();
116
- let resolveResult;
117
- let rejectResult;
118
- const result = new Promise((resolve, reject) => {
119
- resolveResult = resolve;
120
- rejectResult = reject;
121
- });
122
- const abortInvocation = (reason) => {
123
- if (!invocationAbortController.signal.aborted) {
124
- invocationAbortController.abort(reason);
125
- }
126
- };
127
- const cleanupWorker = (reuseWorker) => {
128
- if (workerCleanedUp) {
129
- return;
130
- }
131
- workerCleanedUp = true;
132
- clearTimeout(timeoutHandle);
133
- outerAbortSignal?.removeEventListener("abort", onAbort);
134
- worker.off("message", onMessage);
135
- worker.off("error", onError);
136
- worker.off("exit", onExit);
137
- invocationContext.emitDestroy();
138
- if (reuseWorker) {
139
- releaseWorker(pooledWorker);
140
- } else {
141
- destroyWorker(pooledWorker);
142
- }
143
- };
144
- const settleCaller = (settle) => {
145
- if (callerSettled) {
146
- return;
147
- }
148
- callerSettled = true;
149
- try {
150
- settle();
151
- } catch (error) {
152
- rejectResult(error);
153
- }
154
- };
155
- const failTerminal = (error) => {
156
- if (terminalReached) {
157
- return;
158
- }
159
- terminalReached = true;
160
- abortInvocation(error);
161
- cleanupWorker(false);
162
- settleCaller(() => rejectResult(error));
163
- };
164
- const onAbort = bindInvocationContext(() => {
165
- failTerminal(new CodeModeAbortedError());
166
- });
167
- const timeoutHandle = setTimeout(
168
- bindInvocationContext(() => {
169
- failTerminal(new CodeModeTimeoutError(normalizedOptions.timeoutMs));
170
- }),
171
- normalizedOptions.timeoutMs
172
- );
173
- const onMessage = bindInvocationContext((message) => {
174
- if (message.invocationId !== invocationId) {
175
- failTerminal(
176
- new CodeModeProtocolError(
177
- `Worker message invocationId mismatch: expected ${invocationId}, received ${message.invocationId}.`,
178
- {
179
- expectedInvocationId: invocationId,
180
- receivedInvocationId: message.invocationId,
181
- messageType: message.type
182
- }
183
- )
184
- );
185
- return;
186
- }
187
- if (message.type === "result") {
188
- if (resultMessage !== void 0) {
189
- failTerminal(
190
- new CodeModeProtocolError(
191
- `Worker sent duplicate result for invocation ${invocationId}.`,
192
- { invocationId }
193
- )
194
- );
195
- return;
196
- }
197
- resultMessage = message;
198
- return;
199
- }
200
- if (message.type === "ready") {
201
- handleReadyMessage(message);
202
- return;
203
- }
204
- if (message.type === "bridge-drained") {
205
- if (pendingInterruptDrainId === void 0 || message.drainId !== pendingInterruptDrainId) {
206
- failTerminal(
207
- new CodeModeProtocolError(
208
- `Worker sent unexpected bridge drain acknowledgement ${message.drainId}.`,
209
- {
210
- invocationId,
211
- expectedDrainId: pendingInterruptDrainId,
212
- receivedDrainId: message.drainId
213
- }
214
- )
215
- );
216
- return;
217
- }
218
- pendingInterruptDrainId = void 0;
219
- if (inFlightBridgeRequests === 0) {
220
- settleInterrupt();
221
- }
222
- return;
223
- }
224
- const bridgeIndex = markWorkerRequest(message);
225
- if (bridgeIndex !== void 0) {
226
- void handleToolRequest(message, bridgeIndex);
227
- }
228
- });
229
- const onError = bindInvocationContext((error) => {
230
- failTerminal(error);
231
- });
232
- const onExit = bindInvocationContext((code) => {
233
- if (!terminalReached) {
234
- failTerminal(
235
- new Error(
236
- `Code mode worker exited before completion with code ${code}.`
237
- )
238
- );
239
- }
240
- });
241
- worker.on("message", onMessage);
242
- worker.on("error", onError);
243
- worker.on("exit", onExit);
244
- outerAbortSignal?.addEventListener("abort", onAbort, { once: true });
245
- if (outerAbortSignal?.aborted) {
246
- onAbort();
247
- }
248
- const runMessage = {
249
- type: "run",
250
- invocationId,
251
- js,
252
- determinism,
253
- options: {
254
- timeoutMs: normalizedOptions.timeoutMs,
255
- memoryLimitBytes: normalizedOptions.memoryLimitBytes,
256
- maxStackSizeBytes: normalizedOptions.maxStackSizeBytes,
257
- maxResultBytes: normalizedOptions.maxResultBytes,
258
- maxConsoleOutputBytes: normalizedOptions.maxConsoleOutputBytes
259
- }
260
- };
261
- if (!terminalReached) {
262
- try {
263
- worker.postMessage(runMessage);
264
- } catch (error) {
265
- failTerminal(error);
266
- }
267
- }
268
- return { result };
269
- function markWorkerRequest(message) {
270
- if (terminalReached) {
271
- return void 0;
272
- }
273
- if (seenWorkerRequestIds.has(message.requestId)) {
274
- failTerminal(
275
- new CodeModeProtocolError(
276
- `Worker sent duplicate requestId ${message.requestId}.`,
277
- { invocationId, requestId: message.requestId }
278
- )
279
- );
280
- return void 0;
281
- }
282
- seenWorkerRequestIds.add(message.requestId);
283
- if (totalBridgeRequests >= normalizedOptions.maxBridgeRequests) {
284
- failTerminal(
285
- new CodeModeBridgeLimitError(
286
- `Code mode exceeded the ${normalizedOptions.maxBridgeRequests} bridge request limit.`,
287
- {
288
- invocationId,
289
- maxBridgeRequests: normalizedOptions.maxBridgeRequests
290
- }
291
- )
292
- );
293
- return void 0;
294
- }
295
- if (inFlightBridgeRequests >= normalizedOptions.maxInFlightBridgeRequests) {
296
- failTerminal(
297
- new CodeModeBridgeLimitError(
298
- `Code mode exceeded the ${normalizedOptions.maxInFlightBridgeRequests} in-flight bridge request limit.`,
299
- {
300
- invocationId,
301
- maxInFlightBridgeRequests: normalizedOptions.maxInFlightBridgeRequests
302
- }
303
- )
304
- );
305
- return void 0;
306
- }
307
- totalBridgeRequests++;
308
- inFlightBridgeRequests++;
309
- return totalBridgeRequests;
310
- }
311
- async function handleToolRequest(message, bridgeIndex) {
312
- const replayEntry = bridgeLedger[bridgeIndex - 1];
313
- try {
314
- if (replayEntry !== void 0) {
315
- assertReplayEntryMatches(replayEntry, message, bridgeIndex);
316
- if (replayEntry.status === "fulfilled") {
317
- postBridgeResponse({
318
- type: "bridge-response",
319
- invocationId,
320
- requestId: message.requestId,
321
- success: true,
322
- dateNowMs: replayEntry.dateNowMs,
323
- valueJson: replayEntry.valueJson
324
- });
325
- return;
326
- }
327
- if (replayEntry.status === "rejected") {
328
- postBridgeResponse({
329
- type: "bridge-response",
330
- invocationId,
331
- requestId: message.requestId,
332
- success: false,
333
- dateNowMs: replayEntry.dateNowMs,
334
- error: replayEntry.error
335
- });
336
- return;
337
- }
338
- if (interruptResolution?.interruptId !== replayEntry.interruptId) {
339
- requestInterrupt(bridgeIndex - 1);
340
- return;
341
- }
342
- interruptResolutionConsumed = true;
343
- const isApproval = isCodeModeApprovalInterruptPayload(
344
- replayEntry.interruptPayload
345
- );
346
- if (isApproval) {
347
- const decision = normalizeApprovalResolution(
348
- interruptResolution.resolution
349
- );
350
- if (!decision.approved) {
351
- const error = new CodeModeToolApprovalDeniedError(
352
- replayEntry.name,
353
- fromJsonPayload(message.inputJson),
354
- replayEntry.toolCallId,
355
- decision.reason
356
- );
357
- const dateNowMs3 = Date.now();
358
- const guestError = serializeBridgeErrorForGuest(error, "tool");
359
- bridgeLedger[bridgeIndex - 1] = {
360
- kind: "tool",
361
- name: message.toolName,
362
- inputJson: message.inputJson,
363
- toolCallId: replayEntry.toolCallId,
364
- status: "rejected",
365
- dateNowMs: dateNowMs3,
366
- error: guestError
367
- };
368
- postBridgeResponse({
369
- type: "bridge-response",
370
- invocationId,
371
- requestId: message.requestId,
372
- success: false,
373
- dateNowMs: dateNowMs3,
374
- error: guestError
375
- });
376
- return;
377
- }
378
- }
379
- const codeModeInterrupt = isApproval ? void 0 : {
380
- interruptId: replayEntry.interruptId,
381
- payload: replayEntry.interruptPayload,
382
- resolution: interruptResolution.resolution
383
- };
384
- const outcome2 = await invokeHostTool({
385
- toolName: message.toolName,
386
- inputJson: message.inputJson,
387
- tools,
388
- baseExecutionOptions,
389
- codeModeOptions: options ?? {},
390
- maxToolInputBytes: normalizedOptions.maxToolInputBytes,
391
- maxToolOutputBytes: normalizedOptions.maxToolOutputBytes,
392
- toolCallId: replayEntry.toolCallId,
393
- ...codeModeInterrupt !== void 0 ? { codeModeInterrupt } : {},
394
- skipApproval: true
395
- });
396
- if (outcome2.type === "interrupted") {
397
- bridgeLedger[bridgeIndex - 1] = {
398
- kind: "tool",
399
- name: message.toolName,
400
- inputJson: message.inputJson,
401
- toolCallId: replayEntry.toolCallId,
402
- interruptId: `${replayEntry.toolCallId}:interrupt`,
403
- interruptPayload: outcome2.payload,
404
- status: "interrupted"
405
- };
406
- requestInterrupt(bridgeIndex - 1);
407
- return;
408
- }
409
- const dateNowMs2 = Date.now();
410
- bridgeLedger[bridgeIndex - 1] = {
411
- kind: "tool",
412
- name: message.toolName,
413
- inputJson: message.inputJson,
414
- toolCallId: replayEntry.toolCallId,
415
- status: "fulfilled",
416
- dateNowMs: dateNowMs2,
417
- valueJson: outcome2.valueJson
418
- };
419
- postBridgeResponse({
420
- type: "bridge-response",
421
- invocationId,
422
- requestId: message.requestId,
423
- success: true,
424
- dateNowMs: dateNowMs2,
425
- valueJson: outcome2.valueJson
426
- });
427
- return;
428
- }
429
- const toolCallId = `${baseExecutionOptions.toolCallId}:tool-${++nestedToolCounter}`;
430
- const outcome = await invokeHostTool({
431
- toolName: message.toolName,
432
- inputJson: message.inputJson,
433
- tools,
434
- baseExecutionOptions,
435
- codeModeOptions: options ?? {},
436
- maxToolInputBytes: normalizedOptions.maxToolInputBytes,
437
- maxToolOutputBytes: normalizedOptions.maxToolOutputBytes,
438
- toolCallId
439
- });
440
- if (outcome.type === "interrupted") {
441
- bridgeLedger[bridgeIndex - 1] = {
442
- kind: "tool",
443
- name: message.toolName,
444
- inputJson: message.inputJson,
445
- toolCallId,
446
- interruptId: `${toolCallId}:interrupt`,
447
- interruptPayload: outcome.payload,
448
- status: "interrupted"
449
- };
450
- requestInterrupt(bridgeIndex - 1);
451
- return;
452
- }
453
- const dateNowMs = Date.now();
454
- bridgeLedger[bridgeIndex - 1] = {
455
- kind: "tool",
456
- name: message.toolName,
457
- inputJson: message.inputJson,
458
- toolCallId,
459
- status: "fulfilled",
460
- dateNowMs,
461
- valueJson: outcome.valueJson
462
- };
463
- postBridgeResponse({
464
- type: "bridge-response",
465
- invocationId,
466
- requestId: message.requestId,
467
- success: true,
468
- dateNowMs,
469
- valueJson: outcome.valueJson
470
- });
471
- } catch (error) {
472
- if (error instanceof CodeModeProtocolError) {
473
- failTerminal(error);
474
- return;
475
- }
476
- const dateNowMs = Date.now();
477
- const guestError = serializeBridgeErrorForGuest(error, "tool");
478
- const toolCallId = replayEntry?.toolCallId ?? `${baseExecutionOptions.toolCallId}:tool-${nestedToolCounter}`;
479
- if (replayEntry === void 0 || replayEntry.status === "interrupted" && interruptResolution?.interruptId === replayEntry.interruptId) {
480
- bridgeLedger[bridgeIndex - 1] = {
481
- kind: "tool",
482
- name: message.toolName,
483
- inputJson: message.inputJson,
484
- toolCallId,
485
- status: "rejected",
486
- dateNowMs,
487
- error: guestError
488
- };
489
- }
490
- postBridgeResponse({
491
- type: "bridge-response",
492
- invocationId,
493
- requestId: message.requestId,
494
- success: false,
495
- dateNowMs,
496
- error: guestError
497
- });
498
- } finally {
499
- inFlightBridgeRequests--;
500
- settleInterruptIfReady();
501
- }
502
- }
503
- function requestInterrupt(entryIndex) {
504
- interruptEntryIndex ??= entryIndex;
505
- }
506
- function settleInterruptIfReady() {
507
- if (interruptEntryIndex === void 0 || terminalReached || inFlightBridgeRequests > 0 || pendingInterruptDrainId !== void 0 || !interruptResolutionConsumed) {
508
- return;
509
- }
510
- pendingInterruptDrainId = `${invocationId}:drain-${++interruptDrainCounter}`;
511
- postBridgeResponse({
512
- type: "bridge-drain",
513
- invocationId,
514
- drainId: pendingInterruptDrainId
515
- });
516
- }
517
- function settleInterrupt() {
518
- if (interruptEntryIndex === void 0 || terminalReached || inFlightBridgeRequests > 0 || !interruptResolutionConsumed) {
519
- return;
520
- }
521
- const entry = bridgeLedger[interruptEntryIndex];
522
- if (entry === void 0 || entry.status !== "interrupted") {
523
- failTerminal(
524
- new CodeModeProtocolError(
525
- "Code mode interruption references a missing or resolved ledger entry.",
526
- { invocationId, interruptEntryIndex }
527
- )
528
- );
529
- return;
530
- }
531
- const continuationState = signCodeModeContinuation(
532
- {
533
- version: 1,
534
- js,
535
- outerToolCallId: baseExecutionOptions.toolCallId,
536
- determinism: { ...determinism },
537
- ledger: cloneLedger(bridgeLedger)
538
- },
539
- continuationSecurity
540
- );
541
- const interrupt = {
542
- type: "code-mode-interrupt",
543
- interruptId: entry.interruptId,
544
- toolName: entry.name,
545
- toolCallId: entry.toolCallId,
546
- outerToolCallId: continuationState.outerToolCallId,
547
- input: fromJsonPayload(entry.inputJson),
548
- payload: structuredClone(entry.interruptPayload),
549
- continuation: continuationState
550
- };
551
- terminalReached = true;
552
- abortInvocation(interrupt);
553
- cleanupWorker(false);
554
- settleCaller(() => resolveResult(interrupt));
555
- }
556
- function postBridgeResponse(message) {
557
- if (terminalReached) {
558
- return;
559
- }
560
- try {
561
- worker.postMessage(message);
562
- } catch (error) {
563
- failTerminal(error);
564
- }
565
- }
566
- function handleReadyMessage(message) {
567
- if (terminalReached) {
568
- return;
569
- }
570
- if (interruptEntryIndex !== void 0) {
571
- settleInterruptIfReady();
572
- return;
573
- }
574
- if (resultMessage === void 0) {
575
- failTerminal(
576
- new CodeModeProtocolError(
577
- `Code mode worker became ready without a result for ${message.invocationId}.`,
578
- { invocationId: message.invocationId }
579
- )
580
- );
581
- return;
582
- }
583
- if (!interruptResolutionConsumed) {
584
- failTerminal(
585
- new CodeModeProtocolError(
586
- "Code mode continuation completed without consuming its interrupt resolution.",
587
- { interruptId: interruptResolution?.interruptId }
588
- )
589
- );
590
- return;
591
- }
592
- if (continuation !== void 0 && totalBridgeRequests < bridgeLedger.length) {
593
- failTerminal(
594
- new CodeModeProtocolError(
595
- "Code mode continuation returned before replaying the full bridge ledger.",
596
- {
597
- replayedBridgeRequests: totalBridgeRequests,
598
- ledgerEntries: bridgeLedger.length
599
- }
600
- )
601
- );
602
- return;
603
- }
604
- terminalReached = true;
605
- const finalResultMessage = resultMessage;
606
- if (inFlightBridgeRequests > 0) {
607
- const error = finalResultMessage.success ? new CodeModeDetachedBridgeRequestError(
608
- `Code mode returned while ${inFlightBridgeRequests} bridge request(s) were still in flight.`,
609
- {
610
- invocationId,
611
- inFlightBridgeRequests,
612
- totalBridgeRequests
613
- }
614
- ) : deserializeResultError(finalResultMessage);
615
- abortInvocation(error);
616
- cleanupWorker(false);
617
- settleCaller(() => rejectResult(error));
618
- return;
619
- }
620
- cleanupWorker(true);
621
- settleCaller(
622
- () => settleWithResultMessage(finalResultMessage, resolveResult, rejectResult)
623
- );
624
- }
625
- }
626
- function assertContinuationInput({
627
- js,
628
- continuation,
629
- interruptResolution,
630
- continuationSecurity
631
- }) {
632
- if (continuation === void 0) {
633
- if (interruptResolution !== void 0) {
634
- throw new CodeModeProtocolError(
635
- "A code-mode interrupt resolution was provided without continuation state."
636
- );
637
- }
638
- return;
639
- }
640
- verifyCodeModeContinuation(continuation, continuationSecurity);
641
- if (continuation.version !== 1) {
642
- throw new CodeModeProtocolError(
643
- "Unsupported code-mode continuation version."
644
- );
645
- }
646
- if (continuation.js !== js) {
647
- throw new CodeModeProtocolError(
648
- "Code mode continuation source does not match the resumed source."
649
- );
650
- }
651
- if (!Number.isInteger(continuation.determinism.dateNowMs) || !/^[0-9a-f]{32}$/i.test(continuation.determinism.randomSeed)) {
652
- throw new CodeModeProtocolError(
653
- "Code mode continuation determinism state is malformed."
654
- );
655
- }
656
- for (const entry of continuation.ledger) {
657
- if (entry.kind !== "tool" || typeof entry.name !== "string" || typeof entry.inputJson !== "string" || typeof entry.toolCallId !== "string") {
658
- throw new CodeModeProtocolError(
659
- "Code mode continuation ledger is malformed."
660
- );
661
- }
662
- }
663
- if (interruptResolution !== void 0) {
664
- const matches = continuation.ledger.filter(
665
- (entry) => entry.status === "interrupted" && entry.interruptId === interruptResolution.interruptId
666
- );
667
- if (matches.length !== 1) {
668
- throw new CodeModeProtocolError(
669
- "Interrupt resolution does not match exactly one pending continuation ledger entry.",
670
- {
671
- interruptId: interruptResolution.interruptId,
672
- matches: matches.length
673
- }
674
- );
675
- }
676
- }
677
- }
678
- function assertReplayEntryMatches(entry, message, bridgeIndex) {
679
- if (entry.name !== message.toolName || entry.inputJson !== message.inputJson) {
680
- throw new CodeModeProtocolError(
681
- "Code mode continuation replay diverged from its bridge ledger.",
682
- {
683
- bridgeIndex,
684
- expectedToolName: entry.name,
685
- receivedToolName: message.toolName
686
- }
687
- );
688
- }
689
- }
690
- function createDeterminismState() {
691
- return {
692
- dateNowMs: Date.now(),
693
- randomSeed: randomBytes(16).toString("hex")
694
- };
695
- }
696
- function cloneLedger(ledger) {
697
- return structuredClone(ledger);
698
- }
699
- function getMaxNestedToolCounter(ledger) {
700
- let max = 0;
701
- for (const entry of ledger) {
702
- const match = /:tool-(\d+)$/u.exec(entry.toolCallId);
703
- if (match !== null) {
704
- max = Math.max(max, Number(match[1]));
705
- }
706
- }
707
- return max;
708
- }
709
- function fromJsonPayload(valueJson) {
710
- return valueJson === "" ? void 0 : JSON.parse(valueJson);
711
- }
712
- function acquireWorker(maxPoolSize) {
713
- let pooledWorker = idleWorkers.pop();
714
- while (pooledWorker?.destroyed) {
715
- pooledWorker = idleWorkers.pop();
716
- }
717
- pooledWorker ??= createWorker();
718
- pooledWorker.worker.removeAllListeners("exit");
719
- pooledWorker.worker.ref();
720
- trimIdleWorkers(Math.max(0, maxPoolSize - activeInvocations));
721
- return pooledWorker;
722
- }
723
- function createWorker() {
724
- return {
725
- worker: new Worker(getInlineWorkerUrl(), { execArgv: [] }),
726
- destroyed: false
727
- };
728
- }
729
- function getInlineWorkerUrl() {
730
- inlineWorkerUrl ??= new URL(
731
- `data:text/javascript;base64,${Buffer.from(INLINE_CODE_MODE_WORKER_SOURCE).toString("base64")}`
732
- );
733
- return inlineWorkerUrl;
734
- }
735
- function releaseWorker(pooledWorker) {
736
- if (pooledWorker.destroyed) {
737
- return;
738
- }
739
- pooledWorker.worker.once("exit", () => {
740
- pooledWorker.destroyed = true;
741
- const index = idleWorkers.indexOf(pooledWorker);
742
- if (index !== -1) {
743
- idleWorkers.splice(index, 1);
744
- }
745
- });
746
- pooledWorker.worker.unref();
747
- idleWorkers.push(pooledWorker);
748
- }
749
- function destroyWorker(pooledWorker) {
750
- if (pooledWorker.destroyed) {
751
- return;
752
- }
753
- pooledWorker.destroyed = true;
754
- pooledWorker.worker.removeAllListeners();
755
- void pooledWorker.worker.terminate();
756
- }
757
- function trimIdleWorkers(maxIdleWorkers) {
758
- while (idleWorkers.length > maxIdleWorkers) {
759
- const pooledWorker = idleWorkers.pop();
760
- if (pooledWorker !== void 0) {
761
- destroyWorker(pooledWorker);
762
- }
763
- }
764
- }
765
- function releaseInvocationSlot(memoryLimitBytes) {
766
- activeInvocations = Math.max(0, activeInvocations - 1);
767
- const maxWorkers = getMaxWorkers({
768
- memoryLimitBytes,
769
- activeWorkers: activeInvocations
770
- });
771
- trimIdleWorkers(Math.max(0, maxWorkers - activeInvocations));
772
- }
773
- function settleWithResultMessage(message, resolve, reject) {
774
- if (!message.success) {
775
- reject(deserializeResultError(message));
776
- return;
777
- }
778
- resolve(
779
- message.valueJson === "" || message.valueJson === void 0 ? void 0 : JSON.parse(message.valueJson)
780
- );
781
- }
782
- function deserializeResultError(message) {
783
- if (message.error === void 0) {
784
- return new CodeModeProtocolError(
785
- `Code mode worker failed without an error for ${message.invocationId}.`,
786
- { invocationId: message.invocationId }
787
- );
788
- }
789
- return deserializeError(message.error);
790
- }
791
- export {
792
- runManagedCodeMode
793
- };
794
- //# sourceMappingURL=manager.js.map