deepagents 1.10.8 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -494,7 +494,7 @@ function migrateToFileDataV2(data, filePath) {
494
494
  * @returns BackendProtocolV2-compatible backend
495
495
  */
496
496
  function adaptBackendProtocol(backend) {
497
- return {
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
- const TOOLS_EXCLUDED_FROM_EVICTION = [
1328
- "ls",
1329
- "glob",
1330
- "grep",
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.
@@ -1532,24 +1559,33 @@ function filterByPermissions(entries, rules, operation, getPath) {
1532
1559
  }
1533
1560
  });
1534
1561
  }
1535
- const FILESYSTEM_SYSTEM_PROMPT = langchain.context`
1536
- ## Following Conventions
1562
+ const FILESYSTEM_TOOL_DESCRIPTION_LINES = {
1563
+ ls: "ls: list files in a directory (requires absolute path)",
1564
+ read_file: "read_file: read a file from the filesystem",
1565
+ write_file: "write_file: write to a file in the filesystem",
1566
+ edit_file: "edit_file: edit a file in the filesystem",
1567
+ glob: "glob: find files matching a pattern (e.g., \"**/*.py\")",
1568
+ grep: "grep: search for text within files"
1569
+ };
1570
+ function hasFilesystemToolDescription(name) {
1571
+ return name in FILESYSTEM_TOOL_DESCRIPTION_LINES;
1572
+ }
1573
+ function buildFilesystemSystemPrompt(visibleTools) {
1574
+ const promptToolNames = FILESYSTEM_TOOL_NAMES.filter((name) => visibleTools.has(name));
1575
+ return langchain.context`
1576
+ ## Following Conventions
1537
1577
 
1538
- - Read files before editing — understand existing content before making changes
1539
- - Mimic existing style, naming conventions, and patterns
1578
+ - Read files before editing — understand existing content before making changes
1579
+ - Mimic existing style, naming conventions, and patterns
1540
1580
 
1541
- ## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
1581
+ ## Filesystem Tools ${promptToolNames.map((name) => `\`${name}\``).join(", ")}
1542
1582
 
1543
- You have access to a filesystem which you can interact with using these tools.
1544
- All file paths must start with a /.
1583
+ You have access to a filesystem which you can interact with using these tools.
1584
+ All file paths must start with a /.
1545
1585
 
1546
- - ls: list files in a directory (requires absolute path)
1547
- - read_file: read a file from the filesystem
1548
- - write_file: write to a file in the filesystem
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
- `;
1586
+ ${promptToolNames.filter(hasFilesystemToolDescription).map((name) => `- ${FILESYSTEM_TOOL_DESCRIPTION_LINES[name]}`).join("\n")}
1587
+ `;
1588
+ }
1553
1589
  const LS_TOOL_DESCRIPTION = langchain.context`
1554
1590
  Lists all files in a directory.
1555
1591
 
@@ -1923,6 +1959,12 @@ function createExecuteTool(backend, options) {
1923
1959
  * Returns true only when backend exposes route prefixes (CompositeBackend) and
1924
1960
  * every permission path is scoped under one of them.
1925
1961
  */
1962
+ function normalizeFilesystemTools(tools) {
1963
+ if (tools == null || tools === "all") return null;
1964
+ const enabledTools = new Set(tools);
1965
+ if (!enabledTools.has("read_file")) throw new Error("read_file must be included in tools; it is required by FilesystemMiddleware");
1966
+ return enabledTools;
1967
+ }
1926
1968
  function allPathsScopedToRoutes(permissions, backend) {
1927
1969
  if (!CompositeBackend.isInstance(backend)) return false;
1928
1970
  const prefixes = backend.routePrefixes;
@@ -1930,13 +1972,43 @@ function allPathsScopedToRoutes(permissions, backend) {
1930
1972
  return permissions.every((rule) => rule.paths.every((path) => prefixes.some((prefix) => path.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`))));
1931
1973
  }
