deepagents 1.10.7 → 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.
@@ -470,7 +470,7 @@ function migrateToFileDataV2(data, filePath) {
470
470
  * @returns BackendProtocolV2-compatible backend
471
471
  */
472
472
  function adaptBackendProtocol(backend) {
473
- return {
473
+ const adapted = {
474
474
  async ls(path) {
475
475
  const result = await ("ls" in backend ? backend.ls(path) : backend.lsInfo(path));
476
476
  if (Array.isArray(result)) return { files: result };
@@ -488,6 +488,7 @@ function adaptBackendProtocol(backend) {
488
488
  },
489
489
  write: (filePath, content) => backend.write(filePath, content),
490
490
  edit: (filePath, oldString, newString, replaceAll) => backend.edit(filePath, oldString, newString, replaceAll),
491
+ delete: backend.delete?.bind(backend),
491
492
  uploadFiles: backend.uploadFiles ? (files) => backend.uploadFiles(files) : void 0,
492
493
  downloadFiles: backend.downloadFiles ? (paths) => backend.downloadFiles(paths) : void 0,
493
494
  async read(filePath, offset, limit) {
@@ -502,6 +503,13 @@ function adaptBackendProtocol(backend) {
502
503
  return result;
503
504
  }
504
505
  };
506
+ const routePrefixes = backend.routePrefixes;
507
+ if (Array.isArray(routePrefixes)) Object.defineProperty(adapted, "routePrefixes", {
508
+ value: routePrefixes,
509
+ enumerable: true,
510
+ configurable: true
511
+ });
512
+ return adapted;
505
513
  }
506
514
  /**
507
515
  * Adapt a sandbox backend from v1 to v2 interface.
@@ -669,7 +677,8 @@ var StateBackend = class {
669
677
  * In legacy mode, this is a no-op — the caller uses `filesUpdate`
670
678
  * from the return value instead.
671
679
  *
672
- * @param update - Map of file paths to their updated {@link FileData}
680
+ * @param update - Map of file paths to their updated {@link FileData},
681
+ * or null deletion markers.
673
682
  */
674
683
  sendFilesUpdate(update) {
675
684
  if (this.isLegacy) return;
@@ -793,6 +802,15 @@ var StateBackend = class {
793
802
  };
794
803
  }
795
804
  /**
805
+ * Delete a file from state by sending a null deletion marker through Pregel.
806
+ */
807
+ delete(filePath) {
808
+ if (!(filePath in this.files)) return { error: `Error: File '${filePath}' not found` };
809
+ if (this.isLegacy) return { error: "StateBackend.delete requires a zero-argument StateBackend in a LangGraph execution context." };
810
+ this.sendFilesUpdate({ [filePath]: null });
811
+ return { path: filePath };
812
+ }
813
+ /**
796
814
  * Search file contents for a literal text pattern.
797
815
  * Binary files are skipped.
798
816
  */
@@ -1159,6 +1177,19 @@ var CompositeBackend = class {
1159
1177
  return await backend.edit(strippedKey, oldString, newString, replaceAll);
1160
1178
  }
1161
1179
  /**
1180
+ * Delete a file, routing to the appropriate backend.
1181
+ */
1182
+ async delete(filePath) {
1183
+ const [backend, strippedKey] = this.getBackendAndKey(filePath);
1184
+ if (!backend.delete) return { error: "Backend does not support delete" };
1185
+ const result = await backend.delete(strippedKey);
1186
+ if (result.path !== void 0) return {
1187
+ ...result,
1188
+ path: filePath
1189
+ };
1190
+ return result;
1191
+ }
1192
+ /**
1162
1193
  * Execute a command via the default backend.
1163
1194
  * Execution is not path-specific, so it always delegates to the default backend.
1164
1195
  *
@@ -1300,14 +1331,10 @@ const FILESYSTEM_TOOL_NAMES = [
1300
1331
  "grep",
1301
1332
  "execute"
1302
1333
  ];
1303
- const TOOLS_EXCLUDED_FROM_EVICTION = [
1304
- "ls",
1305
- "glob",
1306
- "grep",
1307
- "read_file",
1308
- "edit_file",
1309
- "write_file"
1310
- ];
1334
+ function isFilesystemToolName(name) {
1335
+ return typeof name === "string" && FILESYSTEM_TOOL_NAMES.includes(name);
1336
+ }
1337
+ const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter((name) => name !== "execute");
1311
1338
  /**
1312
1339
  * Maximum size for binary (non-text) files read via read_file, in bytes.
1313
1340
  * Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.
@@ -1508,24 +1535,33 @@ function filterByPermissions(entries, rules, operation, getPath) {
1508
1535
  }
1509
1536
  });
1510
1537
  }
1511
- const FILESYSTEM_SYSTEM_PROMPT = context`
1512
- ## Following Conventions
1538
+ const FILESYSTEM_TOOL_DESCRIPTION_LINES = {
1539
+ ls: "ls: list files in a directory (requires absolute path)",
1540
+ read_file: "read_file: read a file from the filesystem",
1541
+ write_file: "write_file: write to a file in the filesystem",
1542
+ edit_file: "edit_file: edit a file in the filesystem",
1543
+ glob: "glob: find files matching a pattern (e.g., \"**/*.py\")",
1544
+ grep: "grep: search for text within files"
1545
+ };
1546
+ function hasFilesystemToolDescription(name) {
1547
+ return name in FILESYSTEM_TOOL_DESCRIPTION_LINES;
1548
+ }
1549
+ function buildFilesystemSystemPrompt(visibleTools) {
1550
+ const promptToolNames = FILESYSTEM_TOOL_NAMES.filter((name) => visibleTools.has(name));
1551
+ return context`
1552
+ ## Following Conventions
1513
1553
 
1514
- - Read files before editing — understand existing content before making changes
1515
- - Mimic existing style, naming conventions, and patterns
1554
+ - Read files before editing — understand existing content before making changes
1555
+ - Mimic existing style, naming conventions, and patterns
1516
1556
 
1517
- ## Filesystem Tools \`ls\`, \`read_file\`, \`write_file\`, \`edit_file\`, \`glob\`, \`grep\`
1557
+ ## Filesystem Tools ${promptToolNames.map((name) => `\`${name}\``).join(", ")}
1518
1558
 
1519
- You have access to a filesystem which you can interact with using these tools.
1520
- All file paths must start with a /.
1559
+ You have access to a filesystem which you can interact with using these tools.
1560
+ All file paths must start with a /.
1521
1561
 
1522
- - ls: list files in a directory (requires absolute path)
1523
- - read_file: read a file from the filesystem
1524
- - write_file: write to a file in the filesystem
1525
- - edit_file: edit a file in the filesystem
1526
- - glob: find files matching a pattern (e.g., "**/*.py")
1527
- - grep: search for text within files
1528
- `;
1562
+ ${promptToolNames.filter(hasFilesystemToolDescription).map((name) => `- ${FILESYSTEM_TOOL_DESCRIPTION_LINES[name]}`).join("\n")}
1563
+ `;
1564
+ }
1529
1565
  const LS_TOOL_DESCRIPTION = context`
1530
1566
  Lists all files in a directory.
1531
1567
 
@@ -1899,6 +1935,12 @@ function createExecuteTool(backend, options) {
1899
1935
  * Returns true only when backend exposes route prefixes (CompositeBackend) and
1900
1936
  * every permission path is scoped under one of them.
1901
1937
  */
1938
+ function normalizeFilesystemTools(tools) {
1939
+ if (tools == null || tools === "all") return null;
1940
+ const enabledTools = new Set(tools);
1941
+ if (!enabledTools.has("read_file")) throw new Error("read_file must be included in tools; it is required by FilesystemMiddleware");
1942
+ return enabledTools;
1943
+ }
1902
1944
  function allPathsScopedToRoutes(permissions, backend) {
1903
1945
  if (!CompositeBackend.isInstance(backend)) return false;
1904
1946
  const prefixes = backend.routePrefixes;
@@ -1906,13 +1948,43 @@ function allPathsScopedToRoutes(permissions, backend) {
1906
1948
  return permissions.every((rule) => rule.paths.every((path) => prefixes.some((prefix) => path.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`))));
