@execbox/quickjs 0.2.0 → 0.3.0
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/README.md +21 -5
- package/dist/index.cjs +610 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +19 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +607 -4
- package/dist/index.js.map +1 -1
- package/dist/processEntry.cjs +17 -0
- package/dist/processEntry.cjs.map +1 -0
- package/dist/processEntry.d.cts +5 -0
- package/dist/processEntry.d.ts +5 -0
- package/dist/processEntry.js +18 -0
- package/dist/processEntry.js.map +1 -0
- package/dist/protocolEndpoint-A1JBvHG_.cjs +147 -0
- package/dist/protocolEndpoint-A1JBvHG_.cjs.map +1 -0
- package/dist/protocolEndpoint-CDGgtfFu.js +142 -0
- package/dist/protocolEndpoint-CDGgtfFu.js.map +1 -0
- package/dist/runner/index.cjs +1 -1
- package/dist/runner/index.d.cts +16 -78
- package/dist/runner/index.d.cts.map +1 -1
- package/dist/runner/index.d.ts +16 -78
- package/dist/runner/index.d.ts.map +1 -1
- package/dist/runner/index.js +1 -1
- package/dist/runner/protocolEndpoint.cjs +3 -137
- package/dist/runner/protocolEndpoint.d.cts +4 -0
- package/dist/runner/protocolEndpoint.d.cts.map +1 -1
- package/dist/runner/protocolEndpoint.d.ts +4 -0
- package/dist/runner/protocolEndpoint.d.ts.map +1 -1
- package/dist/runner/protocolEndpoint.js +3 -137
- package/dist/{runner-B4UG88h1.js → runner-CteKTaPD.js} +93 -10
- package/dist/runner-CteKTaPD.js.map +1 -0
- package/dist/{runner-DhOZH9xz.cjs → runner-DRt0kpEk.cjs} +140 -9
- package/dist/{runner-B4UG88h1.js.map → runner-DRt0kpEk.cjs.map} +1 -1
- package/dist/types-BeVqrcj8.d.ts +71 -0
- package/dist/types-BeVqrcj8.d.ts.map +1 -0
- package/dist/types-CnNmLawC.d.cts +71 -0
- package/dist/types-CnNmLawC.d.cts.map +1 -0
- package/dist/workerEntry.cjs +19 -0
- package/dist/workerEntry.cjs.map +1 -0
- package/dist/workerEntry.d.cts +5 -0
- package/dist/workerEntry.d.ts +5 -0
- package/dist/workerEntry.js +20 -0
- package/dist/workerEntry.js.map +1 -0
- package/package.json +16 -7
- package/dist/runner/protocolEndpoint.cjs.map +0 -1
- package/dist/runner/protocolEndpoint.js.map +0 -1
- package/dist/runner-DhOZH9xz.cjs.map +0 -1
- package/dist/types-BB8mb_-T.d.cts +0 -14
- package/dist/types-BB8mb_-T.d.cts.map +0 -1
- package/dist/types-D7uau0GM.d.ts +0 -14
- package/dist/types-D7uau0GM.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/quickjsExecutor.ts"],"sourcesContent":["import {\n createTimeoutExecuteResult,\n createToolCallDispatcher,\n extractProviderManifests,\n type ExecutionOptions,\n type ExecuteResult,\n type Executor,\n type ResolvedToolProvider,\n} from \"@execbox/core\";\n\nimport { runQuickJsSession } from \"./runner/index\";\nimport type { QuickJsExecutorOptions } from \"./types\";\n\n/**\n * QuickJS-backed executor for ephemeral sandboxed JavaScript runs.\n */\nexport class QuickJsExecutor implements Executor {\n private readonly options: QuickJsExecutorOptions;\n\n /**\n * Creates a QuickJS executor with ephemeral runtime limits and host bridging configuration.\n */\n constructor(options: QuickJsExecutorOptions = {}) {\n this.options = options;\n }\n\n /**\n * Executes JavaScript against the provided tool namespaces in a fresh QuickJS runtime.\n */\n async execute(\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n ): Promise<ExecuteResult> {\n if (options.signal?.aborted) {\n return createTimeoutExecuteResult();\n }\n\n const abortController = new AbortController();\n const onToolCall = createToolCallDispatcher(\n providers,\n abortController.signal,\n );\n const onAbort = () => {\n abortController.abort();\n };\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n try {\n return await runQuickJsSession(\n {\n abortController,\n code,\n onToolCall,\n providers: extractProviderManifests(providers),\n },\n {\n ...this.options,\n ...options,\n },\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n abortController.abort();\n }\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAa,kBAAb,MAAiD;CAC/C,AAAiB;;;;CAKjB,YAAY,UAAkC,EAAE,EAAE;AAChD,OAAK,UAAU;;;;;CAMjB,MAAM,QACJ,MACA,WACA,UAA4B,EAAE,EACN;AACxB,MAAI,QAAQ,QAAQ,QAClB,QAAO,4BAA4B;EAGrC,MAAM,kBAAkB,IAAI,iBAAiB;EAC7C,MAAM,aAAa,yBACjB,WACA,gBAAgB,OACjB;EACD,MAAM,gBAAgB;AACpB,mBAAgB,OAAO;;AAGzB,UAAQ,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AAElE,MAAI;AACF,UAAO,MAAM,kBACX;IACE;IACA;IACA;IACA,WAAW,yBAAyB,UAAU;IAC/C,EACD;IACE,GAAG,KAAK;IACR,GAAG;IACJ,CACF;YACO;AACR,WAAQ,QAAQ,oBAAoB,SAAS,QAAQ;AACrD,mBAAgB,OAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["DEFAULT_POOL_OPTIONS: Required<ExecutorPoolOptions>","closeReason: TransportCloseReason | undefined","resolvePoolOptions","leases: Array<{\n release: (reusable: boolean) => Promise<void>;\n value: ProcessShell;\n }>","child: ChildProcess","closeReason: TransportCloseReason | undefined","leases: Array<{\n release: (reusable: boolean) => Promise<void>;\n value: WorkerShell;\n }>"],"sources":["../../core/src/runner.ts","../src/hosted/shared.ts","../src/hosted/processHostedExecutor.ts","../src/hosted/workerHostedExecutor.ts","../src/quickjsExecutor.ts"],"sourcesContent":["import {\n createExecutionContext,\n getExecutionTimeoutMessage,\n normalizeThrownMessage,\n} from \"./executor/shared.ts\";\nimport {\n ExecuteFailure,\n isExecuteFailure,\n isJsonSerializable,\n} from \"./errors.ts\";\nimport type { ExecuteError, ResolvedToolProvider } from \"./types.ts\";\n\n/**\n * Transport-safe metadata for one exposed tool.\n */\nexport interface ProviderToolManifest {\n description?: string;\n originalName: string;\n safeName: string;\n}\n\n/**\n * Namespace manifest shared with runner implementations.\n */\nexport interface ProviderManifest {\n name: string;\n tools: Record<string, ProviderToolManifest>;\n types: string;\n}\n\n/**\n * Execution limits forwarded to runner implementations.\n */\nexport interface ExecutorRuntimeOptions {\n maxLogChars?: number;\n maxLogLines?: number;\n memoryLimitBytes?: number;\n timeoutMs?: number;\n}\n\n/**\n * Public execution options accepted by executors per call.\n */\nexport interface ExecutionOptions extends ExecutorRuntimeOptions {\n signal?: AbortSignal;\n}\n\n/**\n * Tool invocation request emitted from a runner.\n */\nexport interface ToolCall {\n input: unknown;\n providerName: string;\n safeToolName: string;\n}\n\n/**\n * Trusted host response to a tool invocation request.\n */\nexport type ToolCallResult =\n | {\n ok: true;\n result: unknown;\n }\n | {\n error: ExecuteError;\n ok: false;\n };\n\nfunction toTrustedExecuteError(error: unknown): ExecuteError {\n if (isExecuteFailure(error)) {\n return {\n code: error.code,\n message: error.message,\n };\n }\n\n return {\n code: \"tool_error\",\n message: normalizeThrownMessage(error),\n };\n}\n\n/**\n * Converts resolved providers into manifest metadata that reveals only namespace details.\n */\nexport function extractProviderManifests(\n providers: ResolvedToolProvider[],\n): ProviderManifest[] {\n return providers.map((provider) => ({\n name: provider.name,\n tools: Object.fromEntries(\n Object.entries(provider.tools).map(([safeToolName, descriptor]) => [\n safeToolName,\n {\n description: descriptor.description,\n originalName: descriptor.originalName,\n safeName: descriptor.safeName,\n },\n ]),\n ),\n types: provider.types,\n }));\n}\n\n/**\n * Creates a host-side dispatcher for runner-emitted tool calls.\n */\nexport function createToolCallDispatcher(\n providers: ResolvedToolProvider[],\n signal: AbortSignal,\n): (call: ToolCall) => Promise<ToolCallResult> {\n const providerMap = new Map(\n providers.map((provider) => [provider.name, provider] as const),\n );\n\n return async (call) => {\n const provider = providerMap.get(call.providerName);\n const descriptor = provider?.tools[call.safeToolName];\n\n if (!provider || !descriptor) {\n return {\n error: {\n code: \"internal_error\",\n message: `Unknown tool ${call.providerName}.${call.safeToolName}`,\n },\n ok: false,\n };\n }\n\n try {\n if (signal.aborted) {\n return {\n error: {\n code: \"timeout\",\n message: getExecutionTimeoutMessage(),\n },\n ok: false,\n };\n }\n\n const result = await descriptor.execute(\n call.input,\n createExecutionContext(\n signal,\n provider.name,\n descriptor.safeName,\n descriptor.originalName,\n ),\n );\n\n if (result !== undefined && !isJsonSerializable(result)) {\n throw new ExecuteFailure(\n \"serialization_error\",\n \"Host value is not JSON-serializable\",\n );\n }\n\n return {\n ok: true,\n result,\n };\n } catch (error) {\n return {\n error: toTrustedExecuteError(error),\n ok: false,\n };\n }\n };\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport { runHostTransportSession, type HostTransport } from \"@execbox/protocol\";\nimport type { ExecutorPoolOptions } from \"@execbox/core\";\nimport {\n resolveExecutorRuntimeOptions,\n type ExecutionOptions,\n type ExecuteResult,\n type ExecutorRuntimeOptions,\n type ResolvedToolProvider,\n} from \"../../../core/src/runtime.ts\";\n\n/**\n * Default grace period before a hosted shell is forcefully terminated.\n */\nconst DEFAULT_CANCEL_GRACE_MS = 25;\n\n/**\n * Default pooling limits shared by the hosted QuickJS executors.\n */\nconst DEFAULT_POOL_OPTIONS: Required<ExecutorPoolOptions> = {\n idleTimeoutMs: 30_000,\n maxSize: 1,\n minSize: 0,\n prewarm: false,\n};\n\n/**\n * Minimal code used to warm a hosted shell without touching user providers.\n */\nconst DEFAULT_PREWARM_CODE = \"undefined\";\n\nexport { DEFAULT_CANCEL_GRACE_MS, DEFAULT_POOL_OPTIONS, DEFAULT_PREWARM_CODE };\n\n/**\n * Wraps a transport so warmup and pooled execution can borrow it without\n * taking ownership of its lifecycle.\n */\nexport function createBorrowedTransport(\n transport: HostTransport,\n): HostTransport {\n return {\n dispose() {},\n onClose: transport.onClose,\n onError: transport.onError,\n onMessage: transport.onMessage,\n send: transport.send,\n terminate: transport.terminate,\n };\n}\n\n/**\n * Resolves how many pooled shells should be prewarmed from the pool settings.\n */\nexport function getPrewarmCount(pool: ExecutorPoolOptions | undefined): number {\n if (!pool?.prewarm) {\n return 0;\n }\n\n if (typeof pool.prewarm === \"number\") {\n return Math.max(0, Math.min(pool.prewarm, pool.maxSize));\n }\n\n return Math.max(1, Math.min(pool.minSize ?? 1, pool.maxSize));\n}\n\n/**\n * Caps an explicit warmup request to the configured pool boundaries.\n */\nexport function getWarmupTarget(\n count: number | undefined,\n poolOptions: ExecutorPoolOptions,\n): number {\n return Math.max(\n 0,\n Math.min(count ?? poolOptions.minSize ?? 0, poolOptions.maxSize),\n );\n}\n\n/**\n * Returns whether a hosted execution result is safe to return to a pool.\n */\nexport function isReusableResult(result: ExecuteResult): boolean {\n return (\n result.ok || ![\"internal_error\", \"timeout\"].includes(result.error.code)\n );\n}\n\n/**\n * Normalizes a failed warmup result into an actionable host-side error.\n */\nexport function toWarmupError(label: string, result: ExecuteResult): Error {\n if (result.ok) {\n return new Error(`Failed to prewarm pooled ${label}`);\n }\n\n return new Error(\n `Failed to prewarm pooled ${label}: ${result.error.message}`,\n );\n}\n\n/**\n * Runs one transport-backed execution session with resolved runtime limits and\n * a fresh execution identifier.\n */\nexport async function runHostedTransportSession(options: {\n cancelGraceMs: number;\n code: string;\n executorOptions: ExecutorRuntimeOptions;\n onSettled?: (result: ExecuteResult) => Promise<void> | void;\n providers: ResolvedToolProvider[];\n requestOptions?: ExecutionOptions;\n transport: HostTransport;\n}): Promise<ExecuteResult> {\n return await runHostTransportSession({\n cancelGraceMs: options.cancelGraceMs,\n code: options.code,\n executionId: randomUUID(),\n onSettled: options.onSettled,\n providers: options.providers,\n runtimeOptions: resolveExecutorRuntimeOptions(\n options.executorOptions,\n options.requestOptions,\n ),\n signal: options.requestOptions?.signal,\n transport: options.transport,\n });\n}\n\n/**\n * Exercises a set of leased shells with a warmup run and releases each lease\n * according to the warmup result.\n */\nexport async function warmHostedPool<Shell>(options: {\n count: number;\n getTransport: (shell: Shell) => HostTransport;\n label: string;\n onRelease: (shell: Shell, reusable: boolean) => Promise<void>;\n runSession: (\n transport: HostTransport,\n code: string,\n providers: ResolvedToolProvider[],\n ) => Promise<ExecuteResult>;\n shells: Shell[];\n}): Promise<void> {\n const results = await Promise.allSettled(\n options.shells.map(async (shell) => {\n let reusable = false;\n\n try {\n const result = await options.runSession(\n createBorrowedTransport(options.getTransport(shell)),\n DEFAULT_PREWARM_CODE,\n [],\n );\n reusable = result.ok;\n if (!result.ok) {\n throw toWarmupError(options.label, result);\n }\n } finally {\n await options.onRelease(shell, reusable);\n }\n }),\n );\n\n const rejected = results.find((result) => result.status === \"rejected\");\n if (rejected?.status === \"rejected\") {\n throw rejected.reason;\n }\n}\n","import { fork, type ChildProcess } from \"node:child_process\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n createResourcePool,\n getNodeTransportExecArgv,\n type HostTransport,\n type ResourcePool,\n type RunnerMessage,\n type TransportCloseReason,\n} from \"@execbox/protocol\";\nimport {\n createTimeoutExecuteResult,\n type ExecutionOptions,\n type Executor,\n type ExecuteResult,\n type ResolvedToolProvider,\n} from \"../../../core/src/runtime.ts\";\nimport type { ExecutorPoolOptions } from \"@execbox/core\";\n\nimport type { QuickJsProcessExecutorOptions } from \"../types.ts\";\nimport {\n DEFAULT_CANCEL_GRACE_MS,\n DEFAULT_POOL_OPTIONS,\n createBorrowedTransport,\n getPrewarmCount,\n getWarmupTarget,\n isReusableResult,\n runHostedTransportSession,\n warmHostedPool,\n} from \"./shared.ts\";\n\ninterface ProcessShell {\n child: ChildProcess;\n transport: HostTransport;\n}\n\nfunction resolveProcessEntryPath(): string {\n const extension = import.meta.url.endsWith(\".ts\") ? \".ts\" : \".js\";\n return fileURLToPath(new URL(`../processEntry${extension}`, import.meta.url));\n}\n\nfunction createUnexpectedExitMessage(\n code: number | null,\n signal: NodeJS.Signals | null,\n): string {\n if (code !== null) {\n return `Child process exited unexpectedly with code ${code}`;\n }\n\n if (signal) {\n return `Child process exited unexpectedly with signal ${signal}`;\n }\n\n return \"Child process exited unexpectedly\";\n}\n\nfunction createChildProcess(): ChildProcess {\n return fork(resolveProcessEntryPath(), [], {\n execArgv: getNodeTransportExecArgv(import.meta.url),\n stdio: [\"ignore\", \"ignore\", \"ignore\", \"ipc\"],\n });\n}\n\nfunction createProcessTransport(child: ChildProcess): HostTransport {\n let terminated = false;\n let closeReason: TransportCloseReason | undefined;\n const closeHandlers = new Set<(reason?: TransportCloseReason) => void>();\n const errorHandlers = new Set<(error: Error) => void>();\n const messageHandlers = new Set<(message: RunnerMessage) => void>();\n\n const terminateChild = () => {\n if (terminated) {\n return;\n }\n\n terminated = true;\n child.kill(\"SIGKILL\");\n };\n\n const notifyClose = (reason: TransportCloseReason) => {\n if (closeReason) {\n return;\n }\n\n closeReason = reason;\n for (const handler of closeHandlers) {\n handler(reason);\n }\n };\n\n const onDisconnect = () => {\n notifyClose({\n message: \"Child process disconnected unexpectedly\",\n });\n };\n const onExit = (code: number | null, signal: NodeJS.Signals | null) => {\n notifyClose({\n code,\n message: createUnexpectedExitMessage(code, signal),\n signal,\n });\n };\n const onError = (error: Error) => {\n for (const handler of errorHandlers) {\n handler(error);\n }\n };\n const onMessage = (message: unknown) => {\n for (const handler of messageHandlers) {\n handler(message as RunnerMessage);\n }\n };\n\n child.on(\"disconnect\", onDisconnect);\n child.on(\"exit\", onExit);\n child.on(\"error\", onError);\n child.on(\"message\", onMessage);\n\n return {\n dispose: () => {\n child.off(\"disconnect\", onDisconnect);\n child.off(\"exit\", onExit);\n child.off(\"error\", onError);\n child.off(\"message\", onMessage);\n terminateChild();\n },\n onClose: (handler) => {\n closeHandlers.add(handler);\n if (closeReason) {\n queueMicrotask(() => {\n if (closeHandlers.has(handler)) {\n handler(closeReason);\n }\n });\n }\n return () => {\n closeHandlers.delete(handler);\n };\n },\n onError: (handler) => {\n errorHandlers.add(handler);\n return () => errorHandlers.delete(handler);\n },\n onMessage: (handler) => {\n messageHandlers.add(handler);\n return () => messageHandlers.delete(handler);\n },\n send: (message) =>\n new Promise<void>((resolve, reject) => {\n if (!child.connected || typeof child.send !== \"function\") {\n reject(new Error(\"Child process disconnected unexpectedly\"));\n return;\n }\n\n child.send(message, (error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n }),\n terminate: () => {\n terminateChild();\n },\n };\n}\n\nfunction createProcessShell(): ProcessShell {\n const child = createChildProcess();\n return {\n child,\n transport: createProcessTransport(child),\n };\n}\n\nfunction resolvePoolOptions(\n options: QuickJsProcessExecutorOptions,\n): ExecutorPoolOptions | undefined {\n if (options.mode === \"ephemeral\") {\n return undefined;\n }\n\n return {\n ...DEFAULT_POOL_OPTIONS,\n ...options.pool,\n };\n}\n\n/**\n * Child-process executor that runs guest code inside a dedicated QuickJS runtime per call.\n */\nexport class ProcessHostedQuickJsExecutor implements Executor {\n private readonly cancelGraceMs: number;\n private readonly options: QuickJsProcessExecutorOptions;\n private readonly pool: ResourcePool<ProcessShell> | undefined;\n private readonly poolOptions: ExecutorPoolOptions | undefined;\n private readonly warmup: Promise<void> | undefined;\n\n /**\n * Creates a hosted QuickJS executor that launches child-process shells on demand.\n */\n constructor(options: QuickJsProcessExecutorOptions) {\n this.cancelGraceMs = options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS;\n this.options = options;\n const poolOptions = resolvePoolOptions(options);\n this.poolOptions = poolOptions;\n\n if (poolOptions) {\n this.pool = createResourcePool({\n create: async () => createProcessShell(),\n destroy: async (shell) => {\n await shell.transport.dispose();\n },\n idleTimeoutMs: poolOptions.idleTimeoutMs,\n maxSize: poolOptions.maxSize,\n minSize: poolOptions.minSize,\n });\n const prewarmCount = getPrewarmCount(poolOptions);\n if (prewarmCount > 0) {\n this.warmup = this.warmPool(prewarmCount);\n }\n }\n }\n\n /**\n * Disposes any pooled child-process shells owned by this executor.\n */\n async dispose(): Promise<void> {\n await this.pool?.dispose();\n }\n\n /**\n * Prewarms pooled child-process shells up to the requested count.\n */\n async prewarm(count?: number): Promise<void> {\n if (!this.pool || !this.poolOptions) {\n return;\n }\n\n const target = getWarmupTarget(count, this.poolOptions);\n if (target <= 0) {\n return;\n }\n\n await this.warmPool(target);\n }\n\n private async runTransportSession(\n transport: HostTransport,\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n onSettled?: (result: ExecuteResult) => Promise<void> | void,\n ): Promise<ExecuteResult> {\n return await runHostedTransportSession({\n cancelGraceMs: this.cancelGraceMs,\n code,\n executorOptions: this.options,\n onSettled,\n providers,\n requestOptions: options,\n transport,\n });\n }\n\n private async warmPool(count: number): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.prewarm(count);\n\n const leases: Array<{\n release: (reusable: boolean) => Promise<void>;\n value: ProcessShell;\n }> = [];\n try {\n for (let index = 0; index < count; index += 1) {\n leases.push(await this.pool.acquire());\n }\n } catch (error) {\n await Promise.allSettled(\n leases.map(async (lease) => await lease.release(false)),\n );\n throw error;\n }\n\n await warmHostedPool({\n count,\n getTransport: (lease) => lease.value.transport,\n label: \"child process\",\n onRelease: async (lease, reusable) => await lease.release(reusable),\n runSession: async (transport, code, providers) =>\n await this.runTransportSession(transport, code, providers),\n shells: leases,\n });\n }\n\n /**\n * Executes guest code in a child-process-hosted QuickJS shell.\n */\n async execute(\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n ): Promise<ExecuteResult> {\n if (options.signal?.aborted) {\n return createTimeoutExecuteResult();\n }\n\n await this.warmup;\n if (this.pool) {\n const lease = await this.pool.acquire();\n\n return await this.runTransportSession(\n createBorrowedTransport(lease.value.transport),\n code,\n providers,\n options,\n async (result) => {\n await lease.release(isReusableResult(result));\n },\n );\n }\n\n let child: ChildProcess;\n\n try {\n child = createChildProcess();\n } catch (error) {\n return {\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n logs: [],\n ok: false,\n };\n }\n\n return await this.runTransportSession(\n createProcessTransport(child),\n code,\n providers,\n options,\n );\n }\n}\n","import { availableParallelism } from \"node:os\";\nimport { Worker } from \"node:worker_threads\";\n\nimport {\n createResourcePool,\n getNodeTransportExecArgv,\n type HostTransport,\n type ResourcePool,\n type RunnerMessage,\n type TransportCloseReason,\n} from \"@execbox/protocol\";\nimport {\n createTimeoutExecuteResult,\n type ExecutionOptions,\n type Executor,\n type ExecuteResult,\n type ResolvedToolProvider,\n} from \"../../../core/src/runtime.ts\";\nimport type { ExecutorPoolOptions } from \"@execbox/core\";\n\nimport type { QuickJsWorkerExecutorOptions } from \"../types.ts\";\nimport {\n DEFAULT_CANCEL_GRACE_MS,\n DEFAULT_POOL_OPTIONS,\n createBorrowedTransport,\n getPrewarmCount,\n getWarmupTarget,\n isReusableResult,\n runHostedTransportSession,\n warmHostedPool,\n} from \"./shared.ts\";\n\nconst DEFAULT_POOLED_WORKER_MAX_SIZE = 4;\n\ninterface WorkerShell {\n transport: HostTransport;\n worker: Worker;\n}\n\nfunction resolveWorkerEntryUrl(): URL {\n const extension = import.meta.url.endsWith(\".ts\") ? \".ts\" : \".js\";\n return new URL(`../workerEntry${extension}`, import.meta.url);\n}\n\nfunction createWorkerTransport(worker: Worker): HostTransport {\n let terminated = false;\n let closeReason: TransportCloseReason | undefined;\n const closeHandlers = new Set<(reason?: TransportCloseReason) => void>();\n const errorHandlers = new Set<(error: Error) => void>();\n const messageHandlers = new Set<(message: RunnerMessage) => void>();\n\n const terminateWorker = async () => {\n if (terminated) {\n return;\n }\n\n terminated = true;\n await worker.terminate().catch(() => {});\n };\n\n const notifyClose = (reason: TransportCloseReason) => {\n if (closeReason) {\n return;\n }\n\n closeReason = reason;\n for (const handler of closeHandlers) {\n handler(reason);\n }\n };\n\n const onExit = (code: number) => {\n notifyClose({\n code,\n message: `Worker exited unexpectedly with code ${code}`,\n });\n };\n const onError = (error: Error) => {\n for (const handler of errorHandlers) {\n handler(error);\n }\n };\n const onMessage = (message: unknown) => {\n for (const handler of messageHandlers) {\n handler(message as RunnerMessage);\n }\n };\n\n worker.on(\"exit\", onExit);\n worker.on(\"error\", onError);\n worker.on(\"message\", onMessage);\n\n return {\n dispose: async () => {\n worker.off(\"exit\", onExit);\n worker.off(\"error\", onError);\n worker.off(\"message\", onMessage);\n await terminateWorker();\n },\n onClose: (handler) => {\n closeHandlers.add(handler);\n if (closeReason) {\n queueMicrotask(() => {\n if (closeHandlers.has(handler)) {\n handler(closeReason);\n }\n });\n }\n return () => closeHandlers.delete(handler);\n },\n onError: (handler) => {\n errorHandlers.add(handler);\n return () => errorHandlers.delete(handler);\n },\n onMessage: (handler) => {\n messageHandlers.add(handler);\n return () => messageHandlers.delete(handler);\n },\n send: (message) => {\n worker.postMessage(message);\n },\n terminate: async () => {\n await terminateWorker();\n },\n };\n}\n\nfunction createWorkerShell(options: QuickJsWorkerExecutorOptions): WorkerShell {\n const worker = new Worker(resolveWorkerEntryUrl(), {\n execArgv: getNodeTransportExecArgv(import.meta.url),\n resourceLimits: options.workerResourceLimits,\n });\n\n return {\n transport: createWorkerTransport(worker),\n worker,\n };\n}\n\nfunction getDefaultPoolMaxSize(): number {\n try {\n return Math.max(\n 1,\n Math.min(availableParallelism(), DEFAULT_POOLED_WORKER_MAX_SIZE),\n );\n } catch {\n return 1;\n }\n}\n\nfunction resolvePoolOptions(\n options: QuickJsWorkerExecutorOptions,\n): ExecutorPoolOptions | undefined {\n if (options.mode === \"ephemeral\") {\n return undefined;\n }\n\n return {\n ...DEFAULT_POOL_OPTIONS,\n maxSize: getDefaultPoolMaxSize(),\n ...options.pool,\n };\n}\n\n/**\n * Worker-thread executor that runs guest code inside a dedicated QuickJS runtime per call.\n */\nexport class WorkerHostedQuickJsExecutor implements Executor {\n private readonly cancelGraceMs: number;\n private readonly options: QuickJsWorkerExecutorOptions;\n private readonly pool: ResourcePool<WorkerShell> | undefined;\n private readonly poolOptions: ExecutorPoolOptions | undefined;\n private readonly warmup: Promise<void> | undefined;\n\n /**\n * Creates a hosted QuickJS executor that launches worker-thread shells on demand.\n */\n constructor(options: QuickJsWorkerExecutorOptions) {\n this.cancelGraceMs = options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS;\n this.options = options;\n const poolOptions = resolvePoolOptions(options);\n this.poolOptions = poolOptions;\n\n if (poolOptions) {\n this.pool = createResourcePool({\n create: async () => createWorkerShell(options),\n destroy: async (shell) => {\n await shell.transport.dispose();\n },\n idleTimeoutMs: poolOptions.idleTimeoutMs,\n maxSize: poolOptions.maxSize,\n minSize: poolOptions.minSize,\n });\n const prewarmCount = getPrewarmCount(poolOptions);\n if (prewarmCount > 0) {\n this.warmup = this.warmPool(prewarmCount);\n }\n }\n }\n\n /**\n * Disposes any pooled worker-thread shells owned by this executor.\n */\n async dispose(): Promise<void> {\n await this.pool?.dispose();\n }\n\n /**\n * Prewarms pooled worker-thread shells up to the requested count.\n */\n async prewarm(count?: number): Promise<void> {\n if (!this.pool || !this.poolOptions) {\n return;\n }\n\n const target = getWarmupTarget(count, this.poolOptions);\n if (target <= 0) {\n return;\n }\n\n await this.warmPool(target);\n }\n\n private async runTransportSession(\n transport: HostTransport,\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n onSettled?: (result: ExecuteResult) => Promise<void> | void,\n ): Promise<ExecuteResult> {\n return await runHostedTransportSession({\n cancelGraceMs: this.cancelGraceMs,\n code,\n executorOptions: this.options,\n onSettled,\n providers,\n requestOptions: options,\n transport,\n });\n }\n\n private async warmPool(count: number): Promise<void> {\n if (!this.pool) {\n return;\n }\n\n await this.pool.prewarm(count);\n\n const leases: Array<{\n release: (reusable: boolean) => Promise<void>;\n value: WorkerShell;\n }> = [];\n try {\n for (let index = 0; index < count; index += 1) {\n leases.push(await this.pool.acquire());\n }\n } catch (error) {\n await Promise.allSettled(\n leases.map(async (lease) => await lease.release(false)),\n );\n throw error;\n }\n\n await warmHostedPool({\n count,\n getTransport: (lease) => lease.value.transport,\n label: \"worker shell\",\n onRelease: async (lease, reusable) => await lease.release(reusable),\n runSession: async (transport, code, providers) =>\n await this.runTransportSession(transport, code, providers),\n shells: leases,\n });\n }\n\n /**\n * Executes guest code in a worker-thread-hosted QuickJS shell.\n */\n async execute(\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n ): Promise<ExecuteResult> {\n if (options.signal?.aborted) {\n return createTimeoutExecuteResult();\n }\n\n await this.warmup;\n if (this.pool) {\n const lease = await this.pool.acquire();\n\n return await this.runTransportSession(\n createBorrowedTransport(lease.value.transport),\n code,\n providers,\n options,\n async (result) => {\n await lease.release(isReusableResult(result));\n },\n );\n }\n\n const worker = new Worker(resolveWorkerEntryUrl(), {\n execArgv: getNodeTransportExecArgv(import.meta.url),\n resourceLimits: this.options.workerResourceLimits,\n });\n\n return await this.runTransportSession(\n createWorkerTransport(worker),\n code,\n providers,\n options,\n );\n }\n}\n","import {\n createTimeoutExecuteResult,\n createToolCallDispatcher,\n extractProviderManifests,\n} from \"../../core/src/runtime.ts\";\nimport type {\n ExecutionOptions,\n ExecuteResult,\n Executor,\n ResolvedToolProvider,\n} from \"@execbox/core\";\n\nimport { ProcessHostedQuickJsExecutor } from \"./hosted/processHostedExecutor.ts\";\nimport { WorkerHostedQuickJsExecutor } from \"./hosted/workerHostedExecutor.ts\";\nimport { runQuickJsSession } from \"./runner/index.ts\";\nimport type {\n QuickJsExecutorOptions,\n QuickJsInlineExecutorOptions,\n QuickJsProcessExecutorOptions,\n QuickJsWorkerExecutorOptions,\n} from \"./types\";\n\nfunction isWorkerOptions(\n options: QuickJsExecutorOptions,\n): options is QuickJsWorkerExecutorOptions {\n return options.host === \"worker\";\n}\n\nfunction isProcessOptions(\n options: QuickJsExecutorOptions,\n): options is QuickJsProcessExecutorOptions {\n return options.host === \"process\";\n}\n\n/**\n * QuickJS-backed executor for inline, worker-backed, or process-backed JavaScript runs.\n */\nexport class QuickJsExecutor implements Executor {\n private readonly hostedExecutor: Executor | undefined;\n private readonly options: QuickJsInlineExecutorOptions | undefined;\n\n /**\n * Creates a QuickJS executor with inline QuickJS by default, or a hosted\n * worker/process shell when `host` is explicitly set.\n */\n constructor(options: QuickJsExecutorOptions = {}) {\n if (isWorkerOptions(options)) {\n this.hostedExecutor = new WorkerHostedQuickJsExecutor(options);\n return;\n }\n\n if (isProcessOptions(options)) {\n this.hostedExecutor = new ProcessHostedQuickJsExecutor(options);\n return;\n }\n\n this.options = options;\n }\n\n /**\n * Disposes any pooled hosted shells owned by this executor.\n */\n async dispose(): Promise<void> {\n await this.hostedExecutor?.dispose?.();\n }\n\n /**\n * Prewarms pooled hosted shells when the executor is running in worker or\n * process mode. Inline mode treats this as a no-op.\n */\n async prewarm(count?: number): Promise<void> {\n await this.hostedExecutor?.prewarm?.(count);\n }\n\n /**\n * Executes JavaScript against the provided tool namespaces in a fresh QuickJS runtime.\n */\n async execute(\n code: string,\n providers: ResolvedToolProvider[],\n options: ExecutionOptions = {},\n ): Promise<ExecuteResult> {\n if (this.hostedExecutor) {\n return await this.hostedExecutor.execute(code, providers, options);\n }\n\n if (options.signal?.aborted) {\n return createTimeoutExecuteResult();\n }\n\n const abortController = new AbortController();\n const onToolCall = createToolCallDispatcher(\n providers,\n abortController.signal,\n );\n const onAbort = () => {\n abortController.abort();\n };\n\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n try {\n return await runQuickJsSession(\n {\n abortController,\n code,\n onToolCall,\n providers: extractProviderManifests(providers),\n },\n {\n ...this.options,\n ...options,\n },\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n abortController.abort();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require('./runner-DRt0kpEk.cjs');
|
|
2
|
+
const require_protocolEndpoint = require('./protocolEndpoint-A1JBvHG_.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/processEntry.ts
|
|
5
|
+
if (typeof process.send !== "function") throw new Error("QuickJsExecutor process host requires a child process IPC channel");
|
|
6
|
+
require_protocolEndpoint.attachQuickJsProtocolEndpoint({
|
|
7
|
+
onMessage(handler) {
|
|
8
|
+
process.on("message", handler);
|
|
9
|
+
return () => process.off("message", handler);
|
|
10
|
+
},
|
|
11
|
+
send(message) {
|
|
12
|
+
process.send?.(message);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
//# sourceMappingURL=processEntry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processEntry.cjs","names":["attachQuickJsProtocolEndpoint"],"sources":["../src/processEntry.ts"],"sourcesContent":["import type { DispatcherMessage, RunnerMessage } from \"@execbox/protocol\";\n\nimport { attachQuickJsProtocolEndpoint } from \"./runner/protocolEndpoint.ts\";\n\nif (typeof process.send !== \"function\") {\n throw new Error(\n \"QuickJsExecutor process host requires a child process IPC channel\",\n );\n}\n\nattachQuickJsProtocolEndpoint({\n onMessage(handler: (message: DispatcherMessage) => void): () => void {\n process.on(\"message\", handler);\n return () => process.off(\"message\", handler);\n },\n send(message: RunnerMessage): void {\n process.send?.(message);\n },\n});\n"],"mappings":";;;;AAIA,IAAI,OAAO,QAAQ,SAAS,WAC1B,OAAM,IAAI,MACR,oEACD;AAGHA,uDAA8B;CAC5B,UAAU,SAA2D;AACnE,UAAQ,GAAG,WAAW,QAAQ;AAC9B,eAAa,QAAQ,IAAI,WAAW,QAAQ;;CAE9C,KAAK,SAA8B;AACjC,UAAQ,OAAO,QAAQ;;CAE1B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./runner-CteKTaPD.js";
|
|
2
|
+
import { t as attachQuickJsProtocolEndpoint } from "./protocolEndpoint-CDGgtfFu.js";
|
|
3
|
+
|
|
4
|
+
//#region src/processEntry.ts
|
|
5
|
+
if (typeof process.send !== "function") throw new Error("QuickJsExecutor process host requires a child process IPC channel");
|
|
6
|
+
attachQuickJsProtocolEndpoint({
|
|
7
|
+
onMessage(handler) {
|
|
8
|
+
process.on("message", handler);
|
|
9
|
+
return () => process.off("message", handler);
|
|
10
|
+
},
|
|
11
|
+
send(message) {
|
|
12
|
+
process.send?.(message);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { };
|
|
18
|
+
//# sourceMappingURL=processEntry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processEntry.js","names":[],"sources":["../src/processEntry.ts"],"sourcesContent":["import type { DispatcherMessage, RunnerMessage } from \"@execbox/protocol\";\n\nimport { attachQuickJsProtocolEndpoint } from \"./runner/protocolEndpoint.ts\";\n\nif (typeof process.send !== \"function\") {\n throw new Error(\n \"QuickJsExecutor process host requires a child process IPC channel\",\n );\n}\n\nattachQuickJsProtocolEndpoint({\n onMessage(handler: (message: DispatcherMessage) => void): () => void {\n process.on(\"message\", handler);\n return () => process.off(\"message\", handler);\n },\n send(message: RunnerMessage): void {\n process.send?.(message);\n },\n});\n"],"mappings":";;;;AAIA,IAAI,OAAO,QAAQ,SAAS,WAC1B,OAAM,IAAI,MACR,oEACD;AAGH,8BAA8B;CAC5B,UAAU,SAA2D;AACnE,UAAQ,GAAG,WAAW,QAAQ;AAC9B,eAAa,QAAQ,IAAI,WAAW,QAAQ;;CAE9C,KAAK,SAA8B;AACjC,UAAQ,OAAO,QAAQ;;CAE1B,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const require_runner = require('./runner-DRt0kpEk.cjs');
|
|
2
|
+
let node_crypto = require("node:crypto");
|
|
3
|
+
|
|
4
|
+
//#region ../protocol/src/messages.ts
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function isFiniteNumber(value) {
|
|
9
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
10
|
+
}
|
|
11
|
+
function isRuntimeOptions(value) {
|
|
12
|
+
if (!isRecord(value)) return false;
|
|
13
|
+
return isFiniteNumber(value.maxLogChars) && isFiniteNumber(value.maxLogLines) && isFiniteNumber(value.memoryLimitBytes) && isFiniteNumber(value.timeoutMs);
|
|
14
|
+
}
|
|
15
|
+
function isProviderManifest(value) {
|
|
16
|
+
if (!isRecord(value) || typeof value.name !== "string") return false;
|
|
17
|
+
if (!isRecord(value.tools) || typeof value.types !== "string") return false;
|
|
18
|
+
return Object.values(value.tools).every((tool) => isRecord(tool) && typeof tool.originalName === "string" && typeof tool.safeName === "string" && (tool.description === void 0 || typeof tool.description === "string"));
|
|
19
|
+
}
|
|
20
|
+
function isExecuteError(value) {
|
|
21
|
+
return isRecord(value) && typeof value.code === "string" && typeof value.message === "string";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns whether an unknown value is a dispatcher-to-runner message.
|
|
25
|
+
*/
|
|
26
|
+
function isDispatcherMessage(value) {
|
|
27
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
28
|
+
switch (value.type) {
|
|
29
|
+
case "cancel": return typeof value.id === "string";
|
|
30
|
+
case "execute": return typeof value.code === "string" && typeof value.id === "string" && isRuntimeOptions(value.options) && Array.isArray(value.providers) && value.providers.every(isProviderManifest);
|
|
31
|
+
case "tool_result":
|
|
32
|
+
if (typeof value.callId !== "string" || typeof value.ok !== "boolean") return false;
|
|
33
|
+
if (value.ok) return "result" in value;
|
|
34
|
+
return isExecuteError(value.error);
|
|
35
|
+
default: return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/runner/protocolEndpoint.ts
|
|
41
|
+
/**
|
|
42
|
+
* @packageDocumentation
|
|
43
|
+
* Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Attaches the shared QuickJS protocol loop to a worker/process messaging port.
|
|
47
|
+
*/
|
|
48
|
+
function attachQuickJsProtocolEndpoint(port) {
|
|
49
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
50
|
+
let activeAbortController;
|
|
51
|
+
let activeExecutionId;
|
|
52
|
+
async function startExecution(message) {
|
|
53
|
+
if (activeExecutionId) {
|
|
54
|
+
port.send({
|
|
55
|
+
durationMs: 0,
|
|
56
|
+
error: {
|
|
57
|
+
code: "internal_error",
|
|
58
|
+
message: "QuickJS endpoint already has an active execution"
|
|
59
|
+
},
|
|
60
|
+
id: message.id,
|
|
61
|
+
logs: [],
|
|
62
|
+
ok: false,
|
|
63
|
+
type: "done"
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const abortController = new AbortController();
|
|
68
|
+
activeAbortController = abortController;
|
|
69
|
+
activeExecutionId = message.id;
|
|
70
|
+
try {
|
|
71
|
+
const result = await require_runner.runQuickJsSession({
|
|
72
|
+
abortController,
|
|
73
|
+
code: message.code,
|
|
74
|
+
onStarted: () => {
|
|
75
|
+
port.send({
|
|
76
|
+
id: message.id,
|
|
77
|
+
type: "started"
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
onToolCall: (call) => new Promise((resolve) => {
|
|
81
|
+
const callId = (0, node_crypto.randomUUID)();
|
|
82
|
+
pendingToolCalls.set(callId, resolve);
|
|
83
|
+
port.send({
|
|
84
|
+
...call,
|
|
85
|
+
callId,
|
|
86
|
+
type: "tool_call"
|
|
87
|
+
});
|
|
88
|
+
}),
|
|
89
|
+
providers: message.providers
|
|
90
|
+
}, message.options);
|
|
91
|
+
port.send({
|
|
92
|
+
...result,
|
|
93
|
+
id: message.id,
|
|
94
|
+
type: "done"
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
port.send({
|
|
98
|
+
durationMs: 0,
|
|
99
|
+
error: {
|
|
100
|
+
code: "internal_error",
|
|
101
|
+
message: error instanceof Error ? error.message : String(error)
|
|
102
|
+
},
|
|
103
|
+
id: message.id,
|
|
104
|
+
logs: [],
|
|
105
|
+
ok: false,
|
|
106
|
+
type: "done"
|
|
107
|
+
});
|
|
108
|
+
} finally {
|
|
109
|
+
pendingToolCalls.clear();
|
|
110
|
+
activeAbortController = void 0;
|
|
111
|
+
activeExecutionId = void 0;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const maybeDetach = port.onMessage((message) => {
|
|
115
|
+
if (!isDispatcherMessage(message)) return;
|
|
116
|
+
switch (message.type) {
|
|
117
|
+
case "cancel":
|
|
118
|
+
if (message.id === activeExecutionId) activeAbortController?.abort();
|
|
119
|
+
break;
|
|
120
|
+
case "execute":
|
|
121
|
+
startExecution(message);
|
|
122
|
+
break;
|
|
123
|
+
case "tool_result": {
|
|
124
|
+
const resolve = pendingToolCalls.get(message.callId);
|
|
125
|
+
pendingToolCalls.delete(message.callId);
|
|
126
|
+
resolve?.(message);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return () => {
|
|
132
|
+
if (typeof maybeDetach === "function") maybeDetach();
|
|
133
|
+
pendingToolCalls.clear();
|
|
134
|
+
activeAbortController?.abort();
|
|
135
|
+
activeAbortController = void 0;
|
|
136
|
+
activeExecutionId = void 0;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
Object.defineProperty(exports, 'attachQuickJsProtocolEndpoint', {
|
|
142
|
+
enumerable: true,
|
|
143
|
+
get: function () {
|
|
144
|
+
return attachQuickJsProtocolEndpoint;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=protocolEndpoint-A1JBvHG_.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocolEndpoint-A1JBvHG_.cjs","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined","runQuickJsSession"],"sources":["../../protocol/src/messages.ts","../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","/**\n * @packageDocumentation\n * Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n} from \"@execbox/protocol\";\nimport type { ToolCallResult } from \"@execbox/core\";\n// This entrypoint is executed directly from source in worker/process tests before\n// workspace packages are built, so its runtime validator must stay source-local.\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-side port used by the shared QuickJS protocol endpoint.\n */\nexport interface QuickJsProtocolPort {\n onMessage(handler: (message: DispatcherMessage) => void): void | (() => void);\n send(message: RunnerMessage): void;\n}\n\n/**\n * Attaches the shared QuickJS protocol loop to a worker/process messaging port.\n */\nexport function attachQuickJsProtocolEndpoint(\n port: QuickJsProtocolPort,\n): () => void {\n const pendingToolCalls = new Map<string, (result: ToolCallResult) => void>();\n let activeAbortController: AbortController | undefined;\n let activeExecutionId: string | undefined;\n\n async function startExecution(message: ExecuteMessage): Promise<void> {\n if (activeExecutionId) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: \"QuickJS endpoint already has an active execution\",\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n return;\n }\n\n const abortController = new AbortController();\n activeAbortController = abortController;\n activeExecutionId = message.id;\n\n try {\n const result = await runQuickJsSession(\n {\n abortController,\n code: message.code,\n onStarted: () => {\n port.send({\n id: message.id,\n type: \"started\",\n });\n },\n onToolCall: (call) =>\n new Promise<ToolCallResult>((resolve) => {\n const callId = randomUUID();\n pendingToolCalls.set(callId, resolve);\n port.send({\n ...call,\n callId,\n type: \"tool_call\",\n });\n }),\n providers: message.providers,\n },\n message.options,\n );\n\n port.send({\n ...result,\n id: message.id,\n type: \"done\",\n });\n } catch (error) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n } finally {\n pendingToolCalls.clear();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n }\n }\n\n const maybeDetach = port.onMessage((message: DispatcherMessage) => {\n if (!isDispatcherMessage(message)) {\n return;\n }\n\n switch (message.type) {\n case \"cancel\":\n if (message.id === activeExecutionId) {\n activeAbortController?.abort();\n }\n break;\n case \"execute\":\n void startExecution(message);\n break;\n case \"tool_result\": {\n const resolve = pendingToolCalls.get(message.callId);\n pendingToolCalls.delete(message.callId);\n resolve?.(message);\n break;\n }\n }\n });\n\n return () => {\n if (typeof maybeDetach === \"function\") {\n maybeDetach();\n }\n pendingToolCalls.clear();\n activeAbortController?.abort();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { t as runQuickJsSession } from "./runner-CteKTaPD.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
//#region ../protocol/src/messages.ts
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function isFiniteNumber(value) {
|
|
9
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
10
|
+
}
|
|
11
|
+
function isRuntimeOptions(value) {
|
|
12
|
+
if (!isRecord(value)) return false;
|
|
13
|
+
return isFiniteNumber(value.maxLogChars) && isFiniteNumber(value.maxLogLines) && isFiniteNumber(value.memoryLimitBytes) && isFiniteNumber(value.timeoutMs);
|
|
14
|
+
}
|
|
15
|
+
function isProviderManifest(value) {
|
|
16
|
+
if (!isRecord(value) || typeof value.name !== "string") return false;
|
|
17
|
+
if (!isRecord(value.tools) || typeof value.types !== "string") return false;
|
|
18
|
+
return Object.values(value.tools).every((tool) => isRecord(tool) && typeof tool.originalName === "string" && typeof tool.safeName === "string" && (tool.description === void 0 || typeof tool.description === "string"));
|
|
19
|
+
}
|
|
20
|
+
function isExecuteError(value) {
|
|
21
|
+
return isRecord(value) && typeof value.code === "string" && typeof value.message === "string";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns whether an unknown value is a dispatcher-to-runner message.
|
|
25
|
+
*/
|
|
26
|
+
function isDispatcherMessage(value) {
|
|
27
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
28
|
+
switch (value.type) {
|
|
29
|
+
case "cancel": return typeof value.id === "string";
|
|
30
|
+
case "execute": return typeof value.code === "string" && typeof value.id === "string" && isRuntimeOptions(value.options) && Array.isArray(value.providers) && value.providers.every(isProviderManifest);
|
|
31
|
+
case "tool_result":
|
|
32
|
+
if (typeof value.callId !== "string" || typeof value.ok !== "boolean") return false;
|
|
33
|
+
if (value.ok) return "result" in value;
|
|
34
|
+
return isExecuteError(value.error);
|
|
35
|
+
default: return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/runner/protocolEndpoint.ts
|
|
41
|
+
/**
|
|
42
|
+
* @packageDocumentation
|
|
43
|
+
* Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Attaches the shared QuickJS protocol loop to a worker/process messaging port.
|
|
47
|
+
*/
|
|
48
|
+
function attachQuickJsProtocolEndpoint(port) {
|
|
49
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
50
|
+
let activeAbortController;
|
|
51
|
+
let activeExecutionId;
|
|
52
|
+
async function startExecution(message) {
|
|
53
|
+
if (activeExecutionId) {
|
|
54
|
+
port.send({
|
|
55
|
+
durationMs: 0,
|
|
56
|
+
error: {
|
|
57
|
+
code: "internal_error",
|
|
58
|
+
message: "QuickJS endpoint already has an active execution"
|
|
59
|
+
},
|
|
60
|
+
id: message.id,
|
|
61
|
+
logs: [],
|
|
62
|
+
ok: false,
|
|
63
|
+
type: "done"
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const abortController = new AbortController();
|
|
68
|
+
activeAbortController = abortController;
|
|
69
|
+
activeExecutionId = message.id;
|
|
70
|
+
try {
|
|
71
|
+
const result = await runQuickJsSession({
|
|
72
|
+
abortController,
|
|
73
|
+
code: message.code,
|
|
74
|
+
onStarted: () => {
|
|
75
|
+
port.send({
|
|
76
|
+
id: message.id,
|
|
77
|
+
type: "started"
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
onToolCall: (call) => new Promise((resolve) => {
|
|
81
|
+
const callId = randomUUID();
|
|
82
|
+
pendingToolCalls.set(callId, resolve);
|
|
83
|
+
port.send({
|
|
84
|
+
...call,
|
|
85
|
+
callId,
|
|
86
|
+
type: "tool_call"
|
|
87
|
+
});
|
|
88
|
+
}),
|
|
89
|
+
providers: message.providers
|
|
90
|
+
}, message.options);
|
|
91
|
+
port.send({
|
|
92
|
+
...result,
|
|
93
|
+
id: message.id,
|
|
94
|
+
type: "done"
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
port.send({
|
|
98
|
+
durationMs: 0,
|
|
99
|
+
error: {
|
|
100
|
+
code: "internal_error",
|
|
101
|
+
message: error instanceof Error ? error.message : String(error)
|
|
102
|
+
},
|
|
103
|
+
id: message.id,
|
|
104
|
+
logs: [],
|
|
105
|
+
ok: false,
|
|
106
|
+
type: "done"
|
|
107
|
+
});
|
|
108
|
+
} finally {
|
|
109
|
+
pendingToolCalls.clear();
|
|
110
|
+
activeAbortController = void 0;
|
|
111
|
+
activeExecutionId = void 0;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const maybeDetach = port.onMessage((message) => {
|
|
115
|
+
if (!isDispatcherMessage(message)) return;
|
|
116
|
+
switch (message.type) {
|
|
117
|
+
case "cancel":
|
|
118
|
+
if (message.id === activeExecutionId) activeAbortController?.abort();
|
|
119
|
+
break;
|
|
120
|
+
case "execute":
|
|
121
|
+
startExecution(message);
|
|
122
|
+
break;
|
|
123
|
+
case "tool_result": {
|
|
124
|
+
const resolve = pendingToolCalls.get(message.callId);
|
|
125
|
+
pendingToolCalls.delete(message.callId);
|
|
126
|
+
resolve?.(message);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return () => {
|
|
132
|
+
if (typeof maybeDetach === "function") maybeDetach();
|
|
133
|
+
pendingToolCalls.clear();
|
|
134
|
+
activeAbortController?.abort();
|
|
135
|
+
activeAbortController = void 0;
|
|
136
|
+
activeExecutionId = void 0;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { attachQuickJsProtocolEndpoint as t };
|
|
142
|
+
//# sourceMappingURL=protocolEndpoint-CDGgtfFu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocolEndpoint-CDGgtfFu.js","names":["activeAbortController: AbortController | undefined","activeExecutionId: string | undefined"],"sources":["../../protocol/src/messages.ts","../src/runner/protocolEndpoint.ts"],"sourcesContent":["import type {\n ExecuteResult,\n ExecutorRuntimeOptions,\n ProviderManifest,\n ToolCall,\n ToolCallResult,\n} from \"@execbox/core\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRuntimeOptions(value: unknown): value is ExecutorRuntimeOptions {\n if (!isRecord(value)) {\n return false;\n }\n\n return (\n isFiniteNumber(value.maxLogChars) &&\n isFiniteNumber(value.maxLogLines) &&\n isFiniteNumber(value.memoryLimitBytes) &&\n isFiniteNumber(value.timeoutMs)\n );\n}\n\nfunction isProviderManifest(value: unknown): value is ProviderManifest {\n if (!isRecord(value) || typeof value.name !== \"string\") {\n return false;\n }\n\n if (!isRecord(value.tools) || typeof value.types !== \"string\") {\n return false;\n }\n\n return Object.values(value.tools).every(\n (tool) =>\n isRecord(tool) &&\n typeof tool.originalName === \"string\" &&\n typeof tool.safeName === \"string\" &&\n (tool.description === undefined || typeof tool.description === \"string\"),\n );\n}\n\nfunction isExecuteError(\n value: unknown,\n): value is { code: string; message: string } {\n return (\n isRecord(value) &&\n typeof value.code === \"string\" &&\n typeof value.message === \"string\"\n );\n}\n\nfunction isDonePayload(value: unknown): value is DoneMessage {\n if (!isRecord(value) || !isFiniteNumber(value.durationMs)) {\n return false;\n }\n\n if (\n !Array.isArray(value.logs) ||\n !value.logs.every((log) => typeof log === \"string\")\n ) {\n return false;\n }\n\n if (typeof value.ok !== \"boolean\") {\n return false;\n }\n\n return value.ok ? true : isExecuteError(value.error);\n}\n\n/**\n * Message sent from dispatcher to runner to start one execution session.\n */\nexport interface ExecuteMessage {\n code: string;\n id: string;\n options: ExecutorRuntimeOptions;\n providers: ProviderManifest[];\n type: \"execute\";\n}\n\n/**\n * Message sent from dispatcher to request prompt cancellation.\n */\nexport interface CancelMessage {\n id: string;\n type: \"cancel\";\n}\n\n/**\n * Message sent from a runner when guest code invokes a host tool.\n */\nexport interface ToolCallMessage extends ToolCall {\n callId: string;\n type: \"tool_call\";\n}\n\n/**\n * Message carrying a trusted host tool result back to the runner.\n */\nexport type ToolResultMessage = {\n callId: string;\n type: \"tool_result\";\n} & ToolCallResult;\n\n/**\n * Message indicating the runner has finished bootstrapping guest execution timing.\n */\nexport interface StartedMessage {\n id: string;\n type: \"started\";\n}\n\n/**\n * Final successful execution result returned by a runner.\n *\n * Node IPC can omit `undefined` fields during serialization, so `result`\n * remains optional at the protocol boundary and is normalized by the host.\n */\nexport type DoneSuccessMessage<T = unknown> = {\n durationMs: number;\n id: string;\n logs: string[];\n ok: true;\n result?: T;\n type: \"done\";\n};\n\n/**\n * Final failed execution result returned by a runner.\n */\nexport type DoneFailureMessage = {\n id: string;\n type: \"done\";\n} & Extract<ExecuteResult, { ok: false }>;\n\n/**\n * Final execution result returned by a runner.\n */\nexport type DoneMessage = DoneSuccessMessage | DoneFailureMessage;\n\n/**\n * Messages accepted by a runner transport endpoint.\n */\nexport type DispatcherMessage =\n | CancelMessage\n | ExecuteMessage\n | ToolResultMessage;\n\n/**\n * Messages emitted by a runner transport endpoint.\n */\nexport type RunnerMessage = DoneMessage | StartedMessage | ToolCallMessage;\n\n/**\n * Returns whether an unknown value is a dispatcher-to-runner message.\n */\nexport function isDispatcherMessage(\n value: unknown,\n): value is DispatcherMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"cancel\":\n return typeof value.id === \"string\";\n case \"execute\":\n return (\n typeof value.code === \"string\" &&\n typeof value.id === \"string\" &&\n isRuntimeOptions(value.options) &&\n Array.isArray(value.providers) &&\n value.providers.every(isProviderManifest)\n );\n case \"tool_result\":\n if (typeof value.callId !== \"string\" || typeof value.ok !== \"boolean\") {\n return false;\n }\n\n if (value.ok) {\n return \"result\" in value;\n }\n\n return isExecuteError(value.error);\n default:\n return false;\n }\n}\n\n/**\n * Returns whether an unknown value is a runner-to-dispatcher message.\n */\nexport function isRunnerMessage(value: unknown): value is RunnerMessage {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n switch (value.type) {\n case \"started\":\n return typeof value.id === \"string\";\n case \"tool_call\":\n return (\n typeof value.callId === \"string\" &&\n typeof value.providerName === \"string\" &&\n typeof value.safeToolName === \"string\" &&\n \"input\" in value\n );\n case \"done\":\n return typeof value.id === \"string\" && isDonePayload(value);\n default:\n return false;\n }\n}\n","/**\n * @packageDocumentation\n * Public API for the `@execbox/quickjs/runner/protocol-endpoint` entrypoint.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n DispatcherMessage,\n ExecuteMessage,\n RunnerMessage,\n} from \"@execbox/protocol\";\nimport type { ToolCallResult } from \"@execbox/core\";\n// This entrypoint is executed directly from source in worker/process tests before\n// workspace packages are built, so its runtime validator must stay source-local.\nimport { isDispatcherMessage } from \"../../../protocol/src/messages.ts\";\n\nimport { runQuickJsSession } from \"./index.ts\";\n\n/**\n * Minimal worker/process-side port used by the shared QuickJS protocol endpoint.\n */\nexport interface QuickJsProtocolPort {\n onMessage(handler: (message: DispatcherMessage) => void): void | (() => void);\n send(message: RunnerMessage): void;\n}\n\n/**\n * Attaches the shared QuickJS protocol loop to a worker/process messaging port.\n */\nexport function attachQuickJsProtocolEndpoint(\n port: QuickJsProtocolPort,\n): () => void {\n const pendingToolCalls = new Map<string, (result: ToolCallResult) => void>();\n let activeAbortController: AbortController | undefined;\n let activeExecutionId: string | undefined;\n\n async function startExecution(message: ExecuteMessage): Promise<void> {\n if (activeExecutionId) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: \"QuickJS endpoint already has an active execution\",\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n return;\n }\n\n const abortController = new AbortController();\n activeAbortController = abortController;\n activeExecutionId = message.id;\n\n try {\n const result = await runQuickJsSession(\n {\n abortController,\n code: message.code,\n onStarted: () => {\n port.send({\n id: message.id,\n type: \"started\",\n });\n },\n onToolCall: (call) =>\n new Promise<ToolCallResult>((resolve) => {\n const callId = randomUUID();\n pendingToolCalls.set(callId, resolve);\n port.send({\n ...call,\n callId,\n type: \"tool_call\",\n });\n }),\n providers: message.providers,\n },\n message.options,\n );\n\n port.send({\n ...result,\n id: message.id,\n type: \"done\",\n });\n } catch (error) {\n port.send({\n durationMs: 0,\n error: {\n code: \"internal_error\",\n message: error instanceof Error ? error.message : String(error),\n },\n id: message.id,\n logs: [],\n ok: false,\n type: \"done\",\n });\n } finally {\n pendingToolCalls.clear();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n }\n }\n\n const maybeDetach = port.onMessage((message: DispatcherMessage) => {\n if (!isDispatcherMessage(message)) {\n return;\n }\n\n switch (message.type) {\n case \"cancel\":\n if (message.id === activeExecutionId) {\n activeAbortController?.abort();\n }\n break;\n case \"execute\":\n void startExecution(message);\n break;\n case \"tool_result\": {\n const resolve = pendingToolCalls.get(message.callId);\n pendingToolCalls.delete(message.callId);\n resolve?.(message);\n break;\n }\n }\n });\n\n return () => {\n if (typeof maybeDetach === \"function\") {\n maybeDetach();\n }\n pendingToolCalls.clear();\n activeAbortController?.abort();\n activeAbortController = undefined;\n activeExecutionId = undefined;\n };\n}\n"],"mappings":";;;;AAQA,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,eAAe,OAAiC;AACvD,QAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM;;AAG5D,SAAS,iBAAiB,OAAiD;AACzE,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,QACE,eAAe,MAAM,YAAY,IACjC,eAAe,MAAM,YAAY,IACjC,eAAe,MAAM,iBAAiB,IACtC,eAAe,MAAM,UAAU;;AAInC,SAAS,mBAAmB,OAA2C;AACrE,KAAI,CAAC,SAAS,MAAM,IAAI,OAAO,MAAM,SAAS,SAC5C,QAAO;AAGT,KAAI,CAAC,SAAS,MAAM,MAAM,IAAI,OAAO,MAAM,UAAU,SACnD,QAAO;AAGT,QAAO,OAAO,OAAO,MAAM,MAAM,CAAC,OAC/B,SACC,SAAS,KAAK,IACd,OAAO,KAAK,iBAAiB,YAC7B,OAAO,KAAK,aAAa,aACxB,KAAK,gBAAgB,UAAa,OAAO,KAAK,gBAAgB,UAClE;;AAGH,SAAS,eACP,OAC4C;AAC5C,QACE,SAAS,MAAM,IACf,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,YAAY;;;;;AA8G7B,SAAgB,oBACd,OAC4B;AAC5B,KAAI,CAAC,SAAS,MAAM,IAAI,OAAO,MAAM,SAAS,SAC5C,QAAO;AAGT,SAAQ,MAAM,MAAd;EACE,KAAK,SACH,QAAO,OAAO,MAAM,OAAO;EAC7B,KAAK,UACH,QACE,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,OAAO,YACpB,iBAAiB,MAAM,QAAQ,IAC/B,MAAM,QAAQ,MAAM,UAAU,IAC9B,MAAM,UAAU,MAAM,mBAAmB;EAE7C,KAAK;AACH,OAAI,OAAO,MAAM,WAAW,YAAY,OAAO,MAAM,OAAO,UAC1D,QAAO;AAGT,OAAI,MAAM,GACR,QAAO,YAAY;AAGrB,UAAO,eAAe,MAAM,MAAM;EACpC,QACE,QAAO;;;;;;;;;;;;;ACnKb,SAAgB,8BACd,MACY;CACZ,MAAM,mCAAmB,IAAI,KAA+C;CAC5E,IAAIA;CACJ,IAAIC;CAEJ,eAAe,eAAe,SAAwC;AACpE,MAAI,mBAAmB;AACrB,QAAK,KAAK;IACR,YAAY;IACZ,OAAO;KACL,MAAM;KACN,SAAS;KACV;IACD,IAAI,QAAQ;IACZ,MAAM,EAAE;IACR,IAAI;IACJ,MAAM;IACP,CAAC;AACF;;EAGF,MAAM,kBAAkB,IAAI,iBAAiB;AAC7C,0BAAwB;AACxB,sBAAoB,QAAQ;AAE5B,MAAI;GACF,MAAM,SAAS,MAAM,kBACnB;IACE;IACA,MAAM,QAAQ;IACd,iBAAiB;AACf,UAAK,KAAK;MACR,IAAI,QAAQ;MACZ,MAAM;MACP,CAAC;;IAEJ,aAAa,SACX,IAAI,SAAyB,YAAY;KACvC,MAAM,SAAS,YAAY;AAC3B,sBAAiB,IAAI,QAAQ,QAAQ;AACrC,UAAK,KAAK;MACR,GAAG;MACH;MACA,MAAM;MACP,CAAC;MACF;IACJ,WAAW,QAAQ;IACpB,EACD,QAAQ,QACT;AAED,QAAK,KAAK;IACR,GAAG;IACH,IAAI,QAAQ;IACZ,MAAM;IACP,CAAC;WACK,OAAO;AACd,QAAK,KAAK;IACR,YAAY;IACZ,OAAO;KACL,MAAM;KACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;KAChE;IACD,IAAI,QAAQ;IACZ,MAAM,EAAE;IACR,IAAI;IACJ,MAAM;IACP,CAAC;YACM;AACR,oBAAiB,OAAO;AACxB,2BAAwB;AACxB,uBAAoB;;;CAIxB,MAAM,cAAc,KAAK,WAAW,YAA+B;AACjE,MAAI,CAAC,oBAAoB,QAAQ,CAC/B;AAGF,UAAQ,QAAQ,MAAhB;GACE,KAAK;AACH,QAAI,QAAQ,OAAO,kBACjB,wBAAuB,OAAO;AAEhC;GACF,KAAK;AACH,IAAK,eAAe,QAAQ;AAC5B;GACF,KAAK,eAAe;IAClB,MAAM,UAAU,iBAAiB,IAAI,QAAQ,OAAO;AACpD,qBAAiB,OAAO,QAAQ,OAAO;AACvC,cAAU,QAAQ;AAClB;;;GAGJ;AAEF,cAAa;AACX,MAAI,OAAO,gBAAgB,WACzB,cAAa;AAEf,mBAAiB,OAAO;AACxB,yBAAuB,OAAO;AAC9B,0BAAwB;AACxB,sBAAoB"}
|
package/dist/runner/index.cjs
CHANGED
package/dist/runner/index.d.cts
CHANGED
|
@@ -1,82 +1,13 @@
|
|
|
1
|
-
import { t as QuickJsExecutorOptions } from "../types-BB8mb_-T.cjs";
|
|
2
|
-
import { QuickJSWASMModule } from "quickjs-emscripten";
|
|
3
|
-
|
|
4
|
-
//#region ../core/src/types.d.ts
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Stable error codes returned by executors and wrapped tool calls.
|
|
8
|
-
*/
|
|
9
|
-
type ExecuteErrorCode = "timeout" | "memory_limit" | "validation_error" | "tool_error" | "runtime_error" | "serialization_error" | "internal_error";
|
|
10
|
-
/**
|
|
11
|
-
* Structured execution failure returned in {@link ExecuteResult}.
|
|
12
|
-
*/
|
|
13
|
-
interface ExecuteError {
|
|
14
|
-
/** Machine-readable error category. */
|
|
15
|
-
code: ExecuteErrorCode;
|
|
16
|
-
/** Human-readable failure message. */
|
|
17
|
-
message: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Structured result returned by every executor invocation.
|
|
21
|
-
*/
|
|
22
|
-
type ExecuteResult<T = unknown> = {
|
|
23
|
-
durationMs: number;
|
|
24
|
-
logs: string[];
|
|
25
|
-
ok: true;
|
|
26
|
-
result: T;
|
|
27
|
-
} | {
|
|
28
|
-
durationMs: number;
|
|
29
|
-
error: ExecuteError;
|
|
30
|
-
logs: string[];
|
|
31
|
-
ok: false;
|
|
32
|
-
};
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region ../core/src/runner.d.ts
|
|
35
|
-
/**
|
|
36
|
-
* Transport-safe metadata for one exposed tool.
|
|
37
|
-
*/
|
|
38
|
-
interface ProviderToolManifest {
|
|
39
|
-
description?: string;
|
|
40
|
-
originalName: string;
|
|
41
|
-
safeName: string;
|
|
42
|
-
}
|
|
43
1
|
/**
|
|
44
|
-
*
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Public TypeScript declarations for this package entrypoint.
|
|
45
4
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Execution limits forwarded to runner implementations.
|
|
53
|
-
*/
|
|
54
|
-
interface ExecutorRuntimeOptions {
|
|
55
|
-
maxLogChars?: number;
|
|
56
|
-
maxLogLines?: number;
|
|
57
|
-
memoryLimitBytes?: number;
|
|
58
|
-
timeoutMs?: number;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Tool invocation request emitted from a runner.
|
|
62
|
-
*/
|
|
63
|
-
interface ToolCall {
|
|
64
|
-
input: unknown;
|
|
65
|
-
providerName: string;
|
|
66
|
-
safeToolName: string;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Trusted host response to a tool invocation request.
|
|
70
|
-
*/
|
|
71
|
-
type ToolCallResult = {
|
|
72
|
-
ok: true;
|
|
73
|
-
result: unknown;
|
|
74
|
-
} | {
|
|
75
|
-
error: ExecuteError;
|
|
76
|
-
ok: false;
|
|
77
|
-
};
|
|
78
|
-
//#endregion
|
|
5
|
+
import { a as QuickJsProcessExecutorOptions, i as QuickJsInlineExecutorOptions, n as QuickJsExecutorOptions, o as QuickJsWorkerExecutorOptions, r as QuickJsHostedMode, s as WorkerResourceLimits, t as QuickJsExecutorHost } from "../types-CnNmLawC.cjs";
|
|
6
|
+
import { ExecuteResult, ExecutorRuntimeOptions, ProviderManifest, ToolCall, ToolCallResult } from "@execbox/core";
|
|
7
|
+
import { QuickJSWASMModule } from "quickjs-emscripten";
|
|
8
|
+
|
|
79
9
|
//#region src/runner/index.d.ts
|
|
10
|
+
|
|
80
11
|
/**
|
|
81
12
|
* Transport-neutral host tool call emitted from a QuickJS session.
|
|
82
13
|
*/
|
|
@@ -85,17 +16,24 @@ type QuickJsSessionToolCall = ToolCall;
|
|
|
85
16
|
* Input required to run one transport-backed QuickJS execution session.
|
|
86
17
|
*/
|
|
87
18
|
interface QuickJsSessionRequest {
|
|
19
|
+
/** Optional abort controller that should be triggered when execution stops. */
|
|
88
20
|
abortController?: AbortController;
|
|
21
|
+
/** Guest JavaScript source to evaluate inside QuickJS. */
|
|
89
22
|
code: string;
|
|
23
|
+
/** Host callback used to fulfill guest tool calls. */
|
|
90
24
|
onToolCall: (call: ToolCall) => Promise<ToolCallResult> | ToolCallResult;
|
|
25
|
+
/** Optional hook invoked once the guest runtime has started. */
|
|
91
26
|
onStarted?: () => void;
|
|
27
|
+
/** Transport-safe provider manifests exposed to the guest runtime. */
|
|
92
28
|
providers: ProviderManifest[];
|
|
29
|
+
/** Optional caller-owned abort signal for the session. */
|
|
93
30
|
signal?: AbortSignal;
|
|
94
31
|
}
|
|
95
32
|
/**
|
|
96
33
|
* Options controlling one transport-backed QuickJS session.
|
|
97
34
|
*/
|
|
98
|
-
type QuickJsSessionOptions =
|
|
35
|
+
type QuickJsSessionOptions = ExecutorRuntimeOptions & Pick<QuickJsInlineExecutorOptions, "loadModule"> & {
|
|
36
|
+
/** Optional preloaded QuickJS WASM module instance. */
|
|
99
37
|
module?: QuickJSWASMModule;
|
|
100
38
|
};
|
|
101
39
|
/**
|
|
@@ -103,5 +41,5 @@ type QuickJsSessionOptions = QuickJsExecutorOptions & ExecutorRuntimeOptions & {
|
|
|
103
41
|
*/
|
|
104
42
|
declare function runQuickJsSession(request: QuickJsSessionRequest, options?: QuickJsSessionOptions): Promise<ExecuteResult>;
|
|
105
43
|
//#endregion
|
|
106
|
-
export { QuickJsSessionOptions, QuickJsSessionRequest, QuickJsSessionToolCall, runQuickJsSession };
|
|
44
|
+
export { type QuickJsExecutorHost, type QuickJsExecutorOptions, type QuickJsHostedMode, type QuickJsInlineExecutorOptions, type QuickJsProcessExecutorOptions, QuickJsSessionOptions, QuickJsSessionRequest, QuickJsSessionToolCall, type QuickJsWorkerExecutorOptions, type WorkerResourceLimits, runQuickJsSession };
|
|
107
45
|
//# sourceMappingURL=index.d.cts.map
|