1932
1974
  /**
1933
- * Create filesystem middleware with all tools and features.
1975
+ * Create middleware that provides built-in filesystem tools and filesystem-aware
1976
+ * prompt guidance.
1977
+ *
1978
+ * By default, the middleware registers every built-in filesystem tool listed in
1979
+ * {@link FILESYSTEM_TOOL_NAMES}. Use {@link FilesystemMiddlewareOptions.tools}
1980
+ * to narrow that set for read-only, search-only, or otherwise restricted
1981
+ * agents. The allowlist only controls built-in filesystem tools; custom tools
1982
+ * from the agent or other middleware are left untouched.
1983
+ *
1984
+ * The middleware also filters tools whose backend capabilities are unavailable
1985
+ * at request time. In particular, `execute` is only visible when the resolved
1986
+ * backend supports command execution. The filesystem prompt is generated from
1987
+ * the final visible filesystem tools so the model is not instructed to call
1988
+ * tools it cannot see.
1989
+ *
1990
+ * @param options Filesystem middleware configuration.
1991
+ * @returns Agent middleware that contributes filesystem state, tools, prompt
1992
+ * guidance, permission checks, and large-result eviction.
1993
+ *
1994
+ * @example Read-only filesystem middleware
1995
+ * ```ts
1996
+ * const middleware = createFilesystemMiddleware({
1997
+ * tools: ["read_file", "ls", "glob", "grep"],
1998
+ * });
1999
+ * ```
1934
2000
  */
1935
2001
  function createFilesystemMiddleware(options = {}) {
1936
- const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [] } = options;
2002
+ const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null } = options;
2003
+ const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);
2004
+ const executeToolEnabled = enabledFilesystemTools == null || enabledFilesystemTools.has("execute");
1937
2005
  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 || FILESYSTEM_SYSTEM_PROMPT;
