DeepAgents summarization can produce an empty summary when a single tool result exceeds trimTokensToSummarize

Problem

We’re seeing agent runs terminate with a summarization result such as:


There's no prior conversation content in this thread to summarize.

even though the thread contains substantial conversation history and multiple tool calls.

Example

The agent was analyzing a large minified file:


read_file(Resources/Raw/wwwroot/sf-richtexteditor.js)

The tool returned a very large response (hundreds of KB).

Later, when context compaction/summarization was triggered, the summarizer produced:


There's no prior conversation content in this thread to summarize.

This summary was then surfaced as the assistant response, and the task never completed.

Investigation

While reviewing the DeepAgents summarization logic, it appears the summarizer trims the messages being summarized to trimTokensToSummarize (default ~4000 tokens).

The logic is roughly:

let kept = 0;

const trimmed = \[\];

for (let i = messages.length - 1; i >= 0; i--) {

  const t = countTokensApproximately(\[messages\[i\]\]);

  if (kept + t > trimTokensToSummarize) {

    break;

  }

  trimmed.unshift(messages\[i\]);

  kept += t;

}

messagesToSummarize = trimmed;

If the newest message in the summarization slice is a large tool result:


Tool Result: 50,000+ tokens

trimTokensToSummarize: 4,000

the loop exits immediately:


messagesToSummarize = \[\]

which leads to:


conversation = ""

The summarizer effectively receives:


Conversation to summarize:

Summary:

and generates a “no content” response.

Additional Observation

In our run, the task was not actually finished.

The agent still had remaining work to do, but after summarization the thread ended with the summary message as the final assistant response.

The original task never completed.

Questions

  1. Is this the same issue as GitHub issue #6470 and #5913 (“Summary input limit can produce a content-free compaction”) or is this a separate edge case?
  2. Is there any protection against a single tool-result message completely emptying messagesToSummarize?
  3. Should summarization fall back to truncating the oversized message instead of returning an empty summary?
  4. Is it expected that a summarizer response can become the final assistant message while there is still unfinished work in the run?
  5. Are there recommended settings for handling large read_file / grep results from minified files?

Your reading of the trim loop is right. It walks backward from the newest message and stops at the first message that would push the total over trimTokensToSummarize. If that newest message is a 50k-token tool result, nothing is kept, the summarizer gets an empty conversation, and you get the “no prior conversation content” summary you saw.

Taking your questions in order:

1. Same as #6470 / #5913? Same family. deepagents#6470 (about the summary input limit producing a compaction with no content) describes this exact failure on the Python side: the summary-input limit is smaller than a single message, so non-empty history becomes empty summarization input. That issue cites #5913 as related. Your JS repro would be a useful addition there.

2. Protection against one message emptying the slice? Check your deepagents version and config first. In deepagentsjs, langchain-ai/deepagentsjs#732 (“disable summary input trimming by default”, released in 1.12.3) made trimTokensToSummarize opt-in. If you don’t pass it, the full selected conversation goes to the summary model. If you’re on 1.12.3 or later and still see this, you’re probably setting trimTokensToSummarize explicitly, and the backward loop above still applies. Then either remove the option or set it well above your largest possible single message. On older versions, upgrading should fix the default case.

The generic LangChain JS summarizationMiddleware works differently. It uses trimMessages with allowPartial: true, and if trimming still leaves nothing, it returns a fixed “Previous conversation was too long to summarize.” string instead of calling the model. Per #6470, partial splitting happens on newlines, so a huge single-line payload (like a minified JS file) can’t be partially kept either. Avoiding oversized messages (point 5) is the reliable fix in both cases.

3. Truncate instead of returning an empty summary? I agree that’s the better behavior: keep the head and tail of the oversized message, or insert a placeholder like [read_file(X) result, ~N tokens, truncated] so the summary still records what happened. That’s a fair ask to add to the issue.

4. Summary becoming the final answer? I don’t think that’s intended, but I haven’t traced the exact path in your version, so treat this as a hypothesis. In Deep Agents, the summary is injected as a message, not as the agent’s answer. My guess is the model’s next turn saw only “nothing to summarize”, decided there was nothing left to do, and stopped. As a safeguard, check after each run whether the todos are still pending (or the task’s done-condition isn’t met) and resume the thread if so. If you need to spot the summary message itself, inspect your messages for summarization metadata. In the versions I looked at, Deep Agents marks it with additional_kwargs.lc_source === "summarization", but verify that against your installed version before relying on it.

5. Settings for large read_file / grep results:

  • Deep Agents offloads very large tool results to the backend and replaces them with a file path plus a short preview. See “Offloading” here: Context engineering in Deep Agents - Docs by LangChain — if a 50k-token read_file result is still sitting in history, check your version and whether a custom tool or backend bypasses that path.
  • Have the agent read minified/bundled files in slices (read_file supports offset/limit) and grep for the symbol first. Say this explicitly in the system prompt.
  • Push that analysis into a subagent, so the raw file stays in the subagent’s context and only a short report returns.
  • Keep the plan outside the summarized window (write_todos, or progress notes in the agent’s filesystem). Then even a bad compaction doesn’t lose the remaining work.

Reference for the middleware options: summarizationMiddleware | langchain | LangChain Reference