@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 +1 @@
1
- {"version":3,"sources":["../src/tool-invocation.ts"],"sourcesContent":["import { asSchema } from 'ai';\nimport { CODE_MODE_TOOL_APPROVAL_KIND } from './approval.js';\nimport {\n CodeModeProtocolError,\n CodeModeToolApprovalDeniedError,\n CodeModeToolApprovalRequiredError,\n CodeModeToolError,\n} from './errors.js';\nimport { isCodeModeHostInterruptSignal } from './host-interrupt.js';\nimport type {\n CodeModeInterruptExecutionContext,\n CodeModeInterruptPayload,\n CodeModeOptions,\n CodeModeToolExecutionOptions,\n CodeModeToolSet,\n} from './types.js';\nimport {\n assertJsonSerializable,\n toJsonPayload,\n} from './utils/serialization.js';\n\nexport type HostToolInvocationResult =\n | { type: 'success'; valueJson: string }\n | {\n type: 'interrupted';\n toolName: string;\n input: unknown;\n toolCallId: string;\n payload: CodeModeInterruptPayload;\n };\n\nexport async function invokeHostTool({\n toolName,\n inputJson,\n tools,\n baseExecutionOptions,\n codeModeOptions,\n maxToolInputBytes,\n maxToolOutputBytes,\n toolCallId,\n codeModeInterrupt,\n skipApproval = false,\n}: {\n toolName: string;\n inputJson: string;\n tools: CodeModeToolSet;\n baseExecutionOptions: CodeModeToolExecutionOptions;\n codeModeOptions: CodeModeOptions;\n maxToolInputBytes: number;\n maxToolOutputBytes: number;\n toolCallId: string;\n codeModeInterrupt?: CodeModeInterruptExecutionContext;\n skipApproval?: boolean;\n}): Promise<HostToolInvocationResult> {\n throwIfAborted(baseExecutionOptions.abortSignal);\n\n const hostTool = tools[toolName];\n if (!hostTool) {\n throw new CodeModeToolError(`Unknown tool: ${toolName}`, {\n toolName,\n availableTools: Object.keys(tools),\n });\n }\n if (hostTool.execute == null) {\n throw new CodeModeToolError(`Tool \"${toolName}\" does not have execute().`, {\n toolName,\n });\n }\n\n const input = inputJson === '' ? undefined : JSON.parse(inputJson);\n assertJsonSerializable(input, maxToolInputBytes, `Tool \"${toolName}\" input`);\n\n const validation = await raceAgainstAbort(\n validateToolInput(hostTool.inputSchema, input),\n baseExecutionOptions.abortSignal,\n );\n if (!validation.success) {\n throw new CodeModeToolError(\n `Invalid input for tool \"${toolName}\": ${validation.error.message}`,\n { toolName, input, cause: validation.error.message },\n );\n }\n\n const executionOptions: CodeModeToolExecutionOptions = {\n ...baseExecutionOptions,\n toolCallId,\n ...(codeModeInterrupt !== undefined ? { codeModeInterrupt } : {}),\n };\n\n const needsApproval =\n !skipApproval &&\n (await raceAgainstAbort(\n requiresApproval(hostTool, validation.value, executionOptions),\n executionOptions.abortSignal,\n ));\n\n if (needsApproval) {\n if (codeModeOptions.approval?.mode === 'interrupt') {\n return {\n type: 'interrupted',\n toolName,\n input: validation.value,\n toolCallId,\n payload: { kind: CODE_MODE_TOOL_APPROVAL_KIND },\n };\n }\n\n const approval = await raceAgainstAbort(\n Promise.resolve(\n codeModeOptions.approval?.onApprovalRequired?.({\n toolName,\n input: validation.value,\n toolCallId,\n }),\n ),\n baseExecutionOptions.abortSignal,\n );\n if (approval === undefined) {\n throw new CodeModeToolApprovalRequiredError(\n toolName,\n validation.value,\n toolCallId,\n );\n }\n const approved =\n typeof approval === 'string'\n ? approval === 'approved'\n : approval?.approved;\n const reason = typeof approval === 'string' ? undefined : approval?.reason;\n if (typeof approved !== 'boolean') {\n throw new CodeModeProtocolError(\n `Tool \"${toolName}\" approval callback returned a malformed approval decision.`,\n { toolName, toolCallId },\n );\n }\n if (reason !== undefined && typeof reason !== 'string') {\n throw new CodeModeProtocolError(\n `Tool \"${toolName}\" approval callback returned a malformed approval reason.`,\n { toolName, toolCallId },\n );\n }\n if (!approved) {\n throw new CodeModeToolApprovalDeniedError(\n toolName,\n validation.value,\n toolCallId,\n reason,\n );\n }\n }\n\n let output: unknown;\n try {\n output = await raceAgainstAbort(\n executeHostTool(hostTool.execute.bind(hostTool), {\n input: validation.value,\n options: executionOptions,\n }),\n executionOptions.abortSignal,\n );\n } catch (error) {\n if (isCodeModeHostInterruptSignal(error)) {\n return {\n type: 'interrupted',\n toolName,\n input: validation.value,\n toolCallId,\n payload: error.payload,\n };\n }\n throw error;\n }\n return {\n type: 'success',\n valueJson: toJsonPayload(\n output,\n maxToolOutputBytes,\n `Tool \"${toolName}\" output`,\n ),\n };\n}\n\nasync function requiresApproval(\n hostTool: CodeModeToolSet[string],\n input: unknown,\n options: CodeModeToolExecutionOptions,\n): Promise<boolean> {\n if (hostTool.needsApproval == null) {\n return false;\n }\n if (typeof hostTool.needsApproval === 'boolean') {\n return hostTool.needsApproval;\n }\n return await hostTool.needsApproval(input as never, options as never);\n}\n\nasync function validateToolInput(\n schema: CodeModeToolSet[string]['inputSchema'],\n input: unknown,\n): Promise<\n { success: true; value: unknown } | { success: false; error: Error }\n> {\n const normalizedSchema = asSchema(schema);\n if (normalizedSchema.validate === undefined) {\n return { success: true, value: input };\n }\n return await normalizedSchema.validate(input);\n}\n\nasync function executeHostTool(\n execute: NonNullable<CodeModeToolSet[string]['execute']>,\n {\n input,\n options,\n }: {\n input: unknown;\n options: CodeModeToolExecutionOptions;\n },\n): Promise<unknown> {\n const output = execute(input as never, options as never);\n if (isAsyncIterable(output)) {\n let finalOutput: unknown;\n for await (const part of output) {\n finalOutput = part;\n }\n return finalOutput;\n }\n return await output;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n Symbol.asyncIterator in value &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[\n Symbol.asyncIterator\n ] === 'function'\n );\n}\n\nasync function raceAgainstAbort<T>(\n operation: Promise<T>,\n abortSignal: AbortSignal | undefined,\n): Promise<T> {\n if (abortSignal === undefined) {\n return await operation;\n }\n throwIfAborted(abortSignal);\n\n let rejectOnAbort!: (reason?: unknown) => void;\n const aborted = new Promise<never>((_resolve, reject) => {\n rejectOnAbort = reject;\n });\n const onAbort = () => {\n rejectOnAbort(abortReason(abortSignal));\n };\n\n abortSignal.addEventListener('abort', onAbort, { once: true });\n if (abortSignal.aborted) {\n onAbort();\n }\n\n try {\n return await Promise.race([operation, aborted]);\n } finally {\n abortSignal.removeEventListener('abort', onAbort);\n }\n}\n\nfunction throwIfAborted(abortSignal: AbortSignal | undefined): void {\n if (abortSignal?.aborted) {\n throw abortReason(abortSignal);\n }\n}\n\nfunction abortReason(abortSignal: AbortSignal): unknown {\n return (\n abortSignal.reason ??\n new DOMException('The operation was aborted.', 'AbortError')\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/tool-invocation.ts"],"sourcesContent":["import { asSchema } from 'ai';\nimport { CODE_MODE_TOOL_APPROVAL_KIND } from './approval.js';\nimport {\n CodeModeProtocolError,\n CodeModeToolApprovalDeniedError,\n CodeModeToolApprovalRequiredError,\n CodeModeToolError,\n} from './errors.js';\nimport type {\n CodeModeInterruptExecutionContext,\n CodeModeInterruptPayload,\n CodeModeOptions,\n CodeModeToolExecutionOptions,\n CodeModeToolSet,\n} from './types.js';\nimport {\n assertJsonSerializable,\n fromJsonPayload,\n toJsonPayload,\n} from './utils/serialization.js';\n\nexport type HostToolInvocationResult =\n | { type: 'success'; valueJson: string }\n | {\n type: 'interrupted';\n toolName: string;\n input: unknown;\n toolCallId: string;\n payload: CodeModeInterruptPayload;\n };\n\nexport async function invokeHostTool({\n toolName,\n inputJson,\n tools,\n baseExecutionOptions,\n codeModeOptions,\n maxToolInputBytes,\n maxToolOutputBytes,\n toolCallId,\n codeModeInterrupt,\n skipApproval = false,\n}: {\n toolName: string;\n inputJson: string;\n tools: CodeModeToolSet;\n baseExecutionOptions: CodeModeToolExecutionOptions;\n codeModeOptions: CodeModeOptions;\n maxToolInputBytes: number;\n maxToolOutputBytes: number;\n toolCallId: string;\n codeModeInterrupt?: CodeModeInterruptExecutionContext;\n skipApproval?: boolean;\n}): Promise<HostToolInvocationResult> {\n throwIfAborted(baseExecutionOptions.abortSignal);\n\n const hostTool = tools[toolName];\n if (!hostTool) {\n throw new CodeModeToolError(`Unknown tool: ${toolName}`, {\n toolName,\n availableTools: Object.keys(tools),\n });\n }\n if (hostTool.execute == null) {\n throw new CodeModeToolError(`Tool \"${toolName}\" does not have execute().`, {\n toolName,\n });\n }\n\n const input = fromJsonPayload(inputJson);\n assertJsonSerializable(input, maxToolInputBytes, `Tool \"${toolName}\" input`);\n\n const validation = await raceAgainstAbort(\n validateToolInput(hostTool.inputSchema, input),\n baseExecutionOptions.abortSignal,\n );\n if (!validation.success) {\n throw new CodeModeToolError(\n `Invalid input for tool \"${toolName}\": ${validation.error.message}`,\n { toolName, input, cause: validation.error.message },\n );\n }\n\n const executionOptions: CodeModeToolExecutionOptions = {\n ...baseExecutionOptions,\n toolCallId,\n ...(codeModeInterrupt !== undefined ? { codeModeInterrupt } : {}),\n };\n\n const needsApproval =\n !skipApproval &&\n (await raceAgainstAbort(\n requiresApproval(hostTool, validation.value, executionOptions),\n executionOptions.abortSignal,\n ));\n\n if (needsApproval) {\n if (codeModeOptions.approval?.mode === 'interrupt') {\n return {\n type: 'interrupted',\n toolName,\n input: validation.value,\n toolCallId,\n payload: { kind: CODE_MODE_TOOL_APPROVAL_KIND },\n };\n }\n\n const approval = await raceAgainstAbort(\n Promise.resolve(\n codeModeOptions.approval?.onApprovalRequired?.({\n toolName,\n input: validation.value,\n toolCallId,\n }),\n ),\n baseExecutionOptions.abortSignal,\n );\n if (approval === undefined) {\n throw new CodeModeToolApprovalRequiredError(\n toolName,\n validation.value,\n toolCallId,\n );\n }\n const approved =\n typeof approval === 'string'\n ? approval === 'approved'\n : approval?.approved;\n const reason = typeof approval === 'string' ? undefined : approval?.reason;\n if (typeof approved !== 'boolean') {\n throw new CodeModeProtocolError(\n `Tool \"${toolName}\" approval callback returned a malformed approval decision.`,\n { toolName, toolCallId },\n );\n }\n if (reason !== undefined && typeof reason !== 'string') {\n throw new CodeModeProtocolError(\n `Tool \"${toolName}\" approval callback returned a malformed approval reason.`,\n { toolName, toolCallId },\n );\n }\n if (!approved) {\n throw new CodeModeToolApprovalDeniedError(\n toolName,\n validation.value,\n toolCallId,\n reason,\n );\n }\n }\n\n const output = await raceAgainstAbort(\n executeHostTool(hostTool.execute.bind(hostTool), {\n input: validation.value,\n options: executionOptions,\n }),\n executionOptions.abortSignal,\n );\n return {\n type: 'success',\n valueJson: toJsonPayload(\n output,\n maxToolOutputBytes,\n `Tool \"${toolName}\" output`,\n ),\n };\n}\n\nasync function requiresApproval(\n hostTool: CodeModeToolSet[string],\n input: unknown,\n options: CodeModeToolExecutionOptions,\n): Promise<boolean> {\n if (hostTool.needsApproval == null) {\n return false;\n }\n if (typeof hostTool.needsApproval === 'boolean') {\n return hostTool.needsApproval;\n }\n return await hostTool.needsApproval(input as never, options as never);\n}\n\nasync function validateToolInput(\n schema: CodeModeToolSet[string]['inputSchema'],\n input: unknown,\n): Promise<\n { success: true; value: unknown } | { success: false; error: Error }\n> {\n const normalizedSchema = asSchema(schema);\n if (normalizedSchema.validate === undefined) {\n return { success: true, value: input };\n }\n return await normalizedSchema.validate(input);\n}\n\nasync function executeHostTool(\n execute: NonNullable<CodeModeToolSet[string]['execute']>,\n {\n input,\n options,\n }: {\n input: unknown;\n options: CodeModeToolExecutionOptions;\n },\n): Promise<unknown> {\n const output = execute(input as never, options as never);\n if (isAsyncIterable(output)) {\n let finalOutput: unknown;\n for await (const part of output) {\n finalOutput = part;\n }\n return finalOutput;\n }\n return await output;\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n Symbol.asyncIterator in value &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[\n Symbol.asyncIterator\n ] === 'function'\n );\n}\n\nasync function raceAgainstAbort<T>(\n operation: Promise<T>,\n abortSignal: AbortSignal | undefined,\n): Promise<T> {\n if (abortSignal === undefined) {\n return await operation;\n }\n throwIfAborted(abortSignal);\n\n let rejectOnAbort!: (reason?: unknown) => void;\n const aborted = new Promise<never>((_resolve, reject) => {\n rejectOnAbort = reject;\n });\n const onAbort = () => {\n rejectOnAbort(abortReason(abortSignal));\n };\n\n abortSignal.addEventListener('abort', onAbort, { once: true });\n if (abortSignal.aborted) {\n onAbort();\n }\n\n try {\n return await Promise.race([operation, aborted]);\n } finally {\n abortSignal.removeEventListener('abort', onAbort);\n }\n}\n\nfunction throwIfAborted(abortSignal: AbortSignal | undefined): void {\n if (abortSignal?.aborted) {\n throw abortReason(abortSignal);\n }\n}\n\nfunction abortReason(abortSignal: AbortSignal): unknown {\n return (\n abortSignal.reason ??\n new DOMException('The operation was aborted.', 'AbortError')\n );\n}\n"],"mappings":"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","names":[]}
@@ -8,6 +8,9 @@ function toJsonPayload(value, maxBytes, label) {
8
8
  }
