@contractspec/lib.ai-agent 5.0.4 → 6.0.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.
Files changed (67) hide show
  1. package/README.md +41 -0
  2. package/dist/agent/agent-factory.d.ts +13 -0
  3. package/dist/agent/agent-factory.js +290 -63
  4. package/dist/agent/contract-spec-agent.d.ts +9 -0
  5. package/dist/agent/contract-spec-agent.js +287 -63
  6. package/dist/agent/index.js +353 -129
  7. package/dist/agent/json-runner.js +290 -66
  8. package/dist/agent/unified-agent.js +350 -126
  9. package/dist/exporters/claude-agent-exporter.js +12 -1
  10. package/dist/exporters/index.js +12 -1
  11. package/dist/exporters/opencode-exporter.js +11 -0
  12. package/dist/index.js +11 -0
  13. package/dist/interop/index.js +24 -2
  14. package/dist/interop/spec-consumer.js +11 -0
  15. package/dist/interop/tool-consumer.js +13 -2
  16. package/dist/node/agent/agent-factory.js +290 -63
  17. package/dist/node/agent/contract-spec-agent.js +287 -63
  18. package/dist/node/agent/index.js +353 -129
  19. package/dist/node/agent/json-runner.js +290 -66
  20. package/dist/node/agent/unified-agent.js +350 -126
  21. package/dist/node/exporters/claude-agent-exporter.js +12 -1
  22. package/dist/node/exporters/index.js +12 -1
  23. package/dist/node/exporters/opencode-exporter.js +11 -0
  24. package/dist/node/index.js +11 -0
  25. package/dist/node/interop/index.js +24 -2
  26. package/dist/node/interop/spec-consumer.js +11 -0
  27. package/dist/node/interop/tool-consumer.js +13 -2
  28. package/dist/node/providers/claude-agent-sdk/adapter.js +11 -0
  29. package/dist/node/providers/claude-agent-sdk/index.js +11 -0
  30. package/dist/node/providers/index.js +11 -0
  31. package/dist/node/providers/opencode-sdk/adapter.js +11 -0
  32. package/dist/node/providers/opencode-sdk/index.js +11 -0
  33. package/dist/node/spec/index.js +11 -0
  34. package/dist/node/spec/spec.js +11 -0
  35. package/dist/node/tools/agent-memory-store.js +24 -0
  36. package/dist/node/tools/in-memory-agent-memory-store.js +236 -0
  37. package/dist/node/tools/index.js +463 -42
  38. package/dist/node/tools/memory-tools.js +45 -0
  39. package/dist/node/tools/operation-tool-handler.js +35 -0
  40. package/dist/node/tools/subagent-tool.js +95 -0
  41. package/dist/node/tools/tool-adapter.js +192 -25
  42. package/dist/providers/claude-agent-sdk/adapter.js +11 -0
  43. package/dist/providers/claude-agent-sdk/index.js +11 -0
  44. package/dist/providers/index.js +11 -0
  45. package/dist/providers/opencode-sdk/adapter.js +11 -0
  46. package/dist/providers/opencode-sdk/index.js +11 -0
  47. package/dist/spec/index.js +11 -0
  48. package/dist/spec/spec.d.ts +69 -1
  49. package/dist/spec/spec.js +11 -0
  50. package/dist/tools/agent-memory-store.d.ts +26 -0
  51. package/dist/tools/agent-memory-store.js +24 -0
  52. package/dist/tools/agent-memory-store.test.d.ts +1 -0
  53. package/dist/tools/in-memory-agent-memory-store.d.ts +18 -0
  54. package/dist/tools/in-memory-agent-memory-store.js +236 -0
  55. package/dist/tools/index.d.ts +5 -0
  56. package/dist/tools/index.js +463 -42
  57. package/dist/tools/mcp-client.browser.d.ts +6 -6
  58. package/dist/tools/memory-tools.d.ts +29 -0
  59. package/dist/tools/memory-tools.js +45 -0
  60. package/dist/tools/operation-tool-handler.d.ts +24 -0
  61. package/dist/tools/operation-tool-handler.js +35 -0
  62. package/dist/tools/subagent-tool.d.ts +66 -0
  63. package/dist/tools/subagent-tool.js +95 -0
  64. package/dist/tools/tool-adapter.d.ts +26 -10
  65. package/dist/tools/tool-adapter.js +192 -25
  66. package/dist/types.d.ts +9 -3
  67. package/package.json +67 -7
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2211,7 +2222,7 @@ class ClaudeAgentExporter {
2211
2222
  }