1907
1949
  }
1908
1950
  /**
1909
- * Create filesystem middleware with all tools and features.
1951
+ * Create middleware that provides built-in filesystem tools and filesystem-aware
1952
+ * prompt guidance.
1953
+ *
1954
+ * By default, the middleware registers every built-in filesystem tool listed in
1955
+ * {@link FILESYSTEM_TOOL_NAMES}. Use {@link FilesystemMiddlewareOptions.tools}
1956
+ * to narrow that set for read-only, search-only, or otherwise restricted
1957
+ * agents. The allowlist only controls built-in filesystem tools; custom tools
1958
+ * from the agent or other middleware are left untouched.
1959
+ *
1960
+ * The middleware also filters tools whose backend capabilities are unavailable
1961
+ * at request time. In particular, `execute` is only visible when the resolved
1962
+ * backend supports command execution. The filesystem prompt is generated from
1963
+ * the final visible filesystem tools so the model is not instructed to call
1964
+ * tools it cannot see.
1965
+ *
1966
+ * @param options Filesystem middleware configuration.
1967
+ * @returns Agent middleware that contributes filesystem state, tools, prompt
1968
+ * guidance, permission checks, and large-result eviction.
1969
+ *
1970
+ * @example Read-only filesystem middleware
1971
+ * ```ts
1972
+ * const middleware = createFilesystemMiddleware({
1973
+ * tools: ["read_file", "ls", "glob", "grep"],
1974
+ * });
1975
+ * ```
1910
1976
  */
