← Back to PRs

#22465: fix: preserve session history after API error (400/503) in mid-conversation

by hhy5562877 open 2026-02-21 06:22 View on GitHub →
agents size: XS
## Problem When an API error (400/503) occurs mid-conversation, the session transcript already contains the user's message (written by the SDK before the error), but has no assistant reply. On the next turn, `prepareSessionManagerForRun` in `session-manager-init.ts` detects `!hasAssistant` and **resets the entire session file**, wiping all prior conversation history. The user is forced to run `/compact` to recover. ## Root Cause `session-manager-init.ts` line 44 had the condition: ```ts if (params.hadSessionFile && header && !hasAssistant) ``` This was intended to reset **pre-created empty session files** (header only, no messages yet). However, it also incorrectly matched sessions that had a full conversation history but ended with an orphaned user message due to an API error. ## Fix Added a `hasUser` check so the reset only fires when there are **no user messages** in the session (i.e. a truly empty pre-created file): ```ts if (params.hadSessionFile && header && !hasAssistant && !hasUser) ``` If `hasUser` is true, the session already has conversation history — the orphaned trailing user message is handled by the existing repair logic in `attempt.ts` (lines 983–1000) on the next prompt call. ## Impact - All channels affected (Telegram, Slack, Discord, iMessage, Web, etc.) - After a 400/503 API error, conversation history is now preserved - The next message continues the conversation normally without requiring `/compact` <!-- greptile_comment --> <h3>Greptile Summary</h3> Targeted one-line fix in `session-manager-init.ts` that adds a `!hasUser` guard to the session-reset condition. Previously, `prepareSessionManagerForRun` would wipe the entire session file when `hadSessionFile && header && !hasAssistant` was true — this incorrectly matched sessions where the first user turn hit an API error (400/503), leaving a user message but no assistant reply. By also requiring `!hasUser`, the reset now only fires for truly empty pre-created session files (header only, no messages). Sessions with conversation history are preserved, and the existing orphaned-user-message repair in `attempt.ts` (lines 983–1000) handles recovery on the next prompt. - Condition in `prepareSessionManagerForRun` tightened from `!hasAssistant` to `!hasAssistant && !hasUser` - New `hasUser` variable mirrors the existing `hasAssistant` check pattern - Well-documented with inline comments and an updated JSDoc note - No test coverage added for this function (none existed previously either) <h3>Confidence Score: 5/5</h3> - This PR is safe to merge — it's a minimal, well-scoped condition tightening that preserves existing behavior for all previously-handled cases and only changes the outcome for the specific bug scenario. - The change is a single additional boolean guard (`!hasUser`) on an existing condition. The new `hasUser` variable follows the exact same pattern as the existing `hasAssistant` check. The fix correctly narrows the reset to truly empty sessions, while deferring orphaned-user-message recovery to the existing repair logic in `attempt.ts:983-1000`, which I verified handles the case properly. The change is logically sound and cannot regress any previously-working scenario (sessions with assistant messages were already excluded; sessions without any messages still get reset; the only new exclusion is sessions with user messages but no assistant messages, which is the bug scenario). - No files require special attention <sub>Last reviewed commit: 7deee92</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs