← Back to PRs

#4223: fix: compaction safeguard falls through when ctx.model is unavailable

by hanxiao open 2026-01-29 22:17 View on GitHub →
agents
## Problem When Clawdbot runs in embedded mode, `extensionRunner.initialize()` is never called. This means `ExtensionRunner.getModel` stays at its default `() => undefined`. When the compaction safeguard extension runs, it reads `ctx.model` which calls `getModel()` → returns `undefined`. The safeguard then returns a fallback summary with no actual content: ``` Summary unavailable due to context limits. Older messages were truncated. ``` This effectively **discards all conversation history** on every compaction. It also causes **cascading re-compactions**: the empty summary is only ~50 tokens, so the next tool call immediately fills the context again, triggering another compaction, which again produces an empty summary. In a single session I observed **22 consecutive compactions**, all with empty summaries. ## Root Cause `ExtensionRunner.getModel` defaults to `() => undefined` and is only set to the correct getter during `initialize()`. The three built-in pi-coding-agent modes (interactive, print, rpc) all call `initialize()`, but Clawdbot's embedded runner (`compact.js`, `run/attempt.js`) does not. In `AgentSession._runAutoCompaction()`, the model and API key are correctly validated via `this.model` **before** emitting the `session_before_compact` event. So the model is available -- just not through the extension context's `ctx.model` getter. ## Fix When `ctx.model` or `apiKey` is unavailable, return `undefined` instead of the fallback summary. This lets the built-in compaction code in `AgentSession` handle summarization, which correctly accesses the model via `this.model` (`agent.state.model`) and produces a proper summary. ## Alternative The deeper fix would be to ensure `extensionRunner.initialize()` is called in the embedded runner flow, but that's a larger change. This fix is safe and minimal -- the built-in compaction path is well-tested and produces correct summaries. <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR adjusts the `session_before_compact` compaction-safeguard extension so it no longer emits an “empty fallback” compaction result when `ctx.model` or its API key is unavailable (notably in embedded runner mode where `extensionRunner.initialize()` is not invoked). Instead it returns `undefined`, allowing `AgentSession`’s built-in compaction path to run with a valid model sourced from the session state, preventing repeated compactions caused by near-empty summaries. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk. - Change is narrowly scoped to early-return behavior in the compaction safeguard; it removes a harmful fallback output in cases where the extension lacks model/apiKey context and defers to the core, already-validated compaction logic. No API surface changes, and failure path for real summarization errors is unchanged. - No files require special attention <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs