la-machina-engine 0.5.0 → 0.7.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/dist/index.cjs CHANGED
@@ -37,35 +37,124 @@ var init_cjs_shims = __esm({
37
37
  }
38
38
  });
39
39
 
40
+ // src/tools/contract.ts
41
+ function defineTool(tool) {
42
+ return tool;
43
+ }
44
+ var ToolRegistry;
45
+ var init_contract = __esm({
46
+ "src/tools/contract.ts"() {
47
+ "use strict";
48
+ init_cjs_shims();
49
+ ToolRegistry = class {
50
+ tools = /* @__PURE__ */ new Map();
51
+ register(tool) {
52
+ if (typeof tool.name !== "string" || tool.name.length === 0) {
53
+ throw new Error("ToolRegistry: tool.name must be a non-empty string");
54
+ }
55
+ if (this.tools.has(tool.name)) {
56
+ throw new Error(`ToolRegistry: "${tool.name}" is already registered`);
57
+ }
58
+ this.tools.set(tool.name, tool);
59
+ }
60
+ registerAll(tools) {
61
+ for (const tool of tools) this.register(tool);
62
+ }
63
+ unregister(name) {
64
+ this.tools.delete(name);
65
+ }
66
+ get(name) {
67
+ return this.tools.get(name);
68
+ }
69
+ has(name) {
70
+ return this.tools.has(name);
71
+ }
72
+ list() {
73
+ return Array.from(this.tools.values());
74
+ }
75
+ count() {
76
+ return this.tools.size;
77
+ }
78
+ };
79
+ }
80
+ });
81
+
82
+ // src/tools/fetchData.ts
83
+ var fetchData_exports = {};
84
+ __export(fetchData_exports, {
85
+ createFetchDataTool: () => createFetchDataTool
86
+ });
87
+ function createFetchDataTool(opts) {
88
+ return defineTool({
89
+ name: "FetchData",
90
+ description: "Fetch the full content of a tool result that was offloaded because it was too large for the main context. Pass the `ref` token from the summarized tool_result message (the text that looked like 'Use FetchData with ref=\"...\"'). Returns the raw bytes of the original tool output.",
91
+ inputSchema,
92
+ execute: async ({ ref }) => {
93
+ if (!SAFE_REF.test(ref)) {
94
+ return {
95
+ content: `ERR_OFFLOAD_INVALID_REF: ref "${ref}" contains unsafe characters`,
96
+ isError: true
97
+ };
98
+ }
99
+ const path = `${opts.logPath}/toolResults/${ref}.json`;
100
+ const raw = await opts.storage.readFile(path);
101
+ if (raw === null) {
102
+ return {
103
+ content: `ERR_OFFLOAD_REF_NOT_FOUND: no data found for ref "${ref}"`,
104
+ isError: true
105
+ };
106
+ }
107
+ return {
108
+ content: raw,
109
+ isError: false,
110
+ metadata: { ref, bytes: raw.length }
111
+ };
112
+ }
113
+ });
114
+ }
115
+ var import_zod6, SAFE_REF, inputSchema;
116
+ var init_fetchData = __esm({
117
+ "src/tools/fetchData.ts"() {
118
+ "use strict";
119
+ init_cjs_shims();
120
+ import_zod6 = require("zod");
121
+ init_contract();
122
+ SAFE_REF = /^[a-zA-Z0-9_-]+$/;
123
+ inputSchema = import_zod6.z.object({
124
+ ref: import_zod6.z.string().min(1)
125
+ });
126
+ }
127
+ });
128
+
40
129
  // src/orchestrator/types.ts
