deepagents 1.13.2 → 1.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-CH8GB5HD.d.ts → agent-CVBXKZAu.d.ts} +59 -82
- package/dist/{agent-BwYXPTyT.d.cts → agent-D7nWARfg.d.cts} +58 -82
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{langsmith-BBV5JlNW.js → langsmith-BYWZnEVh.js} +241 -95
- package/dist/langsmith-BYWZnEVh.js.map +1 -0
- package/dist/{langsmith-DL32swQ3.cjs → langsmith-Ynj9VKxb.cjs} +240 -99
- package/dist/langsmith-Ynj9VKxb.cjs.map +1 -0
- package/dist/node.cjs +2 -2
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/{src-CKk0apeE.js → src-Blh1ZEYd.js} +2 -2
- package/dist/{src-CKk0apeE.js.map → src-Blh1ZEYd.js.map} +1 -1
- package/dist/{src-DdGDIhZk.cjs → src-DRMLI0-x.cjs} +2 -2
- package/dist/{src-DdGDIhZk.cjs.map → src-DRMLI0-x.cjs.map} +1 -1
- package/package.json +1 -1
- package/dist/langsmith-BBV5JlNW.js.map +0 -1
- package/dist/langsmith-DL32swQ3.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langsmith-BYWZnEVh.js","names":["validatePath","trimTrailingSlashes","getErrorMessage","z","mergeMiddleware","SystemMessage","AIMessage","HumanMessage","z","z","z","z","AIMessage","ToolMessage","SYSTEM_PROMPT_SUFFIX","register","SYSTEM_PROMPT_SUFFIX","register","SYSTEM_PROMPT_SUFFIX","register","mergeMiddleware","trimTrailingSlashes","getLangGraphStore","Client","#sandbox","#defaultTimeout","#isRunning"],"sources":["../src/backends/utils.ts","../src/backends/protocol.ts","../src/backends/state.ts","../src/permissions/enforce.ts","../src/backends/composite.ts","../src/middleware/fs.ts","../src/middleware/summarization.ts","../src/middleware/utils.ts","../src/middleware/subagents.ts","../src/middleware/patch_tool_calls.ts","../src/values.ts","../src/utils.ts","../src/middleware/memory.ts","../src/middleware/skills.ts","../src/middleware/completion_callback.ts","../src/middleware/async_subagents.ts","../src/errors.ts","../src/middleware/cache.ts","../src/middleware/tool_exclusion.ts","../src/profiles/keys.ts","../src/profiles/harness/types.ts","../src/profiles/harness/create.ts","../src/profiles/harness/serialization.ts","../src/profiles/harness/merge.ts","../src/profiles/harness/builtins/anthropic-opus-4-7.ts","../src/profiles/harness/builtins/anthropic-sonnet-4-6.ts","../src/profiles/harness/builtins/anthropic-haiku-4-5.ts","../src/profiles/harness/builtins/openai-codex.ts","../src/profiles/harness/builtins/index.ts","../src/profiles/harness/registry.ts","../src/agent.ts","../src/compat.ts","../src/backends/store.ts","../src/backends/context-hub.ts","../src/backends/sandbox.ts","../src/backends/langsmith.ts"],"sourcesContent":["/**\n * Shared utility functions for memory backend implementations.\n *\n * This module contains both user-facing string formatters and structured\n * helpers used by backends and the composite router. Structured helpers\n * enable composition without fragile string parsing.\n */\n\nimport micromatch from \"micromatch\";\nimport {\n AnyBackendProtocol,\n AnySandboxProtocol,\n applyGrepMaxCount,\n BackendProtocolV1,\n BackendProtocolV2,\n FileData,\n FileDataV1,\n FileDataV2,\n GlobResult,\n GrepMatch,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n SandboxBackendProtocolV2,\n} from \"./protocol.js\";\n\n// Constants\nexport const EMPTY_CONTENT_WARNING =\n \"System reminder: File exists but has empty contents\";\nexport const MAX_LINE_LENGTH = 5000;\nexport const LINE_NUMBER_WIDTH = 6;\nexport const TOOL_RESULT_TOKEN_LIMIT = 20000; // Same threshold as eviction\nexport const TRUNCATION_GUIDANCE =\n \"... [results truncated, try being more specific with your parameters]\";\n\n/**\n * Normalize model- or caller-supplied text pagination bounds.\n *\n * Every backend must slice content and calculate pagination metadata from the\n * same normalized values. Otherwise a fractional or negative argument could\n * return one window while advertising a different `nextOffset`.\n *\n * Binary reads do not use this helper because their backend contract ignores\n * line-based offset and limit values.\n */\nexport function normalizeReadPagination(\n offset: number,\n limit: number,\n): { offset: number; limit: number } {\n return {\n offset: Number.isFinite(offset) ? Math.max(0, Math.floor(offset)) : 0,\n limit: Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0,\n };\n}\n\nconst MIME_TYPES: Record<string, string> = {\n // images\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n \".heic\": \"image/heic\",\n \".heif\": \"image/heif\",\n\n // audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aiff\": \"audio/aiff\",\n \".aac\": \"audio/aac\",\n \".ogg\": \"audio/ogg\",\n \".flac\": \"audio/flac\",\n\n // video\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".mpeg\": \"video/mpeg\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n \".flv\": \"video/x-flv\",\n \".mpg\": \"video/mpeg\",\n \".wmv\": \"video/x-ms-wmv\",\n \".3gpp\": \"video/3gpp\",\n\n // documents\n \".pdf\": \"application/pdf\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".pptx\":\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n\n // text / code — explicit entries give a specific MIME type (e.g.\n // text/markdown, text/css, application/json) rather than the generic\n // \"text/plain\" default that unknown extensions fall through to.\n \".txt\": \"text/plain\",\n \".md\": \"text/markdown\",\n \".markdown\": \"text/markdown\",\n \".html\": \"text/html\",\n \".htm\": \"text/html\",\n \".css\": \"text/css\",\n \".csv\": \"text/csv\",\n \".xml\": \"text/xml\",\n \".json\": \"application/json\",\n \".js\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".cjs\": \"application/javascript\",\n \".ts\": \"text/plain\",\n \".tsx\": \"text/plain\",\n \".jsx\": \"text/plain\",\n \".py\": \"text/plain\",\n \".rb\": \"text/plain\",\n \".java\": \"text/plain\",\n \".c\": \"text/plain\",\n \".cpp\": \"text/plain\",\n \".h\": \"text/plain\",\n \".hpp\": \"text/plain\",\n \".go\": \"text/plain\",\n \".rs\": \"text/plain\",\n \".sh\": \"text/plain\",\n \".bash\": \"text/plain\",\n \".zsh\": \"text/plain\",\n \".yaml\": \"text/plain\",\n \".yml\": \"text/plain\",\n \".toml\": \"text/plain\",\n \".ini\": \"text/plain\",\n \".cfg\": \"text/plain\",\n \".conf\": \"text/plain\",\n \".env\": \"text/plain\",\n \".log\": \"text/plain\",\n \".sql\": \"text/plain\",\n \".graphql\": \"text/plain\",\n \".proto\": \"text/plain\",\n \".r\": \"text/plain\",\n \".swift\": \"text/plain\",\n \".kt\": \"text/plain\",\n \".kts\": \"text/plain\",\n \".scala\": \"text/plain\",\n \".dart\": \"text/plain\",\n \".lua\": \"text/plain\",\n \".pl\": \"text/plain\",\n \".pm\": \"text/plain\",\n \".php\": \"text/plain\",\n \".ex\": \"text/plain\",\n \".exs\": \"text/plain\",\n \".erl\": \"text/plain\",\n \".hs\": \"text/plain\",\n \".ml\": \"text/plain\",\n \".mli\": \"text/plain\",\n \".vue\": \"text/plain\",\n \".svelte\": \"text/plain\",\n \".astro\": \"text/plain\",\n \".tf\": \"text/plain\",\n \".cmake\": \"text/plain\",\n \".makefile\": \"text/plain\",\n \".dockerfile\": \"text/plain\",\n \".gitignore\": \"text/plain\",\n \".dockerignore\": \"text/plain\",\n \".editorconfig\": \"text/plain\",\n};\n\nfunction basename(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, \"/\");\n const slashIdx = normalized.lastIndexOf(\"/\");\n return slashIdx === -1 ? normalized : normalized.slice(slashIdx + 1);\n}\n\nfunction extname(filePath: string): string {\n const name = basename(filePath);\n const dotIdx = name.lastIndexOf(\".\");\n return dotIdx <= 0 ? \"\" : name.slice(dotIdx);\n}\n\n/**\n * Sanitize tool_call_id to prevent path traversal and separator issues.\n *\n * Replaces dangerous characters (., /, \\) with underscores.\n */\nexport function sanitizeToolCallId(toolCallId: string): string {\n return toolCallId.replace(/\\./g, \"_\").replace(/\\//g, \"_\").replace(/\\\\/g, \"_\");\n}\n\nexport interface FormattedContentWithLineNumbers {\n /** Complete line-numbered display text. */\n text: string;\n /**\n * Character offsets immediately after each complete source line.\n *\n * A long source line may span several display rows (`12`, `12.1`, ...),\n * but contributes only one boundary after its final chunk.\n */\n sourceLineBoundaries: Array<{ sourceLine: number; endOffset: number }>;\n}\n\n/**\n * Format file content with line numbers and structured source-line boundaries.\n *\n * The boundaries let downstream size limiting truncate only after complete\n * source lines without reparsing the rendered gutter. This keeps presentation\n * details (padding, tab separators, and continuation labels) encapsulated in\n * the formatter that creates them.\n */\nexport function formatContentWithLineNumbersAndBoundaries(\n content: string | string[],\n startLine: number = 1,\n): FormattedContentWithLineNumbers {\n let lines: string[];\n if (typeof content === \"string\") {\n lines = content.split(\"\\n\");\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines = lines.slice(0, -1);\n }\n } else {\n lines = content;\n }\n\n const resultLines: string[] = [];\n const sourceLineBoundaries: Array<{\n sourceLine: number;\n endOffset: number;\n }> = [];\n let renderedLength = 0;\n\n const appendRow = (\n row: string,\n sourceLine: number,\n completesSourceLine: boolean,\n ) => {\n if (resultLines.length > 0) renderedLength += 1; // Inter-row newline.\n resultLines.push(row);\n renderedLength += row.length;\n if (completesSourceLine) {\n sourceLineBoundaries.push({ sourceLine, endOffset: renderedLength });\n }\n };\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineNum = i + startLine;\n\n if (line.length <= MAX_LINE_LENGTH) {\n appendRow(\n `${lineNum.toString().padStart(LINE_NUMBER_WIDTH)}\\t${line}`,\n lineNum,\n true,\n );\n continue;\n }\n\n const numChunks = Math.ceil(line.length / MAX_LINE_LENGTH);\n for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {\n const start = chunkIdx * MAX_LINE_LENGTH;\n const end = Math.min(start + MAX_LINE_LENGTH, line.length);\n const chunk = line.substring(start, end);\n const marker = chunkIdx === 0 ? `${lineNum}` : `${lineNum}.${chunkIdx}`;\n appendRow(\n `${marker.padStart(LINE_NUMBER_WIDTH)}\\t${chunk}`,\n lineNum,\n chunkIdx === numChunks - 1,\n );\n }\n }\n\n return { text: resultLines.join(\"\\n\"), sourceLineBoundaries };\n}\n\n/**\n * Format file content with line numbers (cat -n style).\n *\n * Lines longer than `MAX_LINE_LENGTH` are split into continuation rows such as\n * `5.1` and `5.2`. Use `formatContentWithLineNumbersAndBoundaries` when a\n * caller also needs safe source-line truncation points.\n */\nexport function formatContentWithLineNumbers(\n content: string | string[],\n startLine: number = 1,\n): string {\n return formatContentWithLineNumbersAndBoundaries(content, startLine).text;\n}\n\n/**\n * Check if content is empty and return warning message.\n *\n * @param content - Content to check\n * @returns Warning message if empty, null otherwise\n */\nexport function checkEmptyContent(content: string): string | null {\n if (!content || content.trim() === \"\") {\n return EMPTY_CONTENT_WARNING;\n }\n return null;\n}\n\n/**\n * Convert FileData to plain string content.\n *\n * @param fileData - FileData object with 'content' key\n * @returns Content as string with lines joined by newlines\n */\nexport function fileDataToString(fileData: FileData): string {\n if (Array.isArray(fileData.content)) {\n return fileData.content.join(\"\\n\");\n }\n if (typeof fileData.content === \"string\") {\n return fileData.content;\n }\n throw new Error(\"Cannot convert binary FileData to string\");\n}\n\n/**\n * Type guard to check if FileData contains binary content (Uint8Array).\n *\n * @param data - FileData to check\n * @returns True if the content is a Uint8Array (binary)\n */\nexport function isFileDataBinary(\n data: FileData,\n): data is FileDataV2 & { content: Uint8Array } {\n return ArrayBuffer.isView(data.content);\n}\n\n/**\n * Create a FileData object.\n *\n * Defaults to v2 format (content as single string). Pass `fileFormat: \"v1\"` for\n * backward compatibility with older readers during a rolling deployment.\n * Binary content (Uint8Array) is only supported with v2.\n *\n * @param content - File content as a string or binary Uint8Array (v2 only)\n * @param createdAt - Optional creation timestamp (ISO format), defaults to now\n * @param fileFormat - Storage format: \"v2\" (default) or \"v1\" (legacy line array)\n * @returns FileData in the requested format\n */\nexport function createFileData(\n content: string | Uint8Array,\n createdAt?: string,\n fileFormat: \"v1\" | \"v2\" = \"v2\",\n mimeType?: string,\n): FileData {\n const now = new Date().toISOString();\n\n if (fileFormat === \"v1\" && ArrayBuffer.isView(content)) {\n throw new Error(\n \"Binary data is not supported with v1 file formats. Please use v2 file format\",\n );\n }\n\n if (fileFormat === \"v2\") {\n if (ArrayBuffer.isView(content)) {\n return {\n content: new Uint8Array(\n content.buffer,\n content.byteOffset,\n content.byteLength,\n ),\n mimeType: mimeType ?? \"application/octet-stream\",\n created_at: createdAt || now,\n modified_at: now,\n } as FileDataV2;\n }\n return {\n content,\n mimeType: mimeType ?? \"text/plain\",\n created_at: createdAt || now,\n modified_at: now,\n } as FileDataV2;\n }\n\n const lines = typeof content === \"string\" ? content.split(\"\\n\") : content;\n return {\n content: lines,\n created_at: createdAt || now,\n modified_at: now,\n } as FileDataV1;\n}\n\n/**\n * Update FileData with new content, preserving creation timestamp.\n *\n * @param fileData - Existing FileData object\n * @param content - New content as string\n * @returns Updated FileData object\n */\nexport function updateFileData(fileData: FileData, content: string): FileData {\n const now = new Date().toISOString();\n\n if (isFileDataV1(fileData)) {\n const lines = typeof content === \"string\" ? content.split(\"\\n\") : content;\n return {\n content: lines,\n created_at: fileData.created_at,\n modified_at: now,\n };\n }\n\n return {\n content,\n mimeType: fileData.mimeType,\n created_at: fileData.created_at,\n modified_at: now,\n };\n}\n\n/**\n * Build FileData for write semantics.\n *\n * Text writes preserve an existing file's creation timestamp. Binary writes\n * accept base64 text input and store decoded bytes with the path's MIME type.\n */\nfunction decodeBase64ToBytes(base64: string): Uint8Array {\n const trimmed = base64.trim();\n const payload = trimmed.startsWith(\"data:\")\n ? trimmed.slice(trimmed.indexOf(\",\") + 1)\n : trimmed;\n const binary = atob(payload.replace(/\\s/g, \"\"));\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nexport function createWriteFileData(\n filePath: string,\n content: string,\n fileFormat: \"v1\" | \"v2\" = \"v2\",\n existing?: FileData,\n): FileData {\n const mimeType = getMimeType(filePath);\n const createdAt = existing?.created_at;\n\n if (!isTextMimeType(mimeType)) {\n return fileFormat === \"v1\"\n ? createFileData(content, createdAt, \"v1\", mimeType)\n : createFileData(decodeBase64ToBytes(content), createdAt, \"v2\", mimeType);\n }\n\n return existing\n ? updateFileData(existing, content)\n : createFileData(content, undefined, fileFormat, mimeType);\n}\n\n/**\n * Format file data for read response with line numbers.\n *\n * @param fileData - FileData object\n * @param offset - Line offset (0-indexed)\n * @param limit - Maximum number of lines\n * @returns Formatted content or error message\n */\nexport function formatReadResponse(\n fileData: FileData,\n offset: number,\n limit: number,\n): string {\n if (isFileDataBinary(fileData)) {\n return \"Error: Cannot format binary FileData as text\";\n }\n const content = fileDataToString(fileData);\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}\n\n/**\n * Perform string replacement with occurrence validation.\n *\n * @param content - Original content\n * @param oldString - String to replace\n * @param newString - Replacement string\n * @param replaceAll - Whether to replace all occurrences\n * @returns Tuple of [new_content, occurrences] on success, or error message string\n *\n * Special case: When both content and oldString are empty, this sets the initial\n * content to newString. This allows editing empty files by treating empty oldString\n * as \"set initial content\" rather than \"replace nothing\".\n */\nexport function performStringReplacement(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean,\n): [string, number] | string {\n // Special case: empty file with empty oldString sets initial content\n if (content === \"\" && oldString === \"\") {\n return [newString, 0];\n }\n\n // Validate that oldString is not empty (for non-empty files)\n if (oldString === \"\") {\n return \"Error: oldString cannot be empty when file has content\";\n }\n\n // Use split to count occurrences (simpler than regex)\n const occurrences = content.split(oldString).length - 1;\n\n if (occurrences === 0) {\n return `Error: String not found in file: '${oldString}'`;\n }\n\n if (occurrences > 1 && !replaceAll) {\n return `Error: String '${oldString}' has multiple occurrences (appears ${occurrences} times) in file. Use replace_all=True to replace all instances, or provide a more specific string with surrounding context.`;\n }\n\n // Python's str.replace() replaces ALL occurrences\n // Use split/join for consistent behavior\n const newContent = content.split(oldString).join(newString);\n\n return [newContent, occurrences];\n}\n\n/**\n * Truncate list or string result if it exceeds token limit (rough estimate: 4 chars/token).\n */\nexport function truncateIfTooLong(\n result: string[] | string,\n): string[] | string {\n if (Array.isArray(result)) {\n const totalChars = result.reduce((sum, item) => sum + item.length, 0);\n if (totalChars > TOOL_RESULT_TOKEN_LIMIT * 4) {\n const truncateAt = Math.floor(\n (result.length * TOOL_RESULT_TOKEN_LIMIT * 4) / totalChars,\n );\n return [...result.slice(0, truncateAt), TRUNCATION_GUIDANCE];\n }\n return result;\n }\n // string\n if (result.length > TOOL_RESULT_TOKEN_LIMIT * 4) {\n return (\n result.substring(0, TOOL_RESULT_TOKEN_LIMIT * 4) +\n \"\\n\" +\n TRUNCATION_GUIDANCE\n );\n }\n return result;\n}\n\n/**\n * Validate and normalize a directory path.\n *\n * Ensures paths are safe to use by preventing directory traversal attacks\n * and enforcing consistent formatting. All paths are normalized to use\n * forward slashes and start with a leading slash.\n *\n * This function is designed for virtual filesystem paths and rejects\n * Windows absolute paths (e.g., C:/..., F:/...) to maintain consistency\n * and prevent path format ambiguity.\n *\n * @param path - Path to validate\n * @returns Normalized path starting with / and ending with /\n * @throws Error if path is invalid\n *\n * @example\n * ```typescript\n * validatePath(\"foo/bar\") // Returns: \"/foo/bar/\"\n * validatePath(\"/./foo//bar\") // Returns: \"/foo/bar/\"\n * validatePath(\"../etc/passwd\") // Throws: Path traversal not allowed\n * validatePath(\"C:\\\\Users\\\\file\") // Throws: Windows absolute paths not supported\n * ```\n */\nexport function validatePath(path: string | null | undefined): string {\n const pathStr = path || \"/\";\n if (!pathStr || pathStr.trim() === \"\") {\n throw new Error(\"Path cannot be empty\");\n }\n\n let normalized = pathStr.startsWith(\"/\") ? pathStr : \"/\" + pathStr;\n\n if (!normalized.endsWith(\"/\")) {\n normalized += \"/\";\n }\n\n return normalized;\n}\n\n/**\n * Validate and normalize a file path for security.\n *\n * Ensures paths are safe to use by preventing directory traversal attacks\n * and enforcing consistent formatting. All paths are normalized to use\n * forward slashes and start with a leading slash.\n *\n * This function is designed for virtual filesystem paths and rejects\n * Windows absolute paths (e.g., C:/..., F:/...) to maintain consistency\n * and prevent path format ambiguity.\n *\n * @param path - The path to validate and normalize.\n * @param allowedPrefixes - Optional list of allowed path prefixes. If provided,\n * the normalized path must start with one of these prefixes.\n * @returns Normalized canonical path starting with `/` and using forward slashes.\n * @throws Error if path contains traversal sequences (`..` or `~`), is a Windows\n * absolute path (e.g., C:/...), or does not start with an allowed prefix\n * when `allowedPrefixes` is specified.\n *\n * @example\n * ```typescript\n * validateFilePath(\"foo/bar\") // Returns: \"/foo/bar\"\n * validateFilePath(\"/./foo//bar\") // Returns: \"/foo/bar\"\n * validateFilePath(\"../etc/passwd\") // Throws: Path traversal not allowed\n * validateFilePath(\"C:\\\\Users\\\\file.txt\") // Throws: Windows absolute paths not supported\n * validateFilePath(\"/data/file.txt\", [\"/data/\"]) // Returns: \"/data/file.txt\"\n * validateFilePath(\"/etc/file.txt\", [\"/data/\"]) // Throws: Path must start with...\n * ```\n */\nexport function validateFilePath(\n path: string,\n allowedPrefixes?: string[],\n): string {\n // Check for path traversal\n if (path.includes(\"..\") || path.startsWith(\"~\")) {\n throw new Error(`Path traversal not allowed: ${path}`);\n }\n\n // Reject Windows absolute paths (e.g., C:\\..., D:/...)\n // This maintains consistency in virtual filesystem paths\n if (/^[a-zA-Z]:/.test(path)) {\n throw new Error(\n `Windows absolute paths are not supported: ${path}. Please use virtual paths starting with / (e.g., /workspace/file.txt)`,\n );\n }\n\n // Normalize path separators and remove redundant slashes\n let normalized = path.replace(/\\\\/g, \"/\");\n\n // Remove redundant path components (./foo becomes foo, foo//bar becomes foo/bar)\n const parts: string[] = [];\n for (const part of normalized.split(\"/\")) {\n if (part === \".\" || part === \"\") {\n continue;\n }\n parts.push(part);\n }\n normalized = \"/\" + parts.join(\"/\");\n\n // Check allowed prefixes if provided\n if (\n allowedPrefixes &&\n !allowedPrefixes.some((prefix) => normalized.startsWith(prefix))\n ) {\n throw new Error(\n `Path must start with one of ${JSON.stringify(allowedPrefixes)}: ${path}`,\n );\n }\n\n return normalized;\n}\n\n/**\n * Resolve the files under `path` for grep/glob search.\n *\n * If `path` exactly names a file that exists in `files`, only that file is\n * returned (exact match) — this lets grep/glob target a specific file\n * directly instead of only matching directories. Otherwise `path` is treated\n * as a directory and files are filtered by the normalized directory prefix.\n *\n * @returns Filtered files map, or null if `path` is invalid (e.g. whitespace-only).\n */\nfunction filterFilesByPath(\n files: Record<string, FileData>,\n path: string | null | undefined,\n): Record<string, FileData> | null {\n const exactPath = path ? (path.startsWith(\"/\") ? path : \"/\" + path) : \"/\";\n if (Object.prototype.hasOwnProperty.call(files, exactPath)) {\n return { [exactPath]: files[exactPath] };\n }\n\n try {\n const normalizedPath = validatePath(path);\n return Object.fromEntries(\n Object.entries(files).filter(([fp]) => fp.startsWith(normalizedPath)),\n );\n } catch {\n return null;\n }\n}\n\n/**\n * Search files dict for paths matching glob pattern.\n *\n * @param files - Dictionary of file paths to FileData\n * @param pattern - Glob pattern (e.g., `*.py`, `**\\/*.ts`)\n * @param path - Base path to search from. If `path` names an exact file, only\n * that file is considered.\n * @returns Newline-separated file paths, sorted by modification time (most recent first).\n * Returns \"No files found\" if no matches.\n *\n * @example\n * ```typescript\n * const files = {\"/src/main.py\": FileData(...), \"/test.py\": FileData(...)};\n * globSearchFiles(files, \"*.py\", \"/\");\n * // Returns: \"/test.py\\n/src/main.py\" (sorted by modified_at)\n * ```\n */\nexport function globSearchFiles(\n files: Record<string, FileData>,\n pattern: string,\n path: string = \"/\",\n): string {\n const filtered = filterFilesByPath(files, path);\n if (filtered === null) {\n return \"No files found\";\n }\n const normalizedPath = validatePath(path);\n\n // Respect standard glob semantics:\n // - Patterns without path separators (e.g., \"*.py\") match only in the current\n // directory (non-recursive) relative to `path`.\n // - Use \"**\" explicitly for recursive matching.\n const effectivePattern = pattern;\n\n const matches: Array<[string, string]> = [];\n for (const [filePath, fileData] of Object.entries(filtered)) {\n let relative = filePath.substring(normalizedPath.length);\n if (relative.startsWith(\"/\")) {\n relative = relative.substring(1);\n }\n if (!relative) {\n const parts = filePath.split(\"/\");\n relative = parts[parts.length - 1] || \"\";\n }\n\n if (\n micromatch.isMatch(relative, effectivePattern, {\n dot: true,\n nobrace: false,\n })\n ) {\n matches.push([filePath, fileData.modified_at]);\n }\n }\n\n matches.sort((a, b) => b[1].localeCompare(a[1])); // Sort by modified_at descending\n\n if (matches.length === 0) {\n return \"No files found\";\n }\n\n return matches.map(([fp]) => fp).join(\"\\n\");\n}\n\n/**\n * Format grep search results based on output mode.\n *\n * @param results - Dictionary mapping file paths to list of [line_num, line_content] tuples\n * @param outputMode - Output format - \"files_with_matches\", \"content\", or \"count\"\n * @returns Formatted string output\n */\nexport function formatGrepResults(\n results: Record<string, Array<[number, string]>>,\n outputMode: \"files_with_matches\" | \"content\" | \"count\",\n): string {\n if (outputMode === \"files_with_matches\") {\n return Object.keys(results).sort().join(\"\\n\");\n }\n if (outputMode === \"count\") {\n const lines: string[] = [];\n for (const filePath of Object.keys(results).sort()) {\n const count = results[filePath].length;\n lines.push(`${filePath}: ${count}`);\n }\n return lines.join(\"\\n\");\n }\n // content mode\n const lines: string[] = [];\n for (const filePath of Object.keys(results).sort()) {\n lines.push(`${filePath}:`);\n for (const [lineNum, line] of results[filePath]) {\n lines.push(` ${lineNum}: ${line}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Search file contents for literal text pattern.\n *\n * Performs literal text search.\n *\n * @param files - Dictionary of file paths to FileData\n * @param pattern - Literal text to search for\n * @param path - Base path to search from. If `path` names an exact file, only\n * that file is considered.\n * @param glob - Optional glob pattern to filter files (e.g., \"*.py\")\n * @param outputMode - Output format - \"files_with_matches\", \"content\", or \"count\"\n * @returns Formatted search results. Returns \"No matches found\" if no results.\n *\n * @example\n * ```typescript\n * const files = {\"/file.py\": FileData({content: [\"import os\", \"print('hi')\"], ...})};\n * grepSearchFiles(files, \"import\", \"/\");\n * // Returns: \"/file.py\" (with output_mode=\"files_with_matches\")\n * ```\n */\nexport function grepSearchFiles(\n files: Record<string, FileData>,\n pattern: string,\n path: string | null = null,\n glob: string | null = null,\n outputMode: \"files_with_matches\" | \"content\" | \"count\" = \"files_with_matches\",\n): string {\n let filtered = filterFilesByPath(files, path);\n if (filtered === null) {\n return \"No matches found\";\n }\n\n if (glob) {\n filtered = Object.fromEntries(\n Object.entries(filtered).filter(([fp]) =>\n micromatch.isMatch(basename(fp), glob, { dot: true, nobrace: false }),\n ),\n );\n }\n\n const results: Record<string, Array<[number, string]>> = {};\n for (const [filePath, fileData] of Object.entries(filtered)) {\n const fileDataV2 = migrateToFileDataV2(fileData, filePath);\n if (!isTextMimeType(fileDataV2.mimeType)) {\n continue;\n }\n\n const content = fileDataToString(fileData);\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineNum = i + 1;\n // Simple substring search for literal matching\n if (line.includes(pattern)) {\n if (!results[filePath]) {\n results[filePath] = [];\n }\n results[filePath].push([lineNum, line]);\n }\n }\n }\n\n if (Object.keys(results).length === 0) {\n return \"No matches found\";\n }\n return formatGrepResults(results, outputMode);\n}\n\n/**\n * Return structured grep matches from an in-memory files mapping.\n *\n * Performs literal text search (not regex). Binary files are skipped.\n * If `path` names an exact file, only that file is considered.\n * Returns an empty array when no matches are found or on invalid input.\n */\nexport function grepMatchesFromFiles(\n files: Record<string, FileData>,\n pattern: string,\n path: string | null = null,\n glob: string | null = null,\n): GrepMatch[] {\n let filtered = filterFilesByPath(files, path);\n if (filtered === null) {\n return [];\n }\n\n if (glob) {\n filtered = Object.fromEntries(\n Object.entries(filtered).filter(([fp]) =>\n micromatch.isMatch(basename(fp), glob, { dot: true, nobrace: false }),\n ),\n );\n }\n\n const matches: GrepMatch[] = [];\n for (const [filePath, fileData] of Object.entries(filtered)) {\n const fileDataV2 = migrateToFileDataV2(fileData, filePath);\n if (!isTextMimeType(fileDataV2.mimeType)) {\n continue;\n }\n\n const content = fileDataToString(fileData);\n const lines = content.split(\"\\n\");\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineNum = i + 1;\n // Simple substring search for literal matching\n if (line.includes(pattern)) {\n matches.push({ path: filePath, line: lineNum, text: line });\n }\n }\n }\n\n return matches;\n}\n\n/**\n * Group structured matches into the legacy dict form used by formatters.\n */\nexport function buildGrepResultsDict(\n matches: GrepMatch[],\n): Record<string, Array<[number, string]>> {\n const grouped: Record<string, Array<[number, string]>> = {};\n for (const m of matches) {\n if (!grouped[m.path]) {\n grouped[m.path] = [];\n }\n grouped[m.path].push([m.line, m.text]);\n }\n return grouped;\n}\n\n/**\n * Format structured grep matches using existing formatting logic.\n */\nexport function formatGrepMatches(\n matches: GrepMatch[],\n outputMode: \"files_with_matches\" | \"content\" | \"count\",\n): string {\n if (matches.length === 0) {\n return \"No matches found\";\n }\n return formatGrepResults(buildGrepResultsDict(matches), outputMode);\n}\n\n/**\n * Determine MIME type from a file path's extension.\n *\n * Defaults to \"text/plain\" for unknown extensions. Only the known non-text\n * formats above (images, audio, video, PDF/PPT) are treated as binary by\n * {@link isTextMimeType}; everything else reads as text, including source files\n * with uncommon extensions (.properties, .scss, .tf) and extension-less files\n * (Dockerfile, mvnw). This avoids base64-encoding text into document blocks,\n * which the model can't read and which the Anthropic provider rejects with a\n * 400.\n *\n * @param filePath - File path to inspect\n * @returns MIME type string (e.g., \"image/png\", \"text/plain\")\n */\nexport function getMimeType(filePath: string): string {\n const ext = extname(filePath).toLocaleLowerCase();\n return MIME_TYPES[ext] || \"text/plain\";\n}\n\n/**\n * Check whether a MIME type represents text content.\n *\n * @param mimeType - MIME type string to check\n * @returns True if the MIME type is text-based\n */\nexport function isTextMimeType(mimeType: string): boolean {\n return (\n mimeType.startsWith(\"text/\") ||\n mimeType === \"application/json\" ||\n mimeType === \"application/javascript\" ||\n mimeType === \"image/svg+xml\"\n );\n}\n\n/**\n * Type guard to check if FileData is v1 format (content as line array).\n *\n * @param data - FileData to check\n * @returns True if data is FileDataV1\n */\nexport function isFileDataV1(data: FileData): data is FileDataV1 {\n return Array.isArray(data.content);\n}\n\n/**\n * Convert FileData to v2 format, joining v1 line arrays into a single string.\n *\n * If the data is already v2, returns it unchanged.\n *\n * @param data - FileData in either format\n * @returns FileDataV2 with content as string (text) or Uint8Array (binary)\n */\nexport function migrateToFileDataV2(\n data: FileDataV1 | FileDataV2,\n filePath: string,\n): FileDataV2 {\n if (isFileDataV1(data)) {\n return {\n content: data.content.join(\"\\n\"),\n mimeType: getMimeType(filePath),\n created_at: data.created_at,\n modified_at: data.modified_at,\n };\n }\n if (!(\"mimeType\" in data) || !data.mimeType) {\n return { ...data, mimeType: getMimeType(filePath) };\n }\n return data;\n}\n\n/**\n * Adapt a v1 {@link BackendProtocol} to {@link BackendProtocolV2}.\n *\n * If the backend already implements v2, it is returned as-is.\n * For v1 backends, wraps returns in Result types:\n * - `read()` string returns wrapped in {@link ReadResult}\n * - `readRaw()` FileData returns wrapped in {@link ReadRawResult}\n * - `grep()` returns wrapped in {@link GrepResult}\n * - `ls()` FileInfo[] returns wrapped in {@link LsResult}\n * - `glob()` FileInfo[] returns wrapped in {@link GlobResult}\n *\n * Note: For sandbox instances, use {@link adaptSandboxProtocol} instead.\n *\n * @param backend - Backend instance (v1 or v2)\n * @returns BackendProtocolV2-compatible backend\n */\nexport function adaptBackendProtocol(\n backend: AnyBackendProtocol,\n): BackendProtocolV2 {\n const adapted: BackendProtocolV2 = {\n async ls(path): Promise<LsResult> {\n const result = await (\"ls\" in backend\n ? (backend as BackendProtocolV2).ls(path)\n : (backend as BackendProtocolV1).lsInfo(path));\n if (Array.isArray(result)) return { files: result };\n return result as LsResult;\n },\n async readRaw(filePath): Promise<ReadRawResult> {\n const result = await backend.readRaw(filePath);\n if (\"data\" in result || \"error\" in result) {\n return result as ReadRawResult;\n }\n return { data: migrateToFileDataV2(result as FileData, filePath) };\n },\n async glob(pattern, path): Promise<GlobResult> {\n const result = await (\"glob\" in backend\n ? (backend as BackendProtocolV2).glob(pattern, path)\n : (backend as BackendProtocolV1).globInfo(pattern, path));\n if (Array.isArray(result)) return { files: result };\n return result as GlobResult;\n },\n write: (filePath, content) => backend.write(filePath, content),\n edit: (filePath, oldString, newString, replaceAll) =>\n backend.edit(filePath, oldString, newString, replaceAll),\n delete: backend.delete?.bind(backend),\n uploadFiles: backend.uploadFiles\n ? (files) => backend.uploadFiles!(files)\n : undefined,\n downloadFiles: backend.downloadFiles\n ? (paths) => backend.downloadFiles!(paths)\n : undefined,\n async read(filePath, offset, limit): Promise<ReadResult> {\n const result = await backend.read(filePath, offset, limit);\n if (typeof result === \"string\") return { content: result };\n return result as ReadResult;\n },\n async grep(pattern, path, glob, maxCount): Promise<GrepResult> {\n const result = await (\"grep\" in backend\n ? (backend as BackendProtocolV2).grep(pattern, path, glob, maxCount)\n : (backend as BackendProtocolV1).grepRaw(pattern, path, glob));\n if (Array.isArray(result)) {\n return applyGrepMaxCount({ result: { matches: result }, maxCount });\n }\n if (typeof result === \"string\") return { error: result };\n return result as GrepResult;\n },\n };\n\n // Preserve `routePrefixes` so `CompositeBackend.isInstance` still detects\n // composites after adaptation and the execute-tool permission guard stays\n // correct; without it, scoped filesystem permissions wrongly disable execute.\n const routePrefixes = (backend as { routePrefixes?: unknown }).routePrefixes;\n if (Array.isArray(routePrefixes)) {\n Object.defineProperty(adapted, \"routePrefixes\", {\n value: routePrefixes,\n enumerable: true,\n configurable: true,\n });\n }\n\n return adapted;\n}\n\n/**\n * Adapt a sandbox backend from v1 to v2 interface.\n *\n * This extends {@link adaptBackendProtocol} to also preserve sandbox-specific\n * properties from {@link SandboxBackendProtocol}: `execute` and `id`.\n *\n * @param sandbox - Sandbox backend (v1 or v2)\n * @returns SandboxBackendProtocolV2-compatible sandbox\n */\nexport function adaptSandboxProtocol(\n sandbox: AnySandboxProtocol,\n): SandboxBackendProtocolV2 {\n // First adapt the backend protocol methods to v2\n const adapted = adaptBackendProtocol(sandbox);\n\n // Preserve sandbox protocol properties (execute, id)\n // Both SandboxBackendProtocol and SandboxBackendProtocolV2 have these\n (adapted as SandboxBackendProtocolV2).execute = (cmd: string) =>\n sandbox.execute(cmd);\n Object.defineProperty(adapted, \"id\", {\n value: sandbox.id,\n enumerable: true,\n configurable: true,\n });\n\n return adapted as SandboxBackendProtocolV2;\n}\n","/**\n * Protocol definition for pluggable memory backends.\n *\n * This module defines the shared types and re-exports the versioned protocol\n * interfaces. Backend protocol interfaces are split by version:\n * - v1 (deprecated): {@link ./v1/protocol.js}\n * - v2 (current): {@link ./v2/protocol.js}\n */\n\nimport type { Runtime, ToolRuntime } from \"langchain\";\nimport type { BaseStore } from \"@langchain/langgraph-checkpoint\";\nimport type {\n BackendProtocolV1,\n SandboxBackendProtocolV1,\n} from \"./v1/protocol.js\";\nimport type {\n BackendProtocolV2,\n SandboxBackendProtocolV2,\n} from \"./v2/protocol.js\";\nimport { adaptBackendProtocol, adaptSandboxProtocol } from \"./utils.js\";\n\nexport type {\n BackendProtocolV1,\n SandboxBackendProtocolV1,\n} from \"./v1/protocol.js\";\nexport type {\n BackendProtocolV2,\n SandboxBackendProtocolV2,\n} from \"./v2/protocol.js\";\n\n/** @deprecated Use {@link BackendProtocolV2} instead. */\nexport interface BackendProtocol extends BackendProtocolV1 {}\n\n/** @deprecated Use {@link SandboxBackendProtocolV2} instead. */\nexport interface SandboxBackendProtocol extends SandboxBackendProtocolV1 {}\n\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Structured file listing info.\n *\n * Minimal contract used across backends. Only \"path\" is required.\n * Other fields are best-effort and may be absent depending on backend.\n */\nexport interface FileInfo {\n /** File path */\n path: string;\n /** Whether this is a directory */\n is_dir?: boolean;\n /** File size in bytes (approximate) */\n size?: number;\n /** ISO 8601 timestamp of last modification */\n modified_at?: string;\n}\n\n/**\n * Structured grep match entry.\n */\nexport interface GrepMatch {\n /** File path where match was found */\n path: string;\n /** Line number (1-indexed) */\n line: number;\n /** The matching line text */\n text: string;\n}\n\n/**\n * Structured result from grep/search operations.\n */\nexport interface GrepResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /**\n * Structured grep match entries. Populated on success and, when the\n * search was cut short, with whatever was found before stopping.\n * Undefined only on a hard failure.\n */\n matches?: GrepMatch[];\n /**\n * True when the search stopped early (e.g. hit a match-count cap) and\n * `matches` is therefore incomplete but still valid.\n */\n truncated?: boolean;\n}\n\n/**\n * Enforce a match cap after a backend grep has completed.\n *\n * When `maxCount` is set and the result exceeds it, the matches are sliced\n * to the cap and the result is flagged `truncated: true`.\n */\nexport function applyGrepMaxCount(params: {\n result: GrepResult;\n maxCount: number | null | undefined;\n}): GrepResult {\n const { result, maxCount } = params;\n if (\n maxCount == null ||\n result.matches == null ||\n result.matches.length <= maxCount\n ) {\n return result;\n }\n return {\n error: result.error,\n matches: result.matches.slice(0, maxCount),\n truncated: true,\n };\n}\n\n/**\n * Legacy file data format (v1).\n *\n * Content is stored as an array of lines (split on \"\\n\"). This format\n * only supports text files and is retained for backwards compatibility\n * with existing state/store data.\n */\nexport interface FileDataV1 {\n /** File content as an array of lines */\n content: string[];\n /** ISO format timestamp of creation */\n created_at: string;\n /** ISO format timestamp of last modification */\n modified_at: string;\n}\n\n/**\n * Current file data format (v2).\n *\n * Content is stored as a string for text files, or as a Uint8Array for\n * binary files (images, PDFs, audio, etc.). The MIME type is stored\n * alongside the content, allowing backend implementations to determine\n * it however they see fit (e.g. from file extension, HTTP headers,\n * database metadata, etc.).\n */\nexport interface FileDataV2 {\n /** File content: string for text, Uint8Array for binary */\n content: string | Uint8Array;\n /** MIME type of the file (e.g. \"image/png\", \"text/plain\") */\n mimeType: string;\n /** ISO format timestamp of creation */\n created_at: string;\n /** ISO format timestamp of last modification */\n modified_at: string;\n}\n\n/**\n * Union of v1 and v2 file data formats.\n *\n * Backends may encounter either format when reading from state or store\n * (v1 from legacy data, v2 from new writes). Use {@link isFileDataV1}\n * from utils for runtime discrimination.\n */\nexport type FileData = FileDataV1 | FileDataV2;\n\n/**\n * Structured result from backend read operations.\n *\n * Replaces the previous plain string return, giving callers a\n * programmatic way to distinguish errors from content.\n */\nexport interface ReadResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** File content: string for text, Uint8Array for binary. Undefined on failure. */\n content?: string | Uint8Array;\n /** MIME type of the file, when available */\n mimeType?: string;\n /**\n * Total number of logical source lines for a text read, when known.\n * Omitted for binary reads and for backends that cannot determine it.\n */\n totalLines?: number;\n /**\n * 1-indexed first source line represented by `content`.\n * Text pagination fields are optional so older/custom backends remain valid.\n */\n startLine?: number;\n /** 1-indexed last source line represented by `content`. */\n endLine?: number;\n /**\n * 0-indexed offset of the next unread source line.\n * Omitted when the returned text reaches EOF.\n */\n nextOffset?: number;\n}\n\n/**\n * Structured result from backend readRaw operations.\n */\nexport interface ReadRawResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** Raw file data, undefined on failure */\n data?: FileData;\n}\n\n/**\n * Structured result from backend ls operations.\n */\nexport interface LsResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** List of FileInfo objects, undefined on failure */\n files?: FileInfo[];\n}\n\n/**\n * Structured result from backend glob operations.\n */\nexport interface GlobResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /**\n * List of FileInfo objects matching the pattern. Populated on success and,\n * when the walk was cut short, with whatever was found before stopping.\n * Undefined only on a hard failure.\n */\n files?: FileInfo[];\n /**\n * True when the walk stopped early (e.g. hit a time or count limit) and\n * `files` is therefore incomplete but still valid.\n */\n truncated?: boolean;\n}\n\n/**\n * Result from backend write operations.\n *\n * Checkpoint backends populate filesUpdate with {file_path: file_data} for LangGraph state.\n * External backends set filesUpdate to null (already persisted to disk/S3/database/etc).\n */\nexport interface WriteResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** File path of written file, undefined on failure */\n path?: string;\n /**\n * State update dict for checkpoint backends, null for external storage.\n * Checkpoint backends populate this with {file_path: file_data} for LangGraph state.\n * External backends set null (already persisted to disk/S3/database/etc).\n *\n * @deprecated Zero-arg backends send state updates internally via\n * `__pregel_send`. Check `if (result.filesUpdate)` before using.\n */\n filesUpdate?: Record<string, FileData> | null;\n /** Metadata for the write operation, attached to the ToolMessage */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result from backend edit operations.\n *\n * Checkpoint backends populate filesUpdate with {file_path: file_data} for LangGraph state.\n * External backends set filesUpdate to null (already persisted to disk/S3/database/etc).\n */\nexport interface EditResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** File path of edited file, undefined on failure */\n path?: string;\n /**\n * State update dict for checkpoint backends, null for external storage.\n * Checkpoint backends populate this with {file_path: file_data} for LangGraph state.\n * External backends set null (already persisted to disk/S3/database/etc).\n *\n * @deprecated Zero-arg backends send state updates internally via\n * `__pregel_send`. Check `if (result.filesUpdate)` before using.\n */\n filesUpdate?: Record<string, FileData> | null;\n /** Number of replacements made, undefined on failure */\n occurrences?: number;\n /** Metadata for the edit operation, attached to the ToolMessage */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result from backend delete operations.\n */\nexport interface DeleteResult {\n /** Error message on failure, undefined on success */\n error?: string;\n /** File path of deleted file or directory, undefined on failure */\n path?: string;\n /**\n * State update dict for checkpoint backends, null for external storage.\n * Deletions are represented as null values keyed by removed path.\n *\n * @deprecated Only the deprecated legacy (runtime-injected) `StateBackend`\n * still populates this field. A modern zero-argument `StateBackend` publishes\n * its own deletion markers through LangGraph's `__pregel_send` channel and\n * returns only `path`, so callers no longer need to apply a `Command` from\n * this value. The delete tool and `CompositeBackend` continue to honor it\n * while the legacy `StateBackend` constructor remains supported; it will be\n * removed alongside that constructor.\n */\n filesUpdate?: Record<string, null> | null;\n /** Metadata for the delete operation, attached to the ToolMessage */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Result of code execution.\n * Simplified schema optimized for LLM consumption.\n */\nexport interface ExecuteResponse {\n /** Combined stdout and stderr output of the executed command */\n output: string;\n /** The process exit code. 0 indicates success, non-zero indicates failure */\n exitCode: number | null;\n /** Whether the output was truncated due to backend limitations */\n truncated: boolean;\n}\n\n/**\n * Standardized error codes for file upload/download operations.\n */\nexport type FileOperationError =\n | \"file_not_found\"\n | \"permission_denied\"\n | \"is_directory\"\n | \"invalid_path\";\n\n/**\n * Result of a single file download operation.\n */\nexport interface FileDownloadResponse {\n /** The file path that was requested */\n path: string;\n /** File contents as Uint8Array on success, null on failure */\n content: Uint8Array | null;\n /** Standardized error code on failure, null on success */\n error: FileOperationError | null;\n}\n\n/**\n * Result of a single file upload operation.\n */\nexport interface FileUploadResponse {\n /** The file path that was requested */\n path: string;\n /** Standardized error code on failure, null on success */\n error: FileOperationError | null;\n}\n\n/**\n * Common options shared across backend constructors.\n */\nexport interface BackendOptions {\n /** File data format to use for new writes. Defaults to \"v2\". */\n fileFormat?: \"v1\" | \"v2\";\n}\n\n/**\n * Type guard to check if a backend supports execution.\n *\n * @param backend - Backend instance to check\n * @returns True if the backend implements SandboxBackendProtocolV2\n */\nexport function isSandboxBackend(\n backend: unknown,\n): backend is SandboxBackendProtocolV2 {\n return (\n backend != null &&\n typeof backend === \"object\" &&\n typeof (backend as SandboxBackendProtocolV2).execute === \"function\" &&\n typeof (backend as SandboxBackendProtocolV2).id === \"string\" &&\n (backend as SandboxBackendProtocolV2).id !== \"\"\n );\n}\n\n/**\n * Union of v1 and v2 sandbox backend protocols.\n *\n * Use this when accepting either protocol version. Pass through\n * {@link adaptSandboxProtocol} to normalize to {@link SandboxBackendProtocolV2}.\n */\nexport type AnySandboxProtocol =\n | SandboxBackendProtocol\n | SandboxBackendProtocolV2;\n\n/**\n * Type guard to check if a backend is a sandbox protocol (v1 or v2).\n *\n * Checks for the presence of `execute` function and `id` string,\n * which are the defining features of sandbox protocols.\n *\n * @param backend - Backend instance to check\n * @returns True if the backend implements sandbox protocol (v1 or v2)\n */\nexport function isSandboxProtocol(\n backend: unknown,\n): backend is AnySandboxProtocol {\n return (\n backend != null &&\n typeof backend === \"object\" &&\n typeof (backend as any).execute === \"function\" &&\n typeof (backend as any).id === \"string\" &&\n (backend as any).id !== \"\"\n );\n}\n\n/**\n * Metadata for a single sandbox instance.\n *\n * This lightweight structure is returned from list operations and provides\n * basic information about a sandbox without requiring a full connection.\n *\n * @typeParam MetadataT - Type of the metadata field. Providers can define\n * their own interface for type-safe metadata access.\n *\n * @example\n * ```typescript\n * // Using default metadata type\n * const info: SandboxInfo = {\n * sandboxId: \"sb_abc123\",\n * metadata: { status: \"running\", createdAt: \"2024-01-15T10:30:00Z\" },\n * };\n *\n * // Using typed metadata\n * interface MyMetadata {\n * status: \"running\" | \"stopped\";\n * createdAt: string;\n * }\n * const typedInfo: SandboxInfo<MyMetadata> = {\n * sandboxId: \"sb_abc123\",\n * metadata: { status: \"running\", createdAt: \"2024-01-15T10:30:00Z\" },\n * };\n * ```\n */\nexport interface SandboxInfo<MetadataT = Record<string, unknown>> {\n /** Unique identifier for the sandbox instance */\n sandboxId: string;\n /** Optional provider-specific metadata (e.g., creation time, status, template) */\n metadata?: MetadataT;\n}\n\n/**\n * Paginated response from a sandbox list operation.\n *\n * This structure supports cursor-based pagination for efficiently browsing\n * large collections of sandboxes.\n *\n * @typeParam MetadataT - Type of the metadata field in SandboxInfo items.\n *\n * @example\n * ```typescript\n * const response: SandboxListResponse = {\n * items: [\n * { sandboxId: \"sb_001\", metadata: { status: \"running\" } },\n * { sandboxId: \"sb_002\", metadata: { status: \"stopped\" } },\n * ],\n * cursor: \"eyJvZmZzZXQiOjEwMH0=\",\n * };\n *\n * // Fetch next page\n * const nextResponse = await provider.list({ cursor: response.cursor });\n * ```\n */\nexport interface SandboxListResponse<MetadataT = Record<string, unknown>> {\n /** List of sandbox metadata objects for the current page */\n items: SandboxInfo<MetadataT>[];\n /**\n * Opaque continuation token for retrieving the next page.\n * null indicates no more pages available.\n */\n cursor: string | null;\n}\n\n/**\n * Options for listing sandboxes.\n */\nexport interface SandboxListOptions {\n /**\n * Continuation token from a previous list() call.\n * Pass undefined to start from the beginning.\n */\n cursor?: string;\n}\n\n/**\n * Options for getting or creating a sandbox.\n */\nexport interface SandboxGetOrCreateOptions {\n /**\n * Unique identifier of an existing sandbox to retrieve.\n * If undefined, creates a new sandbox instance.\n * If provided but the sandbox doesn't exist, an error will be thrown.\n */\n sandboxId?: string;\n}\n\n/**\n * Options for deleting a sandbox.\n */\nexport interface SandboxDeleteOptions {\n /** Unique identifier of the sandbox to delete */\n sandboxId: string;\n}\n\n/**\n * Common error codes shared across all sandbox provider implementations.\n *\n * These represent the core error conditions that any sandbox provider may encounter.\n * Provider-specific error codes should extend this type with additional codes.\n *\n * @example\n * ```typescript\n * // Provider-specific error code type extending the common codes:\n * type MySandboxErrorCode = SandboxErrorCode | \"CUSTOM_ERROR\";\n * ```\n */\nexport type SandboxErrorCode =\n /** Sandbox has not been initialized - call initialize() first */\n | \"NOT_INITIALIZED\"\n /** Sandbox is already initialized - cannot initialize twice */\n | \"ALREADY_INITIALIZED\"\n /** Command execution timed out */\n | \"COMMAND_TIMEOUT\"\n /** Command execution failed */\n | \"COMMAND_FAILED\"\n /** File operation (read/write) failed */\n | \"FILE_OPERATION_FAILED\";\n\nconst SANDBOX_ERROR_SYMBOL = Symbol.for(\"sandbox.error\");\n\n/**\n * Custom error class for sandbox operations.\n *\n * @param message - Human-readable error description\n * @param code - Structured error code for programmatic handling\n * @returns SandboxError with message and code\n *\n * @example\n * ```typescript\n * try {\n * await sandbox.execute(\"some command\");\n * } catch (error) {\n * if (error instanceof SandboxError) {\n * switch (error.code) {\n * case \"NOT_INITIALIZED\":\n * await sandbox.initialize();\n * break;\n * case \"COMMAND_TIMEOUT\":\n * console.error(\"Command took too long\");\n * break;\n * default:\n * throw error;\n * }\n * }\n * }\n * ```\n */\nexport class SandboxError extends Error {\n /** Symbol for identifying sandbox error instances */\n [SANDBOX_ERROR_SYMBOL] = true as const;\n\n /** Error name for instanceof checks and logging */\n override readonly name: string = \"SandboxError\";\n\n /**\n * Creates a new SandboxError.\n *\n * @param message - Human-readable error description\n * @param code - Structured error code for programmatic handling\n */\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: Error,\n ) {\n super(message);\n Object.setPrototypeOf(this, SandboxError.prototype);\n }\n\n static isInstance(error: unknown): error is SandboxError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[SANDBOX_ERROR_SYMBOL] === true\n );\n }\n}\n\n/**\n * State and store container for backend initialization.\n *\n * This provides a clean interface for what backends need to access:\n * - state: Current agent state (with files, messages, etc.)\n * - store: Optional persistent store for cross-conversation data\n *\n * Different contexts build this differently:\n * - Tools: Extract state via getCurrentTaskInput(config)\n * - Middleware: Use request.state directly\n *\n * @deprecated Use {@link BackendRuntime} instead.\n */\nexport interface StateAndStore {\n /** Current agent state with files, messages, etc. */\n state: unknown;\n /** Optional BaseStore for persistent cross-conversation storage */\n store?: BaseStore;\n /** Optional assistant ID for per-assistant isolation in store */\n assistantId?: string;\n}\n\n/**\n * Union of v1 and v2 backend protocols.\n *\n * Use this when accepting either protocol version. Pass through\n * {@link adaptBackendProtocol} to normalize to {@link BackendProtocolV2}.\n */\nexport type AnyBackendProtocol = BackendProtocolV1 | BackendProtocolV2;\n\n/**\n * Agent {@link Runtime} with `state`\n *\n * @deprecated Backends now read state from the LangGraph execution context\n * via `getCurrentTaskInput()`, `getConfig()`, and `getStore()`.\n */\nexport interface BackendRuntime<StateT = unknown> extends Runtime {\n /** Current agent state with files, messages, etc. */\n state: StateT;\n}\n\n/**\n * Factory function type for creating backend instances.\n *\n * Backends receive {@link BackendRuntime} which contains the current state\n * and runtime information, extracted from the execution context.\n *\n * @deprecated Pass a pre-constructed backend instance instead of a factory.\n * E.g., `backend: new StateBackend()` instead of `backend: (runtime) => new StateBackend(runtime)`.\n *\n * @example\n * ```typescript\n * // Using in middleware\n * const middleware = createFilesystemMiddleware({\n * backend: (runtime) => new StateBackend(runtime)\n * });\n * ```\n */\nexport type BackendFactory = (\n runtime: BackendRuntime,\n) => MaybePromise<AnyBackendProtocol>;\n\n/**\n * Resolve a backend instance or await a {@link BackendFactory}.\n *\n * Accepts {@link BackendRuntime} or {@link ToolRuntime} — store typing differs\n * between LangGraph checkpoint stores and core `ToolRuntime`; factories receive\n * a value that is structurally compatible at runtime.\n *\n * @internal\n */\nexport async function resolveBackend(\n backend: AnyBackendProtocol | BackendFactory,\n runtime: BackendRuntime | ToolRuntime,\n): Promise<BackendProtocolV2> {\n if (typeof backend === \"function\") {\n const resolved = await backend(runtime as BackendRuntime);\n return isSandboxProtocol(resolved)\n ? adaptSandboxProtocol(resolved)\n : adaptBackendProtocol(resolved);\n }\n return isSandboxProtocol(backend)\n ? adaptSandboxProtocol(backend)\n : adaptBackendProtocol(backend);\n}\n","/**\n * StateBackend: Store files in LangGraph agent state (ephemeral).\n */\n\nimport type {\n DeleteResult,\n EditResult,\n FileData,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n BackendRuntime,\n WriteResult,\n BackendProtocolV2,\n BackendOptions,\n} from \"./protocol.js\";\nimport { applyGrepMaxCount } from \"./protocol.js\";\nimport {\n createFileData,\n createWriteFileData,\n fileDataToString,\n getMimeType,\n globSearchFiles,\n grepMatchesFromFiles,\n isFileDataBinary,\n isFileDataV1,\n isTextMimeType,\n migrateToFileDataV2,\n normalizeReadPagination,\n performStringReplacement,\n updateFileData,\n} from \"./utils.js\";\nimport { getConfig } from \"@langchain/langgraph\";\n\nfunction trimTrailingSlashes(path: string): string {\n let end = path.length;\n while (end > 1 && path[end - 1] === \"/\") end--;\n return path.slice(0, end);\n}\n\nconst PREGEL_SEND_KEY = \"__pregel_send\";\nconst PREGEL_READ_KEY = \"__pregel_read\";\n\n/**\n * Backend that stores files in agent state (ephemeral).\n *\n * Uses LangGraph's state management and checkpointing. Files persist within\n * a conversation thread but not across threads. State is automatically\n * checkpointed after each agent step.\n *\n * Special handling: Since LangGraph state must be updated via Command objects\n * (not direct mutation), operations return filesUpdate in WriteResult/EditResult\n * for the middleware to apply via Command.\n */\nexport class StateBackend implements BackendProtocolV2 {\n private runtime: BackendRuntime | undefined;\n private fileFormat: \"v1\" | \"v2\";\n\n constructor(options?: BackendOptions);\n /**\n * @deprecated Pass no `runtime` argument\n */\n constructor(runtime: BackendRuntime, options?: BackendOptions);\n constructor(\n runtimeOrOptions?: BackendRuntime | BackendOptions,\n options?: BackendOptions,\n ) {\n if (\n runtimeOrOptions != null &&\n typeof runtimeOrOptions === \"object\" &&\n \"state\" in runtimeOrOptions\n ) {\n // Legacy path: BackendRuntime was passed\n this.runtime = runtimeOrOptions;\n this.fileFormat = options?.fileFormat ?? \"v2\";\n } else {\n // New path: zero-arg or options-only\n this.runtime = undefined;\n this.fileFormat = runtimeOrOptions?.fileFormat ?? \"v2\";\n }\n }\n\n /**\n * Whether this instance was constructed with the legacy factory pattern.\n *\n * When true, state is read from the injected `runtime` and `filesUpdate`\n * is returned to the caller. When false, state is read from LangGraph's\n * execution context and updates are sent via `__pregel_send`.\n */\n private get isLegacy(): boolean {\n return this.runtime !== undefined;\n }\n\n /**\n * Get files from current state.\n *\n * In legacy mode, reads from the injected {@link BackendRuntime}.\n * In zero-arg mode, reads via {@link PREGEL_READ_KEY} with fresh=true,\n * which applies any pending task writes through the reducer before returning.\n */\n private get files(): Record<string, FileData> {\n if (this.runtime) {\n return (\n (this.runtime.state as { files?: Record<string, FileData> }).files ?? {}\n );\n }\n\n const read = getConfig().configurable?.[PREGEL_READ_KEY] as\n | ((\n channel: string,\n fresh: boolean,\n ) => Record<string, FileData> | undefined)\n | undefined;\n\n return read?.(\"files\", true) ?? {};\n }\n\n /**\n * Push a files state update through LangGraph's internal send channel.\n *\n * In zero-arg mode, sends the update via the `__pregel_send` function\n * from {@link getConfig}, mirroring Python's `CONFIG_KEY_SEND`.\n * In legacy mode, this is a no-op — the caller uses `filesUpdate`\n * from the return value instead.\n *\n * @param update - Map of file paths to their updated {@link FileData},\n * or null deletion markers.\n */\n private sendFilesUpdate(update: Record<string, FileData | null>): void {\n if (this.isLegacy) {\n return;\n }\n\n const config = getConfig();\n const send = config.configurable?.[PREGEL_SEND_KEY];\n\n if (typeof send === \"function\") {\n send([[\"files\", update]]);\n }\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n *\n * @param path - Absolute path to directory\n * @returns LsResult with list of FileInfo objects on success or error on failure.\n * Directories have a trailing / in their path and is_dir=true.\n */\n ls(path: string): LsResult {\n const files = this.files;\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 [k, fd] of Object.entries(files)) {\n // Check if file is in the specified directory or a subdirectory\n if (!k.startsWith(normalizedPath)) {\n continue;\n }\n\n // Get the relative path after the directory\n const relative = k.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 const size = isFileDataV1(fd)\n ? fd.content.join(\"\\n\").length\n : isFileDataBinary(fd)\n ? fd.content.byteLength\n : fd.content.length;\n infos.push({\n path: k,\n is_dir: false,\n size: size,\n modified_at: fd.modified_at,\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 { files: infos };\n }\n\n /**\n * Read file content.\n *\n * Text files are paginated by line offset/limit.\n * Binary files return full Uint8Array content (offset/limit ignored).\n *\n * @param filePath - Absolute file path\n * @param offset - Line offset to start reading from (0-indexed)\n * @param limit - Maximum number of lines to read\n * @returns ReadResult with content on success or error on failure\n */\n read(filePath: string, offset: number = 0, limit: number = 500): ReadResult {\n const files = this.files;\n const fileData = files[filePath];\n\n if (!fileData) {\n return { error: `File '${filePath}' not found` };\n }\n\n const fileDataV2 = migrateToFileDataV2(fileData, filePath);\n\n // ignore pagination for binary data, return full content\n if (!isTextMimeType(fileDataV2.mimeType)) {\n return { content: fileDataV2.content, mimeType: fileDataV2.mimeType };\n }\n\n // apply pagination logic for text data\n if (typeof fileDataV2.content !== \"string\") {\n return {\n error: `File '${filePath}' has binary content but text MIME type`,\n };\n }\n const { offset: normalizedOffset, limit: normalizedLimit } =\n normalizeReadPagination(offset, limit);\n const lines = fileDataV2.content.split(\"\\n\");\n const totalLines =\n lines[lines.length - 1] === \"\" ? lines.length - 1 : lines.length;\n const selected = lines.slice(\n normalizedOffset,\n normalizedOffset + normalizedLimit,\n );\n if (\n selected.length === 0 ||\n normalizedOffset >= totalLines ||\n normalizedLimit === 0\n ) {\n return { content: selected.join(\"\\n\"), mimeType: fileDataV2.mimeType };\n }\n const endOffset = Math.min(normalizedOffset + selected.length, totalLines);\n return {\n content: selected.join(\"\\n\"),\n mimeType: fileDataV2.mimeType,\n totalLines,\n startLine: normalizedOffset + 1,\n endLine: endOffset,\n nextOffset: endOffset < totalLines ? endOffset : undefined,\n };\n }\n\n /**\n * Read file content as raw FileData.\n *\n * @param filePath - Absolute file path\n * @returns ReadRawResult with raw file data on success or error on failure\n */\n readRaw(filePath: string): ReadRawResult {\n const files = this.files;\n const fileData = files[filePath];\n\n if (!fileData) {\n return { error: `File '${filePath}' not found` };\n }\n return { data: fileData };\n }\n\n /**\n * Write content to a file, creating it or overwriting it if it already exists.\n * Returns WriteResult with filesUpdate to update LangGraph state.\n */\n write(filePath: string, content: string): WriteResult {\n const files = this.files;\n const existing = files[filePath];\n\n const newFileData = createWriteFileData(\n filePath,\n content,\n this.fileFormat,\n existing,\n );\n\n const update = { [filePath]: newFileData };\n\n if (!this.isLegacy) {\n this.sendFilesUpdate(update);\n return { path: filePath };\n }\n\n return {\n path: filePath,\n filesUpdate: { [filePath]: newFileData },\n };\n }\n\n /**\n * Delete a file or directory from state.\n *\n * Removes the exact file path plus every nested key under it.\n */\n delete(filePath: string): DeleteResult {\n const files = this.files;\n const base = trimTrailingSlashes(filePath) || \"/\";\n const prefix = base === \"/\" ? \"/\" : `${base}/`;\n const paths = Object.keys(files).filter(\n (path) => path === base || path.startsWith(prefix),\n );\n\n if (paths.length === 0) {\n return { error: `Error: File '${filePath}' not found` };\n }\n\n const update: Record<string, null> = Object.fromEntries(\n paths.map((path) => [path, null]),\n );\n\n if (!this.isLegacy) {\n this.sendFilesUpdate(update);\n return { path: filePath };\n }\n\n return { path: filePath, filesUpdate: update };\n }\n\n /**\n * Edit a file by replacing string occurrences.\n * Returns EditResult with filesUpdate and occurrences.\n */\n edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n ): EditResult {\n const files = this.files;\n const fileData = files[filePath];\n\n if (!fileData) {\n return { error: `Error: File '${filePath}' not found` };\n }\n\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 { error: result };\n }\n\n const [newContent, occurrences] = result;\n const newFileData = updateFileData(fileData, newContent);\n const update = { [filePath]: newFileData };\n\n if (!this.isLegacy) {\n this.sendFilesUpdate(update);\n return { path: filePath, occurrences };\n }\n\n return {\n path: filePath,\n filesUpdate: { [filePath]: newFileData },\n occurrences: occurrences,\n };\n }\n\n /**\n * Search file contents for a literal text pattern.\n * Binary files are skipped.\n */\n grep(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null,\n maxCount: number | null = null,\n ): GrepResult {\n const files = this.files;\n const result = grepMatchesFromFiles(files, pattern, path, glob);\n return applyGrepMaxCount({ result: { matches: result }, maxCount });\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n glob(pattern: string, path: string = \"/\"): GlobResult {\n const files = this.files;\n const result = globSearchFiles(files, pattern, path);\n\n if (result === \"No files found\") {\n return { files: [] };\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\n ? isFileDataV1(fd)\n ? fd.content.join(\"\\n\").length\n : isFileDataBinary(fd)\n ? fd.content.byteLength\n : fd.content.length\n : 0;\n infos.push({\n path: p,\n is_dir: false,\n size: size,\n modified_at: fd?.modified_at || \"\",\n });\n }\n return { files: infos };\n }\n\n /**\n * Upload multiple files.\n *\n * Note: Since LangGraph state must be updated via Command objects,\n * the caller must apply filesUpdate via Command after calling this method.\n *\n * @param files - List of [path, content] tuples to upload\n * @returns List of FileUploadResponse objects, one per input file\n */\n uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): FileUploadResponse[] & { filesUpdate?: Record<string, FileData> } {\n const responses: FileUploadResponse[] = [];\n const updates: Record<string, FileData> = {};\n\n for (const [path, content] of files) {\n try {\n const mimeType = getMimeType(path);\n\n if (this.fileFormat === \"v2\" && !isTextMimeType(mimeType)) {\n updates[path] = createFileData(content, undefined, \"v2\", mimeType);\n } else {\n const contentStr = new TextDecoder().decode(content);\n updates[path] = createFileData(\n contentStr,\n undefined,\n this.fileFormat,\n mimeType,\n );\n }\n\n responses.push({ path, error: null });\n } catch {\n responses.push({ path, error: \"invalid_path\" });\n }\n }\n\n if (!this.isLegacy) {\n if (Object.keys(updates).length > 0) {\n this.sendFilesUpdate(updates);\n }\n\n return responses as FileUploadResponse[] & {\n filesUpdate?: Record<string, FileData>;\n };\n }\n\n // Attach filesUpdate for the caller to apply via Command\n const result = responses as FileUploadResponse[] & {\n filesUpdate?: Record<string, FileData>;\n };\n result.filesUpdate = updates;\n return result;\n }\n\n /**\n * Download multiple files.\n *\n * @param paths - List of file paths to download\n * @returns List of FileDownloadResponse objects, one per input path\n */\n downloadFiles(paths: string[]): FileDownloadResponse[] {\n const files = this.files;\n const responses: FileDownloadResponse[] = [];\n\n for (const path of paths) {\n const fileData = files[path];\n if (!fileData) {\n responses.push({ path, content: null, error: \"file_not_found\" });\n continue;\n }\n\n const fileDataV2 = migrateToFileDataV2(fileData, path);\n\n if (typeof fileDataV2.content === \"string\") {\n const content = new TextEncoder().encode(fileDataV2.content);\n responses.push({ path, content, error: null });\n } else {\n responses.push({ path, content: fileDataV2.content, error: null });\n }\n }\n\n return responses;\n }\n}\n","import micromatch from \"micromatch\";\nimport type {\n FilesystemOperation,\n FilesystemPermission,\n PermissionMode,\n} from \"./types.js\";\n\n/**\n * Validate permission rule paths at setup time. Throws if any path is\n * relative, contains `..`, or contains `~`.\n */\nexport function validatePermissionPaths(\n permissions: FilesystemPermission[],\n): void {\n for (const permission of permissions) {\n for (const path of permission.paths) {\n validatePath(path);\n }\n }\n}\n\n/**\n * Canonicalize and validate an absolute path before permission checking.\n *\n * Throws for:\n * - Empty or non-string input\n * - Non-absolute paths (must start with `/`)\n * - Paths containing `..`\n * - Paths containing `~`\n */\nexport function validatePath(raw: string): string {\n if (typeof raw !== \"string\" || raw.length === 0) {\n throw new Error(\"path must be a non-empty string\");\n }\n\n if (!raw.startsWith(\"/\")) {\n throw new Error(`path must be absolute: ${JSON.stringify(raw)}`);\n }\n\n const segments = raw.split(\"/\").filter((s) => s.length > 0);\n if (segments.includes(\"..\")) {\n throw new Error(`path must not contain \"..\": ${JSON.stringify(raw)}`);\n }\n\n if (segments.includes(\"~\")) {\n throw new Error(`path must not contain \"~\": ${JSON.stringify(raw)}`);\n }\n\n return `/${segments.join(\"/\")}`;\n}\n\n/**\n * Test whether `path` matches a glob `pattern`.\n *\n * Supports:\n * - `**` — any number of directory levels\n * - `*` — within a single path segment\n * - `{a,b}` — brace expansion\n *\n * Uses `micromatch` with `dot: true` so dotfiles are matched by default.\n */\nexport function globMatch(path: string, pattern: string): boolean {\n return micromatch.isMatch(path, pattern, { dot: true });\n}\n\n/**\n * Evaluate permission rules against an operation + path and return the\n * access decision.\n *\n * First-match-wins; permissive default.\n *\n * @returns `\"allow\"` if the operation is permitted, `\"deny\"` otherwise.\n */\nexport function decidePathAccess(\n rules: readonly FilesystemPermission[],\n operation: FilesystemOperation,\n path: string,\n): PermissionMode {\n for (const rule of rules) {\n if (!rule.operations.includes(operation)) {\n continue;\n }\n\n if (rule.paths.some((pattern) => globMatch(path, pattern))) {\n return rule.mode ?? \"allow\";\n }\n }\n\n return \"allow\";\n}\n","/**\n * CompositeBackend: Route operations to different backends based on path prefix.\n */\n\nimport type {\n AnyBackendProtocol,\n BackendProtocolV2,\n DeleteResult,\n EditResult,\n ExecuteResponse,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepMatch,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n WriteResult,\n} from \"./protocol.js\";\nimport {\n applyGrepMaxCount,\n isSandboxBackend,\n isSandboxProtocol,\n} from \"./protocol.js\";\nimport { adaptBackendProtocol, adaptSandboxProtocol } from \"./utils.js\";\n\n/**\n * Backend that routes file operations to different backends based on path prefix.\n *\n * This enables hybrid storage strategies like:\n * - `/memories/` → StoreBackend (persistent, cross-thread)\n * - Everything else → StateBackend (ephemeral, per-thread)\n *\n * The CompositeBackend handles path prefix stripping/re-adding transparently.\n */\nexport class CompositeBackend implements BackendProtocolV2 {\n private default: BackendProtocolV2;\n private routes: Record<string, BackendProtocolV2>;\n private sortedRoutes: Array<[string, BackendProtocolV2]>;\n\n constructor(\n defaultBackend: AnyBackendProtocol,\n routes: Record<string, AnyBackendProtocol>,\n ) {\n // Check if default backend is a sandbox and adapt accordingly\n this.default = isSandboxProtocol(defaultBackend)\n ? adaptSandboxProtocol(defaultBackend)\n : adaptBackendProtocol(defaultBackend);\n\n // Adapt route backends (check each one for sandbox properties)\n this.routes = Object.fromEntries(\n Object.entries(routes).map(([k, v]) => [\n k,\n isSandboxProtocol(v)\n ? adaptSandboxProtocol(v)\n : adaptBackendProtocol(v),\n ]),\n );\n\n // Sort routes by length (longest first) for correct prefix matching\n this.sortedRoutes = Object.entries(this.routes).sort(\n (a, b) => b[0].length - a[0].length,\n );\n }\n\n /** Delegates to default backend's id if it is a sandbox, otherwise empty string. */\n get id(): string {\n return isSandboxBackend(this.default) ? this.default.id : \"\";\n }\n\n /** Route prefixes registered on this backend (e.g. `[\"/workspace\"]`). */\n get routePrefixes(): string[] {\n return Object.keys(this.routes);\n }\n\n /**\n * Type guard — returns true if `backend` is a {@link CompositeBackend}.\n *\n * Uses duck-typing on `routePrefixes` so it works across module boundaries\n * where `instanceof` may fail.\n */\n static isInstance(backend: unknown): backend is CompositeBackend {\n return (\n typeof backend === \"object\" &&\n backend !== null &&\n Array.isArray((backend as Record<string, unknown>).routePrefixes)\n );\n }\n\n /**\n * Determine which backend handles this key and strip prefix.\n *\n * @param key - Original file path\n * @returns Tuple of [backend, stripped_key] where stripped_key has the route\n * prefix removed (but keeps leading slash).\n */\n private getBackendAndKey(key: string): [BackendProtocolV2, string] {\n // Check routes in order of length (longest first)\n for (const [prefix, backend] of this.sortedRoutes) {\n if (key === prefix.slice(0, -1) || key.startsWith(prefix)) {\n // Strip full prefix and ensure a leading slash remains\n // e.g., \"/memories/notes.txt\" → \"/notes.txt\"; \"/memories/\" → \"/\"\n const suffix = key.substring(prefix.length);\n const strippedKey = suffix ? \"/\" + suffix : \"/\";\n return [backend, strippedKey];\n }\n }\n\n return [this.default, key];\n }\n\n /**\n * Returns true when `path` points at `routePrefix` or its descendants.\n */\n private isPathWithinRoute(path: string, routePrefix: string): boolean {\n const normalizedRoute = routePrefix.endsWith(\"/\")\n ? routePrefix\n : `${routePrefix}/`;\n const routeRoot = normalizedRoute.slice(0, -1);\n return path === routeRoot || path.startsWith(normalizedRoute);\n }\n\n /**\n * Returns true when `routePrefix` is inside `path` (or equal to it).\n *\n * Examples:\n * - path `/` includes all routes\n * - path `/workspace` includes route `/workspace/memories/`\n * - path `/workspace` excludes route `/skills/`\n */\n private isRouteUnderPath(routePrefix: string, path: string): boolean {\n if (path === \"/\") {\n return true;\n }\n\n const normalizedPath = path.endsWith(\"/\") ? path : `${path}/`;\n const normalizedRoute = routePrefix.endsWith(\"/\")\n ? routePrefix\n : `${routePrefix}/`;\n return normalizedRoute.startsWith(normalizedPath);\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n *\n * @param path - Absolute path to directory\n * @returns LsResult with list of FileInfo objects (with route prefixes added) on success or error on failure.\n * Directories have a trailing / in their path and is_dir=true.\n */\n async ls(path: string): Promise<LsResult> {\n // Check if path matches a specific route\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (this.isPathWithinRoute(path, routePrefix)) {\n // Query only the matching routed backend\n const suffix = path.substring(routePrefix.length);\n const searchPath = suffix ? \"/\" + suffix : \"/\";\n const result = await backend.ls(searchPath);\n\n if (result.error) {\n return result;\n }\n\n // Add route prefix back to paths\n const prefixed: FileInfo[] = [];\n for (const fi of result.files || []) {\n prefixed.push({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n });\n }\n return { files: prefixed };\n }\n }\n\n // At root, aggregate default and all routed backends\n if (path === \"/\") {\n const results: FileInfo[] = [];\n const defaultResult = await this.default.ls(path);\n\n if (defaultResult.error) {\n return defaultResult;\n }\n\n // Loop instead of spread: push(...files) passes each entry as a\n // separate argument and overflows the call stack on huge listings.\n for (const fi of defaultResult.files || []) {\n results.push(fi);\n }\n\n // Add the route itself as a directory (e.g., /memories/)\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 { files: results };\n }\n\n // Path doesn't match a route: query only default backend\n return await this.default.ls(path);\n }\n\n /**\n * Read file content, routing to appropriate backend.\n *\n * @param filePath - Absolute file path\n * @param offset - Line offset to start reading from (0-indexed)\n * @param limit - Maximum number of lines to read\n * @returns Formatted file content with line numbers, or error message\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 500,\n ): Promise<ReadResult> {\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 * @param filePath - Absolute file path\n * @returns ReadRawResult with raw file data on success or error on failure\n */\n async readRaw(filePath: string): Promise<ReadRawResult> {\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 * @param maxCount - Optional total cap on returned matches across all routed\n * backends. When the cap is reached, remaining routes are\n * short-circuited and the result is flagged `truncated: true`.\n */\n async grep(\n pattern: string,\n path: string | null = \"/\",\n glob: string | null = null,\n maxCount: number | null = null,\n ): Promise<GrepResult> {\n const searchPath = path || \"/\";\n\n // If path targets a specific route, search only that backend\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (this.isPathWithinRoute(searchPath, routePrefix)) {\n const routeSearchPath = searchPath.substring(routePrefix.length - 1);\n const raw = await backend.grep(\n pattern,\n routeSearchPath || \"/\",\n glob,\n maxCount,\n );\n\n if (raw.error) {\n return raw;\n }\n\n // Add route prefix back\n const matches = (raw.matches || []).map((m) => ({\n ...m,\n path: routePrefix.slice(0, -1) + m.path,\n }));\n return applyGrepMaxCount({\n result: { matches, truncated: raw.truncated },\n maxCount,\n });\n }\n }\n\n // Otherwise, search default and routed backends mounted inside this path\n const allMatches: GrepMatch[] = [];\n let truncated = false;\n const rawDefault = await this.default.grep(\n pattern,\n searchPath,\n glob,\n maxCount,\n );\n\n if (rawDefault.error) {\n return rawDefault;\n }\n\n for (const m of rawDefault.matches || []) {\n allMatches.push(m);\n }\n truncated = truncated || rawDefault.truncated === true;\n\n // Search only routes that are descendants of the requested path\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n if (!this.isRouteUnderPath(routePrefix, searchPath)) {\n continue;\n }\n\n const remaining =\n maxCount == null ? null : Math.max(maxCount - allMatches.length, 0);\n if (remaining === 0) {\n truncated = true;\n break;\n }\n\n const raw = await backend.grep(pattern, \"/\", glob, remaining);\n\n if (raw.error) {\n return raw;\n }\n\n // Add route prefix back\n for (const m of raw.matches || []) {\n allMatches.push({ ...m, path: routePrefix.slice(0, -1) + m.path });\n }\n truncated = truncated || raw.truncated === true;\n }\n\n return applyGrepMaxCount({\n result: { matches: allMatches, truncated },\n maxCount,\n });\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async glob(pattern: string, path: string = \"/\"): Promise<GlobResult> {\n const results: FileInfo[] = [];\n\n // Route based on path, not pattern\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (this.isPathWithinRoute(path, routePrefix)) {\n const searchPath = path.substring(routePrefix.length - 1);\n const result = await backend.glob(pattern, searchPath || \"/\");\n\n if (result.error) {\n return result;\n }\n\n // Add route prefix back\n const files = (result.files || []).map((fi) => ({\n ...fi,\n path: routePrefix.slice(0, -1) + fi.path,\n }));\n return { files, truncated: result.truncated };\n }\n }\n\n // Path doesn't match any specific route - search default and route descendants\n const defaultResult = await this.default.glob(pattern, path);\n if (defaultResult.error) {\n return defaultResult;\n }\n\n for (const fi of defaultResult.files || []) {\n results.push(fi);\n }\n let truncated = defaultResult.truncated === true;\n\n for (const [routePrefix, backend] of Object.entries(this.routes)) {\n if (!this.isRouteUnderPath(routePrefix, path)) {\n continue;\n }\n\n const result = await backend.glob(pattern, \"/\");\n if (result.error) {\n continue; // Skip backends that error\n }\n for (const fi of result.files || []) {\n results.push({ ...fi, path: routePrefix.slice(0, -1) + fi.path });\n }\n truncated = truncated || result.truncated === true;\n }\n\n // Deterministic ordering\n results.sort((a, b) => a.path.localeCompare(b.path));\n return { files: results, truncated };\n }\n\n /**\n * Write content to a file, routing to appropriate backend.\n *\n * @param filePath - Absolute file path\n * @param content - File content as string\n * @returns WriteResult with path or error\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 * Add a route prefix back to state deletion updates.\n */\n private prefixDeleteFilesUpdate(\n filesUpdate: Record<string, null>,\n routePrefix: string,\n ): Record<string, null> {\n const routeRoot = routePrefix.slice(0, -1);\n return Object.fromEntries(\n Object.keys(filesUpdate).map((path) => [routeRoot + path, null]),\n );\n }\n\n /**\n * Restore composite paths in a deletion result from a single backend.\n */\n private restoreDeleteResult(\n result: DeleteResult,\n filePath: string,\n routePrefix?: string,\n ): DeleteResult {\n const restored = { ...result };\n if (result.path !== undefined) {\n restored.path = filePath;\n }\n if (routePrefix && result.filesUpdate) {\n restored.filesUpdate = this.prefixDeleteFilesUpdate(\n result.filesUpdate,\n routePrefix,\n );\n }\n return restored;\n }\n\n /**\n * Delete a file or directory, routing to appropriate backend.\n *\n * Parent and root deletions run sequentially across the base backend and any\n * mounted routes below the requested path. A failure stops the fan-out so\n * later backends are left untouched, but earlier deletions cannot be rolled\n * back and are reported as potentially partial.\n *\n * @param filePath - Absolute file path\n * @returns DeleteResult with path or error\n */\n async delete(filePath: string): Promise<DeleteResult> {\n const [baseBackend, baseKey] = this.getBackendAndKey(filePath);\n const baseRoute = this.sortedRoutes.find(([routePrefix]) =>\n this.isPathWithinRoute(filePath, routePrefix),\n )?.[0];\n const targets: Array<{\n backend: BackendProtocolV2;\n key: string;\n routePrefix?: string;\n }> = [{ backend: baseBackend, key: baseKey, routePrefix: baseRoute }];\n\n for (const [routePrefix, backend] of this.sortedRoutes) {\n if (\n routePrefix !== baseRoute &&\n this.isRouteUnderPath(routePrefix, filePath)\n ) {\n targets.push({ backend, key: \"/\", routePrefix });\n }\n }\n\n for (const target of targets) {\n if (!target.backend.delete) {\n const location = target.routePrefix\n ? `mounted route '${target.routePrefix}'`\n : \"default backend\";\n return {\n error: `Error: deletion is not available for '${filePath}' on ${location}.`,\n };\n }\n }\n\n if (targets.length === 1) {\n const target = targets[0];\n const result = await target.backend.delete!(target.key);\n return this.restoreDeleteResult(result, filePath, target.routePrefix);\n }\n\n const filesUpdate: Record<string, null> = {};\n let hasFilesUpdate = false;\n let hasNullFilesUpdate = false;\n let completed = 0;\n let firstNotFound: DeleteResult | undefined;\n\n for (const target of targets) {\n let result: DeleteResult;\n try {\n result = await target.backend.delete!(target.key);\n } catch (error) {\n const message =\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ? error.message\n : String(error);\n return {\n error: `Error deleting '${filePath}': ${message}. Deletion may be partial; ${completed} earlier backend(s) completed and remaining backends were not attempted.`,\n };\n }\n\n if (result.error) {\n if (/not found/i.test(result.error)) {\n firstNotFound ??= result;\n continue;\n }\n return {\n error: `Error deleting '${filePath}': ${result.error}. Deletion may be partial; ${completed} earlier backend(s) completed and remaining backends were not attempted.`,\n };\n }\n\n completed += 1;\n if (result.filesUpdate === null) {\n hasNullFilesUpdate = true;\n } else if (result.filesUpdate) {\n hasFilesUpdate = true;\n Object.assign(\n filesUpdate,\n target.routePrefix\n ? this.prefixDeleteFilesUpdate(\n result.filesUpdate,\n target.routePrefix,\n )\n : result.filesUpdate,\n );\n }\n }\n\n if (completed === 0) {\n return firstNotFound ?? { error: `Error: File '${filePath}' not found` };\n }\n\n if (hasFilesUpdate) {\n return { path: filePath, filesUpdate };\n }\n if (hasNullFilesUpdate) {\n return { path: filePath, filesUpdate: null };\n }\n return { path: filePath };\n }\n\n /**\n * Edit a file, routing to appropriate backend.\n *\n * @param filePath - Absolute file path\n * @param oldString - String to find and replace\n * @param newString - Replacement string\n * @param replaceAll - If true, replace all occurrences\n * @returns EditResult with path, occurrences, or error\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 * Execute a command via the default backend.\n * Execution is not path-specific, so it always delegates to the default backend.\n *\n * @param command - Full shell command string to execute\n * @returns ExecuteResponse with combined output, exit code, and truncation flag\n * @throws Error if the default backend doesn't support command execution\n */\n execute(command: string): Promise<ExecuteResponse> {\n if (!isSandboxBackend(this.default)) {\n throw new Error(\n \"Default backend doesn't support command execution (SandboxBackendProtocol). \" +\n \"To enable execution, provide a default backend that implements SandboxBackendProtocol.\",\n );\n }\n return Promise.resolve(this.default.execute(command));\n }\n\n /**\n * Upload multiple files, batching by backend for efficiency.\n *\n * @param files - List of [path, content] tuples to upload\n * @returns List of FileUploadResponse objects, one per input file\n */\n async uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): Promise<FileUploadResponse[]> {\n const results: Array<FileUploadResponse | null> = Array.from(\n { length: files.length },\n () => null,\n );\n const batchesByBackend = new Map<\n BackendProtocolV2,\n Array<{ idx: number; path: string; content: Uint8Array }>\n >();\n\n for (let idx = 0; idx < files.length; idx++) {\n const [path, content] = files[idx];\n const [backend, strippedPath] = this.getBackendAndKey(path);\n\n if (!batchesByBackend.has(backend)) {\n batchesByBackend.set(backend, []);\n }\n batchesByBackend.get(backend)!.push({ idx, path: strippedPath, content });\n }\n\n for (const [backend, batch] of batchesByBackend) {\n if (!backend.uploadFiles) {\n throw new Error(\"Backend does not support uploadFiles\");\n }\n\n const batchFiles = batch.map(\n (b) => [b.path, b.content] as [string, Uint8Array],\n );\n const batchResponses = await backend.uploadFiles(batchFiles);\n\n for (let i = 0; i < batch.length; i++) {\n const originalIdx = batch[i].idx;\n results[originalIdx] = {\n path: files[originalIdx][0], // Original path\n error: batchResponses[i]?.error ?? null,\n };\n }\n }\n\n return results as FileUploadResponse[];\n }\n\n /**\n * Download multiple files, batching by backend for efficiency.\n *\n * @param paths - List of file paths to download\n * @returns List of FileDownloadResponse objects, one per input path\n */\n async downloadFiles(paths: string[]): Promise<FileDownloadResponse[]> {\n const results: Array<FileDownloadResponse | null> = Array.from(\n { length: paths.length },\n () => null,\n );\n const batchesByBackend = new Map<\n BackendProtocolV2,\n Array<{ idx: number; path: string }>\n >();\n\n for (let idx = 0; idx < paths.length; idx++) {\n const path = paths[idx];\n const [backend, strippedPath] = this.getBackendAndKey(path);\n\n if (!batchesByBackend.has(backend)) {\n batchesByBackend.set(backend, []);\n }\n batchesByBackend.get(backend)!.push({ idx, path: strippedPath });\n }\n\n for (const [backend, batch] of batchesByBackend) {\n if (!backend.downloadFiles) {\n throw new Error(\"Backend does not support downloadFiles\");\n }\n\n const batchPaths = batch.map((b) => b.path);\n const batchResponses = await backend.downloadFiles(batchPaths);\n\n for (let i = 0; i < batch.length; i++) {\n const originalIdx = batch[i].idx;\n results[originalIdx] = {\n path: paths[originalIdx], // Original path\n content: batchResponses[i]?.content ?? null,\n error: batchResponses[i]?.error ?? null,\n };\n }\n }\n\n return results as FileDownloadResponse[];\n }\n}\n","/**\n * Middleware for providing filesystem tools to an agent.\n *\n * Provides ls, read_file, write_file, edit_file, delete, glob, and grep tools with support for:\n * - Pluggable backends (StateBackend, StoreBackend, FilesystemBackend, CompositeBackend)\n * - Tool result eviction for large outputs\n */\n\nimport {\n context,\n createMiddleware,\n tool,\n HumanMessage,\n ToolMessage,\n type AgentMiddleware as _AgentMiddleware,\n type ToolRuntime,\n} from \"langchain\";\nimport {\n Command,\n isCommand,\n StateSchema,\n ReducedValue,\n} from \"@langchain/langgraph\";\nimport { z } from \"zod/v4\";\nimport type {\n AnyBackendProtocol,\n BackendFactory,\n BackendProtocolV2,\n BackendRuntime,\n DeleteResult,\n FileData,\n LsResult,\n ReadResult,\n} from \"../backends/protocol.js\";\nimport { isSandboxBackend, resolveBackend } from \"../backends/protocol.js\";\nimport { StateBackend } from \"../backends/state.js\";\nimport {\n sanitizeToolCallId,\n formatContentWithLineNumbers,\n formatContentWithLineNumbersAndBoundaries,\n type FormattedContentWithLineNumbers,\n formatGrepMatches,\n truncateIfTooLong,\n getMimeType,\n isTextMimeType,\n MAX_LINE_LENGTH,\n normalizeReadPagination,\n} from \"../backends/utils.js\";\n\nconst INT_FORMATTER = new Intl.NumberFormat(\"en-US\");\n\n/**\n * Normalizes tool input so that models sending `path` instead of `file_path`\n * still work. If the input has `path` but not `file_path`, copies `path` into\n * `file_path`. This makes the filesystem tools resilient to parameter-name\n * variations across models of different capability levels.\n */\nfunction normalizeFilePathInput(input: unknown): unknown {\n if (\n typeof input === \"object\" &&\n input !== null &&\n \"path\" in input &&\n !(\"file_path\" in input)\n ) {\n const { path, ...rest } = input as Record<string, unknown>;\n return { ...rest, file_path: path };\n }\n return input;\n}\n\n/**\n * Import langchain for type inference\n */\nimport type * as _langchain from \"langchain\";\n\n/**\n * Tools that should be excluded from the large result eviction logic.\n *\n * This array contains tools that should NOT have their results evicted to the filesystem\n * when they exceed token limits. Tools are excluded for different reasons:\n *\n * 1. Tools with built-in truncation (ls, glob, grep):\n * These tools truncate their own output when it becomes too large. When these tools\n * produce truncated output due to many matches, it typically indicates the query\n * needs refinement rather than full result preservation. In such cases, the truncated\n * matches are potentially more like noise and the LLM should be prompted to narrow\n * its search criteria instead.\n *\n * 2. Tools with problematic truncation behavior (read_file):\n * read_file is tricky to handle as the failure mode here is single long lines\n * (e.g., imagine a jsonl file with very long payloads on each line). If we try to\n * truncate the result of read_file, the agent may then attempt to re-read the\n * truncated file using read_file again, which won't help.\n *\n * 3. Tools that never exceed limits (edit_file, write_file, delete):\n * These tools return minimal confirmation messages and are never expected to produce\n * output large enough to exceed token limits, so checking them would be unnecessary.\n */\n/**\n * All tool names registered by FilesystemMiddleware.\n * This is the single source of truth — used by createDeepAgent to detect\n * collisions with user-supplied tools at construction time.\n */\nexport const FILESYSTEM_TOOL_NAMES = [\n \"ls\",\n \"read_file\",\n \"write_file\",\n \"edit_file\",\n \"delete\",\n \"glob\",\n \"grep\",\n \"execute\",\n] as const;\n\n/**\n * Built-in filesystem tool names accepted by\n * {@link createFilesystemMiddleware}'s `tools` allowlist.\n */\nexport type FsToolName = (typeof FILESYSTEM_TOOL_NAMES)[number];\n\nexport const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter(\n (name) => name !== \"execute\",\n);\n\n/**\n * Approximate number of characters per token for truncation calculations.\n * Using 4 chars per token as a conservative approximation (actual ratio varies by content)\n * This errs on the high side to avoid premature eviction of content that might fit.\n */\nexport const NUM_CHARS_PER_TOKEN = 4;\n\n/**\n * Default values for read_file tool pagination (in lines).\n */\nexport const DEFAULT_READ_LINE_OFFSET = 0;\nexport const DEFAULT_READ_LINE_LIMIT = 100;\n\n/**\n * Maximum size for binary (non-text) files read via read_file, in bytes.\n * Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.\n * This keeps inline multimodal payloads within all major provider limits.\n */\nexport const MAX_BINARY_READ_SIZE_BYTES = 10 * 1024 * 1024;\n\n/**\n * Template for truncation message in read_file.\n * {file_path} will be filled in at runtime.\n */\nconst READ_FILE_TRUNCATION_MSG = `\n\n[Output was truncated due to size limits. The file content is very large. Consider reformatting the file to make it easier to navigate. For example, if this is JSON, use execute(command='jq . {file_path}') to pretty-print it with line breaks. For other formats, you can use appropriate formatting tools to split long lines.]`;\n\n/**\n * Render backend pagination metadata as guidance for the model.\n *\n * Backends own source-level pagination because only they know how much of the\n * file was read. The middleware owns presentation: it line-numbers the text\n * and turns optional metadata into a human-readable footer. Keeping the fields\n * optional preserves compatibility with custom backends that predate this\n * contract; those reads simply receive no pagination footer.\n *\n * `nextOffset` is the signal that the read is partial. A result at EOF omits it,\n * so complete reads retain their previous output shape.\n */\nfunction remainingLinesNotice(readResult: ReadResult): string {\n const { startLine, endLine, nextOffset, totalLines } = readResult;\n if (\n startLine === undefined ||\n endLine === undefined ||\n nextOffset === undefined ||\n !Number.isSafeInteger(startLine) ||\n !Number.isSafeInteger(endLine) ||\n !Number.isSafeInteger(nextOffset) ||\n startLine < 1 ||\n endLine < startLine ||\n nextOffset !== endLine ||\n (totalLines !== undefined &&\n (!Number.isSafeInteger(totalLines) || totalLines < endLine))\n ) {\n return \"\";\n }\n\n const readCount = endLine - startLine + 1;\n const readUnit = readCount === 1 ? \"line\" : \"lines\";\n if (totalLines === undefined) {\n return `\\n\\n[Read ${readCount} ${readUnit} (lines ${startLine}-${endLine}). More lines remain from offset ${nextOffset}.]`;\n }\n if (endLine >= totalLines) {\n return \"\";\n }\n\n const remaining = totalLines - endLine;\n const remainingUnit = remaining === 1 ? \"line\" : \"lines\";\n return `\\n\\n[Read ${readCount} ${readUnit} (lines ${startLine}-${endLine} of ${totalLines} total). ${remaining} ${remainingUnit} remaining from offset ${nextOffset}.]`;\n}\n\n/**\n * Fit a line-numbered read into the middleware's output budget without\n * publishing a resume offset that skips content the model did not see.\n *\n * There are two independent forms of limiting:\n *\n * 1. The backend paginates the source file with `offset` and `limit`.\n * 2. The middleware may further shorten that page to fit its token budget.\n *\n * If the backend returned lines 1-100 but the middleware only displayed lines\n * 1-30, forwarding the backend's original `nextOffset: 100` would silently skip\n * lines 31-100 on the next read. This function therefore truncates only after a\n * complete source line and rebuilds the remaining-lines notice using the last\n * line actually displayed.\n *\n * Long source lines may occupy several formatted rows (`12`, `12.1`, ...). The\n * formatter records a structured boundary only after the final chunk, so this\n * function does not need to inspect or understand the gutter representation.\n * If no complete source line can fit beside the truncation message, the function\n * falls back to character truncation and omits pagination guidance rather than\n * advertising an unsafe offset.\n */\nfunction truncatePaginatedRead(\n formatted: FormattedContentWithLineNumbers,\n filePath: string,\n readResult: ReadResult,\n tokenLimit: number | null,\n): string {\n const content = formatted.text;\n const notice = remainingLinesNotice(readResult);\n if (\n !tokenLimit ||\n content.length + notice.length < NUM_CHARS_PER_TOKEN * tokenLimit\n ) {\n return content + notice;\n }\n\n const truncationMsg = READ_FILE_TRUNCATION_MSG.replace(\n \"{file_path}\",\n filePath,\n );\n const threshold = NUM_CHARS_PER_TOKEN * tokenLimit;\n if (readResult.startLine !== undefined && readResult.endLine !== undefined) {\n const finalSourceLine = readResult.endLine;\n const boundaries = formatted.sourceLineBoundaries.filter(\n (boundary) => boundary.sourceLine <= finalSourceLine,\n );\n\n // Prefer the latest complete source line that leaves room for both notices.\n for (let index = boundaries.length - 1; index >= 0; index -= 1) {\n const boundary = boundaries[index];\n const adjustedResult: ReadResult = {\n totalLines: readResult.totalLines,\n startLine: readResult.startLine,\n endLine: boundary.sourceLine,\n nextOffset: boundary.sourceLine,\n };\n const adjustedNotice = remainingLinesNotice(adjustedResult);\n if (\n boundary.endOffset + truncationMsg.length + adjustedNotice.length <=\n threshold\n ) {\n return (\n content.slice(0, boundary.endOffset) + truncationMsg + adjustedNotice\n );\n }\n }\n }\n\n // Without a complete safe boundary, preserve the historical character-level\n // truncation behavior but omit a pagination footer: guessing would risk skips.\n const maxContentLength = Math.max(0, threshold - truncationMsg.length);\n return content.substring(0, maxContentLength) + truncationMsg;\n}\n\n/**\n * Note appended to grep results that were cut short by the match-count cap.\n */\nexport const GREP_TRUNCATION_NOTE =\n \"Note: the search stopped early because it hit the maximum match count. \" +\n \"The matches above are valid but incomplete. Narrow the search (a more \" +\n \"specific pattern or a narrower path), or raise max_count, to see the rest.\";\n\n/**\n * Default cap on the number of matches the grep tool returns.\n * Set to null to disable the cap.\n */\nexport const DEFAULT_GREP_MAX_COUNT = 1000;\n\n/**\n * Message template for evicted tool results.\n */\nconst TOO_LARGE_TOOL_MSG = context`\n Tool result too large, the result of this tool call {tool_call_id} was saved in the filesystem at this path: {file_path}\n You can read the result from the filesystem by using the read_file tool, but make sure to only read part of the result at a time.\n You can do this by specifying an offset and limit in the read_file tool call.\n For example, to read the first ${DEFAULT_READ_LINE_LIMIT} lines, you can use the read_file tool with offset=0 and limit=${DEFAULT_READ_LINE_LIMIT}.\n\n Here is a preview showing the head and tail of the result (lines of the form\n ... [N lines truncated] ...\n indicate omitted lines in the middle of the content):\n\n {content_sample}\n`;\n\n/**\n * Message template for evicted HumanMessages.\n */\nconst TOO_LARGE_HUMAN_MSG = `Message content too large and was saved to the filesystem at: {file_path}\n\nYou can read the full content using the read_file tool with pagination (offset and limit parameters).\n\nHere is a preview showing the head and tail of the content:\n\n{content_sample}`;\n\n/**\n * Extract text content from a message.\n *\n * For string content, returns it directly. For array content (mixed block types\n * like text + image), joins all text blocks. Returns empty string if no text found.\n */\nfunction extractTextFromMessage(message: {\n content: string | Array<Record<string, unknown>>;\n}): string {\n if (typeof message.content === \"string\") {\n return message.content;\n }\n if (Array.isArray(message.content)) {\n return message.content\n .filter(\n (block) => block.type === \"text\" && typeof block.text === \"string\",\n )\n .map((block) => block.text as string)\n .join(\"\\n\");\n }\n return String(message.content);\n}\n\nfunction stringifyToolContent(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (\n typeof block === \"object\" &&\n block !== null &&\n \"type\" in block &&\n block.type === \"text\" &&\n \"text\" in block &&\n typeof block.text === \"string\"\n ) {\n return block.text;\n }\n return JSON.stringify(block);\n })\n .join(\"\\n\");\n }\n return String(content);\n}\n\n/**\n * Build replacement content for an evicted HumanMessage, preserving non-text blocks.\n *\n * For plain string content, returns the replacement text directly. For list content\n * with mixed block types (e.g., text + image), replaces all text blocks with a single\n * text block containing the replacement text while keeping non-text blocks intact.\n */\nfunction buildEvictedHumanContent(\n message: HumanMessage,\n replacementText: string,\n): string | Array<Record<string, unknown>> {\n if (typeof message.content === \"string\") {\n return replacementText;\n }\n if (Array.isArray(message.content)) {\n const mediaBlocks = message.content.filter(\n (block) =>\n typeof block === \"object\" && block !== null && block.type !== \"text\",\n );\n if (mediaBlocks.length === 0) {\n return replacementText;\n }\n return [{ type: \"text\", text: replacementText }, ...mediaBlocks];\n }\n return replacementText;\n}\n\n/**\n * Build a truncated HumanMessage for the model request.\n *\n * Computes a preview from the full content still in state and returns a\n * lightweight replacement the model will see. Pure string computation — no\n * backend I/O.\n */\nfunction buildTruncatedHumanMessage(\n message: HumanMessage,\n filePath: string,\n): HumanMessage {\n const contentStr = extractTextFromMessage(message);\n const contentSample = createContentPreview(contentStr);\n const replacementText = TOO_LARGE_HUMAN_MSG.replace(\n \"{file_path}\",\n filePath,\n ).replace(\"{content_sample}\", contentSample);\n const evictedContent = buildEvictedHumanContent(message, replacementText);\n return new HumanMessage({\n content: evictedContent as any,\n id: message.id,\n additional_kwargs: { ...message.additional_kwargs },\n response_metadata: { ...message.response_metadata },\n });\n}\n\n/**\n * Create a preview of content showing head and tail with truncation marker.\n *\n * @param contentStr - The full content string to preview.\n * @param headLines - Number of lines to show from the start (default: 5).\n * @param tailLines - Number of lines to show from the end (default: 5).\n * @returns Formatted preview string with line numbers.\n */\nexport function createContentPreview(\n contentStr: string,\n headLines: number = 5,\n tailLines: number = 5,\n): string {\n const lines = contentStr.split(\"\\n\");\n\n if (lines.length <= headLines + tailLines) {\n // If file is small enough, show all lines\n const previewLines = lines.map((line) => line.substring(0, 1000));\n return formatContentWithLineNumbers(previewLines, 1);\n }\n\n // Show head and tail with truncation marker\n const head = lines.slice(0, headLines).map((line) => line.substring(0, 1000));\n const tail = lines.slice(-tailLines).map((line) => line.substring(0, 1000));\n\n const headSample = formatContentWithLineNumbers(head, 1);\n const truncationNotice = `\\n... [${lines.length - headLines - tailLines} lines truncated] ...\\n`;\n const tailSample = formatContentWithLineNumbers(\n tail,\n lines.length - tailLines + 1,\n );\n\n return headSample + truncationNotice + tailSample;\n}\n\n/**\n * required for type inference\n */\nimport type * as _zodTypes from \"@langchain/core/utils/types\";\nimport type * as _zodMeta from \"@langchain/langgraph/zod\";\nimport type * as _messages from \"@langchain/core/messages\";\nimport {\n FilesystemOperation,\n FilesystemPermission,\n} from \"../permissions/types.js\";\nimport {\n decidePathAccess,\n globMatch,\n validatePath,\n validatePermissionPaths,\n} from \"../permissions/enforce.js\";\nimport { CompositeBackend } from \"../backends/composite.js\";\n\n/**\n * Zod schema for legacy FileDataV1 (content as line array).\n */\nexport const FileDataV1Schema = z.object({\n content: z.array(z.string()),\n created_at: z.string(),\n modified_at: z.string(),\n});\n\n/**\n * Zod schema for FileDataV2 (content as string for text or Uint8Array for binary).\n */\nexport const FileDataV2Schema = z.object({\n content: z.union([z.string(), z.instanceof(Uint8Array)]),\n mimeType: z.string(),\n created_at: z.string(),\n modified_at: z.string(),\n});\n\n/**\n * Zod v3 schema for FileData (re-export from backends)\n */\nexport const FileDataSchema = z.union([FileDataV1Schema, FileDataV2Schema]);\n\n/**\n * Type for the files state record.\n */\nexport type FilesRecord = Record<string, FileData>;\n\n/**\n * Type for file updates, where null indicates deletion.\n */\nexport type FilesRecordUpdate = Record<string, FileData | null>;\n\n/**\n * Reducer for files state that merges file updates with support for deletions.\n * When a file value is null, the file is deleted from state.\n * When a file value is non-null, it is added or updated in state.\n *\n * This reducer enables concurrent updates from parallel subagents by properly\n * merging their file changes instead of requiring LastValue semantics.\n *\n * @param current - The current files record (from state)\n * @param update - The new files record (from a subagent update), with null values for deletions\n * @returns Merged files record with deletions applied\n */\nexport function fileDataReducer(\n current: FilesRecord | undefined,\n update: FilesRecordUpdate | undefined,\n): FilesRecord {\n // If no update, return current (or empty object)\n if (update === undefined) {\n return current || {};\n }\n\n // If no current, filter out null values from update\n if (current === undefined) {\n const result: FilesRecord = {};\n for (const [key, value] of Object.entries(update)) {\n if (value !== null) {\n result[key] = value;\n }\n }\n return result;\n }\n\n // Merge: apply updates and deletions\n const result = { ...current };\n for (const [key, value] of Object.entries(update)) {\n if (value === null) {\n delete result[key];\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Shared filesystem state schema.\n * Defined at module level to ensure the same object identity is used across all agents,\n * preventing \"Channel already exists with different type\" errors when multiple agents\n * use createFilesystemMiddleware.\n *\n * Uses ReducedValue for files to allow concurrent updates from parallel subagents.\n */\nconst FilesystemStateSchema = new StateSchema({\n files: new ReducedValue(\n z.record(z.string(), FileDataSchema).default(() => ({})),\n {\n inputSchema: z.record(z.string(), FileDataSchema.nullable()).optional(),\n reducer: fileDataReducer,\n },\n ),\n});\n\n/** Extract a message string from an unknown thrown value without `instanceof`. */\nfunction getErrorMessage(error: unknown): string {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof (error as { message?: unknown }).message === \"string\"\n ) {\n return (error as { message: string }).message;\n }\n return String(error);\n}\n\n/**\n * Check whether `path` is permitted under `rules` for `operation`, returning an\n * error string to surface to the model (or `undefined` when allowed).\n *\n * Never throws: an invalid path (non-absolute, or containing `..` or `~`) or a\n * denied path is a recoverable tool error, not a fatal run-ending one. Such\n * paths are rejected, never normalized, so they cannot bypass a deny rule or\n * reach the backend.\n *\n * @internal\n */\nfunction checkPermission(\n rules: FilesystemPermission[],\n operation: FilesystemOperation,\n path: string,\n): string | undefined {\n if (rules.length === 0) {\n return undefined;\n }\n\n let canonical: string;\n try {\n canonical = validatePath(path);\n } catch (error) {\n return `Error: ${getErrorMessage(error)}`;\n }\n\n if (decidePathAccess(rules, operation, canonical) === \"deny\") {\n return `Error: permission denied for ${operation} on ${canonical}`;\n }\n\n return undefined;\n}\n\n/**\n * Build an error {@link ToolMessage} for a rejected or denied path. Returning a\n * bare string would be wrapped as a `status: \"success\"` message whose content\n * merely starts with \"Error:\"; marking `status: \"error\"` reports the failure\n * accurately so callers and the model can distinguish a real failure from a\n * successful result.\n */\nfunction toolError(\n runtime: ToolRuntime,\n toolName: string,\n message: string,\n): ToolMessage {\n return new ToolMessage({\n content: message,\n name: toolName,\n tool_call_id: runtime.toolCall?.id as string,\n status: \"error\",\n });\n}\n\nconst GLOB_WILDCARD_CHARACTERS = [\"*\", \"?\", \"{\", \"[\"];\n\nfunction hasGlobMetaCharacter(pattern: string): boolean {\n return GLOB_WILDCARD_CHARACTERS.some((character) =>\n pattern.includes(character),\n );\n}\n\n/**\n * Split an absolute POSIX path into its components (excluding the leading \"/\").\n * `posixParts(\"/a/b\")` -> `[\"a\", \"b\"]`; `posixParts(\"/\")` -> `[]`.\n */\nfunction posixParts(path: string): string[] {\n return path.split(\"/\").filter(Boolean);\n}\n\n/**\n * Whether `child` is `ancestor` or lives (component-wise) beneath it. The root\n * `/` contains everything. `/secret` is NOT relative to `/secrets`.\n */\nfunction isRelativeTo(child: string, ancestor: string): boolean {\n if (ancestor === \"/\") {\n return true;\n }\n return child === ancestor || child.startsWith(`${ancestor}/`);\n}\n\n/**\n * Return the longest leading directory of `pattern` with no wildcards.\n *\n * For a `**` suffix it returns the wildcard-free prefix, and a pattern whose\n * wildcard sits at or near the root falls back to `/`.\n */\nfunction globAnchor(pattern: string): string {\n const safe: string[] = [];\n for (const part of posixParts(pattern)) {\n if (\n GLOB_WILDCARD_CHARACTERS.some((character) => part.includes(character))\n ) {\n break;\n }\n safe.push(part);\n }\n if (safe.length === 0) {\n return \"/\";\n }\n return `/${safe.join(\"/\")}`;\n}\n\n/**\n * Whether the subtree at `callPath` intersects the subtree at `ruleAnchor`.\n * Two subtrees overlap when one is a (component-wise) prefix of the other, or\n * they are equal. The root `/` overlaps everything.\n */\nfunction pathsOverlap(callPath: string, ruleAnchor: string): boolean {\n const a = validatePath(callPath);\n const b = validatePath(ruleAnchor);\n return a === b || isRelativeTo(a, b) || isRelativeTo(b, a);\n}\n\n/**\n * Whether a wildcard deny `pattern` overlaps a recursive delete of `target`.\n *\n * Deleting `/work/app/child` when `/work/*` is denied mutates the\n * denied `/work/app`, so it must be blocked, while `/work/*.log` can never\n * match anything under `/work/notes.txt` and stays allowed.\n */\nfunction wildcardDeleteOverlap(\n pattern: string,\n anchor: string,\n target: string,\n): boolean {\n // Root anchor (\"/**/x\"): pattern can match anywhere, block all.\n if (anchor === \"/\") {\n return true;\n }\n // Target directly matches the glob: block.\n if (globMatch(target, pattern)) {\n return true;\n }\n // Anchor is inside the delete subtree: a recursive delete would remove\n // matching descendants — block.\n if (isRelativeTo(anchor, target)) {\n return true;\n }\n // Target is below the anchor: safe to allow ONLY when the pattern suffix is a\n // single, non-** component (fixed depth) AND no ancestor of the target\n // matches the glob. Directory wildcards (\"/work/*/secrets\") could match\n // descendants of the target, so fail closed for those.\n if (!isRelativeTo(target, anchor)) {\n return false;\n }\n const anchorParts = posixParts(anchor);\n const patternParts = posixParts(pattern);\n const suffix = patternParts.slice(anchorParts.length);\n if (suffix.length !== 1 || suffix[0].includes(\"**\")) {\n return true;\n }\n // Block when any ancestor of the target (between anchor and target) matches\n // the glob — the target is then inside a denied directory's subtree.\n const targetParts = posixParts(target);\n for (let depth = anchorParts.length; depth < targetParts.length; depth += 1) {\n const ancestor = `/${targetParts.slice(0, depth).join(\"/\")}`;\n if (globMatch(ancestor, pattern)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Resolve delete permission for a confirmed plain file: first matching write\n * rule wins, mirroring `decidePathAccess`'s ordering, but returning the matched\n * deny pattern(s) so the delete tool's error can cite them. An earlier allow\n * rule short-circuits and returns no denials.\n */\nfunction findDeleteDenyPatternsForLeaf(\n rules: readonly FilesystemPermission[],\n target: string,\n): string[] {\n for (const rule of rules) {\n if (!rule.operations.includes(\"write\")) {\n continue;\n }\n const matched = rule.paths.filter((pattern) => globMatch(target, pattern));\n if (matched.length === 0) {\n continue;\n }\n return (rule.mode ?? \"allow\") === \"deny\" ? matched : [];\n }\n return [];\n}\n\n/**\n * Return the deny-write patterns that block deleting `target`.\n *\n * When `hasDescendants` is `true` (the target may be a directory), a recursive\n * delete removes the whole subtree, so any deny-write pattern that could match\n * `target` or anything nested under it blocks the operation regardless of rule\n * order — an earlier allow can't guarantee every descendant is safe. When\n * `hasDescendants` is `false` (a backend-confirmed plain file), the target is\n * resolved exactly like `write_file`/`edit_file`: first matching rule wins.\n *\n * @internal Exported for unit testing the delete permission overlap geometry.\n */\nexport function findDeleteDenyPatterns(\n rules: readonly FilesystemPermission[],\n target: string,\n hasDescendants: boolean = true,\n): string[] {\n const canonicalTarget = validatePath(target);\n\n if (!hasDescendants) {\n return findDeleteDenyPatternsForLeaf(rules, canonicalTarget);\n }\n\n const denying: string[] = [];\n const seen = new Set<string>();\n for (const rule of rules) {\n if (rule.mode !== \"deny\" || !rule.operations.includes(\"write\")) {\n continue;\n }\n for (const pattern of rule.paths) {\n if (seen.has(pattern)) {\n continue;\n }\n const anchor = globAnchor(pattern);\n const overlaps = hasGlobMetaCharacter(pattern)\n ? wildcardDeleteOverlap(pattern, anchor, canonicalTarget)\n : // Literal (wildcard-free) pattern: a deny on \"/work\" blocks deleting\n // \"/work/sub\" and blocks deleting an ancestor that contains it.\n pathsOverlap(canonicalTarget, anchor);\n if (overlaps) {\n seen.add(pattern);\n denying.push(pattern);\n }\n }\n }\n return denying;\n}\n\n/**\n * Whether `delete` should use the conservative recursive permission check.\n *\n * Falls back to the conservative check (returns `true`) when no permission\n * rules are configured, the backend cannot list, or the listing is ambiguous.\n * A non-empty `ls(target)` indicates descendants; a \"not a directory\"-style\n * error confirms a plain file. An empty, error-free listing is disambiguated\n * via the parent listing's `is_dir` flag.\n */\nasync function deleteTargetMayHaveDescendants(\n backend: BackendProtocolV2,\n target: string,\n permissionsConfigured: boolean,\n): Promise<boolean> {\n if (!permissionsConfigured) {\n return false;\n }\n if (typeof backend.ls !== \"function\") {\n return true;\n }\n\n let lsResult: LsResult;\n try {\n lsResult = await backend.ls(target);\n } catch {\n return true;\n }\n if (lsResult.error) {\n return !lsResult.error.includes(\"not a directory\");\n }\n if (lsResult.files && lsResult.files.length > 0) {\n return true;\n }\n\n // Empty, error-free listing: an exact file and an empty directory look\n // identical on flat/virtual backends. Use the parent listing's is_dir flag\n // for the target, which is consistent across backends.\n const parent = parentPath(target);\n let parentResult: LsResult;\n try {\n parentResult = await backend.ls(parent);\n } catch {\n return true;\n }\n if (parentResult.error) {\n return true;\n }\n const targetNorm = trimTrailingSlashesFs(target);\n const matches = (parentResult.files ?? []).filter(\n (entry) => trimTrailingSlashesFs(entry.path) === targetNorm,\n );\n if (matches.length === 0) {\n return true;\n }\n return matches.some((entry) => entry.is_dir === true);\n}\n\nfunction trimTrailingSlashesFs(path: string): string {\n let end = path.length;\n while (end > 1 && path[end - 1] === \"/\") end -= 1;\n return path.slice(0, end);\n}\n\nfunction parentPath(path: string): string {\n const parts = posixParts(path);\n if (parts.length <= 1) {\n return \"/\";\n }\n return `/${parts.slice(0, -1).join(\"/\")}`;\n}\n\nfunction supportsDelete(backend: { delete?: unknown }): backend is {\n delete: (filePath: string) => DeleteResult | Promise<DeleteResult>;\n} {\n return typeof backend.delete === \"function\";\n}\n\n/**\n * Filter a list of filesystem entries to those the rules permit.\n *\n * `getPath` extracts the absolute path from each entry. Entries with\n * unparsable paths are included (not silently dropped). Returns the\n * original array unchanged when `rules` is empty.\n *\n * @internal\n */\nfunction filterByPermissions<T>(\n entries: T[],\n rules: readonly FilesystemPermission[],\n operation: FilesystemOperation,\n getPath: (entry: T) => string,\n): T[] {\n if (rules.length === 0) {\n return entries;\n }\n\n return entries.filter((entry) => {\n try {\n const canonical = validatePath(getPath(entry));\n return decidePathAccess(rules, operation, canonical) !== \"deny\";\n } catch {\n return true;\n }\n });\n}\n\nexport const LS_TOOL_DESCRIPTION = context`\n Lists all files in a directory.\n\n This is useful for exploring the filesystem and finding the right file to read or edit.\n You should almost ALWAYS use this tool before using the read_file or edit_file tools.\n`;\n\nexport const READ_FILE_TOOL_DESCRIPTION = context`\n Reads a file from the filesystem. Assume any path the user provides is valid; reading a missing file returns an error.\n\n Usage:\n - By default, it reads up to ${DEFAULT_READ_LINE_LIMIT} lines starting from the beginning of the file. Use \\`offset\\`/\\`limit\\` to page through large files instead of reading them whole.\n - Results are returned with line numbers starting at \\`offset\\` + 1 (1 by default), then two spaces, then the source line. Never include these line-number prefixes when editing.\n - Lines over ${INT_FORMATTER.format(MAX_LINE_LENGTH)} characters are split with continuation markers (e.g. 5.1, 5.2); \\`limit\\` counts source lines, so continuation rows do not consume the budget.\n - Speculatively batch multiple \\`read_file\\` calls in one response when several files may be useful.\n - An empty file returns a system-reminder warning in place of contents.\n - Large tool results may be offloaded to a file; the tool message gives the path. Read that path here, paging with \\`offset\\`/\\`limit\\`.\n - Images (\\`.png\\`, \\`.jpg\\`, etc.), audio, video, and PDFs return multimodal content blocks (https://docs.langchain.com/javascript/langchain/messages#multimodal).\n - For images and PDFs, pagination via \\`offset\\`/\\`limit\\` is text-only - supply \\`file_path\\` only.\n - Always read a file before editing it.\n`;\n\nexport const WRITE_FILE_TOOL_DESCRIPTION = context`\n Writes content to a file. Creates the file if it does not exist; replaces it entirely if it does.\n\n Usage:\n - Use this tool when you intend to create a new file or replace the whole file. You do not need to read the file first.\n - Prefer to edit existing files (with the edit_file tool) over creating new ones when possible.\n`;\n\nexport const EDIT_FILE_TOOL_DESCRIPTION = context`\n Performs exact string replacements in files.\n\n Usage:\n - You must read the file before editing; this tool errors otherwise.\n - Preserve the exact indentation from the read output, and never include line-number prefixes in old_string or new_string.\n - Prefer editing an existing file over creating a new one.\n - Only use emojis if the user explicitly requests it.\n`;\n\nexport const DELETE_TOOL_DESCRIPTION = context`\n Deletes a file or directory from the filesystem.\n\n Usage:\n - Permanently removes the file or directory at the given absolute path.\n - Deleting a directory removes it and everything inside it, recursively. Prefer\n deleting a directory in one call over deleting each file individually.\n - This cannot be undone, so only delete paths you are sure are no longer needed.\n`;\n\nexport const GLOB_TOOL_DESCRIPTION = context`\n Find files matching a glob pattern, returning absolute paths.\n\n Supports \\`*\\` (any characters), \\`**\\` (any directories), \\`?\\` (single character), e.g. \\`**/*.py\\`, \\`*.txt\\`, \\`/subdir/**/*.md\\`.\n`;\n\nconst GREP_REGEX_EXECUTE_FALLBACK =\n \"\\n- If you genuinely need regex, use the execute tool with `rg '<regex>'` instead.\";\n\nfunction getGrepToolDescription(includeExecution: boolean): string {\n const executeFallback = includeExecution ? GREP_REGEX_EXECUTE_FALLBACK : \"\";\n return context`\n Search for a LITERAL text pattern across files (NOT regex).\n\n The pattern is matched verbatim: regex metacharacters are ordinary characters, not operators. To match any of several strings, run a separate grep for each; \\`grep(pattern=\"foo|bar\")\\` searches for the literal text \"foo|bar\", and \\`.*\\` or \\`\\\\.\\` match those characters literally.${executeFallback}\n\n Returns matching files or content per \\`output_mode\\`. Offloaded large tool results live under the artifacts root (\\`/large_tool_results/\\` by default); grep that directory to search them when you do not know the exact path.\n `;\n}\n\nconst EXECUTE_SEARCH_GUIDANCE = {\n both: \"You MUST avoid using search commands like find and grep. Instead use the grep, glob tools to search. \",\n grep: \"You MUST avoid using shell grep for searches. Instead use the grep tool to search text. \",\n glob: \"You MUST avoid using shell find for searches. Instead use the glob tool to find files. \",\n none: \"\",\n} as const;\n\nfunction getExecuteToolDescription(hasGrep: boolean, hasGlob: boolean): string {\n const searchGuidance = hasGrep\n ? hasGlob\n ? EXECUTE_SEARCH_GUIDANCE.both\n : EXECUTE_SEARCH_GUIDANCE.grep\n : hasGlob\n ? EXECUTE_SEARCH_GUIDANCE.glob\n : EXECUTE_SEARCH_GUIDANCE.none;\n const examples = [\n hasGlob\n ? \"- execute(command=\\\"find . -name '*.py'\\\") # Use glob tool instead\"\n : \"\",\n hasGrep\n ? \"- execute(command=\\\"grep -r 'pattern' .\\\") # Use grep tool instead\"\n : \"\",\n ].filter(Boolean);\n\n return context`\n Executes a shell command in an isolated sandbox and returns combined stdout/stderr with the exit code (truncated if very large).\n\n Usage:\n - Quote paths containing spaces (e.g. cd \"/path/with spaces\").\n - Chain commands with ';' or '&&' (use '&&' when a command depends on the previous); do not use newlines except inside quoted strings.\n - Use absolute paths and avoid \\`cd\\` so the working directory stays stable.\n - ${searchGuidance}Use read_file rather than cat/head/tail.${examples.length ? `\\n${examples.join(\"\\n\")}` : \"\"}\n\n Only available on backends implementing SandboxBackendProtocol; otherwise it returns an error.\n `;\n}\n\n/**\n * Create ls tool using backend.\n */\nfunction createLsTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"read\",\n input.path ?? \"/\",\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"ls\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const path = input.path || \"/\";\n const lsResult = await resolvedBackend.ls(path);\n\n if (lsResult.error) {\n return `Error listing files: ${lsResult.error}`;\n }\n\n const infos = filterByPermissions(\n lsResult.files ?? [],\n permissions,\n \"read\",\n (info) => info.path,\n );\n\n if (infos.length === 0) {\n return `No files found in ${path}`;\n }\n\n // Format output\n const lines: string[] = [];\n for (const info of infos) {\n if (info.is_dir) {\n lines.push(`${info.path} (directory)`);\n } else {\n const size = info.size ? ` (${info.size} bytes)` : \"\";\n lines.push(`${info.path}${size}`);\n }\n }\n\n const result = truncateIfTooLong(lines);\n\n if (Array.isArray(result)) {\n return result.join(\"\\n\");\n }\n return result;\n },\n {\n name: \"ls\",\n description: customDescription || LS_TOOL_DESCRIPTION,\n schema: z.object({\n path: z\n .string()\n .optional()\n .default(\"/\")\n .describe(\"Directory path to list (default: /)\"),\n }),\n },\n );\n}\n\n/**\n * Create read_file tool using backend.\n */\nfunction createReadFileTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n toolTokenLimitBeforeEvict: number | null;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, toolTokenLimitBeforeEvict, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"read\",\n input.file_path,\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"read_file\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const {\n file_path,\n offset: requestedOffset = DEFAULT_READ_LINE_OFFSET,\n limit: requestedLimit = DEFAULT_READ_LINE_LIMIT,\n } = input;\n const { offset, limit } = normalizeReadPagination(\n requestedOffset,\n requestedLimit,\n );\n\n const readResult = await resolvedBackend.read(file_path, offset, limit);\n if (readResult.error) {\n return [{ type: \"text\", text: `Error: ${readResult.error}` }];\n }\n\n const mimeType = readResult.mimeType ?? getMimeType(file_path);\n\n if (!isTextMimeType(mimeType)) {\n const binaryContent = readResult.content;\n if (!binaryContent) {\n return [\n {\n type: \"text\",\n text: `Error: expected binary content for '${file_path}'`,\n },\n ];\n }\n\n // Content may arrive as:\n // - Uint8Array (direct read)\n // - string (already base64)\n // - plain object with numeric keys (Uint8Array lost through serialization)\n let base64Data: string;\n if (typeof binaryContent === \"string\") {\n base64Data = binaryContent;\n } else if (ArrayBuffer.isView(binaryContent)) {\n base64Data = Buffer.from(binaryContent).toString(\"base64\");\n } else {\n const values = Object.values(binaryContent as Record<string, number>);\n base64Data = Buffer.from(new Uint8Array(values)).toString(\"base64\");\n }\n\n const sizeBytes = Math.ceil((base64Data.length * 3) / 4);\n\n if (sizeBytes > MAX_BINARY_READ_SIZE_BYTES) {\n return [\n {\n type: \"text\",\n text: `Error: file too large to read (${Math.round(sizeBytes / (1024 * 1024))}MB exceeds ${MAX_BINARY_READ_SIZE_BYTES / (1024 * 1024)}MB limit for binary files)`,\n },\n ];\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return [{ type: \"image\", mimeType, data: base64Data }];\n }\n if (mimeType.startsWith(\"audio/\")) {\n return [{ type: \"audio\", mimeType, data: base64Data }];\n }\n if (mimeType.startsWith(\"video/\")) {\n return [{ type: \"video\", mimeType, data: base64Data }];\n }\n return [{ type: \"file\", mimeType, data: base64Data }];\n }\n\n let content =\n typeof readResult.content === \"string\" ? readResult.content : \"\";\n\n // Enforce line limit on result (in case backend returns more)\n const lines = content.split(\"\\n\");\n let paginationResult = readResult;\n if (lines.length > limit) {\n content = lines.slice(0, limit).join(\"\\n\");\n if (\n limit > 0 &&\n readResult.startLine !== undefined &&\n readResult.endLine !== undefined\n ) {\n const endLine = Math.min(\n readResult.startLine + limit - 1,\n readResult.endLine,\n readResult.totalLines ?? Number.POSITIVE_INFINITY,\n );\n paginationResult = {\n ...readResult,\n endLine,\n nextOffset: endLine,\n };\n }\n }\n\n const formatted = formatContentWithLineNumbersAndBoundaries(\n content,\n paginationResult.startLine ?? offset + 1,\n );\n const output = truncatePaginatedRead(\n formatted,\n file_path,\n paginationResult,\n toolTokenLimitBeforeEvict,\n );\n\n return [{ type: \"text\", text: output }];\n },\n {\n name: \"read_file\",\n description: customDescription || READ_FILE_TOOL_DESCRIPTION,\n schema: z.preprocess(\n normalizeFilePathInput,\n z.object({\n file_path: z.string().describe(\"Absolute path to the file to read\"),\n offset: z.coerce\n .number()\n .optional()\n .default(DEFAULT_READ_LINE_OFFSET)\n .describe(\"Line offset to start reading from (0-indexed)\"),\n limit: z.coerce\n .number()\n .optional()\n .default(DEFAULT_READ_LINE_LIMIT)\n .describe(\"Maximum number of lines to read\"),\n }),\n ),\n },\n );\n}\n\n/**\n * Create write_file tool using backend.\n */\nfunction createWriteFileTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"write\",\n input.file_path,\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"write_file\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const { file_path, content } = input;\n const result = await resolvedBackend.write(file_path, content);\n\n if (result.error) {\n return result.error;\n }\n\n // If filesUpdate is present, return Command to update state\n const message = new ToolMessage({\n content: `Successfully wrote to '${file_path}'`,\n tool_call_id: runtime.toolCall?.id as string,\n name: \"write_file\",\n metadata: result.metadata,\n });\n\n if (result.filesUpdate) {\n return new Command({\n update: { files: result.filesUpdate, messages: [message] },\n });\n }\n\n return message;\n },\n {\n name: \"write_file\",\n description: customDescription || WRITE_FILE_TOOL_DESCRIPTION,\n schema: z.preprocess(\n normalizeFilePathInput,\n z.object({\n file_path: z\n .string()\n .describe(\n \"Absolute path where the file should be written. Must be absolute, not relative.\",\n ),\n content: z\n .string()\n .describe(\n \"The text content to write to the file. This parameter is required.\",\n ),\n }),\n ),\n },\n );\n}\n\n/**\n * Create edit_file tool using backend.\n */\nfunction createEditFileTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"write\",\n input.file_path,\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"edit_file\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const { file_path, old_string, new_string, replace_all = false } = input;\n const result = await resolvedBackend.edit(\n file_path,\n old_string,\n new_string,\n replace_all,\n );\n\n if (result.error) {\n return result.error;\n }\n\n const message = new ToolMessage({\n content: `Successfully replaced ${result.occurrences} occurrence(s) in '${file_path}'`,\n tool_call_id: runtime.toolCall?.id as string,\n name: \"edit_file\",\n metadata: result.metadata,\n });\n\n // If filesUpdate is present, return Command to update state\n if (result.filesUpdate) {\n return new Command({\n update: { files: result.filesUpdate, messages: [message] },\n });\n }\n\n // External storage (filesUpdate is null)\n return message;\n },\n {\n name: \"edit_file\",\n description: customDescription || EDIT_FILE_TOOL_DESCRIPTION,\n schema: z.preprocess(\n normalizeFilePathInput,\n z.object({\n file_path: z.string().describe(\"Absolute path to the file to edit\"),\n old_string: z\n .string()\n .describe(\"String to be replaced (must match exactly)\"),\n new_string: z.string().describe(\"String to replace with\"),\n replace_all: z\n .boolean()\n .optional()\n .default(false)\n .describe(\"Whether to replace all occurrences\"),\n }),\n ),\n },\n );\n}\n\n/**\n * Create delete tool using backend.\n */\nfunction createDeleteTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n let validatedPath: string;\n try {\n validatedPath = validatePath(input.file_path);\n } catch (error) {\n return toolError(runtime, \"delete\", `Error: ${getErrorMessage(error)}`);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n\n // A recursive delete removes the target and everything under it, so\n // permission is evaluated as a whole-subtree write. Probe the backend to\n // learn whether the target is a plain file (leaf) or may have\n // descendants; a confirmed leaf is resolved with first-match-wins\n // semantics (an earlier allow beats a later deny), while a possible\n // subtree blocks on any overlapping deny-write pattern regardless of\n // rule order. This drives all delete permission gating — write_file's\n // single-path checkPermission is insufficient for a recursive removal.\n const hasDescendants = await deleteTargetMayHaveDescendants(\n resolvedBackend,\n validatedPath,\n permissions.length > 0,\n );\n const denyingPatterns = findDeleteDenyPatterns(\n permissions,\n validatedPath,\n hasDescendants,\n );\n if (denyingPatterns.length > 0) {\n return toolError(\n runtime,\n \"delete\",\n `Error: permission denied for write on ${validatedPath} (matches deny rule(s): ${denyingPatterns.join(\", \")})`,\n );\n }\n\n if (!supportsDelete(resolvedBackend)) {\n return toolError(\n runtime,\n \"delete\",\n `Error: deletion is not available for '${validatedPath}'.`,\n );\n }\n\n const result: DeleteResult = await resolvedBackend.delete(validatedPath);\n if (result.error) {\n return toolError(runtime, \"delete\", result.error);\n }\n\n const message = new ToolMessage({\n content: `Deleted ${result.path ?? validatedPath}`,\n tool_call_id: runtime.toolCall?.id as string,\n name: \"delete\",\n metadata: result.metadata,\n });\n\n if (result.filesUpdate) {\n return new Command({\n update: { files: result.filesUpdate, messages: [message] },\n });\n }\n\n return message;\n },\n {\n name: \"delete\",\n description: customDescription || DELETE_TOOL_DESCRIPTION,\n schema: z.preprocess(\n normalizeFilePathInput,\n z.object({\n file_path: z\n .string()\n .describe(\n \"Absolute path to the file to delete. Must be absolute, not relative.\",\n ),\n }),\n ),\n },\n );\n}\n\n/**\n * Create glob tool using backend.\n */\nfunction createGlobTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n },\n) {\n const { customDescription, permissions } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"read\",\n input.path ?? \"/\",\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"glob\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const { pattern, path } = input;\n const globResult = await resolvedBackend.glob(pattern, path);\n\n if (globResult.error) {\n return `Error finding files: ${globResult.error}`;\n }\n\n const infos = filterByPermissions(\n globResult.files ?? [],\n permissions,\n \"read\",\n (info) => info.path,\n );\n\n if (infos.length === 0) {\n return `No files found matching pattern '${pattern}'`;\n }\n\n const paths = infos.map((info) => info.path);\n const result = truncateIfTooLong(paths);\n\n if (Array.isArray(result)) {\n return result.join(\"\\n\");\n }\n return result;\n },\n {\n name: \"glob\",\n description: customDescription || GLOB_TOOL_DESCRIPTION,\n schema: z.object({\n pattern: z\n .string()\n .describe(\n \"Glob pattern to match files (e.g., '**/*.py', '*.txt', '/subdir/**/*.md')\",\n ),\n path: z\n .string()\n .optional()\n .describe(\n \"Base directory to search from. Defaults to the backend's default root.\",\n ),\n }),\n },\n );\n}\n\n/**\n * Create grep tool using backend.\n */\nfunction createGrepTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n includeExecution: boolean;\n grepMaxCount: number | null;\n },\n) {\n const { customDescription, permissions, includeExecution, grepMaxCount } =\n options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const permissionError = checkPermission(\n permissions,\n \"read\",\n input.path ?? \"/\",\n );\n if (permissionError !== undefined) {\n return toolError(runtime, \"grep\", permissionError);\n }\n\n const resolvedBackend = await resolveBackend(backend, runtime);\n const {\n pattern,\n path = \"/\",\n glob = null,\n output_mode = \"content\",\n } = input;\n // A per-call max_count overrides the configured middleware default.\n const maxCount = input.max_count ?? grepMaxCount;\n const result = await resolvedBackend.grep(pattern, path, glob, maxCount);\n\n // If string, it's an error\n if (result.error) {\n return result.error;\n }\n\n const matches = filterByPermissions(\n result.matches ?? [],\n permissions,\n \"read\",\n (m) => m.path,\n );\n\n if (matches.length === 0) {\n return `No matches found for pattern '${pattern}'`;\n }\n\n const formatted = formatGrepMatches(matches, output_mode);\n const truncated = truncateIfTooLong(formatted);\n let content =\n typeof truncated === \"string\" ? truncated : truncated.join(\"\\n\");\n\n if (result.truncated) {\n content += `\\n\\n${GREP_TRUNCATION_NOTE}`;\n }\n return content;\n },\n {\n name: \"grep\",\n description:\n customDescription || getGrepToolDescription(includeExecution),\n schema: z.object({\n pattern: z\n .string()\n .describe(\"Literal text pattern to search for (not regex)\"),\n path: z\n .string()\n .optional()\n .default(\"/\")\n .describe(\"Base path to search from (default: /)\"),\n glob: z\n .string()\n .optional()\n .nullable()\n .default(null)\n .describe(\"Optional glob pattern to filter files (e.g., '*.py')\"),\n max_count: z.coerce\n .number()\n .int()\n .positive()\n .optional()\n .nullable()\n .default(null)\n .describe(\n \"Optional cap on the total number of matches returned across all files. \" +\n \"Leave unset to use the configured default. When the cap is hit, results \" +\n \"are truncated and a note says so; narrow the pattern or path to see the rest.\",\n ),\n output_mode: z\n .enum([\"files_with_matches\", \"content\", \"count\"])\n .optional()\n .default(\"content\")\n .describe(\n \"Output format: 'files_with_matches' lists matching file paths, 'content' shows matching lines (default), 'count' shows match counts per file\",\n ),\n }),\n },\n );\n}\n\n/**\n * Create execute tool using backend.\n */\nfunction createExecuteTool(\n backend: AnyBackendProtocol | BackendFactory,\n options: {\n customDescription: string | undefined;\n permissions: FilesystemPermission[];\n hasGrep: boolean;\n hasGlob: boolean;\n },\n) {\n const { customDescription, permissions, hasGrep, hasGlob } = options;\n return tool(\n async (input, runtime: ToolRuntime) => {\n const resolvedBackend = await resolveBackend(backend, runtime);\n\n // Runtime check - fail gracefully if not supported\n if (!isSandboxBackend(resolvedBackend)) {\n return (\n \"Error: Execution not available. This agent's backend \" +\n \"does not support command execution (SandboxBackendProtocol). \" +\n \"To use the execute tool, provide a backend that implements SandboxBackendProtocol.\"\n );\n }\n\n // Guard against factory-backed sandbox backends used with permissions.\n // The startup check skips factory backends since they can't be resolved\n // at configuration time — this catches that case at invocation.\n if (\n permissions.length > 0 &&\n !allPathsScopedToRoutes(permissions, resolvedBackend)\n ) {\n return (\n \"Error: Execution not available. Filesystem permissions cannot be \" +\n \"used with a backend that supports command execution because shell \" +\n \"commands can access any path, making path-based rules ineffective.\"\n );\n }\n\n const result = await resolvedBackend.execute(input.command);\n\n // Format output for LLM consumption\n const parts = [result.output];\n\n if (result.exitCode !== null) {\n const status = result.exitCode === 0 ? \"succeeded\" : \"failed\";\n parts.push(`\\n[Command ${status} with exit code ${result.exitCode}]`);\n }\n\n if (result.truncated) {\n parts.push(\"\\n[Output was truncated due to size limits]\");\n }\n\n return parts.join(\"\");\n },\n {\n name: \"execute\",\n description:\n customDescription || getExecuteToolDescription(hasGrep, hasGlob),\n schema: z.object({\n command: z.string().describe(\"The shell command to execute\"),\n }),\n },\n );\n}\n\n/**\n * Options for creating filesystem middleware.\n */\nexport interface FilesystemMiddlewareOptions {\n /** Backend instance or factory (default: StateBackend) */\n backend?: AnyBackendProtocol | BackendFactory;\n /** Optional filesystem-specific usage guidance. Omitted by default because tool schemas provide it. */\n systemPrompt?: string | null;\n /**\n * Optional descriptions for built-in filesystem tools.\n *\n * Keys correspond to {@link FsToolName}. Descriptions for tools that are not\n * enabled by the `tools` allowlist are ignored because those tools are not\n * exposed to the model.\n */\n customToolDescriptions?: Partial<Record<FsToolName, string>> | null;\n /**\n * Allowlist of built-in filesystem tools to expose to the model.\n *\n * - `undefined`, `null`, and `\"all\"` preserve the default behavior: every\n * filesystem tool is registered, subject to backend capability filtering.\n * - Passing an array restricts the middleware to only those tool names.\n * - `read_file` must be included in every explicit array because it is used\n * by normal file-inspection flows and by large-result recovery guidance.\n * - Backend capability checks still narrow the final visible tool set. For\n * example, `execute` is removed when the resolved backend does not support\n * command execution, even if it appears in this allowlist.\n * - User-provided non-filesystem tools are not affected by this allowlist.\n *\n *\n * @example Read/search-only filesystem access\n * ```ts\n * createFilesystemMiddleware({\n * tools: [\"read_file\", \"ls\", \"glob\", \"grep\"],\n * });\n * ```\n */\n tools?: readonly FsToolName[] | \"all\" | null;\n /** Optional token limit before evicting a tool result to the filesystem (default: 20000 tokens, ~80KB) */\n toolTokenLimitBeforeEvict?: number | null;\n /** Optional token limit before evicting a HumanMessage to the filesystem (default: 50000 tokens, ~200KB) */\n humanMessageTokenLimitBeforeEvict?: number | null;\n /**\n * Filesystem permission rules enforced on every tool call.\n *\n * Rules are evaluated in declaration order; first match wins; permissive\n * default. Applies to `ls`, `read_file`, `write_file`, `edit_file`,\n * `glob`, and `grep`.\n *\n * **Note on `execute`**: permissions are not enforced on `execute` because\n * shell commands can access any path regardless of path-based rules. Using\n * permissions with an execution-capable backend (one where `isSandboxBackend`\n * returns `true`) throws a `ConfigurationError` unless either:\n *\n * - `execute` is disabled via `tools`, or\n * - the backend is a `CompositeBackend` and every permission path is scoped to\n * a route prefix.\n *\n * When omitted or empty, all filesystem operations are permitted.\n */\n permissions?: FilesystemPermission[];\n /**\n * Default cap on the number of matches the grep tool returns (default: 1000).\n *\n * When the cap is hit, the returned matches are flagged as truncated and a\n * note tells the model to narrow the search. A per-call `max_count` tool\n * argument overrides this default. Set to `null` to disable the cap.\n */\n grepMaxCount?: number | null;\n}\n\n/**\n * Returns true only when backend exposes route prefixes (CompositeBackend) and\n * every permission path is scoped under one of them.\n */\nfunction normalizeFilesystemTools(\n tools: readonly FsToolName[] | \"all\" | null | undefined,\n): ReadonlySet<FsToolName> | null {\n if (tools == null || tools === \"all\") {\n return null;\n }\n\n const enabledTools = new Set(tools);\n if (!enabledTools.has(\"read_file\")) {\n throw new Error(\n \"read_file must be included in tools; it is required by FilesystemMiddleware\",\n );\n }\n\n return enabledTools;\n}\n\nfunction allPathsScopedToRoutes(\n permissions: FilesystemPermission[],\n backend: AnyBackendProtocol,\n): boolean {\n if (!CompositeBackend.isInstance(backend)) {\n return false;\n }\n\n const prefixes = backend.routePrefixes;\n if (prefixes.length === 0) {\n return false;\n }\n\n return permissions.every((rule) =>\n rule.paths.every((path) =>\n prefixes.some((prefix) => {\n const normalizedRoute = prefix.endsWith(\"/\") ? prefix : `${prefix}/`;\n const routeRoot = normalizedRoute.slice(0, -1);\n return path === routeRoot || path.startsWith(normalizedRoute);\n }),\n ),\n );\n}\n\n/**\n * Create middleware that provides built-in filesystem tools and optional custom\n * prompt guidance.\n *\n * By default, the middleware registers every built-in filesystem tool listed in\n * {@link FILESYSTEM_TOOL_NAMES}. Use {@link FilesystemMiddlewareOptions.tools}\n * to narrow that set for read-only, search-only, or otherwise restricted\n * agents. The allowlist only controls built-in filesystem tools; custom tools\n * from the agent or other middleware are left untouched.\n *\n * The middleware also filters tools whose backend capabilities are unavailable\n * at request time. In particular, `execute` is only visible when the resolved\n * backend supports command execution.\n *\n * @param options Filesystem middleware configuration.\n * @returns Agent middleware that contributes filesystem state, tools, prompt\n * guidance, permission checks, and large-result eviction.\n *\n * @example Read-only filesystem middleware\n * ```ts\n * const middleware = createFilesystemMiddleware({\n * tools: [\"read_file\", \"ls\", \"glob\", \"grep\"],\n * });\n * ```\n */\nexport function createFilesystemMiddleware(\n options: FilesystemMiddlewareOptions = {},\n) {\n const {\n backend = (runtime: BackendRuntime) => new StateBackend(runtime),\n systemPrompt: customSystemPrompt = null,\n customToolDescriptions = null,\n toolTokenLimitBeforeEvict = 20000,\n humanMessageTokenLimitBeforeEvict = 50000,\n permissions = [],\n tools: filesystemTools = null,\n grepMaxCount = DEFAULT_GREP_MAX_COUNT,\n } = options;\n const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);\n const executeToolEnabled =\n enabledFilesystemTools == null || enabledFilesystemTools.has(\"execute\");\n\n if (permissions.length > 0) {\n validatePermissionPaths(permissions);\n }\n\n if (\n permissions.length > 0 &&\n executeToolEnabled &&\n typeof backend !== \"function\" &&\n isSandboxBackend(backend) &&\n !allPathsScopedToRoutes(permissions, backend)\n ) {\n throw new Error(\n \"Filesystem permissions cannot be used with a backend that supports command \" +\n \"execution. Shell commands can access any path, making path-based rules \" +\n \"ineffective. Either remove permissions, use a backend without execution \" +\n \"support, or use a CompositeBackend with all permission paths scoped to a \" +\n \"route prefix.\",\n );\n }\n\n const baseSystemPrompt = customSystemPrompt ?? null;\n const configuredToolNames =\n enabledFilesystemTools ?? new Set<FsToolName>(FILESYSTEM_TOOL_NAMES);\n\n /**\n * All tools including execute\n * (execute will be filtered at runtime if backend doesn't support it)\n */\n const allToolsByName = {\n ls: createLsTool(backend, {\n customDescription: customToolDescriptions?.ls,\n permissions,\n }),\n read_file: createReadFileTool(backend, {\n customDescription: customToolDescriptions?.read_file,\n toolTokenLimitBeforeEvict,\n permissions,\n }),\n write_file: createWriteFileTool(backend, {\n customDescription: customToolDescriptions?.write_file,\n permissions,\n }),\n edit_file: createEditFileTool(backend, {\n customDescription: customToolDescriptions?.edit_file,\n permissions,\n }),\n delete: createDeleteTool(backend, {\n customDescription: customToolDescriptions?.delete,\n permissions,\n }),\n glob: createGlobTool(backend, {\n customDescription: customToolDescriptions?.glob,\n permissions,\n }),\n grep: createGrepTool(backend, {\n customDescription: customToolDescriptions?.grep,\n permissions,\n includeExecution:\n configuredToolNames.has(\"execute\") &&\n typeof backend !== \"function\" &&\n isSandboxBackend(backend),\n grepMaxCount,\n }),\n execute: createExecuteTool(backend, {\n customDescription: customToolDescriptions?.execute,\n permissions,\n hasGrep: configuredToolNames.has(\"grep\"),\n hasGlob: configuredToolNames.has(\"glob\"),\n }),\n } satisfies Record<FsToolName, unknown>;\n const allTools = FILESYSTEM_TOOL_NAMES.filter(\n (name) =>\n enabledFilesystemTools == null || enabledFilesystemTools.has(name),\n ).map((name) => allToolsByName[name]);\n // Retain the built-in delete tool instance so backend-capability filtering\n // removes only this middleware's own tool, never an unrelated caller-supplied\n // tool that happens to be named \"delete\".\n const builtInDeleteTool = allToolsByName.delete;\n\n async function processToolMessage(\n msg: ToolMessage,\n runtime: Record<string, unknown> | undefined,\n state: Record<string, unknown>,\n fallbackToolCallId?: string,\n ) {\n if (!toolTokenLimitBeforeEvict) {\n return { message: msg, filesUpdate: null };\n }\n\n if (\n msg.name &&\n TOOLS_EXCLUDED_FROM_EVICTION.includes(\n msg.name as (typeof TOOLS_EXCLUDED_FROM_EVICTION)[number],\n )\n ) {\n return { message: msg, filesUpdate: null };\n }\n\n const textContent = stringifyToolContent(msg.content);\n if (textContent.length <= toolTokenLimitBeforeEvict * NUM_CHARS_PER_TOKEN) {\n return { message: msg, filesUpdate: null };\n }\n\n const resolvedBackend = await resolveBackend(backend, {\n ...runtime,\n state,\n });\n const sanitizedId = sanitizeToolCallId(\n fallbackToolCallId || msg.tool_call_id,\n );\n const evictPath = `/large_tool_results/${sanitizedId}.txt`;\n\n const writeResult = await resolvedBackend.write(evictPath, textContent);\n\n const contentSample = createContentPreview(textContent);\n const replacementText = writeResult.error\n ? `Tool result too large, but the result could not be saved to the filesystem: ${writeResult.error}`\n : TOO_LARGE_TOOL_MSG.replace(\"{tool_call_id}\", msg.tool_call_id)\n .replace(\"{file_path}\", evictPath)\n .replace(\"{content_sample}\", contentSample);\n\n const truncatedMessage = new ToolMessage({\n content: replacementText,\n tool_call_id: msg.tool_call_id,\n name: msg.name,\n id: msg.id,\n artifact: msg.artifact,\n status: msg.status,\n metadata: msg.metadata,\n additional_kwargs: msg.additional_kwargs,\n response_metadata: msg.response_metadata,\n });\n\n return {\n message: truncatedMessage,\n filesUpdate: writeResult.error ? null : writeResult.filesUpdate,\n };\n }\n\n return createMiddleware({\n name: \"FilesystemMiddleware\",\n stateSchema: FilesystemStateSchema,\n tools: allTools,\n async beforeAgent(state) {\n if (!humanMessageTokenLimitBeforeEvict) {\n return undefined;\n }\n\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return undefined;\n }\n\n const last = messages[messages.length - 1];\n if (!HumanMessage.isInstance(last)) {\n return undefined;\n }\n\n if (last.additional_kwargs?.lc_evicted_to) {\n return undefined;\n }\n\n const contentStr = extractTextFromMessage(last);\n const threshold = NUM_CHARS_PER_TOKEN * humanMessageTokenLimitBeforeEvict;\n if (contentStr.length <= threshold) {\n return undefined;\n }\n\n const resolvedBackend = await resolveBackend(backend, {\n state: state || {},\n } as BackendRuntime);\n\n const fileId = crypto.randomUUID().replace(/-/g, \"\").slice(0, 12);\n const filePath = `/conversation_history/${fileId}`;\n const writeResult = await resolvedBackend.write(filePath, contentStr);\n\n if (writeResult.error) {\n return undefined;\n }\n\n const taggedMessage = new HumanMessage({\n content: last.content as any,\n id: last.id,\n additional_kwargs: {\n ...last.additional_kwargs,\n lc_evicted_to: filePath,\n },\n response_metadata: { ...last.response_metadata },\n });\n\n const result: Record<string, unknown> = {\n messages: [taggedMessage],\n };\n if (writeResult.filesUpdate) {\n result.files = writeResult.filesUpdate;\n }\n return result;\n },\n wrapModelCall: async (request, handler) => {\n // Check if backend supports execution\n const resolvedBackend = await resolveBackend(backend, {\n ...request.runtime,\n state: request.state,\n });\n const supportsExecution = isSandboxBackend(resolvedBackend);\n const backendSupportsDelete = supportsDelete(resolvedBackend);\n\n // Filter tools based on backend capabilities. Execution is filtered by\n // name, but delete is filtered by instance identity so that only this\n // middleware's built-in delete tool is removed when the backend cannot\n // delete — an unrelated caller-supplied tool named \"delete\" is untouched.\n let tools = request.tools;\n if (!supportsExecution || !backendSupportsDelete) {\n tools = tools.filter(\n (t: { name: string }) =>\n (supportsExecution || t.name !== \"execute\") &&\n (backendSupportsDelete || t !== builtInDeleteTool),\n );\n }\n\n // Tool schemas carry the built-in usage guidance. Preserve only explicit\n // caller guidance, rather than adding a redundant filesystem prompt.\n const newSystemMessage = baseSystemPrompt\n ? request.systemMessage.concat(baseSystemPrompt)\n : request.systemMessage;\n\n let messages = request.messages;\n if (humanMessageTokenLimitBeforeEvict && messages) {\n const hasTagged = messages.some(\n (msg: any) =>\n HumanMessage.isInstance(msg) &&\n msg.additional_kwargs?.lc_evicted_to,\n );\n if (hasTagged) {\n messages = messages.map((msg: any) => {\n if (\n HumanMessage.isInstance(msg) &&\n msg.additional_kwargs?.lc_evicted_to\n ) {\n return buildTruncatedHumanMessage(\n msg,\n msg.additional_kwargs.lc_evicted_to as string,\n );\n }\n return msg;\n });\n }\n }\n\n return handler({\n ...request,\n tools,\n messages,\n systemMessage: newSystemMessage,\n });\n },\n wrapToolCall: async (request, handler) => {\n // Return early if eviction is disabled\n if (!toolTokenLimitBeforeEvict) {\n return handler(request);\n }\n\n // Check if this tool is excluded from eviction\n const toolName = request.toolCall?.name;\n if (\n toolName &&\n TOOLS_EXCLUDED_FROM_EVICTION.includes(\n toolName as (typeof TOOLS_EXCLUDED_FROM_EVICTION)[number],\n )\n ) {\n return handler(request);\n }\n\n const result = await handler(request);\n\n if (ToolMessage.isInstance(result)) {\n const processed = await processToolMessage(\n result,\n request.runtime,\n request.state,\n request.toolCall?.id,\n );\n\n if (processed.filesUpdate) {\n return new Command({\n update: {\n files: processed.filesUpdate,\n messages: [processed.message],\n },\n });\n }\n\n return processed.message;\n }\n\n if (isCommand(result)) {\n const update = result.update as any;\n if (!update?.messages) {\n return result;\n }\n\n let hasLargeResults = false;\n const accumulatedFiles: Record<string, FileData> = update.files\n ? { ...update.files }\n : {};\n const processedMessages: ToolMessage[] = [];\n\n for (const msg of update.messages) {\n if (ToolMessage.isInstance(msg)) {\n const processed = await processToolMessage(\n msg,\n request.runtime,\n request.state,\n request.toolCall?.id,\n );\n processedMessages.push(processed.message);\n\n if (processed.filesUpdate) {\n hasLargeResults = true;\n Object.assign(accumulatedFiles, processed.filesUpdate);\n }\n } else {\n processedMessages.push(msg);\n }\n }\n\n if (hasLargeResults) {\n return new Command({\n update: {\n ...update,\n messages: processedMessages,\n files: accumulatedFiles,\n },\n });\n }\n }\n\n return result;\n },\n });\n}\n","/**\n * Summarization middleware with backend support for conversation history offloading.\n *\n * This module extends the base LangChain summarization middleware with additional\n * backend-based features for persisting conversation history before summarization.\n *\n * ## Usage\n *\n * ```typescript\n * import { createSummarizationMiddleware } from \"@anthropic/deepagents\";\n * import { FilesystemBackend } from \"@anthropic/deepagents\";\n *\n * const backend = new FilesystemBackend({ rootDir: \"/data\" });\n *\n * const middleware = createSummarizationMiddleware({\n * model: \"gpt-4o-mini\",\n * backend,\n * trigger: { type: \"fraction\", value: 0.85 },\n * keep: { type: \"fraction\", value: 0.10 },\n * });\n *\n * const agent = createDeepAgent({ middleware: [middleware] });\n * ```\n *\n * ## Storage\n *\n * Offloaded messages are stored as markdown at `/conversation_history/{thread_id}.md`.\n *\n * Each summarization event appends a new section to this file, creating a running log\n * of all evicted messages.\n *\n * ## Relationship to LangChain Summarization Middleware\n *\n * The base `summarizationMiddleware` from `langchain` provides core summarization\n * functionality. This middleware adds:\n * - Backend-based conversation history offloading\n * - Tool argument truncation for old messages\n *\n * For simple use cases without backend offloading, use `summarizationMiddleware`\n * from `langchain` directly.\n */\n\nimport { z } from \"zod\";\nimport {\n createMiddleware,\n countTokensApproximately,\n HumanMessage,\n AIMessage,\n ToolMessage,\n SystemMessage,\n BaseMessage,\n type AgentMiddleware as _AgentMiddleware,\n context,\n} from \"langchain\";\nimport { getBufferString } from \"@langchain/core/messages\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport { ContextOverflowError } from \"@langchain/core/errors\";\nimport { initChatModel } from \"langchain/chat_models/universal\";\nimport { Command } from \"@langchain/langgraph\";\n\nimport type {\n AnyBackendProtocol,\n BackendFactory,\n BackendProtocolV2,\n} from \"../backends/protocol.js\";\nimport { resolveBackend } from \"../backends/protocol.js\";\nimport type { StateBackend } from \"../backends/state.js\";\nimport type { BaseStore } from \"@langchain/langgraph-checkpoint\";\n\n// Re-export the base summarization middleware from langchain for users who don't need backend offloading\nexport { summarizationMiddleware } from \"langchain\";\n\n/**\n * import @langchain/core/messages for type inference\n */\nimport type * as _core from \"@langchain/core/messages\";\n\n/**\n * Context size specification for summarization triggers and retention policies.\n */\nexport interface ContextSize {\n /** Type of context measurement */\n type: \"messages\" | \"tokens\" | \"fraction\";\n /** Threshold value */\n value: number;\n}\n\n/**\n * Settings for truncating large tool arguments in old messages.\n */\nexport interface TruncateArgsSettings {\n /**\n * Threshold to trigger argument truncation.\n * If not provided, truncation is disabled.\n */\n trigger?: ContextSize;\n\n /**\n * Context retention policy for message truncation.\n * Defaults to keeping last 20 messages.\n */\n keep?: ContextSize;\n\n /**\n * Maximum character length for tool arguments before truncation.\n * Defaults to 2000.\n */\n maxLength?: number;\n\n /**\n * Text to replace truncated arguments with.\n * Defaults to \"...(argument truncated)\".\n */\n truncationText?: string;\n}\n\n/**\n * Options for the summarization middleware.\n */\nexport interface SummarizationMiddlewareOptions {\n /**\n * The language model to use for generating summaries.\n * Can be a model string (e.g., \"gpt-4o-mini\") or a language model instance.\n * If omitted, middleware will use the active request model.\n */\n model?: string | BaseChatModel | BaseLanguageModel;\n\n /**\n * Backend instance or factory for persisting conversation history.\n */\n backend:\n | AnyBackendProtocol\n | BackendFactory\n | ((config: { state: unknown; store?: BaseStore }) => StateBackend);\n\n /**\n * Threshold(s) that trigger summarization.\n * Can be a single ContextSize or an array for multiple triggers.\n */\n trigger?: ContextSize | ContextSize[];\n\n /**\n * Context retention policy after summarization.\n * Defaults to keeping last 20 messages.\n */\n keep?: ContextSize;\n\n /**\n * Prompt template for generating summaries.\n */\n summaryPrompt?: string;\n\n /**\n * Max tokens to include when generating a summary.\n * If omitted, the complete selected conversation is provided to the summarizer.\n */\n trimTokensToSummarize?: number;\n\n /**\n * Path prefix for storing conversation history.\n * Defaults to \"/conversation_history\".\n */\n historyPathPrefix?: string;\n\n /**\n * Settings for truncating large tool arguments in old messages.\n * If not provided, argument truncation is disabled.\n */\n truncateArgsSettings?: TruncateArgsSettings;\n}\n\n// Default values\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\n\n// Fallback defaults when model has no profile (matches Python's fallback)\nconst FALLBACK_TRIGGER: ContextSize = { type: \"tokens\", value: 170_000 };\nconst FALLBACK_KEEP: ContextSize = { type: \"messages\", value: 6 };\nconst FALLBACK_TRUNCATE_ARGS: TruncateArgsSettings = {\n trigger: { type: \"messages\", value: 20 },\n keep: { type: \"messages\", value: 20 },\n};\n\n// Profile-based defaults (when model has max_input_tokens in profile)\nconst PROFILE_TRIGGER: ContextSize = { type: \"fraction\", value: 0.85 };\nconst PROFILE_KEEP: ContextSize = { type: \"fraction\", value: 0.1 };\nconst PROFILE_TRUNCATE_ARGS: TruncateArgsSettings = {\n trigger: { type: \"fraction\", value: 0.85 },\n keep: { type: \"fraction\", value: 0.1 },\n};\n\n/**\n * Compute summarization defaults based on model profile.\n * Mirrors Python's `_compute_summarization_defaults`.\n *\n * If the model has a profile with `maxInputTokens`, uses fraction-based\n * settings. Otherwise, uses fixed token/message counts.\n *\n * @param resolvedModel - The resolved chat model instance.\n */\nexport function computeSummarizationDefaults(resolvedModel: BaseChatModel): {\n trigger: ContextSize;\n keep: ContextSize;\n truncateArgsSettings: TruncateArgsSettings;\n} {\n const hasProfile =\n resolvedModel.profile &&\n typeof resolvedModel.profile === \"object\" &&\n \"maxInputTokens\" in resolvedModel.profile &&\n typeof resolvedModel.profile.maxInputTokens === \"number\";\n\n if (hasProfile) {\n return {\n trigger: PROFILE_TRIGGER,\n keep: PROFILE_KEEP,\n truncateArgsSettings: PROFILE_TRUNCATE_ARGS,\n };\n }\n\n return {\n trigger: FALLBACK_TRIGGER,\n keep: FALLBACK_KEEP,\n truncateArgsSettings: FALLBACK_TRUNCATE_ARGS,\n };\n}\nconst DEFAULT_SUMMARY_PROMPT = `You are a conversation summarizer. Your task is to create a concise summary of the conversation that captures:\n1. The main topics discussed\n2. Key decisions or conclusions reached\n3. Any important context that would be needed for continuing the conversation\n\nKeep the summary focused and informative. Do not include unnecessary details.\n\nConversation to summarize:\n{conversation}\n\nSummary:`;\n\n/**\n * Zod schema for a summarization event that tracks what was summarized and\n * where the cutoff is.\n *\n * Instead of rewriting LangGraph state with `RemoveMessage(REMOVE_ALL_MESSAGES)`,\n * the middleware stores this event and uses it to reconstruct the effective message\n * list on subsequent calls.\n */\nconst SummarizationEventSchema = z.object({\n /**\n * The index in the state messages list where summarization occurred.\n * Messages before this index have been summarized. */\n cutoffIndex: z.number(),\n /** The HumanMessage containing the summary. */\n summaryMessage: z.instanceof(HumanMessage),\n /** Path where the conversation history was offloaded, or null if offload failed. */\n filePath: z.string().nullable(),\n});\n\n/**\n * Represents a summarization event that tracks what was summarized and where the cutoff is.\n */\nexport type SummarizationEvent = z.infer<typeof SummarizationEventSchema>;\n\n/**\n * State schema for summarization middleware.\n */\nconst SummarizationStateSchema = z.object({\n /** Session ID for history file naming */\n _summarizationSessionId: z.string().optional(),\n /** Most recent summarization event (private state, not visible to agent) */\n _summarizationEvent: SummarizationEventSchema.optional(),\n});\n\n/**\n * Check if a message is a previous summarization message.\n * Summary messages are HumanMessage objects with lc_source='summarization' in additional_kwargs.\n */\nfunction isSummaryMessage(msg: BaseMessage): boolean {\n if (!HumanMessage.isInstance(msg)) {\n return false;\n }\n return msg.additional_kwargs?.lc_source === \"summarization\";\n}\n\n/**\n * Reconstruct the effective message list based on any previous summarization event.\n *\n * After summarization, instead of using all messages from state, we use the summary\n * message plus messages after the cutoff index. This avoids full state rewrites.\n */\nexport function getEffectiveMessages(\n messages: BaseMessage[],\n state: Record<string, unknown>,\n): BaseMessage[] {\n const event = state._summarizationEvent as SummarizationEvent | undefined;\n\n // If no summarization event, return all messages as-is\n if (!event) {\n return messages;\n }\n\n // Build effective messages: summary message, then messages from cutoff onward\n const result: BaseMessage[] = [event.summaryMessage];\n result.push(...messages.slice(event.cutoffIndex));\n\n return result;\n}\n\n/**\n * Create summarization middleware with backend support for conversation history offloading.\n *\n * This middleware:\n * 1. Monitors conversation length against configured thresholds\n * 2. When triggered, offloads old messages to backend storage\n * 3. Generates a summary of offloaded messages\n * 4. Replaces old messages with the summary, preserving recent context\n *\n * @param options - Configuration options\n * @returns AgentMiddleware for summarization and history offloading\n */\nexport function createSummarizationMiddleware(\n options: SummarizationMiddlewareOptions,\n) {\n const {\n model,\n backend,\n summaryPrompt = DEFAULT_SUMMARY_PROMPT,\n trimTokensToSummarize,\n historyPathPrefix = \"/conversation_history\",\n } = options;\n\n // Mutable config that may be lazily computed from model profile.\n // When trigger/keep/truncateArgsSettings are not provided, they will be\n // computed from the model profile on first wrapModelCall, matching\n // Python's `_compute_summarization_defaults` behavior.\n let trigger = options.trigger;\n let keep: ContextSize = options.keep ?? {\n type: \"messages\",\n value: DEFAULT_MESSAGES_TO_KEEP,\n };\n let truncateArgsSettings = options.truncateArgsSettings;\n let defaultsComputed = trigger != null;\n\n // Parse truncate settings (will be re-parsed after defaults are computed)\n let truncateTrigger = truncateArgsSettings?.trigger;\n let truncateKeep: ContextSize = truncateArgsSettings?.keep ?? {\n type: \"messages\" as const,\n value: 20,\n };\n let maxArgLength = truncateArgsSettings?.maxLength ?? 2000;\n let truncationText =\n truncateArgsSettings?.truncationText ?? \"...(argument truncated)\";\n\n /**\n * Lazily compute defaults from model profile when trigger was not provided.\n * Called once when the model is first resolved.\n */\n function applyModelDefaults(resolvedModel: BaseChatModel): void {\n if (defaultsComputed) {\n return;\n }\n defaultsComputed = true;\n\n const defaults = computeSummarizationDefaults(resolvedModel);\n\n trigger = defaults.trigger;\n keep = options.keep ?? defaults.keep;\n\n if (!options.truncateArgsSettings) {\n truncateArgsSettings = defaults.truncateArgsSettings;\n truncateTrigger = defaults.truncateArgsSettings.trigger;\n truncateKeep = defaults.truncateArgsSettings.keep ?? {\n type: \"messages\" as const,\n value: 20,\n };\n maxArgLength = defaults.truncateArgsSettings.maxLength ?? 2000;\n truncationText =\n defaults.truncateArgsSettings.truncationText ??\n \"...(argument truncated)\";\n }\n }\n\n // Session ID for this middleware instance (fallback if no thread_id)\n let sessionId: string | null = null;\n\n // Calibration multiplier for token estimation. countTokensApproximately\n // can significantly undercount (e.g. it ignores tool_use content blocks,\n // JSON structural overhead). After a ContextOverflowError we learn the\n // gap between estimated and actual tokens and adjust future comparisons\n // so proactive summarization fires before the hard limit is hit.\n let tokenEstimationMultiplier = 1.0;\n\n /**\n * Get or create session ID for history file naming.\n */\n function getSessionId(state: Record<string, unknown>): string {\n if (state._summarizationSessionId) {\n return state._summarizationSessionId as string;\n }\n if (!sessionId) {\n sessionId = `session_${crypto.randomUUID().substring(0, 8)}`;\n }\n return sessionId;\n }\n\n /**\n * Get the history file path.\n */\n function getHistoryPath(state: Record<string, unknown>): string {\n const id = getSessionId(state);\n return `${historyPathPrefix}/${id}.md`;\n }\n\n /**\n * Cached resolved model to avoid repeated initChatModel calls\n */\n let cachedModel: BaseChatModel | undefined = undefined;\n\n /**\n * Resolve the chat model.\n * Uses initChatModel to support any model provider from a string name.\n * The resolved model is cached for subsequent calls.\n */\n async function getChatModel(): Promise<BaseChatModel> {\n if (cachedModel) {\n return cachedModel;\n }\n\n if (!model) {\n throw new Error(\n \"Summarization middleware could not resolve a model. Provide `options.model` or ensure `request.model` is present.\",\n );\n }\n\n if (typeof model === \"string\") {\n cachedModel = await initChatModel(model);\n } else {\n cachedModel = model as BaseChatModel;\n }\n return cachedModel;\n }\n\n /**\n * Get the max input tokens from the model's profile.\n * Similar to Python's _get_profile_limits.\n *\n * When the profile is unavailable, returns undefined. In that case the\n * middleware uses fixed token/message-count fallback defaults for\n * trigger/keep, and relies on the ContextOverflowError catch as a\n * safety net if the prompt still exceeds the model's actual limit.\n */\n function getMaxInputTokens(resolvedModel: BaseChatModel): number | undefined {\n const profile = resolvedModel.profile;\n if (\n profile &&\n typeof profile === \"object\" &&\n \"maxInputTokens\" in profile &&\n typeof profile.maxInputTokens === \"number\"\n ) {\n return profile.maxInputTokens;\n }\n return undefined;\n }\n\n /**\n * Check if summarization should be triggered.\n */\n function shouldSummarize(\n messages: BaseMessage[],\n totalTokens: number,\n maxInputTokens?: number,\n ): boolean {\n if (!trigger) {\n return false;\n }\n\n const adjustedTokens = totalTokens * tokenEstimationMultiplier;\n const triggers = Array.isArray(trigger) ? trigger : [trigger];\n\n for (const t of triggers) {\n if (t.type === \"messages\" && messages.length >= t.value) {\n return true;\n }\n if (t.type === \"tokens\" && adjustedTokens >= t.value) {\n return true;\n }\n if (t.type === \"fraction\" && maxInputTokens) {\n const threshold = Math.floor(maxInputTokens * t.value);\n if (adjustedTokens >= threshold) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Find a safe cutoff point that doesn't split AI/Tool message pairs.\n *\n * If the message at `cutoffIndex` is a ToolMessage, this adjusts the boundary\n * so that related AI and Tool messages stay together. Two strategies are used:\n *\n * 1. **Move backward** to include the AIMessage that produced the tool calls,\n * keeping the pair in the preserved set. Preferred when it doesn't move\n * the cutoff too far back.\n *\n * 2. **Advance forward** past all consecutive ToolMessages, putting the entire\n * pair into the summarized set. Used when moving backward would preserve\n * too many messages (e.g., a single AIMessage made 20+ tool calls).\n */\n function findSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number,\n ): number {\n if (\n cutoffIndex >= messages.length ||\n !ToolMessage.isInstance(messages[cutoffIndex])\n ) {\n return cutoffIndex;\n }\n\n // Advance past all consecutive ToolMessages at the cutoff point\n let forwardIdx = cutoffIndex;\n while (\n forwardIdx < messages.length &&\n ToolMessage.isInstance(messages[forwardIdx])\n ) {\n forwardIdx++;\n }\n\n // Collect tool_call_ids from the ToolMessages at the cutoff boundary\n const toolCallIds = new Set<string>();\n for (let i = cutoffIndex; i < forwardIdx; i++) {\n const toolMsg = messages[i] as InstanceType<typeof ToolMessage>;\n if (toolMsg.tool_call_id) {\n toolCallIds.add(toolMsg.tool_call_id);\n }\n }\n\n // Search backward for AIMessage with matching tool_calls\n let backwardIdx: number | null = null;\n for (let i = cutoffIndex - 1; i >= 0; i--) {\n const msg = messages[i];\n if (AIMessage.isInstance(msg) && msg.tool_calls) {\n const aiToolCallIds = new Set(\n msg.tool_calls\n .map((tc) => tc.id)\n .filter((id): id is string => id != null),\n );\n for (const id of toolCallIds) {\n if (aiToolCallIds.has(id)) {\n backwardIdx = i;\n break;\n }\n }\n if (backwardIdx !== null) break;\n }\n }\n\n if (backwardIdx === null) {\n // No matching AIMessage found - advance forward past ToolMessages\n return forwardIdx;\n }\n\n // Choose strategy: prefer backward (preserves more context) unless it\n // would move the cutoff back by more than half the original position,\n // which indicates a single AIMessage with many tool calls that would\n // defeat the purpose of summarization.\n const backwardDistance = cutoffIndex - backwardIdx;\n if (backwardDistance > cutoffIndex / 2 && cutoffIndex > 2) {\n return forwardIdx;\n }\n\n return backwardIdx;\n }\n\n /**\n * Determine cutoff index for messages to summarize.\n * Messages at index < cutoff will be summarized.\n * Messages at index >= cutoff will be preserved.\n *\n * Uses findSafeCutoffPoint to ensure tool call/result pairs stay together.\n */\n function determineCutoffIndex(\n messages: BaseMessage[],\n maxInputTokens?: number,\n ): number {\n let rawCutoff: number;\n\n if (keep.type === \"messages\") {\n if (messages.length <= keep.value) {\n return 0;\n }\n rawCutoff = messages.length - keep.value;\n } else if (keep.type === \"tokens\" || keep.type === \"fraction\") {\n const targetTokenCount =\n keep.type === \"fraction\" && maxInputTokens\n ? Math.floor(maxInputTokens * keep.value)\n : keep.value;\n\n let tokensKept = 0;\n rawCutoff = 0;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msgTokens = countTokensApproximately([messages[i]]);\n if (tokensKept + msgTokens > targetTokenCount) {\n rawCutoff = i + 1;\n break;\n }\n tokensKept += msgTokens;\n }\n } else {\n return 0;\n }\n\n return findSafeCutoffPoint(messages, rawCutoff);\n }\n\n /**\n * Check if argument truncation should be triggered.\n */\n function shouldTruncateArgs(\n messages: BaseMessage[],\n totalTokens: number,\n maxInputTokens?: number,\n ): boolean {\n if (!truncateTrigger) {\n return false;\n }\n\n const adjustedTokens = totalTokens * tokenEstimationMultiplier;\n if (truncateTrigger.type === \"messages\") {\n return messages.length >= truncateTrigger.value;\n }\n if (truncateTrigger.type === \"tokens\") {\n return adjustedTokens >= truncateTrigger.value;\n }\n if (truncateTrigger.type === \"fraction\" && maxInputTokens) {\n const threshold = Math.floor(maxInputTokens * truncateTrigger.value);\n return adjustedTokens >= threshold;\n }\n\n return false;\n }\n\n /**\n * Determine cutoff index for argument truncation.\n * Uses findSafeCutoffPoint to ensure tool call/result pairs stay together.\n */\n function determineTruncateCutoffIndex(\n messages: BaseMessage[],\n maxInputTokens?: number,\n ): number {\n let rawCutoff: number;\n\n if (truncateKeep.type === \"messages\") {\n if (messages.length <= truncateKeep.value) {\n return messages.length;\n }\n rawCutoff = messages.length - truncateKeep.value;\n } else if (\n truncateKeep.type === \"tokens\" ||\n truncateKeep.type === \"fraction\"\n ) {\n const targetTokenCount =\n truncateKeep.type === \"fraction\" && maxInputTokens\n ? Math.floor(maxInputTokens * truncateKeep.value)\n : truncateKeep.value;\n\n let tokensKept = 0;\n rawCutoff = 0;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msgTokens = countTokensApproximately([messages[i]]);\n if (tokensKept + msgTokens > targetTokenCount) {\n rawCutoff = i + 1;\n break;\n }\n tokensKept += msgTokens;\n }\n } else {\n return messages.length;\n }\n\n return findSafeCutoffPoint(messages, rawCutoff);\n }\n\n /**\n * Count tokens including system message and tools, matching Python's approach.\n * This gives a more accurate picture of what actually gets sent to the model.\n */\n function countTotalTokens(\n messages: BaseMessage[],\n systemMessage?: SystemMessage | unknown,\n tools?: (ServerTool | ClientTool)[] | unknown[],\n ): number {\n const countedMessages: BaseMessage[] =\n systemMessage && SystemMessage.isInstance(systemMessage)\n ? [systemMessage as SystemMessage, ...messages]\n : [...messages];\n\n const toolsArray =\n tools && Array.isArray(tools) && tools.length > 0\n ? (tools as Array<Record<string, unknown>>)\n : null;\n\n return countTokensApproximately(countedMessages, toolsArray);\n }\n\n /**\n * Truncate ToolMessage content so that the total payload fits within the\n * model's context window. Each ToolMessage gets an equal share of the\n * remaining token budget after accounting for non-tool messages, system\n * message, and tool schemas.\n *\n * This is critical for conversations where a single AIMessage triggers\n * many tool calls whose results collectively exceed the context window.\n * Without this, findSafeCutoffPoint cannot split the AI/Tool group and\n * summarization would discard everything, causing the model to re-call\n * the same tools in an infinite loop.\n */\n function compactToolResults(\n messages: BaseMessage[],\n maxInputTokens: number,\n systemMessage?: SystemMessage | unknown,\n tools?: (ServerTool | ClientTool)[] | unknown[],\n ): { messages: BaseMessage[]; modified: boolean } {\n const toolMessageIndices: number[] = [];\n for (let i = 0; i < messages.length; i++) {\n if (ToolMessage.isInstance(messages[i])) {\n toolMessageIndices.push(i);\n }\n }\n if (toolMessageIndices.length === 0) {\n return { messages, modified: false };\n }\n\n const nonToolMessages = messages.filter((m) => !ToolMessage.isInstance(m));\n const overheadTokens = countTotalTokens(\n nonToolMessages,\n systemMessage,\n tools,\n );\n\n // Target: fit within maxInputTokens / multiplier, leaving 30% headroom\n const adjustedMax = maxInputTokens / tokenEstimationMultiplier;\n const budgetForTools = Math.max(adjustedMax * 0.7 - overheadTokens, 1000);\n const perToolBudgetTokens = Math.floor(\n budgetForTools / toolMessageIndices.length,\n );\n const perToolBudgetChars = perToolBudgetTokens * 4;\n\n let modified = false;\n const result = [...messages];\n\n for (const idx of toolMessageIndices) {\n const msg = messages[idx] as InstanceType<typeof ToolMessage>;\n const content =\n typeof msg.content === \"string\"\n ? msg.content\n : JSON.stringify(msg.content);\n\n if (content.length > perToolBudgetChars) {\n result[idx] = new ToolMessage({\n content:\n content.substring(0, perToolBudgetChars) +\n \"\\n...(result truncated)\",\n tool_call_id: msg.tool_call_id,\n name: msg.name,\n });\n modified = true;\n }\n }\n\n return { messages: result, modified };\n }\n\n /**\n * Truncate large tool arguments in old messages.\n */\n function truncateArgs(\n messages: BaseMessage[],\n maxInputTokens?: number,\n systemMessage?: SystemMessage | unknown,\n tools?: (ServerTool | ClientTool)[] | unknown[],\n options?: { totalTokens?: number },\n ): { messages: BaseMessage[]; modified: boolean } {\n const totalTokens =\n options?.totalTokens ?? countTotalTokens(messages, systemMessage, tools);\n if (!shouldTruncateArgs(messages, totalTokens, maxInputTokens)) {\n return { messages, modified: false };\n }\n\n const cutoffIndex = determineTruncateCutoffIndex(messages, maxInputTokens);\n if (cutoffIndex >= messages.length) {\n return { messages, modified: false };\n }\n\n const truncatedMessages: BaseMessage[] = [];\n let modified = false;\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n\n if (i < cutoffIndex && AIMessage.isInstance(msg) && msg.tool_calls) {\n const truncatedToolCalls = msg.tool_calls.map((toolCall) => {\n const args = toolCall.args || {};\n const truncatedArgs: Record<string, unknown> = {};\n let toolModified = false;\n\n for (const [key, value] of Object.entries(args)) {\n if (\n typeof value === \"string\" &&\n value.length > maxArgLength &&\n (toolCall.name === \"write_file\" || toolCall.name === \"edit_file\")\n ) {\n truncatedArgs[key] = value.substring(0, 20) + truncationText;\n toolModified = true;\n } else {\n truncatedArgs[key] = value;\n }\n }\n\n if (toolModified) {\n modified = true;\n return { ...toolCall, args: truncatedArgs };\n }\n return toolCall;\n });\n\n if (modified) {\n const truncatedMsg = new AIMessage({\n content: msg.content,\n tool_calls: truncatedToolCalls,\n additional_kwargs: msg.additional_kwargs,\n });\n truncatedMessages.push(truncatedMsg);\n } else {\n truncatedMessages.push(msg);\n }\n } else {\n truncatedMessages.push(msg);\n }\n }\n\n return { messages: truncatedMessages, modified };\n }\n\n /**\n * Filter out previous summary messages.\n */\n function filterSummaryMessages(messages: BaseMessage[]): BaseMessage[] {\n return messages.filter((msg) => !isSummaryMessage(msg));\n }\n\n /**\n * Offload messages to backend by appending to the history file.\n *\n * Uses uploadFiles() directly with raw byte concatenation instead of\n * edit() to avoid downloading the file twice and performing a full\n * string search-and-replace. This keeps peak memory at ~2x file size\n * (existing bytes + combined bytes) instead of ~6x with the old\n * download → edit(oldContent, newContent) approach.\n */\n async function offloadToBackend(\n resolvedBackend: BackendProtocolV2,\n messages: BaseMessage[],\n state: Record<string, unknown>,\n ): Promise<string | null> {\n const filePath = getHistoryPath(state);\n const filteredMessages = filterSummaryMessages(messages);\n\n const timestamp = new Date().toISOString();\n const newSection = `## Summarized at ${timestamp}\\n\\n${getBufferString(filteredMessages)}\\n\\n`;\n const sectionBytes = new TextEncoder().encode(newSection);\n\n try {\n // Read existing content as raw bytes (no string decode needed)\n let existingBytes: Uint8Array | null = null;\n if (resolvedBackend.downloadFiles) {\n try {\n const responses = await resolvedBackend.downloadFiles([filePath]);\n if (\n responses.length > 0 &&\n responses[0].content &&\n !responses[0].error\n ) {\n existingBytes = responses[0].content;\n }\n } catch {\n // File doesn't exist yet, that's fine\n }\n }\n\n let result: { error?: string; path?: string };\n if (existingBytes && resolvedBackend.uploadFiles) {\n // Append: concatenate raw bytes and upload directly\n const combined = new Uint8Array(\n existingBytes.byteLength + sectionBytes.byteLength,\n );\n combined.set(existingBytes, 0);\n combined.set(sectionBytes, existingBytes.byteLength);\n\n const uploadResults = await resolvedBackend.uploadFiles([\n [filePath, combined],\n ]);\n result = uploadResults[0].error\n ? { error: uploadResults[0].error }\n : { path: filePath };\n } else if (!existingBytes) {\n result = await resolvedBackend.write(filePath, newSection);\n } else {\n // Fallback: uploadFiles unavailable, use edit()\n const existingContent = new TextDecoder().decode(existingBytes);\n result = await resolvedBackend.edit(\n filePath,\n existingContent,\n existingContent + newSection,\n );\n }\n\n if (result.error) {\n // oxlint-disable-next-line no-console\n console.warn(\n `Failed to offload conversation history to ${filePath}: ${result.error}`,\n );\n return null;\n }\n\n return filePath;\n } catch (e) {\n // oxlint-disable-next-line no-console\n console.warn(\n `Exception offloading conversation history to ${filePath}:`,\n e,\n );\n return null;\n }\n }\n\n /**\n * Create summary of messages.\n */\n async function createSummary(\n messages: BaseMessage[],\n chatModel: BaseChatModel,\n ): Promise<string> {\n // Trim messages if too long\n let messagesToSummarize = messages;\n const tokens = countTokensApproximately(messages);\n if (trimTokensToSummarize !== undefined && tokens > trimTokensToSummarize) {\n // Keep only recent messages that fit\n let kept = 0;\n const trimmedMessages: BaseMessage[] = [];\n for (let i = messages.length - 1; i >= 0; i--) {\n const msgTokens = countTokensApproximately([messages[i]]);\n if (kept + msgTokens > trimTokensToSummarize) {\n break;\n }\n trimmedMessages.unshift(messages[i]);\n kept += msgTokens;\n }\n messagesToSummarize = trimmedMessages;\n }\n\n const conversation = getBufferString(messagesToSummarize);\n const prompt = summaryPrompt.replace(\"{conversation}\", conversation);\n\n const response = await chatModel.invoke([\n new HumanMessage({ content: prompt }),\n ]);\n\n return response.text;\n }\n\n /**\n * Build the summary message with file path reference.\n */\n function buildSummaryMessage(\n summary: string,\n filePath: string | null,\n ): HumanMessage {\n let content: string;\n if (filePath) {\n content = context`\n You are in the middle of a conversation that has been summarized.\n\n The full conversation history has been saved to ${filePath} should you need to refer back to it for details.\n\n A condensed summary follows:\n\n <summary>\n ${summary}\n </summary>\n `;\n } else {\n content = `Here is a summary of the conversation to date:\\n\\n${summary}`;\n }\n\n return new HumanMessage({\n content,\n additional_kwargs: { lc_source: \"summarization\" },\n });\n }\n\n /**\n * Summarize a set of messages using the given model and build the\n * summary message + backend offload. Returns the summary message,\n * the file path, and the state cutoff index.\n */\n async function summarizeMessages(\n messagesToSummarize: BaseMessage[],\n resolvedModel: BaseChatModel,\n state: Record<string, unknown>,\n previousCutoffIndex: number | undefined,\n cutoffIndex: number,\n ): Promise<{\n summaryMessage: HumanMessage;\n filePath: string | null;\n stateCutoffIndex: number;\n }> {\n const resolvedBackend = await resolveBackend(backend, { state });\n const filePath = await offloadToBackend(\n resolvedBackend,\n messagesToSummarize,\n state,\n );\n\n if (filePath === null) {\n // oxlint-disable-next-line no-console\n console.warn(\n `[SummarizationMiddleware] Backend offload failed during summarization. Proceeding with summary generation.`,\n );\n }\n\n const summary = await createSummary(messagesToSummarize, resolvedModel);\n const summaryMessage = buildSummaryMessage(summary, filePath);\n\n const stateCutoffIndex =\n previousCutoffIndex != null\n ? previousCutoffIndex + cutoffIndex - 1\n : cutoffIndex;\n\n return { summaryMessage, filePath, stateCutoffIndex };\n }\n\n /**\n * Check if an error (possibly wrapped in MiddlewareError layers) is a\n * ContextOverflowError by walking the `cause` chain.\n */\n function isContextOverflow(err: unknown): boolean {\n let cause: unknown = err;\n for (;;) {\n if (!cause) {\n break;\n }\n if (ContextOverflowError.isInstance(cause)) {\n return true;\n }\n cause =\n typeof cause === \"object\" && \"cause\" in cause\n ? (cause as { cause?: unknown }).cause\n : undefined;\n }\n return false;\n }\n\n async function performSummarization(\n request: {\n messages: BaseMessage[];\n state: Record<string, unknown>;\n systemMessage?: SystemMessage | unknown;\n tools?: (ServerTool | ClientTool)[] | unknown[];\n [key: string]: unknown;\n },\n handler: (req: any) => any,\n truncatedMessages: BaseMessage[],\n resolvedModel: BaseChatModel,\n maxInputTokens: number | undefined,\n ): Promise<any> {\n const cutoffIndex = determineCutoffIndex(truncatedMessages, maxInputTokens);\n if (cutoffIndex <= 0) {\n return handler({ ...request, messages: truncatedMessages });\n }\n\n const messagesToSummarize = truncatedMessages.slice(0, cutoffIndex);\n const preservedMessages = truncatedMessages.slice(cutoffIndex);\n\n // When ALL messages would be summarized (preserving 0), the model loses\n // all tool call context and re-invokes the same tools, creating an\n // infinite loop. Instead, try truncating ToolMessage content so the\n // entire AI/Tool group fits in context without summarization.\n if (preservedMessages.length === 0 && maxInputTokens) {\n const compact = compactToolResults(\n truncatedMessages,\n maxInputTokens,\n request.systemMessage,\n request.tools,\n );\n\n if (compact.modified) {\n try {\n return await handler({\n ...request,\n messages: compact.messages,\n });\n } catch (err: unknown) {\n if (!isContextOverflow(err)) {\n throw err;\n }\n }\n }\n }\n\n const previousEvent = request.state._summarizationEvent;\n const previousCutoffIndex =\n previousEvent != null\n ? (previousEvent as SummarizationEvent).cutoffIndex\n : undefined;\n\n const { summaryMessage, filePath, stateCutoffIndex } =\n await summarizeMessages(\n messagesToSummarize,\n resolvedModel,\n request.state,\n previousCutoffIndex,\n cutoffIndex,\n );\n\n let modifiedMessages = [summaryMessage, ...preservedMessages];\n const modifiedTokens = countTotalTokens(\n modifiedMessages,\n request.systemMessage,\n request.tools,\n );\n\n let finalStateCutoffIndex = stateCutoffIndex;\n let finalSummaryMessage = summaryMessage;\n let finalFilePath = filePath;\n\n try {\n await handler({ ...request, messages: modifiedMessages });\n } catch (err: unknown) {\n if (!isContextOverflow(err)) {\n throw err;\n }\n\n if (maxInputTokens && modifiedTokens > 0) {\n const observedRatio = maxInputTokens / modifiedTokens;\n if (observedRatio > tokenEstimationMultiplier) {\n tokenEstimationMultiplier = observedRatio * 1.1;\n }\n }\n\n const allMessages = [...messagesToSummarize, ...preservedMessages];\n const reSumResult = await summarizeMessages(\n allMessages,\n resolvedModel,\n request.state,\n previousCutoffIndex,\n truncatedMessages.length,\n );\n\n finalSummaryMessage = reSumResult.summaryMessage;\n finalFilePath = reSumResult.filePath;\n finalStateCutoffIndex = reSumResult.stateCutoffIndex;\n\n modifiedMessages = [reSumResult.summaryMessage];\n\n await handler({ ...request, messages: modifiedMessages });\n }\n\n return new Command({\n update: {\n _summarizationEvent: {\n cutoffIndex: finalStateCutoffIndex,\n summaryMessage: finalSummaryMessage,\n filePath: finalFilePath,\n } satisfies SummarizationEvent,\n _summarizationSessionId: getSessionId(request.state),\n },\n });\n }\n\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n stateSchema: SummarizationStateSchema,\n\n async wrapModelCall(request, handler) {\n // Get effective messages based on previous summarization events\n const effectiveMessages = getEffectiveMessages(\n request.messages ?? [],\n request.state,\n );\n\n if (effectiveMessages.length === 0) {\n return handler(request);\n }\n\n const requestModel = request.model as BaseChatModel | undefined;\n\n /**\n * Resolve the chat model and get max input tokens from its profile.\n */\n const resolvedModel = requestModel ?? (await getChatModel());\n const maxInputTokens = getMaxInputTokens(resolvedModel);\n applyModelDefaults(resolvedModel);\n\n const totalTokens = countTotalTokens(\n effectiveMessages,\n request.systemMessage,\n request.tools,\n );\n\n /**\n * Step 1: Truncate args if configured\n */\n const { messages: truncatedMessages, modified: truncateModified } =\n truncateArgs(\n effectiveMessages,\n maxInputTokens,\n request.systemMessage,\n request.tools,\n { totalTokens },\n );\n\n /**\n * Step 2: Check if summarization should happen.\n * Recount only if truncation changed messages.\n */\n const tokensForSummary = truncateModified\n ? countTotalTokens(\n truncatedMessages,\n request.systemMessage,\n request.tools,\n )\n : totalTokens;\n\n const shouldDoSummarization = shouldSummarize(\n truncatedMessages,\n tokensForSummary,\n maxInputTokens,\n );\n\n /**\n * If no summarization needed, try passing through.\n * If the handler throws a ContextOverflowError, fall back to\n * emergency summarization (matching Python's behavior).\n */\n if (!shouldDoSummarization) {\n try {\n return await handler({\n ...request,\n messages: truncatedMessages,\n });\n } catch (err: unknown) {\n if (!isContextOverflow(err)) {\n throw err;\n }\n\n if (maxInputTokens && tokensForSummary > 0) {\n const observedRatio = maxInputTokens / tokensForSummary;\n if (observedRatio > tokenEstimationMultiplier) {\n tokenEstimationMultiplier = observedRatio * 1.1;\n }\n }\n // Fall through to summarization below\n }\n }\n\n /**\n * Step 3: Perform summarization\n */\n return performSummarization(\n request as any,\n handler,\n truncatedMessages,\n resolvedModel,\n maxInputTokens,\n );\n },\n });\n}\n","/**\n * Utility functions for middleware.\n *\n * This module provides shared helpers used across middleware implementations.\n */\n\nimport { SystemMessage } from \"@langchain/core/messages\";\nimport type { AgentMiddleware } from \"langchain\";\n\n/**\n * Merge custom middleware into an assembled stack by `.name`.\n *\n * Matching custom middleware replaces the existing entry in place. New\n * middleware is appended after the base stack in caller-provided order.\n */\nexport function mergeMiddleware(\n base: readonly AgentMiddleware[],\n custom: readonly AgentMiddleware[],\n): AgentMiddleware[] {\n const merged = new Map(\n base.map((middleware) => [middleware.name, middleware]),\n );\n for (const middleware of custom) {\n merged.set(middleware.name, middleware);\n }\n return [...merged.values()];\n}\n\nfunction middlewareNames(middleware: readonly AgentMiddleware[]): Set<string> {\n return new Set(middleware.map((entry) => entry.name));\n}\n\nfunction matchingMiddleware(\n middleware: readonly AgentMiddleware[],\n names: ReadonlySet<string>,\n): AgentMiddleware[] {\n return middleware.filter((entry) => names.has(entry.name));\n}\n\n/**\n * Merge custom middleware into default and tail middleware segments.\n *\n * Same-name custom entries replace matching defaults in either segment. Novel\n * custom entries are inserted between the default and tail segments unless\n * `appendNew` is false.\n */\nexport function mergeMiddlewareStack(\n defaultMiddleware: readonly AgentMiddleware[],\n customMiddleware: readonly AgentMiddleware[],\n tailMiddleware: readonly AgentMiddleware[] = [],\n options: { appendNew?: boolean } = {},\n): AgentMiddleware[] {\n const defaultMiddlewareNames = middlewareNames(defaultMiddleware);\n const tailMiddlewareNames = middlewareNames(tailMiddleware);\n const knownMiddlewareNames = new Set([\n ...defaultMiddlewareNames,\n ...tailMiddlewareNames,\n ]);\n const novelMiddleware =\n options.appendNew === false\n ? []\n : customMiddleware.filter(\n (entry) => !knownMiddlewareNames.has(entry.name),\n );\n\n return [\n ...mergeMiddleware(\n defaultMiddleware,\n matchingMiddleware(customMiddleware, defaultMiddlewareNames),\n ),\n ...novelMiddleware,\n ...mergeMiddleware(\n tailMiddleware,\n matchingMiddleware(customMiddleware, tailMiddlewareNames),\n ),\n ];\n}\n\n/**\n * Append text to a system message.\n *\n * Creates a new SystemMessage with the text appended to the existing content.\n * If the original message has content, the new text is separated by two newlines.\n *\n * @param systemMessage - Existing system message or null/undefined.\n * @param text - Text to add to the system message.\n * @returns New SystemMessage with the text appended.\n *\n * @example\n * ```typescript\n * const original = new SystemMessage({ content: \"You are a helpful assistant.\" });\n * const updated = appendToSystemMessage(original, \"Always be concise.\");\n * // Result: SystemMessage with content \"You are a helpful assistant.\\n\\nAlways be concise.\"\n * ```\n */\nexport function appendToSystemMessage(\n systemMessage: SystemMessage | null | undefined,\n text: string,\n): SystemMessage {\n if (!systemMessage) {\n return new SystemMessage({ content: text });\n }\n\n // Handle both string and array content formats\n const existingContent = systemMessage.content;\n\n if (typeof existingContent === \"string\") {\n const newContent = existingContent ? `${existingContent}\\n\\n${text}` : text;\n return new SystemMessage({ content: newContent });\n }\n\n // For array content (content blocks), append as a new text block\n if (Array.isArray(existingContent)) {\n const newContent = [...existingContent];\n const textToAdd = newContent.length > 0 ? `\\n\\n${text}` : text;\n newContent.push({ type: \"text\", text: textToAdd });\n return new SystemMessage({ content: newContent });\n }\n\n // Fallback for unknown content type\n return new SystemMessage({ content: text });\n}\n\n/**\n * Prepend text to a system message.\n *\n * Creates a new SystemMessage with the text prepended to the existing content.\n * If the original message has content, the new text is separated by two newlines.\n *\n * @param systemMessage - Existing system message or null/undefined.\n * @param text - Text to prepend to the system message.\n * @returns New SystemMessage with the text prepended.\n *\n * @example\n * ```typescript\n * const original = new SystemMessage({ content: \"Always be concise.\" });\n * const updated = prependToSystemMessage(original, \"You are a helpful assistant.\");\n * // Result: SystemMessage with content \"You are a helpful assistant.\\n\\nAlways be concise.\"\n * ```\n */\nexport function prependToSystemMessage(\n systemMessage: SystemMessage | null | undefined,\n text: string,\n): SystemMessage {\n if (!systemMessage) {\n return new SystemMessage({ content: text });\n }\n\n // Handle both string and array content formats\n const existingContent = systemMessage.content;\n\n if (typeof existingContent === \"string\") {\n const newContent = existingContent ? `${text}\\n\\n${existingContent}` : text;\n return new SystemMessage({ content: newContent });\n }\n\n // For array content (content blocks), prepend as a new text block\n if (Array.isArray(existingContent)) {\n const textToAdd = existingContent.length > 0 ? `${text}\\n\\n` : text;\n const newContent = [{ type: \"text\", text: textToAdd }, ...existingContent];\n return new SystemMessage({ content: newContent });\n }\n\n // Fallback for unknown content type\n return new SystemMessage({ content: text });\n}\n","import { z } from \"zod/v4\";\n\nimport {\n createMiddleware,\n createAgent,\n AgentMiddleware,\n tool,\n ToolMessage,\n humanInTheLoopMiddleware,\n SystemMessage,\n type ContentBlock,\n type BaseMessage,\n type InterruptOnConfig,\n type ReactAgent,\n type CreateAgentParams,\n StructuredTool,\n context,\n} from \"langchain\";\nimport { Command, getCurrentTaskInput } from \"@langchain/langgraph\";\nimport type { LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport type { Runnable } from \"@langchain/core/runnables\";\nimport { AIMessage, HumanMessage } from \"@langchain/core/messages\";\nimport { FilesystemPermission } from \"../permissions/types.js\";\nimport { getEffectiveMessages } from \"./summarization.js\";\nimport { appendToSystemMessage } from \"./utils.js\";\n\nexport type { AgentMiddleware };\n\n/**\n * Config key used by task-tool callers to request dynamic response format.\n *\n * When set in `config.configurable`, the task tool recompiles the target\n * subagent with this response format instead of using the pre-compiled graph.\n */\nexport const SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY =\n \"__deepagents_subagent_response_format\";\n\n/**\n * Default system prompt for subagents.\n * Provides a minimal base prompt that can be extended by specific subagent configurations.\n */\nexport const DEFAULT_SUBAGENT_PROMPT =\n \"In order to complete the objective that the user asks of you, you have access to a number of standard tools.\";\n\n// Marks a fork's own state so the task tool can refuse recursive delegation.\nconst FORKED_CONTEXT_KEY = \"_deepagentsForkedContext\";\n\nconst FORK_RECURSION_REFUSAL =\n \"You are a subagent and cannot delegate to another subagent. Complete this task yourself instead of calling this tool again.\";\n\n/**\n * State keys excluded when passing state to subagents and when returning\n * updates from subagents. Summarization keys are excluded because their\n * cutoffIndex is only valid against the message list it was computed from.\n */\nconst EXCLUDED_STATE_KEYS = [\n \"messages\",\n \"todos\",\n \"structuredResponse\",\n \"skillsMetadata\",\n \"memoryContents\",\n \"_summarizationEvent\",\n \"_summarizationSessionId\",\n FORKED_CONTEXT_KEY,\n] as const;\n\n/**\n * State keys excluded when inheriting state into a declarative fork.\n * Narrower than `EXCLUDED_STATE_KEYS`: a fork's mirrored middleware needs\n * the parent's private channels (skills metadata, memory contents, etc.)\n * to rebuild an equivalent prompt.\n */\nconst FORK_EXCLUDED_STATE_KEYS = [\n \"structuredResponse\",\n \"_summarizationEvent\",\n \"_summarizationSessionId\",\n] as const;\n\n/**\n * Default description for the general-purpose subagent.\n * This description is shown to the model when selecting which subagent to use.\n */\nexport const DEFAULT_GENERAL_PURPOSE_DESCRIPTION =\n \"General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.\";\n\nfunction getTaskToolDescription(subagentDescriptions: string[]): string {\n return context`\n Launch an ephemeral subagent to handle a complex, multi-step task.\n\n Available agent types and the tools they have access to:\n ${subagentDescriptions.join(\"\\n\")}\n\n Specify subagent_type to select the agent. Usage notes:\n - Launch multiple agents concurrently when their tasks are independent, using a single message with multiple tool calls.\n - Each invocation is stateless by default: the agent sees only the prompt you give it and returns a single final report. Put full detail in the prompt and state exactly what it should return — unless an agent type below says it inherits your conversation instead.\n - The agent's report is not shown to the user; relay a summary yourself.\n - Tell the agent whether to create content, analyze, or only research, since it can't necessarily see the user's intent unless it inherits your conversation, as noted per agent type below.\n - If an agent's description says to use it proactively, do so without waiting to be asked.\n - When only general-purpose is available, use it for any complex, context-heavy task; it has the same capabilities as the main agent.\n `;\n}\n\nconst FORKED_SUBAGENT_TOOL_NOTE =\n \" (inherits your full conversation and system prompt — no need to restate context here)\";\n\n// A compiled fork's runnable owns its own system prompt (see CompiledSubAgent.mode).\nconst COMPILED_FORKED_SUBAGENT_TOOL_NOTE =\n \" (inherits your conversation history — its system prompt is fixed in its own runnable)\";\n\n/** Render one subagent's listing line for the task tool description. */\nfunction describeSubagentForTool(\n name: string,\n description: string,\n forked: boolean,\n compiled = false,\n): string {\n const suffix = forked\n ? compiled\n ? COMPILED_FORKED_SUBAGENT_TOOL_NOTE\n : FORKED_SUBAGENT_TOOL_NOTE\n : \"\";\n return `- ${name}: ${description}${suffix}`;\n}\n\nconst FORK_TASK_PREAMBLE =\n \"[The messages above are a prior conversation you are continuing as the \" +\n \"subagent that was just invoked. Any mention in them of delegating to a \" +\n \"subagent already happened — you are that subagent, not the one being \" +\n \"asked to delegate further. If you try to delegate to another subagent \" +\n \"yourself, it will be refused — complete this task directly. Use the \" +\n \"specific facts, figures, and identifiers already established in that \" +\n \"conversation when completing the task below — do not answer \" +\n \"generically when exact details are already available above. Your \" +\n \"actual task is below.]\\n\\n\";\n\n/**\n * Type definitions for pre-compiled agents.\n *\n * @typeParam TRunnable - The type of the runnable (ReactAgent or Runnable).\n * When using `createAgent` or `createDeepAgent`, this preserves the middleware\n * types for type inference. Uses `ReactAgent<any>` to accept agents with any\n * type configuration (including DeepAgent instances).\n */\nexport interface CompiledSubAgent<\n TRunnable extends ReactAgent<any> | Runnable = ReactAgent<any> | Runnable,\n> {\n /** The name of the agent */\n name: string;\n /** The description of the agent */\n description: string;\n /** The agent instance */\n runnable: TRunnable;\n\n /**\n * Context mode. `\"fork\"` inherits the parent's conversation history\n * (but not its system prompt — that's baked into the runnable).\n * `\"isolated\"` (default) only sees the delegated task.\n */\n mode?: \"isolated\" | \"fork\";\n}\n\n/**\n * Specification for a declarative subagent.\n *\n * When using `createDeepAgent`, subagents automatically receive a default middleware\n * stack (filesystemMiddleware, summarizationMiddleware, etc.) before any custom\n * `middleware` specified in this spec. Add `todoListMiddleware` explicitly to opt in.\n *\n * By default the subagent is isolated — it only ever sees the delegated task\n * description, never the parent's conversation. Setting `mode: \"fork\"` makes\n * it continue the parent's conversation instead.\n *\n * @example\n * ```typescript\n * const researcher: SubAgent = {\n * name: \"researcher\",\n * description: \"Research assistant for complex topics\",\n * systemPrompt: \"You are a research assistant.\",\n * tools: [webSearchTool],\n * skills: [\"/skills/research/\"],\n * };\n * ```\n *\n * @experimental `mode: \"fork\"` is experimental and subject to change.\n */\nexport interface SubAgent {\n /** Identifier used to select this subagent in the task tool */\n name: string;\n\n /** Description shown to the model for subagent selection */\n description: string;\n\n /**\n * The system prompt for the agent. Falls back to an empty prompt if\n * omitted. Under `mode: \"fork\"`, this is appended to the parent's\n * inherited prompt rather than replacing it.\n */\n systemPrompt?: string | SystemMessage;\n\n /**\n * Context mode. `\"isolated\"` (default) only sees the delegated task.\n * `\"fork\"` inherits the parent's conversation history and mirrors the\n * parent's prompt-producing middleware (skills, memory, custom middleware)\n * so it rebuilds an equivalent system prompt — the tradeoff is cache\n * misses if this subagent's own `model` differs from the parent's. Cannot\n * declare `skills` under `mode: \"fork\"`; the parent's skills are inherited\n * instead.\n */\n mode?: \"isolated\" | \"fork\";\n\n /** The tools to use for the agent (tool instances, not names). Defaults to defaultTools */\n tools?: StructuredTool[];\n\n /** The model for the agent. Defaults to defaultModel */\n model?: LanguageModelLike | string;\n\n /** Additional middleware to append after default_middleware */\n middleware?: readonly AgentMiddleware[];\n\n /** Human-in-the-loop configuration for specific tools. Requires a checkpointer. */\n interruptOn?: Record<string, boolean | InterruptOnConfig>;\n\n /**\n * Skill source paths for SkillsMiddleware.\n *\n * List of paths to skill directories (e.g., `[\"/skills/user/\", \"/skills/project/\"]`).\n * When specified, the subagent will have its own SkillsMiddleware that loads skills\n * from these paths. This allows subagents to have different skill sets than the main agent.\n *\n * Note: Custom subagents do NOT inherit skills from the main agent by default.\n * Only the general-purpose subagent inherits the main agent's skills.\n *\n * @example\n * ```typescript\n * const researcher: SubAgent = {\n * name: \"researcher\",\n * description: \"Research assistant\",\n * systemPrompt: \"You are a researcher.\",\n * skills: [\"/skills/research/\", \"/skills/web-search/\"],\n * };\n * ```\n */\n skills?: string[];\n\n /**\n * Structured output response format for the subagent.\n *\n * When specified, the subagent will produce a `structuredResponse` conforming to the\n * given schema. The structured response is JSON-serialized and returned as the\n * ToolMessage content to the parent agent, replacing the default last-message extraction.\n *\n * Accepts any format supported by `createAgent`: Zod schemas, JSON schema objects,\n * `toolStrategy(schema)`, `providerStrategy(schema)`, etc.\n *\n * @example\n * ```typescript\n * import { z } from \"zod\"\n *\n * const analyzer: SubAgent = {\n * name: \"analyzer\",\n * description: \"Analyzes data and returns structured findings\",\n * systemPrompt: \"Analyze the data and return your findings.\",\n * responseFormat: z.object({\n * findings: z.string(),\n * confidence: z.number(),\n * }),\n * };\n * ```\n */\n responseFormat?: CreateAgentParams[\"responseFormat\"];\n\n /**\n * Filesystem permission rules for this subagent.\n *\n * When specified, these rules **replace** the parent agent's permissions\n * for all tool calls made by this subagent. When omitted, the subagent\n * inherits the parent agent's permissions.\n *\n * Subagent permissions are a full replacement, not a merge.\n *\n * @example\n * ```ts\n * // Parent denies /restricted/**; this subagent can read it.\n * const reader: SubAgent = {\n * name: \"reader\",\n * permissions: [\n * { operations: [\"read\"], paths: [\"/restricted/**\"] },\n * ],\n * };\n * ```\n */\n permissions?: FilesystemPermission[];\n}\n\n/**\n * A {@link SubAgent} with `mode: \"fork\"`.\n *\n * @deprecated Kept as a named type for backward compatibility with code that imported\n * `ForkedSubAgent` before it merged into `SubAgent` — not a distinct shape\n * with its own constraints (a fork can now declare its own `systemPrompt`,\n * same as any `SubAgent`). Prefer `SubAgent` with `mode: \"fork\"` in new code.\n */\nexport interface ForkedSubAgent extends SubAgent {\n mode: \"fork\";\n}\n\n/**\n * Whether a declarative subagent spec has `mode: \"fork\"` set.\n *\n * A plain boolean, not a type predicate: `SubAgent` covers both `\"fork\"` and\n * `\"isolated\"`, so there's no distinct type left to narrow to.\n */\nexport function isForkedSubAgent(value: unknown): boolean {\n if (typeof value !== \"object\" || value == null) return false;\n if (!(\"mode\" in value)) return false;\n return value.mode === \"fork\";\n}\n\n/**\n * Base specification for the general-purpose subagent.\n *\n * This constant provides the default configuration for the general-purpose subagent\n * that is automatically included when `generalPurposeAgent: true` (the default).\n *\n * The general-purpose subagent:\n * - Has access to all tools from the main agent\n * - Inherits skills from the main agent (when skills are configured)\n * - Uses the same model as the main agent (by default)\n * - Is ideal for delegating complex, multi-step tasks\n *\n * You can spread this constant and override specific properties when creating\n * custom subagents that should behave similarly to the general-purpose agent:\n *\n * @example\n * ```typescript\n * import { GENERAL_PURPOSE_SUBAGENT, createDeepAgent } from \"@anthropic/deepagents\";\n *\n * // Use as-is (automatically included with generalPurposeAgent: true)\n * const agent = createDeepAgent({ model: \"claude-sonnet-4-5-20250929\" });\n *\n * // Or create a custom variant with different tools\n * const customGP: SubAgent = {\n * ...GENERAL_PURPOSE_SUBAGENT,\n * name: \"research-gp\",\n * tools: [webSearchTool, readFileTool],\n * };\n *\n * const agent = createDeepAgent({\n * model: \"claude-sonnet-4-5-20250929\",\n * subagents: [customGP],\n * // Disable the default general-purpose agent since we're providing our own\n * // (handled automatically when using createSubAgentMiddleware directly)\n * });\n * ```\n */\nexport const GENERAL_PURPOSE_SUBAGENT = {\n name: \"general-purpose\",\n description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,\n systemPrompt: DEFAULT_SUBAGENT_PROMPT,\n mode: \"isolated\",\n} as const;\n\nfunction filterState(\n state: Record<string, unknown>,\n excludedKeys: readonly string[],\n): Record<string, unknown> {\n const filtered: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(state)) {\n if (!excludedKeys.includes(key)) {\n filtered[key] = value;\n }\n }\n return filtered;\n}\n\n/**\n * Filter state to exclude certain keys when passing to subagents\n */\nexport function filterStateForSubagent(\n state: Record<string, unknown>,\n): Record<string, unknown> {\n return filterState(state, EXCLUDED_STATE_KEYS);\n}\n\n/**\n * Filter state to exclude only the keys a declarative fork must not resume\n * (structured response, summarization event/session) — see\n * `FORK_EXCLUDED_STATE_KEYS`.\n */\nexport function filterStateForFork(\n state: Record<string, unknown>,\n): Record<string, unknown> {\n return filterState(state, FORK_EXCLUDED_STATE_KEYS);\n}\n\n/**\n * Invalid tool message block types\n */\nconst INVALID_TOOL_MESSAGE_BLOCK_TYPES = [\n \"tool_use\",\n \"thinking\",\n \"redacted_thinking\",\n];\n\n/**\n * Create Command with filtered state update from subagent result\n */\nfunction returnCommandWithStateUpdate(\n result: Record<string, unknown>,\n toolCallId: string,\n): Command {\n const stateUpdate = filterStateForSubagent(result);\n\n let content: string | ContentBlock[];\n\n if (result.structuredResponse != null) {\n content = JSON.stringify(result.structuredResponse);\n } else {\n // Walk back to the last AIMessage with non-empty text and forward only that\n // text as a string. Anthropic sometimes emits a trailing empty `end_turn`\n // AIMessage after a final tool call, which would otherwise be forwarded as\n // an empty ToolMessage.\n const messages = (result.messages as BaseMessage[]) ?? [];\n content = \"Task completed\";\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (!message || !AIMessage.isInstance(message)) continue;\n const text =\n typeof message.content === \"string\"\n ? message.content.trim()\n : (message.text?.trim() ?? \"\");\n if (text) {\n content = text;\n break;\n }\n }\n }\n\n return new Command({\n update: {\n ...stateUpdate,\n messages: [\n new ToolMessage({\n content,\n tool_call_id: toolCallId,\n name: \"task\",\n }),\n ],\n },\n });\n}\n\n/** Drop the trailing in-flight AIMessage with unresolved tool_calls. */\nfunction stripInFlightAIMessage(messages: BaseMessage[]): BaseMessage[] {\n const last = messages.at(-1);\n const hasPendingToolCalls =\n AIMessage.isInstance(last) && (last.tool_calls?.length ?? 0) > 0;\n return hasPendingToolCalls ? messages.slice(0, -1) : messages;\n}\n\nconst ForkedContextStateSchema = z.object({\n [FORKED_CONTEXT_KEY]: z.boolean().optional(),\n});\n\n// Flag must be set via beforeAgent, not the initial invoke() input —\n// getCurrentTaskInput() won't see it otherwise.\nfunction createForkTaskToolMiddleware(\n taskTool: StructuredTool,\n): AgentMiddleware {\n return createMiddleware({\n name: \"forkTaskToolMiddleware\",\n stateSchema: ForkedContextStateSchema,\n tools: [taskTool],\n beforeAgent: () => ({ [FORKED_CONTEXT_KEY]: true }),\n });\n}\n\n/**\n * Create a runnable agent from a declarative `SubAgent` spec.\n *\n * This is the shared entrypoint for compiling a `SubAgent` into a\n * `ReactAgent`. Pre-compiled `CompiledSubAgent` runnables bypass this\n * function entirely.\n *\n * The spec must have `model` and `tools` set — the caller is responsible\n * for coalescing any defaults before calling this function.\n *\n * @param spec - Declarative subagent specification. Must specify `model` and `tools`.\n * @returns A compiled `ReactAgent` ready for task-tool invocation.\n */\nexport function createSubAgent(\n spec: SubAgent,\n options?: {\n responseFormat?: CreateAgentParams[\"responseFormat\"];\n },\n): ReactAgent {\n if (!spec.model) {\n throw new Error(`SubAgent '${spec.name}' must specify 'model'`);\n }\n if (!spec.tools) {\n throw new Error(`SubAgent '${spec.name}' must specify 'tools'`);\n }\n\n const middleware: AgentMiddleware[] = [...(spec.middleware ?? [])];\n\n if (spec.interruptOn) {\n middleware.push(\n humanInTheLoopMiddleware({ interruptOn: spec.interruptOn }),\n );\n }\n\n const selectedResponseFormat = options?.responseFormat ?? spec.responseFormat;\n\n return createAgent({\n model: spec.model,\n systemPrompt: spec.systemPrompt,\n tools: spec.tools,\n middleware,\n name: spec.name,\n ...(selectedResponseFormat != null && {\n responseFormat: selectedResponseFormat,\n }),\n });\n}\n\n/**\n * Resolve a fork's system prompt: the parent's inherited prompt, with the\n * fork's own systemPrompt (if any) appended as an addendum rather than\n * replacing it.\n */\nfunction resolveForkSystemPrompt(\n parentSystemPrompt: string | SystemMessage | null,\n forkAddendum: string | SystemMessage | undefined,\n): string | SystemMessage {\n if (!forkAddendum) return parentSystemPrompt ?? \"\";\n const addendumText =\n typeof forkAddendum === \"string\" ? forkAddendum : forkAddendum.text;\n if (SystemMessage.isInstance(parentSystemPrompt)) {\n return appendToSystemMessage(parentSystemPrompt, addendumText);\n }\n return parentSystemPrompt\n ? `${parentSystemPrompt}\\n\\n${addendumText}`\n : addendumText;\n}\n\n/**\n * Create subagent instances from specifications.\n *\n * Returns compiled agents, raw specs keyed by name (for on-demand\n * recompilation with dynamic response formats), descriptions, and the set\n * of names that should fork the parent's conversation.\n */\nfunction getSubagents(options: {\n defaultModel: LanguageModelLike | string;\n defaultTools: StructuredTool[];\n defaultMiddleware: AgentMiddleware[] | null;\n generalPurposeMiddleware: AgentMiddleware[] | null;\n defaultInterruptOn: Record<string, boolean | InterruptOnConfig> | null;\n subagents: (SubAgent | CompiledSubAgent)[];\n generalPurposeAgent: boolean;\n parentSystemPrompt?: string | SystemMessage | null;\n /** The exact tool instance forked subagents mirror — see `createTaskTool`. */\n mirroredTaskTool: StructuredTool;\n}): {\n agents: Record<string, ReactAgent | Runnable>;\n specsByName: Record<string, SubAgent | CompiledSubAgent>;\n descriptions: string[];\n forkModeNames: Set<string>;\n} {\n const {\n defaultModel,\n defaultTools,\n defaultMiddleware,\n generalPurposeMiddleware: gpMiddleware,\n defaultInterruptOn,\n subagents,\n generalPurposeAgent,\n parentSystemPrompt = null,\n mirroredTaskTool,\n } = options;\n\n const defaultSubagentMiddleware = defaultMiddleware || [];\n const generalPurposeMiddlewareBase =\n gpMiddleware || defaultSubagentMiddleware;\n const agents: Record<string, ReactAgent | Runnable> = {};\n const specsByName: Record<string, SubAgent | CompiledSubAgent> = {};\n const subagentDescriptions: string[] = [];\n const forkModeNames = new Set<string>();\n\n // Prevent a duplicate name from silently resolving to the last spec.\n const seenNames = new Set<string>(\n generalPurposeAgent ? [\"general-purpose\"] : [],\n );\n for (const agentParams of subagents) {\n if (seenNames.has(agentParams.name)) {\n throw new Error(\n `Duplicate subagent name '${agentParams.name}'; each subagent must have a unique name.`,\n );\n }\n seenNames.add(agentParams.name);\n }\n\n if (generalPurposeAgent) {\n const generalPurposeMiddleware = [...generalPurposeMiddlewareBase];\n if (defaultInterruptOn) {\n generalPurposeMiddleware.push(\n humanInTheLoopMiddleware({ interruptOn: defaultInterruptOn }),\n );\n }\n\n const gpSpec: SubAgent = {\n name: \"general-purpose\",\n description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,\n model: defaultModel,\n systemPrompt: DEFAULT_SUBAGENT_PROMPT,\n tools: defaultTools as any,\n middleware: generalPurposeMiddleware,\n };\n\n agents[\"general-purpose\"] = createSubAgent(gpSpec);\n specsByName[\"general-purpose\"] = gpSpec;\n subagentDescriptions.push(\n describeSubagentForTool(\n \"general-purpose\",\n DEFAULT_GENERAL_PURPOSE_DESCRIPTION,\n false,\n ),\n );\n }\n\n for (const agentParams of subagents) {\n // Widened to string: a plain-JS/`as any` caller can still pass the\n // legacy \"handoff\" value, which no longer appears in the type itself.\n const rawMode = agentParams.mode as string | undefined;\n if (\n rawMode != null &&\n rawMode !== \"isolated\" &&\n rawMode !== \"fork\" &&\n rawMode !== \"handoff\" // legacy alias for \"isolated\"\n ) {\n throw new Error(\n `SubAgent '${agentParams.name}' has invalid mode '${rawMode}' — must be \"isolated\" or \"fork\".`,\n );\n }\n\n const forked = isForkedSubAgent(agentParams);\n const compiled = \"runnable\" in agentParams;\n\n subagentDescriptions.push(\n describeSubagentForTool(\n agentParams.name,\n agentParams.description,\n forked,\n compiled,\n ),\n );\n\n if (\"runnable\" in agentParams) {\n agents[agentParams.name] = agentParams.runnable;\n specsByName[agentParams.name] = agentParams;\n if (forked) forkModeNames.add(agentParams.name);\n continue;\n }\n\n const subagentMiddleware = [\n ...defaultSubagentMiddleware,\n ...(agentParams.middleware ?? []),\n ];\n\n if (forked) {\n // Re-check at runtime — the type guard doesn't stop a plain-JS/`as any` caller.\n const rawSkills = (agentParams as { skills?: unknown }).skills;\n if (Array.isArray(rawSkills) && rawSkills.length > 0) {\n throw new Error(\n `SubAgent '${agentParams.name}' cannot set skills under mode: \"fork\"; the parent's skills are inherited instead.`,\n );\n }\n // The fork's own systemPrompt (if any) is an addendum appended to the\n // parent's inherited prompt, not a replacement — mirrors createDeepAgent's\n // main-loop merge logic for a declarative fork's own spec.\n const resolvedSystemPrompt = resolveForkSystemPrompt(\n parentSystemPrompt,\n agentParams.systemPrompt,\n );\n // Splice after Filesystem (always present) to match the parent's tool\n // order for prompt-cache parity.\n const fsIndex = subagentMiddleware.findIndex(\n (m) => m.name === \"FilesystemMiddleware\",\n );\n subagentMiddleware.splice(\n fsIndex + 1,\n 0,\n createForkTaskToolMiddleware(mirroredTaskTool),\n );\n const resolvedSpec: SubAgent = {\n ...agentParams,\n systemPrompt: resolvedSystemPrompt,\n mode: undefined,\n model: agentParams.model ?? defaultModel,\n tools: agentParams.tools ?? defaultTools,\n middleware: subagentMiddleware,\n interruptOn: agentParams.interruptOn ?? defaultInterruptOn ?? undefined,\n };\n agents[agentParams.name] = createSubAgent(resolvedSpec);\n specsByName[agentParams.name] = resolvedSpec;\n forkModeNames.add(agentParams.name);\n } else {\n // Plain SubAgent — never forks, keeps its own prompt untouched.\n const resolvedSpec: SubAgent = {\n ...agentParams,\n mode: \"isolated\",\n model: agentParams.model ?? defaultModel,\n tools: agentParams.tools ?? defaultTools,\n middleware: subagentMiddleware,\n interruptOn: agentParams.interruptOn ?? defaultInterruptOn ?? undefined,\n };\n agents[agentParams.name] = createSubAgent(resolvedSpec);\n specsByName[agentParams.name] = resolvedSpec;\n }\n }\n\n return {\n agents,\n specsByName,\n descriptions: subagentDescriptions,\n forkModeNames,\n };\n}\n\n/**\n * Create the task tool for invoking subagents\n */\nfunction createTaskTool(options: {\n defaultModel: LanguageModelLike | string;\n defaultTools: StructuredTool[];\n defaultMiddleware: AgentMiddleware[] | null;\n generalPurposeMiddleware: AgentMiddleware[] | null;\n defaultInterruptOn: Record<string, boolean | InterruptOnConfig> | null;\n subagents: (SubAgent | CompiledSubAgent)[];\n generalPurposeAgent: boolean;\n taskDescription: string | null;\n parentSystemPrompt?: string | SystemMessage | null;\n}) {\n const {\n defaultModel,\n defaultTools,\n defaultMiddleware,\n generalPurposeMiddleware,\n defaultInterruptOn,\n subagents,\n generalPurposeAgent,\n taskDescription,\n parentSystemPrompt = null,\n } = options;\n\n const subagentNames = [\n ...(generalPurposeAgent ? [\"general-purpose\"] : []),\n ...subagents.map((spec) => spec.name),\n ];\n const subagentDescriptions = [\n ...(generalPurposeAgent\n ? [\n describeSubagentForTool(\n \"general-purpose\",\n DEFAULT_GENERAL_PURPOSE_DESCRIPTION,\n false,\n ),\n ]\n : []),\n ...subagents.map((spec) =>\n describeSubagentForTool(\n spec.name,\n spec.description,\n isForkedSubAgent(spec),\n \"runnable\" in spec,\n ),\n ),\n ];\n\n const finalTaskDescription = taskDescription\n ? taskDescription\n : getTaskToolDescription(subagentDescriptions);\n\n // Populated below by getSubagents(); runTask only reads these once actually invoked.\n let subagentGraphs: Record<string, ReactAgent | Runnable> = {};\n let specsByName: Record<string, SubAgent | CompiledSubAgent> = {};\n let forkModeNames: Set<string> = new Set();\n\n function selectSubagent(\n subagentType: string,\n config: Record<string, any>,\n ): Runnable {\n const spec = specsByName[subagentType];\n\n const responseFormat =\n config.configurable?.[SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY];\n if (responseFormat != null && \"runnable\" in spec) {\n throw new Error(\n `responseSchema cannot be used with compiled subagent \"${spec.name}\"; ` +\n \"dynamic schemas require a declarative SubAgent spec.\",\n );\n }\n if (\"runnable\" in spec || responseFormat == null) {\n return subagentGraphs[subagentType] as Runnable;\n }\n\n return createSubAgent(spec, { responseFormat }) as unknown as Runnable;\n }\n\n async function runTask(\n input: { description: string; subagent_type: string },\n config: Record<string, any>,\n ): Promise<Command | string> {\n const { description, subagent_type } = input;\n\n const currentState = getCurrentTaskInput<Record<string, unknown>>();\n if (currentState[FORKED_CONTEXT_KEY]) {\n return FORK_RECURSION_REFUSAL;\n }\n\n if (!(subagent_type in subagentGraphs)) {\n const allowedTypes = Object.keys(subagentGraphs)\n .map((k) => `\\`${k}\\``)\n .join(\", \");\n throw new Error(\n `Error: invoked agent of type ${subagent_type}, the only allowed types are ${allowedTypes}`,\n );\n }\n\n const shouldFork = forkModeNames.has(subagent_type);\n\n const subagent = selectSubagent(subagent_type, config);\n\n // Compiled runnables are opaque, so only declarative forks get the wider filter.\n const spec = specsByName[subagent_type];\n const isDeclarativeFork = shouldFork && !(\"runnable\" in spec);\n\n const subagentState = isDeclarativeFork\n ? filterStateForFork(currentState)\n : filterStateForSubagent(currentState);\n\n if (shouldFork) {\n const trimmed = stripInFlightAIMessage(\n (currentState.messages as BaseMessage[]) ?? [],\n );\n const effective = getEffectiveMessages(trimmed, currentState);\n subagentState.messages = [\n ...effective,\n new HumanMessage({ content: FORK_TASK_PREAMBLE + description }),\n ];\n } else {\n subagentState.messages = [new HumanMessage({ content: description })];\n }\n subagentState._summarizationSessionId = `session_${crypto.randomUUID().substring(0, 8)}`;\n\n const subagentConfig = {\n ...config,\n metadata: {\n ...config.metadata,\n lc_agent_name: subagent_type,\n },\n configurable: {\n ...config.configurable,\n ls_agent_type: \"subagent\",\n },\n };\n const result = (await subagent.invoke(\n subagentState,\n subagentConfig,\n )) as Record<string, unknown>;\n\n if (!config.toolCall?.id) {\n if (result.structuredResponse != null) {\n return JSON.stringify(result.structuredResponse);\n }\n const messages = result.messages as BaseMessage[];\n const lastMessage = messages?.[messages.length - 1];\n let content: string | ContentBlock[] =\n lastMessage?.content || \"Task completed\";\n if (Array.isArray(content)) {\n content = content.filter(\n (block) => !INVALID_TOOL_MESSAGE_BLOCK_TYPES.includes(block.type),\n );\n if (content.length === 0) {\n return \"Task completed\";\n }\n return content\n .map((block) =>\n \"text\" in block ? block.text : JSON.stringify(block),\n )\n .join(\"\\n\");\n }\n return content;\n }\n\n return returnCommandWithStateUpdate(result, config.toolCall.id);\n }\n\n const taskToolSchema = z.object({\n description: z\n .string()\n .describe(\"The task to execute with the selected agent\"),\n subagent_type: z\n .string()\n .describe(\n `Name of the agent to use. Available: ${subagentNames.join(\", \")}`,\n ),\n });\n\n const taskTool = tool(runTask, {\n name: \"task\",\n description: finalTaskDescription,\n schema: taskToolSchema,\n });\n\n // Separate object, not the same tool instance — see createForkTaskToolMiddleware.\n const mirroredTaskTool = tool(runTask, {\n name: \"task\",\n description: finalTaskDescription,\n schema: taskToolSchema,\n });\n\n const {\n agents,\n specsByName: resolvedSpecsByName,\n forkModeNames: resolvedForkModeNames,\n } = getSubagents({\n defaultModel,\n defaultTools,\n defaultMiddleware,\n generalPurposeMiddleware,\n defaultInterruptOn,\n subagents,\n generalPurposeAgent,\n parentSystemPrompt,\n mirroredTaskTool,\n });\n\n subagentGraphs = agents;\n specsByName = resolvedSpecsByName;\n forkModeNames = resolvedForkModeNames;\n\n return taskTool;\n}\n\n/**\n * Options for creating subagent middleware\n */\nexport interface SubAgentMiddlewareOptions {\n /** The model to use for subagents */\n defaultModel: LanguageModelLike | string;\n /** The tools to use for the default general-purpose subagent */\n defaultTools?: StructuredTool[];\n /** Default middleware to apply to custom subagents (WITHOUT skills from main agent) */\n defaultMiddleware?: AgentMiddleware[] | null;\n /**\n * Middleware specifically for the general-purpose subagent (includes skills from main agent).\n * If not provided, falls back to defaultMiddleware.\n */\n generalPurposeMiddleware?: AgentMiddleware[] | null;\n /** The tool configs for the default general-purpose subagent */\n defaultInterruptOn?: Record<string, boolean | InterruptOnConfig> | null;\n /** A list of additional subagents to provide to the agent */\n subagents?: (SubAgent | CompiledSubAgent)[];\n /** Full system prompt override */\n systemPrompt?: string | null;\n /** Whether to include the general-purpose agent */\n generalPurposeAgent?: boolean;\n /** Custom description for the task tool */\n taskDescription?: string | null;\n /** Inherited by a `mode: \"fork\"` declarative or compiled subagent */\n parentSystemPrompt?: string | SystemMessage | null;\n}\n\n/**\n * Create subagent middleware with task tool\n */\nexport function createSubAgentMiddleware(options: SubAgentMiddlewareOptions) {\n const {\n defaultModel,\n defaultTools = [],\n defaultMiddleware = null,\n generalPurposeMiddleware = null,\n defaultInterruptOn = null,\n subagents = [],\n systemPrompt = null,\n generalPurposeAgent = true,\n taskDescription = null,\n parentSystemPrompt = null,\n } = options;\n\n const taskTool = createTaskTool({\n defaultModel,\n defaultTools,\n defaultMiddleware,\n generalPurposeMiddleware,\n defaultInterruptOn,\n subagents,\n generalPurposeAgent,\n taskDescription,\n parentSystemPrompt,\n });\n\n return createMiddleware({\n name: \"subAgentMiddleware\",\n tools: [taskTool],\n wrapModelCall: async (request, handler) => {\n if (systemPrompt !== null) {\n return handler({\n ...request,\n systemMessage: request.systemMessage.concat(\n new SystemMessage({ content: systemPrompt }),\n ),\n });\n }\n return handler(request);\n },\n });\n}\n","import {\n createMiddleware,\n ToolMessage,\n AIMessage,\n /**\n * required for type inference\n */\n type AgentMiddleware as _AgentMiddleware,\n} from \"langchain\";\nimport { RemoveMessage, type BaseMessage } from \"@langchain/core/messages\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\n\n/**\n * Patch tool call / tool response parity in a messages array.\n *\n * Ensures strict 1:1 correspondence between AIMessage tool_calls and\n * ToolMessage responses:\n *\n * 1. **Dangling tool_calls** — an AIMessage contains a tool_call with no\n * matching ToolMessage anywhere after it. A synthetic cancellation\n * ToolMessage is inserted immediately after the AIMessage.\n *\n * 2. **Orphaned ToolMessages** — a ToolMessage whose `tool_call_id` does not\n * match any tool_call in a preceding AIMessage. The ToolMessage is removed.\n *\n * Both directions are required for providers that enforce strict parity\n * (e.g. Google Gemini returns 400 INVALID_ARGUMENT otherwise).\n *\n * @param messages - The messages array to patch\n * @returns Object with patched messages and needsPatch flag\n */\nexport function patchDanglingToolCalls(messages: BaseMessage[]): {\n patchedMessages: BaseMessage[];\n needsPatch: boolean;\n} {\n if (!messages || messages.length === 0) {\n return { patchedMessages: [], needsPatch: false };\n }\n\n // Pass 1: collect all tool_call_ids from AIMessages so we can detect\n // orphaned ToolMessages (those whose tool_call_id has no matching call).\n const allToolCallIds = new Set<string>();\n for (const msg of messages) {\n if (AIMessage.isInstance(msg) && msg.tool_calls != null) {\n for (const tc of msg.tool_calls) {\n if (tc.id) {\n allToolCallIds.add(tc.id);\n }\n }\n }\n }\n\n // Pass 2: build patched message list.\n // - Skip orphaned ToolMessages\n // - Inject synthetic ToolMessages for dangling tool_calls\n const patchedMessages: BaseMessage[] = [];\n let needsPatch = false;\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n\n // Remove orphaned ToolMessages (no preceding AIMessage has a matching tool_call)\n if (ToolMessage.isInstance(msg)) {\n if (!allToolCallIds.has(msg.tool_call_id)) {\n needsPatch = true;\n continue; // drop the orphaned ToolMessage\n }\n }\n\n patchedMessages.push(msg);\n\n // Inject synthetic ToolMessages for dangling tool_calls\n if (AIMessage.isInstance(msg) && msg.tool_calls != null) {\n for (const toolCall of msg.tool_calls) {\n // Look for a corresponding ToolMessage in the messages after this one\n const correspondingToolMsg = messages\n .slice(i + 1)\n .find(\n (m) => ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id,\n );\n\n if (!correspondingToolMsg) {\n // We have a dangling tool call which needs a ToolMessage\n needsPatch = true;\n const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;\n patchedMessages.push(\n new ToolMessage({\n content: toolMsg,\n name: toolCall.name,\n tool_call_id: toolCall.id!,\n }),\n );\n }\n }\n }\n }\n\n return { patchedMessages, needsPatch };\n}\n\n/**\n * Create middleware that enforces strict tool call / tool response parity in\n * the messages history.\n *\n * Two kinds of violations are repaired:\n * 1. **Dangling tool_calls** — an AIMessage contains tool_calls with no\n * matching ToolMessage responses. Synthetic cancellation ToolMessages are\n * injected so every tool_call has a response.\n * 2. **Orphaned ToolMessages** — a ToolMessage exists whose `tool_call_id`\n * does not match any tool_call in a preceding AIMessage. These are removed.\n *\n * This is critical for providers like Google Gemini that reject requests with\n * mismatched function call / function response counts (400 INVALID_ARGUMENT).\n *\n * This middleware patches in two places:\n * 1. `beforeAgent`: Patches state at the start of the agent loop (handles most cases)\n * 2. `wrapModelCall`: Patches the request right before model invocation (handles\n * edge cases like HITL rejection during graph resume where state updates from\n * beforeAgent may not be applied in time)\n *\n * @returns AgentMiddleware that enforces tool call / response parity\n *\n * @example\n * ```typescript\n * import { createAgent } from \"langchain\";\n * import { createPatchToolCallsMiddleware } from \"./middleware/patch_tool_calls\";\n *\n * const agent = createAgent({\n * model: \"claude-sonnet-4-5-20250929\",\n * middleware: [createPatchToolCallsMiddleware()],\n * });\n * ```\n */\nexport function createPatchToolCallsMiddleware() {\n return createMiddleware({\n name: \"patchToolCallsMiddleware\",\n beforeAgent: async (state) => {\n const messages = state.messages;\n\n if (!messages || messages.length === 0) {\n return;\n }\n\n const { patchedMessages, needsPatch } = patchDanglingToolCalls(messages);\n\n /**\n * Only trigger REMOVE_ALL_MESSAGES if patching is actually needed\n */\n if (!needsPatch) {\n return;\n }\n\n // Return state update with RemoveMessage followed by patched messages\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n ...patchedMessages,\n ],\n };\n },\n\n /**\n * Also patch in wrapModelCall as a safety net.\n * This handles edge cases where:\n * - HITL rejects a tool call during graph resume\n * - The state update from beforeAgent might not be applied in time\n * - The model would otherwise receive dangling tool_call_ids\n */\n wrapModelCall: async (request, handler) => {\n const messages = request.messages;\n\n if (!messages || messages.length === 0) {\n return handler(request);\n }\n\n const { patchedMessages, needsPatch } = patchDanglingToolCalls(messages);\n\n if (!needsPatch) {\n return handler(request);\n }\n\n // Pass patched messages to the model\n return handler({\n ...request,\n messages: patchedMessages,\n });\n },\n });\n}\n","/**\n * Shared state values for use in StateSchema definitions.\n *\n * This module provides pre-configured ReducedValue instances that can be\n * reused across different state schemas, similar to LangGraph's messagesValue.\n */\n\nimport { z } from \"zod\";\nimport { ReducedValue } from \"@langchain/langgraph\";\nimport { FileDataSchema, fileDataReducer } from \"./middleware/fs.js\";\n\n/**\n * Shared ReducedValue for file data state management.\n *\n * This provides a reusable pattern for managing file state with automatic\n * merging of concurrent updates from parallel subagents. Files can be updated\n * or deleted (using null values) and the reducer handles the merge logic.\n *\n * Similar to LangGraph's messagesValue, this encapsulates the common pattern\n * of managing files in agent state so you don't have to manually configure\n * the ReducedValue each time.\n *\n * @example\n * ```typescript\n * import { filesValue } from \"@anthropic/deepagents\";\n * import { StateSchema } from \"@langchain/langgraph\";\n *\n * const MyStateSchema = new StateSchema({\n * files: filesValue,\n * // ... other state fields\n * });\n * ```\n */\nexport const filesValue = new ReducedValue(\n z.record(z.string(), FileDataSchema).default(() => ({})),\n {\n inputSchema: z.record(z.string(), FileDataSchema.nullable()).optional(),\n reducer: fileDataReducer,\n },\n);\n","import type { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport type { RunnableInterface } from \"@langchain/core/runnables\";\n\n/**\n * Detect whether a model is an Anthropic model.\n *\n * Used to gate Anthropic-specific prompt caching optimizations\n * (cache_control breakpoints).\n *\n * Accepts the wider `RunnableInterface` shape (the type of `request.model`\n * inside `wrapModelCall`, aliased as `AgentLanguageModelLike` in langchain)\n * because the function only depends on `.getName()`, which is part of the\n * Runnable contract. `BaseLanguageModel` extends `Runnable`, so existing\n * call sites still type-check.\n */\nexport function isAnthropicModel(\n model: BaseLanguageModel | RunnableInterface<unknown, unknown> | string,\n): boolean {\n if (typeof model === \"string\") {\n if (model.includes(\":\")) return model.split(\":\")[0] === \"anthropic\";\n return model.startsWith(\"claude\");\n }\n if (model.getName() === \"ConfigurableModel\") {\n return (model as any)._defaultConfig?.modelProvider === \"anthropic\";\n }\n return model.getName() === \"ChatAnthropic\";\n}\n\n/**\n * A one-shot promise whose settlement is controlled externally.\n *\n * Use this when one part of a workflow must wait for an event that is owned\n * elsewhere—for example, a queued mutation waiting for the worker that will\n * push it. `Deferred` is awaitable because it implements `PromiseLike`, and\n * `.promise` is available when a concrete `Promise` is required.\n *\n * The first call to `resolve` or `reject` wins; later calls are ignored. This\n * class deliberately does not provide cancellation, reset, or notification\n * semantics. It models exactly one eventual outcome.\n */\nexport class Deferred<T = void> implements PromiseLike<T> {\n readonly promise: Promise<T>;\n\n private settled = false;\n private resolvePromise!: (value: T | PromiseLike<T>) => void;\n private rejectPromise!: (reason?: unknown) => void;\n\n constructor() {\n this.promise = new Promise<T>((resolve, reject) => {\n this.resolvePromise = resolve;\n this.rejectPromise = reject;\n });\n }\n\n resolve(value: T | PromiseLike<T>): void {\n if (this.settled) {\n return;\n }\n this.settled = true;\n this.resolvePromise(value);\n }\n\n reject(reason?: unknown): void {\n if (this.settled) {\n return;\n }\n this.settled = true;\n this.rejectPromise(reason);\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.promise.then(onfulfilled, onrejected);\n }\n}\n\n/**\n * Detect whether a model is an AWS Bedrock Converse model.\n *\n * Accepts the wider `RunnableInterface` shape (the type of `request.model`\n * inside `wrapModelCall`, aliased as `AgentLanguageModelLike` in langchain)\n * because the function only depends on `.getName()`, which is part of the\n * Runnable contract. `BaseLanguageModel` extends `Runnable`, so existing\n * call sites still type-check.\n */\nexport function isBedrockConverseModel(\n model: BaseLanguageModel | RunnableInterface<unknown, unknown> | string,\n): boolean {\n if (typeof model === \"string\") {\n // Explicit provider prefix (`bedrock:` or `aws:`) — both map to\n // ChatBedrockConverse in langchain's initChatModel.\n const colonIdx = model.indexOf(\":\");\n if (colonIdx !== -1) {\n const prefix = model.slice(0, colonIdx);\n if (prefix === \"bedrock\" || prefix === \"aws\") return true;\n }\n\n return model.startsWith(\"amazon.\");\n }\n if (model.getName() === \"ConfigurableModel\") {\n const provider = (model as any)._defaultConfig?.modelProvider;\n return provider === \"bedrock\" || provider === \"aws\";\n }\n return model.getName() === \"ChatBedrockConverse\";\n}\n\n/**\n * Extract the provider name from a model instance for profile lookup.\n *\n * Checks `_defaultConfig.modelProvider` (ConfigurableModel) and falls\n * back to known model class name → provider mappings.\n *\n * @internal\n */\nexport function getModelProvider(\n model: BaseLanguageModel | RunnableInterface<unknown, unknown>,\n): string | undefined {\n if (model.getName() === \"ConfigurableModel\") {\n return (model as any)._defaultConfig?.modelProvider as string | undefined;\n }\n const nameMap: Record<string, string> = {\n ChatAnthropic: \"anthropic\",\n ChatOpenAI: \"openai\",\n ChatGoogleGenerativeAI: \"google\",\n };\n return nameMap[model.getName()];\n}\n\n/**\n * Extract the model identifier from a model instance for profile\n * lookup.\n *\n * Checks `_defaultConfig.model`, `model_name`, and `modelName` in\n * that order.\n *\n * @internal\n */\nexport function getModelIdentifier(\n model: BaseLanguageModel | RunnableInterface<unknown, unknown>,\n): string | undefined {\n const configurable =\n model.getName() === \"ConfigurableModel\"\n ? (model as any)._defaultConfig\n : undefined;\n return (\n configurable?.model ??\n (model as any).model_name ??\n (model as any).modelName ??\n undefined\n );\n}\n","/**\n * Middleware for loading agent memory/context from AGENTS.md files.\n *\n * This module implements support for the AGENTS.md specification (https://agents.md/),\n * loading memory/context from configurable sources and injecting into the system prompt.\n *\n * ## Overview\n *\n * AGENTS.md files provide project-specific context and instructions to help AI agents\n * work effectively. Unlike skills (which are on-demand workflows), memory is always\n * loaded and provides persistent context.\n *\n * ## Usage\n *\n * ```typescript\n * import { createMemoryMiddleware } from \"@anthropic/deepagents\";\n * import { FilesystemBackend } from \"@anthropic/deepagents\";\n *\n * // Security: FilesystemBackend allows reading/writing from the entire filesystem.\n * // Either ensure the agent is running within a sandbox OR add human-in-the-loop (HIL)\n * // approval to file operations.\n * const backend = new FilesystemBackend({ rootDir: \"/\" });\n *\n * const middleware = createMemoryMiddleware({\n * backend,\n * sources: [\n * \"~/.deepagents/AGENTS.md\",\n * \"./.deepagents/AGENTS.md\",\n * ],\n * });\n *\n * const agent = createDeepAgent({ middleware: [middleware] });\n * ```\n *\n * ## Memory Sources\n *\n * Sources are simply paths to AGENTS.md files that are loaded in order and combined.\n * Multiple sources are concatenated in order, with all content included.\n * Later sources appear after earlier ones in the combined prompt.\n *\n * ## File Format\n *\n * AGENTS.md files are standard Markdown with no required structure.\n * Common sections include:\n * - Project overview\n * - Build/test commands\n * - Code style guidelines\n * - Architecture notes\n */\n\nimport { z } from \"zod\";\nimport {\n context,\n createMiddleware,\n SystemMessage,\n /**\n * required for type inference\n */\n type AgentMiddleware as _AgentMiddleware,\n} from \"langchain\";\n\nimport type {\n AnyBackendProtocol,\n BackendFactory,\n} from \"../backends/protocol.js\";\nimport { resolveBackend } from \"../backends/protocol.js\";\nimport type { StateBackend } from \"../backends/state.js\";\nimport type { BaseStore } from \"@langchain/langgraph-checkpoint\";\nimport { filesValue } from \"../values.js\";\nimport { StateSchema } from \"@langchain/langgraph\";\nimport { adaptBackendProtocol } from \"../backends/utils.js\";\nimport { isAnthropicModel } from \"../utils.js\";\n\n/**\n * Import @langchain/langgraph for type inference\n */\nimport type * as _langgraph from \"@langchain/langgraph\";\n\n/**\n * Options for the memory middleware.\n */\nexport interface MemoryMiddlewareOptions {\n /**\n * Backend instance or factory function for file operations.\n * Use a factory for StateBackend since it requires runtime state.\n */\n backend:\n | AnyBackendProtocol\n | BackendFactory\n | ((config: { state: unknown; store?: BaseStore }) => StateBackend);\n\n /**\n * List of memory file paths to load (e.g., [\"~/.deepagents/AGENTS.md\", \"./.deepagents/AGENTS.md\"]).\n * Display names are automatically derived from the paths.\n * Sources are loaded in order.\n */\n sources: string[];\n\n /**\n * Whether to add cache_control breakpoints to the memory content block.\n * When true, the memory block is tagged with `cache_control: { type: \"ephemeral\" }`\n * to enable prompt caching for providers that support it (e.g., Anthropic).\n * @default false\n */\n addCacheControl?: boolean;\n}\n\n/**\n * State schema for memory middleware.\n */\nconst MemoryStateSchema = new StateSchema({\n /**\n * Dict mapping source paths to their loaded content.\n * Marked as private so it's not included in the final agent state.\n */\n memoryContents: z.record(z.string(), z.string()).optional(),\n files: filesValue,\n});\n\n/**\n * Default system prompt template for memory.\n * Ported from Python's comprehensive memory guidelines.\n */\nconst MEMORY_SYSTEM_PROMPT = context`\n <agent_memory>\n {memory_contents}\n </agent_memory>\n\n <memory_guidelines>\n The above <agent_memory> was loaded in from files in your filesystem. As you learn from your interactions with the user, you can save new knowledge by calling the \\`edit_file\\` tool.\n\n **Learning from feedback:**\n - One of your MAIN PRIORITIES is to learn from your interactions with the user. These learnings can be implicit or explicit. This means that in the future, you will remember this important information.\n - When you need to remember something, updating memory must be your FIRST, IMMEDIATE action - before responding to the user, before calling other tools, before doing anything else. Just update memory immediately.\n - When user says something is better/worse, capture WHY and encode it as a pattern.\n - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.\n - A great opportunity to update your memories is when the user interrupts a tool call and provides feedback. You should update your memories immediately before revising the tool call.\n - Look for the underlying principle behind corrections, not just the specific mistake.\n - The user might not explicitly ask you to remember something, but if they provide information that is useful for future use, you should update your memories immediately.\n\n **Asking for information:**\n - If you lack context to perform an action (e.g. send a Slack DM, requires a user ID/email) you should explicitly ask the user for this information.\n - It is preferred for you to ask for information, don't assume anything that you do not know!\n - When the user provides information that is useful for future use, you should update your memories immediately.\n\n **When to update memories:**\n - When the user explicitly asks you to remember something (e.g., \"remember my email\", \"save this preference\")\n - When the user describes your role or how you should behave (e.g., \"you are a web researcher\", \"always do X\")\n - When the user gives feedback on your work - capture what was wrong and how to improve\n - When the user provides information required for tool use (e.g., slack channel ID, email addresses)\n - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation\n - When you discover new patterns or preferences (coding styles, conventions, workflows)\n\n **When to NOT update memories:**\n - When the information is temporary or transient (e.g., \"I'm running late\", \"I'm on my phone right now\")\n - When the information is a one-time task request (e.g., \"Find me a recipe\", \"What's 25 * 4?\")\n - When the information is a simple question that doesn't reveal lasting preferences (e.g., \"What day is it?\", \"Can you explain X?\")\n - When the information is an acknowledgment or small talk (e.g., \"Sounds good!\", \"Hello\", \"Thanks for that\")\n - When the information is stale or irrelevant in future conversations\n - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.\n - If the user asks where to put API keys or provides an API key, do NOT echo or save it.\n\n **Examples:**\n Example 1 (remembering user information):\n User: Can you connect to my google account?\n Agent: Sure, I'll connect to your google account, what's your google account email?\n User: john@example.com\n Agent: Let me save this to my memory.\n Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com\n\n Example 2 (remembering implicit user preferences):\n User: Can you write me an example for creating a deep agent in LangChain?\n Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>\n User: Can you do this in JavaScript\n Agent: Let me save this to my memory.\n Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript\n Agent: Sure, here is the JavaScript example<example code in JavaScript>\n\n Example 3 (do not remember transient information):\n User: I'm going to play basketball tonight so I will be offline for a few hours.\n Agent: Okay I'll add a block to your calendar.\n Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information\n </memory_guidelines>\n`;\n\n/**\n * Format loaded memory contents for injection into prompt.\n * Pairs memory locations with their contents for clarity.\n */\nfunction formatMemoryContents(\n contents: Record<string, string>,\n sources: string[],\n): string {\n if (Object.keys(contents).length === 0) {\n return \"(No memory loaded)\";\n }\n\n const sections: string[] = [];\n for (const path of sources) {\n if (contents[path]) {\n sections.push(`${path}\\n${contents[path]}`);\n }\n }\n\n if (sections.length === 0) {\n return \"(No memory loaded)\";\n }\n\n return sections.join(\"\\n\\n\");\n}\n\n/**\n * Load memory content from a backend path.\n *\n * @param backend - Backend to load from.\n * @param path - Path to the AGENTS.md file.\n * @returns File content if found, null otherwise.\n */\nasync function loadMemoryFromBackend(\n backend: AnyBackendProtocol,\n path: string,\n): Promise<string | null> {\n const adaptedBackend = adaptBackendProtocol(backend);\n\n // Use downloadFiles if available, otherwise fall back to read\n if (!adaptedBackend.downloadFiles) {\n const content = await adaptedBackend.read(path);\n if (content.error) {\n return null;\n }\n if (typeof content.content !== \"string\") {\n return null;\n }\n return content.content;\n }\n\n const results = await adaptedBackend.downloadFiles([path]);\n\n // Should get exactly one response for one path\n if (results.length !== 1) {\n throw new Error(\n `Expected 1 response for path ${path}, got ${results.length}`,\n );\n }\n const response = results[0];\n\n if (response.error != null) {\n // For now, memory files are treated as optional. file_not_found is expected\n // and we skip silently to allow graceful degradation.\n if (response.error === \"file_not_found\") {\n return null;\n }\n // Other errors should be raised\n throw new Error(`Failed to download ${path}: ${response.error}`);\n }\n\n if (response.content != null) {\n // Content is a Uint8Array, decode to string\n return new TextDecoder().decode(response.content);\n }\n\n return null;\n}\n\n/**\n * Create middleware for loading agent memory from AGENTS.md files.\n *\n * Loads memory content from configured sources and injects into the system prompt.\n * Supports multiple sources that are combined together.\n *\n * @param options - Configuration options\n * @returns AgentMiddleware for memory loading and injection\n *\n * @example\n * ```typescript\n * const middleware = createMemoryMiddleware({\n * backend: new FilesystemBackend({ rootDir: \"/\" }),\n * sources: [\n * \"~/.deepagents/AGENTS.md\",\n * \"./.deepagents/AGENTS.md\",\n * ],\n * });\n * ```\n */\nexport function createMemoryMiddleware(options: MemoryMiddlewareOptions) {\n const { backend, sources, addCacheControl = false } = options;\n\n return createMiddleware({\n name: \"MemoryMiddleware\",\n stateSchema: MemoryStateSchema,\n\n async beforeAgent(state) {\n // Skip if already loaded\n if (\"memoryContents\" in state && state.memoryContents != null) {\n return undefined;\n }\n\n const resolvedBackend = await resolveBackend(backend, { state });\n const contents: Record<string, string> = {};\n\n for (const path of sources) {\n try {\n const content = await loadMemoryFromBackend(resolvedBackend, path);\n if (content) {\n contents[path] = content;\n }\n } catch (error) {\n // Log but continue - memory is optional\n // oxlint-disable-next-line no-console\n console.debug(`Failed to load memory from ${path}:`, error);\n }\n }\n\n return { memoryContents: contents };\n },\n\n wrapModelCall(request, handler) {\n // Get memory contents from state\n const memoryContents: Record<string, string> =\n request.state?.memoryContents || {};\n\n // Format memory section\n const formattedContents = formatMemoryContents(memoryContents, sources);\n const memorySection = MEMORY_SYSTEM_PROMPT.replace(\n \"{memory_contents}\",\n formattedContents,\n );\n\n const existingContent = request.systemMessage.content;\n const existingBlocks =\n typeof existingContent === \"string\"\n ? [{ type: \"text\" as const, text: existingContent }]\n : Array.isArray(existingContent)\n ? existingContent\n : [];\n\n // `cache_control` is Anthropic-specific. Gate on the per-call model so\n // a fallback swap to a non-Anthropic provider (e.g. via\n // modelFallbackMiddleware) does not leak the marker — OpenAI/Vertex\n // reject the request with `400 Unknown parameter: 'cache_control'`.\n // `addCacheControl` remains the opt-in switch; the per-call model\n // check is an additional safety net.\n const writeCacheControl =\n addCacheControl && isAnthropicModel(request.model);\n\n const newSystemMessage = new SystemMessage({\n content: [\n ...existingBlocks,\n {\n type: \"text\" as const,\n text: memorySection,\n ...(writeCacheControl && {\n cache_control: { type: \"ephemeral\" as const },\n }),\n },\n ],\n });\n\n return handler({\n ...request,\n systemMessage: newSystemMessage,\n });\n },\n });\n}\n","/**\n * Backend-agnostic skills middleware for loading agent skills from any backend.\n *\n * This middleware implements Anthropic's agent skills pattern with progressive disclosure,\n * loading skills from backend storage via configurable sources.\n *\n * ## Architecture\n *\n * Skills are loaded from one or more **sources** - paths in a backend where skills are\n * organized. Sources are loaded in order, with later sources overriding earlier ones\n * when skills have the same name (last one wins). This enables layering: base -> user\n * -> project -> team skills.\n *\n * The middleware uses backend APIs exclusively (no direct filesystem access), making it\n * portable across different storage backends (filesystem, state, remote storage, etc.).\n *\n * ## Usage\n *\n * ```typescript\n * import { createSkillsMiddleware, FilesystemBackend } from \"@anthropic/deepagents\";\n *\n * const middleware = createSkillsMiddleware({\n * backend: new FilesystemBackend({ rootDir: \"/\" }),\n * sources: [\n * \"/skills/user/\", // parent dir: every subdir with SKILL.md is loaded\n * \"/skills/project/\", // parent dir: every subdir with SKILL.md is loaded\n * \"/skills/my-skill/\", // direct path: SKILL.md lives at the root of this dir\n * ],\n * });\n *\n * const agent = createDeepAgent({ middleware: [middleware] });\n * ```\n *\n * Or use the `skills` parameter on createDeepAgent:\n *\n * ```typescript\n * const agent = createDeepAgent({\n * skills: [\"/skills/user/\", \"/skills/project/\", \"/skills/my-skill/\"],\n * });\n * ```\n */\n\nimport { z } from \"zod\";\nimport yaml from \"yaml\";\nimport {\n context,\n createMiddleware,\n /**\n * required for type inference\n */\n type AgentMiddleware as _AgentMiddleware,\n} from \"langchain\";\nimport { StateSchema, ReducedValue } from \"@langchain/langgraph\";\n\nimport type {\n AnyBackendProtocol,\n BackendFactory,\n BackendProtocolV2,\n} from \"../backends/protocol.js\";\nimport { resolveBackend } from \"../backends/protocol.js\";\nimport type { StateBackend } from \"../backends/state.js\";\nimport type { BaseStore } from \"@langchain/langgraph-checkpoint\";\nimport { filesValue } from \"../values.js\";\nimport { adaptBackendProtocol } from \"../backends/utils.js\";\nimport { DEFAULT_READ_LINE_LIMIT } from \"./fs.js\";\n\n// Security: Maximum size for SKILL.md files to prevent DoS attacks (10MB)\nexport const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;\n\nexport const DEFAULT_SKILL_READ_LINE_LIMIT = 1000;\n\n// Agent Skills specification constraints (https://agentskills.io/specification)\nexport const MAX_SKILL_NAME_LENGTH = 64;\nexport const MAX_SKILL_DESCRIPTION_LENGTH = 1024;\nexport const MAX_SKILL_COMPATIBILITY_LENGTH = 500;\n\n/**\n * File extensions a skill module entrypoint may use.\n */\nexport const SKILL_MODULE_EXTENSIONS = [\n \".js\",\n \".mjs\",\n \".cjs\",\n \".ts\",\n \".mts\",\n \".cts\",\n \".jsx\",\n \".tsx\",\n];\n\n/**\n * Metadata for a skill per Agent Skills specification.\n */\nexport interface SkillMetadata {\n /**\n * Skill identifier.\n *\n * Constraints per Agent Skills specification:\n *\n * - 1-64 characters\n * - Unicode lowercase alphanumeric and hyphens only (`a-z` and `-`).\n * - Must not start or end with `-`\n * - Must not contain consecutive `--`\n * - Must match the parent directory name containing the `SKILL.md` file\n */\n name: string;\n\n /**\n * What the skill does.\n *\n * Constraints per Agent Skills specification:\n *\n * - 1-1024 characters\n * - Should describe both what the skill does and when to use it\n * - Should include specific keywords that help agents identify relevant tasks\n */\n description: string;\n\n /** Path to the SKILL.md file in the backend */\n path: string;\n\n /** License name or reference to bundled license file. */\n license?: string | null;\n\n /**\n * Environment requirements.\n *\n * Constraints per Agent Skills specification:\n *\n * - 1-500 characters if provided\n * - Should only be included if there are specific compatibility requirements\n * - Can indicate intended product, required packages, etc.\n */\n compatibility?: string | null;\n\n /**\n * Arbitrary key-value mapping for additional metadata.\n *\n * Clients can use this to store additional properties not defined by the spec.\n *\n * It is recommended to keep key names unique to avoid conflicts.\n */\n metadata?: Record<string, string>;\n\n /**\n * Tool names the skill recommends using.\n *\n * Warning: this is experimental.\n *\n * Constraints per Agent Skills specification:\n *\n * - Space-delimited list of tool names\n */\n allowedTools?: string[];\n\n /**\n * Path to a JS/TS entrypoint file for a QuickJS REPL module, relative to the skill\n * directory.\n */\n module?: string;\n}\n\n/**\n * Options for the skills middleware.\n */\nexport interface SkillsMiddlewareOptions {\n /**\n * Backend instance or factory function for file operations.\n * Use a factory for StateBackend since it requires runtime state.\n */\n backend:\n | AnyBackendProtocol\n | BackendFactory\n | ((config: { state: unknown; store?: BaseStore }) => StateBackend);\n\n /**\n * List of skill source paths to load.\n * Paths must use POSIX conventions (forward slashes).\n * Later sources override earlier ones for skills with the same name (last one wins).\n *\n * Two formats are accepted for each entry:\n *\n * - **Parent directory** (e.g. `\"/skills/\"`, `\"/skills/user/\"`): the directory\n * is scanned and every subdirectory that contains a `SKILL.md` is loaded as\n * a separate skill.\n *\n * - **Direct skill path** (e.g. `\"/skills/my-skill/\"`): the path points to a\n * single skill directory whose `SKILL.md` lives at its root. Detected\n * automatically when the directory listing contains a `SKILL.md` file.\n *\n * Both formats can be mixed in the same array:\n * ```typescript\n * sources: [\n * \"/skills/\", // loads all skills in the directory\n * \"/skills/my-skill/\", // loads a single skill by path\n * ]\n * ```\n */\n sources: string[];\n}\n\n/**\n * Zod schema for a single skill metadata entry.\n */\nexport const SkillMetadataEntrySchema = z.object({\n name: z.string(),\n description: z.string(),\n path: z.string(),\n license: z.string().nullable().optional(),\n compatibility: z.string().nullable().optional(),\n metadata: z.record(z.string(), z.string()).optional(),\n allowedTools: z.array(z.string()).optional(),\n module: z.string().optional(),\n});\n\n/**\n * Type for a single skill metadata entry.\n */\nexport type SkillMetadataEntry = z.infer<typeof SkillMetadataEntrySchema>;\n\n/**\n * Reducer for skillsMetadata that merges arrays from parallel subagents.\n * Skills are deduplicated by name, with later values overriding earlier ones.\n *\n * @param current - The current skillsMetadata array (from state)\n * @param update - The new skillsMetadata array (from a subagent update)\n * @returns Merged array with duplicates resolved by name (later values win)\n */\nexport function skillsMetadataReducer(\n current: SkillMetadataEntry[] | undefined,\n update: SkillMetadataEntry[] | undefined,\n): SkillMetadataEntry[] {\n // If no update, return current (or empty array)\n if (!update || update.length === 0) {\n return current || [];\n }\n // If no current, return update\n if (!current || current.length === 0) {\n return update;\n }\n // Merge by skill name (later values override earlier ones)\n const merged = new Map<string, SkillMetadataEntry>();\n for (const skill of current) {\n merged.set(skill.name, skill);\n }\n for (const skill of update) {\n merged.set(skill.name, skill);\n }\n return Array.from(merged.values());\n}\n\n/**\n * State schema for skills middleware.\n * Uses ReducedValue for skillsMetadata to allow concurrent updates from parallel subagents.\n */\nconst SkillsStateSchema = new StateSchema({\n skillsMetadata: new ReducedValue(\n z.array(SkillMetadataEntrySchema).default(() => []),\n {\n inputSchema: z.array(SkillMetadataEntrySchema).optional(),\n reducer: skillsMetadataReducer,\n },\n ),\n files: filesValue,\n});\n\n/**\n * Skills System Documentation prompt template.\n */\nconst SKILLS_SYSTEM_PROMPT = context`\n ## Skills System\n\n You have access to a skills library that provides specialized capabilities and domain knowledge.\n\n {skills_locations}\n\n **Available Skills:**\n\n {skills_list}\n\n **How to Use Skills (Progressive Disclosure):**\n\n Skills follow a **progressive disclosure** pattern - you know they exist (name + description above), but you only read the full instructions when needed:\n\n 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description\n 2. **Read the skill's full instructions**: Use \\`read_file\\` on the path shown in the skill list above.\n Pass \\`limit=${DEFAULT_SKILL_READ_LINE_LIMIT}\\` since the default of ${DEFAULT_READ_LINE_LIMIT} lines is too small for most skill files.\n 3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples\n 4. **Access supporting files**: Skills may include scripts, configs, or reference docs - use absolute paths\n\n **When to Use Skills:**\n - When the user's request matches a skill's domain (e.g., \"research X\" → web-research skill)\n - When you need specialized knowledge or structured workflows\n - When a skill provides proven patterns for complex tasks\n **Skills are Self-Documenting:**\n - Each SKILL.md tells you exactly what the skill does and how to use it\n - The skill list above shows the full path for each skill's SKILL.md file\n\n **Executing Skill Scripts:**\n Skills may contain scripts or other executable files. Always use absolute paths from the skill list.\n\n **Example Workflow:**\n\n User: \"Can you research the latest developments in quantum computing?\"\n\n 1. Check available skills above → See \"web-research\" skill with its full path\n 2. Read the full skill file: \\`read_file(file_path, limit=${DEFAULT_SKILL_READ_LINE_LIMIT})\\`\n 3. Follow the skill's research workflow (search → organize → synthesize)\n 4. Use any helper scripts with absolute paths\n\n Remember: Skills are tools to make you more capable and consistent. When in doubt, check if a skill exists for the task!\n`;\n\n/**\n * Validate skill name per Agent Skills specification.\n *\n * Constraints per Agent Skills specification:\n *\n * - 1-64 characters\n * - Unicode lowercase alphanumeric and hyphens only (`a-z` and `-`).\n * - Must not start or end with `-`\n * - Must not contain consecutive `--`\n * - Must match the parent directory name containing the `SKILL.md` file\n *\n * Unicode lowercase alphanumeric means any lowercase or decimal digit, which\n * covers accented Latin characters (e.g., `'café'`, `'über-tool'`) and other\n * scripts.\n *\n * @param name - The skill name from YAML frontmatter\n * @param directoryName - The parent directory name\n * @returns `{ valid, error }` tuple. Error is empty string if valid.\n */\nexport function validateSkillName(\n name: string,\n directoryName: string,\n): { valid: boolean; error: string } {\n if (!name) {\n return { valid: false, error: \"name is required\" };\n }\n if (name.length > MAX_SKILL_NAME_LENGTH) {\n return { valid: false, error: \"name exceeds 64 characters\" };\n }\n if (name.startsWith(\"-\") || name.endsWith(\"-\") || name.includes(\"--\")) {\n return {\n valid: false,\n error: \"name must be lowercase alphanumeric with single hyphens only\",\n };\n }\n for (const c of name) {\n if (c === \"-\") continue;\n if (/\\p{Ll}/u.test(c) || /\\p{Nd}/u.test(c)) continue;\n return {\n valid: false,\n error: \"name must be lowercase alphanumeric with single hyphens only\",\n };\n }\n if (name !== directoryName) {\n return {\n valid: false,\n error: `name '${name}' must match directory name '${directoryName}'`,\n };\n }\n return { valid: true, error: \"\" };\n}\n\n/**\n * Validate and normalize the metadata field from YAML frontmatter.\n *\n * YAML parsing can return any type for the `metadata` key. This ensures the\n * value in {@link SkillMetadata} is always a `Record<string, string>` by\n * coercing via `String()` and rejecting non-object inputs.\n *\n * @param raw - Raw value from `frontmatterData.metadata`.\n * @param skillPath - Path to the `SKILL.md` file (for warning messages).\n * @returns A validated `Record<string, string>`.\n */\nexport function validateMetadata(\n raw: unknown,\n skillPath: string,\n): Record<string, string> {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n if (raw) {\n console.warn(\n `Ignoring non-object metadata in ${skillPath} (got ${typeof raw})`,\n );\n }\n return {};\n }\n const result: Record<string, string> = {};\n for (const [k, v] of Object.entries(raw)) {\n result[String(k)] = String(v);\n }\n return result;\n}\n\n/**\n * Build a parenthetical annotation string from optional skill fields.\n *\n * Combines license and compatibility into a comma-separated string for\n * display in the system prompt skill listing.\n *\n * @param skill - Skill metadata to extract annotations from.\n * @returns Annotation string like `'License: MIT, Compatibility: Python 3.10+'`,\n * or empty string if neither field is set.\n */\nexport function formatSkillAnnotations(skill: SkillMetadata): string {\n const parts: string[] = [];\n if (skill.license) {\n parts.push(`License: ${skill.license}`);\n }\n if (skill.compatibility) {\n parts.push(`Compatibility: ${skill.compatibility}`);\n }\n return parts.join(\", \");\n}\n\n/**\n * Parse YAML frontmatter from `SKILL.md` content.\n *\n * Extracts metadata per Agent Skills specification from YAML frontmatter\n * delimited by `---` markers at the start of the content.\n *\n * @param content - Content of the `SKILL.md` file\n * @param skillPath - Path to the `SKILL.md` file (for error messages and metadata)\n * @param directoryName - Name of the parent directory containing the skill\n * @returns `SkillMetadata` if parsing succeeds, `null` if parsing fails or\n * validation errors occur\n */\nexport function parseSkillMetadataFromContent(\n content: string,\n skillPath: string,\n directoryName: string,\n): SkillMetadata | null {\n if (content.length > MAX_SKILL_FILE_SIZE) {\n console.warn(\n `Skipping ${skillPath}: content too large (${content.length} bytes)`,\n );\n return null;\n }\n\n // Match YAML frontmatter between --- delimiters\n const frontmatterPattern = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/;\n const match = content.match(frontmatterPattern);\n\n if (!match) {\n console.warn(`Skipping ${skillPath}: no valid YAML frontmatter found`);\n return null;\n }\n\n const frontmatterStr = match[1];\n\n // Parse YAML\n let frontmatterData: Record<string, unknown>;\n try {\n frontmatterData = yaml.parse(frontmatterStr);\n } catch (e) {\n console.warn(`Invalid YAML in ${skillPath}:`, e);\n return null;\n }\n\n if (!frontmatterData || typeof frontmatterData !== \"object\") {\n console.warn(`Skipping ${skillPath}: frontmatter is not a mapping`);\n return null;\n }\n\n // Validate required fields - coerce and strip whitespace\n const name = String(frontmatterData.name ?? \"\").trim();\n const description = String(frontmatterData.description ?? \"\").trim();\n\n if (!name || !description) {\n console.warn(\n `Skipping ${skillPath}: missing required 'name' or 'description'`,\n );\n return null;\n }\n\n // Validate name format per spec (warn but continue for backwards compatibility)\n const validation = validateSkillName(name, directoryName);\n if (!validation.valid) {\n console.warn(\n `Skill '${name}' in ${skillPath} does not follow Agent Skills specification: ${validation.error}. Consider renaming for spec compliance.`,\n );\n }\n\n // Validate description length per spec (max 1024 chars)\n let descriptionStr = description;\n if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH) {\n console.warn(\n `Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH} characters in ${skillPath}, truncating`,\n );\n descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH);\n }\n\n // Parse allowed-tools: support both YAML list and space-delimited string\n const rawTools = frontmatterData[\"allowed-tools\"];\n let allowedTools: string[];\n if (rawTools) {\n if (Array.isArray(rawTools)) {\n allowedTools = rawTools.map((t) => String(t).trim()).filter(Boolean);\n } else {\n // Split on whitespace (handles multiple consecutive spaces)\n allowedTools = String(rawTools).split(/\\s+/).filter(Boolean);\n }\n } else {\n allowedTools = [];\n }\n\n // Validate and truncate compatibility length\n let compatibilityStr =\n String(frontmatterData.compatibility ?? \"\").trim() || null;\n if (\n compatibilityStr &&\n compatibilityStr.length > MAX_SKILL_COMPATIBILITY_LENGTH\n ) {\n console.warn(\n `Compatibility exceeds ${MAX_SKILL_COMPATIBILITY_LENGTH} characters in ${skillPath}, truncating`,\n );\n compatibilityStr = compatibilityStr.slice(\n 0,\n MAX_SKILL_COMPATIBILITY_LENGTH,\n );\n }\n\n return {\n name,\n description: descriptionStr,\n path: skillPath,\n metadata: validateMetadata(frontmatterData.metadata ?? {}, skillPath),\n license: String(frontmatterData.license ?? \"\").trim() || null,\n compatibility: compatibilityStr,\n allowedTools,\n module: validateModulePath(frontmatterData.module),\n };\n}\n\n/**\n * Read a single file from the backend, returning its content as a string or\n * null if the file does not exist or cannot be read.\n */\nasync function readFileFromBackend(\n backend: BackendProtocolV2,\n filePath: string,\n): Promise<string | null> {\n if (backend.downloadFiles) {\n const results = await backend.downloadFiles([filePath]);\n if (results.length !== 1) {\n return null;\n }\n const response = results[0];\n if (response.error != null || response.content == null) {\n return null;\n }\n return new TextDecoder().decode(response.content);\n }\n const readResult = await backend.read(filePath);\n if (readResult.error) {\n return null;\n }\n if (typeof readResult.content !== \"string\") {\n return null;\n }\n return readResult.content;\n}\n\n/**\n * List all skills from a backend source.\n *\n * Supports two source formats:\n *\n * - **Parent directory** (e.g. `\"/skills/\"`): the directory is scanned for\n * subdirectories, each of which must contain a `SKILL.md` file. This is the\n * standard pattern for hosting a collection of skills in one place.\n *\n * - **Direct skill path** (e.g. `\"/skills/my-skill/\"`): the path points to a\n * single skill directory that contains `SKILL.md` directly. Detected\n * automatically when the directory listing includes a `SKILL.md` file entry.\n */\nasync function listSkillsFromBackend(\n backend: AnyBackendProtocol,\n sourcePath: string,\n): Promise<SkillMetadata[]> {\n const adaptedBackend = adaptBackendProtocol(backend);\n const skills: SkillMetadata[] = [];\n\n // Detect path separator (Windows uses \\, Unix uses /)\n const pathSep = sourcePath.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n\n // Normalize path to ensure it ends with the appropriate separator\n const normalizedPath =\n sourcePath.endsWith(\"/\") || sourcePath.endsWith(\"\\\\\")\n ? sourcePath\n : `${sourcePath}${pathSep}`;\n\n // List entries in the source directory (files and subdirectories) via ls\n let fileInfos: { path: string; is_dir?: boolean }[];\n try {\n const lsResult = await adaptedBackend.ls(normalizedPath);\n if (lsResult.error || !lsResult.files) {\n // Source path doesn't exist or can't be listed\n return [];\n }\n fileInfos = lsResult.files;\n } catch {\n // Source path doesn't exist or can't be listed\n return [];\n }\n\n // Convert FileInfo[] to entries format\n // Handle both forward slashes (Unix) and backslashes (Windows) in paths\n const entries = fileInfos.map((info) => ({\n name:\n info.path\n .replace(/[/\\\\]$/, \"\") // Remove trailing slash or backslash\n .split(/[/\\\\]/) // Split on either separator\n .pop() || \"\",\n type: (info.is_dir ? \"directory\" : \"file\") as \"file\" | \"directory\",\n }));\n\n // Direct skill path: SKILL.md lives immediately inside the source directory.\n // The source path itself is the skill — no subdirectory scan needed.\n if (entries.some((e) => e.type === \"file\" && e.name === \"SKILL.md\")) {\n const directoryName =\n normalizedPath\n .replace(/[/\\\\]$/, \"\")\n .split(/[/\\\\]/)\n .pop() || \"\";\n const skillMdPath = `${normalizedPath}SKILL.md`;\n const content = await readFileFromBackend(adaptedBackend, skillMdPath);\n if (content !== null) {\n const metadata = parseSkillMetadataFromContent(\n content,\n skillMdPath,\n directoryName,\n );\n if (metadata) {\n skills.push(metadata);\n }\n }\n return skills;\n }\n\n // Parent directory: scan subdirectories, each expected to contain SKILL.md.\n for (const entry of entries) {\n if (entry.type !== \"directory\") {\n continue;\n }\n\n const skillMdPath = `${normalizedPath}${entry.name}${pathSep}SKILL.md`;\n const content = await readFileFromBackend(adaptedBackend, skillMdPath);\n if (content === null) {\n continue;\n }\n\n const metadata = parseSkillMetadataFromContent(\n content,\n skillMdPath,\n entry.name,\n );\n\n if (metadata) {\n skills.push(metadata);\n }\n }\n\n return skills;\n}\n\n/**\n * Format skills locations for display in system prompt.\n * Shows priority indicator for the last source (highest priority).\n */\nfunction formatSkillsLocations(sources: string[]): string {\n if (sources.length === 0) {\n return \"**Skills Sources:** None configured\";\n }\n\n const lines: string[] = [];\n for (let i = 0; i < sources.length; i++) {\n const sourcePath = sources[i];\n // Extract a friendly name from the path (last non-empty component)\n // Handle both Unix (/) and Windows (\\) path separators\n const name =\n sourcePath\n .replace(/[/\\\\]$/, \"\")\n .split(/[/\\\\]/)\n .filter(Boolean)\n .pop()\n ?.replace(/^./, (c) => c.toUpperCase()) || \"Skills\";\n const suffix = i === sources.length - 1 ? \" (higher priority)\" : \"\";\n lines.push(`**${name} Skills**: \\`${sourcePath}\\`${suffix}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Format skills metadata for display in system prompt.\n * Shows allowed tools for each skill if specified.\n */\nexport function formatSkillsList(\n skills: SkillMetadata[],\n sources: string[],\n): string {\n if (skills.length === 0) {\n const paths = sources.map((s) => `\\`${s}\\``).join(\" or \");\n return `(No skills available yet. You can create skills in ${paths})`;\n }\n\n const lines: string[] = [];\n for (const skill of skills) {\n const annotations = formatSkillAnnotations(skill);\n let descLine = `- **${skill.name}**: ${skill.description}`;\n if (annotations) {\n descLine += ` (${annotations})`;\n }\n lines.push(descLine);\n if (skill.allowedTools && skill.allowedTools.length > 0) {\n lines.push(` → Allowed tools: ${skill.allowedTools.join(\", \")}`);\n }\n lines.push(` → Read \\`${skill.path}\\` for full instructions`);\n if (skill.module !== undefined) {\n lines.push(` → Import: \\`await import(\"@/skills/${skill.name}\")\\``);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Returns true when `value` ends with a recognized skill module extension.\n */\nfunction endsWithModuleExtension(value: string): boolean {\n for (const ext of SKILL_MODULE_EXTENSIONS) {\n if (value.endsWith(ext)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Validate and normalize the `module` frontmatter key from a `SKILL.md`.\n *\n * Returns the normalized path (e.g. `\"index.ts\"`, `\"lib/entry.js\"`) or\n * `undefined` when the key is absent, empty, non-string, absolute, contains\n * path traversal, or uses an unsupported extension. Invalid values silently\n * degrade the skill to prose-only.\n */\nexport function validateModulePath(raw: unknown): string | undefined {\n if (raw === null || raw === undefined) {\n return;\n }\n\n if (typeof raw !== \"string\") {\n return;\n }\n\n const stripped = raw.trim();\n if (stripped === \"\") {\n return;\n }\n\n // Normalize \"./x\" → \"x\" so the value lines up with the keys the loader\n // uses inside the installed module scope. Leaves \"lib/util.js\" untouched.\n const normalized = stripped.startsWith(\"./\") ? stripped.slice(2) : stripped;\n\n if (normalized.startsWith(\"/\")) {\n return;\n }\n\n if (\n normalized === \"..\" ||\n normalized.startsWith(\"../\") ||\n normalized.includes(\"/../\") ||\n normalized.endsWith(\"/..\")\n ) {\n return;\n }\n\n // Declaration files are type-only stubs with no runtime exports.\n if (\n normalized.endsWith(\".d.ts\") ||\n normalized.endsWith(\".d.mts\") ||\n normalized.endsWith(\".d.cts\")\n ) {\n return;\n }\n\n if (!endsWithModuleExtension(normalized)) {\n return;\n }\n\n return normalized;\n}\n\n/**\n * Create backend-agnostic middleware for loading and exposing agent skills.\n *\n * This middleware loads skills from configurable backend sources and injects\n * skill metadata into the system prompt. It implements the progressive disclosure\n * pattern: skill names and descriptions are shown in the prompt, but the agent\n * reads full SKILL.md content only when needed.\n *\n * @param options - Configuration options\n * @returns AgentMiddleware for skills loading and injection\n *\n * @example\n * ```typescript\n * const middleware = createSkillsMiddleware({\n * backend: new FilesystemBackend({ rootDir: \"/\" }),\n * sources: [\"/skills/user/\", \"/skills/project/\"],\n * });\n * ```\n */\nexport function createSkillsMiddleware(options: SkillsMiddlewareOptions) {\n const { backend, sources } = options;\n\n // Closure variable to store loaded skills - wrapModelCall can access this\n // directly since beforeAgent state updates aren't immediately available\n let loadedSkills: SkillMetadata[] = [];\n\n return createMiddleware({\n name: \"SkillsMiddleware\",\n stateSchema: SkillsStateSchema,\n\n async beforeAgent(state) {\n const stateHasSkills =\n \"skillsMetadata\" in state &&\n Array.isArray(state.skillsMetadata) &&\n state.skillsMetadata.length > 0;\n\n if (loadedSkills.length > 0) {\n // Closure has skills from a prior thread — push to state if missing\n // so getCurrentTaskInput() sees them in the tool node.\n return stateHasSkills ? undefined : { skillsMetadata: loadedSkills };\n }\n\n // Check if skills were restored from checkpoint (non-empty array in state)\n if (stateHasSkills) {\n // Restore from state (e.g., after checkpoint restore)\n loadedSkills = state.skillsMetadata as SkillMetadata[];\n return undefined;\n }\n\n const resolvedBackend = await resolveBackend(backend, {\n state,\n });\n const allSkills: Map<string, SkillMetadata> = new Map();\n\n // Load skills from each source in order (later sources override earlier)\n for (const sourcePath of sources) {\n try {\n const skills = await listSkillsFromBackend(\n resolvedBackend,\n sourcePath,\n );\n for (const skill of skills) {\n allSkills.set(skill.name, skill);\n }\n } catch (error) {\n // Log but continue - individual source failures shouldn't break everything\n console.debug(\n `[BackendSkillsMiddleware] Failed to load skills from ${sourcePath}:`,\n error,\n );\n }\n }\n\n // Store in closure for immediate access by wrapModelCall\n loadedSkills = Array.from(allSkills.values());\n\n return { skillsMetadata: loadedSkills };\n },\n\n wrapModelCall(request, handler) {\n // Use closure variable which is populated by beforeAgent\n // Fall back to state for checkpoint restore scenarios\n const skillsMetadata: SkillMetadata[] =\n loadedSkills.length > 0\n ? loadedSkills\n : (request.state?.skillsMetadata as SkillMetadata[]) || [];\n\n // Format skills section\n const skillsLocations = formatSkillsLocations(sources);\n const skillsList = formatSkillsList(skillsMetadata, sources);\n\n const skillsSection = SKILLS_SYSTEM_PROMPT.replace(\n \"{skills_locations}\",\n skillsLocations,\n ).replace(\"{skills_list}\", skillsList);\n\n // Combine with existing system message\n const newSystemMessage = request.systemMessage.concat(skillsSection);\n\n return handler({ ...request, systemMessage: newSystemMessage });\n },\n });\n}\n","/**\n * Callback middleware for async subagents.\n *\n * @experimental - this middleware is experimental and may change in future releases.\n *\n * This middleware sends a notification to a callback thread when a subagent\n * completes successfully or raises an error. The callback agent can then\n * process that notification instead of relying only on polling via\n * `check_async_task`.\n *\n * ## Architecture\n *\n * A parent agent launches a subagent with `start_async_task` and can later\n * inspect task state with `check_async_task`. This middleware adds an optional\n * completion signal by creating a run on the callback thread when the subagent\n * finishes.\n *\n * ```\n * Parent Subagent\n * | |\n * |--- start_async_task -----> |\n * |<-- task_id (immediately) - |\n * | | (working...)\n * | | (done!)\n * | |\n * |<-- runs.create( |\n * | callback_thread, |\n * | \"completed: ...\") |\n * | |\n * | (processes result) |\n * ```\n *\n * The middleware calls `runs.create()` on the callback thread. From the\n * callback agent's perspective, this appears as a new user message containing\n * structured output from the subagent.\n *\n * ## Callback context\n *\n * - `callbackGraphId` identifies the callback graph or assistant. It is\n * provided when the middleware is constructed.\n * - `url` and `headers` optionally configure a remote callback destination.\n * Omit `url` for same-deployment ASGI transport.\n * - `callback_thread_id` is stored in the subagent state by the parent's\n * `start_async_task` tool. Because it is stored in state rather than config,\n * it survives thread updates and interrupts.\n * - If `callback_thread_id` is not present in state, the middleware does\n * nothing.\n *\n * ## Usage\n *\n * ```typescript\n * import { createCompletionCallbackMiddleware } from \"deepagents\";\n *\n * // Same deployment (callback agent and subagent share a server):\n * const notifier = createCompletionCallbackMiddleware({\n * callbackGraphId: \"supervisor\",\n * });\n *\n * // Remote deployment (callback destination on a different server):\n * const notifier = createCompletionCallbackMiddleware({\n * callbackGraphId: \"supervisor\",\n * url: \"https://my-deployment.langsmith.dev\",\n * });\n *\n * const agent = createDeepAgent({\n * model,\n * middleware: [notifier],\n * });\n * ```\n *\n * The middleware reads `callbackThreadId` from the agent state at the end of\n * execution. This value is injected by the parent's `start_async_task` tool\n * when it creates the run.\n *\n * @module\n */\n\nimport * as z from \"zod\";\nimport {\n createMiddleware,\n /**\n * required for type inference\n */\n type AgentMiddleware as _AgentMiddleware,\n} from \"langchain\";\nimport { Client } from \"@langchain/langgraph-sdk\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\n\n/** Maximum characters to include from the last message in notifications. */\nconst MAX_MESSAGE_LENGTH = 500;\n\n/** Suffix appended when truncating long messages. */\nconst TRUNCATION_SUFFIX = \"... [full result truncated]\";\n\n/** State key for the callback thread ID. */\nconst CALLBACK_THREAD_ID_KEY = \"callbackThreadId\" as const;\n\n/**\n * State extension for subagents that use completion callbacks.\n *\n * @experimental - this state schema is experimental and may change in future releases.\n *\n * `callbackThreadId` is written by the parent's `start_async_task` tool\n * and read by `CompletionCallbackMiddleware` when sending callback\n * notifications.\n */\nconst CompletionCallbackStateSchema = z.object({\n /** The callback thread ID. Used to address the notification. */\n [CALLBACK_THREAD_ID_KEY]: z.string().optional(),\n});\n\n/**\n * Options for creating the completion callback middleware.\n */\nexport interface CompletionCallbackOptions {\n /**\n * Callback graph or assistant identifier. Used as the `assistant_id`\n * argument in `runs.create()`.\n */\n callbackGraphId: string;\n\n /**\n * URL of the callback LangGraph server. Omit to use same-deployment\n * ASGI transport.\n */\n url?: string;\n\n /**\n * Additional headers to include in requests to the callback server.\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Build headers for the callback LangGraph server.\n *\n * Ensures `x-auth-scheme: langsmith` is present unless explicitly overridden.\n */\nexport function resolveHeaders(\n headers: Record<string, string> | undefined,\n): Record<string, string> {\n const resolved: Record<string, string> = { ...headers };\n if (!(\"x-auth-scheme\" in resolved)) {\n resolved[\"x-auth-scheme\"] = \"langsmith\";\n }\n return resolved;\n}\n\n/**\n * Send a notification run to the callback thread.\n *\n * @param callbackGraphId - The callback graph ID used as `assistant_id`\n * in the `runs.create` call.\n * @param callbackThreadId - The callback thread ID.\n * @param message - The message content to send.\n * @param options - Optional url and headers for the callback server.\n */\nexport async function notifyParent(\n callbackGraphId: string,\n callbackThreadId: string,\n message: string,\n options?: {\n url?: string;\n headers?: Record<string, string>;\n },\n): Promise<void> {\n try {\n const client = new Client({\n apiUrl: options?.url ?? undefined,\n apiKey: null,\n defaultHeaders: resolveHeaders(options?.headers),\n });\n await client.runs.create(callbackThreadId, callbackGraphId, {\n input: {\n messages: [{ role: \"user\", content: message }],\n },\n });\n } catch (e) {\n // Swallow errors — the notification is best-effort.\n // Log a warning so operators can debug connectivity issues.\n // oxlint-disable-next-line no-console\n console.warn(\n `[CompletionCallbackMiddleware] Failed to notify callback thread ${callbackThreadId}:`,\n e,\n );\n }\n}\n\n/**\n * Extract a summary from the subagent's final message.\n *\n * Returns at most 500 characters from the last message's content.\n * Throws if no messages exist or if the last message is not an AIMessage.\n *\n * @param state - The agent state dict.\n * @param taskId - Optional task ID to include in truncation hint.\n */\nexport function extractLastMessage(\n state: Record<string, unknown>,\n taskId?: string,\n): string {\n const messages = state.messages as BaseMessage[] | undefined;\n if (!messages || messages.length === 0) {\n throw new Error(\n `Expected at least one message in state ${JSON.stringify(state)}`,\n );\n }\n\n const last = messages[messages.length - 1];\n\n if (!AIMessage.isInstance(last)) {\n throw new TypeError(\n `Expected an AIMessage, got ${typeof last === \"object\" && last !== null ? (last.constructor?.name ?? typeof last) : typeof last} instead`,\n );\n }\n\n let textContent = last.text;\n if (textContent.length > MAX_MESSAGE_LENGTH) {\n textContent = textContent.slice(0, MAX_MESSAGE_LENGTH) + TRUNCATION_SUFFIX;\n if (taskId) {\n textContent += ` Result truncated. Use \\`check_async_task(task_id='${taskId}')\\` to retrieve the full result if needed.`;\n }\n }\n\n return textContent;\n}\n\n/**\n * Create a completion callback middleware for async subagents.\n *\n * **Experimental** — this middleware is experimental and may change.\n *\n * This middleware is added to a subagent's middleware stack. On success or\n * model-call error, it sends a notification to the configured callback\n * thread by calling `runs.create()`.\n *\n * The callback destination is configured with `callbackGraphId` and\n * optional `url` and `headers`. The target thread is read from\n * `callbackThreadId` in the subagent state.\n *\n * If `callbackThreadId` is not present in state, the middleware does\n * nothing.\n *\n * @param options - Configuration options.\n * @returns An `AgentMiddleware` instance.\n *\n * @example\n * ```typescript\n * import { createCompletionCallbackMiddleware } from \"deepagents\";\n *\n * const notifier = createCompletionCallbackMiddleware({\n * callbackGraphId: \"supervisor\",\n * });\n *\n * const agent = createDeepAgent({\n * model: \"claude-sonnet-4-5-20250929\",\n * middleware: [notifier],\n * });\n * ```\n */\nexport function createCompletionCallbackMiddleware(\n options: CompletionCallbackOptions,\n) {\n const { callbackGraphId, url, headers } = options;\n\n /**\n * Send a notification to the callback destination.\n */\n async function sendNotification(\n callbackThreadId: string,\n message: string,\n ): Promise<void> {\n await notifyParent(callbackGraphId, callbackThreadId, message, {\n url,\n headers,\n });\n }\n\n /**\n * Read the subagent's own thread_id from runtime config.\n *\n * The subagent's `thread_id` is the same as the `task_id` from the\n * parent's perspective.\n */\n function getTaskId(\n runtime: { configurable?: { thread_id?: string } } | undefined,\n ): string | undefined {\n return runtime?.configurable?.thread_id;\n }\n\n /**\n * Build a notification string with task_id prefix.\n */\n function formatNotification(\n body: string,\n runtime: { configurable?: { thread_id?: string } } | undefined,\n ): string {\n const taskId = getTaskId(runtime);\n const prefix = taskId ? `[task_id=${taskId}]` : \"\";\n return `${prefix}${body}`;\n }\n\n return createMiddleware({\n name: \"CompletionCallbackMiddleware\",\n stateSchema: CompletionCallbackStateSchema,\n\n /**\n * After-agent hook: fires when the subagent completes successfully.\n *\n * Extracts the last message as a summary and sends it to the callback\n * thread.\n */\n async afterAgent(state, runtime) {\n const callbackThreadId = state[CALLBACK_THREAD_ID_KEY] as string;\n // If callbackThreadId is not present, this will be undefined/falsy.\n // Python raises KeyError here; we match that behavior.\n if (callbackThreadId == null) {\n throw new Error(\n `Missing required state key '${CALLBACK_THREAD_ID_KEY}'`,\n );\n }\n const taskId = getTaskId(runtime);\n const summary = extractLastMessage(\n state,\n typeof taskId === \"string\" ? taskId : undefined,\n );\n const notification = formatNotification(\n `Completed. Result: ${summary}`,\n runtime,\n );\n await sendNotification(callbackThreadId, notification);\n return undefined;\n },\n\n /**\n * Wrap model calls to catch errors and notify the callback thread.\n *\n * If a model call raises an exception, a generic error message is\n * reported to the callback thread before re-raising. The actual error\n * details are not leaked to the callback agent.\n */\n async wrapModelCall(request, handler) {\n try {\n return await handler(request);\n } catch (e) {\n const callbackThreadId = request.state[\n CALLBACK_THREAD_ID_KEY\n ] as string;\n if (typeof callbackThreadId === \"string\") {\n const notification = formatNotification(\n \"The agent encountered an error while calling the model.\",\n request.runtime,\n );\n await sendNotification(callbackThreadId, notification);\n }\n throw e;\n }\n },\n });\n}\n","import { Command, ReducedValue, StateSchema } from \"@langchain/langgraph\";\nimport { Client, type DefaultValues, type Run } from \"@langchain/langgraph-sdk\";\nimport {\n createMiddleware,\n tool,\n ToolMessage,\n SystemMessage,\n type ToolRuntime,\n} from \"langchain\";\nimport { z } from \"zod/v4\";\nimport type { AnySubAgent } from \"../types.js\";\n\n/**\n * Specification for an async subagent running on a remote [Agent Protocol](https://github.com/langchain-ai/agent-protocol)\n * server.\n *\n * Async subagents connect to any Agent Protocol-compliant server via the\n * LangGraph SDK. They run as background tasks that the main agent can\n * monitor and update.\n *\n * Compatible with LangGraph Platform (managed) and self-hosted servers.\n * Authentication for LangGraph Platform is handled automatically by the SDK\n * via environment variables (`LANGGRAPH_API_KEY`, `LANGSMITH_API_KEY`, or\n * `LANGCHAIN_API_KEY`). For self-hosted servers, pass custom auth via `headers`.\n */\nexport interface AsyncSubAgent {\n /** Unique identifier for the async subagent. */\n name: string;\n\n /** What this subagent does. The main agent uses this to decide when to delegate. */\n description: string;\n\n /** The graph name or assistant ID on the Agent Protocol server. */\n graphId: string;\n\n /** URL of the Agent Protocol server. Defaults to the LangGraph SDK's default endpoint. */\n url?: string;\n\n /** Additional headers to include in requests to the server (e.g. for custom auth). */\n headers?: Record<string, string>;\n}\n\n/**\n * Possible statuses for an async subagent task.\n *\n * Statuses set by the middleware tools: `\"running\"`, `\"success\"`, `\"error\"`, `\"cancelled\"`.\n * Statuses that may be returned by the remote server: `\"pending\"`, `\"timeout\"`, `\"interrupted\"`.\n */\nexport type AsyncTaskStatus =\n | \"pending\"\n | \"running\"\n | \"success\"\n | \"error\"\n | \"cancelled\"\n | \"timeout\"\n | \"interrupted\";\n\n/**\n * A tracked async subagent task persisted in agent state.\n *\n * Each task maps to a single thread + run on a remote Agent Protocol server.\n * The `taskId` is the same as `threadId`, so it can be used to look up\n * the thread directly via the SDK.\n */\nexport interface AsyncTask {\n /** Unique identifier for the task (same as thread id). */\n taskId: string;\n\n /** Name of the async subagent type that is running. */\n agentName: string;\n\n /** Thread ID on the remote server. */\n threadId: string;\n\n /** Run ID for the current execution on the thread. */\n runId: string;\n\n /** Current task status. */\n status: AsyncTaskStatus;\n\n /** ISO timestamp of when the task was launched. */\n createdAt: string;\n\n /** The prompt/description passed to the subagent when the task was launched. */\n description?: string;\n\n /** ISO timestamp of the most recent task update — set when the task status changes or a follow-up message is sent via the update tool. */\n updatedAt?: string;\n\n /** ISO timestamp of the most recent status poll via the check tool. */\n checkedAt?: string;\n}\n\n/**\n * Shape of the async subagent state channel.\n *\n * Used with {@link ToolRuntime} so tools get typed access to `asyncTasks`.\n *\n * Declared as a `type` (not `interface`) so `ToolRuntime<AsyncTaskState>` narrows\n * `runtime.state` correctly (see `@langchain/core` `ToolRuntime` conditional).\n */\ntype AsyncTaskState = {\n /** All tracked async subagent tasks, keyed by task ID. */\n asyncTasks?: Record<string, AsyncTask>;\n};\n\nfunction toolCallIdFromRuntime(runtime: ToolRuntime<AsyncTaskState>): string {\n return runtime.toolCall?.id ?? runtime.toolCallId ?? \"\";\n}\n\n/**\n * Result of checking an async subagent's run status.\n *\n * Returned by `buildCheckResult` and used by `buildCheckTool`\n * to construct the `Command` update.\n */\ninterface CheckResult {\n /** Current status of the run. */\n status: AsyncTaskStatus;\n\n /** The thread ID on the remote server. */\n threadId: string;\n\n /** The last message content from the subagent, if the run succeeded. */\n result?: string;\n\n /** Error description, if the run errored. */\n error?: string;\n}\n\n/**\n * Zod schema for {@link AsyncTask}.\n *\n * Used by the {@link ReducedValue} in the state schema so that LangGraph\n * can validate and serialize task records stored in `asyncTasks`.\n */\nconst AsyncTaskSchema = z.object({\n taskId: z.string(),\n agentName: z.string(),\n threadId: z.string(),\n runId: z.string(),\n status: z.string(),\n createdAt: z.string(),\n description: z.string().optional(),\n updatedAt: z.string().optional(),\n checkedAt: z.string().optional(),\n});\n\n/**\n * State schema for the async subagent middleware.\n *\n * Declares `asyncTasks` as a reduced state channel so that individual\n * tool updates (launch, check, update, cancel, list) merge into the existing\n * tasks dict rather than replacing it wholesale.\n */\nconst AsyncTaskStateSchema = new StateSchema({\n asyncTasks: new ReducedValue(\n z.record(z.string(), AsyncTaskSchema).default(() => ({})),\n {\n inputSchema: z.record(z.string(), AsyncTaskSchema).optional(),\n reducer: asyncTasksReducer,\n },\n ),\n});\n\n/**\n * Reducer for the `asyncTasks` state channel.\n *\n * Merges task updates into the existing tasks dict using shallow spread.\n * This allows individual tools to update a single task without overwriting\n * the full map — only the keys present in `update` are replaced.\n *\n * @param existing - The current tasks dict from state (may be undefined on first write).\n * @param update - New or updated task entries to merge in.\n * @returns Merged tasks dict.\n */\nexport function asyncTasksReducer(\n existing?: Record<string, AsyncTask>,\n update?: Record<string, AsyncTask>,\n): Record<string, AsyncTask> {\n return { ...(existing || {}), ...(update || {}) };\n}\n\n/**\n * Description template for the `start_async_task` tool.\n *\n * The `{available_agents}` placeholder is replaced at middleware creation\n * time with a formatted list of configured async subagent names and descriptions.\n */\nconst ASYNC_TASK_TOOL_DESCRIPTION = `Launch an async subagent on a remote server. The subagent runs in the background and returns a task ID immediately.\n\nAvailable async agent types:\n{available_agents}\n\n## Usage notes:\n1. This tool launches a background task and returns immediately with a task ID. Report the task ID to the user and stop — do NOT immediately check status.\n2. Use \\`check_async_task\\` only when the user asks for a status update or result.\n3. Use \\`update_async_task\\` to send new instructions to a running task.\n4. Multiple async subagents can run concurrently — launch several and let them run in the background.\n5. The subagent runs on a remote server, so it has its own tools and capabilities.`;\n\n/**\n * Task statuses that will never change.\n *\n * When listing tasks, live-status fetches are skipped for tasks whose\n * cached status is in this set, since they are guaranteed to be final.\n */\n/**\n * Names of the tools added by the async subagent middleware.\n *\n * Exported so `agent.ts` can include them in `BUILTIN_TOOL_NAMES` and\n * surface a `ConfigurationError` if a user-provided tool collides.\n */\nexport const ASYNC_TASK_TOOL_NAMES = [\n \"start_async_task\",\n \"check_async_task\",\n \"update_async_task\",\n \"cancel_async_task\",\n \"list_async_tasks\",\n] as const;\n\nexport const TERMINAL_STATUSES = new Set<AsyncTaskStatus>([\n \"cancelled\",\n \"success\",\n \"error\",\n \"timeout\",\n \"interrupted\",\n]);\n\n/**\n * Look up a tracked task from state by its `taskId`.\n *\n * @param taskId - The task ID to look up (will be trimmed).\n * @param state - The current agent state containing `asyncTasks`.\n * @returns The tracked task on success, or an error string.\n */\nfunction resolveTrackedTask(\n taskId: string,\n state: AsyncTaskState,\n): AsyncTask | string {\n const tasks = state.asyncTasks ?? {};\n const tracked = tasks[taskId.trim()];\n if (!tracked) {\n return `No tracked task found for taskId: '${taskId}'`;\n }\n return tracked;\n}\n\n/**\n * Build a check result from a run's current status and thread state values.\n *\n * For successful runs, extracts the last message's content from the remote\n * thread's state values. For errored runs, includes a generic error message.\n *\n * @param run - The run object from the SDK.\n * @param threadId - The thread ID for the run.\n * @param threadValues - The `values` from `ThreadState` (the remote subagent's state).\n */\nfunction buildCheckResult(\n run: Run,\n threadId: string,\n threadValues: DefaultValues,\n): CheckResult {\n const checkResult: CheckResult = {\n status: run.status as AsyncTaskStatus,\n threadId,\n };\n\n if (run.status === \"success\") {\n const values = Array.isArray(threadValues) ? {} : threadValues;\n const messages = (values?.messages ?? []) as unknown[];\n if (messages.length > 0) {\n const last = messages[messages.length - 1];\n const rawContent =\n typeof last === \"object\" && last !== null && \"content\" in last\n ? (last as Record<string, unknown>).content\n : last;\n checkResult.result =\n typeof rawContent === \"string\"\n ? rawContent\n : JSON.stringify(rawContent);\n } else {\n checkResult.result = \"Completed with no output messages.\";\n }\n } else if (run.status === \"error\") {\n checkResult.error = \"The async subagent encountered an error.\";\n }\n\n return checkResult;\n}\n\n/**\n * Filter tasks by cached status from agent state.\n *\n * Filtering uses the cached status, not live server status. Live statuses\n * are fetched after filtering by the calling tool.\n *\n * @param tasks - All tracked tasks from state.\n * @param statusFilter - If nullish or `'all'`, return all tasks.\n * Otherwise return only tasks whose cached status matches.\n */\nfunction filterTasks(\n tasks: Record<string, AsyncTask>,\n statusFilter?: string,\n): AsyncTask[] {\n if (!statusFilter || statusFilter === \"all\") {\n return Object.values(tasks);\n }\n return Object.values(tasks).filter((task) => task.status === statusFilter);\n}\n\n/**\n * Fetch the current run status from the server.\n *\n * Returns the cached status immediately for terminal tasks (avoiding\n * unnecessary API calls). Falls back to the cached status on SDK errors.\n */\nasync function fetchLiveTaskStatus(\n clients: ClientCache,\n task: AsyncTask,\n): Promise<AsyncTaskStatus> {\n if (TERMINAL_STATUSES.has(task.status)) {\n return task.status;\n }\n\n try {\n const client = clients.getClient(task.agentName);\n const run = await client.runs.get(task.threadId, task.runId);\n return run.status as AsyncTaskStatus;\n } catch {\n return task.status;\n }\n}\n\n/**\n * Format a single task as a display string for list output.\n */\nfunction formatTaskEntry(task: AsyncTask, status: AsyncTaskStatus): string {\n return `- taskId: ${task.taskId} agent: ${task.agentName} status: ${status}`;\n}\n\n/**\n * Lazily-created, cached LangGraph SDK clients keyed by (url, headers).\n *\n * Agents that share the same URL and headers will reuse a single `Client`\n * instance, avoiding unnecessary connections.\n */\nexport class ClientCache {\n private agents: Record<string, AsyncSubAgent>;\n private clients = new Map<string, Client>();\n\n constructor(agents: Record<string, AsyncSubAgent>) {\n this.agents = agents;\n }\n\n /**\n * Build headers for a remote Agent Protocol server.\n *\n * Adds `x-auth-scheme: langsmith` by default unless already provided.\n * For self-hosted servers that don't require this header, it is typically\n * ignored. Override via the `headers` field on the AsyncSubAgent config.\n */\n private resolveHeaders(spec: AsyncSubAgent): Record<string, string> {\n const headers = { ...(spec.headers || {}) };\n if (!(\"x-auth-scheme\" in headers)) {\n headers[\"x-auth-scheme\"] = \"langsmith\";\n }\n return headers;\n }\n\n /**\n * Build a stable cache key from a spec's url and resolved headers.\n */\n private cacheKey(spec: AsyncSubAgent): string {\n const headers = this.resolveHeaders(spec);\n const headerStr = Object.entries(headers).sort().flat().join(\":\");\n return `${spec.url ?? \"\"}|${headerStr}`;\n }\n\n /**\n * Get or create a `Client` for the named agent.\n */\n getClient(name: string): Client {\n const spec = this.agents[name];\n const key = this.cacheKey(spec);\n\n const existing = this.clients.get(key);\n if (existing) return existing;\n\n const headers = this.resolveHeaders(spec);\n const client = new Client({\n apiUrl: spec.url,\n defaultHeaders: headers,\n });\n this.clients.set(key, client);\n\n return client;\n }\n}\n\n/**\n * Extract the callback thread ID from the tool runtime.\n *\n * The thread ID is included in the subagent's input state so the subagent\n * can notify the parent when it completes (via\n * `CompletionCallbackMiddleware`).\n *\n * @returns Object with `callbackThreadId` if available. Empty object otherwise.\n */\nexport function extractCallbackContext(\n runtime: ToolRuntime<AsyncTaskState>,\n): Record<string, string> {\n const configurable = runtime.config?.configurable as\n | Record<string, unknown>\n | undefined;\n const threadId = configurable?.thread_id;\n if (typeof threadId === \"string\" && threadId) {\n return { callbackThreadId: threadId };\n }\n return {};\n}\n\n/**\n * Build the `start_async_task` tool.\n *\n * Creates a thread on the remote server, starts a run, and returns a\n * `Command` that persists the new task in state.\n */\nexport function buildStartTool(\n agentMap: Record<string, AsyncSubAgent>,\n clients: ClientCache,\n toolDescription: string,\n) {\n return tool(\n async (\n input,\n runtime: ToolRuntime<AsyncTaskState>,\n ): Promise<Command | string> => {\n if (!(input.agentName in agentMap)) {\n const allowed = Object.keys(agentMap)\n .map((k) => `\\`${k}\\``)\n .join(\", \");\n return `Unknown async subagent type \\`${input.agentName}\\`. Available types: ${allowed}`;\n }\n\n const spec = agentMap[input.agentName];\n const callbackContext = extractCallbackContext(runtime);\n try {\n const client = clients.getClient(input.agentName);\n const thread = await client.threads.create();\n const run = await client.runs.create(thread.thread_id, spec.graphId, {\n input: {\n messages: [{ role: \"user\", content: input.description }],\n ...callbackContext,\n },\n });\n\n const taskId = thread.thread_id;\n const task: AsyncTask = {\n taskId,\n agentName: input.agentName,\n threadId: taskId,\n runId: run.run_id,\n status: \"running\",\n createdAt: new Date().toISOString(),\n description: input.description,\n };\n\n return new Command({\n update: {\n messages: [\n new ToolMessage({\n content: `Launched async subagent. taskId: ${taskId}`,\n tool_call_id: toolCallIdFromRuntime(runtime),\n }),\n ],\n asyncTasks: { [taskId]: task },\n },\n });\n } catch (e) {\n return `Failed to launch async subagent '${input.agentName}': ${e}`;\n }\n },\n {\n name: \"start_async_task\",\n description: toolDescription,\n schema: z.object({\n description: z\n .string()\n .describe(\n \"A detailed description of the task for the async subagent to perform.\",\n ),\n agentName: z\n .string()\n .describe(\n \"The type of async subagent to use. Must be one of the available types listed in the tool description.\",\n ),\n }),\n },\n );\n}\n\n/**\n * Build the `check_async_task` tool.\n *\n * Fetches the current run status from the remote server and, if the run\n * succeeded, retrieves the thread state to extract the result.\n */\nexport function buildCheckTool(clients: ClientCache) {\n return tool(\n async (\n input,\n runtime: ToolRuntime<AsyncTaskState>,\n ): Promise<Command | string> => {\n const task = resolveTrackedTask(input.taskId, runtime.state);\n if (typeof task === \"string\") return task;\n\n const client = clients.getClient(task.agentName);\n let run: Run;\n try {\n run = await client.runs.get(task.threadId, task.runId);\n } catch (e) {\n return `Failed to get run status: ${e}`;\n }\n\n let threadValues: DefaultValues = {};\n if (run.status === \"success\") {\n try {\n const threadState = await client.threads.getState(task.threadId);\n threadValues = (threadState.values as DefaultValues) || {};\n } catch {\n // Thread state fetch failed — still report success, just without the output\n }\n }\n\n const result = buildCheckResult(run, task.threadId, threadValues);\n const updatedTask: AsyncTask = {\n taskId: task.taskId,\n agentName: task.agentName,\n threadId: task.threadId,\n runId: task.runId,\n status: result.status,\n createdAt: task.createdAt,\n updatedAt:\n result.status !== task.status\n ? new Date().toISOString()\n : task.updatedAt,\n checkedAt: new Date().toISOString(),\n };\n\n return new Command({\n update: {\n messages: [\n new ToolMessage({\n content: JSON.stringify(result),\n tool_call_id: toolCallIdFromRuntime(runtime),\n }),\n ],\n asyncTasks: { [task.taskId]: updatedTask },\n },\n });\n },\n {\n name: \"check_async_task\",\n description:\n \"Check the status of an async subagent task. Returns the current status and, if complete, the result. Statuses shown earlier in the conversation are always stale, so call this to get the current status rather than reporting a status from a previous tool result.\",\n schema: z.object({\n taskId: z\n .string()\n .describe(\n \"The exact taskId string returned by start_async_task. Pass it verbatim.\",\n ),\n }),\n },\n );\n}\n\n/**\n * Build the `update_async_task` tool.\n *\n * Sends a follow-up message to a running async subagent by creating a new\n * run on the same thread with `multitaskStrategy: \"interrupt\"`. The subagent\n * sees the full conversation history plus the new message. The `taskId`\n * remains the same; only the internal `runId` is updated.\n */\nexport function buildUpdateTool(\n agentMap: Record<string, AsyncSubAgent>,\n clients: ClientCache,\n) {\n return tool(\n async (\n input,\n runtime: ToolRuntime<AsyncTaskState>,\n ): Promise<Command | string> => {\n const tracked = resolveTrackedTask(input.taskId, runtime.state);\n if (typeof tracked === \"string\") return tracked;\n\n const spec = agentMap[tracked.agentName];\n try {\n const client = clients.getClient(tracked.agentName);\n const run = await client.runs.create(tracked.threadId, spec.graphId, {\n input: {\n messages: [{ role: \"user\", content: input.message }],\n },\n multitaskStrategy: \"interrupt\",\n });\n\n const task: AsyncTask = {\n taskId: tracked.taskId,\n agentName: tracked.agentName,\n threadId: tracked.threadId,\n runId: run.run_id,\n status: \"running\",\n createdAt: tracked.createdAt,\n description: input.message,\n updatedAt: new Date().toISOString(),\n checkedAt: tracked.checkedAt,\n };\n\n return new Command({\n update: {\n messages: [\n new ToolMessage({\n content: `Updated async subagent. taskId: ${tracked.taskId}`,\n tool_call_id: toolCallIdFromRuntime(runtime),\n }),\n ],\n asyncTasks: { [tracked.taskId]: task },\n },\n });\n } catch (e) {\n return `Failed to update async subagent: ${e}`;\n }\n },\n {\n name: \"update_async_task\",\n description:\n \"send updated instructions to an async subagent. Interrupts the current run and starts a new one on the same thread so the subagent sees the full conversation history plus your new message. The taskId remains the same.\",\n schema: z.object({\n taskId: z\n .string()\n .describe(\n \"The exact taskId string returned by start_async_task. Pass it verbatim.\",\n ),\n message: z\n .string()\n .describe(\n \"Follow-up instructions or context to send to the subagent\",\n ),\n }),\n },\n );\n}\n\n/**\n * Build the `cancel_async_task` tool.\n *\n * Cancels the current run on the remote server and updates the task's\n * cached status to `\"cancelled\"`.\n */\nexport function buildCancelTool(clients: ClientCache) {\n return tool(\n async (\n input,\n runtime: ToolRuntime<AsyncTaskState>,\n ): Promise<Command | string> => {\n const tracked = resolveTrackedTask(input.taskId, runtime.state);\n if (typeof tracked === \"string\") return tracked;\n\n const client = clients.getClient(tracked.agentName);\n try {\n await client.runs.cancel(tracked.threadId, tracked.runId);\n } catch (e) {\n return `Failed to cancel run: ${e}`;\n }\n\n const updated: AsyncTask = {\n taskId: tracked.taskId,\n agentName: tracked.agentName,\n threadId: tracked.threadId,\n runId: tracked.runId,\n status: \"cancelled\",\n createdAt: tracked.createdAt,\n updatedAt: new Date().toISOString(),\n checkedAt: tracked.checkedAt,\n };\n\n return new Command({\n update: {\n messages: [\n new ToolMessage({\n content: `Cancelled async subagent task: ${tracked.taskId}`,\n tool_call_id: toolCallIdFromRuntime(runtime),\n }),\n ],\n asyncTasks: { [tracked.taskId]: updated },\n },\n });\n },\n {\n name: \"cancel_async_task\",\n description:\n \"Cancel a running async subagent task. Use this to stop a task that is no longer needed.\",\n schema: z.object({\n taskId: z\n .string()\n .describe(\n \"The exact taskId string returned by start_async_task. Pass it verbatim.\",\n ),\n }),\n },\n );\n}\n\n/**\n * Build the `list_async_tasks` tool.\n *\n * Lists all tracked tasks with their live statuses fetched in parallel.\n * Supports optional filtering by cached status.\n */\nexport function buildListTool(clients: ClientCache) {\n return tool(\n async (\n input,\n runtime: ToolRuntime<AsyncTaskState>,\n ): Promise<Command | string> => {\n const tasks = runtime.state.asyncTasks ?? {};\n const filtered = filterTasks(tasks, input.statusFilter ?? undefined);\n\n if (filtered.length === 0) {\n return \"No async subagent tasks tracked\";\n }\n\n const statuses = await Promise.all(\n filtered.map((task) => fetchLiveTaskStatus(clients, task)),\n );\n\n const updatedTasks: Record<string, AsyncTask> = {};\n const entries: string[] = [];\n for (let idx = 0; idx < filtered.length; idx++) {\n const task = filtered[idx];\n const status = statuses[idx];\n\n const taskEntry = formatTaskEntry(task, status);\n entries.push(taskEntry);\n\n updatedTasks[task.taskId] = {\n taskId: task.taskId,\n agentName: task.agentName,\n threadId: task.threadId,\n runId: task.runId,\n status,\n createdAt: task.createdAt,\n updatedAt:\n status !== task.status ? new Date().toISOString() : task.updatedAt,\n checkedAt: task.checkedAt,\n };\n }\n\n return new Command({\n update: {\n messages: [\n new ToolMessage({\n content: `${entries.length} tracked task(s):\\n${entries.join(\"\\n\")}`,\n tool_call_id: toolCallIdFromRuntime(runtime),\n }),\n ],\n asyncTasks: updatedTasks,\n },\n });\n },\n {\n name: \"list_async_tasks\",\n description:\n \"List tracked async subagent tasks with their current live statuses. By default shows all tasks. Use `statusFilter` to narrow by status (e.g., 'running', 'success', 'error', 'cancelled'). Use `check_async_task` to get the full result of a specific completed task. Statuses shown earlier in the conversation are always stale, so call this to read current statuses rather than reporting one from a previous tool result.\",\n schema: z.object({\n statusFilter: z\n .string()\n .nullish()\n .describe(\n \"Filter tasks by status. One of: 'running', 'success', 'error', 'cancelled', 'all'. Defaults to 'all'.\",\n ),\n }),\n },\n );\n}\n\n/**\n * Options for creating async subagent middleware.\n */\nexport interface AsyncSubAgentMiddlewareOptions {\n /** List of async subagent specifications. Must have at least one. */\n asyncSubAgents: AsyncSubAgent[];\n /** Optional system prompt override. Tool schemas provide the built-in guidance. */\n systemPrompt?: string | null;\n}\n\n/**\n * Create middleware that adds async subagent tools to an agent.\n *\n * Provides five tools for launching, checking, updating, cancelling, and\n * listing background tasks on remote Agent Protocol servers. Task state is\n * persisted in the `asyncTasks` state channel so it survives\n * context compaction.\n *\n * Works with any Agent Protocol-compliant server — LangGraph Platform (managed)\n * or self-hosted (e.g. a Hono/Express server implementing the Agent Protocol spec).\n *\n * @throws {Error} If no async subagents are provided or names are duplicated.\n *\n * @example\n * ```ts\n * const middleware = createAsyncSubAgentMiddleware({\n * asyncSubAgents: [{\n * name: \"researcher\",\n * description: \"Research agent for deep analysis\",\n * url: \"https://my-agent-protocol-server.example.com\",\n * graphId: \"research_agent\",\n * }],\n * });\n * ```\n */\n\n/**\n * Type guard to distinguish async SubAgents from sync SubAgents/CompiledSubAgents.\n *\n * Uses the presence of the `graphId` field as the runtime discriminant —\n * `AsyncSubAgent` requires it, while `SubAgent` and `CompiledSubAgent` do not have it.\n */\nexport function isAsyncSubAgent(\n subAgent: AnySubAgent,\n): subAgent is AsyncSubAgent {\n return \"graphId\" in subAgent;\n}\n\nexport function createAsyncSubAgentMiddleware(\n options: AsyncSubAgentMiddlewareOptions,\n) {\n const { asyncSubAgents, systemPrompt = null } = options;\n\n if (!asyncSubAgents || asyncSubAgents.length === 0) {\n throw new Error(\"At least one async subagent must be specified\");\n }\n\n const names = asyncSubAgents.map((a) => a.name);\n const duplicates = names.filter((n, i) => names.indexOf(n) !== i);\n if (duplicates.length > 0) {\n throw new Error(\n `Duplicate async subagent names: ${[...new Set(duplicates)].join(\", \")}`,\n );\n }\n\n const agentMap = Object.fromEntries(asyncSubAgents.map((a) => [a.name, a]));\n const clients = new ClientCache(agentMap);\n\n const agentsDescription = asyncSubAgents\n .map((a) => `- ${a.name}: ${a.description}`)\n .join(\"\\n\");\n const launchDescription = ASYNC_TASK_TOOL_DESCRIPTION.replace(\n \"{available_agents}\",\n agentsDescription,\n );\n\n const tools = [\n buildStartTool(agentMap, clients, launchDescription),\n buildCheckTool(clients),\n buildUpdateTool(agentMap, clients),\n buildCancelTool(clients),\n buildListTool(clients),\n ];\n\n const fullSystemPrompt = systemPrompt\n ? `${systemPrompt}\\n\\nAvailable async subagent types:\\n${agentsDescription}`\n : null;\n\n return createMiddleware({\n name: \"asyncSubAgentMiddleware\",\n stateSchema: AsyncTaskStateSchema,\n tools,\n wrapModelCall: async (request, handler) => {\n if (fullSystemPrompt !== null) {\n return handler({\n ...request,\n systemMessage: request.systemMessage.concat(\n new SystemMessage({ content: fullSystemPrompt }),\n ),\n });\n }\n return handler(request);\n },\n });\n}\n","/**\n * Error codes for {@link ConfigurationError}.\n *\n * Each code represents a distinct misconfiguration that can be detected at\n * agent-construction time. Add new codes here as new validations are added.\n */\nexport type ConfigurationErrorCode = \"TOOL_NAME_COLLISION\";\n\nconst CONFIGURATION_ERROR_SYMBOL = Symbol.for(\"deepagents.configuration_error\");\n\n/**\n * Thrown when `createDeepAgent` receives invalid configuration.\n *\n * Follows the same pattern as {@link SandboxError}: a human-readable\n * `message`, a structured `code` for programmatic handling, and a\n * static `isInstance` guard that works across realms.\n *\n * @example\n * ```typescript\n * try {\n * createDeepAgent({ tools: [myTool] });\n * } catch (error) {\n * if (ConfigurationError.isInstance(error)) {\n * switch (error.code) {\n * case \"TOOL_NAME_COLLISION\":\n * console.error(\"Rename your tool:\", error.message);\n * break;\n * }\n * }\n * }\n * ```\n */\nexport class ConfigurationError extends Error {\n [CONFIGURATION_ERROR_SYMBOL] = true as const;\n\n override readonly name: string = \"ConfigurationError\";\n\n constructor(\n message: string,\n public readonly code: ConfigurationErrorCode,\n public readonly cause?: Error,\n ) {\n super(message);\n Object.setPrototypeOf(this, ConfigurationError.prototype);\n }\n\n static isInstance(error: unknown): error is ConfigurationError {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as Record<symbol, unknown>)[CONFIGURATION_ERROR_SYMBOL] === true\n );\n }\n}\n","import { createMiddleware, SystemMessage } from \"langchain\";\n\n/**\n * Import langchain for type inference\n */\nimport type * as _langchain from \"langchain\";\n\nimport { isAnthropicModel } from \"../utils.js\";\n\n/**\n * Creates a middleware that places a cache breakpoint at the end of the static\n * system prompt content.\n *\n * This middleware tags the last block of the system message with\n * `cache_control: { type: \"ephemeral\" }` at the time it runs, capturing all\n * static content injected by preceding middleware (e.g. todo list instructions,\n * filesystem tools, subagent instructions) in a single cache breakpoint.\n *\n * This should run after all static system prompt middleware and before any\n * dynamic middleware (e.g. memory) so the breakpoint sits at the boundary\n * between stable and changing content.\n *\n * When used alongside memory middleware (which adds its own breakpoint on the\n * memory block), the result is two separate cache breakpoints:\n * - One covering all static content\n * - One covering the memory block\n *\n * The `cache_control` marker is Anthropic-specific. The middleware is gated\n * per-call on `request.model` so it is a no-op when `modelFallbackMiddleware`\n * (or any other middleware) has swapped the request to a non-Anthropic\n * provider. Without this gate, the marker leaks to providers that reject it\n * (e.g. OpenAI returns `400 Unknown parameter: 'cache_control'`).\n *\n * This is a no-op when the system message has no content blocks.\n */\nexport function createCacheBreakpointMiddleware() {\n return createMiddleware({\n name: \"CacheBreakpointMiddleware\",\n\n wrapModelCall(request, handler) {\n // Per-call provider gate: the boot-time install gate in createDeepAgent\n // looks at the *primary* model, but modelFallbackMiddleware can swap\n // request.model at request time. Cache markers must only be written\n // when this specific call is going to Anthropic.\n if (!isAnthropicModel(request.model)) return handler(request);\n\n const existingContent = request.systemMessage.content;\n const existingBlocks =\n typeof existingContent === \"string\"\n ? [{ type: \"text\" as const, text: existingContent }]\n : Array.isArray(existingContent)\n ? [...existingContent]\n : [];\n\n if (existingBlocks.length === 0) return handler(request);\n\n existingBlocks[existingBlocks.length - 1] = {\n ...existingBlocks[existingBlocks.length - 1],\n cache_control: { type: \"ephemeral\" },\n };\n\n return handler({\n ...request,\n systemMessage: new SystemMessage({ content: existingBlocks }),\n });\n },\n });\n}\n","import { ToolMessage } from \"@langchain/core/messages\";\nimport { createMiddleware, type AgentMiddleware } from \"langchain\";\n\nfunction hasToolName(tool: unknown): tool is { name: string } {\n return (\n tool !== null &&\n typeof tool === \"object\" &&\n \"name\" in tool &&\n typeof tool.name === \"string\"\n );\n}\n\n/**\n * Create middleware that hides excluded tools from the model and rejects calls\n * to them. Exclusions calibrate the agent per model; they are not a security\n * boundary.\n *\n * @internal\n */\nexport function createToolExclusionMiddleware(\n excludedTools: ReadonlySet<string>,\n): AgentMiddleware {\n return createMiddleware({\n name: \"_ToolExclusionMiddleware\",\n wrapModelCall(request, handler) {\n return handler({\n ...request,\n tools: request.tools?.filter(\n (tool) => !hasToolName(tool) || !excludedTools.has(tool.name),\n ),\n });\n },\n wrapToolCall(request, handler) {\n const { name, id } = request.toolCall;\n if (!excludedTools.has(name)) {\n return handler(request);\n }\n return new ToolMessage({\n content: `Error: ${name} is not available.`,\n tool_call_id: id ?? \"\",\n name,\n status: \"error\",\n });\n },\n });\n}\n","/**\n * Normalize and validate a profile registry key.\n *\n * Trims leading/trailing whitespace, then enforces the `\"provider\"` or\n * `\"provider:model\"` shape. Rejects empty strings, multiple colons, and\n * empty halves.\n *\n * @param key - The registry key to validate.\n * @returns The trimmed, validated key.\n * @throws {Error} When the key is malformed.\n *\n * @example\n * ```typescript\n * validateProfileKey(\"anthropic:claude-opus-4-7\"); // \"anthropic:claude-opus-4-7\"\n * validateProfileKey(\" openai \"); // \"openai\"\n * validateProfileKey(\"openai:\"); // throws\n * validateProfileKey(\"\"); // throws\n * ```\n */\nexport function validateProfileKey(key: string): string {\n const trimmed = key.trim();\n if (!trimmed) {\n throw new Error(\"Profile key must be a non-empty string\");\n }\n\n if (trimmed.split(\":\").length > 2) {\n throw new Error(\n `Profile key \"${trimmed}\" has more than one \":\"; expected \"provider\" or \"provider:model\"`,\n );\n }\n\n if (trimmed.includes(\":\")) {\n const [provider, model] = trimmed.split(\":\");\n if (!provider.trim() || !model.trim()) {\n throw new Error(\n `Profile key \"${trimmed}\" has an empty provider or model half; expected \"provider:model\"`,\n );\n }\n }\n\n return trimmed;\n}\n","import type { AgentMiddleware } from \"langchain\";\n\n/**\n * Middleware names that provide essential agent capabilities and cannot\n * be excluded via `excludedMiddleware`.\n *\n * - `FilesystemMiddleware` backs all built-in file tools and enforces\n * filesystem permissions.\n * - `SubAgentMiddleware` backs the `task` tool for subagent delegation.\n */\nexport const REQUIRED_MIDDLEWARE_NAMES = new Set([\n \"FilesystemMiddleware\",\n \"SubAgentMiddleware\",\n]);\n\n/**\n * Configuration for the auto-added general-purpose subagent.\n *\n * All fields use three-state semantics: `undefined` inherits the\n * default, an explicit value overrides it. This allows model-level\n * profiles to selectively override provider-level defaults without\n * clobbering fields they don't care about.\n */\nexport interface GeneralPurposeSubagentConfig {\n /**\n * Whether to auto-add the general-purpose subagent.\n *\n * - `undefined` — inherit the default (enabled).\n * - `true` — force inclusion even if a provider profile disables it.\n * - `false` — disable the GP subagent entirely.\n *\n * @default undefined\n */\n enabled?: boolean;\n\n /**\n * Override the default GP subagent description shown to the model.\n *\n * @default undefined (uses `DEFAULT_GENERAL_PURPOSE_DESCRIPTION`)\n */\n description?: string;\n\n /**\n * Override the default GP subagent system prompt.\n *\n * When both this and `HarnessProfile.baseSystemPrompt` are set, this\n * more-specific value wins for the GP subagent.\n *\n * @default undefined (uses `DEFAULT_SUBAGENT_PROMPT`)\n */\n systemPrompt?: string;\n}\n\n/**\n * User-facing options for creating a {@link HarnessProfile}.\n *\n * Accepts plain arrays and records; the factory function converts them\n * to their frozen counterparts. All fields are optional — an empty\n * object produces a no-op profile.\n */\nexport interface HarnessProfileOptions {\n /**\n * Replaces the default empty base prompt when set.\n *\n * Use this when a model requires a fundamentally different base\n * prompt rather than an additive suffix. Most profiles should prefer\n * `systemPromptSuffix` instead.\n *\n * @default undefined (keeps the default empty base prompt)\n */\n baseSystemPrompt?: string;\n\n /**\n * Text appended to the assembled base prompt with a blank-line\n * separator (`\\n\\n`).\n *\n * This is the primary mechanism for model-specific prompt tuning.\n * Applied uniformly to the main agent, declarative subagents, and\n * the auto-added general-purpose subagent.\n *\n * @default undefined (no suffix appended)\n */\n systemPromptSuffix?: string;\n\n /**\n * Per-tool description replacements keyed by tool name.\n *\n * Allows profiles to rewrite tool descriptions for models that\n * respond better to different phrasing. Keys that don't match any\n * tool in the final tool set are silently ignored.\n *\n * @default {} (no overrides)\n */\n toolDescriptionOverrides?: Record<string, string>;\n\n /**\n * Tool names to remove from the agent's visible tool set and reject at the\n * tool-call boundary.\n *\n * Applied via middleware after all tool-injecting middleware have run, so it\n * catches both user-provided and middleware-provided tools. Each declarative\n * subagent uses the profile resolved for its own model. Exclusions are\n * model-facing calibration, not a security boundary.\n *\n * @default [] (no tools excluded)\n */\n excludedTools?: string[];\n\n /**\n * Middleware names to remove from the assembled middleware stack.\n *\n * Matched against each middleware's `.name` property. Cannot include\n * required scaffolding names (`FilesystemMiddleware`,\n * `SubAgentMiddleware`) — attempting to do so throws at construction\n * time.\n *\n * @default [] (no middleware excluded)\n */\n excludedMiddleware?: string[];\n\n /**\n * Additional middleware appended to the stack after user middleware.\n *\n * Can be a static array or a zero-arg factory that returns fresh\n * instances per agent construction (important when middleware carries\n * mutable state).\n *\n * @default [] (no extra middleware)\n */\n extraMiddleware?: AgentMiddleware[] | (() => AgentMiddleware[]);\n\n /**\n * Configuration for the auto-added general-purpose subagent.\n *\n * @default undefined (GP subagent uses all defaults)\n */\n generalPurposeSubagent?: GeneralPurposeSubagentConfig;\n}\n\n/**\n * Frozen runtime harness profile that shapes agent behavior at\n * assembly time.\n *\n * Created by {@link createHarnessProfile} from user-provided\n * {@link HarnessProfileOptions}. Collection types are narrowed\n * (arrays → `Set`, records frozen) and all fields are required.\n * The object is frozen via `Object.freeze()` to prevent mutation\n * after construction.\n *\n * Profiles are **orthogonal to model selection**: they control prompt\n * assembly, tool visibility, middleware composition, and subagent\n * configuration — not which model is used.\n */\nexport interface HarnessProfile {\n /**\n * Replaces the default empty base prompt when set.\n *\n * Use this when a model requires a fundamentally different base\n * prompt rather than an additive suffix. Most profiles should prefer\n * `systemPromptSuffix` instead.\n */\n baseSystemPrompt: string | undefined;\n\n /**\n * Text appended to the assembled base prompt with a blank-line\n * separator (`\\n\\n`).\n *\n * This is the primary mechanism for model-specific prompt tuning.\n * Applied uniformly to the main agent, declarative subagents, and\n * the auto-added general-purpose subagent.\n */\n systemPromptSuffix: string | undefined;\n\n /**\n * Per-tool description replacements keyed by tool name.\n *\n * Allows profiles to rewrite tool descriptions for models that\n * respond better to different phrasing. Keys that don't match any\n * tool in the final tool set are silently ignored.\n */\n toolDescriptionOverrides: Record<string, string>;\n\n /**\n * Tool names to remove from the agent's visible tool set and reject at the\n * tool-call boundary.\n *\n * Applied via middleware after all tool-injecting middleware have run, so it\n * catches both user-provided and middleware-provided tools. Each declarative\n * subagent uses the profile resolved for its own model. Exclusions are\n * model-facing calibration, not a security boundary.\n */\n excludedTools: Set<string>;\n\n /**\n * Middleware names to remove from the assembled middleware stack.\n *\n * Matched against each middleware's `.name` property. Cannot include\n * required scaffolding names (`FilesystemMiddleware`,\n * `SubAgentMiddleware`) — attempting to do so throws at construction\n * time.\n */\n excludedMiddleware: Set<string>;\n\n /**\n * Additional middleware appended to the stack after user middleware.\n *\n * Can be a static array or a zero-arg factory that returns fresh\n * instances per agent construction (important when middleware carries\n * mutable state).\n */\n extraMiddleware: AgentMiddleware[] | (() => AgentMiddleware[]);\n\n /**\n * Configuration for the auto-added general-purpose subagent.\n */\n generalPurposeSubagent: GeneralPurposeSubagentConfig | undefined;\n}\n\n/**\n * Type guard: is this a fully-constructed HarnessProfile (frozen with\n * Set fields) or raw options?\n *\n * Options use arrays for `excludedTools`; profiles use `Set`. We\n * distinguish by checking whether `excludedTools` has a `.has` method\n * (present on Set, absent on Array).\n */\nexport function isHarnessProfile(\n value: HarnessProfile | HarnessProfileOptions,\n): value is HarnessProfile {\n return (\n value.excludedTools != null &&\n typeof (value.excludedTools as Set<string>).has === \"function\" &&\n !Array.isArray(value.excludedTools)\n );\n}\n\n/**\n * Resolve middleware to a concrete array, invoking the factory if\n * needed.\n *\n * @internal\n */\nexport function resolveMiddleware(\n middleware: AgentMiddleware[] | (() => AgentMiddleware[]),\n): AgentMiddleware[] {\n if (typeof middleware === \"function\") {\n return middleware();\n }\n return middleware;\n}\n","import type { HarnessProfile, HarnessProfileOptions } from \"./types.js\";\nimport { REQUIRED_MIDDLEWARE_NAMES } from \"./types.js\";\n\n/**\n * Validate the grammar of an `excludedMiddleware` entry.\n *\n * Runs at profile construction time so malformed entries fail\n * immediately. Checks:\n *\n * 1. Non-empty, non-whitespace string.\n * 2. No colons (class-path `module:Class` syntax is reserved).\n * 3. No underscore prefix (private middleware is not part of the\n * exclusion surface).\n * 4. Not a required scaffolding name.\n *\n * @param name - The middleware name to validate.\n * @throws {Error} When the name violates any rule.\n */\nfunction validateExcludedMiddlewareName(name: string): void {\n if (!name || !name.trim()) {\n throw new Error(\n \"excludedMiddleware entries must be non-empty, non-whitespace strings.\",\n );\n }\n\n if (name.includes(\":\")) {\n throw new Error(\n `excludedMiddleware entries must be plain middleware names; ` +\n `class-path syntax is not supported, got \"${name}\".`,\n );\n }\n\n if (name.startsWith(\"_\")) {\n throw new Error(\n `excludedMiddleware entry \"${name}\" cannot start with \"_\" ` +\n `(underscore-prefixed names refer to private middleware not ` +\n `part of the public exclusion surface).`,\n );\n }\n\n if (REQUIRED_MIDDLEWARE_NAMES.has(name)) {\n throw new Error(\n `Cannot exclude required middleware \"${name}\" — it provides ` +\n `essential agent capabilities that the runtime depends on.`,\n );\n }\n}\n\n/**\n * Create a frozen {@link HarnessProfile} from user-provided options.\n *\n * Validates all fields, converts mutable collections to their\n * frozen counterparts, and returns a frozen object.\n * Empty options produce a no-op profile (all defaults).\n *\n * @param options - Partial profile configuration.\n * @returns A frozen, validated `HarnessProfile`.\n * @throws {Error} When any field violates validation rules (invalid\n * middleware names, scaffolding exclusion attempts).\n *\n * @example\n * ```typescript\n * const profile = createHarnessProfile({\n * systemPromptSuffix: \"Think step by step.\",\n * excludedTools: [\"execute\"],\n * });\n * ```\n */\nexport function createHarnessProfile(\n options: HarnessProfileOptions = {},\n): HarnessProfile {\n for (const name of options.excludedMiddleware ?? []) {\n validateExcludedMiddlewareName(name);\n }\n\n const toolDescriptionOverrides = Object.freeze(\n Object.assign(\n Object.create(null) as Record<string, string>,\n options.toolDescriptionOverrides,\n ),\n );\n\n const generalPurposeSubagent = options.generalPurposeSubagent\n ? Object.freeze({ ...options.generalPurposeSubagent })\n : undefined;\n\n const profile: HarnessProfile = {\n baseSystemPrompt: options.baseSystemPrompt,\n systemPromptSuffix: options.systemPromptSuffix,\n toolDescriptionOverrides,\n excludedTools: new Set(options.excludedTools),\n excludedMiddleware: new Set(options.excludedMiddleware),\n extraMiddleware: options.extraMiddleware ?? [],\n generalPurposeSubagent,\n };\n\n return Object.freeze(profile);\n}\n\n/**\n * An empty no-op profile used as the default when no registered\n * profile matches. Avoids creating a new object on every miss.\n */\nexport const EMPTY_HARNESS_PROFILE: HarnessProfile = createHarnessProfile();\n","import { z } from \"zod/v4\";\nimport type { HarnessProfile } from \"./types.js\";\nimport { resolveMiddleware } from \"./types.js\";\nimport { createHarnessProfile } from \"./create.js\";\n\nconst POISONED_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/**\n * Zod schema for the general-purpose subagent config section of an\n * external harness profile config file.\n */\nexport const generalPurposeSubagentConfigSchema = z\n .object({\n enabled: z.boolean().optional(),\n description: z.string().optional(),\n systemPrompt: z.string().optional(),\n })\n .strict();\n\n/**\n * Zod schema for parsing a harness profile from an external JSON or\n * YAML config file.\n *\n * Uses `.strict()` to reject unknown keys (catches typos early). Array\n * fields (`excludedTools`, `excludedMiddleware`) accept arrays of\n * strings; the result is passed to {@link createHarnessProfile} which\n * converts them to `Set`.\n *\n * Does not include `extraMiddleware` — middleware instances cannot be\n * represented in JSON/YAML.\n *\n * @example\n * ```typescript\n * import { readFileSync } from \"fs\";\n * import YAML from \"yaml\";\n *\n * const raw = YAML.parse(readFileSync(\"profile.yaml\", \"utf-8\"));\n * const config = harnessProfileConfigSchema.parse(raw);\n * const profile = createHarnessProfile(config);\n * ```\n */\nexport const harnessProfileConfigSchema = z\n .object({\n baseSystemPrompt: z.string().optional(),\n systemPromptSuffix: z.string().optional(),\n toolDescriptionOverrides: z.record(z.string(), z.string()).optional(),\n excludedTools: z.array(z.string()).optional(),\n excludedMiddleware: z.array(z.string()).optional(),\n generalPurposeSubagent: generalPurposeSubagentConfigSchema.optional(),\n })\n .strict();\n\n/**\n * TypeScript type inferred from the Zod config schema.\n *\n * Represents the JSON/YAML-compatible shape of a harness profile. This\n * is the type of data that comes out of `harnessProfileConfigSchema.parse()`.\n */\nexport type HarnessProfileConfigData = z.infer<\n typeof harnessProfileConfigSchema\n>;\n\n/**\n * Recursively check an object for prototype-pollution keys.\n *\n * Rejects `__proto__`, `constructor`, and `prototype` at any nesting\n * depth. Called before Zod parsing so poisoned payloads never reach\n * schema validation.\n */\nfunction rejectPoisonedKeys(value: unknown, path = \"\"): void {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return;\n }\n\n for (const key of Object.keys(value)) {\n if (POISONED_KEYS.has(key)) {\n throw new Error(\n `Rejected dangerous key \"${key}\" at ${path || \"root\"} in harness profile config.`,\n );\n }\n rejectPoisonedKeys(\n (value as Record<string, unknown>)[key],\n path ? `${path}.${key}` : key,\n );\n }\n}\n\n/**\n * Parse an untrusted JSON/YAML object into a validated\n * {@link HarnessProfile}.\n *\n * Combines Zod schema validation with prototype-pollution protection\n * and profile construction validation. Use this for any config data\n * that originates from files, network, or user input.\n *\n * @param data - Raw object from `JSON.parse()` or `YAML.parse()`.\n * @returns A frozen, validated `HarnessProfile`.\n * @throws {z.ZodError} When the data fails schema validation.\n * @throws {Error} When profile-level validation fails (e.g.,\n * scaffolding violation in `excludedMiddleware`).\n */\nexport function parseHarnessProfileConfig(data: unknown): HarnessProfile {\n rejectPoisonedKeys(data);\n const parsed = harnessProfileConfigSchema.parse(data);\n return createHarnessProfile(parsed);\n}\n\n/**\n * Serialize a {@link HarnessProfile} to a JSON-compatible object.\n *\n * Omits `undefined` fields and `extraMiddleware` (runtime-only).\n * Throws if `extraMiddleware` contains instances — callers should\n * strip it before serializing if they've set it.\n *\n * @param profile - The profile to serialize.\n * @returns A plain object matching {@link HarnessProfileConfigData}.\n * @throws {Error} When `extraMiddleware` is non-empty (cannot be\n * serialized to JSON).\n */\nexport function serializeProfile(\n profile: HarnessProfile,\n): HarnessProfileConfigData {\n const middleware = resolveMiddleware(profile.extraMiddleware);\n if (middleware.length > 0) {\n throw new Error(\n \"Cannot serialize a HarnessProfile with non-empty extraMiddleware — \" +\n \"middleware instances are runtime-only and have no JSON representation.\",\n );\n }\n\n const result: Record<string, unknown> = {};\n\n if (profile.baseSystemPrompt !== undefined) {\n result.baseSystemPrompt = profile.baseSystemPrompt;\n }\n\n if (profile.systemPromptSuffix !== undefined) {\n result.systemPromptSuffix = profile.systemPromptSuffix;\n }\n\n if (Object.keys(profile.toolDescriptionOverrides).length > 0) {\n result.toolDescriptionOverrides = { ...profile.toolDescriptionOverrides };\n }\n\n if (profile.excludedTools.size > 0) {\n result.excludedTools = [...profile.excludedTools];\n }\n\n if (profile.excludedMiddleware.size > 0) {\n result.excludedMiddleware = [...profile.excludedMiddleware];\n }\n\n if (profile.generalPurposeSubagent !== undefined) {\n const gp: Record<string, unknown> = {};\n if (profile.generalPurposeSubagent.enabled !== undefined) {\n gp.enabled = profile.generalPurposeSubagent.enabled;\n }\n\n if (profile.generalPurposeSubagent.description !== undefined) {\n gp.description = profile.generalPurposeSubagent.description;\n }\n\n if (profile.generalPurposeSubagent.systemPrompt !== undefined) {\n gp.systemPrompt = profile.generalPurposeSubagent.systemPrompt;\n }\n\n if (Object.keys(gp).length > 0) {\n result.generalPurposeSubagent = gp;\n }\n }\n\n return result as HarnessProfileConfigData;\n}\n","import type { AgentMiddleware } from \"langchain\";\nimport type { HarnessProfile, GeneralPurposeSubagentConfig } from \"./types.js\";\nimport { resolveMiddleware } from \"./types.js\";\nimport { createHarnessProfile } from \"./create.js\";\n\n/**\n * Merge two middleware sequences by `.name`.\n *\n * When the override has a middleware whose `.name` already appears in\n * the base, the override instance replaces the base instance at the\n * same position. Novel names from the override are appended. If the\n * base has duplicates of the same name, only the first is replaced;\n * later duplicates are dropped.\n *\n * Returns a factory to ensure fresh resolution on each call.\n */\nfunction mergeMiddleware(\n base: AgentMiddleware[] | (() => AgentMiddleware[]),\n override: AgentMiddleware[] | (() => AgentMiddleware[]),\n): (() => AgentMiddleware[]) | AgentMiddleware[] {\n const baseArr = resolveMiddleware(base);\n const overrideArr = resolveMiddleware(override);\n\n if (baseArr.length === 0) {\n return override;\n }\n\n if (overrideArr.length === 0) {\n return base;\n }\n\n return (): AgentMiddleware[] => {\n const baseSeq = resolveMiddleware(base);\n const overrideSeq = resolveMiddleware(override);\n const overrideByName = new Map(overrideSeq.map((m) => [m.name, m]));\n const merged: AgentMiddleware[] = [];\n const replaced = new Set<string>();\n\n for (const entry of baseSeq) {\n const replacement = overrideByName.get(entry.name);\n if (replacement) {\n if (!replaced.has(entry.name)) {\n merged.push(replacement);\n replaced.add(entry.name);\n }\n } else {\n merged.push(entry);\n }\n }\n\n for (const entry of overrideSeq) {\n if (!replaced.has(entry.name)) {\n merged.push(entry);\n }\n }\n\n return merged;\n };\n}\n\n/**\n * Merge two GP subagent configs field-wise.\n *\n * Override wins per sub-field when not `undefined`; unset fields\n * inherit from base. Returns `undefined` only when both inputs are\n * `undefined`.\n */\nfunction mergeGeneralPurposeSubagentConfigs(\n base?: GeneralPurposeSubagentConfig,\n override?: GeneralPurposeSubagentConfig,\n): GeneralPurposeSubagentConfig | undefined {\n if (base === undefined) {\n return override;\n }\n\n if (override === undefined) {\n return base;\n }\n\n return {\n enabled: override.enabled ?? base.enabled,\n description: override.description ?? base.description,\n systemPrompt: override.systemPrompt ?? base.systemPrompt,\n };\n}\n\n/**\n * Merge two harness profiles, layering `override` on top of `base`.\n *\n * Merge semantics per field:\n *\n * | Field | Strategy |\n * |-------|----------|\n * | `baseSystemPrompt` | Override wins if not `undefined` |\n * | `systemPromptSuffix` | Override wins if not `undefined` |\n * | `toolDescriptionOverrides` | Object spread merge; override wins per key |\n * | `excludedTools` | Set union |\n * | `excludedMiddleware` | Set union |\n * | `extraMiddleware` | Merge by `.name`; override instance replaces base at same position; novel names appended |\n * | `generalPurposeSubagent` | Field-wise merge; override wins per sub-field |\n *\n * @param base - Lower-priority profile (e.g., provider-wide).\n * @param override - Higher-priority profile (e.g., exact model).\n * @returns A new merged profile.\n */\nexport function mergeProfiles(\n base: HarnessProfile,\n override: HarnessProfile,\n): HarnessProfile {\n return createHarnessProfile({\n baseSystemPrompt: override.baseSystemPrompt ?? base.baseSystemPrompt,\n systemPromptSuffix: override.systemPromptSuffix ?? base.systemPromptSuffix,\n toolDescriptionOverrides: {\n ...base.toolDescriptionOverrides,\n ...override.toolDescriptionOverrides,\n },\n excludedTools: [...base.excludedTools, ...override.excludedTools],\n excludedMiddleware: [\n ...base.excludedMiddleware,\n ...override.excludedMiddleware,\n ],\n extraMiddleware: mergeMiddleware(\n base.extraMiddleware,\n override.extraMiddleware,\n ),\n generalPurposeSubagent: mergeGeneralPurposeSubagentConfigs(\n base.generalPurposeSubagent,\n override.generalPurposeSubagent,\n ),\n });\n}\n","import { createHarnessProfile } from \"../create.js\";\nimport { registerHarnessProfileImpl } from \"../registry.js\";\n\nconst SYSTEM_PROMPT_SUFFIX = `\\\n<use_parallel_tool_calls>\nIf you intend to call multiple tools and there are no dependencies between the tool calls, make all of the independent tool calls in parallel. Prioritize calling tools simultaneously whenever the actions can be done in parallel rather than sequentially. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. Maximize use of parallel tool calls where possible to increase speed and efficiency. However, if some tool calls depend on previous calls to inform dependent values like the parameters, do NOT call these tools in parallel and instead call them sequentially. Never use placeholders or guess missing parameters in tool calls.\n</use_parallel_tool_calls>\n\n<investigate_before_answering>\nNever speculate about code you have not opened. If the user references a specific file, you MUST read the file before answering. Make sure to investigate and read relevant files BEFORE answering questions about the codebase. Never make any claims about code before investigating unless you are certain of the correct answer - give grounded and hallucination-free answers.\n</investigate_before_answering>\n\n<tool_result_reflection>\nAfter receiving tool results, carefully reflect on their quality and determine optimal next steps before proceeding. Use your thinking to plan and iterate based on this new information, and then take the best next action.\n</tool_result_reflection>\n\n<tool_usage>\nWhen a task depends on the state of files, tests, or system output, use tools to observe that state directly rather than reasoning from memory about what it probably contains. Read files before describing them. Run tests before claiming they pass. Search the codebase before asserting a symbol does or does not exist. Active investigation with tools is the default mode of working, not a fallback.\n</tool_usage>\n\n<subagent_usage>\nDo not spawn a subagent for work you can complete directly in a single response (e.g. refactoring a function you can already see).\n\nSpawn multiple subagents in the same turn when fanning out across items or reading multiple files.\n</subagent_usage>`;\n\n/**\n * Register the built-in Claude Opus 4.7 harness profile.\n *\n * Layers a system-prompt suffix onto `anthropic:claude-opus-4-7`\n * tuned to the model's documented behaviors: parallel tool calls,\n * grounded answers, post-tool reflection, active investigation, and\n * subagent spawning guidance.\n *\n * @internal\n */\nexport function register(): void {\n registerHarnessProfileImpl(\n \"anthropic:claude-opus-4-7\",\n createHarnessProfile({ systemPromptSuffix: SYSTEM_PROMPT_SUFFIX }),\n );\n}\n","import { createHarnessProfile } from \"../create.js\";\nimport { registerHarnessProfileImpl } from \"../registry.js\";\n\nconst SYSTEM_PROMPT_SUFFIX = `\\\n<use_parallel_tool_calls>\nIf you intend to call multiple tools and there are no dependencies between the tool calls, make all of the independent tool calls in parallel. Prioritize calling tools simultaneously whenever the actions can be done in parallel rather than sequentially. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. Maximize use of parallel tool calls where possible to increase speed and efficiency. However, if some tool calls depend on previous calls to inform dependent values like the parameters, do NOT call these tools in parallel and instead call them sequentially. Never use placeholders or guess missing parameters in tool calls.\n</use_parallel_tool_calls>\n\n<investigate_before_answering>\nNever speculate about code you have not opened. If the user references a specific file, you MUST read the file before answering. Make sure to investigate and read relevant files BEFORE answering questions about the codebase. Never make any claims about code before investigating unless you are certain of the correct answer - give grounded and hallucination-free answers.\n</investigate_before_answering>\n\n<tool_result_reflection>\nAfter receiving tool results, carefully reflect on their quality and determine optimal next steps before proceeding. Use your thinking to plan and iterate based on this new information, and then take the best next action.\n</tool_result_reflection>`;\n\n/**\n * Register the built-in Claude Sonnet 4.6 harness profile.\n *\n * Layers universal Claude guidance (parallel tool calls, grounded\n * answers, post-tool reflection) onto `anthropic:claude-sonnet-4-6`.\n *\n * No Sonnet-specific overlays — Anthropic's guidance for Sonnet 4.6\n * centers on API-level configuration rather than system-prompt\n * adjustments. This module exists as the audit anchor: its presence\n * documents the review and justifies the absence of model-specific\n * content.\n *\n * @internal\n */\nexport function register(): void {\n registerHarnessProfileImpl(\n \"anthropic:claude-sonnet-4-6\",\n createHarnessProfile({ systemPromptSuffix: SYSTEM_PROMPT_SUFFIX }),\n );\n}\n","import { createHarnessProfile } from \"../create.js\";\nimport { registerHarnessProfileImpl } from \"../registry.js\";\n\nconst SYSTEM_PROMPT_SUFFIX = `\\\n<use_parallel_tool_calls>\nIf you intend to call multiple tools and there are no dependencies between the tool calls, make all of the independent tool calls in parallel. Prioritize calling tools simultaneously whenever the actions can be done in parallel rather than sequentially. For example, when reading 3 files, run 3 tool calls in parallel to read all 3 files into context at the same time. Maximize use of parallel tool calls where possible to increase speed and efficiency. However, if some tool calls depend on previous calls to inform dependent values like the parameters, do NOT call these tools in parallel and instead call them sequentially. Never use placeholders or guess missing parameters in tool calls.\n</use_parallel_tool_calls>\n\n<investigate_before_answering>\nNever speculate about code you have not opened. If the user references a specific file, you MUST read the file before answering. Make sure to investigate and read relevant files BEFORE answering questions about the codebase. Never make any claims about code before investigating unless you are certain of the correct answer - give grounded and hallucination-free answers.\n</investigate_before_answering>\n\n<tool_result_reflection>\nAfter receiving tool results, carefully reflect on their quality and determine optimal next steps before proceeding. Use your thinking to plan and iterate based on this new information, and then take the best next action.\n</tool_result_reflection>`;\n\n/**\n * Register the built-in Claude Haiku 4.5 harness profile.\n *\n * Same universal Claude guidance as Sonnet 4.6. No Haiku-specific\n * overlays.\n *\n * @internal\n */\nexport function register(): void {\n registerHarnessProfileImpl(\n \"anthropic:claude-haiku-4-5\",\n createHarnessProfile({ systemPromptSuffix: SYSTEM_PROMPT_SUFFIX }),\n );\n}\n","import { todoListMiddleware, type AgentMiddleware } from \"langchain\";\n\nimport { createHarnessProfile } from \"../create.js\";\nimport { registerHarnessProfileImpl } from \"../registry.js\";\n\n/**\n * Model specs that receive the Codex harness profile.\n *\n * All variants share the same trained response style, so a single\n * suffix works across the family.\n */\nconst CODEX_MODEL_SPECS = [\n \"openai:gpt-5.1-codex\",\n \"openai:gpt-5.2-codex\",\n \"openai:gpt-5.3-codex\",\n];\n\nconst SYSTEM_PROMPT_SUFFIX = `\\\n## Codex-Specific Behavior\n\n- You are an autonomous senior engineer. Once given a direction, proactively \\\ngather context, plan, implement, and verify without waiting for additional \\\nprompts at each step.\n- Persist until the task is fully handled end-to-end within the current turn \\\nwhenever feasible. Do not stop at analysis or partial fixes; carry changes \\\nthrough implementation, verification, and a clear explanation of outcomes.\n- Bias to action: default to implementing with reasonable assumptions. Do not \\\nend your turn with clarifications unless truly blocked.\n- Do not communicate an upfront plan or status preamble before acting. Just act.\n\n## Parallel Tool Use\n\n- Before any tool call, decide ALL files and resources you will need.\n- Batch reads, searches, and other independent operations into parallel tool \\\ncalls instead of issuing them one at a time.\n- Only make sequential calls when you truly cannot determine the next step \\\nwithout seeing a prior result.\n\n## Plan Hygiene\n\n- Before finishing, reconcile every TODO or plan item created via write_todos. \\\nMark each as done, blocked (with a one-sentence reason), or cancelled. Do not \\\nfinish with pending items.`;\n\nfunction createExtraMiddleware(): AgentMiddleware[] {\n return [todoListMiddleware()];\n}\n\n/**\n * Register the built-in Codex harness profiles.\n *\n * Registers the same profile under each Codex model spec. Per-model\n * keys (not the bare `\"openai\"` prefix) keep the default behavior of\n * non-Codex OpenAI models unchanged.\n *\n * @internal\n */\nexport function register(): void {\n const profile = createHarnessProfile({\n systemPromptSuffix: SYSTEM_PROMPT_SUFFIX,\n extraMiddleware: createExtraMiddleware,\n });\n for (const spec of CODEX_MODEL_SPECS) {\n registerHarnessProfileImpl(spec, profile);\n }\n}\n","import { snapshotBuiltinKeys } from \"../registry.js\";\n\nimport { register as registerAnthropicOpus47 } from \"./anthropic-opus-4-7.js\";\nimport { register as registerAnthropicSonnet46 } from \"./anthropic-sonnet-4-6.js\";\nimport { register as registerAnthropicHaiku45 } from \"./anthropic-haiku-4-5.js\";\nimport { register as registerOpenaiCodex } from \"./openai-codex.js\";\n\n/**\n * Register all built-in harness profiles and snapshot the resulting\n * registry keys as the builtin baseline.\n *\n * Called once during lazy bootstrap by `ensureBuiltinsLoaded()`.\n * Uses `registerHarnessProfileImpl` internally (not the public\n * `registerHarnessProfile`) to avoid triggering re-entrant bootstrap.\n *\n * @internal\n */\nexport function loadBuiltinProfiles(): void {\n registerAnthropicOpus47();\n registerAnthropicSonnet46();\n registerAnthropicHaiku45();\n registerOpenaiCodex();\n\n snapshotBuiltinKeys();\n}\n","import { validateProfileKey } from \"../keys.js\";\nimport type { HarnessProfile, HarnessProfileOptions } from \"./types.js\";\nimport { isHarnessProfile } from \"./types.js\";\nimport { createHarnessProfile, EMPTY_HARNESS_PROFILE } from \"./create.js\";\nimport { mergeProfiles } from \"./merge.js\";\nimport { loadBuiltinProfiles } from \"./builtins/index.js\";\n\n/**\n * Process-global symbol key for the harness profile registry. The `.v1`\n * suffix is a version gate — bump it when the {@link HarnessProfileRegistry}\n * shape changes in a breaking way so that incompatible versions coexist\n * on `globalThis` without corrupting each other.\n */\nconst PROFILE_REGISTRY_KEY = Symbol.for(\"deepagents.harness-profiles.v1\");\n\n/**\n * Process-global registry state, keyed by a versioned symbol so that\n * duplicate package installs (transient deps resolving to different\n * copies of deepagents) share a single profile registry.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for\n */\ninterface HarnessProfileRegistry {\n /**\n * Registered profiles keyed by model spec (e.g., `\"anthropic:claude-opus-4-7\"`).\n */\n profiles: Map<string, HarnessProfile>;\n\n /**\n * Keys that existed after built-in bootstrap, used to detect user registrations.\n */\n builtinKeys: Set<string>;\n\n /**\n * Whether built-in profiles have been lazy-loaded into the registry.\n */\n builtinsLoaded: boolean;\n}\n\n/**\n * Returns the process-global registry, creating it on first access.\n */\nfunction getHarnessProfileRegistry(): HarnessProfileRegistry {\n const global = globalThis as Record<symbol, unknown>;\n if (global[PROFILE_REGISTRY_KEY] == null) {\n global[PROFILE_REGISTRY_KEY] = {\n profiles: new Map<string, HarnessProfile>(),\n builtinKeys: new Set<string>(),\n builtinsLoaded: false,\n };\n }\n return global[PROFILE_REGISTRY_KEY] as HarnessProfileRegistry;\n}\n\n/**\n * Options for resolving a harness profile from model metadata.\n */\nexport interface ResolveHarnessProfileOpts {\n /**\n * Model spec string (e.g., `\"anthropic:claude-opus-4-7\"`).\n */\n spec?: string;\n\n /**\n * Provider name extracted from a model instance (e.g., `\"anthropic\"`).\n */\n providerHint?: string;\n\n /**\n * Model identifier extracted from a model instance (e.g., `\"claude-opus-4-7\"`).\n */\n identifierHint?: string;\n}\n\n/**\n * Ensure lazy-loaded builtin profiles have been registered.\n *\n * Called by the public `registerHarnessProfile` and lookup functions.\n * Built-in registration modules call `registerHarnessProfileImpl`\n * directly to avoid re-entrant bootstrap.\n *\n * @internal\n */\nexport function ensureBuiltinsLoaded(): void {\n const registry = getHarnessProfileRegistry();\n if (registry.builtinsLoaded) return;\n registry.builtinsLoaded = true;\n loadBuiltinProfiles();\n}\n\n/**\n * Snapshot the current registry keys as the builtin baseline.\n *\n * Called by the builtin loader after all built-in profiles are\n * registered. This allows {@link hasUserRegisteredProfiles} to\n * distinguish user registrations from built-ins.\n *\n * @internal\n */\nexport function snapshotBuiltinKeys(): void {\n const registry = getHarnessProfileRegistry();\n registry.builtinKeys = new Set(registry.profiles.keys());\n}\n\n/**\n * Core registration implementation. Does not trigger lazy bootstrap.\n *\n * Used by built-in profile modules during bootstrap. External callers\n * should use {@link registerHarnessProfile} instead.\n *\n * @internal\n */\nexport function registerHarnessProfileImpl(\n key: string,\n profile: HarnessProfile,\n): void {\n key = validateProfileKey(key);\n const { profiles } = getHarnessProfileRegistry();\n const existing = profiles.get(key);\n if (existing !== undefined) {\n profiles.set(key, mergeProfiles(existing, profile));\n } else {\n profiles.set(key, profile);\n }\n}\n\n/**\n * Register a harness profile for a provider or specific model.\n *\n * Accepts either a pre-built {@link HarnessProfile} (from\n * {@link createHarnessProfile}) or raw {@link HarnessProfileOptions}\n * that will be validated and frozen automatically.\n *\n * Registrations are **additive**: if a profile already exists under\n * `key`, the new profile is merged on top. The incoming profile's\n * fields win on scalar conflicts; set fields union; middleware\n * sequences merge by name.\n *\n * @param key - Either a bare provider (`\"openai\"`) for provider-wide\n * defaults, or `\"provider:model\"` for a per-model override.\n * @param profile - A `HarnessProfile` or options to build one from.\n * @throws {Error} When `key` is malformed or profile validation\n * fails.\n *\n * @example\n * ```typescript\n * import { registerHarnessProfile } from \"@langchain/deepagents\";\n *\n * registerHarnessProfile(\"openai\", {\n * systemPromptSuffix: \"Respond concisely.\",\n * });\n *\n * registerHarnessProfile(\"openai:gpt-5.4\", {\n * excludedTools: [\"execute\"],\n * });\n * ```\n */\nexport function registerHarnessProfile(\n key: string,\n profile: HarnessProfile | HarnessProfileOptions,\n): void {\n ensureBuiltinsLoaded();\n const resolved = isHarnessProfile(profile)\n ? profile\n : createHarnessProfile(profile);\n registerHarnessProfileImpl(key, resolved);\n}\n\n/**\n * Look up the {@link HarnessProfile} for a model spec string.\n *\n * Resolution order:\n *\n * 1. **Exact match** on `spec` (e.g., `\"openai:gpt-5.4\"`).\n * 2. **Provider prefix** (everything before `:`) when `spec` contains\n * a colon and both halves are non-empty.\n * 3. When both exist, they are **merged** (provider as base, exact as\n * override).\n * 4. `undefined` when nothing matches.\n *\n * Malformed specs (empty, multiple colons, empty halves) return\n * `undefined` without consulting the registry.\n *\n * @param spec - Model spec in `\"provider:model\"` format, or a bare\n * provider/model identifier.\n * @returns The matching profile, or `undefined`.\n */\nexport function getHarnessProfile(spec: string): HarnessProfile | undefined {\n if (spec.split(\":\").length > 2) {\n return undefined;\n }\n\n const colonIdx = spec.indexOf(\":\");\n const hasColon = colonIdx !== -1;\n const provider = hasColon ? spec.slice(0, colonIdx) : undefined;\n const model = hasColon ? spec.slice(colonIdx + 1) : undefined;\n\n if (hasColon && (!provider || !model)) {\n return undefined;\n }\n\n ensureBuiltinsLoaded();\n\n const { profiles } = getHarnessProfileRegistry();\n const exact = profiles.get(spec);\n const base = provider ? profiles.get(provider) : undefined;\n\n if (exact !== undefined && base !== undefined) {\n return mergeProfiles(base, exact);\n }\n\n return exact ?? base;\n}\n\n/**\n * Resolve the harness profile for a model, falling back to the\n * empty default when nothing matches.\n *\n * When `spec` is set (the original model parameter), it drives the\n * lookup directly. When absent (pre-built model instance),\n * `providerHint` and `identifierHint` are used to construct lookup\n * keys.\n *\n * @param opts - Model metadata used to resolve the profile.\n * @returns The resolved profile (never `undefined`).\n *\n * @internal\n */\nexport function resolveHarnessProfile(\n opts: ResolveHarnessProfileOpts = {},\n): HarnessProfile {\n const { spec, providerHint, identifierHint } = opts;\n if (spec !== undefined) {\n return getHarnessProfile(spec) ?? EMPTY_HARNESS_PROFILE;\n }\n\n if (providerHint && identifierHint && !identifierHint.includes(\":\")) {\n const profile = getHarnessProfile(`${providerHint}:${identifierHint}`);\n if (profile) {\n return profile;\n }\n }\n if (identifierHint && identifierHint.includes(\":\")) {\n const profile = getHarnessProfile(identifierHint);\n if (profile) {\n return profile;\n }\n }\n if (providerHint) {\n const profile = getHarnessProfile(providerHint);\n if (profile) {\n return profile;\n }\n }\n\n return EMPTY_HARNESS_PROFILE;\n}\n\n/**\n * Returns `true` when at least one profile was registered by user\n * code (as opposed to built-in bootstrap).\n *\n * Used to calibrate log verbosity — a \"no match\" miss is\n * unsurprising when only built-ins are loaded.\n *\n * @internal\n */\nexport function hasUserRegisteredProfiles(): boolean {\n ensureBuiltinsLoaded();\n const registry = getHarnessProfileRegistry();\n for (const key of registry.profiles.keys()) {\n if (!registry.builtinKeys.has(key)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Apply a profile's prompt overlay to a base prompt string.\n *\n * - `baseSystemPrompt` (when set) replaces `basePrompt` entirely.\n * - `systemPromptSuffix` (when set) is appended with `\\n\\n`.\n *\n * Both are independently optional. A profile that sets only the suffix\n * layers it on top of whatever base the caller passes in.\n *\n * Used uniformly for the main agent, declarative subagents, and the\n * auto-added general-purpose subagent.\n *\n * @param profile - The harness profile to apply.\n * @param basePrompt - The active base prompt (empty by default).\n * @returns The assembled prompt string.\n */\nexport function applyProfilePrompt(\n profile: HarnessProfile,\n basePrompt: string,\n): string {\n const prompt =\n profile.baseSystemPrompt !== undefined\n ? profile.baseSystemPrompt\n : basePrompt;\n if (profile.systemPromptSuffix !== undefined) {\n return prompt\n ? `${prompt}\\n\\n${profile.systemPromptSuffix}`\n : profile.systemPromptSuffix;\n }\n return prompt;\n}\n\n/**\n * Reset the registry to its empty state. For testing only.\n *\n * @internal\n */\nexport function _resetRegistryForTesting(): void {\n const registry = getHarnessProfileRegistry();\n registry.profiles.clear();\n registry.builtinKeys = new Set();\n registry.builtinsLoaded = false;\n}\n","import {\n createAgent,\n humanInTheLoopMiddleware,\n anthropicPromptCachingMiddleware,\n bedrockPromptCachingMiddleware,\n SystemMessage,\n type AgentMiddleware,\n} from \"langchain\";\nimport type {\n ClientTool,\n ServerTool,\n StructuredTool,\n} from \"@langchain/core/tools\";\n\nimport {\n createFilesystemMiddleware,\n createSubAgentMiddleware,\n createPatchToolCallsMiddleware,\n createSummarizationMiddleware,\n createMemoryMiddleware,\n createSkillsMiddleware,\n FILESYSTEM_TOOL_NAMES,\n ASYNC_TASK_TOOL_NAMES,\n type FsToolName,\n type SubAgent,\n createAsyncSubAgentMiddleware,\n isAsyncSubAgent,\n} from \"./middleware/index.js\";\nimport { StateBackend } from \"./backends/state.js\";\nimport { ConfigurationError } from \"./errors.js\";\nimport type { SystemPromptConfig } from \"./compat.js\";\nimport { InteropZodObject } from \"@langchain/core/utils/types\";\nimport { createCacheBreakpointMiddleware } from \"./middleware/cache.js\";\nimport { createToolExclusionMiddleware } from \"./middleware/tool_exclusion.js\";\nimport { mergeMiddleware, mergeMiddlewareStack } from \"./middleware/utils.js\";\nimport {\n GENERAL_PURPOSE_SUBAGENT,\n isForkedSubAgent,\n type CompiledSubAgent,\n} from \"./middleware/subagents.js\";\nimport type { AsyncSubAgent } from \"./middleware/async_subagents.js\";\nimport type {\n AnySubAgent,\n CreateDeepAgentParams,\n DeepAgent,\n DeepAgentTypeConfig,\n FlattenSubAgentMiddleware,\n InferStructuredResponse,\n SupportedResponseFormat,\n} from \"./types.js\";\n/**\n * required for type inference\n */\nimport type * as _messages from \"@langchain/core/messages\";\nimport type * as _langgraph from \"@langchain/langgraph\";\nimport type { AnyStateSchema, StreamTransformer } from \"@langchain/langgraph\";\nimport {\n resolveHarnessProfile,\n applyProfilePrompt,\n resolveMiddleware,\n type HarnessProfile,\n} from \"./profiles/index.js\";\nimport {\n isAnthropicModel,\n getModelProvider,\n getModelIdentifier,\n isBedrockConverseModel,\n} from \"./utils.js\";\n\ntype SystemPromptPart = string | SystemMessage;\n\nfunction normalizeSystemPrompt(\n systemPrompt: SystemPromptPart | SystemPromptConfig | undefined,\n): SystemPromptConfig {\n if (systemPrompt === undefined) return {};\n if (\n typeof systemPrompt === \"string\" ||\n SystemMessage.isInstance(systemPrompt)\n ) {\n return { prefix: systemPrompt };\n }\n return systemPrompt;\n}\n\nfunction assemblePromptParts(\n parts: readonly (SystemPromptPart | null | undefined)[],\n): string | SystemMessage {\n const nonEmptyParts = parts.filter(\n (part): part is SystemPromptPart =>\n part != null && (typeof part !== \"string\" || part.length > 0),\n );\n if (nonEmptyParts.length === 0) return \"\";\n if (nonEmptyParts.every((part) => typeof part === \"string\")) {\n return nonEmptyParts.join(\"\\n\\n\");\n }\n\n const contentBlocks: SystemMessage[\"contentBlocks\"] = [];\n for (const [index, part] of nonEmptyParts.entries()) {\n if (index > 0) contentBlocks.push({ type: \"text\", text: \"\\n\\n\" });\n if (SystemMessage.isInstance(part))\n contentBlocks.push(...part.contentBlocks);\n else contentBlocks.push({ type: \"text\", text: part });\n }\n return new SystemMessage({ contentBlocks });\n}\n\nconst BUILTIN_TOOL_NAMES: ReadonlySet<string> = new Set([\n ...FILESYSTEM_TOOL_NAMES,\n ...ASYNC_TASK_TOOL_NAMES,\n \"task\",\n]);\n\n/**\n * Create a Deep Agent.\n *\n * This is the main entry point for building a production-style agent with\n * deepagents. It gives you a strong default runtime (filesystem, tasks,\n * subagents, summarization) and lets you opt into skills, memory,\n * human-in-the-loop interrupts, async subagents, and custom middleware.\n *\n * The runtime is intentionally opinionated: defaults work out of the box, and\n * when you customize behavior, the middleware ordering stays deterministic.\n *\n * @param params Configuration parameters for the agent\n * @returns Deep Agent instance with inferred state/response types\n *\n * @example\n * ```typescript\n * // Custom state from middleware and/or the agent stateSchema param — both are merged\n * const ResearchMiddleware = createMiddleware({\n * name: \"ResearchMiddleware\",\n * stateSchema: z.object({ research: z.string().default(\"\") }),\n * });\n *\n * const agent = createDeepAgent({\n * middleware: [ResearchMiddleware],\n * stateSchema: z.object({ author: z.string().default(\"Me\") }),\n * });\n *\n * const result = await agent.invoke({ messages: [...] });\n * // result.research and result.author are properly typed as strings\n * ```\n */\nexport function createDeepAgent<\n TResponse extends SupportedResponseFormat = SupportedResponseFormat,\n ContextSchema extends InteropZodObject = InteropZodObject,\n const TMiddleware extends readonly AgentMiddleware[] = readonly [],\n const TSubagents extends readonly AnySubAgent[] = readonly [],\n const TTools extends readonly (ClientTool | ServerTool)[] = readonly [],\n const TStreamTransformers extends ReadonlyArray<\n () => StreamTransformer<any>\n > = readonly [],\n TStateSchema extends AnyStateSchema | InteropZodObject | undefined =\n undefined,\n>(\n params: CreateDeepAgentParams<\n TResponse,\n ContextSchema,\n TMiddleware,\n TSubagents,\n TTools,\n TStreamTransformers,\n TStateSchema\n > = {} as CreateDeepAgentParams<\n TResponse,\n ContextSchema,\n TMiddleware,\n TSubagents,\n TTools,\n TStreamTransformers,\n TStateSchema\n >,\n) {\n const {\n model = \"anthropic:claude-sonnet-4-6\",\n tools = [],\n systemPrompt,\n stateSchema,\n middleware: customMiddleware = [],\n subagents = [],\n responseFormat,\n contextSchema,\n checkpointer,\n store,\n backend = (config) => new StateBackend(config),\n interruptOn,\n name,\n memory,\n skills,\n permissions = [],\n streamTransformers = [],\n } = params;\n\n const collidingTools = tools\n .map((t) => t.name)\n .filter((n) => typeof n === \"string\" && BUILTIN_TOOL_NAMES.has(n));\n\n if (collidingTools.length > 0) {\n throw new ConfigurationError(\n `Tool name(s) [${collidingTools.join(\", \")}] conflict with built-in tools. ` +\n `Rename your custom tools to avoid this.`,\n \"TOOL_NAME_COLLISION\",\n );\n }\n\n const harnessProfile =\n typeof model === \"string\"\n ? resolveHarnessProfile({ spec: model })\n : resolveHarnessProfile({\n providerHint: getModelProvider(model),\n identifierHint: getModelIdentifier(model),\n });\n\n const computeProfileFilesystemTools = (\n profile: HarnessProfile,\n ): readonly FsToolName[] | undefined => {\n const filesystemTools = FILESYSTEM_TOOL_NAMES.filter(\n (toolName) => !profile.excludedTools.has(toolName),\n );\n return filesystemTools.length === FILESYSTEM_TOOL_NAMES.length\n ? undefined\n : filesystemTools.includes(\"read_file\")\n ? filesystemTools\n : [\"read_file\", ...filesystemTools];\n };\n const profileFilesystemTools = computeProfileFilesystemTools(harnessProfile);\n\n const resolveSubagentProfile = (\n subagentModel: SubAgent[\"model\"],\n ): HarnessProfile => {\n if (subagentModel == null || subagentModel === model) return harnessProfile;\n return typeof subagentModel === \"string\"\n ? resolveHarnessProfile({ spec: subagentModel })\n : resolveHarnessProfile({\n providerHint: getModelProvider(subagentModel),\n identifierHint: getModelIdentifier(subagentModel),\n });\n };\n\n const toolOverrides = harnessProfile.toolDescriptionOverrides;\n const effectiveTools: StructuredTool[] =\n Object.keys(toolOverrides).length > 0\n ? (tools as StructuredTool[]).map((t) =>\n t.name in toolOverrides\n ? Object.assign(Object.create(Object.getPrototypeOf(t)), t, {\n description: toolOverrides[t.name],\n })\n : t,\n )\n : (tools as StructuredTool[]);\n\n const anthropicModel = isAnthropicModel(model);\n const bedrockModel = isBedrockConverseModel(model);\n let cacheMiddleware: AgentMiddleware[] = [];\n\n if (anthropicModel) {\n cacheMiddleware = [\n ...cacheMiddleware,\n anthropicPromptCachingMiddleware({\n unsupportedModelBehavior: \"ignore\",\n minMessagesToCache: 1,\n }),\n createCacheBreakpointMiddleware(),\n ];\n }\n\n if (bedrockModel) {\n cacheMiddleware = [\n ...cacheMiddleware,\n bedrockPromptCachingMiddleware({ unsupportedModelBehavior: \"ignore\" }),\n ];\n }\n\n let memoryMiddleware: AgentMiddleware[] = [];\n if (memory && memory.length > 0) {\n memoryMiddleware = [\n createMemoryMiddleware({\n backend,\n sources: memory,\n addCacheControl: anthropicModel,\n }),\n ];\n }\n\n // Hoisted above subagent construction so fork-mode specs can reuse this string.\n const promptConfig = normalizeSystemPrompt(systemPrompt);\n const activeBasePrompt =\n promptConfig.base !== undefined\n ? promptConfig.base\n : harnessProfile.baseSystemPrompt;\n const finalSystemPrompt = assemblePromptParts([\n promptConfig.prefix,\n activeBasePrompt,\n promptConfig.suffix,\n harnessProfile.systemPromptSuffix,\n ]);\n\n /**\n * Process subagents to add SkillsMiddleware for those with their own skills.\n *\n * Custom subagents do NOT inherit skills from the main agent by default.\n * Only the general-purpose subagent inherits the main agent's skills.\n * If a custom subagent needs skills, it must specify its own `skills` array.\n */\n const createSubagentDefaultMiddleware = (\n input: SubAgent,\n subagentProfile: HarnessProfile,\n forked: boolean,\n ): AgentMiddleware[] => {\n const effectivePermissions = input.permissions ?? permissions;\n\n // Middleware for custom subagents (does NOT include skills from main agent).\n // Uses createSummarizationMiddleware (deepagents version) with backend support\n // and auto-computed defaults from model profile.\n return [\n // Enables filesystem operations and optional long-term memory storage.\n createFilesystemMiddleware({\n backend,\n permissions: effectivePermissions,\n tools: computeProfileFilesystemTools(subagentProfile),\n }),\n // Automatically summarizes conversation history when token limits are approached.\n // Uses createSummarizationMiddleware (deepagents version) with backend support\n // and auto-computed defaults from model profile.\n createSummarizationMiddleware({ backend }),\n // Patches tool calls to ensure compatibility across different model providers.\n createPatchToolCallsMiddleware(),\n // Loads subagent-specific skills when configured. Never for a fork: its\n // own `skills` is rejected below, and the parent's are mirrored instead\n // (see buildSubagentMiddleware) — building this here too would produce\n // a second same-named SkillsMiddleware before that rejection even runs.\n ...(!forked && input.skills != null && input.skills.length > 0\n ? [createSkillsMiddleware({ backend, sources: input.skills })]\n : []),\n ];\n };\n\n const buildSubagentMiddleware = (input: SubAgent): AgentMiddleware[] => {\n const subagentProfile = resolveSubagentProfile(input.model);\n const forked = isForkedSubAgent(input);\n const subagentDefaultMiddleware = createSubagentDefaultMiddleware(\n input,\n subagentProfile,\n forked,\n );\n if (forked && skills != null && skills.length > 0) {\n subagentDefaultMiddleware.unshift(\n createSkillsMiddleware({ backend, sources: skills }),\n );\n }\n const inputMiddleware =\n forked && customMiddleware.length > 0\n ? mergeMiddleware(customMiddleware, input.middleware ?? [])\n : (input.middleware ?? []);\n\n let subagentMiddleware = mergeMiddlewareStack(\n subagentDefaultMiddleware,\n inputMiddleware,\n [\n // Resolve profile middleware per stack so factories create fresh instances.\n ...resolveMiddleware(subagentProfile.extraMiddleware),\n ...cacheMiddleware,\n ...(forked && memory != null && memory.length > 0\n ? [\n createMemoryMiddleware({\n backend,\n sources: memory,\n addCacheControl: anthropicModel,\n }),\n ]\n : []),\n ],\n );\n\n if (subagentProfile.excludedMiddleware.size > 0) {\n subagentMiddleware = subagentMiddleware.filter(\n (middleware) =>\n !subagentProfile.excludedMiddleware.has(middleware.name),\n );\n }\n\n if (subagentProfile.excludedTools.size > 0) {\n subagentMiddleware.push(\n createToolExclusionMiddleware(subagentProfile.excludedTools),\n );\n }\n\n return subagentMiddleware;\n };\n\n const normalizeSubagentSpec = (input: SubAgent): SubAgent => ({\n ...input,\n // Omitting tools here lets getSubagents() fall back to the parent's.\n middleware: buildSubagentMiddleware(input),\n });\n\n const allSubagents = subagents as readonly AnySubAgent[];\n\n // Split the unified subagents array into sync and async subagents.\n // AsyncSubAgents are identified by the presence of a `graphId` field.\n const asyncSubAgents = allSubagents.filter((item): item is AsyncSubAgent =>\n isAsyncSubAgent(item),\n );\n\n // Process sync subagents:\n // - CompiledSubAgent: use as-is (already has its own middleware baked in)\n // - SubAgent: apply the default deep-agent subagent middleware stack\n // (a `mode: \"fork\"` spec gets the same treatment, plus mirrored middleware)\n const inlineSubagents = allSubagents\n .filter(\n (item): item is SubAgent | CompiledSubAgent => !isAsyncSubAgent(item),\n )\n .map((item) => (\"runnable\" in item ? item : normalizeSubagentSpec(item)));\n\n const gpConfig = harnessProfile.generalPurposeSubagent;\n const gpDisabled = gpConfig?.enabled === false;\n\n if (\n !gpDisabled &&\n !inlineSubagents.some(\n (item) => item.name === GENERAL_PURPOSE_SUBAGENT[\"name\"],\n )\n ) {\n const gpSystemPrompt =\n gpConfig?.systemPrompt ??\n applyProfilePrompt(harnessProfile, GENERAL_PURPOSE_SUBAGENT.systemPrompt);\n\n const generalPurposeSpec = normalizeSubagentSpec({\n ...GENERAL_PURPOSE_SUBAGENT,\n description:\n gpConfig?.description ?? GENERAL_PURPOSE_SUBAGENT.description,\n systemPrompt: gpSystemPrompt,\n model,\n skills,\n tools: effectiveTools,\n });\n generalPurposeSpec.middleware = mergeMiddlewareStack(\n generalPurposeSpec.middleware ?? [],\n customMiddleware,\n [],\n { appendNew: false },\n );\n inlineSubagents.unshift(generalPurposeSpec);\n }\n\n const skillsMiddleware =\n skills != null && skills.length > 0\n ? [createSkillsMiddleware({ backend, sources: skills })]\n : [];\n\n // Built-in middleware array - core middleware with known types.\n // This tuple is typed without conditional spreads to preserve tuple inference.\n // Optional middleware (skills, memory, HITL, async) are appended at runtime.\n const builtInMiddleware = [\n // Enables filesystem operations and optional long-term memory storage.\n createFilesystemMiddleware({\n backend,\n permissions,\n tools: profileFilesystemTools,\n }),\n // Enables delegation to specialized subagents for complex tasks.\n createSubAgentMiddleware({\n defaultModel: model,\n defaultTools: effectiveTools,\n defaultInterruptOn: interruptOn,\n subagents: inlineSubagents,\n generalPurposeAgent: false,\n parentSystemPrompt: finalSystemPrompt,\n }),\n // Automatically summarizes conversation history when token limits are approached.\n // Uses createSummarizationMiddleware (deepagents version) with backend support\n // for conversation history offloading and auto-computed defaults from model profile.\n createSummarizationMiddleware({ backend }),\n // Patches tool calls to ensure compatibility across different model providers.\n createPatchToolCallsMiddleware(),\n ] as const;\n\n const [\n fsMiddleware,\n subagentMiddleware,\n summarizationMiddleware,\n patchToolCallsMiddleware,\n ] = builtInMiddleware;\n\n // Runtime middleware array: combine core middleware, custom overrides, and tail middleware.\n const coreMiddleware: AgentMiddleware[] = [\n // Optional root-level skills.\n ...skillsMiddleware,\n fsMiddleware,\n subagentMiddleware,\n summarizationMiddleware,\n patchToolCallsMiddleware,\n // Optional async subagent bridge.\n ...(asyncSubAgents.length > 0\n ? [createAsyncSubAgentMiddleware({ asyncSubAgents })]\n : []),\n ];\n const tailMiddleware: AgentMiddleware[] = [\n // Profile middleware runs before cache middleware so it participates in prompt caching.\n ...resolveMiddleware(harnessProfile.extraMiddleware),\n // Optional Anthropic cache controls.\n ...cacheMiddleware,\n // Optional memory support.\n ...memoryMiddleware,\n // Optional human-in-the-loop tool interrupts.\n ...(interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []),\n ];\n\n let middleware: AgentMiddleware[] = mergeMiddlewareStack(\n coreMiddleware,\n customMiddleware,\n tailMiddleware,\n );\n\n // Apply profile middleware exclusions after custom replacement so exclusions win.\n if (harnessProfile.excludedMiddleware.size > 0) {\n const excluded = harnessProfile.excludedMiddleware;\n middleware = middleware.filter((entry) => !excluded.has(entry.name));\n }\n\n // Apply profile tool exclusions via a filtering middleware that runs\n // after all tool-injecting middleware.\n if (harnessProfile.excludedTools.size > 0) {\n middleware.push(\n createToolExclusionMiddleware(harnessProfile.excludedTools),\n );\n }\n\n const agent = createAgent({\n model,\n ...(finalSystemPrompt !== \"\" && { systemPrompt: finalSystemPrompt }),\n stateSchema,\n tools: effectiveTools,\n middleware,\n ...(responseFormat !== null && { responseFormat }),\n contextSchema,\n checkpointer,\n store,\n name,\n streamTransformers,\n }).withConfig({\n recursionLimit: 10_000,\n metadata: {\n ls_integration: \"deepagents\",\n lc_agent_name: name,\n },\n });\n\n /**\n * Combine custom middleware with flattened subagent middleware for complete type inference\n * This ensures InferMiddlewareStates captures state from both sources\n */\n type AllMiddleware = readonly [\n ...typeof builtInMiddleware,\n ...TMiddleware,\n ...FlattenSubAgentMiddleware<TSubagents>,\n ];\n\n /**\n * Return as DeepAgent with proper DeepAgentTypeConfig\n * - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)\n * - State: User-provided stateSchema, merged with middleware-derived state downstream\n * - Context: ContextSchema\n * - Middleware: AllMiddleware (built-in + custom + subagent middleware for state inference)\n * - Tools: TTools\n * - Subagents: TSubagents (for type-safe streaming)\n * - StreamTransformers: TStreamTransformers\n */\n return agent as unknown as DeepAgent<\n DeepAgentTypeConfig<\n InferStructuredResponse<TResponse>,\n TStateSchema,\n ContextSchema,\n AllMiddleware,\n TTools,\n TSubagents,\n TStreamTransformers\n >\n >;\n}\n","/**\n * @deprecated Legacy prompt compatibility exports.\n *\n * These prompts are retained only so existing imports continue to resolve.\n * Deep Agents no longer injects authored base prose or duplicate built-in\n * middleware guidance by default. Do not use these in new code; they will be\n * removed in the next major release.\n */\nimport { context, type SystemMessage } from \"langchain\";\n\n/**\n * @deprecated Compatibility type for the former structured `systemPrompt` API.\n * Existing callers may continue using it, but new code should pass a string or\n * `SystemMessage` directly. This type and its compatibility behavior will be\n * removed in the next major release.\n */\nexport interface SystemPromptConfig {\n /** Content placed before the profile base prompt. */\n prefix?: string | SystemMessage | null;\n /** Replacement for the profile base prompt; `null` omits that base. */\n base?: string | SystemMessage | null;\n /** Content placed after the base prompt and before the profile suffix. */\n suffix?: string | SystemMessage | null;\n}\n\n/**\n * @deprecated Retained for compatibility only. This prompt is not injected by\n * default and will be removed in the next major release.\n */\nexport const BASE_AGENT_PROMPT = context`\n You are a Deep Agent, an AI assistant that helps users accomplish tasks using tools. You respond with text and tool calls. The user can see your responses and tool outputs in real time.\n\n ## Core Behavior\n\n - Be concise and direct. Don't over-explain unless asked.\n - NEVER add unnecessary preamble (\\\"Sure!\\\", \\\"Great question!\\\", \\\"I'll now...\\\").\n - Don't say \\\"I'll now do X\\\" — just do it.\n - If the request is ambiguous, ask questions before acting.\n - If asked how to approach something, explain first, then act.\n\n ## Professional Objectivity\n\n - Prioritize accuracy over validating the user's beliefs\n - Disagree respectfully when the user is incorrect\n - Avoid unnecessary superlatives, praise, or emotional validation\n\n ## Doing Tasks\n\n When the user asks you to do something:\n\n 1. **Understand first** — read relevant files, check existing patterns. Quick but thorough — gather enough evidence to start, then iterate.\n 2. **Act** — implement the solution. Work quickly but accurately.\n 3. **Verify** — check your work against what was asked, not against your own output. Your first attempt is rarely correct — iterate.\n\n Keep working until the task is fully complete. Don't stop partway and explain what you would do — just do it. Only yield back to the user when the task is done or you're genuinely blocked.\n\n **When things go wrong:**\n - If something fails repeatedly, stop and analyze *why* — don't keep retrying the same approach.\n - If you're blocked, tell the user what's wrong and ask for guidance.\n\n ## Progress Updates\n\n For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.\n`;\n\n/**\n * @deprecated Retained for compatibility only. Task-tool guidance now lives in\n * the task tool schema and this export will be removed in the next major release.\n */\nexport const TASK_SYSTEM_PROMPT = context`\n ## \\`task\\` (subagent spawner)\n\n You have access to a \\`task\\` tool to launch short-lived subagents that handle isolated tasks. These agents are ephemeral — they live only for the duration of the task and return a single result.\n\n When to use the task tool:\n - When a task is complex and multi-step, and can be fully delegated in isolation\n - When a task is independent of other tasks and can run in parallel\n - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread\n - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)\n - When you only care about the output of the subagent, and not the intermediate steps (ex. performing a lot of research and then returned a synthesized report, performing a series of computations or lookups to achieve a concise, relevant answer.)\n\n Subagent lifecycle:\n 1. **Spawn** → Provide clear role, instructions, and expected output\n 2. **Run** → The subagent completes the task autonomously\n 3. **Return** → The subagent provides a single structured result\n 4. **Reconcile** → Incorporate or synthesize the result into the main thread\n\n When NOT to use the task tool:\n - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)\n - If the task is trivial (a few tool calls or simple lookup)\n - If delegating does not reduce token usage, complexity, or context switching\n - If splitting would add latency without benefit\n\n ## Important Task Tool Usage Notes to Remember\n - Whenever possible, parallelize the work that you do. This is true for both tool_calls, and for tasks. Whenever you have independent steps to complete - make tool_calls, or kick off tasks (subagents) in parallel to accomplish them faster. This saves time for the user, which is incredibly important.\n - Remember to use the \\`task\\` tool to silo independent tasks within a multi-part objective.\n - You should use the \\`task\\` tool whenever you have a complex task that will take multiple steps, and is independent from other tasks that the agent needs to complete. These agents are highly competent and efficient.\n`;\n\n/**\n * @deprecated Retained for compatibility only. Async-subagent guidance now\n * lives in tool schemas and this export will be removed in the next major release.\n */\nexport const ASYNC_TASK_SYSTEM_PROMPT = `## Async subagents (remote servers)\n\nYou have access to async subagent tools that launch background tasks on remote servers.\n\n### Tools:\n- \\`start_async_task\\`: Start a new background task. Returns a task ID immediately.\n- \\`check_async_task\\`: Check the status of a running task. Returns status and result if complete.\n- \\`update_async_task\\`: Send an update or new instructions to a running task.\n- \\`cancel_async_task\\`: Cancel a running task that is no longer needed.\n- \\`list_async_tasks\\`: List all tracked tasks with live statuses. Use this to check all tasks at once.\n\n### Workflow:\n1. **Launch** — Use \\`start_async_task\\` to start a task. Report the task ID to the user and stop.\n Do NOT immediately check the status — the task runs in the background while you and the user continue other work.\n2. **Check (on request)** — Only use \\`check_async_task\\` when the user explicitly asks for a status update or\n result. If the status is \"running\", report that and stop — do not poll in a loop.\n3. **Update** (optional) — Use \\`update_async_task\\` to send new instructions to a running task. This interrupts\n the current run and starts a fresh one on the same thread. The task_id stays the same.\n4. **Cancel** (optional) — Use \\`cancel_async_task\\` to stop a task that is no longer needed.\n5. **Collect** — When \\`check_async_task\\` returns status \"success\", the result is included in the response.\n6. **List** — Use \\`list_async_tasks\\` to see live statuses for all tasks at once, or to recall task IDs after context compaction.\n\n### Critical rules:\n- After launching, ALWAYS return control to the user immediately. Never auto-check after launching.\n- Never poll \\`check_async_task\\` in a loop. Check once per user request, then stop.\n- If a check returns \"running\", tell the user and wait for them to ask again.\n- Task statuses in conversation history are ALWAYS stale — a task that was \"running\" may now be done.\n NEVER report a status from a previous tool result. ALWAYS call a tool to get the current status:\n use \\`list_async_tasks\\` when the user asks about multiple tasks or \"all tasks\",\n use \\`check_async_task\\` when the user asks about a specific task.\n- Always show the full task_id — never truncate or abbreviate it.\n\n### When to use async subagents:\n- Long-running tasks that would block the main agent\n- Tasks that benefit from running on specialized remote deployments\n- When you want to run multiple tasks concurrently and collect results later`;\n\n/**\n * @deprecated Retained for compatibility only. Execute guidance now lives in\n * the execute tool schema and this export will be removed in the next major release.\n */\nexport const EXECUTION_SYSTEM_PROMPT = context`\n ## Execute Tool \\`execute\\`\n\n You have access to an \\`execute\\` tool for running shell commands in a sandboxed environment.\n Use this tool to run commands, scripts, tests, builds, and other shell operations.\n\n - execute: run a shell command in the sandbox (returns output and exit code)\n`;\n","/**\n * StoreBackend: Adapter for LangGraph's BaseStore (persistent, cross-thread).\n */\n\nimport {\n Item,\n getConfig,\n getCurrentTaskInput,\n getStore as getLangGraphStore,\n} from \"@langchain/langgraph\";\nimport type { BaseStore, PutOperation } from \"@langchain/langgraph-checkpoint\";\nimport type {\n BackendOptions,\n BackendProtocolV2,\n DeleteResult,\n EditResult,\n FileData,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n WriteResult,\n StateAndStore,\n} from \"./protocol.js\";\nimport { applyGrepMaxCount } from \"./protocol.js\";\nimport {\n createFileData,\n createWriteFileData,\n fileDataToString,\n getMimeType,\n globSearchFiles,\n grepMatchesFromFiles,\n isFileDataBinary,\n isFileDataV1,\n isTextMimeType,\n migrateToFileDataV2,\n normalizeReadPagination,\n performStringReplacement,\n updateFileData,\n} from \"./utils.js\";\n\nconst NAMESPACE_COMPONENT_RE = /^[A-Za-z0-9\\-_.@+:~]+$/;\n\nfunction trimTrailingSlashes(path: string): string {\n let end = path.length;\n while (end > 1 && path[end - 1] === \"/\") end--;\n return path.slice(0, end);\n}\n\nfunction getObjectRecord(value: unknown): Record<string, unknown> | undefined {\n return value != null && typeof value === \"object\"\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction getAssistantIdFromRecord(\n value: Record<string, unknown> | undefined,\n): string | undefined {\n const assistantId = value?.assistant_id ?? value?.assistantId;\n return typeof assistantId === \"string\" && assistantId.length > 0\n ? assistantId\n : undefined;\n}\n\n/**\n * Validate a namespace array.\n *\n * Each component must be a non-empty string containing only safe characters:\n * alphanumeric (a-z, A-Z, 0-9), hyphen (-), underscore (_), dot (.),\n * at sign (@), plus (+), colon (:), and tilde (~).\n *\n * Characters like *, ?, [, ], {, } etc. are rejected to prevent\n * wildcard or glob injection in store lookups.\n */\nfunction validateNamespace(namespace: string[]): string[] {\n if (namespace.length === 0) {\n throw new Error(\"Namespace array must not be empty.\");\n }\n for (let i = 0; i < namespace.length; i++) {\n const component = namespace[i];\n if (typeof component !== \"string\") {\n throw new TypeError(\n `Namespace component at index ${i} must be a string, got ${typeof component}.`,\n );\n }\n if (!component) {\n throw new Error(`Namespace component at index ${i} must not be empty.`);\n }\n if (!NAMESPACE_COMPONENT_RE.test(component)) {\n throw new Error(\n `Namespace component at index ${i} contains disallowed characters: \"${component}\". ` +\n `Only alphanumeric characters, hyphens, underscores, dots, @, +, colons, and tildes are allowed.`,\n );\n }\n }\n return namespace;\n}\n\n/**\n * Context provided to dynamic namespace factory functions.\n */\nexport interface StoreBackendContext<StateT = unknown> {\n /**\n * Current graph state, when available.\n *\n * In legacy factory mode this is the injected runtime state. In zero-arg mode\n * this is read from the current LangGraph execution context.\n */\n state: StateT;\n /**\n * Runnable config, when available.\n *\n * This mirrors the Python implementation's access to config metadata for\n * namespace resolution.\n */\n config?: {\n metadata?: Record<string, unknown>;\n configurable?: Record<string, unknown>;\n };\n /**\n * Legacy assistant identifier, resolved from config metadata first and then\n * from the injected runtime for backwards compatibility.\n */\n assistantId?: string;\n}\n\nexport type StoreBackendNamespaceFactory<StateT = unknown> = (\n context: StoreBackendContext<StateT>,\n) => string[];\n\n/**\n * Options for StoreBackend constructor.\n */\nexport interface StoreBackendOptions<StateT = unknown> extends BackendOptions {\n /**\n * Explicit store instance to use for persistence.\n *\n * This mirrors the Python API and allows constructing a backend directly with\n * a store instance, e.g. `new StoreBackend({ store })`.\n *\n * When omitted, the backend uses the legacy injected runtime store or the\n * LangGraph execution-context store.\n */\n store?: BaseStore;\n /**\n * Custom namespace for store operations.\n *\n * Accepts either a static namespace array or a factory that derives the\n * namespace from the current backend context.\n *\n * If not provided, falls back to legacy assistant-id detection from config\n * metadata, then the injected runtime's `assistantId`, and finally\n * `[\"filesystem\"]`.\n *\n * @example\n * ```typescript\n * // Static namespace\n * new StoreBackend({\n * namespace: [\"memories\", orgId, userId, \"filesystem\"],\n * });\n *\n * // Dynamic namespace\n * new StoreBackend({\n * namespace: ({ state }) => [\n * \"memories\",\n * (state as { userId: string }).userId,\n * \"filesystem\",\n * ],\n * });\n * ```\n */\n namespace?: string[] | StoreBackendNamespaceFactory<StateT>;\n}\n\n/**\n * Backend that stores files in LangGraph's BaseStore (persistent).\n *\n * Uses LangGraph's Store for persistent, cross-conversation storage.\n * Files are organized via namespaces and persist across all threads.\n *\n * The namespace can be customized via a factory function for flexible\n * isolation patterns (user-scoped, org-scoped, etc.), or falls back\n * to legacy assistant_id-based isolation.\n */\nexport class StoreBackend implements BackendProtocolV2 {\n private stateAndStore: StateAndStore | undefined;\n private storeOverride: BaseStore | undefined;\n private _namespace: string[] | StoreBackendNamespaceFactory | undefined;\n private fileFormat: \"v1\" | \"v2\";\n\n constructor(options?: StoreBackendOptions);\n /**\n * @deprecated Pass no `stateAndStore` argument\n */\n constructor(stateAndStore: StateAndStore, options?: StoreBackendOptions);\n constructor(\n stateAndStoreOrOptions?: StateAndStore | StoreBackendOptions,\n options?: StoreBackendOptions,\n ) {\n let opts: StoreBackendOptions | undefined;\n if (\n stateAndStoreOrOptions != null &&\n typeof stateAndStoreOrOptions === \"object\" &&\n \"state\" in stateAndStoreOrOptions\n ) {\n // Legacy path\n this.stateAndStore = stateAndStoreOrOptions;\n opts = options;\n } else {\n this.stateAndStore = undefined;\n opts = stateAndStoreOrOptions;\n }\n\n if (Array.isArray(opts?.namespace)) {\n this._namespace = validateNamespace(opts.namespace);\n } else if (opts?.namespace) {\n this._namespace = opts.namespace;\n }\n this.storeOverride = opts?.store;\n this.fileFormat = opts?.fileFormat ?? \"v2\";\n }\n\n /**\n * Get the BaseStore instance for persistent storage operations.\n *\n * In legacy mode, reads from the injected {@link StateAndStore}.\n * In zero-arg mode, retrieves the store from the LangGraph execution\n * context via {@link getLangGraphStore}.\n *\n * @returns BaseStore instance\n * @throws Error if no store is available in either mode\n */\n private getStore() {\n if (this.stateAndStore) {\n const store = this.stateAndStore.store;\n if (!store) {\n throw new Error(\"Store is required but not available in runtime\");\n }\n return store;\n }\n\n if (this.storeOverride) {\n return this.storeOverride;\n }\n\n const store = getLangGraphStore();\n if (!store) {\n throw new Error(\n \"Store is required but not available in LangGraph execution context. \" +\n \"Ensure the graph was configured with a store.\",\n );\n }\n\n return store;\n }\n\n /**\n * Get the current graph state when available.\n */\n private getState(): unknown {\n if (this.stateAndStore) {\n return this.stateAndStore.state;\n }\n\n try {\n return getCurrentTaskInput();\n } catch {\n return undefined;\n }\n }\n\n /**\n * Get the most relevant runnable config for namespace resolution.\n */\n private getNamespaceConfig():\n | {\n metadata?: Record<string, unknown>;\n configurable?: Record<string, unknown>;\n }\n | undefined {\n const injectedConfig = getObjectRecord(\n (this.stateAndStore as { config?: unknown } | undefined)?.config,\n );\n if (injectedConfig) {\n return {\n metadata: getObjectRecord(injectedConfig.metadata),\n configurable: getObjectRecord(injectedConfig.configurable),\n };\n }\n\n try {\n const config = getConfig();\n const configRecord = getObjectRecord(config);\n if (!configRecord) {\n return undefined;\n }\n return {\n metadata: getObjectRecord(configRecord.metadata),\n configurable: getObjectRecord(configRecord.configurable),\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Legacy assistant-id detection compatible with both Python and the\n * historical TypeScript `assistantId` runtime property.\n */\n private getLegacyAssistantId(): string | undefined {\n const config = this.getNamespaceConfig();\n const assistantIdFromConfig =\n getAssistantIdFromRecord(config?.metadata) ??\n getAssistantIdFromRecord(config?.configurable);\n if (assistantIdFromConfig) {\n return assistantIdFromConfig;\n }\n\n const assistantId = this.stateAndStore?.assistantId;\n return typeof assistantId === \"string\" && assistantId.length > 0\n ? assistantId\n : undefined;\n }\n\n /**\n * Get the namespace for store operations.\n *\n * Resolution order:\n * 1. Explicit namespace from constructor options\n * 2. Namespace factory resolved from the current backend context\n * 3. Assistant ID from runtime config / LangGraph config metadata\n * 4. Legacy `assistantId` from the injected runtime\n * 5. `[\"filesystem\"]`\n */\n protected getNamespace(): string[] {\n if (Array.isArray(this._namespace)) {\n return this._namespace;\n }\n\n if (this._namespace) {\n return validateNamespace(\n this._namespace({\n state: this.getState(),\n config: this.getNamespaceConfig(),\n assistantId: this.getLegacyAssistantId(),\n }),\n );\n }\n\n const assistantId = this.getLegacyAssistantId();\n if (assistantId) {\n return [assistantId, \"filesystem\"];\n }\n\n return [\"filesystem\"];\n }\n\n /**\n * Convert a store Item to FileData format.\n *\n * @param storeItem - The store Item containing file data\n * @returns FileData object\n * @throws Error if required fields are missing or have incorrect types\n */\n private convertStoreItemToFileData(storeItem: Item): FileData {\n const value = storeItem.value as any;\n\n const hasValidContent =\n value.content !== undefined &&\n (Array.isArray(value.content) ||\n typeof value.content === \"string\" ||\n ArrayBuffer.isView(value.content));\n\n if (\n !hasValidContent ||\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,\n ...(value.mimeType ? { mimeType: value.mimeType } : {}),\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 * @param fileData - The FileData to convert\n * @returns Object with content, mimeType, created_at, and modified_at fields\n */\n private convertFileDataToStoreValue(fileData: FileData): Record<string, any> {\n return {\n content: fileData.content,\n ...(\"mimeType\" in fileData ? { mimeType: fileData.mimeType } : {}),\n created_at: fileData.created_at,\n modified_at: fileData.modified_at,\n };\n }\n\n /**\n * Search store with automatic pagination to retrieve all results.\n *\n * @param store - The store to search\n * @param namespace - Hierarchical path prefix to search within\n * @param options - Optional query, filter, and page_size\n * @returns List of all items matching the search criteria\n */\n private async searchStorePaginated(\n store: any,\n namespace: string[],\n options: {\n query?: string;\n filter?: Record<string, any>;\n pageSize?: number;\n } = {},\n ): Promise<Item[]> {\n const { query, filter, pageSize = 100 } = options;\n const allItems: Item[] = [];\n let offset = 0;\n\n while (true) {\n const pageItems = await store.search(namespace, {\n query,\n filter,\n limit: pageSize,\n offset,\n });\n\n if (!pageItems || pageItems.length === 0) {\n break;\n }\n\n allItems.push(...pageItems);\n\n if (pageItems.length < pageSize) {\n break;\n }\n\n offset += pageSize;\n }\n\n return allItems;\n }\n\n /**\n * List files and directories in the specified directory (non-recursive).\n *\n * @param path - Absolute path to directory\n * @returns LsResult with list of FileInfo objects on success or error on failure.\n * Directories have a trailing / in their path and is_dir=true.\n */\n async ls(path: string): Promise<LsResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n\n // Retrieve all items and filter by path prefix locally to avoid\n // coupling to store-specific filter semantics\n const items = await this.searchStorePaginated(store, 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 = String(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.convertStoreItemToFileData(item);\n const size = isFileDataV1(fd)\n ? fd.content.join(\"\\n\").length\n : isFileDataBinary(fd)\n ? fd.content.byteLength\n : fd.content.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 { files: infos };\n }\n\n /**\n * Read file content.\n *\n * Text files are paginated by line offset/limit.\n * Binary files return full Uint8Array content (offset/limit ignored).\n *\n * @param filePath - Absolute file path\n * @param offset - Line offset to start reading from (0-indexed)\n * @param limit - Maximum number of lines to read\n * @returns ReadResult with content on success or error on failure\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 500,\n ): Promise<ReadResult> {\n try {\n const readRawResult = await this.readRaw(filePath);\n if (readRawResult.error || !readRawResult.data) {\n return { error: readRawResult.error || \"File data not found\" };\n }\n\n const fileDataV2 = migrateToFileDataV2(readRawResult.data, filePath);\n\n // ignore pagination and return full content\n if (!isTextMimeType(fileDataV2.mimeType)) {\n return { content: fileDataV2.content, mimeType: fileDataV2.mimeType };\n }\n\n if (typeof fileDataV2.content !== \"string\") {\n return {\n error: `File '${filePath}' has binary content but text MIME type`,\n };\n }\n const { offset: normalizedOffset, limit: normalizedLimit } =\n normalizeReadPagination(offset, limit);\n const lines = fileDataV2.content.split(\"\\n\");\n const totalLines =\n lines[lines.length - 1] === \"\" ? lines.length - 1 : lines.length;\n const selected = lines.slice(\n normalizedOffset,\n normalizedOffset + normalizedLimit,\n );\n if (\n selected.length === 0 ||\n normalizedOffset >= totalLines ||\n normalizedLimit === 0\n ) {\n return { content: selected.join(\"\\n\"), mimeType: fileDataV2.mimeType };\n }\n const endOffset = Math.min(\n normalizedOffset + selected.length,\n totalLines,\n );\n return {\n content: selected.join(\"\\n\"),\n mimeType: fileDataV2.mimeType,\n totalLines,\n startLine: normalizedOffset + 1,\n endLine: endOffset,\n nextOffset: endOffset < totalLines ? endOffset : undefined,\n };\n } catch (e: any) {\n return { error: e.message };\n }\n }\n\n /**\n * Read file content as raw FileData.\n *\n * @param filePath - Absolute file path\n * @returns ReadRawResult with raw file data on success or error on failure\n */\n async readRaw(filePath: string): Promise<ReadRawResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const item = await store.get(namespace, filePath);\n\n if (!item) {\n return { error: `File '${filePath}' not found` };\n }\n return { data: this.convertStoreItemToFileData(item) };\n }\n\n /**\n * Write content to a file, creating it or overwriting it if it already exists.\n * Returns WriteResult. External storage sets filesUpdate=null.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n\n const existing = await store.get(namespace, filePath);\n const existingFileData = existing\n ? this.convertStoreItemToFileData(existing)\n : undefined;\n\n const fileData = createWriteFileData(\n filePath,\n content,\n this.fileFormat,\n existingFileData,\n );\n const storeValue = this.convertFileDataToStoreValue(fileData);\n await store.put(namespace, filePath, storeValue);\n return { path: filePath, filesUpdate: null };\n }\n\n /**\n * Delete a file or directory from the store.\n *\n * Removes the exact key plus every nested key under it.\n */\n async delete(filePath: string): Promise<DeleteResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const items = await this.searchStorePaginated(store, namespace);\n const base = trimTrailingSlashes(filePath) || \"/\";\n const prefix = base === \"/\" ? \"/\" : `${base}/`;\n const keys = items\n .map((item) => String(item.key))\n .filter((key) => key === base || key.startsWith(prefix));\n\n if (keys.length === 0) {\n return { error: `Error: File '${filePath}' not found` };\n }\n\n const deleteOperations: PutOperation[] = keys.map((key) => ({\n namespace,\n key,\n value: null,\n }));\n\n try {\n await store.batch(deleteOperations);\n } catch (error) {\n const message =\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ? error.message\n : String(error);\n return { error: `Error deleting '${filePath}': ${message}` };\n }\n\n return { path: filePath, filesUpdate: null };\n }\n\n /**\n * Edit a file by replacing string occurrences.\n * Returns EditResult. External storage sets filesUpdate=null.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n ): Promise<EditResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n\n // Get existing file\n const item = await store.get(namespace, filePath);\n if (!item) {\n return { error: `Error: File '${filePath}' not found` };\n }\n\n try {\n const fileData = this.convertStoreItemToFileData(item);\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 { 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.convertFileDataToStoreValue(newFileData);\n await store.put(namespace, filePath, storeValue);\n return { path: filePath, filesUpdate: null, occurrences: occurrences };\n } catch (e: any) {\n return { error: `Error: ${e.message}` };\n }\n }\n\n /**\n * Search file contents for a literal text pattern.\n * Binary files are skipped.\n */\n async grep(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null,\n maxCount: number | null = null,\n ): Promise<GrepResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const items = await this.searchStorePaginated(store, namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertStoreItemToFileData(item);\n } catch {\n // Skip invalid items\n continue;\n }\n }\n\n const matches = grepMatchesFromFiles(files, pattern, path, glob);\n return applyGrepMaxCount({ result: { matches }, maxCount });\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n */\n async glob(pattern: string, path: string = \"/\"): Promise<GlobResult> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const items = await this.searchStorePaginated(store, namespace);\n\n const files: Record<string, FileData> = {};\n for (const item of items) {\n try {\n files[item.key] = this.convertStoreItemToFileData(item);\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 { files: [] };\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\n ? isFileDataV1(fd)\n ? fd.content.join(\"\\n\").length\n : isFileDataBinary(fd)\n ? fd.content.byteLength\n : fd.content.length\n : 0;\n infos.push({\n path: p,\n is_dir: false,\n size: size,\n modified_at: fd?.modified_at || \"\",\n });\n }\n return { files: infos };\n }\n\n /**\n * Upload multiple files.\n *\n * @param files - List of [path, content] tuples to upload\n * @returns List of FileUploadResponse objects, one per input file\n */\n async uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): Promise<FileUploadResponse[]> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const responses: FileUploadResponse[] = [];\n\n for (const [path, content] of files) {\n try {\n const mimeType = getMimeType(path);\n const isBinary = this.fileFormat === \"v2\" && !isTextMimeType(mimeType);\n\n let fileData: FileData;\n if (isBinary) {\n fileData = createFileData(content, undefined, \"v2\", mimeType);\n } else {\n const contentStr = new TextDecoder().decode(content);\n fileData = createFileData(\n contentStr,\n undefined,\n this.fileFormat,\n mimeType,\n );\n }\n\n const storeValue = this.convertFileDataToStoreValue(fileData);\n await store.put(namespace, path, storeValue);\n responses.push({ path, error: null });\n } catch {\n responses.push({ path, error: \"invalid_path\" });\n }\n }\n\n return responses;\n }\n\n /**\n * Download multiple files.\n *\n * @param paths - List of file paths to download\n * @returns List of FileDownloadResponse objects, one per input path\n */\n async downloadFiles(paths: string[]): Promise<FileDownloadResponse[]> {\n const store = this.getStore();\n const namespace = this.getNamespace();\n const responses: FileDownloadResponse[] = [];\n\n for (const path of paths) {\n try {\n const item = await store.get(namespace, path);\n if (!item) {\n responses.push({ path, content: null, error: \"file_not_found\" });\n continue;\n }\n\n const fileData = this.convertStoreItemToFileData(item);\n const fileDataV2 = migrateToFileDataV2(fileData, path);\n\n if (typeof fileDataV2.content === \"string\") {\n const content = new TextEncoder().encode(fileDataV2.content);\n responses.push({ path, content, error: null });\n } else {\n responses.push({ path, content: fileDataV2.content, error: null });\n }\n } catch {\n responses.push({ path, content: null, error: \"file_not_found\" });\n }\n }\n\n return responses;\n }\n}\n","/**\n * ContextHubBackend: Store files in a LangSmith Hub agent repo (persistent).\n */\n\nimport micromatch from \"micromatch\";\nimport { Client } from \"langsmith\";\nimport type { AgentContext, Entry } from \"langsmith/schemas\";\nimport { Deferred } from \"../utils.js\";\nimport type {\n BackendProtocolV2,\n DeleteResult,\n EditResult,\n FileDownloadResponse,\n FileInfo,\n FileOperationError,\n FileUploadResponse,\n GlobResult,\n GrepMatch,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n WriteResult,\n} from \"./protocol.js\";\nimport { applyGrepMaxCount } from \"./protocol.js\";\nimport { normalizeReadPagination, performStringReplacement } from \"./utils.js\";\n\nconst CONTEXT_URL_COMMIT_PATH_RE = /^\\/context\\/([^/]+)\\/([0-9a-f]{8})$/;\nconst LEGACY_URL_COMMIT_PATH_RE = /^\\/hub\\/([^/]+)\\/([^/:]+):([0-9a-f]{8})$/;\nconst MUTATION_COALESCE_MS = 50;\nconst MAX_CONFLICT_RETRIES = 3;\nconst TEXT_MIME_TYPE = \"text/plain\";\nconst FNMATCH_OPTIONS = { bash: true };\n\ntype FileChanges = Record<string, string | null>;\n\n/**\n * The logical operation a caller requested. `changes` operations are absolute\n * file updates, while `edit` retains the replacement instruction so it can be\n * replayed against a freshly pulled tree after a parent-commit conflict.\n */\ntype MutationIntent =\n | { kind: \"changes\"; changes: FileChanges }\n | {\n kind: \"edit\";\n path: string;\n oldString: string;\n newString: string;\n replaceAll: boolean;\n updateOccurrences: (occurrences: number) => void;\n }\n | { kind: \"delete\"; base: string };\n\n/**\n * A caller waiting for one logical mutation to become durable. Completion is\n * settled only after the batch push succeeds, or rejected if the worker can no\n * longer commit the caller's batch.\n */\ninterface MutationWaiter {\n intent: MutationIntent;\n completion: Deferred<void>;\n}\n\n/**\n * A coalesced group of mutations. `changes` is the current materialization of\n * the ordered waiter intents and is used both for the Hub payload and the\n * optimistic read overlay. A later conflict refresh may rebuild it.\n */\ninterface MutationBatch {\n changes: FileChanges;\n waiters: MutationWaiter[];\n ready: Deferred<void>;\n timer: ReturnType<typeof setTimeout> | null;\n}\n\ninterface MutationAcceptance<T> {\n result: T;\n completion?: Promise<void>;\n}\n\n/** The last authoritative Context Hub tree and its parent commit hash. */\ninterface TreeSnapshot {\n cache: Record<string, string>;\n linkedEntries: Record<string, string>;\n commitHash: string | null;\n}\n\ntype PushBatchResult =\n | { kind: \"commit\"; commitHash: string }\n | { kind: \"snapshot\"; snapshot: TreeSnapshot };\n\nfunction parseHubTargetIdentifier(\n identifier: string,\n): [owner: string, name: string] | null {\n if (\n !identifier ||\n identifier.split(\"/\").length > 2 ||\n identifier.startsWith(\"/\") ||\n identifier.endsWith(\"/\") ||\n identifier.split(\":\").length > 2\n ) {\n return null;\n }\n\n const [ownerNamePart] = identifier.split(\":\");\n if (ownerNamePart.includes(\"/\")) {\n const [owner, name] = ownerNamePart.split(\"/\", 2);\n return owner && name ? [owner, name] : null;\n }\n return ownerNamePart ? [\"-\", ownerNamePart] : null;\n}\n\nfunction parseCommitHashFromUrl(\n url: string,\n identifier: string,\n): string | null {\n try {\n const pathname = decodeURIComponent(new URL(url).pathname);\n const target = parseHubTargetIdentifier(identifier);\n if (target === null) {\n return null;\n }\n const [targetOwner, targetName] = target;\n\n const contextMatch = CONTEXT_URL_COMMIT_PATH_RE.exec(pathname);\n if (contextMatch !== null && contextMatch[1] === targetName) {\n return contextMatch[2];\n }\n\n const legacyMatch = LEGACY_URL_COMMIT_PATH_RE.exec(pathname);\n if (\n legacyMatch !== null &&\n legacyMatch[1] === targetOwner &&\n legacyMatch[2] === targetName\n ) {\n return legacyMatch[3];\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction trimTrailingSlashes(path: string): string {\n let end = path.length;\n while (end > 0 && path[end - 1] === \"/\") end -= 1;\n return path.slice(0, end);\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (typeof error === \"string\") {\n return error;\n }\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n return String(error);\n}\n\nfunction splitLinesKeepEnds(content: string): string[] {\n const lines: string[] = [];\n let lineStart = 0;\n for (let index = 0; index < content.length; index += 1) {\n if (content[index] === \"\\n\") {\n lines.push(content.slice(lineStart, index + 1));\n lineStart = index + 1;\n }\n }\n\n if (lineStart < content.length) {\n lines.push(content.slice(lineStart));\n }\n\n return lines;\n}\n\nfunction sliceReadContent(\n content: string,\n offset: number,\n limit: number,\n): ReadResult {\n if (!content) {\n return { content };\n }\n\n const normalized = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const lines = splitLinesKeepEnds(normalized);\n const startIndex = offset;\n const endIndex = Math.min(startIndex + limit, lines.length);\n\n if (startIndex >= lines.length) {\n return {\n error: `Line offset ${offset} exceeds file length (${lines.length} lines)`,\n };\n }\n\n const selected = lines.slice(startIndex, endIndex);\n if (selected.length === 0 || offset < 0 || limit <= 0) {\n return { content: selected.join(\"\") };\n }\n return {\n content: selected.join(\"\"),\n totalLines: lines.length,\n startLine: startIndex + 1,\n endLine: endIndex,\n nextOffset: endIndex < lines.length ? endIndex : undefined,\n };\n}\n\nfunction isLangSmithNotFoundError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) {\n return false;\n }\n\n const maybeError = error as { name?: unknown; status?: unknown };\n return (\n maybeError.name === \"LangSmithNotFoundError\" || maybeError.status === 404\n );\n}\n\nfunction isLangSmithError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) {\n return false;\n }\n\n const maybeError = error as { name?: unknown; status?: unknown };\n return (\n (typeof maybeError.name === \"string\" &&\n maybeError.name.startsWith(\"LangSmith\")) ||\n typeof maybeError.status === \"number\"\n );\n}\n\nfunction getLangSmithStatus(error: unknown): number | undefined {\n if (typeof error !== \"object\" || error === null) {\n return undefined;\n }\n\n const maybeError = error as { status?: unknown };\n if (typeof maybeError.status === \"number\") {\n return maybeError.status;\n }\n\n return undefined;\n}\n\nfunction createLangSmithConflictError(message: string): Error & {\n status: number;\n} {\n const error = new Error(message) as Error & { status: number };\n error.name = \"LangSmithConflictError\";\n error.status = 409;\n return error;\n}\n\nfunction mapHubFileOperationError(error: unknown): FileOperationError {\n const status = getLangSmithStatus(error);\n if (status === 401 || status === 403) {\n return \"permission_denied\";\n }\n if (status === 404) {\n return \"file_not_found\";\n }\n return \"invalid_path\";\n}\n\n/**\n * Backend that stores files in a LangSmith Hub agent repo (persistent).\n */\n/**\n * Backend that stores files in a LangSmith Hub agent repository.\n *\n * ## Mutation model\n *\n * Mutations are accepted in call order, coalesced for a short window, and\n * pushed by one worker. Only one batch is in flight at a time; mutations that\n * arrive during a push form the next batch. This serializes one backend\n * instance's writes while still reducing the number of Hub commits.\n *\n * Reads use an optimistic view: the last durable cache overlaid with the\n * in-flight batch and then the pending batch. A read can therefore observe an\n * accepted mutation before it is durable; a failed push invalidates that view\n * and the next operation reloads from Hub.\n *\n * A `409` parent conflict triggers an authoritative pull and rematerializes\n * the in-flight batch over the fetched tree before retrying. Edits replay their\n * original replacement intent; absolute writes, deletes, and uploads replay as\n * absolute changes. Retries are bounded by `MAX_CONFLICT_RETRIES`.\n */\nexport class ContextHubBackend implements BackendProtocolV2 {\n private identifier: string;\n private client: Client;\n /** Last durable Hub file state; `null` means the next access must load it. */\n private cache: Record<string, string> | null = null;\n private linkedEntries: Record<string, string> = {};\n /** Parent hash for the durable cache, used for optimistic-concurrency pushes. */\n private commitHash: string | null = null;\n /** Shared cold-load promise so concurrent first operations perform one pull. */\n private loadPromise: Promise<void> | null = null;\n /** Promise chain serializing mutation acceptance and optimistic projections. */\n private mutationOrder = Promise.resolve();\n /** Mutations accepted for the next coalesced push. */\n private pendingBatch: MutationBatch | null = null;\n /** The batch currently submitted to Hub and visible to optimistic reads. */\n private inFlightBatch: MutationBatch | null = null;\n /** The single queue-draining worker, when active. */\n private workerPromise: Promise<void> | null = null;\n /**\n * Blocks cache consumers while a successful push without a parseable commit\n * hash is being confirmed by an authoritative pull.\n */\n private snapshotPublication: Deferred<void> | null = null;\n\n constructor(\n identifier: string,\n options: {\n client?: Client;\n } = {},\n ) {\n this.identifier = identifier;\n this.client = options.client ?? new Client();\n }\n\n private static stripPrefix(path: string): string {\n return path.replace(/^\\/+/, \"\");\n }\n\n private static toHubUnavailableError(error: unknown): string {\n return `Hub unavailable: ${getErrorMessage(error)}`;\n }\n\n private async fetchTree(): Promise<TreeSnapshot> {\n let context: AgentContext;\n try {\n context = await this.client.pullAgent(this.identifier);\n } catch (error) {\n if (isLangSmithNotFoundError(error)) {\n return { cache: {}, linkedEntries: {}, commitHash: null };\n }\n throw error;\n }\n\n const cache: Record<string, string> = {};\n const linkedEntries: Record<string, string> = {};\n\n for (const [path, entry] of Object.entries(context.files)) {\n if (entry.type === \"file\") {\n cache[path] = entry.content;\n } else if (\n (entry.type === \"agent\" || entry.type === \"skill\") &&\n typeof entry.repo_handle === \"string\"\n ) {\n linkedEntries[path] = entry.repo_handle;\n }\n }\n\n return { cache, linkedEntries, commitHash: context.commit_hash };\n }\n\n private publishSnapshot(snapshot: TreeSnapshot): void {\n this.cache = snapshot.cache;\n this.linkedEntries = snapshot.linkedEntries;\n this.commitHash = snapshot.commitHash;\n }\n\n private async loadTree(): Promise<void> {\n this.publishSnapshot(await this.fetchTree());\n }\n\n private beginSnapshotPublication(): void {\n if (this.snapshotPublication !== null) {\n throw new Error(\"Context Hub snapshot publication is already pending\");\n }\n\n this.snapshotPublication = new Deferred<void>();\n }\n\n private finishSnapshotPublication(): void {\n const publication = this.snapshotPublication;\n this.snapshotPublication = null;\n publication?.resolve();\n }\n\n private async ensureCacheLoaded(): Promise<void> {\n // Publish a hashless-push snapshot only after its old in-flight overlay can be removed.\n while (this.snapshotPublication !== null) {\n await this.snapshotPublication;\n }\n\n if (this.cache === null) {\n let loadPromise = this.loadPromise;\n if (loadPromise === null) {\n loadPromise = this.loadTree();\n this.loadPromise = loadPromise;\n }\n\n try {\n await loadPromise;\n } finally {\n if (this.loadPromise === loadPromise) {\n this.loadPromise = null;\n }\n }\n }\n if (this.cache === null) {\n throw new Error(\"Context Hub cache failed to initialize\");\n }\n }\n\n private async ensureCache(): Promise<Record<string, string>> {\n await this.ensureCacheLoaded();\n return this.visibleCache();\n }\n\n private static applyChanges(\n cache: Record<string, string>,\n changes: FileChanges,\n ): Record<string, string> {\n const next = { ...cache };\n for (const [path, content] of Object.entries(changes)) {\n if (content === null) {\n delete next[path];\n } else {\n next[path] = content;\n }\n }\n return next;\n }\n\n /**\n * Select the exact key at `base` plus every key nested under `base + \"/\"`\n * and map each to `null` (a deletion marker). Returns an empty object when\n * nothing is stored at or under `base`. Recomputing this against the current\n * cache is what makes a recursive delete correct under conflict replay.\n */\n private static collectDeleteChanges(\n cache: Record<string, string>,\n base: string,\n ): FileChanges {\n const prefix = base === \"\" ? \"\" : `${base}/`;\n const changes: FileChanges = {};\n for (const key of Object.keys(cache)) {\n if (base === \"\" || key === base || key.startsWith(prefix)) {\n changes[key] = null;\n }\n }\n return changes;\n }\n\n /**\n * Build the read-your-writes view without publishing speculative data as the\n * durable cache. Later batches overlay earlier ones, matching worker order.\n */\n private visibleCache(): Record<string, string> {\n let visible = { ...(this.cache ?? {}) };\n if (this.inFlightBatch !== null) {\n visible = ContextHubBackend.applyChanges(\n visible,\n this.inFlightBatch.changes,\n );\n }\n if (this.pendingBatch !== null) {\n visible = ContextHubBackend.applyChanges(\n visible,\n this.pendingBatch.changes,\n );\n }\n return visible;\n }\n\n private invalidateCache(): void {\n this.cache = null;\n this.linkedEntries = {};\n this.commitHash = null;\n this.loadPromise = null;\n }\n\n private async acquireMutationTurn(): Promise<() => void> {\n let release!: () => void;\n const previous = this.mutationOrder;\n this.mutationOrder = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n return release;\n }\n\n /**\n * Serialize validation and enqueueing so each operation is evaluated against\n * a stable optimistic projection. Cache loading begins before acquiring the\n * turn, allowing concurrent cold-start callers to share the same pull.\n */\n private async acceptMutation<T>(\n operation: (cache: Record<string, string>) => MutationAcceptance<T>,\n ): Promise<MutationAcceptance<T>> {\n const turn = this.acquireMutationTurn();\n const cacheOutcome = this.ensureCacheLoaded().then(\n () => ({ loaded: true }) as const,\n (error: unknown) => ({ loaded: false, error }) as const,\n );\n const release = await turn;\n try {\n const outcome = await cacheOutcome;\n if (!outcome.loaded) {\n throw outcome.error;\n }\n while (this.cache === null) {\n await this.ensureCacheLoaded();\n }\n return operation(this.visibleCache());\n } finally {\n release();\n }\n }\n\n /**\n * Start a batch's coalescing window. The worker waits for this signal before\n * detaching the batch; cancellation resolves it immediately so failures do\n * not leave the worker waiting on a timer.\n */\n private createMutationBatch(): MutationBatch {\n const batch: MutationBatch = {\n changes: {},\n waiters: [],\n ready: new Deferred<void>(),\n timer: null,\n };\n batch.timer = setTimeout(() => {\n batch.timer = null;\n batch.ready.resolve();\n }, MUTATION_COALESCE_MS);\n return batch;\n }\n\n private cancelBatchTimer(batch: MutationBatch): void {\n if (batch.timer !== null) {\n clearTimeout(batch.timer);\n batch.timer = null;\n }\n batch.ready.resolve();\n }\n\n private enqueueCommit(\n changes: FileChanges,\n intent: MutationIntent = { kind: \"changes\", changes: { ...changes } },\n ): Promise<void> {\n if (Object.keys(changes).length === 0) {\n return Promise.resolve();\n }\n\n let batch = this.pendingBatch;\n if (batch === null) {\n batch = this.createMutationBatch();\n this.pendingBatch = batch;\n }\n Object.assign(batch.changes, changes);\n\n const completion = new Deferred<void>();\n batch.waiters.push({ intent, completion });\n this.startWorker();\n return completion.promise;\n }\n\n /**\n * Replay ordered intents over an authoritative base after a conflict. This\n * rebuilds the push payload and optimistic overlay. An edit that no longer\n * applies throws the supplied conflict error; absolute changes are reapplied.\n */\n private rematerializeBatch(\n batch: MutationBatch,\n base: Record<string, string>,\n conflictError: unknown,\n ): Record<string, string> {\n let cache = { ...base };\n const changes: FileChanges = {};\n\n for (const waiter of batch.waiters) {\n const { intent } = waiter;\n if (intent.kind === \"changes\") {\n Object.assign(changes, intent.changes);\n cache = ContextHubBackend.applyChanges(cache, intent.changes);\n continue;\n }\n\n if (intent.kind === \"delete\") {\n // Recompute the recursive delete against the refreshed cache so\n // descendants added concurrently before replay are also removed.\n const deleteChanges = ContextHubBackend.collectDeleteChanges(\n cache,\n intent.base,\n );\n Object.assign(changes, deleteChanges);\n cache = ContextHubBackend.applyChanges(cache, deleteChanges);\n continue;\n }\n\n const current = cache[intent.path];\n if (current === undefined) {\n throw conflictError;\n }\n const replacementResult = performStringReplacement(\n current,\n intent.oldString,\n intent.newString,\n intent.replaceAll,\n );\n if (typeof replacementResult === \"string\") {\n throw conflictError;\n }\n\n const [newContent, occurrences] = replacementResult;\n const editChanges = { [intent.path]: newContent };\n Object.assign(changes, editChanges);\n cache = ContextHubBackend.applyChanges(cache, editChanges);\n intent.updateOccurrences(occurrences);\n }\n\n batch.changes = changes;\n return cache;\n }\n\n private rematerializeAfterConflict(\n batch: MutationBatch,\n snapshot: TreeSnapshot,\n conflictError: unknown,\n ): void {\n const cache = this.rematerializeBatch(batch, snapshot.cache, conflictError);\n let pendingReplayError: unknown = null;\n if (this.pendingBatch !== null) {\n try {\n this.rematerializeBatch(this.pendingBatch, cache, conflictError);\n } catch (error) {\n if (error !== conflictError) {\n throw error;\n }\n pendingReplayError = error;\n }\n }\n this.publishSnapshot(snapshot);\n if (pendingReplayError !== null) {\n // A queued replay failure must not abort the valid in-flight retry.\n this.failPendingBatch(pendingReplayError);\n }\n }\n\n private rematerializePendingBatch(snapshot: TreeSnapshot): Error | null {\n if (this.pendingBatch === null) {\n return null;\n }\n const conflictError = createLangSmithConflictError(\n \"Pending Context Hub mutation conflicts with authoritative state\",\n );\n try {\n this.rematerializeBatch(this.pendingBatch, snapshot.cache, conflictError);\n return null;\n } catch (error) {\n if (error !== conflictError) {\n throw error;\n }\n return conflictError;\n }\n }\n\n private startWorker(): void {\n if (this.workerPromise !== null) {\n return;\n }\n\n const worker = this.drainMutationQueue()\n .catch((error: unknown) => {\n this.failAllBatches(error);\n })\n .finally(() => {\n if (this.workerPromise === worker) {\n this.workerPromise = null;\n if (this.pendingBatch !== null) {\n this.startWorker();\n }\n }\n });\n this.workerPromise = worker;\n }\n\n /**\n * Drain coalesced batches sequentially. A completed batch publishes durable\n * state before settling its callers; a failed batch invalidates local state\n * and rejects both in-flight and queued callers so the next mutation reloads.\n */\n private async drainMutationQueue(): Promise<void> {\n while (this.pendingBatch !== null) {\n const batch = this.pendingBatch;\n await batch.ready;\n if (this.pendingBatch !== batch) {\n continue;\n }\n\n this.pendingBatch = null;\n this.inFlightBatch = batch;\n let pendingReplayError: Error | null = null;\n try {\n const result = await this.pushBatch(batch);\n if (result.kind === \"snapshot\") {\n pendingReplayError = this.rematerializePendingBatch(result.snapshot);\n this.publishSnapshot(result.snapshot);\n } else {\n this.cache = ContextHubBackend.applyChanges(\n this.cache ?? {},\n batch.changes,\n );\n this.commitHash = result.commitHash;\n }\n } catch (error) {\n this.inFlightBatch = null;\n this.invalidateCache();\n this.finishSnapshotPublication();\n for (const waiter of batch.waiters) {\n waiter.completion.reject(error);\n }\n this.failPendingBatch(error);\n return;\n }\n\n this.inFlightBatch = null;\n this.finishSnapshotPublication();\n for (const waiter of batch.waiters) {\n waiter.completion.resolve();\n }\n if (pendingReplayError !== null) {\n this.failPendingBatch(pendingReplayError);\n return;\n }\n }\n }\n\n private failPendingBatch(error: unknown): void {\n const pending = this.pendingBatch;\n if (pending === null) {\n return;\n }\n this.pendingBatch = null;\n this.cancelBatchTimer(pending);\n for (const waiter of pending.waiters) {\n waiter.completion.reject(error);\n }\n }\n\n private failAllBatches(error: unknown): void {\n const inFlight = this.inFlightBatch;\n this.inFlightBatch = null;\n this.invalidateCache();\n this.finishSnapshotPublication();\n if (inFlight !== null) {\n this.cancelBatchTimer(inFlight);\n for (const waiter of inFlight.waiters) {\n waiter.completion.reject(error);\n }\n }\n this.failPendingBatch(error);\n }\n\n /**\n * Push a materialized batch with the durable commit as its parent. On a 409,\n * refresh Hub state, replay the batch, and retry with the new parent. A push\n * response without a trustworthy hash is confirmed by a pull before callers\n * are allowed to observe it as durable.\n */\n private async pushBatch(batch: MutationBatch): Promise<PushBatchResult> {\n for (let attempt = 0; ; attempt += 1) {\n const payload: Record<string, Entry | null> = {};\n for (const [path, content] of Object.entries(batch.changes)) {\n payload[path] = content === null ? null : { type: \"file\", content };\n }\n\n let url: string;\n try {\n url = await this.client.pushAgent(this.identifier, {\n files: payload,\n ...(this.commitHash ? { parentCommit: this.commitHash } : {}),\n });\n } catch (error) {\n if (\n getLangSmithStatus(error) !== 409 ||\n attempt >= MAX_CONFLICT_RETRIES\n ) {\n throw error;\n }\n const snapshot = await this.fetchTree();\n this.rematerializeAfterConflict(batch, snapshot, error);\n continue;\n }\n\n const pushedCommitHash = parseCommitHashFromUrl(url, this.identifier);\n if (pushedCommitHash === null) {\n this.beginSnapshotPublication();\n const snapshot = await this.fetchTree();\n if (snapshot.commitHash === null) {\n throw new Error(\n \"Context Hub commit succeeded but its hash could not be resolved\",\n );\n }\n return {\n kind: \"snapshot\",\n snapshot,\n };\n }\n return { kind: \"commit\", commitHash: pushedCommitHash };\n }\n }\n\n /**\n * Return linked-entry paths mapped to their repo handles.\n */\n async getLinkedEntries(): Promise<Record<string, string>> {\n await this.ensureCache();\n return { ...this.linkedEntries };\n }\n\n /**\n * Return true if the hub repo already exists with at least one commit.\n */\n async hasPriorCommits(): Promise<boolean> {\n await this.ensureCache();\n return this.commitHash !== null;\n }\n\n async ls(path: string = \"/\"): Promise<LsResult> {\n const hubPrefix = ContextHubBackend.stripPrefix(path).replace(/\\/+$/, \"\");\n\n let cache: Record<string, string>;\n try {\n cache = await this.ensureCache();\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n\n const dirs = new Set<string>();\n const entries: FileInfo[] = [];\n\n for (const filePath of Object.keys(cache)) {\n if (hubPrefix && !filePath.startsWith(`${hubPrefix}/`)) {\n continue;\n }\n\n const relative = hubPrefix\n ? filePath.slice(hubPrefix.length + 1)\n : filePath;\n if (!relative) {\n continue;\n }\n\n const slashIndex = relative.indexOf(\"/\");\n if (slashIndex === -1) {\n entries.push({ path: `/${filePath}`, is_dir: false });\n continue;\n }\n\n const dirName = relative.slice(0, slashIndex);\n const dirPath = hubPrefix ? `${hubPrefix}/${dirName}` : dirName;\n if (!dirs.has(dirPath)) {\n dirs.add(dirPath);\n entries.push({ path: `/${dirPath}`, is_dir: true });\n }\n }\n\n return { files: entries };\n }\n\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 2000,\n ): Promise<ReadResult> {\n const hubPath = ContextHubBackend.stripPrefix(filePath);\n\n let cache: Record<string, string>;\n try {\n cache = await this.ensureCache();\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n\n const content = cache[hubPath];\n if (content === undefined) {\n return { error: `File '${filePath}' not found` };\n }\n\n const { offset: normalizedOffset, limit: normalizedLimit } =\n normalizeReadPagination(offset, limit);\n const sliced = sliceReadContent(content, normalizedOffset, normalizedLimit);\n if (sliced.error) {\n return { error: sliced.error };\n }\n\n return {\n ...sliced,\n content: sliced.content ?? \"\",\n mimeType: TEXT_MIME_TYPE,\n };\n }\n\n async readRaw(filePath: string): Promise<ReadRawResult> {\n const readResult = await this.read(filePath, 0, Number.MAX_SAFE_INTEGER);\n if (readResult.error || typeof readResult.content !== \"string\") {\n return { error: readResult.error ?? `File '${filePath}' not found` };\n }\n\n const now = new Date().toISOString();\n return {\n data: {\n content: readResult.content,\n mimeType: TEXT_MIME_TYPE,\n created_at: now,\n modified_at: now,\n },\n };\n }\n\n async grep(\n pattern: string,\n path: string | null = null,\n glob: string | null = null,\n maxCount: number | null = null,\n ): Promise<GrepResult> {\n let cache: Record<string, string>;\n try {\n cache = await this.ensureCache();\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n\n const prefix = path\n ? ContextHubBackend.stripPrefix(path).replace(/\\/+$/, \"\")\n : \"\";\n\n const matches: GrepMatch[] = [];\n for (const [filePath, content] of Object.entries(cache)) {\n if (prefix && !filePath.startsWith(prefix)) {\n continue;\n }\n if (glob && !micromatch.isMatch(filePath, glob, FNMATCH_OPTIONS)) {\n continue;\n }\n\n const lines = content.split(\"\\n\");\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index];\n if (line.includes(pattern)) {\n matches.push({ path: `/${filePath}`, line: index + 1, text: line });\n }\n }\n }\n\n return applyGrepMaxCount({ result: { matches }, maxCount });\n }\n\n async glob(pattern: string, _path: string = \"/\"): Promise<GlobResult> {\n let cache: Record<string, string>;\n try {\n cache = await this.ensureCache();\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n\n const files: FileInfo[] = [];\n for (const filePath of Object.keys(cache)) {\n if (\n micromatch.isMatch(`/${filePath}`, pattern, FNMATCH_OPTIONS) ||\n micromatch.isMatch(filePath, pattern, FNMATCH_OPTIONS)\n ) {\n files.push({ path: `/${filePath}`, is_dir: false });\n }\n }\n\n return { files };\n }\n\n async write(filePath: string, content: string): Promise<WriteResult> {\n const hubPath = ContextHubBackend.stripPrefix(filePath);\n\n try {\n const accepted = await this.acceptMutation<WriteResult>(() => {\n return {\n result: { path: filePath, filesUpdate: null },\n completion: this.enqueueCommit({ [hubPath]: content }),\n };\n });\n await accepted.completion;\n return accepted.result;\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n }\n\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n ): Promise<EditResult> {\n const hubPath = ContextHubBackend.stripPrefix(filePath);\n\n try {\n const accepted = await this.acceptMutation<EditResult>((cache) => {\n const current = cache[hubPath];\n if (current === undefined) {\n return {\n result: { error: `Error: File '${filePath}' not found` },\n };\n }\n\n const replacementResult = performStringReplacement(\n current,\n oldString,\n newString,\n replaceAll,\n );\n if (typeof replacementResult === \"string\") {\n return { result: { error: replacementResult } };\n }\n\n const [newContent, occurrences] = replacementResult;\n const result: EditResult = {\n path: filePath,\n filesUpdate: null,\n occurrences,\n };\n return {\n result,\n completion: this.enqueueCommit(\n { [hubPath]: newContent },\n {\n kind: \"edit\",\n path: hubPath,\n oldString,\n newString,\n replaceAll,\n updateOccurrences: (replayedOccurrences) => {\n result.occurrences = replayedOccurrences;\n },\n },\n ),\n };\n });\n await accepted.completion;\n return accepted.result;\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n }\n\n async delete(filePath: string): Promise<DeleteResult> {\n const hubPath = ContextHubBackend.stripPrefix(filePath);\n\n try {\n const accepted = await this.acceptMutation<DeleteResult>((cache) => {\n // Delete the exact key plus every entry nested under it, so a directory\n // (represented only by descendant keys) is removed recursively. A\n // dedicated delete intent lets conflict replay re-select descendants\n // discovered after the initial materialization.\n const base = trimTrailingSlashes(hubPath);\n const deleteChanges = ContextHubBackend.collectDeleteChanges(\n cache,\n base,\n );\n if (Object.keys(deleteChanges).length === 0) {\n return {\n result: { error: `Error: File '${filePath}' not found` },\n };\n }\n\n return {\n result: { path: filePath },\n completion: this.enqueueCommit(deleteChanges, {\n kind: \"delete\",\n base,\n }),\n };\n });\n await accepted.completion;\n return accepted.result;\n } catch (error) {\n if (isLangSmithError(error)) {\n return { error: ContextHubBackend.toHubUnavailableError(error) };\n }\n throw error;\n }\n }\n\n async uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): Promise<FileUploadResponse[]> {\n const decoder = new TextDecoder(\"utf-8\", { fatal: true });\n const decoded: Array<[string, string | null]> = [];\n const validFiles: Record<string, string> = {};\n\n for (const [path, content] of files) {\n try {\n const text = decoder.decode(content);\n decoded.push([path, text]);\n validFiles[ContextHubBackend.stripPrefix(path)] = text;\n } catch {\n decoded.push([path, null]);\n }\n }\n\n let commitError: FileOperationError | null = null;\n if (Object.keys(validFiles).length > 0) {\n try {\n const accepted = await this.acceptMutation<null>(() => {\n return {\n result: null,\n completion: this.enqueueCommit(validFiles),\n };\n });\n await accepted.completion;\n } catch (error) {\n if (isLangSmithError(error)) {\n commitError = mapHubFileOperationError(error);\n } else {\n throw error;\n }\n }\n }\n\n return decoded.map(([path, text]) => {\n if (text === null) {\n return { path, error: \"invalid_path\" };\n }\n if (commitError !== null) {\n return { path, error: commitError };\n }\n return { path, error: null };\n });\n }\n\n async downloadFiles(paths: string[]): Promise<FileDownloadResponse[]> {\n let cache: Record<string, string>;\n try {\n cache = await this.ensureCache();\n } catch (error) {\n if (isLangSmithError(error)) {\n const mappedError = mapHubFileOperationError(error);\n return paths.map((path) => ({\n path,\n content: null,\n error: mappedError,\n }));\n }\n throw error;\n }\n\n const encoder = new TextEncoder();\n return paths.map((path) => {\n const hubPath = ContextHubBackend.stripPrefix(path);\n const content = cache[hubPath];\n if (content !== undefined) {\n return { path, content: encoder.encode(content), error: null };\n }\n return { path, content: null, error: \"file_not_found\" };\n });\n }\n}\n","/**\n * BaseSandbox: Abstract base class for sandbox backends with command execution.\n *\n * This class provides default implementations for all SandboxBackendProtocol\n * methods. Concrete implementations only need to implement execute(),\n * uploadFiles(), and downloadFiles().\n *\n * Runtime requirements on the sandbox host:\n * - read, grep: Pure POSIX shell (awk, grep) — works on any Linux including Alpine\n * - write, edit, readRaw: No runtime needed — uses uploadFiles/downloadFiles directly\n * - ls, glob: Pure POSIX shell (find, stat) — works on any Linux including Alpine\n *\n * No Python, Node.js, or other runtime required.\n */\n\nimport type {\n DeleteResult,\n EditResult,\n ExecuteResponse,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepMatch,\n GrepResult,\n LsResult,\n MaybePromise,\n ReadRawResult,\n ReadResult,\n SandboxBackendProtocolV2,\n WriteResult,\n} from \"./protocol.js\";\nimport { applyGrepMaxCount } from \"./protocol.js\";\nimport {\n getMimeType,\n isTextMimeType,\n normalizeReadPagination,\n} from \"./utils.js\";\n\n/**\n * Shell-quote a string using single quotes (POSIX).\n * Escapes embedded single quotes with the '\\'' technique.\n */\nfunction shellQuote(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n/**\n * Convert a glob pattern to a path-aware RegExp.\n *\n * Inspired by the just-bash project's glob utilities:\n * - `*` matches any characters except `/`\n * - `**` matches any characters including `/` (recursive)\n * - `?` matches a single character except `/`\n * - `[...]` character classes\n */\nfunction globToPathRegex(pattern: string): RegExp {\n let regex = \"^\";\n let i = 0;\n\n while (i < pattern.length) {\n const c = pattern[i];\n\n if (c === \"*\") {\n if (i + 1 < pattern.length && pattern[i + 1] === \"*\") {\n // ** (globstar) matches everything including /\n i += 2;\n if (i < pattern.length && pattern[i] === \"/\") {\n // **/ matches zero or more directory segments\n regex += \"(.*/)?\";\n i++;\n } else {\n // ** at end matches anything\n regex += \".*\";\n }\n } else {\n // * matches anything except /\n regex += \"[^/]*\";\n i++;\n }\n } else if (c === \"?\") {\n regex += \"[^/]\";\n i++;\n } else if (c === \"[\") {\n // Character class — find closing bracket\n let j = i + 1;\n while (j < pattern.length && pattern[j] !== \"]\") j++;\n regex += pattern.slice(i, j + 1);\n i = j + 1;\n } else if (\n c === \".\" ||\n c === \"+\" ||\n c === \"^\" ||\n c === \"$\" ||\n c === \"{\" ||\n c === \"}\" ||\n c === \"(\" ||\n c === \")\" ||\n c === \"|\" ||\n c === \"\\\\\"\n ) {\n regex += `\\\\${c}`;\n i++;\n } else {\n regex += c;\n i++;\n }\n }\n\n regex += \"$\";\n return new RegExp(regex);\n}\n\n/**\n * Parse a single line of stat/find output in the format: size\\tmtime\\ttype\\tpath\n *\n * The first three tab-delimited fields are always fixed (number, number, string),\n * so we safely take everything after the third tab as the file path — even if the\n * path itself contains tabs.\n *\n * The type field varies by platform / tool:\n * - GNU find -printf %y: single letter \"d\", \"f\", \"l\"\n * - BSD stat -f %Sp: permission strings like \"drwxr-xr-x\", \"-rw-r--r--\"\n *\n * The mtime field may be a float (GNU find %T@ → \"1234567890.0000000000\")\n * or an integer (BSD stat %m → \"1234567890\"); parseInt handles both.\n */\nfunction parseStatLine(\n line: string,\n): { size: number; mtime: number; isDir: boolean; fullPath: string } | null {\n const firstTab = line.indexOf(\"\\t\");\n if (firstTab === -1) return null;\n\n const secondTab = line.indexOf(\"\\t\", firstTab + 1);\n if (secondTab === -1) return null;\n\n const thirdTab = line.indexOf(\"\\t\", secondTab + 1);\n if (thirdTab === -1) return null;\n\n const size = parseInt(line.slice(0, firstTab), 10);\n const mtime = parseInt(line.slice(firstTab + 1, secondTab), 10);\n const fileType = line.slice(secondTab + 1, thirdTab);\n const fullPath = line.slice(thirdTab + 1);\n\n if (isNaN(size) || isNaN(mtime)) return null;\n\n return {\n size,\n mtime,\n // GNU find %y outputs \"d\"; BSD stat %Sp outputs \"drwxr-xr-x\"\n isDir:\n fileType === \"d\" || fileType === \"directory\" || fileType.startsWith(\"d\"),\n fullPath,\n };\n}\n\n/**\n * BusyBox/Alpine fallback script for stat -c.\n *\n * Determines file type with POSIX test builtins, then uses stat -c\n * (supported by both GNU coreutils and BusyBox) for size and mtime.\n * printf handles tab-delimited output formatting.\n */\nconst STAT_C_SCRIPT =\n \"for f; do \" +\n 'if [ -d \"$f\" ]; then t=d; elif [ -L \"$f\" ]; then t=l; else t=f; fi; ' +\n 'sz=$(stat -c %s \"$f\" 2>/dev/null) || continue; ' +\n 'mt=$(stat -c %Y \"$f\" 2>/dev/null) || continue; ' +\n 'printf \"%s\\\\t%s\\\\t%s\\\\t%s\\\\n\" \"$sz\" \"$mt\" \"$t\" \"$f\"; ' +\n \"done\";\n\n/**\n * Shell command for listing directory contents with metadata.\n *\n * Detects the environment at runtime with three-way probing:\n * 1. GNU find (full Linux): uses built-in `-printf` (most efficient)\n * 2. BusyBox / Alpine: uses `find -exec sh -c` with `stat -c` fallback\n * 3. BSD / macOS: uses `find -exec stat -f`\n *\n * Output format per line: size\\tmtime\\ttype\\tpath\n */\nfunction buildLsCommand(dirPath: string): string {\n const quotedPath = shellQuote(dirPath);\n const findBase = `find -L ${quotedPath} -maxdepth 1 -not -path ${quotedPath}`;\n return (\n `if find /dev/null -maxdepth 0 -printf '' 2>/dev/null; then ` +\n `${findBase} -printf '%s\\\\t%T@\\\\t%y\\\\t%p\\\\n' 2>/dev/null; ` +\n `elif stat -c %s /dev/null >/dev/null 2>&1; then ` +\n `${findBase} -exec sh -c '${STAT_C_SCRIPT}' _ {} +; ` +\n `else ` +\n `${findBase} -exec stat -f '%z\\t%m\\t%Sp\\t%N' {} + 2>/dev/null; ` +\n `fi || true`\n );\n}\n\n/**\n * Soft cap on recursive find lines for sandbox glob.\n *\n * Glob currently lists every path under the search root via `find`, then filters\n * in-process. Without a bound, a root-path recursive glob can stream the whole\n * container rootfs (and, with `-L`, loop through proc pid root symlinks) into\n * the host heap and OOM the runtime. Cap the listing; callers mark truncated\n * when the cap is hit.\n */\nconst MAX_GLOB_FIND_LINES = 50_000;\n\n/**\n * Shell command for listing files recursively with metadata.\n * Same three-way detection as buildLsCommand (GNU -printf / stat -c / BSD stat -f).\n *\n * Prunes virtual filesystems (`/proc`, `/sys`, `/dev`, `/run`) so `find -L`\n * cannot follow proc pid root symlinks back into `/` and loop forever. Caps\n * stdout so the host process that buffers `execute()` never materializes an\n * unbounded listing.\n *\n * Output format per line: size\\tmtime\\ttype\\tpath\n */\nfunction buildFindCommand(searchPath: string): string {\n const quotedPath = shellQuote(searchPath);\n // Absolute + search-relative prunes: -L can leave the search tree via\n // symlinks into /proc before the relative prune would apply.\n const prune =\n `\\\\( -path /proc -o -path /sys -o -path /dev -o -path /run ` +\n `-o -path ${quotedPath}/proc -o -path ${quotedPath}/sys ` +\n `-o -path ${quotedPath}/dev -o -path ${quotedPath}/run \\\\) -prune`;\n const findBase = `find -L ${quotedPath} ${prune} -o -not -path ${quotedPath}`;\n const listing =\n `if find /dev/null -maxdepth 0 -printf '' 2>/dev/null; then ` +\n `${findBase} -printf '%s\\\\t%T@\\\\t%y\\\\t%p\\\\n' 2>/dev/null; ` +\n `elif stat -c %s /dev/null >/dev/null 2>&1; then ` +\n `${findBase} -exec sh -c '${STAT_C_SCRIPT}' _ {} +; ` +\n `else ` +\n `${findBase} -exec stat -f '%z\\t%m\\t%Sp\\t%N' {} + 2>/dev/null; ` +\n `fi || true`;\n // Request one past the soft cap so glob() can detect truncation.\n return `{ ${listing}; } | head -n ${MAX_GLOB_FIND_LINES + 1}`;\n}\n\nconst READ_METADATA_PREFIX = \"__DEEPAGENTS_READ_METADATA__\";\n\n/**\n * Pure POSIX shell command for reading files with line numbers.\n * Uses awk for line numbering with offset/limit — works on any Linux including Alpine.\n */\nfunction buildReadCommand(\n filePath: string,\n offset: number,\n limit: number,\n): string {\n const quotedPath = shellQuote(filePath);\n // Coerce offset and limit to safe non-negative integers.\n const safeOffset =\n Number.isFinite(offset) && offset > 0 ? Math.floor(offset) : 0;\n const safeLimit =\n Number.isFinite(limit) && limit > 0\n ? Math.min(Math.floor(limit), 999_999_999)\n : 999_999_999;\n // awk NR is 1-based, our offset is 0-based\n const start = safeOffset + 1;\n const end = safeOffset + safeLimit;\n\n return [\n `if [ ! -f ${quotedPath} ]; then echo \"Error: File not found\"; exit 1; fi`,\n `if [ ! -s ${quotedPath} ]; then echo \"System reminder: File exists but has empty contents\"; exit 0; fi`,\n `awk 'NR >= ${start} && NR <= ${end} { printf \"%6d\\\\t%s\\\\n\", NR, $0 } END { printf \"${READ_METADATA_PREFIX}\\\\t%d\\\\n\", NR }' ${quotedPath}`,\n ].join(\"; \");\n}\n\nfunction parseReadOutput(\n output: string,\n offset: number,\n limit: number,\n): ReadResult {\n const rows = output.split(\"\\n\");\n let metadataIndex = -1;\n for (let index = rows.length - 1; index >= 0; index -= 1) {\n if (rows[index].startsWith(`${READ_METADATA_PREFIX}\\t`)) {\n metadataIndex = index;\n break;\n }\n }\n if (metadataIndex === -1) {\n return { content: output };\n }\n\n const totalLines = Number(\n rows[metadataIndex].slice(READ_METADATA_PREFIX.length + 1),\n );\n if (!Number.isSafeInteger(totalLines) || totalLines < 0) {\n return { content: output };\n }\n\n const contentRows = rows.slice(0, metadataIndex);\n const content = contentRows.length > 0 ? `${contentRows.join(\"\\n\")}\\n` : \"\";\n const startOffset = Math.floor(offset);\n const endOffset = Math.min(startOffset + Math.floor(limit), totalLines);\n if (startOffset >= totalLines || endOffset <= startOffset) {\n return { content };\n }\n\n return {\n content,\n totalLines,\n startLine: startOffset + 1,\n endLine: endOffset,\n nextOffset: endOffset < totalLines ? endOffset : undefined,\n };\n}\n\n/**\n * Build a grep command for literal (fixed-string) search.\n * Uses grep -rHnF for recursive, with-filename, with-line-number, fixed-string search.\n *\n * When a glob pattern is provided, uses `find -name GLOB -exec grep` instead of\n * `grep --include=GLOB` for universal compatibility (BusyBox grep lacks --include).\n *\n * @param pattern - Literal string to search for (NOT regex).\n * @param searchPath - Base path to search in.\n * @param globPattern - Optional glob pattern to filter files.\n */\nfunction buildGrepCommand(\n pattern: string,\n searchPath: string,\n globPattern: string | null,\n): string {\n const patternEscaped = shellQuote(pattern);\n const searchPathQuoted = shellQuote(searchPath);\n\n if (globPattern) {\n // Use find + grep for BusyBox compatibility (BusyBox grep lacks --include)\n const globEscaped = shellQuote(globPattern);\n return `find -L ${searchPathQuoted} -type f -name ${globEscaped} -exec grep -HnF -e ${patternEscaped} {} + 2>/dev/null || true`;\n }\n\n return `grep -rHnF -e ${patternEscaped} ${searchPathQuoted} 2>/dev/null || true`;\n}\n\n/**\n * Base sandbox implementation with execute() as the only abstract method.\n *\n * This class provides default implementations for all SandboxBackendProtocol\n * methods using shell commands executed via execute(). Concrete implementations\n * only need to implement execute(), uploadFiles(), and downloadFiles().\n *\n * All shell commands use pure POSIX utilities (awk, grep, find, stat) that are\n * available on any Linux including Alpine/busybox. No Python, Node.js, or\n * other runtime is required on the sandbox host.\n */\nexport abstract class BaseSandbox implements SandboxBackendProtocolV2 {\n /** Unique identifier for the sandbox backend */\n abstract readonly id: string;\n\n /**\n * Execute a command in the sandbox.\n * This is the only method concrete implementations must provide.\n */\n abstract execute(command: string): MaybePromise<ExecuteResponse>;\n\n /**\n * Upload multiple files to the sandbox.\n * Implementations must support partial success.\n */\n abstract uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): MaybePromise<FileUploadResponse[]>;\n\n /**\n * Download multiple files from the sandbox.\n * Implementations must support partial success.\n */\n abstract downloadFiles(paths: string[]): MaybePromise<FileDownloadResponse[]>;\n\n /**\n * List files and directories in the specified directory (non-recursive).\n *\n * Uses pure POSIX shell (find + stat) via execute() — works on any Linux\n * including Alpine. No Python or Node.js needed.\n *\n * @param path - Absolute path to directory\n * @returns LsResult with list of FileInfo objects on success or error on failure.\n */\n async ls(path: string): Promise<LsResult> {\n const command = buildLsCommand(path);\n const result = await this.execute(command);\n\n const infos: FileInfo[] = [];\n const lines = result.output.trim().split(\"\\n\").filter(Boolean);\n\n for (const line of lines) {\n const parsed = parseStatLine(line);\n if (!parsed) continue;\n\n infos.push({\n path: parsed.isDir ? parsed.fullPath + \"/\" : parsed.fullPath,\n is_dir: parsed.isDir,\n size: parsed.size,\n modified_at: new Date(parsed.mtime * 1000).toISOString(),\n });\n }\n\n return { files: infos };\n }\n\n /**\n * Read file content with line numbers.\n *\n * Uses pure POSIX shell (awk) via execute() — only the requested slice\n * is returned over the wire, making this efficient for large files.\n * Works on any Linux including Alpine (no Python or Node.js needed).\n *\n * @param filePath - Absolute file path\n * @param offset - Line offset to start reading from (0-indexed)\n * @param limit - Maximum number of lines to read\n * @returns Formatted file content with line numbers, or error message\n */\n async read(\n filePath: string,\n offset: number = 0,\n limit: number = 500,\n ): Promise<ReadResult> {\n const mimeType = getMimeType(filePath);\n\n // for binary, download full file and return as Uint8Array\n if (!isTextMimeType(mimeType)) {\n const results = await this.downloadFiles([filePath]);\n if (results[0].error || !results[0].content) {\n return { error: `File '${filePath}' not found` };\n }\n\n return { content: results[0].content, mimeType };\n }\n\n const { offset: normalizedOffset, limit: normalizedLimit } =\n normalizeReadPagination(offset, limit);\n\n // limit=0 means return nothing\n if (normalizedLimit === 0) return { content: \"\", mimeType };\n\n const command = buildReadCommand(\n filePath,\n normalizedOffset,\n normalizedLimit,\n );\n const result = await this.execute(command);\n\n if (result.exitCode !== 0) {\n return { error: `File '${filePath}' not found` };\n }\n\n const parsed = parseReadOutput(\n result.output,\n normalizedOffset,\n normalizedLimit,\n );\n return {\n ...(result.truncated ? { content: parsed.content } : parsed),\n mimeType,\n };\n }\n\n /**\n * Read file content as raw FileData.\n *\n * Uses downloadFiles() directly — no runtime needed on the sandbox host.\n *\n * @param filePath - Absolute file path\n * @returns ReadRawResult with raw file data on success or error on failure\n */\n async readRaw(filePath: string): Promise<ReadRawResult> {\n const results = await this.downloadFiles([filePath]);\n if (results[0].error || !results[0].content) {\n return { error: `File '${filePath}' not found` };\n }\n\n const now = new Date().toISOString();\n const mimeType = getMimeType(filePath);\n\n // Binary: store as Uint8Array\n if (!isTextMimeType(mimeType)) {\n return {\n data: {\n content: results[0].content,\n mimeType,\n created_at: now,\n modified_at: now,\n },\n };\n }\n\n // Text: store as string (v2 format)\n return {\n data: {\n content: new TextDecoder().decode(results[0].content),\n mimeType,\n created_at: now,\n modified_at: now,\n },\n };\n }\n\n /**\n * Search for a literal text pattern in files using grep.\n *\n * @param pattern - Literal string to search for (NOT regex).\n * @param path - Directory or file path to search in.\n * @param glob - Optional glob pattern to filter which files to search.\n * @returns List of GrepMatch dicts containing path, line number, and matched text.\n */\n async grep(\n pattern: string,\n path: string = \"/\",\n glob: string | null = null,\n maxCount: number | null = null,\n ): Promise<GrepResult> {\n const command = buildGrepCommand(pattern, path, glob);\n const result = await this.execute(command);\n\n const output = result.output.trim();\n if (!output) {\n return { matches: [] };\n }\n\n // Parse grep output format: path:line_number:text\n const matches: GrepMatch[] = [];\n for (const line of output.split(\"\\n\")) {\n const parts = line.split(\":\");\n if (parts.length >= 3) {\n const filePath = parts[0];\n\n // Skip binary files\n const mimeType = getMimeType(filePath);\n if (!isTextMimeType(mimeType)) {\n continue;\n }\n\n const lineNum = parseInt(parts[1], 10);\n if (!isNaN(lineNum)) {\n matches.push({\n path: filePath,\n line: lineNum,\n text: parts.slice(2).join(\":\"),\n });\n }\n }\n }\n\n return applyGrepMaxCount({ result: { matches }, maxCount });\n }\n\n /**\n * Structured glob matching returning FileInfo objects.\n *\n * Uses pure POSIX shell (find + stat) via execute() to list all files,\n * then applies glob-to-regex matching in TypeScript. No Python or Node.js\n * needed on the sandbox host.\n *\n * Glob patterns are matched against paths relative to the search base:\n * - `*` matches any characters except `/`\n * - `**` matches any characters including `/` (recursive)\n * - `?` matches a single character except `/`\n * - `[...]` character classes\n */\n async glob(pattern: string, path: string = \"/\"): Promise<GlobResult> {\n const command = buildFindCommand(path);\n const result = await this.execute(command);\n\n const regex = globToPathRegex(pattern);\n const infos: FileInfo[] = [];\n const lines = result.output.trim().split(\"\\n\").filter(Boolean);\n // execute() can cut output before the shell reaches the soft cap, so the\n // backend's own flag has to be folded in or a partial listing looks complete.\n const overCap = lines.length > MAX_GLOB_FIND_LINES;\n const truncated = overCap || result.truncated === true;\n const limited = overCap ? lines.slice(0, MAX_GLOB_FIND_LINES) : lines;\n\n // Normalise base path (strip trailing /)\n const basePath = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n\n for (const line of limited) {\n const parsed = parseStatLine(line);\n if (!parsed) continue;\n\n // Compute path relative to the search base\n const relPath = parsed.fullPath.startsWith(basePath + \"/\")\n ? parsed.fullPath.slice(basePath.length + 1)\n : parsed.fullPath;\n\n if (regex.test(relPath)) {\n infos.push({\n path: relPath,\n is_dir: parsed.isDir,\n size: parsed.size,\n modified_at: new Date(parsed.mtime * 1000).toISOString(),\n });\n }\n }\n\n return { files: infos, truncated };\n }\n\n /**\n * Write content to a file, creating it or overwriting it if it already exists.\n *\n * Uses uploadFiles() to write. No runtime needed on the sandbox host.\n */\n async write(filePath: string, content: string): Promise<WriteResult> {\n const mimeType = getMimeType(filePath);\n let fileContent: Uint8Array;\n\n if (isTextMimeType(mimeType)) {\n fileContent = new TextEncoder().encode(content);\n } else {\n fileContent = Buffer.from(content, \"base64\");\n }\n\n const results = await this.uploadFiles([[filePath, fileContent]]);\n\n if (results[0].error) {\n return {\n error: `Failed to write to ${filePath}: ${results[0].error}`,\n };\n }\n\n return { path: filePath, filesUpdate: null };\n }\n\n /**\n * Delete a file or directory from the sandbox via a server-side `rm`.\n *\n * Runs `test -e || test -L` first: a path that does not exist (and is not a\n * broken symlink) returns a not-found error, matching the contract of\n * `FilesystemBackend` and `StateBackend`. Because a shell `test` has no error\n * channel, a non-zero probe conflates \"absent\" with \"unstattable\" (e.g. an\n * unsearchable parent directory); an unknown exit code is not treated as\n * absent and falls through to the delete.\n *\n * Uses `rm -rf`, so directories are removed recursively along with their\n * contents. A non-zero `rm` exit (e.g. a permission error) is reported as a\n * failure.\n */\n async delete(filePath: string): Promise<DeleteResult> {\n // shellQuote only neutralizes shell metacharacters so the path is passed to\n // `rm` as a single literal argument. It is NOT a security boundary: it does\n // not confine the deletion to any sandbox root. Whatever the sandbox shell\n // can reach, this can delete.\n const quoted = shellQuote(filePath);\n const exists = await this.execute(`test -e ${quoted} || test -L ${quoted}`);\n // Only a definite non-zero probe means the path is absent. A null/unknown\n // exit code is not treated as not-found — fall through to `rm`.\n if (exists.exitCode !== null && exists.exitCode !== 0) {\n return { error: `Error: '${filePath}' not found` };\n }\n\n const result = await this.execute(`rm -rf ${quoted}`);\n if (result.exitCode === 0) {\n return { path: filePath, filesUpdate: null };\n }\n return {\n error: `Error deleting file '${filePath}': ${\n result.output.trim() || \"unknown error\"\n }`,\n };\n }\n\n /**\n * Edit a file by replacing string occurrences.\n *\n * Uses downloadFiles() to read, performs string replacement in TypeScript,\n * then uploadFiles() to write back. No runtime needed on the sandbox host.\n *\n * Memory-conscious: releases intermediate references early so the GC can\n * reclaim buffers before the next large allocation is made.\n */\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n ): Promise<EditResult> {\n const results = await this.downloadFiles([filePath]);\n if (results[0].error || !results[0].content) {\n return { error: `Error: File '${filePath}' not found` };\n }\n\n const text = new TextDecoder().decode(results[0].content);\n results[0].content = null as unknown as Uint8Array;\n\n /**\n * are we editing an empty file?\n */\n if (oldString.length === 0) {\n /**\n * if the file is not empty, we cannot edit it with an empty oldString\n */\n if (text.length !== 0) {\n return {\n error: \"oldString must not be empty unless the file is empty\",\n };\n }\n /**\n * if the newString is empty, we can just return the file as is\n */\n if (newString.length === 0) {\n return { path: filePath, filesUpdate: null, occurrences: 0 };\n }\n\n /**\n * if the newString is not empty, we can edit the file\n */\n const encoded = new TextEncoder().encode(newString);\n const uploadResults = await this.uploadFiles([[filePath, encoded]]);\n /**\n * if the upload fails, we return an error\n */\n if (uploadResults[0].error) {\n return {\n error: `Failed to write edited file '${filePath}': ${uploadResults[0].error}`,\n };\n }\n return { path: filePath, filesUpdate: null, occurrences: 1 };\n }\n\n const firstIdx = text.indexOf(oldString);\n if (firstIdx === -1) {\n return { error: `String not found in file '${filePath}'` };\n }\n\n if (oldString === newString) {\n return { path: filePath, filesUpdate: null, occurrences: 1 };\n }\n\n let newText: string;\n let count: number;\n\n if (replaceAll) {\n newText = text.replaceAll(oldString, newString);\n /**\n * Derive count from the length delta to avoid a separate O(n) counting pass\n */\n const lenDiff = oldString.length - newString.length;\n if (lenDiff !== 0) {\n count = (text.length - newText.length) / lenDiff;\n } else {\n /**\n * Lengths are equal — count via indexOf (we already found the first)\n */\n count = 1;\n let pos = firstIdx + oldString.length;\n while (pos <= text.length) {\n const idx = text.indexOf(oldString, pos);\n if (idx === -1) break;\n count++;\n pos = idx + oldString.length;\n }\n }\n } else {\n const secondIdx = text.indexOf(oldString, firstIdx + oldString.length);\n if (secondIdx !== -1) {\n return {\n error: `Multiple occurrences found in '${filePath}'. Use replaceAll=true to replace all.`,\n };\n }\n count = 1;\n /**\n * Build result from the known index — avoids a redundant search by .replace()\n */\n newText =\n text.slice(0, firstIdx) +\n newString +\n text.slice(firstIdx + oldString.length);\n }\n\n const encoded = new TextEncoder().encode(newText);\n const uploadResults = await this.uploadFiles([[filePath, encoded]]);\n\n if (uploadResults[0].error) {\n return {\n error: `Failed to write edited file '${filePath}': ${uploadResults[0].error}`,\n };\n }\n\n return { path: filePath, filesUpdate: null, occurrences: count };\n }\n}\n","/**\n * LangSmith Sandbox backend for deepagents.\n *\n * @example\n * ```typescript\n * import { LangSmithSandbox, createDeepAgent } from \"deepagents\";\n *\n * const sandbox = await LangSmithSandbox.create({ snapshotId: \"your-snapshot-id\" });\n *\n * const agent = createDeepAgent({ model, backend: sandbox });\n *\n * try {\n * await agent.invoke({ messages: [...] });\n * } finally {\n * await sandbox.close();\n * }\n * ```\n *\n * @module\n */\n\nimport {\n type Sandbox,\n type Snapshot,\n type CreateSandboxOptions,\n type CaptureSnapshotOptions,\n type StartSandboxOptions,\n LangSmithResourceNotFoundError,\n LangSmithSandboxError,\n SandboxClient,\n} from \"langsmith/experimental/sandbox\";\nimport { BaseSandbox } from \"./sandbox.js\";\nimport type {\n ExecuteResponse,\n FileDownloadResponse,\n FileOperationError,\n FileUploadResponse,\n} from \"./protocol.js\";\n\n/** Options for constructing a LangSmithSandbox from an existing Sandbox instance. */\nexport interface LangSmithSandboxOptions {\n /** An already-created LangSmith Sandbox instance to wrap. */\n sandbox: Sandbox;\n /**\n * Default command timeout in seconds.\n * @default 1800 (30 minutes)\n */\n defaultTimeout?: number;\n}\n\n/** Options for the `LangSmithSandbox.create()` static factory. */\nexport interface LangSmithSandboxCreateOptions extends Omit<\n CreateSandboxOptions,\n \"name\" | \"timeout\" | \"waitForReady\" | \"snapshotName\"\n> {\n /**\n * Snapshot ID to boot from.\n * Mutually exclusive with `templateName`.\n */\n snapshotId?: string;\n /**\n * Name of the LangSmith sandbox template to use.\n * Mutually exclusive with `snapshotId`.\n * @deprecated Use `snapshotId` instead. Template-based creation will be\n * removed in a future release.\n */\n templateName?: string;\n /**\n * LangSmith API key. Defaults to the `LANGSMITH_API_KEY` environment variable.\n */\n apiKey?: string;\n /**\n * Default command timeout in seconds.\n * @default 1800 (30 minutes)\n */\n defaultTimeout?: number;\n}\n\n/**\n * LangSmith Sandbox backend for deepagents.\n *\n * Extends `BaseSandbox` to provide command execution and file operations\n * via the LangSmith Sandbox API.\n *\n * Use the static `LangSmithSandbox.create()` factory for the simplest setup,\n * or construct directly with an existing `Sandbox` instance.\n *\n * @experimental This feature is experimental, and breaking changes are expected.\n */\nexport class LangSmithSandbox extends BaseSandbox {\n #sandbox: Sandbox;\n #defaultTimeout: number;\n #isRunning = true;\n\n constructor(options: LangSmithSandboxOptions) {\n super();\n this.#sandbox = options.sandbox;\n this.#defaultTimeout = options.defaultTimeout ?? 30 * 60; // 30 minutes\n }\n\n /** Whether the sandbox is currently active. */\n get isRunning(): boolean {\n return this.#isRunning;\n }\n\n /** Return the LangSmith sandbox name as the unique identifier. */\n get id(): string {\n return this.#sandbox.name;\n }\n\n /**\n * Execute a shell command in the LangSmith sandbox.\n *\n * @param command - Shell command string to execute\n * @param options.timeout - Override timeout in seconds; 0 disables timeout\n */\n async execute(\n command: string,\n options?: { timeout?: number },\n ): Promise<ExecuteResponse> {\n const effectiveTimeout =\n options?.timeout !== undefined ? options.timeout : this.#defaultTimeout;\n\n const result = await this.#sandbox.run(command, {\n timeout: effectiveTimeout,\n });\n\n const out = result.stdout ?? \"\";\n const combined = result.stderr\n ? out\n ? `${out}\\n${result.stderr}`\n : result.stderr\n : out;\n\n return {\n output: combined,\n exitCode: result.exit_code,\n truncated: false,\n };\n }\n\n /**\n * Download files from the sandbox using LangSmith's native file read API.\n * @param paths - List of file paths to download\n * @returns List of FileDownloadResponse objects, one per input path\n */\n async downloadFiles(paths: string[]): Promise<FileDownloadResponse[]> {\n const responses: FileDownloadResponse[] = [];\n\n for (const path of paths) {\n try {\n const content = await this.#sandbox.read(path);\n responses.push({ path, content, error: null });\n } catch (err) {\n // oxlint-disable-next-line no-instanceof/no-instanceof\n if (err instanceof LangSmithResourceNotFoundError) {\n responses.push({ path, content: null, error: \"file_not_found\" });\n // oxlint-disable-next-line no-instanceof/no-instanceof\n } else if (err instanceof LangSmithSandboxError) {\n const msg = String(err.message).toLowerCase();\n const error: FileOperationError = msg.includes(\"is a directory\")\n ? \"is_directory\"\n : \"file_not_found\";\n responses.push({ path, content: null, error });\n } else {\n responses.push({ path, content: null, error: \"invalid_path\" });\n }\n }\n }\n\n return responses;\n }\n\n /**\n * Upload files to the sandbox using LangSmith's native file write API.\n * @param files - List of [path, content] tuples to upload\n * @returns List of FileUploadResponse objects, one per input file\n */\n async uploadFiles(\n files: Array<[string, Uint8Array]>,\n ): Promise<FileUploadResponse[]> {\n const responses: FileUploadResponse[] = [];\n\n for (const [path, content] of files) {\n try {\n await this.#sandbox.write(path, content);\n responses.push({ path, error: null });\n } catch {\n responses.push({ path, error: \"permission_denied\" });\n }\n }\n\n return responses;\n }\n\n /**\n * Delete this sandbox and mark it as no longer running.\n *\n * After calling this, `isRunning` will be `false` and the sandbox\n * cannot be used again.\n */\n async close(): Promise<void> {\n await this.#sandbox.delete();\n this.#isRunning = false;\n }\n\n /**\n * Start a stopped sandbox and wait until it is ready.\n *\n * After calling this, `isRunning` will be `true` and the sandbox\n * can be used for command execution and file operations again.\n *\n * @param options - Start options (timeout, signal).\n */\n async start(options: StartSandboxOptions = {}): Promise<void> {\n await this.#sandbox.start(options);\n this.#isRunning = true;\n }\n\n /**\n * Stop the sandbox without deleting it.\n *\n * Sandbox files are preserved and the sandbox can be restarted later\n * with `start()`. After calling this, `isRunning` will be `false`.\n */\n async stop(): Promise<void> {\n await this.#sandbox.stop();\n this.#isRunning = false;\n }\n\n /**\n * Capture a snapshot from this running sandbox.\n *\n * Snapshots can be used to create new sandboxes via\n * `LangSmithSandbox.create({ snapshotId })`.\n *\n * @param name - Name for the snapshot.\n * @param options - Capture options (checkpoint, timeout).\n * @returns The created Snapshot in \"ready\" status.\n */\n async captureSnapshot(\n name: string,\n options: CaptureSnapshotOptions = {},\n ): Promise<Snapshot> {\n return this.#sandbox.captureSnapshot(name, options);\n }\n\n /**\n * Create and return a new LangSmithSandbox in one step.\n *\n * This is the recommended way to create a sandbox — no need to import\n * anything from `langsmith/experimental/sandbox` directly.\n *\n * @example\n * ```typescript\n * const sandbox = await LangSmithSandbox.create({\n * snapshotId: \"abc-123\",\n * });\n *\n * try {\n * const agent = createDeepAgent({ model, backend: sandbox });\n * await agent.invoke({ messages: [...] });\n * } finally {\n * await sandbox.close();\n * }\n * ```\n */\n static async create(\n options: LangSmithSandboxCreateOptions,\n ): Promise<LangSmithSandbox> {\n const {\n templateName,\n apiKey = process.env.LANGSMITH_API_KEY,\n defaultTimeout,\n snapshotId,\n ...createSandboxOptions\n } = options;\n\n if (snapshotId && templateName) {\n throw new Error(\n \"snapshotId and templateName are mutually exclusive. \" +\n \"Pass only one creation source.\",\n );\n }\n\n if (!snapshotId && !templateName) {\n throw new Error(\n \"Either snapshotId or templateName is required. \" +\n \"snapshotId is recommended — template-based creation is deprecated.\",\n );\n }\n\n const sandboxOptions: CreateSandboxOptions = {\n ...createSandboxOptions,\n };\n\n if (templateName) {\n sandboxOptions.snapshotName = templateName;\n }\n\n const client = new SandboxClient({ apiKey });\n const sandbox = await client.createSandbox(snapshotId, sandboxOptions);\n return new LangSmithSandbox({ sandbox, defaultTimeout });\n }\n}\n"],"mappings":"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"}
|