1911
1977
  function createFilesystemMiddleware(options = {}) {
1912
- const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [] } = options;
1978
+ const { backend = (runtime) => new StateBackend(runtime), systemPrompt: customSystemPrompt = null, customToolDescriptions = null, toolTokenLimitBeforeEvict = 2e4, humanMessageTokenLimitBeforeEvict = 5e4, permissions = [], tools: filesystemTools = null } = options;
1979
+ const enabledFilesystemTools = normalizeFilesystemTools(filesystemTools);
1980
+ const executeToolEnabled = enabledFilesystemTools == null || enabledFilesystemTools.has("execute");
1913
1981
  if (permissions.length > 0) validatePermissionPaths(permissions);
1914
- 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.");
1915
- const baseSystemPrompt = customSystemPrompt || FILESYSTEM_SYSTEM_PROMPT;
1982
+ 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.");
1983
+ const baseSystemPrompt = customSystemPrompt ?? null;
1984
+ /**
1985
+ * All tools including execute
1986
+ * (execute will be filtered at runtime if backend doesn't support it)
1987
+ */
1916
1988
  const allToolsByName = {
1917
1989
  ls: createLsTool(backend, {
1918
1990
  customDescription: customToolDescriptions?.ls,
@@ -1944,7 +2016,7 @@ function createFilesystemMiddleware(options = {}) {
1944
2016
  permissions
1945
2017
  })
1946
2018
  };
1947
- const allTools = Object.values(allToolsByName);
2019
+ const allTools = FILESYSTEM_TOOL_NAMES.filter((name) => enabledFilesystemTools == null || enabledFilesystemTools.has(name)).map((name) => allToolsByName[name]);
1948
2020
  async function processToolMessage(msg, runtime, state, fallbackToolCallId) {
1949
2021
  if (!toolTokenLimitBeforeEvict) return {
1950
2022
  message: msg,
@@ -2018,8 +2090,14 @@ function createFilesystemMiddleware(options = {}) {
2018
2090
  }));
2019
2091
  let tools = request.tools;
2020
2092
  if (!supportsExecution) tools = tools.filter((t) => t.name !== "execute");
2021
- let filesystemPrompt = baseSystemPrompt;
2022
- if (supportsExecution) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
2093
+ const visibleFilesystemTools = /* @__PURE__ */ new Set();
2094
+ for (const currentTool of tools) {
2095
+ const toolName = typeof currentTool.name === "string" ? currentTool.name : void 0;
2096
+ if (isFilesystemToolName(toolName)) visibleFilesystemTools.add(toolName);
2097
+ }
2098
+ const executionActive = supportsExecution && visibleFilesystemTools.has("execute");
2099
+ let filesystemPrompt = baseSystemPrompt ?? buildFilesystemSystemPrompt(visibleFilesystemTools);
2100
+ if (executionActive) filesystemPrompt = `${filesystemPrompt}\n\n${EXECUTION_SYSTEM_PROMPT}`;
2023
2101
  const newSystemMessage = request.systemMessage.concat(filesystemPrompt);
2024
2102
  let messages = request.messages;
2025
2103
  if (humanMessageTokenLimitBeforeEvict && messages) {
@@ -3457,6 +3535,43 @@ function createSkillsMiddleware(options) {
3457
3535
  });
3458
3536
  }
