deepagents 1.9.0-alpha.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  }) : target, mod));
23
23
  //#endregion
24
24
  let langchain = require("langchain");
25
- let _langchain_core_runnables = require("@langchain/core/runnables");
25
+ let _langchain_anthropic = require("@langchain/anthropic");
26
26
  let _langchain_langgraph = require("@langchain/langgraph");
27
27
  let zod_v4 = require("zod/v4");
28
28
  let micromatch = require("micromatch");
@@ -31,6 +31,7 @@ let path = require("path");
31
31
  path = __toESM(path);
32
32
  let _langchain_core_messages = require("@langchain/core/messages");
33
33
  let zod = require("zod");
34
+ zod = __toESM(zod);
34
35
  let yaml = require("yaml");
35
36
  yaml = __toESM(yaml);
36
37
  let _langchain_langgraph_sdk = require("@langchain/langgraph-sdk");
@@ -49,78 +50,6 @@ fast_glob = __toESM(fast_glob);
49
50
  let langsmith_experimental_sandbox = require("langsmith/experimental/sandbox");
50
51
  let node_os = require("node:os");
51
52
  node_os = __toESM(node_os);
52
- //#region src/backends/protocol.ts
53
- /**
54
- * Type guard to check if a backend supports execution.
55
- *
56
- * @param backend - Backend instance to check
57
- * @returns True if the backend implements SandboxBackendProtocolV2
58
- */
59
- function isSandboxBackend(backend) {
60
- return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
61
- }
62
- /**
63
- * Type guard to check if a backend is a sandbox protocol (v1 or v2).
64
- *
65
- * Checks for the presence of `execute` function and `id` string,
66
- * which are the defining features of sandbox protocols.
67
- *
68
- * @param backend - Backend instance to check
69
- * @returns True if the backend implements sandbox protocol (v1 or v2)
70
- */
71
- function isSandboxProtocol(backend) {
72
- return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
73
- }
74
- const SANDBOX_ERROR_SYMBOL = Symbol.for("sandbox.error");
75
- /**
76
- * Custom error class for sandbox operations.
77
- *
78
- * @param message - Human-readable error description
79
- * @param code - Structured error code for programmatic handling
80
- * @returns SandboxError with message and code
81
- *
82
- * @example
83
- * ```typescript
84
- * try {
85
- * await sandbox.execute("some command");
86
- * } catch (error) {
87
- * if (error instanceof SandboxError) {
88
- * switch (error.code) {
89
- * case "NOT_INITIALIZED":
90
- * await sandbox.initialize();
91
- * break;
92
- * case "COMMAND_TIMEOUT":
93
- * console.error("Command took too long");
94
- * break;
95
- * default:
96
- * throw error;
97
- * }
98
- * }
99
- * }
100
- * ```
101
- */
102
- var SandboxError = class SandboxError extends Error {
103
- /** Symbol for identifying sandbox error instances */
104
- [SANDBOX_ERROR_SYMBOL] = true;
105
- /** Error name for instanceof checks and logging */
106
- name = "SandboxError";
107
- /**
108
- * Creates a new SandboxError.
109
- *
110
- * @param message - Human-readable error description
111
- * @param code - Structured error code for programmatic handling
112
- */
113
- constructor(message, code, cause) {
114
- super(message);
115
- this.code = code;
116
- this.cause = cause;
117
- Object.setPrototypeOf(this, SandboxError.prototype);
118
- }
119
- static isInstance(error) {
120
- return typeof error === "object" && error !== null && error[SANDBOX_ERROR_SYMBOL] === true;
121
- }
122
- };
123
- //#endregion
124
53
  //#region src/backends/utils.ts
125
54
  /**
126
55
  * Shared utility functions for memory backend implementations.
@@ -130,7 +59,7 @@ var SandboxError = class SandboxError extends Error {
130
59
  * enable composition without fragile string parsing.
131
60
  */
132
61
  const EMPTY_CONTENT_WARNING = "System reminder: File exists but has empty contents";
133
- const MAX_LINE_LENGTH = 1e4;
62
+ const MAX_LINE_LENGTH = 5e3;
134
63
  const TOOL_RESULT_TOKEN_LIMIT = 2e4;
135
64
  const TRUNCATION_GUIDANCE = "... [results truncated, try being more specific with your parameters]";
