deepagents 1.10.8 → 1.11.1
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/README.md +17 -0
- package/dist/{agent-DsjC63Eg.d.cts → agent-B2XFuA-E.d.cts} +172 -19
- package/dist/{agent-DgVtHOV7.d.ts → agent-k6GiDPCY.d.ts} +172 -19
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{langsmith-DjCMSywL.js → langsmith-DVh4u6Za.js} +318 -96
- package/dist/langsmith-DVh4u6Za.js.map +1 -0
- package/dist/{langsmith-CiAeUke2.cjs → langsmith-DhbsxI45.cjs} +316 -96
- package/dist/langsmith-DhbsxI45.cjs.map +1 -0
- package/dist/node.cjs +2 -2
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/{src-Bzfzo6KX.js → src-Cqag72HH.js} +51 -2
- package/dist/src-Cqag72HH.js.map +1 -0
- package/dist/{src-BgDEYOGN.cjs → src-DtpWpNrN.cjs} +51 -2
- package/dist/src-DtpWpNrN.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/langsmith-CiAeUke2.cjs.map +0 -1
- package/dist/langsmith-DjCMSywL.js.map +0 -1
- package/dist/src-BgDEYOGN.cjs.map +0 -1
- package/dist/src-Bzfzo6KX.js.map +0 -1
|
@@ -494,7 +494,7 @@ function migrateToFileDataV2(data, filePath) {
|
|
|
494
494
|
* @returns BackendProtocolV2-compatible backend
|
|
495
495
|
*/
|
|
496
496
|
function adaptBackendProtocol(backend) {
|
|
497
|
-
|
|
497
|
+
const adapted = {
|
|
498
498
|
async ls(path) {
|
|
499
499
|
const result = await ("ls" in backend ? backend.ls(path) : backend.lsInfo(path));
|
|
500
500
|
if (Array.isArray(result)) return { files: result };
|
|
@@ -512,6 +512,7 @@ function adaptBackendProtocol(backend) {
|
|
|
512
512
|
},
|
|
513
513
|
write: (filePath, content) => backend.write(filePath, content),
|
|
514
514
|
edit: (filePath, oldString, newString, replaceAll) => backend.edit(filePath, oldString, newString, replaceAll),
|
|
515
|
+
delete: backend.delete?.bind(backend),
|
|
515
516
|
uploadFiles: backend.uploadFiles ? (files) => backend.uploadFiles(files) : void 0,
|
|
516
517
|
downloadFiles: backend.downloadFiles ? (paths) => backend.downloadFiles(paths) : void 0,
|
|
517
518
|
async read(filePath, offset, limit) {
|
|
@@ -526,6 +527,13 @@ function adaptBackendProtocol(backend) {
|
|
|
526
527
|
return result;
|
|
527
528
|
}
|
|
528
529
|
};
|
|
530
|
+
const routePrefixes = backend.routePrefixes;
|
|
531
|
+
if (Array.isArray(routePrefixes)) Object.defineProperty(adapted, "routePrefixes", {
|
|
532
|
+
value: routePrefixes,
|
|
533
|
+
enumerable: true,
|
|
534
|
+
configurable: true
|
|
535
|
+
});
|
|
536
|
+
return adapted;
|
|
529
537
|
}
|
|
530
538
|
/**
|
|
531
539
|
* Adapt a sandbox backend from v1 to v2 interface.
|
|
@@ -693,7 +701,8 @@ var StateBackend = class {
|
|
|
693
701
|
* In legacy mode, this is a no-op — the caller uses `filesUpdate`
|
|
694
702
|
* from the return value instead.
|
|
695
703
|
*
|
|
696
|
-
* @param update - Map of file paths to their updated {@link FileData}
|
|
704
|
+
* @param update - Map of file paths to their updated {@link FileData},
|
|
705
|
+
* or null deletion markers.
|
|
697
706
|
*/
|
|
698
707
|
sendFilesUpdate(update) {
|
|
699
708
|
if (this.isLegacy) return;
|
|
@@ -817,6 +826,15 @@ var StateBackend = class {
|
|
|
817
826
|
};
|
|
818
827
|
}
|
|
819
828
|
/**
|
|
829
|
+
* Delete a file from state by sending a null deletion marker through Pregel.
|
|
830
|
+
*/
|
|
831
|
+
delete(filePath) {
|
|
832
|
+
if (!(filePath in this.files)) return { error: `Error: File '${filePath}' not found` };
|
|
833
|
+
if (this.isLegacy) return { error: "StateBackend.delete requires a zero-argument StateBackend in a LangGraph execution context." };
|
|
834
|
+
this.sendFilesUpdate({ [filePath]: null });
|
|
835
|
+
return { path: filePath };
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
820
838
|
* Search file contents for a literal text pattern.
|
|
821
839
|
* Binary files are skipped.
|
|
822
840
|
*/
|
|
@@ -1183,6 +1201,19 @@ var CompositeBackend = class {
|
|
|
1183
1201
|
return await backend.edit(strippedKey, oldString, newString, replaceAll);
|
|
1184
1202
|
}
|
|
1185
1203
|
/**
|
|
1204
|
+
* Delete a file, routing to the appropriate backend.
|
|
1205
|
+
*/
|
|
1206
|
+
async delete(filePath) {
|
|
1207
|
+
const [backend, strippedKey] = this.getBackendAndKey(filePath);
|
|
1208
|
+
if (!backend.delete) return { error: "Backend does not support delete" };
|
|
1209
|
+
const result = await backend.delete(strippedKey);
|
|
1210
|
+
if (result.path !== void 0) return {
|
|
1211
|
+
...result,
|
|
1212
|
+
path: filePath
|
|
1213
|
+
};
|
|
1214
|
+
return result;
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1186
1217
|
* Execute a command via the default backend.
|
|
1187
1218
|
* Execution is not path-specific, so it always delegates to the default backend.
|
|
1188
1219
|
*
|
|
@@ -1324,14 +1355,10 @@ const FILESYSTEM_TOOL_NAMES = [
|
|
|
1324
1355
|
"grep",
|
|
1325
1356
|
"execute"
|
|
1326
1357
|
];
|
|
1327
|
-
|
|
1328
|
-
"
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
"read_file",
|
|
1332
|
-
"edit_file",
|
|
1333
|
-
"write_file"
|
|
1334
|
-
];
|
|
1358
|
+
function isFilesystemToolName(name) {
|
|
1359
|
+
return typeof name === "string" && FILESYSTEM_TOOL_NAMES.includes(name);
|
|
1360
|
+
}
|
|
1361
|
+
const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter((name) => name !== "execute");
|
|
1335
1362
|
/**
|
|
1336
1363
|
* Maximum size for binary (non-text) files read via read_file, in bytes.
|
|
1337
1364
|
* Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.
|
|
@@ -1499,19 +1526,46 @@ const FilesystemStateSchema = new _langchain_langgraph.StateSchema({ files: new
|
|
|
1499
1526
|
inputSchema: zod_v4.z.record(zod_v4.z.string(), FileDataSchema.nullable()).optional(),
|
|
1500
1527
|
reducer: fileDataReducer
|
|
1501
1528
|
}) });
|
|
1529
|
+
/** Extract a message string from an unknown thrown value without `instanceof`. */
|
|
1530
|
+
function getErrorMessage$1(error) {
|
|
1531
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") return error.message;
|
|
1532
|
+
return String(error);
|
|
1533
|
+
}
|
|
1502
1534
|
/**
|
|
1503
|
-
*
|
|
1535
|
+
* Check whether `path` is permitted under `rules` for `operation`, returning an
|
|
1536
|
+
* error string to surface to the model (or `undefined` when allowed).
|
|
1504
1537
|
*
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1538
|
+
* Never throws: an invalid path (non-absolute, or containing `..` or `~`) or a
|
|
1539
|
+
* denied path is a recoverable tool error, not a fatal run-ending one. Such
|
|
1540
|
+
* paths are rejected, never normalized, so they cannot bypass a deny rule or
|
|
1541
|
+
* reach the backend.
|
|
1508
1542
|
*
|
|
1509
1543
|
* @internal
|
|
1510
1544
|
*/
|
|
1511
|
-
function
|
|
1545
|
+
function checkPermission(rules, operation, path) {
|
|
1512
1546
|
if (rules.length === 0) return;
|
|
1513
|
-
|
|
1514
|
-
|
|
1547
|
+
let canonical;
|
|
1548
|
+
try {
|
|
1549
|
+
canonical = validatePath(path);
|
|
1550
|
+
} catch (error) {
|
|
1551
|
+
return `Error: ${getErrorMessage$1(error)}`;
|
|
1552
|
+
}
|
|
1553
|
+
if (decidePathAccess(rules, operation, canonical) === "deny") return `Error: permission denied for ${operation} on ${canonical}`;
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Build an error {@link ToolMessage} for a rejected or denied path. Returning a
|
|
1557
|
+
* bare string would be wrapped as a `status: "success"` message whose content
|
|
1558
|
+
* merely starts with "Error:"; marking `status: "error"` reports the failure
|
|
1559
|
+
* accurately so callers and the model can distinguish a real failure from a
|
|
1560
|
+
* successful result.
|
|
1561
|
+
*/
|
|
1562
|
+
function toolError(runtime, toolName, message) {
|
|
1563
|
+
return new langchain.ToolMessage({
|
|
1564
|
+
content: message,
|
|
1565
|
+
name: toolName,
|
|
1566
|
+
tool_call_id: runtime.toolCall?.id,
|
|
1567
|
+
status: "error"
|
|
1568
|
+
});
|
|
1515
1569
|
}
|
|
1516
1570
|
/**
|
|
1517
1571
|
* Filter a list of filesystem entries to those the rules permit.
|
|
@@ -1532,24 +1586,33 @@ function filterByPermissions(entries, rules, operation, getPath) {
|
|
|
1532
1586
|
}
|
|
1533
1587
|
});
|
|
1534
1588
|
}
|
|
1535
|
-
const
|
|
1536
|
-
|
|
1589
|
+
const FILESYSTEM_TOOL_DESCRIPTION_LINES = {
|
|
1590
|
+
ls: "ls: list files in a directory (requires absolute path)",
|
|
1591
|
+
read_file: "read_file: read a file from the filesystem",
|
|
1592
|
+
write_file: "write_file: write to a file in the filesystem",
|
|
1593
|
+
edit_file: "edit_file: edit a file in the filesystem",
|
|
1594
|
+
glob: "glob: find files matching a pattern (e.g., \"**/*.py\")",
|
|
1595
|
+
grep: "grep: search for text within files"
|
|
1596
|
+
};
|
|
1597
|
+
function hasFilesystemToolDescription(name) {
|
|
1598
|
+
return name in FILESYSTEM_TOOL_DESCRIPTION_LINES;
|
|
1599
|
+
}
|
|
1600
|
+
function buildFilesystemSystemPrompt(visibleTools) {
|
|
1601
|
+
const promptToolNames = FILESYSTEM_TOOL_NAMES.filter((name) => visibleTools.has(name));
|
|
1602
|
+
return langchain.context`
|
|
1603
|
+
## Following Conventions
|
|
1537
1604
|
|
|
1538
|
-
|
|
1539
|
-
|
|
1605
|
+
- Read files before editing — understand existing content before making changes
|
|
1606
|
+
- Mimic existing style, naming conventions, and patterns
|
|
1540
1607
|
|
|
1541
|
-
|
|
1608
|
+
## Filesystem Tools ${promptToolNames.map((name) => `\`${name}\``).join(", ")}
|
|
1542
1609
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1610
|
+
You have access to a filesystem which you can interact with using these tools.
|
|
1611
|
+
All file paths must start with a /.
|
|
1545
1612
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
- edit_file: edit a file in the filesystem
|
|
1550
|
-
- glob: find files matching a pattern (e.g., "**/*.py")
|
|
1551
|
-
- grep: search for text within files
|
|
1552
|
-
`;
|
|
1613
|
+
${promptToolNames.filter(hasFilesystemToolDescription).map((name) => `- ${FILESYSTEM_TOOL_DESCRIPTION_LINES[name]}`).join("\n")}
|
|
1614
|
+
`;
|
|
1615
|
+
}
|
|
1553
1616
|
const LS_TOOL_DESCRIPTION = langchain.context`
|
|
1554
1617
|
Lists all files in a directory.
|
|
1555
1618
|
|
|
@@ -1673,7 +1736,8 @@ const EXECUTION_SYSTEM_PROMPT = langchain.context`
|
|
|
1673
1736
|
function createLsTool(backend, options) {
|
|
1674
1737
|
const { customDescription, permissions } = options;
|
|
1675
1738
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1676
|
-
|
|
1739
|
+
const permissionError = checkPermission(permissions, "read", input.path ?? "/");
|
|
1740
|
+
if (permissionError !== void 0) return toolError(runtime, "ls", permissionError);
|
|
1677
1741
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1678
1742
|
const path = input.path || "/";
|
|
1679
1743
|
const lsResult = await resolvedBackend.ls(path);
|
|
@@ -1701,7 +1765,8 @@ function createLsTool(backend, options) {
|
|
|
1701
1765
|
function createReadFileTool(backend, options) {
|
|
1702
1766
|
const { customDescription, toolTokenLimitBeforeEvict, permissions } = options;
|
|
1703
1767
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1704
|
-
|
|
1768
|
+
const permissionError = checkPermission(permissions, "read", input.file_path);
|
|
1769
|
+
if (permissionError !== void 0) return toolError(runtime, "read_file", permissionError);
|
|
1705
1770
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1706
1771
|
const { file_path, offset = 0, limit = 100 } = input;
|
|
1707
1772
|
const readResult = await resolvedBackend.read(file_path, offset, limit);
|
|
@@ -1778,7 +1843,8 @@ function createReadFileTool(backend, options) {
|
|
|
1778
1843
|
function createWriteFileTool(backend, options) {
|
|
1779
1844
|
const { customDescription, permissions } = options;
|
|
1780
1845
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1781
|
-
|
|
1846
|
+
const permissionError = checkPermission(permissions, "write", input.file_path);
|
|
1847
|
+
if (permissionError !== void 0) return toolError(runtime, "write_file", permissionError);
|
|
1782
1848
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1783
1849
|
const { file_path, content } = input;
|
|
1784
1850
|
const result = await resolvedBackend.write(file_path, content);
|
|
@@ -1809,7 +1875,8 @@ function createWriteFileTool(backend, options) {
|
|
|
1809
1875
|
function createEditFileTool(backend, options) {
|
|
1810
1876
|
const { customDescription, permissions } = options;
|
|
1811
1877
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1812
|
-
|
|
1878
|
+
const permissionError = checkPermission(permissions, "write", input.file_path);
|
|
1879
|
+
if (permissionError !== void 0) return toolError(runtime, "edit_file", permissionError);
|
|
1813
1880
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1814
1881
|
const { file_path, old_string, new_string, replace_all = false } = input;
|
|
1815
1882
|
const result = await resolvedBackend.edit(file_path, old_string, new_string, replace_all);
|
|
@@ -1842,7 +1909,8 @@ function createEditFileTool(backend, options) {
|
|
|
1842
1909
|
function createGlobTool(backend, options) {
|
|
1843
1910
|
const { customDescription, permissions } = options;
|
|
1844
1911
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1845
|
-
|
|
1912
|
+
const permissionError = checkPermission(permissions, "read", input.path ?? "/");
|
|
1913
|
+
if (permissionError !== void 0) return toolError(runtime, "glob", permissionError);
|
|
1846
1914
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1847
1915
|
const { pattern, path = "/" } = input;
|
|
1848
1916
|
const globResult = await resolvedBackend.glob(pattern, path);
|
|
@@ -1867,7 +1935,8 @@ function createGlobTool(backend, options) {
|
|
|
1867
1935
|
function createGrepTool(backend, options) {
|
|
1868
1936
|
const { customDescription, permissions } = options;
|
|
1869
1937
|
return (0, langchain.tool)(async (input, runtime) => {
|
|
1870
|
-
|
|
1938
|
+
const permissionError = checkPermission(permissions, "read", input.path ?? "/");
|
|
1939
|
+
if (permissionError !== void 0) return toolError(runtime, "grep", permissionError);
|
|
1871
1940
|
const resolvedBackend = await resolveBackend(backend, runtime);
|
|
1872
1941
|
const { pattern, path = "/", glob = null } = input;
|
|
1873
1942
|
const result = await resolvedBackend.grep(pattern, path, glob);
|
|
@@ -1923,6 +1992,12 @@ function createExecuteTool(backend, options) {
|
|
|
1923
1992
|
* Returns true only when backend exposes route prefixes (CompositeBackend) and
|
|
1924
1993
|
* every permission path is scoped under one of them.
|
|
1925
1994
|
*/
|
|
1995
|
+
function normalizeFilesystemTools(tools) {
|
|
1996
|
+
if (tools == null || tools === "all") return null;
|
|
1997
|
+
const enabledTools = new Set(tools);
|
|
1998
|
+
if (!enabledTools.has("read_file")) throw new Error("read_file must be included in tools; it is required by FilesystemMiddleware");
|
|
1999
|
+
return enabledTools;
|
|
2000
|
+
}
|
|
1926
2001
|
function allPathsScopedToRoutes(permissions, backend) {
|
|
1927
2002
|
if (!CompositeBackend.isInstance(backend)) return false;
|
|
1928
2003
|
const prefixes = backend.routePrefixes;
|
|
@@ -1930,13 +2005,43 @@ function allPathsScopedToRoutes(permissions, backend) {
|
|
|
1930
2005
|
return permissions.every((rule) => rule.paths.every((path) => prefixes.some((prefix) => path.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`))));
|
|
1931
2006
|
}
|
|
1932
2007
|
/**
|
|
1933
|
-
* Create
|
|
2008
|
+
* Create middleware that provides built-in filesystem tools and filesystem-aware
|
|
2009
|
+
* prompt guidance.
|
|
2010
|
+
*
|
|
2011
|
+
* By default, the middleware registers every built-in filesystem tool listed in
|
|
2012
|
+
* {@link FILESYSTEM_TOOL_NAMES}. Use {@link FilesystemMiddlewareOptions.tools}
|
|
2013
|
+
* to narrow that set for read-only, search-only, or otherwise restricted
|
|
2014
|
+
* agents. The allowlist only controls built-in filesystem tools; custom tools
|
|
2015
|
+
* from the agent or other middleware are left untouched.
|
|
2016
|
+
*
|
|
2017
|
+
* The middleware also filters tools whose backend capabilities are unavailable
|
|
2018
|
+
* at request time. In particular, `execute` is only visible when the resolved
|
|
2019
|
+
* backend supports command execution. The filesystem prompt is generated from
|
|
2020
|
+
* the final visible filesystem tools so the model is not instructed to call
|
|
2021
|
+
* tools it cannot see.
|
|
2022
|
+
*
|
|
2023
|
+
* @param options Filesystem middleware configuration.
|
|
2024
|
+
* @returns Agent middleware that contributes filesystem state, tools, prompt
|
|
2025
|
+
* guidance, permission checks, and large-result eviction.
|
|
2026
|
+
*
|
|
2027
|
+
* @example Read-only filesystem middleware
|
|
2028
|
+
* ```ts
|
|
2029
|
+
* const middleware = createFilesystemMiddleware({
|
|
2030
|
+
* tools: ["read_file", "ls", "glob", "grep"],
|
|
2031
|
+
* });
|
|
2032
|
+
* ```
|
|
1934
2033
|
*/
|
|
1935
2034
|
function createFilesystemMiddleware(options = {}) {
|
|
1936
|
-
const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [] } = options;
|
|
2035
|
+
const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null } = options;
|
|
2036
|
+
const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);
|
|
2037
|
+
const executeToolEnabled = enabledFilesystemTools == null || enabledFilesystemTools.has("execute");
|
|
1937
2038
|
if (permissions.length > 0) validatePermissionPaths(permissions);
|
|
1938
|
-
if (permissions.length > 0 && typeof backend !== "function" && isSandboxBackend(backend) && !allPathsScopedToRoutes(permissions, backend)) throw new Error("Filesystem permissions cannot be used with a backend that supports command execution. Shell commands can access any path, making path-based rules ineffective. Either remove permissions, use a backend without execution support, or use a CompositeBackend with all permission paths scoped to a route prefix.");
|
|
1939
|
-
const baseSystemPrompt = customSystemPrompt
|
|
2039
|
+
if (permissions.length > 0 && executeToolEnabled && typeof backend !== "function" && isSandboxBackend(backend) && !allPathsScopedToRoutes(permissions, backend)) throw new Error("Filesystem permissions cannot be used with a backend that supports command execution. Shell commands can access any path, making path-based rules ineffective. Either remove permissions, use a backend without execution support, or use a CompositeBackend with all permission paths scoped to a route prefix.");
|
|
2040
|
+
const baseSystemPrompt = customSystemPrompt ?? null;
|
|
2041
|
+
/**
|
|
2042
|
+
* All tools including execute
|
|
2043
|
+
* (execute will be filtered at runtime if backend doesn't support it)
|
|
2044
|
+
*/
|
|
1940
2045
|
const allToolsByName = {
|
|
1941
2046
|
ls: createLsTool(backend, {
|
|
1942
2047
|
customDescription: customToolDescriptions?.ls,
|
|
@@ -1968,7 +2073,7 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
1968
2073
|
permissions
|
|
1969
2074
|
})
|
|
1970
2075
|
};
|
|
1971
|
-
const allTools =
|
|
2076
|
+
const allTools = FILESYSTEM_TOOL_NAMES.filter((name) => enabledFilesystemTools == null || enabledFilesystemTools.has(name)).map((name) => allToolsByName[name]);
|
|
1972
2077
|
async function processToolMessage(msg, runtime, state, fallbackToolCallId) {
|
|
1973
2078
|
if (!toolTokenLimitBeforeEvict) return {
|
|
1974
2079
|
message: msg,
|
|
@@ -2042,8 +2147,14 @@ function createFilesystemMiddleware(options = {}) {
|
|
|
2042
2147
|
}));
|
|
2043
2148
|
let tools = request.tools;
|
|
2044
2149
|
if (!supportsExecution) tools = tools.filter((t) => t.name !== "execute");
|
|
2045
|
-
|
|
2046
|
-
|
|
2150
|
+
const visibleFilesystemTools = /* @__PURE__ */ new Set();
|
|
2151
|
+
for (const currentTool of tools) {
|
|
2152
|
+
const toolName = typeof currentTool.name === "string" ? currentTool.name : void 0;
|
|
2153
|
+
if (isFilesystemToolName(toolName)) visibleFilesystemTools.add(toolName);
|
|
2154
|
+
}
|
|
2155
|
+
const executionActive = supportsExecution && visibleFilesystemTools.has("execute");
|
|
2156
|
+
let filesystemPrompt = baseSystemPrompt ?? buildFilesystemSystemPrompt(visibleFilesystemTools);
|
|
2157
|
+
if (executionActive) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
|
|
2047
2158
|
const newSystemMessage = request.systemMessage.concat(filesystemPrompt);
|
|
2048
2159
|
let messages = request.messages;
|
|
2049
2160
|
if (humanMessageTokenLimitBeforeEvict && messages) {
|
|
@@ -3487,6 +3598,41 @@ function createSkillsMiddleware(options) {
|
|
|
3487
3598
|
*
|
|
3488
3599
|
* This module provides shared helpers used across middleware implementations.
|
|
3489
3600
|
*/
|
|
3601
|
+
/**
|
|
3602
|
+
* Merge custom middleware into an assembled stack by `.name`.
|
|
3603
|
+
*
|
|
3604
|
+
* Matching custom middleware replaces the existing entry in place. New
|
|
3605
|
+
* middleware is appended after the base stack in caller-provided order.
|
|
3606
|
+
*/
|
|
3607
|
+
function mergeMiddleware$1(base, custom) {
|
|
3608
|
+
const merged = new Map(base.map((middleware) => [middleware.name, middleware]));
|
|
3609
|
+
for (const middleware of custom) merged.set(middleware.name, middleware);
|
|
3610
|
+
return [...merged.values()];
|
|
3611
|
+
}
|
|
3612
|
+
function middlewareNames(middleware) {
|
|
3613
|
+
return new Set(middleware.map((entry) => entry.name));
|
|
3614
|
+
}
|
|
3615
|
+
function matchingMiddleware(middleware, names) {
|
|
3616
|
+
return middleware.filter((entry) => names.has(entry.name));
|
|
3617
|
+
}
|
|
3618
|
+
/**
|
|
3619
|
+
* Merge custom middleware into default and tail middleware segments.
|
|
3620
|
+
*
|
|
3621
|
+
* Same-name custom entries replace matching defaults in either segment. Novel
|
|
3622
|
+
* custom entries are inserted between the default and tail segments unless
|
|
3623
|
+
* `appendNew` is false.
|
|
3624
|
+
*/
|
|
3625
|
+
function mergeMiddlewareStack(defaultMiddleware, customMiddleware, tailMiddleware = [], options = {}) {
|
|
3626
|
+
const defaultMiddlewareNames = middlewareNames(defaultMiddleware);
|
|
3627
|
+
const tailMiddlewareNames = middlewareNames(tailMiddleware);
|
|
3628
|
+
const knownMiddlewareNames = /* @__PURE__ */ new Set([...defaultMiddlewareNames, ...tailMiddlewareNames]);
|
|
3629
|
+
const novelMiddleware = options.appendNew === false ? [] : customMiddleware.filter((entry) => !knownMiddlewareNames.has(entry.name));
|
|
3630
|
+
return [
|
|
3631
|
+
...mergeMiddleware$1(defaultMiddleware, matchingMiddleware(customMiddleware, defaultMiddlewareNames)),
|
|
3632
|
+
...novelMiddleware,
|
|
3633
|
+
...mergeMiddleware$1(tailMiddleware, matchingMiddleware(customMiddleware, tailMiddlewareNames))
|
|
3634
|
+
];
|
|
3635
|
+
}
|
|
3490
3636
|
//#endregion
|
|
3491
3637
|
//#region src/middleware/completion_callback.ts
|
|
3492
3638
|
/**
|
|
@@ -5079,6 +5225,28 @@ function createCacheBreakpointMiddleware() {
|
|
|
5079
5225
|
});
|
|
5080
5226
|
}
|
|
5081
5227
|
//#endregion
|
|
5228
|
+
//#region src/middleware/tool_exclusion.ts
|
|
5229
|
+
function hasToolName(tool) {
|
|
5230
|
+
return tool !== null && typeof tool === "object" && "name" in tool && typeof tool.name === "string";
|
|
5231
|
+
}
|
|
5232
|
+
/**
|
|
5233
|
+
* Create middleware that removes excluded tools after all tool-injecting
|
|
5234
|
+
* middleware has had a chance to add tools to the request.
|
|
5235
|
+
*
|
|
5236
|
+
* @internal
|
|
5237
|
+
*/
|
|
5238
|
+
function createToolExclusionMiddleware(excludedTools) {
|
|
5239
|
+
return (0, langchain.createMiddleware)({
|
|
5240
|
+
name: "_ToolExclusionMiddleware",
|
|
5241
|
+
wrapModelCall(request, handler) {
|
|
5242
|
+
return handler({
|
|
5243
|
+
...request,
|
|
5244
|
+
tools: request.tools?.filter((tool) => !hasToolName(tool) || !excludedTools.has(tool.name))
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
});
|
|
5248
|
+
}
|
|
5249
|
+
//#endregion
|
|
5082
5250
|
//#region src/profiles/keys.ts
|
|
5083
5251
|
/**
|
|
5084
5252
|
* Normalize and validate a profile registry key.
|
|
@@ -5782,6 +5950,31 @@ const BASE_AGENT_PROMPT = langchain.context`
|
|
|
5782
5950
|
|
|
5783
5951
|
For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
|
|
5784
5952
|
`;
|
|
5953
|
+
const PROMPT_SEPARATOR = "\n\n";
|
|
5954
|
+
/** Normalize legacy system prompt values to the structured representation. */
|
|
5955
|
+
function normalizeSystemPrompt(systemPrompt) {
|
|
5956
|
+
if (systemPrompt === void 0) return {};
|
|
5957
|
+
if (typeof systemPrompt === "string" || langchain.SystemMessage.isInstance(systemPrompt)) return { prefix: systemPrompt };
|
|
5958
|
+
return systemPrompt;
|
|
5959
|
+
}
|
|
5960
|
+
/** Assemble prompt parts while preserving structured message content blocks. */
|
|
5961
|
+
function assemblePromptParts(parts) {
|
|
5962
|
+
if (parts.length === 0) return "";
|
|
5963
|
+
if (parts.every((part) => typeof part === "string")) return parts.join(PROMPT_SEPARATOR);
|
|
5964
|
+
const contentBlocks = [];
|
|
5965
|
+
for (const [index, part] of parts.entries()) {
|
|
5966
|
+
if (index > 0) contentBlocks.push({
|
|
5967
|
+
type: "text",
|
|
5968
|
+
text: PROMPT_SEPARATOR
|
|
5969
|
+
});
|
|
5970
|
+
if (langchain.SystemMessage.isInstance(part)) contentBlocks.push(...part.contentBlocks);
|
|
5971
|
+
else contentBlocks.push({
|
|
5972
|
+
type: "text",
|
|
5973
|
+
text: part
|
|
5974
|
+
});
|
|
5975
|
+
}
|
|
5976
|
+
return new langchain.SystemMessage({ contentBlocks });
|
|
5977
|
+
}
|
|
5785
5978
|
const BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
5786
5979
|
...FILESYSTEM_TOOL_NAMES,
|
|
5787
5980
|
...ASYNC_TASK_TOOL_NAMES,
|
|
@@ -5827,6 +6020,8 @@ function createDeepAgent(params = {}) {
|
|
|
5827
6020
|
providerHint: getModelProvider(model),
|
|
5828
6021
|
identifierHint: getModelIdentifier(model)
|
|
5829
6022
|
});
|
|
6023
|
+
const filesystemTools = FILESYSTEM_TOOL_NAMES.filter((toolName) => !harnessProfile.excludedTools.has(toolName));
|
|
6024
|
+
const profileFilesystemTools = filesystemTools.length === FILESYSTEM_TOOL_NAMES.length || !filesystemTools.includes("read_file") ? void 0 : filesystemTools;
|
|
5830
6025
|
const toolOverrides = harnessProfile.toolDescriptionOverrides;
|
|
5831
6026
|
const effectiveTools = Object.keys(toolOverrides).length > 0 ? tools.map((t) => t.name in toolOverrides ? Object.assign(Object.create(Object.getPrototypeOf(t)), t, { description: toolOverrides[t.name] }) : t) : tools;
|
|
5832
6027
|
const anthropicModel = isAnthropicModel(model);
|
|
@@ -5848,23 +6043,26 @@ function createDeepAgent(params = {}) {
|
|
|
5848
6043
|
* Only the general-purpose subagent inherits the main agent's skills.
|
|
5849
6044
|
* If a custom subagent needs skills, it must specify its own `skills` array.
|
|
5850
6045
|
*/
|
|
5851
|
-
const
|
|
6046
|
+
const createSubagentDefaultMiddleware = (input) => {
|
|
5852
6047
|
const effectivePermissions = input.permissions ?? permissions;
|
|
5853
|
-
|
|
6048
|
+
return [
|
|
5854
6049
|
(0, langchain.todoListMiddleware)(),
|
|
5855
6050
|
createFilesystemMiddleware({
|
|
5856
6051
|
backend,
|
|
5857
|
-
permissions: effectivePermissions
|
|
6052
|
+
permissions: effectivePermissions,
|
|
6053
|
+
tools: profileFilesystemTools
|
|
5858
6054
|
}),
|
|
5859
6055
|
createSummarizationMiddleware({ backend }),
|
|
5860
6056
|
createPatchToolCallsMiddleware(),
|
|
5861
6057
|
...input.skills != null && input.skills.length > 0 ? [createSkillsMiddleware({
|
|
5862
6058
|
backend,
|
|
5863
6059
|
sources: input.skills
|
|
5864
|
-
})] : []
|
|
5865
|
-
...input.middleware ?? [],
|
|
5866
|
-
...cacheMiddleware
|
|
6060
|
+
})] : []
|
|
5867
6061
|
];
|
|
6062
|
+
};
|
|
6063
|
+
const normalizeSubagentSpec = (input) => {
|
|
6064
|
+
let subagentMiddleware = mergeMiddlewareStack(createSubagentDefaultMiddleware(input), input.middleware ?? [], cacheMiddleware);
|
|
6065
|
+
if (harnessProfile.excludedMiddleware.size > 0) subagentMiddleware = subagentMiddleware.filter((middleware) => !harnessProfile.excludedMiddleware.has(middleware.name));
|
|
5868
6066
|
return {
|
|
5869
6067
|
...input,
|
|
5870
6068
|
tools: input.tools ?? [],
|
|
@@ -5885,6 +6083,7 @@ function createDeepAgent(params = {}) {
|
|
|
5885
6083
|
skills,
|
|
5886
6084
|
tools: effectiveTools
|
|
5887
6085
|
});
|
|
6086
|
+
generalPurposeSpec.middleware = mergeMiddlewareStack(generalPurposeSpec.middleware ?? [], customMiddleware, [], { appendNew: false });
|
|
5888
6087
|
inlineSubagents.unshift(generalPurposeSpec);
|
|
5889
6088
|
}
|
|
5890
6089
|
const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
|
|
@@ -5895,7 +6094,8 @@ function createDeepAgent(params = {}) {
|
|
|
5895
6094
|
(0, langchain.todoListMiddleware)(),
|
|
5896
6095
|
createFilesystemMiddleware({
|
|
5897
6096
|
backend,
|
|
5898
|
-
permissions
|
|
6097
|
+
permissions,
|
|
6098
|
+
tools: profileFilesystemTools
|
|
5899
6099
|
}),
|
|
5900
6100
|
createSubAgentMiddleware({
|
|
5901
6101
|
defaultModel: model,
|
|
@@ -5907,15 +6107,16 @@ function createDeepAgent(params = {}) {
|
|
|
5907
6107
|
createSummarizationMiddleware({ backend }),
|
|
5908
6108
|
createPatchToolCallsMiddleware()
|
|
5909
6109
|
];
|
|
5910
|
-
|
|
6110
|
+
let middleware = mergeMiddlewareStack([
|
|
5911
6111
|
todoMiddleware,
|
|
5912
6112
|
...skillsMiddleware,
|
|
5913
6113
|
fsMiddleware,
|
|
5914
6114
|
subagentMiddleware,
|
|
5915
6115
|
summarizationMiddleware,
|
|
5916
6116
|
patchToolCallsMiddleware,
|
|
5917
|
-
...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
|
|
5918
|
-
|
|
6117
|
+
...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
|
|
6118
|
+
], customMiddleware, [
|
|
6119
|
+
...resolveMiddleware(harnessProfile.extraMiddleware),
|
|
5919
6120
|
...cacheMiddleware,
|
|
5920
6121
|
...memory && memory.length > 0 ? [createMemoryMiddleware({
|
|
5921
6122
|
backend,
|
|
@@ -5923,32 +6124,19 @@ function createDeepAgent(params = {}) {
|
|
|
5923
6124
|
addCacheControl: anthropicModel
|
|
5924
6125
|
})] : [],
|
|
5925
6126
|
...interruptOn ? [(0, langchain.humanInTheLoopMiddleware)({ interruptOn })] : []
|
|
5926
|
-
];
|
|
5927
|
-
const profileMiddleware = resolveMiddleware(harnessProfile.extraMiddleware);
|
|
5928
|
-
if (profileMiddleware.length > 0) {
|
|
5929
|
-
const cacheIdx = middleware.findIndex((m) => m.name === "AnthropicPromptCachingMiddleware");
|
|
5930
|
-
if (cacheIdx !== -1) middleware.splice(cacheIdx, 0, ...profileMiddleware);
|
|
5931
|
-
else middleware.push(...profileMiddleware);
|
|
5932
|
-
}
|
|
6127
|
+
]);
|
|
5933
6128
|
if (harnessProfile.excludedMiddleware.size > 0) {
|
|
5934
6129
|
const excluded = harnessProfile.excludedMiddleware;
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
...request,
|
|
5946
|
-
tools: request.tools?.filter((t) => !excludedTools.has(t.name))
|
|
5947
|
-
});
|
|
5948
|
-
}
|
|
5949
|
-
}));
|
|
5950
|
-
}
|
|
5951
|
-
const effectiveBasePrompt = applyProfilePrompt(harnessProfile, BASE_AGENT_PROMPT);
|
|
6130
|
+
middleware = middleware.filter((entry) => !excluded.has(entry.name));
|
|
6131
|
+
}
|
|
6132
|
+
if (harnessProfile.excludedTools.size > 0) middleware.push(createToolExclusionMiddleware(harnessProfile.excludedTools));
|
|
6133
|
+
const promptConfig = normalizeSystemPrompt(systemPrompt);
|
|
6134
|
+
const promptParts = [];
|
|
6135
|
+
if (promptConfig.prefix !== void 0 && promptConfig.prefix !== null) promptParts.push(promptConfig.prefix);
|
|
6136
|
+
const activeBasePrompt = promptConfig.base !== void 0 ? promptConfig.base : harnessProfile.baseSystemPrompt ?? BASE_AGENT_PROMPT;
|
|
6137
|
+
if (activeBasePrompt !== null) promptParts.push(activeBasePrompt);
|
|
6138
|
+
if (promptConfig.suffix) promptParts.push(promptConfig.suffix);
|
|
6139
|
+
if (harnessProfile.systemPromptSuffix) promptParts.push(harnessProfile.systemPromptSuffix);
|
|
5952
6140
|
/**
|
|
5953
6141
|
* Return as DeepAgent with proper DeepAgentTypeConfig
|
|
5954
6142
|
* - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)
|
|
@@ -5961,19 +6149,7 @@ function createDeepAgent(params = {}) {
|
|
|
5961
6149
|
*/
|
|
5962
6150
|
return (0, langchain.createAgent)({
|
|
5963
6151
|
model,
|
|
5964
|
-
systemPrompt:
|
|
5965
|
-
type: "text",
|
|
5966
|
-
text: systemPrompt
|
|
5967
|
-
}, {
|
|
5968
|
-
type: "text",
|
|
5969
|
-
text: effectiveBasePrompt
|
|
5970
|
-
}] }) : langchain.SystemMessage.isInstance(systemPrompt) ? new langchain.SystemMessage({ contentBlocks: [...systemPrompt.contentBlocks, {
|
|
5971
|
-
type: "text",
|
|
5972
|
-
text: effectiveBasePrompt
|
|
5973
|
-
}] }) : new langchain.SystemMessage({ contentBlocks: [{
|
|
5974
|
-
type: "text",
|
|
5975
|
-
text: effectiveBasePrompt
|
|
5976
|
-
}] }),
|
|
6152
|
+
systemPrompt: assemblePromptParts(promptParts),
|
|
5977
6153
|
stateSchema,
|
|
5978
6154
|
tools: effectiveTools,
|
|
5979
6155
|
middleware,
|
|
@@ -6325,6 +6501,19 @@ var StoreBackend = class {
|
|
|
6325
6501
|
}
|
|
6326
6502
|
}
|
|
6327
6503
|
/**
|
|
6504
|
+
* Delete a file from the store.
|
|
6505
|
+
*
|
|
6506
|
+
* The file path is used as an exact store key. Wildcards are treated
|
|
6507
|
+
* literally and do not expand to multiple entries.
|
|
6508
|
+
*/
|
|
6509
|
+
async delete(filePath) {
|
|
6510
|
+
const store = this.getStore();
|
|
6511
|
+
const namespace = this.getNamespace();
|
|
6512
|
+
if (!await store.get(namespace, filePath)) return { error: `Error: File '${filePath}' not found` };
|
|
6513
|
+
await store.delete(namespace, filePath);
|
|
6514
|
+
return { path: filePath };
|
|
6515
|
+
}
|
|
6516
|
+
/**
|
|
6328
6517
|
* Search file contents for a literal text pattern.
|
|
6329
6518
|
* Binary files are skipped.
|
|
6330
6519
|
*/
|
|
@@ -6537,10 +6726,10 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6537
6726
|
if (this.cache === null) throw new Error("Context Hub cache failed to initialize");
|
|
6538
6727
|
return this.cache;
|
|
6539
6728
|
}
|
|
6540
|
-
async commit(
|
|
6541
|
-
if (Object.keys(
|
|
6729
|
+
async commit(changes) {
|
|
6730
|
+
if (Object.keys(changes).length === 0) return;
|
|
6542
6731
|
const payload = {};
|
|
6543
|
-
for (const [path, content] of Object.entries(
|
|
6732
|
+
for (const [path, content] of Object.entries(changes)) payload[path] = content === null ? null : {
|
|
6544
6733
|
type: "file",
|
|
6545
6734
|
content
|
|
6546
6735
|
};
|
|
@@ -6550,7 +6739,14 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6550
6739
|
});
|
|
6551
6740
|
const match = URL_COMMIT_SUFFIX_RE.exec(url);
|
|
6552
6741
|
if (match) this.commitHash = match[1];
|
|
6553
|
-
if (this.cache !== null)
|
|
6742
|
+
if (this.cache !== null) {
|
|
6743
|
+
const deletions = new Set(Object.entries(changes).filter(([, content]) => content === null).map(([path]) => path));
|
|
6744
|
+
const updates = Object.fromEntries(Object.entries(changes).filter((entry) => entry[1] !== null));
|
|
6745
|
+
this.cache = {
|
|
6746
|
+
...Object.fromEntries(Object.entries(this.cache).filter(([path]) => !deletions.has(path))),
|
|
6747
|
+
...updates
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6554
6750
|
}
|
|
6555
6751
|
/**
|
|
6556
6752
|
* Return linked-entry paths mapped to their repo handles.
|
|
@@ -6709,6 +6905,20 @@ var ContextHubBackend = class ContextHubBackend {
|
|
|
6709
6905
|
throw error;
|
|
6710
6906
|
}
|
|
6711
6907
|
}
|
|
6908
|
+
async delete(filePath) {
|
|
6909
|
+
const hubPath = ContextHubBackend.stripPrefix(filePath);
|
|
6910
|
+
try {
|
|
6911
|
+
if (!(hubPath in await this.ensureCache())) return { error: `Error: File '${filePath}' not found` };
|
|
6912
|
+
await this.commit({ [hubPath]: null });
|
|
6913
|
+
return { path: filePath };
|
|
6914
|
+
} catch (error) {
|
|
6915
|
+
if (isLangSmithError(error)) {
|
|
6916
|
+
this.cache = null;
|
|
6917
|
+
return { error: ContextHubBackend.toHubUnavailableError(error) };
|
|
6918
|
+
}
|
|
6919
|
+
throw error;
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6712
6922
|
async uploadFiles(files) {
|
|
6713
6923
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
6714
6924
|
const decoded = [];
|
|
@@ -7201,6 +7411,16 @@ var BaseSandbox = class {
|
|
|
7201
7411
|
occurrences: count
|
|
7202
7412
|
};
|
|
7203
7413
|
}
|
|
7414
|
+
/**
|
|
7415
|
+
* Delete a file from the sandbox via a server-side rm.
|
|
7416
|
+
*
|
|
7417
|
+
* Uses rm -f, so deleting a path that does not exist succeeds silently.
|
|
7418
|
+
*/
|
|
7419
|
+
async delete(filePath) {
|
|
7420
|
+
const result = await this.execute(`rm -f ${shellQuote(filePath)}`);
|
|
7421
|
+
if (result.exitCode === 0) return { path: filePath };
|
|
7422
|
+
return { error: `Error deleting file '${filePath}': ${result.output.trim() || "unknown error"}` };
|
|
7423
|
+
}
|
|
7204
7424
|
};
|
|
7205
7425
|
//#endregion
|
|
7206
7426
|
//#region src/backends/langsmith.ts
|
|
@@ -7691,4 +7911,4 @@ Object.defineProperty(exports, "serializeProfile", {
|
|
|
7691
7911
|
}
|
|
7692
7912
|
});
|
|
7693
7913
|
|
|
7694
|
-
//# sourceMappingURL=langsmith-
|
|
7914
|
+
//# sourceMappingURL=langsmith-DhbsxI45.cjs.map
|