3459
3537
  //#endregion
3538
+ //#region src/middleware/utils.ts
3539
+ /**
3540
+ * Merge custom middleware into an assembled stack by `.name`.
3541
+ *
3542
+ * Matching custom middleware replaces the existing entry in place. New
3543
+ * middleware is appended after the base stack in caller-provided order.
3544
+ */
3545
+ function mergeMiddleware$1(base, custom) {
3546
+ const merged = new Map(base.map((middleware) => [middleware.name, middleware]));
3547
+ for (const middleware of custom) merged.set(middleware.name, middleware);
3548
+ return [...merged.values()];
3549
+ }
3550
+ function middlewareNames(middleware) {
3551
+ return new Set(middleware.map((entry) => entry.name));
3552
+ }
3553
+ function matchingMiddleware(middleware, names) {
3554
+ return middleware.filter((entry) => names.has(entry.name));
3555
+ }
3556
+ /**
3557
+ * Merge custom middleware into default and tail middleware segments.
3558
+ *
3559
+ * Same-name custom entries replace matching defaults in either segment. Novel
3560
+ * custom entries are inserted between the default and tail segments unless
3561
+ * `appendNew` is false.
3562
+ */
3563
+ function mergeMiddlewareStack(defaultMiddleware, customMiddleware, tailMiddleware = [], options = {}) {
3564
+ const defaultMiddlewareNames = middlewareNames(defaultMiddleware);
3565
+ const tailMiddlewareNames = middlewareNames(tailMiddleware);
3566
+ const knownMiddlewareNames = /* @__PURE__ */ new Set([...defaultMiddlewareNames, ...tailMiddlewareNames]);
3567
+ const novelMiddleware = options.appendNew === false ? [] : customMiddleware.filter((entry) => !knownMiddlewareNames.has(entry.name));
3568
+ return [
3569
+ ...mergeMiddleware$1(defaultMiddleware, matchingMiddleware(customMiddleware, defaultMiddlewareNames)),
3570
+ ...novelMiddleware,
3571
+ ...mergeMiddleware$1(tailMiddleware, matchingMiddleware(customMiddleware, tailMiddlewareNames))
3572
+ ];
3573
+ }
3574
+ //#endregion
3460
3575
  //#region src/middleware/completion_callback.ts
3461
3576
  /**
3462
3577
  * Callback middleware for async subagents.
@@ -5048,6 +5163,28 @@ function createCacheBreakpointMiddleware() {
5048
5163
  });
5049
5164
  }
5050
5165
  //#endregion
5166
+ //#region src/middleware/tool_exclusion.ts
5167
+ function hasToolName(tool) {
5168
+ return tool !== null && typeof tool === "object" && "name" in tool && typeof tool.name === "string";
5169
+ }
5170
+ /**
5171
+ * Create middleware that removes excluded tools after all tool-injecting
5172
+ * middleware has had a chance to add tools to the request.
5173
+ *
5174
+ * @internal
5175
+ */
5176
+ function createToolExclusionMiddleware(excludedTools) {
5177
+ return createMiddleware({
5178
+ name: "_ToolExclusionMiddleware",
5179
+ wrapModelCall(request, handler) {
5180
+ return handler({
5181
+ ...request,
5182
+ tools: request.tools?.filter((tool) => !hasToolName(tool) || !excludedTools.has(tool.name))
5183
+ });
5184
+ }
5185
+ });
5186
+ }
5187
+ //#endregion
5051
5188
  //#region src/profiles/keys.ts