2006
+ 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.");
2007
+ const baseSystemPrompt = customSystemPrompt ?? null;
2008
+ /**
2009
+ * All tools including execute
2010
+ * (execute will be filtered at runtime if backend doesn't support it)
2011
+ */
1940
2012
  const allToolsByName = {
1941
2013
  ls: createLsTool(backend, {
1942
2014
  customDescription: customToolDescriptions?.ls,
@@ -1968,7 +2040,7 @@ function createFilesystemMiddleware(options = {}) {
1968
2040
  permissions
1969
2041
  })
1970
2042
  };
1971
- const allTools = Object.values(allToolsByName);
2043
+ const allTools = FILESYSTEM_TOOL_NAMES.filter((name) => enabledFilesystemTools == null || enabledFilesystemTools.has(name)).map((name) => allToolsByName[name]);
1972
2044
  async function processToolMessage(msg, runtime, state, fallbackToolCallId) {
1973
2045
  if (!toolTokenLimitBeforeEvict) return {
1974
2046
  message: msg,
@@ -2042,8 +2114,14 @@ function createFilesystemMiddleware(options = {}) {
2042
2114
  }));
2043
2115
  let tools = request.tools;
2044
2116
  if (!supportsExecution) tools = tools.filter((t) => t.name !== "execute");
2045
- let filesystemPrompt = baseSystemPrompt;
2046
- if (supportsExecution) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
2117
+ const visibleFilesystemTools = /* @__PURE__ */ new Set();
2118
+ for (const currentTool of tools) {
2119
+ const toolName = typeof currentTool.name === "string" ? currentTool.name : void 0;
2120
+ if (isFilesystemToolName(toolName)) visibleFilesystemTools.add(toolName);
2121
+ }
2122
+ const executionActive = supportsExecution && visibleFilesystemTools.has("execute");
2123
+ let filesystemPrompt = baseSystemPrompt ?? buildFilesystemSystemPrompt(visibleFilesystemTools);
2124
+ if (executionActive) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
2047
2125
  const newSystemMessage = request.systemMessage.concat(filesystemPrompt);
2048
2126
  let messages = request.messages;
2049
2127
  if (humanMessageTokenLimitBeforeEvict && messages) {
@@ -3487,6 +3565,41 @@ function createSkillsMiddleware(options) {
3487
3565
  *
3488
3566
  * This module provides shared helpers used across middleware implementations.
3489
3567
  */
3568
+ /**
3569
+ * Merge custom middleware into an assembled stack by `.name`.
3570
+ *
3571
+ * Matching custom middleware replaces the existing entry in place. New
3572
+ * middleware is appended after the base stack in caller-provided order.
3573
+ */
3574
+ function mergeMiddleware$1(base, custom) {
3575
+ const merged = new Map(base.map((middleware) => [middleware.name, middleware]));
3576
+ for (const middleware of custom) merged.set(middleware.name, middleware);
3577
+ return [...merged.values()];
3578
+ }
3579
+ function middlewareNames(middleware) {
3580
+ return new Set(middleware.map((entry) => entry.name));
3581
+ }
3582
+ function matchingMiddleware(middleware, names) {
3583
+ return middleware.filter((entry) => names.has(entry.name));
3584
+ }
3585
+ /**
3586
+ * Merge custom middleware into default and tail middleware segments.
3587
+ *
3588
+ * Same-name custom entries replace matching defaults in either segment. Novel
3589
+ * custom entries are inserted between the default and tail segments unless
3590
+ * `appendNew` is false.
3591
+ */
3592
+ function mergeMiddlewareStack(defaultMiddleware, customMiddleware, tailMiddleware = [], options = {}) {
3593
+ const defaultMiddlewareNames = middlewareNames(defaultMiddleware);
3594
+ const tailMiddlewareNames = middlewareNames(tailMiddleware);
3595
+ const knownMiddlewareNames = /* @__PURE__ */ new Set([...defaultMiddlewareNames, ...tailMiddlewareNames]);
3596
+ const novelMiddleware = options.appendNew === false ? [] : customMiddleware.filter((entry) => !knownMiddlewareNames.has(entry.name));
3597
+ return [
3598
+ ...mergeMiddleware$1(defaultMiddleware, matchingMiddleware(customMiddleware, defaultMiddlewareNames)),
3599
+ ...novelMiddleware,
3600
+ ...mergeMiddleware$1(tailMiddleware, matchingMiddleware(customMiddleware, tailMiddlewareNames))
3601
+ ];
3602
+ }
3490
3603
  //#endregion
3491
3604
  //#region src/middleware/completion_callback.ts
3492
3605
  /**
@@ -5079,6 +5192,28 @@ function createCacheBreakpointMiddleware() {
5079
5192
  });
5080
5193
  }
5081
5194
  //#endregion
5195
+ //#region src/middleware/tool_exclusion.ts
5196
+ function hasToolName(tool) {
5197
+ return tool !== null && typeof tool === "object" && "name" in tool && typeof tool.name === "string";
5198
+ }
5199
+ /**
5200
+ * Create middleware that removes excluded tools after all tool-injecting
5201
+ * middleware has had a chance to add tools to the request.
5202
+ *
5203
+ * @internal
5204
+ */
5205
+ function createToolExclusionMiddleware(excludedTools) {
5206
+ return (0, langchain.createMiddleware)({
5207
+ name: "_ToolExclusionMiddleware",
5208
+ wrapModelCall(request, handler) {
5209
+ return handler({
5210
+ ...request,
5211
+ tools: request.tools?.filter((tool) => !hasToolName(tool) || !excludedTools.has(tool.name))
5212
+ });
5213
+ }
5214
+ });
5215
+ }
5216
+ //#endregion
5082
5217
  //#region src/profiles/keys.ts
5083
5218
  /**
5084
5219
  * Normalize and validate a profile registry key.
@@ -5782,6 +5917,31 @@ const BASE_AGENT_PROMPT = langchain.context`
5782
5917
 
5783
5918
  For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
5784
5919
  `;
5920
+ const PROMPT_SEPARATOR = "\n\n";
5921
+ /** Normalize legacy system prompt values to the structured representation. */
5922
+ function normalizeSystemPrompt(systemPrompt) {
5923
+ if (systemPrompt === void 0) return {};
5924
+ if (typeof systemPrompt === "string" || langchain.SystemMessage.isInstance(systemPrompt)) return { prefix: systemPrompt };
5925
+ return systemPrompt;
5926
+ }
5927
+ /** Assemble prompt parts while preserving structured message content blocks. */
5928
+ function assemblePromptParts(parts) {
5929
+ if (parts.length === 0) return "";
5930
+ if (parts.every((part) => typeof part === "string")) return parts.join(PROMPT_SEPARATOR);
5931
+ const contentBlocks = [];
5932
+ for (const [index, part] of parts.entries()) {
5933
+ if (index > 0) contentBlocks.push({
5934
+ type: "text",
5935
+ text: PROMPT_SEPARATOR
5936
+ });
5937
+ if (langchain.SystemMessage.isInstance(part)) contentBlocks.push(...part.contentBlocks);
5938
+ else contentBlocks.push({
5939
+ type: "text",
5940
+ text: part
5941
+ });
5942
+ }
5943
+ return new langchain.SystemMessage({ contentBlocks });
5944
+ }
5785
5945
  const BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set([
5786
5946
  ...FILESYSTEM_TOOL_NAMES,
5787
5947
  ...ASYNC_TASK_TOOL_NAMES,
@@ -5827,6 +5987,8 @@ function createDeepAgent(params = {}) {
5827
5987
  providerHint: getModelProvider(model),
5828
5988
  identifierHint: getModelIdentifier(model)
5829
5989
  });
5990
+ const filesystemTools = FILESYSTEM_TOOL_NAMES.filter((toolName) => !harnessProfile.excludedTools.has(toolName));
5991
+ const profileFilesystemTools = filesystemTools.length === FILESYSTEM_TOOL_NAMES.length || !filesystemTools.includes("read_file") ? void 0 : filesystemTools;
5830
5992
  const toolOverrides = harnessProfile.toolDescriptionOverrides;
5831
5993
  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
5994
  const anthropicModel = isAnthropicModel(model);
@@ -5848,23 +6010,26 @@ function createDeepAgent(params = {}) {
5848
6010
  * Only the general-purpose subagent inherits the main agent's skills.
5849
6011
  * If a custom subagent needs skills, it must specify its own `skills` array.
5850
6012
  */
5851
- const normalizeSubagentSpec = (input) => {
6013
+ const createSubagentDefaultMiddleware = (input) => {
5852
6014
  const effectivePermissions = input.permissions ?? permissions;
5853
- const subagentMiddleware = [
6015
+ return [
5854
6016
  (0, langchain.todoListMiddleware)(),
5855
6017
  createFilesystemMiddleware({
5856
6018
  backend,
5857
- permissions: effectivePermissions
6019
+ permissions: effectivePermissions,
6020
+ tools: profileFilesystemTools
5858
6021
  }),
5859
6022
  createSummarizationMiddleware({ backend }),
5860
6023
  createPatchToolCallsMiddleware(),
5861
6024
  ...input.skills != null && input.skills.length > 0 ? [createSkillsMiddleware({
5862
6025
  backend,
5863
6026
  sources: input.skills
5864
- })] : [],
5865
- ...input.middleware ?? [],
5866
- ...cacheMiddleware
6027
+ })] : []
5867
6028
  ];
6029
+ };
6030
+ const normalizeSubagentSpec = (input) => {
6031
+ let subagentMiddleware = mergeMiddlewareStack(createSubagentDefaultMiddleware(input), input.middleware ?? [], cacheMiddleware);
6032
+ if (harnessProfile.excludedMiddleware.size > 0) subagentMiddleware = subagentMiddleware.filter((middleware) => !harnessProfile.excludedMiddleware.has(middleware.name));
5868
6033
  return {
5869
6034
  ...input,
5870
6035
  tools: input.tools ?? [],
@@ -5885,6 +6050,7 @@ function createDeepAgent(params = {}) {
5885
6050
  skills,
5886
6051
  tools: effectiveTools
5887
6052
  });
6053
+ generalPurposeSpec.middleware = mergeMiddlewareStack(generalPurposeSpec.middleware ?? [], customMiddleware, [], { appendNew: false });
5888
6054
  inlineSubagents.unshift(generalPurposeSpec);
5889
6055
  }
5890
6056
  const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
@@ -5895,7 +6061,8 @@ function createDeepAgent(params = {}) {
5895
6061
  (0, langchain.todoListMiddleware)(),
5896
6062
  createFilesystemMiddleware({
5897
6063
  backend,
5898
- permissions
6064
+ permissions,
6065
+ tools: profileFilesystemTools
5899
6066
  }),
5900
6067
  createSubAgentMiddleware({
5901
6068
  defaultModel: model,
@@ -5907,15 +6074,16 @@ function createDeepAgent(params = {}) {
5907
6074
  createSummarizationMiddleware({ backend }),
5908
6075
  createPatchToolCallsMiddleware()
5909
6076
  ];
5910
- const middleware = [
6077
+ let middleware = mergeMiddlewareStack([
5911
6078
  todoMiddleware,
5912
6079
  ...skillsMiddleware,
5913
6080
  fsMiddleware,
5914
6081
  subagentMiddleware,
5915
6082
  summarizationMiddleware,
5916
6083
  patchToolCallsMiddleware,
5917
- ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : [],
5918
- ...customMiddleware,
6084
+ ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
6085
+ ], customMiddleware, [
6086
+ ...resolveMiddleware(harnessProfile.extraMiddleware),
5919
6087
  ...cacheMiddleware,
5920
6088
  ...memory && memory.length > 0 ? [createMemoryMiddleware({
5921
6089
  backend,
@@ -5923,32 +6091,19 @@ function createDeepAgent(params = {}) {
5923
6091
  addCacheControl: anthropicModel
5924
6092
  })] : [],
5925
6093
  ...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
- }
6094
+ ]);
5933
6095
  if (harnessProfile.excludedMiddleware.size > 0) {
5934
6096
  const excluded = harnessProfile.excludedMiddleware;
5935
- const filtered = middleware.filter((m) => !excluded.has(m.name));
5936
- middleware.length = 0;
5937
- middleware.push(...filtered);
5938
- }
5939
- if (harnessProfile.excludedTools.size > 0) {
5940
- const excludedTools = harnessProfile.excludedTools;
5941
- middleware.push((0, langchain.createMiddleware)({
5942
- name: "_ToolExclusionMiddleware",
5943
- wrapModelCall: async (request, handler) => {
5944
- return handler({
5945
- ...request,
5946
- tools: request.tools?.filter((t) => !excludedTools.has(t.name))
5947
- });
5948
- }
5949
- }));
5950
- }
5951
- const effectiveBasePrompt = applyProfilePrompt(harnessProfile, BASE_AGENT_PROMPT);
6097
+ middleware = middleware.filter((entry) => !excluded.has(entry.name));
6098
+ }
6099
+ if (harnessProfile.excludedTools.size > 0) middleware.push(createToolExclusionMiddleware(harnessProfile.excludedTools));
6100
+ const promptConfig = normalizeSystemPrompt(systemPrompt);
6101
+ const promptParts = [];
6102
+ if (promptConfig.prefix !== void 0 && promptConfig.prefix !== null) promptParts.push(promptConfig.prefix);
6103
+ const activeBasePrompt = promptConfig.base !== void 0 ? promptConfig.base : harnessProfile.baseSystemPrompt ?? BASE_AGENT_PROMPT;
6104
+ if (activeBasePrompt !== null) promptParts.push(activeBasePrompt);
6105
+ if (promptConfig.suffix) promptParts.push(promptConfig.suffix);
6106
+ if (harnessProfile.systemPromptSuffix) promptParts.push(harnessProfile.systemPromptSuffix);
5952
6107
  /**
5953
6108
  * Return as DeepAgent with proper DeepAgentTypeConfig
5954
6109
  * - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)
@@ -5961,19 +6116,7 @@ function createDeepAgent(params = {}) {
5961
6116
  */
5962
6117
  return (0, langchain.createAgent)({
5963
6118
  model,
5964
- systemPrompt: typeof systemPrompt === "string" ? new langchain.SystemMessage({ contentBlocks: [{
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
- }] }),
6119
+ systemPrompt: assemblePromptParts(promptParts),
5977
6120
  stateSchema,
5978
6121
  tools: effectiveTools,
5979
6122
  middleware,
@@ -6325,6 +6468,19 @@ var StoreBackend = class {
6325
6468
  }
6326
6469
  }
6327
6470
  /**
6471
+ * Delete a file from the store.
6472
+ *
6473
+ * The file path is used as an exact store key. Wildcards are treated
6474
+ * literally and do not expand to multiple entries.
6475
+ */
6476
+ async delete(filePath) {
6477
+ const store = this.getStore();
6478
+ const namespace = this.getNamespace();
6479
+ if (!await store.get(namespace, filePath)) return { error: `Error: File '${filePath}' not found` };
6480
+ await store.delete(namespace, filePath);
6481
+ return { path: filePath };
6482
+ }
6483
+ /**
6328
6484
  * Search file contents for a literal text pattern.
6329
6485
  * Binary files are skipped.
6330
6486
  */
@@ -6537,10 +6693,10 @@ var ContextHubBackend = class ContextHubBackend {
6537
6693
  if (this.cache === null) throw new Error("Context Hub cache failed to initialize");
6538
6694
  return this.cache;
6539
6695
  }
6540
- async commit(files) {
6541
- if (Object.keys(files).length === 0) return;
6696
+ async commit(changes) {
6697
+ if (Object.keys(changes).length === 0) return;
6542
6698
  const payload = {};
6543
- for (const [path, content] of Object.entries(files)) payload[path] = {
6699
+ for (const [path, content] of Object.entries(changes)) payload[path] = content === null ? null : {
6544
6700
  type: "file",
6545
6701
  content
6546
6702
  };
@@ -6550,7 +6706,14 @@ var ContextHubBackend = class ContextHubBackend {
6550
6706
  });
6551
6707
  const match = URL_COMMIT_SUFFIX_RE.exec(url);
6552
6708
  if (match) this.commitHash = match[1];
6553
- if (this.cache !== null) for (const [path, content] of Object.entries(files)) this.cache[path] = content;
6709
+ if (this.cache !== null) {
6710
+ const deletions = new Set(Object.entries(changes).filter(([, content]) => content === null).map(([path]) => path));
6711
+ const updates = Object.fromEntries(Object.entries(changes).filter((entry) => entry[1] !== null));
6712
+ this.cache = {
6713
+ ...Object.fromEntries(Object.entries(this.cache).filter(([path]) => !deletions.has(path))),
6714
+ ...updates
6715
+ };
6716
+ }
6554
6717
  }
6555
6718
  /**
6556
6719
  * Return linked-entry paths mapped to their repo handles.
@@ -6709,6 +6872,20 @@ var ContextHubBackend = class ContextHubBackend {
6709
6872
  throw error;
6710
6873
  }
6711
6874
  }
6875
+ async delete(filePath) {
6876
+ const hubPath = ContextHubBackend.stripPrefix(filePath);
6877
+ try {
6878
+ if (!(hubPath in await this.ensureCache())) return { error: `Error: File '${filePath}' not found` };
6879
+ await this.commit({ [hubPath]: null });
6880
+ return { path: filePath };
6881
+ } catch (error) {
6882
+ if (isLangSmithError(error)) {
6883
+ this.cache = null;
6884
+ return { error: ContextHubBackend.toHubUnavailableError(error) };
6885
+ }
6886
+ throw error;
6887
+ }
6888
+ }
6712
6889
  async uploadFiles(files) {
6713
6890
  const decoder = new TextDecoder("utf-8", { fatal: true });
6714
6891
  const decoded = [];
@@ -7201,6 +7378,16 @@ var BaseSandbox = class {
7201
7378
  occurrences: count
7202
7379
  };
7203
7380
  }
7381
+ /**
7382
+ * Delete a file from the sandbox via a server-side rm.
7383
+ *
7384
+ * Uses rm -f, so deleting a path that does not exist succeeds silently.
7385
+ */
7386
+ async delete(filePath) {
7387
+ const result = await this.execute(`rm -f ${shellQuote(filePath)}`);
7388
+ if (result.exitCode === 0) return { path: filePath };
7389
+ return { error: `Error deleting file '${filePath}': ${result.output.trim() || "unknown error"}` };
7390
+ }
7204
7391
  };
7205
7392
  //#endregion
7206
7393
  //#region src/backends/langsmith.ts
@@ -7691,4 +7878,4 @@ Object.defineProperty(exports, "serializeProfile", {
7691
7878
  }
7692
7879
  });
7693
7880
 
7694
- //# sourceMappingURL=langsmith-CiAeUke2.cjs.map
7881
+ //# sourceMappingURL=langsmith-DDhVumyX.cjs.map