Files
oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery.ts
T
YeonGyu-Kim 5c37dc8210 feat: wire context-window-recovery callers to async SDK/HTTP variants on SQLite
- empty-content-recovery: isSqliteBackend() branch delegating to extracted
  empty-content-recovery-sdk.ts with SDK message scanning
- message-builder: sanitizeEmptyMessagesBeforeSummarize now async with SDK path
  using replaceEmptyTextPartsAsync/injectTextPartAsync
- target-token-truncation: truncateUntilTargetTokens now async with SDK path
  using findToolResultsBySizeFromSDK/truncateToolResultAsync
- aggressive-truncation-strategy: passes client to truncateUntilTargetTokens
- summarize-retry-strategy: await sanitizeEmptyMessagesBeforeSummarize
- client.ts: derive Client from PluginInput['client'] instead of manual defs
- executor.test.ts: .mockReturnValue() → .mockResolvedValue() for async fns
- storage.test.ts: add await for async truncateUntilTargetTokens
2026-02-16 16:13:40 +09:00

126 lines
3.4 KiB
TypeScript

import {
findEmptyMessages,
findEmptyMessageByIndex,
injectTextPart,
replaceEmptyTextParts,
} from "../session-recovery/storage"
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
import type { AutoCompactState } from "./types"
import type { Client } from "./client"
import { PLACEHOLDER_TEXT } from "./message-builder"
import { incrementEmptyContentAttempt } from "./state"
import { fixEmptyMessagesWithSDK } from "./empty-content-recovery-sdk"
export async function fixEmptyMessages(params: {
sessionID: string
autoCompactState: AutoCompactState
client: Client
messageIndex?: number
}): Promise<boolean> {
incrementEmptyContentAttempt(params.autoCompactState, params.sessionID)
let fixed = false
const fixedMessageIds: string[] = []
if (isSqliteBackend()) {
const result = await fixEmptyMessagesWithSDK({
sessionID: params.sessionID,
client: params.client,
placeholderText: PLACEHOLDER_TEXT,
messageIndex: params.messageIndex,
})
if (!result.fixed && result.scannedEmptyCount === 0) {
await params.client.tui
.showToast({
body: {
title: "Empty Content Error",
message: "No empty messages found in storage. Cannot auto-recover.",
variant: "error",
duration: 5000,
},
})
.catch(() => {})
return false
}
if (result.fixed) {
await params.client.tui
.showToast({
body: {
title: "Session Recovery",
message: `Fixed ${result.fixedMessageIds.length} empty message(s). Retrying...`,
variant: "warning",
duration: 3000,
},
})
.catch(() => {})
}
return result.fixed
}
if (params.messageIndex !== undefined) {
const targetMessageId = findEmptyMessageByIndex(params.sessionID, params.messageIndex)
if (targetMessageId) {
const replaced = replaceEmptyTextParts(targetMessageId, PLACEHOLDER_TEXT)
if (replaced) {
fixed = true
fixedMessageIds.push(targetMessageId)
} else {
const injected = injectTextPart(params.sessionID, targetMessageId, PLACEHOLDER_TEXT)
if (injected) {
fixed = true
fixedMessageIds.push(targetMessageId)
}
}
}
}
if (!fixed) {
const emptyMessageIds = findEmptyMessages(params.sessionID)
if (emptyMessageIds.length === 0) {
await params.client.tui
.showToast({
body: {
title: "Empty Content Error",
message: "No empty messages found in storage. Cannot auto-recover.",
variant: "error",
duration: 5000,
},
})
.catch(() => {})
return false
}
for (const messageID of emptyMessageIds) {
const replaced = replaceEmptyTextParts(messageID, PLACEHOLDER_TEXT)
if (replaced) {
fixed = true
fixedMessageIds.push(messageID)
} else {
const injected = injectTextPart(params.sessionID, messageID, PLACEHOLDER_TEXT)
if (injected) {
fixed = true
fixedMessageIds.push(messageID)
}
}
}
}
if (fixed) {
await params.client.tui
.showToast({
body: {
title: "Session Recovery",
message: `Fixed ${fixedMessageIds.length} empty message(s). Retrying...`,
variant: "warning",
duration: 3000,
},
})
.catch(() => {})
}
return fixed
}