deepagentsdk 0.11.1 → 0.13.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 (99) hide show
  1. package/dist/adapters/elements/index.cjs +274 -0
  2. package/dist/adapters/elements/index.cjs.map +1 -0
  3. package/dist/adapters/elements/index.d.cts +122 -0
  4. package/dist/adapters/elements/index.d.mts +122 -0
  5. package/dist/adapters/elements/index.mjs +268 -0
  6. package/dist/adapters/elements/index.mjs.map +1 -0
  7. package/dist/agent-BDM-PIu8.d.mts +1500 -0
  8. package/dist/agent-DToEVxs-.d.cts +1500 -0
  9. package/dist/chunk-C5azi7Hr.cjs +67 -0
  10. package/dist/cli/index.cjs +3162 -0
  11. package/dist/cli/index.cjs.map +1 -0
  12. package/dist/cli/index.d.cts +1 -0
  13. package/dist/cli/index.d.mts +1 -0
  14. package/dist/cli/index.mjs +3120 -0
  15. package/dist/cli/index.mjs.map +1 -0
  16. package/dist/file-saver-BYPKakT4.cjs +3990 -0
  17. package/dist/file-saver-BYPKakT4.cjs.map +1 -0
  18. package/dist/file-saver-Hj5so3dV.mjs +3568 -0
  19. package/dist/file-saver-Hj5so3dV.mjs.map +1 -0
  20. package/dist/index.cjs +1481 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +1233 -0
  23. package/dist/index.d.mts +1233 -0
  24. package/dist/index.mjs +1381 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/load-BBYEnMwz.mjs +142 -0
  27. package/dist/load-BBYEnMwz.mjs.map +1 -0
  28. package/dist/load-BDxe6Cet.mjs +3 -0
  29. package/dist/load-BrRAKlO6.cjs +163 -0
  30. package/dist/load-BrRAKlO6.cjs.map +1 -0
  31. package/dist/load-DqllBbDc.cjs +4 -0
  32. package/package.json +26 -12
  33. package/src/adapters/elements/index.ts +0 -27
  34. package/src/adapters/elements/messageAdapter.ts +0 -165
  35. package/src/adapters/elements/statusAdapter.ts +0 -39
  36. package/src/adapters/elements/types.ts +0 -97
  37. package/src/adapters/elements/useElementsAdapter.ts +0 -261
  38. package/src/agent.ts +0 -1258
  39. package/src/backends/composite.ts +0 -273
  40. package/src/backends/filesystem.ts +0 -692
  41. package/src/backends/index.ts +0 -22
  42. package/src/backends/local-sandbox.ts +0 -175
  43. package/src/backends/persistent.ts +0 -593
  44. package/src/backends/sandbox.ts +0 -510
  45. package/src/backends/state.ts +0 -244
  46. package/src/backends/utils.ts +0 -287
  47. package/src/checkpointer/file-saver.ts +0 -98
  48. package/src/checkpointer/index.ts +0 -5
  49. package/src/checkpointer/kv-saver.ts +0 -82
  50. package/src/checkpointer/memory-saver.ts +0 -82
  51. package/src/checkpointer/types.ts +0 -125
  52. package/src/cli/components/ApiKeyInput.tsx +0 -300
  53. package/src/cli/components/FilePreview.tsx +0 -237
  54. package/src/cli/components/Input.tsx +0 -277
  55. package/src/cli/components/Message.tsx +0 -93
  56. package/src/cli/components/ModelSelection.tsx +0 -338
  57. package/src/cli/components/SlashMenu.tsx +0 -101
  58. package/src/cli/components/StatusBar.tsx +0 -89
  59. package/src/cli/components/Subagent.tsx +0 -91
  60. package/src/cli/components/TodoList.tsx +0 -133
  61. package/src/cli/components/ToolApproval.tsx +0 -70
  62. package/src/cli/components/ToolCall.tsx +0 -144
  63. package/src/cli/components/ToolCallSummary.tsx +0 -175
  64. package/src/cli/components/Welcome.tsx +0 -75
  65. package/src/cli/components/index.ts +0 -24
  66. package/src/cli/hooks/index.ts +0 -12
  67. package/src/cli/hooks/useAgent.ts +0 -933
  68. package/src/cli/index.tsx +0 -1066
  69. package/src/cli/theme.ts +0 -205
  70. package/src/cli/utils/model-list.ts +0 -365
  71. package/src/constants/errors.ts +0 -29
  72. package/src/constants/limits.ts +0 -195
  73. package/src/index.ts +0 -176
  74. package/src/middleware/agent-memory.ts +0 -330
  75. package/src/prompts.ts +0 -196
  76. package/src/skills/index.ts +0 -2
  77. package/src/skills/load.ts +0 -191
  78. package/src/skills/types.ts +0 -53
  79. package/src/tools/execute.ts +0 -167
  80. package/src/tools/filesystem.ts +0 -418
  81. package/src/tools/index.ts +0 -39
  82. package/src/tools/subagent.ts +0 -443
  83. package/src/tools/todos.ts +0 -101
  84. package/src/tools/web.ts +0 -567
  85. package/src/types/backend.ts +0 -177
  86. package/src/types/core.ts +0 -220
  87. package/src/types/events.ts +0 -430
  88. package/src/types/index.ts +0 -94
  89. package/src/types/structured-output.ts +0 -43
  90. package/src/types/subagent.ts +0 -96
  91. package/src/types.ts +0 -22
  92. package/src/utils/approval.ts +0 -213
  93. package/src/utils/events.ts +0 -416
  94. package/src/utils/eviction.ts +0 -181
  95. package/src/utils/index.ts +0 -34
  96. package/src/utils/model-parser.ts +0 -38
  97. package/src/utils/patch-tool-calls.ts +0 -233
  98. package/src/utils/project-detection.ts +0 -32
  99. package/src/utils/summarization.ts +0 -254
