fix(recovery): ignore empty summary-only assistant messages
This commit is contained in:
@@ -158,7 +158,7 @@ export async function getLastAssistant(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
client: any,
|
||||
directory: string,
|
||||
): Promise<Record<string, unknown> | null> {
|
||||
): Promise<{ info: Record<string, unknown>; hasContent: boolean } | null> {
|
||||
try {
|
||||
const resp = await (client as Client).session.messages({
|
||||
path: { id: sessionID },
|
||||
@@ -175,7 +175,15 @@ export async function getLastAssistant(
|
||||
return info?.role === "assistant"
|
||||
})
|
||||
if (!last) return null
|
||||
return (last as { info?: Record<string, unknown> }).info ?? null
|
||||
|
||||
const message = last as SDKMessage & { info?: Record<string, unknown> }
|
||||
const info = message.info
|
||||
if (!info) return null
|
||||
|
||||
return {
|
||||
info,
|
||||
hasContent: messageHasContentFromSDK(message),
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ import * as originalLogger from "../../shared/logger"
|
||||
|
||||
const executeCompactMock = mock(async () => {})
|
||||
const getLastAssistantMock = mock(async () => ({
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonnet-4-6",
|
||||
info: {
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonnet-4-6",
|
||||
},
|
||||
hasContent: true,
|
||||
}))
|
||||
const parseAnthropicTokenLimitErrorMock = mock(() => ({
|
||||
providerID: "anthropic",
|
||||
@@ -115,4 +118,43 @@ describe("createAnthropicContextWindowLimitRecoveryHook", () => {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
|
||||
test("does not treat empty summary assistant messages as successful compaction", async () => {
|
||||
//#given
|
||||
const { restore, getClearTimeoutCalls } = setupDelayedTimeoutMocks()
|
||||
getLastAssistantMock.mockResolvedValueOnce({
|
||||
info: {
|
||||
summary: true,
|
||||
providerID: "anthropic",
|
||||
modelID: "claude-sonnet-4-6",
|
||||
},
|
||||
hasContent: false,
|
||||
})
|
||||
const { createAnthropicContextWindowLimitRecoveryHook } = await import("./recovery-hook")
|
||||
const hook = createAnthropicContextWindowLimitRecoveryHook(createMockContext())
|
||||
|
||||
try {
|
||||
//#when
|
||||
await hook.event({
|
||||
event: {
|
||||
type: "session.error",
|
||||
properties: { sessionID: "session-empty-summary", error: "prompt is too long" },
|
||||
},
|
||||
})
|
||||
|
||||
await hook.event({
|
||||
event: {
|
||||
type: "session.idle",
|
||||
properties: { sessionID: "session-empty-summary" },
|
||||
},
|
||||
})
|
||||
|
||||
//#then
|
||||
expect(getClearTimeoutCalls()).toEqual([1 as ReturnType<typeof setTimeout>])
|
||||
expect(executeCompactMock).toHaveBeenCalledTimes(1)
|
||||
expect(executeCompactMock.mock.calls[0]?.[0]).toBe("session-empty-summary")
|
||||
} finally {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -72,8 +72,9 @@ export function createAnthropicContextWindowLimitRecoveryHook(
|
||||
}
|
||||
|
||||
const lastAssistant = await getLastAssistant(sessionID, ctx.client, ctx.directory)
|
||||
const providerID = parsed.providerID ?? (lastAssistant?.providerID as string | undefined)
|
||||
const modelID = parsed.modelID ?? (lastAssistant?.modelID as string | undefined)
|
||||
const lastAssistantInfo = lastAssistant?.info
|
||||
const providerID = parsed.providerID ?? (lastAssistantInfo?.providerID as string | undefined)
|
||||
const modelID = parsed.modelID ?? (lastAssistantInfo?.modelID as string | undefined)
|
||||
|
||||
await ctx.client.tui
|
||||
.showToast({
|
||||
@@ -136,14 +137,15 @@ export function createAnthropicContextWindowLimitRecoveryHook(
|
||||
|
||||
const errorData = autoCompactState.errorDataBySession.get(sessionID)
|
||||
const lastAssistant = await getLastAssistant(sessionID, ctx.client, ctx.directory)
|
||||
const lastAssistantInfo = lastAssistant?.info
|
||||
|
||||
if (lastAssistant?.summary === true) {
|
||||
if (lastAssistantInfo?.summary === true && lastAssistant?.hasContent) {
|
||||
autoCompactState.pendingCompact.delete(sessionID)
|
||||
return
|
||||
}
|
||||
|
||||
const providerID = errorData?.providerID ?? (lastAssistant?.providerID as string | undefined)
|
||||
const modelID = errorData?.modelID ?? (lastAssistant?.modelID as string | undefined)
|
||||
const providerID = errorData?.providerID ?? (lastAssistantInfo?.providerID as string | undefined)
|
||||
const modelID = errorData?.modelID ?? (lastAssistantInfo?.modelID as string | undefined)
|
||||
|
||||
await ctx.client.tui
|
||||
.showToast({
|
||||
|
||||
Reference in New Issue
Block a user