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
|
@@ -302,13 +302,13 @@ function performStringReplacement(content, oldString, newString, replaceAll) {
|
|
|
302
302
|
function truncateIfTooLong(result) {
|
|
303
303
|
if (Array.isArray(result)) {
|
|
304
304
|
const totalChars = result.reduce((sum, item) => sum + item.length, 0);
|
|
305
|
-
if (totalChars >
|
|
305
|
+
if (totalChars > 8e4) {
|
|
306
306
|
const truncateAt = Math.floor(result.length * TOOL_RESULT_TOKEN_LIMIT * 4 / totalChars);
|
|
307
307
|
return [...result.slice(0, truncateAt), TRUNCATION_GUIDANCE];
|
|
308
308
|
}
|
|
309
309
|
return result;
|
|
310
310
|
}
|
|
311
|
-
if (result.length >
|
|
311
|
+
if (result.length > 8e4) return result.substring(0, TOOL_RESULT_TOKEN_LIMIT * 4) + "\n... [results truncated, try being more specific with your parameters]";
|
|
312
312
|
return result;
|
|
313
313
|
}
|
|
314
314
|
/**
|
|
@@ -401,6 +401,30 @@ function globSearchFiles(files, pattern, path = "/") {
|
|
|
401
401
|
return matches.map(([fp]) => fp).join("\n");
|
|
402
402
|
}
|
|
403
403
|
/**
|
|
404
|
+
* Format grep search results based on output mode.
|
|
405
|
+
*
|
|
406
|
+
* @param results - Dictionary mapping file paths to list of [line_num, line_content] tuples
|
|
407
|
+
* @param outputMode - Output format - "files_with_matches", "content", or "count"
|
|
408
|
+
* @returns Formatted string output
|
|
409
|
+
*/
|
|
410
|
+
function formatGrepResults(results, outputMode) {
|
|
411
|
+
if (outputMode === "files_with_matches") return Object.keys(results).sort().join("\n");
|
|
412
|
+
if (outputMode === "count") {
|
|
413
|
+
const lines = [];
|
|
414
|
+
for (const filePath of Object.keys(results).sort()) {
|
|
415
|
+
const count = results[filePath].length;
|
|
416
|
+
lines.push(`${filePath}: ${count}`);
|
|
417
|
+
}
|
|
418
|
+
return lines.join("\n");
|
|
419
|
+
}
|
|
420
|
+
const lines = [];
|
|
421
|
+
for (const filePath of Object.keys(results).sort()) {
|
|
422
|
+
lines.push(`${filePath}:`);
|
|
423
|
+
for (const [lineNum, line] of results[filePath]) lines.push(` ${lineNum}: ${line}`);
|
|
424
|
+
}
|
|
425
|
+
return lines.join("\n");
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
404
428
|
* Return structured grep matches from an in-memory files mapping.
|
|
405
429
|
*
|
|
406
430
|
* Performs literal text search (not regex). Binary files are skipped.
|
|
@@ -431,6 +455,24 @@ function grepMatchesFromFiles(files, pattern, path = null, glob = null) {
|
|
|
431
455
|
return matches;
|
|
432
456
|
}
|
|
433
457
|
/**
|
|
458
|
+
* Group structured matches into the legacy dict form used by formatters.
|
|
459
|
+
*/
|
|
460
|
+
function buildGrepResultsDict(matches) {
|
|
461
|
+
const grouped = {};
|
|
462
|
+
for (const m of matches) {
|
|
463
|
+
if (!grouped[m.path]) grouped[m.path] = [];
|
|
464
|
+
grouped[m.path].push([m.line, m.text]);
|
|
465
|
+
}
|
|
466
|
+
return grouped;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Format structured grep matches using existing formatting logic.
|
|
470
|
+
*/
|
|
471
|
+
function formatGrepMatches(matches, outputMode) {
|
|
472
|
+
if (matches.length === 0) return "No matches found";
|
|
473
|
+
return formatGrepResults(buildGrepResultsDict(matches), outputMode);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
434
476
|
* Determine MIME type from a file path's extension.
|
|
435
477
|
*
|
|
436
478
|
* Defaults to "text/plain" for unknown extensions. Only the known non-text
|
|
@@ -530,9 +572,12 @@ function adaptBackendProtocol(backend) {
|
|
|
530
572
|
if (typeof result === "string") return { content: result };
|
|
531
573
|
return result;
|
|
532
574
|
},
|
|
533
|
-
async grep(pattern, path, glob) {
|
|
534
|
-
const result = await ("grep" in backend ? backend.grep(pattern, path, glob) : backend.grepRaw(pattern, path, glob));
|
|
535
|
-
if (Array.isArray(result)) return {
|
|
575
|
+
async grep(pattern, path, glob, maxCount) {
|
|
576
|
+
const result = await ("grep" in backend ? backend.grep(pattern, path, glob, maxCount) : backend.grepRaw(pattern, path, glob));
|
|
577
|
+
if (Array.isArray(result)) return applyGrepMaxCount({
|
|
578
|
+
result: { matches: result },
|
|
579
|
+
maxCount
|
|
580
|
+
});
|
|
536
581
|
if (typeof result === "string") return { error: result };
|
|
537
582
|
return result;
|
|
538
583
|
}
|
|
@@ -567,6 +612,21 @@ function adaptSandboxProtocol(sandbox) {
|
|
|
567
612
|
//#endregion
|
|
568
613
|
//#region src/backends/protocol.ts
|
|
569
614
|
/**
|
|
615
|
+
* Enforce a match cap after a backend grep has completed.
|
|
616
|
+
*
|
|
617
|
+
* When `maxCount` is set and the result exceeds it, the matches are sliced
|
|
618
|
+
* to the cap and the result is flagged `truncated: true`.
|
|
619
|
+
*/
|
|
620
|
+
function applyGrepMaxCount(params) {
|
|
621
|
+
const { result, maxCount } = params;
|
|
622
|
+
if (maxCount == null || result.matches == null || result.matches.length <= maxCount) return result;
|
|
623
|
+
return {
|
|
624
|
+
error: result.error,
|
|
625
|
+
matches: result.matches.slice(0, maxCount),
|
|
626
|
+
truncated: true
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
570
630
|
* Type guard to check if a backend supports execution.
|
|
571
631
|
*
|
|
572
632
|
* @param backend - Backend instance to check
|
|
@@ -847,9 +907,12 @@ var StateBackend = class {
|
|
|
847
907
|
* Search file contents for a literal text pattern.
|
|
848
908
|
* Binary files are skipped.
|
|
849
909
|
*/
|
|
850
|
-
grep(pattern, path = "/", glob = null) {
|
|
910
|
+
grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
851
911
|
const files = this.files;
|
|
852
|
-
return {
|
|
912
|
+
return applyGrepMaxCount({
|
|
913
|
+
result: { matches: grepMatchesFromFiles(files, pattern, path, glob) },
|
|
914
|
+
maxCount
|
|
915
|
+
});
|
|
853
916
|
}
|
|
854
917
|
/**
|
|
855
918
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -1091,7 +1154,7 @@ var CompositeBackend = class {
|
|
|
1091
1154
|
const results = [];
|
|
1092
1155
|
const defaultResult = await this.default.ls(path);
|
|
1093
1156
|
if (defaultResult.error) return defaultResult;
|
|
1094
|
-
|
|
1157
|
+
for (const fi of defaultResult.files || []) results.push(fi);
|
|
1095
1158
|
for (const [routePrefix] of this.sortedRoutes) results.push({
|
|
1096
1159
|
path: routePrefix,
|
|
1097
1160
|
is_dir: true,
|
|
@@ -1127,33 +1190,56 @@ var CompositeBackend = class {
|
|
|
1127
1190
|
}
|
|
1128
1191
|
/**
|
|
1129
1192
|
* Structured search results or error string for invalid input.
|
|
1193
|
+
*
|
|
1194
|
+
* @param maxCount - Optional total cap on returned matches across all routed
|
|
1195
|
+
* backends. When the cap is reached, remaining routes are
|
|
1196
|
+
* short-circuited and the result is flagged `truncated: true`.
|
|
1130
1197
|
*/
|
|
1131
|
-
async grep(pattern, path = "/", glob = null) {
|
|
1198
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
1132
1199
|
const searchPath = path || "/";
|
|
1133
1200
|
for (const [routePrefix, backend] of this.sortedRoutes) if (this.isPathWithinRoute(searchPath, routePrefix)) {
|
|
1134
1201
|
const routeSearchPath = searchPath.substring(routePrefix.length - 1);
|
|
1135
|
-
const raw = await backend.grep(pattern, routeSearchPath || "/", glob);
|
|
1202
|
+
const raw = await backend.grep(pattern, routeSearchPath || "/", glob, maxCount);
|
|
1136
1203
|
if (raw.error) return raw;
|
|
1137
|
-
return
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1204
|
+
return applyGrepMaxCount({
|
|
1205
|
+
result: {
|
|
1206
|
+
matches: (raw.matches || []).map((m) => ({
|
|
1207
|
+
...m,
|
|
1208
|
+
path: routePrefix.slice(0, -1) + m.path
|
|
1209
|
+
})),
|
|
1210
|
+
truncated: raw.truncated
|
|
1211
|
+
},
|
|
1212
|
+
maxCount
|
|
1213
|
+
});
|
|
1141
1214
|
}
|
|
1142
1215
|
const allMatches = [];
|
|
1143
|
-
|
|
1216
|
+
let truncated = false;
|
|
1217
|
+
const rawDefault = await this.default.grep(pattern, searchPath, glob, maxCount);
|
|
1144
1218
|
if (rawDefault.error) return rawDefault;
|
|
1145
|
-
|
|
1219
|
+
for (const m of rawDefault.matches || []) allMatches.push(m);
|
|
1220
|
+
truncated = truncated || rawDefault.truncated === true;
|
|
1146
1221
|
for (const [routePrefix, backend] of Object.entries(this.routes)) {
|
|
1147
1222
|
if (!this.isRouteUnderPath(routePrefix, searchPath)) continue;
|
|
1148
|
-
const
|
|
1223
|
+
const remaining = maxCount == null ? null : Math.max(maxCount - allMatches.length, 0);
|
|
1224
|
+
if (remaining === 0) {
|
|
1225
|
+
truncated = true;
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
1228
|
+
const raw = await backend.grep(pattern, "/", glob, remaining);
|
|
1149
1229
|
if (raw.error) return raw;
|
|
1150
|
-
const
|
|
1230
|
+
for (const m of raw.matches || []) allMatches.push({
|
|
1151
1231
|
...m,
|
|
1152
1232
|
path: routePrefix.slice(0, -1) + m.path
|
|
1153
|
-
})
|
|
1154
|
-
|
|
1233
|
+
});
|
|
1234
|
+
truncated = truncated || raw.truncated === true;
|
|
1155
1235
|
}
|
|
1156
|
-
return {
|
|
1236
|
+
return applyGrepMaxCount({
|
|
1237
|
+
result: {
|
|
1238
|
+
matches: allMatches,
|
|
1239
|
+
truncated
|
|
1240
|
+
},
|
|
1241
|
+
maxCount
|
|
1242
|
+
});
|
|
1157
1243
|
}
|
|
1158
1244
|
/**
|
|
1159
1245
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -1164,26 +1250,33 @@ var CompositeBackend = class {
|
|
|
1164
1250
|
const searchPath = path.substring(routePrefix.length - 1);
|
|
1165
1251
|
const result = await backend.glob(pattern, searchPath || "/");
|
|
1166
1252
|
if (result.error) return result;
|
|
1167
|
-
return {
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1253
|
+
return {
|
|
1254
|
+
files: (result.files || []).map((fi) => ({
|
|
1255
|
+
...fi,
|
|
1256
|
+
path: routePrefix.slice(0, -1) + fi.path
|
|
1257
|
+
})),
|
|
1258
|
+
truncated: result.truncated
|
|
1259
|
+
};
|
|
1171
1260
|
}
|
|
1172
1261
|
const defaultResult = await this.default.glob(pattern, path);
|
|
1173
1262
|
if (defaultResult.error) return defaultResult;
|
|
1174
|
-
|
|
1263
|
+
for (const fi of defaultResult.files || []) results.push(fi);
|
|
1264
|
+
let truncated = defaultResult.truncated === true;
|
|
1175
1265
|
for (const [routePrefix, backend] of Object.entries(this.routes)) {
|
|
1176
1266
|
if (!this.isRouteUnderPath(routePrefix, path)) continue;
|
|
1177
1267
|
const result = await backend.glob(pattern, "/");
|
|
1178
1268
|
if (result.error) continue;
|
|
1179
|
-
const
|
|
1269
|
+
for (const fi of result.files || []) results.push({
|
|
1180
1270
|
...fi,
|
|
1181
1271
|
path: routePrefix.slice(0, -1) + fi.path
|
|
1182
|
-
})
|
|
1183
|
-
|
|
1272
|
+
});
|
|
1273
|
+
truncated = truncated || result.truncated === true;
|
|
1184
1274
|
}
|
|
1185
1275
|
results.sort((a, b) => a.path.localeCompare(b.path));
|
|
1186
|
-
return {
|
|
1276
|
+
return {
|
|
1277
|
+
files: results,
|
|
1278
|
+
truncated
|
|
1279
|
+
};
|
|
1187
1280
|
}
|
|
1188
1281
|
/**
|
|
1189
1282
|
* Write content to a file, routing to appropriate backend.
|
|
@@ -1370,7 +1463,7 @@ const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter((name) => name
|
|
|
1370
1463
|
* Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.
|
|
1371
1464
|
* This keeps inline multimodal payloads within all major provider limits.
|
|
1372
1465
|
*/
|
|
1373
|
-
const MAX_BINARY_READ_SIZE_BYTES =
|
|
1466
|
+
const MAX_BINARY_READ_SIZE_BYTES = 10485760;
|
|
1374
1467
|
/**
|
|
1375
1468
|
* Template for truncation message in read_file.
|
|
1376
1469
|
* {file_path} will be filled in at runtime.
|
|
@@ -1379,6 +1472,15 @@ const READ_FILE_TRUNCATION_MSG = `
|
|
|
1379
1472
|
|
|
1380
1473
|
[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.]`;
|
|
1381
1474
|
/**
|
|
1475
|
+
* Note appended to grep results that were cut short by the match-count cap.
|
|
1476
|
+
*/
|
|
1477
|
+
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.";
|
|
1478
|
+
/**
|
|
1479
|
+
* Default cap on the number of matches the grep tool returns.
|
|
1480
|
+
* Set to null to disable the cap.
|
|
1481
|
+
*/
|
|
1482
|
+
const DEFAULT_GREP_MAX_COUNT = 1e3;
|
|
1483
|
+
/**
|
|
1382
1484
|
* Message template for evicted tool results.
|
|
1383
1485
|
*/
|
|
1384
1486
|
const TOO_LARGE_TOOL_MSG = context`
|
|
@@ -1450,8 +1552,9 @@ function buildEvictedHumanContent(message, replacementText) {
|
|
|
1450
1552
|
*/
|
|
1451
1553
|
function buildTruncatedHumanMessage(message, filePath) {
|
|
1452
1554
|
const contentSample = createContentPreview(extractTextFromMessage(message));
|
|
1555
|
+
const evictedContent = buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample));
|
|
1453
1556
|
return new HumanMessage({
|
|
1454
|
-
content:
|
|
1557
|
+
content: evictedContent,
|
|
1455
1558
|
id: message.id,
|
|
1456
1559
|
additional_kwargs: { ...message.additional_kwargs },
|
|
1457
1560
|
response_metadata: { ...message.response_metadata }
|
|
@@ -1725,7 +1828,7 @@ function createReadFileTool(backend, options) {
|
|
|
1725
1828
|
const sizeBytes = Math.ceil(base64Data.length * 3 / 4);
|
|
1726
1829
|
if (sizeBytes > 10485760) return [{
|
|
1727
1830
|
type: "text",
|
|
1728
|
-
text: `Error: file too large to read (${Math.round(sizeBytes /
|
|
1831
|
+
text: `Error: file too large to read (${Math.round(sizeBytes / 1048576)}MB exceeds ${MAX_BINARY_READ_SIZE_BYTES / 1048576}MB limit for binary files)`
|
|
1729
1832
|
}];
|
|
1730
1833
|
if (mimeType.startsWith("image/")) return [{
|
|
1731
1834
|
type: "image",
|
|
@@ -1867,35 +1970,34 @@ function createGlobTool(backend, options) {
|
|
|
1867
1970
|
* Create grep tool using backend.
|
|
1868
1971
|
*/
|
|
1869
1972
|
function createGrepTool(backend, options) {
|
|
1870
|
-
const { customDescription, permissions, includeExecution } = options;
|
|
1973
|
+
const { customDescription, permissions, includeExecution, grepMaxCount } = options;
|
|
1871
1974
|
return tool(async (input, runtime) => {
|
|
1872
1975
|
const permissionError = checkPermission(permissions, "read", input.path ?? "/");
|
|
1873
1976
|
if (permissionError !== void 0) return toolError(runtime, "grep", permissionError);
|
|
1874
1977
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1875
|
-
const { pattern, path = "/", glob = null } = input;
|
|
1876
|
-
const
|
|
1978
|
+
const { pattern, path = "/", glob = null, output_mode = "content" } = input;
|
|
1979
|
+
const maxCount = input.max_count ?? grepMaxCount;
|
|
1980
|
+
const result = await resolvedBackend.grep(pattern, path, glob, maxCount);
|
|
1877
1981
|
if (result.error) return result.error;
|
|
1878
1982
|
const matches = filterByPermissions(result.matches ?? [], permissions, "read", (m) => m.path);
|
|
1879
1983
|
if (matches.length === 0) return `No matches found for pattern '${pattern}'`;
|
|
1880
|
-
const
|
|
1881
|
-
let
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
currentFile = match.path;
|
|
1885
|
-
lines.push(`\n${currentFile}:`);
|
|
1886
|
-
}
|
|
1887
|
-
lines.push(` ${match.line}: ${match.text}`);
|
|
1888
|
-
}
|
|
1889
|
-
const truncated = truncateIfTooLong(lines);
|
|
1890
|
-
if (Array.isArray(truncated)) return truncated.join("\n");
|
|
1891
|
-
return truncated;
|
|
1984
|
+
const truncated = truncateIfTooLong(formatGrepMatches(matches, output_mode));
|
|
1985
|
+
let content = typeof truncated === "string" ? truncated : truncated.join("\n");
|
|
1986
|
+
if (result.truncated) content += `\n\n${GREP_TRUNCATION_NOTE}`;
|
|
1987
|
+
return content;
|
|
1892
1988
|
}, {
|
|
1893
1989
|
name: "grep",
|
|
1894
1990
|
description: customDescription || getGrepToolDescription(includeExecution),
|
|
1895
1991
|
schema: z.object({
|
|
1896
1992
|
pattern: z.string().describe("Literal text pattern to search for (not regex)"),
|
|
1897
1993
|
path: z.string().optional().default("/").describe("Base path to search from (default: /)"),
|
|
1898
|
-
glob: z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')")
|
|
1994
|
+
glob: z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')"),
|
|
1995
|
+
max_count: 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."),
|
|
1996
|
+
output_mode: z.enum([
|
|
1997
|
+
"files_with_matches",
|
|
1998
|
+
"content",
|
|
1999
|
+
"count"
|
|
2000
|
+
]).optional().default("content").describe("Output format: 'files_with_matches' lists matching file paths, 'content' shows matching lines (default), 'count' shows match counts per file")
|
|
1899
2001
|
})
|
|
1900
2002
|
});
|
|
1901
2003
|
}
|
|
@@ -1964,7 +2066,7 @@ function allPathsScopedToRoutes(permissions, backend) {
|
|
|
1964
2066
|
* ```
|
|
1965
2067
|
*/
|
|
1966
2068
|
function createFilesystemMiddleware(options = {}) {
|
|
1967
|
-
const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null } = options;
|
|
2069
|
+
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;
|
|
1968
2070
|
const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);
|
|
1969
2071
|
const executeToolEnabled = enabledFilesystemTools == null || enabledFilesystemTools.has("execute");
|
|
1970
2072
|
if (permissions.length > 0) validatePermissionPaths(permissions);
|
|
@@ -2000,7 +2102,8 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
2000
2102
|
grep: createGrepTool(backend, {
|
|
2001
2103
|
customDescription: customToolDescriptions?.grep,
|
|
2002
2104
|
permissions,
|
|
2003
|
-
includeExecution: configuredToolNames.has("execute") && typeof backend !== "function" && isSandboxBackend(backend)
|
|
2105
|
+
includeExecution: configuredToolNames.has("execute") && typeof backend !== "function" && isSandboxBackend(backend),
|
|
2106
|
+
grepMaxCount
|
|
2004
2107
|
}),
|
|
2005
2108
|
execute: createExecuteTool(backend, {
|
|
2006
2109
|
customDescription: customToolDescriptions?.execute,
|
|
@@ -2031,9 +2134,10 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
2031
2134
|
const evictPath = `/large_tool_results/${sanitizeToolCallId(fallbackToolCallId || msg.tool_call_id)}.txt`;
|
|
2032
2135
|
const writeResult = await resolvedBackend.write(evictPath, textContent);
|
|
2033
2136
|
const contentSample = createContentPreview(textContent);
|
|
2137
|
+
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);
|
|
2034
2138
|
return {
|
|
2035
2139
|
message: new ToolMessage({
|
|
2036
|
-
content:
|
|
2140
|
+
content: replacementText,
|
|
2037
2141
|
tool_call_id: msg.tool_call_id,
|
|
2038
2142
|
name: msg.name,
|
|
2039
2143
|
id: msg.id,
|
|
@@ -2378,6 +2482,7 @@ function createTaskTool(options) {
|
|
|
2378
2482
|
}
|
|
2379
2483
|
return subagentGraphs[subagentType];
|
|
2380
2484
|
}
|
|
2485
|
+
const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
|
|
2381
2486
|
return tool(async (input, config) => {
|
|
2382
2487
|
const { description, subagent_type } = input;
|
|
2383
2488
|
if (!(subagent_type in subagentGraphs)) {
|
|
@@ -2413,7 +2518,7 @@ function createTaskTool(options) {
|
|
|
2413
2518
|
return returnCommandWithStateUpdate(result, config.toolCall.id);
|
|
2414
2519
|
}, {
|
|
2415
2520
|
name: "task",
|
|
2416
|
-
description:
|
|
2521
|
+
description: finalTaskDescription,
|
|
2417
2522
|
schema: z.object({
|
|
2418
2523
|
description: z.string().describe("The task to execute with the selected agent"),
|
|
2419
2524
|
subagent_type: z.string().describe(`Name of the agent to use. Available: ${Object.keys(subagentGraphs).join(", ")}`)
|
|
@@ -2425,18 +2530,19 @@ function createTaskTool(options) {
|
|
|
2425
2530
|
*/
|
|
2426
2531
|
function createSubAgentMiddleware(options) {
|
|
2427
2532
|
const { defaultModel, defaultTools = [], defaultMiddleware = null, generalPurposeMiddleware = null, defaultInterruptOn = null, subagents = [], systemPrompt = null, generalPurposeAgent = true, taskDescription = null } = options;
|
|
2533
|
+
const taskTool = createTaskTool({
|
|
2534
|
+
defaultModel,
|
|
2535
|
+
defaultTools,
|
|
2536
|
+
defaultMiddleware,
|
|
2537
|
+
generalPurposeMiddleware,
|
|
2538
|
+
defaultInterruptOn,
|
|
2539
|
+
subagents,
|
|
2540
|
+
generalPurposeAgent,
|
|
2541
|
+
taskDescription
|
|
2542
|
+
});
|
|
2428
2543
|
return createMiddleware({
|
|
2429
2544
|
name: "subAgentMiddleware",
|
|
2430
|
-
tools: [
|
|
2431
|
-
defaultModel,
|
|
2432
|
-
defaultTools,
|
|
2433
|
-
defaultMiddleware,
|
|
2434
|
-
generalPurposeMiddleware,
|
|
2435
|
-
defaultInterruptOn,
|
|
2436
|
-
subagents,
|
|
2437
|
-
generalPurposeAgent,
|
|
2438
|
-
taskDescription
|
|
2439
|
-
})],
|
|
2545
|
+
tools: [taskTool],
|
|
2440
2546
|
wrapModelCall: async (request, handler) => {
|
|
2441
2547
|
if (systemPrompt !== null) return handler({
|
|
2442
2548
|
...request,
|
|
@@ -2941,7 +3047,7 @@ function createMemoryMiddleware(options) {
|
|
|
2941
3047
|
* });
|
|
2942
3048
|
* ```
|
|
2943
3049
|
*/
|
|
2944
|
-
const MAX_SKILL_FILE_SIZE =
|
|
3050
|
+
const MAX_SKILL_FILE_SIZE = 10485760;
|
|
2945
3051
|
const DEFAULT_SKILL_READ_LINE_LIMIT = 1e3;
|
|
2946
3052
|
const MAX_SKILL_NAME_LENGTH = 64;
|
|
2947
3053
|
const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
|
|
@@ -3704,7 +3810,6 @@ function createCompletionCallbackMiddleware(options) {
|
|
|
3704
3810
|
* from `langchain` directly.
|
|
3705
3811
|
*/
|
|
3706
3812
|
const DEFAULT_MESSAGES_TO_KEEP = 20;
|
|
3707
|
-
const DEFAULT_TRIM_TOKEN_LIMIT = 4e3;
|
|
3708
3813
|
const FALLBACK_TRIGGER = {
|
|
3709
3814
|
type: "tokens",
|
|
3710
3815
|
value: 17e4
|
|
@@ -3821,7 +3926,7 @@ function isSummaryMessage(msg) {
|
|
|
3821
3926
|
* @returns AgentMiddleware for summarization and history offloading
|
|
3822
3927
|
*/
|
|
3823
3928
|
function createSummarizationMiddleware(options) {
|
|
3824
|
-
const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize
|
|
3929
|
+
const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize, historyPathPrefix = "/conversation_history" } = options;
|
|
3825
3930
|
let trigger = options.trigger;
|
|
3826
3931
|
let keep = options.keep ?? {
|
|
3827
3932
|
type: "messages",
|
|
@@ -4025,7 +4130,9 @@ function createSummarizationMiddleware(options) {
|
|
|
4025
4130
|
* This gives a more accurate picture of what actually gets sent to the model.
|
|
4026
4131
|
*/
|
|
4027
4132
|
function countTotalTokens(messages, systemMessage, tools) {
|
|
4028
|
-
|
|
4133
|
+
const countedMessages = systemMessage && SystemMessage.isInstance(systemMessage) ? [systemMessage, ...messages] : [...messages];
|
|
4134
|
+
const toolsArray = tools && Array.isArray(tools) && tools.length > 0 ? tools : null;
|
|
4135
|
+
return countTokensApproximately(countedMessages, toolsArray);
|
|
4029
4136
|
}
|
|
4030
4137
|
/**
|
|
4031
4138
|
* Truncate ToolMessage content so that the total payload fits within the
|
|
@@ -4172,7 +4279,8 @@ function createSummarizationMiddleware(options) {
|
|
|
4172
4279
|
*/
|
|
4173
4280
|
async function createSummary(messages, chatModel) {
|
|
4174
4281
|
let messagesToSummarize = messages;
|
|
4175
|
-
|
|
4282
|
+
const tokens = countTokensApproximately(messages);
|
|
4283
|
+
if (trimTokensToSummarize !== void 0 && tokens > trimTokensToSummarize) {
|
|
4176
4284
|
let kept = 0;
|
|
4177
4285
|
const trimmedMessages = [];
|
|
4178
4286
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -4185,8 +4293,7 @@ function createSummarizationMiddleware(options) {
|
|
|
4185
4293
|
}
|
|
4186
4294
|
const conversation = getBufferString(messagesToSummarize);
|
|
4187
4295
|
const prompt = summaryPrompt.replace("{conversation}", conversation);
|
|
4188
|
-
|
|
4189
|
-
return typeof response.content === "string" ? response.content : JSON.stringify(response.content);
|
|
4296
|
+
return (await chatModel.invoke([new HumanMessage({ content: prompt })])).text;
|
|
4190
4297
|
}
|
|
4191
4298
|
/**
|
|
4192
4299
|
* Build the summary message with file path reference.
|
|
@@ -6357,7 +6464,7 @@ var StoreBackend = class {
|
|
|
6357
6464
|
* Search file contents for a literal text pattern.
|
|
6358
6465
|
* Binary files are skipped.
|
|
6359
6466
|
*/
|
|
6360
|
-
async grep(pattern, path = "/", glob = null) {
|
|
6467
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
6361
6468
|
const store = this.getStore();
|
|
6362
6469
|
const namespace = this.getNamespace();
|
|
6363
6470
|
const items = await this.searchStorePaginated(store, namespace);
|
|
@@ -6367,7 +6474,10 @@ var StoreBackend = class {
|
|
|
6367
6474
|
} catch {
|
|
6368
6475
|
continue;
|
|
6369
6476
|
}
|
|
6370
|
-
return {
|
|
6477
|
+
return applyGrepMaxCount({
|
|
6478
|
+
result: { matches: grepMatchesFromFiles(files, pattern, path, glob) },
|
|
6479
|
+
maxCount
|
|
6480
|
+
});
|
|
6371
6481
|
}
|
|
6372
6482
|
/**
|
|
6373
6483
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -6666,7 +6776,7 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6666
6776
|
modified_at: now
|
|
6667
6777
|
} };
|
|
6668
6778
|
}
|
|
6669
|
-
async grep(pattern, path = null, glob = null) {
|
|
6779
|
+
async grep(pattern, path = null, glob = null, maxCount = null) {
|
|
6670
6780
|
let cache;
|
|
6671
6781
|
try {
|
|
6672
6782
|
cache = await this.ensureCache();
|
|
@@ -6689,7 +6799,10 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6689
6799
|
});
|
|
6690
6800
|
}
|
|
6691
6801
|
}
|
|
6692
|
-
return {
|
|
6802
|
+
return applyGrepMaxCount({
|
|
6803
|
+
result: { matches },
|
|
6804
|
+
maxCount
|
|
6805
|
+
});
|
|
6693
6806
|
}
|
|
6694
6807
|
async glob(pattern, _path = "/") {
|
|
6695
6808
|
let cache;
|
|
@@ -7085,7 +7198,7 @@ var BaseSandbox = class {
|
|
|
7085
7198
|
* @param glob - Optional glob pattern to filter which files to search.
|
|
7086
7199
|
* @returns List of GrepMatch dicts containing path, line number, and matched text.
|
|
7087
7200
|
*/
|
|
7088
|
-
async grep(pattern, path = "/", glob = null) {
|
|
7201
|
+
async grep(pattern, path = "/", glob = null, maxCount = null) {
|
|
7089
7202
|
const command = buildGrepCommand(pattern, path, glob);
|
|
7090
7203
|
const output = (await this.execute(command)).output.trim();
|
|
7091
7204
|
if (!output) return { matches: [] };
|
|
@@ -7103,7 +7216,10 @@ var BaseSandbox = class {
|
|
|
7103
7216
|
});
|
|
7104
7217
|
}
|
|
7105
7218
|
}
|
|
7106
|
-
return {
|
|
7219
|
+
return applyGrepMaxCount({
|
|
7220
|
+
result: { matches },
|
|
7221
|
+
maxCount
|
|
7222
|
+
});
|
|
7107
7223
|
}
|
|
7108
7224
|
/**
|
|
7109
7225
|
* Structured glob matching returning FileInfo objects.
|
|
@@ -7458,6 +7574,6 @@ var LangSmithSandbox = class LangSmithSandbox extends BaseSandbox {
|
|
|
7458
7574
|
}
|
|
7459
7575
|
};
|
|
7460
7576
|
//#endregion
|
|
7461
|
-
export { filesValue as A, StateBackend as B, createSummarizationMiddleware as C, MAX_SKILL_NAME_LENGTH as D, MAX_SKILL_FILE_SIZE as E, SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY as F,
|
|
7577
|
+
export { filesValue as A, StateBackend as B, createSummarizationMiddleware as C, MAX_SKILL_NAME_LENGTH as D, MAX_SKILL_FILE_SIZE as E, SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY as F, resolveBackend as G, applyGrepMaxCount as H, createSubAgent as I, checkEmptyContent as J, adaptBackendProtocol as K, createSubAgentMiddleware as L, DEFAULT_GENERAL_PURPOSE_DESCRIPTION as M, DEFAULT_SUBAGENT_PROMPT as N, createSkillsMiddleware as O, GENERAL_PURPOSE_SUBAGENT as P, createFilesystemMiddleware as R, computeSummarizationDefaults as S, MAX_SKILL_DESCRIPTION_LENGTH as T, isSandboxBackend as U, SandboxError as V, isSandboxProtocol as W, isTextMimeType as X, getMimeType as Y, performStringReplacement as Z, createHarnessProfile as _, ASYNC_TASK_SYSTEM_PROMPT as a, createAsyncSubAgentMiddleware as b, TASK_SYSTEM_PROMPT as c, registerHarnessProfile as d, generalPurposeSubagentConfigSchema as f, EMPTY_HARNESS_PROFILE as g, serializeProfile as h, StoreBackend as i, createPatchToolCallsMiddleware as j, createMemoryMiddleware as k, createDeepAgent as l, parseHarnessProfileConfig as m, BaseSandbox as n, BASE_AGENT_PROMPT as o, harnessProfileConfigSchema as p, adaptSandboxProtocol as q, ContextHubBackend as r, EXECUTION_SYSTEM_PROMPT as s, LangSmithSandbox as t, getHarnessProfile as u, REQUIRED_MIDDLEWARE_NAMES as v, createCompletionCallbackMiddleware as w, isAsyncSubAgent as x, ConfigurationError as y, CompositeBackend as z };
|
|
7462
7578
|
|
|
7463
|
-
//# sourceMappingURL=langsmith-
|
|
7579
|
+
//# sourceMappingURL=langsmith-CUTUAjHo.js.map
|