package/dist/index.cjs ADDED
@@ -0,0 +1,1481 @@
1
+ const require_chunk = require('./chunk-C5azi7Hr.cjs');
2
+ const require_file_saver = require('./file-saver-BYPKakT4.cjs');
3
+ const require_load = require('./load-BrRAKlO6.cjs');
4
+ let ai = require("ai");
5
+ let micromatch = require("micromatch");
6
+ micromatch = require_chunk.__toESM(micromatch);
7
+ let path = require("path");
8
+ path = require_chunk.__toESM(path);
9
+ let fs_promises = require("fs/promises");
10
+ fs_promises = require_chunk.__toESM(fs_promises);
11
+ let fs = require("fs");
12
+ fs = require_chunk.__toESM(fs);
13
+ let child_process = require("child_process");
14
+ let fast_glob = require("fast-glob");
15
+ fast_glob = require_chunk.__toESM(fast_glob);
16
+ let node_path = require("node:path");
17
+ node_path = require_chunk.__toESM(node_path);
18
+ let node_fs_promises = require("node:fs/promises");
19
+ node_fs_promises = require_chunk.__toESM(node_fs_promises);
20
+ let node_os = require("node:os");
21
+ node_os = require_chunk.__toESM(node_os);
22
+
23
+ //#region src/types/structured-output.ts
24
+ require_file_saver.init_limits();
25
+ /**
26
+ * Type guard for checking if a result has structured output
27
+ */
28
+ function hasStructuredOutput(result) {
29
+ return result && typeof result === "object" && "output" in result;
30
+ }
31
+ /**
32
+ * Type guard for checking if an event has structured output
33
+ */
34
+ function eventHasStructuredOutput(event) {
35
+ return event && event.type === "done" && "output" in event;
36
+ }
37
+ /**
38
+ * Extract structured output from agent result with type safety
39
+ */
40
+ function getStructuredOutput(result) {
41
+ return hasStructuredOutput(result) ? result.output : void 0;
42
+ }
43
+ /**
44
+ * Extract structured output from event with type safety
45
+ */
46
+ function getEventOutput(event) {
47
+ return eventHasStructuredOutput(event) ? event.output : void 0;
48
+ }
49
+
50
+ //#endregion
51
+ //#region src/backends/filesystem.ts
52
+ /**
53
+ * FilesystemBackend: Read and write files directly from the filesystem.
54
+ */
55
+ require_file_saver.init_errors();
56
+ const SUPPORTS_NOFOLLOW = fs.constants.O_NOFOLLOW !== void 0;
57
+ /**
58
+ * Backend that reads and writes files directly from the filesystem.
59
+ *
60
+ * Files are persisted to disk, making them available across agent invocations.
61
+ * This backend provides real file I/O operations with security checks to prevent
62
+ * directory traversal attacks.
63
+ *
64
+ * @example Basic usage
65
+ * ```typescript
66
+ * const backend = new FilesystemBackend({ rootDir: './workspace' });
67
+ * const agent = createDeepAgent({
68
+ * model: anthropic('claude-sonnet-4-20250514'),
69
+ * backend,
70
+ * });
71
+ * ```
72
+ *
73
+ * @example With custom options
74
+ * ```typescript
75
+ * const backend = new FilesystemBackend({
76
+ * rootDir: './my-project',
77
+ * virtualMode: false,
78
+ * maxFileSizeMb: 50, // Allow larger files
79
+ * });
80
+ * ```
81
+ */
82
+ var FilesystemBackend = class {
83
+ cwd;
84
+ virtualMode;
85
+ maxFileSizeBytes;
86
+ /**
87
+ * Create a new FilesystemBackend instance.
88
+ *
89
+ * @param options - Configuration options
90
+ * @param options.rootDir - Optional root directory for file operations (default: current working directory).
91
+ * All file paths are resolved relative to this directory.
92
+ * @param options.virtualMode - Optional flag for virtual mode (default: false).
93
+ * When true, files are stored in memory but paths are validated against filesystem.
94
+ * @param options.maxFileSizeMb - Optional maximum file size in MB (default: 10).
95
+ * Files larger than this will be rejected.
96
+ */
97
+ constructor(options = {}) {
98
+ const { rootDir, virtualMode = false, maxFileSizeMb = require_file_saver.MAX_FILE_SIZE_MB } = options;
99
+ this.cwd = rootDir ? path.resolve(rootDir) : process.cwd();
100
+ this.virtualMode = virtualMode;
101
+ this.maxFileSizeBytes = maxFileSizeMb * 1024 * 1024;
102
+ }
103
+ /**
104
+ * Resolve a file path with security checks.
105
+ */
106
+ resolvePath(key) {
107
+ if (this.virtualMode) {
108
+ const vpath = key.startsWith("/") ? key : "/" + key;
109
+ if (vpath.includes("..") || vpath.startsWith("~")) throw new Error("Path traversal not allowed");
110
+ const full = path.resolve(this.cwd, vpath.substring(1));
111
+ const relative = path.relative(this.cwd, full);
112
+ if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Path: ${full} outside root directory: ${this.cwd}`);
113
+ return full;
114
+ }
115
+ if (path.isAbsolute(key)) return key;
116
+ return path.resolve(this.cwd, key);
117
+ }
118
+ /**
119
+ * List files and directories in the specified directory (non-recursive).
120
+ */
121
+ async lsInfo(dirPath) {
122
+ try {
123
+ const resolvedPath = this.resolvePath(dirPath);
124
+ if (!(await fs_promises.stat(resolvedPath)).isDirectory()) return [];
125
+ const entries = await fs_promises.readdir(resolvedPath, { withFileTypes: true });
126
+ const results = [];
127
+ const cwdStr = this.cwd.endsWith(path.sep) ? this.cwd : this.cwd + path.sep;
128
+ for (const entry of entries) {
129
+ const fullPath = path.join(resolvedPath, entry.name);
130
+ try {
131
+ const entryStat = await fs_promises.stat(fullPath);
132
+ const isFile = entryStat.isFile();
133
+ const isDir = entryStat.isDirectory();
134
+ if (!this.virtualMode) {
135
+ if (isFile) results.push({
136
+ path: fullPath,
137
+ is_dir: false,
138
+ size: entryStat.size,
139
+ modified_at: entryStat.mtime.toISOString()
140
+ });
141
+ else if (isDir) results.push({
142
+ path: fullPath + path.sep,
143
+ is_dir: true,
144
+ size: 0,
145
+ modified_at: entryStat.mtime.toISOString()
146
+ });
147
+ } else {
148
+ let relativePath;
149
+ if (fullPath.startsWith(cwdStr)) relativePath = fullPath.substring(cwdStr.length);
150
+ else if (fullPath.startsWith(this.cwd)) relativePath = fullPath.substring(this.cwd.length).replace(/^[/\\]/, "");
151
+ else relativePath = fullPath;
152
+ relativePath = relativePath.split(path.sep).join("/");
153
+ const virtPath = "/" + relativePath;
154
+ if (isFile) results.push({
155
+ path: virtPath,
156
+ is_dir: false,
157
+ size: entryStat.size,
158
+ modified_at: entryStat.mtime.toISOString()
159
+ });
160
+ else if (isDir) results.push({
161
+ path: virtPath + "/",
162
+ is_dir: true,
163
+ size: 0,
164
+ modified_at: entryStat.mtime.toISOString()
165
+ });
166
+ }
167
+ } catch {
168
+ continue;
169
+ }
170
+ }
171
+ results.sort((a, b) => a.path.localeCompare(b.path));
172
+ return results;
173
+ } catch {
174
+ return [];
175
+ }
176
+ }
177
+ /**
178
+ * Read file content with line numbers.
179
+ */
180
+ async read(filePath, offset = 0, limit = require_file_saver.DEFAULT_READ_LIMIT) {
181
+ try {
182
+ const resolvedPath = this.resolvePath(filePath);
183
+ let content;
184
+ if (SUPPORTS_NOFOLLOW) {
185
+ if (!(await fs_promises.stat(resolvedPath)).isFile()) return require_file_saver.FILE_NOT_FOUND(filePath);
186
+ const fd = await fs_promises.open(resolvedPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
187
+ try {
188
+ content = await fd.readFile({ encoding: "utf-8" });
189
+ } finally {
190
+ await fd.close();
191
+ }
192
+ } else {
193
+ const stat = await fs_promises.lstat(resolvedPath);
194
+ if (stat.isSymbolicLink()) return `Error: Symlinks are not allowed: ${filePath}`;
195
+ if (!stat.isFile()) return require_file_saver.FILE_NOT_FOUND(filePath);
196
+ content = await fs_promises.readFile(resolvedPath, "utf-8");
197
+ }
198
+ const emptyMsg = require_file_saver.checkEmptyContent(content);
199
+ if (emptyMsg) return emptyMsg;
200
+ const lines = content.split("\n");
201
+ const startIdx = offset;
202
+ const endIdx = Math.min(startIdx + limit, lines.length);
203
+ if (startIdx >= lines.length) return `Error: Line offset ${offset} exceeds file length (${lines.length} lines)`;
204
+ return require_file_saver.formatContentWithLineNumbers(lines.slice(startIdx, endIdx), startIdx + 1);
205
+ } catch (e) {
206
+ return `Error reading file '${filePath}': ${e.message}`;
207
+ }
208
+ }
209
+ /**
210
+ * Read file content as raw FileData.
211
+ */
212
+ async readRaw(filePath) {
213
+ const resolvedPath = this.resolvePath(filePath);
214
+ let content;
215
+ let stat;
216
+ if (SUPPORTS_NOFOLLOW) {
217
+ stat = await fs_promises.stat(resolvedPath);
218
+ if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
219
+ const fd = await fs_promises.open(resolvedPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
220
+ try {
221
+ content = await fd.readFile({ encoding: "utf-8" });
222
+ } finally {
223
+ await fd.close();
224
+ }
225
+ } else {
226
+ stat = await fs_promises.lstat(resolvedPath);
227
+ if (stat.isSymbolicLink()) throw new Error(`Symlinks are not allowed: ${filePath}`);
228
+ if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
229
+ content = await fs_promises.readFile(resolvedPath, "utf-8");
230
+ }
231
+ return {
232
+ content: content.split("\n"),
233
+ created_at: stat.ctime.toISOString(),
234
+ modified_at: stat.mtime.toISOString()
235
+ };
236
+ }
237
+ /**
238
+ * Create a new file with content.
239
+ */
240
+ async write(filePath, content) {
241
+ try {
242
+ const resolvedPath = this.resolvePath(filePath);
243
+ try {
244
+ if ((await fs_promises.lstat(resolvedPath)).isSymbolicLink()) return {
245
+ success: false,
246
+ error: `Cannot write to ${filePath} because it is a symlink. Symlinks are not allowed.`
247
+ };
248
+ return {
249
+ success: false,
250
+ error: require_file_saver.FILE_ALREADY_EXISTS(filePath)
251
+ };
252
+ } catch {}
253
+ await fs_promises.mkdir(path.dirname(resolvedPath), { recursive: true });
254
+ if (SUPPORTS_NOFOLLOW) {
255
+ const flags = fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_TRUNC | fs.constants.O_NOFOLLOW;
256
+ const fd = await fs_promises.open(resolvedPath, flags, 420);
257
+ try {
258
+ await fd.writeFile(content, "utf-8");
259
+ } finally {
260
+ await fd.close();
261
+ }
262
+ } else await fs_promises.writeFile(resolvedPath, content, "utf-8");
263
+ return {
264
+ success: true,
265
+ path: filePath
266
+ };
267
+ } catch (e) {
268
+ return {
269
+ success: false,
270
+ error: `Error writing file '${filePath}': ${e.message}`
271
+ };
272
+ }
273
+ }
274
+ /**
275
+ * Edit a file by replacing string occurrences.
276
+ */
277
+ async edit(filePath, oldString, newString, replaceAll = false) {
278
+ try {
279
+ const resolvedPath = this.resolvePath(filePath);
280
+ let content;
281
+ if (SUPPORTS_NOFOLLOW) {
282
+ if (!(await fs_promises.stat(resolvedPath)).isFile()) return {
283
+ success: false,
284
+ error: require_file_saver.FILE_NOT_FOUND(filePath)
285
+ };
286
+ const fd = await fs_promises.open(resolvedPath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
287
+ try {
288
+ content = await fd.readFile({ encoding: "utf-8" });
289
+ } finally {
290
+ await fd.close();
291
+ }
292
+ } else {
293
+ const stat = await fs_promises.lstat(resolvedPath);
294
+ if (stat.isSymbolicLink()) return {
295
+ success: false,
296
+ error: `Error: Symlinks are not allowed: ${filePath}`
297
+ };
298
+ if (!stat.isFile()) return {
299
+ success: false,
300
+ error: require_file_saver.FILE_NOT_FOUND(filePath)
301
+ };
302
+ content = await fs_promises.readFile(resolvedPath, "utf-8");
303
+ }
304
+ const result = require_file_saver.performStringReplacement(content, oldString, newString, replaceAll);
305
+ if (typeof result === "string") return {
306
+ success: false,
307
+ error: result
308
+ };
309
+ const [newContent, occurrences] = result;
310
+ if (SUPPORTS_NOFOLLOW) {
311
+ const flags = fs.constants.O_WRONLY | fs.constants.O_TRUNC | fs.constants.O_NOFOLLOW;
312
+ const fd = await fs_promises.open(resolvedPath, flags);
313
+ try {
314
+ await fd.writeFile(newContent, "utf-8");
315
+ } finally {
316
+ await fd.close();
317
+ }
318
+ } else await fs_promises.writeFile(resolvedPath, newContent, "utf-8");
319
+ return {
320
+ success: true,
321
+ path: filePath,
322
+ occurrences
323
+ };
324
+ } catch (e) {
325
+ return {
326
+ success: false,
327
+ error: `Error editing file '${filePath}': ${e.message}`
328
+ };
329
+ }
330
+ }
331
+ /**
332
+ * Structured search results or error string for invalid input.
333
+ */
334
+ async grepRaw(pattern, dirPath = "/", glob$1 = null) {
335
+ try {
336
+ new RegExp(pattern);
337
+ } catch (e) {
338
+ return `Invalid regex pattern: ${e.message}`;
339
+ }
340
+ let baseFull;
341
+ try {
342
+ baseFull = this.resolvePath(dirPath || ".");
343
+ } catch {
344
+ return [];
345
+ }
346
+ try {
347
+ await fs_promises.stat(baseFull);
348
+ } catch {
349
+ return [];
350
+ }
351
+ let results = await this.ripgrepSearch(pattern, baseFull, glob$1);
352
+ if (results === null) results = await this.regexSearch(pattern, baseFull, glob$1);
353
+ const matches = [];
354
+ for (const [fpath, items] of Object.entries(results)) for (const [lineNum, lineText] of items) matches.push({
355
+ path: fpath,
356
+ line: lineNum,
357
+ text: lineText
358
+ });
359
+ return matches;
360
+ }
361
+ /**
362
+ * Try to use ripgrep for fast searching.
363
+ */
364
+ async ripgrepSearch(pattern, baseFull, includeGlob) {
365
+ return new Promise((resolve) => {
366
+ const args = ["--json"];
367
+ if (includeGlob) args.push("--glob", includeGlob);
368
+ args.push("--", pattern, baseFull);
369
+ const proc = (0, child_process.spawn)("rg", args, { timeout: 3e4 });
370
+ const results = {};
371
+ let output = "";
372
+ proc.stdout.on("data", (data) => {
373
+ output += data.toString();
374
+ });
375
+ proc.on("close", (code) => {
376
+ if (code !== 0 && code !== 1) {
377
+ resolve(null);
378
+ return;
379
+ }
380
+ for (const line of output.split("\n")) {
381
+ if (!line.trim()) continue;
382
+ try {
383
+ const data = JSON.parse(line);
384
+ if (data.type !== "match") continue;
385
+ const pdata = data.data || {};
386
+ const ftext = pdata.path?.text;
387
+ if (!ftext) continue;
388
+ let virtPath;
389
+ if (this.virtualMode) try {
390
+ const resolved = path.resolve(ftext);
391
+ const relative = path.relative(this.cwd, resolved);
392
+ if (relative.startsWith("..")) continue;
393
+ virtPath = "/" + relative.split(path.sep).join("/");
394
+ } catch {
395
+ continue;
396
+ }
397
+ else virtPath = ftext;
398
+ const ln = pdata.line_number;
399
+ const lt = pdata.lines?.text?.replace(/\n$/, "") || "";
400
+ if (ln === void 0) continue;
401
+ if (!results[virtPath]) results[virtPath] = [];
402
+ results[virtPath].push([ln, lt]);
403
+ } catch {
404
+ continue;
405
+ }
406
+ }
407
+ resolve(results);
408
+ });
409
+ proc.on("error", () => {
410
+ resolve(null);
411
+ });
412
+ });
413
+ }
414
+ /**
415
+ * Fallback regex search implementation.
416
+ */
417
+ async regexSearch(pattern, baseFull, includeGlob) {
418
+ let regex;
419
+ try {
420
+ regex = new RegExp(pattern);
421
+ } catch {
422
+ return {};
423
+ }
424
+ const results = {};
425
+ const files = await (0, fast_glob.default)("**/*", {
426
+ cwd: (await fs_promises.stat(baseFull)).isDirectory() ? baseFull : path.dirname(baseFull),
427
+ absolute: true,
428
+ onlyFiles: true,
429
+ dot: true
430
+ });
431
+ for (const fp of files) try {
432
+ if (includeGlob && !micromatch.default.isMatch(path.basename(fp), includeGlob)) continue;
433
+ if ((await fs_promises.stat(fp)).size > this.maxFileSizeBytes) continue;
434
+ const lines = (await fs_promises.readFile(fp, "utf-8")).split("\n");
435
+ for (let i = 0; i < lines.length; i++) {
436
+ const line = lines[i];
437
+ if (line && regex.test(line)) {
438
+ let virtPath;
439
+ if (this.virtualMode) try {
440
+ const relative = path.relative(this.cwd, fp);
441
+ if (relative.startsWith("..")) continue;
442
+ virtPath = "/" + relative.split(path.sep).join("/");
443
+ } catch {
444
+ continue;
445
+ }
446
+ else virtPath = fp;
447
+ if (!results[virtPath]) results[virtPath] = [];
448
+ results[virtPath].push([i + 1, line]);
449
+ }
450
+ }
451
+ } catch {
452
+ continue;
453
+ }
454
+ return results;
455
+ }
456
+ /**
457
+ * Structured glob matching returning FileInfo objects.
458
+ */
459
+ async globInfo(pattern, searchPath = "/") {
460
+ if (pattern.startsWith("/")) pattern = pattern.substring(1);
461
+ const resolvedSearchPath = searchPath === "/" ? this.cwd : this.resolvePath(searchPath);
462
+ try {
463
+ if (!(await fs_promises.stat(resolvedSearchPath)).isDirectory()) return [];
464
+ } catch {
465
+ return [];
466
+ }
467
+ const results = [];
468
+ try {
469
+ const matches = await (0, fast_glob.default)(pattern, {
470
+ cwd: resolvedSearchPath,
471
+ absolute: true,
472
+ onlyFiles: true,
473
+ dot: true
474
+ });
475
+ for (const matchedPath of matches) try {
476
+ const fileStat = await fs_promises.stat(matchedPath);
477
+ if (!fileStat.isFile()) continue;
478
+ const normalizedPath = matchedPath.split("/").join(path.sep);
479
+ if (!this.virtualMode) results.push({
480
+ path: normalizedPath,
481
+ is_dir: false,
482
+ size: fileStat.size,
483
+ modified_at: fileStat.mtime.toISOString()
484
+ });
485
+ else {
486
+ const cwdStr = this.cwd.endsWith(path.sep) ? this.cwd : this.cwd + path.sep;
487
+ let relativePath;
488
+ if (normalizedPath.startsWith(cwdStr)) relativePath = normalizedPath.substring(cwdStr.length);
489
+ else if (normalizedPath.startsWith(this.cwd)) relativePath = normalizedPath.substring(this.cwd.length).replace(/^[/\\]/, "");
490
+ else relativePath = normalizedPath;
491
+ relativePath = relativePath.split(path.sep).join("/");
492
+ const virt = "/" + relativePath;
493
+ results.push({
494
+ path: virt,
495
+ is_dir: false,
496
+ size: fileStat.size,
497
+ modified_at: fileStat.mtime.toISOString()
498
+ });
499
+ }
500
+ } catch {
501
+ continue;
502
+ }
503
+ } catch {}
504
+ results.sort((a, b) => a.path.localeCompare(b.path));
505
+ return results;
506
+ }
507
+ };
508
+
509
+ //#endregion
510
+ //#region src/backends/composite.ts
511
+ /**
512
+ * Backend that routes file operations to different backends based on path prefix.
513
+ *
514
+ * This enables hybrid storage strategies by routing files to different backends
515
+ * based on their path prefix. Useful for separating persistent and ephemeral storage,
516
+ * or using different storage backends for different types of files.
517
+ *
518
+ * @example Hybrid storage strategy
519
+ * ```typescript
520
+ * import { CompositeBackend, FilesystemBackend, StateBackend } from 'deepagentsdk';
521
+ *
522
+ * const state = { todos: [], files: {} };
523
+ * const backend = new CompositeBackend(
524
+ * new StateBackend(state), // Default: ephemeral storage
525
+ * {
526
+ * '/persistent/': new FilesystemBackend({ rootDir: './persistent' }), // Persistent files
527
+ * '/cache/': new StateBackend(state), // Cached files (ephemeral)
528
+ * }
529
+ * );
530
+ *
531
+ * const agent = createDeepAgent({
532
+ * model: anthropic('claude-sonnet-4-20250514'),
533
+ * backend,
534
+ * });
535
+ * ```
536
+ *
537
+ * @example Multiple persistent backends
538
+ * ```typescript
539
+ * const backend = new CompositeBackend(
540
+ * new FilesystemBackend({ rootDir: './default' }),
541
+ * {
542
+ * '/user-data/': new FilesystemBackend({ rootDir: './user-data' }),
543
+ * '/system/': new FilesystemBackend({ rootDir: './system' }),
544
+ * }
545
+ * );
546
+ * ```
547
+ */
548
+ var CompositeBackend = class {
549
+ defaultBackend;
550
+ routes;
551
+ sortedRoutes;
552
+ /**
553
+ * Create a new CompositeBackend instance.
554
+ *
555
+ * @param defaultBackend - Backend to use for paths that don't match any route prefix
556
+ * @param routes - Record mapping path prefixes to backends.
557
+ * Routes are matched by longest prefix first.
558
+ * Example: `{ '/persistent/': filesystemBackend, '/cache/': stateBackend }`
559
+ */
560
+ constructor(defaultBackend, routes) {
561
+ this.defaultBackend = defaultBackend;
562
+ this.routes = routes;
563
+ this.sortedRoutes = Object.entries(routes).sort((a, b) => b[0].length - a[0].length);
564
+ }
565
+ /**
566
+ * Determine which backend handles this key and strip prefix.
567
+ */
568
+ getBackendAndKey(key) {
569
+ for (const [prefix, backend] of this.sortedRoutes) if (key.startsWith(prefix)) {
570
+ const suffix = key.substring(prefix.length);
571
+ return [backend, suffix ? "/" + suffix : "/"];
572
+ }
573
+ return [this.defaultBackend, key];
574
+ }
575
+ /**
576
+ * List files and directories in the specified directory (non-recursive).
577
+ */
578
+ async lsInfo(path$1) {
579
+ for (const [routePrefix, backend] of this.sortedRoutes) if (path$1.startsWith(routePrefix.replace(/\/$/, ""))) {
580
+ const suffix = path$1.substring(routePrefix.length);
581
+ const searchPath = suffix ? "/" + suffix : "/";
582
+ const infos = await backend.lsInfo(searchPath);
583
+ const prefixed = [];
584
+ for (const fi of infos) prefixed.push({
585
+ ...fi,
586
+ path: routePrefix.slice(0, -1) + fi.path
587
+ });
588
+ return prefixed;
589
+ }
590
+ if (path$1 === "/") {
591
+ const results = [];
592
+ const defaultInfos = await this.defaultBackend.lsInfo(path$1);
593
+ results.push(...defaultInfos);
594
+ for (const [routePrefix] of this.sortedRoutes) results.push({
595
+ path: routePrefix,
596
+ is_dir: true,
597
+ size: 0,
598
+ modified_at: ""
599
+ });
600
+ results.sort((a, b) => a.path.localeCompare(b.path));
601
+ return results;
602
+ }
603
+ return await this.defaultBackend.lsInfo(path$1);
604
+ }
605
+ /**
606
+ * Read file content, routing to appropriate backend.
607
+ */
608
+ async read(filePath, offset = 0, limit = 2e3) {
609
+ const [backend, strippedKey] = this.getBackendAndKey(filePath);
610
+ return await backend.read(strippedKey, offset, limit);
611
+ }
612
+ /**
613
+ * Read file content as raw FileData.
614
+ */
615
+ async readRaw(filePath) {
616
+ const [backend, strippedKey] = this.getBackendAndKey(filePath);
617
+ return await backend.readRaw(strippedKey);
618
+ }
619
+ /**
620
+ * Structured search results or error string for invalid input.
621
+ */
622
+ async grepRaw(pattern, path$1 = "/", glob$1 = null) {
623
+ for (const [routePrefix, backend] of this.sortedRoutes) if (path$1.startsWith(routePrefix.replace(/\/$/, ""))) {
624
+ const suffix = path$1.substring(routePrefix.length);
625
+ const searchPath = suffix ? "/" + suffix : "/";
626
+ const raw = await backend.grepRaw(pattern, searchPath, glob$1);
627
+ if (typeof raw === "string") return raw;
628
+ return raw.map((m) => ({
629
+ ...m,
630
+ path: routePrefix.slice(0, -1) + m.path
631
+ }));
632
+ }
633
+ const allMatches = [];
634
+ const rawDefault = await this.defaultBackend.grepRaw(pattern, path$1, glob$1);
635
+ if (typeof rawDefault === "string") return rawDefault;
636
+ allMatches.push(...rawDefault);
637
+ for (const [routePrefix, backend] of Object.entries(this.routes)) {
638
+ const raw = await backend.grepRaw(pattern, "/", glob$1);
639
+ if (typeof raw === "string") return raw;
640
+ allMatches.push(...raw.map((m) => ({
641
+ ...m,
642
+ path: routePrefix.slice(0, -1) + m.path
643
+ })));
644
+ }
645
+ return allMatches;
646
+ }
647
+ /**
648
+ * Structured glob matching returning FileInfo objects.
649
+ */
650
+ async globInfo(pattern, path$1 = "/") {
651
+ const results = [];
652
+ for (const [routePrefix, backend] of this.sortedRoutes) if (path$1.startsWith(routePrefix.replace(/\/$/, ""))) {
653
+ const suffix = path$1.substring(routePrefix.length);
654
+ const searchPath = suffix ? "/" + suffix : "/";
655
+ return (await backend.globInfo(pattern, searchPath)).map((fi) => ({
656
+ ...fi,
657
+ path: routePrefix.slice(0, -1) + fi.path
658
+ }));
659
+ }
660
+ const defaultInfos = await this.defaultBackend.globInfo(pattern, path$1);
661
+ results.push(...defaultInfos);
662
+ for (const [routePrefix, backend] of Object.entries(this.routes)) {
663
+ const infos = await backend.globInfo(pattern, "/");
664
+ results.push(...infos.map((fi) => ({
665
+ ...fi,
666
+ path: routePrefix.slice(0, -1) + fi.path
667
+ })));
668
+ }
669
+ results.sort((a, b) => a.path.localeCompare(b.path));
670
+ return results;
671
+ }
672
+ /**
673
+ * Create a new file, routing to appropriate backend.
674
+ */
675
+ async write(filePath, content) {
676
+ const [backend, strippedKey] = this.getBackendAndKey(filePath);
677
+ return await backend.write(strippedKey, content);
678
+ }
679
+ /**
680
+ * Edit a file, routing to appropriate backend.
681
+ */
682
+ async edit(filePath, oldString, newString, replaceAll = false) {
683
+ const [backend, strippedKey] = this.getBackendAndKey(filePath);
684
+ return await backend.edit(strippedKey, oldString, newString, replaceAll);
685
+ }
686
+ };
687
+
688
+ //#endregion
689
+ //#region src/backends/persistent.ts
690
+ require_file_saver.init_errors();
691
+ /**
692
+ * Simple in-memory implementation of KeyValueStore.
693
+ *
694
+ * Useful for testing or single-session persistence. Data is stored in a Map
695
+ * and does not persist across application restarts.
696
+ *
697
+ * @example Basic usage
698
+ * ```typescript
699
+ * const store = new InMemoryStore();
700
+ * const backend = new PersistentBackend({ store });
701
+ * ```
702
+ *
703
+ * @example For testing
704
+ * ```typescript
705
+ * const store = new InMemoryStore();
706
+ * // ... run tests ...
707
+ * store.clear(); // Clean up after tests
708
+ * ```
709
+ */
710
+ var InMemoryStore = class {
711
+ data = /* @__PURE__ */ new Map();
712
+ makeKey(namespace, key) {
713
+ return [...namespace, key].join(":");
714
+ }
715
+ parseKey(fullKey, namespace) {
716
+ const prefix = namespace.join(":") + ":";
717
+ if (fullKey.startsWith(prefix)) return fullKey.substring(prefix.length);
718
+ return null;
719
+ }
720
+ async get(namespace, key) {
721
+ return this.data.get(this.makeKey(namespace, key));
722
+ }
723
+ async put(namespace, key, value) {
724
+ this.data.set(this.makeKey(namespace, key), value);
725
+ }
726
+ async delete(namespace, key) {
727
+ this.data.delete(this.makeKey(namespace, key));
728
+ }
729
+ async list(namespace) {
730
+ const results = [];
731
+ const prefix = namespace.join(":") + ":";
732
+ for (const [fullKey, value] of this.data.entries()) if (fullKey.startsWith(prefix)) {
733
+ const key = fullKey.substring(prefix.length);
734
+ if (!key.includes(":")) results.push({
735
+ key,
736
+ value
737
+ });
738
+ }
739
+ return results;
740
+ }
741
+ /**
742
+ * Clear all data (useful for testing).
743
+ */
744
+ clear() {
745
+ this.data.clear();
746
+ }
747
+ /**
748
+ * Get the number of stored items.
749
+ */
750
+ size() {
751
+ return this.data.size;
752
+ }
753
+ };
754
+ /**
755
+ * Backend that stores files in a persistent key-value store.
756
+ *
757
+ * This provides cross-conversation file persistence that survives between agent sessions.
758
+ * Files are stored in the provided key-value store, allowing you to use any storage backend
759
+ * (Redis, SQLite, cloud storage, etc.) by implementing the `KeyValueStore` interface.
760
+ *
761
+ * @example Using InMemoryStore (for testing or single-session persistence)
762
+ * ```typescript
763
+ * import { createDeepAgent } from 'deepagentsdk';
764
+ * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';
765
+ * import { anthropic } from '@ai-sdk/anthropic';
766
+ *
767
+ * const store = new InMemoryStore();
768
+ * const backend = new PersistentBackend({ store });
769
+ * const agent = createDeepAgent({
770
+ * model: anthropic('claude-sonnet-4-20250514'),
771
+ * backend,
772
+ * });
773
+ * ```
774
+ *
775
+ * @example With custom namespace for project isolation
776
+ * ```typescript
777
+ * import { createDeepAgent } from 'deepagentsdk';
778
+ * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';
779
+ * import { anthropic } from '@ai-sdk/anthropic';
780
+ *
781
+ * const store = new InMemoryStore();
782
+ * const backend = new PersistentBackend({
783
+ * store,
784
+ * namespace: 'project-123', // Isolate files for this project
785
+ * });
786
+ * const agent = createDeepAgent({
787
+ * model: anthropic('claude-sonnet-4-20250514'),
788
+ * backend,
789
+ * });
790
+ * ```
791
+ *
792
+ * @example Custom KeyValueStore implementation (Redis)
793
+ * ```typescript
794
+ * import { createDeepAgent } from 'deepagentsdk';
795
+ * import { PersistentBackend, type KeyValueStore } from 'deepagentsdk';
796
+ * import { anthropic } from '@ai-sdk/anthropic';
797
+ * import { createClient } from 'redis';
798
+ *
799
+ * class RedisStore implements KeyValueStore {
800
+ * constructor(private redis: ReturnType<typeof createClient>) {}
801
+ *
802
+ * async get(namespace: string[], key: string) {
803
+ * const redisKey = [...namespace, key].join(':');
804
+ * const data = await this.redis.get(redisKey);
805
+ * return data ? JSON.parse(data) : undefined;
806
+ * }
807
+ *
808
+ * async put(namespace: string[], key: string, value: Record<string, unknown>) {
809
+ * const redisKey = [...namespace, key].join(':');
810
+ * await this.redis.set(redisKey, JSON.stringify(value));
811
+ * }
812
+ *
813
+ * async delete(namespace: string[], key: string) {
814
+ * const redisKey = [...namespace, key].join(':');
815
+ * await this.redis.del(redisKey);
816
+ * }
817
+ *
818
+ * async list(namespace: string[]) {
819
+ * const prefix = [...namespace].join(':') + ':';
820
+ * const keys = await this.redis.keys(prefix + '*');
821
+ * const results = [];
822
+ * for (const key of keys) {
823
+ * const data = await this.redis.get(key);
824
+ * if (data) {
825
+ * const relativeKey = key.substring(prefix.length);
826
+ * results.push({ key: relativeKey, value: JSON.parse(data) });
827
+ * }
828
+ * }
829
+ * return results;
830
+ * }
831
+ * }
832
+ *
833
+ * const redis = createClient();
834
+ * await redis.connect();
835
+ *
836
+ * const backend = new PersistentBackend({
837
+ * store: new RedisStore(redis),
838
+ * namespace: 'production'
839
+ * });
840
+ *
841
+ * const agent = createDeepAgent({
842
+ * model: anthropic('claude-sonnet-4-20250514'),
843
+ * backend,
844
+ * });
845
+ * ```
846
+ */
847
+ var PersistentBackend = class {
848
+ store;
849
+ namespacePrefix;
850
+ /**
851
+ * Create a new PersistentBackend instance.
852
+ *
853
+ * @param options - Configuration options
854
+ * @param options.store - The key-value store implementation to use
855
+ * @param options.namespace - Optional namespace prefix for file isolation
856
+ */
857
+ constructor(options) {
858
+ this.store = options.store;
859
+ this.namespacePrefix = options.namespace || "default";
860
+ }
861
+ /**
862
+ * Get the namespace for store operations.
863
+ */
864
+ getNamespace() {
865
+ return [this.namespacePrefix, "filesystem"];
866
+ }
867
+ /**
868
+ * Convert a store value to FileData format.
869
+ */
870
+ convertToFileData(value) {
871
+ if (!value.content || !Array.isArray(value.content) || typeof value.created_at !== "string" || typeof value.modified_at !== "string") throw new Error(`Store item does not contain valid FileData fields. Got keys: ${Object.keys(value).join(", ")}`);
872
+ return {
873
+ content: value.content,
874
+ created_at: value.created_at,
875
+ modified_at: value.modified_at
876
+ };
877
+ }
878
+ /**
879
+ * Convert FileData to a value suitable for store.put().
880
+ */
881
+ convertFromFileData(fileData) {
882
+ return {
883
+ content: fileData.content,
884
+ created_at: fileData.created_at,
885
+ modified_at: fileData.modified_at
886
+ };
887
+ }
888
+ /**
889
+ * List files and directories in the specified directory (non-recursive).
890
+ */
891
+ async lsInfo(path$1) {
892
+ const namespace = this.getNamespace();
893
+ const items = await this.store.list(namespace);
894
+ const infos = [];
895
+ const subdirs = /* @__PURE__ */ new Set();
896
+ const normalizedPath = path$1.endsWith("/") ? path$1 : path$1 + "/";
897
+ for (const item of items) {
898
+ const itemKey = item.key;
899
+ if (!itemKey.startsWith(normalizedPath)) continue;
900
+ const relative = itemKey.substring(normalizedPath.length);
901
+ if (relative.includes("/")) {
902
+ const subdirName = relative.split("/")[0];
903
+ subdirs.add(normalizedPath + subdirName + "/");
904
+ continue;
905
+ }
906
+ try {
907
+ const fd = this.convertToFileData(item.value);
908
+ const size = fd.content.join("\n").length;
909
+ infos.push({
910
+ path: itemKey,
911
+ is_dir: false,
912
+ size,
913
+ modified_at: fd.modified_at
914
+ });
915
+ } catch {
916
+ continue;
917
+ }
918
+ }
919
+ for (const subdir of Array.from(subdirs).sort()) infos.push({
920
+ path: subdir,
921
+ is_dir: true,
922
+ size: 0,
923
+ modified_at: ""
924
+ });
925
+ infos.sort((a, b) => a.path.localeCompare(b.path));
926
+ return infos;
927
+ }
928
+ /**
929
+ * Read file content with line numbers.
930
+ */
931
+ async read(filePath, offset = 0, limit = 2e3) {
932
+ try {
933
+ return require_file_saver.formatReadResponse(await this.readRaw(filePath), offset, limit);
934
+ } catch (e) {
935
+ return `Error: ${e.message}`;
936
+ }
937
+ }
938
+ /**
939
+ * Read file content as raw FileData.
940
+ */
941
+ async readRaw(filePath) {
942
+ const namespace = this.getNamespace();
943
+ const value = await this.store.get(namespace, filePath);
944
+ if (!value) throw new Error(`File '${filePath}' not found`);
945
+ return this.convertToFileData(value);
946
+ }
947
+ /**
948
+ * Create a new file with content.
949
+ */
950
+ async write(filePath, content) {
951
+ const namespace = this.getNamespace();
952
+ if (await this.store.get(namespace, filePath)) return {
953
+ success: false,
954
+ error: require_file_saver.FILE_ALREADY_EXISTS(filePath)
955
+ };
956
+ const fileData = require_file_saver.createFileData(content);
957
+ const storeValue = this.convertFromFileData(fileData);
958
+ await this.store.put(namespace, filePath, storeValue);
959
+ return {
960
+ success: true,
961
+ path: filePath
962
+ };
963
+ }
964
+ /**
965
+ * Edit a file by replacing string occurrences.
966
+ */
967
+ async edit(filePath, oldString, newString, replaceAll = false) {
968
+ const namespace = this.getNamespace();
969
+ const value = await this.store.get(namespace, filePath);
970
+ if (!value) return {
971
+ success: false,
972
+ error: require_file_saver.FILE_NOT_FOUND(filePath)
973
+ };
974
+ try {
975
+ const fileData = this.convertToFileData(value);
976
+ const result = require_file_saver.performStringReplacement(require_file_saver.fileDataToString(fileData), oldString, newString, replaceAll);
977
+ if (typeof result === "string") return {
978
+ success: false,
979
+ error: result
980
+ };
981
+ const [newContent, occurrences] = result;
982
+ const newFileData = require_file_saver.updateFileData(fileData, newContent);
983
+ const storeValue = this.convertFromFileData(newFileData);
984
+ await this.store.put(namespace, filePath, storeValue);
985
+ return {
986
+ success: true,
987
+ path: filePath,
988
+ occurrences
989
+ };
990
+ } catch (e) {
991
+ return {
992
+ success: false,
993
+ error: `Error: ${e.message}`
994
+ };
995
+ }
996
+ }
997
+ /**
998
+ * Structured search results or error string for invalid input.
999
+ */
1000
+ async grepRaw(pattern, path$1 = "/", glob$1 = null) {
1001
+ const namespace = this.getNamespace();
1002
+ const items = await this.store.list(namespace);
1003
+ const files = {};
1004
+ for (const item of items) try {
1005
+ files[item.key] = this.convertToFileData(item.value);
1006
+ } catch {
1007
+ continue;
1008
+ }
1009
+ return require_file_saver.grepMatchesFromFiles(files, pattern, path$1, glob$1);
1010
+ }
1011
+ /**
1012
+ * Structured glob matching returning FileInfo objects.
1013
+ */
1014
+ async globInfo(pattern, path$1 = "/") {
1015
+ const namespace = this.getNamespace();
1016
+ const items = await this.store.list(namespace);
1017
+ const files = {};
1018
+ for (const item of items) try {
1019
+ files[item.key] = this.convertToFileData(item.value);
1020
+ } catch {
1021
+ continue;
1022
+ }
1023
+ const result = require_file_saver.globSearchFiles(files, pattern, path$1);
1024
+ if (result === "No files found") return [];
1025
+ const paths = result.split("\n");
1026
+ const infos = [];
1027
+ for (const p of paths) {
1028
+ const fd = files[p];
1029
+ const size = fd ? fd.content.join("\n").length : 0;
1030
+ infos.push({
1031
+ path: p,
1032
+ is_dir: false,
1033
+ size,
1034
+ modified_at: fd?.modified_at || ""
1035
+ });
1036
+ }
1037
+ return infos;
1038
+ }
1039
+ /**
1040
+ * Delete a file.
1041
+ */
1042
+ async deleteFile(filePath) {
1043
+ const namespace = this.getNamespace();
1044
+ if (!await this.store.get(namespace, filePath)) return { error: `File '${filePath}' not found` };
1045
+ await this.store.delete(namespace, filePath);
1046
+ return {};
1047
+ }
1048
+ };
1049
+
1050
+ //#endregion
1051
+ //#region src/tools/index.ts
1052
+ require_file_saver.init_web();
1053
+
1054
+ //#endregion
1055
+ //#region src/utils/index.ts
1056
+ require_file_saver.init_eviction();
1057
+
1058
+ //#endregion
1059
+ //#region src/checkpointer/memory-saver.ts
1060
+ /**
1061
+ * In-memory checkpoint saver.
1062
+ *
1063
+ * Stores checkpoints in a Map. Data is lost when the process exits.
1064
+ * Useful for testing or single-session applications.
1065
+ *
1066
+ * @example
1067
+ * ```typescript
1068
+ * const saver = new MemorySaver();
1069
+ * const agent = createDeepAgent({
1070
+ * model: anthropic('claude-sonnet-4-20250514'),
1071
+ * checkpointer: saver,
1072
+ * });
1073
+ * ```
1074
+ */
1075
+ var MemorySaver = class {
1076
+ checkpoints = /* @__PURE__ */ new Map();
1077
+ namespace;
1078
+ constructor(options = {}) {
1079
+ this.namespace = options.namespace || "default";
1080
+ }
1081
+ getKey(threadId) {
1082
+ return `${this.namespace}:${threadId}`;
1083
+ }
1084
+ async save(checkpoint) {
1085
+ const key = this.getKey(checkpoint.threadId);
1086
+ this.checkpoints.set(key, {
1087
+ ...checkpoint,
1088
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1089
+ });
1090
+ }
1091
+ async load(threadId) {
1092
+ const key = this.getKey(threadId);
1093
+ return this.checkpoints.get(key);
1094
+ }
1095
+ async list() {
1096
+ const prefix = `${this.namespace}:`;
1097
+ const threadIds = [];
1098
+ for (const key of this.checkpoints.keys()) if (key.startsWith(prefix)) threadIds.push(key.substring(prefix.length));
1099
+ return threadIds;
1100
+ }
1101
+ async delete(threadId) {
1102
+ const key = this.getKey(threadId);
1103
+ this.checkpoints.delete(key);
1104
+ }
1105
+ async exists(threadId) {
1106
+ const key = this.getKey(threadId);
1107
+ return this.checkpoints.has(key);
1108
+ }
1109
+ /**
1110
+ * Clear all checkpoints (useful for testing).
1111
+ */
1112
+ clear() {
1113
+ this.checkpoints.clear();
1114
+ }
1115
+ /**
1116
+ * Get the number of stored checkpoints.
1117
+ */
1118
+ size() {
1119
+ return this.checkpoints.size;
1120
+ }
1121
+ };
1122
+
1123
+ //#endregion
1124
+ //#region src/checkpointer/kv-saver.ts
1125
+ /**
1126
+ * Checkpoint saver using KeyValueStore interface.
1127
+ *
1128
+ * This adapter allows using any KeyValueStore implementation (Redis,
1129
+ * database, cloud storage, etc.) for checkpoint storage.
1130
+ *
1131
+ * @example
1132
+ * ```typescript
1133
+ * import { InMemoryStore } from 'deepagentsdk';
1134
+ *
1135
+ * const store = new InMemoryStore();
1136
+ * const saver = new KeyValueStoreSaver({ store });
1137
+ * const agent = createDeepAgent({
1138
+ * model: anthropic('claude-sonnet-4-20250514'),
1139
+ * checkpointer: saver,
1140
+ * });
1141
+ * ```
1142
+ *
1143
+ * @example With Redis
1144
+ * ```typescript
1145
+ * const redisStore = new RedisStore(redisClient); // Your implementation
1146
+ * const saver = new KeyValueStoreSaver({ store: redisStore });
1147
+ * ```
1148
+ */
1149
+ var KeyValueStoreSaver = class {
1150
+ store;
1151
+ namespace;
1152
+ constructor(options) {
1153
+ this.store = options.store;
1154
+ this.namespace = [options.namespace || "default", "checkpoints"];
1155
+ }
1156
+ async save(checkpoint) {
1157
+ const data = {
1158
+ ...checkpoint,
1159
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1160
+ };
1161
+ await this.store.put(this.namespace, checkpoint.threadId, data);
1162
+ }
1163
+ async load(threadId) {
1164
+ const data = await this.store.get(this.namespace, threadId);
1165
+ if (!data) return;
1166
+ return data;
1167
+ }
1168
+ async list() {
1169
+ return (await this.store.list(this.namespace)).map((item) => item.key);
1170
+ }
1171
+ async delete(threadId) {
1172
+ await this.store.delete(this.namespace, threadId);
1173
+ }
1174
+ async exists(threadId) {
1175
+ return await this.store.get(this.namespace, threadId) !== void 0;
1176
+ }
1177
+ };
1178
+
1179
+ //#endregion
1180
+ //#region src/middleware/agent-memory.ts
1181
+ /**
1182
+ * Load agent memory from a file path.
1183
+ * Returns empty string if file doesn't exist or can't be read.
1184
+ */
1185
+ async function loadAgentMemory(filePath) {
1186
+ try {
1187
+ return (await node_fs_promises.readFile(filePath, "utf-8")).trim();
1188
+ } catch {
1189
+ return "";
1190
+ }
1191
+ }
1192
+ /**
1193
+ * Load all additional .md files from the agent's directory (excluding agent.md).
1194
+ * Returns an array of { filename, content } objects.
1195
+ */
1196
+ async function loadAdditionalMemoryFiles(dirPath) {
1197
+ try {
1198
+ const mdFiles = (await node_fs_promises.readdir(dirPath)).filter((f) => f.endsWith(".md") && f !== "agent.md");
1199
+ return (await Promise.all(mdFiles.map(async (filename) => {
1200
+ return {
1201
+ filename,
1202
+ content: await loadAgentMemory(node_path.join(dirPath, filename))
1203
+ };
1204
+ }))).filter((r) => r.content.length > 0);
1205
+ } catch {
1206
+ return [];
1207
+ }
1208
+ }
1209
+ /**
1210
+ * Build the memory section for the system prompt.
1211
+ * This comprehensive prompt teaches the agent how to use memory effectively.
1212
+ */
1213
+ function buildMemorySection(userMemory, projectMemory, additionalFiles, agentId, userMemoryPath, projectMemoryPath) {
1214
+ let sections = [];
1215
+ if (userMemory) sections.push(`# Agent Memory (User-Level)
1216
+
1217
+ The following is your persistent memory stored at ${userMemoryPath}:
1218
+
1219
+ ${userMemory}`);
1220
+ if (projectMemory && projectMemoryPath) sections.push(`# Agent Memory (Project-Level)
1221
+
1222
+ The following is project-specific context stored at ${projectMemoryPath}:
1223
+
1224
+ ${projectMemory}`);
1225
+ if (additionalFiles.length > 0) {
1226
+ const additionalSections = additionalFiles.map(({ filename, content }) => `## ${filename}
1227
+
1228
+ ${content}`);
1229
+ sections.push(`# Additional Context Files
1230
+
1231
+ ${additionalSections.join("\n\n")}`);
1232
+ }
1233
+ if (sections.length === 0) return "";
1234
+ return `
1235
+ <agent_memory>
1236
+ ${sections.join("\n\n---\n\n")}
1237
+
1238
+ ---
1239
+
1240
+ ## How to Use This Memory
1241
+
1242
+ **What is this?**
1243
+ - The content above is your persistent memory, stored in markdown files
1244
+ - **User-level memory** (${userMemoryPath}) contains your core personality, preferences, and cross-project context
1245
+ - **Project-level memory** ${projectMemoryPath ? `(${projectMemoryPath})` : "(not available)"} contains project-specific context and conventions
1246
+
1247
+ **When to read memory:**
1248
+ - You already have the memory content above in your context - no need to read the files unless you need to verify exact content
1249
+ - If you need to check current memory state or see if it's been updated, use \`read_file\` tool
1250
+
1251
+ **When to update memory:**
1252
+ - **User memory**: When you learn something important about the user's preferences, working style, or recurring patterns
1253
+ - **Project memory**: When you discover project-specific conventions, architecture decisions, or important context
1254
+ - **Additional files**: For specialized context that doesn't fit in agent.md (e.g., decision logs, architecture notes)
1255
+
1256
+ **How to update memory:**
1257
+ - Use the \`write_file\` or \`edit_file\` tools with the file paths shown above
1258
+ - Keep entries concise and relevant
1259
+ - Organize information clearly with markdown headings
1260
+ - Remove outdated information when updating
1261
+
1262
+ **Important guidelines:**
1263
+ - Memory is meant for long-term context, not temporary task tracking
1264
+ - Don't store information that's already in the codebase or documentation
1265
+ - Focus on insights, patterns, and preferences that aren't obvious from other sources
1266
+ - When in doubt, ask the user if something should be remembered
1267
+
1268
+ **Example use cases:**
1269
+ - User prefers TypeScript strict mode and comprehensive error handling
1270
+ - Project uses custom testing framework located in \`test-utils/\`
1271
+ - User wants all API responses to follow specific error format
1272
+ - Project has specific commit message conventions
1273
+ </agent_memory>
1274
+ `.trim();
1275
+ }
1276
+ /**
1277
+ * Create agent memory middleware for AI SDK v6.
1278
+ *
1279
+ * This middleware loads agent memory from:
1280
+ * 1. User-level: ~/.deepagents/{agentId}/agent.md (personality, preferences)
1281
+ * 2. Project-level: [git-root]/.deepagents/agent.md (project-specific context)
1282
+ * 3. Additional files: Any other .md files in the user-level directory
1283
+ *
1284
+ * The memory is injected into the system prompt before each model call, teaching
1285
+ * the agent when and how to read/update its own memory using filesystem tools.
1286
+ *
1287
+ * @param options - Configuration for agent memory
1288
+ * @param options.agentId - Unique identifier for the agent (e.g., "code-architect")
1289
+ * @param options.workingDirectory - Optional working directory for project detection (defaults to process.cwd())
1290
+ * @param options.userDeepagentsDir - Optional custom path for user-level .deepagents directory (defaults to ~/.deepagents)
1291
+ * @param options.requestProjectApproval - Optional callback to request approval before creating project .deepagents/ directory
1292
+ * @returns AI SDK v6 middleware
1293
+ *
1294
+ * @example Basic usage
1295
+ * ```typescript
1296
+ * import { createDeepAgent } from 'deepagentsdk';
1297
+ * import { createAgentMemoryMiddleware } from 'deepagentsdk/middleware';
1298
+ * import { anthropic } from '@ai-sdk/anthropic';
1299
+ *
1300
+ * const memoryMiddleware = createAgentMemoryMiddleware({
1301
+ * agentId: 'code-architect',
1302
+ * });
1303
+ *
1304
+ * const agent = createDeepAgent({
1305
+ * model: anthropic('claude-sonnet-4-5'),
1306
+ * middleware: memoryMiddleware,
1307
+ * });
1308
+ * ```
1309
+ *
1310
+ * @example With project approval callback
1311
+ * ```typescript
1312
+ * const memoryMiddleware = createAgentMemoryMiddleware({
1313
+ * agentId: 'code-architect',
1314
+ * requestProjectApproval: async (projectPath) => {
1315
+ * console.log(`Create .deepagents/ in ${projectPath}? (y/n)`);
1316
+ * // ... get user input
1317
+ * return userSaidYes;
1318
+ * }
1319
+ * });
1320
+ * ```
1321
+ *
1322
+ * @example With custom user directory path
1323
+ * ```typescript
1324
+ * const memoryMiddleware = createAgentMemoryMiddleware({
1325
+ * agentId: 'code-architect',
1326
+ * userDeepagentsDir: '/custom/path/.deepagents',
1327
+ * // Memory will be loaded from:
1328
+ * // - /custom/path/.deepagents/code-architect/agent.md
1329
+ * // - [git-root]/.deepagents/agent.md (project-level)
1330
+ * });
1331
+ * ```
1332
+ */
1333
+ function createAgentMemoryMiddleware(options) {
1334
+ const { agentId, workingDirectory, userDeepagentsDir, requestProjectApproval } = options;
1335
+ let memoryLoaded = false;
1336
+ let cachedMemorySection = "";
1337
+ return {
1338
+ specificationVersion: "v3",
1339
+ transformParams: async ({ params }) => {
1340
+ if (!memoryLoaded) {
1341
+ const workDir = workingDirectory || process.cwd();
1342
+ const baseUserDir = userDeepagentsDir || node_path.join(node_os.default.homedir(), ".deepagents");
1343
+ const userAgentDir = node_path.join(baseUserDir, agentId);
1344
+ const userMemoryPath = node_path.join(userAgentDir, "agent.md");
1345
+ const userMemory = await loadAgentMemory(userMemoryPath);
1346
+ if (!userMemory) try {
1347
+ await node_fs_promises.mkdir(userAgentDir, { recursive: true });
1348
+ } catch {}
1349
+ const additionalFiles = await loadAdditionalMemoryFiles(userAgentDir);
1350
+ let projectMemory = "";
1351
+ let projectMemoryPath = null;
1352
+ const gitRoot = await require_load.findGitRoot(workDir);
1353
+ if (gitRoot) {
1354
+ const projectDeepagentsDir = node_path.join(gitRoot, ".deepagents");
1355
+ projectMemoryPath = node_path.join(projectDeepagentsDir, "agent.md");
1356
+ try {
1357
+ await node_fs_promises.stat(projectDeepagentsDir);
1358
+ projectMemory = await loadAgentMemory(projectMemoryPath);
1359
+ } catch {
1360
+ if (requestProjectApproval) {
1361
+ if (await requestProjectApproval(gitRoot)) try {
1362
+ await node_fs_promises.mkdir(projectDeepagentsDir, { recursive: true });
1363
+ } catch {}
1364
+ }
1365
+ }
1366
+ }
1367
+ cachedMemorySection = buildMemorySection(userMemory, projectMemory, additionalFiles, agentId, userMemoryPath, projectMemoryPath);
1368
+ memoryLoaded = true;
1369
+ }
1370
+ if (cachedMemorySection) {
1371
+ const updatedPrompt = params.prompt.map((msg) => {
1372
+ if (msg.role === "system") return {
1373
+ ...msg,
1374
+ content: `${msg.content}\n\n${cachedMemorySection}`
1375
+ };
1376
+ return msg;
1377
+ });
1378
+ return {
1379
+ ...params,
1380
+ prompt: updatedPrompt
1381
+ };
1382
+ }
1383
+ return params;
1384
+ }
1385
+ };
1386
+ }
1387
+
1388
+ //#endregion
1389
+ exports.BASE_PROMPT = require_file_saver.BASE_PROMPT;
1390
+ exports.BaseSandbox = require_file_saver.BaseSandbox;
1391
+ exports.CompositeBackend = CompositeBackend;
1392
+ exports.DEFAULT_EVICTION_TOKEN_LIMIT = require_file_saver.DEFAULT_EVICTION_TOKEN_LIMIT;
1393
+ exports.DEFAULT_GENERAL_PURPOSE_DESCRIPTION = require_file_saver.DEFAULT_GENERAL_PURPOSE_DESCRIPTION;
1394
+ exports.DEFAULT_KEEP_MESSAGES = require_file_saver.DEFAULT_KEEP_MESSAGES;
1395
+ exports.DEFAULT_SUBAGENT_PROMPT = require_file_saver.DEFAULT_SUBAGENT_PROMPT;
1396
+ exports.DEFAULT_SUMMARIZATION_THRESHOLD = require_file_saver.DEFAULT_SUMMARIZATION_THRESHOLD;
1397
+ exports.DeepAgent = require_file_saver.DeepAgent;
1398
+ exports.EXECUTE_SYSTEM_PROMPT = require_file_saver.EXECUTE_SYSTEM_PROMPT;
1399
+ exports.FILESYSTEM_SYSTEM_PROMPT = require_file_saver.FILESYSTEM_SYSTEM_PROMPT;
1400
+ exports.FileSaver = require_file_saver.FileSaver;
1401
+ exports.FilesystemBackend = FilesystemBackend;
1402
+ exports.InMemoryStore = InMemoryStore;
1403
+ exports.KeyValueStoreSaver = KeyValueStoreSaver;
1404
+ exports.LocalSandbox = require_file_saver.LocalSandbox;
1405
+ exports.MemorySaver = MemorySaver;
1406
+ exports.PersistentBackend = PersistentBackend;
1407
+ exports.StateBackend = require_file_saver.StateBackend;
1408
+ exports.TASK_SYSTEM_PROMPT = require_file_saver.TASK_SYSTEM_PROMPT;
1409
+ exports.TODO_SYSTEM_PROMPT = require_file_saver.TODO_SYSTEM_PROMPT;
1410
+ Object.defineProperty(exports, 'ToolLoopAgent', {
1411
+ enumerable: true,
1412
+ get: function () {
1413
+ return ai.ToolLoopAgent;
1414
+ }
1415
+ });
1416
+ exports.createAgentMemoryMiddleware = createAgentMemoryMiddleware;
1417
+ exports.createDeepAgent = require_file_saver.createDeepAgent;
1418
+ exports.createEditFileTool = require_file_saver.createEditFileTool;
1419
+ exports.createExecuteTool = require_file_saver.createExecuteTool;
1420
+ exports.createExecuteToolFromBackend = require_file_saver.createExecuteToolFromBackend;
1421
+ exports.createFetchUrlTool = require_file_saver.createFetchUrlTool;
1422
+ exports.createFilesystemTools = require_file_saver.createFilesystemTools;
1423
+ exports.createGlobTool = require_file_saver.createGlobTool;
1424
+ exports.createGrepTool = require_file_saver.createGrepTool;
1425
+ exports.createHttpRequestTool = require_file_saver.createHttpRequestTool;
1426
+ exports.createLsTool = require_file_saver.createLsTool;
1427
+ exports.createReadFileTool = require_file_saver.createReadFileTool;
1428
+ exports.createSubagentTool = require_file_saver.createSubagentTool;
1429
+ exports.createTodosTool = require_file_saver.createTodosTool;
1430
+ exports.createToolResultWrapper = require_file_saver.createToolResultWrapper;
1431
+ exports.createWebSearchTool = require_file_saver.createWebSearchTool;
1432
+ exports.createWebTools = require_file_saver.createWebTools;
1433
+ exports.createWriteFileTool = require_file_saver.createWriteFileTool;
1434
+ exports.edit_file = require_file_saver.edit_file;
1435
+ exports.estimateMessagesTokens = require_file_saver.estimateMessagesTokens;
1436
+ exports.estimateTokens = require_file_saver.estimateTokens;
1437
+ exports.eventHasStructuredOutput = eventHasStructuredOutput;
1438
+ exports.evictToolResult = require_file_saver.evictToolResult;
1439
+ exports.execute = require_file_saver.execute;
1440
+ exports.fetch_url = require_file_saver.fetch_url;
1441
+ exports.findGitRoot = require_load.findGitRoot;
1442
+ exports.getEventOutput = getEventOutput;
1443
+ exports.getStructuredOutput = getStructuredOutput;
1444
+ exports.getTaskToolDescription = require_file_saver.getTaskToolDescription;
1445
+ exports.glob = require_file_saver.glob;
1446
+ exports.grep = require_file_saver.grep;
1447
+ exports.hasDanglingToolCalls = require_file_saver.hasDanglingToolCalls;
1448
+ exports.hasStructuredOutput = hasStructuredOutput;
1449
+ Object.defineProperty(exports, 'hasToolCall', {
1450
+ enumerable: true,
1451
+ get: function () {
1452
+ return ai.hasToolCall;
1453
+ }
1454
+ });
1455
+ exports.htmlToMarkdown = require_file_saver.htmlToMarkdown;
1456
+ exports.http_request = require_file_saver.http_request;
1457
+ exports.isSandboxBackend = require_file_saver.isSandboxBackend;
1458
+ exports.listSkills = require_load.listSkills;
1459
+ exports.ls = require_file_saver.ls;
1460
+ exports.needsSummarization = require_file_saver.needsSummarization;
1461
+ exports.parseSkillMetadata = require_load.parseSkillMetadata;
1462
+ exports.patchToolCalls = require_file_saver.patchToolCalls;
1463
+ exports.read_file = require_file_saver.read_file;
1464
+ exports.shouldEvict = require_file_saver.shouldEvict;
1465
+ Object.defineProperty(exports, 'stepCountIs', {
1466
+ enumerable: true,
1467
+ get: function () {
1468
+ return ai.stepCountIs;
1469
+ }
1470
+ });
1471
+ exports.summarizeIfNeeded = require_file_saver.summarizeIfNeeded;
1472
+ exports.web_search = require_file_saver.web_search;
1473
+ Object.defineProperty(exports, 'wrapLanguageModel', {
1474
+ enumerable: true,
1475
+ get: function () {
1476
+ return ai.wrapLanguageModel;
1477
+ }
1478
+ });
1479
+ exports.write_file = require_file_saver.write_file;
1480
+ exports.write_todos = require_file_saver.write_todos;
1481
+ //# sourceMappingURL=index.cjs.map