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.js CHANGED
@@ -1,10 +1,11 @@
1
- import { AIMessage, HumanMessage, SystemMessage, ToolMessage, anthropicPromptCachingMiddleware, countTokensApproximately, createAgent, createMiddleware, humanInTheLoopMiddleware, todoListMiddleware, tool } from "langchain";
2
- import { Runnable } from "@langchain/core/runnables";
3
- import { Command, REMOVE_ALL_MESSAGES, ReducedValue, StateSchema, getCurrentTaskInput, isCommand } from "@langchain/langgraph";
1
+ import { AIMessage, HumanMessage, SystemMessage, ToolMessage, anthropicPromptCachingMiddleware, context, countTokensApproximately, createAgent, createMiddleware, humanInTheLoopMiddleware, todoListMiddleware, tool } from "langchain";
2
+ import { ChatAnthropic } from "@langchain/anthropic";
3
+ import { Command, REMOVE_ALL_MESSAGES, ReducedValue, StateSchema, getConfig, getCurrentTaskInput, getStore, isCommand } from "@langchain/langgraph";
4
4
  import { z } from "zod/v4";
5
5
  import micromatch from "micromatch";
6
6
  import path, { basename } from "path";
7
- import { HumanMessage as HumanMessage$1, RemoveMessage, getBufferString } from "@langchain/core/messages";
7
+ import { AIMessage as AIMessage$1, HumanMessage as HumanMessage$1, RemoveMessage, getBufferString } from "@langchain/core/messages";
8
+ import * as z$2 from "zod";
8
9
  import { z as z$1 } from "zod";
9
10
  import yaml from "yaml";
10
11
  import { Client } from "@langchain/langgraph-sdk";
@@ -17,78 +18,6 @@ import cp, { spawn } from "node:child_process";
17
18
  import fg from "fast-glob";
18
19
  import { LangSmithResourceNotFoundError, LangSmithSandboxError, SandboxClient } from "langsmith/experimental/sandbox";
19
20
  import os from "node:os";
20
- //#region src/backends/protocol.ts
21
- /**
22
- * Type guard to check if a backend supports execution.
23
- *
24
- * @param backend - Backend instance to check
25
- * @returns True if the backend implements SandboxBackendProtocolV2
26
- */
27
- function isSandboxBackend(backend) {
28
- return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
29
- }
30
- /**
31
- * Type guard to check if a backend is a sandbox protocol (v1 or v2).
32
- *
33
- * Checks for the presence of `execute` function and `id` string,
34
- * which are the defining features of sandbox protocols.
35
- *
36
- * @param backend - Backend instance to check
37
- * @returns True if the backend implements sandbox protocol (v1 or v2)
38
- */
39
- function isSandboxProtocol(backend) {
40
- return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
41
- }
42
- const SANDBOX_ERROR_SYMBOL = Symbol.for("sandbox.error");
43
- /**
44
- * Custom error class for sandbox operations.
45
- *
46
- * @param message - Human-readable error description
47
- * @param code - Structured error code for programmatic handling
48
- * @returns SandboxError with message and code
49
- *
50
- * @example
51
- * ```typescript
52
- * try {
53
- * await sandbox.execute("some command");
54
- * } catch (error) {
55
- * if (error instanceof SandboxError) {
56
- * switch (error.code) {
57
- * case "NOT_INITIALIZED":
58
- * await sandbox.initialize();
59
- * break;
60
- * case "COMMAND_TIMEOUT":
61
- * console.error("Command took too long");
62
- * break;
63
- * default:
64
- * throw error;
65
- * }
66
- * }
67
- * }
68
- * ```
69
- */
70
- var SandboxError = class SandboxError extends Error {
71
- /** Symbol for identifying sandbox error instances */
72
- [SANDBOX_ERROR_SYMBOL] = true;
73
- /** Error name for instanceof checks and logging */
74
- name = "SandboxError";
75
- /**
76
- * Creates a new SandboxError.
77
- *
78
- * @param message - Human-readable error description
79
- * @param code - Structured error code for programmatic handling
80
- */
81
- constructor(message, code, cause) {
82
- super(message);
83
- this.code = code;
84
- this.cause = cause;
85
- Object.setPrototypeOf(this, SandboxError.prototype);
86
- }
87
- static isInstance(error) {
88
- return typeof error === "object" && error !== null && error[SANDBOX_ERROR_SYMBOL] === true;
89
- }
90
- };
91
- //#endregion
92
21
  //#region src/backends/utils.ts
93
22
  /**
94
23
  * Shared utility functions for memory backend implementations.
@@ -98,7 +27,7 @@ var SandboxError = class SandboxError extends Error {
98
27
  * enable composition without fragile string parsing.
99
28
  */
100
29
  const EMPTY_CONTENT_WARNING = "System reminder: File exists but has empty contents";
101
- const MAX_LINE_LENGTH = 1e4;
30
+ const MAX_LINE_LENGTH = 5e3;
102
31
  const TOOL_RESULT_TOKEN_LIMIT = 2e4;
103
32
  const TRUNCATION_GUIDANCE = "... [results truncated, try being more specific with your parameters]";
104
33
  const MIME_TYPES = {
@@ -108,11 +37,26 @@ const MIME_TYPES = {
108
37
  ".gif": "image/gif",
109
38
  ".webp": "image/webp",
110
39
  ".svg": "image/svg+xml",
40
+ ".heic": "image/heic",
41
+ ".heif": "image/heif",
111
42
  ".mp3": "audio/mpeg",
112
43
  ".wav": "audio/wav",
44
+ ".aiff": "audio/aiff",
45
+ ".aac": "audio/aac",
46
+ ".ogg": "audio/ogg",
47
+ ".flac": "audio/flac",
113
48
  ".mp4": "video/mp4",
114
49
  ".webm": "video/webm",
115
- ".pdf": "application/pdf"
50
+ ".mpeg": "video/mpeg",
51
+ ".mov": "video/quicktime",
52
+ ".avi": "video/x-msvideo",
53
+ ".flv": "video/x-flv",
54
+ ".mpg": "video/mpeg",
55
+ ".wmv": "video/x-ms-wmv",
56
+ ".3gpp": "video/3gpp",
57
+ ".pdf": "application/pdf",
58
+ ".ppt": "application/vnd.ms-powerpoint",
59
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
116
60
  };
117
61
  /**
118
62
  * Sanitize tool_call_id to prevent path traversal and separator issues.
@@ -141,7 +85,7 @@ function formatContentWithLineNumbers(content, startLine = 1) {
141
85
  for (let i = 0; i < lines.length; i++) {
142
86
  const line = lines[i];
143
87
  const lineNum = i + startLine;
144
- if (line.length <= 1e4) resultLines.push(`${lineNum.toString().padStart(6)}\t${line}`);
88
+ if (line.length <= 5e3) resultLines.push(`${lineNum.toString().padStart(6)}\t${line}`);
145
89
  else {
146
90
  const numChunks = Math.ceil(line.length / MAX_LINE_LENGTH);
147
91
  for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
@@ -506,7 +450,96 @@ function adaptSandboxProtocol(sandbox) {
506
450
  return adapted;
507
451
  }
508
452
  //#endregion
453
+ //#region src/backends/protocol.ts
454
+ /**
455
+ * Type guard to check if a backend supports execution.
456
+ *
457
+ * @param backend - Backend instance to check
458
+ * @returns True if the backend implements SandboxBackendProtocolV2
459
+ */
460
+ function isSandboxBackend(backend) {
461
+ return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
462
+ }
463
+ /**
464
+ * Type guard to check if a backend is a sandbox protocol (v1 or v2).
465
+ *
466
+ * Checks for the presence of `execute` function and `id` string,
467
+ * which are the defining features of sandbox protocols.
468
+ *
469
+ * @param backend - Backend instance to check
470
+ * @returns True if the backend implements sandbox protocol (v1 or v2)
471
+ */
472
+ function isSandboxProtocol(backend) {
473
+ return backend != null && typeof backend === "object" && typeof backend.execute === "function" && typeof backend.id === "string" && backend.id !== "";
474
+ }
475
+ const SANDBOX_ERROR_SYMBOL = Symbol.for("sandbox.error");
476
+ /**
477
+ * Custom error class for sandbox operations.
478
+ *
479
+ * @param message - Human-readable error description
480
+ * @param code - Structured error code for programmatic handling
481
+ * @returns SandboxError with message and code
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * try {
486
+ * await sandbox.execute("some command");
487
+ * } catch (error) {
488
+ * if (error instanceof SandboxError) {
489
+ * switch (error.code) {
490
+ * case "NOT_INITIALIZED":
491
+ * await sandbox.initialize();
492
+ * break;
493
+ * case "COMMAND_TIMEOUT":
494
+ * console.error("Command took too long");
495
+ * break;
496
+ * default:
497
+ * throw error;
498
+ * }
499
+ * }
500
+ * }
501
+ * ```
502
+ */
503
+ var SandboxError = class SandboxError extends Error {
504
+ /** Symbol for identifying sandbox error instances */
505
+ [SANDBOX_ERROR_SYMBOL] = true;
506
+ /** Error name for instanceof checks and logging */
507
+ name = "SandboxError";
508
+ /**
509
+ * Creates a new SandboxError.
510
+ *
511
+ * @param message - Human-readable error description
512
+ * @param code - Structured error code for programmatic handling
513
+ */
514
+ constructor(message, code, cause) {
515
+ super(message);
516
+ this.code = code;
517
+ this.cause = cause;
518
+ Object.setPrototypeOf(this, SandboxError.prototype);
519
+ }
520
+ static isInstance(error) {
521
+ return typeof error === "object" && error !== null && error[SANDBOX_ERROR_SYMBOL] === true;
522
+ }
523
+ };
524
+ /**
525
+ * Resolve a backend instance or await a {@link BackendFactory}.
526
+ *
527
+ * Accepts {@link BackendRuntime} or {@link ToolRuntime} — store typing differs
528
+ * between LangGraph checkpoint stores and core `ToolRuntime`; factories receive
529
+ * a value that is structurally compatible at runtime.
530
+ *
531
+ * @internal
532
+ */
533
+ async function resolveBackend(backend, runtime) {
534
+ if (typeof backend === "function") {
535
+ const resolved = await backend(runtime);
536
+ return isSandboxProtocol(resolved) ? adaptSandboxProtocol(resolved) : adaptBackendProtocol(resolved);
537
+ }
538
+ return isSandboxProtocol(backend) ? adaptSandboxProtocol(backend) : adaptBackendProtocol(backend);
539
+ }
540
+ //#endregion
509
541
  //#region src/backends/state.ts
542
+ const PREGEL_SEND_KEY = "__pregel_send";
510
543
  /**
511
544
  * Backend that stores files in agent state (ephemeral).
512
545
  *
@@ -519,17 +552,52 @@ function adaptSandboxProtocol(sandbox) {
519
552
  * for the middleware to apply via Command.
520
553
  */
521
554
  var StateBackend = class {
522
- stateAndStore;
555
+ runtime;
523
556
  fileFormat;
524
- constructor(stateAndStore, options) {
525
- this.stateAndStore = stateAndStore;
526
- this.fileFormat = options?.fileFormat ?? "v2";
557
+ constructor(runtimeOrOptions, options) {
558
+ if (runtimeOrOptions != null && typeof runtimeOrOptions === "object" && "state" in runtimeOrOptions) {
559
+ this.runtime = runtimeOrOptions;
560
+ this.fileFormat = options?.fileFormat ?? "v2";
561
+ } else {
562
+ this.runtime = void 0;
563
+ this.fileFormat = runtimeOrOptions?.fileFormat ?? "v2";
564
+ }
565
+ }
566
+ /**
567
+ * Whether this instance was constructed with the legacy factory pattern.
568
+ *
569
+ * When true, state is read from the injected `runtime` and `filesUpdate`
570
+ * is returned to the caller. When false, state is read from LangGraph's
571
+ * execution context and updates are sent via `__pregel_send`.
572
+ */
573
+ get isLegacy() {
574
+ return this.runtime !== void 0;
527
575
  }
528
576
  /**
529
577
  * Get files from current state.
578
+ *
579
+ * In legacy mode, reads from the injected {@link BackendRuntime}.
580
+ * In zero-arg mode, reads from the LangGraph execution context via
581
+ * {@link getCurrentTaskInput}.
530
582
  */
531
583
  getFiles() {
532
- return this.stateAndStore.state.files || {};
584
+ if (this.runtime) return this.runtime.state.files || {};
585
+ return getCurrentTaskInput()?.files || {};
586
+ }
587
+ /**
588
+ * Push a files state update through LangGraph's internal send channel.
589
+ *
590
+ * In zero-arg mode, sends the update via the `__pregel_send` function
591
+ * from {@link getConfig}, mirroring Python's `CONFIG_KEY_SEND`.
592
+ * In legacy mode, this is a no-op — the caller uses `filesUpdate`
593
+ * from the return value instead.
594
+ *
595
+ * @param update - Map of file paths to their updated {@link FileData}
596
+ */
597
+ sendFilesUpdate(update) {
598
+ if (this.isLegacy) return;
599
+ const send = getConfig().configurable?.[PREGEL_SEND_KEY];
600
+ if (typeof send === "function") send([["files", update]]);
533
601
  }
534
602
  /**
535
603
  * List files and directories in the specified directory (non-recursive).
@@ -612,6 +680,11 @@ var StateBackend = class {
612
680
  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.` };
613
681
  const mimeType = getMimeType(filePath);
614
682
  const newFileData = createFileData(content, void 0, this.fileFormat, mimeType);
683
+ const update = { [filePath]: newFileData };
684
+ if (!this.isLegacy) {
685
+ this.sendFilesUpdate(update);
686
+ return { path: filePath };
687
+ }
615
688
  return {
616
689
  path: filePath,
617
690
  filesUpdate: { [filePath]: newFileData }
@@ -628,6 +701,14 @@ var StateBackend = class {
628
701
  if (typeof result === "string") return { error: result };
629
702
  const [newContent, occurrences] = result;
630
703
  const newFileData = updateFileData(fileData, newContent);
704
+ const update = { [filePath]: newFileData };
705
+ if (!this.isLegacy) {
706
+ this.sendFilesUpdate(update);
707
+ return {
708
+ path: filePath,
709
+ occurrences
710
+ };
711
+ }
631
712
  return {
632
713
  path: filePath,
633
714
  filesUpdate: { [filePath]: newFileData },
@@ -688,6 +769,10 @@ var StateBackend = class {
688
769
  error: "invalid_path"
689
770
  });
690
771
  }
772
+ if (!this.isLegacy) {
773
+ if (Object.keys(updates).length > 0) this.sendFilesUpdate(updates);
774
+ return responses;
775
+ }
691
776
  const result = responses;
692
777
  result.filesUpdate = updates;
693
778
  return result;
@@ -737,6 +822,7 @@ var StateBackend = class {
737
822
  * - Pluggable backends (StateBackend, StoreBackend, FilesystemBackend, CompositeBackend)
738
823
  * - Tool result eviction for large outputs
739
824
  */
825
+ const INT_FORMATTER = new Intl.NumberFormat("en-US");
740
826
  /**
741
827
  * Tools that should be excluded from the large result eviction logic.
742
828
  *
@@ -798,17 +884,75 @@ const READ_FILE_TRUNCATION_MSG = `
798
884
  /**
799
885
  * Message template for evicted tool results.
800
886
  */
801
- 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}
802
- 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.
803
- You can do this by specifying an offset and limit in the read_file tool call.
804
- For example, to read the first 100 lines, you can use the read_file tool with offset=0 and limit=100.
887
+ const TOO_LARGE_TOOL_MSG = context`
888
+ Tool result too large, the result of this tool call {tool_call_id} was saved in the filesystem at this path: {file_path}
889
+ 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.
890
+ You can do this by specifying an offset and limit in the read_file tool call.
891
+ For example, to read the first 100 lines, you can use the read_file tool with offset=0 and limit=100.
892
+
893
+ Here is a preview showing the head and tail of the result (lines of the form
894
+ ... [N lines truncated] ...
895
+ indicate omitted lines in the middle of the content):
896
+
897
+ {content_sample}
898
+ `;
899
+ /**
900
+ * Message template for evicted HumanMessages.
901
+ */
902
+ const TOO_LARGE_HUMAN_MSG = `Message content too large and was saved to the filesystem at: {file_path}
903
+
904
+ You can read the full content using the read_file tool with pagination (offset and limit parameters).
805
905
 
806
- Here is a preview showing the head and tail of the result (lines of the form
807
- ... [N lines truncated] ...
808
- indicate omitted lines in the middle of the content):
906
+ Here is a preview showing the head and tail of the content:
809
907
 
810
908
  {content_sample}`;
811
909
  /**
910
+ * Extract text content from a message.
911
+ *
912
+ * For string content, returns it directly. For array content (mixed block types
913
+ * like text + image), joins all text blocks. Returns empty string if no text found.
914
+ */
915
+ function extractTextFromMessage(message) {
916
+ if (typeof message.content === "string") return message.content;
917
+ if (Array.isArray(message.content)) return message.content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
918
+ return String(message.content);
919
+ }
920
+ /**
921
+ * Build replacement content for an evicted HumanMessage, preserving non-text blocks.
922
+ *
923
+ * For plain string content, returns the replacement text directly. For list content
924
+ * with mixed block types (e.g., text + image), replaces all text blocks with a single
925
+ * text block containing the replacement text while keeping non-text blocks intact.
926
+ */
927
+ function buildEvictedHumanContent(message, replacementText) {
928
+ if (typeof message.content === "string") return replacementText;
929
+ if (Array.isArray(message.content)) {
930
+ const mediaBlocks = message.content.filter((block) => typeof block === "object" && block !== null && block.type !== "text");
931
+ if (mediaBlocks.length === 0) return replacementText;
932
+ return [{
933
+ type: "text",
934
+ text: replacementText
935
+ }, ...mediaBlocks];
936
+ }
937
+ return replacementText;
938
+ }
939
+ /**
940
+ * Build a truncated HumanMessage for the model request.
941
+ *
942
+ * Computes a preview from the full content still in state and returns a
943
+ * lightweight replacement the model will see. Pure string computation — no
944
+ * backend I/O.
945
+ */
946
+ function buildTruncatedHumanMessage(message, filePath) {
947
+ const contentSample = createContentPreview(extractTextFromMessage(message));
948
+ return new HumanMessage({
949
+ content: buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample)),
950
+ id: message.id,
951
+ additional_kwargs: { ...message.additional_kwargs },
952
+ response_metadata: { ...message.response_metadata }
953
+ });
954
+ }
955
+ /**
812
956
  * Create a preview of content showing head and tail with truncation marker.
813
957
  *
814
958
  * @param contentStr - The full content string to preview.
@@ -883,138 +1027,148 @@ const FilesystemStateSchema = new StateSchema({ files: new ReducedValue(z.record
883
1027
  inputSchema: z.record(z.string(), FileDataSchema.nullable()).optional(),
884
1028
  reducer: fileDataReducer
885
1029
  }) });
886
- /**
887
- * Resolve backend from factory or instance.
888
- *
889
- * @param backend - Backend instance or factory function
890
- * @param stateAndStore - State and store container for backend initialization
891
- */
892
- function getBackend(backend, stateAndStore) {
893
- const actualBackend = typeof backend === "function" ? backend(stateAndStore) : backend;
894
- return isSandboxProtocol(actualBackend) ? adaptSandboxProtocol(actualBackend) : adaptBackendProtocol(actualBackend);
895
- }
896
- const FILESYSTEM_SYSTEM_PROMPT = `## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
1030
+ const FILESYSTEM_SYSTEM_PROMPT = context`
1031
+ ## Following Conventions
897
1032
 
