deepagents 1.2.0 → 1.3.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.d.ts CHANGED
@@ -4,10 +4,11 @@ import { AnnotationRoot } from "@langchain/langgraph";
4
4
  import { StructuredTool as StructuredTool$1 } from "@langchain/core/tools";
5
5
  import { BaseLanguageModel, LanguageModelLike } from "@langchain/core/language_models/base";
6
6
  import { BaseCheckpointSaver, BaseStore } from "@langchain/langgraph-checkpoint";
7
+ import { Runnable } from "@langchain/core/runnables";
7
8
  import { InteropZodObject } from "@langchain/core/utils/types";
8
9
 
9
10
  //#region src/backends/protocol.d.ts
10
-
11
+ type MaybePromise<T> = T | Promise<T>;
11
12
  /**
12
13
  * Structured file listing info.
13
14
  *
@@ -65,6 +66,8 @@ interface WriteResult {
65
66
  * External backends set null (already persisted to disk/S3/database/etc).
66
67
  */
67
68
  filesUpdate?: Record<string, FileData> | null;
69
+ /** Metadata for the write operation, attached to the ToolMessage */
70
+ metadata?: Record<string, unknown>;
68
71
  }
69
72
  /**
70
73
  * Result from backend edit operations.
@@ -85,6 +88,8 @@ interface EditResult {
85
88
  filesUpdate?: Record<string, FileData> | null;
86
89
  /** Number of replacements made, undefined on failure */
87
90
  occurrences?: number;
91
+ /** Metadata for the edit operation, attached to the ToolMessage */
92
+ metadata?: Record<string, unknown>;
88
93
  }
89
94
  /**
90
95
  * Protocol for pluggable memory backends (single, unified).
@@ -107,7 +112,7 @@ interface BackendProtocol {
107
112
  * @param path - Absolute path to directory
108
113
  * @returns List of FileInfo objects for files and directories directly in the directory
109
114
  */
110
- lsInfo(path: string): FileInfo[] | Promise<FileInfo[]>;
115
+ lsInfo(path: string): MaybePromise<FileInfo[]>;
111
116
  /**
112
117
  * Read file content with line numbers or an error string.
113
118
  *
@@ -116,14 +121,14 @@ interface BackendProtocol {
116
121
  * @param limit - Maximum number of lines to read, default 2000
117
122
  * @returns Formatted file content with line numbers, or error message
118
123
  */
119
- read(filePath: string, offset?: number, limit?: number): string | Promise<string>;
124
+ read(filePath: string, offset?: number, limit?: number): MaybePromise<string>;
120
125
  /**
121
126
  * Read file content as raw FileData.
122
127
  *
123
128
  * @param filePath - Absolute file path
124
129
  * @returns Raw file content as FileData
125
130
  */
126
- readRaw(filePath: string): FileData | Promise<FileData>;
131
+ readRaw(filePath: string): MaybePromise<FileData>;
127
132
  /**
128
133
  * Structured search results or error string for invalid input.
129
134
  *
@@ -134,7 +139,7 @@ interface BackendProtocol {
134
139
  * @param glob - Optional glob pattern to filter files (e.g., "*.py")
135
140
  * @returns List of GrepMatch objects or error string for invalid regex
136
141
  */
137
- grepRaw(pattern: string, path?: string | null, glob?: string | null): GrepMatch[] | string | Promise<GrepMatch[] | string>;
142
+ grepRaw(pattern: string, path?: string | null, glob?: string | null): MaybePromise<GrepMatch[] | string>;
138
143
  /**
139
144
  * Structured glob matching returning FileInfo objects.
140
145
  *
@@ -142,7 +147,7 @@ interface BackendProtocol {
142
147
  * @param path - Base path to search from (default: "/")
143
148
  * @returns List of FileInfo objects matching the pattern
144
149
  */