136
65
  const MIME_TYPES = {
@@ -140,11 +69,26 @@ const MIME_TYPES = {
140
69
  ".gif": "image/gif",
141
70
  ".webp": "image/webp",
142
71
  ".svg": "image/svg+xml",
72
+ ".heic": "image/heic",
73
+ ".heif": "image/heif",
143
74
  ".mp3": "audio/mpeg",
144
75
  ".wav": "audio/wav",
76
+ ".aiff": "audio/aiff",
77
+ ".aac": "audio/aac",
78
+ ".ogg": "audio/ogg",
79
+ ".flac": "audio/flac",
145
80
  ".mp4": "video/mp4",
146
81
  ".webm": "video/webm",
147
- ".pdf": "application/pdf"
82
+ ".mpeg": "video/mpeg",
83
+ ".mov": "video/quicktime",
84
+ ".avi": "video/x-msvideo",
85
+ ".flv": "video/x-flv",
86
+ ".mpg": "video/mpeg",
87
+ ".wmv": "video/x-ms-wmv",
88
+ ".3gpp": "video/3gpp",
89
+ ".pdf": "application/pdf",
90
+ ".ppt": "application/vnd.ms-powerpoint",
91
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
148
92
  };
149
93
  /**
150
94
  * Sanitize tool_call_id to prevent path traversal and separator issues.
@@ -173,7 +117,7 @@ function formatContentWithLineNumbers(content, startLine = 1) {
173
117
  for (let i = 0; i < lines.length; i++) {
174
118
  const line = lines[i];
175
119
  const lineNum = i + startLine;
176
- if (line.length <= 1e4) resultLines.push(`${lineNum.toString().padStart(6)}\t${line}`);
120
+ if (line.length <= 5e3) resultLines.push(`${lineNum.toString().padStart(6)}\t${line}`);
177
121
  else {
178
122
  const numChunks = Math.ceil(line.length / MAX_LINE_LENGTH);
179
123
  for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
@@ -538,7 +482,96 @@ function adaptSandboxProtocol(sandbox) {
538
482
  return adapted;
539
483
  }
540
484
  //#endregion
485
+ //#region src/backends/protocol.ts
486
+ /**
487
+ * Type guard to check if a backend supports execution.
488
+ *
489
+ * @param backend - Backend instance to check
490
+ * @returns True if the backend implements SandboxBackendProtocolV2
491
+ */
492
+ function isSandboxBackend(backend) {
493
+ return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
494
+ }
495
+ /**
496
+ * Type guard to check if a backend is a sandbox protocol (v1 or v2).
497
+ *
498
+ * Checks for the presence of `execute` function and `id` string,
499
+ * which are the defining features of sandbox protocols.
500
+ *
501
+ * @param backend - Backend instance to check
502
+ * @returns True if the backend implements sandbox protocol (v1 or v2)
503
+ */
504
+ function isSandboxProtocol(backend) {
505
+ return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
506
+ }
507
+ const SANDBOX_ERROR_SYMBOL = Symbol.for("sandbox.error");
508
+ /**
509
+ * Custom error class for sandbox operations.
510
+ *
511
+ * @param message - Human-readable error description
512
+ * @param code - Structured error code for programmatic handling
513
+ * @returns SandboxError with message and code
514
+ *
515
+ * @example
516
+ * ```typescript
517
+ * try {
518
+ * await sandbox.execute("some command");
519
+ * } catch (error) {
520
+ * if (error instanceof SandboxError) {
521
+ * switch (error.code) {
522
+ * case "NOT_INITIALIZED":
523
+ * await sandbox.initialize();
524
+ * break;
525
+ * case "COMMAND_TIMEOUT":
526
+ * console.error("Command took too long");
527
+ * break;
528
+ * default:
529
+ * throw error;
530
+ * }
531
+ * }
532
+ * }
533
+ * ```
534
+ */
535
+ var SandboxError = class SandboxError extends Error {
536
+ /** Symbol for identifying sandbox error instances */
537
+ [SANDBOX_ERROR_SYMBOL] = true;
538
+ /** Error name for instanceof checks and logging */
539
+ name = "SandboxError";
540
+ /**
541
+ * Creates a new SandboxError.
542
+ *
543
+ * @param message - Human-readable error description
544
+ * @param code - Structured error code for programmatic handling
545
+ */
546
+ constructor(message, code, cause) {
547
+ super(message);
548
+ this.code = code;
549
+ this.cause = cause;
550
+ Object.setPrototypeOf(this, SandboxError.prototype);
551
+ }
552
+ static isInstance(error) {
553
+ return typeof error === "object" && error !== null && error[SANDBOX_ERROR_SYMBOL] === true;
554
+ }
555
+ };
556
+ /**
557
+ * Resolve a backend instance or await a {@link BackendFactory}.
558
+ *
559
+ * Accepts {@link BackendRuntime} or {@link ToolRuntime} — store typing differs
560
+ * between LangGraph checkpoint stores and core `ToolRuntime`; factories receive
561
+ * a value that is structurally compatible at runtime.
562
+ *
563
+ * @internal
564
+ */
565
+ async function resolveBackend(backend, runtime) {
566
+ if (typeof backend === "function") {
567
+ const resolved = await backend(runtime);
568
+ return isSandboxProtocol(resolved) ? adaptSandboxProtocol(resolved) : adaptBackendProtocol(resolved);
569
+ }
570
+ return isSandboxProtocol(backend) ? adaptSandboxProtocol(backend) : adaptBackendProtocol(backend);
571
+ }
572
+ //#endregion
541
573
  //#region src/backends/state.ts
574
+ const PREGEL_SEND_KEY = "__pregel_send";
542
575
  /**
543
576
  * Backend that stores files in agent state (ephemeral).
544
577
  *
@@ -551,17 +584,52 @@ function adaptSandboxProtocol(sandbox) {
551
584
  * for the middleware to apply via Command.
552
585
  */
553
586
  var StateBackend = class {
554
- stateAndStore;
587
+ runtime;
555
588
  fileFormat;
556
- constructor(stateAndStore, options) {
557
- this.stateAndStore = stateAndStore;
558
- this.fileFormat = options?.fileFormat ?? "v2";
589
+ constructor(runtimeOrOptions, options) {
590
+ if (runtimeOrOptions != null && typeof runtimeOrOptions === "object" && "state" in runtimeOrOptions) {
591
+ this.runtime = runtimeOrOptions;
592
+ this.fileFormat = options?.fileFormat ?? "v2";
593
+ } else {
594
+ this.runtime = void 0;
595
+ this.fileFormat = runtimeOrOptions?.fileFormat ?? "v2";
596
+ }
597
+ }
598
+ /**
599
+ * Whether this instance was constructed with the legacy factory pattern.
600
+ *
601
+ * When true, state is read from the injected `runtime` and `filesUpdate`
602
+ * is returned to the caller. When false, state is read from LangGraph's
603
+ * execution context and updates are sent via `__pregel_send`.
604
+ */
605
+ get isLegacy() {
606
+ return this.runtime !== void 0;
559
607
  }
560
608
  /**
561
609
  * Get files from current state.
610
+ *
611
+ * In legacy mode, reads from the injected {@link BackendRuntime}.
612
+ * In zero-arg mode, reads from the LangGraph execution context via
613
+ * {@link getCurrentTaskInput}.
562
614
  */
563
615
  getFiles() {
564
- return this.stateAndStore.state.files || {};
616
+ if (this.runtime) return this.runtime.state.files || {};
617
+ return (0, _langchain_langgraph.getCurrentTaskInput)()?.files || {};
618
+ }
619
+ /**
620
+ * Push a files state update through LangGraph's internal send channel.
621
+ *
622
+ * In zero-arg mode, sends the update via the `__pregel_send` function
623
+ * from {@link getConfig}, mirroring Python's `CONFIG_KEY_SEND`.
624
+ * In legacy mode, this is a no-op — the caller uses `filesUpdate`
625
+ * from the return value instead.
626
+ *
627
+ * @param update - Map of file paths to their updated {@link FileData}
628
+ */
629
+ sendFilesUpdate(update) {
630
+ if (this.isLegacy) return;
631
+ const send = (0, _langchain_langgraph.getConfig)().configurable?.[PREGEL_SEND_KEY];
632
+ if (typeof send === "function") send([["files", update]]);
565
633
  }
566
634
  /**
567
635
  * List files and directories in the specified directory (non-recursive).
@@ -644,6 +712,11 @@ var StateBackend = class {
644
712
  if (filePath in this.getFiles()) return { error: `Cannot write to ${filePath} because it already exists. Read and then make an edit, or write to a new path.` };
645
713
  const mimeType = getMimeType(filePath);
646
714
  const newFileData = createFileData(content, void 0, this.fileFormat, mimeType);
715
+ const update = { [filePath]: newFileData };
716
+ if (!this.isLegacy) {
717
+ this.sendFilesUpdate(update);
718
+ return { path: filePath };
719
+ }
647
720
  return {
648
721
  path: filePath,
649
722
  filesUpdate: { [filePath]: newFileData }
@@ -660,6 +733,14 @@ var StateBackend = class {
660
733
  if (typeof result === "string") return { error: result };
661
734
  const [newContent, occurrences] = result;
662
735
  const newFileData = updateFileData(fileData, newContent);
736
+ const update = { [filePath]: newFileData };
737
+ if (!this.isLegacy) {
738
+ this.sendFilesUpdate(update);
739
+ return {
740
+ path: filePath,
741
+ occurrences
742
+ };
743
+ }
663
744
  return {
664
745
  path: filePath,
665
746
  filesUpdate: { [filePath]: newFileData },
@@ -720,6 +801,10 @@ var StateBackend = class {
720
801
  error: "invalid_path"
721
802
  });
722
803
  }
804
+ if (!this.isLegacy) {
805
+ if (Object.keys(updates).length > 0) this.sendFilesUpdate(updates);
806
+ return responses;
807
+ }
723
808
  const result = responses;
724
809
  result.filesUpdate = updates;
725
810
  return result;
@@ -769,6 +854,7 @@ var StateBackend = class {
769
854
  * - Pluggable backends (StateBackend, StoreBackend, FilesystemBackend, CompositeBackend)
770
855
  * - Tool result eviction for large outputs
771
856
  */
857
+ const INT_FORMATTER = new Intl.NumberFormat("en-US");
772
858
  /**
773
859
  * Tools that should be excluded from the large result eviction logic.
774
860
  *
@@ -830,17 +916,75 @@ const READ_FILE_TRUNCATION_MSG = `
830
916
  /**
831
917
  * Message template for evicted tool results.
832
918
  */
833
- const TOO_LARGE_TOOL_MSG = `Tool result too large, the result of this tool call {tool_call_id} was saved in the filesystem at this path: {file_path}
834
- 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.
835
- You can do this by specifying an offset and limit in the read_file tool call.
836
- For example, to read the first 100 lines, you can use the read_file tool with offset=0 and limit=100.
919
+ const TOO_LARGE_TOOL_MSG = langchain.context`
920
+ Tool result too large, the result of this tool call {tool_call_id} was saved in the filesystem at this path: {file_path}
921
+ 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.
922
+ You can do this by specifying an offset and limit in the read_file tool call.
923
+ For example, to read the first 100 lines, you can use the read_file tool with offset=0 and limit=100.
924
+
925
+ Here is a preview showing the head and tail of the result (lines of the form
926
+ ... [N lines truncated] ...
927
+ indicate omitted lines in the middle of the content):
928
+
929
+ {content_sample}
930
+ `;
931
+ /**
932
+ * Message template for evicted HumanMessages.
933
+ */
934
+ const TOO_LARGE_HUMAN_MSG = `Message content too large and was saved to the filesystem at: {file_path}
935
+
936
+ You can read the full content using the read_file tool with pagination (offset and limit parameters).
837
937
 
838
- Here is a preview showing the head and tail of the result (lines of the form
839
- ... [N lines truncated] ...
840
- indicate omitted lines in the middle of the content):
938
+ Here is a preview showing the head and tail of the content:
841
939
 
842
940
  {content_sample}`;
843
941
  /**
942
+ * Extract text content from a message.
943
+ *
944
+ * For string content, returns it directly. For array content (mixed block types
945
+ * like text + image), joins all text blocks. Returns empty string if no text found.
946
+ */
947
+ function extractTextFromMessage(message) {
948
+ if (typeof message.content === "string") return message.content;
949
+ if (Array.isArray(message.content)) return message.content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
950
+ return String(message.content);
951
+ }
952
+ /**
953
+ * Build replacement content for an evicted HumanMessage, preserving non-text blocks.
954
+ *
955
+ * For plain string content, returns the replacement text directly. For list content
956
+ * with mixed block types (e.g., text + image), replaces all text blocks with a single
957
+ * text block containing the replacement text while keeping non-text blocks intact.
958
+ */
959
+ function buildEvictedHumanContent(message, replacementText) {
960
+ if (typeof message.content === "string") return replacementText;
961
+ if (Array.isArray(message.content)) {
962
+ const mediaBlocks = message.content.filter((block) => typeof block === "object" && block !== null && block.type !== "text");
963
+ if (mediaBlocks.length === 0) return replacementText;
964
+ return [{
965
+ type: "text",
966
+ text: replacementText
967
+ }, ...mediaBlocks];
968
+ }
969
+ return replacementText;
970
+ }
971
+ /**
972
+ * Build a truncated HumanMessage for the model request.
973
+ *
974
+ * Computes a preview from the full content still in state and returns a
975
+ * lightweight replacement the model will see. Pure string computation — no
976
+ * backend I/O.
977
+ */
978
+ function buildTruncatedHumanMessage(message, filePath) {
979
+ const contentSample = createContentPreview(extractTextFromMessage(message));
980
+ return new langchain.HumanMessage({
981
+ content: buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample)),
982
+ id: message.id,
983
+ additional_kwargs: { ...message.additional_kwargs },
984
+ response_metadata: { ...message.response_metadata }
985
+ });
986
+ }
987
+ /**
844
988
  * Create a preview of content showing head and tail with truncation marker.
845
989
  *
846
990
  * @param contentStr - The full content string to preview.
@@ -915,138 +1059,148 @@ const FilesystemStateSchema = new _langchain_langgraph.StateSchema({ files: new
915
1059
  inputSchema: zod_v4.z.record(zod_v4.z.string(), FileDataSchema.nullable()).optional(),
916
1060
  reducer: fileDataReducer
917
1061
  }) });
918
- /**
919
- * Resolve backend from factory or instance.
920
- *
921
- * @param backend - Backend instance or factory function
922
- * @param stateAndStore - State and store container for backend initialization
923
- */
924
- function getBackend(backend, stateAndStore) {
925
- const actualBackend = typeof backend === "function" ? backend(stateAndStore) : backend;
926
- return isSandboxProtocol(actualBackend) ? adaptSandboxProtocol(actualBackend) : adaptBackendProtocol(actualBackend);
927
- }
928
- const FILESYSTEM_SYSTEM_PROMPT = `## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
1062
+ const FILESYSTEM_SYSTEM_PROMPT = langchain.context`
1063
+ ## Following Conventions
929
1064
 
930
- You have access to a filesystem which you can interact with using these tools.
931
- All file paths must start with a /.
1065
+ - Read files before editing understand existing content before making changes
1066
+ - Mimic existing style, naming conventions, and patterns
932
1067
 
933
- - ls: list files in a directory (requires absolute path)
934
- - read_file: read a file from the filesystem
935
- - write_file: write to a file in the filesystem
936
- - edit_file: edit a file in the filesystem
937
- - glob: find files matching a pattern (e.g., "**/*.py")
938
- - grep: search for text within files`;
939
- const LS_TOOL_DESCRIPTION = `Lists all files in a directory.
1068
+ ## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
940
1069
 
941
- This is useful for exploring the filesystem and finding the right file to read or edit.
942
- You should almost ALWAYS use this tool before using the read_file or edit_file tools.`;
943
- const READ_FILE_TOOL_DESCRIPTION = `Reads a file from the filesystem.
1070
+ You have access to a filesystem which you can interact with using these tools.
1071
+ All file paths must start with a /.
944
1072
 
945
- Assume this tool is able to read all files. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
1073
+ - ls: list files in a directory (requires absolute path)
1074
+ - read_file: read a file from the filesystem
1075
+ - write_file: write to a file in the filesystem
1076
+ - edit_file: edit a file in the filesystem
1077
+ - glob: find files matching a pattern (e.g., "**/*.py")
1078
+ - grep: search for text within files
1079
+ `;
1080
+ const LS_TOOL_DESCRIPTION = langchain.context`
1081
+ Lists all files in a directory.
946
1082
 
947
- Usage:
948
- - By default, it reads up to 100 lines starting from the beginning of the file
949
- - **IMPORTANT for large files and codebase exploration**: Use pagination with offset and limit parameters to avoid context overflow
950
- - First scan: read_file(path, limit=100) to see file structure
951
- - Read more sections: read_file(path, offset=100, limit=200) for next 200 lines
952
- - Only omit limit (read full file) when necessary for editing
953
- - Specify offset and limit: read_file(path, offset=0, limit=100) reads first 100 lines
954
- - Results are returned using cat -n format, with line numbers starting at 1
955
- - Lines longer than 10,000 characters will be split into multiple lines with continuation markers (e.g., 5.1, 5.2, etc.). When you specify a limit, these continuation lines count towards the limit.
956
- - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
957
- - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
958
- - You should ALWAYS make sure a file has been read before editing it.`;
959
- const WRITE_FILE_TOOL_DESCRIPTION = `Writes to a new file in the filesystem.
1083
+ This is useful for exploring the filesystem and finding the right file to read or edit.
1084
+ You should almost ALWAYS use this tool before using the read_file or edit_file tools.
1085
+ `;
1086
+ const READ_FILE_TOOL_DESCRIPTION = langchain.context`
1087
+ Reads a file from the filesystem.
1088
+
1089
+ Assume this tool is able to read all files. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
960
1090
 
961
- Usage:
962
- - The write_file tool will create a new file.
963
- - Prefer to edit existing files (with the edit_file tool) over creating new ones when possible.`;
964
- const EDIT_FILE_TOOL_DESCRIPTION = `Performs exact string replacements in files.
1091
+ Usage:
1092
+ - By default, it reads up to 100 lines starting from the beginning of the file
1093
+ - **IMPORTANT for large files and codebase exploration**: Use pagination with offset and limit parameters to avoid context overflow
1094
+ - First scan: read_file(path, limit=100) to see file structure
1095
+ - Read more sections: read_file(path, offset=100, limit=200) for next 200 lines
1096
+ - Only omit limit (read full file) when necessary for editing
1097
+ - Specify offset and limit: read_file(path, offset=0, limit=100) reads first 100 lines
1098
+ - Results are returned using cat -n format, with line numbers starting at 1
1099
+ - Lines longer than ${INT_FORMATTER.format(MAX_LINE_LENGTH)} characters will be split into multiple lines with continuation markers (e.g., 5.1, 5.2, etc.). When you specify a limit, these continuation lines count towards the limit.
1100
+ - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
1101
+ - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
1102
+ - You should ALWAYS make sure a file has been read before editing it.
1103
+ `;
1104
+ const WRITE_FILE_TOOL_DESCRIPTION = langchain.context`
1105
+ Writes to a new file in the filesystem.
1106
+
1107
+ Usage:
1108
+ - The write_file tool will create a new file.
1109
+ - Prefer to edit existing files (with the edit_file tool) over creating new ones when possible.
1110
+ `;
1111
+ const EDIT_FILE_TOOL_DESCRIPTION = langchain.context`
1112
+ Performs exact string replacements in files.
965
1113
 
966
- Usage:
967
- - You must read the file before editing. This tool will error if you attempt an edit without reading the file first.
968
- - When editing, preserve the exact indentation (tabs/spaces) from the read output. Never include line number prefixes in old_string or new_string.
969
- - ALWAYS prefer editing existing files over creating new ones.
970
- - Only use emojis if the user explicitly requests it.`;
971
- const GLOB_TOOL_DESCRIPTION = `Find files matching a glob pattern.
1114
+ Usage:
1115
+ - You must read the file before editing. This tool will error if you attempt an edit without reading the file first.
1116
+ - When editing, preserve the exact indentation (tabs/spaces) from the read output. Never include line number prefixes in old_string or new_string.
1117
+ - ALWAYS prefer editing existing files over creating new ones.
1118
+ - Only use emojis if the user explicitly requests it.
1119
+ `;
1120
+ const GLOB_TOOL_DESCRIPTION = langchain.context`
1121
+ Find files matching a glob pattern.
972
1122
 
973
- Supports standard glob patterns: \`*\` (any characters), \`**\` (any directories), \`?\` (single character).
974
- Returns a list of absolute file paths that match the pattern.
1123
+ Supports standard glob patterns: \`*\` (any characters), \`**\` (any directories), \`?\` (single character).
1124
+ Returns a list of absolute file paths that match the pattern.
975
1125
 
976
- Examples:
977
- - \`**/*.py\` - Find all Python files
978
- - \`*.txt\` - Find all text files in root
979
- - \`/subdir/**/*.md\` - Find all markdown files under /subdir`;
980
- const GREP_TOOL_DESCRIPTION = `Search for a text pattern across files.
1126
+ Examples:
1127
+ - \`**/*.py\` - Find all Python files
1128
+ - \`*.txt\` - Find all text files in root
1129
+ - \`/subdir/**/*.md\` - Find all markdown files under /subdir
1130
+ `;
1131
+ const GREP_TOOL_DESCRIPTION = langchain.context`
1132
+ Search for a text pattern across files.
981
1133
 
982
- Searches for literal text (not regex) and returns matching files or content based on output_mode.
983
- Special characters like parentheses, brackets, pipes, etc. are treated as literal characters, not regex operators.
1134
+ Searches for literal text (not regex) and returns matching files or content based on output_mode.
1135
+ Special characters like parentheses, brackets, pipes, etc. are treated as literal characters, not regex operators.
984
1136
 
985
- Examples:
986
- - Search all files: \`grep(pattern="TODO")\`
987
- - Search Python files only: \`grep(pattern="import", glob="*.py")\`
988
- - Show matching lines: \`grep(pattern="error", output_mode="content")\`
989
- - Search for code with special chars: \`grep(pattern="def __init__(self):")\``;
990
- const EXECUTE_TOOL_DESCRIPTION = `Executes a shell command in an isolated sandbox environment.
1137
+ Examples:
1138
+ - Search all files: \`grep(pattern="TODO")\`
1139
+ - Search Python files only: \`grep(pattern="import", glob="*.py")\`
1140
+ - Show matching lines: \`grep(pattern="error", output_mode="content")\`
1141
+ - Search for code with special chars: \`grep(pattern="def __init__(self):")\`
1142
+ `;
1143
+ const EXECUTE_TOOL_DESCRIPTION = langchain.context`
1144
+ Executes a shell command in an isolated sandbox environment.
991
1145
 
992
- Usage:
993
- Executes a given command in the sandbox environment with proper handling and security measures.
994
- Before executing the command, please follow these steps:
1146
+ Usage:
1147
+ Executes a given command in the sandbox environment with proper handling and security measures.
1148
+ Before executing the command, please follow these steps:
995
1149
 
996
- 1. Directory Verification:
997
- - If the command will create new directories or files, first use the ls tool to verify the parent directory exists and is the correct location
998
- - For example, before running "mkdir foo/bar", first use ls to check that "foo" exists and is the intended parent directory
1150
+ 1. Directory Verification:
1151
+ - If the command will create new directories or files, first use the ls tool to verify the parent directory exists and is the correct location
1152
+ - For example, before running "mkdir foo/bar", first use ls to check that "foo" exists and is the intended parent directory
999
1153
 
1000
- 2. Command Execution:
1001
- - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
1002
- - Examples of proper quoting:
1003
- - cd "/Users/name/My Documents" (correct)
1004
- - cd /Users/name/My Documents (incorrect - will fail)
1005
- - python "/path/with spaces/script.py" (correct)
1006
- - python /path/with spaces/script.py (incorrect - will fail)
1007
- - After ensuring proper quoting, execute the command
1008
- - Capture the output of the command
1154
+ 2. Command Execution:
1155
+ - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
1156
+ - Examples of proper quoting:
1157
+ - cd "/Users/name/My Documents" (correct)
1158
+ - cd /Users/name/My Documents (incorrect - will fail)
1159
+ - python "/path/with spaces/script.py" (correct)
1160
+ - python /path/with spaces/script.py (incorrect - will fail)
1161
+ - After ensuring proper quoting, execute the command
1162
+ - Capture the output of the command
1009
1163
 
1010
- Usage notes:
1011
- - Commands run in an isolated sandbox environment
1012
- - Returns combined stdout/stderr output with exit code
1013
- - If the output is very large, it may be truncated
1014
- - VERY IMPORTANT: You MUST avoid using search commands like find and grep. Instead use the grep, glob tools to search. You MUST avoid read tools like cat, head, tail, and use read_file to read files.
1015
- - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings)
1016
- - Use '&&' when commands depend on each other (e.g., "mkdir dir && cd dir")
1017
- - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
1018
- - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd
1164
+ Usage notes:
1165
+ - Commands run in an isolated sandbox environment
1166
+ - Returns combined stdout/stderr output with exit code
1167
+ - If the output is very large, it may be truncated
1168
+ - VERY IMPORTANT: You MUST avoid using search commands like find and grep. Instead use the grep, glob tools to search. You MUST avoid read tools like cat, head, tail, and use read_file to read files.
1169
+ - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings)
1170
+ - Use '&&' when commands depend on each other (e.g., "mkdir dir && cd dir")
1171
+ - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
1172
+ - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd
1019
1173
 
1020
- Examples:
1021
- Good examples:
1022
- - execute(command="pytest /foo/bar/tests")
1023
- - execute(command="python /path/to/script.py")
1024
- - execute(command="npm install && npm test")
1174
+ Examples:
1175
+ Good examples:
1176
+ - execute(command="pytest /foo/bar/tests")
1177
+ - execute(command="python /path/to/script.py")
1178
+ - execute(command="npm install && npm test")
1025
1179
 
1026
- Bad examples (avoid these):
1027
- - execute(command="cd /foo/bar && pytest tests") # Use absolute path instead
1028
- - execute(command="cat file.txt") # Use read_file tool instead
1029
- - execute(command="find . -name '*.py'") # Use glob tool instead
1030
- - execute(command="grep -r 'pattern' .") # Use grep tool instead
1180
+ Bad examples (avoid these):
1181
+ - execute(command="cd /foo/bar && pytest tests") # Use absolute path instead
1182
+ - execute(command="cat file.txt") # Use read_file tool instead
1183
+ - execute(command="find . -name '*.py'") # Use glob tool instead
1184
+ - execute(command="grep -r 'pattern' .") # Use grep tool instead
1031
1185
 
1032
- Note: This tool is only available if the backend supports execution (SandboxBackendProtocol).
1033
- If execution is not supported, the tool will return an error message.`;
1034
- const EXECUTION_SYSTEM_PROMPT = `## Execute Tool \`execute\`
1186
+ Note: This tool is only available if the backend supports execution (SandboxBackendProtocol).
1187
+ If execution is not supported, the tool will return an error message.
1188
+ `;
1189
+ const EXECUTION_SYSTEM_PROMPT = langchain.context`
1190
+ ## Execute Tool \`execute\`
1035
1191
 
1036
- You have access to an \`execute\` tool for running shell commands in a sandboxed environment.
1037
- Use this tool to run commands, scripts, tests, builds, and other shell operations.
1192
+ You have access to an \`execute\` tool for running shell commands in a sandboxed environment.
1193
+ Use this tool to run commands, scripts, tests, builds, and other shell operations.
1038
1194
 
1039
- - execute: run a shell command in the sandbox (returns output and exit code)`;
1195
+ - execute: run a shell command in the sandbox (returns output and exit code)
1196
+ `;
1040
1197
  /**
1041
1198
  * Create ls tool using backend.
1042
1199
  */
1043
1200
  function createLsTool(backend, options) {
1044
1201
  const { customDescription } = options;
1045
- return (0, langchain.tool)(async (input, config) => {
1046
- const resolvedBackend = getBackend(backend, {
1047
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1048
- store: config.store
1049
- });
1202
+ return (0, langchain.tool)(async (input, runtime) => {
1203
+ const resolvedBackend = await resolveBackend(backend, runtime);
1050
1204
  const path = input.path || "/";
1051
1205
  const lsResult = await resolvedBackend.ls(path);
1052
1206
  if (lsResult.error) return `Error listing files: ${lsResult.error}`;
@@ -1072,11 +1226,8 @@ function createLsTool(backend, options) {
1072
1226
  */
1073
1227
  function createReadFileTool(backend, options) {
1074
1228
  const { customDescription, toolTokenLimitBeforeEvict } = options;
1075
- return (0, langchain.tool)(async (input, config) => {
1076
- const resolvedBackend = getBackend(backend, {
1077
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1078
- store: config.store
1079
- });
1229
+ return (0, langchain.tool)(async (input, runtime) => {
1230
+ const resolvedBackend = await resolveBackend(backend, runtime);
1080
1231
  const { file_path, offset = 0, limit = 100 } = input;
1081
1232
  const readResult = await resolvedBackend.read(file_path, offset, limit);
1082
1233
  if (readResult.error) return [{
@@ -1151,17 +1302,14 @@ function createReadFileTool(backend, options) {
1151
1302
  */
1152
1303
  function createWriteFileTool(backend, options) {
1153
1304
  const { customDescription } = options;
1154
- return (0, langchain.tool)(async (input, config) => {
1155
- const resolvedBackend = getBackend(backend, {
1156
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1157
- store: config.store
1158
- });
1305
+ return (0, langchain.tool)(async (input, runtime) => {
1306
+ const resolvedBackend = await resolveBackend(backend, runtime);
1159
1307
  const { file_path, content } = input;
1160
1308
  const result = await resolvedBackend.write(file_path, content);
1161
1309
  if (result.error) return result.error;
1162
1310
  const message = new langchain.ToolMessage({
1163
1311
  content: `Successfully wrote to '${file_path}'`,
1164
- tool_call_id: config.toolCall?.id,
1312
+ tool_call_id: runtime.toolCall?.id,
1165
1313
  name: "write_file",
1166
1314
  metadata: result.metadata
1167
1315
  });
@@ -1184,17 +1332,14 @@ function createWriteFileTool(backend, options) {
1184
1332
  */
1185
1333
  function createEditFileTool(backend, options) {
1186
1334
  const { customDescription } = options;
1187
- return (0, langchain.tool)(async (input, config) => {
1188
- const resolvedBackend = getBackend(backend, {
1189
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1190
- store: config.store
1191
- });
1335
+ return (0, langchain.tool)(async (input, runtime) => {
1336
+ const resolvedBackend = await resolveBackend(backend, runtime);
1192
1337
  const { file_path, old_string, new_string, replace_all = false } = input;
1193
1338
  const result = await resolvedBackend.edit(file_path, old_string, new_string, replace_all);
1194
1339
  if (result.error) return result.error;
1195
1340
  const message = new langchain.ToolMessage({
1196
1341
  content: `Successfully replaced ${result.occurrences} occurrence(s) in '${file_path}'`,
1197
- tool_call_id: config.toolCall?.id,
1342
+ tool_call_id: runtime.toolCall?.id,
1198
1343
  name: "edit_file",
1199
1344
  metadata: result.metadata
1200
1345
  });
@@ -1219,11 +1364,8 @@ function createEditFileTool(backend, options) {
1219
1364
  */
1220
1365
  function createGlobTool(backend, options) {
1221
1366
  const { customDescription } = options;
1222
- return (0, langchain.tool)(async (input, config) => {
1223
- const resolvedBackend = getBackend(backend, {
1224
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1225
- store: config.store
1226
- });
1367
+ return (0, langchain.tool)(async (input, runtime) => {
1368
+ const resolvedBackend = await resolveBackend(backend, runtime);
1227
1369
  const { pattern, path = "/" } = input;
1228
1370
  const globResult = await resolvedBackend.glob(pattern, path);
1229
1371
  if (globResult.error) return `Error finding files: ${globResult.error}`;
@@ -1246,11 +1388,8 @@ function createGlobTool(backend, options) {
1246
1388
  */
1247
1389
  function createGrepTool(backend, options) {
1248
1390
  const { customDescription } = options;
1249
- return (0, langchain.tool)(async (input, config) => {
1250
- const resolvedBackend = getBackend(backend, {
1251
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1252
- store: config.store
1253
- });
1391
+ return (0, langchain.tool)(async (input, runtime) => {
1392
+ const resolvedBackend = await resolveBackend(backend, runtime);
1254
1393
  const { pattern, path = "/", glob = null } = input;
1255
1394
  const result = await resolvedBackend.grep(pattern, path, glob);
1256
1395
  if (result.error) return result.error;
@@ -1274,7 +1413,7 @@ function createGrepTool(backend, options) {
1274
1413
  schema: zod_v4.z.object({
1275
1414
  pattern: zod_v4.z.string().describe("Regex pattern to search for"),
1276
1415
  path: zod_v4.z.string().optional().default("/").describe("Base path to search from (default: /)"),
1277
- glob: zod_v4.z.string().optional().nullable().describe("Optional glob pattern to filter files (e.g., '*.py')")
1416
+ glob: zod_v4.z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')")
1278
1417
  })
1279
1418
  });
1280
1419
  }
@@ -1283,11 +1422,8 @@ function createGrepTool(backend, options) {
1283
1422
  */
1284
1423
  function createExecuteTool(backend, options) {
1285
1424
  const { customDescription } = options;
1286
- return (0, langchain.tool)(async (input, config) => {
1287
- const resolvedBackend = getBackend(backend, {
1288
- state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
1289
- store: config.store
1290
- });
1425
+ return (0, langchain.tool)(async (input, runtime) => {
1426
+ const resolvedBackend = await resolveBackend(backend, runtime);
1291
1427
  if (!isSandboxBackend(resolvedBackend)) return "Error: Execution not available. This agent's backend does not support command execution (SandboxBackendProtocol). To use the execute tool, provide a backend that implements SandboxBackendProtocol.";
1292
1428
  const result = await resolvedBackend.execute(input.command);
1293
1429
  const parts = [result.output];
@@ -1307,7 +1443,7 @@ function createExecuteTool(backend, options) {
1307
1443
  * Create filesystem middleware with all tools and features.
1308
1444
  */
1309
1445
  function createFilesystemMiddleware(options = {}) {
1310
- const { backend = (stateAndStore) => new StateBackend(stateAndStore), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4 } = options;
1446
+ const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4 } = options;
1311
1447
  const baseSystemPrompt = customSystemPrompt || FILESYSTEM_SYSTEM_PROMPT;
1312
1448
  const allToolsByName = {
1313
1449
  ls: createLsTool(backend, { customDescription: customToolDescriptions?.ls }),
@@ -1325,19 +1461,53 @@ function createFilesystemMiddleware(options = {}) {
1325
1461
  name: "FilesystemMiddleware",
1326
1462
  stateSchema: FilesystemStateSchema,
1327
1463
  tools: Object.values(allToolsByName),
1464
+ async beforeAgent(state) {
1465
+ if (!humanMessageTokenLimitBeforeEvict) return;
1466
+ const messages = state.messages;
1467
+ if (!messages || messages.length === 0) return;
1468
+ const last = messages[messages.length - 1];
1469
+ if (!langchain.HumanMessage.isInstance(last)) return;
1470
+ if (last.additional_kwargs?.lc_evicted_to) return;
1471
+ const contentStr = extractTextFromMessage(last);
1472
+ const threshold = 4 * humanMessageTokenLimitBeforeEvict;
1473
+ if (contentStr.length <= threshold) return;
1474
+ const resolvedBackend = await resolveBackend(backend, { state: state || {} });
1475
+ const filePath = `/conversation_history/${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
1476
+ const writeResult = await resolvedBackend.write(filePath, contentStr);
1477
+ if (writeResult.error) return;
1478
+ const result = { messages: [new langchain.HumanMessage({
1479
+ content: last.content,
1480
+ id: last.id,
1481
+ additional_kwargs: {
1482
+ ...last.additional_kwargs,
1483
+ lc_evicted_to: filePath
1484
+ },
1485
+ response_metadata: { ...last.response_metadata }
1486
+ })] };
1487
+ if (writeResult.filesUpdate) result.files = writeResult.filesUpdate;
1488
+ return result;
1489
+ },
1328
1490
  wrapModelCall: async (request, handler) => {
1329
- const supportsExecution = isSandboxBackend(getBackend(backend, {
1330
- state: request.state || {},
1331
- store: request.runtime?.store
1491
+ const supportsExecution = isSandboxBackend(await resolveBackend(backend, {
1492
+ ...request.runtime,
1493
+ state: request.state
1332
1494
  }));
1333
1495
  let tools = request.tools;
1334
1496
  if (!supportsExecution) tools = tools.filter((t) => t.name !== "execute");
1335
1497
  let filesystemPrompt = baseSystemPrompt;
1336
1498
  if (supportsExecution) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
1337
1499
  const newSystemMessage = request.systemMessage.concat(filesystemPrompt);
1500
+ let messages = request.messages;
1501
+ if (humanMessageTokenLimitBeforeEvict && messages) {
1502
+ if (messages.some((msg) => langchain.HumanMessage.isInstance(msg) && msg.additional_kwargs?.lc_evicted_to)) messages = messages.map((msg) => {
1503
+ if (langchain.HumanMessage.isInstance(msg) && msg.additional_kwargs?.lc_evicted_to) return buildTruncatedHumanMessage(msg, msg.additional_kwargs.lc_evicted_to);
1504
+ return msg;
1505
+ });
1506
+ }
1338
1507
  return handler({
1339
1508
  ...request,
1340
1509
  tools,
1510
+ messages,
1341
1511
  systemMessage: newSystemMessage
1342
1512
  });
1343
1513
  },
@@ -1348,9 +1518,9 @@ function createFilesystemMiddleware(options = {}) {
1348
1518
  const result = await handler(request);
1349
1519
  async function processToolMessage(msg, toolTokenLimitBeforeEvict) {
1350
1520
  if (typeof msg.content === "string" && msg.content.length > toolTokenLimitBeforeEvict * 4) {
1351
- const resolvedBackend = getBackend(backend, {
1352
- state: request.state || {},
1353
- store: request.runtime?.store
1521
+ const resolvedBackend = await resolveBackend(backend, {
1522
+ ...request.runtime,
1523
+ state: request.state
1354
1524
  });
1355
1525
  const evictPath = `/large_tool_results/${sanitizeToolCallId(request.toolCall?.id || msg.tool_call_id)}`;
1356
1526
  const writeResult = await resolvedBackend.write(evictPath, msg.content);
@@ -1443,117 +1613,117 @@ const EXCLUDED_STATE_KEYS = [
1443
1613
  */
1444
1614
  const DEFAULT_GENERAL_PURPOSE_DESCRIPTION = "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.";
1445
1615
  function getTaskToolDescription(subagentDescriptions) {
1446
- return `
1447
- Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
1616
+ return langchain.context`
1617
+ Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
1448
1618
 
1449
- Available agent types and the tools they have access to:
1450
- ${subagentDescriptions.join("\n")}
1619
+ Available agent types and the tools they have access to:
1620
+ ${subagentDescriptions.join("\n")}
1451
1621
 
1452
- When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
1622
+ When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
1453
1623
 
1454
- ## Usage notes:
1455
- 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
1456
- 2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
1457
- 3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
1458
- 4. The agent's outputs should generally be trusted
1459
- 5. Clearly tell the agent whether you expect it to create content, perform analysis, or just do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
1460
- 6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
1461
- 7. When only the general-purpose agent is provided, you should use it for all tasks. It is great for isolating context and token usage, and completing specific, complex tasks, as it has all the same capabilities as the main agent.
1624
+ ## Usage notes:
1625
+ 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
1626
+ 2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
1627
+ 3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
1628
+ 4. The agent's outputs should generally be trusted
1629
+ 5. Clearly tell the agent whether you expect it to create content, perform analysis, or just do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
1630
+ 6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
1631
+ 7. When only the general-purpose agent is provided, you should use it for all tasks. It is great for isolating context and token usage, and completing specific, complex tasks, as it has all the same capabilities as the main agent.
1462
1632
 
1463
- ### Example usage of the general-purpose agent:
1633
+ ### Example usage of the general-purpose agent:
1464
1634
 
1465
- <example_agent_descriptions>
1466
- "general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.
1467
- </example_agent_descriptions>
1635
+ <example_agent_descriptions>
1636
+ "general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.
1637
+ </example_agent_descriptions>
1468
1638
 
1469
- <example>
1470
- User: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."
1471
- Assistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*
1472
- Assistant: *Synthesizes the results of the three isolated research tasks and responds to the User*
1473
- <commentary>
1474
- Research is a complex, multi-step task in it of itself.
1475
- The research of each individual player is not dependent on the research of the other players.
1476
- The assistant uses the task tool to break down the complex objective into three isolated tasks.
1477
- Each research task only needs to worry about context and tokens about one player, then returns synthesized information about each player as the Tool Result.
1478
- This means each research task can dive deep and spend tokens and context deeply researching each player, but the final result is synthesized information, and saves us tokens in the long run when comparing the players to each other.
1479
- </commentary>
1480
- </example>
1639
+ <example>
1640
+ User: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."
1641
+ Assistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*
1642
+ Assistant: *Synthesizes the results of the three isolated research tasks and responds to the User*
1643
+ <commentary>
1644
+ Research is a complex, multi-step task in it of itself.
1645
+ The research of each individual player is not dependent on the research of the other players.
1646
+ The assistant uses the task tool to break down the complex objective into three isolated tasks.
1647
+ Each research task only needs to worry about context and tokens about one player, then returns synthesized information about each player as the Tool Result.
1648
+ This means each research task can dive deep and spend tokens and context deeply researching each player, but the final result is synthesized information, and saves us tokens in the long run when comparing the players to each other.
1649
+ </commentary>
1650
+ </example>
1481
1651
 
1482
- <example>
1483
- User: "Analyze a single large code repository for security vulnerabilities and generate a report."
1484
- Assistant: *Launches a single \`task\` subagent for the repository analysis*
1485
- Assistant: *Receives report and integrates results into final summary*
1486
- <commentary>
1487
- Subagent is used to isolate a large, context-heavy task, even though there is only one. This prevents the main thread from being overloaded with details.
1488
- If the user then asks followup questions, we have a concise report to reference instead of the entire history of analysis and tool calls, which is good and saves us time and money.
1489
- </commentary>
1490
- </example>
1652
+ <example>
1653
+ User: "Analyze a single large code repository for security vulnerabilities and generate a report."
1654
+ Assistant: *Launches a single \`task\` subagent for the repository analysis*
1655
+ Assistant: *Receives report and integrates results into final summary*
1656
+ <commentary>
1657
+ Subagent is used to isolate a large, context-heavy task, even though there is only one. This prevents the main thread from being overloaded with details.
1658
+ If the user then asks followup questions, we have a concise report to reference instead of the entire history of analysis and tool calls, which is good and saves us time and money.
1659
+ </commentary>
1660
+ </example>
1491
1661
 
1492
- <example>
1493
- User: "Schedule two meetings for me and prepare agendas for each."
1494
- Assistant: *Calls the task tool in parallel to launch two \`task\` subagents (one per meeting) to prepare agendas*
1495
- Assistant: *Returns final schedules and agendas*
1496
- <commentary>
1497
- Tasks are simple individually, but subagents help silo agenda preparation.
1498
- Each subagent only needs to worry about the agenda for one meeting.
1499
- </commentary>
1500
- </example>
1662
+ <example>
1663
+ User: "Schedule two meetings for me and prepare agendas for each."
1664
+ Assistant: *Calls the task tool in parallel to launch two \`task\` subagents (one per meeting) to prepare agendas*
1665
+ Assistant: *Returns final schedules and agendas*
1666
+ <commentary>
1667
+ Tasks are simple individually, but subagents help silo agenda preparation.
1668
+ Each subagent only needs to worry about the agenda for one meeting.
1669
+ </commentary>
1670
+ </example>
1501
1671
 
1502
- <example>
1503
- User: "I want to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway."
1504
- Assistant: *Calls tools directly in parallel to order a pizza from Dominos, a burger from McDonald's, and a salad from Subway*
1505
- <commentary>
1506
- The assistant did not use the task tool because the objective is super simple and clear and only requires a few trivial tool calls.
1507
- It is better to just complete the task directly and NOT use the \`task\`tool.
1508
- </commentary>
1509
- </example>
1672
+ <example>
1673
+ User: "I want to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway."
1674
+ Assistant: *Calls tools directly in parallel to order a pizza from Dominos, a burger from McDonald's, and a salad from Subway*
1675
+ <commentary>
1676
+ The assistant did not use the task tool because the objective is super simple and clear and only requires a few trivial tool calls.
1677
+ It is better to just complete the task directly and NOT use the \`task\`tool.
1678
+ </commentary>
1679
+ </example>
1510
1680
 
1511
- ### Example usage with custom agents:
1681
+ ### Example usage with custom agents:
1512
1682
 
1513
- <example_agent_descriptions>
1514
- "content-reviewer": use this agent after you are done creating significant content or documents
1515
- "greeting-responder": use this agent when to respond to user greetings with a friendly joke
1516
- "research-analyst": use this agent to conduct thorough research on complex topics
1517
- </example_agent_description>
1683
+ <example_agent_descriptions>
1684
+ "content-reviewer": use this agent after you are done creating significant content or documents
1685
+ "greeting-responder": use this agent when to respond to user greetings with a friendly joke
1686
+ "research-analyst": use this agent to conduct thorough research on complex topics
1687
+ </example_agent_description>
1518
1688
 
1519
- <example>
1520
- user: "Please write a function that checks if a number is prime"
1521
- assistant: Sure let me write a function that checks if a number is prime
1522
- assistant: First let me use the Write tool to write a function that checks if a number is prime
1523
- assistant: I'm going to use the Write tool to write the following code:
1524
- <code>
1525
- function isPrime(n) {
1526
- if (n <= 1) return false
1527
- for (let i = 2; i * i <= n; i++) {
1528
- if (n % i === 0) return false
1529
- }
1530
- return true
1531
- }
1532
- </code>
1533
- <commentary>
1534
- Since significant content was created and the task was completed, now use the content-reviewer agent to review the work
1535
- </commentary>
1536
- assistant: Now let me use the content-reviewer agent to review the code
1537
- assistant: Uses the Task tool to launch with the content-reviewer agent
1538
- </example>
1689
+ <example>
1690
+ user: "Please write a function that checks if a number is prime"
1691
+ assistant: Sure let me write a function that checks if a number is prime
1692
+ assistant: First let me use the Write tool to write a function that checks if a number is prime
1693
+ assistant: I'm going to use the Write tool to write the following code:
1694
+ <code>
1695
+ function isPrime(n) {{
1696
+ if (n <= 1) return false
1697
+ for (let i = 2; i * i <= n; i++) {{
1698
+ if (n % i === 0) return false
1699
+ }}
1700
+ return true
1701
+ }}
1702
+ </code>
1703
+ <commentary>
1704
+ Since significant content was created and the task was completed, now use the content-reviewer agent to review the work
1705
+ </commentary>
1706
+ assistant: Now let me use the content-reviewer agent to review the code
1707
+ assistant: Uses the Task tool to launch with the content-reviewer agent
1708
+ </example>
1539
1709
 
1540
- <example>
1541
- user: "Can you help me research the environmental impact of different renewable energy sources and create a comprehensive report?"
1542
- <commentary>
1543
- This is a complex research task that would benefit from using the research-analyst agent to conduct thorough analysis
1544
- </commentary>
1545
- assistant: I'll help you research the environmental impact of renewable energy sources. Let me use the research-analyst agent to conduct comprehensive research on this topic.
1546
- assistant: Uses the Task tool to launch with the research-analyst agent, providing detailed instructions about what research to conduct and what format the report should take
1547
- </example>
1710
+ <example>
1711
+ user: "Can you help me research the environmental impact of different renewable energy sources and create a comprehensive report?"
1712
+ <commentary>
1713
+ This is a complex research task that would benefit from using the research-analyst agent to conduct thorough analysis
1714
+ </commentary>
1715
+ assistant: I'll help you research the environmental impact of renewable energy sources. Let me use the research-analyst agent to conduct comprehensive research on this topic.
1716
+ assistant: Uses the Task tool to launch with the research-analyst agent, providing detailed instructions about what research to conduct and what format the report should take
1717
+ </example>
1548
1718
 
1549
- <example>
1550
- user: "Hello"
1551
- <commentary>
1552
- Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
1553
- </commentary>
1554
- assistant: "I'm going to use the Task tool to launch with the greeting-responder agent"
1555
- </example>
1556
- `.trim();
1719
+ <example>
1720
+ user: "Hello"
1721
+ <commentary>
1722
+ Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
1723
+ </commentary>
1724
+ assistant: "I'm going to use the Task tool to launch with the greeting-responder agent"
1725
+ </example>
1726
+ `;
1557
1727
  }
1558
1728
  /**
1559
1729
  * System prompt section that explains how to use the task tool for spawning subagents.
@@ -1568,33 +1738,35 @@ assistant: "I'm going to use the Task tool to launch with the greeting-responder
1568
1738
  * You can provide a custom `systemPrompt` to `createSubAgentMiddleware` to override
1569
1739
  * or extend this default.
1570
1740
  */
1571
- const TASK_SYSTEM_PROMPT = `## \`task\` (subagent spawner)
1741
+ const TASK_SYSTEM_PROMPT = langchain.context`
1742
+ ## \`task\` (subagent spawner)
1572
1743
 
1573
- 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.
1744
+ 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.
1574
1745
 
1575
- When to use the task tool:
1576
- - When a task is complex and multi-step, and can be fully delegated in isolation
1577
- - When a task is independent of other tasks and can run in parallel
1578
- - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread
1579
- - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)
1580
- - 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.)
1746
+ When to use the task tool:
1747
+ - When a task is complex and multi-step, and can be fully delegated in isolation
1748
+ - When a task is independent of other tasks and can run in parallel
1749
+ - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread
1750
+ - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)
1751
+ - 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.)
1581
1752
 
1582
- Subagent lifecycle:
1583
- 1. **Spawn** → Provide clear role, instructions, and expected output
1584
- 2. **Run** → The subagent completes the task autonomously
1585
- 3. **Return** → The subagent provides a single structured result
1586
- 4. **Reconcile** → Incorporate or synthesize the result into the main thread
1753
+ Subagent lifecycle:
1754
+ 1. **Spawn** → Provide clear role, instructions, and expected output
1755
+ 2. **Run** → The subagent completes the task autonomously
1756
+ 3. **Return** → The subagent provides a single structured result
1757
+ 4. **Reconcile** → Incorporate or synthesize the result into the main thread
1587
1758
 
1588
- When NOT to use the task tool:
1589
- - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)
1590
- - If the task is trivial (a few tool calls or simple lookup)
1591
- - If delegating does not reduce token usage, complexity, or context switching
1592
- - If splitting would add latency without benefit
1759
+ When NOT to use the task tool:
1760
+ - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)
1761
+ - If the task is trivial (a few tool calls or simple lookup)
1762
+ - If delegating does not reduce token usage, complexity, or context switching
1763
+ - If splitting would add latency without benefit
1593
1764
 
1594
- ## Important Task Tool Usage Notes to Remember
1595
- - 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.
1596
- - Remember to use the \`task\` tool to silo independent tasks within a multi-part objective.
1597
- - 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.`;
1765
+ ## Important Task Tool Usage Notes to Remember
1766
+ - 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.
1767
+ - Remember to use the \`task\` tool to silo independent tasks within a multi-part objective.
1768
+ - 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.
1769
+ `;
1598
1770
  /**
1599
1771
  * Base specification for the general-purpose subagent.
1600
1772
  *
@@ -2003,65 +2175,67 @@ const MemoryStateSchema = new _langchain_langgraph.StateSchema({
2003
2175
  * Default system prompt template for memory.
2004
2176
  * Ported from Python's comprehensive memory guidelines.
2005
2177
  */
2006
- const MEMORY_SYSTEM_PROMPT = `<agent_memory>
2007
- {memory_contents}
2008
- </agent_memory>
2178
+ const MEMORY_SYSTEM_PROMPT = langchain.context`
2179
+ <agent_memory>
2180
+ {memory_contents}
2181
+ </agent_memory>
2009
2182
 
2010
- <memory_guidelines>
2011
- 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.
2183
+ <memory_guidelines>
2184
+ 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.
2012
2185
 
2013
- **Learning from feedback:**
2014
- - 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.
2015
- - 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.
2016
- - When user says something is better/worse, capture WHY and encode it as a pattern.
2017
- - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
2018
- - 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.
2019
- - Look for the underlying principle behind corrections, not just the specific mistake.
2020
- - 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.
2186
+ **Learning from feedback:**
2187
+ - 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.
2188
+ - 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.
2189
+ - When user says something is better/worse, capture WHY and encode it as a pattern.
2190
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
2191
+ - 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.
2192
+ - Look for the underlying principle behind corrections, not just the specific mistake.
2193
+ - 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.
2021
2194
 
2022
- **Asking for information:**
2023
- - 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.
2024
- - It is preferred for you to ask for information, don't assume anything that you do not know!
2025
- - When the user provides information that is useful for future use, you should update your memories immediately.
2195
+ **Asking for information:**
2196
+ - 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.
2197
+ - It is preferred for you to ask for information, don't assume anything that you do not know!
2198
+ - When the user provides information that is useful for future use, you should update your memories immediately.
2026
2199
 
2027
- **When to update memories:**
2028
- - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
2029
- - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
2030
- - When the user gives feedback on your work - capture what was wrong and how to improve
2031
- - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
2032
- - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
2033
- - When you discover new patterns or preferences (coding styles, conventions, workflows)
2200
+ **When to update memories:**
2201
+ - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
2202
+ - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
2203
+ - When the user gives feedback on your work - capture what was wrong and how to improve
2204
+ - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
2205
+ - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
2206
+ - When you discover new patterns or preferences (coding styles, conventions, workflows)
2034
2207
 
2035
- **When to NOT update memories:**
2036
- - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
2037
- - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
2038
- - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
2039
- - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
2040
- - When the information is stale or irrelevant in future conversations
2041
- - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
2042
- - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
2208
+ **When to NOT update memories:**
2209
+ - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
2210
+ - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
2211
+ - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
2212
+ - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
2213
+ - When the information is stale or irrelevant in future conversations
2214
+ - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
2215
+ - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
2043
2216
 
2044
- **Examples:**
2045
- Example 1 (remembering user information):
2046
- User: Can you connect to my google account?
2047
- Agent: Sure, I'll connect to your google account, what's your google account email?
2048
- User: john@example.com
2049
- Agent: Let me save this to my memory.
2050
- Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
2217
+ **Examples:**
2218
+ Example 1 (remembering user information):
2219
+ User: Can you connect to my google account?
2220
+ Agent: Sure, I'll connect to your google account, what's your google account email?
2221
+ User: john@example.com
2222
+ Agent: Let me save this to my memory.
2223
+ Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
2051
2224
 
2052
- Example 2 (remembering implicit user preferences):
2053
- User: Can you write me an example for creating a deep agent in LangChain?
2054
- Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
2055
- User: Can you do this in JavaScript
2056
- Agent: Let me save this to my memory.
2057
- Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
2058
- Agent: Sure, here is the JavaScript example<example code in JavaScript>
2225
+ Example 2 (remembering implicit user preferences):
2226
+ User: Can you write me an example for creating a deep agent in LangChain?
2227
+ Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
2228
+ User: Can you do this in JavaScript
2229
+ Agent: Let me save this to my memory.
2230
+ Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
2231
+ Agent: Sure, here is the JavaScript example<example code in JavaScript>
2059
2232
 
2060
- Example 3 (do not remember transient information):
2061
- User: I'm going to play basketball tonight so I will be offline for a few hours.
2062
- Agent: Okay I'll add a block to your calendar.
2063
- Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
2064
- </memory_guidelines>`;
2233
+ Example 3 (do not remember transient information):
2234
+ User: I'm going to play basketball tonight so I will be offline for a few hours.
2235
+ Agent: Okay I'll add a block to your calendar.
2236
+ Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
2237
+ </memory_guidelines>
2238
+ `;
2065
2239
  /**
2066
2240
  * Format loaded memory contents for injection into prompt.
2067
2241
  * Pairs memory locations with their contents for clarity.
@@ -2120,19 +2294,12 @@ async function loadMemoryFromBackend(backend, path) {
2120
2294
  */
2121
2295
  function createMemoryMiddleware(options) {
2122
2296
  const { backend, sources, addCacheControl = false } = options;
2123
- /**
2124
- * Resolve backend from instance or factory.
2125
- */
2126
- function getBackend(state) {
2127
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
2128
- return adaptBackendProtocol(backend);
2129
- }
2130
2297
  return (0, langchain.createMiddleware)({
2131
2298
  name: "MemoryMiddleware",
2132
2299
  stateSchema: MemoryStateSchema,
2133
2300
  async beforeAgent(state) {
2134
2301
  if ("memoryContents" in state && state.memoryContents != null) return;
2135
- const resolvedBackend = getBackend(state);
2302
+ const resolvedBackend = await resolveBackend(backend, { state });
2136
2303
  const contents = {};
2137
2304
  for (const path of sources) try {
2138
2305
  const content = await loadMemoryFromBackend(resolvedBackend, path);
@@ -2266,7 +2433,7 @@ Skills follow a **progressive disclosure** pattern - you know they exist (name +
2266
2433
  1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
2267
2434
  2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
2268
2435
  3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
2269
- 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
2436
+ 4. **Access supporting files**: Skills may include scripts, configs, or reference docs - use absolute paths
2270
2437
 
2271
2438
  **When to Use Skills:**
2272
2439
  - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
@@ -2278,7 +2445,7 @@ Skills follow a **progressive disclosure** pattern - you know they exist (name +
2278
2445
  - The skill list above shows the full path for each skill's SKILL.md file
2279
2446
 
2280
2447
  **Executing Skill Scripts:**
2281
- Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
2448
+ Skills may contain scripts or other executable files. Always use absolute paths from the skill list.
2282
2449
 
2283
2450
  **Example Workflow:**
2284
2451
 
@@ -2538,13 +2705,6 @@ function formatSkillsList(skills, sources) {
2538
2705
  function createSkillsMiddleware(options) {
2539
2706
  const { backend, sources } = options;
2540
2707
  let loadedSkills = [];
2541
- /**
2542
- * Resolve backend from instance or factory.
2543
- */
2544
- function getBackend(state) {
2545
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
2546
- return adaptBackendProtocol(backend);
2547
- }
2548
2708
  return (0, langchain.createMiddleware)({
2549
2709
  name: "SkillsMiddleware",
2550
2710
  stateSchema: SkillsStateSchema,
@@ -2554,7 +2714,7 @@ function createSkillsMiddleware(options) {
2554
2714
  loadedSkills = state.skillsMetadata;
2555
2715
  return;
2556
2716
  }
2557
- const resolvedBackend = getBackend(state);
2717
+ const resolvedBackend = await resolveBackend(backend, { state });
2558
2718
  const allSkills = /* @__PURE__ */ new Map();
2559
2719
  for (const sourcePath of sources) try {
2560
2720
  const skills = await listSkillsFromBackend(resolvedBackend, sourcePath);
@@ -2586,25 +2746,26 @@ function createSkillsMiddleware(options) {
2586
2746
  * This module provides shared helpers used across middleware implementations.
2587
2747
  */
2588
2748
  //#endregion
2589
- //#region src/middleware/completion_notifier.ts
2749
+ //#region src/middleware/completion_callback.ts
2590
2750
  /**
2591
- * Completion notifier middleware for async subagents.
2751
+ * Callback middleware for async subagents.
2592
2752
  *
2593
- * **Experimental** this middleware is experimental and may change in future releases.
2753
+ * @experimental - this middleware is experimental and may change in future releases.
2594
2754
  *
2595
- * When an async subagent finishes (success or error), this middleware sends a
2596
- * message back to the **supervisor's** thread so the supervisor wakes up and can
2597
- * proactively relay results to the user without the user having to poll via
2755
+ * This middleware sends a notification to a callback thread when a subagent
2756
+ * completes successfully or raises an error. The callback agent can then
2757
+ * process that notification instead of relying only on polling via
2598
2758
  * `check_async_task`.
2599
2759
  *
2600
2760
  * ## Architecture
2601
2761
  *
2602
- * The async subagent protocol is inherently fire-and-forget: the supervisor
2603
- * launches a job via `start_async_task` and only learns about completion
2604
- * when someone calls `check_async_task`. This middleware closes that gap.
2762
+ * A parent agent launches a subagent with `start_async_task` and can later
2763
+ * inspect task state with `check_async_task`. This middleware adds an optional
2764
+ * completion signal by creating a run on the callback thread when the subagent
2765
+ * finishes.
2605
2766
  *
2606
2767
  * ```
2607
- * Supervisor Subagent
2768
+ * Parent Subagent
2608
2769
  * | |
2609
2770
  * |--- start_async_task -----> |
2610
2771
  * |<-- task_id (immediately) - |
@@ -2612,67 +2773,74 @@ function createSkillsMiddleware(options) {
2612
2773
  * | | (done!)
2613
2774
  * | |
2614
2775
  * |<-- runs.create( |
2615
- * | supervisor_thread, |
2776
+ * | callback_thread, |
2616
2777
  * | "completed: ...") |
2617
2778
  * | |
2618
- * | (wakes up, sees result) |
2779
+ * | (processes result) |
2619
2780
  * ```
2620
2781
  *
2621
- * The notifier calls `runs.create()` on the supervisor's thread, which
2622
- * queues a new run. From the supervisor's perspective, it looks like a new
2623
- * user message arrived — except the content is a structured notification
2624
- * from the subagent.
2625
- *
2626
- * ## How parent context is propagated
2627
- *
2628
- * - `parentGraphId` is passed as a **constructor argument** to the middleware.
2629
- * This is the supervisor's graph ID (or assistant ID), which the subagent
2630
- * developer knows at configuration time.
2631
- * - `url` is the URL of the LangGraph server where the supervisor is deployed.
2632
- * This is required since JS does not support in-process ASGI transport.
2633
- * - `headers` are optional additional headers for authenticating with the
2634
- * supervisor's server.
2635
- * - `parent_thread_id` is injected into the subagent's input state by the
2636
- * supervisor's `start_async_task` tool. It survives thread interrupts and
2637
- * updates because it lives in state, not config.
2638
- * - If `parent_thread_id` is not present in state, the notifier silently no-ops.
2782
+ * The middleware calls `runs.create()` on the callback thread. From the
2783
+ * callback agent's perspective, this appears as a new user message containing
2784
+ * structured output from the subagent.
2785
+ *
2786
+ * ## Callback context
2787
+ *
2788
+ * - `callbackGraphId` identifies the callback graph or assistant. It is
2789
+ * provided when the middleware is constructed.
2790
+ * - `url` and `headers` optionally configure a remote callback destination.
2791
+ * Omit `url` for same-deployment ASGI transport.
2792
+ * - `callback_thread_id` is stored in the subagent state by the parent's
2793
+ * `start_async_task` tool. Because it is stored in state rather than config,
2794
+ * it survives thread updates and interrupts.
2795
+ * - If `callback_thread_id` is not present in state, the middleware does
2796
+ * nothing.
2639
2797
  *
2640
2798
  * ## Usage
2641
2799
  *
2642
2800
  * ```typescript
2643
- * import { createCompletionNotifierMiddleware } from "deepagents";
2801
+ * import { createCompletionCallbackMiddleware } from "deepagents";
2644
2802
  *
2645
- * const notifier = createCompletionNotifierMiddleware({
2646
- * parentGraphId: "supervisor",
2803
+ * // Same deployment (callback agent and subagent share a server):
2804
+ * const notifier = createCompletionCallbackMiddleware({
2805
+ * callbackGraphId: "supervisor",
2806
+ * });
2807
+ *
2808
+ * // Remote deployment (callback destination on a different server):
2809
+ * const notifier = createCompletionCallbackMiddleware({
2810
+ * callbackGraphId: "supervisor",
2647
2811
  * url: "https://my-deployment.langsmith.dev",
2648
2812
  * });
2649
2813
  *
2650
2814
  * const agent = createDeepAgent({
2651
- * model: "claude-sonnet-4-5-20250929",
2815
+ * model,
2652
2816
  * middleware: [notifier],
2653
2817
  * });
2654
2818
  * ```
2655
2819
  *
2656
- * The middleware will read `parent_thread_id` from the agent's state at the
2657
- * end of execution. This is injected automatically by the supervisor's
2658
- * `start_async_task` tool when it creates the run.
2820
+ * The middleware reads `callbackThreadId` from the agent state at the end of
2821
+ * execution. This value is injected by the parent's `start_async_task` tool
2822
+ * when it creates the run.
2659
2823
  *
2660
2824
  * @module
2661
2825
  */
2662
- /** State key where the supervisor's launch tool stores the parent thread ID. */
2663
- const PARENT_THREAD_ID_KEY = "parent_thread_id";
2664
2826
  /** Maximum characters to include from the last message in notifications. */
2665
- const MAX_SUMMARY_LENGTH = 500;
2827
+ const MAX_MESSAGE_LENGTH = 500;
2828
+ /** Suffix appended when truncating long messages. */
2829
+ const TRUNCATION_SUFFIX = "... [full result truncated]";
2830
+ /** State key for the callback thread ID. */
2831
+ const CALLBACK_THREAD_ID_KEY = "callbackThreadId";
2666
2832
  /**
2667
- * State extension for subagents that use the completion notifier.
2833
+ * State extension for subagents that use completion callbacks.
2668
2834
  *
2669
- * These fields are injected by the supervisor's `start_async_task`
2670
- * tool and read by the completion notifier middleware to send notifications
2671
- * back to the supervisor's thread.
2835
+ * @experimental - this state schema is experimental and may change in future releases.
2836
+ *
2837
+ * `callbackThreadId` is written by the parent's `start_async_task` tool
2838
+ * and read by `CompletionCallbackMiddleware` when sending callback
2839
+ * notifications.
2672
2840
  */
2673
- const CompletionNotifierStateSchema = zod_v4.z.object({ parent_thread_id: zod_v4.z.string().nullish() });
2841
+ const CompletionCallbackStateSchema = zod.object({ [CALLBACK_THREAD_ID_KEY]: zod.string().optional() });
2674
2842
  /**
2675
- * Build headers for the supervisor's LangGraph server.
2843
+ * Build headers for the callback LangGraph server.
2676
2844
  *
2677
2845
  * Ensures `x-auth-scheme: langsmith` is present unless explicitly overridden.
2678
2846
  */
@@ -2682,55 +2850,63 @@ function resolveHeaders(headers) {
2682
2850
  return resolved;
2683
2851
  }
2684
2852
  /**
2685
- * Send a notification run to the parent supervisor's thread.
2853
+ * Send a notification run to the callback thread.
2854
+ *
2855
+ * @param callbackGraphId - The callback graph ID used as `assistant_id`
2856
+ * in the `runs.create` call.
2857
+ * @param callbackThreadId - The callback thread ID.
2858
+ * @param message - The message content to send.
2859
+ * @param options - Optional url and headers for the callback server.
2686
2860
  */
2687
- async function notifyParent(parentThreadId, parentGraphId, notification, options) {
2861
+ async function notifyParent(callbackGraphId, callbackThreadId, message, options) {
2688
2862
  try {
2689
2863
  await new _langchain_langgraph_sdk.Client({
2690
- apiUrl: options.url,
2864
+ apiUrl: options?.url ?? void 0,
2691
2865
  apiKey: null,
2692
- defaultHeaders: resolveHeaders(options.headers)
2693
- }).runs.create(parentThreadId, parentGraphId, { input: { messages: [{
2866
+ defaultHeaders: resolveHeaders(options?.headers)
2867
+ }).runs.create(callbackThreadId, callbackGraphId, { input: { messages: [{
2694
2868
  role: "user",
2695
- content: notification
2869
+ content: message
2696
2870
  }] } });
2697
2871
  } catch (e) {
2698
- console.warn(`[CompletionNotifierMiddleware] Failed to notify parent thread ${parentThreadId}:`, e);
2872
+ console.warn(`[CompletionCallbackMiddleware] Failed to notify callback thread ${callbackThreadId}:`, e);
2699
2873
  }
2700
2874
  }
2701
2875
  /**
2702
2876
  * Extract a summary from the subagent's final message.
2703
2877
  *
2704
2878
  * Returns at most 500 characters from the last message's content.
2879
+ * Throws if no messages exist or if the last message is not an AIMessage.
2880
+ *
2881
+ * @param state - The agent state dict.
2882
+ * @param taskId - Optional task ID to include in truncation hint.
2705
2883
  */
2706
- function extractLastMessage(state) {
2884
+ function extractLastMessage(state, taskId) {
2707
2885
  const messages = state.messages;
2708
- if (!messages || messages.length === 0) return "(no output)";
2886
+ if (!messages || messages.length === 0) throw new Error(`Expected at least one message in state ${JSON.stringify(state)}`);
2709
2887
  const last = messages[messages.length - 1];
2710
- if (last && typeof last === "object" && "content" in last) {
2711
- const content = last.content;
2712
- if (typeof content === "string") return content.slice(0, MAX_SUMMARY_LENGTH);
2713
- return JSON.stringify(content).slice(0, MAX_SUMMARY_LENGTH);
2888
+ if (!_langchain_core_messages.AIMessage.isInstance(last)) throw new TypeError(`Expected an AIMessage, got ${typeof last === "object" && last !== null ? last.constructor?.name ?? typeof last : typeof last} instead`);
2889
+ let textContent = last.text;
2890
+ if (textContent.length > MAX_MESSAGE_LENGTH) {
2891
+ textContent = textContent.slice(0, MAX_MESSAGE_LENGTH) + TRUNCATION_SUFFIX;
2892
+ if (taskId) textContent += ` Result truncated. Use \`check_async_task(task_id='${taskId}')\` to retrieve the full result if needed.`;
2714
2893
  }
2715
- return String(last).slice(0, MAX_SUMMARY_LENGTH);
2894
+ return textContent;
2716
2895
  }
2717
2896
  /**
2718
- * Create a completion notifier middleware for async subagents.
2897
+ * Create a completion callback middleware for async subagents.
2719
2898
  *
2720
2899
  * **Experimental** — this middleware is experimental and may change.
2721
2900
  *
2722
- * This middleware is added to the **subagent's** middleware stack (not the
2723
- * supervisor's). When the subagent finishes, it sends a message to the
2724
- * supervisor's thread via `runs.create()`, waking the supervisor so it can
2725
- * proactively relay results.
2901
+ * This middleware is added to a subagent's middleware stack. On success or
2902
+ * model-call error, it sends a notification to the configured callback
2903
+ * thread by calling `runs.create()`.
2726
2904
  *
2727
- * The supervisor's `parent_thread_id` is read from the subagent's own state
2728
- * (injected by the supervisor's `start_async_task` tool at launch time).
2729
- * The `parentGraphId` is provided as a constructor argument since it's static
2730
- * configuration known at deployment time.
2905
+ * The callback destination is configured with `callbackGraphId` and
2906
+ * optional `url` and `headers`. The target thread is read from
2907
+ * `callbackThreadId` in the subagent state.
2731
2908
  *
2732
- * If `parent_thread_id` is not present in state (e.g., the subagent was
2733
- * launched manually without a supervisor), the middleware silently does
2909
+ * If `callbackThreadId` is not present in state, the middleware does
2734
2910
  * nothing.
2735
2911
  *
2736
2912
  * @param options - Configuration options.
@@ -2738,11 +2914,10 @@ function extractLastMessage(state) {
2738
2914
  *
2739
2915
  * @example
2740
2916
  * ```typescript
2741
- * import { createCompletionNotifierMiddleware } from "deepagents";
2917
+ * import { createCompletionCallbackMiddleware } from "deepagents";
2742
2918
  *
2743
- * const notifier = createCompletionNotifierMiddleware({
2744
- * parentGraphId: "supervisor",
2745
- * url: "https://my-deployment.langsmith.dev",
2919
+ * const notifier = createCompletionCallbackMiddleware({
2920
+ * callbackGraphId: "supervisor",
2746
2921
  * });
2747
2922
  *
2748
2923
  * const agent = createDeepAgent({
@@ -2751,23 +2926,13 @@ function extractLastMessage(state) {
2751
2926
  * });
2752
2927
  * ```
2753
2928
  */
2754
- function createCompletionNotifierMiddleware(options) {
2755
- const { parentGraphId, url, headers } = options;
2756
- let notified = false;
2929
+ function createCompletionCallbackMiddleware(options) {
2930
+ const { callbackGraphId, url, headers } = options;
2757
2931
  /**
2758
- * Check whether we should send a notification.
2932
+ * Send a notification to the callback destination.
2759
2933
  */
2760
- function shouldNotify(state) {
2761
- if (notified) return false;
2762
- return Boolean(state[PARENT_THREAD_ID_KEY]);
2763
- }
2764
- /**
2765
- * Send a notification to the parent if conditions are met.
2766
- */
2767
- async function sendNotification(state, message) {
2768
- if (!shouldNotify(state)) return;
2769
- notified = true;
2770
- await notifyParent(state[PARENT_THREAD_ID_KEY], parentGraphId, message, {
2934
+ async function sendNotification(callbackThreadId, message) {
2935
+ await notifyParent(callbackGraphId, callbackThreadId, message, {
2771
2936
  url,
2772
2937
  headers
2773
2938
  });
@@ -2776,7 +2941,7 @@ function createCompletionNotifierMiddleware(options) {
2776
2941
  * Read the subagent's own thread_id from runtime config.
2777
2942
  *
2778
2943
  * The subagent's `thread_id` is the same as the `task_id` from the
2779
- * supervisor's perspective.
2944
+ * parent's perspective.
2780
2945
  */
2781
2946
  function getTaskId(runtime) {
2782
2947
  return runtime?.configurable?.thread_id;
@@ -2789,17 +2954,20 @@ function createCompletionNotifierMiddleware(options) {
2789
2954
  return `${taskId ? `[task_id=${taskId}]` : ""}${body}`;
2790
2955
  }
2791
2956
  return (0, langchain.createMiddleware)({
2792
- name: "CompletionNotifierMiddleware",
2793
- stateSchema: CompletionNotifierStateSchema,
2957
+ name: "CompletionCallbackMiddleware",
2958
+ stateSchema: CompletionCallbackStateSchema,
2794
2959
  async afterAgent(state, runtime) {
2795
- await sendNotification(state, formatNotification(`Completed. Result: ${extractLastMessage(state)}`, runtime));
2960
+ const callbackThreadId = state[CALLBACK_THREAD_ID_KEY];
2961
+ if (callbackThreadId == null) throw new Error(`Missing required state key '${CALLBACK_THREAD_ID_KEY}'`);
2962
+ const taskId = getTaskId(runtime);
2963
+ await sendNotification(callbackThreadId, formatNotification(`Completed. Result: ${extractLastMessage(state, typeof taskId === "string" ? taskId : void 0)}`, runtime));
2796
2964
  },
2797
2965
  async wrapModelCall(request, handler) {
2798
2966
  try {
2799
2967
  return await handler(request);
2800
2968
  } catch (e) {
2801
- const notification = formatNotification(`Error: ${e instanceof Error ? e.message : String(e)}`, request.runtime);
2802
- await sendNotification(request.state, notification);
2969
+ const callbackThreadId = request.state[CALLBACK_THREAD_ID_KEY];
2970
+ if (typeof callbackThreadId === "string") await sendNotification(callbackThreadId, formatNotification("The agent encountered an error while calling the model.", request.runtime));
2803
2971
  throw e;
2804
2972
  }
2805
2973
  }
@@ -2998,13 +3166,6 @@ function createSummarizationMiddleware(options) {
2998
3166
  let sessionId = null;
2999
3167
  let tokenEstimationMultiplier = 1;
3000
3168
  /**
3001
- * Resolve backend from instance or factory.
3002
- */
3003
- function getBackend(state) {
3004
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
3005
- return adaptBackendProtocol(backend);
3006
- }
3007
- /**
3008
3169
  * Get or create session ID for history file naming.
3009
3170
  */
3010
3171
  function getSessionId(state) {
@@ -3336,15 +3497,17 @@ function createSummarizationMiddleware(options) {
3336
3497
  */
3337
3498
  function buildSummaryMessage(summary, filePath) {
3338
3499
  let content;
3339
- if (filePath) content = `You are in the middle of a conversation that has been summarized.
3500
+ if (filePath) content = langchain.context`
3501
+ You are in the middle of a conversation that has been summarized.
3340
3502
 
3341
- The full conversation history has been saved to ${filePath} should you need to refer back to it for details.
3503
+ The full conversation history has been saved to ${filePath} should you need to refer back to it for details.
3342
3504
 
3343
- A condensed summary follows:
3505
+ A condensed summary follows:
3344
3506
 
3345
- <summary>
3346
- ${summary}
3347
- </summary>`;
3507
+ <summary>
3508
+ ${summary}
3509
+ </summary>
3510
+ `;
3348
3511
  else content = `Here is a summary of the conversation to date:\n\n${summary}`;
3349
3512
  return new langchain.HumanMessage({
3350
3513
  content,
@@ -3370,7 +3533,7 @@ ${summary}
3370
3533
  * the file path, and the state cutoff index.
3371
3534
  */
3372
3535
  async function summarizeMessages(messagesToSummarize, resolvedModel, state, previousCutoffIndex, cutoffIndex) {
3373
- const filePath = await offloadToBackend(getBackend(state), messagesToSummarize, state);
3536
+ const filePath = await offloadToBackend(await resolveBackend(backend, { state }), messagesToSummarize, state);
3374
3537
  if (filePath === null) console.warn(`[SummarizationMiddleware] Backend offload failed during summarization. Proceeding with summary generation.`);
3375
3538
  return {
3376
3539
  summaryMessage: buildSummaryMessage(await createSummary(messagesToSummarize, resolvedModel), filePath),
@@ -3512,6 +3675,7 @@ const AsyncTaskSchema = zod_v4.z.object({
3512
3675
  runId: zod_v4.z.string(),
3513
3676
  status: zod_v4.z.string(),
3514
3677
  createdAt: zod_v4.z.string(),
3678
+ description: zod_v4.z.string().optional(),
3515
3679
  updatedAt: zod_v4.z.string().optional(),
3516
3680
  checkedAt: zod_v4.z.string().optional()
3517
3681
  });
@@ -3549,7 +3713,7 @@ function asyncTasksReducer(existing, update) {
3549
3713
  * The `{available_agents}` placeholder is replaced at middleware creation
3550
3714
  * time with a formatted list of configured async subagent names and descriptions.
3551
3715
  */
3552
- const ASYNC_TASK_TOOL_DESCRIPTION = `Launch an async subagent on a remote LangGraph server. The subagent runs in the background and returns a task ID immediately.
3716
+ const ASYNC_TASK_TOOL_DESCRIPTION = `Launch an async subagent on a remote server. The subagent runs in the background and returns a task ID immediately.
3553
3717
 
3554
3718
  Available async agent types:
3555
3719
  {available_agents}
@@ -3559,7 +3723,7 @@ Available async agent types:
3559
3723
  2. Use \`check_async_task\` only when the user asks for a status update or result.
3560
3724
  3. Use \`update_async_task\` to send new instructions to a running task.
3561
3725
  4. Multiple async subagents can run concurrently — launch several and let them run in the background.
3562
- 5. The subagent runs on a remote LangGraph server, so it has its own tools and capabilities.`;
3726
+ 5. The subagent runs on a remote server, so it has its own tools and capabilities.`;
3563
3727
  /**
3564
3728
  * Default system prompt appended to the main agent's system message when
3565
3729
  * async subagent middleware is active.
@@ -3569,9 +3733,9 @@ Available async agent types:
3569
3733
  * critical rules about polling behavior, and guidance on when to use async
3570
3734
  * subagents vs. synchronous delegation.
3571
3735
  */
3572
- const ASYNC_TASK_SYSTEM_PROMPT = `## Async subagents (remote LangGraph servers)
3736
+ const ASYNC_TASK_SYSTEM_PROMPT = `## Async subagents (remote servers)
3573
3737
 
3574
- You have access to async subagent tools that launch background tasks on remote LangGraph servers.
3738
+ You have access to async subagent tools that launch background tasks on remote servers.
3575
3739
 
3576
3740
  ### Tools:
3577
3741
  - \`start_async_task\`: Start a new background task. Returns a task ID immediately.
@@ -3611,6 +3775,19 @@ You have access to async subagent tools that launch background tasks on remote L
3611
3775
  * When listing tasks, live-status fetches are skipped for tasks whose
3612
3776
  * cached status is in this set, since they are guaranteed to be final.
3613
3777
  */
3778
+ /**
3779
+ * Names of the tools added by the async subagent middleware.
3780
+ *
3781
+ * Exported so `agent.ts` can include them in `BUILTIN_TOOL_NAMES` and
3782
+ * surface a `ConfigurationError` if a user-provided tool collides.
3783
+ */
3784
+ const ASYNC_TASK_TOOL_NAMES = [
3785
+ "start_async_task",
3786
+ "check_async_task",
3787
+ "update_async_task",
3788
+ "cancel_async_task",
3789
+ "list_async_tasks"
3790
+ ];
3614
3791
  const TERMINAL_STATUSES = new Set([
3615
3792
  "cancelled",
3616
3793
  "success",
@@ -3702,8 +3879,11 @@ var ClientCache = class {
3702
3879
  this.agents = agents;
3703
3880
  }
3704
3881
  /**
3705
- * Build headers for a remote LangGraph server, adding the default
3706
- * `x-auth-scheme: langsmith` header if not already present.
3882
+ * Build headers for a remote Agent Protocol server.
3883
+ *
3884
+ * Adds `x-auth-scheme: langsmith` by default unless already provided.
3885
+ * For self-hosted servers that don't require this header, it is typically
3886
+ * ignored. Override via the `headers` field on the AsyncSubAgent config.
3707
3887
  */
3708
3888
  resolveHeaders(spec) {
3709
3889
  const headers = { ...spec.headers || {} };
@@ -3736,6 +3916,20 @@ var ClientCache = class {
3736
3916
  }
3737
3917
  };
3738
3918
  /**
3919
+ * Extract the callback thread ID from the tool runtime.
3920
+ *
3921
+ * The thread ID is included in the subagent's input state so the subagent
3922
+ * can notify the parent when it completes (via
3923
+ * `CompletionCallbackMiddleware`).
3924
+ *
3925
+ * @returns Object with `callbackThreadId` if available. Empty object otherwise.
3926
+ */
3927
+ function extractCallbackContext(runtime) {
3928
+ const threadId = (runtime.config?.configurable)?.thread_id;
3929
+ if (typeof threadId === "string" && threadId) return { callbackThreadId: threadId };
3930
+ return {};
3931
+ }
3932
+ /**
3739
3933
  * Build the `start_async_task` tool.
3740
3934
  *
3741
3935
  * Creates a thread on the remote server, starts a run, and returns a
@@ -3748,13 +3942,17 @@ function buildStartTool(agentMap, clients, toolDescription) {
3748
3942
  return `Unknown async subagent type \`${input.agentName}\`. Available types: ${allowed}`;
3749
3943
  }
3750
3944
  const spec = agentMap[input.agentName];
3945
+ const callbackContext = extractCallbackContext(runtime);
3751
3946
  try {
3752
3947
  const client = clients.getClient(input.agentName);
3753
3948
  const thread = await client.threads.create();
3754
- const run = await client.runs.create(thread.thread_id, spec.graphId, { input: { messages: [{
3755
- role: "user",
3756
- content: input.description
3757
- }] } });
3949
+ const run = await client.runs.create(thread.thread_id, spec.graphId, { input: {
3950
+ messages: [{
3951
+ role: "user",
3952
+ content: input.description
3953
+ }],
3954
+ ...callbackContext
3955
+ } });
3758
3956
  const taskId = thread.thread_id;
3759
3957
  const task = {
3760
3958
  taskId,
@@ -3762,7 +3960,8 @@ function buildStartTool(agentMap, clients, toolDescription) {
3762
3960
  threadId: taskId,
3763
3961
  runId: run.run_id,
3764
3962
  status: "running",
3765
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
3963
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3964
+ description: input.description
3766
3965
  };
3767
3966
  return new _langchain_langgraph.Command({ update: {
3768
3967
  messages: [new langchain.ToolMessage({
@@ -3812,7 +4011,7 @@ function buildCheckTool(clients) {
3812
4011
  runId: task.runId,
3813
4012
  status: result.status,
3814
4013
  createdAt: task.createdAt,
3815
- updatedAt: task.updatedAt,
4014
+ updatedAt: result.status !== task.status ? (/* @__PURE__ */ new Date()).toISOString() : task.updatedAt,
3816
4015
  checkedAt: (/* @__PURE__ */ new Date()).toISOString()
3817
4016
  };
3818
4017
  return new _langchain_langgraph.Command({ update: {
@@ -3856,6 +4055,7 @@ function buildUpdateTool(agentMap, clients) {
3856
4055
  runId: run.run_id,
3857
4056
  status: "running",
3858
4057
  createdAt: tracked.createdAt,
4058
+ description: input.message,
3859
4059
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3860
4060
  checkedAt: tracked.checkedAt
3861
4061
  };
@@ -3901,7 +4101,7 @@ function buildCancelTool(clients) {
3901
4101
  runId: tracked.runId,
3902
4102
  status: "cancelled",
3903
4103
  createdAt: tracked.createdAt,
3904
- updatedAt: tracked.updatedAt,
4104
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3905
4105
  checkedAt: tracked.checkedAt
3906
4106
  };
3907
4107
  return new _langchain_langgraph.Command({ update: {
@@ -3942,7 +4142,7 @@ function buildListTool(clients) {
3942
4142
  runId: task.runId,
3943
4143
  status,
3944
4144
  createdAt: task.createdAt,
3945
- updatedAt: task.updatedAt,
4145
+ updatedAt: status !== task.status ? (/* @__PURE__ */ new Date()).toISOString() : task.updatedAt,
3946
4146
  checkedAt: task.checkedAt
3947
4147
  };
3948
4148
  }
@@ -3963,10 +4163,13 @@ function buildListTool(clients) {
3963
4163
  * Create middleware that adds async subagent tools to an agent.
3964
4164
  *
3965
4165
  * Provides five tools for launching, checking, updating, cancelling, and
3966
- * listing background tasks on remote LangGraph deployments. Task state is
4166
+ * listing background tasks on remote Agent Protocol servers. Task state is
3967
4167
  * persisted in the `asyncTasks` state channel so it survives
3968
4168
  * context compaction.
3969
4169
  *
4170
+ * Works with any Agent Protocol-compliant server — LangGraph Platform (managed)
4171
+ * or self-hosted (e.g. a Hono/Express server implementing the Agent Protocol spec).
4172
+ *
3970
4173
  * @throws {Error} If no async subagents are provided or names are duplicated.
3971
4174
  *
3972
4175
  * @example
@@ -3975,7 +4178,7 @@ function buildListTool(clients) {
3975
4178
  * asyncSubAgents: [{
3976
4179
  * name: "researcher",
3977
4180
  * description: "Research agent for deep analysis",
3978
- * url: "https://my-deployment.langsmith.dev",
4181
+ * url: "https://my-agent-protocol-server.example.com",
3979
4182
  * graphId: "research_agent",
3980
4183
  * }],
3981
4184
  * });
@@ -4022,6 +4225,9 @@ function createAsyncSubAgentMiddleware(options) {
4022
4225
  }
4023
4226
  //#endregion
4024
4227
  //#region src/backends/store.ts
4228
+ /**
4229
+ * StoreBackend: Adapter for LangGraph's BaseStore (persistent, cross-thread).
4230
+ */
4025
4231
  const NAMESPACE_COMPONENT_RE = /^[A-Za-z0-9\-_.@+:~]+$/;
4026
4232
  /**
4027
4233
  * Validate a namespace array.
@@ -4057,35 +4263,54 @@ var StoreBackend = class {
4057
4263
  stateAndStore;
4058
4264
  _namespace;
4059
4265
  fileFormat;
4060
- constructor(stateAndStore, options) {
4061
- this.stateAndStore = stateAndStore;
4062
- if (options?.namespace) this._namespace = validateNamespace(options.namespace);
4063
- this.fileFormat = options?.fileFormat ?? "v2";
4266
+ constructor(stateAndStoreOrOptions, options) {
4267
+ let opts;
4268
+ if (stateAndStoreOrOptions != null && typeof stateAndStoreOrOptions === "object" && "state" in stateAndStoreOrOptions) {
4269
+ this.stateAndStore = stateAndStoreOrOptions;
4270
+ opts = options;
4271
+ } else {
4272
+ this.stateAndStore = void 0;
4273
+ opts = stateAndStoreOrOptions;
4274
+ }
4275
+ if (opts?.namespace) this._namespace = validateNamespace(opts.namespace);
4276
+ this.fileFormat = opts?.fileFormat ?? "v2";
4064
4277
  }
4065
4278
  /**
4066
- * Get the store instance.
4279
+ * Get the BaseStore instance for persistent storage operations.
4280
+ *
4281
+ * In legacy mode, reads from the injected {@link StateAndStore}.
4282
+ * In zero-arg mode, retrieves the store from the LangGraph execution
4283
+ * context via {@link getLangGraphStore}.
4067
4284
  *
4068
4285
  * @returns BaseStore instance
4069
- * @throws Error if no store is available
4286
+ * @throws Error if no store is available in either mode
4070
4287
  */
4071
4288
  getStore() {
4072
- const store = this.stateAndStore.store;
4073
- if (!store) throw new Error("Store is required but not available in StateAndStore");
4289
+ if (this.stateAndStore) {
4290
+ const store = this.stateAndStore.store;
4291
+ if (!store) throw new Error("Store is required but not available in runtime");
4292
+ return store;
4293
+ }
4294
+ const store = (0, _langchain_langgraph.getStore)();
4295
+ if (!store) throw new Error("Store is required but not available in LangGraph execution context. Ensure the graph was configured with a store.");
4074
4296
  return store;
4075
4297
  }
4076
4298
  /**
4077
4299
  * Get the namespace for store operations.
4078
4300
  *
4079
- * If a custom namespace was provided, returns it directly.
4080
- *
4081
- * Otherwise, falls back to legacy behavior:
4082
- * - If assistantId is set: [assistantId, "filesystem"]
4083
- * - Otherwise: ["filesystem"]
4301
+ * Resolution order:
4302
+ * 1. Explicit namespace from constructor options (both modes)
4303
+ * 2. Legacy mode: `[assistantId, "filesystem"]` fallback from {@link StateAndStore}
4304
+ * 3. Zero-arg mode without namespace: `["filesystem"]` with a deprecation warning
4305
+ * nudging callers to pass an explicit namespace
4306
+ * 4. Legacy mode without assistantId: `["filesystem"]`
4084
4307
  */
4085
4308
  getNamespace() {
4086
4309
  if (this._namespace) return this._namespace;
4087
- const assistantId = this.stateAndStore.assistantId;
4088
- if (assistantId) return [assistantId, "filesystem"];
4310
+ if (this.stateAndStore) {
4311
+ const assistantId = this.stateAndStore.assistantId;
4312
+ if (assistantId) return [assistantId, "filesystem"];
4313
+ }
4089
4314
  return ["filesystem"];
4090
4315
  }
4091
4316
  /**
@@ -6094,9 +6319,9 @@ var LangSmithSandbox = class LangSmithSandbox extends BaseSandbox {
6094
6319
  * ```
6095
6320
  */
6096
6321
  static async create(options = {}) {
6097
- const { templateName = "deepagents", apiKey = process.env.LANGSMITH_API_KEY, defaultTimeout } = options;
6322
+ const { templateName = "deepagents", apiKey = process.env.LANGSMITH_API_KEY, defaultTimeout, ...createSandboxOptions } = options;
6098
6323
  return new LangSmithSandbox({
6099
- sandbox: await new langsmith_experimental_sandbox.SandboxClient({ apiKey }).createSandbox(templateName),
6324
+ sandbox: await new langsmith_experimental_sandbox.SandboxClient({ apiKey }).createSandbox(templateName, createSandboxOptions),
6100
6325
  defaultTimeout
6101
6326
  });
6102
6327
  }
@@ -6184,9 +6409,44 @@ function createCacheBreakpointMiddleware() {
6184
6409
  }
6185
6410
  //#endregion
6186
6411
  //#region src/agent.ts
6187
- const BASE_PROMPT = `In order to complete the objective that the user asks of you, you have access to a number of standard tools.`;
6412
+ const BASE_AGENT_PROMPT = langchain.context`
6413
+ 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.
6414
+
6415
+ ## Core Behavior
6416
+
6417
+ - Be concise and direct. Don't over-explain unless asked.
6418
+ - NEVER add unnecessary preamble (\"Sure!\", \"Great question!\", \"I'll now...\").
6419
+ - Don't say \"I'll now do X\" — just do it.
6420
+ - If the request is ambiguous, ask questions before acting.
6421
+ - If asked how to approach something, explain first, then act.
6422
+
6423
+ ## Professional Objectivity
6424
+
6425
+ - Prioritize accuracy over validating the user's beliefs
6426
+ - Disagree respectfully when the user is incorrect
6427
+ - Avoid unnecessary superlatives, praise, or emotional validation
6428
+
6429
+ ## Doing Tasks
6430
+
6431
+ When the user asks you to do something:
6432
+
6433
+ 1. **Understand first** — read relevant files, check existing patterns. Quick but thorough — gather enough evidence to start, then iterate.
6434
+ 2. **Act** — implement the solution. Work quickly but accurately.
6435
+ 3. **Verify** — check your work against what was asked, not against your own output. Your first attempt is rarely correct — iterate.
6436
+
6437
+ 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.
6438
+
6439
+ **When things go wrong:**
6440
+ - If something fails repeatedly, stop and analyze *why* — don't keep retrying the same approach.
6441
+ - If you're blocked, tell the user what's wrong and ask for guidance.
6442
+
6443
+ ## Progress Updates
6444
+
6445
+ For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
6446
+ `;
6188
6447
  const BUILTIN_TOOL_NAMES = new Set([
6189
6448
  ...FILESYSTEM_TOOL_NAMES,
6449
+ ...ASYNC_TASK_TOOL_NAMES,
6190
6450
  "task",
6191
6451
  "write_todos"
6192
6452
  ]);
@@ -6203,19 +6463,18 @@ function isAnthropicModel(model) {
6203
6463
  return model.getName() === "ChatAnthropic";
6204
6464
  }
6205
6465
  /**
6206
- * Create a Deep Agent with middleware-based architecture.
6466
+ * Create a Deep Agent.
6467
+ *
6468
+ * This is the main entry point for building a production-style agent with
6469
+ * deepagents. It gives you a strong default runtime (filesystem, tasks,
6470
+ * subagents, summarization) and lets you opt into skills, memory,
6471
+ * human-in-the-loop interrupts, async subagents, and custom middleware.
6207
6472
  *
6208
- * Matches Python's create_deep_agent function, using middleware for all features:
6209
- * - Todo management (todoListMiddleware)
6210
- * - Filesystem tools (createFilesystemMiddleware)
6211
- * - Subagent delegation (createSubAgentMiddleware)
6212
- * - Conversation summarization (createSummarizationMiddleware) with backend offloading
6213
- * - Prompt caching (anthropicPromptCachingMiddleware)
6214
- * - Tool call patching (createPatchToolCallsMiddleware)
6215
- * - Human-in-the-loop (humanInTheLoopMiddleware) - optional
6473
+ * The runtime is intentionally opinionated: defaults work out of the box, and
6474
+ * when you customize behavior, the middleware ordering stays deterministic.
6216
6475
  *
6217
6476
  * @param params Configuration parameters for the agent
6218
- * @returns ReactAgent instance ready for invocation with properly inferred state types
6477
+ * @returns Deep Agent instance with inferred state/response types
6219
6478
  *
6220
6479
  * @example
6221
6480
  * ```typescript
@@ -6234,98 +6493,92 @@ function isAnthropicModel(model) {
6234
6493
  * ```
6235
6494
  */
6236
6495
  function createDeepAgent(params = {}) {
6237
- const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name, memory, skills } = params;
6496
+ const { model = new _langchain_anthropic.ChatAnthropic("claude-sonnet-4-6"), tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend = (config) => new StateBackend(config), interruptOn, name, memory, skills } = params;
6238
6497
  const collidingTools = tools.map((t) => t.name).filter((n) => typeof n === "string" && BUILTIN_TOOL_NAMES.has(n));
6239
6498
  if (collidingTools.length > 0) throw new ConfigurationError(`Tool name(s) [${collidingTools.join(", ")}] conflict with built-in tools. Rename your custom tools to avoid this.`, "TOOL_NAME_COLLISION");
6240
6499
  const anthropicModel = isAnthropicModel(model);
6241
- const finalSystemPrompt = new langchain.SystemMessage({ content: systemPrompt ? typeof systemPrompt === "string" ? [{
6242
- type: "text",
6243
- text: `${systemPrompt}\n\n${BASE_PROMPT}`
6244
- }] : [{
6245
- type: "text",
6246
- text: BASE_PROMPT
6247
- }, ...typeof systemPrompt.content === "string" ? [{
6248
- type: "text",
6249
- text: systemPrompt.content
6250
- }] : systemPrompt.content] : [{
6251
- type: "text",
6252
- text: BASE_PROMPT
6253
- }] });
6254
- /**
6255
- * Create backend configuration for filesystem middleware
6256
- * If no backend is provided, use a factory that creates a StateBackend
6257
- */
6258
- const filesystemBackend = backend ? backend : (config) => new StateBackend(config);
6259
- /**
6260
- * Skills middleware (created conditionally for runtime use)
6261
- */
6262
- const skillsMiddlewareArray = skills != null && skills.length > 0 ? [createSkillsMiddleware({
6263
- backend: filesystemBackend,
6264
- sources: skills
6265
- })] : [];
6266
- /**
6267
- * Memory middleware (created conditionally for runtime use)
6268
- */
6269
- const memoryMiddlewareArray = memory != null && memory.length > 0 ? [createMemoryMiddleware({
6270
- backend: filesystemBackend,
6271
- sources: memory,
6272
- addCacheControl: anthropicModel
6273
- })] : [];
6274
- /**
6275
- * Split the unified subagents array into sync and async subagents.
6276
- * AsyncSubAgents are identified by the presence of a `graphId` field.
6277
- */
6278
- const syncSubAgents = subagents.filter((a) => !isAsyncSubAgent(a));
6279
- const asyncSubAgents = subagents.filter((a) => isAsyncSubAgent(a));
6500
+ const cacheMiddleware = anthropicModel ? [(0, langchain.anthropicPromptCachingMiddleware)({
6501
+ unsupportedModelBehavior: "ignore",
6502
+ minMessagesToCache: 1
6503
+ }), createCacheBreakpointMiddleware()] : [];
6280
6504
  /**
6281
6505
  * Process subagents to add SkillsMiddleware for those with their own skills.
6282
6506
  *
6283
6507
  * Custom subagents do NOT inherit skills from the main agent by default.
6284
- * Only the general-purpose subagent inherits the main agent's skills (via defaultMiddleware).
6508
+ * Only the general-purpose subagent inherits the main agent's skills.
6285
6509
  * If a custom subagent needs skills, it must specify its own `skills` array.
6286
6510
  */
6287
- const processedSubagents = syncSubAgents.map((subagent) => {
6288
- /**
6289
- * CompiledSubAgent - use as-is (already has its own middleware baked in)
6290
- */
6291
- if (_langchain_core_runnables.Runnable.isRunnable(subagent)) return subagent;
6292
- /**
6293
- * SubAgent without skills - use as-is
6294
- */
6295
- if (!("skills" in subagent) || subagent.skills?.length === 0) return subagent;
6296
- /**
6297
- * SubAgent with skills - add SkillsMiddleware BEFORE user's middleware
6298
- * Order: base middleware (via defaultMiddleware) → skills → user's middleware
6299
- * This matches Python's ordering in create_deep_agent
6300
- */
6301
- const subagentSkillsMiddleware = createSkillsMiddleware({
6302
- backend: filesystemBackend,
6303
- sources: subagent.skills ?? []
6304
- });
6511
+ const normalizeSubagentSpec = (input) => {
6512
+ const subagentMiddleware = [
6513
+ (0, langchain.todoListMiddleware)(),
6514
+ createFilesystemMiddleware({ backend }),
6515
+ createSummarizationMiddleware({
6516
+ backend,
6517
+ model
6518
+ }),
6519
+ createPatchToolCallsMiddleware(),
6520
+ ...input.skills != null && input.skills.length > 0 ? [createSkillsMiddleware({
6521
+ backend,
6522
+ sources: input.skills
6523
+ })] : [],
6524
+ ...input.middleware ?? [],
6525
+ ...cacheMiddleware
6526
+ ];
6305
6527
  return {
6306
- ...subagent,
6307
- middleware: [subagentSkillsMiddleware, ...subagent.middleware || []]
6528
+ ...input,
6529
+ tools: input.tools ?? [],
6530
+ middleware: subagentMiddleware
6308
6531
  };
6309
- });
6310
- /**
6311
- * Middleware for custom subagents (does NOT include skills from main agent).
6312
- * Custom subagents must define their own `skills` property to get skills.
6313
- *
6314
- * Uses createSummarizationMiddleware (deepagents version) with backend support
6315
- * and auto-computed defaults from model profile, matching Python's create_deep_agent.
6316
- * When trigger is not provided, defaults are lazily computed:
6317
- * - With model profile: fraction-based (trigger=0.85, keep=0.10)
6318
- * - Without profile: fixed (trigger=170k tokens, keep=6 messages)
6319
- */
6320
- const subagentMiddleware = [
6532
+ };
6533
+ const allSubagents = subagents;
6534
+ const asyncSubAgents = allSubagents.filter((item) => isAsyncSubAgent(item));
6535
+ const inlineSubagents = allSubagents.filter((item) => !isAsyncSubAgent(item)).map((item) => "runnable" in item ? item : normalizeSubagentSpec(item));
6536
+ if (!inlineSubagents.some((item) => item.name === GENERAL_PURPOSE_SUBAGENT["name"])) {
6537
+ const generalPurposeSpec = normalizeSubagentSpec({
6538
+ ...GENERAL_PURPOSE_SUBAGENT,
6539
+ model,
6540
+ skills,
6541
+ tools
6542
+ });
6543
+ inlineSubagents.unshift(generalPurposeSpec);
6544
+ }
6545
+ const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
6546
+ backend,
6547
+ sources: skills
6548
+ })] : [];
6549
+ const [todoMiddleware, fsMiddleware, subagentMiddleware, summarizationMiddleware, patchToolCallsMiddleware] = [
6321
6550
  (0, langchain.todoListMiddleware)(),
6322
- createFilesystemMiddleware({ backend: filesystemBackend }),
6551
+ createFilesystemMiddleware({ backend }),
6552
+ createSubAgentMiddleware({
6553
+ defaultModel: model,
6554
+ defaultTools: tools,
6555
+ defaultInterruptOn: interruptOn,
6556
+ subagents: inlineSubagents,
6557
+ generalPurposeAgent: false
6558
+ }),
6323
6559
  createSummarizationMiddleware({
6324
6560
  model,
6325
- backend: filesystemBackend
6561
+ backend
6326
6562
  }),
6327
6563
  createPatchToolCallsMiddleware()
6328
6564
  ];
6565
+ const middleware = [
6566
+ todoMiddleware,
6567
+ ...skillsMiddleware,
6568
+ fsMiddleware,
6569
+ subagentMiddleware,
6570
+ summarizationMiddleware,
6571
+ patchToolCallsMiddleware,
6572
+ ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : [],
6573
+ ...customMiddleware,
6574
+ ...cacheMiddleware,
6575
+ ...memory && memory.length > 0 ? [createMemoryMiddleware({
6576
+ backend,
6577
+ sources: memory,
6578
+ addCacheControl: anthropicModel
6579
+ })] : [],
6580
+ ...interruptOn ? [(0, langchain.humanInTheLoopMiddleware)({ interruptOn })] : []
6581
+ ];
6329
6582
  /**
6330
6583
  * Return as DeepAgent with proper DeepAgentTypeConfig
6331
6584
  * - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)
@@ -6337,55 +6590,32 @@ function createDeepAgent(params = {}) {
6337
6590
  */
6338
6591
  return (0, langchain.createAgent)({
6339
6592
  model,
6340
- systemPrompt: finalSystemPrompt,
6593
+ systemPrompt: typeof systemPrompt === "string" ? new langchain.SystemMessage({ contentBlocks: [{
6594
+ type: "text",
6595
+ text: systemPrompt
6596
+ }, {
6597
+ type: "text",
6598
+ text: BASE_AGENT_PROMPT
6599
+ }] }) : langchain.SystemMessage.isInstance(systemPrompt) ? new langchain.SystemMessage({ contentBlocks: [...systemPrompt.contentBlocks, {
6600
+ type: "text",
6601
+ text: BASE_AGENT_PROMPT
6602
+ }] }) : new langchain.SystemMessage({ contentBlocks: [{
6603
+ type: "text",
6604
+ text: BASE_AGENT_PROMPT
6605
+ }] }),
6341
6606
  tools,
6342
- middleware: [
6343
- ...[
6344
- (0, langchain.todoListMiddleware)(),
6345
- createFilesystemMiddleware({ backend: filesystemBackend }),
6346
- createSubAgentMiddleware({
6347
- defaultModel: model,
6348
- defaultTools: tools,
6349
- defaultMiddleware: [...subagentMiddleware, ...anthropicModel ? [(0, langchain.anthropicPromptCachingMiddleware)({
6350
- unsupportedModelBehavior: "ignore",
6351
- minMessagesToCache: 1
6352
- }), createCacheBreakpointMiddleware()] : []],
6353
- generalPurposeMiddleware: [
6354
- ...subagentMiddleware,
6355
- ...skillsMiddlewareArray,
6356
- ...anthropicModel ? [(0, langchain.anthropicPromptCachingMiddleware)({
6357
- unsupportedModelBehavior: "ignore",
6358
- minMessagesToCache: 1
6359
- }), createCacheBreakpointMiddleware()] : []
6360
- ],
6361
- defaultInterruptOn: interruptOn,
6362
- subagents: processedSubagents,
6363
- generalPurposeAgent: true
6364
- }),
6365
- createSummarizationMiddleware({
6366
- model,
6367
- backend: filesystemBackend
6368
- }),
6369
- createPatchToolCallsMiddleware()
6370
- ],
6371
- ...skillsMiddlewareArray,
6372
- ...customMiddleware,
6373
- ...anthropicModel ? [(0, langchain.anthropicPromptCachingMiddleware)({
6374
- unsupportedModelBehavior: "ignore",
6375
- minMessagesToCache: 1
6376
- }), createCacheBreakpointMiddleware()] : [],
6377
- ...memoryMiddlewareArray,
6378
- ...interruptOn ? [(0, langchain.humanInTheLoopMiddleware)({ interruptOn })] : [],
6379
- ...asyncSubAgents && asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
6380
- ],
6381
- ...responseFormat != null && { responseFormat },
6607
+ middleware,
6608
+ ...responseFormat !== null && { responseFormat },
6382
6609
  contextSchema,
6383
6610
  checkpointer,
6384
6611
  store,
6385
6612
  name
6386
6613
  }).withConfig({
6387
6614
  recursionLimit: 1e4,
6388
- metadata: { ls_integration: "deepagents" }
6615
+ metadata: {
6616
+ ls_integration: "deepagents",
6617
+ lc_agent_name: name
6618
+ }
6389
6619
  });
6390
6620
  }
6391
6621
  //#endregion
@@ -6920,7 +7150,7 @@ exports.adaptSandboxProtocol = adaptSandboxProtocol;
6920
7150
  exports.computeSummarizationDefaults = computeSummarizationDefaults;
6921
7151
  exports.createAgentMemoryMiddleware = createAgentMemoryMiddleware;
6922
7152
  exports.createAsyncSubAgentMiddleware = createAsyncSubAgentMiddleware;
6923
- exports.createCompletionNotifierMiddleware = createCompletionNotifierMiddleware;
7153
+ exports.createCompletionCallbackMiddleware = createCompletionCallbackMiddleware;
6924
7154
  exports.createDeepAgent = createDeepAgent;
6925
7155
  exports.createFilesystemMiddleware = createFilesystemMiddleware;
6926
7156
  exports.createMemoryMiddleware = createMemoryMiddleware;
@@ -6936,5 +7166,6 @@ exports.isSandboxBackend = isSandboxBackend;
6936
7166
  exports.isSandboxProtocol = isSandboxProtocol;
6937
7167
  exports.listSkills = listSkills;
6938
7168
  exports.parseSkillMetadata = parseSkillMetadata;
7169
+ exports.resolveBackend = resolveBackend;
6939
7170
 
6940
7171
  //# sourceMappingURL=index.cjs.map