deepagents 1.12.2 → 1.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -302,13 +302,13 @@ function performStringReplacement(content, oldString, newString, replaceAll) {
302
302
  function truncateIfTooLong(result) {
303
303
  if (Array.isArray(result)) {
304
304
  const totalChars = result.reduce((sum, item) => sum + item.length, 0);
305
- if (totalChars > 2e4 * 4) {
305
+ if (totalChars > 8e4) {
306
306
  const truncateAt = Math.floor(result.length * TOOL_RESULT_TOKEN_LIMIT * 4 / totalChars);
307
307
  return [...result.slice(0, truncateAt), TRUNCATION_GUIDANCE];
308
308
  }
309
309
  return result;
310
310
  }
311
- if (result.length > 2e4 * 4) return result.substring(0, TOOL_RESULT_TOKEN_LIMIT * 4) + "\n... [results truncated, try being more specific with your parameters]";
311
+ if (result.length > 8e4) return result.substring(0, TOOL_RESULT_TOKEN_LIMIT * 4) + "\n... [results truncated, try being more specific with your parameters]";
312
312
  return result;
313
313
  }
314
314
  /**
@@ -401,6 +401,30 @@ function globSearchFiles(files, pattern, path = "/") {
401
401
  return matches.map(([fp]) => fp).join("\n");
402
402
  }
403
403
  /**
404
+ * Format grep search results based on output mode.
405
+ *
406
+ * @param results - Dictionary mapping file paths to list of [line_num, line_content] tuples
407
+ * @param outputMode - Output format - "files_with_matches", "content", or "count"
408
+ * @returns Formatted string output
409
+ */
410
+ function formatGrepResults(results, outputMode) {
411
+ if (outputMode === "files_with_matches") return Object.keys(results).sort().join("\n");
412
+ if (outputMode === "count") {
413
+ const lines = [];
414
+ for (const filePath of Object.keys(results).sort()) {
415
+ const count = results[filePath].length;
416
+ lines.push(`${filePath}: ${count}`);
417
+ }
418
+ return lines.join("\n");
419
+ }
420
+ const lines = [];
421
+ for (const filePath of Object.keys(results).sort()) {
422
+ lines.push(`${filePath}:`);
423
+ for (const [lineNum, line] of results[filePath]) lines.push(` ${lineNum}: ${line}`);
424
+ }
425
+ return lines.join("\n");
426
+ }
427
+ /**
404
428
  * Return structured grep matches from an in-memory files mapping.
405
429
  *
406
430
  * Performs literal text search (not regex). Binary files are skipped.
@@ -431,6 +455,24 @@ function grepMatchesFromFiles(files, pattern, path = null, glob = null) {
431
455
  return matches;
432
456
  }
433
457
  /**
458
+ * Group structured matches into the legacy dict form used by formatters.
459
+ */
460
+ function buildGrepResultsDict(matches) {
461
+ const grouped = {};
462
+ for (const m of matches) {
463
+ if (!grouped[m.path]) grouped[m.path] = [];
464
+ grouped[m.path].push([m.line, m.text]);
465
+ }
466
+ return grouped;
467
+ }
468
+ /**
469
+ * Format structured grep matches using existing formatting logic.
470
+ */
471
+ function formatGrepMatches(matches, outputMode) {
472
+ if (matches.length === 0) return "No matches found";
473
+ return formatGrepResults(buildGrepResultsDict(matches), outputMode);
474
+ }
475
+ /**
434
476
  * Determine MIME type from a file path's extension.
435
477
  *
436
478
  * Defaults to "text/plain" for unknown extensions. Only the known non-text
@@ -1421,7 +1463,7 @@ const TOOLS_EXCLUDED_FROM_EVICTION = FILESYSTEM_TOOL_NAMES.filter((name) => name
1421
1463
  * Base64-encoded content is ~33% larger, so 10MB raw ≈ 13.3MB in context.
1422
1464
  * This keeps inline multimodal payloads within all major provider limits.
1423
1465
  */
1424
- const MAX_BINARY_READ_SIZE_BYTES = 10 * 1024 * 1024;
1466
+ const MAX_BINARY_READ_SIZE_BYTES = 10485760;
1425
1467
  /**
1426
1468
  * Template for truncation message in read_file.
1427
1469
  * {file_path} will be filled in at runtime.
@@ -1510,8 +1552,9 @@ function buildEvictedHumanContent(message, replacementText) {
1510
1552
  */
1511
1553
  function buildTruncatedHumanMessage(message, filePath) {
1512
1554
  const contentSample = createContentPreview(extractTextFromMessage(message));
1555
+ const evictedContent = buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample));
1513
1556
  return new HumanMessage({
1514
- content: buildEvictedHumanContent(message, TOO_LARGE_HUMAN_MSG.replace("{file_path}", filePath).replace("{content_sample}", contentSample)),
1557
+ content: evictedContent,
1515
1558
  id: message.id,
1516
1559
  additional_kwargs: { ...message.additional_kwargs },
1517
1560
  response_metadata: { ...message.response_metadata }
@@ -1785,7 +1828,7 @@ function createReadFileTool(backend, options) {
1785
1828
  const sizeBytes = Math.ceil(base64Data.length * 3 / 4);
1786
1829
  if (sizeBytes > 10485760) return [{
1787
1830
  type: "text",
1788
- text: `Error: file too large to read (${Math.round(sizeBytes / (1024 * 1024))}MB exceeds ${MAX_BINARY_READ_SIZE_BYTES / (1024 * 1024)}MB limit for binary files)`
1831
+ text: `Error: file too large to read (${Math.round(sizeBytes / 1048576)}MB exceeds ${MAX_BINARY_READ_SIZE_BYTES / 1048576}MB limit for binary files)`
1789
1832
  }];
1790
1833
  if (mimeType.startsWith("image/")) return [{
1791
1834
  type: "image",
@@ -1932,23 +1975,14 @@ function createGrepTool(backend, options) {
1932
1975
  const permissionError = checkPermission(permissions, "read", input.path ?? "/");
1933
1976
  if (permissionError !== void 0) return toolError(runtime, "grep", permissionError);
1934
1977
  const resolvedBackend = await resolveBackend(backend, runtime);
1935
- const { pattern, path = "/", glob = null } = input;
1978
+ const { pattern, path = "/", glob = null, output_mode = "content" } = input;
1936
1979
  const maxCount = input.max_count ?? grepMaxCount;
1937
1980
  const result = await resolvedBackend.grep(pattern, path, glob, maxCount);
1938
1981
  if (result.error) return result.error;
1939
1982
  const matches = filterByPermissions(result.matches ?? [], permissions, "read", (m) => m.path);
1940
1983
  if (matches.length === 0) return `No matches found for pattern '${pattern}'`;
1941
- const lines = [];
1942
- let currentFile = null;
1943
- for (const match of matches) {
1944
- if (match.path !== currentFile) {
1945
- currentFile = match.path;
1946
- lines.push(`\n${currentFile}:`);
1947
- }
1948
- lines.push(` ${match.line}: ${match.text}`);
1949
- }
1950
- const truncated = truncateIfTooLong(lines);
1951
- let content = Array.isArray(truncated) ? truncated.join("\n") : truncated;
1984
+ const truncated = truncateIfTooLong(formatGrepMatches(matches, output_mode));
1985
+ let content = typeof truncated === "string" ? truncated : truncated.join("\n");
1952
1986
  if (result.truncated) content += `\n\n${GREP_TRUNCATION_NOTE}`;
1953
1987
  return content;
1954
1988
  }, {
@@ -1958,7 +1992,12 @@ function createGrepTool(backend, options) {
1958
1992
  pattern: z.string().describe("Literal text pattern to search for (not regex)"),
1959
1993
  path: z.string().optional().default("/").describe("Base path to search from (default: /)"),
1960
1994
  glob: z.string().optional().nullable().default(null).describe("Optional glob pattern to filter files (e.g., '*.py')"),
1961
- max_count: z.number().int().positive().optional().nullable().default(null).describe("Optional cap on the total number of matches returned across all files. Leave unset to use the configured default. When the cap is hit, results are truncated and a note says so; narrow the pattern or path to see the rest.")
1995
+ max_count: z.number().int().positive().optional().nullable().default(null).describe("Optional cap on the total number of matches returned across all files. Leave unset to use the configured default. When the cap is hit, results are truncated and a note says so; narrow the pattern or path to see the rest."),
1996
+ output_mode: z.enum([
1997
+ "files_with_matches",
1998
+ "content",
1999
+ "count"
2000
+ ]).optional().default("content").describe("Output format: 'files_with_matches' lists matching file paths, 'content' shows matching lines (default), 'count' shows match counts per file")
1962
2001
  })
1963
2002
  });
1964
2003
  }
@@ -2095,9 +2134,10 @@ function createFilesystemMiddleware(options = {}) {
2095
2134
  const evictPath = `/large_tool_results/${sanitizeToolCallId(fallbackToolCallId || msg.tool_call_id)}.txt`;
2096
2135
  const writeResult = await resolvedBackend.write(evictPath, textContent);
2097
2136
  const contentSample = createContentPreview(textContent);
2137
+ const replacementText = writeResult.error ? `Tool result too large, but the result could not be saved to the filesystem: ${writeResult.error}` : TOO_LARGE_TOOL_MSG.replace("{tool_call_id}", msg.tool_call_id).replace("{file_path}", evictPath).replace("{content_sample}", contentSample);
2098
2138
  return {
2099
2139
  message: new ToolMessage({
2100
- content: writeResult.error ? `Tool result too large, but the result could not be saved to the filesystem: ${writeResult.error}` : TOO_LARGE_TOOL_MSG.replace("{tool_call_id}", msg.tool_call_id).replace("{file_path}", evictPath).replace("{content_sample}", contentSample),
2140
+ content: replacementText,
2101
2141
  tool_call_id: msg.tool_call_id,
2102
2142
  name: msg.name,
2103
2143
  id: msg.id,
@@ -2442,6 +2482,7 @@ function createTaskTool(options) {
2442
2482
  }
2443
2483
  return subagentGraphs[subagentType];
2444
2484
  }
2485
+ const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
2445
2486
  return tool(async (input, config) => {
2446
2487
  const { description, subagent_type } = input;
2447
2488
  if (!(subagent_type in subagentGraphs)) {
@@ -2477,7 +2518,7 @@ function createTaskTool(options) {
2477
2518
  return returnCommandWithStateUpdate(result, config.toolCall.id);
2478
2519
  }, {
2479
2520
  name: "task",
2480
- description: taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions),
2521
+ description: finalTaskDescription,
2481
2522
  schema: z.object({
2482
2523
  description: z.string().describe("The task to execute with the selected agent"),
2483
2524
  subagent_type: z.string().describe(`Name of the agent to use. Available: ${Object.keys(subagentGraphs).join(", ")}`)
@@ -2489,18 +2530,19 @@ function createTaskTool(options) {
2489
2530
  */
2490
2531
  function createSubAgentMiddleware(options) {
2491
2532
  const { defaultModel, defaultTools = [], defaultMiddleware = null, generalPurposeMiddleware = null, defaultInterruptOn = null, subagents = [], systemPrompt = null, generalPurposeAgent = true, taskDescription = null } = options;
2533
+ const taskTool = createTaskTool({
2534
+ defaultModel,
2535
+ defaultTools,
2536
+ defaultMiddleware,
2537
+ generalPurposeMiddleware,
2538
+ defaultInterruptOn,
2539
+ subagents,
2540
+ generalPurposeAgent,
2541
+ taskDescription
2542
+ });
2492
2543
  return createMiddleware({
2493
2544
  name: "subAgentMiddleware",
2494
- tools: [createTaskTool({
2495
- defaultModel,
2496
- defaultTools,
2497
- defaultMiddleware,
2498
- generalPurposeMiddleware,
2499
- defaultInterruptOn,
2500
- subagents,
2501
- generalPurposeAgent,
2502
- taskDescription
2503
- })],
2545
+ tools: [taskTool],
2504
2546
  wrapModelCall: async (request, handler) => {
2505
2547
  if (systemPrompt !== null) return handler({
2506
2548
  ...request,
@@ -3005,7 +3047,7 @@ function createMemoryMiddleware(options) {
3005
3047
  * });
3006
3048
  * ```
3007
3049
  */
3008
- const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;
3050
+ const MAX_SKILL_FILE_SIZE = 10485760;
3009
3051
  const DEFAULT_SKILL_READ_LINE_LIMIT = 1e3;
3010
3052
  const MAX_SKILL_NAME_LENGTH = 64;
3011
3053
  const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
@@ -3768,7 +3810,6 @@ function createCompletionCallbackMiddleware(options) {
3768
3810
  * from `langchain` directly.
3769
3811
  */
3770
3812
  const DEFAULT_MESSAGES_TO_KEEP = 20;
3771
- const DEFAULT_TRIM_TOKEN_LIMIT = 4e3;
3772
3813
  const FALLBACK_TRIGGER = {
3773
3814
  type: "tokens",
3774
3815
  value: 17e4
@@ -3885,7 +3926,7 @@ function isSummaryMessage(msg) {
3885
3926
  * @returns AgentMiddleware for summarization and history offloading
3886
3927
  */
3887
3928
  function createSummarizationMiddleware(options) {
3888
- const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize = DEFAULT_TRIM_TOKEN_LIMIT, historyPathPrefix = "/conversation_history" } = options;
3929
+ const { model, backend, summaryPrompt = DEFAULT_SUMMARY_PROMPT, trimTokensToSummarize, historyPathPrefix = "/conversation_history" } = options;
3889
3930
  let trigger = options.trigger;
3890
3931
  let keep = options.keep ?? {
3891
3932
  type: "messages",
@@ -4089,7 +4130,9 @@ function createSummarizationMiddleware(options) {
4089
4130
  * This gives a more accurate picture of what actually gets sent to the model.
4090
4131
  */
4091
4132
  function countTotalTokens(messages, systemMessage, tools) {
4092
- return countTokensApproximately(systemMessage && SystemMessage.isInstance(systemMessage) ? [systemMessage, ...messages] : [...messages], tools && Array.isArray(tools) && tools.length > 0 ? tools : null);
4133
+ const countedMessages = systemMessage && SystemMessage.isInstance(systemMessage) ? [systemMessage, ...messages] : [...messages];
4134
+ const toolsArray = tools && Array.isArray(tools) && tools.length > 0 ? tools : null;
4135
+ return countTokensApproximately(countedMessages, toolsArray);
4093
4136
  }
4094
4137
  /**
4095
4138
  * Truncate ToolMessage content so that the total payload fits within the
@@ -4236,7 +4279,8 @@ function createSummarizationMiddleware(options) {
4236
4279
  */
4237
4280
  async function createSummary(messages, chatModel) {
4238
4281
  let messagesToSummarize = messages;
4239
- if (countTokensApproximately(messages) > trimTokensToSummarize) {
4282
+ const tokens = countTokensApproximately(messages);
4283
+ if (trimTokensToSummarize !== void 0 && tokens > trimTokensToSummarize) {
4240
4284
  let kept = 0;
4241
4285
  const trimmedMessages = [];
4242
4286
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -4249,8 +4293,7 @@ function createSummarizationMiddleware(options) {
4249
4293
  }
4250
4294
  const conversation = getBufferString(messagesToSummarize);
4251
4295
  const prompt = summaryPrompt.replace("{conversation}", conversation);
4252
- const response = await chatModel.invoke([new HumanMessage({ content: prompt })]);
4253
- return typeof response.content === "string" ? response.content : JSON.stringify(response.content);
4296
+ return (await chatModel.invoke([new HumanMessage({ content: prompt })])).text;
4254
4297
  }
4255
4298
  /**
4256
4299
  * Build the summary message with file path reference.
@@ -7533,4 +7576,4 @@ var LangSmithSandbox = class LangSmithSandbox extends BaseSandbox {
7533
7576
  //#endregion
7534
7577
  export { filesValue as A, StateBackend as B, createSummarizationMiddleware as C, MAX_SKILL_NAME_LENGTH as D, MAX_SKILL_FILE_SIZE as E, SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY as F, resolveBackend as G, applyGrepMaxCount as H, createSubAgent as I, checkEmptyContent as J, adaptBackendProtocol as K, createSubAgentMiddleware as L, DEFAULT_GENERAL_PURPOSE_DESCRIPTION as M, DEFAULT_SUBAGENT_PROMPT as N, createSkillsMiddleware as O, GENERAL_PURPOSE_SUBAGENT as P, createFilesystemMiddleware as R, computeSummarizationDefaults as S, MAX_SKILL_DESCRIPTION_LENGTH as T, isSandboxBackend as U, SandboxError as V, isSandboxProtocol as W, isTextMimeType as X, getMimeType as Y, performStringReplacement as Z, createHarnessProfile as _, ASYNC_TASK_SYSTEM_PROMPT as a, createAsyncSubAgentMiddleware as b, TASK_SYSTEM_PROMPT as c, registerHarnessProfile as d, generalPurposeSubagentConfigSchema as f, EMPTY_HARNESS_PROFILE as g, serializeProfile as h, StoreBackend as i, createPatchToolCallsMiddleware as j, createMemoryMiddleware as k, createDeepAgent as l, parseHarnessProfileConfig as m, BaseSandbox as n, BASE_AGENT_PROMPT as o, harnessProfileConfigSchema as p, adaptSandboxProtocol as q, ContextHubBackend as r, EXECUTION_SYSTEM_PROMPT as s, LangSmithSandbox as t, getHarnessProfile as u, REQUIRED_MIDDLEWARE_NAMES as v, createCompletionCallbackMiddleware as w, isAsyncSubAgent as x, ConfigurationError as y, CompositeBackend as z };
7535
7578
 
7536
- //# sourceMappingURL=langsmith-b3Dpu8rS.js.map
7579
+ //# sourceMappingURL=langsmith-CUTUAjHo.js.map