Merge pull request #3236 from code-yeongyu/fix/compaction-failure-toast
fix(preemptive-compaction): notify user on failure and reduce timeout
This commit is contained in:
@@ -284,10 +284,57 @@ describe("preemptive-compaction", () => {
|
|||||||
//#then
|
//#then
|
||||||
expect(logMock).toHaveBeenCalledWith("[preemptive-compaction] Compaction failed", {
|
expect(logMock).toHaveBeenCalledWith("[preemptive-compaction] Compaction failed", {
|
||||||
sessionID,
|
sessionID,
|
||||||
|
providerID: "anthropic",
|
||||||
|
modelID: "claude-sonnet-4-6",
|
||||||
error: String(summarizeError),
|
error: String(summarizeError),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #given compaction fails
|
||||||
|
// #when tool.execute.after completes the catch block
|
||||||
|
// #then should show a warning toast explaining the failure to the user
|
||||||
|
it("should show a warning toast when preemptive compaction fails", async () => {
|
||||||
|
//#given
|
||||||
|
const hook = createPreemptiveCompactionHook(ctx as never, {} as never)
|
||||||
|
const sessionID = "ses_toast_on_failure"
|
||||||
|
const summarizeError = new Error("upstream rate limited")
|
||||||
|
ctx.client.session.summarize.mockRejectedValueOnce(summarizeError)
|
||||||
|
|
||||||
|
await hook.event({
|
||||||
|
event: {
|
||||||
|
type: "message.updated",
|
||||||
|
properties: {
|
||||||
|
info: {
|
||||||
|
role: "assistant",
|
||||||
|
sessionID,
|
||||||
|
providerID: "anthropic",
|
||||||
|
modelID: "claude-sonnet-4-6",
|
||||||
|
finish: true,
|
||||||
|
tokens: {
|
||||||
|
input: 170000,
|
||||||
|
output: 0,
|
||||||
|
reasoning: 0,
|
||||||
|
cache: { read: 10000, write: 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
//#when
|
||||||
|
await hook["tool.execute.after"](
|
||||||
|
{ tool: "bash", sessionID, callID: "call_toast" },
|
||||||
|
{ title: "", output: "test", metadata: null },
|
||||||
|
)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(ctx.client.tui.showToast).toHaveBeenCalledTimes(1)
|
||||||
|
const toastCall = ctx.client.tui.showToast.mock.calls[0]?.[0]
|
||||||
|
expect(toastCall?.body?.title).toBe("Preemptive compaction failed")
|
||||||
|
expect(toastCall?.body?.variant).toBe("warning")
|
||||||
|
expect(String(toastCall?.body?.message)).toContain("upstream rate limited")
|
||||||
|
})
|
||||||
|
|
||||||
// #given compaction fails
|
// #given compaction fails
|
||||||
// #when tool.execute.after is called again immediately
|
// #when tool.execute.after is called again immediately
|
||||||
// #then should NOT retry due to cooldown
|
// #then should NOT retry due to cooldown
|
||||||
@@ -475,6 +522,8 @@ describe("preemptive-compaction", () => {
|
|||||||
expect(ctx.client.session.summarize).toHaveBeenCalledTimes(1)
|
expect(ctx.client.session.summarize).toHaveBeenCalledTimes(1)
|
||||||
expect(logMock).toHaveBeenCalledWith("[preemptive-compaction] Compaction failed", {
|
expect(logMock).toHaveBeenCalledWith("[preemptive-compaction] Compaction failed", {
|
||||||
sessionID,
|
sessionID,
|
||||||
|
providerID: "anthropic",
|
||||||
|
modelID: "claude-sonnet-4-6",
|
||||||
error: expect.stringContaining("Compaction summarize timed out"),
|
error: expect.stringContaining("Compaction summarize timed out"),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
import { resolveCompactionModel } from "./shared/compaction-model-resolver"
|
import { resolveCompactionModel } from "./shared/compaction-model-resolver"
|
||||||
import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-degradation-monitor"
|
import { createPostCompactionDegradationMonitor } from "./preemptive-compaction-degradation-monitor"
|
||||||
|
|
||||||
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 120_000
|
const PREEMPTIVE_COMPACTION_TIMEOUT_MS = 60_000
|
||||||
const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78
|
const PREEMPTIVE_COMPACTION_THRESHOLD = 0.78
|
||||||
const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000
|
const PREEMPTIVE_COMPACTION_COOLDOWN_MS = 60_000
|
||||||
|
|
||||||
@@ -134,7 +134,25 @@ export function createPreemptiveCompactionHook(
|
|||||||
|
|
||||||
compactedSessions.add(sessionID)
|
compactedSessions.add(sessionID)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log("[preemptive-compaction] Compaction failed", { sessionID, error: String(error) })
|
log("[preemptive-compaction] Compaction failed", {
|
||||||
|
sessionID,
|
||||||
|
providerID: cached.providerID,
|
||||||
|
modelID: cached.modelID,
|
||||||
|
error: String(error),
|
||||||
|
})
|
||||||
|
ctx.client.tui.showToast({
|
||||||
|
body: {
|
||||||
|
title: "Preemptive compaction failed",
|
||||||
|
message: `Context window is above ${Math.round(PREEMPTIVE_COMPACTION_THRESHOLD * 100)}% and auto-compaction could not run. The session may grow large. Error: ${String(error)}`,
|
||||||
|
variant: "warning",
|
||||||
|
duration: 10000,
|
||||||
|
},
|
||||||
|
}).catch((toastError: unknown) => {
|
||||||
|
log("[preemptive-compaction] Failed to show toast", {
|
||||||
|
sessionID,
|
||||||
|
toastError: String(toastError),
|
||||||
|
})
|
||||||
|
})
|
||||||
} finally {
|
} finally {
|
||||||
compactionInProgress.delete(sessionID)
|
compactionInProgress.delete(sessionID)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user