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.cjs
CHANGED
|
@@ -38,23 +38,23 @@ var init_cjs_shims = __esm({
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
// src/orchestrator/types.ts
|
|
41
|
-
var
|
|
41
|
+
var import_zod25, PlanStepSchema, PlanSchema;
|
|
42
42
|
var init_types = __esm({
|
|
43
43
|
"src/orchestrator/types.ts"() {
|
|
44
44
|
"use strict";
|
|
45
45
|
init_cjs_shims();
|
|
46
|
-
|
|
47
|
-
PlanStepSchema =
|
|
48
|
-
id:
|
|
49
|
-
description:
|
|
50
|
-
action:
|
|
51
|
-
files:
|
|
52
|
-
spec:
|
|
53
|
-
dependsOn:
|
|
46
|
+
import_zod25 = require("zod");
|
|
47
|
+
PlanStepSchema = import_zod25.z.object({
|
|
48
|
+
id: import_zod25.z.string().min(1),
|
|
49
|
+
description: import_zod25.z.string().min(1),
|
|
50
|
+
action: import_zod25.z.enum(["research", "implement", "verify", "review", "custom"]),
|
|
51
|
+
files: import_zod25.z.array(import_zod25.z.string()).optional(),
|
|
52
|
+
spec: import_zod25.z.string().optional(),
|
|
53
|
+
dependsOn: import_zod25.z.array(import_zod25.z.string()).optional()
|
|
54
54
|
});
|
|
55
|
-
PlanSchema =
|
|
56
|
-
summary:
|
|
57
|
-
steps:
|
|
55
|
+
PlanSchema = import_zod25.z.object({
|
|
56
|
+
summary: import_zod25.z.string().min(1),
|
|
57
|
+
steps: import_zod25.z.array(PlanStepSchema).min(1)
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
});
|
|
@@ -785,6 +785,8 @@ __export(index_exports, {
|
|
|
785
785
|
buildSystemPrompt: () => buildSystemPrompt,
|
|
786
786
|
buildWorkerAgent: () => buildWorkerAgent,
|
|
787
787
|
canSpawnProcesses: () => canSpawnProcesses,
|
|
788
|
+
capabilityStub: () => capabilityStub,
|
|
789
|
+
createApiCallTool: () => createApiCallTool,
|
|
788
790
|
createLogger: () => createLogger,
|
|
789
791
|
createModelAdapter: () => createModelAdapter,
|
|
790
792
|
createSendMessageTool: () => createSendMessageTool,
|
|
@@ -816,7 +818,8 @@ __export(index_exports, {
|
|
|
816
818
|
synthesizeSpec: () => synthesizeSpec,
|
|
817
819
|
toResponse: () => toResponse,
|
|
818
820
|
tryParseJSON: () => tryParseJSON,
|
|
819
|
-
validateOutput: () => validateOutput
|
|
821
|
+
validateOutput: () => validateOutput,
|
|
822
|
+
withCapabilityCheck: () => withCapabilityCheck
|
|
820
823
|
});
|
|
821
824
|
module.exports = __toCommonJS(index_exports);
|
|
822
825
|
init_cjs_shims();
|
|
@@ -1110,6 +1113,42 @@ var LoggingConfigResolved = import_zod.z.object({
|
|
|
1110
1113
|
level: LogLevelEnum,
|
|
1111
1114
|
sink: LogSinkSchema
|
|
1112
1115
|
}).strict();
|
|
1116
|
+
var ApiHttpMethodEnum = import_zod.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]);
|
|
1117
|
+
var ApiAuthSchema = import_zod.z.discriminatedUnion("type", [
|
|
1118
|
+
import_zod.z.object({ type: import_zod.z.literal("none") }).strict(),
|
|
1119
|
+
import_zod.z.object({ type: import_zod.z.literal("bearer"), tokenRef: import_zod.z.string().min(1) }).strict(),
|
|
1120
|
+
import_zod.z.object({
|
|
1121
|
+
type: import_zod.z.literal("header"),
|
|
1122
|
+
name: import_zod.z.string().min(1),
|
|
1123
|
+
valueRef: import_zod.z.string().min(1)
|
|
1124
|
+
}).strict(),
|
|
1125
|
+
import_zod.z.object({
|
|
1126
|
+
type: import_zod.z.literal("basic"),
|
|
1127
|
+
userRef: import_zod.z.string().min(1),
|
|
1128
|
+
passRef: import_zod.z.string().min(1)
|
|
1129
|
+
}).strict(),
|
|
1130
|
+
import_zod.z.object({ type: import_zod.z.literal("custom"), id: import_zod.z.string().min(1) }).strict()
|
|
1131
|
+
]);
|
|
1132
|
+
var ApiServiceSchema = import_zod.z.object({
|
|
1133
|
+
name: import_zod.z.string().min(1),
|
|
1134
|
+
description: import_zod.z.string().optional(),
|
|
1135
|
+
baseUrl: import_zod.z.string().url(),
|
|
1136
|
+
auth: ApiAuthSchema.optional(),
|
|
1137
|
+
// Allow both strings and RegExp values via z.union — RegExp is
|
|
1138
|
+
// serialized as its source when cloned, so we accept both.
|
|
1139
|
+
allowedPaths: import_zod.z.array(import_zod.z.union([import_zod.z.string(), import_zod.z.instanceof(RegExp)])).optional(),
|
|
1140
|
+
allowedMethods: import_zod.z.array(ApiHttpMethodEnum).optional(),
|
|
1141
|
+
defaultHeaders: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
1142
|
+
maxBodyBytes: import_zod.z.number().int().positive().optional()
|
|
1143
|
+
}).strict();
|
|
1144
|
+
var ApiConfigResolved = import_zod.z.object({
|
|
1145
|
+
services: import_zod.z.array(ApiServiceSchema),
|
|
1146
|
+
maxResponseBytes: import_zod.z.number().int().positive().optional()
|
|
1147
|
+
}).strict();
|
|
1148
|
+
var RunnerConfigResolved = import_zod.z.object({
|
|
1149
|
+
url: import_zod.z.string().url(),
|
|
1150
|
+
secret: import_zod.z.string().min(1, "runner.secret cannot be empty")
|
|
1151
|
+
}).strict();
|
|
1113
1152
|
var ResolvedConfigSchema = import_zod.z.object({
|
|
1114
1153
|
model: ModelConfigResolved,
|
|
1115
1154
|
storage: StorageConfigResolved,
|
|
@@ -1125,7 +1164,9 @@ var ResolvedConfigSchema = import_zod.z.object({
|
|
|
1125
1164
|
permissions: PermissionsConfigResolved,
|
|
1126
1165
|
compaction: CompactionConfigResolved,
|
|
1127
1166
|
coordinator: CoordinatorConfigResolved,
|
|
1128
|
-
orchestrator: OrchestratorConfigResolved
|
|
1167
|
+
orchestrator: OrchestratorConfigResolved,
|
|
1168
|
+
runner: RunnerConfigResolved.optional(),
|
|
1169
|
+
api: ApiConfigResolved.optional()
|
|
1129
1170
|
}).strict();
|
|
1130
1171
|
var R2ConfigUser = R2ConfigResolved.partial();
|
|
1131
1172
|
var ModelConfigUser = ModelConfigResolved.partial();
|
|
@@ -1166,6 +1207,8 @@ var McpConfigUser = import_zod.z.object({
|
|
|
1166
1207
|
shutdownTimeoutMs: import_zod.z.number().int().positive().optional()
|
|
1167
1208
|
}).strict();
|
|
1168
1209
|
var PermissionsConfigUser = PermissionsConfigResolved.partial();
|
|
1210
|
+
var RunnerConfigUser = RunnerConfigResolved;
|
|
1211
|
+
var ApiConfigUser = ApiConfigResolved.partial();
|
|
1169
1212
|
var CompactionConfigUser = CompactionConfigResolved.partial();
|
|
1170
1213
|
var CoordinatorConfigUser = CoordinatorConfigResolved.partial();
|
|
1171
1214
|
var OrchestratorConfigUser = OrchestratorConfigResolved.deepPartial();
|
|
@@ -1184,7 +1227,9 @@ var UserConfigSchema = import_zod.z.object({
|
|
|
1184
1227
|
permissions: PermissionsConfigUser.optional(),
|
|
1185
1228
|
compaction: CompactionConfigUser.optional(),
|
|
1186
1229
|
coordinator: CoordinatorConfigUser.optional(),
|
|
1187
|
-
orchestrator: OrchestratorConfigUser.optional()
|
|
1230
|
+
orchestrator: OrchestratorConfigUser.optional(),
|
|
1231
|
+
runner: RunnerConfigUser.optional(),
|
|
1232
|
+
api: ApiConfigUser.optional()
|
|
1188
1233
|
}).strict();
|
|
1189
1234
|
|
|
1190
1235
|
// src/config/merge.ts
|
|
@@ -1229,10 +1274,36 @@ function deepMerge(base, override) {
|
|
|
1229
1274
|
}
|
|
1230
1275
|
return result;
|
|
1231
1276
|
}
|
|
1277
|
+
var API_RUNTIME_KEYS = ["env", "resolveAuth", "onRequest", "onResponse"];
|
|
1278
|
+
function splitApiRuntime(user) {
|
|
1279
|
+
const api = user.api;
|
|
1280
|
+
if (api === void 0) return { stripped: user, runtime: {} };
|
|
1281
|
+
const runtime = {};
|
|
1282
|
+
const schemaSafe = {};
|
|
1283
|
+
for (const [k, v] of Object.entries(api)) {
|
|
1284
|
+
if (API_RUNTIME_KEYS.includes(k)) {
|
|
1285
|
+
runtime[k] = v;
|
|
1286
|
+
} else {
|
|
1287
|
+
schemaSafe[k] = v;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
const clone = { ...user, api: schemaSafe };
|
|
1291
|
+
return { stripped: clone, runtime };
|
|
1292
|
+
}
|
|
1232
1293
|
function mergeConfig(user) {
|
|
1233
|
-
const
|
|
1294
|
+
const { stripped, runtime } = splitApiRuntime(user);
|
|
1295
|
+
const validatedUser = UserConfigSchema.parse(stripped);
|
|
1234
1296
|
const merged = deepMerge(DEFAULTS, validatedUser);
|
|
1235
|
-
|
|
1297
|
+
const resolved = ResolvedConfigSchema.parse(merged);
|
|
1298
|
+
if (resolved.api !== void 0 && Object.keys(runtime).length > 0) {
|
|
1299
|
+
const mutableResolved = resolved;
|
|
1300
|
+
mutableResolved.api = {
|
|
1301
|
+
...resolved.api,
|
|
1302
|
+
...runtime
|
|
1303
|
+
};
|
|
1304
|
+
} else if (Object.keys(runtime).length > 0) {
|
|
1305
|
+
}
|
|
1306
|
+
return resolved;
|
|
1236
1307
|
}
|
|
1237
1308
|
|
|
1238
1309
|
// src/engine/engine.ts
|
|
@@ -1676,8 +1747,8 @@ function toAISdkMessages(messages) {
|
|
|
1676
1747
|
textParts.push({ type: "text", text: block.text });
|
|
1677
1748
|
}
|
|
1678
1749
|
}
|
|
1679
|
-
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1680
1750
|
if (toolResults.length > 0) out.push({ role: "tool", content: toolResults });
|
|
1751
|
+
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1681
1752
|
} else if (role === "assistant") {
|
|
1682
1753
|
if (typeof content === "string") {
|
|
1683
1754
|
out.push({ role: "assistant", content });
|
|
@@ -1875,6 +1946,68 @@ function hasProcessLifecycle() {
|
|
|
1875
1946
|
return typeof process !== "undefined" && typeof process.on === "function" && typeof process.removeListener === "function" && detectRuntime() === "node";
|
|
1876
1947
|
}
|
|
1877
1948
|
|
|
1949
|
+
// src/tools/capabilityStub.ts
|
|
1950
|
+
init_cjs_shims();
|
|
1951
|
+
var import_zod2 = require("zod");
|
|
1952
|
+
|
|
1953
|
+
// src/tools/contract.ts
|
|
1954
|
+
init_cjs_shims();
|
|
1955
|
+
function defineTool(tool) {
|
|
1956
|
+
return tool;
|
|
1957
|
+
}
|
|
1958
|
+
var ToolRegistry = class {
|
|
1959
|
+
tools = /* @__PURE__ */ new Map();
|
|
1960
|
+
register(tool) {
|
|
1961
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) {
|
|
1962
|
+
throw new Error("ToolRegistry: tool.name must be a non-empty string");
|
|
1963
|
+
}
|
|
1964
|
+
if (this.tools.has(tool.name)) {
|
|
1965
|
+
throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
|
|
1966
|
+
}
|
|
1967
|
+
this.tools.set(tool.name, tool);
|
|
1968
|
+
}
|
|
1969
|
+
registerAll(tools) {
|
|
1970
|
+
for (const tool of tools) this.register(tool);
|
|
1971
|
+
}
|
|
1972
|
+
unregister(name) {
|
|
1973
|
+
this.tools.delete(name);
|
|
1974
|
+
}
|
|
1975
|
+
get(name) {
|
|
1976
|
+
return this.tools.get(name);
|
|
1977
|
+
}
|
|
1978
|
+
has(name) {
|
|
1979
|
+
return this.tools.has(name);
|
|
1980
|
+
}
|
|
1981
|
+
list() {
|
|
1982
|
+
return Array.from(this.tools.values());
|
|
1983
|
+
}
|
|
1984
|
+
count() {
|
|
1985
|
+
return this.tools.size;
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
|
|
1989
|
+
// src/tools/capabilityStub.ts
|
|
1990
|
+
var anyInput = import_zod2.z.unknown();
|
|
1991
|
+
function capabilityStub(original) {
|
|
1992
|
+
return defineTool({
|
|
1993
|
+
name: original.name,
|
|
1994
|
+
description: original.description,
|
|
1995
|
+
inputSchema: anyInput,
|
|
1996
|
+
isCapabilityStub: true,
|
|
1997
|
+
execute: async () => ({
|
|
1998
|
+
isError: true,
|
|
1999
|
+
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.`,
|
|
2000
|
+
metadata: { capabilityMissing: original.name }
|
|
2001
|
+
})
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
function withCapabilityCheck(tool, spawnAvailable) {
|
|
2005
|
+
if (tool.requiresNode === true && !spawnAvailable) {
|
|
2006
|
+
return capabilityStub(tool);
|
|
2007
|
+
}
|
|
2008
|
+
return tool;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
1878
2011
|
// src/subagent/registry.ts
|
|
1879
2012
|
init_cjs_shims();
|
|
1880
2013
|
|
|
@@ -2057,7 +2190,7 @@ var SubagentRegistry = class _SubagentRegistry {
|
|
|
2057
2190
|
|
|
2058
2191
|
// src/tools/agent.ts
|
|
2059
2192
|
init_cjs_shims();
|
|
2060
|
-
var
|
|
2193
|
+
var import_zod6 = require("zod");
|
|
2061
2194
|
|
|
2062
2195
|
// src/subagent/runner.ts
|
|
2063
2196
|
init_cjs_shims();
|
|
@@ -2068,48 +2201,49 @@ var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
|
2068
2201
|
|
|
2069
2202
|
// src/transcript/snapshot.ts
|
|
2070
2203
|
init_cjs_shims();
|
|
2071
|
-
var
|
|
2204
|
+
var import_zod3 = require("zod");
|
|
2072
2205
|
var SNAPSHOT_FILENAME = "snapshot.json";
|
|
2073
|
-
var TokenUsageSchema =
|
|
2074
|
-
input:
|
|
2075
|
-
output:
|
|
2076
|
-
cacheCreationInput:
|
|
2077
|
-
cacheReadInput:
|
|
2206
|
+
var TokenUsageSchema = import_zod3.z.object({
|
|
2207
|
+
input: import_zod3.z.number().int().nonnegative(),
|
|
2208
|
+
output: import_zod3.z.number().int().nonnegative(),
|
|
2209
|
+
cacheCreationInput: import_zod3.z.number().int().nonnegative().optional(),
|
|
2210
|
+
cacheReadInput: import_zod3.z.number().int().nonnegative().optional()
|
|
2078
2211
|
}).strict();
|
|
2079
|
-
var PendingToolCallSchema =
|
|
2080
|
-
toolName:
|
|
2081
|
-
toolUseId:
|
|
2082
|
-
input:
|
|
2083
|
-
calledAt:
|
|
2212
|
+
var PendingToolCallSchema = import_zod3.z.object({
|
|
2213
|
+
toolName: import_zod3.z.string().min(1),
|
|
2214
|
+
toolUseId: import_zod3.z.string().min(1),
|
|
2215
|
+
input: import_zod3.z.unknown(),
|
|
2216
|
+
calledAt: import_zod3.z.string().datetime({ offset: true })
|
|
2084
2217
|
}).strict();
|
|
2085
|
-
var PendingSubagentSchema =
|
|
2086
|
-
() =>
|
|
2087
|
-
subagentType:
|
|
2088
|
-
parentToolUseId:
|
|
2218
|
+
var PendingSubagentSchema = import_zod3.z.lazy(
|
|
2219
|
+
() => import_zod3.z.object({
|
|
2220
|
+
subagentType: import_zod3.z.string().min(1),
|
|
2221
|
+
parentToolUseId: import_zod3.z.string().min(1),
|
|
2089
2222
|
childSnapshot: RunSnapshotSchema
|
|
2090
2223
|
}).strict()
|
|
2091
2224
|
);
|
|
2092
|
-
var RunSnapshotSchema =
|
|
2093
|
-
() =>
|
|
2094
|
-
version:
|
|
2095
|
-
status:
|
|
2096
|
-
runId:
|
|
2097
|
-
nodeId:
|
|
2098
|
-
pausedAt:
|
|
2099
|
-
pauseReason:
|
|
2225
|
+
var RunSnapshotSchema = import_zod3.z.lazy(
|
|
2226
|
+
() => import_zod3.z.object({
|
|
2227
|
+
version: import_zod3.z.literal(1),
|
|
2228
|
+
status: import_zod3.z.literal("paused"),
|
|
2229
|
+
runId: import_zod3.z.string().min(1),
|
|
2230
|
+
nodeId: import_zod3.z.string().min(1),
|
|
2231
|
+
pausedAt: import_zod3.z.string().datetime({ offset: true }),
|
|
2232
|
+
pauseReason: import_zod3.z.enum([
|
|
2100
2233
|
"gate_required",
|
|
2101
2234
|
"subagent_gate_required",
|
|
2235
|
+
"handoff_to_runner",
|
|
2102
2236
|
"max_turns",
|
|
2103
2237
|
"explicit",
|
|
2104
2238
|
"timeout"
|
|
2105
2239
|
]),
|
|
2106
|
-
messageCount:
|
|
2107
|
-
lastShardIndex:
|
|
2108
|
-
lastMessageUuid:
|
|
2240
|
+
messageCount: import_zod3.z.number().int().nonnegative(),
|
|
2241
|
+
lastShardIndex: import_zod3.z.number().int().nonnegative(),
|
|
2242
|
+
lastMessageUuid: import_zod3.z.string().uuid(),
|
|
2109
2243
|
pendingToolCall: PendingToolCallSchema.optional(),
|
|
2110
2244
|
pendingSubagent: PendingSubagentSchema.optional(),
|
|
2111
2245
|
tokensUsedSoFar: TokenUsageSchema,
|
|
2112
|
-
turnsUsed:
|
|
2246
|
+
turnsUsed: import_zod3.z.number().int().nonnegative()
|
|
2113
2247
|
}).strict()
|
|
2114
2248
|
);
|
|
2115
2249
|
function snapshotPath(logPath) {
|
|
@@ -2837,6 +2971,27 @@ async function agentLoop(options) {
|
|
|
2837
2971
|
}
|
|
2838
2972
|
}
|
|
2839
2973
|
}
|
|
2974
|
+
if (options.handoffToRunner === true) {
|
|
2975
|
+
for (const call of toolCallsToDispatch) {
|
|
2976
|
+
const tool = options.registry?.get(call.name);
|
|
2977
|
+
if (tool?.isCapabilityStub === true) {
|
|
2978
|
+
const paused = await pauseHere({
|
|
2979
|
+
ctx,
|
|
2980
|
+
transcript,
|
|
2981
|
+
reason: "handoff_to_runner",
|
|
2982
|
+
pendingToolCall: {
|
|
2983
|
+
toolName: call.name,
|
|
2984
|
+
toolUseId: call.id,
|
|
2985
|
+
input: call.input,
|
|
2986
|
+
calledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2987
|
+
},
|
|
2988
|
+
storage: options.storage,
|
|
2989
|
+
subagentRegistry: options.subagentRegistry
|
|
2990
|
+
});
|
|
2991
|
+
return paused;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2840
2995
|
const firstTool = toolCallsToDispatch[0]?.name;
|
|
2841
2996
|
await fireProgress("tool_dispatch", firstTool);
|
|
2842
2997
|
const streamExec = new StreamingToolExecutor(executor);
|
|
@@ -2847,6 +3002,10 @@ async function agentLoop(options) {
|
|
|
2847
3002
|
}
|
|
2848
3003
|
try {
|
|
2849
3004
|
for await (const { id, result } of streamExec.results()) {
|
|
3005
|
+
const missing = result.metadata?.capabilityMissing;
|
|
3006
|
+
if (typeof missing === "string") {
|
|
3007
|
+
ctx.recordCapabilityMissing(missing);
|
|
3008
|
+
}
|
|
2850
3009
|
await ctx.addToolResult(id, truncateToolResult(result.content), result.isError === true);
|
|
2851
3010
|
}
|
|
2852
3011
|
} catch (err) {
|
|
@@ -3105,6 +3264,12 @@ var RunContext = class {
|
|
|
3105
3264
|
turnCount = 0;
|
|
3106
3265
|
tokensUsed = { input: 0, output: 0 };
|
|
3107
3266
|
lastUuid = null;
|
|
3267
|
+
/**
|
|
3268
|
+
* Plan 019 — names of tools whose capability-stub returned an
|
|
3269
|
+
* `isError` result during this run. Aggregated and surfaced on the
|
|
3270
|
+
* response's `meta.capabilitiesMissing` (deduped, insertion-ordered).
|
|
3271
|
+
*/
|
|
3272
|
+
capabilitiesMissing = /* @__PURE__ */ new Set();
|
|
3108
3273
|
constructor(options) {
|
|
3109
3274
|
this.runId = options.runId;
|
|
3110
3275
|
this.nodeId = options.nodeId;
|
|
@@ -3145,6 +3310,42 @@ var RunContext = class {
|
|
|
3145
3310
|
this.episodes.logTurn(this.turnCount, "assistant", summary);
|
|
3146
3311
|
}
|
|
3147
3312
|
}
|
|
3313
|
+
/**
|
|
3314
|
+
* Inject a tool_result + a follow-up text block as a SINGLE user
|
|
3315
|
+
* message. Used by the resume() synthetic-release path when a
|
|
3316
|
+
* paused run is resumed without an explicit `gateAnswer`: we need
|
|
3317
|
+
* to both satisfy the tool_use↔tool_result pairing AND give the
|
|
3318
|
+
* model a retry instruction, in the same user turn.
|
|
3319
|
+
*
|
|
3320
|
+
* Splitting this into `addToolResult(...) + addUserMessage(...)`
|
|
3321
|
+
* produces two consecutive user messages, which the AI SDK's
|
|
3322
|
+
* openai-compatible adapter rejects with
|
|
3323
|
+
* `MissingToolResultsError`. Combining them into one user message
|
|
3324
|
+
* is the portable shape that works on every provider we support.
|
|
3325
|
+
*
|
|
3326
|
+
* Writes a single `user` transcript entry carrying the mixed
|
|
3327
|
+
* content, so `rebuildMessagesFromEntries` reconstructs the same
|
|
3328
|
+
* single-message shape on resume.
|
|
3329
|
+
*/
|
|
3330
|
+
async addMixedUserMessage(blocks) {
|
|
3331
|
+
this.messages.push({ role: "user", content: blocks });
|
|
3332
|
+
await this.writeEntry({
|
|
3333
|
+
type: "user",
|
|
3334
|
+
uuid: this.nextUuid(),
|
|
3335
|
+
parentUuid: this.lastUuid,
|
|
3336
|
+
ts: this.now(),
|
|
3337
|
+
message: { role: "user", content: blocks }
|
|
3338
|
+
});
|
|
3339
|
+
const summary = blocks.map((b) => {
|
|
3340
|
+
const x = b;
|
|
3341
|
+
if (x.type === "text") return x.text ?? "";
|
|
3342
|
+
if (x.type === "tool_result") {
|
|
3343
|
+
return typeof x.content === "string" ? x.content : JSON.stringify(x.content);
|
|
3344
|
+
}
|
|
3345
|
+
return "";
|
|
3346
|
+
}).filter((s) => s.length > 0).join("\n");
|
|
3347
|
+
this.episodes?.logTurn(this.turnCount, "user", summary);
|
|
3348
|
+
}
|
|
3148
3349
|
/**
|
|
3149
3350
|
* Append a tool result to the conversation. The Anthropic Messages
|
|
3150
3351
|
* API requires tool_result blocks to be wrapped in a user message,
|
|
@@ -3190,6 +3391,14 @@ var RunContext = class {
|
|
|
3190
3391
|
getTokensUsed() {
|
|
3191
3392
|
return this.tokensUsed;
|
|
3192
3393
|
}
|
|
3394
|
+
/** Plan 019 — record that a capability-stubbed tool fired during this run. */
|
|
3395
|
+
recordCapabilityMissing(toolName) {
|
|
3396
|
+
this.capabilitiesMissing.add(toolName);
|
|
3397
|
+
}
|
|
3398
|
+
/** Plan 019 — capability-stubbed tool names observed this run (deduped). */
|
|
3399
|
+
getCapabilitiesMissing() {
|
|
3400
|
+
return [...this.capabilitiesMissing];
|
|
3401
|
+
}
|
|
3193
3402
|
shouldContinue() {
|
|
3194
3403
|
return this.turnCount < this.maxTurns;
|
|
3195
3404
|
}
|
|
@@ -3363,9 +3572,9 @@ init_cjs_shims();
|
|
|
3363
3572
|
|
|
3364
3573
|
// src/transcript/entries.ts
|
|
3365
3574
|
init_cjs_shims();
|
|
3366
|
-
var
|
|
3367
|
-
var UuidSchema =
|
|
3368
|
-
var IsoTsSchema =
|
|
3575
|
+
var import_zod4 = require("zod");
|
|
3576
|
+
var UuidSchema = import_zod4.z.string().uuid();
|
|
3577
|
+
var IsoTsSchema = import_zod4.z.string().datetime({ offset: true });
|
|
3369
3578
|
var TimelineBase = {
|
|
3370
3579
|
uuid: UuidSchema,
|
|
3371
3580
|
parentUuid: UuidSchema.nullable(),
|
|
@@ -3375,55 +3584,55 @@ var SessionBase = {
|
|
|
3375
3584
|
uuid: UuidSchema,
|
|
3376
3585
|
ts: IsoTsSchema
|
|
3377
3586
|
};
|
|
3378
|
-
var MessageSchema =
|
|
3379
|
-
role:
|
|
3380
|
-
content:
|
|
3587
|
+
var MessageSchema = import_zod4.z.object({
|
|
3588
|
+
role: import_zod4.z.enum(["user", "assistant"]),
|
|
3589
|
+
content: import_zod4.z.array(import_zod4.z.unknown())
|
|
3381
3590
|
}).strict();
|
|
3382
|
-
var UserEntrySchema =
|
|
3383
|
-
type:
|
|
3591
|
+
var UserEntrySchema = import_zod4.z.object({
|
|
3592
|
+
type: import_zod4.z.literal("user"),
|
|
3384
3593
|
...TimelineBase,
|
|
3385
3594
|
message: MessageSchema
|
|
3386
3595
|
}).strict();
|
|
3387
|
-
var AssistantEntrySchema =
|
|
3388
|
-
type:
|
|
3596
|
+
var AssistantEntrySchema = import_zod4.z.object({
|
|
3597
|
+
type: import_zod4.z.literal("assistant"),
|
|
3389
3598
|
...TimelineBase,
|
|
3390
3599
|
message: MessageSchema
|
|
3391
3600
|
}).strict();
|
|
3392
|
-
var ToolResultEntrySchema =
|
|
3393
|
-
type:
|
|
3601
|
+
var ToolResultEntrySchema = import_zod4.z.object({
|
|
3602
|
+
type: import_zod4.z.literal("tool_result"),
|
|
3394
3603
|
...TimelineBase,
|
|
3395
|
-
toolUseId:
|
|
3396
|
-
content:
|
|
3397
|
-
isError:
|
|
3604
|
+
toolUseId: import_zod4.z.string().min(1),
|
|
3605
|
+
content: import_zod4.z.unknown(),
|
|
3606
|
+
isError: import_zod4.z.boolean().optional()
|
|
3398
3607
|
}).strict();
|
|
3399
|
-
var SubagentSpawnEntrySchema =
|
|
3400
|
-
type:
|
|
3608
|
+
var SubagentSpawnEntrySchema = import_zod4.z.object({
|
|
3609
|
+
type: import_zod4.z.literal("subagent_spawn"),
|
|
3401
3610
|
...TimelineBase,
|
|
3402
|
-
agentId:
|
|
3403
|
-
agentType:
|
|
3611
|
+
agentId: import_zod4.z.string().min(1),
|
|
3612
|
+
agentType: import_zod4.z.string().min(1)
|
|
3404
3613
|
}).strict();
|
|
3405
|
-
var SubagentDoneEntrySchema =
|
|
3406
|
-
type:
|
|
3614
|
+
var SubagentDoneEntrySchema = import_zod4.z.object({
|
|
3615
|
+
type: import_zod4.z.literal("subagent_done"),
|
|
3407
3616
|
...TimelineBase,
|
|
3408
|
-
agentId:
|
|
3409
|
-
output:
|
|
3617
|
+
agentId: import_zod4.z.string().min(1),
|
|
3618
|
+
output: import_zod4.z.string()
|
|
3410
3619
|
}).strict();
|
|
3411
|
-
var MetaEntrySchema =
|
|
3412
|
-
type:
|
|
3620
|
+
var MetaEntrySchema = import_zod4.z.object({
|
|
3621
|
+
type: import_zod4.z.literal("meta"),
|
|
3413
3622
|
...SessionBase,
|
|
3414
|
-
key:
|
|
3415
|
-
value:
|
|
3623
|
+
key: import_zod4.z.string().min(1),
|
|
3624
|
+
value: import_zod4.z.unknown()
|
|
3416
3625
|
}).strict();
|
|
3417
|
-
var ErrorEntrySchema =
|
|
3418
|
-
type:
|
|
3626
|
+
var ErrorEntrySchema = import_zod4.z.object({
|
|
3627
|
+
type: import_zod4.z.literal("error"),
|
|
3419
3628
|
...SessionBase,
|
|
3420
|
-
error:
|
|
3421
|
-
code:
|
|
3422
|
-
message:
|
|
3423
|
-
stack:
|
|
3629
|
+
error: import_zod4.z.object({
|
|
3630
|
+
code: import_zod4.z.string().min(1),
|
|
3631
|
+
message: import_zod4.z.string(),
|
|
3632
|
+
stack: import_zod4.z.string().optional()
|
|
3424
3633
|
}).strict()
|
|
3425
3634
|
}).strict();
|
|
3426
|
-
var EntrySchema =
|
|
3635
|
+
var EntrySchema = import_zod4.z.discriminatedUnion("type", [
|
|
3427
3636
|
UserEntrySchema,
|
|
3428
3637
|
AssistantEntrySchema,
|
|
3429
3638
|
ToolResultEntrySchema,
|
|
@@ -3455,16 +3664,16 @@ function parseEntryLine(line) {
|
|
|
3455
3664
|
|
|
3456
3665
|
// src/transcript/meta.ts
|
|
3457
3666
|
init_cjs_shims();
|
|
3458
|
-
var
|
|
3459
|
-
var TranscriptMetaSchema =
|
|
3460
|
-
version:
|
|
3461
|
-
status:
|
|
3462
|
-
startedAt:
|
|
3463
|
-
updatedAt:
|
|
3464
|
-
turnCount:
|
|
3465
|
-
messageCount:
|
|
3466
|
-
lastShardIndex:
|
|
3467
|
-
shardCount:
|
|
3667
|
+
var import_zod5 = require("zod");
|
|
3668
|
+
var TranscriptMetaSchema = import_zod5.z.object({
|
|
3669
|
+
version: import_zod5.z.literal(1),
|
|
3670
|
+
status: import_zod5.z.enum(["pending", "running", "paused", "done", "failed"]),
|
|
3671
|
+
startedAt: import_zod5.z.string().datetime({ offset: true }),
|
|
3672
|
+
updatedAt: import_zod5.z.string().datetime({ offset: true }),
|
|
3673
|
+
turnCount: import_zod5.z.number().int().nonnegative(),
|
|
3674
|
+
messageCount: import_zod5.z.number().int().nonnegative(),
|
|
3675
|
+
lastShardIndex: import_zod5.z.number().int().nonnegative().nullable(),
|
|
3676
|
+
shardCount: import_zod5.z.number().int().nonnegative()
|
|
3468
3677
|
}).strict();
|
|
3469
3678
|
var META_FILENAME = "meta.json";
|
|
3470
3679
|
function metaPath(logPath) {
|
|
@@ -3812,47 +4021,11 @@ Output format:
|
|
|
3812
4021
|
Directive: ${directive}`;
|
|
3813
4022
|
}
|
|
3814
4023
|
|
|
3815
|
-
// src/tools/contract.ts
|
|
3816
|
-
init_cjs_shims();
|
|
3817
|
-
function defineTool(tool) {
|
|
3818
|
-
return tool;
|
|
3819
|
-
}
|
|
3820
|
-
var ToolRegistry = class {
|
|
3821
|
-
tools = /* @__PURE__ */ new Map();
|
|
3822
|
-
register(tool) {
|
|
3823
|
-
if (typeof tool.name !== "string" || tool.name.length === 0) {
|
|
3824
|
-
throw new Error("ToolRegistry: tool.name must be a non-empty string");
|
|
3825
|
-
}
|
|
3826
|
-
if (this.tools.has(tool.name)) {
|
|
3827
|
-
throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
|
|
3828
|
-
}
|
|
3829
|
-
this.tools.set(tool.name, tool);
|
|
3830
|
-
}
|
|
3831
|
-
registerAll(tools) {
|
|
3832
|
-
for (const tool of tools) this.register(tool);
|
|
3833
|
-
}
|
|
3834
|
-
unregister(name) {
|
|
3835
|
-
this.tools.delete(name);
|
|
3836
|
-
}
|
|
3837
|
-
get(name) {
|
|
3838
|
-
return this.tools.get(name);
|
|
3839
|
-
}
|
|
3840
|
-
has(name) {
|
|
3841
|
-
return this.tools.has(name);
|
|
3842
|
-
}
|
|
3843
|
-
list() {
|
|
3844
|
-
return Array.from(this.tools.values());
|
|
3845
|
-
}
|
|
3846
|
-
count() {
|
|
3847
|
-
return this.tools.size;
|
|
3848
|
-
}
|
|
3849
|
-
};
|
|
3850
|
-
|
|
3851
4024
|
// src/tools/agent.ts
|
|
3852
|
-
var inputSchema =
|
|
3853
|
-
description:
|
|
3854
|
-
subagent_type:
|
|
3855
|
-
run_in_background:
|
|
4025
|
+
var inputSchema = import_zod6.z.object({
|
|
4026
|
+
description: import_zod6.z.string().min(1),
|
|
4027
|
+
subagent_type: import_zod6.z.string().optional(),
|
|
4028
|
+
run_in_background: import_zod6.z.boolean().optional()
|
|
3856
4029
|
});
|
|
3857
4030
|
function createAgentTool(options) {
|
|
3858
4031
|
if (options.agents.length === 0) {
|
|
@@ -4057,7 +4230,7 @@ function handlePausedResult(result, agentId, subagentType) {
|
|
|
4057
4230
|
|
|
4058
4231
|
// src/tools/bash.ts
|
|
4059
4232
|
init_cjs_shims();
|
|
4060
|
-
var
|
|
4233
|
+
var import_zod7 = require("zod");
|
|
4061
4234
|
var _spawn = null;
|
|
4062
4235
|
async function getSpawn() {
|
|
4063
4236
|
if (_spawn === null) {
|
|
@@ -4069,15 +4242,16 @@ async function getSpawn() {
|
|
|
4069
4242
|
var MAX_OUTPUT_BYTES = 512 * 1024;
|
|
4070
4243
|
var SIGKILL_GRACE_MS = 500;
|
|
4071
4244
|
var BLOCKED_DEVICE_PATHS = /\b(\/dev\/zero|\/dev\/random|\/dev\/urandom|\/proc\/kcore|\/dev\/sda|\/dev\/mem)\b/;
|
|
4072
|
-
var inputSchema2 =
|
|
4073
|
-
command:
|
|
4074
|
-
cwd:
|
|
4245
|
+
var inputSchema2 = import_zod7.z.object({
|
|
4246
|
+
command: import_zod7.z.string().min(1),
|
|
4247
|
+
cwd: import_zod7.z.string().min(1).optional()
|
|
4075
4248
|
});
|
|
4076
4249
|
function createBashTool() {
|
|
4077
4250
|
return defineTool({
|
|
4078
4251
|
name: "Bash",
|
|
4079
4252
|
description: "Execute a shell command via /bin/sh -c. Returns combined stdout+stderr and the exit code.",
|
|
4080
4253
|
inputSchema: inputSchema2,
|
|
4254
|
+
requiresNode: true,
|
|
4081
4255
|
execute: async ({ command, cwd }, ctx) => {
|
|
4082
4256
|
if (BLOCKED_DEVICE_PATHS.test(command)) {
|
|
4083
4257
|
return {
|
|
@@ -4157,10 +4331,10 @@ function createBashTool() {
|
|
|
4157
4331
|
|
|
4158
4332
|
// src/tools/sendMessage.ts
|
|
4159
4333
|
init_cjs_shims();
|
|
4160
|
-
var
|
|
4161
|
-
var inputSchema3 =
|
|
4162
|
-
to:
|
|
4163
|
-
message:
|
|
4334
|
+
var import_zod8 = require("zod");
|
|
4335
|
+
var inputSchema3 = import_zod8.z.object({
|
|
4336
|
+
to: import_zod8.z.string().min(1).describe("Agent name (subagent_type) or agentId to send the message to."),
|
|
4337
|
+
message: import_zod8.z.string().min(1).describe("Message content to deliver to the target agent.")
|
|
4164
4338
|
});
|
|
4165
4339
|
function createSendMessageTool(options) {
|
|
4166
4340
|
return defineTool({
|
|
@@ -4211,12 +4385,12 @@ function createSendMessageTool(options) {
|
|
|
4211
4385
|
|
|
4212
4386
|
// src/tools/fileEdit.ts
|
|
4213
4387
|
init_cjs_shims();
|
|
4214
|
-
var
|
|
4215
|
-
var inputSchema4 =
|
|
4216
|
-
path:
|
|
4217
|
-
old_string:
|
|
4218
|
-
new_string:
|
|
4219
|
-
replace_all:
|
|
4388
|
+
var import_zod9 = require("zod");
|
|
4389
|
+
var inputSchema4 = import_zod9.z.object({
|
|
4390
|
+
path: import_zod9.z.string().min(1),
|
|
4391
|
+
old_string: import_zod9.z.string().min(1),
|
|
4392
|
+
new_string: import_zod9.z.string(),
|
|
4393
|
+
replace_all: import_zod9.z.boolean().optional()
|
|
4220
4394
|
});
|
|
4221
4395
|
function createFileEditTool(storage) {
|
|
4222
4396
|
return defineTool({
|
|
@@ -4300,13 +4474,13 @@ function normalizeQuotes(s) {
|
|
|
4300
4474
|
|
|
4301
4475
|
// src/tools/fileRead.ts
|
|
4302
4476
|
init_cjs_shims();
|
|
4303
|
-
var
|
|
4304
|
-
var inputSchema5 =
|
|
4305
|
-
path:
|
|
4306
|
-
offset:
|
|
4307
|
-
limit:
|
|
4477
|
+
var import_zod10 = require("zod");
|
|
4478
|
+
var inputSchema5 = import_zod10.z.object({
|
|
4479
|
+
path: import_zod10.z.string().min(1),
|
|
4480
|
+
offset: import_zod10.z.number().int().positive().optional(),
|
|
4481
|
+
limit: import_zod10.z.number().int().positive().optional(),
|
|
4308
4482
|
/** PDF page range, e.g. "1-5", "3", "10-20". Max 20 pages per request. */
|
|
4309
|
-
pages:
|
|
4483
|
+
pages: import_zod10.z.string().optional()
|
|
4310
4484
|
});
|
|
4311
4485
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg"]);
|
|
4312
4486
|
var PDF_EXTENSION = ".pdf";
|
|
@@ -4474,7 +4648,7 @@ async function readImage(storage, filePath, ext) {
|
|
|
4474
4648
|
".svg": "image/svg+xml"
|
|
4475
4649
|
};
|
|
4476
4650
|
const mimeType = mimeMap[ext] ?? "application/octet-stream";
|
|
4477
|
-
const
|
|
4651
|
+
const base642 = buffer.toString("base64");
|
|
4478
4652
|
return {
|
|
4479
4653
|
content: `[Image: ${filePath} (${mimeType}, ${(buffer.length / 1024).toFixed(1)}KB)]
|
|
4480
4654
|
|
|
@@ -4483,17 +4657,17 @@ Base64 data is included in the metadata for visual analysis.`,
|
|
|
4483
4657
|
format: "image",
|
|
4484
4658
|
mimeType,
|
|
4485
4659
|
bytes: buffer.length,
|
|
4486
|
-
base64
|
|
4660
|
+
base64: base642
|
|
4487
4661
|
}
|
|
4488
4662
|
};
|
|
4489
4663
|
}
|
|
4490
4664
|
|
|
4491
4665
|
// src/tools/fileWrite.ts
|
|
4492
4666
|
init_cjs_shims();
|
|
4493
|
-
var
|
|
4494
|
-
var inputSchema6 =
|
|
4495
|
-
path:
|
|
4496
|
-
content:
|
|
4667
|
+
var import_zod11 = require("zod");
|
|
4668
|
+
var inputSchema6 = import_zod11.z.object({
|
|
4669
|
+
path: import_zod11.z.string().min(1),
|
|
4670
|
+
content: import_zod11.z.string()
|
|
4497
4671
|
});
|
|
4498
4672
|
function createFileWriteTool(storageOrOptions) {
|
|
4499
4673
|
const opts = "readFile" in storageOrOptions ? { storage: storageOrOptions } : storageOrOptions;
|
|
@@ -4532,7 +4706,7 @@ function createFileWriteTool(storageOrOptions) {
|
|
|
4532
4706
|
// src/tools/glob.ts
|
|
4533
4707
|
init_cjs_shims();
|
|
4534
4708
|
var import_picomatch = __toESM(require("picomatch"), 1);
|
|
4535
|
-
var
|
|
4709
|
+
var import_zod12 = require("zod");
|
|
4536
4710
|
|
|
4537
4711
|
// src/tools/walkAdapter.ts
|
|
4538
4712
|
init_cjs_shims();
|
|
@@ -4569,9 +4743,9 @@ async function* walkAdapter(adapter, startPath, options = {}) {
|
|
|
4569
4743
|
}
|
|
4570
4744
|
|
|
4571
4745
|
// src/tools/glob.ts
|
|
4572
|
-
var inputSchema7 =
|
|
4573
|
-
pattern:
|
|
4574
|
-
path:
|
|
4746
|
+
var inputSchema7 = import_zod12.z.object({
|
|
4747
|
+
pattern: import_zod12.z.string().min(1),
|
|
4748
|
+
path: import_zod12.z.string().optional()
|
|
4575
4749
|
});
|
|
4576
4750
|
var MAX_RESULTS = 1e3;
|
|
4577
4751
|
function createGlobTool(storage) {
|
|
@@ -4624,22 +4798,22 @@ function createGlobTool(storage) {
|
|
|
4624
4798
|
// src/tools/grep.ts
|
|
4625
4799
|
init_cjs_shims();
|
|
4626
4800
|
var import_picomatch2 = __toESM(require("picomatch"), 1);
|
|
4627
|
-
var
|
|
4628
|
-
var inputSchema8 =
|
|
4629
|
-
pattern:
|
|
4630
|
-
path:
|
|
4631
|
-
glob:
|
|
4632
|
-
type:
|
|
4633
|
-
output_mode:
|
|
4634
|
-
"-i":
|
|
4635
|
-
"-n":
|
|
4636
|
-
"-A":
|
|
4637
|
-
"-B":
|
|
4638
|
-
"-C":
|
|
4639
|
-
context:
|
|
4640
|
-
multiline:
|
|
4641
|
-
head_limit:
|
|
4642
|
-
offset:
|
|
4801
|
+
var import_zod13 = require("zod");
|
|
4802
|
+
var inputSchema8 = import_zod13.z.object({
|
|
4803
|
+
pattern: import_zod13.z.string().min(1),
|
|
4804
|
+
path: import_zod13.z.string().optional(),
|
|
4805
|
+
glob: import_zod13.z.string().optional(),
|
|
4806
|
+
type: import_zod13.z.string().optional(),
|
|
4807
|
+
output_mode: import_zod13.z.enum(["content", "files_with_matches", "count"]).optional(),
|
|
4808
|
+
"-i": import_zod13.z.boolean().optional(),
|
|
4809
|
+
"-n": import_zod13.z.boolean().optional(),
|
|
4810
|
+
"-A": import_zod13.z.number().int().nonnegative().optional(),
|
|
4811
|
+
"-B": import_zod13.z.number().int().nonnegative().optional(),
|
|
4812
|
+
"-C": import_zod13.z.number().int().nonnegative().optional(),
|
|
4813
|
+
context: import_zod13.z.number().int().nonnegative().optional(),
|
|
4814
|
+
multiline: import_zod13.z.boolean().optional(),
|
|
4815
|
+
head_limit: import_zod13.z.number().int().nonnegative().optional(),
|
|
4816
|
+
offset: import_zod13.z.number().int().nonnegative().optional()
|
|
4643
4817
|
});
|
|
4644
4818
|
var MAX_FILES_SCANNED = 5e3;
|
|
4645
4819
|
var MAX_MATCHES_PER_FILE = 100;
|
|
@@ -4863,10 +5037,10 @@ function formatJsResults(results, mode, limit) {
|
|
|
4863
5037
|
|
|
4864
5038
|
// src/tools/webFetch.ts
|
|
4865
5039
|
init_cjs_shims();
|
|
4866
|
-
var
|
|
4867
|
-
var inputSchema9 =
|
|
4868
|
-
url:
|
|
4869
|
-
prompt:
|
|
5040
|
+
var import_zod14 = require("zod");
|
|
5041
|
+
var inputSchema9 = import_zod14.z.object({
|
|
5042
|
+
url: import_zod14.z.string().url(),
|
|
5043
|
+
prompt: import_zod14.z.string().optional()
|
|
4870
5044
|
});
|
|
4871
5045
|
var MAX_OUTPUT_BYTES2 = 256 * 1024;
|
|
4872
5046
|
function createWebFetchTool(options = {}) {
|
|
@@ -4995,10 +5169,10 @@ function normalizePath(p) {
|
|
|
4995
5169
|
|
|
4996
5170
|
// src/tools/webSearch.ts
|
|
4997
5171
|
init_cjs_shims();
|
|
4998
|
-
var
|
|
4999
|
-
var inputSchema10 =
|
|
5000
|
-
query:
|
|
5001
|
-
max_results:
|
|
5172
|
+
var import_zod15 = require("zod");
|
|
5173
|
+
var inputSchema10 = import_zod15.z.object({
|
|
5174
|
+
query: import_zod15.z.string().min(2),
|
|
5175
|
+
max_results: import_zod15.z.number().int().positive().optional()
|
|
5002
5176
|
});
|
|
5003
5177
|
function createWebSearchTool() {
|
|
5004
5178
|
return defineTool({
|
|
@@ -5055,10 +5229,10 @@ function htmlToText2(html) {
|
|
|
5055
5229
|
|
|
5056
5230
|
// src/tools/sleep.ts
|
|
5057
5231
|
init_cjs_shims();
|
|
5058
|
-
var
|
|
5059
|
-
var inputSchema11 =
|
|
5060
|
-
durationMs:
|
|
5061
|
-
reason:
|
|
5232
|
+
var import_zod16 = require("zod");
|
|
5233
|
+
var inputSchema11 = import_zod16.z.object({
|
|
5234
|
+
durationMs: import_zod16.z.number().int().nonnegative().max(3e5),
|
|
5235
|
+
reason: import_zod16.z.string().optional()
|
|
5062
5236
|
});
|
|
5063
5237
|
function createSleepTool() {
|
|
5064
5238
|
return defineTool({
|
|
@@ -5098,10 +5272,10 @@ function createSleepTool() {
|
|
|
5098
5272
|
|
|
5099
5273
|
// src/tools/toolSearch.ts
|
|
5100
5274
|
init_cjs_shims();
|
|
5101
|
-
var
|
|
5102
|
-
var inputSchema12 =
|
|
5103
|
-
query:
|
|
5104
|
-
max_results:
|
|
5275
|
+
var import_zod17 = require("zod");
|
|
5276
|
+
var inputSchema12 = import_zod17.z.object({
|
|
5277
|
+
query: import_zod17.z.string().min(1),
|
|
5278
|
+
max_results: import_zod17.z.number().int().positive().optional()
|
|
5105
5279
|
});
|
|
5106
5280
|
function createToolSearchTool(registry) {
|
|
5107
5281
|
return defineTool({
|
|
@@ -5144,11 +5318,11 @@ ${lines.join("\n")}`,
|
|
|
5144
5318
|
|
|
5145
5319
|
// src/tools/memorize.ts
|
|
5146
5320
|
init_cjs_shims();
|
|
5147
|
-
var
|
|
5148
|
-
var inputSchema13 =
|
|
5149
|
-
text:
|
|
5150
|
-
kind:
|
|
5151
|
-
topic:
|
|
5321
|
+
var import_zod18 = require("zod");
|
|
5322
|
+
var inputSchema13 = import_zod18.z.object({
|
|
5323
|
+
text: import_zod18.z.string().min(1),
|
|
5324
|
+
kind: import_zod18.z.enum(["rule", "lesson"]).default("lesson"),
|
|
5325
|
+
topic: import_zod18.z.string().optional()
|
|
5152
5326
|
});
|
|
5153
5327
|
function createMemorizeTool(memory) {
|
|
5154
5328
|
return defineTool({
|
|
@@ -5180,11 +5354,11 @@ function createMemorizeTool(memory) {
|
|
|
5180
5354
|
|
|
5181
5355
|
// src/tools/recall.ts
|
|
5182
5356
|
init_cjs_shims();
|
|
5183
|
-
var
|
|
5184
|
-
var inputSchema14 =
|
|
5185
|
-
query:
|
|
5186
|
-
scope:
|
|
5187
|
-
topic:
|
|
5357
|
+
var import_zod19 = require("zod");
|
|
5358
|
+
var inputSchema14 = import_zod19.z.object({
|
|
5359
|
+
query: import_zod19.z.string().min(1),
|
|
5360
|
+
scope: import_zod19.z.enum(["identity", "rules", "lessons", "all"]).default("all"),
|
|
5361
|
+
topic: import_zod19.z.string().optional()
|
|
5188
5362
|
});
|
|
5189
5363
|
function createRecallTool(memory) {
|
|
5190
5364
|
return defineTool({
|
|
@@ -5239,13 +5413,13 @@ ${content}`,
|
|
|
5239
5413
|
|
|
5240
5414
|
// src/tools/notebookEdit.ts
|
|
5241
5415
|
init_cjs_shims();
|
|
5242
|
-
var
|
|
5243
|
-
var inputSchema15 =
|
|
5244
|
-
notebook_path:
|
|
5245
|
-
edit_mode:
|
|
5246
|
-
cell_index:
|
|
5247
|
-
new_source:
|
|
5248
|
-
cell_type:
|
|
5416
|
+
var import_zod20 = require("zod");
|
|
5417
|
+
var inputSchema15 = import_zod20.z.object({
|
|
5418
|
+
notebook_path: import_zod20.z.string().min(1),
|
|
5419
|
+
edit_mode: import_zod20.z.enum(["replace", "insert", "delete"]).default("replace"),
|
|
5420
|
+
cell_index: import_zod20.z.number().int().nonnegative(),
|
|
5421
|
+
new_source: import_zod20.z.string().optional(),
|
|
5422
|
+
cell_type: import_zod20.z.enum(["code", "markdown"]).optional()
|
|
5249
5423
|
});
|
|
5250
5424
|
function createNotebookEditTool(storage) {
|
|
5251
5425
|
return defineTool({
|
|
@@ -5400,12 +5574,12 @@ var TaskStore = class {
|
|
|
5400
5574
|
|
|
5401
5575
|
// src/tools/tasks/tools.ts
|
|
5402
5576
|
init_cjs_shims();
|
|
5403
|
-
var
|
|
5404
|
-
var TaskStatusEnum =
|
|
5405
|
-
var createSchema =
|
|
5406
|
-
subject:
|
|
5407
|
-
description:
|
|
5408
|
-
metadata:
|
|
5577
|
+
var import_zod21 = require("zod");
|
|
5578
|
+
var TaskStatusEnum = import_zod21.z.enum(["pending", "in_progress", "completed", "deleted"]);
|
|
5579
|
+
var createSchema = import_zod21.z.object({
|
|
5580
|
+
subject: import_zod21.z.string().min(1),
|
|
5581
|
+
description: import_zod21.z.string().default(""),
|
|
5582
|
+
metadata: import_zod21.z.record(import_zod21.z.unknown()).optional()
|
|
5409
5583
|
});
|
|
5410
5584
|
function createTaskCreateTool(store) {
|
|
5411
5585
|
return defineTool({
|
|
@@ -5421,8 +5595,8 @@ function createTaskCreateTool(store) {
|
|
|
5421
5595
|
}
|
|
5422
5596
|
});
|
|
5423
5597
|
}
|
|
5424
|
-
var getSchema =
|
|
5425
|
-
taskId:
|
|
5598
|
+
var getSchema = import_zod21.z.object({
|
|
5599
|
+
taskId: import_zod21.z.string().min(1)
|
|
5426
5600
|
});
|
|
5427
5601
|
function createTaskGetTool(store) {
|
|
5428
5602
|
return defineTool({
|
|
@@ -5443,7 +5617,7 @@ ${task.description}`,
|
|
|
5443
5617
|
}
|
|
5444
5618
|
});
|
|
5445
5619
|
}
|
|
5446
|
-
var listSchema =
|
|
5620
|
+
var listSchema = import_zod21.z.object({
|
|
5447
5621
|
status: TaskStatusEnum.optional()
|
|
5448
5622
|
});
|
|
5449
5623
|
function createTaskListTool(store) {
|
|
@@ -5469,12 +5643,12 @@ ${lines.join("\n")}`,
|
|
|
5469
5643
|
}
|
|
5470
5644
|
});
|
|
5471
5645
|
}
|
|
5472
|
-
var updateSchema =
|
|
5473
|
-
taskId:
|
|
5474
|
-
subject:
|
|
5646
|
+
var updateSchema = import_zod21.z.object({
|
|
5647
|
+
taskId: import_zod21.z.string().min(1),
|
|
5648
|
+
subject: import_zod21.z.string().min(1).optional(),
|
|
5475
5649
|
status: TaskStatusEnum.optional(),
|
|
5476
|
-
description:
|
|
5477
|
-
metadata:
|
|
5650
|
+
description: import_zod21.z.string().optional(),
|
|
5651
|
+
metadata: import_zod21.z.record(import_zod21.z.unknown()).optional()
|
|
5478
5652
|
});
|
|
5479
5653
|
function createTaskUpdateTool(store) {
|
|
5480
5654
|
return defineTool({
|
|
@@ -6321,7 +6495,7 @@ function wrapFetchWithHeadersProvider(baseFetch, headersProvider, staticHeaders)
|
|
|
6321
6495
|
|
|
6322
6496
|
// src/mcp/toolAdapter.ts
|
|
6323
6497
|
init_cjs_shims();
|
|
6324
|
-
var
|
|
6498
|
+
var import_zod22 = require("zod");
|
|
6325
6499
|
function mcpToolName(serverName, toolName) {
|
|
6326
6500
|
return `mcp__${serverName}__${toolName}`;
|
|
6327
6501
|
}
|
|
@@ -6330,7 +6504,7 @@ function adaptMcpTool(client, serverName, def) {
|
|
|
6330
6504
|
return defineTool({
|
|
6331
6505
|
name: registeredName,
|
|
6332
6506
|
description: def.description.length > 0 ? def.description : `MCP tool ${serverName}/${def.name}`,
|
|
6333
|
-
inputSchema:
|
|
6507
|
+
inputSchema: import_zod22.z.unknown(),
|
|
6334
6508
|
// Pass the MCP server's JSON Schema through to Anthropic verbatim,
|
|
6335
6509
|
// bypassing Zod-to-JSON-Schema conversion (which would produce `{}`
|
|
6336
6510
|
// for our `z.unknown()` Zod schema).
|
|
@@ -7439,11 +7613,11 @@ ${issues.join("\n")}` };
|
|
|
7439
7613
|
|
|
7440
7614
|
// src/skills/skillPage.ts
|
|
7441
7615
|
init_cjs_shims();
|
|
7442
|
-
var
|
|
7616
|
+
var import_zod23 = require("zod");
|
|
7443
7617
|
var SAFE_NAME3 = /^[a-zA-Z0-9_-]+$/;
|
|
7444
|
-
var inputSchema16 =
|
|
7445
|
-
skill:
|
|
7446
|
-
page:
|
|
7618
|
+
var inputSchema16 = import_zod23.z.object({
|
|
7619
|
+
skill: import_zod23.z.string().min(1),
|
|
7620
|
+
page: import_zod23.z.string().min(1).optional()
|
|
7447
7621
|
});
|
|
7448
7622
|
function createSkillPageTool(options) {
|
|
7449
7623
|
return defineTool({
|
|
@@ -7499,6 +7673,203 @@ The skill "${skill}" has no pages.`;
|
|
|
7499
7673
|
});
|
|
7500
7674
|
}
|
|
7501
7675
|
|
|
7676
|
+
// src/tools/apiCall.ts
|
|
7677
|
+
init_cjs_shims();
|
|
7678
|
+
var import_zod24 = require("zod");
|
|
7679
|
+
var ALL_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
7680
|
+
var DEFAULT_MAX_BODY_BYTES = 256 * 1024;
|
|
7681
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024;
|
|
7682
|
+
function createApiCallTool(opts) {
|
|
7683
|
+
if (opts.services.length === 0) {
|
|
7684
|
+
throw new Error("createApiCallTool: services list must be non-empty");
|
|
7685
|
+
}
|
|
7686
|
+
const services = /* @__PURE__ */ new Map();
|
|
7687
|
+
for (const svc of opts.services) {
|
|
7688
|
+
if (services.has(svc.name)) {
|
|
7689
|
+
throw new Error(`createApiCallTool: duplicate service name "${svc.name}"`);
|
|
7690
|
+
}
|
|
7691
|
+
services.set(svc.name, svc);
|
|
7692
|
+
}
|
|
7693
|
+
const serviceNames = [...services.keys()];
|
|
7694
|
+
for (const svc of opts.services) {
|
|
7695
|
+
if (svc.auth?.type === "custom" && opts.resolveAuth === void 0) {
|
|
7696
|
+
throw new Error(
|
|
7697
|
+
`createApiCallTool: service "${svc.name}" uses custom auth (id: ${svc.auth.id}) but no resolveAuth was supplied`
|
|
7698
|
+
);
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
7702
|
+
const maxResponseBytes = opts.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
7703
|
+
const inputSchema17 = import_zod24.z.object({
|
|
7704
|
+
service: import_zod24.z.enum(serviceNames),
|
|
7705
|
+
method: import_zod24.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
7706
|
+
path: import_zod24.z.string().regex(/^\//, "path must start with /"),
|
|
7707
|
+
query: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
|
|
7708
|
+
body: import_zod24.z.unknown().optional(),
|
|
7709
|
+
headers: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
|
|
7710
|
+
});
|
|
7711
|
+
const description = opts.toolDescription ?? `Call a configured external API. Services: ${serviceNames.join(", ")}. Auth is injected automatically \u2014 do not pass credentials via headers.`;
|
|
7712
|
+
return defineTool({
|
|
7713
|
+
name: opts.toolName ?? "ApiCall",
|
|
7714
|
+
description,
|
|
7715
|
+
inputSchema: inputSchema17,
|
|
7716
|
+
execute: async (input) => {
|
|
7717
|
+
const svc = services.get(input.service);
|
|
7718
|
+
if (!svc) {
|
|
7719
|
+
return errResult(`ERR_API_UNKNOWN_SERVICE: ${input.service}`);
|
|
7720
|
+
}
|
|
7721
|
+
const allowedMethods = svc.allowedMethods ?? ALL_METHODS;
|
|
7722
|
+
if (!allowedMethods.includes(input.method)) {
|
|
7723
|
+
return errResult(
|
|
7724
|
+
`ERR_API_METHOD_NOT_ALLOWED: ${input.method} not permitted for service ${svc.name}`
|
|
7725
|
+
);
|
|
7726
|
+
}
|
|
7727
|
+
if (!pathAllowed(input.path, svc.allowedPaths)) {
|
|
7728
|
+
return errResult(`ERR_API_PATH_NOT_ALLOWED: ${input.path} for service ${svc.name}`);
|
|
7729
|
+
}
|
|
7730
|
+
let bodyText;
|
|
7731
|
+
if (input.body !== void 0) {
|
|
7732
|
+
bodyText = JSON.stringify(input.body);
|
|
7733
|
+
const cap = svc.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
7734
|
+
if (byteLength(bodyText) > cap) {
|
|
7735
|
+
return errResult(`ERR_API_BODY_TOO_LARGE: exceeds ${cap} bytes`);
|
|
7736
|
+
}
|
|
7737
|
+
}
|
|
7738
|
+
let authHeaders;
|
|
7739
|
+
try {
|
|
7740
|
+
authHeaders = await resolveAuth({
|
|
7741
|
+
auth: svc.auth ?? { type: "none" },
|
|
7742
|
+
env: opts.env,
|
|
7743
|
+
resolver: opts.resolveAuth,
|
|
7744
|
+
ctx: { serviceName: svc.name, method: input.method, path: input.path }
|
|
7745
|
+
});
|
|
7746
|
+
} catch (err) {
|
|
7747
|
+
const raw2 = err instanceof Error ? err.message : String(err);
|
|
7748
|
+
const truncated = raw2.length > 200 ? raw2.slice(0, 200) + "\u2026" : raw2;
|
|
7749
|
+
return errResult(`ERR_API_RESOLVER_FAILED: ${truncated}`);
|
|
7750
|
+
}
|
|
7751
|
+
const userHeaders = sanitizeHeaders(input.headers ?? {}, authHeaders);
|
|
7752
|
+
const url = buildUrl(svc.baseUrl, input.path, input.query);
|
|
7753
|
+
await invokeHook(opts.onRequest, {
|
|
7754
|
+
service: svc.name,
|
|
7755
|
+
method: input.method,
|
|
7756
|
+
path: input.path
|
|
7757
|
+
});
|
|
7758
|
+
const started = Date.now();
|
|
7759
|
+
let res;
|
|
7760
|
+
try {
|
|
7761
|
+
res = await fetchFn(url, {
|
|
7762
|
+
method: input.method,
|
|
7763
|
+
headers: {
|
|
7764
|
+
"Content-Type": "application/json",
|
|
7765
|
+
...svc.defaultHeaders ?? {},
|
|
7766
|
+
...userHeaders,
|
|
7767
|
+
...authHeaders
|
|
7768
|
+
// wins last — model cannot override
|
|
7769
|
+
},
|
|
7770
|
+
...bodyText !== void 0 ? { body: bodyText } : {}
|
|
7771
|
+
});
|
|
7772
|
+
} catch (err) {
|
|
7773
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7774
|
+
return errResult(`network error: ${msg}`);
|
|
7775
|
+
}
|
|
7776
|
+
const raw = await res.text();
|
|
7777
|
+
const content = raw.length > maxResponseBytes ? raw.slice(0, maxResponseBytes) + "\n\u2026[TRUNCATED]" : raw;
|
|
7778
|
+
await invokeHook(opts.onResponse, {
|
|
7779
|
+
service: svc.name,
|
|
7780
|
+
method: input.method,
|
|
7781
|
+
path: input.path,
|
|
7782
|
+
status: res.status,
|
|
7783
|
+
latencyMs: Date.now() - started,
|
|
7784
|
+
bytesIn: raw.length
|
|
7785
|
+
});
|
|
7786
|
+
return {
|
|
7787
|
+
content,
|
|
7788
|
+
isError: !res.ok,
|
|
7789
|
+
metadata: { status: res.status, service: svc.name }
|
|
7790
|
+
};
|
|
7791
|
+
}
|
|
7792
|
+
});
|
|
7793
|
+
}
|
|
7794
|
+
function errResult(msg) {
|
|
7795
|
+
return { content: msg, isError: true };
|
|
7796
|
+
}
|
|
7797
|
+
function pathAllowed(path, allowed) {
|
|
7798
|
+
if (!allowed || allowed.length === 0) return true;
|
|
7799
|
+
for (const a of allowed) {
|
|
7800
|
+
if (typeof a === "string") {
|
|
7801
|
+
if (path.startsWith(a)) return true;
|
|
7802
|
+
} else if (a.test(path)) {
|
|
7803
|
+
return true;
|
|
7804
|
+
}
|
|
7805
|
+
}
|
|
7806
|
+
return false;
|
|
7807
|
+
}
|
|
7808
|
+
function byteLength(s) {
|
|
7809
|
+
return new TextEncoder().encode(s).byteLength;
|
|
7810
|
+
}
|
|
7811
|
+
function buildUrl(baseUrl, path, query) {
|
|
7812
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
7813
|
+
const url = new URL(base + path);
|
|
7814
|
+
for (const [k, v] of Object.entries(query ?? {})) {
|
|
7815
|
+
url.searchParams.set(k, v);
|
|
7816
|
+
}
|
|
7817
|
+
return url.toString();
|
|
7818
|
+
}
|
|
7819
|
+
function sanitizeHeaders(user, auth) {
|
|
7820
|
+
const banned = new Set(Object.keys(auth).map((k) => k.toLowerCase()));
|
|
7821
|
+
const out = {};
|
|
7822
|
+
for (const [k, v] of Object.entries(user)) {
|
|
7823
|
+
if (banned.has(k.toLowerCase())) continue;
|
|
7824
|
+
out[k] = v;
|
|
7825
|
+
}
|
|
7826
|
+
return out;
|
|
7827
|
+
}
|
|
7828
|
+
async function resolveAuth(args) {
|
|
7829
|
+
const { auth, env, resolver, ctx } = args;
|
|
7830
|
+
switch (auth.type) {
|
|
7831
|
+
case "none":
|
|
7832
|
+
return {};
|
|
7833
|
+
case "bearer": {
|
|
7834
|
+
const token = envLookup(env, auth.tokenRef);
|
|
7835
|
+
return { Authorization: `Bearer ${token}` };
|
|
7836
|
+
}
|
|
7837
|
+
case "header": {
|
|
7838
|
+
const value = envLookup(env, auth.valueRef);
|
|
7839
|
+
return { [auth.name]: value };
|
|
7840
|
+
}
|
|
7841
|
+
case "basic": {
|
|
7842
|
+
const u = envLookup(env, auth.userRef);
|
|
7843
|
+
const p = envLookup(env, auth.passRef);
|
|
7844
|
+
return { Authorization: `Basic ${base64(`${u}:${p}`)}` };
|
|
7845
|
+
}
|
|
7846
|
+
case "custom":
|
|
7847
|
+
if (resolver === void 0) {
|
|
7848
|
+
throw new Error(`custom auth id "${auth.id}" requires resolveAuth`);
|
|
7849
|
+
}
|
|
7850
|
+
return resolver(auth, ctx);
|
|
7851
|
+
}
|
|
7852
|
+
}
|
|
7853
|
+
function envLookup(env, ref) {
|
|
7854
|
+
if (env === void 0 || env[ref] === void 0) {
|
|
7855
|
+
throw new Error(`ERR_API_ENV_MISSING: ${ref}`);
|
|
7856
|
+
}
|
|
7857
|
+
return env[ref];
|
|
7858
|
+
}
|
|
7859
|
+
function base64(input) {
|
|
7860
|
+
if (typeof globalThis.btoa === "function") {
|
|
7861
|
+
return globalThis.btoa(input);
|
|
7862
|
+
}
|
|
7863
|
+
return Buffer.from(input, "utf8").toString("base64");
|
|
7864
|
+
}
|
|
7865
|
+
async function invokeHook(hook, event) {
|
|
7866
|
+
if (hook === void 0) return;
|
|
7867
|
+
try {
|
|
7868
|
+
await hook(event);
|
|
7869
|
+
} catch {
|
|
7870
|
+
}
|
|
7871
|
+
}
|
|
7872
|
+
|
|
7502
7873
|
// src/skills/storageSkillSource.ts
|
|
7503
7874
|
init_cjs_shims();
|
|
7504
7875
|
var SAFE_NAME4 = /^[a-zA-Z0-9_-]+$/;
|
|
@@ -8274,6 +8645,7 @@ function rebuildMessagesFromEntries(entries) {
|
|
|
8274
8645
|
init_cjs_shims();
|
|
8275
8646
|
function toResponse(result, extra) {
|
|
8276
8647
|
const timestamp = Date.now();
|
|
8648
|
+
const capsField = extra.capabilitiesMissing !== void 0 && extra.capabilitiesMissing.length > 0 ? { capabilitiesMissing: extra.capabilitiesMissing } : {};
|
|
8277
8649
|
if (result.status === "done") {
|
|
8278
8650
|
return {
|
|
8279
8651
|
runId: extra.runId,
|
|
@@ -8285,7 +8657,8 @@ function toResponse(result, extra) {
|
|
|
8285
8657
|
tokensUsed: result.tokensUsed,
|
|
8286
8658
|
durationMs: extra.durationMs,
|
|
8287
8659
|
output: result.output,
|
|
8288
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {}
|
|
8660
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {},
|
|
8661
|
+
...capsField
|
|
8289
8662
|
},
|
|
8290
8663
|
errors: [],
|
|
8291
8664
|
timestamp
|
|
@@ -8304,7 +8677,8 @@ function toResponse(result, extra) {
|
|
|
8304
8677
|
snapshot: result.snapshot,
|
|
8305
8678
|
...result.snapshot.pendingToolCall !== void 0 ? { pendingToolCall: result.snapshot.pendingToolCall } : {},
|
|
8306
8679
|
pauseReason: result.reason,
|
|
8307
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {}
|
|
8680
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {},
|
|
8681
|
+
...capsField
|
|
8308
8682
|
},
|
|
8309
8683
|
errors: [],
|
|
8310
8684
|
timestamp
|
|
@@ -8638,7 +9012,15 @@ var Engine = class {
|
|
|
8638
9012
|
this.mcpManager = new McpManager(config.mcp, createLogger(config.logging), { samplingHandler });
|
|
8639
9013
|
this.permissionPolicy = buildPermissionPolicy(config.permissions);
|
|
8640
9014
|
}
|
|
8641
|
-
|
|
9015
|
+
/**
|
|
9016
|
+
* Run a task synchronously to completion. The `_internal` parameter is
|
|
9017
|
+
* reserved for the engine's own async wrappers (`start`, `resumeAsync`)
|
|
9018
|
+
* to request runner handoff (Plan 019) — external callers must leave
|
|
9019
|
+
* it unset. Sync callers never hand off; if they hit a Node-only tool
|
|
9020
|
+
* on a restricted runtime, the capability stub returns an error and
|
|
9021
|
+
* the model adapts.
|
|
9022
|
+
*/
|
|
9023
|
+
async run(options, _internal) {
|
|
8642
9024
|
const startTime = Date.now();
|
|
8643
9025
|
const runId = options.runId ?? `run_${randomUUID()}`;
|
|
8644
9026
|
const log = createLogger(this.config.logging);
|
|
@@ -8661,6 +9043,7 @@ var Engine = class {
|
|
|
8661
9043
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8662
9044
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8663
9045
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
9046
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8664
9047
|
let systemPrompt = await buildSystemPrompt({
|
|
8665
9048
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8666
9049
|
memory,
|
|
@@ -8691,7 +9074,9 @@ var Engine = class {
|
|
|
8691
9074
|
mcpTools,
|
|
8692
9075
|
memory,
|
|
8693
9076
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8694
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
9077
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
9078
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
9079
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8695
9080
|
});
|
|
8696
9081
|
const writer = new TranscriptWriter({
|
|
8697
9082
|
storage: storage.workspace,
|
|
@@ -8745,7 +9130,8 @@ var Engine = class {
|
|
|
8745
9130
|
onProgress: this.buildHeartbeat(storage, runId, options.nodeId),
|
|
8746
9131
|
...options.tokenBudget !== void 0 ? { tokenBudget: options.tokenBudget } : {},
|
|
8747
9132
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8748
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9133
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9134
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8749
9135
|
});
|
|
8750
9136
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8751
9137
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8753,18 +9139,20 @@ var Engine = class {
|
|
|
8753
9139
|
});
|
|
8754
9140
|
this.logRunEnd(log, runId, options.nodeId, result);
|
|
8755
9141
|
await this.firePostRunHook(runId, options.nodeId, result, ctx, logPath);
|
|
9142
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8756
9143
|
return toResponse(result, {
|
|
8757
9144
|
runId,
|
|
8758
9145
|
nodeId: options.nodeId,
|
|
8759
9146
|
durationMs: Date.now() - startTime,
|
|
8760
|
-
logPath
|
|
9147
|
+
logPath,
|
|
9148
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8761
9149
|
});
|
|
8762
9150
|
} finally {
|
|
8763
9151
|
runTimeout.clear();
|
|
8764
9152
|
await writer.close();
|
|
8765
9153
|
}
|
|
8766
9154
|
}
|
|
8767
|
-
async resume(options) {
|
|
9155
|
+
async resume(options, _internal) {
|
|
8768
9156
|
const startTime = Date.now();
|
|
8769
9157
|
const log = createLogger(this.config.logging);
|
|
8770
9158
|
const storage = await this.buildStorage();
|
|
@@ -8797,6 +9185,7 @@ var Engine = class {
|
|
|
8797
9185
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8798
9186
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8799
9187
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
9188
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8800
9189
|
let systemPrompt = await buildSystemPrompt({
|
|
8801
9190
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8802
9191
|
memory,
|
|
@@ -8827,7 +9216,9 @@ var Engine = class {
|
|
|
8827
9216
|
mcpTools,
|
|
8828
9217
|
memory,
|
|
8829
9218
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8830
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
9219
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
9220
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
9221
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8831
9222
|
});
|
|
8832
9223
|
const priorState = await loadWriterState(storage.workspace, logPath);
|
|
8833
9224
|
const writer = new TranscriptWriter({
|
|
@@ -8881,18 +9272,21 @@ var Engine = class {
|
|
|
8881
9272
|
const answer = typeof options.gateAnswer === "string" ? options.gateAnswer : JSON.stringify(options.gateAnswer);
|
|
8882
9273
|
await ctx.addToolResult(pending.toolUseId, answer, false);
|
|
8883
9274
|
} else {
|
|
8884
|
-
await ctx.addToolResult(
|
|
8885
|
-
pending.toolUseId,
|
|
8886
|
-
`APPROVAL_GATE_RELEASED: the prior ${pending.toolName} call was paused for human approval and has now been approved. Retry is required.`,
|
|
8887
|
-
false
|
|
8888
|
-
);
|
|
8889
9275
|
const inputJson = JSON.stringify(pending.input ?? {}, null, 2);
|
|
8890
|
-
await ctx.
|
|
8891
|
-
|
|
9276
|
+
await ctx.addMixedUserMessage([
|
|
9277
|
+
{
|
|
9278
|
+
type: "tool_result",
|
|
9279
|
+
tool_use_id: pending.toolUseId,
|
|
9280
|
+
content: `APPROVAL_GATE_RELEASED: the prior ${pending.toolName} call was paused for human approval and has now been approved. Retry is required.`
|
|
9281
|
+
},
|
|
9282
|
+
{
|
|
9283
|
+
type: "text",
|
|
9284
|
+
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):
|
|
8892
9285
|
\`\`\`json
|
|
8893
9286
|
${inputJson}
|
|
8894
9287
|
\`\`\``
|
|
8895
|
-
|
|
9288
|
+
}
|
|
9289
|
+
]);
|
|
8896
9290
|
}
|
|
8897
9291
|
}
|
|
8898
9292
|
await writer.setStatus("running");
|
|
@@ -8913,7 +9307,8 @@ ${inputJson}
|
|
|
8913
9307
|
stopHooks: this.config.hooks.stopHooks,
|
|
8914
9308
|
onProgress: this.buildHeartbeat(storage, snapshot.runId, snapshot.nodeId),
|
|
8915
9309
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8916
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9310
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9311
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8917
9312
|
});
|
|
8918
9313
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8919
9314
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8921,11 +9316,13 @@ ${inputJson}
|
|
|
8921
9316
|
});
|
|
8922
9317
|
this.logRunEnd(log, snapshot.runId, snapshot.nodeId, result);
|
|
8923
9318
|
await this.firePostRunHook(snapshot.runId, snapshot.nodeId, result, ctx, logPath);
|
|
9319
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8924
9320
|
return toResponse(result, {
|
|
8925
9321
|
runId: snapshot.runId,
|
|
8926
9322
|
nodeId: snapshot.nodeId,
|
|
8927
9323
|
durationMs: Date.now() - startTime,
|
|
8928
|
-
logPath
|
|
9324
|
+
logPath,
|
|
9325
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8929
9326
|
});
|
|
8930
9327
|
} finally {
|
|
8931
9328
|
runTimeout.clear();
|
|
@@ -8995,13 +9392,15 @@ ${inputJson}
|
|
|
8995
9392
|
} : void 0;
|
|
8996
9393
|
const initial = RunStateManager.initial(runId, options.nodeId, webhook);
|
|
8997
9394
|
await stateManager.write(initial);
|
|
9395
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
8998
9396
|
this.backgroundExecutor.schedule(runId, async (signal) => {
|
|
8999
9397
|
await stateManager.update(runId, options.nodeId, { status: "running" });
|
|
9000
9398
|
try {
|
|
9001
|
-
const response = await this.run({ ...options, runId });
|
|
9399
|
+
const response = await this.run({ ...options, runId }, { handoffToRunner: handoffEnabled });
|
|
9002
9400
|
if (signal.aborted) return;
|
|
9003
|
-
await
|
|
9004
|
-
await
|
|
9401
|
+
const postHandoff = await this.maybeHandoffToRunner(runId, options.nodeId, response);
|
|
9402
|
+
await stateManager.finalize(runId, options.nodeId, postHandoff);
|
|
9403
|
+
await this.maybeFireWebhook(stateManager, runId, options.nodeId, postHandoff);
|
|
9005
9404
|
} catch (err) {
|
|
9006
9405
|
if (signal.aborted) return;
|
|
9007
9406
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9049,12 +9448,14 @@ ${inputJson}
|
|
|
9049
9448
|
} : { ...RunStateManager.initial(options.runId, nodeId, webhook), status: "running" };
|
|
9050
9449
|
await stateManager.write(next);
|
|
9051
9450
|
const resumeNodeId = nodeId;
|
|
9451
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
9052
9452
|
this.backgroundExecutor.schedule(options.runId, async (signal) => {
|
|
9053
9453
|
try {
|
|
9054
|
-
const response = await this.resume(options);
|
|
9454
|
+
const response = await this.resume(options, { handoffToRunner: handoffEnabled });
|
|
9055
9455
|
if (signal.aborted) return;
|
|
9056
|
-
await
|
|
9057
|
-
await
|
|
9456
|
+
const postHandoff = await this.maybeHandoffToRunner(options.runId, resumeNodeId, response);
|
|
9457
|
+
await stateManager.finalize(options.runId, resumeNodeId, postHandoff);
|
|
9458
|
+
await this.maybeFireWebhook(stateManager, options.runId, resumeNodeId, postHandoff);
|
|
9058
9459
|
} catch (err) {
|
|
9059
9460
|
if (signal.aborted) return;
|
|
9060
9461
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9243,6 +9644,68 @@ ${inputJson}
|
|
|
9243
9644
|
}
|
|
9244
9645
|
return orphaned;
|
|
9245
9646
|
}
|
|
9647
|
+
// ---------- runner handoff (Plan 019) ----------
|
|
9648
|
+
/**
|
|
9649
|
+
* When the response indicates the run paused for runner handoff, POST
|
|
9650
|
+
* `{ runId }` to the configured runner URL. On success, return the
|
|
9651
|
+
* response unchanged — state stays `paused` and the runner will flip
|
|
9652
|
+
* it to `done` (or `failed`) on its side. On POST failure, convert
|
|
9653
|
+
* the response to `failed` with `ERR_RUNNER_UNREACHABLE` so the
|
|
9654
|
+
* caller sees a terminal state instead of a silent hang.
|
|
9655
|
+
*
|
|
9656
|
+
* Called only from `start()` / `resumeAsync()`. Sync `run()` never
|
|
9657
|
+
* produces a `handoff_to_runner` pause (see `_internal.handoffToRunner`).
|
|
9658
|
+
*/
|
|
9659
|
+
async maybeHandoffToRunner(runId, nodeId, response) {
|
|
9660
|
+
if (response.status !== "paused") return response;
|
|
9661
|
+
if (response.meta.pauseReason !== "handoff_to_runner") return response;
|
|
9662
|
+
const runner = this.config.runner;
|
|
9663
|
+
if (runner === void 0) {
|
|
9664
|
+
return response;
|
|
9665
|
+
}
|
|
9666
|
+
const fetchFn = this.internals.fetch ?? globalThis.fetch.bind(globalThis);
|
|
9667
|
+
try {
|
|
9668
|
+
const res = await fetchFn(runner.url, {
|
|
9669
|
+
method: "POST",
|
|
9670
|
+
headers: {
|
|
9671
|
+
"Content-Type": "application/json",
|
|
9672
|
+
Authorization: `Bearer ${runner.secret}`
|
|
9673
|
+
},
|
|
9674
|
+
body: JSON.stringify({ runId })
|
|
9675
|
+
});
|
|
9676
|
+
if (!res.ok) {
|
|
9677
|
+
return {
|
|
9678
|
+
runId,
|
|
9679
|
+
status: "failed",
|
|
9680
|
+
data: null,
|
|
9681
|
+
meta: { nodeId },
|
|
9682
|
+
errors: [
|
|
9683
|
+
{
|
|
9684
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9685
|
+
message: `Runner returned HTTP ${res.status}`
|
|
9686
|
+
}
|
|
9687
|
+
],
|
|
9688
|
+
timestamp: Date.now()
|
|
9689
|
+
};
|
|
9690
|
+
}
|
|
9691
|
+
return response;
|
|
9692
|
+
} catch (err) {
|
|
9693
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9694
|
+
return {
|
|
9695
|
+
runId,
|
|
9696
|
+
status: "failed",
|
|
9697
|
+
data: null,
|
|
9698
|
+
meta: { nodeId },
|
|
9699
|
+
errors: [
|
|
9700
|
+
{
|
|
9701
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9702
|
+
message: `Runner handoff failed: ${msg}`
|
|
9703
|
+
}
|
|
9704
|
+
],
|
|
9705
|
+
timestamp: Date.now()
|
|
9706
|
+
};
|
|
9707
|
+
}
|
|
9708
|
+
}
|
|
9246
9709
|
// ---------- webhook helpers ----------
|
|
9247
9710
|
async maybeFireWebhook(stateManager, runId, nodeId, response) {
|
|
9248
9711
|
const state = await stateManager.read(runId, nodeId);
|
|
@@ -9386,6 +9849,11 @@ ${inputJson}
|
|
|
9386
9849
|
if (disabled.has(name)) continue;
|
|
9387
9850
|
if (wantAll || enabled.has(name)) names.add(name);
|
|
9388
9851
|
}
|
|
9852
|
+
if ((this.config.api?.services.length ?? 0) > 0) {
|
|
9853
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
9854
|
+
names.add("ApiCall");
|
|
9855
|
+
}
|
|
9856
|
+
}
|
|
9389
9857
|
for (const tool of this.config.tools.custom) {
|
|
9390
9858
|
names.add(tool.name);
|
|
9391
9859
|
}
|
|
@@ -9542,6 +10010,34 @@ ${inputJson}
|
|
|
9542
10010
|
}
|
|
9543
10011
|
return void 0;
|
|
9544
10012
|
}
|
|
10013
|
+
/**
|
|
10014
|
+
* Plan 020 — resolve the effective ApiCall config for a run.
|
|
10015
|
+
*
|
|
10016
|
+
* Precedence (each field independently):
|
|
10017
|
+
* RunOptions.api.X > config.api.X
|
|
10018
|
+
*
|
|
10019
|
+
* If neither side provides any services, returns undefined so the
|
|
10020
|
+
* tool isn't registered at all. Env + resolveAuth + hooks flow
|
|
10021
|
+
* through untouched — they never hit the Zod schema.
|
|
10022
|
+
*/
|
|
10023
|
+
resolveApiConfig(override) {
|
|
10024
|
+
const base = this.config.api;
|
|
10025
|
+
if (override === void 0 && base === void 0) return void 0;
|
|
10026
|
+
const services = override?.services ?? base?.services;
|
|
10027
|
+
if (services === void 0 || services.length === 0) return void 0;
|
|
10028
|
+
const env = override?.env ?? base?.env;
|
|
10029
|
+
const resolveAuth2 = override?.resolveAuth ?? base?.resolveAuth;
|
|
10030
|
+
const onRequest = override?.onRequest ?? base?.onRequest;
|
|
10031
|
+
const onResponse = override?.onResponse ?? base?.onResponse;
|
|
10032
|
+
return {
|
|
10033
|
+
services,
|
|
10034
|
+
...env !== void 0 ? { env } : {},
|
|
10035
|
+
...resolveAuth2 !== void 0 ? { resolveAuth: resolveAuth2 } : {},
|
|
10036
|
+
...onRequest !== void 0 ? { onRequest } : {},
|
|
10037
|
+
...onResponse !== void 0 ? { onResponse } : {},
|
|
10038
|
+
...base?.maxResponseBytes !== void 0 ? { maxResponseBytes: base.maxResponseBytes } : {}
|
|
10039
|
+
};
|
|
10040
|
+
}
|
|
9545
10041
|
/**
|
|
9546
10042
|
* Build a throttled heartbeat callback for agentLoop's `onProgress` hook.
|
|
9547
10043
|
*
|
|
@@ -9636,8 +10132,8 @@ function buildToolRegistry(options) {
|
|
|
9636
10132
|
const fileTracker = new FileTracker();
|
|
9637
10133
|
const spawnAvailable = canSpawnProcesses();
|
|
9638
10134
|
const candidates = [
|
|
9639
|
-
// Bash — requires child_process.spawn
|
|
9640
|
-
|
|
10135
|
+
// Bash — requires child_process.spawn. Stubbed on Workers.
|
|
10136
|
+
{ name: "Bash", tool: withCapabilityCheck(createBashTool(), spawnAvailable) },
|
|
9641
10137
|
{
|
|
9642
10138
|
name: "Read",
|
|
9643
10139
|
tool: createFileReadTool({ storage: storage.workspace, tracker: fileTracker })
|
|
@@ -9683,6 +10179,21 @@ function buildToolRegistry(options) {
|
|
|
9683
10179
|
childRegistry.register(skillTool);
|
|
9684
10180
|
}
|
|
9685
10181
|
}
|
|
10182
|
+
if (options.apiConfig !== void 0 && options.apiConfig.services.length > 0) {
|
|
10183
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
10184
|
+
const apiTool = createApiCallTool({
|
|
10185
|
+
services: options.apiConfig.services,
|
|
10186
|
+
...options.fetch !== void 0 ? { fetch: options.fetch } : {},
|
|
10187
|
+
...options.apiConfig.env !== void 0 ? { env: options.apiConfig.env } : {},
|
|
10188
|
+
...options.apiConfig.resolveAuth !== void 0 ? { resolveAuth: options.apiConfig.resolveAuth } : {},
|
|
10189
|
+
...options.apiConfig.onRequest !== void 0 ? { onRequest: options.apiConfig.onRequest } : {},
|
|
10190
|
+
...options.apiConfig.onResponse !== void 0 ? { onResponse: options.apiConfig.onResponse } : {},
|
|
10191
|
+
...options.apiConfig.maxResponseBytes !== void 0 ? { maxResponseBytes: options.apiConfig.maxResponseBytes } : {}
|
|
10192
|
+
});
|
|
10193
|
+
registry.register(apiTool);
|
|
10194
|
+
childRegistry.register(apiTool);
|
|
10195
|
+
}
|
|
10196
|
+
}
|
|
9686
10197
|
const agentTool = createAgentTool({
|
|
9687
10198
|
storage: storage.workspace,
|
|
9688
10199
|
client,
|
|
@@ -9805,6 +10316,8 @@ function resolveApiKey(config) {
|
|
|
9805
10316
|
buildSystemPrompt,
|
|
9806
10317
|
buildWorkerAgent,
|
|
9807
10318
|
canSpawnProcesses,
|
|
10319
|
+
capabilityStub,
|
|
10320
|
+
createApiCallTool,
|
|
9808
10321
|
createLogger,
|
|
9809
10322
|
createModelAdapter,
|
|
9810
10323
|
createSendMessageTool,
|
|
@@ -9836,6 +10349,7 @@ function resolveApiKey(config) {
|
|
|
9836
10349
|
synthesizeSpec,
|
|
9837
10350
|
toResponse,
|
|
9838
10351
|
tryParseJSON,
|
|
9839
|
-
validateOutput
|
|
10352
|
+
validateOutput,
|
|
10353
|
+
withCapabilityCheck
|
|
9840
10354
|
});
|
|
9841
10355
|
//# sourceMappingURL=index.cjs.map
|