145
- globInfo(pattern: string, path?: string): FileInfo[] | Promise<FileInfo[]>;
150
+ globInfo(pattern: string, path?: string): MaybePromise<FileInfo[]>;
146
151
  /**
147
152
  * Create a new file.
148
153
  *
@@ -150,7 +155,7 @@ interface BackendProtocol {
150
155
  * @param content - File content as string
151
156
  * @returns WriteResult with error populated on failure
152
157
  */
153
- write(filePath: string, content: string): WriteResult | Promise<WriteResult>;
158
+ write(filePath: string, content: string): MaybePromise<WriteResult>;
154
159
  /**
155
160
  * Edit a file by replacing string occurrences.
156
161
  *
@@ -160,7 +165,7 @@ interface BackendProtocol {
160
165
  * @param replaceAll - If true, replace all occurrences (default: false)
161
166
  * @returns EditResult with error, path, filesUpdate, and occurrences
162
167
  */
163
- edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): EditResult | Promise<EditResult>;
168
+ edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): MaybePromise<EditResult>;
164
169
  }
165
170
  /**
166
171
  * State and store container for backend initialization.
@@ -198,15 +203,6 @@ interface StateAndStore {
198
203
  type BackendFactory = (stateAndStore: StateAndStore) => BackendProtocol;
199
204
  //#endregion
200
205
  //#region src/middleware/fs.d.ts
201
- type FilesystemEventResponse = {
202
- kind: "raw-contents";
203
- } | {
204
- kind: "metadata";
205
- data: Record<string, unknown>;
206
- };
207
- interface FilesystemEvents {
208
- onWrite?: (path: string, backend: BackendProtocol) => void | FilesystemEventResponse | Promise<void | FilesystemEventResponse>;
209
- }
210
206
  /**
211
207
  * Options for creating filesystem middleware.
212
208
  */
@@ -219,8 +215,6 @@ interface FilesystemMiddlewareOptions {
219
215
  customToolDescriptions?: Record<string, string> | null;
220
216
  /** Optional token limit before evicting a tool result to the filesystem (default: 20000 tokens, ~80KB) */
221
217
  toolTokenLimitBeforeEvict?: number | null;
222
- /** Filesystem events callbacks */
223
- events?: FilesystemEvents;
224
218
  }
225
219
  /**
226
220
  * Create filesystem middleware with all tools and features.
@@ -228,6 +222,17 @@ interface FilesystemMiddlewareOptions {
228
222
  declare function createFilesystemMiddleware(options?: FilesystemMiddlewareOptions): langchain0.AgentMiddleware<any, undefined, any>;
229
223
  //#endregion
230
224
  //#region src/middleware/subagents.d.ts
225
+ /**
226
+ * Type definitions for pre-compiled agents.
227
+ */
228
+ interface CompiledSubAgent {
229
+ /** The name of the agent */
230
+ name: string;
231
+ /** The description of the agent */
232
+ description: string;
233
+ /** The agent instance */
234
+ runnable: ReactAgent<any, any, any, any> | Runnable;
235
+ }
231
236
  /**
232
237
  * Type definitions for subagents
233
238
  */