5052
5189
  /**
5053
5190
  * Normalize and validate a profile registry key.
@@ -5751,6 +5888,31 @@ const BASE_AGENT_PROMPT = context`
5751
5888
 
5752
5889
  For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
5753
5890
  `;
5891
+ const PROMPT_SEPARATOR = "\n\n";
5892
+ /** Normalize legacy system prompt values to the structured representation. */
5893
+ function normalizeSystemPrompt(systemPrompt) {
5894
+ if (systemPrompt === void 0) return {};
5895
+ if (typeof systemPrompt === "string" || SystemMessage.isInstance(systemPrompt)) return { prefix: systemPrompt };
5896
+ return systemPrompt;
5897
+ }
5898
+ /** Assemble prompt parts while preserving structured message content blocks. */
5899
+ function assemblePromptParts(parts) {
5900
+ if (parts.length === 0) return "";
5901
+ if (parts.every((part) => typeof part === "string")) return parts.join(PROMPT_SEPARATOR);
5902
+ const contentBlocks = [];
5903
+ for (const [index, part] of parts.entries()) {
5904
+ if (index > 0) contentBlocks.push({
5905
+ type: "text",
5906
+ text: PROMPT_SEPARATOR
5907
+ });
5908
+ if (SystemMessage.isInstance(part)) contentBlocks.push(...part.contentBlocks);
5909
+ else contentBlocks.push({
5910
+ type: "text",
5911
+ text: part
5912
+ });
5913
+ }
5914
+ return new SystemMessage({ contentBlocks });
5915
+ }
5754
5916
  const BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set([
5755
5917
  ...FILESYSTEM_TOOL_NAMES,
5756
5918
  ...ASYNC_TASK_TOOL_NAMES,
@@ -5796,6 +5958,8 @@ function createDeepAgent(params = {}) {
5796
5958
  providerHint: getModelProvider(model),
5797
5959
  identifierHint: getModelIdentifier(model)
5798
5960
  });
5961
+ const filesystemTools = FILESYSTEM_TOOL_NAMES.filter((toolName) => !harnessProfile.excludedTools.has(toolName));
5962
+ const profileFilesystemTools = filesystemTools.length === FILESYSTEM_TOOL_NAMES.length || !filesystemTools.includes("read_file") ? void 0 : filesystemTools;
5799
5963
  const toolOverrides = harnessProfile.toolDescriptionOverrides;
5800
5964
  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;
5801
5965
  const anthropicModel = isAnthropicModel(model);
@@ -5817,23 +5981,26 @@ function createDeepAgent(params = {}) {
5817
5981
  * Only the general-purpose subagent inherits the main agent's skills.
5818
5982
  * If a custom subagent needs skills, it must specify its own `skills` array.
5819
5983
  */
5820
- const normalizeSubagentSpec = (input) => {
5984
+ const createSubagentDefaultMiddleware = (input) => {
5821
5985
  const effectivePermissions = input.permissions ?? permissions;
5822
- const subagentMiddleware = [
5986
+ return [
5823
5987
  todoListMiddleware(),
5824
5988
  createFilesystemMiddleware({
5825
5989
  backend,
5826
- permissions: effectivePermissions
5990
+ permissions: effectivePermissions,
5991
+ tools: profileFilesystemTools
5827
5992
  }),
5828
5993
  createSummarizationMiddleware({ backend }),
5829
5994
  createPatchToolCallsMiddleware(),
5830
5995
  ...input.skills != null && input.skills.length > 0 ? [createSkillsMiddleware({
5831
5996
  backend,
5832
5997
  sources: input.skills
5833
- })] : [],
5834
- ...input.middleware ?? [],
5835
- ...cacheMiddleware
5998
+ })] : []
5836
5999
  ];
6000
+ };
6001
+ const normalizeSubagentSpec = (input) => {
6002
+ let subagentMiddleware = mergeMiddlewareStack(createSubagentDefaultMiddleware(input), input.middleware ?? [], cacheMiddleware);
6003
+ if (harnessProfile.excludedMiddleware.size > 0) subagentMiddleware = subagentMiddleware.filter((middleware) => !harnessProfile.excludedMiddleware.has(middleware.name));
5837
6004
  return {
5838
6005
  ...input,
5839
6006
  tools: input.tools ?? [],
@@ -5854,6 +6021,7 @@ function createDeepAgent(params = {}) {
5854
6021
  skills,
5855
6022
  tools: effectiveTools
5856
6023
  });
6024
+ generalPurposeSpec.middleware = mergeMiddlewareStack(generalPurposeSpec.middleware ?? [], customMiddleware, [], { appendNew: false });
5857
6025
  inlineSubagents.unshift(generalPurposeSpec);
5858
6026
  }
5859
6027
  const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
@@ -5864,7 +6032,8 @@ function createDeepAgent(params = {}) {
5864
6032
  todoListMiddleware(),
5865
6033
  createFilesystemMiddleware({
5866
6034
  backend,
5867
- permissions
6035
+ permissions,
6036
+ tools: profileFilesystemTools
5868
6037
  }),
5869
6038
  createSubAgentMiddleware({
5870
6039
  defaultModel: model,
@@ -5876,15 +6045,16 @@ function createDeepAgent(params = {}) {
5876
6045
  createSummarizationMiddleware({ backend }),
5877
6046
  createPatchToolCallsMiddleware()
5878
6047
  ];
5879
- const middleware = [
6048
+ let middleware = mergeMiddlewareStack([
5880
6049
  todoMiddleware,
5881
6050
  ...skillsMiddleware,
5882
6051
  fsMiddleware,
5883
6052
  subagentMiddleware,
5884
6053
  summarizationMiddleware,
5885
6054
  patchToolCallsMiddleware,
5886
- ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : [],
5887
- ...customMiddleware,
6055
+ ...asyncSubAgents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents })] : []
6056
+ ], customMiddleware, [
6057
+ ...resolveMiddleware(harnessProfile.extraMiddleware),
5888
6058
  ...cacheMiddleware,
5889
6059
  ...memory && memory.length > 0 ? [createMemoryMiddleware({
5890
6060
  backend,
@@ -5892,32 +6062,19 @@ function createDeepAgent(params = {}) {
5892
6062
  addCacheControl: anthropicModel
5893
6063
  })] : [],
5894
6064
  ...interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []
5895
- ];
5896
- const profileMiddleware = resolveMiddleware(harnessProfile.extraMiddleware);
5897
- if (profileMiddleware.length > 0) {
5898
- const cacheIdx = middleware.findIndex((m) => m.name === "AnthropicPromptCachingMiddleware");
5899
- if (cacheIdx !== -1) middleware.splice(cacheIdx, 0, ...profileMiddleware);
5900
- else middleware.push(...profileMiddleware);
5901
- }
6065
+ ]);
5902
6066
  if (harnessProfile.excludedMiddleware.size > 0) {
5903
6067
  const excluded = harnessProfile.excludedMiddleware;
5904
- const filtered = middleware.filter((m) => !excluded.has(m.name));
5905
- middleware.length = 0;
5906
- middleware.push(...filtered);
5907
- }
5908
- if (harnessProfile.excludedTools.size > 0) {
5909
- const excludedTools = harnessProfile.excludedTools;
5910
- middleware.push(createMiddleware({
5911
- name: "_ToolExclusionMiddleware",
5912
- wrapModelCall: async (request, handler) => {
5913
- return handler({
5914
- ...request,
5915
- tools: request.tools?.filter((t) => !excludedTools.has(t.name))
5916
- });
5917
- }
5918
- }));
5919
- }
5920
- const effectiveBasePrompt = applyProfilePrompt(harnessProfile, BASE_AGENT_PROMPT);
6068
+ middleware = middleware.filter((entry) => !excluded.has(entry.name));
6069
+ }
6070
+ if (harnessProfile.excludedTools.size > 0) middleware.push(createToolExclusionMiddleware(harnessProfile.excludedTools));
6071
+ const promptConfig = normalizeSystemPrompt(systemPrompt);
6072
+ const promptParts = [];
6073
+ if (promptConfig.prefix !== void 0 && promptConfig.prefix !== null) promptParts.push(promptConfig.prefix);
6074
+ const activeBasePrompt = promptConfig.base !== void 0 ? promptConfig.base : harnessProfile.baseSystemPrompt ?? BASE_AGENT_PROMPT;
6075
+ if (activeBasePrompt !== null) promptParts.push(activeBasePrompt);
6076
+ if (promptConfig.suffix) promptParts.push(promptConfig.suffix);
6077
+ if (harnessProfile.systemPromptSuffix) promptParts.push(harnessProfile.systemPromptSuffix);
5921
6078
  /**
5922
6079
  * Return as DeepAgent with proper DeepAgentTypeConfig
5923
6080
  * - Response: InferStructuredResponse<TResponse> (unwraps ToolStrategy<T>/ProviderStrategy<T> → T)
@@ -5930,19 +6087,7 @@ function createDeepAgent(params = {}) {
5930
6087
  */
5931
6088
  return createAgent({
5932
6089
  model,
5933
- systemPrompt: typeof systemPrompt === "string" ? new SystemMessage({ contentBlocks: [{
5934
- type: "text",
5935
- text: systemPrompt
5936
- }, {
5937
- type: "text",
5938
- text: effectiveBasePrompt
5939
- }] }) : SystemMessage.isInstance(systemPrompt) ? new SystemMessage({ contentBlocks: [...systemPrompt.contentBlocks, {
5940
- type: "text",
5941
- text: effectiveBasePrompt
5942
- }] }) : new SystemMessage({ contentBlocks: [{
5943
- type: "text",
5944
- text: effectiveBasePrompt
5945
- }] }),
6090
+ systemPrompt: assemblePromptParts(promptParts),
5946
6091
  stateSchema,
5947
6092
  tools: effectiveTools,
5948
6093
  middleware,
@@ -6294,6 +6439,19 @@ var StoreBackend = class {
6294
6439
  }
6295
6440
  }
6296
6441
  /**
6442
+ * Delete a file from the store.
6443
+ *
6444
+ * The file path is used as an exact store key. Wildcards are treated
6445
+ * literally and do not expand to multiple entries.
6446
+ */
6447
+ async delete(filePath) {
6448
+ const store = this.getStore();
6449
+ const namespace = this.getNamespace();
6450
+ if (!await store.get(namespace, filePath)) return { error: `Error: File '${filePath}' not found` };
6451
+ await store.delete(namespace, filePath);
6452
+ return { path: filePath };
6453
+ }
6454
+ /**
6297
6455
  * Search file contents for a literal text pattern.
6298
6456
  * Binary files are skipped.
6299
6457
  */
@@ -6506,10 +6664,10 @@ var ContextHubBackend = class ContextHubBackend {
6506
6664
  if (this.cache === null) throw new Error("Context Hub cache failed to initialize");
6507
6665
  return this.cache;
6508
6666
  }
6509
- async commit(files) {
6510
- if (Object.keys(files).length === 0) return;
6667
+ async commit(changes) {
6668
+ if (Object.keys(changes).length === 0) return;
6511
6669
  const payload = {};
6512
- for (const [path, content] of Object.entries(files)) payload[path] = {
6670
+ for (const [path, content] of Object.entries(changes)) payload[path] = content === null ? null : {
6513
6671
  type: "file",
6514
6672
  content
6515
6673
  };
@@ -6519,7 +6677,14 @@ var ContextHubBackend = class ContextHubBackend {
6519
6677
  });
6520
6678
  const match = URL_COMMIT_SUFFIX_RE.exec(url);
6521
6679
  if (match) this.commitHash = match[1];
6522
- if (this.cache !== null) for (const [path, content] of Object.entries(files)) this.cache[path] = content;
6680
+ if (this.cache !== null) {
6681
+ const deletions = new Set(Object.entries(changes).filter(([, content]) => content === null).map(([path]) => path));
6682
+ const updates = Object.fromEntries(Object.entries(changes).filter((entry) => entry[1] !== null));
6683
+ this.cache = {
6684
+ ...Object.fromEntries(Object.entries(this.cache).filter(([path]) => !deletions.has(path))),
6685
+ ...updates
6686
+ };
6687
+ }
6523
6688
  }
6524
6689
  /**
6525
6690
  * Return linked-entry paths mapped to their repo handles.
@@ -6678,6 +6843,20 @@ var ContextHubBackend = class ContextHubBackend {
6678
6843
  throw error;
6679
6844
  }
6680
6845
  }
6846
+ async delete(filePath) {
6847
+ const hubPath = ContextHubBackend.stripPrefix(filePath);
6848
+ try {
6849
+ if (!(hubPath in await this.ensureCache())) return { error: `Error: File '${filePath}' not found` };
6850
+ await this.commit({ [hubPath]: null });
6851
+ return { path: filePath };
6852
+ } catch (error) {
6853
+ if (isLangSmithError(error)) {
6854
+ this.cache = null;
6855
+ return { error: ContextHubBackend.toHubUnavailableError(error) };
6856
+ }
6857
+ throw error;
6858
+ }
6859
+ }
6681
6860
  async uploadFiles(files) {
6682
6861
  const decoder = new TextDecoder("utf-8", { fatal: true });
6683
6862
  const decoded = [];
@@ -7170,6 +7349,16 @@ var BaseSandbox = class {
7170
7349
  occurrences: count
7171
7350
  };
7172
7351
  }
7352
+ /**
7353
+ * Delete a file from the sandbox via a server-side rm.
7354
+ *
7355
+ * Uses rm -f, so deleting a path that does not exist succeeds silently.
7356
+ */
7357
+ async delete(filePath) {
7358
+ const result = await this.execute(`rm -f ${shellQuote(filePath)}`);
7359
+ if (result.exitCode === 0) return { path: filePath };
7360
+ return { error: `Error deleting file '${filePath}': ${result.output.trim() || "unknown error"}` };
7361
+ }
7173
7362
  };
7174
7363
  //#endregion
7175
7364
  //#region src/backends/langsmith.ts
@@ -7373,4 +7562,4 @@ var LangSmithSandbox = class LangSmithSandbox extends BaseSandbox {
7373
7562
  //#endregion
7374
7563
  export { GENERAL_PURPOSE_SUBAGENT as A, isSandboxProtocol as B, MAX_SKILL_NAME_LENGTH as C, createPatchToolCallsMiddleware as D, filesValue as E, createFilesystemMiddleware as F, getMimeType as G, adaptBackendProtocol as H, CompositeBackend as I, isTextMimeType as K, StateBackend as L, TASK_SYSTEM_PROMPT as M, createSubAgent as N, DEFAULT_GENERAL_PURPOSE_DESCRIPTION as O, createSubAgentMiddleware as P, SandboxError as R, MAX_SKILL_FILE_SIZE as S, createMemoryMiddleware as T, adaptSandboxProtocol as U, resolveBackend as V, checkEmptyContent as W, isAsyncSubAgent as _, createDeepAgent as a, createCompletionCallbackMiddleware as b, generalPurposeSubagentConfigSchema as c, serializeProfile as d, EMPTY_HARNESS_PROFILE as f, createAsyncSubAgentMiddleware as g, ConfigurationError as h, StoreBackend as i, SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY as j, DEFAULT_SUBAGENT_PROMPT as k, harnessProfileConfigSchema as l, REQUIRED_MIDDLEWARE_NAMES as m, BaseSandbox as n, getHarnessProfile as o, createHarnessProfile as p, performStringReplacement as q, ContextHubBackend as r, registerHarnessProfile as s, LangSmithSandbox as t, parseHarnessProfileConfig as u, computeSummarizationDefaults as v, createSkillsMiddleware as w, MAX_SKILL_DESCRIPTION_LENGTH as x, createSummarizationMiddleware as y, isSandboxBackend as z };
7375
7564
 
7376
- //# sourceMappingURL=langsmith-DjCMSywL.js.map
7565
+ //# sourceMappingURL=langsmith-C7Ok9lF-.js.map