Skip to content

fix(chat): summarize all replaced history; one token estimator for meter and trigger - #548

Open
Leo310 wants to merge 2 commits into
mainfrom
fix/545-summarization
Open

Leo310 wants to merge 2 commits into
mainfrom
fix/545-summarization

Conversation

@Leo310

@Leo310 Leo310 commented Oct 13, 2026

Copy link
Copy Markdown
Member

What

Fixes three verified problems from #545 with chat summarization. Thanks to the reporter for an unusually thorough analysis; it made each of these easy to confirm against the source.

  1. Older history was dropped silently. LangChain's summarizationMiddleware trims the messages it is about to replace to trimTokensToSummarize (keeping the newest), then removes all of them. Our budget was min(trigger/2, 24k), so at a 128k window about 78k tokens of older history disappeared without being summarized. The budget now comes from the summarization model's own context window (85% of it, minus the prompt), so the summarizer reads everything it replaces. The old conservative cap is kept only when a dedicated summary model has no configured window. If history still overflows (a small dedicated summary model), it is logged and a Notice says roughly how much was left out.
  2. The meter and the trigger used different rulers. The context meter estimated words×1.3 and ignored ToolMessage bodies, while the middleware counted chars/4 including tool results. The meter now uses chars/4 (LangChain's ratio), counts tool results under "Tool results", and has realistic per-message overheads. The same function (countMessageTokens) is passed to the middleware as tokenCounter, and the trigger is lowered by the system prompt's size, because the middleware never sees it. The meter, shouldPredictSummarization and the actual trigger now agree.
  3. Failure detection was too narrow. guardSummarizationFailure now also rejects an empty summary and LangChain's "Previous conversation was too long to summarize." stub. After 3 consecutive failures it shows a Notice, once per streak, because by then the full history keeps growing toward the provider limit. The log line now includes the failed summary text.

The reporter's fourth claim, that a failed summary gets persisted as the thread's memory, was already handled by #435 (guardSummarizationFailure aborts the trim).

Fixes #545

How I tested it

Unit tests: estimator rework (tool-result counting, parity with countTokensApproximately within 2%), trim budget sizing, middleware config (shared counter, system-prompt-adjusted trigger, dedicated-summarizer bound), and guard behaviour against the real summarizationMiddleware (empty/too-long stubs rejected, failure streak reported once and reset by success, dropped history reported with exact token figures). bun run check, format, lint and test pass. Not yet tried in a live vault; a dev build is in slot vault S2B WT3 for the maintainer's live test.

AI assistance: Claude Code (Opus) wrote the change and tests from the maintainer's brief for #545, after verifying each claim against langchain 1.5.10's middleware source; the maintainer reviews and live-tests before merging.

Checklist

  • bun run check, bun run format, bun run lint, and bun run test pass locally
  • I tried the change in a real Obsidian vault (or explained above why that isn't applicable)
  • I read CONTRIBUTING.md, including the section on AI assistance
  • If this adds a provider, a bundled skill, a built-in tool, or changes manifest.json: I noted that the docs site needs updating (see "Documentation" in CONTRIBUTING.md)

…ter and trigger (#545)

- Size the summarizer's input budget from the summarization model's own
  context window (85% minus the prompt) instead of a fixed 24k cap, so it
  reads everything LangChain removes; keep the old cap only when that
  window is unknown. If history still overflows, log it and show a Notice.
- Count ToolMessage bodies in the context meter, switch it to chars/4, and
  pass the same counter to summarizationMiddleware; lower the trigger by
  the system prompt so it fires at the total the meter shows.
- Treat an empty summary and LangChain's "too long to summarize" stub as
  failures, and show a Notice after 3 consecutive failures.

Co-Authored-By: Claude <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High impact] The PR appears safe to merge; the shared failure-warning issue is fixed.

Summary

The PR increases how much history the summarizer can read, shares the token estimator with the context meter, and warns about repeated failures or omitted history.

  • Chat summaries read history within the summarizer’s context window.
  • The context meter and summary trigger use the same message-token estimate.
  • Empty and overlong summaries count as failures, and repeated failures are reported.

Reviews (2) · Last reviewed commit: "fix(chat): count summary failure streaks..." · Reviewed by Greptile

Comment thread src/agent/summarization.ts Outdated
The summarization runnable is cached per agent config and shared by every
chat, so one counter mixed chats: failures in two chats could add up to a
warning, and a success elsewhere hid one. Key the streak by thread_id.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Summarisation: the summary is written from ~23% of the history it replaces, and the drop is silent

1 participant