@@ -260,7 +265,7 @@ interface SubAgentMiddlewareOptions {
260
265
  /** The tool configs for the default general-purpose subagent */
261
266
  defaultInterruptOn?: Record<string, boolean | InterruptOnConfig> | null;
262
267
  /** A list of additional subagents to provide to the agent */
263
- subagents?: Array<SubAgent>;
268
+ subagents?: (SubAgent | CompiledSubAgent)[];
264
269
  /** Full system prompt override */
265
270
  systemPrompt?: string | null;
266
271
  /** Whether to include the general-purpose agent */
@@ -627,7 +632,7 @@ interface CreateDeepAgentParams<ContextSchema extends AnnotationRoot<any> | Inte
627
632
  /** Custom middleware to apply after standard middleware */
628
633
  middleware?: AgentMiddleware[];
629
634
  /** List of subagent specifications for task delegation */
630
- subagents?: SubAgent[];
635
+ subagents?: (SubAgent | CompiledSubAgent)[];
631
636
  /** Structured output response format for the agent */
632
637
  responseFormat?: any;
633
638
  /** Optional schema for context (not persisted between invocations) */
@@ -667,4 +672,4 @@ interface CreateDeepAgentParams<ContextSchema extends AnnotationRoot<any> | Inte
667
672
  */
668
673
  declare function createDeepAgent<ContextSchema extends AnnotationRoot<any> | InteropZodObject = AnnotationRoot<any>>(params?: CreateDeepAgentParams<ContextSchema>): ReactAgent<any, any, ContextSchema, any>;
669
674
  //#endregion
670
- export { type BackendFactory, type BackendProtocol, CompositeBackend, type CreateDeepAgentParams, type EditResult, type FileData, type FileInfo, FilesystemBackend, type FilesystemMiddlewareOptions, type GrepMatch, StateBackend, StoreBackend, type SubAgent, type SubAgentMiddlewareOptions, type WriteResult, createDeepAgent, createFilesystemMiddleware, createPatchToolCallsMiddleware, createSubAgentMiddleware };
675
+ export { type BackendFactory, type BackendProtocol, type CompiledSubAgent, CompositeBackend, type CreateDeepAgentParams, type EditResult, type FileData, type FileInfo, FilesystemBackend, type FilesystemMiddlewareOptions, type GrepMatch, StateBackend, StoreBackend, type SubAgent, type SubAgentMiddlewareOptions, type WriteResult, createDeepAgent, createFilesystemMiddleware, createPatchToolCallsMiddleware, createSubAgentMiddleware };
package/dist/index.js CHANGED
@@ -414,12 +414,6 @@ function getBackend(backend, stateAndStore) {
414
414
  if (typeof backend === "function") return backend(stateAndStore);
415
415
  return backend;
416
416
  }
417
- /**
418
- * Helper to await if Promise, otherwise return value directly.
419
- */
420
- async function awaitIfPromise(value) {
421
- return value;
422
- }
423
417
  const FILESYSTEM_SYSTEM_PROMPT = `You have access to a virtual filesystem. All file paths must start with a /.
424
418
 
425
419
  - ls: list files in a directory (requires absolute path)
@@ -445,7 +439,7 @@ function createLsTool(backend, options) {
445
439
  store: config.store
446
440
  });
447
441
  const path$1 = input.path || "/";
448
- const infos = await awaitIfPromise(resolvedBackend.lsInfo(path$1));
442
+ const infos = await resolvedBackend.lsInfo(path$1);
449
443
  if (infos.length === 0) return `No files found in ${path$1}`;
450
444
  const lines = [];
451
445
  for (const info of infos) if (info.is_dir) lines.push(`${info.path} (directory)`);
@@ -471,7 +465,7 @@ function createReadFileTool(backend, options) {
471
465
  store: config.store
472
466
  });
473
467
  const { file_path, offset = 0, limit = 2e3 } = input;
474
- return await awaitIfPromise(resolvedBackend.read(file_path, offset, limit));
468
+ return await resolvedBackend.read(file_path, offset, limit);
475
469
  }, {
476
470
  name: "read_file",
477
471
  description: customDescription || READ_FILE_TOOL_DESCRIPTION,
@@ -486,7 +480,7 @@ function createReadFileTool(backend, options) {
486
480
  * Create write_file tool using backend.
487
481
  */
488
482
  function createWriteFileTool(backend, options) {
489
- const { customDescription, events } = options;
483
+ const { customDescription } = options;
490
484
  return tool(async (input, config) => {
491
485
  const resolvedBackend = getBackend(backend, {
492
486
  state: getCurrentTaskInput(config),
@@ -495,16 +489,11 @@ function createWriteFileTool(backend, options) {
495
489
  const { file_path, content } = input;
496
490
  const result = await resolvedBackend.write(file_path, content);
497
491
  if (result.error) return result.error;
498
- const resolved = await events?.onWrite?.(file_path, resolvedBackend) ?? void 0;
499
- const metadata = await (async () => {
500
- if (resolved?.kind === "metadata") return resolved.data;
501
- if (resolved?.kind === "raw-contents") return { ...await resolvedBackend.readRaw(file_path) };
502
- })();
503
492
  const message = new ToolMessage({
504
493
  content: `Successfully wrote to '${file_path}'`,
505
494
  tool_call_id: config.toolCall?.id,
506
495
  name: "write_file",
507
- metadata
496
+ metadata: result.metadata
508
497
  });
509
498
  if (result.filesUpdate) return new Command({ update: {
510
499
  files: result.filesUpdate,
@@ -524,25 +513,20 @@ function createWriteFileTool(backend, options) {
524
513
  * Create edit_file tool using backend.
525
514
  */
526
515
  function createEditFileTool(backend, options) {
527
- const { customDescription, events } = options;
516
+ const { customDescription } = options;
528
517
  return tool(async (input, config) => {
529
518
  const resolvedBackend = getBackend(backend, {
530
519
  state: getCurrentTaskInput(config),
531
520
  store: config.store
532
521
  });
533
522
  const { file_path, old_string, new_string, replace_all = false } = input;
534
- const result = await awaitIfPromise(resolvedBackend.edit(file_path, old_string, new_string, replace_all));
523
+ const result = await resolvedBackend.edit(file_path, old_string, new_string, replace_all);
535
524
  if (result.error) return result.error;
536
- const resolved = await events?.onWrite?.(file_path, resolvedBackend) ?? void 0;
537
- const metadata = await (async () => {
538
- if (resolved?.kind === "metadata") return resolved.data;
539
- if (resolved?.kind === "raw-contents") return { ...await resolvedBackend.readRaw(file_path) };
540
- })();
541
525
  const message = new ToolMessage({
542
526
  content: `Successfully replaced ${result.occurrences} occurrence(s) in '${file_path}'`,
543
527
  tool_call_id: config.toolCall?.id,
544
528
  name: "edit_file",
545
- metadata
529
+ metadata: result.metadata
546
530
  });
547
531
  if (result.filesUpdate) return new Command({ update: {
548
532
  files: result.filesUpdate,
@@ -571,7 +555,7 @@ function createGlobTool(backend, options) {
571
555
  store: config.store
572
556
  });
573
557
  const { pattern, path: path$1 = "/" } = input;
574
- const infos = await awaitIfPromise(resolvedBackend.globInfo(pattern, path$1));
558
+ const infos = await resolvedBackend.globInfo(pattern, path$1);
575
559
  if (infos.length === 0) return `No files found matching pattern '${pattern}'`;
576
560
  return infos.map((info) => info.path).join("\n");
577
561
  }, {
@@ -594,7 +578,7 @@ function createGrepTool(backend, options) {
594
578
  store: config.store
595
579
  });
596
580
  const { pattern, path: path$1 = "/", glob = null } = input;
597
- const result = await awaitIfPromise(resolvedBackend.grepRaw(pattern, path$1, glob));
581
+ const result = await resolvedBackend.grepRaw(pattern, path$1, glob);
598
582
  if (typeof result === "string") return result;
599
583
  if (result.length === 0) return `No matches found for pattern '${pattern}'`;
600
584
  const lines = [];
@@ -621,33 +605,15 @@ function createGrepTool(backend, options) {
621
605
  * Create filesystem middleware with all tools and features.
622
606
  */
623
607
  function createFilesystemMiddleware(options = {}) {
624
- const { backend = (stateAndStore) => new StateBackend(stateAndStore), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, events = void 0 } = options;
608
+ const { backend = (stateAndStore) => new StateBackend(stateAndStore), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4 } = options;
625
609
  const systemPrompt = customSystemPrompt || FILESYSTEM_SYSTEM_PROMPT;
626
610
  const tools = [
627
- createLsTool(backend, {
628
- customDescription: customToolDescriptions?.ls ?? null,
629
- events
630
- }),
631
- createReadFileTool(backend, {
632
- customDescription: customToolDescriptions?.read_file ?? null,
633
- events
634
- }),
635
- createWriteFileTool(backend, {
636
- customDescription: customToolDescriptions?.write_file ?? null,
637
- events
638
- }),
639
- createEditFileTool(backend, {
640
- customDescription: customToolDescriptions?.edit_file ?? null,
641
- events
642
- }),
643
- createGlobTool(backend, {
644
- customDescription: customToolDescriptions?.glob ?? null,
645
- events
646
- }),
647
- createGrepTool(backend, {
648
- customDescription: customToolDescriptions?.grep ?? null,
649
- events
650
- })
611
+ createLsTool(backend, { customDescription: customToolDescriptions?.ls }),
612
+ createReadFileTool(backend, { customDescription: customToolDescriptions?.read_file }),
613
+ createWriteFileTool(backend, { customDescription: customToolDescriptions?.write_file }),
614
+ createEditFileTool(backend, { customDescription: customToolDescriptions?.edit_file }),
615
+ createGlobTool(backend, { customDescription: customToolDescriptions?.glob }),
616
+ createGrepTool(backend, { customDescription: customToolDescriptions?.grep })
651
617
  ];
652
618
  return createMiddleware({
653
619
  name: "FilesystemMiddleware",
@@ -673,7 +639,7 @@ function createFilesystemMiddleware(options = {}) {
673
639
  store: request.config?.store
674
640
  });
675
641
  const evictPath = `/large_tool_results/${sanitizeToolCallId(request.toolCall?.id || msg.tool_call_id)}`;
676
- const writeResult = await awaitIfPromise(resolvedBackend.write(evictPath, msg.content));
642
+ const writeResult = await resolvedBackend.write(evictPath, msg.content);
677
643
  if (writeResult.error) return {
678
644
  message: msg,
679
645
  filesUpdate: null
@@ -919,15 +885,18 @@ function getSubagents(options) {
919
885
  }
920
886
  for (const agentParams of subagents) {
921
887
  subagentDescriptions.push(`- ${agentParams.name}: ${agentParams.description}`);
922
- const middleware = agentParams.middleware ? [...defaultSubagentMiddleware, ...agentParams.middleware] : [...defaultSubagentMiddleware];
923
- const interruptOn = agentParams.interruptOn || defaultInterruptOn;
924
- if (interruptOn) middleware.push(humanInTheLoopMiddleware({ interruptOn }));
925
- agents[agentParams.name] = createAgent({
926
- model: agentParams.model ?? defaultModel,
927
- systemPrompt: agentParams.systemPrompt,
928
- tools: agentParams.tools ?? defaultTools,
929
- middleware
930
- });
888
+ if ("runnable" in agentParams) agents[agentParams.name] = agentParams.runnable;
889
+ else {
890
+ const middleware = agentParams.middleware ? [...defaultSubagentMiddleware, ...agentParams.middleware] : [...defaultSubagentMiddleware];
891
+ const interruptOn = agentParams.interruptOn || defaultInterruptOn;
892
+ if (interruptOn) middleware.push(humanInTheLoopMiddleware({ interruptOn }));
893
+ agents[agentParams.name] = createAgent({
894
+ model: agentParams.model ?? defaultModel,
895
+ systemPrompt: agentParams.systemPrompt,
896
+ tools: agentParams.tools ?? defaultTools,
897
+ middleware
898
+ });
899
+ }
931
900
  }
932
901
  return {
933
902
  agents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepagents",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Deep Agents - a library for building controllable AI agents with LangGraph",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",