898
- You have access to a filesystem which you can interact with using these tools.
899
- All file paths must start with a /.
1033
+ - Read files before editing understand existing content before making changes
1034
+ - Mimic existing style, naming conventions, and patterns
900
1035
 
901
- - ls: list files in a directory (requires absolute path)
902
- - read_file: read a file from the filesystem
903
- - write_file: write to a file in the filesystem
904
- - edit_file: edit a file in the filesystem
905
- - glob: find files matching a pattern (e.g., "**/*.py")
906
- - grep: search for text within files`;
907
- const LS_TOOL_DESCRIPTION = `Lists all files in a directory.
1036
+ ## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
908
1037
 
909
- This is useful for exploring the filesystem and finding the right file to read or edit.
910
- You should almost ALWAYS use this tool before using the read_file or edit_file tools.`;
911
- const READ_FILE_TOOL_DESCRIPTION = `Reads a file from the filesystem.
1038
+ You have access to a filesystem which you can interact with using these tools.
1039
+ All file paths must start with a /.
912
1040
 
913
- 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.
1041
+ - ls: list files in a directory (requires absolute path)
1042
+ - read_file: read a file from the filesystem
1043
+ - write_file: write to a file in the filesystem
1044
+ - edit_file: edit a file in the filesystem
1045
+ - glob: find files matching a pattern (e.g., "**/*.py")
1046
+ - grep: search for text within files
1047
+ `;
1048
+ const LS_TOOL_DESCRIPTION = context`
1049
+ Lists all files in a directory.
914
1050
 
915
- Usage:
916
- - By default, it reads up to 100 lines starting from the beginning of the file
917
- - **IMPORTANT for large files and codebase exploration**: Use pagination with offset and limit parameters to avoid context overflow
918
- - First scan: read_file(path, limit=100) to see file structure
919
- - Read more sections: read_file(path, offset=100, limit=200) for next 200 lines
920
- - Only omit limit (read full file) when necessary for editing
921
- - Specify offset and limit: read_file(path, offset=0, limit=100) reads first 100 lines
922
- - Results are returned using cat -n format, with line numbers starting at 1
923
- - 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.
924
- - 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.
925
- - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
926
- - You should ALWAYS make sure a file has been read before editing it.`;
927
- const WRITE_FILE_TOOL_DESCRIPTION = `Writes to a new file in the filesystem.
1051
+ This is useful for exploring the filesystem and finding the right file to read or edit.
1052
+ You should almost ALWAYS use this tool before using the read_file or edit_file tools.
1053
+ `;
1054
+ const READ_FILE_TOOL_DESCRIPTION = context`
1055
+ Reads a file from the filesystem.
1056
+
1057
+ 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.
928
1058
 
929
- Usage:
930
- - The write_file tool will create a new file.
931
- - Prefer to edit existing files (with the edit_file tool) over creating new ones when possible.`;
932
- const EDIT_FILE_TOOL_DESCRIPTION = `Performs exact string replacements in files.
1059
+ Usage:
1060
+ - By default, it reads up to 100 lines starting from the beginning of the file
1061
+ - **IMPORTANT for large files and codebase exploration**: Use pagination with offset and limit parameters to avoid context overflow
1062
+ - First scan: read_file(path, limit=100) to see file structure
1063
+ - Read more sections: read_file(path, offset=100, limit=200) for next 200 lines
1064
+ - Only omit limit (read full file) when necessary for editing
1065
+ - Specify offset and limit: read_file(path, offset=0, limit=100) reads first 100 lines
1066
+ - Results are returned using cat -n format, with line numbers starting at 1
1067
+ - 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.
1068
+ - 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.
1069
+ - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
1070
+ - You should ALWAYS make sure a file has been read before editing it.
1071
+ `;
1072
+ const WRITE_FILE_TOOL_DESCRIPTION = context`
1073
+ Writes to a new file in the filesystem.
1074
+
1075
+ Usage:
1076
+ - The write_file tool will create a new file.
1077
+ - Prefer to edit existing files (with the edit_file tool) over creating new ones when possible.
1078
+ `;
1079
+ const EDIT_FILE_TOOL_DESCRIPTION = context`
1080
+ Performs exact string replacements in files.
933
1081
 
934
- Usage:
935
- - You must read the file before editing. This tool will error if you attempt an edit without reading the file first.
936
- - When editing, preserve the exact indentation (tabs/spaces) from the read output. Never include line number prefixes in old_string or new_string.
937
- - ALWAYS prefer editing existing files over creating new ones.
938
- - Only use emojis if the user explicitly requests it.`;
939
- const GLOB_TOOL_DESCRIPTION = `Find files matching a glob pattern.
1082
+ Usage:
1083
+ - You must read the file before editing. This tool will error if you attempt an edit without reading the file first.
1084
+ - When editing, preserve the exact indentation (tabs/spaces) from the read output. Never include line number prefixes in old_string or new_string.
1085
+ - ALWAYS prefer editing existing files over creating new ones.
1086
+ - Only use emojis if the user explicitly requests it.
1087
+ `;
1088
+ const GLOB_TOOL_DESCRIPTION = context`
1089
+ Find files matching a glob pattern.
940
1090
 
