la-machina-engine 0.3.0 → 0.5.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 +215 -1
- package/dist/index.cjs +797 -294
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +345 -24
- package/dist/index.d.ts +345 -24
- package/dist/index.js +792 -292
- 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();
|
|
@@ -940,7 +943,8 @@ var ModelProviderEnum = import_zod.z.enum([
|
|
|
940
943
|
]);
|
|
941
944
|
var StorageProviderEnum = import_zod.z.enum(["local", "r2", "r2-binding"]);
|
|
942
945
|
var MemoryModeEnum = import_zod.z.enum(["off", "read-only", "read-write"]);
|
|
943
|
-
var
|
|
946
|
+
var MemoryScopeUserEnum = import_zod.z.enum(["workspace", "global"]);
|
|
947
|
+
var MemoryScopeResolvedEnum = import_zod.z.enum(["workspace"]);
|
|
944
948
|
var FlushPolicyEnum = import_zod.z.enum(["turn-end", "entry", "manual"]);
|
|
945
949
|
var LogLevelEnum = import_zod.z.enum(["silent", "error", "warn", "info", "debug"]);
|
|
946
950
|
var R2ConfigResolved = import_zod.z.object({
|
|
@@ -979,7 +983,7 @@ var StorageConfigResolved = import_zod.z.object({
|
|
|
979
983
|
});
|
|
980
984
|
var MemoryConfigResolved = import_zod.z.object({
|
|
981
985
|
mode: MemoryModeEnum,
|
|
982
|
-
scope:
|
|
986
|
+
scope: MemoryScopeResolvedEnum
|
|
983
987
|
}).strict();
|
|
984
988
|
var ToolsConfigResolved = import_zod.z.object({
|
|
985
989
|
enabled: import_zod.z.array(import_zod.z.string()),
|
|
@@ -1110,6 +1114,42 @@ var LoggingConfigResolved = import_zod.z.object({
|
|
|
1110
1114
|
level: LogLevelEnum,
|
|
1111
1115
|
sink: LogSinkSchema
|
|
1112
1116
|
}).strict();
|
|
1117
|
+
var ApiHttpMethodEnum = import_zod.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]);
|
|
1118
|
+
var ApiAuthSchema = import_zod.z.discriminatedUnion("type", [
|
|
1119
|
+
import_zod.z.object({ type: import_zod.z.literal("none") }).strict(),
|
|
1120
|
+
import_zod.z.object({ type: import_zod.z.literal("bearer"), tokenRef: import_zod.z.string().min(1) }).strict(),
|
|
1121
|
+
import_zod.z.object({
|
|
1122
|
+
type: import_zod.z.literal("header"),
|
|
1123
|
+
name: import_zod.z.string().min(1),
|
|
1124
|
+
valueRef: import_zod.z.string().min(1)
|
|
1125
|
+
}).strict(),
|
|
1126
|
+
import_zod.z.object({
|
|
1127
|
+
type: import_zod.z.literal("basic"),
|
|
1128
|
+
userRef: import_zod.z.string().min(1),
|
|
1129
|
+
passRef: import_zod.z.string().min(1)
|
|
1130
|
+
}).strict(),
|
|
1131
|
+
import_zod.z.object({ type: import_zod.z.literal("custom"), id: import_zod.z.string().min(1) }).strict()
|
|
1132
|
+
]);
|
|
1133
|
+
var ApiServiceSchema = import_zod.z.object({
|
|
1134
|
+
name: import_zod.z.string().min(1),
|
|
1135
|
+
description: import_zod.z.string().optional(),
|
|
1136
|
+
baseUrl: import_zod.z.string().url(),
|
|
1137
|
+
auth: ApiAuthSchema.optional(),
|
|
1138
|
+
// Allow both strings and RegExp values via z.union — RegExp is
|
|
1139
|
+
// serialized as its source when cloned, so we accept both.
|
|
1140
|
+
allowedPaths: import_zod.z.array(import_zod.z.union([import_zod.z.string(), import_zod.z.instanceof(RegExp)])).optional(),
|
|
1141
|
+
allowedMethods: import_zod.z.array(ApiHttpMethodEnum).optional(),
|
|
1142
|
+
defaultHeaders: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
1143
|
+
maxBodyBytes: import_zod.z.number().int().positive().optional()
|
|
1144
|
+
}).strict();
|
|
1145
|
+
var ApiConfigResolved = import_zod.z.object({
|
|
1146
|
+
services: import_zod.z.array(ApiServiceSchema),
|
|
1147
|
+
maxResponseBytes: import_zod.z.number().int().positive().optional()
|
|
1148
|
+
}).strict();
|
|
1149
|
+
var RunnerConfigResolved = import_zod.z.object({
|
|
1150
|
+
url: import_zod.z.string().url(),
|
|
1151
|
+
secret: import_zod.z.string().min(1, "runner.secret cannot be empty")
|
|
1152
|
+
}).strict();
|
|
1113
1153
|
var ResolvedConfigSchema = import_zod.z.object({
|
|
1114
1154
|
model: ModelConfigResolved,
|
|
1115
1155
|
storage: StorageConfigResolved,
|
|
@@ -1125,7 +1165,9 @@ var ResolvedConfigSchema = import_zod.z.object({
|
|
|
1125
1165
|
permissions: PermissionsConfigResolved,
|
|
1126
1166
|
compaction: CompactionConfigResolved,
|
|
1127
1167
|
coordinator: CoordinatorConfigResolved,
|
|
1128
|
-
orchestrator: OrchestratorConfigResolved
|
|
1168
|
+
orchestrator: OrchestratorConfigResolved,
|
|
1169
|
+
runner: RunnerConfigResolved.optional(),
|
|
1170
|
+
api: ApiConfigResolved.optional()
|
|
1129
1171
|
}).strict();
|
|
1130
1172
|
var R2ConfigUser = R2ConfigResolved.partial();
|
|
1131
1173
|
var ModelConfigUser = ModelConfigResolved.partial();
|
|
@@ -1136,7 +1178,10 @@ var StorageConfigUser = import_zod.z.object({
|
|
|
1136
1178
|
r2: R2ConfigUser.optional(),
|
|
1137
1179
|
r2Binding: R2BucketBindingShape.optional()
|
|
1138
1180
|
}).strict();
|
|
1139
|
-
var MemoryConfigUser =
|
|
1181
|
+
var MemoryConfigUser = import_zod.z.object({
|
|
1182
|
+
mode: MemoryModeEnum.optional(),
|
|
1183
|
+
scope: MemoryScopeUserEnum.optional()
|
|
1184
|
+
}).strict();
|
|
1140
1185
|
var ToolsConfigUser = ToolsConfigResolved.partial();
|
|
1141
1186
|
var AgentsConfigUser = AgentsConfigResolved.partial();
|
|
1142
1187
|
var SkillsConfigUser = SkillsConfigResolved.partial();
|
|
@@ -1166,6 +1211,8 @@ var McpConfigUser = import_zod.z.object({
|
|
|
1166
1211
|
shutdownTimeoutMs: import_zod.z.number().int().positive().optional()
|
|
1167
1212
|
}).strict();
|
|
1168
1213
|
var PermissionsConfigUser = PermissionsConfigResolved.partial();
|
|
1214
|
+
var RunnerConfigUser = RunnerConfigResolved;
|
|
1215
|
+
var ApiConfigUser = ApiConfigResolved.partial();
|
|
1169
1216
|
var CompactionConfigUser = CompactionConfigResolved.partial();
|
|
1170
1217
|
var CoordinatorConfigUser = CoordinatorConfigResolved.partial();
|
|
1171
1218
|
var OrchestratorConfigUser = OrchestratorConfigResolved.deepPartial();
|
|
@@ -1184,7 +1231,9 @@ var UserConfigSchema = import_zod.z.object({
|
|
|
1184
1231
|
permissions: PermissionsConfigUser.optional(),
|
|
1185
1232
|
compaction: CompactionConfigUser.optional(),
|
|
1186
1233
|
coordinator: CoordinatorConfigUser.optional(),
|
|
1187
|
-
orchestrator: OrchestratorConfigUser.optional()
|
|
1234
|
+
orchestrator: OrchestratorConfigUser.optional(),
|
|
1235
|
+
runner: RunnerConfigUser.optional(),
|
|
1236
|
+
api: ApiConfigUser.optional()
|
|
1188
1237
|
}).strict();
|
|
1189
1238
|
|
|
1190
1239
|
// src/config/merge.ts
|
|
@@ -1229,10 +1278,49 @@ function deepMerge(base, override) {
|
|
|
1229
1278
|
}
|
|
1230
1279
|
return result;
|
|
1231
1280
|
}
|
|
1281
|
+
var API_RUNTIME_KEYS = ["env", "resolveAuth", "onRequest", "onResponse"];
|
|
1282
|
+
function splitApiRuntime(user) {
|
|
1283
|
+
const api = user.api;
|
|
1284
|
+
if (api === void 0) return { stripped: user, runtime: {} };
|
|
1285
|
+
const runtime = {};
|
|
1286
|
+
const schemaSafe = {};
|
|
1287
|
+
for (const [k, v] of Object.entries(api)) {
|
|
1288
|
+
if (API_RUNTIME_KEYS.includes(k)) {
|
|
1289
|
+
runtime[k] = v;
|
|
1290
|
+
} else {
|
|
1291
|
+
schemaSafe[k] = v;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
const clone = { ...user, api: schemaSafe };
|
|
1295
|
+
return { stripped: clone, runtime };
|
|
1296
|
+
}
|
|
1297
|
+
function coerceDeprecatedMemoryScope(user) {
|
|
1298
|
+
const scope = user.memory?.scope;
|
|
1299
|
+
if (scope !== "global") return user;
|
|
1300
|
+
console.warn(
|
|
1301
|
+
'[la-machina] config.memory.scope: "global" is deprecated and has been rewritten to "workspace". Cross-tenant memory sharing was removed in Plan 022 \u2014 the workspace is the tenant root. This field value will be rejected outright in a future major release.'
|
|
1302
|
+
);
|
|
1303
|
+
const memory = user.memory ?? {};
|
|
1304
|
+
return {
|
|
1305
|
+
...user,
|
|
1306
|
+
memory: { ...memory, scope: "workspace" }
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1232
1309
|
function mergeConfig(user) {
|
|
1233
|
-
const
|
|
1310
|
+
const withCoercedScope = coerceDeprecatedMemoryScope(user);
|
|
1311
|
+
const { stripped, runtime } = splitApiRuntime(withCoercedScope);
|
|
1312
|
+
const validatedUser = UserConfigSchema.parse(stripped);
|
|
1234
1313
|
const merged = deepMerge(DEFAULTS, validatedUser);
|
|
1235
|
-
|
|
1314
|
+
const resolved = ResolvedConfigSchema.parse(merged);
|
|
1315
|
+
if (resolved.api !== void 0 && Object.keys(runtime).length > 0) {
|
|
1316
|
+
const mutableResolved = resolved;
|
|
1317
|
+
mutableResolved.api = {
|
|
1318
|
+
...resolved.api,
|
|
1319
|
+
...runtime
|
|
1320
|
+
};
|
|
1321
|
+
} else if (Object.keys(runtime).length > 0) {
|
|
1322
|
+
}
|
|
1323
|
+
return resolved;
|
|
1236
1324
|
}
|
|
1237
1325
|
|
|
1238
1326
|
// src/engine/engine.ts
|
|
@@ -1676,8 +1764,8 @@ function toAISdkMessages(messages) {
|
|
|
1676
1764
|
textParts.push({ type: "text", text: block.text });
|
|
1677
1765
|
}
|
|
1678
1766
|
}
|
|
1679
|
-
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1680
1767
|
if (toolResults.length > 0) out.push({ role: "tool", content: toolResults });
|
|
1768
|
+
if (textParts.length > 0) out.push({ role: "user", content: textParts });
|
|
1681
1769
|
} else if (role === "assistant") {
|
|
1682
1770
|
if (typeof content === "string") {
|
|
1683
1771
|
out.push({ role: "assistant", content });
|
|
@@ -1875,6 +1963,68 @@ function hasProcessLifecycle() {
|
|
|
1875
1963
|
return typeof process !== "undefined" && typeof process.on === "function" && typeof process.removeListener === "function" && detectRuntime() === "node";
|
|
1876
1964
|
}
|
|
1877
1965
|
|
|
1966
|
+
// src/tools/capabilityStub.ts
|
|
1967
|
+
init_cjs_shims();
|
|
1968
|
+
var import_zod2 = require("zod");
|
|
1969
|
+
|
|
1970
|
+
// src/tools/contract.ts
|
|
1971
|
+
init_cjs_shims();
|
|
1972
|
+
function defineTool(tool) {
|
|
1973
|
+
return tool;
|
|
1974
|
+
}
|
|
1975
|
+
var ToolRegistry = class {
|
|
1976
|
+
tools = /* @__PURE__ */ new Map();
|
|
1977
|
+
register(tool) {
|
|
1978
|
+
if (typeof tool.name !== "string" || tool.name.length === 0) {
|
|
1979
|
+
throw new Error("ToolRegistry: tool.name must be a non-empty string");
|
|
1980
|
+
}
|
|
1981
|
+
if (this.tools.has(tool.name)) {
|
|
1982
|
+
throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
|
|
1983
|
+
}
|
|
1984
|
+
this.tools.set(tool.name, tool);
|
|
1985
|
+
}
|
|
1986
|
+
registerAll(tools) {
|
|
1987
|
+
for (const tool of tools) this.register(tool);
|
|
1988
|
+
}
|
|
1989
|
+
unregister(name) {
|
|
1990
|
+
this.tools.delete(name);
|
|
1991
|
+
}
|
|
1992
|
+
get(name) {
|
|
1993
|
+
return this.tools.get(name);
|
|
1994
|
+
}
|
|
1995
|
+
has(name) {
|
|
1996
|
+
return this.tools.has(name);
|
|
1997
|
+
}
|
|
1998
|
+
list() {
|
|
1999
|
+
return Array.from(this.tools.values());
|
|
2000
|
+
}
|
|
2001
|
+
count() {
|
|
2002
|
+
return this.tools.size;
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
|
|
2006
|
+
// src/tools/capabilityStub.ts
|
|
2007
|
+
var anyInput = import_zod2.z.unknown();
|
|
2008
|
+
function capabilityStub(original) {
|
|
2009
|
+
return defineTool({
|
|
2010
|
+
name: original.name,
|
|
2011
|
+
description: original.description,
|
|
2012
|
+
inputSchema: anyInput,
|
|
2013
|
+
isCapabilityStub: true,
|
|
2014
|
+
execute: async () => ({
|
|
2015
|
+
isError: true,
|
|
2016
|
+
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.`,
|
|
2017
|
+
metadata: { capabilityMissing: original.name }
|
|
2018
|
+
})
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
function withCapabilityCheck(tool, spawnAvailable) {
|
|
2022
|
+
if (tool.requiresNode === true && !spawnAvailable) {
|
|
2023
|
+
return capabilityStub(tool);
|
|
2024
|
+
}
|
|
2025
|
+
return tool;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
1878
2028
|
// src/subagent/registry.ts
|
|
1879
2029
|
init_cjs_shims();
|
|
1880
2030
|
|
|
@@ -2057,7 +2207,7 @@ var SubagentRegistry = class _SubagentRegistry {
|
|
|
2057
2207
|
|
|
2058
2208
|
// src/tools/agent.ts
|
|
2059
2209
|
init_cjs_shims();
|
|
2060
|
-
var
|
|
2210
|
+
var import_zod6 = require("zod");
|
|
2061
2211
|
|
|
2062
2212
|
// src/subagent/runner.ts
|
|
2063
2213
|
init_cjs_shims();
|
|
@@ -2068,48 +2218,49 @@ var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
|
2068
2218
|
|
|
2069
2219
|
// src/transcript/snapshot.ts
|
|
2070
2220
|
init_cjs_shims();
|
|
2071
|
-
var
|
|
2221
|
+
var import_zod3 = require("zod");
|
|
2072
2222
|
var SNAPSHOT_FILENAME = "snapshot.json";
|
|
2073
|
-
var TokenUsageSchema =
|
|
2074
|
-
input:
|
|
2075
|
-
output:
|
|
2076
|
-
cacheCreationInput:
|
|
2077
|
-
cacheReadInput:
|
|
2223
|
+
var TokenUsageSchema = import_zod3.z.object({
|
|
2224
|
+
input: import_zod3.z.number().int().nonnegative(),
|
|
2225
|
+
output: import_zod3.z.number().int().nonnegative(),
|
|
2226
|
+
cacheCreationInput: import_zod3.z.number().int().nonnegative().optional(),
|
|
2227
|
+
cacheReadInput: import_zod3.z.number().int().nonnegative().optional()
|
|
2078
2228
|
}).strict();
|
|
2079
|
-
var PendingToolCallSchema =
|
|
2080
|
-
toolName:
|
|
2081
|
-
toolUseId:
|
|
2082
|
-
input:
|
|
2083
|
-
calledAt:
|
|
2229
|
+
var PendingToolCallSchema = import_zod3.z.object({
|
|
2230
|
+
toolName: import_zod3.z.string().min(1),
|
|
2231
|
+
toolUseId: import_zod3.z.string().min(1),
|
|
2232
|
+
input: import_zod3.z.unknown(),
|
|
2233
|
+
calledAt: import_zod3.z.string().datetime({ offset: true })
|
|
2084
2234
|
}).strict();
|
|
2085
|
-
var PendingSubagentSchema =
|
|
2086
|
-
() =>
|
|
2087
|
-
subagentType:
|
|
2088
|
-
parentToolUseId:
|
|
2235
|
+
var PendingSubagentSchema = import_zod3.z.lazy(
|
|
2236
|
+
() => import_zod3.z.object({
|
|
2237
|
+
subagentType: import_zod3.z.string().min(1),
|
|
2238
|
+
parentToolUseId: import_zod3.z.string().min(1),
|
|
2089
2239
|
childSnapshot: RunSnapshotSchema
|
|
2090
2240
|
}).strict()
|
|
2091
2241
|
);
|
|
2092
|
-
var RunSnapshotSchema =
|
|
2093
|
-
() =>
|
|
2094
|
-
version:
|
|
2095
|
-
status:
|
|
2096
|
-
runId:
|
|
2097
|
-
nodeId:
|
|
2098
|
-
pausedAt:
|
|
2099
|
-
pauseReason:
|
|
2242
|
+
var RunSnapshotSchema = import_zod3.z.lazy(
|
|
2243
|
+
() => import_zod3.z.object({
|
|
2244
|
+
version: import_zod3.z.literal(1),
|
|
2245
|
+
status: import_zod3.z.literal("paused"),
|
|
2246
|
+
runId: import_zod3.z.string().min(1),
|
|
2247
|
+
nodeId: import_zod3.z.string().min(1),
|
|
2248
|
+
pausedAt: import_zod3.z.string().datetime({ offset: true }),
|
|
2249
|
+
pauseReason: import_zod3.z.enum([
|
|
2100
2250
|
"gate_required",
|
|
2101
2251
|
"subagent_gate_required",
|
|
2252
|
+
"handoff_to_runner",
|
|
2102
2253
|
"max_turns",
|
|
2103
2254
|
"explicit",
|
|
2104
2255
|
"timeout"
|
|
2105
2256
|
]),
|
|
2106
|
-
messageCount:
|
|
2107
|
-
lastShardIndex:
|
|
2108
|
-
lastMessageUuid:
|
|
2257
|
+
messageCount: import_zod3.z.number().int().nonnegative(),
|
|
2258
|
+
lastShardIndex: import_zod3.z.number().int().nonnegative(),
|
|
2259
|
+
lastMessageUuid: import_zod3.z.string().uuid(),
|
|
2109
2260
|
pendingToolCall: PendingToolCallSchema.optional(),
|
|
2110
2261
|
pendingSubagent: PendingSubagentSchema.optional(),
|
|
2111
2262
|
tokensUsedSoFar: TokenUsageSchema,
|
|
2112
|
-
turnsUsed:
|
|
2263
|
+
turnsUsed: import_zod3.z.number().int().nonnegative()
|
|
2113
2264
|
}).strict()
|
|
2114
2265
|
);
|
|
2115
2266
|
function snapshotPath(logPath) {
|
|
@@ -2837,6 +2988,27 @@ async function agentLoop(options) {
|
|
|
2837
2988
|
}
|
|
2838
2989
|
}
|
|
2839
2990
|
}
|
|
2991
|
+
if (options.handoffToRunner === true) {
|
|
2992
|
+
for (const call of toolCallsToDispatch) {
|
|
2993
|
+
const tool = options.registry?.get(call.name);
|
|
2994
|
+
if (tool?.isCapabilityStub === true) {
|
|
2995
|
+
const paused = await pauseHere({
|
|
2996
|
+
ctx,
|
|
2997
|
+
transcript,
|
|
2998
|
+
reason: "handoff_to_runner",
|
|
2999
|
+
pendingToolCall: {
|
|
3000
|
+
toolName: call.name,
|
|
3001
|
+
toolUseId: call.id,
|
|
3002
|
+
input: call.input,
|
|
3003
|
+
calledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3004
|
+
},
|
|
3005
|
+
storage: options.storage,
|
|
3006
|
+
subagentRegistry: options.subagentRegistry
|
|
3007
|
+
});
|
|
3008
|
+
return paused;
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
2840
3012
|
const firstTool = toolCallsToDispatch[0]?.name;
|
|
2841
3013
|
await fireProgress("tool_dispatch", firstTool);
|
|
2842
3014
|
const streamExec = new StreamingToolExecutor(executor);
|
|
@@ -2847,6 +3019,10 @@ async function agentLoop(options) {
|
|
|
2847
3019
|
}
|
|
2848
3020
|
try {
|
|
2849
3021
|
for await (const { id, result } of streamExec.results()) {
|
|
3022
|
+
const missing = result.metadata?.capabilityMissing;
|
|
3023
|
+
if (typeof missing === "string") {
|
|
3024
|
+
ctx.recordCapabilityMissing(missing);
|
|
3025
|
+
}
|
|
2850
3026
|
await ctx.addToolResult(id, truncateToolResult(result.content), result.isError === true);
|
|
2851
3027
|
}
|
|
2852
3028
|
} catch (err) {
|
|
@@ -3105,6 +3281,12 @@ var RunContext = class {
|
|
|
3105
3281
|
turnCount = 0;
|
|
3106
3282
|
tokensUsed = { input: 0, output: 0 };
|
|
3107
3283
|
lastUuid = null;
|
|
3284
|
+
/**
|
|
3285
|
+
* Plan 019 — names of tools whose capability-stub returned an
|
|
3286
|
+
* `isError` result during this run. Aggregated and surfaced on the
|
|
3287
|
+
* response's `meta.capabilitiesMissing` (deduped, insertion-ordered).
|
|
3288
|
+
*/
|
|
3289
|
+
capabilitiesMissing = /* @__PURE__ */ new Set();
|
|
3108
3290
|
constructor(options) {
|
|
3109
3291
|
this.runId = options.runId;
|
|
3110
3292
|
this.nodeId = options.nodeId;
|
|
@@ -3145,6 +3327,42 @@ var RunContext = class {
|
|
|
3145
3327
|
this.episodes.logTurn(this.turnCount, "assistant", summary);
|
|
3146
3328
|
}
|
|
3147
3329
|
}
|
|
3330
|
+
/**
|
|
3331
|
+
* Inject a tool_result + a follow-up text block as a SINGLE user
|
|
3332
|
+
* message. Used by the resume() synthetic-release path when a
|
|
3333
|
+
* paused run is resumed without an explicit `gateAnswer`: we need
|
|
3334
|
+
* to both satisfy the tool_use↔tool_result pairing AND give the
|
|
3335
|
+
* model a retry instruction, in the same user turn.
|
|
3336
|
+
*
|
|
3337
|
+
* Splitting this into `addToolResult(...) + addUserMessage(...)`
|
|
3338
|
+
* produces two consecutive user messages, which the AI SDK's
|
|
3339
|
+
* openai-compatible adapter rejects with
|
|
3340
|
+
* `MissingToolResultsError`. Combining them into one user message
|
|
3341
|
+
* is the portable shape that works on every provider we support.
|
|
3342
|
+
*
|
|
3343
|
+
* Writes a single `user` transcript entry carrying the mixed
|
|
3344
|
+
* content, so `rebuildMessagesFromEntries` reconstructs the same
|
|
3345
|
+
* single-message shape on resume.
|
|
3346
|
+
*/
|
|
3347
|
+
async addMixedUserMessage(blocks) {
|
|
3348
|
+
this.messages.push({ role: "user", content: blocks });
|
|
3349
|
+
await this.writeEntry({
|
|
3350
|
+
type: "user",
|
|
3351
|
+
uuid: this.nextUuid(),
|
|
3352
|
+
parentUuid: this.lastUuid,
|
|
3353
|
+
ts: this.now(),
|
|
3354
|
+
message: { role: "user", content: blocks }
|
|
3355
|
+
});
|
|
3356
|
+
const summary = blocks.map((b) => {
|
|
3357
|
+
const x = b;
|
|
3358
|
+
if (x.type === "text") return x.text ?? "";
|
|
3359
|
+
if (x.type === "tool_result") {
|
|
3360
|
+
return typeof x.content === "string" ? x.content : JSON.stringify(x.content);
|
|
3361
|
+
}
|
|
3362
|
+
return "";
|
|
3363
|
+
}).filter((s) => s.length > 0).join("\n");
|
|
3364
|
+
this.episodes?.logTurn(this.turnCount, "user", summary);
|
|
3365
|
+
}
|
|
3148
3366
|
/**
|
|
3149
3367
|
* Append a tool result to the conversation. The Anthropic Messages
|
|
3150
3368
|
* API requires tool_result blocks to be wrapped in a user message,
|
|
@@ -3190,6 +3408,14 @@ var RunContext = class {
|
|
|
3190
3408
|
getTokensUsed() {
|
|
3191
3409
|
return this.tokensUsed;
|
|
3192
3410
|
}
|
|
3411
|
+
/** Plan 019 — record that a capability-stubbed tool fired during this run. */
|
|
3412
|
+
recordCapabilityMissing(toolName) {
|
|
3413
|
+
this.capabilitiesMissing.add(toolName);
|
|
3414
|
+
}
|
|
3415
|
+
/** Plan 019 — capability-stubbed tool names observed this run (deduped). */
|
|
3416
|
+
getCapabilitiesMissing() {
|
|
3417
|
+
return [...this.capabilitiesMissing];
|
|
3418
|
+
}
|
|
3193
3419
|
shouldContinue() {
|
|
3194
3420
|
return this.turnCount < this.maxTurns;
|
|
3195
3421
|
}
|
|
@@ -3363,9 +3589,9 @@ init_cjs_shims();
|
|
|
3363
3589
|
|
|
3364
3590
|
// src/transcript/entries.ts
|
|
3365
3591
|
init_cjs_shims();
|
|
3366
|
-
var
|
|
3367
|
-
var UuidSchema =
|
|
3368
|
-
var IsoTsSchema =
|
|
3592
|
+
var import_zod4 = require("zod");
|
|
3593
|
+
var UuidSchema = import_zod4.z.string().uuid();
|
|
3594
|
+
var IsoTsSchema = import_zod4.z.string().datetime({ offset: true });
|
|
3369
3595
|
var TimelineBase = {
|
|
3370
3596
|
uuid: UuidSchema,
|
|
3371
3597
|
parentUuid: UuidSchema.nullable(),
|
|
@@ -3375,55 +3601,55 @@ var SessionBase = {
|
|
|
3375
3601
|
uuid: UuidSchema,
|
|
3376
3602
|
ts: IsoTsSchema
|
|
3377
3603
|
};
|
|
3378
|
-
var MessageSchema =
|
|
3379
|
-
role:
|
|
3380
|
-
content:
|
|
3604
|
+
var MessageSchema = import_zod4.z.object({
|
|
3605
|
+
role: import_zod4.z.enum(["user", "assistant"]),
|
|
3606
|
+
content: import_zod4.z.array(import_zod4.z.unknown())
|
|
3381
3607
|
}).strict();
|
|
3382
|
-
var UserEntrySchema =
|
|
3383
|
-
type:
|
|
3608
|
+
var UserEntrySchema = import_zod4.z.object({
|
|
3609
|
+
type: import_zod4.z.literal("user"),
|
|
3384
3610
|
...TimelineBase,
|
|
3385
3611
|
message: MessageSchema
|
|
3386
3612
|
}).strict();
|
|
3387
|
-
var AssistantEntrySchema =
|
|
3388
|
-
type:
|
|
3613
|
+
var AssistantEntrySchema = import_zod4.z.object({
|
|
3614
|
+
type: import_zod4.z.literal("assistant"),
|
|
3389
3615
|
...TimelineBase,
|
|
3390
3616
|
message: MessageSchema
|
|
3391
3617
|
}).strict();
|
|
3392
|
-
var ToolResultEntrySchema =
|
|
3393
|
-
type:
|
|
3618
|
+
var ToolResultEntrySchema = import_zod4.z.object({
|
|
3619
|
+
type: import_zod4.z.literal("tool_result"),
|
|
3394
3620
|
...TimelineBase,
|
|
3395
|
-
toolUseId:
|
|
3396
|
-
content:
|
|
3397
|
-
isError:
|
|
3621
|
+
toolUseId: import_zod4.z.string().min(1),
|
|
3622
|
+
content: import_zod4.z.unknown(),
|
|
3623
|
+
isError: import_zod4.z.boolean().optional()
|
|
3398
3624
|
}).strict();
|
|
3399
|
-
var SubagentSpawnEntrySchema =
|
|
3400
|
-
type:
|
|
3625
|
+
var SubagentSpawnEntrySchema = import_zod4.z.object({
|
|
3626
|
+
type: import_zod4.z.literal("subagent_spawn"),
|
|
3401
3627
|
...TimelineBase,
|
|
3402
|
-
agentId:
|
|
3403
|
-
agentType:
|
|
3628
|
+
agentId: import_zod4.z.string().min(1),
|
|
3629
|
+
agentType: import_zod4.z.string().min(1)
|
|
3404
3630
|
}).strict();
|
|
3405
|
-
var SubagentDoneEntrySchema =
|
|
3406
|
-
type:
|
|
3631
|
+
var SubagentDoneEntrySchema = import_zod4.z.object({
|
|
3632
|
+
type: import_zod4.z.literal("subagent_done"),
|
|
3407
3633
|
...TimelineBase,
|
|
3408
|
-
agentId:
|
|
3409
|
-
output:
|
|
3634
|
+
agentId: import_zod4.z.string().min(1),
|
|
3635
|
+
output: import_zod4.z.string()
|
|
3410
3636
|
}).strict();
|
|
3411
|
-
var MetaEntrySchema =
|
|
3412
|
-
type:
|
|
3637
|
+
var MetaEntrySchema = import_zod4.z.object({
|
|
3638
|
+
type: import_zod4.z.literal("meta"),
|
|
3413
3639
|
...SessionBase,
|
|
3414
|
-
key:
|
|
3415
|
-
value:
|
|
3640
|
+
key: import_zod4.z.string().min(1),
|
|
3641
|
+
value: import_zod4.z.unknown()
|
|
3416
3642
|
}).strict();
|
|
3417
|
-
var ErrorEntrySchema =
|
|
3418
|
-
type:
|
|
3643
|
+
var ErrorEntrySchema = import_zod4.z.object({
|
|
3644
|
+
type: import_zod4.z.literal("error"),
|
|
3419
3645
|
...SessionBase,
|
|
3420
|
-
error:
|
|
3421
|
-
code:
|
|
3422
|
-
message:
|
|
3423
|
-
stack:
|
|
3646
|
+
error: import_zod4.z.object({
|
|
3647
|
+
code: import_zod4.z.string().min(1),
|
|
3648
|
+
message: import_zod4.z.string(),
|
|
3649
|
+
stack: import_zod4.z.string().optional()
|
|
3424
3650
|
}).strict()
|
|
3425
3651
|
}).strict();
|
|
3426
|
-
var EntrySchema =
|
|
3652
|
+
var EntrySchema = import_zod4.z.discriminatedUnion("type", [
|
|
3427
3653
|
UserEntrySchema,
|
|
3428
3654
|
AssistantEntrySchema,
|
|
3429
3655
|
ToolResultEntrySchema,
|
|
@@ -3455,16 +3681,16 @@ function parseEntryLine(line) {
|
|
|
3455
3681
|
|
|
3456
3682
|
// src/transcript/meta.ts
|
|
3457
3683
|
init_cjs_shims();
|
|
3458
|
-
var
|
|
3459
|
-
var TranscriptMetaSchema =
|
|
3460
|
-
version:
|
|
3461
|
-
status:
|
|
3462
|
-
startedAt:
|
|
3463
|
-
updatedAt:
|
|
3464
|
-
turnCount:
|
|
3465
|
-
messageCount:
|
|
3466
|
-
lastShardIndex:
|
|
3467
|
-
shardCount:
|
|
3684
|
+
var import_zod5 = require("zod");
|
|
3685
|
+
var TranscriptMetaSchema = import_zod5.z.object({
|
|
3686
|
+
version: import_zod5.z.literal(1),
|
|
3687
|
+
status: import_zod5.z.enum(["pending", "running", "paused", "done", "failed"]),
|
|
3688
|
+
startedAt: import_zod5.z.string().datetime({ offset: true }),
|
|
3689
|
+
updatedAt: import_zod5.z.string().datetime({ offset: true }),
|
|
3690
|
+
turnCount: import_zod5.z.number().int().nonnegative(),
|
|
3691
|
+
messageCount: import_zod5.z.number().int().nonnegative(),
|
|
3692
|
+
lastShardIndex: import_zod5.z.number().int().nonnegative().nullable(),
|
|
3693
|
+
shardCount: import_zod5.z.number().int().nonnegative()
|
|
3468
3694
|
}).strict();
|
|
3469
3695
|
var META_FILENAME = "meta.json";
|
|
3470
3696
|
function metaPath(logPath) {
|
|
@@ -3812,47 +4038,11 @@ Output format:
|
|
|
3812
4038
|
Directive: ${directive}`;
|
|
3813
4039
|
}
|
|
3814
4040
|
|
|
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
4041
|
// src/tools/agent.ts
|
|
3852
|
-
var inputSchema =
|
|
3853
|
-
description:
|
|
3854
|
-
subagent_type:
|
|
3855
|
-
run_in_background:
|
|
4042
|
+
var inputSchema = import_zod6.z.object({
|
|
4043
|
+
description: import_zod6.z.string().min(1),
|
|
4044
|
+
subagent_type: import_zod6.z.string().optional(),
|
|
4045
|
+
run_in_background: import_zod6.z.boolean().optional()
|
|
3856
4046
|
});
|
|
3857
4047
|
function createAgentTool(options) {
|
|
3858
4048
|
if (options.agents.length === 0) {
|
|
@@ -4057,7 +4247,7 @@ function handlePausedResult(result, agentId, subagentType) {
|
|
|
4057
4247
|
|
|
4058
4248
|
// src/tools/bash.ts
|
|
4059
4249
|
init_cjs_shims();
|
|
4060
|
-
var
|
|
4250
|
+
var import_zod7 = require("zod");
|
|
4061
4251
|
var _spawn = null;
|
|
4062
4252
|
async function getSpawn() {
|
|
4063
4253
|
if (_spawn === null) {
|
|
@@ -4069,15 +4259,16 @@ async function getSpawn() {
|
|
|
4069
4259
|
var MAX_OUTPUT_BYTES = 512 * 1024;
|
|
4070
4260
|
var SIGKILL_GRACE_MS = 500;
|
|
4071
4261
|
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:
|
|
4262
|
+
var inputSchema2 = import_zod7.z.object({
|
|
4263
|
+
command: import_zod7.z.string().min(1),
|
|
4264
|
+
cwd: import_zod7.z.string().min(1).optional()
|
|
4075
4265
|
});
|
|
4076
4266
|
function createBashTool() {
|
|
4077
4267
|
return defineTool({
|
|
4078
4268
|
name: "Bash",
|
|
4079
4269
|
description: "Execute a shell command via /bin/sh -c. Returns combined stdout+stderr and the exit code.",
|
|
4080
4270
|
inputSchema: inputSchema2,
|
|
4271
|
+
requiresNode: true,
|
|
4081
4272
|
execute: async ({ command, cwd }, ctx) => {
|
|
4082
4273
|
if (BLOCKED_DEVICE_PATHS.test(command)) {
|
|
4083
4274
|
return {
|
|
@@ -4157,10 +4348,10 @@ function createBashTool() {
|
|
|
4157
4348
|
|
|
4158
4349
|
// src/tools/sendMessage.ts
|
|
4159
4350
|
init_cjs_shims();
|
|
4160
|
-
var
|
|
4161
|
-
var inputSchema3 =
|
|
4162
|
-
to:
|
|
4163
|
-
message:
|
|
4351
|
+
var import_zod8 = require("zod");
|
|
4352
|
+
var inputSchema3 = import_zod8.z.object({
|
|
4353
|
+
to: import_zod8.z.string().min(1).describe("Agent name (subagent_type) or agentId to send the message to."),
|
|
4354
|
+
message: import_zod8.z.string().min(1).describe("Message content to deliver to the target agent.")
|
|
4164
4355
|
});
|
|
4165
4356
|
function createSendMessageTool(options) {
|
|
4166
4357
|
return defineTool({
|
|
@@ -4211,12 +4402,12 @@ function createSendMessageTool(options) {
|
|
|
4211
4402
|
|
|
4212
4403
|
// src/tools/fileEdit.ts
|
|
4213
4404
|
init_cjs_shims();
|
|
4214
|
-
var
|
|
4215
|
-
var inputSchema4 =
|
|
4216
|
-
path:
|
|
4217
|
-
old_string:
|
|
4218
|
-
new_string:
|
|
4219
|
-
replace_all:
|
|
4405
|
+
var import_zod9 = require("zod");
|
|
4406
|
+
var inputSchema4 = import_zod9.z.object({
|
|
4407
|
+
path: import_zod9.z.string().min(1),
|
|
4408
|
+
old_string: import_zod9.z.string().min(1),
|
|
4409
|
+
new_string: import_zod9.z.string(),
|
|
4410
|
+
replace_all: import_zod9.z.boolean().optional()
|
|
4220
4411
|
});
|
|
4221
4412
|
function createFileEditTool(storage) {
|
|
4222
4413
|
return defineTool({
|
|
@@ -4300,13 +4491,13 @@ function normalizeQuotes(s) {
|
|
|
4300
4491
|
|
|
4301
4492
|
// src/tools/fileRead.ts
|
|
4302
4493
|
init_cjs_shims();
|
|
4303
|
-
var
|
|
4304
|
-
var inputSchema5 =
|
|
4305
|
-
path:
|
|
4306
|
-
offset:
|
|
4307
|
-
limit:
|
|
4494
|
+
var import_zod10 = require("zod");
|
|
4495
|
+
var inputSchema5 = import_zod10.z.object({
|
|
4496
|
+
path: import_zod10.z.string().min(1),
|
|
4497
|
+
offset: import_zod10.z.number().int().positive().optional(),
|
|
4498
|
+
limit: import_zod10.z.number().int().positive().optional(),
|
|
4308
4499
|
/** PDF page range, e.g. "1-5", "3", "10-20". Max 20 pages per request. */
|
|
4309
|
-
pages:
|
|
4500
|
+
pages: import_zod10.z.string().optional()
|
|
4310
4501
|
});
|
|
4311
4502
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg"]);
|
|
4312
4503
|
var PDF_EXTENSION = ".pdf";
|
|
@@ -4474,7 +4665,7 @@ async function readImage(storage, filePath, ext) {
|
|
|
4474
4665
|
".svg": "image/svg+xml"
|
|
4475
4666
|
};
|
|
4476
4667
|
const mimeType = mimeMap[ext] ?? "application/octet-stream";
|
|
4477
|
-
const
|
|
4668
|
+
const base642 = buffer.toString("base64");
|
|
4478
4669
|
return {
|
|
4479
4670
|
content: `[Image: ${filePath} (${mimeType}, ${(buffer.length / 1024).toFixed(1)}KB)]
|
|
4480
4671
|
|
|
@@ -4483,17 +4674,17 @@ Base64 data is included in the metadata for visual analysis.`,
|
|
|
4483
4674
|
format: "image",
|
|
4484
4675
|
mimeType,
|
|
4485
4676
|
bytes: buffer.length,
|
|
4486
|
-
base64
|
|
4677
|
+
base64: base642
|
|
4487
4678
|
}
|
|
4488
4679
|
};
|
|
4489
4680
|
}
|
|
4490
4681
|
|
|
4491
4682
|
// src/tools/fileWrite.ts
|
|
4492
4683
|
init_cjs_shims();
|
|
4493
|
-
var
|
|
4494
|
-
var inputSchema6 =
|
|
4495
|
-
path:
|
|
4496
|
-
content:
|
|
4684
|
+
var import_zod11 = require("zod");
|
|
4685
|
+
var inputSchema6 = import_zod11.z.object({
|
|
4686
|
+
path: import_zod11.z.string().min(1),
|
|
4687
|
+
content: import_zod11.z.string()
|
|
4497
4688
|
});
|
|
4498
4689
|
function createFileWriteTool(storageOrOptions) {
|
|
4499
4690
|
const opts = "readFile" in storageOrOptions ? { storage: storageOrOptions } : storageOrOptions;
|
|
@@ -4532,7 +4723,7 @@ function createFileWriteTool(storageOrOptions) {
|
|
|
4532
4723
|
// src/tools/glob.ts
|
|
4533
4724
|
init_cjs_shims();
|
|
4534
4725
|
var import_picomatch = __toESM(require("picomatch"), 1);
|
|
4535
|
-
var
|
|
4726
|
+
var import_zod12 = require("zod");
|
|
4536
4727
|
|
|
4537
4728
|
// src/tools/walkAdapter.ts
|
|
4538
4729
|
init_cjs_shims();
|
|
@@ -4569,9 +4760,9 @@ async function* walkAdapter(adapter, startPath, options = {}) {
|
|
|
4569
4760
|
}
|
|
4570
4761
|
|
|
4571
4762
|
// src/tools/glob.ts
|
|
4572
|
-
var inputSchema7 =
|
|
4573
|
-
pattern:
|
|
4574
|
-
path:
|
|
4763
|
+
var inputSchema7 = import_zod12.z.object({
|
|
4764
|
+
pattern: import_zod12.z.string().min(1),
|
|
4765
|
+
path: import_zod12.z.string().optional()
|
|
4575
4766
|
});
|
|
4576
4767
|
var MAX_RESULTS = 1e3;
|
|
4577
4768
|
function createGlobTool(storage) {
|
|
@@ -4624,22 +4815,22 @@ function createGlobTool(storage) {
|
|
|
4624
4815
|
// src/tools/grep.ts
|
|
4625
4816
|
init_cjs_shims();
|
|
4626
4817
|
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:
|
|
4818
|
+
var import_zod13 = require("zod");
|
|
4819
|
+
var inputSchema8 = import_zod13.z.object({
|
|
4820
|
+
pattern: import_zod13.z.string().min(1),
|
|
4821
|
+
path: import_zod13.z.string().optional(),
|
|
4822
|
+
glob: import_zod13.z.string().optional(),
|
|
4823
|
+
type: import_zod13.z.string().optional(),
|
|
4824
|
+
output_mode: import_zod13.z.enum(["content", "files_with_matches", "count"]).optional(),
|
|
4825
|
+
"-i": import_zod13.z.boolean().optional(),
|
|
4826
|
+
"-n": import_zod13.z.boolean().optional(),
|
|
4827
|
+
"-A": import_zod13.z.number().int().nonnegative().optional(),
|
|
4828
|
+
"-B": import_zod13.z.number().int().nonnegative().optional(),
|
|
4829
|
+
"-C": import_zod13.z.number().int().nonnegative().optional(),
|
|
4830
|
+
context: import_zod13.z.number().int().nonnegative().optional(),
|
|
4831
|
+
multiline: import_zod13.z.boolean().optional(),
|
|
4832
|
+
head_limit: import_zod13.z.number().int().nonnegative().optional(),
|
|
4833
|
+
offset: import_zod13.z.number().int().nonnegative().optional()
|
|
4643
4834
|
});
|
|
4644
4835
|
var MAX_FILES_SCANNED = 5e3;
|
|
4645
4836
|
var MAX_MATCHES_PER_FILE = 100;
|
|
@@ -4863,10 +5054,10 @@ function formatJsResults(results, mode, limit) {
|
|
|
4863
5054
|
|
|
4864
5055
|
// src/tools/webFetch.ts
|
|
4865
5056
|
init_cjs_shims();
|
|
4866
|
-
var
|
|
4867
|
-
var inputSchema9 =
|
|
4868
|
-
url:
|
|
4869
|
-
prompt:
|
|
5057
|
+
var import_zod14 = require("zod");
|
|
5058
|
+
var inputSchema9 = import_zod14.z.object({
|
|
5059
|
+
url: import_zod14.z.string().url(),
|
|
5060
|
+
prompt: import_zod14.z.string().optional()
|
|
4870
5061
|
});
|
|
4871
5062
|
var MAX_OUTPUT_BYTES2 = 256 * 1024;
|
|
4872
5063
|
function createWebFetchTool(options = {}) {
|
|
@@ -4995,10 +5186,10 @@ function normalizePath(p) {
|
|
|
4995
5186
|
|
|
4996
5187
|
// src/tools/webSearch.ts
|
|
4997
5188
|
init_cjs_shims();
|
|
4998
|
-
var
|
|
4999
|
-
var inputSchema10 =
|
|
5000
|
-
query:
|
|
5001
|
-
max_results:
|
|
5189
|
+
var import_zod15 = require("zod");
|
|
5190
|
+
var inputSchema10 = import_zod15.z.object({
|
|
5191
|
+
query: import_zod15.z.string().min(2),
|
|
5192
|
+
max_results: import_zod15.z.number().int().positive().optional()
|
|
5002
5193
|
});
|
|
5003
5194
|
function createWebSearchTool() {
|
|
5004
5195
|
return defineTool({
|
|
@@ -5055,10 +5246,10 @@ function htmlToText2(html) {
|
|
|
5055
5246
|
|
|
5056
5247
|
// src/tools/sleep.ts
|
|
5057
5248
|
init_cjs_shims();
|
|
5058
|
-
var
|
|
5059
|
-
var inputSchema11 =
|
|
5060
|
-
durationMs:
|
|
5061
|
-
reason:
|
|
5249
|
+
var import_zod16 = require("zod");
|
|
5250
|
+
var inputSchema11 = import_zod16.z.object({
|
|
5251
|
+
durationMs: import_zod16.z.number().int().nonnegative().max(3e5),
|
|
5252
|
+
reason: import_zod16.z.string().optional()
|
|
5062
5253
|
});
|
|
5063
5254
|
function createSleepTool() {
|
|
5064
5255
|
return defineTool({
|
|
@@ -5098,10 +5289,10 @@ function createSleepTool() {
|
|
|
5098
5289
|
|
|
5099
5290
|
// src/tools/toolSearch.ts
|
|
5100
5291
|
init_cjs_shims();
|
|
5101
|
-
var
|
|
5102
|
-
var inputSchema12 =
|
|
5103
|
-
query:
|
|
5104
|
-
max_results:
|
|
5292
|
+
var import_zod17 = require("zod");
|
|
5293
|
+
var inputSchema12 = import_zod17.z.object({
|
|
5294
|
+
query: import_zod17.z.string().min(1),
|
|
5295
|
+
max_results: import_zod17.z.number().int().positive().optional()
|
|
5105
5296
|
});
|
|
5106
5297
|
function createToolSearchTool(registry) {
|
|
5107
5298
|
return defineTool({
|
|
@@ -5144,11 +5335,11 @@ ${lines.join("\n")}`,
|
|
|
5144
5335
|
|
|
5145
5336
|
// src/tools/memorize.ts
|
|
5146
5337
|
init_cjs_shims();
|
|
5147
|
-
var
|
|
5148
|
-
var inputSchema13 =
|
|
5149
|
-
text:
|
|
5150
|
-
kind:
|
|
5151
|
-
topic:
|
|
5338
|
+
var import_zod18 = require("zod");
|
|
5339
|
+
var inputSchema13 = import_zod18.z.object({
|
|
5340
|
+
text: import_zod18.z.string().min(1),
|
|
5341
|
+
kind: import_zod18.z.enum(["rule", "lesson"]).default("lesson"),
|
|
5342
|
+
topic: import_zod18.z.string().optional()
|
|
5152
5343
|
});
|
|
5153
5344
|
function createMemorizeTool(memory) {
|
|
5154
5345
|
return defineTool({
|
|
@@ -5180,11 +5371,11 @@ function createMemorizeTool(memory) {
|
|
|
5180
5371
|
|
|
5181
5372
|
// src/tools/recall.ts
|
|
5182
5373
|
init_cjs_shims();
|
|
5183
|
-
var
|
|
5184
|
-
var inputSchema14 =
|
|
5185
|
-
query:
|
|
5186
|
-
scope:
|
|
5187
|
-
topic:
|
|
5374
|
+
var import_zod19 = require("zod");
|
|
5375
|
+
var inputSchema14 = import_zod19.z.object({
|
|
5376
|
+
query: import_zod19.z.string().min(1),
|
|
5377
|
+
scope: import_zod19.z.enum(["identity", "rules", "lessons", "all"]).default("all"),
|
|
5378
|
+
topic: import_zod19.z.string().optional()
|
|
5188
5379
|
});
|
|
5189
5380
|
function createRecallTool(memory) {
|
|
5190
5381
|
return defineTool({
|
|
@@ -5239,13 +5430,13 @@ ${content}`,
|
|
|
5239
5430
|
|
|
5240
5431
|
// src/tools/notebookEdit.ts
|
|
5241
5432
|
init_cjs_shims();
|
|
5242
|
-
var
|
|
5243
|
-
var inputSchema15 =
|
|
5244
|
-
notebook_path:
|
|
5245
|
-
edit_mode:
|
|
5246
|
-
cell_index:
|
|
5247
|
-
new_source:
|
|
5248
|
-
cell_type:
|
|
5433
|
+
var import_zod20 = require("zod");
|
|
5434
|
+
var inputSchema15 = import_zod20.z.object({
|
|
5435
|
+
notebook_path: import_zod20.z.string().min(1),
|
|
5436
|
+
edit_mode: import_zod20.z.enum(["replace", "insert", "delete"]).default("replace"),
|
|
5437
|
+
cell_index: import_zod20.z.number().int().nonnegative(),
|
|
5438
|
+
new_source: import_zod20.z.string().optional(),
|
|
5439
|
+
cell_type: import_zod20.z.enum(["code", "markdown"]).optional()
|
|
5249
5440
|
});
|
|
5250
5441
|
function createNotebookEditTool(storage) {
|
|
5251
5442
|
return defineTool({
|
|
@@ -5400,12 +5591,12 @@ var TaskStore = class {
|
|
|
5400
5591
|
|
|
5401
5592
|
// src/tools/tasks/tools.ts
|
|
5402
5593
|
init_cjs_shims();
|
|
5403
|
-
var
|
|
5404
|
-
var TaskStatusEnum =
|
|
5405
|
-
var createSchema =
|
|
5406
|
-
subject:
|
|
5407
|
-
description:
|
|
5408
|
-
metadata:
|
|
5594
|
+
var import_zod21 = require("zod");
|
|
5595
|
+
var TaskStatusEnum = import_zod21.z.enum(["pending", "in_progress", "completed", "deleted"]);
|
|
5596
|
+
var createSchema = import_zod21.z.object({
|
|
5597
|
+
subject: import_zod21.z.string().min(1),
|
|
5598
|
+
description: import_zod21.z.string().default(""),
|
|
5599
|
+
metadata: import_zod21.z.record(import_zod21.z.unknown()).optional()
|
|
5409
5600
|
});
|
|
5410
5601
|
function createTaskCreateTool(store) {
|
|
5411
5602
|
return defineTool({
|
|
@@ -5421,8 +5612,8 @@ function createTaskCreateTool(store) {
|
|
|
5421
5612
|
}
|
|
5422
5613
|
});
|
|
5423
5614
|
}
|
|
5424
|
-
var getSchema =
|
|
5425
|
-
taskId:
|
|
5615
|
+
var getSchema = import_zod21.z.object({
|
|
5616
|
+
taskId: import_zod21.z.string().min(1)
|
|
5426
5617
|
});
|
|
5427
5618
|
function createTaskGetTool(store) {
|
|
5428
5619
|
return defineTool({
|
|
@@ -5443,7 +5634,7 @@ ${task.description}`,
|
|
|
5443
5634
|
}
|
|
5444
5635
|
});
|
|
5445
5636
|
}
|
|
5446
|
-
var listSchema =
|
|
5637
|
+
var listSchema = import_zod21.z.object({
|
|
5447
5638
|
status: TaskStatusEnum.optional()
|
|
5448
5639
|
});
|
|
5449
5640
|
function createTaskListTool(store) {
|
|
@@ -5469,12 +5660,12 @@ ${lines.join("\n")}`,
|
|
|
5469
5660
|
}
|
|
5470
5661
|
});
|
|
5471
5662
|
}
|
|
5472
|
-
var updateSchema =
|
|
5473
|
-
taskId:
|
|
5474
|
-
subject:
|
|
5663
|
+
var updateSchema = import_zod21.z.object({
|
|
5664
|
+
taskId: import_zod21.z.string().min(1),
|
|
5665
|
+
subject: import_zod21.z.string().min(1).optional(),
|
|
5475
5666
|
status: TaskStatusEnum.optional(),
|
|
5476
|
-
description:
|
|
5477
|
-
metadata:
|
|
5667
|
+
description: import_zod21.z.string().optional(),
|
|
5668
|
+
metadata: import_zod21.z.record(import_zod21.z.unknown()).optional()
|
|
5478
5669
|
});
|
|
5479
5670
|
function createTaskUpdateTool(store) {
|
|
5480
5671
|
return defineTool({
|
|
@@ -6321,7 +6512,7 @@ function wrapFetchWithHeadersProvider(baseFetch, headersProvider, staticHeaders)
|
|
|
6321
6512
|
|
|
6322
6513
|
// src/mcp/toolAdapter.ts
|
|
6323
6514
|
init_cjs_shims();
|
|
6324
|
-
var
|
|
6515
|
+
var import_zod22 = require("zod");
|
|
6325
6516
|
function mcpToolName(serverName, toolName) {
|
|
6326
6517
|
return `mcp__${serverName}__${toolName}`;
|
|
6327
6518
|
}
|
|
@@ -6330,7 +6521,7 @@ function adaptMcpTool(client, serverName, def) {
|
|
|
6330
6521
|
return defineTool({
|
|
6331
6522
|
name: registeredName,
|
|
6332
6523
|
description: def.description.length > 0 ? def.description : `MCP tool ${serverName}/${def.name}`,
|
|
6333
|
-
inputSchema:
|
|
6524
|
+
inputSchema: import_zod22.z.unknown(),
|
|
6334
6525
|
// Pass the MCP server's JSON Schema through to Anthropic verbatim,
|
|
6335
6526
|
// bypassing Zod-to-JSON-Schema conversion (which would produce `{}`
|
|
6336
6527
|
// for our `z.unknown()` Zod schema).
|
|
@@ -6991,7 +7182,7 @@ ${entries.map((e) => `- ${e}`).join("\n")}
|
|
|
6991
7182
|
// src/memory/memoryConfig.ts
|
|
6992
7183
|
function createSmartMemory(options) {
|
|
6993
7184
|
const { storage, config } = options;
|
|
6994
|
-
const adapter =
|
|
7185
|
+
const adapter = storage.workspace;
|
|
6995
7186
|
const hippocampus = new Hippocampus(adapter, "smart-memory");
|
|
6996
7187
|
const writesEnabled = config.mode === "read-write";
|
|
6997
7188
|
const readsEnabled = config.mode !== "off";
|
|
@@ -7362,18 +7553,7 @@ ${lessons}`);
|
|
|
7362
7553
|
}
|
|
7363
7554
|
async function collectSkills(storage, skillsDir) {
|
|
7364
7555
|
const workspace = await loadSkills(storage.workspace, skillsDir);
|
|
7365
|
-
|
|
7366
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7367
|
-
const out = [];
|
|
7368
|
-
for (const s of workspace) {
|
|
7369
|
-
seen.add(s.name);
|
|
7370
|
-
out.push({ name: s.name, description: s.description });
|
|
7371
|
-
}
|
|
7372
|
-
for (const s of global) {
|
|
7373
|
-
if (seen.has(s.name)) continue;
|
|
7374
|
-
out.push({ name: s.name, description: s.description });
|
|
7375
|
-
}
|
|
7376
|
-
return out;
|
|
7556
|
+
return workspace.map((s) => ({ name: s.name, description: s.description }));
|
|
7377
7557
|
}
|
|
7378
7558
|
|
|
7379
7559
|
// src/engine/jsonOutput.ts
|
|
@@ -7439,11 +7619,11 @@ ${issues.join("\n")}` };
|
|
|
7439
7619
|
|
|
7440
7620
|
// src/skills/skillPage.ts
|
|
7441
7621
|
init_cjs_shims();
|
|
7442
|
-
var
|
|
7622
|
+
var import_zod23 = require("zod");
|
|
7443
7623
|
var SAFE_NAME3 = /^[a-zA-Z0-9_-]+$/;
|
|
7444
|
-
var inputSchema16 =
|
|
7445
|
-
skill:
|
|
7446
|
-
page:
|
|
7624
|
+
var inputSchema16 = import_zod23.z.object({
|
|
7625
|
+
skill: import_zod23.z.string().min(1),
|
|
7626
|
+
page: import_zod23.z.string().min(1).optional()
|
|
7447
7627
|
});
|
|
7448
7628
|
function createSkillPageTool(options) {
|
|
7449
7629
|
return defineTool({
|
|
@@ -7499,6 +7679,203 @@ The skill "${skill}" has no pages.`;
|
|
|
7499
7679
|
});
|
|
7500
7680
|
}
|
|
7501
7681
|
|
|
7682
|
+
// src/tools/apiCall.ts
|
|
7683
|
+
init_cjs_shims();
|
|
7684
|
+
var import_zod24 = require("zod");
|
|
7685
|
+
var ALL_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
7686
|
+
var DEFAULT_MAX_BODY_BYTES = 256 * 1024;
|
|
7687
|
+
var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024;
|
|
7688
|
+
function createApiCallTool(opts) {
|
|
7689
|
+
if (opts.services.length === 0) {
|
|
7690
|
+
throw new Error("createApiCallTool: services list must be non-empty");
|
|
7691
|
+
}
|
|
7692
|
+
const services = /* @__PURE__ */ new Map();
|
|
7693
|
+
for (const svc of opts.services) {
|
|
7694
|
+
if (services.has(svc.name)) {
|
|
7695
|
+
throw new Error(`createApiCallTool: duplicate service name "${svc.name}"`);
|
|
7696
|
+
}
|
|
7697
|
+
services.set(svc.name, svc);
|
|
7698
|
+
}
|
|
7699
|
+
const serviceNames = [...services.keys()];
|
|
7700
|
+
for (const svc of opts.services) {
|
|
7701
|
+
if (svc.auth?.type === "custom" && opts.resolveAuth === void 0) {
|
|
7702
|
+
throw new Error(
|
|
7703
|
+
`createApiCallTool: service "${svc.name}" uses custom auth (id: ${svc.auth.id}) but no resolveAuth was supplied`
|
|
7704
|
+
);
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
7708
|
+
const maxResponseBytes = opts.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
7709
|
+
const inputSchema17 = import_zod24.z.object({
|
|
7710
|
+
service: import_zod24.z.enum(serviceNames),
|
|
7711
|
+
method: import_zod24.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
7712
|
+
path: import_zod24.z.string().regex(/^\//, "path must start with /"),
|
|
7713
|
+
query: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
|
|
7714
|
+
body: import_zod24.z.unknown().optional(),
|
|
7715
|
+
headers: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
|
|
7716
|
+
});
|
|
7717
|
+
const description = opts.toolDescription ?? `Call a configured external API. Services: ${serviceNames.join(", ")}. Auth is injected automatically \u2014 do not pass credentials via headers.`;
|
|
7718
|
+
return defineTool({
|
|
7719
|
+
name: opts.toolName ?? "ApiCall",
|
|
7720
|
+
description,
|
|
7721
|
+
inputSchema: inputSchema17,
|
|
7722
|
+
execute: async (input) => {
|
|
7723
|
+
const svc = services.get(input.service);
|
|
7724
|
+
if (!svc) {
|
|
7725
|
+
return errResult(`ERR_API_UNKNOWN_SERVICE: ${input.service}`);
|
|
7726
|
+
}
|
|
7727
|
+
const allowedMethods = svc.allowedMethods ?? ALL_METHODS;
|
|
7728
|
+
if (!allowedMethods.includes(input.method)) {
|
|
7729
|
+
return errResult(
|
|
7730
|
+
`ERR_API_METHOD_NOT_ALLOWED: ${input.method} not permitted for service ${svc.name}`
|
|
7731
|
+
);
|
|
7732
|
+
}
|
|
7733
|
+
if (!pathAllowed(input.path, svc.allowedPaths)) {
|
|
7734
|
+
return errResult(`ERR_API_PATH_NOT_ALLOWED: ${input.path} for service ${svc.name}`);
|
|
7735
|
+
}
|
|
7736
|
+
let bodyText;
|
|
7737
|
+
if (input.body !== void 0) {
|
|
7738
|
+
bodyText = JSON.stringify(input.body);
|
|
7739
|
+
const cap = svc.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
7740
|
+
if (byteLength(bodyText) > cap) {
|
|
7741
|
+
return errResult(`ERR_API_BODY_TOO_LARGE: exceeds ${cap} bytes`);
|
|
7742
|
+
}
|
|
7743
|
+
}
|
|
7744
|
+
let authHeaders;
|
|
7745
|
+
try {
|
|
7746
|
+
authHeaders = await resolveAuth({
|
|
7747
|
+
auth: svc.auth ?? { type: "none" },
|
|
7748
|
+
env: opts.env,
|
|
7749
|
+
resolver: opts.resolveAuth,
|
|
7750
|
+
ctx: { serviceName: svc.name, method: input.method, path: input.path }
|
|
7751
|
+
});
|
|
7752
|
+
} catch (err) {
|
|
7753
|
+
const raw2 = err instanceof Error ? err.message : String(err);
|
|
7754
|
+
const truncated = raw2.length > 200 ? raw2.slice(0, 200) + "\u2026" : raw2;
|
|
7755
|
+
return errResult(`ERR_API_RESOLVER_FAILED: ${truncated}`);
|
|
7756
|
+
}
|
|
7757
|
+
const userHeaders = sanitizeHeaders(input.headers ?? {}, authHeaders);
|
|
7758
|
+
const url = buildUrl(svc.baseUrl, input.path, input.query);
|
|
7759
|
+
await invokeHook(opts.onRequest, {
|
|
7760
|
+
service: svc.name,
|
|
7761
|
+
method: input.method,
|
|
7762
|
+
path: input.path
|
|
7763
|
+
});
|
|
7764
|
+
const started = Date.now();
|
|
7765
|
+
let res;
|
|
7766
|
+
try {
|
|
7767
|
+
res = await fetchFn(url, {
|
|
7768
|
+
method: input.method,
|
|
7769
|
+
headers: {
|
|
7770
|
+
"Content-Type": "application/json",
|
|
7771
|
+
...svc.defaultHeaders ?? {},
|
|
7772
|
+
...userHeaders,
|
|
7773
|
+
...authHeaders
|
|
7774
|
+
// wins last — model cannot override
|
|
7775
|
+
},
|
|
7776
|
+
...bodyText !== void 0 ? { body: bodyText } : {}
|
|
7777
|
+
});
|
|
7778
|
+
} catch (err) {
|
|
7779
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7780
|
+
return errResult(`network error: ${msg}`);
|
|
7781
|
+
}
|
|
7782
|
+
const raw = await res.text();
|
|
7783
|
+
const content = raw.length > maxResponseBytes ? raw.slice(0, maxResponseBytes) + "\n\u2026[TRUNCATED]" : raw;
|
|
7784
|
+
await invokeHook(opts.onResponse, {
|
|
7785
|
+
service: svc.name,
|
|
7786
|
+
method: input.method,
|
|
7787
|
+
path: input.path,
|
|
7788
|
+
status: res.status,
|
|
7789
|
+
latencyMs: Date.now() - started,
|
|
7790
|
+
bytesIn: raw.length
|
|
7791
|
+
});
|
|
7792
|
+
return {
|
|
7793
|
+
content,
|
|
7794
|
+
isError: !res.ok,
|
|
7795
|
+
metadata: { status: res.status, service: svc.name }
|
|
7796
|
+
};
|
|
7797
|
+
}
|
|
7798
|
+
});
|
|
7799
|
+
}
|
|
7800
|
+
function errResult(msg) {
|
|
7801
|
+
return { content: msg, isError: true };
|
|
7802
|
+
}
|
|
7803
|
+
function pathAllowed(path, allowed) {
|
|
7804
|
+
if (!allowed || allowed.length === 0) return true;
|
|
7805
|
+
for (const a of allowed) {
|
|
7806
|
+
if (typeof a === "string") {
|
|
7807
|
+
if (path.startsWith(a)) return true;
|
|
7808
|
+
} else if (a.test(path)) {
|
|
7809
|
+
return true;
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
return false;
|
|
7813
|
+
}
|
|
7814
|
+
function byteLength(s) {
|
|
7815
|
+
return new TextEncoder().encode(s).byteLength;
|
|
7816
|
+
}
|
|
7817
|
+
function buildUrl(baseUrl, path, query) {
|
|
7818
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
7819
|
+
const url = new URL(base + path);
|
|
7820
|
+
for (const [k, v] of Object.entries(query ?? {})) {
|
|
7821
|
+
url.searchParams.set(k, v);
|
|
7822
|
+
}
|
|
7823
|
+
return url.toString();
|
|
7824
|
+
}
|
|
7825
|
+
function sanitizeHeaders(user, auth) {
|
|
7826
|
+
const banned = new Set(Object.keys(auth).map((k) => k.toLowerCase()));
|
|
7827
|
+
const out = {};
|
|
7828
|
+
for (const [k, v] of Object.entries(user)) {
|
|
7829
|
+
if (banned.has(k.toLowerCase())) continue;
|
|
7830
|
+
out[k] = v;
|
|
7831
|
+
}
|
|
7832
|
+
return out;
|
|
7833
|
+
}
|
|
7834
|
+
async function resolveAuth(args) {
|
|
7835
|
+
const { auth, env, resolver, ctx } = args;
|
|
7836
|
+
switch (auth.type) {
|
|
7837
|
+
case "none":
|
|
7838
|
+
return {};
|
|
7839
|
+
case "bearer": {
|
|
7840
|
+
const token = envLookup(env, auth.tokenRef);
|
|
7841
|
+
return { Authorization: `Bearer ${token}` };
|
|
7842
|
+
}
|
|
7843
|
+
case "header": {
|
|
7844
|
+
const value = envLookup(env, auth.valueRef);
|
|
7845
|
+
return { [auth.name]: value };
|
|
7846
|
+
}
|
|
7847
|
+
case "basic": {
|
|
7848
|
+
const u = envLookup(env, auth.userRef);
|
|
7849
|
+
const p = envLookup(env, auth.passRef);
|
|
7850
|
+
return { Authorization: `Basic ${base64(`${u}:${p}`)}` };
|
|
7851
|
+
}
|
|
7852
|
+
case "custom":
|
|
7853
|
+
if (resolver === void 0) {
|
|
7854
|
+
throw new Error(`custom auth id "${auth.id}" requires resolveAuth`);
|
|
7855
|
+
}
|
|
7856
|
+
return resolver(auth, ctx);
|
|
7857
|
+
}
|
|
7858
|
+
}
|
|
7859
|
+
function envLookup(env, ref) {
|
|
7860
|
+
if (env === void 0 || env[ref] === void 0) {
|
|
7861
|
+
throw new Error(`ERR_API_ENV_MISSING: ${ref}`);
|
|
7862
|
+
}
|
|
7863
|
+
return env[ref];
|
|
7864
|
+
}
|
|
7865
|
+
function base64(input) {
|
|
7866
|
+
if (typeof globalThis.btoa === "function") {
|
|
7867
|
+
return globalThis.btoa(input);
|
|
7868
|
+
}
|
|
7869
|
+
return Buffer.from(input, "utf8").toString("base64");
|
|
7870
|
+
}
|
|
7871
|
+
async function invokeHook(hook, event) {
|
|
7872
|
+
if (hook === void 0) return;
|
|
7873
|
+
try {
|
|
7874
|
+
await hook(event);
|
|
7875
|
+
} catch {
|
|
7876
|
+
}
|
|
7877
|
+
}
|
|
7878
|
+
|
|
7502
7879
|
// src/skills/storageSkillSource.ts
|
|
7503
7880
|
init_cjs_shims();
|
|
7504
7881
|
var SAFE_NAME4 = /^[a-zA-Z0-9_-]+$/;
|
|
@@ -7510,14 +7887,8 @@ var StorageSkillSource = class {
|
|
|
7510
7887
|
this.baseDir = options.baseDir ?? "skills";
|
|
7511
7888
|
}
|
|
7512
7889
|
async list() {
|
|
7513
|
-
const
|
|
7514
|
-
|
|
7515
|
-
loadSkills(this.storage.global, this.baseDir)
|
|
7516
|
-
]);
|
|
7517
|
-
const byName = /* @__PURE__ */ new Map();
|
|
7518
|
-
for (const s of global) byName.set(s.name, s);
|
|
7519
|
-
for (const s of workspace) byName.set(s.name, s);
|
|
7520
|
-
return Array.from(byName.values()).map((s) => ({
|
|
7890
|
+
const loaded = await loadSkills(this.storage.workspace, this.baseDir);
|
|
7891
|
+
return loaded.map((s) => ({
|
|
7521
7892
|
name: s.name,
|
|
7522
7893
|
description: s.description,
|
|
7523
7894
|
hasPages: s.hasPages
|
|
@@ -7525,8 +7896,7 @@ var StorageSkillSource = class {
|
|
|
7525
7896
|
}
|
|
7526
7897
|
async getSkillFile(skill) {
|
|
7527
7898
|
if (!SAFE_NAME4.test(skill)) return null;
|
|
7528
|
-
|
|
7529
|
-
return found;
|
|
7899
|
+
return this.findFile(skill, "SKILL.md");
|
|
7530
7900
|
}
|
|
7531
7901
|
async getPage(skill, page) {
|
|
7532
7902
|
if (!SAFE_NAME4.test(skill)) return null;
|
|
@@ -7535,9 +7905,7 @@ var StorageSkillSource = class {
|
|
|
7535
7905
|
}
|
|
7536
7906
|
async listPages(skill) {
|
|
7537
7907
|
if (!SAFE_NAME4.test(skill)) return [];
|
|
7538
|
-
|
|
7539
|
-
if (wsPages.length > 0) return wsPages;
|
|
7540
|
-
return this.listPagesIn(this.storage.global, skill);
|
|
7908
|
+
return this.listPagesIn(this.storage.workspace, skill);
|
|
7541
7909
|
}
|
|
7542
7910
|
async listPagesIn(adapter, skill) {
|
|
7543
7911
|
const pagesDir = `${this.baseDir}/${skill}/pages`;
|
|
@@ -7550,9 +7918,7 @@ var StorageSkillSource = class {
|
|
|
7550
7918
|
}
|
|
7551
7919
|
async findFile(skill, relative) {
|
|
7552
7920
|
const path = `${this.baseDir}/${skill}/${relative}`;
|
|
7553
|
-
|
|
7554
|
-
if (fromWorkspace !== null) return fromWorkspace;
|
|
7555
|
-
return this.readIfExists(this.storage.global, path);
|
|
7921
|
+
return this.readIfExists(this.storage.workspace, path);
|
|
7556
7922
|
}
|
|
7557
7923
|
async readIfExists(adapter, path) {
|
|
7558
7924
|
try {
|
|
@@ -8135,7 +8501,6 @@ async function createEngineStorage(config) {
|
|
|
8135
8501
|
}
|
|
8136
8502
|
async function createLocalStorage(config) {
|
|
8137
8503
|
const path = await import("path");
|
|
8138
|
-
const globalRoot = path.join(config.rootPath, ENGINE_DATA_FOLDER);
|
|
8139
8504
|
const workspaceRoot = path.join(
|
|
8140
8505
|
config.rootPath,
|
|
8141
8506
|
WORKSPACES_FOLDER,
|
|
@@ -8143,7 +8508,6 @@ async function createLocalStorage(config) {
|
|
|
8143
8508
|
ENGINE_DATA_FOLDER
|
|
8144
8509
|
);
|
|
8145
8510
|
return {
|
|
8146
|
-
global: new LocalStorageAdapter(globalRoot),
|
|
8147
8511
|
workspace: new LocalStorageAdapter(workspaceRoot)
|
|
8148
8512
|
};
|
|
8149
8513
|
}
|
|
@@ -8152,10 +8516,8 @@ function createR2Storage(config) {
|
|
|
8152
8516
|
throw new StorageError('storage.r2 is required when storage.provider === "r2"');
|
|
8153
8517
|
}
|
|
8154
8518
|
const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
|
|
8155
|
-
const globalPrefix = `${rootPrefix}/${ENGINE_DATA_FOLDER}`;
|
|
8156
8519
|
const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
|
|
8157
8520
|
return {
|
|
8158
|
-
global: new R2StorageAdapter(config.r2, globalPrefix),
|
|
8159
8521
|
workspace: new R2StorageAdapter(config.r2, workspacePrefix)
|
|
8160
8522
|
};
|
|
8161
8523
|
}
|
|
@@ -8164,10 +8526,8 @@ function createR2BindingStorage(config) {
|
|
|
8164
8526
|
throw new StorageError('storage.r2Binding is required when storage.provider === "r2-binding"');
|
|
8165
8527
|
}
|
|
8166
8528
|
const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
|
|
8167
|
-
const globalPrefix = `${rootPrefix}/${ENGINE_DATA_FOLDER}`;
|
|
8168
8529
|
const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
|
|
8169
8530
|
return {
|
|
8170
|
-
global: new R2BindingStorageAdapter(config.r2Binding, globalPrefix),
|
|
8171
8531
|
workspace: new R2BindingStorageAdapter(config.r2Binding, workspacePrefix)
|
|
8172
8532
|
};
|
|
8173
8533
|
}
|
|
@@ -8274,6 +8634,7 @@ function rebuildMessagesFromEntries(entries) {
|
|
|
8274
8634
|
init_cjs_shims();
|
|
8275
8635
|
function toResponse(result, extra) {
|
|
8276
8636
|
const timestamp = Date.now();
|
|
8637
|
+
const capsField = extra.capabilitiesMissing !== void 0 && extra.capabilitiesMissing.length > 0 ? { capabilitiesMissing: extra.capabilitiesMissing } : {};
|
|
8277
8638
|
if (result.status === "done") {
|
|
8278
8639
|
return {
|
|
8279
8640
|
runId: extra.runId,
|
|
@@ -8285,7 +8646,8 @@ function toResponse(result, extra) {
|
|
|
8285
8646
|
tokensUsed: result.tokensUsed,
|
|
8286
8647
|
durationMs: extra.durationMs,
|
|
8287
8648
|
output: result.output,
|
|
8288
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {}
|
|
8649
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: 0 } } : {},
|
|
8650
|
+
...capsField
|
|
8289
8651
|
},
|
|
8290
8652
|
errors: [],
|
|
8291
8653
|
timestamp
|
|
@@ -8304,7 +8666,8 @@ function toResponse(result, extra) {
|
|
|
8304
8666
|
snapshot: result.snapshot,
|
|
8305
8667
|
...result.snapshot.pendingToolCall !== void 0 ? { pendingToolCall: result.snapshot.pendingToolCall } : {},
|
|
8306
8668
|
pauseReason: result.reason,
|
|
8307
|
-
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {}
|
|
8669
|
+
...extra.logPath !== void 0 ? { transcript: { path: extra.logPath, lastShardIndex: result.snapshot.lastShardIndex } } : {},
|
|
8670
|
+
...capsField
|
|
8308
8671
|
},
|
|
8309
8672
|
errors: [],
|
|
8310
8673
|
timestamp
|
|
@@ -8638,7 +9001,15 @@ var Engine = class {
|
|
|
8638
9001
|
this.mcpManager = new McpManager(config.mcp, createLogger(config.logging), { samplingHandler });
|
|
8639
9002
|
this.permissionPolicy = buildPermissionPolicy(config.permissions);
|
|
8640
9003
|
}
|
|
8641
|
-
|
|
9004
|
+
/**
|
|
9005
|
+
* Run a task synchronously to completion. The `_internal` parameter is
|
|
9006
|
+
* reserved for the engine's own async wrappers (`start`, `resumeAsync`)
|
|
9007
|
+
* to request runner handoff (Plan 019) — external callers must leave
|
|
9008
|
+
* it unset. Sync callers never hand off; if they hit a Node-only tool
|
|
9009
|
+
* on a restricted runtime, the capability stub returns an error and
|
|
9010
|
+
* the model adapts.
|
|
9011
|
+
*/
|
|
9012
|
+
async run(options, _internal) {
|
|
8642
9013
|
const startTime = Date.now();
|
|
8643
9014
|
const runId = options.runId ?? `run_${randomUUID()}`;
|
|
8644
9015
|
const log = createLogger(this.config.logging);
|
|
@@ -8661,6 +9032,7 @@ var Engine = class {
|
|
|
8661
9032
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8662
9033
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8663
9034
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
9035
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8664
9036
|
let systemPrompt = await buildSystemPrompt({
|
|
8665
9037
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8666
9038
|
memory,
|
|
@@ -8691,7 +9063,9 @@ var Engine = class {
|
|
|
8691
9063
|
mcpTools,
|
|
8692
9064
|
memory,
|
|
8693
9065
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8694
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
9066
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
9067
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
9068
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8695
9069
|
});
|
|
8696
9070
|
const writer = new TranscriptWriter({
|
|
8697
9071
|
storage: storage.workspace,
|
|
@@ -8745,7 +9119,8 @@ var Engine = class {
|
|
|
8745
9119
|
onProgress: this.buildHeartbeat(storage, runId, options.nodeId),
|
|
8746
9120
|
...options.tokenBudget !== void 0 ? { tokenBudget: options.tokenBudget } : {},
|
|
8747
9121
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8748
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9122
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9123
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8749
9124
|
});
|
|
8750
9125
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8751
9126
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8753,18 +9128,20 @@ var Engine = class {
|
|
|
8753
9128
|
});
|
|
8754
9129
|
this.logRunEnd(log, runId, options.nodeId, result);
|
|
8755
9130
|
await this.firePostRunHook(runId, options.nodeId, result, ctx, logPath);
|
|
9131
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8756
9132
|
return toResponse(result, {
|
|
8757
9133
|
runId,
|
|
8758
9134
|
nodeId: options.nodeId,
|
|
8759
9135
|
durationMs: Date.now() - startTime,
|
|
8760
|
-
logPath
|
|
9136
|
+
logPath,
|
|
9137
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8761
9138
|
});
|
|
8762
9139
|
} finally {
|
|
8763
9140
|
runTimeout.clear();
|
|
8764
9141
|
await writer.close();
|
|
8765
9142
|
}
|
|
8766
9143
|
}
|
|
8767
|
-
async resume(options) {
|
|
9144
|
+
async resume(options, _internal) {
|
|
8768
9145
|
const startTime = Date.now();
|
|
8769
9146
|
const log = createLogger(this.config.logging);
|
|
8770
9147
|
const storage = await this.buildStorage();
|
|
@@ -8797,6 +9174,7 @@ var Engine = class {
|
|
|
8797
9174
|
const coordinatorBase = isCoordinatorMode(this.config) ? getCoordinatorBasePrompt() : void 0;
|
|
8798
9175
|
const skillSource = this.resolveSkillSource(options.skills, storage);
|
|
8799
9176
|
const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
|
|
9177
|
+
const apiConfig = this.resolveApiConfig(options.api);
|
|
8800
9178
|
let systemPrompt = await buildSystemPrompt({
|
|
8801
9179
|
...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
|
|
8802
9180
|
memory,
|
|
@@ -8827,7 +9205,9 @@ var Engine = class {
|
|
|
8827
9205
|
mcpTools,
|
|
8828
9206
|
memory,
|
|
8829
9207
|
...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
|
|
8830
|
-
...skillSource !== void 0 ? { skillSource } : {}
|
|
9208
|
+
...skillSource !== void 0 ? { skillSource } : {},
|
|
9209
|
+
...apiConfig !== void 0 ? { apiConfig } : {},
|
|
9210
|
+
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
8831
9211
|
});
|
|
8832
9212
|
const priorState = await loadWriterState(storage.workspace, logPath);
|
|
8833
9213
|
const writer = new TranscriptWriter({
|
|
@@ -8881,18 +9261,21 @@ var Engine = class {
|
|
|
8881
9261
|
const answer = typeof options.gateAnswer === "string" ? options.gateAnswer : JSON.stringify(options.gateAnswer);
|
|
8882
9262
|
await ctx.addToolResult(pending.toolUseId, answer, false);
|
|
8883
9263
|
} 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
9264
|
const inputJson = JSON.stringify(pending.input ?? {}, null, 2);
|
|
8890
|
-
await ctx.
|
|
8891
|
-
|
|
9265
|
+
await ctx.addMixedUserMessage([
|
|
9266
|
+
{
|
|
9267
|
+
type: "tool_result",
|
|
9268
|
+
tool_use_id: pending.toolUseId,
|
|
9269
|
+
content: `APPROVAL_GATE_RELEASED: the prior ${pending.toolName} call was paused for human approval and has now been approved. Retry is required.`
|
|
9270
|
+
},
|
|
9271
|
+
{
|
|
9272
|
+
type: "text",
|
|
9273
|
+
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
9274
|
\`\`\`json
|
|
8893
9275
|
${inputJson}
|
|
8894
9276
|
\`\`\``
|
|
8895
|
-
|
|
9277
|
+
}
|
|
9278
|
+
]);
|
|
8896
9279
|
}
|
|
8897
9280
|
}
|
|
8898
9281
|
await writer.setStatus("running");
|
|
@@ -8913,7 +9296,8 @@ ${inputJson}
|
|
|
8913
9296
|
stopHooks: this.config.hooks.stopHooks,
|
|
8914
9297
|
onProgress: this.buildHeartbeat(storage, snapshot.runId, snapshot.nodeId),
|
|
8915
9298
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
8916
|
-
...gate !== void 0 ? { gateBeforeTool: gate } : {}
|
|
9299
|
+
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
9300
|
+
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
|
|
8917
9301
|
});
|
|
8918
9302
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
8919
9303
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
@@ -8921,11 +9305,13 @@ ${inputJson}
|
|
|
8921
9305
|
});
|
|
8922
9306
|
this.logRunEnd(log, snapshot.runId, snapshot.nodeId, result);
|
|
8923
9307
|
await this.firePostRunHook(snapshot.runId, snapshot.nodeId, result, ctx, logPath);
|
|
9308
|
+
const capabilitiesMissing = ctx.getCapabilitiesMissing();
|
|
8924
9309
|
return toResponse(result, {
|
|
8925
9310
|
runId: snapshot.runId,
|
|
8926
9311
|
nodeId: snapshot.nodeId,
|
|
8927
9312
|
durationMs: Date.now() - startTime,
|
|
8928
|
-
logPath
|
|
9313
|
+
logPath,
|
|
9314
|
+
...capabilitiesMissing.length > 0 ? { capabilitiesMissing } : {}
|
|
8929
9315
|
});
|
|
8930
9316
|
} finally {
|
|
8931
9317
|
runTimeout.clear();
|
|
@@ -8995,13 +9381,15 @@ ${inputJson}
|
|
|
8995
9381
|
} : void 0;
|
|
8996
9382
|
const initial = RunStateManager.initial(runId, options.nodeId, webhook);
|
|
8997
9383
|
await stateManager.write(initial);
|
|
9384
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
8998
9385
|
this.backgroundExecutor.schedule(runId, async (signal) => {
|
|
8999
9386
|
await stateManager.update(runId, options.nodeId, { status: "running" });
|
|
9000
9387
|
try {
|
|
9001
|
-
const response = await this.run({ ...options, runId });
|
|
9388
|
+
const response = await this.run({ ...options, runId }, { handoffToRunner: handoffEnabled });
|
|
9002
9389
|
if (signal.aborted) return;
|
|
9003
|
-
await
|
|
9004
|
-
await
|
|
9390
|
+
const postHandoff = await this.maybeHandoffToRunner(runId, options.nodeId, response);
|
|
9391
|
+
await stateManager.finalize(runId, options.nodeId, postHandoff);
|
|
9392
|
+
await this.maybeFireWebhook(stateManager, runId, options.nodeId, postHandoff);
|
|
9005
9393
|
} catch (err) {
|
|
9006
9394
|
if (signal.aborted) return;
|
|
9007
9395
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9049,12 +9437,14 @@ ${inputJson}
|
|
|
9049
9437
|
} : { ...RunStateManager.initial(options.runId, nodeId, webhook), status: "running" };
|
|
9050
9438
|
await stateManager.write(next);
|
|
9051
9439
|
const resumeNodeId = nodeId;
|
|
9440
|
+
const handoffEnabled = this.config.runner !== void 0;
|
|
9052
9441
|
this.backgroundExecutor.schedule(options.runId, async (signal) => {
|
|
9053
9442
|
try {
|
|
9054
|
-
const response = await this.resume(options);
|
|
9443
|
+
const response = await this.resume(options, { handoffToRunner: handoffEnabled });
|
|
9055
9444
|
if (signal.aborted) return;
|
|
9056
|
-
await
|
|
9057
|
-
await
|
|
9445
|
+
const postHandoff = await this.maybeHandoffToRunner(options.runId, resumeNodeId, response);
|
|
9446
|
+
await stateManager.finalize(options.runId, resumeNodeId, postHandoff);
|
|
9447
|
+
await this.maybeFireWebhook(stateManager, options.runId, resumeNodeId, postHandoff);
|
|
9058
9448
|
} catch (err) {
|
|
9059
9449
|
if (signal.aborted) return;
|
|
9060
9450
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9243,6 +9633,68 @@ ${inputJson}
|
|
|
9243
9633
|
}
|
|
9244
9634
|
return orphaned;
|
|
9245
9635
|
}
|
|
9636
|
+
// ---------- runner handoff (Plan 019) ----------
|
|
9637
|
+
/**
|
|
9638
|
+
* When the response indicates the run paused for runner handoff, POST
|
|
9639
|
+
* `{ runId }` to the configured runner URL. On success, return the
|
|
9640
|
+
* response unchanged — state stays `paused` and the runner will flip
|
|
9641
|
+
* it to `done` (or `failed`) on its side. On POST failure, convert
|
|
9642
|
+
* the response to `failed` with `ERR_RUNNER_UNREACHABLE` so the
|
|
9643
|
+
* caller sees a terminal state instead of a silent hang.
|
|
9644
|
+
*
|
|
9645
|
+
* Called only from `start()` / `resumeAsync()`. Sync `run()` never
|
|
9646
|
+
* produces a `handoff_to_runner` pause (see `_internal.handoffToRunner`).
|
|
9647
|
+
*/
|
|
9648
|
+
async maybeHandoffToRunner(runId, nodeId, response) {
|
|
9649
|
+
if (response.status !== "paused") return response;
|
|
9650
|
+
if (response.meta.pauseReason !== "handoff_to_runner") return response;
|
|
9651
|
+
const runner = this.config.runner;
|
|
9652
|
+
if (runner === void 0) {
|
|
9653
|
+
return response;
|
|
9654
|
+
}
|
|
9655
|
+
const fetchFn = this.internals.fetch ?? globalThis.fetch.bind(globalThis);
|
|
9656
|
+
try {
|
|
9657
|
+
const res = await fetchFn(runner.url, {
|
|
9658
|
+
method: "POST",
|
|
9659
|
+
headers: {
|
|
9660
|
+
"Content-Type": "application/json",
|
|
9661
|
+
Authorization: `Bearer ${runner.secret}`
|
|
9662
|
+
},
|
|
9663
|
+
body: JSON.stringify({ runId })
|
|
9664
|
+
});
|
|
9665
|
+
if (!res.ok) {
|
|
9666
|
+
return {
|
|
9667
|
+
runId,
|
|
9668
|
+
status: "failed",
|
|
9669
|
+
data: null,
|
|
9670
|
+
meta: { nodeId },
|
|
9671
|
+
errors: [
|
|
9672
|
+
{
|
|
9673
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9674
|
+
message: `Runner returned HTTP ${res.status}`
|
|
9675
|
+
}
|
|
9676
|
+
],
|
|
9677
|
+
timestamp: Date.now()
|
|
9678
|
+
};
|
|
9679
|
+
}
|
|
9680
|
+
return response;
|
|
9681
|
+
} catch (err) {
|
|
9682
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9683
|
+
return {
|
|
9684
|
+
runId,
|
|
9685
|
+
status: "failed",
|
|
9686
|
+
data: null,
|
|
9687
|
+
meta: { nodeId },
|
|
9688
|
+
errors: [
|
|
9689
|
+
{
|
|
9690
|
+
code: "ERR_RUNNER_UNREACHABLE",
|
|
9691
|
+
message: `Runner handoff failed: ${msg}`
|
|
9692
|
+
}
|
|
9693
|
+
],
|
|
9694
|
+
timestamp: Date.now()
|
|
9695
|
+
};
|
|
9696
|
+
}
|
|
9697
|
+
}
|
|
9246
9698
|
// ---------- webhook helpers ----------
|
|
9247
9699
|
async maybeFireWebhook(stateManager, runId, nodeId, response) {
|
|
9248
9700
|
const state = await stateManager.read(runId, nodeId);
|
|
@@ -9386,6 +9838,11 @@ ${inputJson}
|
|
|
9386
9838
|
if (disabled.has(name)) continue;
|
|
9387
9839
|
if (wantAll || enabled.has(name)) names.add(name);
|
|
9388
9840
|
}
|
|
9841
|
+
if ((this.config.api?.services.length ?? 0) > 0) {
|
|
9842
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
9843
|
+
names.add("ApiCall");
|
|
9844
|
+
}
|
|
9845
|
+
}
|
|
9389
9846
|
for (const tool of this.config.tools.custom) {
|
|
9390
9847
|
names.add(tool.name);
|
|
9391
9848
|
}
|
|
@@ -9542,6 +9999,34 @@ ${inputJson}
|
|
|
9542
9999
|
}
|
|
9543
10000
|
return void 0;
|
|
9544
10001
|
}
|
|
10002
|
+
/**
|
|
10003
|
+
* Plan 020 — resolve the effective ApiCall config for a run.
|
|
10004
|
+
*
|
|
10005
|
+
* Precedence (each field independently):
|
|
10006
|
+
* RunOptions.api.X > config.api.X
|
|
10007
|
+
*
|
|
10008
|
+
* If neither side provides any services, returns undefined so the
|
|
10009
|
+
* tool isn't registered at all. Env + resolveAuth + hooks flow
|
|
10010
|
+
* through untouched — they never hit the Zod schema.
|
|
10011
|
+
*/
|
|
10012
|
+
resolveApiConfig(override) {
|
|
10013
|
+
const base = this.config.api;
|
|
10014
|
+
if (override === void 0 && base === void 0) return void 0;
|
|
10015
|
+
const services = override?.services ?? base?.services;
|
|
10016
|
+
if (services === void 0 || services.length === 0) return void 0;
|
|
10017
|
+
const env = override?.env ?? base?.env;
|
|
10018
|
+
const resolveAuth2 = override?.resolveAuth ?? base?.resolveAuth;
|
|
10019
|
+
const onRequest = override?.onRequest ?? base?.onRequest;
|
|
10020
|
+
const onResponse = override?.onResponse ?? base?.onResponse;
|
|
10021
|
+
return {
|
|
10022
|
+
services,
|
|
10023
|
+
...env !== void 0 ? { env } : {},
|
|
10024
|
+
...resolveAuth2 !== void 0 ? { resolveAuth: resolveAuth2 } : {},
|
|
10025
|
+
...onRequest !== void 0 ? { onRequest } : {},
|
|
10026
|
+
...onResponse !== void 0 ? { onResponse } : {},
|
|
10027
|
+
...base?.maxResponseBytes !== void 0 ? { maxResponseBytes: base.maxResponseBytes } : {}
|
|
10028
|
+
};
|
|
10029
|
+
}
|
|
9545
10030
|
/**
|
|
9546
10031
|
* Build a throttled heartbeat callback for agentLoop's `onProgress` hook.
|
|
9547
10032
|
*
|
|
@@ -9636,8 +10121,8 @@ function buildToolRegistry(options) {
|
|
|
9636
10121
|
const fileTracker = new FileTracker();
|
|
9637
10122
|
const spawnAvailable = canSpawnProcesses();
|
|
9638
10123
|
const candidates = [
|
|
9639
|
-
// Bash — requires child_process.spawn
|
|
9640
|
-
|
|
10124
|
+
// Bash — requires child_process.spawn. Stubbed on Workers.
|
|
10125
|
+
{ name: "Bash", tool: withCapabilityCheck(createBashTool(), spawnAvailable) },
|
|
9641
10126
|
{
|
|
9642
10127
|
name: "Read",
|
|
9643
10128
|
tool: createFileReadTool({ storage: storage.workspace, tracker: fileTracker })
|
|
@@ -9683,6 +10168,21 @@ function buildToolRegistry(options) {
|
|
|
9683
10168
|
childRegistry.register(skillTool);
|
|
9684
10169
|
}
|
|
9685
10170
|
}
|
|
10171
|
+
if (options.apiConfig !== void 0 && options.apiConfig.services.length > 0) {
|
|
10172
|
+
if (!disabled.has("ApiCall") && (wantAll || enabled.has("ApiCall"))) {
|
|
10173
|
+
const apiTool = createApiCallTool({
|
|
10174
|
+
services: options.apiConfig.services,
|
|
10175
|
+
...options.fetch !== void 0 ? { fetch: options.fetch } : {},
|
|
10176
|
+
...options.apiConfig.env !== void 0 ? { env: options.apiConfig.env } : {},
|
|
10177
|
+
...options.apiConfig.resolveAuth !== void 0 ? { resolveAuth: options.apiConfig.resolveAuth } : {},
|
|
10178
|
+
...options.apiConfig.onRequest !== void 0 ? { onRequest: options.apiConfig.onRequest } : {},
|
|
10179
|
+
...options.apiConfig.onResponse !== void 0 ? { onResponse: options.apiConfig.onResponse } : {},
|
|
10180
|
+
...options.apiConfig.maxResponseBytes !== void 0 ? { maxResponseBytes: options.apiConfig.maxResponseBytes } : {}
|
|
10181
|
+
});
|
|
10182
|
+
registry.register(apiTool);
|
|
10183
|
+
childRegistry.register(apiTool);
|
|
10184
|
+
}
|
|
10185
|
+
}
|
|
9686
10186
|
const agentTool = createAgentTool({
|
|
9687
10187
|
storage: storage.workspace,
|
|
9688
10188
|
client,
|
|
@@ -9805,6 +10305,8 @@ function resolveApiKey(config) {
|
|
|
9805
10305
|
buildSystemPrompt,
|
|
9806
10306
|
buildWorkerAgent,
|
|
9807
10307
|
canSpawnProcesses,
|
|
10308
|
+
capabilityStub,
|
|
10309
|
+
createApiCallTool,
|
|
9808
10310
|
createLogger,
|
|
9809
10311
|
createModelAdapter,
|
|
9810
10312
|
createSendMessageTool,
|
|
@@ -9836,6 +10338,7 @@ function resolveApiKey(config) {
|
|
|
9836
10338
|
synthesizeSpec,
|
|
9837
10339
|
toResponse,
|
|
9838
10340
|
tryParseJSON,
|
|
9839
|
-
validateOutput
|
|
10341
|
+
validateOutput,
|
|
10342
|
+
withCapabilityCheck
|
|
9840
10343
|
});
|
|
9841
10344
|
//# sourceMappingURL=index.cjs.map
|