Merge branch 'fix-empty-message-content'

This commit is contained in:
YeonGyu-Kim
2025-12-16 21:02:38 +09:00
2 changed files with 74 additions and 3 deletions

View File

@@ -4,12 +4,14 @@ import {
findEmptyMessages,
findEmptyMessageByIndex,
findMessageByIndexNeedingThinking,
findMessagesWithEmptyTextParts,
findMessagesWithOrphanThinking,
findMessagesWithThinkingBlocks,
findMessagesWithThinkingOnly,
injectTextPart,
prependThinkingPart,
readParts,
replaceEmptyTextParts,
stripThinkingParts,
} from "./storage"
import type { MessageData } from "./types"
@@ -222,28 +224,48 @@ async function recoverEmptyContentMessage(
): Promise<boolean> {
const targetIndex = extractMessageIndex(error)
const failedID = failedAssistantMsg.info?.id
let anySuccess = false
const messagesWithEmptyText = findMessagesWithEmptyTextParts(sessionID)
for (const messageID of messagesWithEmptyText) {
if (replaceEmptyTextParts(messageID, PLACEHOLDER_TEXT)) {
anySuccess = true
}
}
const thinkingOnlyIDs = findMessagesWithThinkingOnly(sessionID)
for (const messageID of thinkingOnlyIDs) {
injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT)
if (injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT)) {
anySuccess = true
}
}
if (targetIndex !== null) {
const targetMessageID = findEmptyMessageByIndex(sessionID, targetIndex)
if (targetMessageID) {
return injectTextPart(sessionID, targetMessageID, PLACEHOLDER_TEXT)
if (replaceEmptyTextParts(targetMessageID, PLACEHOLDER_TEXT)) {
return true
}
if (injectTextPart(sessionID, targetMessageID, PLACEHOLDER_TEXT)) {
return true
}
}
}
if (failedID) {
if (replaceEmptyTextParts(failedID, PLACEHOLDER_TEXT)) {
return true
}
if (injectTextPart(sessionID, failedID, PLACEHOLDER_TEXT)) {
return true
}
}
const emptyMessageIDs = findEmptyMessages(sessionID)
let anySuccess = thinkingOnlyIDs.length > 0
for (const messageID of emptyMessageIDs) {
if (replaceEmptyTextParts(messageID, PLACEHOLDER_TEXT)) {
anySuccess = true
}
if (injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT)) {
anySuccess = true
}

View File

@@ -271,6 +271,55 @@ export function stripThinkingParts(messageID: string): boolean {
return anyRemoved
}
export function replaceEmptyTextParts(messageID: string, replacementText: string): boolean {
const partDir = join(PART_STORAGE, messageID)
if (!existsSync(partDir)) return false
let anyReplaced = false
for (const file of readdirSync(partDir)) {
if (!file.endsWith(".json")) continue
try {
const filePath = join(partDir, file)
const content = readFileSync(filePath, "utf-8")
const part = JSON.parse(content) as StoredPart
if (part.type === "text") {
const textPart = part as StoredTextPart
if (!textPart.text?.trim()) {
textPart.text = replacementText
textPart.synthetic = true
writeFileSync(filePath, JSON.stringify(textPart, null, 2))
anyReplaced = true
}
}
} catch {
continue
}
}
return anyReplaced
}
export function findMessagesWithEmptyTextParts(sessionID: string): string[] {
const messages = readMessages(sessionID)
const result: string[] = []
for (const msg of messages) {
const parts = readParts(msg.id)
const hasEmptyTextPart = parts.some((p) => {
if (p.type !== "text") return false
const textPart = p as StoredTextPart
return !textPart.text?.trim()
})
if (hasEmptyTextPart) {
result.push(msg.id)
}
}
return result
}
export function findMessageByIndexNeedingThinking(sessionID: string, targetIndex: number): string | null {
const messages = readMessages(sessionID)