941
- Supports standard glob patterns: \`*\` (any characters), \`**\` (any directories), \`?\` (single character).
942
- Returns a list of absolute file paths that match the pattern.
1091
+ Supports standard glob patterns: \`*\` (any characters), \`**\` (any directories), \`?\` (single character).
1092
+ Returns a list of absolute file paths that match the pattern.
943
1093
 
944
- Examples:
945
- - \`**/*.py\` - Find all Python files
946
- - \`*.txt\` - Find all text files in root
947
- - \`/subdir/**/*.md\` - Find all markdown files under /subdir`;
948
- const GREP_TOOL_DESCRIPTION = `Search for a text pattern across files.
1094
+ Examples:
1095
+ - \`**/*.py\` - Find all Python files
1096
+ - \`*.txt\` - Find all text files in root
1097
+ - \`/subdir/**/*.md\` - Find all markdown files under /subdir
1098
+ `;
1099
+ const GREP_TOOL_DESCRIPTION = context`
1100
+ Search for a text pattern across files.
949
1101
 
950
- Searches for literal text (not regex) and returns matching files or content based on output_mode.
951
- Special characters like parentheses, brackets, pipes, etc. are treated as literal characters, not regex operators.
1102
+ Searches for literal text (not regex) and returns matching files or content based on output_mode.
1103
+ Special characters like parentheses, brackets, pipes, etc. are treated as literal characters, not regex operators.
952
1104
 
953
- Examples:
954
- - Search all files: \`grep(pattern="TODO")\`
955
- - Search Python files only: \`grep(pattern="import", glob="*.py")\`
956
- - Show matching lines: \`grep(pattern="error", output_mode="content")\`
957
- - Search for code with special chars: \`grep(pattern="def __init__(self):")\``;
958
- const EXECUTE_TOOL_DESCRIPTION = `Executes a shell command in an isolated sandbox environment.
1105
+ Examples:
1106
+ - Search all files: \`grep(pattern="TODO")\`
1107
+ - Search Python files only: \`grep(pattern="import", glob="*.py")\`
1108
+ - Show matching lines: \`grep(pattern="error", output_mode="content")\`
1109
+ - Search for code with special chars: \`grep(pattern="def __init__(self):")\`
1110
+ `;
1111
+ const EXECUTE_TOOL_DESCRIPTION = context`
1112
+ Executes a shell command in an isolated sandbox environment.
959
1113
 
960
- Usage:
961
- Executes a given command in the sandbox environment with proper handling and security measures.
962
- Before executing the command, please follow these steps:
1114
+ Usage:
1115
+ Executes a given command in the sandbox environment with proper handling and security measures.
1116
+ Before executing the command, please follow these steps:
963
1117
 
964
- 1. Directory Verification:
965
- - 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
966
- - For example, before running "mkdir foo/bar", first use ls to check that "foo" exists and is the intended parent directory
1118
+ 1. Directory Verification:
1119
+ - 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
1120
+ - For example, before running "mkdir foo/bar", first use ls to check that "foo" exists and is the intended parent directory
967
1121
 
968
- 2. Command Execution:
969
- - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
970
- - Examples of proper quoting:
971
- - cd "/Users/name/My Documents" (correct)
972
- - cd /Users/name/My Documents (incorrect - will fail)
973
- - python "/path/with spaces/script.py" (correct)
974
- - python /path/with spaces/script.py (incorrect - will fail)
975
- - After ensuring proper quoting, execute the command
976
- - Capture the output of the command
1122
+ 2. Command Execution:
1123
+ - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
1124
+ - Examples of proper quoting:
1125
+ - cd "/Users/name/My Documents" (correct)
1126
+ - cd /Users/name/My Documents (incorrect - will fail)
1127
+ - python "/path/with spaces/script.py" (correct)
1128
+ - python /path/with spaces/script.py (incorrect - will fail)
1129
+ - After ensuring proper quoting, execute the command
1130
+ - Capture the output of the command
977
1131
 
978
- Usage notes:
979
- - Commands run in an isolated sandbox environment
980
- - Returns combined stdout/stderr output with exit code
981
- - If the output is very large, it may be truncated
982
- - 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.
983
- - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings)
984
- - Use '&&' when commands depend on each other (e.g., "mkdir dir && cd dir")
985
- - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
986
- - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd
1132
+ Usage notes:
1133
+ - Commands run in an isolated sandbox environment
1134
+ - Returns combined stdout/stderr output with exit code
1135
+ - If the output is very large, it may be truncated
1136
+ - 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.
1137
+ - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings)
1138
+ - Use '&&' when commands depend on each other (e.g., "mkdir dir && cd dir")
1139
+ - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
1140
+ - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of cd
987
1141
 
988
- Examples:
989
- Good examples:
990
- - execute(command="pytest /foo/bar/tests")
991
- - execute(command="python /path/to/script.py")
992
- - execute(command="npm install && npm test")
1142
+ Examples:
1143
+ Good examples:
1144
+ - execute(command="pytest /foo/bar/tests")
1145
+ - execute(command="python /path/to/script.py")
1146
+ - execute(command="npm install && npm test")
993
1147
 
994
- Bad examples (avoid these):
995
- - execute(command="cd /foo/bar && pytest tests") # Use absolute path instead
996
- - execute(command="cat file.txt") # Use read_file tool instead
997
- - execute(command="find . -name '*.py'") # Use glob tool instead
998
- - execute(command="grep -r 'pattern' .") # Use grep tool instead
1148
+ Bad examples (avoid these):
1149
+ - execute(command="cd /foo/bar && pytest tests") # Use absolute path instead
1150
+ - execute(command="cat file.txt") # Use read_file tool instead
1151
+ - execute(command="find . -name '*.py'") # Use glob tool instead
1152
+ - execute(command="grep -r 'pattern' .") # Use grep tool instead
999
1153
 
1000
- Note: This tool is only available if the backend supports execution (SandboxBackendProtocol).
1001
- If execution is not supported, the tool will return an error message.`;
1002
- const EXECUTION_SYSTEM_PROMPT = `## Execute Tool \`execute\`
1154
+ Note: This tool is only available if the backend supports execution (SandboxBackendProtocol).
1155
+ If execution is not supported, the tool will return an error message.
1156
+ `;
1157
+ const EXECUTION_SYSTEM_PROMPT = context`
1158
+ ## Execute Tool \`execute\`
1003
1159
 
1004
- You have access to an \`execute\` tool for running shell commands in a sandboxed environment.
1005
- Use this tool to run commands, scripts, tests, builds, and other shell operations.
1160
+ You have access to an \`execute\` tool for running shell commands in a sandboxed environment.
1161
+ Use this tool to run commands, scripts, tests, builds, and other shell operations.
1006
1162
 
1007
- - execute: run a shell command in the sandbox (returns output and exit code)`;
1163
+ - execute: run a shell command in the sandbox (returns output and exit code)
1164
+ `;
1008
1165
  /**
1009
1166
  * Create ls tool using backend.
1010
1167
  */
1011
1168
  function createLsTool(backend, options) {
1012
1169
  const { customDescription } = options;
1013
- return tool(async (input, config) => {
1014
- const resolvedBackend = getBackend(backend, {
1015
- state: getCurrentTaskInput(config),
1016
- store: config.store
1017
- });
1170
+ return tool(async (input, runtime) => {
1171
+ const resolvedBackend = await resolveBackend(backend, runtime);
1018
1172
  const path = input.path || "/";
1019
1173
  const lsResult = await resolvedBackend.ls(path);
1020
1174
  if (lsResult.error) return `Error listing files: ${lsResult.error}`;
@@ -1040,11 +1194,8 @@ function createLsTool(backend, options) {
1040
1194
  */
1041
1195
  function createReadFileTool(backend, options) {
1042
1196
  const { customDescription, toolTokenLimitBeforeEvict } = options;
1043
- return tool(async (input, config) => {
1044
- const resolvedBackend = getBackend(backend, {
1045
- state: getCurrentTaskInput(config),
1046
- store: config.store
1047
- });
1197
+ return tool(async (input, runtime) => {
1198
+ const resolvedBackend = await resolveBackend(backend, runtime);
1048
1199
  const { file_path, offset = 0, limit = 100 } = input;
1049
1200
  const readResult = await resolvedBackend.read(file_path, offset, limit);
1050
1201
  if (readResult.error) return [{
@@ -1119,17 +1270,14 @@ function createReadFileTool(backend, options) {
1119
1270
  */
1120
1271
  function createWriteFileTool(backend, options) {
1121
1272
  const { customDescription } = options;
1122
- return tool(async (input, config) => {
1123
- const resolvedBackend = getBackend(backend, {
1124
- state: getCurrentTaskInput(config),
1125
- store: config.store
1126
- });
1273
+ return tool(async (input, runtime) => {
1274
+ const resolvedBackend = await resolveBackend(backend, runtime);
1127
1275
  const { file_path, content } = input;
1128
1276
  const result = await resolvedBackend.write(file_path, content);
1129
1277
  if (result.error) return result.error;
1130
1278
  const message = new ToolMessage({
1131
1279
  content: `Successfully wrote to '${file_path}'`,
1132
- tool_call_id: config.toolCall?.id,
1280
+ tool_call_id: runtime.toolCall?.id,
1133
1281
  name: "write_file",
1134
1282
  metadata: result.metadata
1135
1283
  });
@@ -1152,17 +1300,14 @@ function createWriteFileTool(backend, options) {
1152
1300
  */
1153
1301
  function createEditFileTool(backend, options) {
1154
1302
  const { customDescription } = options;
1155
- return tool(async (input, config) => {
1156
- const resolvedBackend = getBackend(backend, {
1157
- state: getCurrentTaskInput(config),
1158
- store: config.store
1159
- });
1303
+ return tool(async (input, runtime) => {
1304
+ const resolvedBackend = await resolveBackend(backend, runtime);
1160
1305
  const { file_path, old_string, new_string, replace_all = false } = input;
1161
1306
  const result = await resolvedBackend.edit(file_path, old_string, new_string, replace_all);
1162
1307
  if (result.error) return result.error;
1163
1308
  const message = new ToolMessage({
1164
1309
  content: `Successfully replaced ${result.occurrences} occurrence(s) in '${file_path}'`,
1165
- tool_call_id: config.toolCall?.id,
1310
+ tool_call_id: runtime.toolCall?.id,
1166
1311
  name: "edit_file",
1167
1312
  metadata: result.metadata
1168
1313
  });
@@ -1187,11 +1332,8 @@ function createEditFileTool(backend, options) {
1187
1332
  */
1188
1333
  function createGlobTool(backend, options) {
1189
1334
  const { customDescription } = options;
1190
- return tool(async (input, config) => {
1191
- const resolvedBackend = getBackend(backend, {
1192
- state: getCurrentTaskInput(config),
1193
- store: config.store
1194
- });
1335
+ return tool(async (input, runtime) => {
1336
+ const resolvedBackend = await resolveBackend(backend, runtime);
1195
1337
  const { pattern, path = "/" } = input;
1196
1338
  const globResult = await resolvedBackend.glob(pattern, path);
1197
1339
  if (globResult.error) return `Error finding files: ${globResult.error}`;
@@ -1214,11 +1356,8 @@ function createGlobTool(backend, options) {
1214
1356
  */
1215
1357
  function createGrepTool(backend, options) {
1216
1358
  const { customDescription } = options;
1217
- return tool(async (input, config) => {
1218
- const resolvedBackend = getBackend(backend, {
1219
- state: getCurrentTaskInput(config),
1220
- store: config.store
1221
- });
1359
+ return tool(async (input, runtime) => {
1360
+ const resolvedBackend = await resolveBackend(backend, runtime);
1222
1361
  const { pattern, path = "/", glob = null } = input;
1223
1362
  const result = await resolvedBackend.grep(pattern, path, glob);
1224
1363
  if (result.error) return result.error;
@@ -1242,7 +1381,7 @@ function createGrepTool(backend, options) {
1242
1381
  schema: z.object({
1243
1382
  pattern: z.string().describe("Regex pattern to search for"),
1244
1383
  path: z.string().optional().default("/").describe("Base path to search from (default: /)"),
1245
- glob: z.string().optional().nullable().describe("Optional glob pattern to filter files (e.g., '*.py')")
1384
+ glob: z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')")
1246
1385
  })
1247
1386
  });
1248
1387
  }
@@ -1251,11 +1390,8 @@ function createGrepTool(backend, options) {
1251
1390
  */
1252
1391
  function createExecuteTool(backend, options) {
1253
1392
  const { customDescription } = options;
1254
- return tool(async (input, config) => {
1255
- const resolvedBackend = getBackend(backend, {
1256
- state: getCurrentTaskInput(config),
1257
- store: config.store
1258
- });
1393
+ return tool(async (input, runtime) => {
1394
+ const resolvedBackend = await resolveBackend(backend, runtime);
1259
1395
  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.";
1260
1396
  const result = await resolvedBackend.execute(input.command);
1261
1397
  const parts = [result.output];
@@ -1275,7 +1411,7 @@ function createExecuteTool(backend, options) {
1275
1411
  * Create filesystem middleware with all tools and features.
1276
1412
  */
1277
1413
  function createFilesystemMiddleware(options = {}) {
1278
- const { backend = (stateAndStore) => new StateBackend(stateAndStore), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4 } = options;
1414
+ const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4 } = options;
1279
1415
  const baseSystemPrompt = customSystemPrompt || FILESYSTEM_SYSTEM_PROMPT;
1280
1416
  const allToolsByName = {
1281
1417
  ls: createLsTool(backend, { customDescription: customToolDescriptions?.ls }),
@@ -1293,19 +1429,53 @@ function createFilesystemMiddleware(options = {}) {
1293
1429
  name: "FilesystemMiddleware",
1294
1430
  stateSchema: FilesystemStateSchema,
1295
1431
  tools: Object.values(allToolsByName),
1432
+ async beforeAgent(state) {
1433
+ if (!humanMessageTokenLimitBeforeEvict) return;
1434
+ const messages = state.messages;
1435
+ if (!messages || messages.length === 0) return;
1436
+ const last = messages[messages.length - 1];
1437
+ if (!HumanMessage.isInstance(last)) return;
1438
+ if (last.additional_kwargs?.lc_evicted_to) return;
1439
+ const contentStr = extractTextFromMessage(last);
1440
+ const threshold = 4 * humanMessageTokenLimitBeforeEvict;
1441
+ if (contentStr.length <= threshold) return;
1442
+ const resolvedBackend = await resolveBackend(backend, { state: state || {} });
1443
+ const filePath = `/conversation_history/${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
1444
+ const writeResult = await resolvedBackend.write(filePath, contentStr);
1445
+ if (writeResult.error) return;
1446
+ const result = { messages: [new HumanMessage({
1447
+ content: last.content,
1448
+ id: last.id,
1449
+ additional_kwargs: {
1450
+ ...last.additional_kwargs,
1451
+ lc_evicted_to: filePath
1452
+ },
1453
+ response_metadata: { ...last.response_metadata }
1454
+ })] };
1455
+ if (writeResult.filesUpdate) result.files = writeResult.filesUpdate;
1456
+ return result;
1457
+ },
1296
1458
  wrapModelCall: async (request, handler) => {
1297
- const supportsExecution = isSandboxBackend(getBackend(backend, {
1298
- state: request.state || {},
1299
- store: request.runtime?.store
1459
+ const supportsExecution = isSandboxBackend(await resolveBackend(backend, {
1460
+ ...request.runtime,
1461
+ state: request.state
1300
1462
  }));
1301
1463
  let tools = request.tools;
1302
1464
  if (!supportsExecution) tools = tools.filter((t) => t.name !== "execute");
1303
1465
  let filesystemPrompt = baseSystemPrompt;
1304
1466
  if (supportsExecution) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
1305
1467
  const newSystemMessage = request.systemMessage.concat(filesystemPrompt);
1468
+ let messages = request.messages;
1469
+ if (humanMessageTokenLimitBeforeEvict && messages) {
1470
+ if (messages.some((msg) => HumanMessage.isInstance(msg) && msg.additional_kwargs?.lc_evicted_to)) messages = messages.map((msg) => {
1471
+ if (HumanMessage.isInstance(msg) && msg.additional_kwargs?.lc_evicted_to) return buildTruncatedHumanMessage(msg, msg.additional_kwargs.lc_evicted_to);
1472
+ return msg;
1473
+ });
1474
+ }
1306
1475
  return handler({
1307
1476
  ...request,
1308
1477
  tools,
1478
+ messages,
1309
1479
  systemMessage: newSystemMessage
1310
1480
  });
1311
1481
  },
@@ -1316,9 +1486,9 @@ function createFilesystemMiddleware(options = {}) {
1316
1486
  const result = await handler(request);
1317
1487
  async function processToolMessage(msg, toolTokenLimitBeforeEvict) {
1318
1488
  if (typeof msg.content === "string" && msg.content.length > toolTokenLimitBeforeEvict * 4) {
1319
- const resolvedBackend = getBackend(backend, {
1320
- state: request.state || {},
1321
- store: request.runtime?.store
1489
+ const resolvedBackend = await resolveBackend(backend, {
1490
+ ...request.runtime,
1491
+ state: request.state
1322
1492
  });
1323
1493
  const evictPath = `/large_tool_results/${sanitizeToolCallId(request.toolCall?.id || msg.tool_call_id)}`;
1324
1494
  const writeResult = await resolvedBackend.write(evictPath, msg.content);
@@ -1411,117 +1581,117 @@ const EXCLUDED_STATE_KEYS = [
1411
1581
  */
1412
1582
  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.";
1413
1583
  function getTaskToolDescription(subagentDescriptions) {
1414
- return `
1415
- Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
1584
+ return context`
1585
+ Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
1416
1586
 
1417
- Available agent types and the tools they have access to:
1418
- ${subagentDescriptions.join("\n")}
1587
+ Available agent types and the tools they have access to:
1588
+ ${subagentDescriptions.join("\n")}
1419
1589
 
1420
- When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
1590
+ When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
1421
1591
 
1422
- ## Usage notes:
1423
- 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
1424
- 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.
1425
- 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.
1426
- 4. The agent's outputs should generally be trusted
1427
- 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
1428
- 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.
1429
- 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.
1592
+ ## Usage notes:
1593
+ 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
1594
+ 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.
1595
+ 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.
1596
+ 4. The agent's outputs should generally be trusted
1597
+ 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
1598
+ 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.
1599
+ 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.
1430
1600
 
1431
- ### Example usage of the general-purpose agent:
1601
+ ### Example usage of the general-purpose agent:
1432
1602
 
1433
- <example_agent_descriptions>
1434
- "general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.
1435
- </example_agent_descriptions>
1603
+ <example_agent_descriptions>
1604
+ "general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.
1605
+ </example_agent_descriptions>
1436
1606
 
1437
- <example>
1438
- User: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."
1439
- Assistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*
1440
- Assistant: *Synthesizes the results of the three isolated research tasks and responds to the User*
1441
- <commentary>
1442
- Research is a complex, multi-step task in it of itself.
1443
- The research of each individual player is not dependent on the research of the other players.
1444
- The assistant uses the task tool to break down the complex objective into three isolated tasks.
1445
- 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.
1446
- 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.
1447
- </commentary>
1448
- </example>
1607
+ <example>
1608
+ User: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."
1609
+ Assistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*
1610
+ Assistant: *Synthesizes the results of the three isolated research tasks and responds to the User*
1611
+ <commentary>
1612
+ Research is a complex, multi-step task in it of itself.
1613
+ The research of each individual player is not dependent on the research of the other players.
1614
+ The assistant uses the task tool to break down the complex objective into three isolated tasks.
1615
+ 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.
1616
+ 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.
1617
+ </commentary>
1618
+ </example>
1449
1619
 
1450
- <example>
1451
- User: "Analyze a single large code repository for security vulnerabilities and generate a report."
1452
- Assistant: *Launches a single \`task\` subagent for the repository analysis*
1453
- Assistant: *Receives report and integrates results into final summary*
1454
- <commentary>
1455
- 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.
1456
- 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.
1457
- </commentary>
1458
- </example>
1620
+ <example>
1621
+ User: "Analyze a single large code repository for security vulnerabilities and generate a report."
1622
+ Assistant: *Launches a single \`task\` subagent for the repository analysis*
1623
+ Assistant: *Receives report and integrates results into final summary*
1624
+ <commentary>
1625
+ 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.
1626
+ 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.
1627
+ </commentary>
1628
+ </example>
1459
1629
 
1460
- <example>
1461
- User: "Schedule two meetings for me and prepare agendas for each."
1462
- Assistant: *Calls the task tool in parallel to launch two \`task\` subagents (one per meeting) to prepare agendas*
1463
- Assistant: *Returns final schedules and agendas*
1464
- <commentary>
1465
- Tasks are simple individually, but subagents help silo agenda preparation.
1466
- Each subagent only needs to worry about the agenda for one meeting.
1467
- </commentary>
1468
- </example>
1630
+ <example>
1631
+ User: "Schedule two meetings for me and prepare agendas for each."
1632
+ Assistant: *Calls the task tool in parallel to launch two \`task\` subagents (one per meeting) to prepare agendas*
1633
+ Assistant: *Returns final schedules and agendas*
1634
+ <commentary>
1635
+ Tasks are simple individually, but subagents help silo agenda preparation.
1636
+ Each subagent only needs to worry about the agenda for one meeting.
1637
+ </commentary>
1638
+ </example>
1469
1639
 
1470
- <example>
1471
- User: "I want to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway."
1472
- Assistant: *Calls tools directly in parallel to order a pizza from Dominos, a burger from McDonald's, and a salad from Subway*
1473
- <commentary>
1474
- The assistant did not use the task tool because the objective is super simple and clear and only requires a few trivial tool calls.
1475
- It is better to just complete the task directly and NOT use the \`task\`tool.
1476
- </commentary>
1477
- </example>
1640
+ <example>
1641
+ User: "I want to order a pizza from Dominos, order a burger from McDonald's, and order a salad from Subway."
1642
+ Assistant: *Calls tools directly in parallel to order a pizza from Dominos, a burger from McDonald's, and a salad from Subway*
1643
+ <commentary>
1644
+ The assistant did not use the task tool because the objective is super simple and clear and only requires a few trivial tool calls.
1645
+ It is better to just complete the task directly and NOT use the \`task\`tool.
1646
+ </commentary>
1647
+ </example>
1478
1648
 
1479
- ### Example usage with custom agents:
1649
+ ### Example usage with custom agents:
1480
1650
 
1481
- <example_agent_descriptions>
1482
- "content-reviewer": use this agent after you are done creating significant content or documents
1483
- "greeting-responder": use this agent when to respond to user greetings with a friendly joke
1484
- "research-analyst": use this agent to conduct thorough research on complex topics
1485
- </example_agent_description>
1651
+ <example_agent_descriptions>
1652
+ "content-reviewer": use this agent after you are done creating significant content or documents
1653
+ "greeting-responder": use this agent when to respond to user greetings with a friendly joke
1654
+ "research-analyst": use this agent to conduct thorough research on complex topics
1655
+ </example_agent_description>
1486
1656
 
1487
- <example>
1488
- user: "Please write a function that checks if a number is prime"
1489
- assistant: Sure let me write a function that checks if a number is prime
1490
- assistant: First let me use the Write tool to write a function that checks if a number is prime
1491
- assistant: I'm going to use the Write tool to write the following code:
1492
- <code>
1493
- function isPrime(n) {
1494
- if (n <= 1) return false
1495
- for (let i = 2; i * i <= n; i++) {
1496
- if (n % i === 0) return false
1497
- }
1498
- return true
1499
- }
1500
- </code>
1501
- <commentary>
1502
- Since significant content was created and the task was completed, now use the content-reviewer agent to review the work
1503
- </commentary>
1504
- assistant: Now let me use the content-reviewer agent to review the code
1505
- assistant: Uses the Task tool to launch with the content-reviewer agent
1506
- </example>
1657
+ <example>
1658
+ user: "Please write a function that checks if a number is prime"
1659
+ assistant: Sure let me write a function that checks if a number is prime
1660
+ assistant: First let me use the Write tool to write a function that checks if a number is prime
1661
+ assistant: I'm going to use the Write tool to write the following code:
1662
+ <code>
1663
+ function isPrime(n) {{
1664
+ if (n <= 1) return false
1665
+ for (let i = 2; i * i <= n; i++) {{
1666
+ if (n % i === 0) return false
1667
+ }}
1668
+ return true
1669
+ }}
1670
+ </code>
1671
+ <commentary>
1672
+ Since significant content was created and the task was completed, now use the content-reviewer agent to review the work
1673
+ </commentary>
1674
+ assistant: Now let me use the content-reviewer agent to review the code
1675
+ assistant: Uses the Task tool to launch with the content-reviewer agent
1676
+ </example>
1507
1677
 
1508
- <example>
1509
- user: "Can you help me research the environmental impact of different renewable energy sources and create a comprehensive report?"
1510
- <commentary>
1511
- This is a complex research task that would benefit from using the research-analyst agent to conduct thorough analysis
1512
- </commentary>
1513
- 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.
1514
- 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
1515
- </example>
1678
+ <example>
1679
+ user: "Can you help me research the environmental impact of different renewable energy sources and create a comprehensive report?"
1680
+ <commentary>
1681
+ This is a complex research task that would benefit from using the research-analyst agent to conduct thorough analysis
1682
+ </commentary>
1683
+ 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.
1684
+ 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
1685
+ </example>
1516
1686
 
1517
- <example>
1518
- user: "Hello"
1519
- <commentary>
1520
- Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
1521
- </commentary>
1522
- assistant: "I'm going to use the Task tool to launch with the greeting-responder agent"
1523
- </example>
1524
- `.trim();
1687
+ <example>
1688
+ user: "Hello"
1689
+ <commentary>
1690
+ Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
1691
+ </commentary>
1692
+ assistant: "I'm going to use the Task tool to launch with the greeting-responder agent"
1693
+ </example>
1694
+ `;
1525
1695
  }
1526
1696
  /**
1527
1697
  * System prompt section that explains how to use the task tool for spawning subagents.
@@ -1536,33 +1706,35 @@ assistant: "I'm going to use the Task tool to launch with the greeting-responder
1536
1706
  * You can provide a custom `systemPrompt` to `createSubAgentMiddleware` to override
1537
1707
  * or extend this default.
1538
1708
  */
1539
- const TASK_SYSTEM_PROMPT = `## \`task\` (subagent spawner)
1709
+ const TASK_SYSTEM_PROMPT = context`
1710
+ ## \`task\` (subagent spawner)
1540
1711
 
1541
- 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.
1712
+ 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.
1542
1713
 
1543
- When to use the task tool:
1544
- - When a task is complex and multi-step, and can be fully delegated in isolation
1545
- - When a task is independent of other tasks and can run in parallel
1546
- - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread
1547
- - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)
1548
- - 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.)
1714
+ When to use the task tool:
1715
+ - When a task is complex and multi-step, and can be fully delegated in isolation
1716
+ - When a task is independent of other tasks and can run in parallel
1717
+ - When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread
1718
+ - When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)
1719
+ - 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.)
1549
1720
 
1550
- Subagent lifecycle:
1551
- 1. **Spawn** → Provide clear role, instructions, and expected output
1552
- 2. **Run** → The subagent completes the task autonomously
1553
- 3. **Return** → The subagent provides a single structured result
1554
- 4. **Reconcile** → Incorporate or synthesize the result into the main thread
1721
+ Subagent lifecycle:
1722
+ 1. **Spawn** → Provide clear role, instructions, and expected output
1723
+ 2. **Run** → The subagent completes the task autonomously
1724
+ 3. **Return** → The subagent provides a single structured result
1725
+ 4. **Reconcile** → Incorporate or synthesize the result into the main thread
1555
1726
 
1556
- When NOT to use the task tool:
1557
- - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)
1558
- - If the task is trivial (a few tool calls or simple lookup)
1559
- - If delegating does not reduce token usage, complexity, or context switching
1560
- - If splitting would add latency without benefit
1727
+ When NOT to use the task tool:
1728
+ - If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)
1729
+ - If the task is trivial (a few tool calls or simple lookup)
1730
+ - If delegating does not reduce token usage, complexity, or context switching
1731
+ - If splitting would add latency without benefit
1561
1732
 
1562
- ## Important Task Tool Usage Notes to Remember
1563
- - 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.
1564
- - Remember to use the \`task\` tool to silo independent tasks within a multi-part objective.
1565
- - 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.`;
1733
+ ## Important Task Tool Usage Notes to Remember
1734
+ - 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.
1735
+ - Remember to use the \`task\` tool to silo independent tasks within a multi-part objective.
1736
+ - 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.
1737
+ `;
1566
1738
  /**
1567
1739
  * Base specification for the general-purpose subagent.
1568
1740
  *
@@ -1971,65 +2143,67 @@ const MemoryStateSchema = new StateSchema({
1971
2143
  * Default system prompt template for memory.
1972
2144
  * Ported from Python's comprehensive memory guidelines.
1973
2145
  */
1974
- const MEMORY_SYSTEM_PROMPT = `<agent_memory>
1975
- {memory_contents}
1976
- </agent_memory>
2146
+ const MEMORY_SYSTEM_PROMPT = context`
2147
+ <agent_memory>
2148
+ {memory_contents}
2149
+ </agent_memory>
1977
2150
 
1978
- <memory_guidelines>
1979
- 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.
2151
+ <memory_guidelines>
2152
+ 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.
1980
2153
 
1981
- **Learning from feedback:**
1982
- - 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.
1983
- - 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.
1984
- - When user says something is better/worse, capture WHY and encode it as a pattern.
1985
- - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
1986
- - 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.
1987
- - Look for the underlying principle behind corrections, not just the specific mistake.
1988
- - 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.
2154
+ **Learning from feedback:**
2155
+ - 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.
2156
+ - 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.
2157
+ - When user says something is better/worse, capture WHY and encode it as a pattern.
2158
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
2159
+ - 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.
2160
+ - Look for the underlying principle behind corrections, not just the specific mistake.
2161
+ - 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.
1989
2162
 
1990
- **Asking for information:**
1991
- - 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.
1992
- - It is preferred for you to ask for information, don't assume anything that you do not know!
1993
- - When the user provides information that is useful for future use, you should update your memories immediately.
2163
+ **Asking for information:**
2164
+ - 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.
2165
+ - It is preferred for you to ask for information, don't assume anything that you do not know!
2166
+ - When the user provides information that is useful for future use, you should update your memories immediately.
1994
2167
 
1995
- **When to update memories:**
1996
- - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
1997
- - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
1998
- - When the user gives feedback on your work - capture what was wrong and how to improve
1999
- - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
2000
- - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
2001
- - When you discover new patterns or preferences (coding styles, conventions, workflows)
2168
+ **When to update memories:**
2169
+ - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
2170
+ - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
2171
+ - When the user gives feedback on your work - capture what was wrong and how to improve
2172
+ - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
2173
+ - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
2174
+ - When you discover new patterns or preferences (coding styles, conventions, workflows)
2002
2175
 
2003
- **When to NOT update memories:**
2004
- - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
2005
- - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
2006
- - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
2007
- - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
2008
- - When the information is stale or irrelevant in future conversations
2009
- - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
2010
- - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
2176
+ **When to NOT update memories:**
2177
+ - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
2178
+ - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
2179
+ - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
2180
+ - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
2181
+ - When the information is stale or irrelevant in future conversations
2182
+ - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
2183
+ - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
2011
2184
 
2012
- **Examples:**
2013
- Example 1 (remembering user information):
2014
- User: Can you connect to my google account?
2015
- Agent: Sure, I'll connect to your google account, what's your google account email?
2016
- User: john@example.com
2017
- Agent: Let me save this to my memory.
2018
- Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
2185
+ **Examples:**
2186
+ Example 1 (remembering user information):
2187
+ User: Can you connect to my google account?
2188
+ Agent: Sure, I'll connect to your google account, what's your google account email?
2189
+ User: john@example.com
2190
+ Agent: Let me save this to my memory.
2191
+ Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
2019
2192
 
2020
- Example 2 (remembering implicit user preferences):
2021
- User: Can you write me an example for creating a deep agent in LangChain?
2022
- Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
2023
- User: Can you do this in JavaScript
2024
- Agent: Let me save this to my memory.
2025
- Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
2026
- Agent: Sure, here is the JavaScript example<example code in JavaScript>
2193
+ Example 2 (remembering implicit user preferences):
2194
+ User: Can you write me an example for creating a deep agent in LangChain?
2195
+ Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
2196
+ User: Can you do this in JavaScript
2197
+ Agent: Let me save this to my memory.
2198
+ Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
2199
+ Agent: Sure, here is the JavaScript example<example code in JavaScript>
2027
2200
 
2028
- Example 3 (do not remember transient information):
2029
- User: I'm going to play basketball tonight so I will be offline for a few hours.
2030
- Agent: Okay I'll add a block to your calendar.
2031
- Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
2032
- </memory_guidelines>`;
2201
+ Example 3 (do not remember transient information):
2202
+ User: I'm going to play basketball tonight so I will be offline for a few hours.
2203
+ Agent: Okay I'll add a block to your calendar.
2204
+ Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
2205
+ </memory_guidelines>
2206
+ `;
2033
2207
  /**
2034
2208
  * Format loaded memory contents for injection into prompt.
2035
2209
  * Pairs memory locations with their contents for clarity.
@@ -2088,19 +2262,12 @@ async function loadMemoryFromBackend(backend, path) {
2088
2262
  */
2089
2263
  function createMemoryMiddleware(options) {
2090
2264
  const { backend, sources, addCacheControl = false } = options;
2091
- /**
2092
- * Resolve backend from instance or factory.
2093
- */
2094
- function getBackend(state) {
2095
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
2096
- return adaptBackendProtocol(backend);
2097
- }
2098
2265
  return createMiddleware({
2099
2266
  name: "MemoryMiddleware",
2100
2267
  stateSchema: MemoryStateSchema,
2101
2268
  async beforeAgent(state) {
2102
2269
  if ("memoryContents" in state && state.memoryContents != null) return;
2103
- const resolvedBackend = getBackend(state);
2270
+ const resolvedBackend = await resolveBackend(backend, { state });
2104
2271
  const contents = {};
2105
2272
  for (const path of sources) try {
2106
2273
  const content = await loadMemoryFromBackend(resolvedBackend, path);
@@ -2234,7 +2401,7 @@ Skills follow a **progressive disclosure** pattern - you know they exist (name +
2234
2401
  1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
2235
2402
  2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
2236
2403
  3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
2237
- 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
2404
+ 4. **Access supporting files**: Skills may include scripts, configs, or reference docs - use absolute paths
2238
2405
 
2239
2406
  **When to Use Skills:**
2240
2407
  - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
@@ -2246,7 +2413,7 @@ Skills follow a **progressive disclosure** pattern - you know they exist (name +
2246
2413
  - The skill list above shows the full path for each skill's SKILL.md file
2247
2414
 
2248
2415
  **Executing Skill Scripts:**
2249
- Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
2416
+ Skills may contain scripts or other executable files. Always use absolute paths from the skill list.
2250
2417
 
2251
2418
  **Example Workflow:**
2252
2419
 
@@ -2506,13 +2673,6 @@ function formatSkillsList(skills, sources) {
2506
2673
  function createSkillsMiddleware(options) {
2507
2674
  const { backend, sources } = options;
2508
2675
  let loadedSkills = [];
2509
- /**
2510
- * Resolve backend from instance or factory.
2511
- */
2512
- function getBackend(state) {
2513
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
2514
- return adaptBackendProtocol(backend);
2515
- }
2516
2676
  return createMiddleware({
2517
2677
  name: "SkillsMiddleware",
2518
2678
  stateSchema: SkillsStateSchema,
@@ -2522,7 +2682,7 @@ function createSkillsMiddleware(options) {
2522
2682
  loadedSkills = state.skillsMetadata;
2523
2683
  return;
2524
2684
  }
2525
- const resolvedBackend = getBackend(state);
2685
+ const resolvedBackend = await resolveBackend(backend, { state });
2526
2686
  const allSkills = /* @__PURE__ */ new Map();
2527
2687
  for (const sourcePath of sources) try {
2528
2688
  const skills = await listSkillsFromBackend(resolvedBackend, sourcePath);
@@ -2547,25 +2707,26 @@ function createSkillsMiddleware(options) {
2547
2707
  });
2548
2708
  }
2549
2709
  //#endregion
2550
- //#region src/middleware/completion_notifier.ts
2710
+ //#region src/middleware/completion_callback.ts
2551
2711
  /**
2552
- * Completion notifier middleware for async subagents.
2712
+ * Callback middleware for async subagents.
2553
2713
  *
2554
- * **Experimental** this middleware is experimental and may change in future releases.
2714
+ * @experimental - this middleware is experimental and may change in future releases.
2555
2715
  *
2556
- * When an async subagent finishes (success or error), this middleware sends a
2557
- * message back to the **supervisor's** thread so the supervisor wakes up and can
2558
- * proactively relay results to the user without the user having to poll via
2716
+ * This middleware sends a notification to a callback thread when a subagent
2717
+ * completes successfully or raises an error. The callback agent can then
2718
+ * process that notification instead of relying only on polling via
2559
2719
  * `check_async_task`.
2560
2720
  *
2561
2721
  * ## Architecture
2562
2722
  *
2563
- * The async subagent protocol is inherently fire-and-forget: the supervisor
2564
- * launches a job via `start_async_task` and only learns about completion
2565
- * when someone calls `check_async_task`. This middleware closes that gap.
2723
+ * A parent agent launches a subagent with `start_async_task` and can later
2724
+ * inspect task state with `check_async_task`. This middleware adds an optional
2725
+ * completion signal by creating a run on the callback thread when the subagent
2726
+ * finishes.
2566
2727
  *
2567
2728
  * ```
2568
- * Supervisor Subagent
2729
+ * Parent Subagent
2569
2730
  * | |
2570
2731
  * |--- start_async_task -----> |
2571
2732
  * |<-- task_id (immediately) - |
@@ -2573,67 +2734,74 @@ function createSkillsMiddleware(options) {
2573
2734
  * | | (done!)
2574
2735
  * | |
2575
2736
  * |<-- runs.create( |
2576
- * | supervisor_thread, |
2737
+ * | callback_thread, |
2577
2738
  * | "completed: ...") |
2578
2739
  * | |
2579
- * | (wakes up, sees result) |
2740
+ * | (processes result) |
2580
2741
  * ```
2581
2742
  *
2582
- * The notifier calls `runs.create()` on the supervisor's thread, which
2583
- * queues a new run. From the supervisor's perspective, it looks like a new
2584
- * user message arrived — except the content is a structured notification
2585
- * from the subagent.
2586
- *
2587
- * ## How parent context is propagated
2588
- *
2589
- * - `parentGraphId` is passed as a **constructor argument** to the middleware.
2590
- * This is the supervisor's graph ID (or assistant ID), which the subagent
2591
- * developer knows at configuration time.
2592
- * - `url` is the URL of the LangGraph server where the supervisor is deployed.
2593
- * This is required since JS does not support in-process ASGI transport.
2594
- * - `headers` are optional additional headers for authenticating with the
2595
- * supervisor's server.
2596
- * - `parent_thread_id` is injected into the subagent's input state by the
2597
- * supervisor's `start_async_task` tool. It survives thread interrupts and
2598
- * updates because it lives in state, not config.
2599
- * - If `parent_thread_id` is not present in state, the notifier silently no-ops.
2743
+ * The middleware calls `runs.create()` on the callback thread. From the
2744
+ * callback agent's perspective, this appears as a new user message containing
2745
+ * structured output from the subagent.
2746
+ *
2747
+ * ## Callback context
2748
+ *
2749
+ * - `callbackGraphId` identifies the callback graph or assistant. It is
2750
+ * provided when the middleware is constructed.
2751
+ * - `url` and `headers` optionally configure a remote callback destination.
2752
+ * Omit `url` for same-deployment ASGI transport.
2753
+ * - `callback_thread_id` is stored in the subagent state by the parent's
2754
+ * `start_async_task` tool. Because it is stored in state rather than config,
2755
+ * it survives thread updates and interrupts.
2756
+ * - If `callback_thread_id` is not present in state, the middleware does
2757
+ * nothing.
2600
2758
  *
2601
2759
  * ## Usage
2602
2760
  *
2603
2761
  * ```typescript
2604
- * import { createCompletionNotifierMiddleware } from "deepagents";
2762
+ * import { createCompletionCallbackMiddleware } from "deepagents";
2605
2763
  *
2606
- * const notifier = createCompletionNotifierMiddleware({
2607
- * parentGraphId: "supervisor",
2764
+ * // Same deployment (callback agent and subagent share a server):
2765
+ * const notifier = createCompletionCallbackMiddleware({
2766
+ * callbackGraphId: "supervisor",
2767
+ * });
2768
+ *
2769
+ * // Remote deployment (callback destination on a different server):
2770
+ * const notifier = createCompletionCallbackMiddleware({
2771
+ * callbackGraphId: "supervisor",
2608
2772
  * url: "https://my-deployment.langsmith.dev",
2609
2773
  * });
2610
2774
  *
2611
2775
  * const agent = createDeepAgent({
2612
- * model: "claude-sonnet-4-5-20250929",
2776
+ * model,
2613
2777
  * middleware: [notifier],
2614
2778
  * });
2615
2779
  * ```
2616
2780
  *
2617
- * The middleware will read `parent_thread_id` from the agent's state at the
2618
- * end of execution. This is injected automatically by the supervisor's
2619
- * `start_async_task` tool when it creates the run.
2781
+ * The middleware reads `callbackThreadId` from the agent state at the end of
2782
+ * execution. This value is injected by the parent's `start_async_task` tool
2783
+ * when it creates the run.
2620
2784
  *
2621
2785
  * @module
2622
2786
  */
2623
- /** State key where the supervisor's launch tool stores the parent thread ID. */
2624
- const PARENT_THREAD_ID_KEY = "parent_thread_id";
2625
2787
  /** Maximum characters to include from the last message in notifications. */
2626
- const MAX_SUMMARY_LENGTH = 500;
2788
+ const MAX_MESSAGE_LENGTH = 500;
2789
+ /** Suffix appended when truncating long messages. */
2790
+ const TRUNCATION_SUFFIX = "... [full result truncated]";
2791
+ /** State key for the callback thread ID. */
2792
+ const CALLBACK_THREAD_ID_KEY = "callbackThreadId";
2627
2793
  /**
2628
- * State extension for subagents that use the completion notifier.
2794
+ * State extension for subagents that use completion callbacks.
2629
2795
  *
2630
- * These fields are injected by the supervisor's `start_async_task`
2631
- * tool and read by the completion notifier middleware to send notifications
2632
- * back to the supervisor's thread.
2796
+ * @experimental - this state schema is experimental and may change in future releases.
2797
+ *
2798
+ * `callbackThreadId` is written by the parent's `start_async_task` tool
2799
+ * and read by `CompletionCallbackMiddleware` when sending callback
2800
+ * notifications.
2633
2801
  */
2634
- const CompletionNotifierStateSchema = z.object({ parent_thread_id: z.string().nullish() });
2802
+ const CompletionCallbackStateSchema = z$2.object({ [CALLBACK_THREAD_ID_KEY]: z$2.string().optional() });
2635
2803
  /**
2636
- * Build headers for the supervisor's LangGraph server.
2804
+ * Build headers for the callback LangGraph server.
2637
2805
  *
2638
2806
  * Ensures `x-auth-scheme: langsmith` is present unless explicitly overridden.
2639
2807
  */
@@ -2643,55 +2811,63 @@ function resolveHeaders(headers) {
2643
2811
  return resolved;
2644
2812
  }
2645
2813
  /**
2646
- * Send a notification run to the parent supervisor's thread.
2814
+ * Send a notification run to the callback thread.
2815
+ *
2816
+ * @param callbackGraphId - The callback graph ID used as `assistant_id`
2817
+ * in the `runs.create` call.
2818
+ * @param callbackThreadId - The callback thread ID.
2819
+ * @param message - The message content to send.
2820
+ * @param options - Optional url and headers for the callback server.
2647
2821
  */
2648
- async function notifyParent(parentThreadId, parentGraphId, notification, options) {
2822
+ async function notifyParent(callbackGraphId, callbackThreadId, message, options) {
2649
2823
  try {
2650
2824
  await new Client({
2651
- apiUrl: options.url,
2825
+ apiUrl: options?.url ?? void 0,
2652
2826
  apiKey: null,
2653
- defaultHeaders: resolveHeaders(options.headers)
2654
- }).runs.create(parentThreadId, parentGraphId, { input: { messages: [{
2827
+ defaultHeaders: resolveHeaders(options?.headers)
2828
+ }).runs.create(callbackThreadId, callbackGraphId, { input: { messages: [{
2655
2829
  role: "user",
2656
- content: notification
2830
+ content: message
2657
2831
  }] } });
2658
2832
  } catch (e) {
2659
- console.warn(`[CompletionNotifierMiddleware] Failed to notify parent thread ${parentThreadId}:`, e);
2833
+ console.warn(`[CompletionCallbackMiddleware] Failed to notify callback thread ${callbackThreadId}:`, e);
2660
2834
  }
2661
2835
  }
2662
2836
  /**
2663
2837
  * Extract a summary from the subagent's final message.
2664
2838
  *
2665
2839
  * Returns at most 500 characters from the last message's content.
2840
+ * Throws if no messages exist or if the last message is not an AIMessage.
2841
+ *
2842
+ * @param state - The agent state dict.
2843
+ * @param taskId - Optional task ID to include in truncation hint.
2666
2844
  */
2667
- function extractLastMessage(state) {
2845
+ function extractLastMessage(state, taskId) {
2668
2846
  const messages = state.messages;
2669
- if (!messages || messages.length === 0) return "(no output)";
2847
+ if (!messages || messages.length === 0) throw new Error(`Expected at least one message in state ${JSON.stringify(state)}`);
2670
2848
  const last = messages[messages.length - 1];
2671
- if (last && typeof last === "object" && "content" in last) {
2672
- const content = last.content;
2673
- if (typeof content === "string") return content.slice(0, MAX_SUMMARY_LENGTH);
2674
- return JSON.stringify(content).slice(0, MAX_SUMMARY_LENGTH);
2849
+ if (!AIMessage$1.isInstance(last)) throw new TypeError(`Expected an AIMessage, got ${typeof last === "object" && last !== null ? last.constructor?.name ?? typeof last : typeof last} instead`);
2850
+ let textContent = last.text;
2851
+ if (textContent.length > MAX_MESSAGE_LENGTH) {
2852
+ textContent = textContent.slice(0, MAX_MESSAGE_LENGTH) + TRUNCATION_SUFFIX;
2853
+ if (taskId) textContent += ` Result truncated. Use \`check_async_task(task_id='${taskId}')\` to retrieve the full result if needed.`;
2675
2854
  }
2676
- return String(last).slice(0, MAX_SUMMARY_LENGTH);
2855
+ return textContent;
2677
2856
  }
2678
2857
  /**
2679
- * Create a completion notifier middleware for async subagents.
2858
+ * Create a completion callback middleware for async subagents.
2680
2859
  *
2681
2860
  * **Experimental** — this middleware is experimental and may change.
2682
2861
  *
2683
- * This middleware is added to the **subagent's** middleware stack (not the
2684
- * supervisor's). When the subagent finishes, it sends a message to the
2685
- * supervisor's thread via `runs.create()`, waking the supervisor so it can
2686
- * proactively relay results.
2862
+ * This middleware is added to a subagent's middleware stack. On success or
2863
+ * model-call error, it sends a notification to the configured callback
2864
+ * thread by calling `runs.create()`.
2687
2865
  *
2688
- * The supervisor's `parent_thread_id` is read from the subagent's own state
2689
- * (injected by the supervisor's `start_async_task` tool at launch time).
2690
- * The `parentGraphId` is provided as a constructor argument since it's static
2691
- * configuration known at deployment time.
2866
+ * The callback destination is configured with `callbackGraphId` and
2867
+ * optional `url` and `headers`. The target thread is read from
2868
+ * `callbackThreadId` in the subagent state.
2692
2869
  *
2693
- * If `parent_thread_id` is not present in state (e.g., the subagent was
2694
- * launched manually without a supervisor), the middleware silently does
2870
+ * If `callbackThreadId` is not present in state, the middleware does
2695
2871
  * nothing.
2696
2872
  *
2697
2873
  * @param options - Configuration options.
@@ -2699,11 +2875,10 @@ function extractLastMessage(state) {
2699
2875
  *
2700
2876
  * @example
2701
2877
  * ```typescript
2702
- * import { createCompletionNotifierMiddleware } from "deepagents";
2878
+ * import { createCompletionCallbackMiddleware } from "deepagents";
2703
2879
  *
2704
- * const notifier = createCompletionNotifierMiddleware({
2705
- * parentGraphId: "supervisor",
2706
- * url: "https://my-deployment.langsmith.dev",
2880
+ * const notifier = createCompletionCallbackMiddleware({
2881
+ * callbackGraphId: "supervisor",
2707
2882
  * });
2708
2883
  *
2709
2884
  * const agent = createDeepAgent({
@@ -2712,23 +2887,13 @@ function extractLastMessage(state) {
2712
2887
  * });
2713
2888
  * ```
2714
2889
  */
2715
- function createCompletionNotifierMiddleware(options) {
2716
- const { parentGraphId, url, headers } = options;
2717
- let notified = false;
2890
+ function createCompletionCallbackMiddleware(options) {
2891
+ const { callbackGraphId, url, headers } = options;
2718
2892
  /**
2719
- * Check whether we should send a notification.
2893
+ * Send a notification to the callback destination.
2720
2894
  */
2721
- function shouldNotify(state) {
2722
- if (notified) return false;
2723
- return Boolean(state[PARENT_THREAD_ID_KEY]);
2724
- }
2725
- /**
2726
- * Send a notification to the parent if conditions are met.
2727
- */
2728
- async function sendNotification(state, message) {
2729
- if (!shouldNotify(state)) return;
2730
- notified = true;
2731
- await notifyParent(state[PARENT_THREAD_ID_KEY], parentGraphId, message, {
2895
+ async function sendNotification(callbackThreadId, message) {
2896
+ await notifyParent(callbackGraphId, callbackThreadId, message, {
2732
2897
  url,
2733
2898
  headers
2734
2899
  });
@@ -2737,7 +2902,7 @@ function createCompletionNotifierMiddleware(options) {
2737
2902
  * Read the subagent's own thread_id from runtime config.
2738
2903
  *
2739
2904
  * The subagent's `thread_id` is the same as the `task_id` from the
2740
- * supervisor's perspective.
2905
+ * parent's perspective.
2741
2906
  */
2742
2907
  function getTaskId(runtime) {
2743
2908
  return runtime?.configurable?.thread_id;
@@ -2750,17 +2915,20 @@ function createCompletionNotifierMiddleware(options) {
2750
2915
  return `${taskId ? `[task_id=${taskId}]` : ""}${body}`;
2751
2916
  }
2752
2917
  return createMiddleware({
2753
- name: "CompletionNotifierMiddleware",
2754
- stateSchema: CompletionNotifierStateSchema,
2918
+ name: "CompletionCallbackMiddleware",
2919
+ stateSchema: CompletionCallbackStateSchema,
2755
2920
  async afterAgent(state, runtime) {
2756
- await sendNotification(state, formatNotification(`Completed. Result: ${extractLastMessage(state)}`, runtime));
2921
+ const callbackThreadId = state[CALLBACK_THREAD_ID_KEY];
2922
+ if (callbackThreadId == null) throw new Error(`Missing required state key '${CALLBACK_THREAD_ID_KEY}'`);
2923
+ const taskId = getTaskId(runtime);
2924
+ await sendNotification(callbackThreadId, formatNotification(`Completed. Result: ${extractLastMessage(state, typeof taskId === "string" ? taskId : void 0)}`, runtime));
2757
2925
  },
2758
2926
  async wrapModelCall(request, handler) {
2759
2927
  try {
2760
2928
  return await handler(request);
2761
2929
  } catch (e) {
2762
- const notification = formatNotification(`Error: ${e instanceof Error ? e.message : String(e)}`, request.runtime);
2763
- await sendNotification(request.state, notification);
2930
+ const callbackThreadId = request.state[CALLBACK_THREAD_ID_KEY];
2931
+ if (typeof callbackThreadId === "string") await sendNotification(callbackThreadId, formatNotification("The agent encountered an error while calling the model.", request.runtime));
2764
2932
  throw e;
2765
2933
  }
2766
2934
  }
@@ -2959,13 +3127,6 @@ function createSummarizationMiddleware(options) {
2959
3127
  let sessionId = null;
2960
3128
  let tokenEstimationMultiplier = 1;
2961
3129
  /**
2962
- * Resolve backend from instance or factory.
2963
- */
2964
- function getBackend(state) {
2965
- if (typeof backend === "function") return adaptBackendProtocol(backend({ state }));
2966
- return adaptBackendProtocol(backend);
2967
- }
2968
- /**
2969
3130
  * Get or create session ID for history file naming.
2970
3131
  */
2971
3132
  function getSessionId(state) {
@@ -3297,15 +3458,17 @@ function createSummarizationMiddleware(options) {
3297
3458
  */
3298
3459
  function buildSummaryMessage(summary, filePath) {
3299
3460
  let content;
3300
- if (filePath) content = `You are in the middle of a conversation that has been summarized.
3461
+ if (filePath) content = context`
3462
+ You are in the middle of a conversation that has been summarized.
3301
3463
 
3302
- The full conversation history has been saved to ${filePath} should you need to refer back to it for details.
3464
+ The full conversation history has been saved to ${filePath} should you need to refer back to it for details.
3303
3465
 
3304
- A condensed summary follows:
3466
+ A condensed summary follows:
3305
3467
 
3306
- <summary>
3307
- ${summary}
3308
- </summary>`;
3468
+ <summary>
3469
+ ${summary}
3470
+ </summary>
3471
+ `;
3309
3472
  else content = `Here is a summary of the conversation to date:\n\n${summary}`;
3310
3473
  return new HumanMessage({
3311
3474
  content,
@@ -3331,7 +3494,7 @@ ${summary}
3331
3494
  * the file path, and the state cutoff index.
3332
3495
  */
3333
3496
  async function summarizeMessages(messagesToSummarize, resolvedModel, state, previousCutoffIndex, cutoffIndex) {
3334
- const filePath = await offloadToBackend(getBackend(state), messagesToSummarize, state);
3497
+ const filePath = await offloadToBackend(await resolveBackend(backend, { state }), messagesToSummarize, state);
3335
3498
  if (filePath === null) console.warn(`[SummarizationMiddleware] Backend offload failed during summarization. Proceeding with summary generation.`);
3336
3499
  return {
3337
3500
  summaryMessage: buildSummaryMessage(await createSummary(messagesToSummarize, resolvedModel), filePath),
@@ -3473,6 +3636,7 @@ const AsyncTaskSchema = z.object({
3473
3636
  runId: z.string(),
3474
3637
  status: z.string(),
3475
3638
  createdAt: z.string(),
3639
+ description: z.string().optional(),
3476
3640
  updatedAt: z.string().optional(),
3477
3641
  checkedAt: z.string().optional()
3478
3642
  });
@@ -3510,7 +3674,7 @@ function asyncTasksReducer(existing, update) {
3510
3674
  * The `{available_agents}` placeholder is replaced at middleware creation
3511
3675
  * time with a formatted list of configured async subagent names and descriptions.
3512
3676
  */
3513
- 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.
3677
+ 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.
3514
3678
 
3515
3679
  Available async agent types:
3516
3680
  {available_agents}
@@ -3520,7 +3684,7 @@ Available async agent types:
3520
3684
  2. Use \`check_async_task\` only when the user asks for a status update or result.
3521
3685
  3. Use \`update_async_task\` to send new instructions to a running task.
3522
3686
  4. Multiple async subagents can run concurrently — launch several and let them run in the background.
3523
- 5. The subagent runs on a remote LangGraph server, so it has its own tools and capabilities.`;
3687
+ 5. The subagent runs on a remote server, so it has its own tools and capabilities.`;
3524
3688
  /**
3525
3689
  * Default system prompt appended to the main agent's system message when
3526
3690
  * async subagent middleware is active.
@@ -3530,9 +3694,9 @@ Available async agent types:
3530
3694
  * critical rules about polling behavior, and guidance on when to use async
3531
3695
  * subagents vs. synchronous delegation.
3532
3696
  */
3533
- const ASYNC_TASK_SYSTEM_PROMPT = `## Async subagents (remote LangGraph servers)
3697
+ const ASYNC_TASK_SYSTEM_PROMPT = `## Async subagents (remote servers)
3534
3698
 
3535
- You have access to async subagent tools that launch background tasks on remote LangGraph servers.
3699
+ You have access to async subagent tools that launch background tasks on remote servers.
3536
3700
 
3537
3701
  ### Tools:
3538
3702
  - \`start_async_task\`: Start a new background task. Returns a task ID immediately.
@@ -3572,6 +3736,19 @@ You have access to async subagent tools that launch background tasks on remote L
3572
3736
  * When listing tasks, live-status fetches are skipped for tasks whose
3573
3737
  * cached status is in this set, since they are guaranteed to be final.
3574
3738
  */
3739
+ /**
3740
+ * Names of the tools added by the async subagent middleware.
3741
+ *
3742
+ * Exported so `agent.ts` can include them in `BUILTIN_TOOL_NAMES` and
3743
+ * surface a `ConfigurationError` if a user-provided tool collides.
3744
+ */
3745
+ const ASYNC_TASK_TOOL_NAMES = [
3746
+ "start_async_task",
3747
+ "check_async_task",
3748
+ "update_async_task",
3749
+ "cancel_async_task",
3750
+ "list_async_tasks"
3751
+ ];
3575
3752
  const TERMINAL_STATUSES = new Set([
3576
3753
  "cancelled",
3577
3754
  "success",
@@ -3663,8 +3840,11 @@ var ClientCache = class {
3663
3840
  this.agents = agents;
3664
3841
  }
3665
3842
  /**
3666
- * Build headers for a remote LangGraph server, adding the default
3667
- * `x-auth-scheme: langsmith` header if not already present.
3843
+ * Build headers for a remote Agent Protocol server.
3844
+ *
3845
+ * Adds `x-auth-scheme: langsmith` by default unless already provided.
3846
+ * For self-hosted servers that don't require this header, it is typically
3847
+ * ignored. Override via the `headers` field on the AsyncSubAgent config.
3668
3848
  */
3669
3849
  resolveHeaders(spec) {
3670
3850
  const headers = { ...spec.headers || {} };
@@ -3697,6 +3877,20 @@ var ClientCache = class {
3697
3877
  }
3698
3878
  };
3699
3879
  /**
3880
+ * Extract the callback thread ID from the tool runtime.
3881
+ *
3882
+ * The thread ID is included in the subagent's input state so the subagent
3883
+ * can notify the parent when it completes (via
3884
+ * `CompletionCallbackMiddleware`).
3885
+ *
3886
+ * @returns Object with `callbackThreadId` if available. Empty object otherwise.
3887
+ */
3888
+ function extractCallbackContext(runtime) {
3889
+ const threadId = (runtime.config?.configurable)?.thread_id;
3890
+ if (typeof threadId === "string" && threadId) return { callbackThreadId: threadId };
3891
+ return {};
3892
+ }
3893
+ /**
3700
3894
  * Build the `start_async_task` tool.
3701
3895
  *
3702
3896
  * Creates a thread on the remote server, starts a run, and returns a
@@ -3709,13 +3903,17 @@ function buildStartTool(agentMap, clients, toolDescription) {
3709
3903
  return `Unknown async subagent type \`${input.agentName}\`. Available types: ${allowed}`;
3710
3904
  }
3711
3905
  const spec = agentMap[input.agentName];
3906
+ const callbackContext = extractCallbackContext(runtime);
3712
3907
  try {
3713
3908
  const client = clients.getClient(input.agentName);
3714
3909
  const thread = await client.threads.create();
3715
- const run = await client.runs.create(thread.thread_id, spec.graphId, { input: { messages: [{
3716
- role: "user",
3717
- content: input.description
3718
- }] } });
3910
+ const run = await client.runs.create(thread.thread_id, spec.graphId, { input: {
3911
+ messages: [{
3912
+ role: "user",
3913
+ content: input.description
3914
+ }],
3915
+ ...callbackContext
3916
+ } });
3719
3917
  const taskId = thread.thread_id;
3720
3918
  const task = {
3721
3919
  taskId,
@@ -3723,7 +3921,8 @@ function buildStartTool(agentMap, clients, toolDescription) {
3723
3921
  threadId: taskId,
3724
3922
  runId: run.run_id,
3725
3923
  status: "running",
3726
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
3924
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3925
+ description: input.description
3727
3926
  };
3728
3927
  return new Command({ update: {
3729
3928
  messages: [new ToolMessage({
@@ -3773,7 +3972,7 @@ function buildCheckTool(clients) {
3773
3972
  runId: task.runId,
3774
3973
  status: result.status,
3775
3974
  createdAt: task.createdAt,
3776
- updatedAt: task.updatedAt,
3975
+ updatedAt: result.status !== task.status ? (/* @__PURE__ */ new Date()).toISOString() : task.updatedAt,
3777
3976
  checkedAt: (/* @__PURE__ */ new Date()).toISOString()
3778
3977
  };
3779
3978
  return new Command({ update: {
@@ -3817,6 +4016,7 @@ function buildUpdateTool(agentMap, clients) {
3817
4016
  runId: run.run_id,
3818
4017
  status: "running",
3819
4018
  createdAt: tracked.createdAt,
4019
+ description: input.message,
3820
4020
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3821
4021
  checkedAt: tracked.checkedAt
3822
4022
  };
@@ -3862,7 +4062,7 @@ function buildCancelTool(clients) {
3862
4062
  runId: tracked.runId,
3863
4063
  status: "cancelled",
3864
4064
  createdAt: tracked.createdAt,
3865
- updatedAt: tracked.updatedAt,
4065
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3866
4066
  checkedAt: tracked.checkedAt
3867
4067
  };
3868
4068
  return new Command({ update: {
@@ -3903,7 +4103,7 @@ function buildListTool(clients) {
3903
4103
  runId: task.runId,
3904
4104
  status,
3905
4105
  createdAt: task.createdAt,
3906
- updatedAt: task.updatedAt,
4106
+ updatedAt: status !== task.status ? (/* @__PURE__ */ new Date()).toISOString() : task.updatedAt,
3907
4107
  checkedAt: task.checkedAt
3908
4108
  };
3909
4109
  }
@@ -3924,10 +4124,13 @@ function buildListTool(clients) {
3924
4124
  * Create middleware that adds async subagent tools to an agent.
3925
4125
  *
3926
4126
  * Provides five tools for launching, checking, updating, cancelling, and
3927
- * listing background tasks on remote LangGraph deployments. Task state is
4127
+ * listing background tasks on remote Agent Protocol servers. Task state is
3928
4128
  * persisted in the `asyncTasks` state channel so it survives
3929
4129
  * context compaction.
3930
4130
  *
4131
+ * Works with any Agent Protocol-compliant server — LangGraph Platform (managed)
4132
+ * or self-hosted (e.g. a Hono/Express server implementing the Agent Protocol spec).
4133
+ *
3931
4134
  * @throws {Error} If no async subagents are provided or names are duplicated.
3932
4135
  *
3933
4136
  * @example
@@ -3936,7 +4139,7 @@ function buildListTool(clients) {
3936
4139
  * asyncSubAgents: [{
3937
4140
  * name: "researcher",
3938
4141
  * description: "Research agent for deep analysis",
3939
- * url: "https://my-deployment.langsmith.dev",
4142
+ * url: "https://my-agent-protocol-server.example.com",
3940
4143
  * graphId: "research_agent",
3941
4144
  * }],
3942
4145
  * });
@@ -3983,6 +4186,9 @@ function createAsyncSubAgentMiddleware(options) {
3983
4186
  }
3984
4187
  //#endregion
3985
4188
  //#region src/backends/store.ts
4189
+ /**
4190
+ * StoreBackend: Adapter for LangGraph's BaseStore (persistent, cross-thread).
4191
+ */
3986
4192
  const NAMESPACE_COMPONENT_RE = /^[A-Za-z0-9\-_.@+:~]+$/;
3987
4193
  /**
3988
4194
  * Validate a namespace array.
@@ -4018,35 +4224,54 @@ var StoreBackend = class {
4018
4224
  stateAndStore;
4019
4225
  _namespace;
4020
4226
  fileFormat;
4021
- constructor(stateAndStore, options) {
4022
- this.stateAndStore = stateAndStore;
4023
- if (options?.namespace) this._namespace = validateNamespace(options.namespace);
4024
- this.fileFormat = options?.fileFormat ?? "v2";
4227
+ constructor(stateAndStoreOrOptions, options) {
4228
+ let opts;
4229
+ if (stateAndStoreOrOptions != null && typeof stateAndStoreOrOptions === "object" && "state" in stateAndStoreOrOptions) {
4230
+ this.stateAndStore = stateAndStoreOrOptions;
4231
+ opts = options;
4232
+ } else {
4233
+ this.stateAndStore = void 0;
4234
+ opts = stateAndStoreOrOptions;
4235
+ }
4236
+ if (opts?.namespace) this._namespace = validateNamespace(opts.namespace);
4237
+ this.fileFormat = opts?.fileFormat ?? "v2";
4025
4238
  }
4026
4239
  /**
4027
- * Get the store instance.
4240
+ * Get the BaseStore instance for persistent storage operations.
4241
+ *
4242
+ * In legacy mode, reads from the injected {@link StateAndStore}.
4243
+ * In zero-arg mode, retrieves the store from the LangGraph execution
4244
+ * context via {@link getLangGraphStore}.
4028
4245
  *
4029
4246
  * @returns BaseStore instance
4030
- * @throws Error if no store is available
4247
+ * @throws Error if no store is available in either mode
4031
4248
  */
4032
4249
  getStore() {
4033
- const store = this.stateAndStore.store;
4034
- if (!store) throw new Error("Store is required but not available in StateAndStore");
4250
+ if (this.stateAndStore) {
4251
+ const store = this.stateAndStore.store;
4252
+ if (!store) throw new Error("Store is required but not available in runtime");
4253
+ return store;
4254
+ }
4255
+ const store = getStore();
4256
+ if (!store) throw new Error("Store is required but not available in LangGraph execution context. Ensure the graph was configured with a store.");
4035
4257
  return store;
4036
4258
  }
4037
4259
  /**
4038
4260
  * Get the namespace for store operations.
4039
4261
  *
4040
- * If a custom namespace was provided, returns it directly.
4041
- *
4042
- * Otherwise, falls back to legacy behavior:
4043
- * - If assistantId is set: [assistantId, "filesystem"]
4044
- * - Otherwise: ["filesystem"]
4262
+ * Resolution order:
4263
+ * 1. Explicit namespace from constructor options (both modes)
4264
+ * 2. Legacy mode: `[assistantId, "filesystem"]` fallback from {@link StateAndStore}
4265
+ * 3. Zero-arg mode without namespace: `["filesystem"]` with a deprecation warning
4266
+ * nudging callers to pass an explicit namespace
4267
+ * 4. Legacy mode without assistantId: `["filesystem"]`
4045
4268
  */
4046
4269
  getNamespace() {
4047
4270
  if (this._namespace) return this._namespace;
4048
- const assistantId = this.stateAndStore.assistantId;
4049
- if (assistantId) return [assistantId, "filesystem"];
4271
+ if (this.stateAndStore) {
4272
+ const assistantId = this.stateAndStore.assistantId;
4273
+ if (assistantId) return [assistantId, "filesystem"];
4274
+ }
4050
4275
  return ["filesystem"];
4051
4276
  }
4052
4277
  /**
@@ -6055,9 +6280,9 @@ var LangSmithSandbox = class LangSmithSandbox extends BaseSandbox {
6055
6280
  * ```
6056
6281
  */
6057
6282
  static async create(options = {}) {
6058
- const { templateName = "deepagents", apiKey = process.env.LANGSMITH_API_KEY, defaultTimeout } = options;
6283
+ const { templateName = "deepagents", apiKey = process.env.LANGSMITH_API_KEY, defaultTimeout, ...createSandboxOptions } = options;
6059
6284
  return new LangSmithSandbox({
6060
- sandbox: await new SandboxClient({ apiKey }).createSandbox(templateName),
6285
+ sandbox: await new SandboxClient({ apiKey }).createSandbox(templateName, createSandboxOptions),
6061
6286
  defaultTimeout
6062
6287
  });
6063
6288
  }
@@ -6145,9 +6370,44 @@ function createCacheBreakpointMiddleware() {
6145
6370
  }
6146
6371
  //#endregion
6147
6372
  //#region src/agent.ts
6148
- const BASE_PROMPT = `In order to complete the objective that the user asks of you, you have access to a number of standard tools.`;
6373
+ const BASE_AGENT_PROMPT = context`
6374
+ 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.
6375
+
6376
+ ## Core Behavior
6377
+
6378
+ - Be concise and direct. Don't over-explain unless asked.
6379
+ - NEVER add unnecessary preamble (\"Sure!\", \"Great question!\", \"I'll now...\").
6380
+ - Don't say \"I'll now do X\" — just do it.
6381
+ - If the request is ambiguous, ask questions before acting.
6382
+ - If asked how to approach something, explain first, then act.
6383
+
6384
+ ## Professional Objectivity
6385
+
6386
+ - Prioritize accuracy over validating the user's beliefs
6387
+ - Disagree respectfully when the user is incorrect
6388
+ - Avoid unnecessary superlatives, praise, or emotional validation
6389
+
6390
+ ## Doing Tasks
6391
+
6392
+ When the user asks you to do something:
6393
+
6394
+ 1. **Understand first** — read relevant files, check existing patterns. Quick but thorough — gather enough evidence to start, then iterate.
6395
+ 2. **Act** — implement the solution. Work quickly but accurately.
6396
+ 3. **Verify** — check your work against what was asked, not against your own output. Your first attempt is rarely correct — iterate.
6397
+
6398
+ 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.
6399
+
6400
+ **When things go wrong:**
6401
+ - If something fails repeatedly, stop and analyze *why* — don't keep retrying the same approach.
6402
+ - If you're blocked, tell the user what's wrong and ask for guidance.
6403
+
6404
+ ## Progress Updates
6405
+
6406
+ For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
6407
+ `;
6149
6408
  const BUILTIN_TOOL_NAMES = new Set([
6150
6409
  ...FILESYSTEM_TOOL_NAMES,
6410
+ ...ASYNC_TASK_TOOL_NAMES,
6151
6411
  "task",
6152
6412
  "write_todos"
6153
6413
  ]);
@@ -6164,19 +6424,18 @@ function isAnthropicModel(model) {
6164
6424
  return model.getName() === "ChatAnthropic";
6165
6425
  }
6166
6426
  /**
6167
- * Create a Deep Agent with middleware-based architecture.
6427
+ * Create a Deep Agent.
6428
+ *
6429
+ * This is the main entry point for building a production-style agent with
6430
+ * deepagents. It gives you a strong default runtime (filesystem, tasks,
6431
+ * subagents, summarization) and lets you opt into skills, memory,
6432
+ * human-in-the-loop interrupts, async subagents, and custom middleware.
6168
6433
  *
6169
- * Matches Python's create_deep_agent function, using middleware for all features:
6170
- * - Todo management (todoListMiddleware)
6171
- * - Filesystem tools (createFilesystemMiddleware)
6172
- * - Subagent delegation (createSubAgentMiddleware)
6173
- * - Conversation summarization (createSummarizationMiddleware) with backend offloading
6174
- * - Prompt caching (anthropicPromptCachingMiddleware)
6175
- * - Tool call patching (createPatchToolCallsMiddleware)
6176
- * - Human-in-the-loop (humanInTheLoopMiddleware) - optional
6434
+ * The runtime is intentionally opinionated: defaults work out of the box, and
6435
+ * when you customize behavior, the middleware ordering stays deterministic.
6177
6436
  *
6178
6437
  * @param params Configuration parameters for the agent
6179
- * @returns ReactAgent instance ready for invocation with properly inferred state types
6438
+ * @returns Deep Agent instance with inferred state/response types
6180
6439
  *
6181
6440
  * @example
6182
6441
  * ```typescript
@@ -6195,98 +6454,92 @@ function isAnthropicModel(model) {
6195
6454
  * ```
6196
6455
  */
6197
6456
  function createDeepAgent(params = {}) {
6198
- const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name, memory, skills } = params;
6457
+ const { model = new ChatAnthropic("claude-sonnet-4-6"), tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend = (config) => new StateBackend(config), interruptOn, name, memory, skills } = params;
6199
6458
  const collidingTools = tools.map((t) => t.name).filter((n) => typeof n === "string" && BUILTIN_TOOL_NAMES.has(n));
6200
6459
  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");
6201
6460
  const anthropicModel = isAnthropicModel(model);
6202
- const finalSystemPrompt = new SystemMessage({ content: systemPrompt ? typeof systemPrompt === "string" ? [{
6203
- type: "text",
6204
- text: `${systemPrompt}\n\n${BASE_PROMPT}`
6205
- }] : [{
6206
- type: "text",
6207
- text: BASE_PROMPT
6208
- }, ...typeof systemPrompt.content === "string" ? [{
6209
- type: "text",
6210
- text: systemPrompt.content
6211
- }] : systemPrompt.content] : [{
6212
- type: "text",
6213
- text: BASE_PROMPT
6214
- }] });
6215
- /**
6216
- * Create backend configuration for filesystem middleware
6217
- * If no backend is provided, use a factory that creates a StateBackend
6218
- */
6219
- const filesystemBackend = backend ? backend : (config) => new StateBackend(config);
6220
- /**
6221
- * Skills middleware (created conditionally for runtime use)
6222
- */
6223
- const skillsMiddlewareArray = skills != null && skills.length > 0 ? [createSkillsMiddleware({
6224
- backend: filesystemBackend,
6225
- sources: skills
6226
- })] : [];
6227
- /**
6228
- * Memory middleware (created conditionally for runtime use)
6229
- */
6230
- const memoryMiddlewareArray = memory != null && memory.length > 0 ? [createMemoryMiddleware({
6231
- backend: filesystemBackend,
6232
- sources: memory,
6233
- addCacheControl: anthropicModel
6234
- })] : [];
6235
- /**
6236
- * Split the unified subagents array into sync and async subagents.
6237
- * AsyncSubAgents are identified by the presence of a `graphId` field.
6238
- */
6239
- const syncSubAgents = subagents.filter((a) => !isAsyncSubAgent(a));
6240
- const asyncSubAgents = subagents.filter((a) => isAsyncSubAgent(a));
6461
+ const cacheMiddleware = anthropicModel ? [anthropicPromptCachingMiddleware({
6462
+ unsupportedModelBehavior: "ignore",
6463
+ minMessagesToCache: 1
6464
+ }), createCacheBreakpointMiddleware()] : [];
6241
6465
  /**
6242
6466
  * Process subagents to add SkillsMiddleware for those with their own skills.
6243
6467
  *
6244
6468
  * Custom subagents do NOT inherit skills from the main agent by default.
6245
- * Only the general-purpose subagent inherits the main agent's skills (via defaultMiddleware).
6469
+ * Only the general-purpose subagent inherits the main agent's skills.
6246
6470
  * If a custom subagent needs skills, it must specify its own `skills` array.
6247
6471
  */
6248
- const processedSubagents = syncSubAgents.map((subagent) => {
6249
- /**
6250
- * CompiledSubAgent - use as-is (already has its own middleware baked in)
6251
- */
6252
- if (Runnable.isRunnable(subagent)) return subagent;
6253
- /**
6254
- * SubAgent without skills - use as-is
6255
- */
6256
- if (!("skills" in subagent) || subagent.skills?.length === 0) return subagent;
6257
- /**
6258
- * SubAgent with skills - add SkillsMiddleware BEFORE user's middleware
6259
- * Order: base middleware (via defaultMiddleware) → skills → user's middleware
6260
- * This matches Python's ordering in create_deep_agent
6261
- */
6262
- const subagentSkillsMiddleware = createSkillsMiddleware({
6263
- backend: filesystemBackend,
6264
- sources: subagent.skills ?? []
6265
- });
6472
+ const normalizeSubagentSpec = (input) => {
6473
+ const subagentMiddleware = [
6474
+ todoListMiddleware(),
6475
+ createFilesystemMiddleware({ backend }),
6476
+ createSummarizationMiddleware({
6477
+ backend,
6478
+ model
6479
+ }),
6480
+ createPatchToolCallsMiddleware(),
6481
+ ...input.skills != null && input.skills.length > 0 ? [createSkillsMiddleware({
6482
+ backend,
6483
+ sources: input.skills
6484
+ })] : [],
6485
+ ...input.middleware ?? [],
6486
+ ...cacheMiddleware
6487
+ ];
6266
6488
  return {
6267
- ...subagent,
6268
- middleware: [subagentSkillsMiddleware, ...subagent.middleware || []]
6489
+ ...input,
6490
+ tools: input.tools ?? [],
6491
+ middleware: subagentMiddleware
6269
6492
  };
6270
- });
6271
- /**
6272
- * Middleware for custom subagents (does NOT include skills from main agent).
6273
- * Custom subagents must define their own `skills` property to get skills.
6274
- *
6275
- * Uses createSummarizationMiddleware (deepagents version) with backend support
6276
- * and auto-computed defaults from model profile, matching Python's create_deep_agent.
6277
- * When trigger is not provided, defaults are lazily computed:
6278
- * - With model profile: fraction-based (trigger=0.85, keep=0.10)
6279
- * - Without profile: fixed (trigger=170k tokens, keep=6 messages)
6280
- */
6281
- const subagentMiddleware = [
6493
+ };
6494
+ const allSubagents = subagents;
6495
+ const asyncSubAgents = allSubagents.filter((item) => isAsyncSubAgent(item));
6496
+ const inlineSubagents = allSubagents.filter((item) => !isAsyncSubAgent(item)).map((item) => "runnable" in item ? item : normalizeSubagentSpec(item));
6497
+ if (!inlineSubagents.some((item) => item.name === GENERAL_PURPOSE_SUBAGENT["name"])) {
6498
+ const generalPurposeSpec = normalizeSubagentSpec({
6499
+ ...GENERAL_PURPOSE_SUBAGENT,
6500
+ model,
6501
+ skills,
6502
+ tools
6503
+ });
6504
+ inlineSubagents.unshift(generalPurposeSpec);
6505
+ }
6506
+ const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
6507
+ backend,
6508
+ sources: skills
6509
+ })] : [];
6510
+ const [todoMiddleware, fsMiddleware, subagentMiddleware, summarizationMiddleware, patchToolCallsMiddleware] = [
6282
6511
  todoListMiddleware(),
6283
- createFilesystemMiddleware({ backend: filesystemBackend }),
6512
+ createFilesystemMiddleware({ backend }),
6513
+ createSubAgentMiddleware({
6514
+ defaultModel: model,
6515
+ defaultTools: tools,
6516
+ defaultInterruptOn: interruptOn,
6517
+ subagents: inlineSubagents,
6518
+ generalPurposeAgent: false
6519
+ }),
6284
6520
  createSummarizationMiddleware({
6285
6521
  model,
6286
- backend: filesystemBackend
6522
+ backend
6287
6523
  }),
6288
6524
  createPatchToolCallsMiddleware()
6289
6525
  ];
6526
+ const middleware = [
6527
+ todoMiddleware,
6528
+ ...skillsMiddleware,
6529
+ fsMiddleware,
6530
+ subagentMiddleware,
6531
+ summarizationMiddleware,
6532
+ patchToolCallsMiddleware,
6533
+ ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : [],
6534
+ ...customMiddleware,
6535
+ ...cacheMiddleware,
6536
+ ...memory && memory.length > 0 ? [createMemoryMiddleware({
6537
+ backend,
6538
+ sources: memory,
6539
+ addCacheControl: anthropicModel
6540
+ })] : [],
6541
+ ...interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []
6542
+ ];
6290
6543
  /**
6291
6544
  * Return as DeepAgent with proper DeepAgentTypeConfig
6292
6545
  * - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)
@@ -6298,55 +6551,32 @@ function createDeepAgent(params = {}) {
6298
6551
  */
6299
6552
  return createAgent({
6300
6553
  model,
6301
- systemPrompt: finalSystemPrompt,
6554
+ systemPrompt: typeof systemPrompt === "string" ? new SystemMessage({ contentBlocks: [{
6555
+ type: "text",
6556
+ text: systemPrompt
6557
+ }, {
6558
+ type: "text",
6559
+ text: BASE_AGENT_PROMPT
6560
+ }] }) : SystemMessage.isInstance(systemPrompt) ? new SystemMessage({ contentBlocks: [...systemPrompt.contentBlocks, {
6561
+ type: "text",
6562
+ text: BASE_AGENT_PROMPT
6563
+ }] }) : new SystemMessage({ contentBlocks: [{
6564
+ type: "text",
6565
+ text: BASE_AGENT_PROMPT
6566
+ }] }),
6302
6567
  tools,
6303
- middleware: [
6304
- ...[
6305
- todoListMiddleware(),
6306
- createFilesystemMiddleware({ backend: filesystemBackend }),
6307
- createSubAgentMiddleware({
6308
- defaultModel: model,
6309
- defaultTools: tools,
6310
- defaultMiddleware: [...subagentMiddleware, ...anthropicModel ? [anthropicPromptCachingMiddleware({
6311
- unsupportedModelBehavior: "ignore",
6312
- minMessagesToCache: 1
6313
- }), createCacheBreakpointMiddleware()] : []],
6314
- generalPurposeMiddleware: [
6315
- ...subagentMiddleware,
6316
- ...skillsMiddlewareArray,
6317
- ...anthropicModel ? [anthropicPromptCachingMiddleware({
6318
- unsupportedModelBehavior: "ignore",
6319
- minMessagesToCache: 1
6320
- }), createCacheBreakpointMiddleware()] : []
6321
- ],
6322
- defaultInterruptOn: interruptOn,
6323
- subagents: processedSubagents,
6324
- generalPurposeAgent: true
6325
- }),
6326
- createSummarizationMiddleware({
6327
- model,
6328
- backend: filesystemBackend
6329
- }),
6330
- createPatchToolCallsMiddleware()
6331
- ],
6332
- ...skillsMiddlewareArray,
6333
- ...customMiddleware,
6334
- ...anthropicModel ? [anthropicPromptCachingMiddleware({
6335
- unsupportedModelBehavior: "ignore",
6336
- minMessagesToCache: 1
6337
- }), createCacheBreakpointMiddleware()] : [],
6338
- ...memoryMiddlewareArray,
6339
- ...interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : [],
6340
- ...asyncSubAgents && asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
6341
- ],
6342
- ...responseFormat != null && { responseFormat },
6568
+ middleware,
6569
+ ...responseFormat !== null && { responseFormat },
6343
6570
  contextSchema,
6344
6571
  checkpointer,
6345
6572
  store,
6346
6573
  name
6347
6574
  }).withConfig({
6348
6575
  recursionLimit: 1e4,
6349
- metadata: { ls_integration: "deepagents" }
6576
+ metadata: {
6577
+ ls_integration: "deepagents",
6578
+ lc_agent_name: name
6579
+ }
6350
6580
  });
6351
6581
  }
6352
6582
  //#endregion
@@ -6860,6 +7090,6 @@ function listSkills(options) {
6860
7090
  return Array.from(allSkills.values());
6861
7091
  }
6862
7092
  //#endregion
6863
- export { BaseSandbox, CompositeBackend, ConfigurationError, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, FilesystemBackend, GENERAL_PURPOSE_SUBAGENT, LangSmithSandbox, LocalShellBackend, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, SandboxError, StateBackend, StoreBackend, TASK_SYSTEM_PROMPT, adaptBackendProtocol, adaptSandboxProtocol, computeSummarizationDefaults, createAgentMemoryMiddleware, createAsyncSubAgentMiddleware, createCompletionNotifierMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isAsyncSubAgent, isSandboxBackend, isSandboxProtocol, listSkills, parseSkillMetadata };
7093
+ export { BaseSandbox, CompositeBackend, ConfigurationError, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT, FilesystemBackend, GENERAL_PURPOSE_SUBAGENT, LangSmithSandbox, LocalShellBackend, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, SandboxError, StateBackend, StoreBackend, TASK_SYSTEM_PROMPT, adaptBackendProtocol, adaptSandboxProtocol, computeSummarizationDefaults, createAgentMemoryMiddleware, createAsyncSubAgentMiddleware, createCompletionCallbackMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, createSummarizationMiddleware, filesValue, findProjectRoot, isAsyncSubAgent, isSandboxBackend, isSandboxProtocol, listSkills, parseSkillMetadata, resolveBackend };
6864
7094
 
6865
7095
  //# sourceMappingURL=index.js.map