From 7fe85a11da71f74cf62f7785827fc4dd15c359a1 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 13 Dec 2025 04:16:42 +0900 Subject: [PATCH] fix(session-recovery): handle API/storage index mismatch in empty message recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Try both targetIndex and targetIndex-1 to handle system message offset - Remove 'last assistant message' skip logic (API error means it's not final) 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- src/hooks/session-recovery/storage.ts | 35 ++++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/hooks/session-recovery/storage.ts b/src/hooks/session-recovery/storage.ts index 2719929..4f978f8 100644 --- a/src/hooks/session-recovery/storage.ts +++ b/src/hooks/session-recovery/storage.ts @@ -122,13 +122,7 @@ export function findEmptyMessages(sessionID: string): string[] { const messages = readMessages(sessionID) const emptyIds: string[] = [] - for (let i = 0; i < messages.length; i++) { - const msg = messages[i] - - // API rule: only the final assistant message may have empty content - const isLastMessage = i === messages.length - 1 - if (isLastMessage && msg.role === "assistant") continue - + for (const msg of messages) { if (!messageHasContent(msg.id)) { emptyIds.push(msg.id) } @@ -140,18 +134,25 @@ export function findEmptyMessages(sessionID: string): string[] { export function findEmptyMessageByIndex(sessionID: string, targetIndex: number): string | null { const messages = readMessages(sessionID) - if (targetIndex < 0 || targetIndex >= messages.length) return null - - const targetMsg = messages[targetIndex] + // Try multiple indices to handle system message offset + // API includes system message at index 0, storage may not + const indicesToTry = [targetIndex, targetIndex - 1] - // API rule: only the final assistant message may have empty content - // All other messages (user AND assistant) must have non-empty content - const isLastMessage = targetIndex === messages.length - 1 - if (isLastMessage && targetMsg.role === "assistant") return null - - if (messageHasContent(targetMsg.id)) return null + for (const idx of indicesToTry) { + if (idx < 0 || idx >= messages.length) continue - return targetMsg.id + const targetMsg = messages[idx] + + // NOTE: Do NOT skip last assistant message here + // If API returned an error, this message is NOT the final assistant message + // (the API only allows empty content for the ACTUAL final assistant message) + + if (!messageHasContent(targetMsg.id)) { + return targetMsg.id + } + } + + return null } export function findFirstEmptyMessage(sessionID: string): string | null {