Merge pull request #1649 from code-yeongyu/feat/anthropic-prefill-recovery
feat: auto-recover from Anthropic assistant message prefill errors
This commit is contained in:
commit
d0bdf521c3
@ -129,6 +129,63 @@ describe("detectErrorType", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("assistant_prefill_unsupported errors", () => {
|
||||||
|
it("should detect assistant message prefill error from direct message", () => {
|
||||||
|
//#given an error about assistant message prefill not being supported
|
||||||
|
const error = {
|
||||||
|
message: "This model does not support assistant message prefill. The conversation must end with a user message.",
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when detectErrorType is called
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then should return assistant_prefill_unsupported
|
||||||
|
expect(result).toBe("assistant_prefill_unsupported")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should detect assistant message prefill error from nested error object", () => {
|
||||||
|
//#given an Anthropic API error with nested structure matching the real error format
|
||||||
|
const error = {
|
||||||
|
error: {
|
||||||
|
type: "invalid_request_error",
|
||||||
|
message: "This model does not support assistant message prefill. The conversation must end with a user message.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when detectErrorType is called
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then should return assistant_prefill_unsupported
|
||||||
|
expect(result).toBe("assistant_prefill_unsupported")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should detect error with only 'conversation must end with a user message' fragment", () => {
|
||||||
|
//#given an error containing only the user message requirement
|
||||||
|
const error = {
|
||||||
|
message: "The conversation must end with a user message.",
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when detectErrorType is called
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then should return assistant_prefill_unsupported
|
||||||
|
expect(result).toBe("assistant_prefill_unsupported")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should detect error with only 'assistant message prefill' fragment", () => {
|
||||||
|
//#given an error containing only the prefill mention
|
||||||
|
const error = {
|
||||||
|
message: "This model does not support assistant message prefill.",
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when detectErrorType is called
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then should return assistant_prefill_unsupported
|
||||||
|
expect(result).toBe("assistant_prefill_unsupported")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("unrecognized errors", () => {
|
describe("unrecognized errors", () => {
|
||||||
it("should return null for unrecognized error patterns", () => {
|
it("should return null for unrecognized error patterns", () => {
|
||||||
// given an unrelated error
|
// given an unrelated error
|
||||||
|
|||||||
@ -28,6 +28,7 @@ type RecoveryErrorType =
|
|||||||
| "tool_result_missing"
|
| "tool_result_missing"
|
||||||
| "thinking_block_order"
|
| "thinking_block_order"
|
||||||
| "thinking_disabled_violation"
|
| "thinking_disabled_violation"
|
||||||
|
| "assistant_prefill_unsupported"
|
||||||
| null
|
| null
|
||||||
|
|
||||||
interface MessageInfo {
|
interface MessageInfo {
|
||||||
@ -126,6 +127,13 @@ function extractMessageIndex(error: unknown): number | null {
|
|||||||
export function detectErrorType(error: unknown): RecoveryErrorType {
|
export function detectErrorType(error: unknown): RecoveryErrorType {
|
||||||
const message = getErrorMessage(error)
|
const message = getErrorMessage(error)
|
||||||
|
|
||||||
|
if (
|
||||||
|
message.includes("assistant message prefill") ||
|
||||||
|
message.includes("conversation must end with a user message")
|
||||||
|
) {
|
||||||
|
return "assistant_prefill_unsupported"
|
||||||
|
}
|
||||||
|
|
||||||
// IMPORTANT: Check thinking_block_order BEFORE tool_result_missing
|
// IMPORTANT: Check thinking_block_order BEFORE tool_result_missing
|
||||||
// because Anthropic's extended thinking error messages contain "tool_use" and "tool_result"
|
// because Anthropic's extended thinking error messages contain "tool_use" and "tool_result"
|
||||||
// in the documentation URL, which would incorrectly match tool_result_missing
|
// in the documentation URL, which would incorrectly match tool_result_missing
|
||||||
@ -375,11 +383,13 @@ export function createSessionRecoveryHook(ctx: PluginInput, options?: SessionRec
|
|||||||
tool_result_missing: "Tool Crash Recovery",
|
tool_result_missing: "Tool Crash Recovery",
|
||||||
thinking_block_order: "Thinking Block Recovery",
|
thinking_block_order: "Thinking Block Recovery",
|
||||||
thinking_disabled_violation: "Thinking Strip Recovery",
|
thinking_disabled_violation: "Thinking Strip Recovery",
|
||||||
|
assistant_prefill_unsupported: "Prefill Error Recovery",
|
||||||
}
|
}
|
||||||
const toastMessages: Record<RecoveryErrorType & string, string> = {
|
const toastMessages: Record<RecoveryErrorType & string, string> = {
|
||||||
tool_result_missing: "Injecting cancelled tool results...",
|
tool_result_missing: "Injecting cancelled tool results...",
|
||||||
thinking_block_order: "Fixing message structure...",
|
thinking_block_order: "Fixing message structure...",
|
||||||
thinking_disabled_violation: "Stripping thinking blocks...",
|
thinking_disabled_violation: "Stripping thinking blocks...",
|
||||||
|
assistant_prefill_unsupported: "Sending 'Continue' to recover...",
|
||||||
}
|
}
|
||||||
|
|
||||||
await ctx.client.tui
|
await ctx.client.tui
|
||||||
@ -411,6 +421,8 @@ export function createSessionRecoveryHook(ctx: PluginInput, options?: SessionRec
|
|||||||
const resumeConfig = extractResumeConfig(lastUser, sessionID)
|
const resumeConfig = extractResumeConfig(lastUser, sessionID)
|
||||||
await resumeSession(ctx.client, resumeConfig)
|
await resumeSession(ctx.client, resumeConfig)
|
||||||
}
|
}
|
||||||
|
} else if (errorType === "assistant_prefill_unsupported") {
|
||||||
|
success = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user