fix: wire deduplication into compaction recovery for prompt-too-long errors (#96)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-02-07 19:18:12 +09:00
parent 2727f0f429
commit 844ac26e2a
4 changed files with 320 additions and 0 deletions
@@ -0,0 +1,92 @@
import { existsSync, readdirSync, readFileSync } from "node:fs"
import { join } from "node:path"
import { getOpenCodeStorageDir } from "../../shared/data-path"
import { truncateToolResult } from "./storage"
import { log } from "../../shared/logger"
interface StoredToolPart {
type?: string
callID?: string
truncated?: boolean
state?: {
output?: string
}
}
const OPENCODE_STORAGE = getOpenCodeStorageDir()
const MESSAGE_STORAGE = join(OPENCODE_STORAGE, "message")
const PART_STORAGE = join(OPENCODE_STORAGE, "part")
function getMessageDir(sessionID: string): string | null {
if (!existsSync(MESSAGE_STORAGE)) return null
const directPath = join(MESSAGE_STORAGE, sessionID)
if (existsSync(directPath)) return directPath
for (const dir of readdirSync(MESSAGE_STORAGE)) {
const sessionPath = join(MESSAGE_STORAGE, dir, sessionID)
if (existsSync(sessionPath)) return sessionPath
}
return null
}
function getMessageIds(sessionID: string): string[] {
const messageDir = getMessageDir(sessionID)
if (!messageDir) return []
const messageIds: string[] = []
for (const file of readdirSync(messageDir)) {
if (!file.endsWith(".json")) continue
messageIds.push(file.replace(".json", ""))
}
return messageIds
}
export function truncateToolOutputsByCallId(
sessionID: string,
callIds: Set<string>,
): { truncatedCount: number } {
if (callIds.size === 0) return { truncatedCount: 0 }
const messageIds = getMessageIds(sessionID)
if (messageIds.length === 0) return { truncatedCount: 0 }
let truncatedCount = 0
for (const messageID of messageIds) {
const partDir = join(PART_STORAGE, messageID)
if (!existsSync(partDir)) continue
for (const file of readdirSync(partDir)) {
if (!file.endsWith(".json")) continue
const partPath = join(partDir, file)
try {
const content = readFileSync(partPath, "utf-8")
const part = JSON.parse(content) as StoredToolPart
if (part.type !== "tool" || !part.callID) continue
if (!callIds.has(part.callID)) continue
if (!part.state?.output || part.truncated) continue
const result = truncateToolResult(partPath)
if (result.success) {
truncatedCount++
}
} catch {
continue
}
}
}
if (truncatedCount > 0) {
log("[auto-compact] pruned duplicate tool outputs", {
sessionID,
truncatedCount,
})
}
return { truncatedCount }
}