la-machina-engine 0.3.0 → 0.4.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 +187 -0
- package/dist/index.cjs +770 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -4
- package/dist/index.d.ts +307 -4
- package/dist/index.js +765 -254
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,23 +24,23 @@ var init_esm_shims = __esm({
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
// src/orchestrator/types.ts
|
|
27
|
-
import { z as
|
|
27
|
+
import { z as z25 } from "zod";
|
|
28
28
|
var PlanStepSchema, PlanSchema;
|
|
29
29
|
var init_types = __esm({
|
|
30
30
|
"src/orchestrator/types.ts"() {
|
|
31
31
|
"use strict";
|
|
32
32
|
init_esm_shims();
|
|
33
|
-
PlanStepSchema =
|
|
34
|
-
id:
|
|
35
|
-
description:
|
|
36
|
-
action:
|
|
37
|
-
files:
|
|
38
|
-
spec:
|
|
39
|
-
dependsOn:
|
|
33
|
+
PlanStepSchema = z25.object({
|
|
34
|
+
id: z25.string().min(1),
|
|
35
|
+
description: z25.string().min(1),
|
|
36
|
+
action: z25.enum(["research", "implement", "verify", "review", "custom"]),
|
|
37
|
+
files: z25.array(z25.string()).optional(),
|
|
38
|
+
spec: z25.string().optional(),
|
|
39
|
+
dependsOn: z25.array(z25.string()).optional()
|
|
40
40
|
});
|
|
41
|
-
PlanSchema =
|
|
42
|
-
summary:
|
|
43
|
-
steps:
|
|
41
|
+
PlanSchema = z25.object({
|
|
42
|
+
summary: z25.string().min(1),
|
|
43
|
+
steps: z25.array(PlanStepSchema).min(1)
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
});
|
|
@@ -1014,6 +1014,42 @@ var LoggingConfigResolved = z.object({
|
|
|
1014
1014
|
level: LogLevelEnum,
|
|
1015
1015
|
sink: LogSinkSchema
|
|
1016
1016
|
}).strict();
|
|
1017
|
+
var ApiHttpMethodEnum = z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]);
|
|
1018
|
+
var ApiAuthSchema = z.discriminatedUnion("type", [
|
|
1019
|
+
z.object({ type: z.literal("none") }).strict(),
|
|
1020
|
+
z.object({ type: z.literal("bearer"), tokenRef: z.string().min(1) }).strict(),
|
|
1021
|
+
z.object({
|
|
1022
|
+
type: z.literal("header"),
|
|
1023
|
+
name: z.string().min(1),
|
|
1024
|
+
valueRef: z.string().min(1)
|
|
1025
|
+
}).strict(),
|
|
1026
|
+
z.object({
|
|
1027
|
+
type: z.literal("basic"),
|
|
1028
|
+
userRef: z.string().min(1),
|
|
1029
|
+
passRef: z.string().min(1)
|
|
1030
|
+
}).strict(),
|
|
1031
|
+
z.object({ type: z.literal("custom"), id: z.string().min(1) }).strict()
|
|
1032
|
+
]);
|
|
1033
|
+
var ApiServiceSchema = z.object({
|
|
1034
|
+
name: z.string().min(1),
|
|
1035
|
+
description: z.string().optional(),
|
|
1036
|
+
baseUrl: z.string().url(),
|
|
1037
|
+
auth: ApiAuthSchema.optional(),
|
|
1038
|
+
// Allow both strings and RegExp values via z.union — RegExp is
|
|
1039
|
+
// serialized as its source when cloned, so we accept both.
|
|
1040
|
+
allowedPaths: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
|
|
1041
|
+
allowedMethods: z.array(ApiHttpMethodEnum).optional(),
|
|
1042
|
+
defaultHeaders: z.record(z.string(), z.string()).optional(),
|
|
1043
|
+
maxBodyBytes: z.number().int().positive().optional()
|
|
1044
|
+
}).strict();
|
|
1045
|
+
var ApiConfigResolved = z.object({
|
|
1046
|
+
services: z.array(ApiServiceSchema),
|
|
1047
|
+
maxResponseBytes: z.number().int().positive().optional()
|
|
1048
|
+
}).strict();
|
|
1049
|
+
var RunnerConfigResolved = z.object({
|
|
1050
|
+
url: z.string().url(),
|
|
1051
|
+
secret: z.string().min(1, "runner.secret cannot be empty")
|
|
1052
|
+
}).strict();
|
|
1017
1053
|
var ResolvedConfigSchema = z.object({
|
|
1018
1054
|
model: ModelConfigResolved,
|
|
1019
1055
|
storage: StorageConfigResolved,
|
|
@@ -1029,7 +1065,9 @@ var ResolvedConfigSchema = z.object({
|
|
|
1029
1065
|
permissions: PermissionsConfigResolved,
|
|
1030
1066
|
compaction: CompactionConfigResolved,
|
|
1031
1067
|
coordinator: CoordinatorConfigResolved,
|
|
1032
|
-
orchestrator: OrchestratorConfigResolved
|
|
1068
|
+
orchestrator: OrchestratorConfigResolved,
|
|
1069
|
+
runner: RunnerConfigResolved.optional(),
|
|
1070
|
+
api: ApiConfigResolved.optional()
|
|
1033
1071
|
}).strict();
|
|
1034
1072
|
var R2ConfigUser = R2ConfigResolved.partial();
|
|
1035
1073
|
var ModelConfigUser = ModelConfigResolved.partial();
|
|
@@ -1070,6 +1108,8 @@ var McpConfigUser = z.object({
|
|
|
1070
1108
|
shutdownTimeoutMs: z.number().int().positive().optional()
|
|
1071
1109
|
}).strict();
|
|
1072
1110
|
var PermissionsConfigUser = PermissionsConfigResolved.partial();
|
|
1111
|
+
var RunnerConfigUser = RunnerConfigResolved;
|
|
1112
|
+
var ApiConfigUser = ApiConfigResolved.partial();
|
|
1073
1113
|
var CompactionConfigUser = CompactionConfigResolved.partial();
|
|
1074
1114
|
var CoordinatorConfigUser = CoordinatorConfigResolved.partial();
|
|
1075
1115
|
var OrchestratorConfigUser = OrchestratorConfigResolved.deepPartial();
|
|
@@ -1088,7 +1128,9 @@ var UserConfigSchema = z.object({
|
|
|
1088
1128
|
permissions: PermissionsConfigUser.optional(),
|
|
1089
1129
|
compaction: CompactionConfigUser.optional(),
|
|
1090
1130
|
coordinator: CoordinatorConfigUser.optional(),
|
|
1091
|
-
orchestrator: OrchestratorConfigUser.optional()
|
|
1131
|
+
orchestrator: OrchestratorConfigUser.optional(),
|
|
1132
|
+
runner: RunnerConfigUser.optional(),
|
|
1133
|
+
api: ApiConfigUser.optional()
|
|
1092
1134
|
}).strict();
|
|
1093
1135
|
|
|
1094
1136
|
// src/config/merge.ts
|
|
@@ -1133,10 +1175,36 @@ function deepMerge(base, override) {
|
|
|
1133
1175
|
}
|
|
1134
1176
|
return result;
|
|
1135
1177
|
}
|
|
1178
|
+
var API_RUNTIME_KEYS = ["env", "resolveAuth", "onRequest", "onResponse"];
|
|
1179
|
+
function splitApiRuntime(user) {
|
|
1180
|
+
const api = user.api;
|
|
1181
|
+
if (api === void 0) return { stripped: user, runtime: {} };
|
|
1182
|
+
const runtime = {};
|
|
1183
|
+
const schemaSafe = {};
|
|
1184
|
+
for (const [k, v] of Object.entries(api)) {
|
|
1185
|
+
if (API_RUNTIME_KEYS.includes(k)) {
|
|
1186
|
+
runtime[k] = v;
|
|
1187
|
+
} else {
|
|
1188
|
+
schemaSafe[k] = v;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
const clone = { ...user, api: schemaSafe };
|
|
1192
|
+
return { stripped: clone, runtime };
|
|
1193
|
+
}
|
|
1136
1194
|
function mergeConfig(user) {
|
|
1137
|
-
const
|
|
1195
|
+
const { stripped, runtime } = splitApiRuntime(user);
|
|
1196
|
+
const validatedUser = UserConfigSchema.parse(stripped);
|
|
1138
1197
|
const merged = deepMerge(DEFAULTS, validatedUser);
|
|
1139
|
-
|
|
1198
|
+
const resolved = ResolvedConfigSchema.parse(merged);
|
|
1199
|
+
if (resolved.api !== void 0 && Object.keys(runtime).length > 0) {
|
|
1200
|
+
const mutableResolved = resolved;
|
|
1201
|
+
mutableResolved.api = {
|
|
1202
|
+
...resolved.api,
|
|
1203
|
+
...runtime
|
|
1204
|
+
};
|
|
1205
|
+
} else if (Object.keys(runtime).length > 0) {
|
|
1206
|
+
}
|
|
1207
|
+
return resolved;
|
|
1140
1208
|
}
|
|
1141
1209
|
|
|
1142
1210
|
// src/engine/engine.ts
|
|
@@ -1585,8 +1653,8 @@ function toAISdkMessages(messages) {
|
|
|
1585
1653
|
textParts.push({ type: "text", text: block.text });
|
|
1586
1654
|
}
|
|
1587
1655
|
}
|
|
1588
|
-
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1589
1656
|
if (toolResults.length > 0) out.push({ role: "tool", content: toolResults });
|
|
1657
|
+
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1590
1658
|
} else if (role === "assistant") {
|
|
1591
1659
|
if (typeof content === "string") {
|
|
1592
1660
|
out.push({ role: "assistant", content });
|
|
@@ -1784,6 +1852,68 @@ function hasProcessLifecycle() {
|
|
|
1784
1852
|
return typeof process !== "undefined" && typeof process.on === "function" && typeof process.removeListener === "function" && detectRuntime() === "node";
|
|
1785
1853
|
}
|
|
1786
1854
|
|
|
1855
|
+
// src/tools/capabilityStub.ts
|
|
1856
|
+
init_esm_shims();
|
|
1857
|
+
import { z as z2 } from "zod";
|
|
1858
|
+
|
|
1859
|
+
// src/tools/contract.ts
|
|
1860
|
+
init_esm_shims();
|
|
1861
|
+
function defineTool(tool) {
|
|
1862
|
+
return tool;
|
|
1863
|
+
}
|
|
1864
|
+
var ToolRegistry = class {
|
|
1865
|
+
tools = /* @__PURE__ */ new Map();
|
|
1866
|
+
register(tool) {
|
|
1867
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) {
|
|
1868
|
+
throw new Error("ToolRegistry: tool.name must be a non-empty string");
|
|
1869
|
+
}
|
|
1870
|
+
if (this.tools.has(tool.name)) {
|
|
1871
|
+
throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
|
|
1872
|
+
}
|
|
1873
|
+
this.tools.set(tool.name, tool);
|
|
1874
|
+
}
|
|
1875
|
+
registerAll(tools) {
|
|
1876
|
+
for (const tool of tools) this.register(tool);
|
|
1877
|
+
}
|
|
1878
|
+
unregister(name) {
|
|
1879
|
+
this.tools.delete(name);
|
|
1880
|
+
}
|
|
1881
|
+
get(name) {
|
|
1882
|
+
return this.tools.get(name);
|
|
1883
|
+
}
|
|
1884
|
+
has(name) {
|
|
1885
|
+
return this.tools.has(name);
|
|
1886
|
+
}
|
|
1887
|
+
list() {
|
|
1888
|
+
return Array.from(this.tools.values());
|
|
1889
|
+
}
|
|
1890
|
+
count() {
|
|
1891
|
+
return this.tools.size;
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
|
|
1895
|
+
// src/tools/capabilityStub.ts
|
|
1896
|
+
var anyInput = z2.unknown();
|
|
1897
|
+
function capabilityStub(original) {
|
|
1898
|
+
return defineTool({
|
|
1899
|
+
name: original.name,
|
|
1900
|
+
description: original.description,
|
|
1901
|
+
inputSchema: anyInput,
|
|
1902
|
+
isCapabilityStub: true,
|
|
1903
|
+
execute: async () => ({
|
|
1904
|
+
isError: true,
|
|
1905
|
+
content: `Tool "${original.name}" requires Node runtime and cannot execute in this environment. To use this tool, run async via engine.start() with config.runner configured so the run can hand off to a Node runner. See README \xA7"Runner contract" for setup.`,
|
|
1906
|
+
metadata: { capabilityMissing: original.name }
|
|
1907
|
+
})
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
function withCapabilityCheck(tool, spawnAvailable) {
|
|
1911
|
+
if (tool.requiresNode === true && !spawnAvailable) {
|
|
1912
|
+
return capabilityStub(tool);
|
|
1913
|
+
}
|
|
1914
|
+
return tool;
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1787
1917
|
// src/subagent/registry.ts
|
|
1788
1918
|
init_esm_shims();
|
|
1789
1919
|
|
|
@@ -1966,7 +2096,7 @@ var SubagentRegistry = class _SubagentRegistry {
|
|
|
1966
2096
|
|
|
1967
2097
|
// src/tools/agent.ts
|
|
1968
2098
|
init_esm_shims();
|
|
1969
|
-
import { z as
|
|
2099
|
+
import { z as z6 } from "zod";
|
|
1970
2100
|
|
|
1971
2101
|
// src/subagent/runner.ts
|
|
1972
2102
|
init_esm_shims();
|
|
@@ -1977,48 +2107,49 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
1977
2107
|
|
|
1978
2108
|
// src/transcript/snapshot.ts
|
|
1979
2109
|
init_esm_shims();
|
|
1980
|
-
import { z as
|
|
2110
|
+
import { z as z3 } from "zod";
|
|
1981
2111
|
var SNAPSHOT_FILENAME = "snapshot.json";
|
|
1982
|
-
var TokenUsageSchema =
|
|
1983
|
-
input:
|
|
1984
|
-
output:
|
|
1985
|
-
cacheCreationInput:
|
|
1986
|
-
cacheReadInput:
|
|
2112
|
+
var TokenUsageSchema = z3.object({
|
|
2113
|
+
input: z3.number().int().nonnegative(),
|
|
2114
|
+
output: z3.number().int().nonnegative(),
|
|
2115
|
+
cacheCreationInput: z3.number().int().nonnegative().optional(),
|
|
2116
|
+
cacheReadInput: z3.number().int().nonnegative().optional()
|
|
1987
2117
|
}).strict();
|
|
1988
|
-
var PendingToolCallSchema =
|
|
1989
|
-
toolName:
|
|
1990
|
-
toolUseId:
|
|
1991
|
-
input:
|
|
1992
|
-
calledAt:
|
|
2118
|
+
var PendingToolCallSchema = z3.object({
|
|
2119
|
+
toolName: z3.string().min(1),
|
|
2120
|
+
toolUseId: z3.string().min(1),
|
|
2121
|
+
input: z3.unknown(),
|
|
2122
|
+
calledAt: z3.string().datetime({ offset: true })
|
|
1993
2123
|
}).strict();
|
|
1994
|
-
var PendingSubagentSchema =
|
|
1995
|
-
() =>
|
|
1996
|
-
subagentType:
|
|
1997
|
-
parentToolUseId:
|
|
2124
|
+
var PendingSubagentSchema = z3.lazy(
|
|
2125
|
+
() => z3.object({
|
|
2126
|
+
subagentType: z3.string().min(1),
|
|
2127
|
+
parentToolUseId: z3.string().min(1),
|
|
1998
2128
|
childSnapshot: RunSnapshotSchema
|
|
1999
2129
|
}).strict()
|
|
2000
2130
|
);
|
|
2001
|
-
var RunSnapshotSchema =
|
|
2002
|
-
() =>
|
|
2003
|
-
version:
|
|
2004
|
-
status:
|
|
2005
|
-
runId:
|
|
2006
|
-
nodeId:
|
|
2007
|
-
pausedAt:
|
|
2008
|
-
pauseReason:
|
|
2131
|
+
var RunSnapshotSchema = z3.lazy(
|
|
2132
|
+
() => z3.object({
|
|
2133
|
+
version: z3.literal(1),
|
|
2134
|
+
status: z3.literal("paused"),
|
|
2135
|
+
runId: z3.string().min(1),
|
|
2136
|
+
nodeId: z3.string().min(1),
|
|
2137
|
+
pausedAt: z3.string().datetime({ offset: true }),
|
|
2138
|
+
pauseReason: z3.enum([
|
|
2009
2139
|
"gate_required",
|
|
2010
2140
|
"subagent_gate_required",
|
|
2141
|
+
"handoff_to_runner",
|
|
2011
2142
|
"max_turns",
|
|
2012
2143
|
"explicit",
|
|
2013
2144
|
"timeout"
|
|
2014
2145
|
]),
|
|
2015
|
-
messageCount:
|
|
2016
|
-
lastShardIndex:
|
|
2017
|
-
lastMessageUuid:
|
|
2146
|
+
messageCount: z3.number().int().nonnegative(),
|
|
2147
|
+
lastShardIndex: z3.number().int().nonnegative(),
|
|
2148
|
+
lastMessageUuid: z3.string().uuid(),
|
|
2018
2149
|
pendingToolCall: PendingToolCallSchema.optional(),
|
|
2019
2150
|
pendingSubagent: PendingSubagentSchema.optional(),
|
|
2020
2151
|
tokensUsedSoFar: TokenUsageSchema,
|
|
2021
|
-
turnsUsed:
|
|
2152
|
+
turnsUsed: z3.number().int().nonnegative()
|
|
2022
2153
|
}).strict()
|
|
2023
2154
|
);
|
|
2024
2155
|
function snapshotPath(logPath) {
|
|
@@ -2746,6 +2877,27 @@ async function agentLoop(options) {
|
|
|
2746
2877
|
}
|
|
2747
2878
|
}
|
|
2748
2879
|
}
|
|
2880
|
+
if (options.handoffToRunner === true) {
|
|
2881
|
+
for (const call of toolCallsToDispatch) {
|
|
2882
|
+
const tool = options.registry?.get(call.name);
|
|
2883
|
+
if (tool?.isCapabilityStub === true) {
|
|
2884
|
+
const paused = await pauseHere({
|
|
2885
|
+
ctx,
|
|
2886
|
+
transcript,
|
|
2887
|
+
reason: "handoff_to_runner",
|
|
2888
|
+
pendingToolCall: {
|
|
2889
|
+
toolName: call.name,
|
|
2890
|
+
toolUseId: call.id,
|
|
2891
|
+
input: call.input,
|
|
2892
|
+
calledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2893
|
+
},
|
|
2894
|
+
storage: options.storage,
|
|
2895
|
+
subagentRegistry: options.subagentRegistry
|
|
2896
|
+
});
|
|
2897
|
+
return paused;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2749
2901
|
const firstTool = toolCallsToDispatch[0]?.name;
|
|
2750
2902
|
await fireProgress("tool_dispatch", firstTool);
|
|
2751
2903
|
const streamExec = new StreamingToolExecutor(executor);
|
|
@@ -2756,6 +2908,10 @@ async function agentLoop(options) {
|
|
|
2756
2908
|
}
|
|
2757
2909
|
try {
|
|
2758
2910
|
for await (const { id, result } of streamExec.results()) {
|
|
2911
|
+
const missing = result.metadata?.capabilityMissing;
|
|
2912
|
+
if (typeof missing === "string") {
|
|
2913
|
+
ctx.recordCapabilityMissing(missing);
|
|
2914
|
+
}
|
|
2759
2915
|
await ctx.addToolResult(id, truncateToolResult(result.content), result.isError === true);
|
|
2760
2916
|
}
|
|
2761
2917
|
} catch (err) {
|
|
@@ -3014,6 +3170,12 @@ var RunContext = class {
|
|
|
3014
3170
|
turnCount = 0;
|
|
3015
3171
|
tokensUsed = { input: 0, output: 0 };
|
|
3016
3172
|
lastUuid = null;
|
|
3173
|
+
/**
|
|
3174
|
+
* Plan 019 — names of tools whose capability-stub returned an
|
|
3175
|
+
* `isError` result during this run. Aggregated and surfaced on the
|
|
3176
|
+
* response's `meta.capabilitiesMissing` (deduped, insertion-ordered).
|
|
3177
|
+
*/
|
|
3178
|
+
capabilitiesMissing = /* @__PURE__ */ new Set();
|
|
3017
3179
|
constructor(options) {
|
|
3018
3180
|
this.runId = options.runId;
|
|
3019
3181
|
this.nodeId = options.nodeId;
|
|
@@ -3054,6 +3216,42 @@ var RunContext = class {
|
|
|
3054
3216
|
this.episodes.logTurn(this.turnCount, "assistant", summary);
|
|
3055
3217
|
}
|
|
3056
3218
|
}
|
|
3219
|
+
/**
|
|
3220
|
+
* Inject a tool_result + a follow-up text block as a SINGLE user
|
|
3221
|
+
* message. Used by the resume() synthetic-release path when a
|
|
3222
|
+
* paused run is resumed without an explicit `gateAnswer`: we need
|
|
3223
|
+
* to both satisfy the tool_use↔tool_result pairing AND give the
|
|
3224
|
+
* model a retry instruction, in the same user turn.
|
|
3225
|
+
*
|
|
3226
|
+
* Splitting this into `addToolResult(...) + addUserMessage(...)`
|
|
3227
|
+
* produces two consecutive user messages, which the AI SDK's
|
|
3228
|
+
* openai-compatible adapter rejects with
|
|
3229
|
+
* `MissingToolResultsError`. Combining them into one user message
|
|
3230
|
+
* is the portable shape that works on every provider we support.
|
|
3231
|
+
*
|
|
3232
|
+
* Writes a single `user` transcript entry carrying the mixed
|
|
3233
|
+
* content, so `rebuildMessagesFromEntries` reconstructs the same
|
|
3234
|
+
* single-message shape on resume.
|
|
3235
|
+
*/
|
|
3236
|
+
async addMixedUserMessage(blocks) {
|
|
3237
|
+
this.messages.push({ role: "user", content: blocks });
|
|
3238
|
+
await this.writeEntry({
|
|
3239
|
+
type: "user",
|
|
3240
|
+
uuid: this.nextUuid(),
|
|
3241
|
+
parentUuid: this.lastUuid,
|
|
3242
|
+
ts: this.now(),
|
|
3243
|
+
message: { role: "user", content: blocks }
|
|
3244
|
+
});
|
|
3245
|
+
const summary = blocks.map((b) => {
|
|
3246
|
+
const x = b;
|
|
3247
|
+
if (x.type === "text") return x.text ?? "";
|
|
3248
|
+
if (x.type === "tool_result") {
|
|
3249
|
+
return typeof x.content === "string" ? x.content : JSON.stringify(x.content);
|
|
3250
|
+
}
|
|
3251
|
+
return "";
|
|
3252
|
+
}).filter((s) => s.length > 0).join("\n");
|
|
3253
|
+
this.episodes?.logTurn(this.turnCount, "user", summary);
|
|
3254
|
+
}
|
|
3057
3255
|
/**
|
|
3058
3256
|
* Append a tool result to the conversation. The Anthropic Messages
|
|
3059
3257
|
* API requires tool_result blocks to be wrapped in a user message,
|
|
@@ -3099,6 +3297,14 @@ var RunContext = class {
|
|
|
3099
3297
|
getTokensUsed() {
|
|
3100
3298
|
return this.tokensUsed;
|
|
3101
3299
|
}
|
|
3300
|
+
/** Plan 019 — record that a capability-stubbed tool fired during this run. */
|
|
3301
|
+
recordCapabilityMissing(toolName) {
|
|
3302
|
+
this.capabilitiesMissing.add(toolName);
|
|
3303
|
+
}
|
|
3304
|
+
/** Plan 019 — capability-stubbed tool names observed this run (deduped). */
|
|
3305
|
+
getCapabilitiesMissing() {
|
|
3306
|
+
return [...this.capabilitiesMissing];
|
|
3307
|
+
}
|
|
3102
3308
|
shouldContinue() {
|
|
3103
3309
|
return this.turnCount < this.maxTurns;
|
|
3104
3310
|
}
|
|
@@ -3272,9 +3478,9 @@ init_esm_shims();
|
|
|
3272
3478
|
|
|
3273
3479
|
// src/transcript/entries.ts
|
|
3274
3480
|
init_esm_shims();
|
|
3275
|
-
import { z as
|
|
3276
|
-
var UuidSchema =
|
|
3277
|
-
var IsoTsSchema =
|
|
3481
|
+
import { z as z4 } from "zod";
|
|
3482
|
+
var UuidSchema = z4.string().uuid();
|
|
3483
|
+
var IsoTsSchema = z4.string().datetime({ offset: true });
|
|
3278
3484
|
var TimelineBase = {
|
|
3279
3485
|
uuid: UuidSchema,
|
|
3280
3486
|
parentUuid: UuidSchema.nullable(),
|
|
@@ -3284,55 +3490,55 @@ var SessionBase = {
|
|
|
3284
3490
|
uuid: UuidSchema,
|
|
3285
3491
|
ts: IsoTsSchema
|
|
3286
3492
|
};
|
|
3287
|
-
var MessageSchema =
|
|
3288
|
-
role:
|
|
3289
|
-
content:
|
|
3493
|
+
var MessageSchema = z4.object({
|
|
3494
|
+
role: z4.enum(["user", "assistant"]),
|
|
3495
|
+
content: z4.array(z4.unknown())
|
|
3290
3496
|
}).strict();
|
|
3291
|
-
var UserEntrySchema =
|
|
3292
|
-
type:
|
|
3497
|
+
var UserEntrySchema = z4.object({
|
|
3498
|
+
type: z4.literal("user"),
|
|
3293
3499
|
...TimelineBase,
|
|
3294
3500
|
message: MessageSchema
|
|
3295
3501
|
}).strict();
|
|
3296
|
-
var AssistantEntrySchema =
|
|
3297
|
-
type:
|
|
3502
|
+
var AssistantEntrySchema = z4.object({
|
|
3503
|
+
type: z4.literal("assistant"),
|
|
3298
3504
|
...TimelineBase,
|
|
3299
3505
|
message: MessageSchema
|
|
3300
3506
|
}).strict();
|
|
3301
|
-
var ToolResultEntrySchema =
|
|
3302
|
-
type:
|
|
3507
|
+
var ToolResultEntrySchema = z4.object({
|
|
3508
|
+
type: z4.literal("tool_result"),
|
|
3303
3509
|
...TimelineBase,
|
|
3304
|
-
toolUseId:
|
|
3305
|
-
content:
|
|
3306
|
-
isError:
|
|
3510
|
+
toolUseId: z4.string().min(1),
|
|
3511
|
+
content: z4.unknown(),
|
|
3512
|
+
isError: z4.boolean().optional()
|
|
3307
3513
|
}).strict();
|
|
3308
|
-
var SubagentSpawnEntrySchema =
|
|
3309
|
-
type:
|
|
3514
|
+
var SubagentSpawnEntrySchema = z4.object({
|
|
3515
|
+
type: z4.literal("subagent_spawn"),
|
|
3310
3516
|
...TimelineBase,
|
|
3311
|
-
agentId:
|
|
3312
|
-
agentType:
|
|
3517
|
+
agentId: z4.string().min(1),
|
|
3518
|
+
agentType: z4.string().min(1)
|
|
3313
3519
|
}).strict();
|
|
3314
|
-
var SubagentDoneEntrySchema =
|
|
3315
|
-
type:
|
|
3520
|
+
var SubagentDoneEntrySchema = z4.object({
|
|
3521
|
+
type: z4.literal("subagent_done"),
|
|
3316
3522
|
...TimelineBase,
|
|
3317
|
-
agentId:
|
|
3318
|
-
output:
|
|
3523
|
+
agentId: z4.string().min(1),
|
|
3524
|
+
output: z4.string()
|
|
3319
3525
|
}).strict();
|
|
3320
|
-
var MetaEntrySchema =
|
|
3321
|
-
type:
|
|
3526
|
+
var MetaEntrySchema = z4.object({
|
|
3527
|
+
type: z4.literal("meta"),
|
|
3322
3528
|
...SessionBase,
|
|
3323
|
-
key:
|
|
3324
|
-
value:
|
|
3529
|
+
key: z4.string().min(1),
|
|
3530
|
+
value: z4.unknown()
|
|
3325
3531
|
}).strict();
|
|
3326
|
-
var ErrorEntrySchema =
|
|
3327
|
-
type:
|
|
3532
|
+
var ErrorEntrySchema = z4.object({
|
|
3533
|
+
type: z4.literal("error"),
|
|
3328
3534
|
...SessionBase,
|
|
3329
|
-
error:
|
|
3330
|
-
code:
|
|
3331
|
-
message:
|
|
3332
|
-
stack:
|
|
3535
|
+
error: z4.object({
|
|
3536
|
+
code: z4.string().min(1),
|
|
3537
|
+
message: z4.string(),
|
|
3538
|
+
stack: z4.string().optional()
|
|
3333
3539
|
}).strict()
|
|
3334
3540
|
}).strict();
|
|
3335
|
-
var EntrySchema =
|
|
3541
|
+
var EntrySchema = z4.discriminatedUnion("type", [
|
|
3336
3542
|
UserEntrySchema,
|
|
3337
3543
|
AssistantEntrySchema,
|
|
3338
3544
|
ToolResultEntrySchema,
|
|
@@ -3364,16 +3570,16 @@ function parseEntryLine(line) {
|
|
|
3364
3570
|
|
|
3365
3571
|
// src/transcript/meta.ts
|
|
3366
3572
|
init_esm_shims();
|
|
3367
|
-
import { z as
|
|
3368
|
-
var TranscriptMetaSchema =
|
|
3369
|
-
version:
|
|
3370
|
-
status:
|
|
3371
|
-
startedAt:
|
|
3372
|
-
updatedAt:
|
|
3373
|
-
turnCount:
|
|
3374
|
-
messageCount:
|
|
3375
|
-
lastShardIndex:
|
|
3376
|
-
shardCount:
|
|
3573
|
+
import { z as z5 } from "zod";
|
|
3574
|
+
var TranscriptMetaSchema = z5.object({
|
|
3575
|
+
version: z5.literal(1),
|
|
3576
|
+
status: z5.enum(["pending", "running", "paused", "done", "failed"]),
|
|
3577
|
+
startedAt: z5.string().datetime({ offset: true }),
|
|
3578
|
+
updatedAt: z5.string().datetime({ offset: true }),
|
|
3579
|
+
turnCount: z5.number().int().nonnegative(),
|
|
3580
|
+
messageCount: z5.number().int().nonnegative(),
|
|
3581
|
+
lastShardIndex: z5.number().int().nonnegative().nullable(),
|
|
3582
|
+
shardCount: z5.number().int().nonnegative()
|
|
3377
3583
|
}).strict();
|
|
3378
3584
|
var META_FILENAME = "meta.json";
|
|
3379
3585
|
function metaPath(logPath) {
|
|
@@ -3721,47 +3927,11 @@ Output format:
|
|
|
3721
3927
|
Directive: ${directive}`;
|
|
3722
3928
|
}
|
|
3723
3929
|
|
|
3724
|
-
// src/tools/contract.ts
|
|
3725
|
-
init_esm_shims();
|
|
3726
|
-
function defineTool(tool) {
|
|
3727
|
-
return tool;
|
|
3728
|
-
}
|
|
3729
|
-
var ToolRegistry = class {
|
|
3730
|
-
tools = /* @__PURE__ */ new Map();
|
|
3731
|
-
register(tool) {
|
|
3732
|
-
if (typeof tool.name !== "string" || tool.name.length === 0) {
|
|
3733
|
-
throw new Error("ToolRegistry: tool.name must be a non-empty string");
|
|
3734
|
-
}
|
|
3735
|
-
if (this.tools.has(tool.name)) {
|
|
3736
|
-
throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
|
|
3737
|
-
}
|
|
3738
|
-
this.tools.set(tool.name, tool);
|
|
3739
|
-
}
|
|
3740
|
-
registerAll(tools) {
|
|
3741
|
-
for (const tool of tools) this.register(tool);
|
|
3742
|
-
}
|
|
3743
|
-
unregister(name) {
|
|
3744
|
-
this.tools.delete(name);
|
|
3745
|
-
}
|
|
3746
|
-
get(name) {
|
|
3747
|
-
return this.tools.get(name);
|
|
3748
|
-
}
|
|
3749
|
-
has(name) {
|
|
3750
|
-
return this.tools.has(name);
|
|
3751
|
-
}
|
|
3752
|
-
list() {
|
|
3753
|
-
return Array.from(this.tools.values());
|
|
3754
|
-
}
|
|
3755
|
-
count() {
|
|
3756
|
-
return this.tools.size;
|
|
3757
|
-
}
|
|
3758
|
-
};
|
|
3759
|
-
|
|
3760
3930
|
// src/tools/agent.ts
|
|
3761
|
-
var inputSchema =
|
|
3762
|
-
description:
|
|
3763
|
-
subagent_type:
|
|
3764
|
-
run_in_background:
|
|
3931
|
+
var inputSchema = z6.object({
|
|
3932
|
+
description: z6.string().min(1),
|
|
3933
|
+
subagent_type: z6.string().optional(),
|
|
3934
|
+
run_in_background: z6.boolean().optional()
|
|
3765
3935
|
});
|
|
3766
3936
|
function createAgentTool(options) {
|
|
3767
3937
|
if (options.agents.length === 0) {
|
|
@@ -3966,7 +4136,7 @@ function handlePausedResult(result, agentId, subagentType) {
|
|
|
3966
4136
|
|
|
3967
4137
|
// src/tools/bash.ts
|
|
3968
4138
|
init_esm_shims();
|
|
3969
|
-
import { z as
|
|
4139
|
+
import { z as z7 } from "zod";
|
|
3970
4140
|
var _spawn = null;
|
|
3971
4141
|
async function getSpawn() {
|
|
3972
4142
|
if (_spawn === null) {
|
|
@@ -3978,15 +4148,16 @@ async function getSpawn() {
|
|
|
3978
4148
|
var MAX_OUTPUT_BYTES = 512 * 1024;
|
|
3979
4149
|
var SIGKILL_GRACE_MS = 500;
|
|
3980
4150
|
var BLOCKED_DEVICE_PATHS = /\b(\/dev\/zero|\/dev\/random|\/dev\/urandom|\/proc\/kcore|\/dev\/sda|\/dev\/mem)\b/;
|
|
3981
|
-
var inputSchema2 =
|
|
3982
|
-
command:
|
|
3983
|
-
cwd:
|
|
4151
|
+
var inputSchema2 = z7.object({
|
|
4152
|
+
command: z7.string().min(1),
|
|
4153
|
+
cwd: z7.string().min(1).optional()
|
|
3984
4154
|
});
|
|
3985
4155
|
function createBashTool() {
|
|
3986
4156
|
return defineTool({
|
|
3987
4157
|
name: "Bash",
|
|
3988
4158
|
description: "Execute a shell command via /bin/sh -c. Returns combined stdout+stderr and the exit code.",
|
|
3989
4159
|
inputSchema: inputSchema2,
|
|
4160
|
+
requiresNode: true,
|
|
3990
4161
|
execute: async ({ command, cwd }, ctx) => {
|
|
3991
4162
|
if (BLOCKED_DEVICE_PATHS.test(command)) {
|
|
3992
4163
|
return {
|
|
@@ -4066,10 +4237,10 @@ function createBashTool() {
|
|
|
4066
4237
|
|
|
4067
4238
|
// src/tools/sendMessage.ts
|
|
4068
4239
|
init_esm_shims();
|
|
4069
|
-
import { z as
|
|
4070
|
-
var inputSchema3 =
|
|
4071
|
-
to:
|
|
4072
|
-
message:
|
|
4240
|
+
import { z as z8 } from "zod";
|
|
4241
|
+
var inputSchema3 = z8.object({
|
|
4242
|
+
to: z8.string().min(1).describe("Agent name (subagent_type) or agentId to send the message to."),
|
|
4243
|
+
message: z8.string().min(1).describe("Message content to deliver to the target agent.")
|
|
4073
4244
|
});
|
|
4074
4245
|
function createSendMessageTool(options) {
|
|
4075
4246
|
return defineTool({
|
|
@@ -4120,12 +4291,12 @@ function createSendMessageTool(options) {
|
|
|
4120
4291
|
|
|
4121
4292
|
// src/tools/fileEdit.ts
|
|
4122
4293
|
init_esm_shims();
|
|
4123
|
-
import { z as
|
|
4124
|
-
var inputSchema4 =
|
|
4125
|
-
path:
|
|
4126
|
-
old_string:
|
|
4127
|
-
new_string:
|
|
4128
|
-
replace_all:
|
|
4294
|
+
import { z as z9 } from "zod";
|
|
4295
|
+
var inputSchema4 = z9.object({
|
|
4296
|
+
path: z9.string().min(1),
|
|
4297
|
+
old_string: z9.string().min(1),
|
|
4298
|
+
new_string: z9.string(),
|
|
4299
|
+
replace_all: z9.boolean().optional()
|
|
4129
4300
|
});
|
|
4130
4301
|
function createFileEditTool(storage) {
|
|
4131
4302
|
return defineTool({
|
|
@@ -4209,13 +4380,13 @@ function normalizeQuotes(s) {
|
|
|
4209
4380
|
|
|
4210
4381
|
// src/tools/fileRead.ts
|
|
4211
4382
|
init_esm_shims();
|
|
4212
|
-
import { z as
|
|
4213
|
-
var inputSchema5 =
|
|
4214
|
-
path:
|
|
4215
|
-
offset:
|
|
4216
|
-
limit:
|
|
4383
|
+
import { z as z10 } from "zod";
|
|
4384
|
+
var inputSchema5 = z10.object({
|
|
4385
|
+
path: z10.string().min(1),
|
|
4386
|
+
offset: z10.number().int().positive().optional(),
|
|
4387
|
+
limit: z10.number().int().positive().optional(),
|
|
4217
4388
|
/** PDF page range, e.g. "1-5", "3", "10-20". Max 20 pages per request. */
|
|
4218
|
-
pages:
|
|
4389
|
+
pages: z10.string().optional()
|
|
4219
4390
|
});
|
|
4220
4391
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg"]);
|
|
4221
4392
|
var PDF_EXTENSION = ".pdf";
|
|
@@ -4383,7 +4554,7 @@ async function readImage(storage, filePath, ext) {
|
|
|
4383
4554
|
".svg": "image/svg+xml"
|
|
4384
4555
|
};
|
|
4385
4556
|
const mimeType = mimeMap[ext] ?? "application/octet-stream";
|
|
4386
|
-
const
|
|
4557
|
+
const base642 = buffer.toString("base64");
|
|
4387
4558
|
return {
|
|
4388
4559
|
content: `[Image: ${filePath} (${mimeType}, ${(buffer.length / 1024).toFixed(1)}KB)]
|
|
4389
4560
|
|
|
@@ -4392,17 +4563,17 @@ Base64 data is included in the metadata for visual analysis.`,
|
|
|
4392
4563
|
format: "image",
|
|
4393
4564
|
mimeType,
|
|
4394
4565
|
bytes: buffer.length,
|
|
4395
|
-
base64
|
|
4566
|
+
base64: base642
|
|
4396
4567
|
}
|
|
4397
4568
|
};
|
|
4398
4569
|
}
|
|
4399
4570
|
|
|
4400
4571
|
// src/tools/fileWrite.ts
|
|
4401
4572
|
init_esm_shims();
|
|
4402
|
-
import { z as
|
|
4403
|
-
var inputSchema6 =
|
|
4404
|
-
path:
|
|
4405
|
-
content:
|
|
4573
|
+
import { z as z11 } from "zod";
|
|
4574
|
+
var inputSchema6 = z11.object({
|
|
4575
|
+
path: z11.string().min(1),
|
|
4576
|
+
content: z11.string()
|
|
4406
4577
|
});
|
|
4407
4578
|
function createFileWriteTool(storageOrOptions) {
|
|
4408
4579
|
const opts = "readFile" in storageOrOptions ? { storage: storageOrOptions } : storageOrOptions;
|
|
@@ -4441,7 +4612,7 @@ function createFileWriteTool(storageOrOptions) {
|
|
|
4441
4612
|
// src/tools/glob.ts
|
|
4442
4613
|
init_esm_shims();
|
|
4443
4614
|
import picomatch from "picomatch";
|
|
4444
|
-
import { z as
|
|
4615
|
+
import { z as z12 } from "zod";
|
|
4445
4616
|
|
|
4446
4617
|
// src/tools/walkAdapter.ts
|
|
4447
4618
|
init_esm_shims();
|
|
@@ -4478,9 +4649,9 @@ async function* walkAdapter(adapter, startPath, options = {}) {
|
|
|
4478
4649
|
}
|
|
4479
4650
|
|
|
4480
4651
|
// src/tools/glob.ts
|
|
4481
|
-
var inputSchema7 =
|
|
4482
|
-
pattern:
|
|
4483
|
-
path:
|
|
4652
|
+
var inputSchema7 = z12.object({
|
|
4653
|
+
pattern: z12.string().min(1),
|
|
4654
|
+
path: z12.string().optional()
|
|
4484
4655
|
});
|
|
4485
4656
|
var MAX_RESULTS = 1e3;
|
|
4486
4657
|
function createGlobTool(storage) {
|
|
@@ -4533,22 +4704,22 @@ function createGlobTool(storage) {
|
|
|
4533
4704
|
// src/tools/grep.ts
|
|
4534
4705
|
init_esm_shims();
|
|
4535
4706
|
import picomatch2 from "picomatch";
|
|
4536
|
-
import { z as
|
|
4537
|
-
var inputSchema8 =
|
|
4538
|
-
pattern:
|
|
4539
|
-
path:
|
|
4540
|
-
glob:
|
|
4541
|
-
type:
|
|
4542
|
-
output_mode:
|
|
4543
|
-
"-i":
|
|
4544
|
-
"-n":
|
|
4545
|
-
"-A":
|
|
4546
|
-
"-B":
|
|
4547
|
-
"-C":
|
|
4548
|
-
context:
|
|
4549
|
-
multiline:
|
|
4550
|
-
head_limit:
|
|
4551
|
-
offset:
|
|
4707
|
+
import { z as z13 } from "zod";
|
|
4708
|
+
var inputSchema8 = z13.object({
|
|
4709
|
+
pattern: z13.string().min(1),
|
|
4710
|
+
path: z13.string().optional(),
|
|
4711
|
+
glob: z13.string().optional(),
|
|
4712
|
+
type: z13.string().optional(),
|
|
4713
|
+
output_mode: z13.enum(["content", "files_with_matches", "count"]).optional(),
|
|
4714
|
+
"-i": z13.boolean().optional(),
|
|
4715
|
+
"-n": z13.boolean().optional(),
|
|
4716
|
+
"-A": z13.number().int().nonnegative().optional(),
|
|
4717
|
+
"-B": z13.number().int().nonnegative().optional(),
|
|
4718
|
+
"-C": z13.number().int().nonnegative().optional(),
|
|
4719
|
+
context: z13.number().int().nonnegative().optional(),
|
|
4720
|
+
multiline: z13.boolean().optional(),
|
|
4721
|
+
head_limit: z13.number().int().nonnegative().optional(),
|
|
4722
|
+
offset: z13.number().int().nonnegative().optional()
|
|
4552
4723
|
});
|
|
4553
4724
|
var MAX_FILES_SCANNED = 5e3;
|
|
4554
4725
|
var MAX_MATCHES_PER_FILE = 100;
|
|
@@ -4772,10 +4943,10 @@ function formatJsResults(results, mode, limit) {
|
|
|
4772
4943
|
|
|
4773
4944
|
// src/tools/webFetch.ts
|
|
4774
4945
|
init_esm_shims();
|
|
4775
|
-
import { z as
|
|
4776
|
-
var inputSchema9 =
|
|
4777
|
-
url:
|
|
4778
|
-
prompt:
|
|
4946
|
+
import { z as z14 } from "zod";
|
|
4947
|
+
var inputSchema9 = z14.object({
|
|
4948
|
+
url: z14.string().url(),
|
|
4949
|
+
prompt: z14.string().optional()
|
|
4779
4950
|
});
|
|
4780
4951
|
var MAX_OUTPUT_BYTES2 = 256 * 1024;
|
|
4781
4952
|
function createWebFetchTool(options = {}) {
|
|
@@ -4904,10 +5075,10 @@ function normalizePath(p) {
|
|
|
4904
5075
|
|
|
4905
5076
|
// src/tools/webSearch.ts
|
|
4906
5077
|
init_esm_shims();
|
|
4907
|
-
import { z as
|
|
4908
|
-
var inputSchema10 =
|
|
4909
|
-
query:
|
|
4910
|
-
max_results:
|
|
5078
|
+
import { z as z15 } from "zod";
|
|
5079
|
+
var inputSchema10 = z15.object({
|
|
5080
|
+
query: z15.string().min(2),
|
|
5081
|
+
max_results: z15.number().int().positive().optional()
|
|
4911
5082
|
});
|
|
4912
5083
|
function createWebSearchTool() {
|
|
4913
5084
|
return defineTool({
|
|
@@ -4964,10 +5135,10 @@ function htmlToText2(html) {
|
|
|
4964
5135
|
|
|
4965
5136
|
// src/tools/sleep.ts
|
|
4966
5137
|
init_esm_shims();
|
|
4967
|
-
import { z as
|
|
4968
|
-
var inputSchema11 =
|
|
4969
|
-
durationMs:
|
|
4970
|
-
reason:
|
|
5138
|
+
import { z as z16 } from "zod";
|
|
5139
|
+
var inputSchema11 = z16.object({
|
|
5140
|
+
durationMs: z16.number().int().nonnegative().max(3e5),
|
|
5141
|
+
reason: z16.string().optional()
|
|
4971
5142
|
});
|
|
4972
5143
|
function createSleepTool() {
|
|
4973
5144
|
return defineTool({
|
|
@@ -5007,10 +5178,10 @@ function createSleepTool() {
|
|
|
5007
5178
|
|
|
5008
5179
|
// src/tools/toolSearch.ts
|
|
5009
5180
|
init_esm_shims();
|
|
5010
|
-
import { z as
|
|
5011
|
-
var inputSchema12 =
|
|
5012
|
-
query:
|
|
5013
|
-
max_results:
|
|
5181
|
+
import { z as z17 } from "zod";
|
|
5182
|
+
var inputSchema12 = z17.object({
|
|
5183
|
+
query: z17.string().min(1),
|
|
5184
|
+
max_results: z17.number().int().positive().optional()
|
|
5014
5185
|
});
|
|
5015
5186
|
function createToolSearchTool(registry) {
|
|
5016
5187
|
return defineTool({
|
|
@@ -5053,11 +5224,11 @@ ${lines.join("\n")}`,
|
|
|
5053
5224
|
|
|
5054
5225
|
// src/tools/memorize.ts
|
|
5055
5226
|
init_esm_shims();
|
|
5056
|
-
import { z as
|
|
5057
|
-
var inputSchema13 =
|
|
5058
|
-
text:
|
|
5059
|
-
kind:
|
|
5060
|
-
topic:
|
|
5227
|
+
import { z as z18 } from "zod";
|
|
5228
|
+
var inputSchema13 = z18.object({
|
|
5229
|
+
text: z18.string().min(1),
|
|
5230
|
+
kind: z18.enum(["rule", "lesson"]).default("lesson"),
|
|
5231
|
+
topic: z18.string().optional()
|
|
5061
5232
|
});
|
|
5062
5233
|
function createMemorizeTool(memory) {
|
|
5063
5234
|
return defineTool({
|
|
@@ -5089,11 +5260,11 @@ function createMemorizeTool(memory) {
|
|
|
5089
5260
|
|
|
5090
5261
|
// src/tools/recall.ts
|
|
5091
5262
|
init_esm_shims();
|
|
5092
|
-
import { z as
|
|
5093
|
-
var inputSchema14 =
|
|
5094
|
-
query:
|
|
5095
|
-
scope:
|
|
5096
|
-
topic:
|
|
5263
|
+
import { z as z19 } from "zod";
|
|
5264
|
+
var inputSchema14 = z19.object({
|
|
5265
|
+
query: z19.string().min(1),
|
|
5266
|
+
scope: z19.enum(["identity", "rules", "lessons", "all"]).default("all"),
|
|
5267
|
+
topic: z19.string().optional()
|
|
5097
5268
|
});
|
|
5098
5269
|
function createRecallTool(memory) {
|
|
5099
5270
|
return defineTool({
|
|
@@ -5148,13 +5319,13 @@ ${content}`,
|
|
|
5148
5319
|
|
|
5149
5320
|
// src/tools/notebookEdit.ts
|
|
5150
5321
|
init_esm_shims();
|
|
5151
|
-
import { z as
|
|
5152
|
-
var inputSchema15 =
|
|
5153
|
-
notebook_path:
|
|
5154
|
-
edit_mode:
|
|
5155
|
-
cell_index:
|
|
5156
|
-
new_source:
|
|
5157
|
-
cell_type:
|
|
5322
|
+
import { z as z20 } from "zod";
|
|
5323
|
+
var inputSchema15 = z20.object({
|
|
5324
|
+
notebook_path: z20.string().min(1),
|
|
5325
|
+
edit_mode: z20.enum(["replace", "insert", "delete"]).default("replace"),
|
|
5326
|
+
cell_index: z20.number().int().nonnegative(),
|
|
5327
|
+
new_source: z20.string().optional(),
|
|
5328
|
+
cell_type: z20.enum(["code", "markdown"]).optional()
|
|
5158
5329
|
});
|
|
5159
5330
|
function createNotebookEditTool(storage) {
|
|
5160
5331
|
return defineTool({
|
|
@@ -5309,12 +5480,12 @@ var TaskStore = class {
|
|
|
5309
5480
|
|
|
5310
5481
|
// src/tools/tasks/tools.ts
|
|
5311
5482
|
init_esm_shims();
|
|
5312
|
-
import { z as
|
|
5313
|
-
var TaskStatusEnum =
|
|
5314
|
-
var createSchema =
|
|
5315
|
-
subject:
|
|
5316
|
-
description:
|
|
5317
|
-
metadata:
|
|
5483
|
+
import { z as z21 } from "zod";
|
|
5484
|
+
var TaskStatusEnum = z21.enum(["pending", "in_progress", "completed", "deleted"]);
|
|
5485
|
+
var createSchema = z21.object({
|
|
5486
|
+
subject: z21.string().min(1),
|
|
5487
|
+
description: z21.string().default(""),
|
|
5488
|
+
metadata: z21.record(z21.unknown()).optional()
|
|
5318
5489
|
});
|
|
5319
5490
|
function createTaskCreateTool(store) {
|
|
5320
5491
|
return defineTool({
|
|
@@ -5330,8 +5501,8 @@ function createTaskCreateTool(store) {
|
|
|
5330
5501
|
}
|
|
5331
5502
|
});
|
|
5332
5503
|
}
|
|
5333
|
-
var getSchema =
|
|
5334
|
-
taskId:
|
|
5504
|
+
var getSchema = z21.object({
|
|
5505
|
+
taskId: z21.string().min(1)
|
|
5335
5506
|
});
|
|
5336
5507
|
function createTaskGetTool(store) {
|
|
5337
5508
|
return defineTool({
|
|
@@ -5352,7 +5523,7 @@ ${task.description}`,
|
|
|
5352
5523
|
}
|
|
5353
5524
|
});
|
|
5354
5525
|
}
|
|
5355
|
-
var listSchema =
|
|
5526
|
+
var listSchema = z21.object({
|
|
5356
5527
|
status: TaskStatusEnum.optional()
|
|
5357
5528
|
});
|
|
5358
5529
|
function createTaskListTool(store) {
|
|
@@ -5378,12 +5549,12 @@ ${lines.join("\n")}`,
|
|
|
5378
5549
|
}
|
|
5379
5550
|
});
|
|
5380
5551
|
}
|
|
5381
|
-
var updateSchema =
|
|
5382
|
-
taskId:
|
|
5383
|
-
subject:
|
|
5552
|
+
var updateSchema = z21.object({
|
|
5553
|
+
taskId: z21.string().min(1),
|
|
5554
|
+
subject: z21.string().min(1).optional(),
|
|
5384
5555
|
status: TaskStatusEnum.optional(),
|
|
5385
|
-
description:
|
|
5386
|
-
metadata:
|
|
5556
|
+
description: z21.string().optional(),
|
|
5557
|
+
metadata: z21.record(z21.unknown()).optional()
|
|
5387
5558
|
});
|
|
5388
5559
|
function createTaskUpdateTool(store) {
|
|
5389
5560
|
return defineTool({
|
|
@@ -6232,7 +6403,7 @@ function wrapFetchWithHeadersProvider(baseFetch, headersProvider, staticHeaders)
|
|
|
6232
6403
|
|
|
6233
6404
|
// src/mcp/toolAdapter.ts
|
|
6234
6405
|
init_esm_shims();
|
|
6235
|
-
import { z as
|
|
6406
|
+
import { z as z22 } from "zod";
|
|
6236
6407
|
function mcpToolName(serverName, toolName) {
|
|
6237
6408
|
return `mcp__${serverName}__${toolName}`;
|
|
6238
6409
|
}
|
|
@@ -6241,7 +6412,7 @@ function adaptMcpTool(client, serverName, def) {
|
|
|
6241
6412
|
return defineTool({
|
|
6242
6413
|
name: registeredName,
|
|
6243
6414
|
description: def.description.length > 0 ? def.description : `MCP tool ${serverName}/${def.name}`,
|
|
6244
|
-
inputSchema:
|
|
6415
|
+
inputSchema: z22.unknown(),
|
|
6245
6416
|
// Pass the MCP server's JSON Schema through to Anthropic verbatim,
|
|
6246
6417
|
// bypassing Zod-to-JSON-Schema conversion (which would produce `{}`
|
|
6247
6418
|
// for our `z.unknown()` Zod schema).
|
|
@@ -7350,11 +7521,11 @@ ${issues.join("\n")}` };
|
|
|
7350
7521
|
|
|
7351
7522
|
// src/skills/skillPage.ts
|
|
7352
7523
|
init_esm_shims();
|
|
7353
|
-
import { z as
|
|
7524
|
+
import { z as z23 } from "zod";
|
|
7354
7525
|
var SAFE_NAME3 = /^[a-zA-Z0-9_-]+$/;
|
|
7355
|
-
var inputSchema16 =
|
|
7356
|
-
skill:
|
|
7357
|
-
page:
|
|
7526
|
+
var inputSchema16 = z23.object({
|
|
7527
|
+
skill: z23.string().min(1),
|
|
7528
|
+
page: z23.string().min(1).optional()
|
|
7358
7529
|
});
|
|
7359
7530
|
function createSkillPageTool(options) {
|
|
7360
7531
|
return defineTool({
|
|
@@ -7410,6 +7581,203 @@ The skill "${skill}" has no pages.`;
|
|
|
7410
7581
|
});
|
|
7411
7582
|
}
|
|
7412
7583
|
|
|
7584
|
+
// src/tools/apiCall.ts
|
|
7585
|
+
init_esm_shims();
|
|
7586
|
+
import { z as z24 } from "zod";
|
|
7587
|
+
var ALL_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
7588
|
+
var DEFAULT_MAX_BODY_BYTES = 256 * 1024;
|
|
7589
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024;
|
|
7590
|
+
function createApiCallTool(opts) {
|
|
7591
|
+
if (opts.services.length === 0) {
|
|
7592
|
+
throw new Error("createApiCallTool: services list must be non-empty");
|
|
7593
|
+
}
|
|
7594
|
+
const services = /* @__PURE__ */ new Map();
|
|
7595
|
+
for (const svc of opts.services) {
|
|
7596
|
+
if (services.has(svc.name)) {
|
|
7597
|
+
throw new Error(`createApiCallTool: duplicate service name "${svc.name}"`);
|
|
7598
|
+
}
|
|
7599
|
+
services.set(svc.name, svc);
|
|
7600
|
+
}
|
|
7601
|
+
const serviceNames = [...services.keys()];
|
|
7602
|
+
for (const svc of opts.services) {
|
|
7603
|
+
if (svc.auth?.type === "custom" && opts.resolveAuth === void 0) {
|
|
7604
|
+
throw new Error(
|
|
7605
|
+
`createApiCallTool: service "${svc.name}" uses custom auth (id: ${svc.auth.id}) but no resolveAuth was supplied`
|
|
7606
|
+
);
|
|
7607
|
+
}
|
|
7608
|
+
}
|
|
7609
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
7610
|
+
const maxResponseBytes = opts.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
7611
|
+
const inputSchema17 = z24.object({
|
|
7612
|
+
service: z24.enum(serviceNames),
|
|
7613
|
+
method: z24.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
7614
|
+
path: z24.string().regex(/^\//, "path must start with /"),
|
|
7615
|
+
query: z24.record(z24.string(), z24.string()).optional(),
|
|
7616
|
+
body: z24.unknown().optional(),
|
|
7617
|
+
headers: z24.record(z24.string(), z24.string()).optional()
|
|
7618
|
+
});
|
|
7619
|
+
const description = opts.toolDescription ?? `Call a configured external API. Services: ${serviceNames.join(", ")}. Auth is injected automatically \u2014 do not pass credentials via headers.`;
|
|
7620
|
+
return defineTool({
|
|
7621
|
+
name: opts.toolName ?? "ApiCall",
|
|
7622
|
+
description,
|
|
7623
|
+
inputSchema: inputSchema17,
|
|
7624
|
+
execute: async (input) => {
|
|
7625
|
+
const svc = services.get(input.service);
|
|
7626
|
+
if (!svc) {
|
|
7627
|
+
return errResult(`ERR_API_UNKNOWN_SERVICE: ${input.service}`);
|
|
7628
|
+
}
|
|
7629
|
+
const allowedMethods = svc.allowedMethods ?? ALL_METHODS;
|
|
7630
|
+
if (!allowedMethods.includes(input.method)) {
|
|
7631
|
+
return errResult(
|
|
7632
|
+
`ERR_API_METHOD_NOT_ALLOWED: ${input.method} not permitted for service ${svc.name}`
|
|
7633
|
+
);
|
|
7634
|
+
}
|
|
7635
|
+
if (!pathAllowed(input.path, svc.allowedPaths)) {
|
|
7636
|
+
return errResult(`ERR_API_PATH_NOT_ALLOWED: ${input.path} for service ${svc.name}`);
|
|
7637
|
+
}
|
|
7638
|
+
let bodyText;
|
|
7639
|
+
if (input.body !== void 0) {
|
|
7640
|
+
bodyText = JSON.stringify(input.body);
|
|
7641
|
+
const cap = svc.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
7642
|
+
if (byteLength(bodyText) > cap) {
|
|
7643
|
+
return errResult(`ERR_API_BODY_TOO_LARGE: exceeds ${cap} bytes`);
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
let authHeaders;
|
|
7647
|
+
try {
|
|
7648
|
+
authHeaders = await resolveAuth({
|
|
7649
|
+
auth: svc.auth ?? { type: "none" },
|
|
7650
|
+
env: opts.env,
|
|
7651
|
+
resolver: opts.resolveAuth,
|
|
7652
|
+
ctx: { serviceName: svc.name, method: input.method, path: input.path }
|
|
7653
|
+
});
|
|
7654
|
+
} catch (err) {
|
|
7655
|
+
const raw2 = err instanceof Error ? err.message : String(err);
|
|
7656
|
+
const truncated = raw2.length > 200 ? raw2.slice(0, 200) + "\u2026" : raw2;
|
|
7657
|
+
return errResult(`ERR_API_RESOLVER_FAILED: ${truncated}`);
|
|
7658
|
+
}
|
|
7659
|
+
const userHeaders = sanitizeHeaders(input.headers ?? {}, authHeaders);
|
|
7660
|
+
const url = buildUrl(svc.baseUrl, input.path, input.query);
|
|
7661
|
+
await invokeHook(opts.onRequest, {
|
|
7662
|
+
service: svc.name,
|
|
7663
|
+
method: input.method,
|
|
7664
|
+
path: input.path
|
|
7665
|
+
});
|
|
7666
|
+
const started = Date.now();
|
|
7667
|
+
let res;
|
|
7668
|
+
try {
|
|
7669
|
+
res = await fetchFn(url, {
|
|
7670
|
+
method: input.method,
|
|
7671
|
+
headers: {
|
|
7672
|
+
"Content-Type": "application/json",
|
|
7673
|
+
...svc.defaultHeaders ?? {},
|
|
7674
|
+
...userHeaders,
|
|
7675
|
+
...authHeaders
|
|
7676
|
+
// wins last — model cannot override
|
|
7677
|
+
},
|
|
7678
|
+
...bodyText !== void 0 ? { body: bodyText } : {}
|
|
7679
|
+
});
|
|
7680
|
+
} catch (err) {
|
|
7681
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7682
|
+
return errResult(`network error: ${msg}`);
|
|
7683
|
+
}
|
|
7684
|
+
const raw = await res.text();
|
|
7685
|
+
const content = raw.length > maxResponseBytes ? raw.slice(0, maxResponseBytes) + "\n\u2026[TRUNCATED]" : raw;
|
|
7686
|
+
await invokeHook(opts.onResponse, {
|
|
7687
|
+
service: svc.name,
|
|
7688
|
+
method: input.method,
|
|
7689
|
+
path: input.path,
|
|
7690
|
+
status: res.status,
|
|
7691
|
+
latencyMs: Date.now() - started,
|
|
7692
|
+
bytesIn: raw.length
|
|
7693
|
+
});
|
|
7694
|
+
return {
|
|
7695
|
+
content,
|
|
7696
|
+
isError: !res.ok,
|
|
7697
|
+
metadata: { status: res.status, service: svc.name }
|
|
7698
|
+
};
|
|
7699
|
+
}
|
|
7700
|
+
});
|
|
7701
|
+
}
|
|
7702
|
+
function errResult(msg) {
|
|
7703
|
+
return { content: msg, isError: true };
|
|
7704
|
+
}
|
|
7705
|
+
function pathAllowed(path2, allowed) {
|
|
7706
|
+
if (!allowed || allowed.length === 0) return true;
|
|
7707
|
+
for (const a of allowed) {
|
|
7708
|
+
if (typeof a === "string") {
|
|
7709
|
+
if (path2.startsWith(a)) return true;
|
|
7710
|
+
} else if (a.test(path2)) {
|
|
7711
|
+
return true;
|
|
7712
|
+
}
|
|
7713
|
+
}
|
|
7714
|
+
return false;
|
|
7715
|
+
}
|
|
7716
|
+
function byteLength(s) {
|
|
7717
|
+
return new TextEncoder().encode(s).byteLength;
|
|
7718
|
+
}
|
|
7719
|
+
function buildUrl(baseUrl, path2, query) {
|
|
7720
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
7721
|
+
const url = new URL(base + path2);
|
|
7722
|
+
for (const [k, v] of Object.entries(query ?? {})) {
|
|
7723
|
+
url.searchParams.set(k, v);
|
|
7724
|
+
}
|
|
7725
|
+
return url.toString();
|
|
7726
|
+
}
|
|
7727
|
+
function sanitizeHeaders(user, auth) {
|
|
7728
|
+
const banned = new Set(Object.keys(auth).map((k) => k.toLowerCase()));
|
|
7729
|
+
const out = {};
|
|
7730
|
+
for (const [k, v] of Object.entries(user)) {
|
|
7731
|
+
if (banned.has(k.toLowerCase())) continue;
|
|
7732
|
+
out[k] = v;
|
|
7733
|
+
}
|
|
7734
|
+
return out;
|
|
7735
|
+
}
|
|
7736
|
+
async function resolveAuth(args) {
|
|
7737
|
+
const { auth, env, resolver, ctx } = args;
|
|
7738
|
+
switch (auth.type) {
|
|
7739
|
+
case "none":
|
|
7740
|
+
return {};
|
|
7741
|
+
case "bearer": {
|
|
7742
|
+
const token = envLookup(env, auth.tokenRef);
|
|
7743
|
+
return { Authorization: `Bearer ${token}` };
|
|
7744
|
+
}
|
|
7745
|
+
case "header": {
|
|
7746
|
+
const value = envLookup(env, auth.valueRef);
|
|
7747
|
+
return { [auth.name]: value };
|
|
7748
|
+
}
|
|
7749
|
+
case "basic": {
|
|
7750
|
+
const u = envLookup(env, auth.userRef);
|
|
7751
|
+
const p = envLookup(env, auth.passRef);
|
|
7752
|
+
return { Authorization: `Basic ${base64(`${u}:${p}`)}` };
|
|
7753
|
+
}
|
|
7754
|
+
case "custom":
|
|
7755
|
+
if (resolver === void 0) {
|
|
7756
|
+
throw new Error(`custom auth id "${auth.id}" requires resolveAuth`);
|
|
7757
|
+
}
|
|
7758
|
+
return resolver(auth, ctx);
|
|
7759
|
+
}
|
|
7760
|
+
}
|
|
7761
|
+
function envLookup(env, ref) {
|
|
7762
|
+
if (env === void 0 || env[ref] === void 0) {
|
|
7763
|
+
throw new Error(`ERR_API_ENV_MISSING: ${ref}`);
|
|
7764
|
+
}
|
|
7765
|
+
return env[ref];
|
|
7766
|
+
}
|
|
7767
|
+
function base64(input) {
|
|
7768
|
+
if (typeof globalThis.btoa === "function") {
|
|
7769
|
+
return globalThis.btoa(input);
|
|
7770
|
+
}
|
|
7771
|
+
return Buffer.from(input, "utf8").toString("base64");
|
|
7772
|
+
}
|
|
7773
|
+
async function invokeHook(hook, event) {
|
|
7774
|
+
if (hook === void 0) return;
|
|
7775
|
+
try {
|
|
7776
|
+
await hook(event);
|
|
7777
|
+
} catch {
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7780
|
+
|
|
7413
7781
|
// src/skills/storageSkillSource.ts
|
|
7414
7782
|
init_esm_shims();
|
|
7415
7783
|
var SAFE_NAME4 = /^[a-zA-Z0-9_-]+$/;
|
|
@@ -8192,6 +8560,7 @@ function rebuildMessagesFromEntries(entries) {
|
|
|
8192
8560
|
init_esm_shims();
|
|
8193
8561
|
function toResponse(result, extra) {
|
|
8194
8562
|
const timestamp = Date.now();
|
|
8563
|
+
const capsField = extra.capabilitiesMissing !== void 0 && extra.capabilitiesMissing.length > 0 ? { capabilitiesMissing: extra.capabilitiesMissing } : {};
|
|
8195
8564
|
if (result.status === "done") {
|
|
8196
8565
|
return {
|
|
8197
8566
|
runId: extra.runId,
|
|
@@ -8203,7 +8572,8 @@ function toResponse(result, extra) {
|
|
|
8203
8572
|
tokensUsed: result.tokensUsed,
|
|
8204
8573
|
durationMs: extra.durationMs,
|
|
8205
8574
|
output: result.output,
|
|
8206
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {}
|
|
8575
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {},
|
|
8576
|
+
...capsField
|
|
8207
8577
|
},
|
|
8208
8578
|
errors: [],
|
|
8209
8579
|
timestamp
|
|
@@ -8222,7 +8592,8 @@ function toResponse(result, extra) {
|
|
|
8222
8592
|
snapshot: result.snapshot,
|
|
8223
8593
|
...result.snapshot.pendingToolCall !== void 0 ? { pendingToolCall: result.snapshot.pendingToolCall } : {},
|
|
8224
8594
|
pauseReason: result.reason,
|
|
8225
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {}
|
|
8595
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {},
|
|
8596
|
+
...capsField
|
|
8226
8597
|
},
|
|
8227
8598
|
errors: [],
|
|
8228
8599
|
timestamp
|
|
@@ -8556,7 +8927,15 @@ var Engine = class {
|
|
|
8556
8927
|
this.mcpManager = new McpManager(config.mcp, createLogger(config.logging), { samplingHandler });
|
|
8557
8928
|
this.permissionPolicy = buildPermissionPolicy(config.permissions);
|
|
8558
8929
|
}
|
|
8559
|
-
|
|
8930
|
+
/**
|
|
8931
|
+
* Run a task synchronously to completion. The `_internal` parameter is
|
|
8932
|
+
* reserved for the engine's own async wrappers (`start`, `resumeAsync`)
|
|
8933
|
+
* to request runner handoff (Plan 019) — external callers must leave
|
|
8934
|
+
* it unset. Sync callers never hand off; if they hit a Node-only tool
|
|
8935
|
+
* on a restricted runtime, the capability stub returns an error and
|
|
8936
|
+
* the model adapts.
|
|
8937
|
+
*/
|
|
8938
|
+
async run(options, _internal) {
|
|
8560
8939
|
const startTime = Date.now();
|
|
8561
8940
|
const runId = options.runId ?? `run_${randomUUID()}`;
|
|
8562
8941
|
const log = createLogger(this.config.logging);
|
|
@@ -8579,6 +8958,7 @@ var Engine = class {
|
|
|
8579
8958
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8580
8959
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8581
8960
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
8961
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8582
8962
|
let systemPrompt = await buildSystemPrompt({
|
|
8583
8963
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8584
8964
|
memory,
|
|
@@ -8609,7 +8989,9 @@ var Engine = class {
|
|
|
8609
8989
|
mcpTools,
|
|
8610
8990
|
memory,
|
|
8611
8991
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8612
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
8992
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
8993
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
8994
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8613
8995
|
});
|
|
8614
8996
|
const writer = new TranscriptWriter({
|
|
8615
8997
|
storage: storage.workspace,
|
|
@@ -8663,7 +9045,8 @@ var Engine = class {
|
|
|
8663
9045
|
onProgress: this.buildHeartbeat(storage, runId, options.nodeId),
|
|
8664
9046
|
...options.tokenBudget !== void 0 ? { tokenBudget: options.tokenBudget } : {},
|
|
8665
9047
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8666
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9048
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9049
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8667
9050
|
});
|
|
8668
9051
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8669
9052
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8671,18 +9054,20 @@ var Engine = class {
|
|
|
8671
9054
|
});
|
|
8672
9055
|
this.logRunEnd(log, runId, options.nodeId, result);
|
|
8673
9056
|
await this.firePostRunHook(runId, options.nodeId, result, ctx, logPath);
|
|
9057
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8674
9058
|
return toResponse(result, {
|
|
8675
9059
|
runId,
|
|
8676
9060
|
nodeId: options.nodeId,
|
|
8677
9061
|
durationMs: Date.now() - startTime,
|
|
8678
|
-
logPath
|
|
9062
|
+
logPath,
|
|
9063
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8679
9064
|
});
|
|
8680
9065
|
} finally {
|
|
8681
9066
|
runTimeout.clear();
|
|
8682
9067
|
await writer.close();
|
|
8683
9068
|
}
|
|
8684
9069
|
}
|
|
8685
|
-
async resume(options) {
|
|
9070
|
+
async resume(options, _internal) {
|
|
8686
9071
|
const startTime = Date.now();
|
|
8687
9072
|
const log = createLogger(this.config.logging);
|
|
8688
9073
|
const storage = await this.buildStorage();
|
|
@@ -8715,6 +9100,7 @@ var Engine = class {
|
|
|
8715
9100
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8716
9101
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8717
9102
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
9103
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8718
9104
|
let systemPrompt = await buildSystemPrompt({
|
|
8719
9105
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8720
9106
|
memory,
|
|
@@ -8745,7 +9131,9 @@ var Engine = class {
|
|
|
8745
9131
|
mcpTools,
|
|
8746
9132
|
memory,
|
|
8747
9133
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8748
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
9134
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
9135
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
9136
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8749
9137
|
});
|
|
8750
9138
|
const priorState = await loadWriterState(storage.workspace, logPath);
|
|
8751
9139
|
const writer = new TranscriptWriter({
|
|
@@ -8799,18 +9187,21 @@ var Engine = class {
|
|
|
8799
9187
|
const answer = typeof options.gateAnswer === "string" ? options.gateAnswer : JSON.stringify(options.gateAnswer);
|
|
8800
9188
|
await ctx.addToolResult(pending.toolUseId, answer, false);
|
|
8801
9189
|
} else {
|
|
8802
|
-
await ctx.addToolResult(
|
|
8803
|
-
pending.toolUseId,
|
|
8804
|
-
`APPROVAL_GATE_RELEASED: the prior ${pending.toolName} call was paused for human approval and has now been approved. Retry is required.`,
|
|
8805
|
-
false
|
|
8806
|
-
);
|
|
8807
9190
|
const inputJson = JSON.stringify(pending.input ?? {}, null, 2);
|
|
8808
|
-
await ctx.
|
|
8809
|
-
|
|
9191
|
+
await ctx.addMixedUserMessage([
|
|
9192
|
+
{
|
|
9193
|
+
type: "tool_result",
|
|
9194
|
+
tool_use_id: pending.toolUseId,
|
|
9195
|
+
content: `APPROVAL_GATE_RELEASED: the prior ${pending.toolName} call was paused for human approval and has now been approved. Retry is required.`
|
|
9196
|
+
},
|
|
9197
|
+
{
|
|
9198
|
+
type: "text",
|
|
9199
|
+
text: `The human has approved the paused ${pending.toolName} tool call. You MUST now re-issue the EXACT same tool call to complete the work \u2014 do not change the arguments, do not answer in text, do not declare the task done. Approved arguments (copy verbatim):
|
|
8810
9200
|
\`\`\`json
|
|
8811
9201
|
${inputJson}
|
|
8812
9202
|
\`\`\``
|
|
8813
|
-
|
|
9203
|
+
}
|
|
9204
|
+
]);
|
|
8814
9205
|
}
|
|
8815
9206
|
}
|
|
8816
9207
|
await writer.setStatus("running");
|
|
@@ -8831,7 +9222,8 @@ ${inputJson}
|
|
|
8831
9222
|
stopHooks: this.config.hooks.stopHooks,
|
|
8832
9223
|
onProgress: this.buildHeartbeat(storage, snapshot.runId, snapshot.nodeId),
|
|
8833
9224
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8834
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9225
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9226
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8835
9227
|
});
|
|
8836
9228
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8837
9229
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8839,11 +9231,13 @@ ${inputJson}
|
|
|
8839
9231
|
});
|
|
8840
9232
|
this.logRunEnd(log, snapshot.runId, snapshot.nodeId, result);
|
|
8841
9233
|
await this.firePostRunHook(snapshot.runId, snapshot.nodeId, result, ctx, logPath);
|
|
9234
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8842
9235
|
return toResponse(result, {
|
|
8843
9236
|
runId: snapshot.runId,
|
|
8844
9237
|
nodeId: snapshot.nodeId,
|
|
8845
9238
|
durationMs: Date.now() - startTime,
|
|
8846
|
-
logPath
|
|
9239
|
+
logPath,
|
|
9240
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8847
9241
|
});
|
|
8848
9242
|
} finally {
|
|
8849
9243
|
runTimeout.clear();
|
|
@@ -8913,13 +9307,15 @@ ${inputJson}
|
|
|
8913
9307
|
} : void 0;
|
|
8914
9308
|
const initial = RunStateManager.initial(runId, options.nodeId, webhook);
|
|
8915
9309
|
await stateManager.write(initial);
|
|
9310
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
8916
9311
|
this.backgroundExecutor.schedule(runId, async (signal) => {
|
|
8917
9312
|
await stateManager.update(runId, options.nodeId, { status: "running" });
|
|
8918
9313
|
try {
|
|
8919
|
-
const response = await this.run({ ...options, runId });
|
|
9314
|
+
const response = await this.run({ ...options, runId }, { handoffToRunner: handoffEnabled });
|
|
8920
9315
|
if (signal.aborted) return;
|
|
8921
|
-
await
|
|
8922
|
-
await
|
|
9316
|
+
const postHandoff = await this.maybeHandoffToRunner(runId, options.nodeId, response);
|
|
9317
|
+
await stateManager.finalize(runId, options.nodeId, postHandoff);
|
|
9318
|
+
await this.maybeFireWebhook(stateManager, runId, options.nodeId, postHandoff);
|
|
8923
9319
|
} catch (err) {
|
|
8924
9320
|
if (signal.aborted) return;
|
|
8925
9321
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -8967,12 +9363,14 @@ ${inputJson}
|
|
|
8967
9363
|
} : { ...RunStateManager.initial(options.runId, nodeId, webhook), status: "running" };
|
|
8968
9364
|
await stateManager.write(next);
|
|
8969
9365
|
const resumeNodeId = nodeId;
|
|
9366
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
8970
9367
|
this.backgroundExecutor.schedule(options.runId, async (signal) => {
|
|
8971
9368
|
try {
|
|
8972
|
-
const response = await this.resume(options);
|
|
9369
|
+
const response = await this.resume(options, { handoffToRunner: handoffEnabled });
|
|
8973
9370
|
if (signal.aborted) return;
|
|
8974
|
-
await
|
|
8975
|
-
await
|
|
9371
|
+
const postHandoff = await this.maybeHandoffToRunner(options.runId, resumeNodeId, response);
|
|
9372
|
+
await stateManager.finalize(options.runId, resumeNodeId, postHandoff);
|
|
9373
|
+
await this.maybeFireWebhook(stateManager, options.runId, resumeNodeId, postHandoff);
|
|
8976
9374
|
} catch (err) {
|
|
8977
9375
|
if (signal.aborted) return;
|
|
8978
9376
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9161,6 +9559,68 @@ ${inputJson}
|
|
|
9161
9559
|
}
|
|
9162
9560
|
return orphaned;
|
|
9163
9561
|
}
|
|
9562
|
+
// ---------- runner handoff (Plan 019) ----------
|
|
9563
|
+
/**
|
|
9564
|
+
* When the response indicates the run paused for runner handoff, POST
|
|
9565
|
+
* `{ runId }` to the configured runner URL. On success, return the
|
|
9566
|
+
* response unchanged — state stays `paused` and the runner will flip
|
|
9567
|
+
* it to `done` (or `failed`) on its side. On POST failure, convert
|
|
9568
|
+
* the response to `failed` with `ERR_RUNNER_UNREACHABLE` so the
|
|
9569
|
+
* caller sees a terminal state instead of a silent hang.
|
|
9570
|
+
*
|
|
9571
|
+
* Called only from `start()` / `resumeAsync()`. Sync `run()` never
|
|
9572
|
+
* produces a `handoff_to_runner` pause (see `_internal.handoffToRunner`).
|
|
9573
|
+
*/
|
|
9574
|
+
async maybeHandoffToRunner(runId, nodeId, response) {
|
|
9575
|
+
if (response.status !== "paused") return response;
|
|
9576
|
+
if (response.meta.pauseReason !== "handoff_to_runner") return response;
|
|
9577
|
+
const runner = this.config.runner;
|
|
9578
|
+
if (runner === void 0) {
|
|
9579
|
+
return response;
|
|
9580
|
+
}
|
|
9581
|
+
const fetchFn = this.internals.fetch ?? globalThis.fetch.bind(globalThis);
|
|
9582
|
+
try {
|
|
9583
|
+
const res = await fetchFn(runner.url, {
|
|
9584
|
+
method: "POST",
|
|
9585
|
+
headers: {
|
|
9586
|
+
"Content-Type": "application/json",
|
|
9587
|
+
Authorization: `Bearer ${runner.secret}`
|
|
9588
|
+
},
|
|
9589
|
+
body: JSON.stringify({ runId })
|
|
9590
|
+
});
|
|
9591
|
+
if (!res.ok) {
|
|
9592
|
+
return {
|
|
9593
|
+
runId,
|
|
9594
|
+
status: "failed",
|
|
9595
|
+
data: null,
|
|
9596
|
+
meta: { nodeId },
|
|
9597
|
+
errors: [
|
|
9598
|
+
{
|
|
9599
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9600
|
+
message: `Runner returned HTTP ${res.status}`
|
|
9601
|
+
}
|
|
9602
|
+
],
|
|
9603
|
+
timestamp: Date.now()
|
|
9604
|
+
};
|
|
9605
|
+
}
|
|
9606
|
+
return response;
|
|
9607
|
+
} catch (err) {
|
|
9608
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9609
|
+
return {
|
|
9610
|
+
runId,
|
|
9611
|
+
status: "failed",
|
|
9612
|
+
data: null,
|
|
9613
|
+
meta: { nodeId },
|
|
9614
|
+
errors: [
|
|
9615
|
+
{
|
|
9616
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9617
|
+
message: `Runner handoff failed: ${msg}`
|
|
9618
|
+
}
|
|
9619
|
+
],
|
|
9620
|
+
timestamp: Date.now()
|
|
9621
|
+
};
|
|
9622
|
+
}
|
|
9623
|
+
}
|
|
9164
9624
|
// ---------- webhook helpers ----------
|
|
9165
9625
|
async maybeFireWebhook(stateManager, runId, nodeId, response) {
|
|
9166
9626
|
const state = await stateManager.read(runId, nodeId);
|
|
@@ -9304,6 +9764,11 @@ ${inputJson}
|
|
|
9304
9764
|
if (disabled.has(name)) continue;
|
|
9305
9765
|
if (wantAll || enabled.has(name)) names.add(name);
|
|
9306
9766
|
}
|
|
9767
|
+
if ((this.config.api?.services.length ?? 0) > 0) {
|
|
9768
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
9769
|
+
names.add("ApiCall");
|
|
9770
|
+
}
|
|
9771
|
+
}
|
|
9307
9772
|
for (const tool of this.config.tools.custom) {
|
|
9308
9773
|
names.add(tool.name);
|
|
9309
9774
|
}
|
|
@@ -9460,6 +9925,34 @@ ${inputJson}
|
|
|
9460
9925
|
}
|
|
9461
9926
|
return void 0;
|
|
9462
9927
|
}
|
|
9928
|
+
/**
|
|
9929
|
+
* Plan 020 — resolve the effective ApiCall config for a run.
|
|
9930
|
+
*
|
|
9931
|
+
* Precedence (each field independently):
|
|
9932
|
+
* RunOptions.api.X > config.api.X
|
|
9933
|
+
*
|
|
9934
|
+
* If neither side provides any services, returns undefined so the
|
|
9935
|
+
* tool isn't registered at all. Env + resolveAuth + hooks flow
|
|
9936
|
+
* through untouched — they never hit the Zod schema.
|
|
9937
|
+
*/
|
|
9938
|
+
resolveApiConfig(override) {
|
|
9939
|
+
const base = this.config.api;
|
|
9940
|
+
if (override === void 0 && base === void 0) return void 0;
|
|
9941
|
+
const services = override?.services ?? base?.services;
|
|
9942
|
+
if (services === void 0 || services.length === 0) return void 0;
|
|
9943
|
+
const env = override?.env ?? base?.env;
|
|
9944
|
+
const resolveAuth2 = override?.resolveAuth ?? base?.resolveAuth;
|
|
9945
|
+
const onRequest = override?.onRequest ?? base?.onRequest;
|
|
9946
|
+
const onResponse = override?.onResponse ?? base?.onResponse;
|
|
9947
|
+
return {
|
|
9948
|
+
services,
|
|
9949
|
+
...env !== void 0 ? { env } : {},
|
|
9950
|
+
...resolveAuth2 !== void 0 ? { resolveAuth: resolveAuth2 } : {},
|
|
9951
|
+
...onRequest !== void 0 ? { onRequest } : {},
|
|
9952
|
+
...onResponse !== void 0 ? { onResponse } : {},
|
|
9953
|
+
...base?.maxResponseBytes !== void 0 ? { maxResponseBytes: base.maxResponseBytes } : {}
|
|
9954
|
+
};
|
|
9955
|
+
}
|
|
9463
9956
|
/**
|
|
9464
9957
|
* Build a throttled heartbeat callback for agentLoop's `onProgress` hook.
|
|
9465
9958
|
*
|
|
@@ -9554,8 +10047,8 @@ function buildToolRegistry(options) {
|
|
|
9554
10047
|
const fileTracker = new FileTracker();
|
|
9555
10048
|
const spawnAvailable = canSpawnProcesses();
|
|
9556
10049
|
const candidates = [
|
|
9557
|
-
// Bash — requires child_process.spawn
|
|
9558
|
-
|
|
10050
|
+
// Bash — requires child_process.spawn. Stubbed on Workers.
|
|
10051
|
+
{ name: "Bash", tool: withCapabilityCheck(createBashTool(), spawnAvailable) },
|
|
9559
10052
|
{
|
|
9560
10053
|
name: "Read",
|
|
9561
10054
|
tool: createFileReadTool({ storage: storage.workspace, tracker: fileTracker })
|
|
@@ -9601,6 +10094,21 @@ function buildToolRegistry(options) {
|
|
|
9601
10094
|
childRegistry.register(skillTool);
|
|
9602
10095
|
}
|
|
9603
10096
|
}
|
|
10097
|
+
if (options.apiConfig !== void 0 && options.apiConfig.services.length > 0) {
|
|
10098
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
10099
|
+
const apiTool = createApiCallTool({
|
|
10100
|
+
services: options.apiConfig.services,
|
|
10101
|
+
...options.fetch !== void 0 ? { fetch: options.fetch } : {},
|
|
10102
|
+
...options.apiConfig.env !== void 0 ? { env: options.apiConfig.env } : {},
|
|
10103
|
+
...options.apiConfig.resolveAuth !== void 0 ? { resolveAuth: options.apiConfig.resolveAuth } : {},
|
|
10104
|
+
...options.apiConfig.onRequest !== void 0 ? { onRequest: options.apiConfig.onRequest } : {},
|
|
10105
|
+
...options.apiConfig.onResponse !== void 0 ? { onResponse: options.apiConfig.onResponse } : {},
|
|
10106
|
+
...options.apiConfig.maxResponseBytes !== void 0 ? { maxResponseBytes: options.apiConfig.maxResponseBytes } : {}
|
|
10107
|
+
});
|
|
10108
|
+
registry.register(apiTool);
|
|
10109
|
+
childRegistry.register(apiTool);
|
|
10110
|
+
}
|
|
10111
|
+
}
|
|
9604
10112
|
const agentTool = createAgentTool({
|
|
9605
10113
|
storage: storage.workspace,
|
|
9606
10114
|
client,
|
|
@@ -9722,6 +10230,8 @@ export {
|
|
|
9722
10230
|
buildSystemPrompt,
|
|
9723
10231
|
buildWorkerAgent,
|
|
9724
10232
|
canSpawnProcesses,
|
|
10233
|
+
capabilityStub,
|
|
10234
|
+
createApiCallTool,
|
|
9725
10235
|
createLogger,
|
|
9726
10236
|
createModelAdapter,
|
|
9727
10237
|
createSendMessageTool,
|
|
@@ -9753,6 +10263,7 @@ export {
|
|
|
9753
10263
|
synthesizeSpec,
|
|
9754
10264
|
toResponse,
|
|
9755
10265
|
tryParseJSON,
|
|
9756
|
-
validateOutput
|
|
10266
|
+
validateOutput,
|
|
10267
|
+
withCapabilityCheck
|
|
9757
10268
|
};
|
|
9758
10269
|
//# sourceMappingURL=index.js.map
|