2212
2223
  buildConfig(spec, tools, options) {
2213
2224
  const config = {
2214
- model: options.model ?? "claude-sonnet-4-20250514",
2225
+ model: options.model ?? "claude-sonnet-4-6",
2215
2226
  system: this.buildSystemPrompt(spec, options),
2216
2227
  tools,
2217
2228
  max_turns: spec.maxSteps ?? 10
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2497,7 +2508,7 @@ class ClaudeAgentExporter {
2497
2508
  }
2498
2509
  buildConfig(spec, tools, options) {
2499
2510
  const config = {
2500
- model: options.model ?? "claude-sonnet-4-20250514",
2511
+ model: options.model ?? "claude-sonnet-4-6",
2501
2512
  system: this.buildSystemPrompt(spec, options),
2502
2513
  tools,
2503
2514
  max_turns: spec.maxSteps ?? 10
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2678,6 +2689,17 @@ function createSingleSpecConsumer(spec, options) {
2678
2689
  init_tool_bridge();
2679
2690
  init_tool_bridge2();
2680
2691
  init_i18n();
2692
+ async function resolveToolResult(result) {
2693
+ const resolved = await result;
2694
+ if (typeof resolved === "object" && resolved !== null && typeof resolved.next === "function" && typeof resolved[Symbol.asyncIterator] === "function") {
2695
+ let last;
2696
+ for await (const value of resolved) {
2697
+ last = value;
2698
+ }
2699
+ return typeof last === "string" ? last : JSON.stringify(last ?? "");
2700
+ }
2701
+ return typeof resolved === "string" ? resolved : JSON.stringify(resolved ?? "");
2702
+ }
2681
2703
 
2682
2704
  class MCPToolServer {
2683
2705
  tools;
@@ -2738,7 +2760,7 @@ class MCPToolServer {
2738
2760
  metadata: context?.metadata,
2739
2761
  signal: context?.signal
2740
2762
  };
2741
- return await tool.handler(args, fullContext);
2763
+ return resolveToolResult(tool.handler(args, fullContext));
2742
2764
  }
2743
2765
  getMCPToolDefinitions() {
2744
2766
  const definitions = [];
@@ -2853,7 +2875,7 @@ class ContractSpecToolConsumer {
2853
2875
  metadata: context?.metadata,
2854
2876
  signal: context?.signal
2855
2877
  };
2856
- return await tool.handler(args, fullContext);
2878
+ return resolveToolResult(tool.handler(args, fullContext));
2857
2879
  }
2858
2880
  addTool(config, handler) {
2859
2881
  this.tools.set(config.name, { config, handler });
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2357,6 +2357,17 @@ var init_tool_bridge2 = __esm(() => {
2357
2357
  init_tool_bridge();
2358
2358
  init_tool_bridge2();
2359
2359
  init_i18n();
2360
+ async function resolveToolResult(result) {
2361
+ const resolved = await result;
2362
+ if (typeof resolved === "object" && resolved !== null && typeof resolved.next === "function" && typeof resolved[Symbol.asyncIterator] === "function") {
2363
+ let last;
2364
+ for await (const value of resolved) {
2365
+ last = value;
2366
+ }
2367
+ return typeof last === "string" ? last : JSON.stringify(last ?? "");
2368
+ }
2369
+ return typeof resolved === "string" ? resolved : JSON.stringify(resolved ?? "");
2370
+ }
2360
2371
 
2361
2372
  class MCPToolServer {
2362
2373
  tools;
@@ -2417,7 +2428,7 @@ class MCPToolServer {
2417
2428
  metadata: context?.metadata,
2418
2429
  signal: context?.signal
2419
2430
  };
2420
- return await tool.handler(args, fullContext);
2431
+ return resolveToolResult(tool.handler(args, fullContext));
2421
2432
  }
2422
2433
  getMCPToolDefinitions() {
2423
2434
  const definitions = [];
@@ -2532,7 +2543,7 @@ class ContractSpecToolConsumer {
2532
2543
  metadata: context?.metadata,
2533
2544
  signal: context?.signal
2534
2545
  };
2535
- return await tool.handler(args, fullContext);
2546
+ return resolveToolResult(tool.handler(args, fullContext));
2536
2547
  }
2537
2548
  addTool(config, handler) {
2538
2549
  this.tools.set(config.name, { config, handler });
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -2156,6 +2156,17 @@ function defineAgent(spec) {
2156
2156
  }));
2157
2157
  }
2158
2158
  toolNames.add(tool.name);
2159
+ if (tool.subagentRef && tool.operationRef) {
2160
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
2161
+ }
2162
+ const outputRefCount = [
2163
+ tool.outputPresentation,
2164
+ tool.outputForm,
2165
+ tool.outputDataView
2166
+ ].filter(Boolean).length;
2167
+ if (outputRefCount > 1) {
2168
+ throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
2169
+ }
2159
2170
  }
2160
2171
  return Object.freeze(spec);
2161
2172
  }
@@ -0,0 +1,24 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
14
+
15
+ // src/tools/agent-memory-store.ts
16
+ function validateMemoryPath(path) {
17
+ const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
18
+ if (!normalized.startsWith("/memories") || normalized.includes("..") || normalized === "/memories/.." || normalized.startsWith("/memories/../")) {
19
+ throw new Error(`Invalid memory path: ${path}. Path must be under /memories and cannot contain traversal sequences.`);
20
+ }
21
+ }
22
+ export {
23
+ validateMemoryPath
24
+ };
@@ -0,0 +1,236 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
14
+
15
+ // src/tools/agent-memory-store.ts
16
+ function validateMemoryPath(path) {
17
+ const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
18
+ if (!normalized.startsWith("/memories") || normalized.includes("..") || normalized === "/memories/.." || normalized.startsWith("/memories/../")) {
19
+ throw new Error(`Invalid memory path: ${path}. Path must be under /memories and cannot contain traversal sequences.`);
20
+ }
21
+ }
22
+
23
+ // src/tools/in-memory-agent-memory-store.ts
24
+ function formatSize(bytes) {
25
+ if (bytes < 1024)
26
+ return `${bytes}B`;
27
+ if (bytes < 1024 * 1024)
28
+ return `${(bytes / 1024).toFixed(1)}K`;
29
+ return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
30
+ }
31
+
32
+ class InMemoryAgentMemoryStore {
33
+ store = new Map;
34
+ async view(path, viewRange) {
35
+ validateMemoryPath(path);
36
+ const normalized = path.replace(/\/+/g, "/").replace(/\/$/, "") || "/memories";
37
+ if (this.isDirectory(normalized)) {
38
+ return this.listDirectory(normalized);
39
+ }
40
+ const content = this.store.get(normalized);
41
+ if (content === undefined) {
42
+ return `The path ${path} does not exist. Please provide a valid path.`;
43
+ }
44
+ const lines = content.split(`
45
+ `);
46
+ if (lines.length > 999999) {
47
+ return `File ${path} exceeds maximum line limit of 999,999 lines.`;
48
+ }
49
+ const [start, end] = viewRange ?? [1, lines.length];
50
+ const from = Math.max(0, start - 1);
51
+ const to = Math.min(lines.length, end);
52
+ const selected = lines.slice(from, to);
53
+ const numbered = selected.map((line, i) => {
54
+ const num = from + i + 1;
55
+ return `${String(num).padStart(6)} ${line}`;
56
+ }).join(`
57
+ `);
58
+ return `Here's the content of ${path} with line numbers:
59
+ ${numbered}`;
60
+ }
61
+ async create(path, fileText) {
62
+ validateMemoryPath(path);
63
+ const normalized = path.replace(/\/+/g, "/");
64
+ if (this.store.has(normalized)) {
65
+ return `Error: File ${path} already exists`;
66
+ }
67
+ this.ensureParentDir(normalized);
68
+ this.store.set(normalized, fileText);
69
+ return `File created successfully at: ${path}`;
70
+ }
71
+ async strReplace(path, oldStr, newStr) {
72
+ validateMemoryPath(path);
73
+ const normalized = path.replace(/\/+/g, "/");
74
+ const content = this.store.get(normalized);
75
+ if (content === undefined) {
76
+ return `Error: The path ${path} does not exist. Please provide a valid path.`;
77
+ }
78
+ const count = (content.match(new RegExp(escapeRegex(oldStr), "g")) ?? []).length;
79
+ if (count > 1) {
80
+ const lines = content.split(`
81
+ `);
82
+ const lineNums = [];
83
+ lines.forEach((line, i) => {
84
+ if (line.includes(oldStr))
85
+ lineNums.push(i + 1);
86
+ });
87
+ return `No replacement was performed. Multiple occurrences of old_str \`${oldStr}\` in lines: ${lineNums.join(", ")}. Please ensure it is unique`;
88
+ }
89
+ if (count === 0) {
90
+ return `No replacement was performed, old_str \`${oldStr}\` did not appear verbatim in ${path}.`;
91
+ }
92
+ const newContent = content.replace(oldStr, newStr);
93
+ this.store.set(normalized, newContent);
94
+ const snippet = newContent.split(`
95
+ `).slice(0, 5);
96
+ const numbered = snippet.map((line, i) => `${String(i + 1).padStart(6)} ${line}`).join(`
97
+ `);
98
+ return `The memory file has been edited.
99
+ ${numbered}`;
100
+ }
101
+ async insert(path, insertLine, insertText) {
102
+ validateMemoryPath(path);
103
+ const normalized = path.replace(/\/+/g, "/");
104
+ const content = this.store.get(normalized);
105
+ if (content === undefined) {
106
+ return `Error: The path ${path} does not exist`;
107
+ }
108
+ const lines = content.split(`
109
+ `);
110
+ const n = lines.length;
111
+ if (insertLine < 0 || insertLine > n) {
112
+ return `Error: Invalid \`insert_line\` parameter: ${insertLine}. It should be within the range of lines of the file: [0, ${n}]`;
113
+ }
114
+ lines.splice(insertLine, 0, insertText.replace(/\n$/, ""));
115
+ this.store.set(normalized, lines.join(`
116
+ `));
117
+ return `The file ${path} has been edited.`;
118
+ }
119
+ async delete(path) {
120
+ validateMemoryPath(path);
121
+ const normalized = path.replace(/\/+/g, "/");
122
+ if (this.isDirectory(normalized)) {
123
+ const prefix = normalized === "/memories" ? "/memories/" : `${normalized}/`;
124
+ for (const key of this.store.keys()) {
125
+ if (key.startsWith(prefix) || key === normalized) {
126
+ this.store.delete(key);
127
+ }
128
+ }
129
+ } else {
130
+ if (!this.store.has(normalized)) {
131
+ return `Error: The path ${path} does not exist`;
132
+ }
133
+ this.store.delete(normalized);
134
+ }
135
+ return `Successfully deleted ${path}`;
136
+ }
137
+ async rename(oldPath, newPath) {
138
+ validateMemoryPath(oldPath);
139
+ validateMemoryPath(newPath);
140
+ const oldNorm = oldPath.replace(/\/+/g, "/");
141
+ const newNorm = newPath.replace(/\/+/g, "/");
142
+ if (this.store.has(newNorm) || this.hasAnyChild(newNorm)) {
143
+ return `Error: The destination ${newPath} already exists`;
144
+ }
145
+ if (this.isDirectory(oldNorm)) {
146
+ const oldPrefix = `${oldNorm}/`;
147
+ const entries = Array.from(this.store.entries()).filter(([k]) => k.startsWith(oldPrefix) || k === oldNorm);
148
+ const newPrefix = `${newNorm}/`;
149
+ for (const [k, v] of entries) {
150
+ this.store.delete(k);
151
+ const newKey = k === oldNorm ? newNorm : newPrefix + k.slice(oldPrefix.length);
152
+ this.store.set(newKey, v);
153
+ }
154
+ } else {
155
+ const content = this.store.get(oldNorm);
156
+ if (content === undefined) {
157
+ return `Error: The path ${oldPath} does not exist`;
158
+ }
159
+ this.store.delete(oldNorm);
160
+ this.ensureParentDir(newNorm);
161
+ this.store.set(newNorm, content);
162
+ }
163
+ return `Successfully renamed ${oldPath} to ${newPath}`;
164
+ }
165
+ isDirectory(path) {
166
+ if (path === "/memories")
167
+ return true;
168
+ for (const key of this.store.keys()) {
169
+ if (key.startsWith(path + "/"))
170
+ return true;
171
+ }
172
+ return false;
173
+ }
174
+ hasAnyChild(path) {
175
+ const prefix = path.endsWith("/") ? path : `${path}/`;
176
+ for (const key of this.store.keys()) {
177
+ if (key.startsWith(prefix))
178
+ return true;
179
+ }
180
+ return false;
181
+ }
182
+ ensureParentDir(path) {
183
+ const parts = path.split("/").filter(Boolean);
184
+ parts.pop();
185
+ for (let i = 1;i <= parts.length; i++) {
186
+ const p = "/" + parts.slice(0, i).join("/");
187
+ if (!this.store.has(p)) {
188
+ this.store.set(p, "");
189
+ }
190
+ }
191
+ }
192
+ listDirectory(path) {
193
+ const prefix = path === "/memories" ? "/memories/" : `${path}/`;
194
+ const seen = new Set;
195
+ const entries = [];
196
+ if (path === "/memories") {
197
+ entries.push({
198
+ path: "/memories",
199
+ size: Array.from(this.store.keys()).filter((k) => k.startsWith("/memories/")).reduce((acc, k) => acc + (this.store.get(k)?.length ?? 0), 0)
200
+ });
201
+ }
202
+ for (const key of this.store.keys()) {
203
+ if (!key.startsWith(prefix) && key !== path)
204
+ continue;
205
+ const rel = key.slice(prefix.length);
206
+ const first = rel.split("/")[0];
207
+ if (!first || first.startsWith(".") || first === "node_modules")
208
+ continue;
209
+ const fullPath = path === "/memories" ? `/memories/${first}` : `${path}/${first}`;
210
+ if (seen.has(fullPath))
211
+ continue;
212
+ seen.add(fullPath);
213
+ let size = 0;
214
+ if (this.store.has(key)) {
215
+ size = (this.store.get(key) ?? "").length;
216
+ } else {
217
+ for (const k of this.store.keys()) {
218
+ if (k.startsWith(fullPath + "/") || k === fullPath) {
219
+ size += (this.store.get(k) ?? "").length;
220
+ }
221
+ }
222
+ }
223
+ entries.push({ path: fullPath, size });
224
+ }
225
+ const lines = entries.slice(0, 50).map((e) => `${formatSize(e.size)} ${e.path}`).join(`
226
+ `);
227
+ return `Here're the files and directories up to 2 levels deep in ${path}, excluding hidden items and node_modules:
228
+ ${lines}`;
229
+ }
230
+ }
231
+ function escapeRegex(s) {
232
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
233
+ }
234
+ export {
235
+ InMemoryAgentMemoryStore
236
+ };