#380

fix(multiagent): prevent read_file pagination loops and context compaction amnesia

Open3099404236wants to merge intofrom

Summary

Fixes an interlocking infinite-loop bug during multi-file source code audits and long agentic runs where the agent repeatedly re-reads the same files (read_file) after context reduction or summarization compaction.

Root Causes Addressed

  1. read_file Past-EOF Blindness & Micro-Pagination (internal/multiagent/eino_skills.go, internal/multiagent/tool_error_middleware.go):

    • Previously, filesystem.read_file returned raw numbered lines without total file line counts or EOF indicators. When models paginated through a file in small chunks (e.g., limit=60) and requested an offset past EOF, read_file returned empty output without signaling EOF, causing models to either paginate infinitely past EOF or restart reading from offset=1.
    • Fix:
      • Added enrichReadFileToolResult to prepend [File: <path> | Total lines: <N> | Showing lines <start>..<end> (<rem> lines remaining)] and append explicit [EOF REACHED] / [PAST EOF] loop-breaker notices.
      • Added normalizeReadFileArguments to coalesce tiny limit values into full-file reads for normal-sized source files (<= 600 lines) or >= 500-line chunks for larger files.
      • Added session-level deduplication (sessionReadFiles, reset at the start of each run) so redundant full-file reads of an already-read file in the same session return a compact notice instead of flooding the context window with duplicate tokens.
  2. Reduction Middleware Prematurely Wiping read_file Outputs (internal/multiagent/eino_middleware.go, internal/config/config.go):

    • Previously, Reduction truncated/cleared read_file outputs into <persisted-output>...使用 read_file 进行查看</persisted-output>, which actively instructed the model to call read_file again on files it had just finished reading.
    • Fix:
      • Added "read_file", "ls", "glob" to TruncExcludeTools and "read_file", "ls", "glob", "grep", "record_vulnerability", "update_vulnerability" to ClearExcludeTools.
      • Increased ClearRetentionSuffixLimit (12) and ClearAtLeastTokens (12000) when ReductionMaxTokensForClearEffective() >= 20000.
  3. Summarization 40K Output Reserve Starving Input Budget (internal/config/config.go):

    • DefaultSummarizationOutputReserveTokens was set to 40960 tokens, which starved summaryInputMax = trigger - 40960 and forced buildBudgetedSummarizationModelInput to drop the earliest 7–10 rounds (dropped_rounds > 0, including Round 1 with the user's initial prompt and early file reads) before generating the summary.
    • Fix: Lowered DefaultSummarizationOutputReserveTokens from 40960 to 8192.
  4. Post-Compaction Trail Momentum & Missing File Ledger (internal/multiagent/eino_summarize.go, internal/multiagent/eino_agentic_summarize.go, internal/multiagent/eino_context_checkpoint.go):

    • Previously, summarizeFinalizeWithRecentAssistantToolTrail appended up to 8–10 already-summarized read_file rounds after <summary>, putting the model back into mid-exploration tool-calling momentum instead of following <summary>'s next step.
    • Fix:
      • Capped maxKeepRounds = 1 in summarizeFinalizeWithRecentAssistantToolTrail.
      • Added buildAuditedFilesLedgerSection (## 9. 已读取文件台账) in eino_context_checkpoint.go to deterministically record all read file paths and line counts across compactions.

Verification

  • go test ./internal/config/... ./internal/multiagent/... passes cleanly.
  • Verified on a full 31-file Python repository white-hat security audit (agent-mcp): prior to this fix, the agent looped for 124+ turns re-reading the same files across compactions; with this fix, the agent reads all 31 files once without repetition and finishes naturally (reason=final) in 15 turns.