41
- var import_zod25, PlanStepSchema, PlanSchema;
130
+ var import_zod28, PlanStepSchema, PlanSchema;
42
131
  var init_types = __esm({
43
132
  "src/orchestrator/types.ts"() {
44
133
  "use strict";
45
134
  init_cjs_shims();
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()
135
+ import_zod28 = require("zod");
136
+ PlanStepSchema = import_zod28.z.object({
137
+ id: import_zod28.z.string().min(1),
138
+ description: import_zod28.z.string().min(1),
139
+ action: import_zod28.z.enum(["research", "implement", "verify", "review", "custom"]),
140
+ files: import_zod28.z.array(import_zod28.z.string()).optional(),
141
+ spec: import_zod28.z.string().optional(),
142
+ dependsOn: import_zod28.z.array(import_zod28.z.string()).optional()
54
143
  });
55
- PlanSchema = import_zod25.z.object({
56
- summary: import_zod25.z.string().min(1),
57
- steps: import_zod25.z.array(PlanStepSchema).min(1)
144
+ PlanSchema = import_zod28.z.object({
145
+ summary: import_zod28.z.string().min(1),
146
+ steps: import_zod28.z.array(PlanStepSchema).min(1)
58
147
  });
59
148
  }
60
149
  });
61
150
 
62
151
  // src/orchestrator/planParser.ts
63
152
  function parsePlan(raw, maxSteps) {
64
- const json = extractJson(raw);
65
- if (json === null) return null;
153
+ const json2 = extractJson(raw);
154
+ if (json2 === null) return null;
66
155
  let parsed;
67
156
  try {
68
- parsed = JSON.parse(json);
157
+ parsed = JSON.parse(json2);
69
158
  } catch {
70
159
  return null;
71
160
  }
@@ -75,23 +164,23 @@ function parsePlan(raw, maxSteps) {
75
164
  if (plan.steps.length > maxSteps) return null;
76
165
  return plan;
77
166
  }
78
- function extractJson(text) {
79
- const fenceMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
167
+ function extractJson(text2) {
168
+ const fenceMatch = text2.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
80
169
  if (fenceMatch?.[1]) {
81
170
  const inner = fenceMatch[1].trim();
82
171
  if (inner.startsWith("{")) return inner;
83
172
  }
84
173
  let start = -1;
85
174
  let depth = 0;
86
- for (let i = 0; i < text.length; i++) {
87
- const c = text[i];
175
+ for (let i = 0; i < text2.length; i++) {
176
+ const c = text2[i];
88
177
  if (c === "{") {
89
178
  if (depth === 0) start = i;
90
179
  depth++;
91
180
  } else if (c === "}") {
92
181
  depth--;
93
182
  if (depth === 0 && start !== -1) {
94
- return text.slice(start, i + 1);
183
+ return text2.slice(start, i + 1);
95
184
  }
96
185
  }
97
186
  }
@@ -780,6 +869,7 @@ __export(index_exports, {
780
869
  WebhookDispatcher: () => WebhookDispatcher,
781
870
  adaptMcpTool: () => adaptMcpTool,
782
871
  buildForkedMessages: () => buildForkedMessages,
872
+ buildKnowledgeIndex: () => buildKnowledgeIndex,
783
873
  buildPermissionPolicy: () => buildPermissionPolicy,
784
874
  buildSchemaPrompt: () => buildSchemaPrompt,
785
875
  buildSystemPrompt: () => buildSystemPrompt,
@@ -787,16 +877,21 @@ __export(index_exports, {
787
877
  canSpawnProcesses: () => canSpawnProcesses,
788
878
  capabilityStub: () => capabilityStub,
789
879
  createApiCallTool: () => createApiCallTool,
880
+ createFetchDataTool: () => createFetchDataTool,
790
881
  createLogger: () => createLogger,
791
882
  createModelAdapter: () => createModelAdapter,
883
+ createReadKnowledgeTool: () => createReadKnowledgeTool,
884
+ createSearchKnowledgeTool: () => createSearchKnowledgeTool,
792
885
  createSendMessageTool: () => createSendMessageTool,
793
886
  createSkillPageTool: () => createSkillPageTool,
794
887
  createSmartMemory: () => createSmartMemory,
795
888
  defaultSamplingHandler: () => defaultSamplingHandler,
889
+ defaultToolResultSummarizer: () => defaultToolResultSummarizer,
796
890
  defineTool: () => defineTool,
797
891
  detectRuntime: () => detectRuntime,
798
892
  getCoordinatorBasePrompt: () => getCoordinatorBasePrompt,
799
893
  getCoordinatorSystemPrompt: () => getCoordinatorSystemPrompt,
894
+ getExtractor: () => getExtractor,
800
895
  hasProcessLifecycle: () => hasProcessLifecycle,
801
896
  initEngine: () => initEngine,
802
897
  isCoordinatorMode: () => isCoordinatorMode,
@@ -817,9 +912,10 @@ __export(index_exports, {
817
912
  snapshotFiles: () => snapshotFiles,
818
913
  synthesizeSpec: () => synthesizeSpec,
819
914
  toResponse: () => toResponse,
820
- tryParseJSON: () => tryParseJSON,
915
+ tryParseJSON: () => tryParseJSON2,
821
916
  validateOutput: () => validateOutput,
822
- withCapabilityCheck: () => withCapabilityCheck
917
+ withCapabilityCheck: () => withCapabilityCheck,
918
+ writeKnowledgeIndex: () => writeKnowledgeIndex
823
919
  });
824
920
  module.exports = __toCommonJS(index_exports);
825
921
  init_cjs_shims();
@@ -1071,13 +1167,19 @@ var McpConfigResolved = import_zod.z.object({
1071
1167
  shutdownTimeoutMs: import_zod.z.number().int().positive()
1072
1168
  }).strict();
1073
1169
  var CompactionStrategyEnum = import_zod.z.enum(["drop-middle", "summarize", "session-memory", "auto"]);
1170
+ var ToolResultOffloadConfigResolved = import_zod.z.object({
1171
+ enabled: import_zod.z.boolean(),
1172
+ thresholdBytes: import_zod.z.number().int().positive(),
1173
+ maxPreviewChars: import_zod.z.number().int().positive()
1174
+ }).strict();
1074
1175
  var CompactionConfigResolved = import_zod.z.object({
1075
1176
  strategy: CompactionStrategyEnum,
1076
1177
  threshold: import_zod.z.number().min(0).max(1),
1077
1178
  keepLast: import_zod.z.number().int().positive(),
1078
1179
  summaryMaxTokens: import_zod.z.number().int().positive(),
1079
1180
  microcompact: import_zod.z.boolean(),
1080
- microcompactAgeMs: import_zod.z.number().int().nonnegative()
1181
+ microcompactAgeMs: import_zod.z.number().int().nonnegative(),
1182
+ toolResultOffload: ToolResultOffloadConfigResolved.optional()
1081
1183
  }).strict();
1082
1184
  var CoordinatorConfigResolved = import_zod.z.object({
1083
1185
  enabled: import_zod.z.boolean(),
@@ -1146,6 +1248,11 @@ var ApiConfigResolved = import_zod.z.object({
1146
1248
  services: import_zod.z.array(ApiServiceSchema),
1147
1249
  maxResponseBytes: import_zod.z.number().int().positive().optional()
1148
1250
  }).strict();
1251
+ var KnowledgeConfigResolved = import_zod.z.object({
1252
+ enabled: import_zod.z.boolean(),
1253
+ maxSearchResults: import_zod.z.number().int().positive(),
1254
+ maxReadBytes: import_zod.z.number().int().positive()
1255
+ }).strict();
1149
1256
  var RunnerConfigResolved = import_zod.z.object({
1150
1257
  url: import_zod.z.string().url(),
1151
1258
  secret: import_zod.z.string().min(1, "runner.secret cannot be empty")
@@ -1167,7 +1274,8 @@ var ResolvedConfigSchema = import_zod.z.object({
1167
1274
  coordinator: CoordinatorConfigResolved,
1168
1275
  orchestrator: OrchestratorConfigResolved,
1169
1276
  runner: RunnerConfigResolved.optional(),
1170
- api: ApiConfigResolved.optional()
1277
+ api: ApiConfigResolved.optional(),
1278
+ knowledge: KnowledgeConfigResolved.optional()
1171
1279
  }).strict();
1172
1280
  var R2ConfigUser = R2ConfigResolved.partial();
1173
1281
  var ModelConfigUser = ModelConfigResolved.partial();
@@ -1178,6 +1286,7 @@ var StorageConfigUser = import_zod.z.object({
1178
1286
  r2: R2ConfigUser.optional(),
1179
1287
  r2Binding: R2BucketBindingShape.optional()
1180
1288
  }).strict();
1289
+ var KnowledgeConfigUser = KnowledgeConfigResolved.partial();
1181
1290
  var MemoryConfigUser = import_zod.z.object({
1182
1291
  mode: MemoryModeEnum.optional(),
1183
1292
  scope: MemoryScopeUserEnum.optional()
@@ -1213,7 +1322,16 @@ var McpConfigUser = import_zod.z.object({
1213
1322
  var PermissionsConfigUser = PermissionsConfigResolved.partial();
1214
1323
  var RunnerConfigUser = RunnerConfigResolved;
1215
1324
  var ApiConfigUser = ApiConfigResolved.partial();
1216
- var CompactionConfigUser = CompactionConfigResolved.partial();
1325
+ var ToolResultOffloadConfigUser = ToolResultOffloadConfigResolved.partial();
1326
+ var CompactionConfigUser = import_zod.z.object({
1327
+ strategy: CompactionStrategyEnum.optional(),
1328
+ threshold: import_zod.z.number().min(0).max(1).optional(),
1329
+ keepLast: import_zod.z.number().int().positive().optional(),
1330
+ summaryMaxTokens: import_zod.z.number().int().positive().optional(),
1331
+ microcompact: import_zod.z.boolean().optional(),
1332
+ microcompactAgeMs: import_zod.z.number().int().nonnegative().optional(),
1333
+ toolResultOffload: ToolResultOffloadConfigUser.optional()
1334
+ }).strict();
1217
1335
  var CoordinatorConfigUser = CoordinatorConfigResolved.partial();
1218
1336
  var OrchestratorConfigUser = OrchestratorConfigResolved.deepPartial();
1219
1337
  var UserConfigSchema = import_zod.z.object({
@@ -1233,7 +1351,8 @@ var UserConfigSchema = import_zod.z.object({
1233
1351
  coordinator: CoordinatorConfigUser.optional(),
1234
1352
  orchestrator: OrchestratorConfigUser.optional(),
1235
1353
  runner: RunnerConfigUser.optional(),
1236
- api: ApiConfigUser.optional()
1354
+ api: ApiConfigUser.optional(),
1355
+ knowledge: KnowledgeConfigUser.optional()
1237
1356
  }).strict();
1238
1357
 
1239
1358
  // src/config/merge.ts
@@ -1306,9 +1425,41 @@ function coerceDeprecatedMemoryScope(user) {
1306
1425
  memory: { ...memory, scope: "workspace" }
1307
1426
  };
1308
1427
  }
1428
+ var OFFLOAD_DEFAULTS = { thresholdBytes: 2048, maxPreviewChars: 500 };
1429
+ function splitOffloadRuntime(user) {
1430
+ const block = user.compaction?.toolResultOffload;
1431
+ if (block === void 0) return { stripped: user };
1432
+ const { summarizer, ...schemaSafe } = block;
1433
+ const filled = {
1434
+ enabled: schemaSafe.enabled ?? false,
1435
+ thresholdBytes: schemaSafe.thresholdBytes ?? OFFLOAD_DEFAULTS.thresholdBytes,
1436
+ maxPreviewChars: schemaSafe.maxPreviewChars ?? OFFLOAD_DEFAULTS.maxPreviewChars
1437
+ };
1438
+ const clone = {
1439
+ ...user,
1440
+ compaction: {
1441
+ ...user.compaction ?? {},
1442
+ toolResultOffload: filled
1443
+ }
1444
+ };
1445
+ return { stripped: clone, summarizer };
1446
+ }
1447
+ var KNOWLEDGE_DEFAULTS = { maxSearchResults: 5, maxReadBytes: 1e4 };
1448
+ function fillKnowledgeDefaults(user) {
1449
+ const block = user.knowledge;
1450
+ if (block === void 0) return user;
1451
+ const filled = {
1452
+ enabled: block.enabled ?? false,
1453
+ maxSearchResults: block.maxSearchResults ?? KNOWLEDGE_DEFAULTS.maxSearchResults,
1454
+ maxReadBytes: block.maxReadBytes ?? KNOWLEDGE_DEFAULTS.maxReadBytes
1455
+ };
1456
+ return { ...user, knowledge: filled };
1457
+ }
1309
1458
  function mergeConfig(user) {
1310
1459
  const withCoercedScope = coerceDeprecatedMemoryScope(user);
1311
- const { stripped, runtime } = splitApiRuntime(withCoercedScope);
1460
+ const withKnowledge = fillKnowledgeDefaults(withCoercedScope);
1461
+ const { stripped: afterOffload, summarizer } = splitOffloadRuntime(withKnowledge);
1462
+ const { stripped, runtime } = splitApiRuntime(afterOffload);
1312
1463
  const validatedUser = UserConfigSchema.parse(stripped);
1313
1464
  const merged = deepMerge(DEFAULTS, validatedUser);
1314
1465
  const resolved = ResolvedConfigSchema.parse(merged);
@@ -1320,6 +1471,13 @@ function mergeConfig(user) {
1320
1471
  };
1321
1472
  } else if (Object.keys(runtime).length > 0) {
1322
1473
  }
1474
+ if (summarizer !== void 0 && resolved.compaction.toolResultOffload !== void 0) {
1475
+ const mutable = resolved.compaction;
1476
+ mutable.toolResultOffload = {
1477
+ ...resolved.compaction.toolResultOffload,
1478
+ summarizer
1479
+ };
1480
+ }
1323
1481
  return resolved;
1324
1482
  }
1325
1483
 
@@ -1966,44 +2124,7 @@ function hasProcessLifecycle() {
1966
2124
  // src/tools/capabilityStub.ts
1967
2125
  init_cjs_shims();
1968
2126
  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
2127
+ init_contract();
2007
2128
  var anyInput = import_zod2.z.unknown();
2008
2129
  function capabilityStub(original) {
2009
2130
  return defineTool({
@@ -2207,7 +2328,7 @@ var SubagentRegistry = class _SubagentRegistry {
2207
2328
 
2208
2329
  // src/tools/agent.ts
2209
2330
  init_cjs_shims();
2210
- var import_zod6 = require("zod");
2331
+ var import_zod7 = require("zod");
2211
2332
 
2212
2333
  // src/subagent/runner.ts
2213
2334
  init_cjs_shims();
@@ -2271,6 +2392,131 @@ async function writeSnapshot(storage, logPath, snapshot) {
2271
2392
  await storage.writeFile(snapshotPath(logPath), JSON.stringify(validated, null, 2));
2272
2393
  }
2273
2394
 
2395
+ // src/engine/toolResultOffload.ts
2396
+ init_cjs_shims();
2397
+
2398
+ // src/engine/toolResultSummarizer.ts
2399
+ init_cjs_shims();
2400
+ var MAX_ITEM_PREVIEW_CHARS = 150;
2401
+ var MAX_TOP_LEVEL_KEYS = 8;
2402
+ var defaultToolResultSummarizer = (ctx) => {
2403
+ return summarize(ctx);
2404
+ };
2405
+ function summarize(ctx) {
2406
+ const { toolName, rawContent, rawBytes, ref, maxPreviewChars } = ctx;
2407
+ const parsed = tryParseJSON(rawContent);
2408
+ if (parsed.ok) {
2409
+ if (Array.isArray(parsed.value)) {
2410
+ return summarizeArray(toolName, parsed.value, ref, rawBytes);
2411
+ }
2412
+ if (parsed.value !== null && typeof parsed.value === "object") {
2413
+ return summarizeObject(toolName, parsed.value, ref, rawBytes);
2414
+ }
2415
+ }
2416
+ const preview = rawContent.slice(0, maxPreviewChars);
2417
+ const truncated = rawContent.length > maxPreviewChars ? "\u2026" : "";
2418
+ return `[${toolName}] ${formatBytes(rawBytes)} offloaded.
2419
+ ` + (preview.length > 0 ? `Preview: ${preview}${truncated}
2420
+ ` : "") + `Use FetchData with ref="${ref}" to read the full content.`;
2421
+ }
2422
+ function summarizeArray(toolName, arr, ref, bytes) {
2423
+ const count = arr.length;
2424
+ const firstHint = arr.length > 0 ? compactPreview(arr[0]) : "";
2425
+ const hintLine = firstHint ? `First item preview: ${firstHint}
2426
+ ` : "";
2427
+ return `[${toolName}] Array of ${count} item${count === 1 ? "" : "s"} (${formatBytes(bytes)}).
2428
+ ` + hintLine + `Use FetchData with ref="${ref}" to read the full array.`;
2429
+ }
2430
+ function summarizeObject(toolName, obj, ref, bytes) {
2431
+ const keys = Object.keys(obj);
2432
+ const shown = keys.slice(0, MAX_TOP_LEVEL_KEYS);
2433
+ const overflow = keys.length > MAX_TOP_LEVEL_KEYS ? ` (+${keys.length - shown.length} more)` : "";
2434
+ const parts = shown.map((k) => `${k}=${compactPreview(obj[k])}`).join(", ");
2435
+ return `[${toolName}] Object (${formatBytes(bytes)}). Keys: ${parts}${overflow}
2436
+ Use FetchData with ref="${ref}" to read the full object.`;
2437
+ }
2438
+ function compactPreview(value) {
2439
+ let str;
2440
+ if (value === null) {
2441
+ str = "null";
2442
+ } else if (typeof value === "string") {
2443
+ str = JSON.stringify(value);
2444
+ } else if (Array.isArray(value)) {
2445
+ str = `[${value.length} item${value.length === 1 ? "" : "s"}]`;
2446
+ } else if (typeof value === "object") {
2447
+ const keys = Object.keys(value);
2448
+ str = `{${keys.slice(0, 3).join(", ")}${keys.length > 3 ? ", \u2026" : ""}}`;
2449
+ } else {
2450
+ str = String(value);
2451
+ }
2452
+ if (str.length > MAX_ITEM_PREVIEW_CHARS) {
2453
+ return str.slice(0, MAX_ITEM_PREVIEW_CHARS) + "\u2026";
2454
+ }
2455
+ return str;
2456
+ }
2457
+ function tryParseJSON(text2) {
2458
+ const trimmed = text2.replace(/^\uFEFF/, "").trim();
2459
+ if (trimmed.length === 0) return { ok: false };
2460
+ const first = trimmed[0];
2461
+ if (first !== "{" && first !== "[" && first !== '"') return { ok: false };
2462
+ try {
2463
+ return { ok: true, value: JSON.parse(trimmed) };
2464
+ } catch {
2465
+ return { ok: false };
2466
+ }
2467
+ }
2468
+ function formatBytes(bytes) {
2469
+ if (bytes < 1024) return `${bytes} B`;
2470
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2471
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2472
+ }
2473
+
2474
+ // src/engine/toolResultOffload.ts
2475
+ async function maybeOffloadToolResult(input) {
2476
+ const {
2477
+ offloadConfig,
2478
+ storage,
2479
+ logPath,
2480
+ toolUseId,
2481
+ toolName,
2482
+ toolInput,
2483
+ rawContent,
2484
+ rawIsError
2485
+ } = input;
2486
+ if (offloadConfig === void 0 || offloadConfig.enabled !== true) {
2487
+ return rawContent;
2488
+ }
2489
+ if (rawIsError) {
2490
+ return rawContent;
2491
+ }
2492
+ if (toolName === "FetchData") {
2493
+ return rawContent;
2494
+ }
2495
+ const rawBytes = byteLength(rawContent);
2496
+ if (rawBytes <= offloadConfig.thresholdBytes) {
2497
+ return rawContent;
2498
+ }
2499
+ const path = `${logPath}/toolResults/${toolUseId}.json`;
2500
+ await storage.writeFile(path, rawContent);
2501
+ const summarizer = offloadConfig.summarizer ?? defaultToolResultSummarizer;
2502
+ const summary = await summarizer({
2503
+ toolName,
2504
+ toolInput,
2505
+ rawContent,
2506
+ rawBytes,
2507
+ ref: toolUseId,
2508
+ maxPreviewChars: offloadConfig.maxPreviewChars
2509
+ });
2510
+ if (!summary.includes(toolUseId)) {
2511
+ return `${summary}
2512
+ [offloaded \u2014 ref=${toolUseId}, use FetchData to read the full content]`;
2513
+ }
2514
+ return summary;
2515
+ }
2516
+ function byteLength(s) {
2517
+ return new TextEncoder().encode(s).byteLength;
2518
+ }
2519
+
2274
2520
  // src/hooks/dispatch.ts
2275
2521
  init_cjs_shims();
2276
2522
  async function dispatchHooks(hooks, event) {
@@ -2293,8 +2539,8 @@ var INTERNAL_BLOCK_PATTERNS = [
2293
2539
  /<git_signature>[\s\S]*?<\/git_signature>/g,
2294
2540
  /<caller>[\s\S]*?<\/caller>/g
2295
2541
  ];
2296
- function stripInternalBlocks(text) {
2297
- let result = text;
2542
+ function stripInternalBlocks(text2) {
2543
+ let result = text2;
2298
2544
  for (const pattern of INTERNAL_BLOCK_PATTERNS) {
2299
2545
  pattern.lastIndex = 0;
2300
2546
  result = result.replace(pattern, "");
@@ -2942,8 +3188,8 @@ async function agentLoop(options) {
2942
3188
  assistantContent.push({ type: "thinking", thinking });
2943
3189
  }
2944
3190
  }
2945
- for (const text of textBlocks) {
2946
- if (text.length > 0) assistantContent.push({ type: "text", text });
3191
+ for (const text2 of textBlocks) {
3192
+ if (text2.length > 0) assistantContent.push({ type: "text", text: text2 });
2947
3193
  }
2948
3194
  for (const tc of toolCalls) {
2949
3195
  assistantContent.push({
@@ -3023,7 +3269,32 @@ async function agentLoop(options) {
3023
3269
  if (typeof missing === "string") {
3024
3270
  ctx.recordCapabilityMissing(missing);
3025
3271
  }
3026
- await ctx.addToolResult(id, truncateToolResult(result.content), result.isError === true);
3272
+ const call = toolCallsToDispatch.find((c) => c.id === id);
3273
+ let contentForTranscript;
3274
+ if (options.toolResultOffload !== void 0 && options.storage !== void 0) {
3275
+ try {
3276
+ contentForTranscript = await maybeOffloadToolResult({
3277
+ offloadConfig: options.toolResultOffload,
3278
+ storage: options.storage,
3279
+ logPath: options.offloadLogPath ?? transcript.path,
3280
+ toolUseId: id,
3281
+ toolName: call?.name ?? "unknown",
3282
+ toolInput: call?.input,
3283
+ rawContent: result.content,
3284
+ rawIsError: result.isError === true
3285
+ });
3286
+ } catch (err) {
3287
+ const msg = err instanceof Error ? err.message : String(err);
3288
+ contentForTranscript = `[tool-result offload failed: ${msg}] ${result.content.slice(0, 500)}`;
3289
+ }
3290
+ } else {
3291
+ contentForTranscript = result.content;
3292
+ }
3293
+ await ctx.addToolResult(
3294
+ id,
3295
+ truncateToolResult(contentForTranscript),
3296
+ result.isError === true
3297
+ );
3027
3298
  }
3028
3299
  } catch (err) {
3029
3300
  if (err instanceof SubagentPausedError) {
@@ -3157,11 +3428,11 @@ function toAnthropicTool(tool) {
3157
3428
  target: "jsonSchema7",
3158
3429
  $refStrategy: "none"
3159
3430
  });
3160
- const { $schema: _schema, ...inputSchema17 } = schema;
3431
+ const { $schema: _schema, ...inputSchema20 } = schema;
3161
3432
  return {
3162
3433
  name: tool.name,
3163
3434
  description: tool.description,
3164
- input_schema: inputSchema17
3435
+ input_schema: inputSchema20
3165
3436
  };
3166
3437
  }
3167
3438
  function partitionToolCalls(calls, registry) {
@@ -3296,8 +3567,8 @@ var RunContext = class {
3296
3567
  this.episodes = options.episodes ?? null;
3297
3568
  }
3298
3569
  // ---------- message mutators ----------
3299
- async addUserMessage(text) {
3300
- const content = [{ type: "text", text }];
3570
+ async addUserMessage(text2) {
3571
+ const content = [{ type: "text", text: text2 }];
3301
3572
  this.messages.push({ role: "user", content });
3302
3573
  await this.writeEntry({
3303
3574
  type: "user",
@@ -3306,7 +3577,7 @@ var RunContext = class {
3306
3577
  ts: this.now(),
3307
3578
  message: { role: "user", content }
3308
3579
  });
3309
- this.episodes?.logTurn(this.turnCount, "user", text);
3580
+ this.episodes?.logTurn(this.turnCount, "user", text2);
3310
3581
  }
3311
3582
  async addAssistantMessage(content) {
3312
3583
  this.messages.push({ role: "assistant", content });
@@ -3871,6 +4142,19 @@ async function loadWriterState(storage, logPath) {
3871
4142
  // src/subagent/runner.ts
3872
4143
  async function runAgent(options) {
3873
4144
  const childLogPath = `${options.parentLogPath}/subagents/${options.agentId}`;
4145
+ let restorePrevFetchData = null;
4146
+ if (options.toolResultOffload !== void 0 && options.toolResultOffload.enabled) {
4147
+ const { createFetchDataTool: createFetchDataTool2 } = await Promise.resolve().then(() => (init_fetchData(), fetchData_exports));
4148
+ const existing = options.registry.get("FetchData");
4149
+ options.registry.unregister("FetchData");
4150
+ options.registry.register(
4151
+ createFetchDataTool2({ storage: options.storage, logPath: childLogPath })
4152
+ );
4153
+ restorePrevFetchData = () => {
4154
+ options.registry.unregister("FetchData");
4155
+ if (existing !== void 0) options.registry.register(existing);
4156
+ };
4157
+ }
3874
4158
  const writer = new TranscriptWriter({
3875
4159
  storage: options.storage,
3876
4160
  logPath: childLogPath,
@@ -3911,7 +4195,15 @@ async function runAgent(options) {
3911
4195
  // Propagate parent's gate + storage into the child loop when set.
3912
4196
  // Without `storage`, a gate denial would fail the child instead of
3913
4197
  // pausing it, so both must travel together.
3914
- ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool, storage: options.storage } : {}
4198
+ ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool, storage: options.storage } : {},
4199
+ // Plan 021 — the child needs its own storage + offload config
4200
+ // so its own large tool results get offloaded into
4201
+ // `childLogPath/toolResults/...`, not the parent's folder.
4202
+ ...options.toolResultOffload !== void 0 ? {
4203
+ storage: options.storage,
4204
+ toolResultOffload: options.toolResultOffload,
4205
+ offloadLogPath: childLogPath
4206
+ } : {}
3915
4207
  });
3916
4208
  if (result.status === "done") {
3917
4209
  await writer.setStatus("done");
@@ -3967,6 +4259,7 @@ async function runAgent(options) {
3967
4259
  } catch {
3968
4260
  }
3969
4261
  await writer.close();
4262
+ restorePrevFetchData?.();
3970
4263
  }
3971
4264
  }
3972
4265
 
@@ -4039,10 +4332,11 @@ Directive: ${directive}`;
4039
4332
  }
4040
4333
 
4041
4334
  // src/tools/agent.ts
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()
4335
+ init_contract();
4336
+ var inputSchema2 = import_zod7.z.object({
4337
+ description: import_zod7.z.string().min(1),
4338
+ subagent_type: import_zod7.z.string().optional(),
4339
+ run_in_background: import_zod7.z.boolean().optional()
4046
4340
  });
4047
4341
  function createAgentTool(options) {
4048
4342
  if (options.agents.length === 0) {
@@ -4062,7 +4356,7 @@ If omitted, defaults to "${defaultAgent.name}".`;
4062
4356
  return defineTool({
4063
4357
  name: "Agent",
4064
4358
  description,
4065
- inputSchema,
4359
+ inputSchema: inputSchema2,
4066
4360
  isConcurrencySafe: (input) => {
4067
4361
  const typed = input;
4068
4362
  const typeName = typed?.subagent_type ?? defaultAgent.name;
@@ -4103,7 +4397,8 @@ If omitted, defaults to "${defaultAgent.name}".`;
4103
4397
  idleFlushMs: options.idleFlushMs,
4104
4398
  // Fork: prepend parent messages + forked messages
4105
4399
  prependMessages: [...parentMsgs, ...forkedMsgs],
4106
- ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool } : {}
4400
+ ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool } : {},
4401
+ ...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {}
4107
4402
  });
4108
4403
  handlePausedResult(result2, spawn2.agentId, "fork");
4109
4404
  const t2 = result2;
@@ -4152,7 +4447,8 @@ If omitted, defaults to "${defaultAgent.name}".`;
4152
4447
  turnTimeoutMs: options.turnTimeoutMs,
4153
4448
  flushPolicy: options.flushPolicy,
4154
4449
  idleFlushMs: options.idleFlushMs,
4155
- ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool } : {}
4450
+ ...options.gateBeforeTool !== void 0 ? { gateBeforeTool: options.gateBeforeTool } : {},
4451
+ ...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {}
4156
4452
  };
4157
4453
  const shouldRunAsync = run_in_background === true || options.coordinatorMode === true;
4158
4454
  if (shouldRunAsync) {
@@ -4247,7 +4543,8 @@ function handlePausedResult(result, agentId, subagentType) {
4247
4543
 
4248
4544
  // src/tools/bash.ts
4249
4545
  init_cjs_shims();
4250
- var import_zod7 = require("zod");
4546
+ var import_zod8 = require("zod");
4547
+ init_contract();
4251
4548
  var _spawn = null;
4252
4549
  async function getSpawn() {
4253
4550
  if (_spawn === null) {
@@ -4259,15 +4556,15 @@ async function getSpawn() {
4259
4556
  var MAX_OUTPUT_BYTES = 512 * 1024;
4260
4557
  var SIGKILL_GRACE_MS = 500;
4261
4558
  var BLOCKED_DEVICE_PATHS = /\b(\/dev\/zero|\/dev\/random|\/dev\/urandom|\/proc\/kcore|\/dev\/sda|\/dev\/mem)\b/;
4262
- var inputSchema2 = import_zod7.z.object({
4263
- command: import_zod7.z.string().min(1),
4264
- cwd: import_zod7.z.string().min(1).optional()
4559
+ var inputSchema3 = import_zod8.z.object({
4560
+ command: import_zod8.z.string().min(1),
4561
+ cwd: import_zod8.z.string().min(1).optional()
4265
4562
  });
4266
4563
  function createBashTool() {
4267
4564
  return defineTool({
4268
4565
  name: "Bash",
4269
4566
  description: "Execute a shell command via /bin/sh -c. Returns combined stdout+stderr and the exit code.",
4270
- inputSchema: inputSchema2,
4567
+ inputSchema: inputSchema3,
4271
4568
  requiresNode: true,
4272
4569
  execute: async ({ command, cwd }, ctx) => {
4273
4570
  if (BLOCKED_DEVICE_PATHS.test(command)) {
@@ -4348,16 +4645,17 @@ function createBashTool() {
4348
4645
 
4349
4646
  // src/tools/sendMessage.ts
4350
4647
  init_cjs_shims();
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.")
4648
+ var import_zod9 = require("zod");
4649
+ init_contract();
4650
+ var inputSchema4 = import_zod9.z.object({
4651
+ to: import_zod9.z.string().min(1).describe("Agent name (subagent_type) or agentId to send the message to."),
4652
+ message: import_zod9.z.string().min(1).describe("Message content to deliver to the target agent.")
4355
4653
  });
4356
4654
  function createSendMessageTool(options) {
4357
4655
  return defineTool({
4358
4656
  name: "SendMessage",
4359
4657
  description: "Send a text message to a running subagent by name or agentId. The message is queued and delivered at the start of the agent's next turn. Use this to redirect, provide additional context, or coordinate with agents you spawned.",
4360
- inputSchema: inputSchema3,
4658
+ inputSchema: inputSchema4,
4361
4659
  execute: async ({ to, message }) => {
4362
4660
  const { registry } = options;
4363
4661
  let agentId = registry.findByName(to);
@@ -4400,20 +4698,24 @@ function createSendMessageTool(options) {
4400
4698
  });
4401
4699
  }
4402
4700
 
4701
+ // src/engine/engine.ts
4702
+ init_contract();
4703
+
4403
4704
  // src/tools/fileEdit.ts
4404
4705
  init_cjs_shims();
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()
4706
+ var import_zod10 = require("zod");
4707
+ init_contract();
4708
+ var inputSchema5 = import_zod10.z.object({
4709
+ path: import_zod10.z.string().min(1),
4710
+ old_string: import_zod10.z.string().min(1),
4711
+ new_string: import_zod10.z.string(),
4712
+ replace_all: import_zod10.z.boolean().optional()
4411
4713
  });
4412
4714
  function createFileEditTool(storage) {
4413
4715
  return defineTool({
4414
4716
  name: "Edit",
4415
4717
  description: "Replace old_string with new_string in a file. By default old_string must be unique; set replace_all to replace every occurrence.",
4416
- inputSchema: inputSchema4,
4718
+ inputSchema: inputSchema5,
4417
4719
  execute: async ({ path, old_string, new_string, replace_all }) => {
4418
4720
  if (old_string === new_string) {
4419
4721
  return {
@@ -4491,13 +4793,14 @@ function normalizeQuotes(s) {
4491
4793
 
4492
4794
  // src/tools/fileRead.ts
4493
4795
  init_cjs_shims();
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(),
4796
+ var import_zod11 = require("zod");
4797
+ init_contract();
4798
+ var inputSchema6 = import_zod11.z.object({
4799
+ path: import_zod11.z.string().min(1),
4800
+ offset: import_zod11.z.number().int().positive().optional(),
4801
+ limit: import_zod11.z.number().int().positive().optional(),
4499
4802
  /** PDF page range, e.g. "1-5", "3", "10-20". Max 20 pages per request. */
4500
- pages: import_zod10.z.string().optional()
4803
+ pages: import_zod11.z.string().optional()
4501
4804
  });
4502
4805
  var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg"]);
4503
4806
  var PDF_EXTENSION = ".pdf";
@@ -4516,7 +4819,7 @@ function createFileReadTool(storageOrOptions) {
4516
4819
  return defineTool({
4517
4820
  name: "Read",
4518
4821
  description: "Read a file from the workspace. Text files return cat -n style line numbers. PDF files extract text per page (use pages param). Image files return base64 for visual analysis.",
4519
- inputSchema: inputSchema5,
4822
+ inputSchema: inputSchema6,
4520
4823
  isConcurrencySafe: () => true,
4521
4824
  execute: async ({ path, offset, limit, pages }) => {
4522
4825
  const ext = extname(path);
@@ -4681,10 +4984,11 @@ Base64 data is included in the metadata for visual analysis.`,
4681
4984
 
4682
4985
  // src/tools/fileWrite.ts
4683
4986
  init_cjs_shims();
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()
4987
+ var import_zod12 = require("zod");
4988
+ init_contract();
4989
+ var inputSchema7 = import_zod12.z.object({
4990
+ path: import_zod12.z.string().min(1),
4991
+ content: import_zod12.z.string()
4688
4992
  });
4689
4993
  function createFileWriteTool(storageOrOptions) {
4690
4994
  const opts = "readFile" in storageOrOptions ? { storage: storageOrOptions } : storageOrOptions;
@@ -4692,7 +4996,7 @@ function createFileWriteTool(storageOrOptions) {
4692
4996
  return defineTool({
4693
4997
  name: "Write",
4694
4998
  description: "Write a file to the workspace. Creates parents and overwrites existing files.",
4695
- inputSchema: inputSchema6,
4999
+ inputSchema: inputSchema7,
4696
5000
  execute: async ({ path, content }) => {
4697
5001
  if (tracker !== void 0) {
4698
5002
  const exists = await storage.exists(path);
@@ -4723,7 +5027,8 @@ function createFileWriteTool(storageOrOptions) {
4723
5027
  // src/tools/glob.ts
4724
5028
  init_cjs_shims();
4725
5029
  var import_picomatch = __toESM(require("picomatch"), 1);
4726
- var import_zod12 = require("zod");
5030
+ var import_zod13 = require("zod");
5031
+ init_contract();
4727
5032
 
4728
5033
  // src/tools/walkAdapter.ts
4729
5034
  init_cjs_shims();
@@ -4760,16 +5065,16 @@ async function* walkAdapter(adapter, startPath, options = {}) {
4760
5065
  }
4761
5066
 
4762
5067
  // src/tools/glob.ts
4763
- var inputSchema7 = import_zod12.z.object({
4764
- pattern: import_zod12.z.string().min(1),
4765
- path: import_zod12.z.string().optional()
5068
+ var inputSchema8 = import_zod13.z.object({
5069
+ pattern: import_zod13.z.string().min(1),
5070
+ path: import_zod13.z.string().optional()
4766
5071
  });
4767
5072
  var MAX_RESULTS = 1e3;
4768
5073
  function createGlobTool(storage) {
4769
5074
  return defineTool({
4770
5075
  name: "Glob",
4771
5076
  description: "Find files by glob pattern. Supports *, **, ?, [abc], {a,b}. Returns paths sorted by mtime descending.",
4772
- inputSchema: inputSchema7,
5077
+ inputSchema: inputSchema8,
4773
5078
  isConcurrencySafe: () => true,
4774
5079
  execute: async ({ pattern, path: searchPath }) => {
4775
5080
  const startPath = searchPath ?? "";
@@ -4815,22 +5120,23 @@ function createGlobTool(storage) {
4815
5120
  // src/tools/grep.ts
4816
5121
  init_cjs_shims();
4817
5122
  var import_picomatch2 = __toESM(require("picomatch"), 1);
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()
5123
+ var import_zod14 = require("zod");
5124
+ init_contract();
5125
+ var inputSchema9 = import_zod14.z.object({
5126
+ pattern: import_zod14.z.string().min(1),
5127
+ path: import_zod14.z.string().optional(),
5128
+ glob: import_zod14.z.string().optional(),
5129
+ type: import_zod14.z.string().optional(),
5130
+ output_mode: import_zod14.z.enum(["content", "files_with_matches", "count"]).optional(),
5131
+ "-i": import_zod14.z.boolean().optional(),
5132
+ "-n": import_zod14.z.boolean().optional(),
5133
+ "-A": import_zod14.z.number().int().nonnegative().optional(),
5134
+ "-B": import_zod14.z.number().int().nonnegative().optional(),
5135
+ "-C": import_zod14.z.number().int().nonnegative().optional(),
5136
+ context: import_zod14.z.number().int().nonnegative().optional(),
5137
+ multiline: import_zod14.z.boolean().optional(),
5138
+ head_limit: import_zod14.z.number().int().nonnegative().optional(),
5139
+ offset: import_zod14.z.number().int().nonnegative().optional()
4834
5140
  });
4835
5141
  var MAX_FILES_SCANNED = 5e3;
4836
5142
  var MAX_MATCHES_PER_FILE = 100;
@@ -4876,7 +5182,7 @@ function createGrepTool(storage) {
4876
5182
  return defineTool({
4877
5183
  name: "Grep",
4878
5184
  description: "Search for a regex pattern across files. Supports ripgrep when available (context lines, multiline, type filters, pagination). Falls back to JS RegExp scanner.",
4879
- inputSchema: inputSchema8,
5185
+ inputSchema: inputSchema9,
4880
5186
  isConcurrencySafe: () => true,
4881
5187
  execute: async (input, ctx) => {
4882
5188
  if (rgAvailable && input.path !== void 0) {
@@ -5054,10 +5360,11 @@ function formatJsResults(results, mode, limit) {
5054
5360
 
5055
5361
  // src/tools/webFetch.ts
5056
5362
  init_cjs_shims();
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()
5363
+ var import_zod15 = require("zod");
5364
+ init_contract();
5365
+ var inputSchema10 = import_zod15.z.object({
5366
+ url: import_zod15.z.string().url(),
5367
+ prompt: import_zod15.z.string().optional()
5061
5368
  });
5062
5369
  var MAX_OUTPUT_BYTES2 = 256 * 1024;
5063
5370
  function createWebFetchTool(options = {}) {
@@ -5065,7 +5372,7 @@ function createWebFetchTool(options = {}) {
5065
5372
  return defineTool({
5066
5373
  name: "WebFetch",
5067
5374
  description: "Fetch a URL and return its content as plain text. HTML is stripped to its readable text.",
5068
- inputSchema: inputSchema9,
5375
+ inputSchema: inputSchema10,
5069
5376
  isConcurrencySafe: () => true,
5070
5377
  execute: async ({ url }, ctx) => {
5071
5378
  let response;
@@ -5123,8 +5430,8 @@ Make a new WebFetch request with the redirect URL if you want to follow it.`,
5123
5430
  isError: true
5124
5431
  };
5125
5432
  }
5126
- const text = isHtml(contentType) ? htmlToText(raw) : raw;
5127
- const { content, truncated } = truncate(text, MAX_OUTPUT_BYTES2);
5433
+ const text2 = isHtml(contentType) ? htmlToText(raw) : raw;
5434
+ const { content, truncated } = truncate(text2, MAX_OUTPUT_BYTES2);
5128
5435
  return {
5129
5436
  content,
5130
5437
  metadata: {
@@ -5140,24 +5447,24 @@ Make a new WebFetch request with the redirect URL if you want to follow it.`,
5140
5447
  function isHtml(contentType) {
5141
5448
  return contentType.toLowerCase().includes("html");
5142
5449
  }
5143
- function htmlToText(html) {
5144
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5450
+ function htmlToText(html2) {
5451
+ return html2.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5145
5452
  }
5146
- function truncate(text, maxBytes) {
5147
- if (Buffer.byteLength(text, "utf8") <= maxBytes) {
5148
- return { content: text, truncated: false };
5453
+ function truncate(text2, maxBytes) {
5454
+ if (Buffer.byteLength(text2, "utf8") <= maxBytes) {
5455
+ return { content: text2, truncated: false };
5149
5456
  }
5150
5457
  let lo = 0;
5151
- let hi = text.length;
5458
+ let hi = text2.length;
5152
5459
  while (lo < hi) {
5153
5460
  const mid = lo + hi + 1 >>> 1;
5154
- if (Buffer.byteLength(text.slice(0, mid), "utf8") <= maxBytes) {
5461
+ if (Buffer.byteLength(text2.slice(0, mid), "utf8") <= maxBytes) {
5155
5462
  lo = mid;
5156
5463
  } else {
5157
5464
  hi = mid - 1;
5158
5465
  }
5159
5466
  }
5160
- return { content: text.slice(0, lo) + "\n... (truncated)", truncated: true };
5467
+ return { content: text2.slice(0, lo) + "\n... (truncated)", truncated: true };
5161
5468
  }
5162
5469
  async function safeText(response) {
5163
5470
  try {
@@ -5186,16 +5493,17 @@ function normalizePath(p) {
5186
5493
 
5187
5494
  // src/tools/webSearch.ts
5188
5495
  init_cjs_shims();
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()
5496
+ var import_zod16 = require("zod");
5497
+ init_contract();
5498
+ var inputSchema11 = import_zod16.z.object({
5499
+ query: import_zod16.z.string().min(2),
5500
+ max_results: import_zod16.z.number().int().positive().optional()
5193
5501
  });
5194
5502
  function createWebSearchTool() {
5195
5503
  return defineTool({
5196
5504
  name: "WebSearch",
5197
5505
  description: "Search the web for information. Returns search result snippets. Use when you need current information not available in local files.",
5198
- inputSchema: inputSchema10,
5506
+ inputSchema: inputSchema11,
5199
5507
  isConcurrencySafe: () => true,
5200
5508
  execute: async ({ query }) => {
5201
5509
  const encoded = encodeURIComponent(query);
@@ -5220,17 +5528,17 @@ function createWebSearchTool() {
5220
5528
  isError: true
5221
5529
  };
5222
5530
  }
5223
- let html;
5531
+ let html2;
5224
5532
  try {
5225
- html = await response.text();
5533
+ html2 = await response.text();
5226
5534
  } catch (err) {
5227
5535
  return {
5228
5536
  content: `Failed to read search response: ${err.message}`,
5229
5537
  isError: true
5230
5538
  };
5231
5539
  }
5232
- const text = htmlToText2(html);
5233
- const trimmed = text.slice(0, 8e3);
5540
+ const text2 = htmlToText2(html2);
5541
+ const trimmed = text2.slice(0, 8e3);
5234
5542
  return {
5235
5543
  content: `Search results for "${query}":
5236
5544
 
@@ -5240,22 +5548,23 @@ ${trimmed}`,
5240
5548
  }
5241
5549
  });
5242
5550
  }
5243
- function htmlToText2(html) {
5244
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5551
+ function htmlToText2(html2) {
5552
+ return html2.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5245
5553
  }
5246
5554
 
5247
5555
  // src/tools/sleep.ts
5248
5556
  init_cjs_shims();
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()
5557
+ var import_zod17 = require("zod");
5558
+ init_contract();
5559
+ var inputSchema12 = import_zod17.z.object({
5560
+ durationMs: import_zod17.z.number().int().nonnegative().max(3e5),
5561
+ reason: import_zod17.z.string().optional()
5253
5562
  });
5254
5563
  function createSleepTool() {
5255
5564
  return defineTool({
5256
5565
  name: "Sleep",
5257
5566
  description: "Pause execution for the given number of milliseconds (max 300000 = 5 minutes). Use when you need to wait for an external process or rate limit.",
5258
- inputSchema: inputSchema11,
5567
+ inputSchema: inputSchema12,
5259
5568
  isConcurrencySafe: () => true,
5260
5569
  execute: async ({ durationMs, reason }, ctx) => {
5261
5570
  if (durationMs === 0) {
@@ -5289,16 +5598,17 @@ function createSleepTool() {
5289
5598
 
5290
5599
  // src/tools/toolSearch.ts
5291
5600
  init_cjs_shims();
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()
5601
+ var import_zod18 = require("zod");
5602
+ init_contract();
5603
+ var inputSchema13 = import_zod18.z.object({
5604
+ query: import_zod18.z.string().min(1),
5605
+ max_results: import_zod18.z.number().int().positive().optional()
5296
5606
  });
5297
5607
  function createToolSearchTool(registry) {
5298
5608
  return defineTool({
5299
5609
  name: "ToolSearch",
5300
5610
  description: "Search the available tools by keyword. Returns matching tool names and descriptions. Use when you want to discover what tools are available for a task.",
5301
- inputSchema: inputSchema12,
5611
+ inputSchema: inputSchema13,
5302
5612
  isConcurrencySafe: () => true,
5303
5613
  execute: async ({ query, max_results }) => {
5304
5614
  const limit = max_results ?? 10;
@@ -5335,18 +5645,19 @@ ${lines.join("\n")}`,
5335
5645
 
5336
5646
  // src/tools/memorize.ts
5337
5647
  init_cjs_shims();
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()
5648
+ var import_zod19 = require("zod");
5649
+ init_contract();
5650
+ var inputSchema14 = import_zod19.z.object({
5651
+ text: import_zod19.z.string().min(1),
5652
+ kind: import_zod19.z.enum(["rule", "lesson"]).default("lesson"),
5653
+ topic: import_zod19.z.string().optional()
5343
5654
  });
5344
5655
  function createMemorizeTool(memory) {
5345
5656
  return defineTool({
5346
5657
  name: "Memorize",
5347
5658
  description: 'Save a fact, rule, or lesson to persistent memory. Memories survive across runs and are included in the system prompt of future runs. Use "rule" for behavioral constraints (always/never do X). Use "lesson" for learnings and observations.',
5348
- inputSchema: inputSchema13,
5349
- execute: async ({ text, kind, topic }) => {
5659
+ inputSchema: inputSchema14,
5660
+ execute: async ({ text: text2, kind, topic }) => {
5350
5661
  if (memory.mode === "off" || memory.mode === "read-only") {
5351
5662
  return {
5352
5663
  content: `Cannot memorize: memory mode is "${memory.mode}". Set config.memory.mode to "read-write" to enable.`,
@@ -5354,15 +5665,15 @@ function createMemorizeTool(memory) {
5354
5665
  };
5355
5666
  }
5356
5667
  if (kind === "rule") {
5357
- await memory.encodeRule(text, "always");
5668
+ await memory.encodeRule(text2, "always");
5358
5669
  return {
5359
- content: `Memorized rule: "${text.slice(0, 80)}${text.length > 80 ? "\u2026" : ""}"`,
5670
+ content: `Memorized rule: "${text2.slice(0, 80)}${text2.length > 80 ? "\u2026" : ""}"`,
5360
5671
  metadata: { kind: "rule" }
5361
5672
  };
5362
5673
  }
5363
- await memory.encodeLesson(text, topic);
5674
+ await memory.encodeLesson(text2, topic);
5364
5675
  return {
5365
- content: `Memorized lesson: "${text.slice(0, 80)}${text.length > 80 ? "\u2026" : ""}"${topic ? ` (topic: ${topic})` : ""}`,
5676
+ content: `Memorized lesson: "${text2.slice(0, 80)}${text2.length > 80 ? "\u2026" : ""}"${topic ? ` (topic: ${topic})` : ""}`,
5366
5677
  metadata: { kind: "lesson", topic }
5367
5678
  };
5368
5679
  }
@@ -5371,17 +5682,18 @@ function createMemorizeTool(memory) {
5371
5682
 
5372
5683
  // src/tools/recall.ts
5373
5684
  init_cjs_shims();
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()
5685
+ var import_zod20 = require("zod");
5686
+ init_contract();
5687
+ var inputSchema15 = import_zod20.z.object({
5688
+ query: import_zod20.z.string().min(1),
5689
+ scope: import_zod20.z.enum(["identity", "rules", "lessons", "all"]).default("all"),
5690
+ topic: import_zod20.z.string().optional()
5379
5691
  });
5380
5692
  function createRecallTool(memory) {
5381
5693
  return defineTool({
5382
5694
  name: "Recall",
5383
5695
  description: "Search persistent memory for previously saved facts, rules, and lessons. Use when you need to recall information from prior runs or check what rules/lessons are stored.",
5384
- inputSchema: inputSchema14,
5696
+ inputSchema: inputSchema15,
5385
5697
  isConcurrencySafe: () => true,
5386
5698
  execute: async ({ query, scope, topic }) => {
5387
5699
  if (memory.mode === "off") {
@@ -5430,19 +5742,20 @@ ${content}`,
5430
5742
 
5431
5743
  // src/tools/notebookEdit.ts
5432
5744
  init_cjs_shims();
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()
5745
+ var import_zod21 = require("zod");
5746
+ init_contract();
5747
+ var inputSchema16 = import_zod21.z.object({
5748
+ notebook_path: import_zod21.z.string().min(1),
5749
+ edit_mode: import_zod21.z.enum(["replace", "insert", "delete"]).default("replace"),
5750
+ cell_index: import_zod21.z.number().int().nonnegative(),
5751
+ new_source: import_zod21.z.string().optional(),
5752
+ cell_type: import_zod21.z.enum(["code", "markdown"]).optional()
5440
5753
  });
5441
5754
  function createNotebookEditTool(storage) {
5442
5755
  return defineTool({
5443
5756
  name: "NotebookEdit",
5444
5757
  description: "Edit a Jupyter notebook (.ipynb) by inserting, replacing, or deleting cells. Specify the cell_index (0-based) and the operation.",
5445
- inputSchema: inputSchema15,
5758
+ inputSchema: inputSchema16,
5446
5759
  execute: async ({
5447
5760
  notebook_path,
5448
5761
  edit_mode,
@@ -5591,12 +5904,13 @@ var TaskStore = class {
5591
5904
 
5592
5905
  // src/tools/tasks/tools.ts
5593
5906
  init_cjs_shims();
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()
5907
+ var import_zod22 = require("zod");
5908
+ init_contract();
5909
+ var TaskStatusEnum = import_zod22.z.enum(["pending", "in_progress", "completed", "deleted"]);
5910
+ var createSchema = import_zod22.z.object({
5911
+ subject: import_zod22.z.string().min(1),
5912
+ description: import_zod22.z.string().default(""),
5913
+ metadata: import_zod22.z.record(import_zod22.z.unknown()).optional()
5600
5914
  });
5601
5915
  function createTaskCreateTool(store) {
5602
5916
  return defineTool({
@@ -5612,8 +5926,8 @@ function createTaskCreateTool(store) {
5612
5926
  }
5613
5927
  });
5614
5928
  }
5615
- var getSchema = import_zod21.z.object({
5616
- taskId: import_zod21.z.string().min(1)
5929
+ var getSchema = import_zod22.z.object({
5930
+ taskId: import_zod22.z.string().min(1)
5617
5931
  });
5618
5932
  function createTaskGetTool(store) {
5619
5933
  return defineTool({
@@ -5634,7 +5948,7 @@ ${task.description}`,
5634
5948
  }
5635
5949
  });
5636
5950
  }
5637
- var listSchema = import_zod21.z.object({
5951
+ var listSchema = import_zod22.z.object({
5638
5952
  status: TaskStatusEnum.optional()
5639
5953
  });
5640
5954
  function createTaskListTool(store) {
@@ -5660,12 +5974,12 @@ ${lines.join("\n")}`,
5660
5974
  }
5661
5975
  });
5662
5976
  }
5663
- var updateSchema = import_zod21.z.object({
5664
- taskId: import_zod21.z.string().min(1),
5665
- subject: import_zod21.z.string().min(1).optional(),
5977
+ var updateSchema = import_zod22.z.object({
5978
+ taskId: import_zod22.z.string().min(1),
5979
+ subject: import_zod22.z.string().min(1).optional(),
5666
5980
  status: TaskStatusEnum.optional(),
5667
- description: import_zod21.z.string().optional(),
5668
- metadata: import_zod21.z.record(import_zod21.z.unknown()).optional()
5981
+ description: import_zod22.z.string().optional(),
5982
+ metadata: import_zod22.z.record(import_zod22.z.unknown()).optional()
5669
5983
  });
5670
5984
  function createTaskUpdateTool(store) {
5671
5985
  return defineTool({
@@ -6036,17 +6350,17 @@ var BindingHttpTransport = class {
6036
6350
  }
6037
6351
  if (response.status === 202 || response.status === 204) return;
6038
6352
  if (!response.ok) {
6039
- const text = await safeText2(response);
6353
+ const text2 = await safeText2(response);
6040
6354
  const err = new Error(
6041
- `BindingHttpTransport: HTTP ${String(response.status)} ${response.statusText}${text ? ` \u2014 ${text}` : ""}`
6355
+ `BindingHttpTransport: HTTP ${String(response.status)} ${response.statusText}${text2 ? ` \u2014 ${text2}` : ""}`
6042
6356
  );
6043
6357
  this.onerror?.(err);
6044
6358
  throw err;
6045
6359
  }
6046
6360
  const contentType = response.headers.get("Content-Type") ?? "";
6047
6361
  if (!contentType.includes("application/json")) {
6048
- const text = await response.text();
6049
- const parsed2 = parseSseFrames(text);
6362
+ const text2 = await response.text();
6363
+ const parsed2 = parseSseFrames(text2);
6050
6364
  for (const msg of parsed2) this.onmessage?.(msg);
6051
6365
  return;
6052
6366
  }
@@ -6113,9 +6427,9 @@ async function safeText2(r) {
6113
6427
  return "";
6114
6428
  }
6115
6429
  }
6116
- function parseSseFrames(text) {
6430
+ function parseSseFrames(text2) {
6117
6431
  const out = [];
6118
- for (const block of text.split(/\r?\n\r?\n/)) {
6432
+ for (const block of text2.split(/\r?\n\r?\n/)) {
6119
6433
  const lines = block.split(/\r?\n/).filter((l) => l.startsWith("data:"));
6120
6434
  if (lines.length === 0) continue;
6121
6435
  const raw = lines.map((l) => l.slice(5).trimStart()).join("\n");
@@ -6402,8 +6716,8 @@ function normalizeToolList(response, serverName) {
6402
6716
  const name = typeof obj.name === "string" ? obj.name : null;
6403
6717
  if (name === null) continue;
6404
6718
  const description = typeof obj.description === "string" ? obj.description : "";
6405
- const inputSchema17 = obj.inputSchema !== null && typeof obj.inputSchema === "object" && !Array.isArray(obj.inputSchema) ? obj.inputSchema : { type: "object", properties: {} };
6406
- out.push({ name, description, inputSchema: inputSchema17 });
6719
+ const inputSchema20 = obj.inputSchema !== null && typeof obj.inputSchema === "object" && !Array.isArray(obj.inputSchema) ? obj.inputSchema : { type: "object", properties: {} };
6720
+ out.push({ name, description, inputSchema: inputSchema20 });
6407
6721
  }
6408
6722
  return out;
6409
6723
  }
@@ -6512,7 +6826,8 @@ function wrapFetchWithHeadersProvider(baseFetch, headersProvider, staticHeaders)
6512
6826
 
6513
6827
  // src/mcp/toolAdapter.ts
6514
6828
  init_cjs_shims();
6515
- var import_zod22 = require("zod");
6829
+ var import_zod23 = require("zod");
6830
+ init_contract();
6516
6831
  function mcpToolName(serverName, toolName) {
6517
6832
  return `mcp__${serverName}__${toolName}`;
6518
6833
  }
@@ -6521,7 +6836,7 @@ function adaptMcpTool(client, serverName, def) {
6521
6836
  return defineTool({
6522
6837
  name: registeredName,
6523
6838
  description: def.description.length > 0 ? def.description : `MCP tool ${serverName}/${def.name}`,
6524
- inputSchema: import_zod22.z.unknown(),
6839
+ inputSchema: import_zod23.z.unknown(),
6525
6840
  // Pass the MCP server's JSON Schema through to Anthropic verbatim,
6526
6841
  // bypassing Zod-to-JSON-Schema conversion (which would produce `{}`
6527
6842
  // for our `z.unknown()` Zod schema).
@@ -7053,15 +7368,15 @@ var Hippocampus = class _Hippocampus {
7053
7368
  return (content ?? "").trim();
7054
7369
  }
7055
7370
  // ---------- encode (write) ----------
7056
- async encodeRule(text, kind, confidence = "medium", source = "llm") {
7371
+ async encodeRule(text2, kind, confidence = "medium", source = "llm") {
7057
7372
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7058
7373
  const metadata = `<!-- confidence:${confidence} source:${source} ts:${ts} -->`;
7059
- const entry = `- ${text} ${metadata}
7374
+ const entry = `- ${text2} ${metadata}
7060
7375
  `;
7061
7376
  const sectionHeader = `## ${kind.charAt(0).toUpperCase()}${kind.slice(1)}`;
7062
7377
  let content = await this.storage.readFile(this.rulesPath);
7063
7378
  if (content === null) content = RULES_SKELETON;
7064
- if (_Hippocampus.extractEntryTexts(content).has(text)) return;
7379
+ if (_Hippocampus.extractEntryTexts(content).has(text2)) return;
7065
7380
  const lines = content.split(/(?<=\n)/);
7066
7381
  const out = [];
7067
7382
  let inserted = false;
@@ -7094,17 +7409,17 @@ ${entry}`);
7094
7409
  }
7095
7410
  await this.storage.writeFile(this.rulesPath, out.join(""));
7096
7411
  }
7097
- async encodeLesson(text, topic = "", source = "llm") {
7412
+ async encodeLesson(text2, topic = "", source = "llm") {
7098
7413
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7099
7414
  const topicTag = topic ? ` topic:${topic}` : "";
7100
7415
  const sourceTag = source !== "llm" ? ` source:${source}` : "";
7101
- const entry = `- ${text} <!--${topicTag}${sourceTag} ts:${ts} -->
7416
+ const entry = `- ${text2} <!--${topicTag}${sourceTag} ts:${ts} -->
7102
7417
  `;
7103
7418
  const existing = await this.storage.readFile(this.lessonsPath);
7104
7419
  if (existing === null) {
7105
7420
  await this.storage.writeFile(this.lessonsPath, `# Lessons
7106
7421
  ${entry}`);
7107
- } else if (!_Hippocampus.extractEntryTexts(existing).has(text)) {
7422
+ } else if (!_Hippocampus.extractEntryTexts(existing).has(text2)) {
7108
7423
  await this.storage.appendFile(this.lessonsPath, entry);
7109
7424
  }
7110
7425
  if (topic) {
@@ -7114,7 +7429,7 @@ ${entry}`);
7114
7429
  if (topicContent === null) {
7115
7430
  await this.storage.writeFile(topicPath, `# ${topic}
7116
7431
  ${entry}`);
7117
- } else if (!_Hippocampus.extractEntryTexts(topicContent).has(text)) {
7432
+ } else if (!_Hippocampus.extractEntryTexts(topicContent).has(text2)) {
7118
7433
  await this.storage.appendFile(topicPath, entry);
7119
7434
  }
7120
7435
  }
@@ -7170,12 +7485,12 @@ ${entries.map((e) => `- ${e}`).join("\n")}
7170
7485
  }
7171
7486
  /** Sanitize a topic name into a safe file slug. */
7172
7487
  static sanitizeSlug(name) {
7173
- let text = name.toLowerCase().trim();
7174
- text = text.replace(/[^a-z0-9\s_-]/g, "");
7175
- text = text.replace(/\s+/g, "-");
7176
- text = text.replace(/-+/g, "-");
7177
- text = text.replace(/^-|-$/g, "");
7178
- return text.length > 0 ? text : "general";
7488
+ let text2 = name.toLowerCase().trim();
7489
+ text2 = text2.replace(/[^a-z0-9\s_-]/g, "");
7490
+ text2 = text2.replace(/\s+/g, "-");
7491
+ text2 = text2.replace(/-+/g, "-");
7492
+ text2 = text2.replace(/^-|-$/g, "");
7493
+ return text2.length > 0 ? text2 : "general";
7179
7494
  }
7180
7495
  };
7181
7496
 
@@ -7207,13 +7522,13 @@ function createSmartMemory(options) {
7207
7522
  if (!readsEnabled) return "";
7208
7523
  return hippocampus.recallTopic(slug);
7209
7524
  },
7210
- async encodeRule(text, kind, confidence, source) {
7525
+ async encodeRule(text2, kind, confidence, source) {
7211
7526
  if (!writesEnabled) return;
7212
- await hippocampus.encodeRule(text, kind, confidence, source);
7527
+ await hippocampus.encodeRule(text2, kind, confidence, source);
7213
7528
  },
7214
- async encodeLesson(text, topic, source) {
7529
+ async encodeLesson(text2, topic, source) {
7215
7530
  if (!writesEnabled) return;
7216
- await hippocampus.encodeLesson(text, topic, source);
7531
+ await hippocampus.encodeLesson(text2, topic, source);
7217
7532
  },
7218
7533
  async rewriteIdentity(entries) {
7219
7534
  if (!writesEnabled) return;
@@ -7579,8 +7894,8 @@ function buildSchemaPrompt(schema) {
7579
7894
  }
7580
7895
  return lines.join("\n");
7581
7896
  }
7582
- function tryParseJSON(text) {
7583
- const trimmed = text.trim();
7897
+ function tryParseJSON2(text2) {
7898
+ const trimmed = text2.trim();
7584
7899
  try {
7585
7900
  return { ok: true, value: JSON.parse(trimmed) };
7586
7901
  } catch {
@@ -7619,17 +7934,18 @@ ${issues.join("\n")}` };
7619
7934
 
7620
7935
  // src/skills/skillPage.ts
7621
7936
  init_cjs_shims();
7622
- var import_zod23 = require("zod");
7937
+ var import_zod24 = require("zod");
7938
+ init_contract();
7623
7939
  var SAFE_NAME3 = /^[a-zA-Z0-9_-]+$/;
7624
- var inputSchema16 = import_zod23.z.object({
7625
- skill: import_zod23.z.string().min(1),
7626
- page: import_zod23.z.string().min(1).optional()
7940
+ var inputSchema17 = import_zod24.z.object({
7941
+ skill: import_zod24.z.string().min(1),
7942
+ page: import_zod24.z.string().min(1).optional()
7627
7943
  });
7628
7944
  function createSkillPageTool(options) {
7629
7945
  return defineTool({
7630
7946
  name: "SkillPage",
7631
7947
  description: "Load a skill. Pass `skill` alone to read the main SKILL.md; pass both `skill` and `page` to read a supplemental page. Skill names appear in the system prompt skill index.",
7632
- inputSchema: inputSchema16,
7948
+ inputSchema: inputSchema17,
7633
7949
  execute: async ({ skill, page }) => {
7634
7950
  if (!SAFE_NAME3.test(skill)) {
7635
7951
  return {
@@ -7681,7 +7997,8 @@ The skill "${skill}" has no pages.`;
7681
7997
 
7682
7998
  // src/tools/apiCall.ts
7683
7999
  init_cjs_shims();
7684
- var import_zod24 = require("zod");
8000
+ var import_zod25 = require("zod");
8001
+ init_contract();
7685
8002
  var ALL_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
7686
8003
  var DEFAULT_MAX_BODY_BYTES = 256 * 1024;
7687
8004
  var DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024;
@@ -7706,19 +8023,19 @@ function createApiCallTool(opts) {
7706
8023
  }
7707
8024
  const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
7708
8025
  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()
8026
+ const inputSchema20 = import_zod25.z.object({
8027
+ service: import_zod25.z.enum(serviceNames),
8028
+ method: import_zod25.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
8029
+ path: import_zod25.z.string().regex(/^\//, "path must start with /"),
8030
+ query: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.string()).optional(),
8031
+ body: import_zod25.z.unknown().optional(),
8032
+ headers: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.string()).optional()
7716
8033
  });
7717
8034
  const description = opts.toolDescription ?? `Call a configured external API. Services: ${serviceNames.join(", ")}. Auth is injected automatically \u2014 do not pass credentials via headers.`;
7718
8035
  return defineTool({
7719
8036
  name: opts.toolName ?? "ApiCall",
7720
8037
  description,
7721
- inputSchema: inputSchema17,
8038
+ inputSchema: inputSchema20,
7722
8039
  execute: async (input) => {
7723
8040
  const svc = services.get(input.service);
7724
8041
  if (!svc) {
@@ -7737,7 +8054,7 @@ function createApiCallTool(opts) {
7737
8054
  if (input.body !== void 0) {
7738
8055
  bodyText = JSON.stringify(input.body);
7739
8056
  const cap = svc.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
7740
- if (byteLength(bodyText) > cap) {
8057
+ if (byteLength2(bodyText) > cap) {
7741
8058
  return errResult(`ERR_API_BODY_TOO_LARGE: exceeds ${cap} bytes`);
7742
8059
  }
7743
8060
  }
@@ -7811,7 +8128,7 @@ function pathAllowed(path, allowed) {
7811
8128
  }
7812
8129
  return false;
7813
8130
  }
7814
- function byteLength(s) {
8131
+ function byteLength2(s) {
7815
8132
  return new TextEncoder().encode(s).byteLength;
7816
8133
  }
7817
8134
  function buildUrl(baseUrl, path, query) {
@@ -7876,6 +8193,572 @@ async function invokeHook(hook, event) {
7876
8193
  }
7877
8194
  }
7878
8195
 
8196
+ // src/engine/engine.ts
8197
+ init_fetchData();
8198
+
8199
+ // src/tools/searchKnowledge.ts
8200
+ init_cjs_shims();
8201
+ var import_zod26 = require("zod");
8202
+ init_contract();
8203
+
8204
+ // src/knowledge/scope.ts
8205
+ init_cjs_shims();
8206
+ var SAFE_PATH_RE = /^[a-zA-Z0-9_\-./]+$/;
8207
+ function parseFolderRef(raw) {
8208
+ if (typeof raw !== "string" || raw.length === 0) {
8209
+ throw new Error(`invalid knowledge folder ref: empty`);
8210
+ }
8211
+ if (raw.startsWith("/")) {
8212
+ throw new Error(`invalid knowledge folder ref: absolute paths not allowed ("${raw}")`);
8213
+ }
8214
+ const trimmed = raw.replace(/\/+$/g, "");
8215
+ if (trimmed.length === 0) {
8216
+ throw new Error(`invalid knowledge folder ref: "${raw}"`);
8217
+ }
8218
+ if (!SAFE_PATH_RE.test(trimmed)) {
8219
+ throw new Error(`invalid knowledge folder ref: unsafe characters in "${raw}"`);
8220
+ }
8221
+ if (trimmed.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
8222
+ throw new Error(`invalid knowledge folder ref: traversal in "${raw}"`);
8223
+ }
8224
+ const segs = trimmed.split("/");
8225
+ const base = segs[0];
8226
+ const subPath = segs.slice(1).join("/");
8227
+ return { path: trimmed, base, subPath };
8228
+ }
8229
+ function relPathInScope(folder, relPath) {
8230
+ if (folder.subPath === "") return true;
8231
+ return relPath === folder.subPath || relPath.startsWith(`${folder.subPath}/`);
8232
+ }
8233
+ function parseKnowledgeRef(raw) {
8234
+ if (typeof raw !== "string" || raw.length === 0) {
8235
+ throw new Error("invalid knowledge ref: empty");
8236
+ }
8237
+ if (raw.startsWith("ext:")) {
8238
+ const name = raw.slice("ext:".length);
8239
+ if (!/^[a-zA-Z0-9_-]+$/.test(name) || name.length === 0) {
8240
+ throw new Error(`invalid knowledge ref: external name "${name}" has unsafe characters`);
8241
+ }
8242
+ return { kind: "ext", target: name };
8243
+ }
8244
+ if (raw.startsWith("/")) {
8245
+ throw new Error(`invalid knowledge ref: absolute paths not allowed ("${raw}")`);
8246
+ }
8247
+ const hashAt = raw.indexOf("#");
8248
+ const filePath = hashAt === -1 ? raw : raw.slice(0, hashAt);
8249
+ const section = hashAt === -1 ? void 0 : raw.slice(hashAt + 1);
8250
+ if (!SAFE_PATH_RE.test(filePath)) {
8251
+ throw new Error(`invalid knowledge ref: unsafe characters in "${filePath}"`);
8252
+ }
8253
+ if (filePath.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
8254
+ throw new Error(`invalid knowledge ref: traversal in "${filePath}"`);
8255
+ }
8256
+ if (section !== void 0) {
8257
+ if (section.length > 0 && !/^[a-zA-Z0-9_-]+$/.test(section)) {
8258
+ throw new Error(`invalid knowledge ref: unsafe characters in section "${section}"`);
8259
+ }
8260
+ return { kind: "section", target: filePath, section };
8261
+ }
8262
+ return { kind: "file", target: filePath };
8263
+ }
8264
+ function refInScope(folders, filePath) {
8265
+ return folders.some((f) => {
8266
+ if (filePath === f.base || filePath.startsWith(`${f.base}/`)) {
8267
+ const relInBase = filePath === f.base ? "" : filePath.slice(f.base.length + 1);
8268
+ return relPathInScope(f, relInBase);
8269
+ }
8270
+ return false;
8271
+ });
8272
+ }
8273
+
8274
+ // src/knowledge/tokenize.ts
8275
+ init_cjs_shims();
8276
+ var STOP_WORDS = /* @__PURE__ */ new Set([
8277
+ "the",
8278
+ "and",
8279
+ "of",
8280
+ "to",
8281
+ "a",
8282
+ "in",
8283
+ "is",
8284
+ "it",
8285
+ "you",
8286
+ "that",
8287
+ "was",
8288
+ "for",
8289
+ "on",
8290
+ "are",
8291
+ "with",
8292
+ "as",
8293
+ "this",
8294
+ "by",
8295
+ "from",
8296
+ "or",
8297
+ "but",
8298
+ "not",
8299
+ "all",
8300
+ "an",
8301
+ "has",
8302
+ "have",
8303
+ "had",
8304
+ "will",
8305
+ "can",
8306
+ "do",
8307
+ "did",
8308
+ "be",
8309
+ "been",
8310
+ "being",
8311
+ "your",
8312
+ "our",
8313
+ "their",
8314
+ "his",
8315
+ "her",
8316
+ "my",
8317
+ "we",
8318
+ "they",
8319
+ "them",
8320
+ "than",
8321
+ "so",
8322
+ "if",
8323
+ "at",
8324
+ "no",
8325
+ "yes",
8326
+ "me",
8327
+ "us",
8328
+ "i",
8329
+ "he",
8330
+ "she"
8331
+ ]);
8332
+ function tokenize(text2) {
8333
+ if (typeof text2 !== "string" || text2.length === 0) return [];
8334
+ const seen = /* @__PURE__ */ new Set();
8335
+ for (const raw of text2.toLowerCase().split(/[\W_]+/)) {
8336
+ if (raw.length < 2) continue;
8337
+ if (STOP_WORDS.has(raw)) continue;
8338
+ seen.add(raw);
8339
+ }
8340
+ return [...seen].sort();
8341
+ }
8342
+ function scoreOverlap(sectionWords, queryTokens) {
8343
+ const set = sectionWords instanceof Set ? sectionWords : new Set(sectionWords);
8344
+ let n = 0;
8345
+ for (const t of queryTokens) if (set.has(t)) n++;
8346
+ return n;
8347
+ }
8348
+
8349
+ // src/tools/searchKnowledge.ts
8350
+ var DEFAULT_MAX_RESULTS = 5;
8351
+ var inputSchema18 = import_zod26.z.object({
8352
+ query: import_zod26.z.string().min(1),
8353
+ maxResults: import_zod26.z.number().int().positive().optional()
8354
+ });
8355
+ function createSearchKnowledgeTool(opts) {
8356
+ const scoped = opts.folders.map(parseFolderRef);
8357
+ const indexCache = /* @__PURE__ */ new Map();
8358
+ const cap = opts.maxSearchResults ?? DEFAULT_MAX_RESULTS;
8359
+ const externals = opts.external;
8360
+ return defineTool({
8361
+ name: "SearchKnowledge",
8362
+ description: "Search the agent's knowledge base. Returns up to K ranked snippets matching the query (across all configured knowledge folders + any attached external file links). Each result carries a `ref` you can pass back to the `ReadKnowledge` tool to load the full content of that section or file.",
8363
+ inputSchema: inputSchema18,
8364
+ execute: async ({ query, maxResults }) => {
8365
+ const limit = Math.min(maxResults ?? cap, cap);
8366
+ const queryTokens = tokenize(query);
8367
+ if (queryTokens.length === 0) {
8368
+ return { content: "no searchable tokens in query", isError: false };
8369
+ }
8370
+ const sectionHits = [];
8371
+ const seenBases = /* @__PURE__ */ new Set();
8372
+ for (const folder of scoped) {
8373
+ if (!seenBases.has(folder.base)) {
8374
+ seenBases.add(folder.base);
8375
+ }
8376
+ }
8377
+ for (const baseName of seenBases) {
8378
+ const idx = await loadIndex(opts.adapter, baseName, indexCache);
8379
+ if (idx === null) continue;
8380
+ for (const section of idx.sections) {
8381
+ const eligible = scoped.some(
8382
+ (f) => f.base === baseName && relPathInScope(f, section.relPath)
8383
+ );
8384
+ if (!eligible) continue;
8385
+ const score = scoreOverlap(section.words, queryTokens);
8386
+ if (score > 0) sectionHits.push({ section, base: baseName, score });
8387
+ }
8388
+ }
8389
+ const externalHits = [];
8390
+ for (const link of externals) {
8391
+ const score = scoreOverlap(tokenize(link.description), queryTokens);
8392
+ if (score > 0) externalHits.push({ link, score });
8393
+ }
8394
+ const all = [
8395
+ ...sectionHits.map((h) => ({
8396
+ kind: "knowledge",
8397
+ score: h.score,
8398
+ render: () => `[knowledge] ${h.base}/${h.section.relPath} \xA7"${h.section.heading || "(lead-in)"}"
8399
+ ${truncatePreview(h.section.preview)}
8400
+ ref: ${h.base}/${h.section.slug}`
8401
+ })),
8402
+ ...externalHits.map((h) => ({
8403
+ kind: "external",
8404
+ score: h.score,
8405
+ render: () => `[external] ${h.link.name} (${h.link.format})
8406
+ ${h.link.description}
8407
+ ref: ext:${h.link.name}`
8408
+ }))
8409
+ ];
8410
+ if (all.length === 0) {
8411
+ return { content: `no knowledge matches for "${query}"`, isError: false };
8412
+ }
8413
+ all.sort((a, b) => b.score - a.score);
8414
+ const top = all.slice(0, limit);
8415
+ const body = top.map((h, i) => `${i + 1}. ${h.render()}`).join("\n\n");
8416
+ return {
8417
+ content: `Found ${top.length} knowledge match${top.length === 1 ? "" : "es"} (of ${all.length} ranked):
8418
+
8419
+ ${body}`,
8420
+ isError: false,
8421
+ metadata: { hits: all.length, returned: top.length }
8422
+ };
8423
+ }
8424
+ });
8425
+ }
8426
+ function truncatePreview(s) {
8427
+ if (s.length <= 200) return s;
8428
+ return s.slice(0, 200) + "\u2026";
8429
+ }
8430
+ async function loadIndex(adapter, base, cache) {
8431
+ const cached2 = cache.get(base);
8432
+ if (cached2 !== void 0) return cached2;
8433
+ let raw;
8434
+ try {
8435
+ raw = await adapter.readFile(`${base}/_index.json`);
8436
+ } catch {
8437
+ return null;
8438
+ }
8439
+ if (raw === null) return null;
8440
+ try {
8441
+ const parsed = JSON.parse(raw);
8442
+ cache.set(base, parsed);
8443
+ return parsed;
8444
+ } catch {
8445
+ return null;
8446
+ }
8447
+ }
8448
+
8449
+ // src/tools/readKnowledge.ts
8450
+ init_cjs_shims();
8451
+ var import_zod27 = require("zod");
8452
+ init_contract();
8453
+
8454
+ // src/knowledge/extractors.ts
8455
+ init_cjs_shims();
8456
+ var CSV_MAX_ROWS = 100;
8457
+ var HTML_TAG_RE = /<[^>]+>/g;
8458
+ var HTML_ENTITIES = {
8459
+ "&amp;": "&",
8460
+ "&lt;": "<",
8461
+ "&gt;": ">",
8462
+ "&quot;": '"',
8463
+ "&#39;": "'",
8464
+ "&nbsp;": " "
8465
+ };
8466
+ function decodeHtmlEntities(s) {
8467
+ return s.replace(/&(amp|lt|gt|quot|#39|nbsp);/g, (m) => HTML_ENTITIES[m] ?? m);
8468
+ }
8469
+ var text = {
8470
+ format: "txt",
8471
+ requiresNode: false,
8472
+ extract: async (raw) => raw
8473
+ };
8474
+ var md = {
8475
+ format: "md",
8476
+ requiresNode: false,
8477
+ extract: async (raw) => raw
8478
+ };
8479
+ var json = {
8480
+ format: "json",
8481
+ requiresNode: false,
8482
+ extract: async (raw) => {
8483
+ try {
8484
+ return JSON.stringify(JSON.parse(raw), null, 2);
8485
+ } catch {
8486
+ return raw;
8487
+ }
8488
+ }
8489
+ };
8490
+ var csv = {
8491
+ format: "csv",
8492
+ requiresNode: false,
8493
+ extract: async (raw) => {
8494
+ const lines = raw.split(/\r?\n/).filter((l) => l.length > 0);
8495
+ if (lines.length === 0) return "";
8496
+ if (lines.length <= CSV_MAX_ROWS + 1) return lines.join("\n");
8497
+ const head = lines.slice(0, CSV_MAX_ROWS + 1);
8498
+ const remaining = lines.length - head.length;
8499
+ return `${head.join("\n")}
8500
+ \u2026[${remaining.toLocaleString()} more row${remaining === 1 ? "" : "s"} truncated]`;
8501
+ }
8502
+ };
8503
+ var html = {
8504
+ format: "html",
8505
+ requiresNode: false,
8506
+ extract: async (raw) => {
8507
+ const stripped = raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(HTML_TAG_RE, " ");
8508
+ return decodeHtmlEntities(stripped).replace(/\s+/g, " ").trim();
8509
+ }
8510
+ };
8511
+ var pdf = {
8512
+ format: "pdf",
8513
+ requiresNode: true,
8514
+ extract: async (raw) => {
8515
+ let pdfParse;
8516
+ try {
8517
+ const mod = await import("pdf-parse");
8518
+ pdfParse = mod.default ?? mod;
8519
+ } catch {
8520
+ throw new Error(
8521
+ "ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: pdf-parse is not installed. Run `npm install pdf-parse` to enable PDF extraction."
8522
+ );
8523
+ }
8524
+ const buf = Buffer.from(raw, "binary");
8525
+ const result = await pdfParse(buf);
8526
+ return result.text;
8527
+ }
8528
+ };
8529
+ var docx = {
8530
+ format: "docx",
8531
+ requiresNode: true,
8532
+ extract: async (raw) => {
8533
+ let mammoth;
8534
+ try {
8535
+ mammoth = await import("mammoth");
8536
+ } catch {
8537
+ throw new Error(
8538
+ "ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: mammoth is not installed. Run `npm install mammoth` to enable DOCX extraction."
8539
+ );
8540
+ }
8541
+ const buf = Buffer.from(raw, "binary");
8542
+ const result = await mammoth.extractRawText({ buffer: buf });
8543
+ return result.value;
8544
+ }
8545
+ };
8546
+ var EXTRACTORS = {
8547
+ md,
8548
+ txt: text,
8549
+ json,
8550
+ csv,
8551
+ html,
8552
+ pdf,
8553
+ docx
8554
+ };
8555
+ function getExtractor(format) {
8556
+ const e = EXTRACTORS[format];
8557
+ if (e === void 0) throw new Error(`ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: ${format}`);
8558
+ return e;
8559
+ }
8560
+
8561
+ // src/tools/readKnowledge.ts
8562
+ var DEFAULT_MAX_READ_BYTES = 1e4;
8563
+ var inputSchema19 = import_zod27.z.object({
8564
+ ref: import_zod27.z.string().min(1)
8565
+ });
8566
+ function createReadKnowledgeTool(opts) {
8567
+ const scoped = opts.folders.map(parseFolderRef);
8568
+ const indexCache = /* @__PURE__ */ new Map();
8569
+ const fileCache = /* @__PURE__ */ new Map();
8570
+ const cap = opts.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;
8571
+ const externalsByName = new Map(opts.external.map((e) => [e.name, e]));
8572
+ const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
8573
+ return defineTool({
8574
+ name: "ReadKnowledge",
8575
+ description: "Load the full content of a knowledge ref returned by SearchKnowledge. Use the `ref` value verbatim from the search results \u2014 section refs return one section, file refs return the whole file (with format-specific extraction for non-markdown formats), and `ext:{name}` refs fetch a pre-registered external file.",
8576
+ inputSchema: inputSchema19,
8577
+ execute: async ({ ref }) => {
8578
+ let parsed;
8579
+ try {
8580
+ parsed = parseKnowledgeRef(ref);
8581
+ } catch (err) {
8582
+ return {
8583
+ content: `ERR_KNOWLEDGE_REF_INVALID: ${err instanceof Error ? err.message : String(err)}`,
8584
+ isError: true
8585
+ };
8586
+ }
8587
+ if (parsed.kind === "ext") {
8588
+ return readExternal(parsed.target, externalsByName, fetchFn, cap);
8589
+ }
8590
+ if (!refInScope(scoped, parsed.target)) {
8591
+ return {
8592
+ content: `ERR_KNOWLEDGE_FOLDER_NOT_ALLOWED: ref "${parsed.target}" is outside the run's allowed folders`,
8593
+ isError: true
8594
+ };
8595
+ }
8596
+ const base = parsed.target.split("/")[0];
8597
+ const relPath = parsed.target.slice(base.length + 1);
8598
+ if (parsed.kind === "section") {
8599
+ const idx = await loadIndex2(opts.adapter, base, indexCache);
8600
+ if (idx === null) {
8601
+ return {
8602
+ content: `ERR_KNOWLEDGE_INDEX_MISSING: no _index.json for base "${base}"`,
8603
+ isError: true
8604
+ };
8605
+ }
8606
+ const sectionSlug = parsed.section ?? "";
8607
+ const section = idx.sections.find(
8608
+ (s) => s.relPath === relPath && extractAnchor(s.slug) === sectionSlug
8609
+ );
8610
+ if (section === void 0) {
8611
+ return {
8612
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: section ${parsed.target}#${sectionSlug} not in index for "${base}"`,
8613
+ isError: true
8614
+ };
8615
+ }
8616
+ const fullContent = await readFile(opts.adapter, parsed.target, fileCache);
8617
+ if (fullContent === null) {
8618
+ return {
8619
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: file ${parsed.target} not found in storage`,
8620
+ isError: true
8621
+ };
8622
+ }
8623
+ const sliced = sliceLines(fullContent, section.startLine, section.endLine);
8624
+ return wrapResult(`[knowledge] ${parsed.target}#${sectionSlug}`, sliced, cap);
8625
+ }
8626
+ const fmt = inferFormat(parsed.target);
8627
+ if (fmt === null) {
8628
+ return {
8629
+ content: `ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: cannot infer format for "${parsed.target}"`,
8630
+ isError: true
8631
+ };
8632
+ }
8633
+ const raw = await readFile(opts.adapter, parsed.target, fileCache);
8634
+ if (raw === null) {
8635
+ return {
8636
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: file ${parsed.target} not found in storage`,
8637
+ isError: true
8638
+ };
8639
+ }
8640
+ let extracted;
8641
+ try {
8642
+ extracted = await getExtractor(fmt).extract(raw);
8643
+ } catch (err) {
8644
+ return {
8645
+ content: `ERR_KNOWLEDGE_EXTRACTOR_FAILED: ${err instanceof Error ? err.message : String(err)}`,
8646
+ isError: true
8647
+ };
8648
+ }
8649
+ return wrapResult(`[knowledge] ${parsed.target} (${fmt})`, extracted, cap);
8650
+ }
8651
+ });
8652
+ }
8653
+ async function readExternal(name, registry, fetchFn, cap) {
8654
+ const link = registry.get(name);
8655
+ if (link === void 0) {
8656
+ return {
8657
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: no external link named "${name}"`,
8658
+ isError: true
8659
+ };
8660
+ }
8661
+ let res;
8662
+ try {
8663
+ res = await fetchFn(link.url, {
8664
+ headers: link.headers ?? {}
8665
+ });
8666
+ } catch (err) {
8667
+ const msg = err instanceof Error ? err.message : String(err);
8668
+ return {
8669
+ content: `ERR_KNOWLEDGE_NETWORK: ${msg.slice(0, 200)}`,
8670
+ isError: true
8671
+ };
8672
+ }
8673
+ if (!res.ok) {
8674
+ return {
8675
+ content: `ERR_KNOWLEDGE_NETWORK: HTTP ${res.status} fetching ext:${name}`,
8676
+ isError: true
8677
+ };
8678
+ }
8679
+ const raw = await res.text();
8680
+ let extracted;
8681
+ try {
8682
+ extracted = await getExtractor(link.format).extract(raw);
8683
+ } catch (err) {
8684
+ return {
8685
+ content: `ERR_KNOWLEDGE_EXTRACTOR_FAILED: ${err instanceof Error ? err.message : String(err)}`,
8686
+ isError: true
8687
+ };
8688
+ }
8689
+ return wrapResult(`[external] ${name} (${link.format})`, extracted, cap);
8690
+ }
8691
+ function wrapResult(header, body, cap) {
8692
+ let payload = body;
8693
+ if (body.length > cap) {
8694
+ payload = body.slice(0, cap) + `
8695
+ \u2026[+${body.length - cap} more chars truncated]`;
8696
+ }
8697
+ return {
8698
+ content: `${header}
8699
+
8700
+ ${payload}`,
8701
+ isError: false,
8702
+ metadata: { bytes: body.length }
8703
+ };
8704
+ }
8705
+ async function loadIndex2(adapter, base, cache) {
8706
+ const cached2 = cache.get(base);
8707
+ if (cached2 !== void 0) return cached2;
8708
+ let raw;
8709
+ try {
8710
+ raw = await adapter.readFile(`${base}/_index.json`);
8711
+ } catch {
8712
+ return null;
8713
+ }
8714
+ if (raw === null) return null;
8715
+ try {
8716
+ const idx = JSON.parse(raw);
8717
+ cache.set(base, idx);
8718
+ return idx;
8719
+ } catch {
8720
+ return null;
8721
+ }
8722
+ }
8723
+ async function readFile(adapter, path, cache) {
8724
+ const cached2 = cache.get(path);
8725
+ if (cached2 !== void 0) return cached2;
8726
+ const content = await adapter.readFile(path).catch(() => null);
8727
+ if (content === null) return null;
8728
+ cache.set(path, content);
8729
+ return content;
8730
+ }
8731
+ function sliceLines(content, start, end) {
8732
+ const lines = content.split(/\r?\n/);
8733
+ return lines.slice(start - 1, end).join("\n");
8734
+ }
8735
+ function extractAnchor(slug) {
8736
+ const i = slug.indexOf("#");
8737
+ return i === -1 ? "" : slug.slice(i + 1);
8738
+ }
8739
+ function inferFormat(filePath) {
8740
+ const ext = (filePath.split(".").pop() ?? "").toLowerCase();
8741
+ switch (ext) {
8742
+ case "md":
8743
+ case "markdown":
8744
+ return "md";
8745
+ case "txt":
8746
+ return "txt";
8747
+ case "json":
8748
+ return "json";
8749
+ case "csv":
8750
+ return "csv";
8751
+ case "html":
8752
+ case "htm":
8753
+ return "html";
8754
+ case "pdf":
8755
+ return "pdf";
8756
+ case "docx":
8757
+ return "docx";
8758
+ }
8759
+ return null;
8760
+ }
8761
+
7879
8762
  // src/skills/storageSkillSource.ts
7880
8763
  init_cjs_shims();
7881
8764
  var SAFE_NAME4 = /^[a-zA-Z0-9_-]+$/;
@@ -8015,9 +8898,9 @@ var InlineSkillSource = class {
8015
8898
  `InlineSkillSource: fetch ${url} \u2192 HTTP ${String(response.status)} ${response.statusText}`
8016
8899
  );
8017
8900
  }
8018
- const text = await response.text();
8019
- this.cache.set(cacheKey, text);
8020
- return text;
8901
+ const text2 = await response.text();
8902
+ this.cache.set(cacheKey, text2);
8903
+ return text2;
8021
8904
  }
8022
8905
  assertUrlAllowed(url) {
8023
8906
  const hosts = this.allowedHosts;
@@ -8489,47 +9372,60 @@ var R2BindingStorageAdapter = class {
8489
9372
  // src/storage/factory.ts
8490
9373
  var ENGINE_DATA_FOLDER = ".claude";
8491
9374
  var WORKSPACES_FOLDER = "workspaces";
8492
- async function createEngineStorage(config) {
9375
+ var KNOWLEDGE_FOLDER = "knowledge";
9376
+ async function createEngineStorage(config, options = {}) {
8493
9377
  switch (config.provider) {
8494
9378
  case "local":
8495
- return createLocalStorage(config);
9379
+ return createLocalStorage(config, options);
8496
9380
  case "r2":
8497
- return createR2Storage(config);
9381
+ return createR2Storage(config, options);
8498
9382
  case "r2-binding":
8499
- return createR2BindingStorage(config);
9383
+ return createR2BindingStorage(config, options);
8500
9384
  }
8501
9385
  }
8502
- async function createLocalStorage(config) {
9386
+ async function createLocalStorage(config, options) {
8503
9387
  const path = await import("path");
8504
- const workspaceRoot = path.join(
8505
- config.rootPath,
8506
- WORKSPACES_FOLDER,
8507
- config.workspaceId,
8508
- ENGINE_DATA_FOLDER
8509
- );
8510
- return {
8511
- workspace: new LocalStorageAdapter(workspaceRoot)
8512
- };
9388
+ const tenantRoot = path.join(config.rootPath, WORKSPACES_FOLDER, config.workspaceId);
9389
+ const workspaceRoot = path.join(tenantRoot, ENGINE_DATA_FOLDER);
9390
+ const out = { workspace: new LocalStorageAdapter(workspaceRoot) };
9391
+ if (options.withKnowledge) {
9392
+ const knowledgeRoot = path.join(tenantRoot, KNOWLEDGE_FOLDER);
9393
+ return { ...out, knowledge: new LocalStorageAdapter(knowledgeRoot) };
9394
+ }
9395
+ return out;
8513
9396
  }
8514
- function createR2Storage(config) {
9397
+ function createR2Storage(config, options) {
8515
9398
  if (!config.r2) {
8516
9399
  throw new StorageError('storage.r2 is required when storage.provider === "r2"');
8517
9400
  }
8518
9401
  const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
8519
- const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
8520
- return {
8521
- workspace: new R2StorageAdapter(config.r2, workspacePrefix)
8522
- };
9402
+ const tenantPrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}`;
9403
+ const workspacePrefix = `${tenantPrefix}/${ENGINE_DATA_FOLDER}`;
9404
+ const out = { workspace: new R2StorageAdapter(config.r2, workspacePrefix) };
9405
+ if (options.withKnowledge) {
9406
+ const knowledgePrefix = `${tenantPrefix}/${KNOWLEDGE_FOLDER}`;
9407
+ return { ...out, knowledge: new R2StorageAdapter(config.r2, knowledgePrefix) };
9408
+ }
9409
+ return out;
8523
9410
  }
8524
- function createR2BindingStorage(config) {
9411
+ function createR2BindingStorage(config, options) {
8525
9412
  if (!config.r2Binding) {
8526
9413
  throw new StorageError('storage.r2Binding is required when storage.provider === "r2-binding"');
8527
9414
  }
8528
9415
  const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
8529
- const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
8530
- return {
9416
+ const tenantPrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}`;
9417
+ const workspacePrefix = `${tenantPrefix}/${ENGINE_DATA_FOLDER}`;
9418
+ const out = {
8531
9419
  workspace: new R2BindingStorageAdapter(config.r2Binding, workspacePrefix)
8532
9420
  };
9421
+ if (options.withKnowledge) {
9422
+ const knowledgePrefix = `${tenantPrefix}/${KNOWLEDGE_FOLDER}`;
9423
+ return {
9424
+ ...out,
9425
+ knowledge: new R2BindingStorageAdapter(config.r2Binding, knowledgePrefix)
9426
+ };
9427
+ }
9428
+ return out;
8533
9429
  }
8534
9430
 
8535
9431
  // src/transcript/reader.ts
@@ -9033,6 +9929,8 @@ var Engine = class {
9033
9929
  const skillSource = this.resolveSkillSource(options.skills, storage);
9034
9930
  const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
9035
9931
  const apiConfig = this.resolveApiConfig(options.api);
9932
+ const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
9933
+ const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
9036
9934
  let systemPrompt = await buildSystemPrompt({
9037
9935
  ...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
9038
9936
  memory,
@@ -9065,6 +9963,8 @@ var Engine = class {
9065
9963
  ...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
9066
9964
  ...skillSource !== void 0 ? { skillSource } : {},
9067
9965
  ...apiConfig !== void 0 ? { apiConfig } : {},
9966
+ ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
9967
+ ...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
9068
9968
  ...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
9069
9969
  });
9070
9970
  const writer = new TranscriptWriter({
@@ -9120,7 +10020,8 @@ var Engine = class {
9120
10020
  ...options.tokenBudget !== void 0 ? { tokenBudget: options.tokenBudget } : {},
9121
10021
  ...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
9122
10022
  ...gate !== void 0 ? { gateBeforeTool: gate } : {},
9123
- ..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
10023
+ ..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {},
10024
+ ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {}
9124
10025
  });
9125
10026
  const result = await this.finalizeResult(loopResult, writer, logPath, {
9126
10027
  ...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
@@ -9175,6 +10076,8 @@ var Engine = class {
9175
10076
  const skillSource = this.resolveSkillSource(options.skills, storage);
9176
10077
  const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
9177
10078
  const apiConfig = this.resolveApiConfig(options.api);
10079
+ const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
10080
+ const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
9178
10081
  let systemPrompt = await buildSystemPrompt({
9179
10082
  ...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
9180
10083
  memory,
@@ -9207,6 +10110,8 @@ var Engine = class {
9207
10110
  ...this.config.hooks.propagateGateToSubagents === true && gate !== void 0 ? { subagentGate: gate } : {},
9208
10111
  ...skillSource !== void 0 ? { skillSource } : {},
9209
10112
  ...apiConfig !== void 0 ? { apiConfig } : {},
10113
+ ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
10114
+ ...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
9210
10115
  ...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
9211
10116
  });
9212
10117
  const priorState = await loadWriterState(storage.workspace, logPath);
@@ -9297,7 +10202,8 @@ ${inputJson}
9297
10202
  onProgress: this.buildHeartbeat(storage, snapshot.runId, snapshot.nodeId),
9298
10203
  ...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
9299
10204
  ...gate !== void 0 ? { gateBeforeTool: gate } : {},
9300
- ..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {}
10205
+ ..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {},
10206
+ ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {}
9301
10207
  });
9302
10208
  const result = await this.finalizeResult(loopResult, writer, logPath, {
9303
10209
  ...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
@@ -9843,6 +10749,19 @@ ${inputJson}
9843
10749
  names.add("ApiCall");
9844
10750
  }
9845
10751
  }
10752
+ if (this.config.compaction.toolResultOffload?.enabled === true) {
10753
+ if (!disabled.has("FetchData") && (wantAll || enabled.has("FetchData"))) {
10754
+ names.add("FetchData");
10755
+ }
10756
+ }
10757
+ if (this.config.knowledge?.enabled === true) {
10758
+ if (!disabled.has("SearchKnowledge") && (wantAll || enabled.has("SearchKnowledge"))) {
10759
+ names.add("SearchKnowledge");
10760
+ }
10761
+ if (!disabled.has("ReadKnowledge") && (wantAll || enabled.has("ReadKnowledge"))) {
10762
+ names.add("ReadKnowledge");
10763
+ }
10764
+ }
9846
10765
  for (const tool of this.config.tools.custom) {
9847
10766
  names.add(tool.name);
9848
10767
  }
@@ -9944,7 +10863,7 @@ ${inputJson}
9944
10863
  await writer.setStatus("done");
9945
10864
  let data;
9946
10865
  if (jsonOptions?.outputFormat === "json") {
9947
- const parsed = tryParseJSON(loopResult.output);
10866
+ const parsed = tryParseJSON2(loopResult.output);
9948
10867
  if (parsed.ok) {
9949
10868
  if (jsonOptions.outputSchema) {
9950
10869
  const validated = validateOutput(parsed.value, jsonOptions.outputSchema);
@@ -10009,6 +10928,61 @@ ${inputJson}
10009
10928
  * tool isn't registered at all. Env + resolveAuth + hooks flow
10010
10929
  * through untouched — they never hit the Zod schema.
10011
10930
  */
10931
+ /**
10932
+ * Plan 021 — resolve the effective tool-result offload config.
10933
+ *
10934
+ * Precedence (each field independently):
10935
+ * RunOptions.compaction.toolResultOffload.X >
10936
+ * config.compaction.toolResultOffload.X
10937
+ *
10938
+ * When neither side enables offload, returns undefined and no
10939
+ * `FetchData` tool is registered.
10940
+ */
10941
+ resolveOffloadConfig(override) {
10942
+ const base = this.config.compaction.toolResultOffload;
10943
+ if (override === void 0 && base === void 0) return void 0;
10944
+ const enabled = override?.enabled ?? base?.enabled ?? false;
10945
+ if (!enabled) return void 0;
10946
+ const thresholdBytes = override?.thresholdBytes ?? base?.thresholdBytes ?? 2048;
10947
+ const maxPreviewChars = override?.maxPreviewChars ?? base?.maxPreviewChars ?? 500;
10948
+ const summarizer = override?.summarizer ?? base?.summarizer;
10949
+ return {
10950
+ enabled: true,
10951
+ thresholdBytes,
10952
+ maxPreviewChars,
10953
+ ...summarizer !== void 0 ? { summarizer } : {}
10954
+ };
10955
+ }
10956
+ /**
10957
+ * Plan 023 — resolve the effective runtime knowledge bundle for a
10958
+ * single run.
10959
+ *
10960
+ * Engine-level config (`config.knowledge`) carries the capability
10961
+ * flag + scalar caps. The actual folders + external links are
10962
+ * RUNTIME-only, supplied via `RunOptions.knowledge`. Returning
10963
+ * `undefined` means "don't register the knowledge tools" — callers
10964
+ * skip the bundle entirely.
10965
+ *
10966
+ * Three gates must all pass:
10967
+ * 1. `config.knowledge.enabled === true` (engine opt-in)
10968
+ * 2. `storage.knowledge !== undefined` (adapter was built)
10969
+ * 3. There IS something to look at — at least one folder OR
10970
+ * one external link supplied for this run.
10971
+ */
10972
+ resolveKnowledgeRuntime(override, storage) {
10973
+ if (this.config.knowledge?.enabled !== true) return void 0;
10974
+ if (storage.knowledge === void 0) return void 0;
10975
+ const folders = override?.folders ?? [];
10976
+ const external = override?.external ?? [];
10977
+ if (folders.length === 0 && external.length === 0) return void 0;
10978
+ return {
10979
+ adapter: storage.knowledge,
10980
+ folders,
10981
+ external,
10982
+ maxSearchResults: this.config.knowledge.maxSearchResults,
10983
+ maxReadBytes: this.config.knowledge.maxReadBytes
10984
+ };
10985
+ }
10012
10986
  resolveApiConfig(override) {
10013
10987
  const base = this.config.api;
10014
10988
  if (override === void 0 && base === void 0) return void 0;
@@ -10071,7 +11045,9 @@ ${inputJson}
10071
11045
  if (this.internals.buildStorage !== void 0) {
10072
11046
  return this.internals.buildStorage();
10073
11047
  }
10074
- return createEngineStorage(this.config.storage);
11048
+ return createEngineStorage(this.config.storage, {
11049
+ withKnowledge: this.config.knowledge?.enabled === true
11050
+ });
10075
11051
  }
10076
11052
  buildClient() {
10077
11053
  return createModelAdapter(this.config.model, {
@@ -10183,6 +11159,39 @@ function buildToolRegistry(options) {
10183
11159
  childRegistry.register(apiTool);
10184
11160
  }
10185
11161
  }
11162
+ if (options.toolResultOffload?.enabled === true) {
11163
+ if (!disabled.has("FetchData") && (wantAll || enabled.has("FetchData"))) {
11164
+ const fetchDataTool = createFetchDataTool({
11165
+ storage: storage.workspace,
11166
+ logPath: options.parentLogPath
11167
+ });
11168
+ registry.register(fetchDataTool);
11169
+ }
11170
+ }
11171
+ if (options.knowledge !== void 0) {
11172
+ const k = options.knowledge;
11173
+ if (!disabled.has("SearchKnowledge") && (wantAll || enabled.has("SearchKnowledge"))) {
11174
+ const searchTool = createSearchKnowledgeTool({
11175
+ adapter: k.adapter,
11176
+ folders: k.folders,
11177
+ external: k.external,
11178
+ maxSearchResults: k.maxSearchResults
11179
+ });
11180
+ registry.register(searchTool);
11181
+ childRegistry.register(searchTool);
11182
+ }
11183
+ if (!disabled.has("ReadKnowledge") && (wantAll || enabled.has("ReadKnowledge"))) {
11184
+ const readTool = createReadKnowledgeTool({
11185
+ adapter: k.adapter,
11186
+ folders: k.folders,
11187
+ external: k.external,
11188
+ maxReadBytes: k.maxReadBytes,
11189
+ ...options.fetch !== void 0 ? { fetch: options.fetch } : {}
11190
+ });
11191
+ registry.register(readTool);
11192
+ childRegistry.register(readTool);
11193
+ }
11194
+ }
10186
11195
  const agentTool = createAgentTool({
10187
11196
  storage: storage.workspace,
10188
11197
  client,
@@ -10198,7 +11207,8 @@ function buildToolRegistry(options) {
10198
11207
  idleFlushMs: config.transcript.idleFlushMs,
10199
11208
  agents,
10200
11209
  coordinatorMode: isCoordinatorMode(config),
10201
- ...subagentGate !== void 0 ? { gateBeforeTool: subagentGate } : {}
11210
+ ...subagentGate !== void 0 ? { gateBeforeTool: subagentGate } : {},
11211
+ ...options.toolResultOffload !== void 0 ? { toolResultOffload: options.toolResultOffload } : {}
10202
11212
  });
10203
11213
  if (!disabled.has("Agent") && (wantAll || enabled.has("Agent"))) {
10204
11214
  registry.register(agentTool);
@@ -10226,6 +11236,155 @@ function buildToolRegistry(options) {
10226
11236
  return registry;
10227
11237
  }
10228
11238
 
11239
+ // src/index.ts
11240
+ init_contract();
11241
+ init_fetchData();
11242
+
11243
+ // src/knowledge/indexer.ts
11244
+ init_cjs_shims();
11245
+ var HEADING_RE = /^(#{1,6})[ \t]+(.+?)\s*$/;
11246
+ var WIKI_LINK_RE = /\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g;
11247
+ var FORMAT_BY_EXT = {
11248
+ md: "md",
11249
+ markdown: "md",
11250
+ txt: "txt",
11251
+ json: "json",
11252
+ csv: "csv",
11253
+ html: "html",
11254
+ htm: "html",
11255
+ pdf: "pdf",
11256
+ docx: "docx"
11257
+ };
11258
+ var PREVIEW_CHARS = 200;
11259
+ async function buildKnowledgeIndex(options) {
11260
+ const { adapter, base } = options;
11261
+ const safeBase = base.replace(/^\/+|\/+$/g, "");
11262
+ if (safeBase.length === 0 || safeBase.includes("..")) {
11263
+ throw new Error(`buildKnowledgeIndex: invalid base "${base}"`);
11264
+ }
11265
+ const files = await listFilesRecursive(adapter, safeBase);
11266
+ const sections = [];
11267
+ const filesMeta = {};
11268
+ for (const fileRel of files) {
11269
+ if (fileRel === "_index.json") continue;
11270
+ const fullPath = `${safeBase}/${fileRel}`;
11271
+ const ext = (fileRel.split(".").pop() ?? "").toLowerCase();
11272
+ const format = FORMAT_BY_EXT[ext];
11273
+ if (format === void 0) continue;
11274
+ const raw = await adapter.readFile(fullPath);
11275
+ if (raw === null) continue;
11276
+ const sizeBytes = byteLength3(raw);
11277
+ const meta = { format, size: sizeBytes };
11278
+ if (format === "md" || format === "txt") {
11279
+ const fileSections = splitSections(raw, fileRel);
11280
+ sections.push(...fileSections);
11281
+ const wikiLinks = extractWikiLinks(raw);
11282
+ if (wikiLinks.length > 0) meta.wikiLinks = wikiLinks;
11283
+ }
11284
+ filesMeta[fileRel] = meta;
11285
+ }
11286
+ return {
11287
+ schema: "v1",
11288
+ base: safeBase,
11289
+ builtAt: options.nowIso ?? (/* @__PURE__ */ new Date()).toISOString(),
11290
+ fileCount: Object.keys(filesMeta).length,
11291
+ sections,
11292
+ files: filesMeta
11293
+ };
11294
+ }
11295
+ async function writeKnowledgeIndex(options) {
11296
+ const index = await buildKnowledgeIndex(options);
11297
+ await options.adapter.writeFile(`${index.base}/_index.json`, JSON.stringify(index, null, 2));
11298
+ return index;
11299
+ }
11300
+ async function listFilesRecursive(adapter, dir) {
11301
+ const out = [];
11302
+ const stack = [""];
11303
+ while (stack.length > 0) {
11304
+ const sub = stack.pop();
11305
+ const fullDir = sub === "" ? dir : `${dir}/${sub}`;
11306
+ let entries = [];
11307
+ try {
11308
+ entries = await adapter.listDir(fullDir);
11309
+ } catch {
11310
+ continue;
11311
+ }
11312
+ for (const name of entries) {
11313
+ const childRel = sub === "" ? name : `${sub}/${name}`;
11314
+ const childFull = `${dir}/${childRel}`;
11315
+ const isDir = await adapter.isDirectory(childFull).catch(() => false);
11316
+ if (isDir) {
11317
+ stack.push(childRel);
11318
+ } else {
11319
+ out.push(childRel);
11320
+ }
11321
+ }
11322
+ }
11323
+ return out.sort();
11324
+ }
11325
+ function splitSections(content, relPath) {
11326
+ const lines = content.split(/\r?\n/);
11327
+ const out = [];
11328
+ const heads = [];
11329
+ for (let i = 0; i < lines.length; i++) {
11330
+ const line = lines[i];
11331
+ const m = HEADING_RE.exec(line);
11332
+ if (m) heads.push({ line: i + 1, depth: m[1].length, heading: m[2].trim() });
11333
+ }
11334
+ const leadInEndLine = heads.length > 0 ? heads[0].line - 1 : lines.length;
11335
+ const leadInBody = lines.slice(0, leadInEndLine).join("\n").trim();
11336
+ if (leadInBody.length > 0) {
11337
+ out.push({
11338
+ relPath,
11339
+ heading: "",
11340
+ slug: `${relPath}#`,
11341
+ depth: 0,
11342
+ words: tokenize(leadInBody),
11343
+ preview: makePreview(leadInBody),
11344
+ startLine: 1,
11345
+ endLine: leadInEndLine
11346
+ });
11347
+ }
11348
+ for (let i = 0; i < heads.length; i++) {
11349
+ const h = heads[i];
11350
+ const startLine = h.line;
11351
+ const endLine = i + 1 < heads.length ? heads[i + 1].line - 1 : lines.length;
11352
+ const body = lines.slice(startLine - 1, endLine).join("\n");
11353
+ out.push({
11354
+ relPath,
11355
+ heading: h.heading,
11356
+ slug: `${relPath}#${slugify(h.heading)}`,
11357
+ depth: h.depth,
11358
+ words: tokenize(body),
11359
+ preview: makePreview(body),
11360
+ startLine,
11361
+ endLine
11362
+ });
11363
+ }
11364
+ return out;
11365
+ }
11366
+ function makePreview(body) {
11367
+ const trimmed = body.replace(/^#{1,6}\s+.+$\r?\n?/m, "").trim();
11368
+ if (trimmed.length <= PREVIEW_CHARS) return trimmed;
11369
+ return trimmed.slice(0, PREVIEW_CHARS) + "\u2026";
11370
+ }
11371
+ function slugify(text2) {
11372
+ return text2.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
11373
+ }
11374
+ function extractWikiLinks(text2) {
11375
+ const seen = /* @__PURE__ */ new Set();
11376
+ let m;
11377
+ WIKI_LINK_RE.lastIndex = 0;
11378
+ while ((m = WIKI_LINK_RE.exec(text2)) !== null) {
11379
+ const target = m[1].trim();
11380
+ if (target.length > 0) seen.add(target);
11381
+ }
11382
+ return [...seen].sort();
11383
+ }
11384
+ function byteLength3(s) {
11385
+ return new TextEncoder().encode(s).byteLength;
11386
+ }
11387
+
10229
11388
  // src/index.ts
10230
11389
  init_orchestrate();
10231
11390
  init_planParser();
@@ -10300,6 +11459,7 @@ function resolveApiKey(config) {
10300
11459
  WebhookDispatcher,
10301
11460
  adaptMcpTool,
10302
11461
  buildForkedMessages,
11462
+ buildKnowledgeIndex,
10303
11463
  buildPermissionPolicy,
10304
11464
  buildSchemaPrompt,
10305
11465
  buildSystemPrompt,
@@ -10307,16 +11467,21 @@ function resolveApiKey(config) {
10307
11467
  canSpawnProcesses,
10308
11468
  capabilityStub,
10309
11469
  createApiCallTool,
11470
+ createFetchDataTool,
10310
11471
  createLogger,
10311
11472
  createModelAdapter,
11473
+ createReadKnowledgeTool,
11474
+ createSearchKnowledgeTool,
10312
11475
  createSendMessageTool,
10313
11476
  createSkillPageTool,
10314
11477
  createSmartMemory,
10315
11478
  defaultSamplingHandler,
11479
+ defaultToolResultSummarizer,
10316
11480
  defineTool,
10317
11481
  detectRuntime,
10318
11482
  getCoordinatorBasePrompt,
10319
11483
  getCoordinatorSystemPrompt,
11484
+ getExtractor,
10320
11485
  hasProcessLifecycle,
10321
11486
  initEngine,
10322
11487
  isCoordinatorMode,
@@ -10339,6 +11504,7 @@ function resolveApiKey(config) {
10339
11504
  toResponse,
10340
11505
  tryParseJSON,
10341
11506
  validateOutput,
10342
- withCapabilityCheck
11507
+ withCapabilityCheck,
11508
+ writeKnowledgeIndex
10343
11509
  });
10344
11510
  //# sourceMappingURL=index.cjs.map