deepagentsdk 0.12.0 → 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 (37) hide show
  1. package/dist/adapters/elements/index.cjs +244 -294
  2. package/dist/adapters/elements/index.cjs.map +1 -1
  3. package/dist/adapters/elements/index.d.cts +84 -174
  4. package/dist/adapters/elements/index.d.mts +84 -174
  5. package/dist/adapters/elements/index.mjs +238 -290
  6. package/dist/adapters/elements/index.mjs.map +1 -1
  7. package/dist/{types-4g9UvXal.d.mts → agent-BDM-PIu8.d.mts} +374 -25
  8. package/dist/{types-IulnvhFg.d.cts → agent-DToEVxs-.d.cts} +374 -25
  9. package/dist/{chunk-CbDLau6x.cjs → chunk-C5azi7Hr.cjs} +33 -0
  10. package/dist/cli/index.cjs +12 -12
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.mjs +2 -2
  13. package/dist/cli/index.mjs.map +1 -1
  14. package/dist/{agent-Cuks-Idh.cjs → file-saver-BYPKakT4.cjs} +799 -205
  15. package/dist/file-saver-BYPKakT4.cjs.map +1 -0
  16. package/dist/{agent-CrH-He58.mjs → file-saver-Hj5so3dV.mjs} +793 -199
  17. package/dist/file-saver-Hj5so3dV.mjs.map +1 -0
  18. package/dist/index.cjs +83 -73
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +5 -353
  21. package/dist/index.d.mts +5 -353
  22. package/dist/index.mjs +13 -3
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{load-B6CA5js_.mjs → load-BBYEnMwz.mjs} +1 -1
  25. package/dist/{load-B6CA5js_.mjs.map → load-BBYEnMwz.mjs.map} +1 -1
  26. package/dist/{load-94gjHorc.mjs → load-BDxe6Cet.mjs} +1 -1
  27. package/dist/{load-79a2H4m0.cjs → load-BrRAKlO6.cjs} +2 -2
  28. package/dist/{load-79a2H4m0.cjs.map → load-BrRAKlO6.cjs.map} +1 -1
  29. package/dist/load-DqllBbDc.cjs +4 -0
  30. package/package.json +1 -1
  31. package/dist/agent-CrH-He58.mjs.map +0 -1
  32. package/dist/agent-Cuks-Idh.cjs.map +0 -1
  33. package/dist/file-saver-BJCqMIb5.mjs +0 -655
  34. package/dist/file-saver-BJCqMIb5.mjs.map +0 -1
  35. package/dist/file-saver-C6O2LAvg.cjs +0 -679
  36. package/dist/file-saver-C6O2LAvg.cjs.map +0 -1
  37. package/dist/load-C2qVmZMp.cjs +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["fsSync","MAX_FILE_SIZE_MB","fs","DEFAULT_READ_LIMIT","FILE_NOT_FOUND","checkEmptyContent","formatContentWithLineNumbers","FILE_ALREADY_EXISTS","performStringReplacement","glob","path","glob","path","formatReadResponse","FILE_ALREADY_EXISTS","createFileData","FILE_NOT_FOUND","performStringReplacement","fileDataToString","updateFileData","grepMatchesFromFiles","glob","globSearchFiles","fs","path","os","findGitRoot"],"sources":["../src/types/structured-output.ts","../src/backends/filesystem.ts","../src/backends/composite.ts","../src/backends/persistent.ts","../src/checkpointer/memory-saver.ts","../src/checkpointer/kv-saver.ts","../src/middleware/agent-memory.ts"],"sourcesContent":["// Zod import removed - not needed for these utility functions\n\n/**\n * Interface for agent results that include structured output\n */\nexport interface StructuredAgentResult<T = unknown> {\n text: string;\n output?: T;\n state?: any; // DeepAgentState from core types\n messages?: any[]; // ModelMessage array\n}\n\n/**\n * Type guard for checking if a result has structured output\n */\nexport function hasStructuredOutput<T>(\n result: any\n): result is StructuredAgentResult<T> {\n return result && typeof result === \"object\" && \"output\" in result;\n}\n\n/**\n * Type guard for checking if an event has structured output\n */\nexport function eventHasStructuredOutput<T>(\n event: any\n): event is { type: \"done\"; output: T } {\n return event && event.type === \"done\" && \"output\" in event;\n}\n\n/**\n * Extract structured output from agent result with type safety\n */\nexport function getStructuredOutput<T>(result: any): T | undefined {\n return hasStructuredOutput<T>(result) ? result.output : undefined;\n}\n\n/**\n * Extract structured output from event with type safety\n */\nexport function getEventOutput<T>(event: any): T | undefined {\n return eventHasStructuredOutput<T>(event) ? event.output : undefined;\n}","/**\n * FilesystemBackend: Read and write files directly from the filesystem.\n */\n\nimport * as fs from \"fs/promises\";\nimport * as fsSync from \"fs\";\nimport * as path from \"path\";\nimport { spawn } from \"child_process\";\nimport fg from \"fast-glob\";\nimport micromatch from \"micromatch\";\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\nimport {\n checkEmptyContent,\n formatContentWithLineNumbers,\n performStringReplacement,\n} from \"./utils\";\nimport {\n FILE_NOT_FOUND,\n FILE_ALREADY_EXISTS,\n} from \"../constants/errors\";\nimport { MAX_FILE_SIZE_MB, DEFAULT_READ_LIMIT } from \"../constants/limits\";\n\nconst SUPPORTS_NOFOLLOW = fsSync.constants.O_NOFOLLOW !== undefined;\n\n/**\n * Backend that reads and writes files directly from the filesystem.\n *\n * Files are persisted to disk, making them available across agent invocations.\n * This backend provides real file I/O operations with security checks to prevent\n * directory traversal attacks.\n *\n * @example Basic usage\n * ```typescript\n * const backend = new FilesystemBackend({ rootDir: './workspace' });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example With custom options\n * ```typescript\n * const backend = new FilesystemBackend({\n * rootDir: './my-project',\n * virtualMode: false,\n * maxFileSizeMb: 50, // Allow larger files\n * });\n * ```\n */\nexport class FilesystemBackend implements BackendProtocol {\n private cwd: string;\n private virtualMode: boolean;\n private maxFileSizeBytes: number;\n\n /**\n * Create a new FilesystemBackend instance.\n *\n * @param options - Configuration options\n * @param options.rootDir - Optional root directory for file operations (default: current working directory).\n * All file paths are resolved relative to this directory.\n * @param options.virtualMode - Optional flag for virtual mode (default: false).\n * When true, files are stored in memory but paths are validated against filesystem.\n * @param options.maxFileSizeMb - Optional maximum file size in MB (default: 10).\n * Files larger than this will be rejected.\n */\n constructor(\n options: {\n rootDir?: string;\n virtualMode?: boolean;\n maxFileSizeMb?: number;\n } = {}\n ) {\n const { rootDir, virtualMode = false, maxFileSizeMb = MAX_FILE_SIZE_MB } = options;\n this.cwd = rootDir ? path.resolve(rootDir) : process.cwd();\n this.virtualMode = virtualMode;\n this.maxFileSizeBytes = maxFileSizeMb * 1024 * 1024;\n }\n\n /**\n * Resolve a file path with security checks.\n */\n private resolvePath(key: string): string {\n if (this.virtualMode) {\n const vpath = key.startsWith(\"/\") ? key : \"/\" + key;\n if (vpath.includes(\"..\") || vpath.startsWith(\"~\")) {\n throw new Error(\"Path traversal not allowed\");\n }\n const full = path.resolve(this.cwd, vpath.substring(1));\n const relative = path.relative(this.cwd, full);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`Path: ${full} outside root directory: ${this.cwd}`);\n }\n return full;\n }\n\n if (path.isAbsolute(key)) {\n return key;\n }\n return path.resolve(this.cwd, key);\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(dirPath: string): Promise<FileInfo[]> {\n try {\n const resolvedPath = this.resolvePath(dirPath);\n const stat = await fs.stat(resolvedPath);\n\n if (!stat.isDirectory()) {\n return [];\n }\n\n const entries = await fs.readdir(resolvedPath, { withFileTypes: true });\n const results: FileInfo[] = [];\n\n const cwdStr = this.cwd.endsWith(path.sep)\n ? this.cwd\n : this.cwd + path.sep;\n\n for (const entry of entries) {\n const fullPath = path.join(resolvedPath, entry.name);\n\n try {\n const entryStat = await fs.stat(fullPath);\n const isFile = entryStat.isFile();\n const isDir = entryStat.isDirectory();\n\n if (!this.virtualMode) {\n if (isFile) {\n results.push({\n path: fullPath,\n is_dir: false,\n size: entryStat.size,\n modified_at: entryStat.mtime.toISOString(),\n });\n } else if (isDir) {\n results.push({\n path: fullPath + path.sep,\n is_dir: true,\n size: 0,\n modified_at: entryStat.mtime.toISOString(),\n });\n }\n } else {\n let relativePath: string;\n if (fullPath.startsWith(cwdStr)) {\n relativePath = fullPath.substring(cwdStr.length);\n } else if (fullPath.startsWith(this.cwd)) {\n relativePath = fullPath\n .substring(this.cwd.length)\n .replace(/^[/\\\\]/, \"\");\n } else {\n relativePath = fullPath;\n }\n\n relativePath = relativePath.split(path.sep).join(\"/\");\n const virtPath = \"/\" + relativePath;\n\n if (isFile) {\n results.push({\n path: virtPath,\n is_dir: false,\n size: entryStat.size,\n modified_at: entryStat.mtime.toISOString(),\n });\n } else if (isDir) {\n results.push({\n path: virtPath + \"/\",\n is_dir: true,\n size: 0,\n modified_at: entryStat.mtime.toISOString(),\n });\n }\n }\n } catch {\n continue;\n }\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n } catch {\n return [];\n }\n }\n\n /**\n * Read file content with line numbers.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = DEFAULT_READ_LIMIT\n ): Promise<string> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n\n if (SUPPORTS_NOFOLLOW) {\n const stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) {\n return FILE_NOT_FOUND(filePath);\n }\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return `Error: Symlinks are not allowed: ${filePath}`;\n }\n if (!stat.isFile()) {\n return FILE_NOT_FOUND(filePath);\n }\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n const emptyMsg = checkEmptyContent(content);\n if (emptyMsg) {\n return emptyMsg;\n }\n\n const lines = content.split(\"\\n\");\n const startIdx = offset;\n const endIdx = Math.min(startIdx + limit, lines.length);\n\n if (startIdx >= lines.length) {\n return `Error: Line offset ${offset} exceeds file length (${lines.length} lines)`;\n }\n\n const selectedLines = lines.slice(startIdx, endIdx);\n return formatContentWithLineNumbers(selectedLines, startIdx + 1);\n } catch (e: unknown) {\n const error = e as Error;\n return `Error reading file '${filePath}': ${error.message}`;\n }\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n let stat: fsSync.Stats;\n\n if (SUPPORTS_NOFOLLOW) {\n stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Symlinks are not allowed: ${filePath}`);\n }\n if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n return {\n content: content.split(\"\\n\"),\n created_at: stat.ctime.toISOString(),\n modified_at: stat.mtime.toISOString(),\n };\n }\n\n /**\n * Create a new file with content.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n try {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return {\n success: false,\n error: `Cannot write to ${filePath} because it is a symlink. Symlinks are not allowed.`,\n };\n }\n return {\n success: false,\n error: FILE_ALREADY_EXISTS(filePath),\n };\n } catch {\n // File doesn't exist, good to proceed\n }\n\n await fs.mkdir(path.dirname(resolvedPath), { recursive: true });\n\n if (SUPPORTS_NOFOLLOW) {\n const flags =\n fsSync.constants.O_WRONLY |\n fsSync.constants.O_CREAT |\n fsSync.constants.O_TRUNC |\n fsSync.constants.O_NOFOLLOW;\n\n const fd = await fs.open(resolvedPath, flags, 0o644);\n try {\n await fd.writeFile(content, \"utf-8\");\n } finally {\n await fd.close();\n }\n } else {\n await fs.writeFile(resolvedPath, content, \"utf-8\");\n }\n\n return { success: true, path: filePath };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error writing file '${filePath}': ${error.message}` };\n }\n }\n\n /**\n * Edit a file by replacing string occurrences.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n\n if (SUPPORTS_NOFOLLOW) {\n const stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return { success: false, error: `Error: Symlinks are not allowed: ${filePath}` };\n }\n if (!stat.isFile()) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n const result = performStringReplacement(\n content,\n oldString,\n newString,\n replaceAll\n );\n\n if (typeof result === \"string\") {\n return { success: false, error: result };\n }\n\n const [newContent, occurrences] = result;\n\n if (SUPPORTS_NOFOLLOW) {\n const flags =\n fsSync.constants.O_WRONLY |\n fsSync.constants.O_TRUNC |\n fsSync.constants.O_NOFOLLOW;\n\n const fd = await fs.open(resolvedPath, flags);\n try {\n await fd.writeFile(newContent, \"utf-8\");\n } finally {\n await fd.close();\n }\n } else {\n await fs.writeFile(resolvedPath, newContent, \"utf-8\");\n }\n\n return { success: true, path: filePath, occurrences };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error editing file '${filePath}': ${error.message}` };\n }\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n dirPath: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n // Validate regex\n try {\n new RegExp(pattern);\n } catch (e: unknown) {\n const error = e as Error;\n return `Invalid regex pattern: ${error.message}`;\n }\n\n // Resolve base path\n let baseFull: string;\n try {\n baseFull = this.resolvePath(dirPath || \".\");\n } catch {\n return [];\n }\n\n try {\n await fs.stat(baseFull);\n } catch {\n return [];\n }\n\n // Try ripgrep first, fallback to regex search\n let results = await this.ripgrepSearch(pattern, baseFull, glob);\n if (results === null) {\n results = await this.regexSearch(pattern, baseFull, glob);\n }\n\n const matches: GrepMatch[] = [];\n for (const [fpath, items] of Object.entries(results)) {\n for (const [lineNum, lineText] of items) {\n matches.push({ path: fpath, line: lineNum, text: lineText });\n }\n }\n return matches;\n }\n\n /**\n * Try to use ripgrep for fast searching.\n */\n private async ripgrepSearch(\n pattern: string,\n baseFull: string,\n includeGlob: string | null\n ): Promise<Record<string, Array<[number, string]>> | null> {\n return new Promise((resolve) => {\n const args = [\"--json\"];\n if (includeGlob) {\n args.push(\"--glob\", includeGlob);\n }\n args.push(\"--\", pattern, baseFull);\n\n const proc = spawn(\"rg\", args, { timeout: 30000 });\n const results: Record<string, Array<[number, string]>> = {};\n let output = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n output += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n if (code !== 0 && code !== 1) {\n resolve(null);\n return;\n }\n\n for (const line of output.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const data = JSON.parse(line);\n if (data.type !== \"match\") continue;\n\n const pdata = data.data || {};\n const ftext = pdata.path?.text;\n if (!ftext) continue;\n\n let virtPath: string;\n if (this.virtualMode) {\n try {\n const resolved = path.resolve(ftext);\n const relative = path.relative(this.cwd, resolved);\n if (relative.startsWith(\"..\")) continue;\n const normalizedRelative = relative.split(path.sep).join(\"/\");\n virtPath = \"/\" + normalizedRelative;\n } catch {\n continue;\n }\n } else {\n virtPath = ftext;\n }\n\n const ln = pdata.line_number;\n const lt = pdata.lines?.text?.replace(/\\n$/, \"\") || \"\";\n if (ln === undefined) continue;\n\n if (!results[virtPath]) {\n results[virtPath] = [];\n }\n results[virtPath]!.push([ln, lt]);\n } catch {\n continue;\n }\n }\n\n resolve(results);\n });\n\n proc.on(\"error\", () => {\n resolve(null);\n });\n });\n }\n\n /**\n * Fallback regex search implementation.\n */\n private async regexSearch(\n pattern: string,\n baseFull: string,\n includeGlob: string | null\n ): Promise<Record<string, Array<[number, string]>>> {\n let regex: RegExp;\n try {\n regex = new RegExp(pattern);\n } catch {\n return {};\n }\n\n const results: Record<string, Array<[number, string]>> = {};\n const stat = await fs.stat(baseFull);\n const root = stat.isDirectory() ? baseFull : path.dirname(baseFull);\n\n const files = await fg(\"**/*\", {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n dot: true,\n });\n\n for (const fp of files) {\n try {\n if (\n includeGlob &&\n !micromatch.isMatch(path.basename(fp), includeGlob)\n ) {\n continue;\n }\n\n const fileStat = await fs.stat(fp);\n if (fileStat.size > this.maxFileSizeBytes) {\n continue;\n }\n\n const content = await fs.readFile(fp, \"utf-8\");\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line && regex.test(line)) {\n let virtPath: string;\n if (this.virtualMode) {\n try {\n const relative = path.relative(this.cwd, fp);\n if (relative.startsWith(\"..\")) continue;\n const normalizedRelative = relative.split(path.sep).join(\"/\");\n virtPath = \"/\" + normalizedRelative;\n } catch {\n continue;\n }\n } else {\n virtPath = fp;\n }\n\n if (!results[virtPath]) {\n results[virtPath] = [];\n }\n results[virtPath]!.push([i + 1, line]);\n }\n }\n } catch {\n continue;\n }\n }\n\n return results;\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, searchPath: string = \"/\"): Promise<FileInfo[]> {\n if (pattern.startsWith(\"/\")) {\n pattern = pattern.substring(1);\n }\n\n const resolvedSearchPath =\n searchPath === \"/\" ? this.cwd : this.resolvePath(searchPath);\n\n try {\n const stat = await fs.stat(resolvedSearchPath);\n if (!stat.isDirectory()) {\n return [];\n }\n } catch {\n return [];\n }\n\n const results: FileInfo[] = [];\n\n try {\n const matches = await fg(pattern, {\n cwd: resolvedSearchPath,\n absolute: true,\n onlyFiles: true,\n dot: true,\n });\n\n for (const matchedPath of matches) {\n try {\n const fileStat = await fs.stat(matchedPath);\n if (!fileStat.isFile()) continue;\n\n const normalizedPath = matchedPath.split(\"/\").join(path.sep);\n\n if (!this.virtualMode) {\n results.push({\n path: normalizedPath,\n is_dir: false,\n size: fileStat.size,\n modified_at: fileStat.mtime.toISOString(),\n });\n } else {\n const cwdStr = this.cwd.endsWith(path.sep)\n ? this.cwd\n : this.cwd + path.sep;\n let relativePath: string;\n\n if (normalizedPath.startsWith(cwdStr)) {\n relativePath = normalizedPath.substring(cwdStr.length);\n } else if (normalizedPath.startsWith(this.cwd)) {\n relativePath = normalizedPath\n .substring(this.cwd.length)\n .replace(/^[/\\\\]/, \"\");\n } else {\n relativePath = normalizedPath;\n }\n\n relativePath = relativePath.split(path.sep).join(\"/\");\n const virt = \"/\" + relativePath;\n results.push({\n path: virt,\n is_dir: false,\n size: fileStat.size,\n modified_at: fileStat.mtime.toISOString(),\n });\n }\n } catch {\n continue;\n }\n }\n } catch {\n // Ignore glob errors\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n}\n\n","/**\n * CompositeBackend: Route operations to different backends based on path prefix.\n */\n\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\n\n/**\n * Backend that routes file operations to different backends based on path prefix.\n *\n * This enables hybrid storage strategies by routing files to different backends\n * based on their path prefix. Useful for separating persistent and ephemeral storage,\n * or using different storage backends for different types of files.\n *\n * @example Hybrid storage strategy\n * ```typescript\n * import { CompositeBackend, FilesystemBackend, StateBackend } from 'deepagentsdk';\n *\n * const state = { todos: [], files: {} };\n * const backend = new CompositeBackend(\n * new StateBackend(state), // Default: ephemeral storage\n * {\n * '/persistent/': new FilesystemBackend({ rootDir: './persistent' }), // Persistent files\n * '/cache/': new StateBackend(state), // Cached files (ephemeral)\n * }\n * );\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example Multiple persistent backends\n * ```typescript\n * const backend = new CompositeBackend(\n * new FilesystemBackend({ rootDir: './default' }),\n * {\n * '/user-data/': new FilesystemBackend({ rootDir: './user-data' }),\n * '/system/': new FilesystemBackend({ rootDir: './system' }),\n * }\n * );\n * ```\n */\nexport class CompositeBackend implements BackendProtocol {\n private defaultBackend: BackendProtocol;\n private routes: Record<string, BackendProtocol>;\n private sortedRoutes: Array<[string, BackendProtocol]>;\n\n /**\n * Create a new CompositeBackend instance.\n *\n * @param defaultBackend - Backend to use for paths that don't match any route prefix\n * @param routes - Record mapping path prefixes to backends.\n * Routes are matched by longest prefix first.\n * Example: `{ '/persistent/': filesystemBackend, '/cache/': stateBackend }`\n */\n constructor(\n defaultBackend: BackendProtocol,\n routes: Record<string, BackendProtocol>\n ) {\n this.defaultBackend = defaultBackend;\n this.routes = routes;\n\n // Sort routes by length (longest first) for correct prefix matching\n this.sortedRoutes = Object.entries(routes).sort(\n (a, b) => b[0].length - a[0].length\n );\n }\n\n /**\n * Determine which backend handles this key and strip prefix.\n */\n private getBackendAndKey(key: string): [BackendProtocol, string] {\n for (const [prefix, backend] of this.sortedRoutes) {\n if (key.startsWith(prefix)) {\n const suffix = key.substring(prefix.length);\n const strippedKey = suffix ? \"/\" + suffix : \"/\";\n return [backend, strippedKey];\n }\n }\n\n return [this.defaultBackend, key];\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(path: string): Promise<FileInfo[]> {\n // Check if path matches a specific route\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const infos = await backend.lsInfo(searchPath);\n\n // Add route prefix back to paths\n const prefixed: FileInfo[] = [];\n for (const fi of infos) {\n prefixed.push({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n });\n }\n return prefixed;\n }\n }\n\n // At root, aggregate default and all routed backends\n if (path === \"/\") {\n const results: FileInfo[] = [];\n const defaultInfos = await this.defaultBackend.lsInfo(path);\n results.push(...defaultInfos);\n\n // Add the route itself as a directory\n for (const [routePrefix] of this.sortedRoutes) {\n results.push({\n path: routePrefix,\n is_dir: true,\n size: 0,\n modified_at: \"\",\n });\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n\n // Path doesn't match a route: query only default backend\n return await this.defaultBackend.lsInfo(path);\n }\n\n /**\n * Read file content, routing to appropriate backend.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 2000\n ): Promise<string> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.read(strippedKey, offset, limit);\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.readRaw(strippedKey);\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n // If path targets a specific route, search only that backend\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const raw = await backend.grepRaw(pattern, searchPath, glob);\n\n if (typeof raw === \"string\") {\n return raw;\n }\n\n return raw.map((m) => ({\n ...m,\n path: routePrefix.slice(0, -1) + m.path,\n }));\n }\n }\n\n // Otherwise, search default and all routed backends and merge\n const allMatches: GrepMatch[] = [];\n const rawDefault = await this.defaultBackend.grepRaw(pattern, path, glob);\n\n if (typeof rawDefault === \"string\") {\n return rawDefault;\n }\n\n allMatches.push(...rawDefault);\n\n // Search all routes\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n const raw = await backend.grepRaw(pattern, \"/\", glob);\n\n if (typeof raw === \"string\") {\n return raw;\n }\n\n allMatches.push(\n ...raw.map((m) => ({\n ...m,\n path: routePrefix.slice(0, -1) + m.path,\n }))\n );\n }\n\n return allMatches;\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, path: string = \"/\"): Promise<FileInfo[]> {\n const results: FileInfo[] = [];\n\n // Route based on path\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const infos = await backend.globInfo(pattern, searchPath);\n\n return infos.map((fi) => ({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n }));\n }\n }\n\n // Path doesn't match any specific route - search all backends\n const defaultInfos = await this.defaultBackend.globInfo(pattern, path);\n results.push(...defaultInfos);\n\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n const infos = await backend.globInfo(pattern, \"/\");\n results.push(\n ...infos.map((fi) => ({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n }))\n );\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n\n /**\n * Create a new file, routing to appropriate backend.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.write(strippedKey, content);\n }\n\n /**\n * Edit a file, routing to appropriate backend.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.edit(strippedKey, oldString, newString, replaceAll);\n }\n}\n\n","/**\n * PersistentBackend: Generic persistent storage backend.\n *\n * This backend provides cross-conversation file persistence using a\n * pluggable key-value store interface. It can be used with various\n * storage solutions like Redis, SQLite, or any custom implementation.\n */\n\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\nimport {\n createFileData,\n fileDataToString,\n formatReadResponse,\n globSearchFiles,\n grepMatchesFromFiles,\n performStringReplacement,\n updateFileData,\n} from \"./utils\";\nimport {\n FILE_NOT_FOUND,\n FILE_ALREADY_EXISTS,\n} from \"../constants/errors\";\n\n/**\n * Generic key-value store interface for persistent storage.\n *\n * Implement this interface to use any storage backend (Redis, SQLite, cloud storage, etc.)\n * with PersistentBackend. The interface uses hierarchical namespaces for organization.\n *\n * @example Redis implementation\n * ```typescript\n * class RedisStore implements KeyValueStore {\n * constructor(private redis: RedisClient) {}\n *\n * async get(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * const data = await this.redis.get(redisKey);\n * return data ? JSON.parse(data) : undefined;\n * }\n *\n * async put(namespace: string[], key: string, value: Record<string, unknown>) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.set(redisKey, JSON.stringify(value));\n * }\n *\n * async delete(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.del(redisKey);\n * }\n *\n * async list(namespace: string[]) {\n * const prefix = [...namespace].join(':') + ':';\n * const keys = await this.redis.keys(prefix + '*');\n * const results = [];\n * for (const key of keys) {\n * const data = await this.redis.get(key);\n * if (data) {\n * const relativeKey = key.substring(prefix.length);\n * results.push({ key: relativeKey, value: JSON.parse(data) });\n * }\n * }\n * return results;\n * }\n * }\n * ```\n */\nexport interface KeyValueStore {\n /**\n * Get a value by key from the store.\n * @param namespace - Hierarchical namespace array (e.g., [\"project1\", \"filesystem\"])\n * @param key - The key to retrieve (file path in the case of PersistentBackend)\n * @returns The stored value as a record, or undefined if not found\n */\n get(namespace: string[], key: string): Promise<Record<string, unknown> | undefined>;\n\n /**\n * Store a value by key in the store.\n * @param namespace - Hierarchical namespace array\n * @param key - The key to store (file path in the case of PersistentBackend)\n * @param value - The value to store (must be serializable to JSON)\n */\n put(namespace: string[], key: string, value: Record<string, unknown>): Promise<void>;\n\n /**\n * Delete a value by key from the store.\n * @param namespace - Hierarchical namespace array\n * @param key - The key to delete (file path in the case of PersistentBackend)\n */\n delete(namespace: string[], key: string): Promise<void>;\n\n /**\n * List all keys and values in a namespace.\n * @param namespace - Hierarchical namespace array\n * @returns Array of items with key and value pairs directly in this namespace\n * (not including sub-namespaces)\n */\n list(namespace: string[]): Promise<Array<{ key: string; value: Record<string, unknown> }>>;\n}\n\n/**\n * Simple in-memory implementation of KeyValueStore.\n *\n * Useful for testing or single-session persistence. Data is stored in a Map\n * and does not persist across application restarts.\n *\n * @example Basic usage\n * ```typescript\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({ store });\n * ```\n *\n * @example For testing\n * ```typescript\n * const store = new InMemoryStore();\n * // ... run tests ...\n * store.clear(); // Clean up after tests\n * ```\n */\nexport class InMemoryStore implements KeyValueStore {\n private data = new Map<string, Record<string, unknown>>();\n\n private makeKey(namespace: string[], key: string): string {\n return [...namespace, key].join(\":\");\n }\n\n private parseKey(fullKey: string, namespace: string[]): string | null {\n const prefix = namespace.join(\":\") + \":\";\n if (fullKey.startsWith(prefix)) {\n return fullKey.substring(prefix.length);\n }\n return null;\n }\n\n async get(namespace: string[], key: string): Promise<Record<string, unknown> | undefined> {\n return this.data.get(this.makeKey(namespace, key));\n }\n\n async put(namespace: string[], key: string, value: Record<string, unknown>): Promise<void> {\n this.data.set(this.makeKey(namespace, key), value);\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n this.data.delete(this.makeKey(namespace, key));\n }\n\n async list(namespace: string[]): Promise<Array<{ key: string; value: Record<string, unknown> }>> {\n const results: Array<{ key: string; value: Record<string, unknown> }> = [];\n const prefix = namespace.join(\":\") + \":\";\n\n for (const [fullKey, value] of this.data.entries()) {\n if (fullKey.startsWith(prefix)) {\n const key = fullKey.substring(prefix.length);\n // Only include items directly in this namespace (no sub-namespaces)\n if (!key.includes(\":\")) {\n results.push({ key, value });\n }\n }\n }\n\n return results;\n }\n\n /**\n * Clear all data (useful for testing).\n */\n clear(): void {\n this.data.clear();\n }\n\n /**\n * Get the number of stored items.\n */\n size(): number {\n return this.data.size;\n }\n}\n\n/**\n * Options for creating a PersistentBackend.\n */\nexport interface PersistentBackendOptions {\n /** \n * **Required.** The key-value store implementation to use.\n * \n * You can use the built-in `InMemoryStore` for testing, or implement `KeyValueStore`\n * for custom storage (Redis, SQLite, etc.).\n * \n * @see {@link KeyValueStore} for the interface definition\n * @see {@link InMemoryStore} for a simple in-memory implementation\n */\n store: KeyValueStore;\n /** \n * Optional namespace prefix for isolation (e.g., project ID, user ID).\n * \n * This allows multiple agents or projects to share the same store without conflicts.\n * Files are stored under `[namespace]/filesystem/` in the key-value store.\n * \n * Default: \"default\"\n */\n namespace?: string;\n}\n\n/**\n * Backend that stores files in a persistent key-value store.\n *\n * This provides cross-conversation file persistence that survives between agent sessions.\n * Files are stored in the provided key-value store, allowing you to use any storage backend\n * (Redis, SQLite, cloud storage, etc.) by implementing the `KeyValueStore` interface.\n *\n * @example Using InMemoryStore (for testing or single-session persistence)\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({ store });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example With custom namespace for project isolation\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({\n * store,\n * namespace: 'project-123', // Isolate files for this project\n * });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example Custom KeyValueStore implementation (Redis)\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, type KeyValueStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { createClient } from 'redis';\n *\n * class RedisStore implements KeyValueStore {\n * constructor(private redis: ReturnType<typeof createClient>) {}\n *\n * async get(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * const data = await this.redis.get(redisKey);\n * return data ? JSON.parse(data) : undefined;\n * }\n *\n * async put(namespace: string[], key: string, value: Record<string, unknown>) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.set(redisKey, JSON.stringify(value));\n * }\n *\n * async delete(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.del(redisKey);\n * }\n *\n * async list(namespace: string[]) {\n * const prefix = [...namespace].join(':') + ':';\n * const keys = await this.redis.keys(prefix + '*');\n * const results = [];\n * for (const key of keys) {\n * const data = await this.redis.get(key);\n * if (data) {\n * const relativeKey = key.substring(prefix.length);\n * results.push({ key: relativeKey, value: JSON.parse(data) });\n * }\n * }\n * return results;\n * }\n * }\n *\n * const redis = createClient();\n * await redis.connect();\n *\n * const backend = new PersistentBackend({ \n * store: new RedisStore(redis),\n * namespace: 'production'\n * });\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n */\nexport class PersistentBackend implements BackendProtocol {\n private store: KeyValueStore;\n private namespacePrefix: string;\n\n /**\n * Create a new PersistentBackend instance.\n *\n * @param options - Configuration options\n * @param options.store - The key-value store implementation to use\n * @param options.namespace - Optional namespace prefix for file isolation\n */\n constructor(options: PersistentBackendOptions) {\n this.store = options.store;\n this.namespacePrefix = options.namespace || \"default\";\n }\n\n /**\n * Get the namespace for store operations.\n */\n protected getNamespace(): string[] {\n return [this.namespacePrefix, \"filesystem\"];\n }\n\n /**\n * Convert a store value to FileData format.\n */\n private convertToFileData(value: Record<string, unknown>): FileData {\n if (\n !value.content ||\n !Array.isArray(value.content) ||\n typeof value.created_at !== \"string\" ||\n typeof value.modified_at !== \"string\"\n ) {\n throw new Error(\n `Store item does not contain valid FileData fields. Got keys: ${Object.keys(value).join(\", \")}`\n );\n }\n\n return {\n content: value.content as string[],\n created_at: value.created_at,\n modified_at: value.modified_at,\n };\n }\n\n /**\n * Convert FileData to a value suitable for store.put().\n */\n private convertFromFileData(fileData: FileData): Record<string, unknown> {\n return {\n content: fileData.content,\n created_at: fileData.created_at,\n modified_at: fileData.modified_at,\n };\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(path: string): Promise<FileInfo[]> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n const infos: FileInfo[] = [];\n const subdirs = new Set<string>();\n\n // Normalize path to have trailing slash for proper prefix matching\n const normalizedPath = path.endsWith(\"/\") ? path : path + \"/\";\n\n for (const item of items) {\n const itemKey = item.key;\n\n // Check if file is in the specified directory or a subdirectory\n if (!itemKey.startsWith(normalizedPath)) {\n continue;\n }\n\n // Get the relative path after the directory\n const relative = itemKey.substring(normalizedPath.length);\n\n // If relative path contains '/', it's in a subdirectory\n if (relative.includes(\"/\")) {\n // Extract the immediate subdirectory name\n const subdirName = relative.split(\"/\")[0];\n subdirs.add(normalizedPath + subdirName + \"/\");\n continue;\n }\n\n // This is a file directly in the current directory\n try {\n const fd = this.convertToFileData(item.value);\n const size = fd.content.join(\"\\n\").length;\n infos.push({\n path: itemKey,\n is_dir: false,\n size: size,\n modified_at: fd.modified_at,\n });\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n // Add directories to the results\n for (const subdir of Array.from(subdirs).sort()) {\n infos.push({\n path: subdir,\n is_dir: true,\n size: 0,\n modified_at: \"\",\n });\n }\n\n infos.sort((a, b) => a.path.localeCompare(b.path));\n return infos;\n }\n\n /**\n * Read file content with line numbers.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 2000\n ): Promise<string> {\n try {\n const fileData = await this.readRaw(filePath);\n return formatReadResponse(fileData, offset, limit);\n } catch (e: unknown) {\n const error = e as Error;\n return `Error: ${error.message}`;\n }\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const namespace = this.getNamespace();\n const value = await this.store.get(namespace, filePath);\n\n if (!value) {\n throw new Error(`File '${filePath}' not found`);\n }\n\n return this.convertToFileData(value);\n }\n\n /**\n * Create a new file with content.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const namespace = this.getNamespace();\n\n // Check if file exists\n const existing = await this.store.get(namespace, filePath);\n if (existing) {\n return {\n success: false,\n error: FILE_ALREADY_EXISTS(filePath),\n };\n }\n\n // Create new file\n const fileData = createFileData(content);\n const storeValue = this.convertFromFileData(fileData);\n await this.store.put(namespace, filePath, storeValue);\n return { success: true, path: filePath };\n }\n\n /**\n * Edit a file by replacing string occurrences.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n const namespace = this.getNamespace();\n\n // Get existing file\n const value = await this.store.get(namespace, filePath);\n if (!value) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n\n try {\n const fileData = this.convertToFileData(value);\n const content = fileDataToString(fileData);\n const result = performStringReplacement(\n content,\n oldString,\n newString,\n replaceAll\n );\n\n if (typeof result === \"string\") {\n return { success: false, error: result };\n }\n\n const [newContent, occurrences] = result;\n const newFileData = updateFileData(fileData, newContent);\n\n // Update file in store\n const storeValue = this.convertFromFileData(newFileData);\n await this.store.put(namespace, filePath, storeValue);\n return { success: true, path: filePath, occurrences };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error: ${error.message}` };\n }\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertToFileData(item.value);\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n return grepMatchesFromFiles(files, pattern, path, glob);\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, path: string = \"/\"): Promise<FileInfo[]> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertToFileData(item.value);\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n const result = globSearchFiles(files, pattern, path);\n if (result === \"No files found\") {\n return [];\n }\n\n const paths = result.split(\"\\n\");\n const infos: FileInfo[] = [];\n for (const p of paths) {\n const fd = files[p];\n const size = fd ? fd.content.join(\"\\n\").length : 0;\n infos.push({\n path: p,\n is_dir: false,\n size: size,\n modified_at: fd?.modified_at || \"\",\n });\n }\n return infos;\n }\n\n /**\n * Delete a file.\n */\n async deleteFile(filePath: string): Promise<{ error?: string }> {\n const namespace = this.getNamespace();\n const existing = await this.store.get(namespace, filePath);\n\n if (!existing) {\n return { error: `File '${filePath}' not found` };\n }\n\n await this.store.delete(namespace, filePath);\n return {};\n }\n}\n\n","/**\n * In-memory checkpoint saver for testing and single-session use.\n */\n\nimport type { Checkpoint, BaseCheckpointSaver, CheckpointSaverOptions } from \"./types\";\n\n/**\n * In-memory checkpoint saver.\n * \n * Stores checkpoints in a Map. Data is lost when the process exits.\n * Useful for testing or single-session applications.\n * \n * @example\n * ```typescript\n * const saver = new MemorySaver();\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * checkpointer: saver,\n * });\n * ```\n */\nexport class MemorySaver implements BaseCheckpointSaver {\n private checkpoints = new Map<string, Checkpoint>();\n private namespace: string;\n\n constructor(options: CheckpointSaverOptions = {}) {\n this.namespace = options.namespace || \"default\";\n }\n\n private getKey(threadId: string): string {\n return `${this.namespace}:${threadId}`;\n }\n\n async save(checkpoint: Checkpoint): Promise<void> {\n const key = this.getKey(checkpoint.threadId);\n this.checkpoints.set(key, {\n ...checkpoint,\n updatedAt: new Date().toISOString(),\n });\n }\n\n async load(threadId: string): Promise<Checkpoint | undefined> {\n const key = this.getKey(threadId);\n return this.checkpoints.get(key);\n }\n\n async list(): Promise<string[]> {\n const prefix = `${this.namespace}:`;\n const threadIds: string[] = [];\n for (const key of this.checkpoints.keys()) {\n if (key.startsWith(prefix)) {\n threadIds.push(key.substring(prefix.length));\n }\n }\n return threadIds;\n }\n\n async delete(threadId: string): Promise<void> {\n const key = this.getKey(threadId);\n this.checkpoints.delete(key);\n }\n\n async exists(threadId: string): Promise<boolean> {\n const key = this.getKey(threadId);\n return this.checkpoints.has(key);\n }\n\n /**\n * Clear all checkpoints (useful for testing).\n */\n clear(): void {\n this.checkpoints.clear();\n }\n\n /**\n * Get the number of stored checkpoints.\n */\n size(): number {\n return this.checkpoints.size;\n }\n}\n\n","/**\n * Checkpoint saver using KeyValueStore interface.\n * \n * Allows using existing KeyValueStore implementations (Redis, etc.)\n * for checkpoint storage.\n */\n\nimport type { KeyValueStore } from \"../backends/persistent\";\nimport type { Checkpoint, BaseCheckpointSaver, CheckpointSaverOptions } from \"./types\";\n\n/**\n * Options for KeyValueStoreSaver.\n */\nexport interface KeyValueStoreSaverOptions extends CheckpointSaverOptions {\n /** The KeyValueStore implementation to use */\n store: KeyValueStore;\n}\n\n/**\n * Checkpoint saver using KeyValueStore interface.\n * \n * This adapter allows using any KeyValueStore implementation (Redis,\n * database, cloud storage, etc.) for checkpoint storage.\n * \n * @example\n * ```typescript\n * import { InMemoryStore } from 'deepagentsdk';\n * \n * const store = new InMemoryStore();\n * const saver = new KeyValueStoreSaver({ store });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * checkpointer: saver,\n * });\n * ```\n * \n * @example With Redis\n * ```typescript\n * const redisStore = new RedisStore(redisClient); // Your implementation\n * const saver = new KeyValueStoreSaver({ store: redisStore });\n * ```\n */\nexport class KeyValueStoreSaver implements BaseCheckpointSaver {\n private store: KeyValueStore;\n private namespace: string[];\n\n constructor(options: KeyValueStoreSaverOptions) {\n this.store = options.store;\n this.namespace = [options.namespace || \"default\", \"checkpoints\"];\n }\n\n async save(checkpoint: Checkpoint): Promise<void> {\n const data = {\n ...checkpoint,\n updatedAt: new Date().toISOString(),\n };\n await this.store.put(this.namespace, checkpoint.threadId, data as unknown as Record<string, unknown>);\n }\n\n async load(threadId: string): Promise<Checkpoint | undefined> {\n const data = await this.store.get(this.namespace, threadId);\n if (!data) {\n return undefined;\n }\n return data as unknown as Checkpoint;\n }\n\n async list(): Promise<string[]> {\n const items = await this.store.list(this.namespace);\n return items.map(item => item.key);\n }\n\n async delete(threadId: string): Promise<void> {\n await this.store.delete(this.namespace, threadId);\n }\n\n async exists(threadId: string): Promise<boolean> {\n const data = await this.store.get(this.namespace, threadId);\n return data !== undefined;\n }\n}\n\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport os from 'node:os';\nimport type { LanguageModelMiddleware } from 'ai';\nimport { findGitRoot } from '../utils/project-detection';\n\n/**\n * Configuration options for agent memory middleware.\n */\nexport interface AgentMemoryOptions {\n /**\n * Unique identifier for the agent (e.g., \"code-architect\", \"research-agent\").\n * Used to locate agent-specific memory at ~/.deepagents/{agentId}/agent.md\n */\n agentId: string;\n\n /**\n * Optional working directory for project-level memory detection.\n * Defaults to process.cwd().\n */\n workingDirectory?: string;\n\n /**\n * Optional custom path for user-level .deepagents directory.\n * Defaults to os.homedir() + '/.deepagents'.\n *\n * Useful for testing or custom deployment environments.\n *\n * @example\n * ```typescript\n * userDeepagentsDir: '/custom/path/.deepagents'\n * // Will look for memory at: /custom/path/.deepagents/{agentId}/agent.md\n * ```\n */\n userDeepagentsDir?: string;\n\n /**\n * Optional callback to request user approval for creating project-level .deepagents/ directory.\n * If not provided, project memory will be silently skipped if directory doesn't exist.\n *\n * @param projectPath - Absolute path to the detected git root\n * @returns Promise<boolean> - true if user approves, false otherwise\n */\n requestProjectApproval?: (projectPath: string) => Promise<boolean>;\n}\n\n/**\n * Load agent memory from a file path.\n * Returns empty string if file doesn't exist or can't be read.\n */\nasync function loadAgentMemory(filePath: string): Promise<string> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim();\n } catch {\n return '';\n }\n}\n\n/**\n * Load all additional .md files from the agent's directory (excluding agent.md).\n * Returns an array of { filename, content } objects.\n */\nasync function loadAdditionalMemoryFiles(\n dirPath: string\n): Promise<Array<{ filename: string; content: string }>> {\n try {\n const files = await fs.readdir(dirPath);\n const mdFiles = files.filter(\n (f) => f.endsWith('.md') && f !== 'agent.md'\n );\n\n const results = await Promise.all(\n mdFiles.map(async (filename) => {\n const content = await loadAgentMemory(path.join(dirPath, filename));\n return { filename, content };\n })\n );\n\n return results.filter((r) => r.content.length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Build the memory section for the system prompt.\n * This comprehensive prompt teaches the agent how to use memory effectively.\n */\nfunction buildMemorySection(\n userMemory: string,\n projectMemory: string,\n additionalFiles: Array<{ filename: string; content: string }>,\n agentId: string,\n userMemoryPath: string,\n projectMemoryPath: string | null\n): string {\n let sections: string[] = [];\n\n // Build memory content sections\n if (userMemory) {\n sections.push(`# Agent Memory (User-Level)\n\nThe following is your persistent memory stored at ${userMemoryPath}:\n\n${userMemory}`);\n }\n\n if (projectMemory && projectMemoryPath) {\n sections.push(`# Agent Memory (Project-Level)\n\nThe following is project-specific context stored at ${projectMemoryPath}:\n\n${projectMemory}`);\n }\n\n if (additionalFiles.length > 0) {\n const additionalSections = additionalFiles.map(\n ({ filename, content }) => `## ${filename}\n\n${content}`\n );\n sections.push(`# Additional Context Files\n\n${additionalSections.join('\\n\\n')}`);\n }\n\n if (sections.length === 0) {\n return ''; // No memory to inject\n }\n\n // Build comprehensive instructions\n const memoryContent = sections.join('\\n\\n---\\n\\n');\n const instructions = `\n<agent_memory>\n${memoryContent}\n\n---\n\n## How to Use This Memory\n\n**What is this?**\n- The content above is your persistent memory, stored in markdown files\n- **User-level memory** (${userMemoryPath}) contains your core personality, preferences, and cross-project context\n- **Project-level memory** ${projectMemoryPath ? `(${projectMemoryPath})` : '(not available)'} contains project-specific context and conventions\n\n**When to read memory:**\n- You already have the memory content above in your context - no need to read the files unless you need to verify exact content\n- If you need to check current memory state or see if it's been updated, use \\`read_file\\` tool\n\n**When to update memory:**\n- **User memory**: When you learn something important about the user's preferences, working style, or recurring patterns\n- **Project memory**: When you discover project-specific conventions, architecture decisions, or important context\n- **Additional files**: For specialized context that doesn't fit in agent.md (e.g., decision logs, architecture notes)\n\n**How to update memory:**\n- Use the \\`write_file\\` or \\`edit_file\\` tools with the file paths shown above\n- Keep entries concise and relevant\n- Organize information clearly with markdown headings\n- Remove outdated information when updating\n\n**Important guidelines:**\n- Memory is meant for long-term context, not temporary task tracking\n- Don't store information that's already in the codebase or documentation\n- Focus on insights, patterns, and preferences that aren't obvious from other sources\n- When in doubt, ask the user if something should be remembered\n\n**Example use cases:**\n- User prefers TypeScript strict mode and comprehensive error handling\n- Project uses custom testing framework located in \\`test-utils/\\`\n- User wants all API responses to follow specific error format\n- Project has specific commit message conventions\n</agent_memory>\n`;\n\n return instructions.trim();\n}\n\n/**\n * Create agent memory middleware for AI SDK v6.\n *\n * This middleware loads agent memory from:\n * 1. User-level: ~/.deepagents/{agentId}/agent.md (personality, preferences)\n * 2. Project-level: [git-root]/.deepagents/agent.md (project-specific context)\n * 3. Additional files: Any other .md files in the user-level directory\n *\n * The memory is injected into the system prompt before each model call, teaching\n * the agent when and how to read/update its own memory using filesystem tools.\n *\n * @param options - Configuration for agent memory\n * @param options.agentId - Unique identifier for the agent (e.g., \"code-architect\")\n * @param options.workingDirectory - Optional working directory for project detection (defaults to process.cwd())\n * @param options.userDeepagentsDir - Optional custom path for user-level .deepagents directory (defaults to ~/.deepagents)\n * @param options.requestProjectApproval - Optional callback to request approval before creating project .deepagents/ directory\n * @returns AI SDK v6 middleware\n *\n * @example Basic usage\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { createAgentMemoryMiddleware } from 'deepagentsdk/middleware';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * });\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-5'),\n * middleware: memoryMiddleware,\n * });\n * ```\n *\n * @example With project approval callback\n * ```typescript\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * requestProjectApproval: async (projectPath) => {\n * console.log(`Create .deepagents/ in ${projectPath}? (y/n)`);\n * // ... get user input\n * return userSaidYes;\n * }\n * });\n * ```\n *\n * @example With custom user directory path\n * ```typescript\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * userDeepagentsDir: '/custom/path/.deepagents',\n * // Memory will be loaded from:\n * // - /custom/path/.deepagents/code-architect/agent.md\n * // - [git-root]/.deepagents/agent.md (project-level)\n * });\n * ```\n */\nexport function createAgentMemoryMiddleware(\n options: AgentMemoryOptions\n): LanguageModelMiddleware {\n const { agentId, workingDirectory, userDeepagentsDir, requestProjectApproval } = options;\n\n // Memory is loaded once and cached in closure variables\n let memoryLoaded = false;\n let cachedMemorySection = '';\n\n return {\n specificationVersion: 'v3',\n transformParams: async ({ params }) => {\n // Load memory on first call only (closure-based caching)\n if (!memoryLoaded) {\n const workDir = workingDirectory || process.cwd();\n\n // 1. Load user-level memory\n const baseUserDir = userDeepagentsDir || path.join(os.homedir(), '.deepagents');\n const userAgentDir = path.join(baseUserDir, agentId);\n const userMemoryPath = path.join(userAgentDir, 'agent.md');\n const userMemory = await loadAgentMemory(userMemoryPath);\n\n // Auto-create user directory if it doesn't exist (safe operation)\n if (!userMemory) {\n try {\n await fs.mkdir(userAgentDir, { recursive: true });\n } catch {\n // Ignore errors - directory might already exist or permissions issue\n }\n }\n\n // 2. Load additional .md files from user directory\n const additionalFiles = await loadAdditionalMemoryFiles(userAgentDir);\n\n // 3. Load project-level memory (if in git repository)\n let projectMemory = '';\n let projectMemoryPath: string | null = null;\n\n const gitRoot = await findGitRoot(workDir);\n if (gitRoot) {\n const projectDeepagentsDir = path.join(gitRoot, '.deepagents');\n projectMemoryPath = path.join(projectDeepagentsDir, 'agent.md');\n\n // Check if project directory exists\n try {\n await fs.stat(projectDeepagentsDir);\n projectMemory = await loadAgentMemory(projectMemoryPath);\n } catch {\n // Project directory doesn't exist - request approval if callback provided\n if (requestProjectApproval) {\n const approved = await requestProjectApproval(gitRoot);\n if (approved) {\n try {\n await fs.mkdir(projectDeepagentsDir, { recursive: true });\n // Don't create agent.md yet - let the agent do it when needed\n } catch {\n // Ignore errors - permissions issue or race condition\n }\n }\n }\n }\n }\n\n // Build and cache memory section\n cachedMemorySection = buildMemorySection(\n userMemory,\n projectMemory,\n additionalFiles,\n agentId,\n userMemoryPath,\n projectMemoryPath\n );\n\n memoryLoaded = true;\n }\n\n // Inject memory into system prompt if available\n if (cachedMemorySection) {\n const updatedPrompt = params.prompt.map((msg) => {\n if (msg.role === 'system') {\n return {\n ...msg,\n content: `${msg.content}\\n\\n${cachedMemorySection}`,\n };\n }\n return msg;\n });\n\n return { ...params, prompt: updatedPrompt };\n }\n\n return params;\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["fsSync","MAX_FILE_SIZE_MB","fs","DEFAULT_READ_LIMIT","FILE_NOT_FOUND","checkEmptyContent","formatContentWithLineNumbers","FILE_ALREADY_EXISTS","performStringReplacement","glob","path","glob","path","formatReadResponse","FILE_ALREADY_EXISTS","createFileData","FILE_NOT_FOUND","performStringReplacement","fileDataToString","updateFileData","grepMatchesFromFiles","glob","globSearchFiles","fs","path","os","findGitRoot"],"sources":["../src/types/structured-output.ts","../src/backends/filesystem.ts","../src/backends/composite.ts","../src/backends/persistent.ts","../src/tools/index.ts","../src/utils/index.ts","../src/checkpointer/memory-saver.ts","../src/checkpointer/kv-saver.ts","../src/middleware/agent-memory.ts"],"sourcesContent":["// Zod import removed - not needed for these utility functions\n\n/**\n * Interface for agent results that include structured output\n */\nexport interface StructuredAgentResult<T = unknown> {\n text: string;\n output?: T;\n state?: any; // DeepAgentState from core types\n messages?: any[]; // ModelMessage array\n}\n\n/**\n * Type guard for checking if a result has structured output\n */\nexport function hasStructuredOutput<T>(\n result: any\n): result is StructuredAgentResult<T> {\n return result && typeof result === \"object\" && \"output\" in result;\n}\n\n/**\n * Type guard for checking if an event has structured output\n */\nexport function eventHasStructuredOutput<T>(\n event: any\n): event is { type: \"done\"; output: T } {\n return event && event.type === \"done\" && \"output\" in event;\n}\n\n/**\n * Extract structured output from agent result with type safety\n */\nexport function getStructuredOutput<T>(result: any): T | undefined {\n return hasStructuredOutput<T>(result) ? result.output : undefined;\n}\n\n/**\n * Extract structured output from event with type safety\n */\nexport function getEventOutput<T>(event: any): T | undefined {\n return eventHasStructuredOutput<T>(event) ? event.output : undefined;\n}","/**\n * FilesystemBackend: Read and write files directly from the filesystem.\n */\n\nimport * as fs from \"fs/promises\";\nimport * as fsSync from \"fs\";\nimport * as path from \"path\";\nimport { spawn } from \"child_process\";\nimport fg from \"fast-glob\";\nimport micromatch from \"micromatch\";\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\nimport {\n checkEmptyContent,\n formatContentWithLineNumbers,\n performStringReplacement,\n} from \"./utils\";\nimport {\n FILE_NOT_FOUND,\n FILE_ALREADY_EXISTS,\n} from \"../constants/errors\";\nimport { MAX_FILE_SIZE_MB, DEFAULT_READ_LIMIT } from \"../constants/limits\";\n\nconst SUPPORTS_NOFOLLOW = fsSync.constants.O_NOFOLLOW !== undefined;\n\n/**\n * Backend that reads and writes files directly from the filesystem.\n *\n * Files are persisted to disk, making them available across agent invocations.\n * This backend provides real file I/O operations with security checks to prevent\n * directory traversal attacks.\n *\n * @example Basic usage\n * ```typescript\n * const backend = new FilesystemBackend({ rootDir: './workspace' });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example With custom options\n * ```typescript\n * const backend = new FilesystemBackend({\n * rootDir: './my-project',\n * virtualMode: false,\n * maxFileSizeMb: 50, // Allow larger files\n * });\n * ```\n */\nexport class FilesystemBackend implements BackendProtocol {\n private cwd: string;\n private virtualMode: boolean;\n private maxFileSizeBytes: number;\n\n /**\n * Create a new FilesystemBackend instance.\n *\n * @param options - Configuration options\n * @param options.rootDir - Optional root directory for file operations (default: current working directory).\n * All file paths are resolved relative to this directory.\n * @param options.virtualMode - Optional flag for virtual mode (default: false).\n * When true, files are stored in memory but paths are validated against filesystem.\n * @param options.maxFileSizeMb - Optional maximum file size in MB (default: 10).\n * Files larger than this will be rejected.\n */\n constructor(\n options: {\n rootDir?: string;\n virtualMode?: boolean;\n maxFileSizeMb?: number;\n } = {}\n ) {\n const { rootDir, virtualMode = false, maxFileSizeMb = MAX_FILE_SIZE_MB } = options;\n this.cwd = rootDir ? path.resolve(rootDir) : process.cwd();\n this.virtualMode = virtualMode;\n this.maxFileSizeBytes = maxFileSizeMb * 1024 * 1024;\n }\n\n /**\n * Resolve a file path with security checks.\n */\n private resolvePath(key: string): string {\n if (this.virtualMode) {\n const vpath = key.startsWith(\"/\") ? key : \"/\" + key;\n if (vpath.includes(\"..\") || vpath.startsWith(\"~\")) {\n throw new Error(\"Path traversal not allowed\");\n }\n const full = path.resolve(this.cwd, vpath.substring(1));\n const relative = path.relative(this.cwd, full);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`Path: ${full} outside root directory: ${this.cwd}`);\n }\n return full;\n }\n\n if (path.isAbsolute(key)) {\n return key;\n }\n return path.resolve(this.cwd, key);\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(dirPath: string): Promise<FileInfo[]> {\n try {\n const resolvedPath = this.resolvePath(dirPath);\n const stat = await fs.stat(resolvedPath);\n\n if (!stat.isDirectory()) {\n return [];\n }\n\n const entries = await fs.readdir(resolvedPath, { withFileTypes: true });\n const results: FileInfo[] = [];\n\n const cwdStr = this.cwd.endsWith(path.sep)\n ? this.cwd\n : this.cwd + path.sep;\n\n for (const entry of entries) {\n const fullPath = path.join(resolvedPath, entry.name);\n\n try {\n const entryStat = await fs.stat(fullPath);\n const isFile = entryStat.isFile();\n const isDir = entryStat.isDirectory();\n\n if (!this.virtualMode) {\n if (isFile) {\n results.push({\n path: fullPath,\n is_dir: false,\n size: entryStat.size,\n modified_at: entryStat.mtime.toISOString(),\n });\n } else if (isDir) {\n results.push({\n path: fullPath + path.sep,\n is_dir: true,\n size: 0,\n modified_at: entryStat.mtime.toISOString(),\n });\n }\n } else {\n let relativePath: string;\n if (fullPath.startsWith(cwdStr)) {\n relativePath = fullPath.substring(cwdStr.length);\n } else if (fullPath.startsWith(this.cwd)) {\n relativePath = fullPath\n .substring(this.cwd.length)\n .replace(/^[/\\\\]/, \"\");\n } else {\n relativePath = fullPath;\n }\n\n relativePath = relativePath.split(path.sep).join(\"/\");\n const virtPath = \"/\" + relativePath;\n\n if (isFile) {\n results.push({\n path: virtPath,\n is_dir: false,\n size: entryStat.size,\n modified_at: entryStat.mtime.toISOString(),\n });\n } else if (isDir) {\n results.push({\n path: virtPath + \"/\",\n is_dir: true,\n size: 0,\n modified_at: entryStat.mtime.toISOString(),\n });\n }\n }\n } catch {\n continue;\n }\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n } catch {\n return [];\n }\n }\n\n /**\n * Read file content with line numbers.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = DEFAULT_READ_LIMIT\n ): Promise<string> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n\n if (SUPPORTS_NOFOLLOW) {\n const stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) {\n return FILE_NOT_FOUND(filePath);\n }\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return `Error: Symlinks are not allowed: ${filePath}`;\n }\n if (!stat.isFile()) {\n return FILE_NOT_FOUND(filePath);\n }\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n const emptyMsg = checkEmptyContent(content);\n if (emptyMsg) {\n return emptyMsg;\n }\n\n const lines = content.split(\"\\n\");\n const startIdx = offset;\n const endIdx = Math.min(startIdx + limit, lines.length);\n\n if (startIdx >= lines.length) {\n return `Error: Line offset ${offset} exceeds file length (${lines.length} lines)`;\n }\n\n const selectedLines = lines.slice(startIdx, endIdx);\n return formatContentWithLineNumbers(selectedLines, startIdx + 1);\n } catch (e: unknown) {\n const error = e as Error;\n return `Error reading file '${filePath}': ${error.message}`;\n }\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n let stat: fsSync.Stats;\n\n if (SUPPORTS_NOFOLLOW) {\n stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Symlinks are not allowed: ${filePath}`);\n }\n if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n return {\n content: content.split(\"\\n\"),\n created_at: stat.ctime.toISOString(),\n modified_at: stat.mtime.toISOString(),\n };\n }\n\n /**\n * Create a new file with content.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n try {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return {\n success: false,\n error: `Cannot write to ${filePath} because it is a symlink. Symlinks are not allowed.`,\n };\n }\n return {\n success: false,\n error: FILE_ALREADY_EXISTS(filePath),\n };\n } catch {\n // File doesn't exist, good to proceed\n }\n\n await fs.mkdir(path.dirname(resolvedPath), { recursive: true });\n\n if (SUPPORTS_NOFOLLOW) {\n const flags =\n fsSync.constants.O_WRONLY |\n fsSync.constants.O_CREAT |\n fsSync.constants.O_TRUNC |\n fsSync.constants.O_NOFOLLOW;\n\n const fd = await fs.open(resolvedPath, flags, 0o644);\n try {\n await fd.writeFile(content, \"utf-8\");\n } finally {\n await fd.close();\n }\n } else {\n await fs.writeFile(resolvedPath, content, \"utf-8\");\n }\n\n return { success: true, path: filePath };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error writing file '${filePath}': ${error.message}` };\n }\n }\n\n /**\n * Edit a file by replacing string occurrences.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n try {\n const resolvedPath = this.resolvePath(filePath);\n\n let content: string;\n\n if (SUPPORTS_NOFOLLOW) {\n const stat = await fs.stat(resolvedPath);\n if (!stat.isFile()) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n\n const fd = await fs.open(\n resolvedPath,\n fsSync.constants.O_RDONLY | fsSync.constants.O_NOFOLLOW\n );\n try {\n content = await fd.readFile({ encoding: \"utf-8\" });\n } finally {\n await fd.close();\n }\n } else {\n const stat = await fs.lstat(resolvedPath);\n if (stat.isSymbolicLink()) {\n return { success: false, error: `Error: Symlinks are not allowed: ${filePath}` };\n }\n if (!stat.isFile()) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n content = await fs.readFile(resolvedPath, \"utf-8\");\n }\n\n const result = performStringReplacement(\n content,\n oldString,\n newString,\n replaceAll\n );\n\n if (typeof result === \"string\") {\n return { success: false, error: result };\n }\n\n const [newContent, occurrences] = result;\n\n if (SUPPORTS_NOFOLLOW) {\n const flags =\n fsSync.constants.O_WRONLY |\n fsSync.constants.O_TRUNC |\n fsSync.constants.O_NOFOLLOW;\n\n const fd = await fs.open(resolvedPath, flags);\n try {\n await fd.writeFile(newContent, \"utf-8\");\n } finally {\n await fd.close();\n }\n } else {\n await fs.writeFile(resolvedPath, newContent, \"utf-8\");\n }\n\n return { success: true, path: filePath, occurrences };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error editing file '${filePath}': ${error.message}` };\n }\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n dirPath: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n // Validate regex\n try {\n new RegExp(pattern);\n } catch (e: unknown) {\n const error = e as Error;\n return `Invalid regex pattern: ${error.message}`;\n }\n\n // Resolve base path\n let baseFull: string;\n try {\n baseFull = this.resolvePath(dirPath || \".\");\n } catch {\n return [];\n }\n\n try {\n await fs.stat(baseFull);\n } catch {\n return [];\n }\n\n // Try ripgrep first, fallback to regex search\n let results = await this.ripgrepSearch(pattern, baseFull, glob);\n if (results === null) {\n results = await this.regexSearch(pattern, baseFull, glob);\n }\n\n const matches: GrepMatch[] = [];\n for (const [fpath, items] of Object.entries(results)) {\n for (const [lineNum, lineText] of items) {\n matches.push({ path: fpath, line: lineNum, text: lineText });\n }\n }\n return matches;\n }\n\n /**\n * Try to use ripgrep for fast searching.\n */\n private async ripgrepSearch(\n pattern: string,\n baseFull: string,\n includeGlob: string | null\n ): Promise<Record<string, Array<[number, string]>> | null> {\n return new Promise((resolve) => {\n const args = [\"--json\"];\n if (includeGlob) {\n args.push(\"--glob\", includeGlob);\n }\n args.push(\"--\", pattern, baseFull);\n\n const proc = spawn(\"rg\", args, { timeout: 30000 });\n const results: Record<string, Array<[number, string]>> = {};\n let output = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n output += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n if (code !== 0 && code !== 1) {\n resolve(null);\n return;\n }\n\n for (const line of output.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const data = JSON.parse(line);\n if (data.type !== \"match\") continue;\n\n const pdata = data.data || {};\n const ftext = pdata.path?.text;\n if (!ftext) continue;\n\n let virtPath: string;\n if (this.virtualMode) {\n try {\n const resolved = path.resolve(ftext);\n const relative = path.relative(this.cwd, resolved);\n if (relative.startsWith(\"..\")) continue;\n const normalizedRelative = relative.split(path.sep).join(\"/\");\n virtPath = \"/\" + normalizedRelative;\n } catch {\n continue;\n }\n } else {\n virtPath = ftext;\n }\n\n const ln = pdata.line_number;\n const lt = pdata.lines?.text?.replace(/\\n$/, \"\") || \"\";\n if (ln === undefined) continue;\n\n if (!results[virtPath]) {\n results[virtPath] = [];\n }\n results[virtPath]!.push([ln, lt]);\n } catch {\n continue;\n }\n }\n\n resolve(results);\n });\n\n proc.on(\"error\", () => {\n resolve(null);\n });\n });\n }\n\n /**\n * Fallback regex search implementation.\n */\n private async regexSearch(\n pattern: string,\n baseFull: string,\n includeGlob: string | null\n ): Promise<Record<string, Array<[number, string]>>> {\n let regex: RegExp;\n try {\n regex = new RegExp(pattern);\n } catch {\n return {};\n }\n\n const results: Record<string, Array<[number, string]>> = {};\n const stat = await fs.stat(baseFull);\n const root = stat.isDirectory() ? baseFull : path.dirname(baseFull);\n\n const files = await fg(\"**/*\", {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n dot: true,\n });\n\n for (const fp of files) {\n try {\n if (\n includeGlob &&\n !micromatch.isMatch(path.basename(fp), includeGlob)\n ) {\n continue;\n }\n\n const fileStat = await fs.stat(fp);\n if (fileStat.size > this.maxFileSizeBytes) {\n continue;\n }\n\n const content = await fs.readFile(fp, \"utf-8\");\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line && regex.test(line)) {\n let virtPath: string;\n if (this.virtualMode) {\n try {\n const relative = path.relative(this.cwd, fp);\n if (relative.startsWith(\"..\")) continue;\n const normalizedRelative = relative.split(path.sep).join(\"/\");\n virtPath = \"/\" + normalizedRelative;\n } catch {\n continue;\n }\n } else {\n virtPath = fp;\n }\n\n if (!results[virtPath]) {\n results[virtPath] = [];\n }\n results[virtPath]!.push([i + 1, line]);\n }\n }\n } catch {\n continue;\n }\n }\n\n return results;\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, searchPath: string = \"/\"): Promise<FileInfo[]> {\n if (pattern.startsWith(\"/\")) {\n pattern = pattern.substring(1);\n }\n\n const resolvedSearchPath =\n searchPath === \"/\" ? this.cwd : this.resolvePath(searchPath);\n\n try {\n const stat = await fs.stat(resolvedSearchPath);\n if (!stat.isDirectory()) {\n return [];\n }\n } catch {\n return [];\n }\n\n const results: FileInfo[] = [];\n\n try {\n const matches = await fg(pattern, {\n cwd: resolvedSearchPath,\n absolute: true,\n onlyFiles: true,\n dot: true,\n });\n\n for (const matchedPath of matches) {\n try {\n const fileStat = await fs.stat(matchedPath);\n if (!fileStat.isFile()) continue;\n\n const normalizedPath = matchedPath.split(\"/\").join(path.sep);\n\n if (!this.virtualMode) {\n results.push({\n path: normalizedPath,\n is_dir: false,\n size: fileStat.size,\n modified_at: fileStat.mtime.toISOString(),\n });\n } else {\n const cwdStr = this.cwd.endsWith(path.sep)\n ? this.cwd\n : this.cwd + path.sep;\n let relativePath: string;\n\n if (normalizedPath.startsWith(cwdStr)) {\n relativePath = normalizedPath.substring(cwdStr.length);\n } else if (normalizedPath.startsWith(this.cwd)) {\n relativePath = normalizedPath\n .substring(this.cwd.length)\n .replace(/^[/\\\\]/, \"\");\n } else {\n relativePath = normalizedPath;\n }\n\n relativePath = relativePath.split(path.sep).join(\"/\");\n const virt = \"/\" + relativePath;\n results.push({\n path: virt,\n is_dir: false,\n size: fileStat.size,\n modified_at: fileStat.mtime.toISOString(),\n });\n }\n } catch {\n continue;\n }\n }\n } catch {\n // Ignore glob errors\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n}\n\n","/**\n * CompositeBackend: Route operations to different backends based on path prefix.\n */\n\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\n\n/**\n * Backend that routes file operations to different backends based on path prefix.\n *\n * This enables hybrid storage strategies by routing files to different backends\n * based on their path prefix. Useful for separating persistent and ephemeral storage,\n * or using different storage backends for different types of files.\n *\n * @example Hybrid storage strategy\n * ```typescript\n * import { CompositeBackend, FilesystemBackend, StateBackend } from 'deepagentsdk';\n *\n * const state = { todos: [], files: {} };\n * const backend = new CompositeBackend(\n * new StateBackend(state), // Default: ephemeral storage\n * {\n * '/persistent/': new FilesystemBackend({ rootDir: './persistent' }), // Persistent files\n * '/cache/': new StateBackend(state), // Cached files (ephemeral)\n * }\n * );\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example Multiple persistent backends\n * ```typescript\n * const backend = new CompositeBackend(\n * new FilesystemBackend({ rootDir: './default' }),\n * {\n * '/user-data/': new FilesystemBackend({ rootDir: './user-data' }),\n * '/system/': new FilesystemBackend({ rootDir: './system' }),\n * }\n * );\n * ```\n */\nexport class CompositeBackend implements BackendProtocol {\n private defaultBackend: BackendProtocol;\n private routes: Record<string, BackendProtocol>;\n private sortedRoutes: Array<[string, BackendProtocol]>;\n\n /**\n * Create a new CompositeBackend instance.\n *\n * @param defaultBackend - Backend to use for paths that don't match any route prefix\n * @param routes - Record mapping path prefixes to backends.\n * Routes are matched by longest prefix first.\n * Example: `{ '/persistent/': filesystemBackend, '/cache/': stateBackend }`\n */\n constructor(\n defaultBackend: BackendProtocol,\n routes: Record<string, BackendProtocol>\n ) {\n this.defaultBackend = defaultBackend;\n this.routes = routes;\n\n // Sort routes by length (longest first) for correct prefix matching\n this.sortedRoutes = Object.entries(routes).sort(\n (a, b) => b[0].length - a[0].length\n );\n }\n\n /**\n * Determine which backend handles this key and strip prefix.\n */\n private getBackendAndKey(key: string): [BackendProtocol, string] {\n for (const [prefix, backend] of this.sortedRoutes) {\n if (key.startsWith(prefix)) {\n const suffix = key.substring(prefix.length);\n const strippedKey = suffix ? \"/\" + suffix : \"/\";\n return [backend, strippedKey];\n }\n }\n\n return [this.defaultBackend, key];\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(path: string): Promise<FileInfo[]> {\n // Check if path matches a specific route\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const infos = await backend.lsInfo(searchPath);\n\n // Add route prefix back to paths\n const prefixed: FileInfo[] = [];\n for (const fi of infos) {\n prefixed.push({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n });\n }\n return prefixed;\n }\n }\n\n // At root, aggregate default and all routed backends\n if (path === \"/\") {\n const results: FileInfo[] = [];\n const defaultInfos = await this.defaultBackend.lsInfo(path);\n results.push(...defaultInfos);\n\n // Add the route itself as a directory\n for (const [routePrefix] of this.sortedRoutes) {\n results.push({\n path: routePrefix,\n is_dir: true,\n size: 0,\n modified_at: \"\",\n });\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n\n // Path doesn't match a route: query only default backend\n return await this.defaultBackend.lsInfo(path);\n }\n\n /**\n * Read file content, routing to appropriate backend.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 2000\n ): Promise<string> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.read(strippedKey, offset, limit);\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.readRaw(strippedKey);\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n // If path targets a specific route, search only that backend\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const raw = await backend.grepRaw(pattern, searchPath, glob);\n\n if (typeof raw === \"string\") {\n return raw;\n }\n\n return raw.map((m) => ({\n ...m,\n path: routePrefix.slice(0, -1) + m.path,\n }));\n }\n }\n\n // Otherwise, search default and all routed backends and merge\n const allMatches: GrepMatch[] = [];\n const rawDefault = await this.defaultBackend.grepRaw(pattern, path, glob);\n\n if (typeof rawDefault === \"string\") {\n return rawDefault;\n }\n\n allMatches.push(...rawDefault);\n\n // Search all routes\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n const raw = await backend.grepRaw(pattern, \"/\", glob);\n\n if (typeof raw === \"string\") {\n return raw;\n }\n\n allMatches.push(\n ...raw.map((m) => ({\n ...m,\n path: routePrefix.slice(0, -1) + m.path,\n }))\n );\n }\n\n return allMatches;\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, path: string = \"/\"): Promise<FileInfo[]> {\n const results: FileInfo[] = [];\n\n // Route based on path\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (path.startsWith(routePrefix.replace(/\\/$/, \"\"))) {\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const infos = await backend.globInfo(pattern, searchPath);\n\n return infos.map((fi) => ({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n }));\n }\n }\n\n // Path doesn't match any specific route - search all backends\n const defaultInfos = await this.defaultBackend.globInfo(pattern, path);\n results.push(...defaultInfos);\n\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n const infos = await backend.globInfo(pattern, \"/\");\n results.push(\n ...infos.map((fi) => ({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n }))\n );\n }\n\n results.sort((a, b) => a.path.localeCompare(b.path));\n return results;\n }\n\n /**\n * Create a new file, routing to appropriate backend.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.write(strippedKey, content);\n }\n\n /**\n * Edit a file, routing to appropriate backend.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n const [backend, strippedKey] = this.getBackendAndKey(filePath);\n return await backend.edit(strippedKey, oldString, newString, replaceAll);\n }\n}\n\n","/**\n * PersistentBackend: Generic persistent storage backend.\n *\n * This backend provides cross-conversation file persistence using a\n * pluggable key-value store interface. It can be used with various\n * storage solutions like Redis, SQLite, or any custom implementation.\n */\n\nimport type {\n BackendProtocol,\n EditResult,\n FileData,\n FileInfo,\n GrepMatch,\n WriteResult,\n} from \"../types\";\nimport {\n createFileData,\n fileDataToString,\n formatReadResponse,\n globSearchFiles,\n grepMatchesFromFiles,\n performStringReplacement,\n updateFileData,\n} from \"./utils\";\nimport {\n FILE_NOT_FOUND,\n FILE_ALREADY_EXISTS,\n} from \"../constants/errors\";\n\n/**\n * Generic key-value store interface for persistent storage.\n *\n * Implement this interface to use any storage backend (Redis, SQLite, cloud storage, etc.)\n * with PersistentBackend. The interface uses hierarchical namespaces for organization.\n *\n * @example Redis implementation\n * ```typescript\n * class RedisStore implements KeyValueStore {\n * constructor(private redis: RedisClient) {}\n *\n * async get(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * const data = await this.redis.get(redisKey);\n * return data ? JSON.parse(data) : undefined;\n * }\n *\n * async put(namespace: string[], key: string, value: Record<string, unknown>) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.set(redisKey, JSON.stringify(value));\n * }\n *\n * async delete(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.del(redisKey);\n * }\n *\n * async list(namespace: string[]) {\n * const prefix = [...namespace].join(':') + ':';\n * const keys = await this.redis.keys(prefix + '*');\n * const results = [];\n * for (const key of keys) {\n * const data = await this.redis.get(key);\n * if (data) {\n * const relativeKey = key.substring(prefix.length);\n * results.push({ key: relativeKey, value: JSON.parse(data) });\n * }\n * }\n * return results;\n * }\n * }\n * ```\n */\nexport interface KeyValueStore {\n /**\n * Get a value by key from the store.\n * @param namespace - Hierarchical namespace array (e.g., [\"project1\", \"filesystem\"])\n * @param key - The key to retrieve (file path in the case of PersistentBackend)\n * @returns The stored value as a record, or undefined if not found\n */\n get(namespace: string[], key: string): Promise<Record<string, unknown> | undefined>;\n\n /**\n * Store a value by key in the store.\n * @param namespace - Hierarchical namespace array\n * @param key - The key to store (file path in the case of PersistentBackend)\n * @param value - The value to store (must be serializable to JSON)\n */\n put(namespace: string[], key: string, value: Record<string, unknown>): Promise<void>;\n\n /**\n * Delete a value by key from the store.\n * @param namespace - Hierarchical namespace array\n * @param key - The key to delete (file path in the case of PersistentBackend)\n */\n delete(namespace: string[], key: string): Promise<void>;\n\n /**\n * List all keys and values in a namespace.\n * @param namespace - Hierarchical namespace array\n * @returns Array of items with key and value pairs directly in this namespace\n * (not including sub-namespaces)\n */\n list(namespace: string[]): Promise<Array<{ key: string; value: Record<string, unknown> }>>;\n}\n\n/**\n * Simple in-memory implementation of KeyValueStore.\n *\n * Useful for testing or single-session persistence. Data is stored in a Map\n * and does not persist across application restarts.\n *\n * @example Basic usage\n * ```typescript\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({ store });\n * ```\n *\n * @example For testing\n * ```typescript\n * const store = new InMemoryStore();\n * // ... run tests ...\n * store.clear(); // Clean up after tests\n * ```\n */\nexport class InMemoryStore implements KeyValueStore {\n private data = new Map<string, Record<string, unknown>>();\n\n private makeKey(namespace: string[], key: string): string {\n return [...namespace, key].join(\":\");\n }\n\n private parseKey(fullKey: string, namespace: string[]): string | null {\n const prefix = namespace.join(\":\") + \":\";\n if (fullKey.startsWith(prefix)) {\n return fullKey.substring(prefix.length);\n }\n return null;\n }\n\n async get(namespace: string[], key: string): Promise<Record<string, unknown> | undefined> {\n return this.data.get(this.makeKey(namespace, key));\n }\n\n async put(namespace: string[], key: string, value: Record<string, unknown>): Promise<void> {\n this.data.set(this.makeKey(namespace, key), value);\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n this.data.delete(this.makeKey(namespace, key));\n }\n\n async list(namespace: string[]): Promise<Array<{ key: string; value: Record<string, unknown> }>> {\n const results: Array<{ key: string; value: Record<string, unknown> }> = [];\n const prefix = namespace.join(\":\") + \":\";\n\n for (const [fullKey, value] of this.data.entries()) {\n if (fullKey.startsWith(prefix)) {\n const key = fullKey.substring(prefix.length);\n // Only include items directly in this namespace (no sub-namespaces)\n if (!key.includes(\":\")) {\n results.push({ key, value });\n }\n }\n }\n\n return results;\n }\n\n /**\n * Clear all data (useful for testing).\n */\n clear(): void {\n this.data.clear();\n }\n\n /**\n * Get the number of stored items.\n */\n size(): number {\n return this.data.size;\n }\n}\n\n/**\n * Options for creating a PersistentBackend.\n */\nexport interface PersistentBackendOptions {\n /** \n * **Required.** The key-value store implementation to use.\n * \n * You can use the built-in `InMemoryStore` for testing, or implement `KeyValueStore`\n * for custom storage (Redis, SQLite, etc.).\n * \n * @see {@link KeyValueStore} for the interface definition\n * @see {@link InMemoryStore} for a simple in-memory implementation\n */\n store: KeyValueStore;\n /** \n * Optional namespace prefix for isolation (e.g., project ID, user ID).\n * \n * This allows multiple agents or projects to share the same store without conflicts.\n * Files are stored under `[namespace]/filesystem/` in the key-value store.\n * \n * Default: \"default\"\n */\n namespace?: string;\n}\n\n/**\n * Backend that stores files in a persistent key-value store.\n *\n * This provides cross-conversation file persistence that survives between agent sessions.\n * Files are stored in the provided key-value store, allowing you to use any storage backend\n * (Redis, SQLite, cloud storage, etc.) by implementing the `KeyValueStore` interface.\n *\n * @example Using InMemoryStore (for testing or single-session persistence)\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({ store });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example With custom namespace for project isolation\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, InMemoryStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const store = new InMemoryStore();\n * const backend = new PersistentBackend({\n * store,\n * namespace: 'project-123', // Isolate files for this project\n * });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n *\n * @example Custom KeyValueStore implementation (Redis)\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { PersistentBackend, type KeyValueStore } from 'deepagentsdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { createClient } from 'redis';\n *\n * class RedisStore implements KeyValueStore {\n * constructor(private redis: ReturnType<typeof createClient>) {}\n *\n * async get(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * const data = await this.redis.get(redisKey);\n * return data ? JSON.parse(data) : undefined;\n * }\n *\n * async put(namespace: string[], key: string, value: Record<string, unknown>) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.set(redisKey, JSON.stringify(value));\n * }\n *\n * async delete(namespace: string[], key: string) {\n * const redisKey = [...namespace, key].join(':');\n * await this.redis.del(redisKey);\n * }\n *\n * async list(namespace: string[]) {\n * const prefix = [...namespace].join(':') + ':';\n * const keys = await this.redis.keys(prefix + '*');\n * const results = [];\n * for (const key of keys) {\n * const data = await this.redis.get(key);\n * if (data) {\n * const relativeKey = key.substring(prefix.length);\n * results.push({ key: relativeKey, value: JSON.parse(data) });\n * }\n * }\n * return results;\n * }\n * }\n *\n * const redis = createClient();\n * await redis.connect();\n *\n * const backend = new PersistentBackend({ \n * store: new RedisStore(redis),\n * namespace: 'production'\n * });\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * backend,\n * });\n * ```\n */\nexport class PersistentBackend implements BackendProtocol {\n private store: KeyValueStore;\n private namespacePrefix: string;\n\n /**\n * Create a new PersistentBackend instance.\n *\n * @param options - Configuration options\n * @param options.store - The key-value store implementation to use\n * @param options.namespace - Optional namespace prefix for file isolation\n */\n constructor(options: PersistentBackendOptions) {\n this.store = options.store;\n this.namespacePrefix = options.namespace || \"default\";\n }\n\n /**\n * Get the namespace for store operations.\n */\n protected getNamespace(): string[] {\n return [this.namespacePrefix, \"filesystem\"];\n }\n\n /**\n * Convert a store value to FileData format.\n */\n private convertToFileData(value: Record<string, unknown>): FileData {\n if (\n !value.content ||\n !Array.isArray(value.content) ||\n typeof value.created_at !== \"string\" ||\n typeof value.modified_at !== \"string\"\n ) {\n throw new Error(\n `Store item does not contain valid FileData fields. Got keys: ${Object.keys(value).join(\", \")}`\n );\n }\n\n return {\n content: value.content as string[],\n created_at: value.created_at,\n modified_at: value.modified_at,\n };\n }\n\n /**\n * Convert FileData to a value suitable for store.put().\n */\n private convertFromFileData(fileData: FileData): Record<string, unknown> {\n return {\n content: fileData.content,\n created_at: fileData.created_at,\n modified_at: fileData.modified_at,\n };\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n */\n async lsInfo(path: string): Promise<FileInfo[]> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n const infos: FileInfo[] = [];\n const subdirs = new Set<string>();\n\n // Normalize path to have trailing slash for proper prefix matching\n const normalizedPath = path.endsWith(\"/\") ? path : path + \"/\";\n\n for (const item of items) {\n const itemKey = item.key;\n\n // Check if file is in the specified directory or a subdirectory\n if (!itemKey.startsWith(normalizedPath)) {\n continue;\n }\n\n // Get the relative path after the directory\n const relative = itemKey.substring(normalizedPath.length);\n\n // If relative path contains '/', it's in a subdirectory\n if (relative.includes(\"/\")) {\n // Extract the immediate subdirectory name\n const subdirName = relative.split(\"/\")[0];\n subdirs.add(normalizedPath + subdirName + \"/\");\n continue;\n }\n\n // This is a file directly in the current directory\n try {\n const fd = this.convertToFileData(item.value);\n const size = fd.content.join(\"\\n\").length;\n infos.push({\n path: itemKey,\n is_dir: false,\n size: size,\n modified_at: fd.modified_at,\n });\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n // Add directories to the results\n for (const subdir of Array.from(subdirs).sort()) {\n infos.push({\n path: subdir,\n is_dir: true,\n size: 0,\n modified_at: \"\",\n });\n }\n\n infos.sort((a, b) => a.path.localeCompare(b.path));\n return infos;\n }\n\n /**\n * Read file content with line numbers.\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 2000\n ): Promise<string> {\n try {\n const fileData = await this.readRaw(filePath);\n return formatReadResponse(fileData, offset, limit);\n } catch (e: unknown) {\n const error = e as Error;\n return `Error: ${error.message}`;\n }\n }\n\n /**\n * Read file content as raw FileData.\n */\n async readRaw(filePath: string): Promise<FileData> {\n const namespace = this.getNamespace();\n const value = await this.store.get(namespace, filePath);\n\n if (!value) {\n throw new Error(`File '${filePath}' not found`);\n }\n\n return this.convertToFileData(value);\n }\n\n /**\n * Create a new file with content.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const namespace = this.getNamespace();\n\n // Check if file exists\n const existing = await this.store.get(namespace, filePath);\n if (existing) {\n return {\n success: false,\n error: FILE_ALREADY_EXISTS(filePath),\n };\n }\n\n // Create new file\n const fileData = createFileData(content);\n const storeValue = this.convertFromFileData(fileData);\n await this.store.put(namespace, filePath, storeValue);\n return { success: true, path: filePath };\n }\n\n /**\n * Edit a file by replacing string occurrences.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false\n ): Promise<EditResult> {\n const namespace = this.getNamespace();\n\n // Get existing file\n const value = await this.store.get(namespace, filePath);\n if (!value) {\n return { success: false, error: FILE_NOT_FOUND(filePath) };\n }\n\n try {\n const fileData = this.convertToFileData(value);\n const content = fileDataToString(fileData);\n const result = performStringReplacement(\n content,\n oldString,\n newString,\n replaceAll\n );\n\n if (typeof result === \"string\") {\n return { success: false, error: result };\n }\n\n const [newContent, occurrences] = result;\n const newFileData = updateFileData(fileData, newContent);\n\n // Update file in store\n const storeValue = this.convertFromFileData(newFileData);\n await this.store.put(namespace, filePath, storeValue);\n return { success: true, path: filePath, occurrences };\n } catch (e: unknown) {\n const error = e as Error;\n return { success: false, error: `Error: ${error.message}` };\n }\n }\n\n /**\n * Structured search results or error string for invalid input.\n */\n async grepRaw(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null\n ): Promise<GrepMatch[] | string> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertToFileData(item.value);\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n return grepMatchesFromFiles(files, pattern, path, glob);\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async globInfo(pattern: string, path: string = \"/\"): Promise<FileInfo[]> {\n const namespace = this.getNamespace();\n const items = await this.store.list(namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertToFileData(item.value);\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n const result = globSearchFiles(files, pattern, path);\n if (result === \"No files found\") {\n return [];\n }\n\n const paths = result.split(\"\\n\");\n const infos: FileInfo[] = [];\n for (const p of paths) {\n const fd = files[p];\n const size = fd ? fd.content.join(\"\\n\").length : 0;\n infos.push({\n path: p,\n is_dir: false,\n size: size,\n modified_at: fd?.modified_at || \"\",\n });\n }\n return infos;\n }\n\n /**\n * Delete a file.\n */\n async deleteFile(filePath: string): Promise<{ error?: string }> {\n const namespace = this.getNamespace();\n const existing = await this.store.get(namespace, filePath);\n\n if (!existing) {\n return { error: `File '${filePath}' not found` };\n }\n\n await this.store.delete(namespace, filePath);\n return {};\n }\n}\n\n","/**\n * Tools exports.\n */\n\nexport { createTodosTool, write_todos } from \"./todos\";\nexport {\n createFilesystemTools,\n createLsTool,\n createReadFileTool,\n createWriteFileTool,\n createEditFileTool,\n createGlobTool,\n createGrepTool,\n ls,\n read_file,\n write_file,\n edit_file,\n glob,\n grep,\n} from \"./filesystem\";\nexport { createSubagentTool, type CreateSubagentToolOptions } from \"./subagent\";\nexport {\n createExecuteTool,\n createExecuteToolFromBackend,\n type CreateExecuteToolOptions,\n execute,\n} from \"./execute\";\nexport {\n createWebTools,\n htmlToMarkdown,\n type CreateWebToolsOptions,\n createWebSearchTool,\n createHttpRequestTool,\n createFetchUrlTool,\n web_search,\n http_request,\n fetch_url,\n} from \"./web\";\n\n","/**\n * Utility functions for AI SDK Deep Agent.\n */\n\nexport { patchToolCalls, hasDanglingToolCalls } from \"./patch-tool-calls\";\nexport {\n evictToolResult,\n createToolResultWrapper,\n shouldEvict,\n estimateTokens,\n sanitizeToolCallId,\n DEFAULT_EVICTION_TOKEN_LIMIT,\n type EvictOptions,\n type EvictResult,\n} from \"./eviction\";\nexport {\n summarizeIfNeeded,\n needsSummarization,\n estimateMessagesTokens,\n DEFAULT_SUMMARIZATION_THRESHOLD,\n DEFAULT_KEEP_MESSAGES,\n type SummarizationOptions,\n type SummarizationResult,\n} from \"./summarization\";\nexport {\n parseModelString,\n} from \"./model-parser\";\nexport {\n applyInterruptConfig,\n wrapToolsWithApproval,\n hasApprovalTools,\n type ApprovalCallback,\n} from \"./approval\";\n\n","/**\n * In-memory checkpoint saver for testing and single-session use.\n */\n\nimport type { Checkpoint, BaseCheckpointSaver, CheckpointSaverOptions } from \"./types\";\n\n/**\n * In-memory checkpoint saver.\n * \n * Stores checkpoints in a Map. Data is lost when the process exits.\n * Useful for testing or single-session applications.\n * \n * @example\n * ```typescript\n * const saver = new MemorySaver();\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * checkpointer: saver,\n * });\n * ```\n */\nexport class MemorySaver implements BaseCheckpointSaver {\n private checkpoints = new Map<string, Checkpoint>();\n private namespace: string;\n\n constructor(options: CheckpointSaverOptions = {}) {\n this.namespace = options.namespace || \"default\";\n }\n\n private getKey(threadId: string): string {\n return `${this.namespace}:${threadId}`;\n }\n\n async save(checkpoint: Checkpoint): Promise<void> {\n const key = this.getKey(checkpoint.threadId);\n this.checkpoints.set(key, {\n ...checkpoint,\n updatedAt: new Date().toISOString(),\n });\n }\n\n async load(threadId: string): Promise<Checkpoint | undefined> {\n const key = this.getKey(threadId);\n return this.checkpoints.get(key);\n }\n\n async list(): Promise<string[]> {\n const prefix = `${this.namespace}:`;\n const threadIds: string[] = [];\n for (const key of this.checkpoints.keys()) {\n if (key.startsWith(prefix)) {\n threadIds.push(key.substring(prefix.length));\n }\n }\n return threadIds;\n }\n\n async delete(threadId: string): Promise<void> {\n const key = this.getKey(threadId);\n this.checkpoints.delete(key);\n }\n\n async exists(threadId: string): Promise<boolean> {\n const key = this.getKey(threadId);\n return this.checkpoints.has(key);\n }\n\n /**\n * Clear all checkpoints (useful for testing).\n */\n clear(): void {\n this.checkpoints.clear();\n }\n\n /**\n * Get the number of stored checkpoints.\n */\n size(): number {\n return this.checkpoints.size;\n }\n}\n\n","/**\n * Checkpoint saver using KeyValueStore interface.\n * \n * Allows using existing KeyValueStore implementations (Redis, etc.)\n * for checkpoint storage.\n */\n\nimport type { KeyValueStore } from \"../backends/persistent\";\nimport type { Checkpoint, BaseCheckpointSaver, CheckpointSaverOptions } from \"./types\";\n\n/**\n * Options for KeyValueStoreSaver.\n */\nexport interface KeyValueStoreSaverOptions extends CheckpointSaverOptions {\n /** The KeyValueStore implementation to use */\n store: KeyValueStore;\n}\n\n/**\n * Checkpoint saver using KeyValueStore interface.\n * \n * This adapter allows using any KeyValueStore implementation (Redis,\n * database, cloud storage, etc.) for checkpoint storage.\n * \n * @example\n * ```typescript\n * import { InMemoryStore } from 'deepagentsdk';\n * \n * const store = new InMemoryStore();\n * const saver = new KeyValueStoreSaver({ store });\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-20250514'),\n * checkpointer: saver,\n * });\n * ```\n * \n * @example With Redis\n * ```typescript\n * const redisStore = new RedisStore(redisClient); // Your implementation\n * const saver = new KeyValueStoreSaver({ store: redisStore });\n * ```\n */\nexport class KeyValueStoreSaver implements BaseCheckpointSaver {\n private store: KeyValueStore;\n private namespace: string[];\n\n constructor(options: KeyValueStoreSaverOptions) {\n this.store = options.store;\n this.namespace = [options.namespace || \"default\", \"checkpoints\"];\n }\n\n async save(checkpoint: Checkpoint): Promise<void> {\n const data = {\n ...checkpoint,\n updatedAt: new Date().toISOString(),\n };\n await this.store.put(this.namespace, checkpoint.threadId, data as unknown as Record<string, unknown>);\n }\n\n async load(threadId: string): Promise<Checkpoint | undefined> {\n const data = await this.store.get(this.namespace, threadId);\n if (!data) {\n return undefined;\n }\n return data as unknown as Checkpoint;\n }\n\n async list(): Promise<string[]> {\n const items = await this.store.list(this.namespace);\n return items.map(item => item.key);\n }\n\n async delete(threadId: string): Promise<void> {\n await this.store.delete(this.namespace, threadId);\n }\n\n async exists(threadId: string): Promise<boolean> {\n const data = await this.store.get(this.namespace, threadId);\n return data !== undefined;\n }\n}\n\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport os from 'node:os';\nimport type { LanguageModelMiddleware } from 'ai';\nimport { findGitRoot } from '../utils/project-detection';\n\n/**\n * Configuration options for agent memory middleware.\n */\nexport interface AgentMemoryOptions {\n /**\n * Unique identifier for the agent (e.g., \"code-architect\", \"research-agent\").\n * Used to locate agent-specific memory at ~/.deepagents/{agentId}/agent.md\n */\n agentId: string;\n\n /**\n * Optional working directory for project-level memory detection.\n * Defaults to process.cwd().\n */\n workingDirectory?: string;\n\n /**\n * Optional custom path for user-level .deepagents directory.\n * Defaults to os.homedir() + '/.deepagents'.\n *\n * Useful for testing or custom deployment environments.\n *\n * @example\n * ```typescript\n * userDeepagentsDir: '/custom/path/.deepagents'\n * // Will look for memory at: /custom/path/.deepagents/{agentId}/agent.md\n * ```\n */\n userDeepagentsDir?: string;\n\n /**\n * Optional callback to request user approval for creating project-level .deepagents/ directory.\n * If not provided, project memory will be silently skipped if directory doesn't exist.\n *\n * @param projectPath - Absolute path to the detected git root\n * @returns Promise<boolean> - true if user approves, false otherwise\n */\n requestProjectApproval?: (projectPath: string) => Promise<boolean>;\n}\n\n/**\n * Load agent memory from a file path.\n * Returns empty string if file doesn't exist or can't be read.\n */\nasync function loadAgentMemory(filePath: string): Promise<string> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim();\n } catch {\n return '';\n }\n}\n\n/**\n * Load all additional .md files from the agent's directory (excluding agent.md).\n * Returns an array of { filename, content } objects.\n */\nasync function loadAdditionalMemoryFiles(\n dirPath: string\n): Promise<Array<{ filename: string; content: string }>> {\n try {\n const files = await fs.readdir(dirPath);\n const mdFiles = files.filter(\n (f) => f.endsWith('.md') && f !== 'agent.md'\n );\n\n const results = await Promise.all(\n mdFiles.map(async (filename) => {\n const content = await loadAgentMemory(path.join(dirPath, filename));\n return { filename, content };\n })\n );\n\n return results.filter((r) => r.content.length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Build the memory section for the system prompt.\n * This comprehensive prompt teaches the agent how to use memory effectively.\n */\nfunction buildMemorySection(\n userMemory: string,\n projectMemory: string,\n additionalFiles: Array<{ filename: string; content: string }>,\n agentId: string,\n userMemoryPath: string,\n projectMemoryPath: string | null\n): string {\n let sections: string[] = [];\n\n // Build memory content sections\n if (userMemory) {\n sections.push(`# Agent Memory (User-Level)\n\nThe following is your persistent memory stored at ${userMemoryPath}:\n\n${userMemory}`);\n }\n\n if (projectMemory && projectMemoryPath) {\n sections.push(`# Agent Memory (Project-Level)\n\nThe following is project-specific context stored at ${projectMemoryPath}:\n\n${projectMemory}`);\n }\n\n if (additionalFiles.length > 0) {\n const additionalSections = additionalFiles.map(\n ({ filename, content }) => `## ${filename}\n\n${content}`\n );\n sections.push(`# Additional Context Files\n\n${additionalSections.join('\\n\\n')}`);\n }\n\n if (sections.length === 0) {\n return ''; // No memory to inject\n }\n\n // Build comprehensive instructions\n const memoryContent = sections.join('\\n\\n---\\n\\n');\n const instructions = `\n<agent_memory>\n${memoryContent}\n\n---\n\n## How to Use This Memory\n\n**What is this?**\n- The content above is your persistent memory, stored in markdown files\n- **User-level memory** (${userMemoryPath}) contains your core personality, preferences, and cross-project context\n- **Project-level memory** ${projectMemoryPath ? `(${projectMemoryPath})` : '(not available)'} contains project-specific context and conventions\n\n**When to read memory:**\n- You already have the memory content above in your context - no need to read the files unless you need to verify exact content\n- If you need to check current memory state or see if it's been updated, use \\`read_file\\` tool\n\n**When to update memory:**\n- **User memory**: When you learn something important about the user's preferences, working style, or recurring patterns\n- **Project memory**: When you discover project-specific conventions, architecture decisions, or important context\n- **Additional files**: For specialized context that doesn't fit in agent.md (e.g., decision logs, architecture notes)\n\n**How to update memory:**\n- Use the \\`write_file\\` or \\`edit_file\\` tools with the file paths shown above\n- Keep entries concise and relevant\n- Organize information clearly with markdown headings\n- Remove outdated information when updating\n\n**Important guidelines:**\n- Memory is meant for long-term context, not temporary task tracking\n- Don't store information that's already in the codebase or documentation\n- Focus on insights, patterns, and preferences that aren't obvious from other sources\n- When in doubt, ask the user if something should be remembered\n\n**Example use cases:**\n- User prefers TypeScript strict mode and comprehensive error handling\n- Project uses custom testing framework located in \\`test-utils/\\`\n- User wants all API responses to follow specific error format\n- Project has specific commit message conventions\n</agent_memory>\n`;\n\n return instructions.trim();\n}\n\n/**\n * Create agent memory middleware for AI SDK v6.\n *\n * This middleware loads agent memory from:\n * 1. User-level: ~/.deepagents/{agentId}/agent.md (personality, preferences)\n * 2. Project-level: [git-root]/.deepagents/agent.md (project-specific context)\n * 3. Additional files: Any other .md files in the user-level directory\n *\n * The memory is injected into the system prompt before each model call, teaching\n * the agent when and how to read/update its own memory using filesystem tools.\n *\n * @param options - Configuration for agent memory\n * @param options.agentId - Unique identifier for the agent (e.g., \"code-architect\")\n * @param options.workingDirectory - Optional working directory for project detection (defaults to process.cwd())\n * @param options.userDeepagentsDir - Optional custom path for user-level .deepagents directory (defaults to ~/.deepagents)\n * @param options.requestProjectApproval - Optional callback to request approval before creating project .deepagents/ directory\n * @returns AI SDK v6 middleware\n *\n * @example Basic usage\n * ```typescript\n * import { createDeepAgent } from 'deepagentsdk';\n * import { createAgentMemoryMiddleware } from 'deepagentsdk/middleware';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * });\n *\n * const agent = createDeepAgent({\n * model: anthropic('claude-sonnet-4-5'),\n * middleware: memoryMiddleware,\n * });\n * ```\n *\n * @example With project approval callback\n * ```typescript\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * requestProjectApproval: async (projectPath) => {\n * console.log(`Create .deepagents/ in ${projectPath}? (y/n)`);\n * // ... get user input\n * return userSaidYes;\n * }\n * });\n * ```\n *\n * @example With custom user directory path\n * ```typescript\n * const memoryMiddleware = createAgentMemoryMiddleware({\n * agentId: 'code-architect',\n * userDeepagentsDir: '/custom/path/.deepagents',\n * // Memory will be loaded from:\n * // - /custom/path/.deepagents/code-architect/agent.md\n * // - [git-root]/.deepagents/agent.md (project-level)\n * });\n * ```\n */\nexport function createAgentMemoryMiddleware(\n options: AgentMemoryOptions\n): LanguageModelMiddleware {\n const { agentId, workingDirectory, userDeepagentsDir, requestProjectApproval } = options;\n\n // Memory is loaded once and cached in closure variables\n let memoryLoaded = false;\n let cachedMemorySection = '';\n\n return {\n specificationVersion: 'v3',\n transformParams: async ({ params }) => {\n // Load memory on first call only (closure-based caching)\n if (!memoryLoaded) {\n const workDir = workingDirectory || process.cwd();\n\n // 1. Load user-level memory\n const baseUserDir = userDeepagentsDir || path.join(os.homedir(), '.deepagents');\n const userAgentDir = path.join(baseUserDir, agentId);\n const userMemoryPath = path.join(userAgentDir, 'agent.md');\n const userMemory = await loadAgentMemory(userMemoryPath);\n\n // Auto-create user directory if it doesn't exist (safe operation)\n if (!userMemory) {\n try {\n await fs.mkdir(userAgentDir, { recursive: true });\n } catch {\n // Ignore errors - directory might already exist or permissions issue\n }\n }\n\n // 2. Load additional .md files from user directory\n const additionalFiles = await loadAdditionalMemoryFiles(userAgentDir);\n\n // 3. Load project-level memory (if in git repository)\n let projectMemory = '';\n let projectMemoryPath: string | null = null;\n\n const gitRoot = await findGitRoot(workDir);\n if (gitRoot) {\n const projectDeepagentsDir = path.join(gitRoot, '.deepagents');\n projectMemoryPath = path.join(projectDeepagentsDir, 'agent.md');\n\n // Check if project directory exists\n try {\n await fs.stat(projectDeepagentsDir);\n projectMemory = await loadAgentMemory(projectMemoryPath);\n } catch {\n // Project directory doesn't exist - request approval if callback provided\n if (requestProjectApproval) {\n const approved = await requestProjectApproval(gitRoot);\n if (approved) {\n try {\n await fs.mkdir(projectDeepagentsDir, { recursive: true });\n // Don't create agent.md yet - let the agent do it when needed\n } catch {\n // Ignore errors - permissions issue or race condition\n }\n }\n }\n }\n }\n\n // Build and cache memory section\n cachedMemorySection = buildMemorySection(\n userMemory,\n projectMemory,\n additionalFiles,\n agentId,\n userMemoryPath,\n projectMemoryPath\n );\n\n memoryLoaded = true;\n }\n\n // Inject memory into system prompt if available\n if (cachedMemorySection) {\n const updatedPrompt = params.prompt.map((msg) => {\n if (msg.role === 'system') {\n return {\n ...msg,\n content: `${msg.content}\\n\\n${cachedMemorySection}`,\n };\n }\n return msg;\n });\n\n return { ...params, prompt: updatedPrompt };\n }\n\n return params;\n },\n };\n}\n"],"mappings":"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"}