deepagents 1.6.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +166 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -56
- package/dist/index.d.ts +48 -56
- package/dist/index.js +166 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -193,8 +193,14 @@ function formatReadResponse(fileData, offset, limit) {
|
|
|
193
193
|
* @param newString - Replacement string
|
|
194
194
|
* @param replaceAll - Whether to replace all occurrences
|
|
195
195
|
* @returns Tuple of [new_content, occurrences] on success, or error message string
|
|
196
|
+
*
|
|
197
|
+
* Special case: When both content and oldString are empty, this sets the initial
|
|
198
|
+
* content to newString. This allows editing empty files by treating empty oldString
|
|
199
|
+
* as "set initial content" rather than "replace nothing".
|
|
196
200
|
*/
|
|
197
201
|
function performStringReplacement(content, oldString, newString, replaceAll) {
|
|
202
|
+
if (content === "" && oldString === "") return [newString, 0];
|
|
203
|
+
if (oldString === "") return "Error: oldString cannot be empty when file has content";
|
|
198
204
|
const occurrences = content.split(oldString).length - 1;
|
|
199
205
|
if (occurrences === 0) return `Error: String not found in file: '${oldString}'`;
|
|
200
206
|
if (occurrences > 1 && !replaceAll) return `Error: String '${oldString}' appears ${occurrences} times in file. Use replace_all=True to replace all instances, or provide a more specific string with surrounding context.`;
|
|
@@ -557,6 +563,18 @@ const TOOLS_EXCLUDED_FROM_EVICTION = [
|
|
|
557
563
|
*/
|
|
558
564
|
const NUM_CHARS_PER_TOKEN = 4;
|
|
559
565
|
/**
|
|
566
|
+
* Default values for read_file tool pagination (in lines).
|
|
567
|
+
*/
|
|
568
|
+
const DEFAULT_READ_LINE_OFFSET = 0;
|
|
569
|
+
const DEFAULT_READ_LINE_LIMIT = 100;
|
|
570
|
+
/**
|
|
571
|
+
* Template for truncation message in read_file.
|
|
572
|
+
* {file_path} will be filled in at runtime.
|
|
573
|
+
*/
|
|
574
|
+
const READ_FILE_TRUNCATION_MSG = `
|
|
575
|
+
|
|
576
|
+
[Output was truncated due to size limits. The file content is very large. Consider reformatting the file to make it easier to navigate. For example, if this is JSON, use execute(command='jq . {file_path}') to pretty-print it with line breaks. For other formats, you can use appropriate formatting tools to split long lines.]`;
|
|
577
|
+
/**
|
|
560
578
|
* Message template for evicted tool results.
|
|
561
579
|
*/
|
|
562
580
|
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}
|
|
@@ -661,7 +679,7 @@ const READ_FILE_TOOL_DESCRIPTION = `Reads a file from the filesystem.
|
|
|
661
679
|
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.
|
|
662
680
|
|
|
663
681
|
Usage:
|
|
664
|
-
- By default, it reads up to
|
|
682
|
+
- By default, it reads up to 100 lines starting from the beginning of the file
|
|
665
683
|
- **IMPORTANT for large files and codebase exploration**: Use pagination with offset and limit parameters to avoid context overflow
|
|
666
684
|
- First scan: read_file(path, limit=100) to see file structure
|
|
667
685
|
- Read more sections: read_file(path, offset=100, limit=200) for next 200 lines
|
|
@@ -781,21 +799,29 @@ function createLsTool(backend, options) {
|
|
|
781
799
|
* Create read_file tool using backend.
|
|
782
800
|
*/
|
|
783
801
|
function createReadFileTool(backend, options) {
|
|
784
|
-
const { customDescription } = options;
|
|
802
|
+
const { customDescription, toolTokenLimitBeforeEvict } = options;
|
|
785
803
|
return (0, langchain.tool)(async (input, config) => {
|
|
786
804
|
const resolvedBackend = getBackend(backend, {
|
|
787
805
|
state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
|
|
788
806
|
store: config.store
|
|
789
807
|
});
|
|
790
|
-
const { file_path, offset =
|
|
791
|
-
|
|
808
|
+
const { file_path, offset = DEFAULT_READ_LINE_OFFSET, limit = DEFAULT_READ_LINE_LIMIT } = input;
|
|
809
|
+
let result = await resolvedBackend.read(file_path, offset, limit);
|
|
810
|
+
const lines = result.split("\n");
|
|
811
|
+
if (lines.length > limit) result = lines.slice(0, limit).join("\n");
|
|
812
|
+
if (toolTokenLimitBeforeEvict && result.length >= NUM_CHARS_PER_TOKEN * toolTokenLimitBeforeEvict) {
|
|
813
|
+
const truncationMsg = READ_FILE_TRUNCATION_MSG.replace("{file_path}", file_path);
|
|
814
|
+
const maxContentLength = NUM_CHARS_PER_TOKEN * toolTokenLimitBeforeEvict - truncationMsg.length;
|
|
815
|
+
result = result.substring(0, maxContentLength) + truncationMsg;
|
|
816
|
+
}
|
|
817
|
+
return result;
|
|
792
818
|
}, {
|
|
793
819
|
name: "read_file",
|
|
794
820
|
description: customDescription || READ_FILE_TOOL_DESCRIPTION,
|
|
795
821
|
schema: zod_v4.z.object({
|
|
796
822
|
file_path: zod_v4.z.string().describe("Absolute path to the file to read"),
|
|
797
|
-
offset: zod_v4.z.coerce.number().optional().default(
|
|
798
|
-
limit: zod_v4.z.coerce.number().optional().default(
|
|
823
|
+
offset: zod_v4.z.coerce.number().optional().default(DEFAULT_READ_LINE_OFFSET).describe("Line offset to start reading from (0-indexed)"),
|
|
824
|
+
limit: zod_v4.z.coerce.number().optional().default(DEFAULT_READ_LINE_LIMIT).describe("Maximum number of lines to read")
|
|
799
825
|
})
|
|
800
826
|
});
|
|
801
827
|
}
|
|
@@ -960,7 +986,10 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
960
986
|
stateSchema: FilesystemStateSchema,
|
|
961
987
|
tools: [
|
|
962
988
|
createLsTool(backend, { customDescription: customToolDescriptions?.ls }),
|
|
963
|
-
createReadFileTool(backend, {
|
|
989
|
+
createReadFileTool(backend, {
|
|
990
|
+
customDescription: customToolDescriptions?.read_file,
|
|
991
|
+
toolTokenLimitBeforeEvict
|
|
992
|
+
}),
|
|
964
993
|
createWriteFileTool(backend, { customDescription: customToolDescriptions?.write_file }),
|
|
965
994
|
createEditFileTool(backend, { customDescription: customToolDescriptions?.edit_file }),
|
|
966
995
|
createGlobTool(backend, { customDescription: customToolDescriptions?.glob }),
|
|
@@ -1324,12 +1353,52 @@ function createSubAgentMiddleware(options) {
|
|
|
1324
1353
|
//#endregion
|
|
1325
1354
|
//#region src/middleware/patch_tool_calls.ts
|
|
1326
1355
|
/**
|
|
1356
|
+
* Patch dangling tool calls in a messages array.
|
|
1357
|
+
* Returns the patched messages array and a flag indicating if patching was needed.
|
|
1358
|
+
*
|
|
1359
|
+
* @param messages - The messages array to patch
|
|
1360
|
+
* @returns Object with patched messages and needsPatch flag
|
|
1361
|
+
*/
|
|
1362
|
+
function patchDanglingToolCalls(messages) {
|
|
1363
|
+
if (!messages || messages.length === 0) return {
|
|
1364
|
+
patchedMessages: [],
|
|
1365
|
+
needsPatch: false
|
|
1366
|
+
};
|
|
1367
|
+
const patchedMessages = [];
|
|
1368
|
+
let needsPatch = false;
|
|
1369
|
+
for (let i = 0; i < messages.length; i++) {
|
|
1370
|
+
const msg = messages[i];
|
|
1371
|
+
patchedMessages.push(msg);
|
|
1372
|
+
if (langchain.AIMessage.isInstance(msg) && msg.tool_calls != null) {
|
|
1373
|
+
for (const toolCall of msg.tool_calls) if (!messages.slice(i).find((m) => langchain.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id)) {
|
|
1374
|
+
needsPatch = true;
|
|
1375
|
+
const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;
|
|
1376
|
+
patchedMessages.push(new langchain.ToolMessage({
|
|
1377
|
+
content: toolMsg,
|
|
1378
|
+
name: toolCall.name,
|
|
1379
|
+
tool_call_id: toolCall.id
|
|
1380
|
+
}));
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
return {
|
|
1385
|
+
patchedMessages,
|
|
1386
|
+
needsPatch
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1327
1390
|
* Create middleware that patches dangling tool calls in the messages history.
|
|
1328
1391
|
*
|
|
1329
1392
|
* When an AI message contains tool_calls but subsequent messages don't include
|
|
1330
1393
|
* the corresponding ToolMessage responses, this middleware adds synthetic
|
|
1331
1394
|
* ToolMessages saying the tool call was cancelled.
|
|
1332
1395
|
*
|
|
1396
|
+
* This middleware patches in two places:
|
|
1397
|
+
* 1. `beforeAgent`: Patches state at the start of the agent loop (handles most cases)
|
|
1398
|
+
* 2. `wrapModelCall`: Patches the request right before model invocation (handles
|
|
1399
|
+
* edge cases like HITL rejection during graph resume where state updates from
|
|
1400
|
+
* beforeAgent may not be applied in time)
|
|
1401
|
+
*
|
|
1333
1402
|
* @returns AgentMiddleware that patches dangling tool calls
|
|
1334
1403
|
*
|
|
1335
1404
|
* @example
|
|
@@ -1349,22 +1418,22 @@ function createPatchToolCallsMiddleware() {
|
|
|
1349
1418
|
beforeAgent: async (state) => {
|
|
1350
1419
|
const messages = state.messages;
|
|
1351
1420
|
if (!messages || messages.length === 0) return;
|
|
1352
|
-
const patchedMessages =
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
for (const toolCall of msg.tool_calls) if (!messages.slice(i).find((m) => langchain.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id)) {
|
|
1358
|
-
const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;
|
|
1359
|
-
patchedMessages.push(new langchain.ToolMessage({
|
|
1360
|
-
content: toolMsg,
|
|
1361
|
-
name: toolCall.name,
|
|
1362
|
-
tool_call_id: toolCall.id
|
|
1363
|
-
}));
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1421
|
+
const { patchedMessages, needsPatch } = patchDanglingToolCalls(messages);
|
|
1422
|
+
/**
|
|
1423
|
+
* Only trigger REMOVE_ALL_MESSAGES if patching is actually needed
|
|
1424
|
+
*/
|
|
1425
|
+
if (!needsPatch) return;
|
|
1367
1426
|
return { messages: [new _langchain_core_messages.RemoveMessage({ id: _langchain_langgraph.REMOVE_ALL_MESSAGES }), ...patchedMessages] };
|
|
1427
|
+
},
|
|
1428
|
+
wrapModelCall: async (request, handler) => {
|
|
1429
|
+
const messages = request.messages;
|
|
1430
|
+
if (!messages || messages.length === 0) return handler(request);
|
|
1431
|
+
const { patchedMessages, needsPatch } = patchDanglingToolCalls(messages);
|
|
1432
|
+
if (!needsPatch) return handler(request);
|
|
1433
|
+
return handler({
|
|
1434
|
+
...request,
|
|
1435
|
+
messages: patchedMessages
|
|
1436
|
+
});
|
|
1368
1437
|
}
|
|
1369
1438
|
});
|
|
1370
1439
|
}
|
|
@@ -1423,7 +1492,13 @@ function createPatchToolCallsMiddleware() {
|
|
|
1423
1492
|
/**
|
|
1424
1493
|
* State schema for memory middleware.
|
|
1425
1494
|
*/
|
|
1426
|
-
const MemoryStateSchema =
|
|
1495
|
+
const MemoryStateSchema = new _langchain_langgraph.StateSchema({
|
|
1496
|
+
memoryContents: zod.z.record(zod.z.string(), zod.z.string()).optional(),
|
|
1497
|
+
files: new _langchain_langgraph.ReducedValue(zod.z.record(zod.z.string(), FileDataSchema).default(() => ({})), {
|
|
1498
|
+
inputSchema: zod.z.record(zod.z.string(), FileDataSchema.nullable()).optional(),
|
|
1499
|
+
reducer: fileDataReducer
|
|
1500
|
+
})
|
|
1501
|
+
});
|
|
1427
1502
|
/**
|
|
1428
1503
|
* Default system prompt template for memory.
|
|
1429
1504
|
* Ported from Python's comprehensive memory guidelines.
|
|
@@ -1655,10 +1730,16 @@ function skillsMetadataReducer(current, update) {
|
|
|
1655
1730
|
* State schema for skills middleware.
|
|
1656
1731
|
* Uses ReducedValue for skillsMetadata to allow concurrent updates from parallel subagents.
|
|
1657
1732
|
*/
|
|
1658
|
-
const SkillsStateSchema = new _langchain_langgraph.StateSchema({
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1733
|
+
const SkillsStateSchema = new _langchain_langgraph.StateSchema({
|
|
1734
|
+
skillsMetadata: new _langchain_langgraph.ReducedValue(zod.z.array(SkillMetadataEntrySchema).default(() => []), {
|
|
1735
|
+
inputSchema: zod.z.array(SkillMetadataEntrySchema).optional(),
|
|
1736
|
+
reducer: skillsMetadataReducer
|
|
1737
|
+
}),
|
|
1738
|
+
files: new _langchain_langgraph.ReducedValue(zod.z.record(zod.z.string(), FileDataSchema).default(() => ({})), {
|
|
1739
|
+
inputSchema: zod.z.record(zod.z.string(), FileDataSchema.nullable()).optional(),
|
|
1740
|
+
reducer: fileDataReducer
|
|
1741
|
+
})
|
|
1742
|
+
});
|
|
1662
1743
|
/**
|
|
1663
1744
|
* Skills System Documentation prompt template.
|
|
1664
1745
|
*/
|
|
@@ -1879,7 +1960,7 @@ function createSkillsMiddleware(options) {
|
|
|
1879
1960
|
stateSchema: SkillsStateSchema,
|
|
1880
1961
|
async beforeAgent(state) {
|
|
1881
1962
|
if (loadedSkills.length > 0) return;
|
|
1882
|
-
if ("skillsMetadata" in state && state.skillsMetadata
|
|
1963
|
+
if ("skillsMetadata" in state && Array.isArray(state.skillsMetadata) && state.skillsMetadata.length > 0) {
|
|
1883
1964
|
loadedSkills = state.skillsMetadata;
|
|
1884
1965
|
return;
|
|
1885
1966
|
}
|
|
@@ -3457,6 +3538,9 @@ const BASE_PROMPT = `In order to complete the objective that the user asks of yo
|
|
|
3457
3538
|
*/
|
|
3458
3539
|
function createDeepAgent(params = {}) {
|
|
3459
3540
|
const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name, memory, skills } = params;
|
|
3541
|
+
/**
|
|
3542
|
+
* Combine system prompt with base prompt like Python implementation
|
|
3543
|
+
*/
|
|
3460
3544
|
const finalSystemPrompt = systemPrompt ? typeof systemPrompt === "string" ? `${systemPrompt}\n\n${BASE_PROMPT}` : new langchain.SystemMessage({ content: [{
|
|
3461
3545
|
type: "text",
|
|
3462
3546
|
text: BASE_PROMPT
|
|
@@ -3464,22 +3548,61 @@ function createDeepAgent(params = {}) {
|
|
|
3464
3548
|
type: "text",
|
|
3465
3549
|
text: systemPrompt.content
|
|
3466
3550
|
}] : systemPrompt.content] }) : BASE_PROMPT;
|
|
3551
|
+
/**
|
|
3552
|
+
* Create backend configuration for filesystem middleware
|
|
3553
|
+
* If no backend is provided, use a factory that creates a StateBackend
|
|
3554
|
+
*/
|
|
3467
3555
|
const filesystemBackend = backend ? backend : (config) => new StateBackend(config);
|
|
3468
|
-
|
|
3556
|
+
/**
|
|
3557
|
+
* Skills middleware (created conditionally for runtime use)
|
|
3558
|
+
*/
|
|
3559
|
+
const skillsMiddlewareArray = skills != null && skills.length > 0 ? [createSkillsMiddleware({
|
|
3469
3560
|
backend: filesystemBackend,
|
|
3470
3561
|
sources: skills
|
|
3471
3562
|
})] : [];
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3563
|
+
/**
|
|
3564
|
+
* Memory middleware (created conditionally for runtime use)
|
|
3565
|
+
*/
|
|
3566
|
+
const memoryMiddlewareArray = memory != null && memory.length > 0 ? [createMemoryMiddleware({
|
|
3567
|
+
backend: filesystemBackend,
|
|
3568
|
+
sources: memory
|
|
3569
|
+
})] : [];
|
|
3570
|
+
/**
|
|
3571
|
+
* Return as DeepAgent with proper DeepAgentTypeConfig
|
|
3572
|
+
* - Response: TResponse (from responseFormat parameter)
|
|
3573
|
+
* - State: undefined (state comes from middleware)
|
|
3574
|
+
* - Context: ContextSchema
|
|
3575
|
+
* - Middleware: AllMiddleware (built-in + custom + subagent middleware for state inference)
|
|
3576
|
+
* - Tools: TTools
|
|
3577
|
+
* - Subagents: TSubagents (for type-safe streaming)
|
|
3578
|
+
*/
|
|
3579
|
+
return (0, langchain.createAgent)({
|
|
3580
|
+
model,
|
|
3581
|
+
systemPrompt: finalSystemPrompt,
|
|
3582
|
+
tools,
|
|
3583
|
+
middleware: [
|
|
3584
|
+
...[
|
|
3480
3585
|
(0, langchain.todoListMiddleware)(),
|
|
3481
|
-
...skillsMiddleware,
|
|
3482
3586
|
createFilesystemMiddleware({ backend: filesystemBackend }),
|
|
3587
|
+
createSubAgentMiddleware({
|
|
3588
|
+
defaultModel: model,
|
|
3589
|
+
defaultTools: tools,
|
|
3590
|
+
defaultMiddleware: [
|
|
3591
|
+
(0, langchain.todoListMiddleware)(),
|
|
3592
|
+
...skillsMiddlewareArray,
|
|
3593
|
+
createFilesystemMiddleware({ backend: filesystemBackend }),
|
|
3594
|
+
(0, langchain.summarizationMiddleware)({
|
|
3595
|
+
model,
|
|
3596
|
+
trigger: { tokens: 17e4 },
|
|
3597
|
+
keep: { messages: 6 }
|
|
3598
|
+
}),
|
|
3599
|
+
(0, langchain.anthropicPromptCachingMiddleware)({ unsupportedModelBehavior: "ignore" }),
|
|
3600
|
+
createPatchToolCallsMiddleware()
|
|
3601
|
+
],
|
|
3602
|
+
defaultInterruptOn: interruptOn,
|
|
3603
|
+
subagents,
|
|
3604
|
+
generalPurposeAgent: true
|
|
3605
|
+
}),
|
|
3483
3606
|
(0, langchain.summarizationMiddleware)({
|
|
3484
3607
|
model,
|
|
3485
3608
|
trigger: { tokens: 17e4 },
|
|
@@ -3488,28 +3611,11 @@ function createDeepAgent(params = {}) {
|
|
|
3488
3611
|
(0, langchain.anthropicPromptCachingMiddleware)({ unsupportedModelBehavior: "ignore" }),
|
|
3489
3612
|
createPatchToolCallsMiddleware()
|
|
3490
3613
|
],
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
model,
|
|
3497
|
-
trigger: { tokens: 17e4 },
|
|
3498
|
-
keep: { messages: 6 }
|
|
3499
|
-
}),
|
|
3500
|
-
(0, langchain.anthropicPromptCachingMiddleware)({ unsupportedModelBehavior: "ignore" }),
|
|
3501
|
-
createPatchToolCallsMiddleware(),
|
|
3502
|
-
...memory != null && memory.length > 0 ? [createMemoryMiddleware({
|
|
3503
|
-
backend: filesystemBackend,
|
|
3504
|
-
sources: memory
|
|
3505
|
-
})] : []
|
|
3506
|
-
];
|
|
3507
|
-
if (interruptOn) builtInMiddleware.push((0, langchain.humanInTheLoopMiddleware)({ interruptOn }));
|
|
3508
|
-
return (0, langchain.createAgent)({
|
|
3509
|
-
model,
|
|
3510
|
-
systemPrompt: finalSystemPrompt,
|
|
3511
|
-
tools,
|
|
3512
|
-
middleware: [...builtInMiddleware, ...customMiddleware],
|
|
3614
|
+
...skillsMiddlewareArray,
|
|
3615
|
+
...memoryMiddlewareArray,
|
|
3616
|
+
...interruptOn ? [(0, langchain.humanInTheLoopMiddleware)({ interruptOn })] : [],
|
|
3617
|
+
...customMiddleware
|
|
3618
|
+
],
|
|
3513
3619
|
responseFormat,
|
|
3514
3620
|
contextSchema,
|
|
3515
3621
|
checkpointer,
|