deepagents 1.12.1 → 1.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-B2Wfp1cf.d.cts → agent-CKQ2LDaJ.d.cts} +77 -13
- package/dist/{agent-C_iR-pdx.d.ts → agent-JA9TGZlt.d.ts} +77 -13
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/index.cjs +3 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/{langsmith-DdOXam6Z.cjs → langsmith-Bjhs2iT_.cjs} +200 -78
- package/dist/langsmith-Bjhs2iT_.cjs.map +1 -0
- package/dist/{langsmith-DgbmWtWj.js → langsmith-CUTUAjHo.js} +194 -78
- package/dist/langsmith-CUTUAjHo.js.map +1 -0
- package/dist/node.cjs +3 -2
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +3 -3
- package/dist/{src-BApYUljI.cjs → src-Dc8werER.cjs} +15 -7
- package/dist/src-Dc8werER.cjs.map +1 -0
- package/dist/{src-DeCEf6Ie.js → src-Dr5XWqq_.js} +15 -7
- package/dist/src-Dr5XWqq_.js.map +1 -0
- package/package.json +1 -1
- package/dist/langsmith-DdOXam6Z.cjs.map +0 -1
- package/dist/langsmith-DgbmWtWj.js.map +0 -1
- package/dist/src-BApYUljI.cjs.map +0 -1
- package/dist/src-DeCEf6Ie.js.map +0 -1
|
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
19
19
|
value: mod,
|
|
20
20
|
enumerable: true
|
|
21
21
|
}) : target, mod));
|
|
@@ -326,13 +326,13 @@ function performStringReplacement(content, oldString, newString, replaceAll) {
|
|
|
326
326
|
function truncateIfTooLong(result) {
|
|
327
327
|
if (Array.isArray(result)) {
|
|
328
328
|
const totalChars = result.reduce((sum, item) => sum + item.length, 0);
|
|
329
|
-
if (totalChars >
|
|
329
|
+
if (totalChars > 8e4) {
|
|
330
330
|
const truncateAt = Math.floor(result.length * TOOL_RESULT_TOKEN_LIMIT * 4 / totalChars);
|
|
331
331
|
return [...result.slice(0, truncateAt), TRUNCATION_GUIDANCE];
|
|
332
332
|
}
|
|
333
333
|
return result;
|
|
334
334
|
}
|
|
335
|
-
if (result.length >
|
|
335
|
+
if (result.length > 8e4) return result.substring(0, TOOL_RESULT_TOKEN_LIMIT * 4) + "\n... [results truncated, try being more specific with your parameters]";
|
|
336
336
|
return result;
|
|
337
337
|
}
|
|
338
338
|
/**
|
|
@@ -425,6 +425,30 @@ function globSearchFiles(files, pattern, path = "/") {
|
|
|
425
425
|
return matches.map(([fp]) => fp).join("\n");
|
|
426
426
|
}
|
|
427
427
|
/**
|
|
428
|
+
* Format grep search results based on output mode.
|
|
429
|
+
*
|
|
430
|
+
* @param results - Dictionary mapping file paths to list of [line_num, line_content] tuples
|
|
431
|
+
* @param outputMode - Output format - "files_with_matches", "content", or "count"
|
|
432
|
+
* @returns Formatted string output
|
|
433
|
+
*/
|
|
434
|
+
function formatGrepResults(results, outputMode) {
|
|
435
|
+
if (outputMode === "files_with_matches") return Object.keys(results).sort().join("\n");
|
|
436
|
+
if (outputMode === "count") {
|
|
437
|
+
const lines = [];
|
|
438
|
+
for (const filePath of Object.keys(results).sort()) {
|
|
439
|
+
const count = results[filePath].length;
|
|
440
|
+
lines.push(`${filePath}: ${count}`);
|
|
441
|
+
}
|
|
442
|
+
return lines.join("\n");
|
|
443
|
+
}
|
|
444
|
+
const lines = [];
|
|
445
|
+
for (const filePath of Object.keys(results).sort()) {
|
|
446
|
+
lines.push(`${filePath}:`);
|
|
447
|
+
for (const [lineNum, line] of results[filePath]) lines.push(` ${lineNum}: ${line}`);
|
|
448
|
+
}
|
|
449
|
+
return lines.join("\n");
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
428
452
|
* Return structured grep matches from an in-memory files mapping.
|
|
429
453
|
*
|
|
430
454
|
* Performs literal text search (not regex). Binary files are skipped.
|
|
@@ -455,6 +479,24 @@ function grepMatchesFromFiles(files, pattern, path = null, glob = null) {
|
|
|
455
479
|
return matches;
|
|
456
480
|
}
|
|
457
481
|
/**
|
|
482
|
+
* Group structured matches into the legacy dict form used by formatters.
|
|
483
|
+
*/
|
|
484
|
+
function buildGrepResultsDict(matches) {
|
|
485
|
+
const grouped = {};
|
|
486
|
+
for (const m of matches) {
|
|
487
|
+
if (!grouped[m.path]) grouped[m.path] = [];
|
|
488
|
+
grouped[m.path].push([m.line, m.text]);
|
|
489
|
+
}
|
|
490
|
+
return grouped;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Format structured grep matches using existing formatting logic.
|
|
494
|
+
*/
|
|
495
|
+
function formatGrepMatches(matches, outputMode) {
|
|
496
|
+
if (matches.length === 0) return "No matches found";
|
|
497
|
+
return formatGrepResults(buildGrepResultsDict(matches), outputMode);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
458
500
|
* Determine MIME type from a file path's extension.
|
|
459
501
|
*
|
|
460
502
|
* Defaults to "text/plain" for unknown extensions. Only the known non-text
|
|
@@ -554,9 +596,12 @@ function adaptBackendProtocol(backend) {
|
|
|
554
596
|
if (typeof result === "string") return { content: result };
|
|
555
597
|
return result;
|
|
556
598
|
},
|
|
557
|
-
async grep(pattern, path, glob) {
|
|
558
|
-
const result = await ("grep" in backend ? backend.grep(pattern, path, glob) : backend.grepRaw(pattern, path, glob));
|
|
559
|
-
if (Array.isArray(result)) return {
|
|
599
|
+
async grep(pattern, path, glob, maxCount) {
|
|
600
|
+
const result = await ("grep" in backend ? backend.grep(pattern, path, glob, maxCount) : backend.grepRaw(pattern, path, glob));
|
|
601
|
+
if (Array.isArray(result)) return applyGrepMaxCount({
|
|
602
|
+
result: { matches: result },
|
|
603
|
+
maxCount
|
|
604
|
+
});
|
|
560
605
|
if (typeof result === "string") return { error: result };
|
|
561
606
|
return result;
|
|
562
607
|
}
|
|
@@ -591,6 +636,21 @@ function adaptSandboxProtocol(sandbox) {
|
|
|
591
636
|
//#endregion
|
|
592
637
|
//#region src/backends/protocol.ts
|
|
593
638
|
/**
|
|
639
|
+
* Enforce a match cap after a backend grep has completed.
|
|
640
|
+
*
|
|
641
|
+
* When `maxCount` is set and the result exceeds it, the matches are sliced
|
|
642
|
+
* to the cap and the result is flagged `truncated: true`.
|
|
643
|
+
*/
|
|
644
|
+
function applyGrepMaxCount(params) {
|
|
645
|
+
const { result, maxCount } = params;
|
|
646
|
+
if (maxCount == null || result.matches == null || result.matches.length <= maxCount) return result;
|
|
647
|
+
return {
|
|
648
|
+
error: result.error,
|
|
649
|
+
matches: result.matches.slice(0, maxCount),
|
|
650
|
+
truncated: true
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
594
654
|
* Type guard to check if a backend supports execution.
|
|
595
655
|
*
|
|
596
656
|
* @param backend - Backend instance to check
|
|
@@ -871,9 +931,12 @@ var StateBackend = class {
|
|
|
871
931
|
* Search file contents for a literal text pattern.
|
|
872
932
|
* Binary files are skipped.
|
|
873
933
|
*/
|
|
874
|
-
grep(pattern, path = "/", glob = null) {
|
|
934
|
+
grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
875
935
|
const files = this.files;
|
|
876
|
-
return {
|
|
936
|
+
return applyGrepMaxCount({
|
|
937
|
+
result: { matches: grepMatchesFromFiles(files, pattern, path, glob) },
|
|
938
|
+
maxCount
|
|
939
|
+
});
|
|
877
940
|
}
|
|
878
941
|
/**
|
|
879
942
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -1115,7 +1178,7 @@ var CompositeBackend = class {
|
|
|
1115
1178
|
const results = [];
|
|
1116
1179
|
const defaultResult = await this.default.ls(path);
|
|
1117
1180
|
if (defaultResult.error) return defaultResult;
|
|
1118
|
-
|
|
1181
|
+
for (const fi of defaultResult.files || []) results.push(fi);
|
|
1119
1182
|
for (const [routePrefix] of this.sortedRoutes) results.push({
|
|
1120
1183
|
path: routePrefix,
|
|
1121
1184
|
is_dir: true,
|
|
@@ -1151,33 +1214,56 @@ var CompositeBackend = class {
|
|
|
1151
1214
|
}
|
|
1152
1215
|
/**
|
|
1153
1216
|
* Structured search results or error string for invalid input.
|
|
1217
|
+
*
|
|
1218
|
+
* @param maxCount - Optional total cap on returned matches across all routed
|
|
1219
|
+
* backends. When the cap is reached, remaining routes are
|
|
1220
|
+
* short-circuited and the result is flagged `truncated: true`.
|
|
1154
1221
|
*/
|
|
1155
|
-
async grep(pattern, path = "/", glob = null) {
|
|
1222
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
1156
1223
|
const searchPath = path || "/";
|
|
1157
1224
|
for (const [routePrefix, backend] of this.sortedRoutes) if (this.isPathWithinRoute(searchPath, routePrefix)) {
|
|
1158
1225
|
const routeSearchPath = searchPath.substring(routePrefix.length - 1);
|
|
1159
|
-
const raw = await backend.grep(pattern, routeSearchPath || "/", glob);
|
|
1226
|
+
const raw = await backend.grep(pattern, routeSearchPath || "/", glob, maxCount);
|
|
1160
1227
|
if (raw.error) return raw;
|
|
1161
|
-
return
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1228
|
+
return applyGrepMaxCount({
|
|
1229
|
+
result: {
|
|
1230
|
+
matches: (raw.matches || []).map((m) => ({
|
|
1231
|
+
...m,
|
|
1232
|
+
path: routePrefix.slice(0, -1) + m.path
|
|
1233
|
+
})),
|
|
1234
|
+
truncated: raw.truncated
|
|
1235
|
+
},
|
|
1236
|
+
maxCount
|
|
1237
|
+
});
|
|
1165
1238
|
}
|
|
1166
1239
|
const allMatches = [];
|
|
1167
|
-
|
|
1240
|
+
let truncated = false;
|
|
1241
|
+
const rawDefault = await this.default.grep(pattern, searchPath, glob, maxCount);
|
|
1168
1242
|
if (rawDefault.error) return rawDefault;
|
|
1169
|
-
|
|
1243
|
+
for (const m of rawDefault.matches || []) allMatches.push(m);
|
|
1244
|
+
truncated = truncated || rawDefault.truncated === true;
|
|
1170
1245
|
for (const [routePrefix, backend] of Object.entries(this.routes)) {
|
|
1171
1246
|
if (!this.isRouteUnderPath(routePrefix, searchPath)) continue;
|
|
1172
|
-
const
|
|
1247
|
+
const remaining = maxCount == null ? null : Math.max(maxCount - allMatches.length, 0);
|
|
1248
|
+
if (remaining === 0) {
|
|
1249
|
+
truncated = true;
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
const raw = await backend.grep(pattern, "/", glob, remaining);
|
|
1173
1253
|
if (raw.error) return raw;
|
|
1174
|
-
const
|
|
1254
|
+
for (const m of raw.matches || []) allMatches.push({
|
|
1175
1255
|
...m,
|
|
1176
1256
|
path: routePrefix.slice(0, -1) + m.path
|
|
1177
|
-
})
|
|
1178
|
-
|
|
1257
|
+
});
|
|
1258
|
+
truncated = truncated || raw.truncated === true;
|
|
1179
1259
|
}
|
|
1180
|
-
return {
|
|
1260
|
+
return applyGrepMaxCount({
|
|
1261
|
+
result: {
|
|
1262
|
+
matches: allMatches,
|
|
1263
|
+
truncated
|
|
1264
|
+
},
|
|
1265
|
+
maxCount
|
|
1266
|
+
});
|
|
1181
1267
|
}
|
|
1182
1268
|
/**
|
|
1183
1269
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -1188,26 +1274,33 @@ var CompositeBackend = class {
|
|
|
1188
1274
|
const searchPath = path.substring(routePrefix.length - 1);
|
|
1189
1275
|
const result = await backend.glob(pattern, searchPath || "/");
|
|
1190
1276
|
if (result.error) return result;
|
|
1191
|
-
return {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1277
|
+
return {
|
|
1278
|
+
files: (result.files || []).map((fi) => ({
|
|
1279
|
+
...fi,
|
|
1280
|
+
path: routePrefix.slice(0, -1) + fi.path
|
|
1281
|
+
})),
|
|
1282
|
+
truncated: result.truncated
|
|
1283
|
+
};
|
|
1195
1284
|
}
|
|
1196
1285
|
const defaultResult = await this.default.glob(pattern, path);
|
|
1197
1286
|
if (defaultResult.error) return defaultResult;
|
|
1198
|
-
|
|
1287
|
+
for (const fi of defaultResult.files || []) results.push(fi);
|
|
1288
|
+
let truncated = defaultResult.truncated === true;
|
|
1199
1289
|
for (const [routePrefix, backend] of Object.entries(this.routes)) {
|
|
1200
1290
|
if (!this.isRouteUnderPath(routePrefix, path)) continue;
|
|
1201
1291
|
const result = await backend.glob(pattern, "/");
|
|
1202
1292
|
if (result.error) continue;
|
|
1203
|
-
const
|
|
1293
|
+
for (const fi of result.files || []) results.push({
|
|
1204
1294
|
...fi,
|
|
1205
1295
|
path: routePrefix.slice(0, -1) + fi.path
|
|
1206
|
-
})
|
|
1207
|
-
|
|
1296
|
+
});
|
|
1297
|
+
truncated = truncated || result.truncated === true;
|
|
1208
1298
|
}
|
|
1209
1299
|
results.sort((a, b) => a.path.localeCompare(b.path));
|
|
1210
|
-
return {
|
|
1300
|
+
return {
|
|
1301
|
+
files: results,
|
|
1302
|
+
truncated
|
|
1303
|
+
};
|
|
1211
1304
|
}
|
|
1212
1305
|
/**
|
|
1213
1306
|
* Write content to a file, routing to appropriate backend.
|
|
@@ -1394,7 +1487,7 @@ const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter((name) => name
|
|
|
1394
1487
|
* Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.
|
|
1395
1488
|
* This keeps inline multimodal payloads within all major provider limits.
|
|
1396
1489
|
*/
|
|
1397
|
-
const MAX_BINARY_READ_SIZE_BYTES =
|
|
1490
|
+
const MAX_BINARY_READ_SIZE_BYTES = 10485760;
|
|
1398
1491
|
/**
|
|
1399
1492
|
* Template for truncation message in read_file.
|
|
1400
1493
|
* {file_path} will be filled in at runtime.
|
|
@@ -1403,6 +1496,15 @@ const READ_FILE_TRUNCATION_MSG = `
|
|
|
1403
1496
|
|
|
1404
1497
|
[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.]`;
|
|
1405
1498
|
/**
|
|
1499
|
+
* Note appended to grep results that were cut short by the match-count cap.
|
|
1500
|
+
*/
|
|
1501
|
+
const GREP_TRUNCATION_NOTE = "Note: the search stopped early because it hit the maximum match count. The matches above are valid but incomplete. Narrow the search (a more specific pattern or a narrower path), or raise max_count, to see the rest.";
|
|
1502
|
+
/**
|
|
1503
|
+
* Default cap on the number of matches the grep tool returns.
|
|
1504
|
+
* Set to null to disable the cap.
|
|
1505
|
+
*/
|
|
1506
|
+
const DEFAULT_GREP_MAX_COUNT = 1e3;
|
|
1507
|
+
/**
|
|
1406
1508
|
* Message template for evicted tool results.
|
|
1407
1509
|
*/
|
|
1408
1510
|
const TOO_LARGE_TOOL_MSG = langchain.context`
|
|
@@ -1474,8 +1576,9 @@ function buildEvictedHumanContent(message, replacementText) {
|
|
|
1474
1576
|
*/
|
|
1475
1577
|
function buildTruncatedHumanMessage(message, filePath) {
|
|
1476
1578
|
const contentSample = createContentPreview(extractTextFromMessage(message));
|
|
1579
|
+
const evictedContent = buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample));
|
|
1477
1580
|
return new langchain.HumanMessage({
|
|
1478
|
-
content:
|
|
1581
|
+
content: evictedContent,
|
|
1479
1582
|
id: message.id,
|
|
1480
1583
|
additional_kwargs: { ...message.additional_kwargs },
|
|
1481
1584
|
response_metadata: { ...message.response_metadata }
|
|
@@ -1749,7 +1852,7 @@ function createReadFileTool(backend, options) {
|
|
|
1749
1852
|
const sizeBytes = Math.ceil(base64Data.length * 3 / 4);
|
|
1750
1853
|
if (sizeBytes > 10485760) return [{
|
|
1751
1854
|
type: "text",
|
|
1752
|
-
text: `Error: file too large to read (${Math.round(sizeBytes /
|
|
1855
|
+
text: `Error: file too large to read (${Math.round(sizeBytes / 1048576)}MB exceeds ${MAX_BINARY_READ_SIZE_BYTES / 1048576}MB limit for binary files)`
|
|
1753
1856
|
}];
|
|
1754
1857
|
if (mimeType.startsWith("image/")) return [{
|
|
1755
1858
|
type: "image",
|
|
@@ -1891,35 +1994,34 @@ function createGlobTool(backend, options) {
|
|
|
1891
1994
|
* Create grep tool using backend.
|
|
1892
1995
|
*/
|
|
1893
1996
|
function createGrepTool(backend, options) {
|
|
1894
|
-
const { customDescription, permissions, includeExecution } = options;
|
|
1997
|
+
const { customDescription, permissions, includeExecution, grepMaxCount } = options;
|
|
1895
1998
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1896
1999
|
const permissionError = checkPermission(permissions, "read", input.path ?? "/");
|
|
1897
2000
|
if (permissionError !== void 0) return toolError(runtime, "grep", permissionError);
|
|
1898
2001
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1899
|
-
const { pattern, path = "/", glob = null } = input;
|
|
1900
|
-
const
|
|
2002
|
+
const { pattern, path = "/", glob = null, output_mode = "content" } = input;
|
|
2003
|
+
const maxCount = input.max_count ?? grepMaxCount;
|
|
2004
|
+
const result = await resolvedBackend.grep(pattern, path, glob, maxCount);
|
|
1901
2005
|
if (result.error) return result.error;
|
|
1902
2006
|
const matches = filterByPermissions(result.matches ?? [], permissions, "read", (m) => m.path);
|
|
1903
2007
|
if (matches.length === 0) return `No matches found for pattern '${pattern}'`;
|
|
1904
|
-
const
|
|
1905
|
-
let
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
currentFile = match.path;
|
|
1909
|
-
lines.push(`\n${currentFile}:`);
|
|
1910
|
-
}
|
|
1911
|
-
lines.push(` ${match.line}: ${match.text}`);
|
|
1912
|
-
}
|
|
1913
|
-
const truncated = truncateIfTooLong(lines);
|
|
1914
|
-
if (Array.isArray(truncated)) return truncated.join("\n");
|
|
1915
|
-
return truncated;
|
|
2008
|
+
const truncated = truncateIfTooLong(formatGrepMatches(matches, output_mode));
|
|
2009
|
+
let content = typeof truncated === "string" ? truncated : truncated.join("\n");
|
|
2010
|
+
if (result.truncated) content += `\n\n${GREP_TRUNCATION_NOTE}`;
|
|
2011
|
+
return content;
|
|
1916
2012
|
}, {
|
|
1917
2013
|
name: "grep",
|
|
1918
2014
|
description: customDescription || getGrepToolDescription(includeExecution),
|
|
1919
2015
|
schema: zod_v4.z.object({
|
|
1920
2016
|
pattern: zod_v4.z.string().describe("Literal text pattern to search for (not regex)"),
|
|
1921
2017
|
path: zod_v4.z.string().optional().default("/").describe("Base path to search from (default: /)"),
|
|
1922
|
-
glob: zod_v4.z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')")
|
|
2018
|
+
glob: zod_v4.z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')"),
|
|
2019
|
+
max_count: zod_v4.z.number().int().positive().optional().nullable().default(null).describe("Optional cap on the total number of matches returned across all files. Leave unset to use the configured default. When the cap is hit, results are truncated and a note says so; narrow the pattern or path to see the rest."),
|
|
2020
|
+
output_mode: zod_v4.z.enum([
|
|
2021
|
+
"files_with_matches",
|
|
2022
|
+
"content",
|
|
2023
|
+
"count"
|
|
2024
|
+
]).optional().default("content").describe("Output format: 'files_with_matches' lists matching file paths, 'content' shows matching lines (default), 'count' shows match counts per file")
|
|
1923
2025
|
})
|
|
1924
2026
|
});
|
|
1925
2027
|
}
|
|
@@ -1988,7 +2090,7 @@ function allPathsScopedToRoutes(permissions, backend) {
|
|
|
1988
2090
|
* ```
|
|
1989
2091
|
*/
|
|
1990
2092
|
function createFilesystemMiddleware(options = {}) {
|
|
1991
|
-
const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null } = options;
|
|
2093
|
+
const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null, grepMaxCount = DEFAULT_GREP_MAX_COUNT } = options;
|
|
1992
2094
|
const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);
|
|
1993
2095
|
const executeToolEnabled = enabledFilesystemTools == null || enabledFilesystemTools.has("execute");
|
|
1994
2096
|
if (permissions.length > 0) validatePermissionPaths(permissions);
|
|
@@ -2024,7 +2126,8 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
2024
2126
|
grep: createGrepTool(backend, {
|
|
2025
2127
|
customDescription: customToolDescriptions?.grep,
|
|
2026
2128
|
permissions,
|
|
2027
|
-
includeExecution: configuredToolNames.has("execute") && typeof backend !== "function" && isSandboxBackend(backend)
|
|
2129
|
+
includeExecution: configuredToolNames.has("execute") && typeof backend !== "function" && isSandboxBackend(backend),
|
|
2130
|
+
grepMaxCount
|
|
2028
2131
|
}),
|
|
2029
2132
|
execute: createExecuteTool(backend, {
|
|
2030
2133
|
customDescription: customToolDescriptions?.execute,
|
|
@@ -2055,9 +2158,10 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
2055
2158
|
const evictPath = `/large_tool_results/${sanitizeToolCallId(fallbackToolCallId || msg.tool_call_id)}.txt`;
|
|
2056
2159
|
const writeResult = await resolvedBackend.write(evictPath, textContent);
|
|
2057
2160
|
const contentSample = createContentPreview(textContent);
|
|
2161
|
+
const replacementText = writeResult.error ? `Tool result too large, but the result could not be saved to the filesystem: ${writeResult.error}` : TOO_LARGE_TOOL_MSG.replace("{tool_call_id}", msg.tool_call_id).replace("{file_path}", evictPath).replace("{content_sample}", contentSample);
|
|
2058
2162
|
return {
|
|
2059
2163
|
message: new langchain.ToolMessage({
|
|
2060
|
-
content:
|
|
2164
|
+
content: replacementText,
|
|
2061
2165
|
tool_call_id: msg.tool_call_id,
|
|
2062
2166
|
name: msg.name,
|
|
2063
2167
|
id: msg.id,
|
|
@@ -2402,6 +2506,7 @@ function createTaskTool(options) {
|
|
|
2402
2506
|
}
|
|
2403
2507
|
return subagentGraphs[subagentType];
|
|
2404
2508
|
}
|
|
2509
|
+
const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
|
|
2405
2510
|
return (0, langchain.tool)(async (input, config) => {
|
|
2406
2511
|
const { description, subagent_type } = input;
|
|
2407
2512
|
if (!(subagent_type in subagentGraphs)) {
|
|
@@ -2437,7 +2542,7 @@ function createTaskTool(options) {
|
|
|
2437
2542
|
return returnCommandWithStateUpdate(result, config.toolCall.id);
|
|
2438
2543
|
}, {
|
|
2439
2544
|
name: "task",
|
|
2440
|
-
description:
|
|
2545
|
+
description: finalTaskDescription,
|
|
2441
2546
|
schema: zod_v4.z.object({
|
|
2442
2547
|
description: zod_v4.z.string().describe("The task to execute with the selected agent"),
|
|
2443
2548
|
subagent_type: zod_v4.z.string().describe(`Name of the agent to use. Available: ${Object.keys(subagentGraphs).join(", ")}`)
|
|
@@ -2449,18 +2554,19 @@ function createTaskTool(options) {
|
|
|
2449
2554
|
*/
|
|
2450
2555
|
function createSubAgentMiddleware(options) {
|
|
2451
2556
|
const { defaultModel, defaultTools = [], defaultMiddleware = null, generalPurposeMiddleware = null, defaultInterruptOn = null, subagents = [], systemPrompt = null, generalPurposeAgent = true, taskDescription = null } = options;
|
|
2557
|
+
const taskTool = createTaskTool({
|
|
2558
|
+
defaultModel,
|
|
2559
|
+
defaultTools,
|
|
2560
|
+
defaultMiddleware,
|
|
2561
|
+
generalPurposeMiddleware,
|
|
2562
|
+
defaultInterruptOn,
|
|
2563
|
+
subagents,
|
|
2564
|
+
generalPurposeAgent,
|
|
2565
|
+
taskDescription
|
|
2566
|
+
});
|
|
2452
2567
|
return (0, langchain.createMiddleware)({
|
|
2453
2568
|
name: "subAgentMiddleware",
|
|
2454
|
-
tools: [
|
|
2455
|
-
defaultModel,
|
|
2456
|
-
defaultTools,
|
|
2457
|
-
defaultMiddleware,
|
|
2458
|
-
generalPurposeMiddleware,
|
|
2459
|
-
defaultInterruptOn,
|
|
2460
|
-
subagents,
|
|
2461
|
-
generalPurposeAgent,
|
|
2462
|
-
taskDescription
|
|
2463
|
-
})],
|
|
2569
|
+
tools: [taskTool],
|
|
2464
2570
|
wrapModelCall: async (request, handler) => {
|
|
2465
2571
|
if (systemPrompt !== null) return handler({
|
|
2466
2572
|
...request,
|
|
@@ -2965,7 +3071,7 @@ function createMemoryMiddleware(options) {
|
|
|
2965
3071
|
* });
|
|
2966
3072
|
* ```
|
|
2967
3073
|
*/
|
|
2968
|
-
const MAX_SKILL_FILE_SIZE =
|
|
3074
|
+
const MAX_SKILL_FILE_SIZE = 10485760;
|
|
2969
3075
|
const DEFAULT_SKILL_READ_LINE_LIMIT = 1e3;
|
|
2970
3076
|
const MAX_SKILL_NAME_LENGTH = 64;
|
|
2971
3077
|
const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
|
|
@@ -3733,7 +3839,6 @@ function createCompletionCallbackMiddleware(options) {
|
|
|
3733
3839
|
* from `langchain` directly.
|
|
3734
3840
|
*/
|
|
3735
3841
|
const DEFAULT_MESSAGES_TO_KEEP = 20;
|
|
3736
|
-
const DEFAULT_TRIM_TOKEN_LIMIT = 4e3;
|
|
3737
3842
|
const FALLBACK_TRIGGER = {
|
|
3738
3843
|
type: "tokens",
|
|
3739
3844
|
value: 17e4
|
|
@@ -3850,7 +3955,7 @@ function isSummaryMessage(msg) {
|
|
|
3850
3955
|
* @returns AgentMiddleware for summarization and history offloading
|
|
3851
3956
|
*/
|
|
3852
3957
|
function createSummarizationMiddleware(options) {
|
|
3853
|
-
const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize
|
|
3958
|
+
const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize, historyPathPrefix = "/conversation_history" } = options;
|
|
3854
3959
|
let trigger = options.trigger;
|
|
3855
3960
|
let keep = options.keep ?? {
|
|
3856
3961
|
type: "messages",
|
|
@@ -4054,7 +4159,9 @@ function createSummarizationMiddleware(options) {
|
|
|
4054
4159
|
* This gives a more accurate picture of what actually gets sent to the model.
|
|
4055
4160
|
*/
|
|
4056
4161
|
function countTotalTokens(messages, systemMessage, tools) {
|
|
4057
|
-
|
|
4162
|
+
const countedMessages = systemMessage && langchain.SystemMessage.isInstance(systemMessage) ? [systemMessage, ...messages] : [...messages];
|
|
4163
|
+
const toolsArray = tools && Array.isArray(tools) && tools.length > 0 ? tools : null;
|
|
4164
|
+
return (0, langchain.countTokensApproximately)(countedMessages, toolsArray);
|
|
4058
4165
|
}
|
|
4059
4166
|
/**
|
|
4060
4167
|
* Truncate ToolMessage content so that the total payload fits within the
|
|
@@ -4201,7 +4308,8 @@ function createSummarizationMiddleware(options) {
|
|
|
4201
4308
|
*/
|
|
4202
4309
|
async function createSummary(messages, chatModel) {
|
|
4203
4310
|
let messagesToSummarize = messages;
|
|
4204
|
-
|
|
4311
|
+
const tokens = (0, langchain.countTokensApproximately)(messages);
|
|
4312
|
+
if (trimTokensToSummarize !== void 0 && tokens > trimTokensToSummarize) {
|
|
4205
4313
|
let kept = 0;
|
|
4206
4314
|
const trimmedMessages = [];
|
|
4207
4315
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -4214,8 +4322,7 @@ function createSummarizationMiddleware(options) {
|
|
|
4214
4322
|
}
|
|
4215
4323
|
const conversation = (0, _langchain_core_messages.getBufferString)(messagesToSummarize);
|
|
4216
4324
|
const prompt = summaryPrompt.replace("{conversation}", conversation);
|
|
4217
|
-
|
|
4218
|
-
return typeof response.content === "string" ? response.content : JSON.stringify(response.content);
|
|
4325
|
+
return (await chatModel.invoke([new langchain.HumanMessage({ content: prompt })])).text;
|
|
4219
4326
|
}
|
|
4220
4327
|
/**
|
|
4221
4328
|
* Build the summary message with file path reference.
|
|
@@ -6386,7 +6493,7 @@ var StoreBackend = class {
|
|
|
6386
6493
|
* Search file contents for a literal text pattern.
|
|
6387
6494
|
* Binary files are skipped.
|
|
6388
6495
|
*/
|
|
6389
|
-
async grep(pattern, path = "/", glob = null) {
|
|
6496
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
6390
6497
|
const store = this.getStore();
|
|
6391
6498
|
const namespace = this.getNamespace();
|
|
6392
6499
|
const items = await this.searchStorePaginated(store, namespace);
|
|
@@ -6396,7 +6503,10 @@ var StoreBackend = class {
|
|
|
6396
6503
|
} catch {
|
|
6397
6504
|
continue;
|
|
6398
6505
|
}
|
|
6399
|
-
return {
|
|
6506
|
+
return applyGrepMaxCount({
|
|
6507
|
+
result: { matches: grepMatchesFromFiles(files, pattern, path, glob) },
|
|
6508
|
+
maxCount
|
|
6509
|
+
});
|
|
6400
6510
|
}
|
|
6401
6511
|
/**
|
|
6402
6512
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -6695,7 +6805,7 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6695
6805
|
modified_at: now
|
|
6696
6806
|
} };
|
|
6697
6807
|
}
|
|
6698
|
-
async grep(pattern, path = null, glob = null) {
|
|
6808
|
+
async grep(pattern, path = null, glob = null, maxCount = null) {
|
|
6699
6809
|
let cache;
|
|
6700
6810
|
try {
|
|
6701
6811
|
cache = await this.ensureCache();
|
|
@@ -6718,7 +6828,10 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6718
6828
|
});
|
|
6719
6829
|
}
|
|
6720
6830
|
}
|
|
6721
|
-
return {
|
|
6831
|
+
return applyGrepMaxCount({
|
|
6832
|
+
result: { matches },
|
|
6833
|
+
maxCount
|
|
6834
|
+
});
|
|
6722
6835
|
}
|
|
6723
6836
|
async glob(pattern, _path = "/") {
|
|
6724
6837
|
let cache;
|
|
@@ -7114,7 +7227,7 @@ var BaseSandbox = class {
|
|
|
7114
7227
|
* @param glob - Optional glob pattern to filter which files to search.
|
|
7115
7228
|
* @returns List of GrepMatch dicts containing path, line number, and matched text.
|
|
7116
7229
|
*/
|
|
7117
|
-
async grep(pattern, path = "/", glob = null) {
|
|
7230
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
7118
7231
|
const command = buildGrepCommand(pattern, path, glob);
|
|
7119
7232
|
const output = (await this.execute(command)).output.trim();
|
|
7120
7233
|
if (!output) return { matches: [] };
|
|
@@ -7132,7 +7245,10 @@ var BaseSandbox = class {
|
|
|
7132
7245
|
});
|
|
7133
7246
|
}
|
|
7134
7247
|
}
|
|
7135
|
-
return {
|
|
7248
|
+
return applyGrepMaxCount({
|
|
7249
|
+
result: { matches },
|
|
7250
|
+
maxCount
|
|
7251
|
+
});
|
|
7136
7252
|
}
|
|
7137
7253
|
/**
|
|
7138
7254
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -7631,6 +7747,12 @@ Object.defineProperty(exports, "adaptSandboxProtocol", {
|
|
|
7631
7747
|
return adaptSandboxProtocol;
|
|
7632
7748
|
}
|
|
7633
7749
|
});
|
|
7750
|
+
Object.defineProperty(exports, "applyGrepMaxCount", {
|
|
7751
|
+
enumerable: true,
|
|
7752
|
+
get: function() {
|
|
7753
|
+
return applyGrepMaxCount;
|
|
7754
|
+
}
|
|
7755
|
+
});
|
|
7634
7756
|
Object.defineProperty(exports, "checkEmptyContent", {
|
|
7635
7757
|
enumerable: true,
|
|
7636
7758
|
get: function() {
|
|
@@ -7794,4 +7916,4 @@ Object.defineProperty(exports, "serializeProfile", {
|
|
|
7794
7916
|
}
|
|
7795
7917
|
});
|
|
7796
7918
|
|
|
7797
|
-
//# sourceMappingURL=langsmith-
|
|
7919
|
+
//# sourceMappingURL=langsmith-Bjhs2iT_.cjs.map
|