@code-yeongyu/senpi 2026.9.15-2 → 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 +21 -0
- 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/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/docs/extensions.md +3 -0
- package/docs/settings.md +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +21 -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 +29 -0
- 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 +2 -0
- 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/run-eval-cell.ts +49 -30
- 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/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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type Static, Type } from "typebox";
|
|
2
|
+
|
|
3
|
+
const kernelToolErrorSchema = Type.Object({
|
|
4
|
+
message: Type.String(),
|
|
5
|
+
name: Type.Optional(Type.String()),
|
|
6
|
+
stack: Type.Optional(Type.String()),
|
|
7
|
+
code: Type.Optional(Type.String()),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const kernelToolDescriptorSchema = Type.Object({
|
|
11
|
+
name: Type.String({ minLength: 1 }),
|
|
12
|
+
description: Type.String(),
|
|
13
|
+
input_schema: Type.Unknown(),
|
|
14
|
+
language: Type.Literal("js"),
|
|
15
|
+
kernel_generation: Type.Integer({ minimum: 0 }),
|
|
16
|
+
definition_revision: Type.Integer({ minimum: 1 }),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const describeResultSchema = Type.Union([
|
|
20
|
+
Type.Object({
|
|
21
|
+
name: Type.String({ minLength: 1 }),
|
|
22
|
+
ok: Type.Literal(true),
|
|
23
|
+
descriptor: kernelToolDescriptorSchema,
|
|
24
|
+
}),
|
|
25
|
+
Type.Object({
|
|
26
|
+
name: Type.String({ minLength: 1 }),
|
|
27
|
+
ok: Type.Literal(false),
|
|
28
|
+
error: kernelToolErrorSchema,
|
|
29
|
+
}),
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
export const kernelToolHostToKernelSchemas = [
|
|
33
|
+
Type.Object({
|
|
34
|
+
type: Type.Literal("kernel-tool-describe"),
|
|
35
|
+
requestId: Type.String({ minLength: 1 }),
|
|
36
|
+
names: Type.Array(Type.String({ minLength: 1 })),
|
|
37
|
+
}),
|
|
38
|
+
Type.Object({
|
|
39
|
+
type: Type.Literal("kernel-tool-invoke"),
|
|
40
|
+
requestId: Type.String({ minLength: 1 }),
|
|
41
|
+
name: Type.String({ minLength: 1 }),
|
|
42
|
+
kernel_generation: Type.Integer({ minimum: 0 }),
|
|
43
|
+
definition_revision: Type.Integer({ minimum: 1 }),
|
|
44
|
+
args: Type.Unknown(),
|
|
45
|
+
call_id: Type.String({ minLength: 1 }),
|
|
46
|
+
}),
|
|
47
|
+
Type.Object({
|
|
48
|
+
type: Type.Literal("kernel-tool-cancel"),
|
|
49
|
+
requestId: Type.String({ minLength: 1 }),
|
|
50
|
+
}),
|
|
51
|
+
Type.Object({
|
|
52
|
+
type: Type.Literal("kernel-tools-names"),
|
|
53
|
+
hostToolNames: Type.Array(Type.String({ minLength: 1 })),
|
|
54
|
+
foreignLanguageNames: Type.Array(Type.String({ minLength: 1 })),
|
|
55
|
+
}),
|
|
56
|
+
] as const;
|
|
57
|
+
|
|
58
|
+
export const kernelToolKernelToHostSchemas = [
|
|
59
|
+
Type.Object({
|
|
60
|
+
type: Type.Literal("kernel-tool-describe-reply"),
|
|
61
|
+
requestId: Type.String({ minLength: 1 }),
|
|
62
|
+
ok: Type.Literal(true),
|
|
63
|
+
results: Type.Array(describeResultSchema),
|
|
64
|
+
}),
|
|
65
|
+
Type.Object({
|
|
66
|
+
type: Type.Literal("kernel-tool-describe-reply"),
|
|
67
|
+
requestId: Type.String({ minLength: 1 }),
|
|
68
|
+
ok: Type.Literal(false),
|
|
69
|
+
error: kernelToolErrorSchema,
|
|
70
|
+
}),
|
|
71
|
+
Type.Object({
|
|
72
|
+
type: Type.Literal("kernel-tool-invoke-reply"),
|
|
73
|
+
requestId: Type.String({ minLength: 1 }),
|
|
74
|
+
ok: Type.Literal(true),
|
|
75
|
+
value: Type.Unknown(),
|
|
76
|
+
}),
|
|
77
|
+
Type.Object({
|
|
78
|
+
type: Type.Literal("kernel-tool-invoke-reply"),
|
|
79
|
+
requestId: Type.String({ minLength: 1 }),
|
|
80
|
+
ok: Type.Literal(false),
|
|
81
|
+
error: kernelToolErrorSchema,
|
|
82
|
+
}),
|
|
83
|
+
] as const;
|
|
84
|
+
|
|
85
|
+
export type KernelToolDescriptorMessage = Static<typeof kernelToolDescriptorSchema>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { type Static, Type } from "typebox";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
|
+
import { kernelToolHostToKernelSchemas, kernelToolKernelToHostSchemas } from "./kernel-tools-protocol.ts";
|
|
4
5
|
|
|
5
6
|
export const BRIDGE_FRAME_MAX_BYTES = 10 * 1024 * 1024;
|
|
6
7
|
|
|
@@ -27,6 +28,9 @@ const hostToKernelMessageSchema = Type.Union([
|
|
|
27
28
|
sessionId: Type.String({ minLength: 1 }),
|
|
28
29
|
connection: connectionConfigSchema,
|
|
29
30
|
sessionEnv: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
31
|
+
kernelGeneration: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
32
|
+
hostToolNames: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
33
|
+
foreignLanguageNames: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
30
34
|
}),
|
|
31
35
|
Type.Object({
|
|
32
36
|
type: Type.Literal("run"),
|
|
@@ -53,6 +57,7 @@ const hostToKernelMessageSchema = Type.Union([
|
|
|
53
57
|
Type.Object({
|
|
54
58
|
type: Type.Literal("close"),
|
|
55
59
|
}),
|
|
60
|
+
...kernelToolHostToKernelSchemas,
|
|
56
61
|
]);
|
|
57
62
|
|
|
58
63
|
const kernelToHostMessageSchema = Type.Union([
|
|
@@ -92,6 +97,7 @@ const kernelToHostMessageSchema = Type.Union([
|
|
|
92
97
|
durationMs: Type.Integer({ minimum: 0 }),
|
|
93
98
|
}),
|
|
94
99
|
Type.Object({ type: Type.Literal("closed") }),
|
|
100
|
+
...kernelToolKernelToHostSchemas,
|
|
95
101
|
]);
|
|
96
102
|
|
|
97
103
|
const bridgeMessageSchema = Type.Union([hostToKernelMessageSchema, kernelToHostMessageSchema]);
|
|
@@ -11,6 +11,7 @@ const agentArgsSchema = Type.Object(
|
|
|
11
11
|
label: Type.Optional(Type.String()),
|
|
12
12
|
schema: Type.Optional(Type.Unknown()),
|
|
13
13
|
handle: Type.Optional(Type.Boolean()),
|
|
14
|
+
tools: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
14
15
|
isolated: Type.Optional(Type.Boolean()),
|
|
15
16
|
apply: Type.Optional(Type.Boolean()),
|
|
16
17
|
merge: Type.Optional(Type.Boolean()),
|
|
@@ -19,7 +20,19 @@ const agentArgsSchema = Type.Object(
|
|
|
19
20
|
);
|
|
20
21
|
|
|
21
22
|
const unsupportedIsolationWarning = "isolated/apply/merge unsupported (no isolation in task engine)";
|
|
22
|
-
const
|
|
23
|
+
const taskHandleSchema = Type.Object(
|
|
24
|
+
{
|
|
25
|
+
task_id: Type.String({ pattern: "^st_[0-9a-f]+$" }),
|
|
26
|
+
run_epoch: Type.Integer({ minimum: 0 }),
|
|
27
|
+
},
|
|
28
|
+
{ additionalProperties: true },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
/** Structural host contract; no orchestration package dependency. */
|
|
32
|
+
export type TaskHandleDetails = {
|
|
33
|
+
readonly task_id: string;
|
|
34
|
+
readonly run_epoch: number;
|
|
35
|
+
};
|
|
23
36
|
const droppedOptionNames = ["isolated", "apply", "merge"] as const;
|
|
24
37
|
|
|
25
38
|
type AgentArgs = Static<typeof agentArgsSchema>;
|
|
@@ -29,6 +42,7 @@ type TaskParams = {
|
|
|
29
42
|
readonly model?: string;
|
|
30
43
|
readonly name?: string;
|
|
31
44
|
readonly run_in_background: boolean;
|
|
45
|
+
readonly tools?: readonly string[];
|
|
32
46
|
};
|
|
33
47
|
type ProgressContext = { readonly fallbackId: string; readonly warning?: string };
|
|
34
48
|
|
|
@@ -48,7 +62,7 @@ export type EvalAgentResult =
|
|
|
48
62
|
| { readonly text: string }
|
|
49
63
|
| { readonly text: string; readonly data: unknown }
|
|
50
64
|
| { readonly text: string; readonly parseError: string }
|
|
51
|
-
| { readonly text: string; readonly id: string; readonly handle: string };
|
|
65
|
+
| { readonly text: string; readonly id: string; readonly handle: string; readonly run_epoch: number };
|
|
52
66
|
|
|
53
67
|
class AgentArgumentsError extends Error {
|
|
54
68
|
readonly name = "AgentArgumentsError";
|
|
@@ -68,9 +82,10 @@ class AgentUnavailableError extends Error {
|
|
|
68
82
|
|
|
69
83
|
class AgentHandleError extends Error {
|
|
70
84
|
readonly name = "AgentHandleError";
|
|
85
|
+
readonly code = "invalid_task_handle";
|
|
71
86
|
|
|
72
87
|
constructor() {
|
|
73
|
-
super("agent()
|
|
88
|
+
super("agent() requires successful task details with a valid task_id and nonnegative integer run_epoch");
|
|
74
89
|
}
|
|
75
90
|
}
|
|
76
91
|
|
|
@@ -105,9 +120,8 @@ export async function runEvalAgent(args: unknown, options: RunEvalAgentOptions):
|
|
|
105
120
|
|
|
106
121
|
const text = resultText(result);
|
|
107
122
|
if (parsed.handle === true) {
|
|
108
|
-
const id =
|
|
109
|
-
|
|
110
|
-
return { text, id, handle: `agent://${id}` };
|
|
123
|
+
const { task_id: id, run_epoch } = resultTaskHandle(result);
|
|
124
|
+
return { text, id, handle: `agent://${id}`, run_epoch };
|
|
111
125
|
}
|
|
112
126
|
if (!structured) return { text };
|
|
113
127
|
return parseStructuredText(text);
|
|
@@ -130,6 +144,7 @@ function toTaskParams(args: AgentArgs, structured: boolean): TaskParams {
|
|
|
130
144
|
...(args.model === undefined ? {} : { model: args.model }),
|
|
131
145
|
...(args.label === undefined ? {} : { name: args.label }),
|
|
132
146
|
run_in_background: args.handle === true,
|
|
147
|
+
...(args.tools === undefined ? {} : { tools: args.tools }),
|
|
133
148
|
};
|
|
134
149
|
}
|
|
135
150
|
|
|
@@ -168,11 +183,15 @@ function resultText(result: AgentToolResult<unknown>): string {
|
|
|
168
183
|
.join("\n");
|
|
169
184
|
}
|
|
170
185
|
|
|
171
|
-
function
|
|
172
|
-
const details =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
186
|
+
function resultTaskHandle(result: AgentToolResult<unknown>): TaskHandleDetails {
|
|
187
|
+
const details = result.details;
|
|
188
|
+
if (
|
|
189
|
+
("isError" in result && result.isError === true) ||
|
|
190
|
+
(isRecord(details) && (details.isError === true || details.error !== undefined)) ||
|
|
191
|
+
!Check(taskHandleSchema, details)
|
|
192
|
+
)
|
|
193
|
+
throw new AgentHandleError();
|
|
194
|
+
return details;
|
|
176
195
|
}
|
|
177
196
|
|
|
178
197
|
function firstString(
|
|
@@ -215,6 +215,8 @@ class DefaultCodemodeSessionManager implements CodemodeSessionManager {
|
|
|
215
215
|
cwd: this.#options.cwd,
|
|
216
216
|
parallelPoolWidth,
|
|
217
217
|
onMessage,
|
|
218
|
+
hostToolNames: () => this.#options.listTools?.().map((tool) => tool.name) ?? [],
|
|
219
|
+
foreignLanguageNames: () => this.#foreignKernelToolNames(),
|
|
218
220
|
...(this.#options.sessionEnv ? { sessionEnv: this.#options.sessionEnv } : {}),
|
|
219
221
|
...(localRoots ? { localRoots: { ...localRoots } } : {}),
|
|
220
222
|
...(this.#options.artifactsDir ? { artifactsDir: this.#options.artifactsDir } : {}),
|
|
@@ -259,6 +261,15 @@ class DefaultCodemodeSessionManager implements CodemodeSessionManager {
|
|
|
259
261
|
});
|
|
260
262
|
}
|
|
261
263
|
|
|
264
|
+
#foreignKernelToolNames(): string[] {
|
|
265
|
+
const names: string[] = [];
|
|
266
|
+
for (const [language, kernel] of this.#kernels) {
|
|
267
|
+
if (language === "js") continue;
|
|
268
|
+
names.push(...(kernel.listKernelToolNames?.() ?? []));
|
|
269
|
+
}
|
|
270
|
+
return names;
|
|
271
|
+
}
|
|
272
|
+
|
|
262
273
|
#contextFor(signal: AbortSignal): ExtensionContext {
|
|
263
274
|
const ctx = this.#context;
|
|
264
275
|
if (!ctx) throw new CodemodeContextUnavailableError();
|
|
@@ -23,6 +23,7 @@ import type { CodemodeSessionManager, CreateCodemodeSessionManagerOptions } from
|
|
|
23
23
|
import { SessionManagerProxy } from "./extension/session-manager-proxy.ts";
|
|
24
24
|
import { activeBunSkillPath, registerBunSkillContribution } from "./extension/skill-contribution.ts";
|
|
25
25
|
import { WAKE_SOURCE_STATE_EVENT, type WakeSourceState } from "./extension/wake-source-state.ts";
|
|
26
|
+
import type { KernelToolsCapability } from "./kernels/js/kernel-tools-types.ts";
|
|
26
27
|
import { EvalDetachedCellManager, type EvalDetachedCellStatusEntry } from "./tool/detached-cell-manager.ts";
|
|
27
28
|
import {
|
|
28
29
|
EVAL_EXECUTION_EVENT,
|
|
@@ -48,6 +49,8 @@ export interface CodemodeExtensionAPI {
|
|
|
48
49
|
registerRemovedToolHint(name: string, hint: string): void;
|
|
49
50
|
on(event: CodemodeEvent | "resources_discover", handler: (event: unknown, ctx: ExtensionContext) => unknown): void;
|
|
50
51
|
executeTool: AgentExecuteTool;
|
|
52
|
+
/** Present only while a live JavaScript eval owns the host-tool context. */
|
|
53
|
+
kernelTools?: KernelToolsCapability;
|
|
51
54
|
getActiveTools(): string[];
|
|
52
55
|
getAllTools(): readonly EvalSchemaToolInfo[];
|
|
53
56
|
sendMessage(
|
|
@@ -259,4 +262,11 @@ function modelIdFrom(event: unknown): string | undefined {
|
|
|
259
262
|
return typeof model.id === "string" ? model.id : undefined;
|
|
260
263
|
}
|
|
261
264
|
|
|
265
|
+
export {
|
|
266
|
+
KERNEL_TOOLS_UNSUPPORTED,
|
|
267
|
+
type KernelToolDescriptor,
|
|
268
|
+
type KernelToolsCapability,
|
|
269
|
+
type KernelToolsDescribeResult,
|
|
270
|
+
type KernelToolsInvokeRequest,
|
|
271
|
+
} from "./kernels/js/kernel-tools-types.ts";
|
|
262
272
|
export { enabledLanguagesFrom };
|
|
@@ -181,6 +181,51 @@ end
|
|
|
181
181
|
Base.getproperty(::SenpiToolProxy, name::Symbol) = SenpiToolCallable(string(name))
|
|
182
182
|
const tool = SenpiToolProxy()
|
|
183
183
|
|
|
184
|
+
struct SenpiBridgeError <: Exception
|
|
185
|
+
message::String
|
|
186
|
+
code::Union{String, Nothing}
|
|
187
|
+
end
|
|
188
|
+
Base.showerror(io::IO, error::SenpiBridgeError) = Base.print(io, error.message)
|
|
189
|
+
|
|
190
|
+
function senpi_workpool_call(args)
|
|
191
|
+
try
|
|
192
|
+
return tool.workpool(args)
|
|
193
|
+
catch error
|
|
194
|
+
if error isa SenpiBridgeError && error.code in ("unknown_tool", "inactive_tool")
|
|
195
|
+
throw(SenpiBridgeError("No active host workpool tool", "workpool_unavailable"))
|
|
196
|
+
end
|
|
197
|
+
rethrow()
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
struct SenpiWorkpool
|
|
202
|
+
pool_id::String
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
function Base.getproperty(pool::SenpiWorkpool, name::Symbol)
|
|
206
|
+
pool_id = getfield(pool, :pool_id)
|
|
207
|
+
name === :pool_id && return pool_id
|
|
208
|
+
name === :push && return items -> senpi_workpool_call(Dict("op" => "push", "pool_id" => pool_id, "items" => items))
|
|
209
|
+
name in (:close, :inspect, :cancel) && return () -> senpi_workpool_call(Dict("op" => string(name), "pool_id" => pool_id))
|
|
210
|
+
getfield(pool, name)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
function workpool(agent::AbstractDict, name::AbstractString; mode=nothing)
|
|
214
|
+
args = Dict{String, Any}("op" => "create", "agent" => agent, "name" => name)
|
|
215
|
+
mode !== nothing && (args["mode"] = mode)
|
|
216
|
+
result = senpi_workpool_call(args)
|
|
217
|
+
details = get(result, "details", nothing)
|
|
218
|
+
if details isa AbstractDict
|
|
219
|
+
error = get(details, "error", nothing)
|
|
220
|
+
error isa AbstractDict && throw(SenpiBridgeError(error["message"], error["code"]))
|
|
221
|
+
pool_id = get(details, "pool_id", nothing)
|
|
222
|
+
if get(result, "hasError", false) !== true && pool_id isa AbstractString && occursin(r"^wp_[0-9a-f]{32}$", pool_id)
|
|
223
|
+
return SenpiWorkpool(pool_id)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
throw(SenpiBridgeError("Host did not return a workpool identity", "workpool_unavailable"))
|
|
227
|
+
end
|
|
228
|
+
|
|
184
229
|
function completion(prompt::AbstractString; model="default", system=nothing, schema=nothing, kwargs...)
|
|
185
230
|
options = Dict{String, Any}("model" => model)
|
|
186
231
|
system !== nothing && (options["system"] = system)
|
|
@@ -225,6 +270,7 @@ function agent(prompt::AbstractString; agent="task", model=nothing, label=nothin
|
|
|
225
270
|
handle || return parsed
|
|
226
271
|
result = Dict{String, Any}("text" => text_value, "output" => text_value, "id" => get(record, "id", nothing), "agent" => get(record, "agent", agent))
|
|
227
272
|
result["handle"] = get(record, "handle", result["id"] === nothing ? nothing : "agent://" * string(result["id"]))
|
|
273
|
+
result["run_epoch"] = get(record, "run_epoch", nothing)
|
|
228
274
|
schema !== nothing && (result["data"] = parsed)
|
|
229
275
|
result
|
|
230
276
|
end
|
|
@@ -244,7 +244,7 @@ function senpi_bridge_request(path::String, payload)
|
|
|
244
244
|
parsed isa AbstractDict || error("Bridge returned invalid JSON")
|
|
245
245
|
get(parsed, "ok", false) === true && return get(parsed, "value", nothing)
|
|
246
246
|
failure = get(parsed, "error", parsed)
|
|
247
|
-
|
|
247
|
+
throw(SenpiBridgeError(failure isa AbstractDict ? string(get(failure, "message", failure)) : string(failure), failure isa AbstractDict ? get(failure, "code", nothing) : nothing))
|
|
248
248
|
finally
|
|
249
249
|
close(socket)
|
|
250
250
|
end
|
|
@@ -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";
|
|
@@ -36,6 +40,10 @@ export class JavaScriptKernel {
|
|
|
36
40
|
#recovery: Promise<void> | null = null;
|
|
37
41
|
#closePromise: Promise<void> | null = null;
|
|
38
42
|
readonly #runs = new JavaScriptRunQueue();
|
|
43
|
+
readonly #kernelTools = new KernelToolHostPump(
|
|
44
|
+
(message) => this.#slot.postMessage(message),
|
|
45
|
+
() => this.#lifecycle === "open" && this.#slot.present,
|
|
46
|
+
);
|
|
39
47
|
#timeout: NodeJS.Timeout | null = null;
|
|
40
48
|
#toolWaiters: Array<(message: ToolCallMessage) => void> = [];
|
|
41
49
|
#pendingToolCalls: ToolCallMessage[] = [];
|
|
@@ -56,6 +64,18 @@ export class JavaScriptKernel {
|
|
|
56
64
|
return this.#slot.mode;
|
|
57
65
|
}
|
|
58
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
|
+
|
|
59
79
|
async run(input: JavaScriptRunInput): Promise<ResultMessage> {
|
|
60
80
|
assertJavaScriptKernelOpen(this.#lifecycle, "run");
|
|
61
81
|
const promise = this.#runs.enqueue(input);
|
|
@@ -102,6 +122,7 @@ export class JavaScriptKernel {
|
|
|
102
122
|
this.#slot.postMessage({ type: "close" });
|
|
103
123
|
this.#lifecycle = "closing";
|
|
104
124
|
this.#runs.settleAll("JS kernel closed");
|
|
125
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JS kernel closed"));
|
|
105
126
|
this.#clearToolCalls();
|
|
106
127
|
const recovery = this.#recovery;
|
|
107
128
|
const closePromise = (async () => {
|
|
@@ -146,6 +167,11 @@ export class JavaScriptKernel {
|
|
|
146
167
|
if (next.input.timeoutMs) {
|
|
147
168
|
this.#timeout = setTimeout(() => void this.#timeoutActive(next), next.input.timeoutMs);
|
|
148
169
|
}
|
|
170
|
+
this.#slot.postMessage({
|
|
171
|
+
type: "kernel-tools-names",
|
|
172
|
+
hostToolNames: resolveKernelToolNameSource(this.#options.hostToolNames),
|
|
173
|
+
foreignLanguageNames: resolveKernelToolNameSource(this.#options.foreignLanguageNames),
|
|
174
|
+
});
|
|
149
175
|
this.#slot.postMessage({
|
|
150
176
|
type: "run",
|
|
151
177
|
cellId: next.input.cellId,
|
|
@@ -220,6 +246,7 @@ export class JavaScriptKernel {
|
|
|
220
246
|
}
|
|
221
247
|
|
|
222
248
|
#handleMessage(message: KernelToHostMessage): void {
|
|
249
|
+
if (this.#kernelTools.consume(message) && message.type !== "tool-call") return;
|
|
223
250
|
if (message.type === "status" && message.event.op === INTERRUPT_ACK_OP) {
|
|
224
251
|
this.#runs.active?.interruptAck?.resolve();
|
|
225
252
|
return;
|
|
@@ -253,6 +280,7 @@ export class JavaScriptKernel {
|
|
|
253
280
|
const active = this.#runs.active;
|
|
254
281
|
if (!active && this.#slot.startingUp) return;
|
|
255
282
|
this.#clearTimeout();
|
|
283
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", error.message));
|
|
256
284
|
if (active) {
|
|
257
285
|
this.#runs.releaseActive(active);
|
|
258
286
|
this.#runs.settle(active, {
|
|
@@ -290,6 +318,7 @@ export class JavaScriptKernel {
|
|
|
290
318
|
*/
|
|
291
319
|
async #terminate(): Promise<WorkerRetirement> {
|
|
292
320
|
this.#clearTimeout();
|
|
321
|
+
this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JavaScript worker reset"));
|
|
293
322
|
const retirement = await this.#slot.retire();
|
|
294
323
|
await this.#retireWorkerChildren();
|
|
295
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
|
+
}
|