9
9
  return toStrictJsonPayload(value, maxBytes, label);
10
10
  }
11
+ function fromJsonPayload(valueJson) {
12
+ return valueJson === "" ? void 0 : JSON.parse(valueJson);
13
+ }
11
14
  function toStrictJsonPayload(value, maxBytes, label) {
12
15
  let encoded;
13
16
  try {
@@ -43,6 +46,7 @@ function getErrorMessage(error) {
43
46
  export {
44
47
  assertJsonPayloadSize,
45
48
  assertJsonSerializable,
49
+ fromJsonPayload,
46
50
  toJsonPayload,
47
51
  toStrictJsonPayload
48
52
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/serialization.ts"],"sourcesContent":["import { CodeModeError } from '../errors.js';\n\nexport function assertJsonSerializable(\n value: unknown,\n maxBytes: number,\n label: string,\n): void {\n void toJsonPayload(value, maxBytes, label);\n}\n\nexport function toJsonPayload(\n value: unknown,\n maxBytes: number,\n label: string,\n): string {\n if (value === undefined) {\n return '';\n }\n\n return toStrictJsonPayload(value, maxBytes, label);\n}\n\nexport function toStrictJsonPayload(\n value: unknown,\n maxBytes: number,\n label: string,\n): string {\n let encoded: string | undefined;\n try {\n encoded = JSON.stringify(value);\n } catch (error) {\n throw new CodeModeError(\n `${label} is not JSON-serializable: ${getErrorMessage(error)}`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n );\n }\n\n if (encoded === undefined) {\n throw new CodeModeError(\n `${label} is not JSON-serializable.`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n );\n }\n\n assertJsonPayloadSize(encoded, maxBytes, label);\n return encoded;\n}\n\nexport function assertJsonPayloadSize(\n valueJson: string,\n maxBytes: number,\n label: string,\n): void {\n const bytes = new TextEncoder().encode(valueJson).byteLength;\n if (bytes > maxBytes) {\n throw new CodeModeError(\n `${label} exceeds the ${maxBytes} byte size limit.`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n { bytes, maxBytes },\n );\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"AAAA,SAAS,qBAAqB;AAEvB,SAAS,uBACd,OACA,UACA,OACM;AACN,OAAK,cAAc,OAAO,UAAU,KAAK;AAC3C;AAEO,SAAS,cACd,OACA,UACA,OACQ;AACR,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,SAAO,oBAAoB,OAAO,UAAU,KAAK;AACnD;AAEO,SAAS,oBACd,OACA,UACA,OACQ;AACR,MAAI;AACJ,MAAI;AACF,cAAU,KAAK,UAAU,KAAK;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,8BAA8B,gBAAgB,KAAK,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI;AAAA,MACR,GAAG,KAAK;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,wBAAsB,SAAS,UAAU,KAAK;AAC9C,SAAO;AACT;AAEO,SAAS,sBACd,WACA,UACA,OACM;AACN,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,SAAS,EAAE;AAClD,MAAI,QAAQ,UAAU;AACpB,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,gBAAgB,QAAQ;AAAA,MAChC;AAAA,MACA,EAAE,OAAO,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/serialization.ts"],"sourcesContent":["import { CodeModeError } from '../errors.js';\n\nexport function assertJsonSerializable(\n value: unknown,\n maxBytes: number,\n label: string,\n): void {\n void toJsonPayload(value, maxBytes, label);\n}\n\nexport function toJsonPayload(\n value: unknown,\n maxBytes: number,\n label: string,\n): string {\n if (value === undefined) {\n return '';\n }\n\n return toStrictJsonPayload(value, maxBytes, label);\n}\n\nexport function fromJsonPayload(valueJson: string): unknown {\n return valueJson === '' ? undefined : JSON.parse(valueJson);\n}\n\nexport function toStrictJsonPayload(\n value: unknown,\n maxBytes: number,\n label: string,\n): string {\n let encoded: string | undefined;\n try {\n encoded = JSON.stringify(value);\n } catch (error) {\n throw new CodeModeError(\n `${label} is not JSON-serializable: ${getErrorMessage(error)}`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n );\n }\n\n if (encoded === undefined) {\n throw new CodeModeError(\n `${label} is not JSON-serializable.`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n );\n }\n\n assertJsonPayloadSize(encoded, maxBytes, label);\n return encoded;\n}\n\nexport function assertJsonPayloadSize(\n valueJson: string,\n maxBytes: number,\n label: string,\n): void {\n const bytes = new TextEncoder().encode(valueJson).byteLength;\n if (bytes > maxBytes) {\n throw new CodeModeError(\n `${label} exceeds the ${maxBytes} byte size limit.`,\n 'CODE_MODE_SERIALIZATION_ERROR',\n { bytes, maxBytes },\n );\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"AAAA,SAAS,qBAAqB;AAEvB,SAAS,uBACd,OACA,UACA,OACM;AACN,OAAK,cAAc,OAAO,UAAU,KAAK;AAC3C;AAEO,SAAS,cACd,OACA,UACA,OACQ;AACR,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,SAAO,oBAAoB,OAAO,UAAU,KAAK;AACnD;AAEO,SAAS,gBAAgB,WAA4B;AAC1D,SAAO,cAAc,KAAK,SAAY,KAAK,MAAM,SAAS;AAC5D;AAEO,SAAS,oBACd,OACA,UACA,OACQ;AACR,MAAI;AACJ,MAAI;AACF,cAAU,KAAK,UAAU,KAAK;AAAA,EAChC,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,8BAA8B,gBAAgB,KAAK,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI;AAAA,MACR,GAAG,KAAK;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,wBAAsB,SAAS,UAAU,KAAK;AAC9C,SAAO;AACT;AAEO,SAAS,sBACd,WACA,UACA,OACM;AACN,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,SAAS,EAAE;AAClD,MAAI,QAAQ,UAAU;AACpB,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,gBAAgB,QAAQ;AAAA,MAChC;AAAA,MACA,EAAE,OAAO,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/code-mode",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "QuickJS-backed code mode tool for AI SDK",
5
5
  "keywords": [
6
6
  "ai",
@@ -37,20 +37,18 @@
37
37
  "README.md"
38
38
  ],
39
39
  "peerDependencies": {
40
- "ai": "7.0.63"
40
+ "ai": "7.0.65"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "22.19.19",
44
- "esbuild": "^0.28.1",
45
- "quickjs-emscripten": "^0.32.0",
46
44
  "tsup": "^8.5.1",
47
45
  "typescript": "5.8.3",
48
46
  "zod": "3.25.76",
49
47
  "@vercel/ai-tsconfig": "0.0.0",
50
- "ai": "7.0.63"
48
+ "ai": "7.0.65"
51
49
  },
52
50
  "engines": {
53
- "node": ">=22"
51
+ "node": ">=22.13.0"
54
52
  },
55
53
  "publishConfig": {
56
54
  "access": "public",
@@ -65,8 +63,11 @@
65
63
  "bugs": {
66
64
  "url": "https://github.com/vercel/ai/issues"
67
65
  },
66
+ "dependencies": {
67
+ "run": "^2.0.0"
68
+ },
68
69
  "scripts": {
69
- "build": "pnpm clean && tsup --tsconfig tsconfig.build.json && node scripts/embed-inline-worker.mjs",
70
+ "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
70
71
  "clean": "del-cli build dist *.tsbuildinfo",
71
72
  "type-check": "tsc --build && tsc -p src/tsconfig.json",
72
73
  "test": "pnpm test:node",
@@ -82,6 +82,24 @@ export function verifyCodeModeContinuation(
82
82
  continuation: CodeModeContinuation,
83
83
  security: CodeModeContinuationSecurityOptions = {},
84
84
  ): void {
85
+ if (
86
+ typeof continuation !== 'object' ||
87
+ continuation === null ||
88
+ continuation.version !== 2 ||
89
+ typeof continuation.js !== 'string' ||
90
+ typeof continuation.outerToolCallId !== 'string' ||
91
+ !Array.isArray(continuation.toolNames) ||
92
+ !continuation.toolNames.every(name => typeof name === 'string') ||
93
+ typeof continuation.token !== 'string' ||
94
+ continuation.token.length === 0 ||
95
+ !Array.isArray(continuation.pendingInterruptions) ||
96
+ continuation.pendingInterruptions.length === 0 ||
97
+ !Array.isArray(continuation.resolutions)
98
+ ) {
99
+ throw new CodeModeProtocolError(
100
+ 'Code mode continuation envelope is malformed.',
101
+ );
102
+ }
85
103
  assertAuthShape(continuation.auth);
86
104
  const now = Date.now();
87
105
  if (continuation.auth.expiresAtMs < now) {
package/src/errors.ts CHANGED
@@ -1,5 +1,3 @@
1
- import type { SerializableError } from './types.js';
2
-
3
1
  /**
4
2
  * Base class for errors raised by code mode.
5
3
  *
@@ -142,191 +140,3 @@ export class CodeModeToolApprovalDeniedError extends CodeModeToolError {
142
140
  this.code = 'CODE_MODE_TOOL_APPROVAL_DENIED';
143
141
  }
144
142
  }
145
-
146
- /**
147
- * Converts an unknown thrown value into a worker-safe serializable shape.
148
- *
149
- * @internal
150
- */
151
- export function serializeError(error: unknown): SerializableError {
152
- if (error instanceof CodeModeError) {
153
- const result = compactError({
154
- name: error.name,
155
- message: error.message,
156
- code: error.code,
157
- });
158
- if (error.stack !== undefined) {
159
- result.stack = error.stack;
160
- }
161
- if (error.details !== undefined) {
162
- result.details = error.details;
163
- }
164
- return result;
165
- }
166
-
167
- if (error instanceof Error) {
168
- const result = compactError({
169
- name: error.name,
170
- message: error.message,
171
- });
172
- if (error.stack !== undefined) {
173
- result.stack = error.stack;
174
- }
175
- const maybeCoded = error as Error & { code?: unknown; details?: unknown };
176
- if (typeof maybeCoded.code === 'string') {
177
- result.code = maybeCoded.code;
178
- }
179
- if (maybeCoded.details !== undefined) {
180
- result.details = maybeCoded.details;
181
- }
182
- return result;
183
- }
184
-
185
- return {
186
- name: 'Error',
187
- message: String(error),
188
- };
189
- }
190
-
191
- /**
192
- * Converts host bridge failures into a sandbox-visible sanitized shape.
193
- *
194
- * This intentionally omits stack traces and diagnostic details. Full host
195
- * diagnostics remain on the host side.
196
- *
197
- * @internal
198
- */
199
- export function serializeBridgeErrorForGuest(
200
- error: unknown,
201
- context: 'tool' | 'bridge',
202
- ): SerializableError {
203
- if (error instanceof CodeModeError) {
204
- return compactError({
205
- name: error.name,
206
- message: error.message,
207
- code: error.code,
208
- });
209
- }
210
-
211
- const fallback =
212
- context === 'tool'
213
- ? {
214
- message: 'Host tool failed.',
215
- code: 'CODE_MODE_HOST_TOOL_ERROR',
216
- }
217
- : {
218
- message: 'Host bridge request failed.',
219
- code: 'CODE_MODE_HOST_BRIDGE_ERROR',
220
- };
221
-
222
- return {
223
- name: 'Error',
224
- message: fallback.message,
225
- code: fallback.code,
226
- };
227
- }
228
-
229
- function compactError(error: {
230
- name: string;
231
- message: string;
232
- stack?: string;
233
- code?: string;
234
- details?: unknown;
235
- }): SerializableError {
236
- return {
237
- name: error.name,
238
- message: error.message,
239
- ...(error.stack !== undefined ? { stack: error.stack } : {}),
240
- ...(error.code !== undefined ? { code: error.code } : {}),
241
- ...(error.details !== undefined ? { details: error.details } : {}),
242
- };
243
- }
244
-
245
- /**
246
- * Rehydrates a serialized worker error into an Error instance.
247
- *
248
- * @internal
249
- */
250
- export function deserializeError(error: SerializableError): Error {
251
- if (error.code === 'CODE_MODE_SOURCE_TOO_LARGE') {
252
- const details = error.details as
253
- | { bytes?: number; maxBytes?: number }
254
- | undefined;
255
- const result = new CodeModeSourceTooLargeError(
256
- details?.bytes ?? 0,
257
- details?.maxBytes ?? 0,
258
- );
259
- restoreStack(result, error);
260
- return result;
261
- }
262
-
263
- if (error.code === 'CODE_MODE_BRIDGE_LIMIT') {
264
- const result = new CodeModeBridgeLimitError(error.message, error.details);
265
- restoreStack(result, error);
266
- return result;
267
- }
268
-
269
- if (error.code === 'CODE_MODE_DETACHED_BRIDGE_REQUEST') {
270
- const result = new CodeModeDetachedBridgeRequestError(
271
- error.message,
272
- error.details,
273
- );
274
- restoreStack(result, error);
275
- return result;
276
- }
277
-
278
- if (error.code === 'CODE_MODE_PROTOCOL_ERROR') {
279
- const result = new CodeModeProtocolError(error.message, error.details);
280
- restoreStack(result, error);
281
- return result;
282
- }
283
-
284
- if (error.code === 'CODE_MODE_TOOL_APPROVAL_REQUIRED') {
285
- const details = error.details as
286
- | { toolName?: string; input?: unknown; toolCallId?: string }
287
- | undefined;
288
- const result = new CodeModeToolApprovalRequiredError(
289
- details?.toolName ?? 'unknown',
290
- details?.input,
291
- details?.toolCallId ?? 'unknown',
292
- );
293
- result.message = error.message;
294
- restoreStack(result, error);
295
- return result;
296
- }
297
-
298
- if (error.code === 'CODE_MODE_TOOL_APPROVAL_DENIED') {
299
- const details = error.details as
300
- | {
301
- toolName?: string;
302
- input?: unknown;
303
- toolCallId?: string;
304
- reason?: string;
305
- }
306
- | undefined;
307
- const result = new CodeModeToolApprovalDeniedError(
308
- details?.toolName ?? 'unknown',
309
- details?.input,
310
- details?.toolCallId ?? 'unknown',
311
- details?.reason,
312
- );
313
- result.message = error.message;
314
- restoreStack(result, error);
315
- return result;
316
- }
317
-
318
- const result = new CodeModeError(
319
- error.message,
320
- error.code ?? 'CODE_MODE_ERROR',
321
- error.details,
322
- );
323
- result.name = error.name;
324
- restoreStack(result, error);
325
- return result;
326
- }
327
-
328
- function restoreStack(error: Error, serialized: SerializableError): void {
329
- if (serialized.stack) {
330
- error.stack = serialized.stack;
331
- }
332
- }
@@ -1,14 +1,6 @@
1
+ import { getHostFunctionContext } from 'run';
1
2
  import type { CodeModeInterruptPayload } from './types.js';
2
3
 
3
- const CODE_MODE_HOST_INTERRUPT_SIGNAL = Symbol.for(
4
- '@ai-sdk/code-mode.host-interrupt',
5
- );
6
-
7
- interface CodeModeHostInterruptSignal extends Error {
8
- readonly [CODE_MODE_HOST_INTERRUPT_SIGNAL]: true;
9
- readonly payload: CodeModeInterruptPayload;
10
- }
11
-
12
4
  export function requestCodeModeInterrupt<
13
5
  TPayload extends CodeModeInterruptPayload,
14
6
  >(payload: TPayload): never {
@@ -24,26 +16,5 @@ export function requestCodeModeInterrupt<
24
16
  'Code mode interrupt payload must include a string kind.',
25
17
  );
26
18
  }
27
-
28
- const error = new Error('Code mode host interruption requested.');
29
- error.name = 'CodeModeHostInterruptSignal';
30
- Object.defineProperties(error, {
31
- [CODE_MODE_HOST_INTERRUPT_SIGNAL]: { value: true },
32
- payload: { value: payload },
33
- });
34
- throw error;
35
- }
36
-
37
- export function isCodeModeHostInterruptSignal(
38
- value: unknown,
39
- ): value is CodeModeHostInterruptSignal {
40
- return (
41
- typeof value === 'object' &&
42
- value !== null &&
43
- (value as { [CODE_MODE_HOST_INTERRUPT_SIGNAL]?: unknown })[
44
- CODE_MODE_HOST_INTERRUPT_SIGNAL
45
- ] === true &&
46
- typeof (value as { payload?: unknown }).payload === 'object' &&
47
- (value as { payload?: unknown }).payload !== null
48
- );
19
+ return getHostFunctionContext().interrupt(payload);
49
20
  }
package/src/index.ts CHANGED
@@ -31,7 +31,7 @@ export {
31
31
  } from './interrupt-continuation.js';
32
32
  export { runCodeMode as experimental_runCodeMode } from './run-code-mode.js';
33
33
  export { setCodeModeContinuationSigningKey as experimental_setCodeModeContinuationSigningKey } from './continuation-capability.js';
34
- export { setMaxWorkers as experimental_setMaxWorkers } from './runtime/max-workers.js';
34
+ export { setMaxWorkers as experimental_setMaxWorkers } from 'run';
35
35
  export type {
36
36
  ApprovalDecision,
37
37
  CodeModeApprovalInterrupt,
@@ -143,19 +143,21 @@ function assertInterruptMatchesLedger(interrupt: CodeModeInterrupt): void {
143
143
  'Code-mode interrupt outer tool call id does not match its continuation.',
144
144
  );
145
145
  }
146
- const matches = interrupt.continuation.ledger.filter(
147
- entry =>
148
- entry.status === 'interrupted' &&
149
- entry.interruptId === interrupt.interruptId &&
150
- entry.toolCallId === interrupt.toolCallId &&
151
- entry.name === interrupt.toolName &&
152
- jsonEqual(fromJsonPayload(entry.inputJson), interrupt.input) &&
153
- jsonEqual(entry.interruptPayload, interrupt.payload),
154
- );
155
- if (matches.length !== 1) {
146
+ const pending =
147
+ interrupt.continuation.pendingInterruptions[
148
+ interrupt.continuation.resolutions.length
149
+ ];
150
+ if (
151
+ pending === undefined ||
152
+ pending.interruptId !== interrupt.interruptId ||
153
+ pending.toolCallId !== interrupt.toolCallId ||
154
+ pending.toolName !== interrupt.toolName ||
155
+ !jsonEqual(pending.input, interrupt.input) ||
156
+ !jsonEqual(pending.payload, interrupt.payload)
157
+ ) {
156
158
  throw new CodeModeProtocolError(
157
159
  'Code-mode interrupt metadata does not match the signed continuation ledger.',
158
- { interruptId: interrupt.interruptId, matches: matches.length },
160
+ { interruptId: interrupt.interruptId },
159
161
  );
160
162
  }
161
163
  }
@@ -164,10 +166,6 @@ function jsonEqual(left: unknown, right: unknown): boolean {
164
166
  return JSON.stringify(left) === JSON.stringify(right);
165
167
  }
166
168
 
167
- function fromJsonPayload(valueJson: string): unknown {
168
- return valueJson === '' ? undefined : JSON.parse(valueJson);
169
- }
170
-
171
169
  function isRecord(value: unknown): value is Record<string, unknown> {
172
170
  return typeof value === 'object' && value !== null && !Array.isArray(value);
173
171
  }