← Back to PRs

#22277: fix: prevent heartbeat model override from bleeding into main session

by zhangjunmengyang open 2026-02-21 00:01 View on GitHub →
size: XS
## Summary When `heartbeat.model` is configured with a different model (e.g., a local Ollama model with a 16k context window), the heartbeat model's `model`, `modelProvider`, and `contextTokens` were being persisted to the session store after each heartbeat run. This caused the main session to inherit the heartbeat model's smaller context window on the next user request, triggering aggressive compaction and a compounding feedback loop. Fixes #22133 ## Root Cause `persistSessionUsageUpdate()` in `session-usage.ts` unconditionally writes `model`, `modelProvider`, and `contextTokens` to the session entry after every run — including heartbeat runs. When the heartbeat uses a different model (e.g., `ollama/qwen3:8b` with 16k context), these values overwrite the main session's stored state. Subsequent non-heartbeat requests then read `entry.contextTokens` (16k) before falling through to `lookupContextTokens(model)`, causing the main session to think its context window is 16k even though it's running a 200k model. ## Fix Add an `isHeartbeat` flag to `persistSessionUsageUpdate()`. When `true`: - Token usage counters (input/output/cache) are **still recorded** (usage tracking is preserved) - `model`, `modelProvider`, and `contextTokens` fields are **not overwritten** — the session entry retains its existing values - The secondary code path (model/context-only update when there's no usage data) is skipped entirely for heartbeat runs The flag is passed from both call sites: - `agent-runner.ts` — main agent execution path - `followup-runner.ts` — followup/queue execution path ## Changes - `src/auto-reply/reply/session-usage.ts` — Add `isHeartbeat` param; conditionally skip model/provider/context persistence - `src/auto-reply/reply/agent-runner.ts` — Pass `isHeartbeat` to `persistRunSessionUsage()` - `src/auto-reply/reply/followup-runner.ts` — Pass `isHeartbeat` to `persistRunSessionUsage()` ## Testing This fix addresses all symptoms described in #22133: 1. ✅ Main session model no longer switches to heartbeat model 2. ✅ Context window no longer drops to heartbeat model's value 3. ✅ No more compaction cascade from inherited small context window 4. ✅ `/new` properly restores default model (no stale `entry.model` from heartbeat) 5. ✅ Token usage is still tracked for heartbeat runs (no data loss) <!-- greptile_comment --> <h3>Greptile Summary</h3> Prevents heartbeat model configuration from overriding main session state by adding an `isHeartbeat` flag to `persistSessionUsageUpdate()`. When true, the function still records token usage counters but preserves the session's existing `model`, `modelProvider`, and `contextTokens` fields instead of overwriting them with heartbeat values. **Key changes:** - `session-usage.ts`: Added `isHeartbeat` parameter that conditionally skips model/provider/context persistence while preserving usage tracking - `agent-runner.ts`: Passes `isHeartbeat` flag from `opts` to `persistRunSessionUsage()` - `followup-runner.ts`: Passes `isHeartbeat: opts?.isHeartbeat === true` to `persistRunSessionUsage()` **Behavior:** - Token usage (input/output/cache counters) continues to be recorded for heartbeat runs - Model metadata fields are not persisted when `isHeartbeat` is true, preventing the heartbeat model's smaller context window from affecting subsequent main session requests - The fix applies to both code paths: the usage-based update (line 103-109) and the model-only update (line 124) <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The fix is focused, well-documented, and surgically addresses the root cause. The implementation correctly preserves usage tracking while preventing model state bleed. The logic is sound: token counters are still recorded (preserving telemetry), but model/provider/context fields are conditionally excluded when `isHeartbeat` is true. Both code paths in `session-usage.ts` are properly guarded. - No files require special attention <sub>Last reviewed commit: 16a963b</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs