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
This commit is contained in:
@@ -1,14 +1,113 @@
|
||||
import { log } from "../../shared/logger"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
|
||||
import {
|
||||
findEmptyMessages,
|
||||
injectTextPart,
|
||||
replaceEmptyTextParts,
|
||||
} from "../session-recovery/storage"
|
||||
import { replaceEmptyTextPartsAsync } from "../session-recovery/storage/empty-text"
|
||||
import { injectTextPartAsync } from "../session-recovery/storage/text-part-injector"
|
||||
import type { Client } from "./client"
|
||||
|
||||
export const PLACEHOLDER_TEXT = "[user interrupted]"
|
||||
|
||||
export function sanitizeEmptyMessagesBeforeSummarize(sessionID: string): number {
|
||||
type OpencodeClient = PluginInput["client"]
|
||||
|
||||
interface SDKPart {
|
||||
type?: string
|
||||
text?: string
|
||||
}
|
||||
|
||||
interface SDKMessage {
|
||||
info?: { id?: string }
|
||||
parts?: SDKPart[]
|
||||
}
|
||||
|
||||
const IGNORE_TYPES = new Set(["thinking", "redacted_thinking", "meta"])
|
||||
const TOOL_TYPES = new Set(["tool", "tool_use", "tool_result"])
|
||||
|
||||
function messageHasContentFromSDK(message: SDKMessage): boolean {
|
||||
const parts = message.parts
|
||||
if (!parts || parts.length === 0) return false
|
||||
|
||||
for (const part of parts) {
|
||||
const type = part.type
|
||||
if (!type) continue
|
||||
if (IGNORE_TYPES.has(type)) continue
|
||||
|
||||
if (type === "text") {
|
||||
if (part.text?.trim()) return true
|
||||
continue
|
||||
}
|
||||
|
||||
if (TOOL_TYPES.has(type)) return true
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
async function findEmptyMessageIdsFromSDK(
|
||||
client: OpencodeClient,
|
||||
sessionID: string,
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
const response = (await client.session.messages({
|
||||
path: { id: sessionID },
|
||||
})) as { data?: SDKMessage[] }
|
||||
const messages = response.data ?? []
|
||||
|
||||
const emptyIds: string[] = []
|
||||
for (const message of messages) {
|
||||
const messageID = message.info?.id
|
||||
if (!messageID) continue
|
||||
if (!messageHasContentFromSDK(message)) {
|
||||
emptyIds.push(messageID)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyIds
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export async function sanitizeEmptyMessagesBeforeSummarize(
|
||||
sessionID: string,
|
||||
client?: OpencodeClient,
|
||||
): Promise<number> {
|
||||
if (client && isSqliteBackend()) {
|
||||
const emptyMessageIds = await findEmptyMessageIdsFromSDK(client, sessionID)
|
||||
if (emptyMessageIds.length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
let fixedCount = 0
|
||||
for (const messageID of emptyMessageIds) {
|
||||
const replaced = await replaceEmptyTextPartsAsync(client, sessionID, messageID, PLACEHOLDER_TEXT)
|
||||
if (replaced) {
|
||||
fixedCount++
|
||||
} else {
|
||||
const injected = await injectTextPartAsync(client, sessionID, messageID, PLACEHOLDER_TEXT)
|
||||
if (injected) {
|
||||
fixedCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedCount > 0) {
|
||||
log("[auto-compact] pre-summarize sanitization fixed empty messages", {
|
||||
sessionID,
|
||||
fixedCount,
|
||||
totalEmpty: emptyMessageIds.length,
|
||||
})
|
||||
}
|
||||
|
||||
return fixedCount
|
||||
}
|
||||
|
||||
const emptyMessageIds = findEmptyMessages(sessionID)
|
||||
if (emptyMessageIds.length === 0) {
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user