@code-yeongyu/senpi 2026.9.15 → 2026.9.16
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/CHANGELOG.md +46 -0
- package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.js +25 -8
- package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +4 -5
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-engine.js +14 -18
- package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-event-source.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-event-source.js +32 -9
- package/dist/core/extensions/builtin/config-reload/watch-event-source.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts +23 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js +48 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts +13 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js +24 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js +7 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts +2 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +11 -9
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts +18 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js +61 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts +4 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +1 -44
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +22 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js +2 -13
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts +3 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.js +25 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts +9 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.js +33 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts +6 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js +22 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +14 -35
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/kernel-tools-context.d.ts +13 -0
- package/dist/core/extensions/kernel-tools-context.d.ts.map +1 -0
- package/dist/core/extensions/kernel-tools-context.js +3 -0
- package/dist/core/extensions/kernel-tools-context.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +19 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +103 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +21 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +9 -17
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +14 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +23 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +41 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +4 -3
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts +3 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +16 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +3 -3
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +5 -24
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -8
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +3 -0
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-worker-client.d.ts +3 -0
- package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-client.js +17 -6
- package/dist/modes/rpc/session-worker-client.js.map +1 -1
- package/dist/modes/rpc/shutdown.d.ts +3 -0
- package/dist/modes/rpc/shutdown.d.ts.map +1 -0
- package/dist/modes/rpc/shutdown.js +17 -0
- package/dist/modes/rpc/shutdown.js.map +1 -0
- package/docs/extensions.md +3 -0
- package/docs/settings.md +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +36 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/http-server.ts +7 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/kernel-tools-protocol.ts +85 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +6 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +30 -11
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +11 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +46 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +58 -10
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.d.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.js +7 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.d.ts +10 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.js +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.js +22 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.ts +26 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-host.ts +134 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-naming.js +28 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.d.ts +5 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.js +255 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-pump.js +105 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.d.ts +27 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.js +127 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-schema.js +69 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-types.ts +42 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +26 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +20 -8
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-slot.ts +6 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-startup.ts +9 -7
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/workpool.js +37 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/kernel-tools-unavailable.ts +5 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +57 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +13 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/workpool.rb +38 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +9 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +4 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +8 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +36 -71
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image-resize.ts +52 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +37 -72
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +78 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +30 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +49 -30
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +35 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/tool-result-marshal.ts +23 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +51 -12
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts +3 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js +18 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts +4 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js +268 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts +18 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js +69 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts +27 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js +118 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts +21 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js +24 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts +12 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js +92 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts +47 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js +8 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts +52 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js +155 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +10 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -8,8 +8,12 @@ import {
|
|
|
8
8
|
type JavaScriptRunInput,
|
|
9
9
|
type LifecycleState,
|
|
10
10
|
type ResultMessage,
|
|
11
|
+
resolveKernelToolNameSource,
|
|
11
12
|
type ToolCallMessage,
|
|
12
13
|
} from "./kernel-contract.ts";
|
|
14
|
+
import { kernelToolError } from "./kernel-tools-errors.ts";
|
|
15
|
+
import { KernelToolHostPump } from "./kernel-tools-host.ts";
|
|
16
|
+
import type { KernelToolsDescribeResult, KernelToolsInvokeRequest } from "./kernel-tools-types.ts";
|
|
13
17
|
import { type JavaScriptKernelOptions, LocalModuleLoader } from "./local-module-loader.ts";
|
|
14
18
|
import { terminateProcessTrees } from "./process-tree-host.ts";
|
|
15
19
|
import { JavaScriptRunQueue, type PendingJavaScriptRun, stoppedResult } from "./run-queue.ts";
|
|
@@ -23,6 +27,10 @@ export { type JavaScriptWorkerEntryUrlOptions, resolveJsWorkerEntryUrl } from ".
|
|
|
23
27
|
/** How long a lost worker's children get to honour SIGTERM before the host sends SIGKILL. */
|
|
24
28
|
const WORKER_LOSS_CHILD_GRACE_MS = 1_000;
|
|
25
29
|
|
|
30
|
+
// Pull-API fallback queue bound: a nextToolCall consumer this far behind is already stalled, and the
|
|
31
|
+
// normal push path (onMessage) never reads the queue, so unbounded growth only pins tool args (#1695).
|
|
32
|
+
const MAX_PENDING_TOOL_CALLS = 256;
|
|
33
|
+
|
|
26
34
|
export class JavaScriptKernel {
|
|
27
35
|
readonly #options: JavaScriptKernelOptions;
|
|
28
36
|
readonly #moduleLoader: LocalModuleLoader;
|
|
@@ -32,6 +40,10 @@ export class JavaScriptKernel {
|
|
|
32
40
|
#recovery: Promise<void> | null = null;
|
|
33
41
|
#closePromise: Promise<void> | null = null;
|
|
34
42
|
readonly #runs = new JavaScriptRunQueue();
|
|
43
|
+
readonly #kernelTools = new KernelToolHostPump(
|
|
44
|
+
(message) => this.#slot.postMessage(message),
|
|
45
|
+
() => this.#lifecycle === "open" && this.#slot.present,
|
|
46
|
+
);
|
|
35
47
|
#timeout: NodeJS.Timeout | null = null;
|
|
36
48
|
#toolWaiters: Array<(message: ToolCallMessage) => void> = [];
|
|
37
49
|
#pendingToolCalls: ToolCallMessage[] = [];
|
|
@@ -52,6 +64,18 @@ export class JavaScriptKernel {
|
|
|
52
64
|
return this.#slot.mode;
|
|
53
65
|
}
|
|
54
66
|
|
|
67
|
+
get kernelToolEvents(): EventTarget {
|
|
68
|
+
return this.#kernelTools.events;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describeKernelTools(names: readonly string[]): Promise<KernelToolsDescribeResult> {
|
|
72
|
+
return this.#kernelTools.describe(names);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
invokeKernelTool(request: KernelToolsInvokeRequest, signal?: AbortSignal): Promise<unknown> {
|
|
76
|
+
return this.#kernelTools.invoke(request, signal);
|
|
77
|
+
}
|
|
78
|
+
|
|
55
79
|
async run(input: JavaScriptRunInput): Promise<ResultMessage> {
|
|
56
80
|
assertJavaScriptKernelOpen(this.#lifecycle, "run");
|
|
57
81
|
const promise = this.#runs.enqueue(input);
|
|
@@ -77,6 +101,7 @@ export class JavaScriptKernel {
|
|
|
77
101
|
async reset(): Promise<void> {
|
|
78
102
|
assertJavaScriptKernelOpen(this.#lifecycle, "reset");
|
|
79
103
|
await this.#terminate();
|
|
104
|
+
this.#clearToolCalls();
|
|
80
105
|
assertJavaScriptKernelOpen(this.#lifecycle, "reset");
|
|
81
106
|
await this.#ensureReady();
|
|
82
107
|
this.#startNext();
|
|
@@ -97,6 +122,8 @@ export class JavaScriptKernel {
|
|
|
97
122
|
this.#slot.postMessage({ type: "close" });
|
|
98
123
|
this.#lifecycle = "closing";
|
|
99
124
|
this.#runs.settleAll("JS kernel closed");
|
|
125
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JS kernel closed"));
|
|
126
|
+
this.#clearToolCalls();
|
|
100
127
|
const recovery = this.#recovery;
|
|
101
128
|
const closePromise = (async () => {
|
|
102
129
|
if (recovery) await recovery;
|
|
@@ -140,6 +167,11 @@ export class JavaScriptKernel {
|
|
|
140
167
|
if (next.input.timeoutMs) {
|
|
141
168
|
this.#timeout = setTimeout(() => void this.#timeoutActive(next), next.input.timeoutMs);
|
|
142
169
|
}
|
|
170
|
+
this.#slot.postMessage({
|
|
171
|
+
type: "kernel-tools-names",
|
|
172
|
+
hostToolNames: resolveKernelToolNameSource(this.#options.hostToolNames),
|
|
173
|
+
foreignLanguageNames: resolveKernelToolNameSource(this.#options.foreignLanguageNames),
|
|
174
|
+
});
|
|
143
175
|
this.#slot.postMessage({
|
|
144
176
|
type: "run",
|
|
145
177
|
cellId: next.input.cellId,
|
|
@@ -170,15 +202,19 @@ export class JavaScriptKernel {
|
|
|
170
202
|
message: string,
|
|
171
203
|
durationMs = 0,
|
|
172
204
|
): Promise<{ readonly retained: boolean; readonly note?: string }> {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
try {
|
|
206
|
+
run.interruptResult = { type: "result", cellId: run.input.cellId, ok: false, error: { message }, durationMs };
|
|
207
|
+
run.interruptAck ??= Promise.withResolvers<void>();
|
|
208
|
+
this.#slot.postMessage({ type: "interrupt", reason });
|
|
209
|
+
if ((await awaitCooperativeSettlement(run)) === "settled") return { retained: run.settledByWorker };
|
|
210
|
+
if (!this.#runs.releaseActive(run)) return { retained: run.settledByWorker };
|
|
211
|
+
const retirement = await this.#terminate();
|
|
212
|
+
this.#runs.settle(run, run.interruptResult ?? stoppedResult(run.input.cellId, message));
|
|
213
|
+
void this.#recover(() => Promise.resolve());
|
|
214
|
+
return retirement === "abandoned" ? { retained: false, note: abandonedWorkerNote() } : { retained: false };
|
|
215
|
+
} finally {
|
|
216
|
+
this.#clearToolCalls();
|
|
217
|
+
}
|
|
182
218
|
}
|
|
183
219
|
|
|
184
220
|
async #restartAfterStop(): Promise<void> {
|
|
@@ -210,6 +246,7 @@ export class JavaScriptKernel {
|
|
|
210
246
|
}
|
|
211
247
|
|
|
212
248
|
#handleMessage(message: KernelToHostMessage): void {
|
|
249
|
+
if (this.#kernelTools.consume(message) && message.type !== "tool-call") return;
|
|
213
250
|
if (message.type === "status" && message.event.op === INTERRUPT_ACK_OP) {
|
|
214
251
|
this.#runs.active?.interruptAck?.resolve();
|
|
215
252
|
return;
|
|
@@ -223,7 +260,10 @@ export class JavaScriptKernel {
|
|
|
223
260
|
if (message.type === "tool-call") {
|
|
224
261
|
const waiter = this.#toolWaiters.shift();
|
|
225
262
|
if (waiter) waiter(message);
|
|
226
|
-
else
|
|
263
|
+
else {
|
|
264
|
+
this.#pendingToolCalls.push(message);
|
|
265
|
+
if (this.#pendingToolCalls.length > MAX_PENDING_TOOL_CALLS) this.#pendingToolCalls.shift();
|
|
266
|
+
}
|
|
227
267
|
return;
|
|
228
268
|
}
|
|
229
269
|
if (message.type !== "result") return;
|
|
@@ -240,6 +280,7 @@ export class JavaScriptKernel {
|
|
|
240
280
|
const active = this.#runs.active;
|
|
241
281
|
if (!active && this.#slot.startingUp) return;
|
|
242
282
|
this.#clearTimeout();
|
|
283
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", error.message));
|
|
243
284
|
if (active) {
|
|
244
285
|
this.#runs.releaseActive(active);
|
|
245
286
|
this.#runs.settle(active, {
|
|
@@ -250,9 +291,15 @@ export class JavaScriptKernel {
|
|
|
250
291
|
durationMs: this.#runs.durationMs(active, performance.now()),
|
|
251
292
|
});
|
|
252
293
|
}
|
|
294
|
+
this.#clearToolCalls();
|
|
253
295
|
void this.#restartAfterStop();
|
|
254
296
|
}
|
|
255
297
|
|
|
298
|
+
#clearToolCalls(): void {
|
|
299
|
+
this.#pendingToolCalls.length = 0;
|
|
300
|
+
this.#toolWaiters.length = 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
256
303
|
#clearTimeout(): void {
|
|
257
304
|
if (this.#timeout) clearTimeout(this.#timeout);
|
|
258
305
|
this.#timeout = null;
|
|
@@ -271,6 +318,7 @@ export class JavaScriptKernel {
|
|
|
271
318
|
*/
|
|
272
319
|
async #terminate(): Promise<WorkerRetirement> {
|
|
273
320
|
this.#clearTimeout();
|
|
321
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JavaScript worker reset"));
|
|
274
322
|
const retirement = await this.#slot.retire();
|
|
275
323
|
await this.#retireWorkerChildren();
|
|
276
324
|
return retirement;
|
|
@@ -6,6 +6,14 @@ export type ToolCallMessage = Extract<KernelToHostMessage, { type: "tool-call" }
|
|
|
6
6
|
|
|
7
7
|
export type JavaScriptKernelMode = "worker" | "inline";
|
|
8
8
|
|
|
9
|
+
/** Snapshot or live provider consulted when the worker registry checks collisions. */
|
|
10
|
+
export type KernelToolNameSource = readonly string[] | (() => readonly string[]);
|
|
11
|
+
|
|
12
|
+
export function resolveKernelToolNameSource(names?: KernelToolNameSource): string[] {
|
|
13
|
+
if (typeof names === "function") return [...names()];
|
|
14
|
+
return names === undefined ? [] : [...names];
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
export interface JavaScriptKernelOptions {
|
|
10
18
|
readonly sessionId: string;
|
|
11
19
|
readonly cwd: string;
|
|
@@ -14,6 +22,10 @@ export interface JavaScriptKernelOptions {
|
|
|
14
22
|
readonly workerEntryUrl?: URL;
|
|
15
23
|
/** Per-session PI_* values applied to the worker environment before the first cell runs. */
|
|
16
24
|
readonly sessionEnv?: SessionEnvironment;
|
|
25
|
+
/** Host tool names denied as JS kernel-tool identifiers (init protocol). */
|
|
26
|
+
readonly hostToolNames?: KernelToolNameSource;
|
|
27
|
+
/** Tool names registered in another kernel language, denied as JS kernel-tool identifiers. */
|
|
28
|
+
readonly foreignLanguageNames?: KernelToolNameSource;
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
export interface JavaScriptRunInput {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const kernelToolCallContext: {
|
|
2
|
+
run<T>(store: KernelToolCallStore, fn: () => T): T;
|
|
3
|
+
getStore(): KernelToolCallStore | undefined;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type KernelToolCallStore = {
|
|
7
|
+
readonly pendingTools: Map<string, { resolve: (value: unknown) => void; reject: (error: Error) => void }>;
|
|
8
|
+
readonly callId: string;
|
|
9
|
+
readonly generation: number;
|
|
10
|
+
readonly signal: AbortSignal;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function inKernelToolInvoke(): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type KernelToolFunction = {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export function createToolNamespace(
|
|
6
|
+
define: (fn: KernelToolFunction, metadata?: unknown) => unknown,
|
|
7
|
+
callHost: (name: string, args: unknown) => Promise<unknown>,
|
|
8
|
+
): ((fn: KernelToolFunction, metadata?: unknown) => unknown) & {
|
|
9
|
+
readonly [name: string]: (args?: unknown) => Promise<unknown>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function createToolNamespace(define, callHost) {
|
|
2
|
+
const registrar = function tool(fn, metadata) {
|
|
3
|
+
return define(fn, metadata);
|
|
4
|
+
};
|
|
5
|
+
return new Proxy(registrar, {
|
|
6
|
+
get(target, prop) {
|
|
7
|
+
if (typeof prop !== "string") return undefined;
|
|
8
|
+
if (prop in Function.prototype || prop === "arguments" || prop === "caller") return target[prop];
|
|
9
|
+
return async (args) => await callHost(prop, args ?? {});
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const KERNEL_TOOL_ERROR_CODES = Object.freeze([
|
|
2
|
+
"tools_unavailable",
|
|
3
|
+
"invalid_tool_definition",
|
|
4
|
+
"reserved_tool_name",
|
|
5
|
+
"tool_name_collision",
|
|
6
|
+
"kernel_tool_stale",
|
|
7
|
+
"kernel_tool_missing",
|
|
8
|
+
"kernel_tool_failed",
|
|
9
|
+
"kernel_tool_recursion",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export class KernelToolError extends Error {
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "KernelToolError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function kernelToolError(code, message) {
|
|
21
|
+
return new KernelToolError(code, message);
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const KERNEL_TOOL_ERROR_CODES = [
|
|
2
|
+
"tools_unavailable",
|
|
3
|
+
"invalid_tool_definition",
|
|
4
|
+
"reserved_tool_name",
|
|
5
|
+
"tool_name_collision",
|
|
6
|
+
"kernel_tool_stale",
|
|
7
|
+
"kernel_tool_missing",
|
|
8
|
+
"kernel_tool_failed",
|
|
9
|
+
"kernel_tool_recursion",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export type KernelToolErrorCode = (typeof KERNEL_TOOL_ERROR_CODES)[number];
|
|
13
|
+
|
|
14
|
+
export class KernelToolError extends Error {
|
|
15
|
+
readonly name = "KernelToolError";
|
|
16
|
+
readonly code: KernelToolErrorCode;
|
|
17
|
+
|
|
18
|
+
constructor(code: KernelToolErrorCode, message: string) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function kernelToolError(code: KernelToolErrorCode, message: string): KernelToolError {
|
|
25
|
+
return new KernelToolError(code, message);
|
|
26
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { HostToKernelMessage, KernelToHostMessage } from "../../bridge/protocol.ts";
|
|
2
|
+
import { generateCorrelationId } from "../../bridge/protocol.ts";
|
|
3
|
+
import { RESERVED_AGENT_TOOL } from "../../bridge/reserved.ts";
|
|
4
|
+
import { kernelToolError } from "./kernel-tools-errors.ts";
|
|
5
|
+
import type { KernelToolsDescribeResult, KernelToolsInvokeRequest } from "./kernel-tools-types.ts";
|
|
6
|
+
|
|
7
|
+
type KernelToolReply = Extract<
|
|
8
|
+
KernelToHostMessage,
|
|
9
|
+
{ type: "kernel-tool-describe-reply" } | { type: "kernel-tool-invoke-reply" }
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
type Waiter = {
|
|
13
|
+
readonly resolve: (message: KernelToolReply) => void;
|
|
14
|
+
readonly reject: (error: Error) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class KernelToolHostPump {
|
|
18
|
+
readonly events = new EventTarget();
|
|
19
|
+
readonly #waiters = new Map<string, Waiter>();
|
|
20
|
+
readonly #post: (message: HostToKernelMessage) => void;
|
|
21
|
+
readonly #isOpen: () => boolean;
|
|
22
|
+
|
|
23
|
+
constructor(post: (message: HostToKernelMessage) => void, isOpen: () => boolean) {
|
|
24
|
+
this.#post = post;
|
|
25
|
+
this.#isOpen = isOpen;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
consume(message: KernelToHostMessage): boolean {
|
|
29
|
+
if (message.type === "tool-call" && message.toolName === RESERVED_AGENT_TOOL) {
|
|
30
|
+
this.events.dispatchEvent(new Event("outerAwaitingAgent"));
|
|
31
|
+
}
|
|
32
|
+
if (message.type !== "kernel-tool-describe-reply" && message.type !== "kernel-tool-invoke-reply") return false;
|
|
33
|
+
const waiter = this.#waiters.get(message.requestId);
|
|
34
|
+
if (!waiter) return true;
|
|
35
|
+
this.#waiters.delete(message.requestId);
|
|
36
|
+
waiter.resolve(message);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rejectAll(error: Error): void {
|
|
41
|
+
for (const [requestId, waiter] of this.#waiters) {
|
|
42
|
+
this.#waiters.delete(requestId);
|
|
43
|
+
waiter.reject(error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async describe(names: readonly string[]): Promise<KernelToolsDescribeResult> {
|
|
48
|
+
const reply = await this.#request({
|
|
49
|
+
type: "kernel-tool-describe",
|
|
50
|
+
requestId: generateCorrelationId(),
|
|
51
|
+
names: [...names],
|
|
52
|
+
});
|
|
53
|
+
if (reply.type !== "kernel-tool-describe-reply") {
|
|
54
|
+
throw kernelToolError("kernel_tool_failed", "unexpected kernel-tool describe reply");
|
|
55
|
+
}
|
|
56
|
+
if (!reply.ok) {
|
|
57
|
+
throw kernelToolError(codeOf(reply.error.code), reply.error.message);
|
|
58
|
+
}
|
|
59
|
+
return { results: reply.results as KernelToolsDescribeResult["results"] };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async invoke(request: KernelToolsInvokeRequest, signal?: AbortSignal): Promise<unknown> {
|
|
63
|
+
this.events.dispatchEvent(new Event("nestedInvoke"));
|
|
64
|
+
const reply = await this.#request(
|
|
65
|
+
{
|
|
66
|
+
type: "kernel-tool-invoke",
|
|
67
|
+
requestId: generateCorrelationId(),
|
|
68
|
+
name: request.name,
|
|
69
|
+
kernel_generation: request.kernel_generation,
|
|
70
|
+
definition_revision: request.definition_revision,
|
|
71
|
+
args: request.args,
|
|
72
|
+
call_id: request.call_id,
|
|
73
|
+
},
|
|
74
|
+
signal,
|
|
75
|
+
);
|
|
76
|
+
if (reply.type !== "kernel-tool-invoke-reply") {
|
|
77
|
+
throw kernelToolError("kernel_tool_failed", "unexpected kernel-tool invoke reply");
|
|
78
|
+
}
|
|
79
|
+
if (!reply.ok) throw kernelToolError(codeOf(reply.error.code), reply.error.message);
|
|
80
|
+
return reply.value;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#request(
|
|
84
|
+
message: Extract<HostToKernelMessage, { requestId: string }>,
|
|
85
|
+
signal?: AbortSignal,
|
|
86
|
+
): Promise<KernelToolReply> {
|
|
87
|
+
if (!this.#isOpen()) throw kernelToolError("tools_unavailable", "JavaScript worker is not available");
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const onAbort = (): void => {
|
|
90
|
+
if (!this.#waiters.delete(message.requestId)) return;
|
|
91
|
+
this.#post({ type: "kernel-tool-cancel", requestId: message.requestId });
|
|
92
|
+
reject(kernelToolError("kernel_tool_stale", "Kernel tool call cancelled"));
|
|
93
|
+
};
|
|
94
|
+
const cleanup = (): void => signal?.removeEventListener("abort", onAbort);
|
|
95
|
+
this.#waiters.set(message.requestId, {
|
|
96
|
+
resolve: (reply) => {
|
|
97
|
+
cleanup();
|
|
98
|
+
resolve(reply);
|
|
99
|
+
},
|
|
100
|
+
reject: (error) => {
|
|
101
|
+
cleanup();
|
|
102
|
+
reject(error);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
if (signal?.aborted) {
|
|
106
|
+
onAbort();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
110
|
+
this.#post(message);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function codeOf(
|
|
116
|
+
code: string | undefined,
|
|
117
|
+
):
|
|
118
|
+
| "kernel_tool_failed"
|
|
119
|
+
| "kernel_tool_stale"
|
|
120
|
+
| "kernel_tool_missing"
|
|
121
|
+
| "kernel_tool_recursion"
|
|
122
|
+
| "tools_unavailable"
|
|
123
|
+
| "invalid_tool_definition" {
|
|
124
|
+
if (
|
|
125
|
+
code === "kernel_tool_stale" ||
|
|
126
|
+
code === "kernel_tool_missing" ||
|
|
127
|
+
code === "kernel_tool_recursion" ||
|
|
128
|
+
code === "tools_unavailable" ||
|
|
129
|
+
code === "invalid_tool_definition"
|
|
130
|
+
) {
|
|
131
|
+
return code;
|
|
132
|
+
}
|
|
133
|
+
return "kernel_tool_failed";
|
|
134
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** MCP name rules from coding-agent mcp/expose/naming.ts, applied explicitly for kernel tools. */
|
|
2
|
+
export const MCP_TOOL_NAME_MAX_LENGTH = 64;
|
|
3
|
+
|
|
4
|
+
export function sanitizeNamePart(name) {
|
|
5
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function matcherKey(name) {
|
|
9
|
+
return name.replace(/-/g, "_");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ellipsizeMiddle(value, maxLength) {
|
|
13
|
+
if (value.length <= maxLength) return value;
|
|
14
|
+
if (maxLength <= 3) return value.slice(0, maxLength);
|
|
15
|
+
const marker = "...";
|
|
16
|
+
const remaining = maxLength - marker.length;
|
|
17
|
+
const prefixLength = Math.ceil(remaining / 2);
|
|
18
|
+
const suffixLength = Math.floor(remaining / 2);
|
|
19
|
+
return `${value.slice(0, prefixLength)}${marker}${value.slice(value.length - suffixLength)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function normalizeKernelToolName(name) {
|
|
23
|
+
return ellipsizeMiddle(sanitizeNamePart(name), MCP_TOOL_NAME_MAX_LENGTH);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function kernelToolKey(name) {
|
|
27
|
+
return matcherKey(normalizeKernelToolName(name));
|
|
28
|
+
}
|