Detect runtime retry signals from assistant text parts
This commit is contained in:
committed by
YeonGyu-Kim
parent
56396a8dc2
commit
b12aeaa512
@@ -387,6 +387,92 @@ describe("runtime-fallback", () => {
|
|||||||
expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-6" })
|
expect(fallbackLog?.data).toMatchObject({ from: "openai/gpt-5.3-codex", to: "anthropic/claude-opus-4-6" })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("should trigger fallback on auto-retry signal in assistant text parts", async () => {
|
||||||
|
const hook = createRuntimeFallbackHook(createMockPluginInput(), {
|
||||||
|
config: createMockConfig({ notify_on_fallback: false }),
|
||||||
|
pluginConfig: createMockPluginConfigWithCategoryFallback(["openai/gpt-5.2"]),
|
||||||
|
})
|
||||||
|
|
||||||
|
const sessionID = "test-session-parts-auto-retry"
|
||||||
|
SessionCategoryRegistry.register(sessionID, "test")
|
||||||
|
|
||||||
|
await hook.event({
|
||||||
|
event: {
|
||||||
|
type: "session.created",
|
||||||
|
properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await hook.event({
|
||||||
|
event: {
|
||||||
|
type: "message.updated",
|
||||||
|
properties: {
|
||||||
|
info: {
|
||||||
|
sessionID,
|
||||||
|
role: "assistant",
|
||||||
|
model: "quotio/claude-opus-4-6",
|
||||||
|
},
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: "This request would exceed your account's rate limit. Please try again later. [retrying in 2s attempt #2]",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const signalLog = logCalls.find((c) => c.msg.includes("Detected provider auto-retry signal"))
|
||||||
|
expect(signalLog).toBeDefined()
|
||||||
|
|
||||||
|
const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback"))
|
||||||
|
expect(fallbackLog).toBeDefined()
|
||||||
|
expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should trigger fallback when auto-retry text parts are nested under info.parts", async () => {
|
||||||
|
const hook = createRuntimeFallbackHook(createMockPluginInput(), {
|
||||||
|
config: createMockConfig({ notify_on_fallback: false }),
|
||||||
|
pluginConfig: createMockPluginConfigWithCategoryFallback(["openai/gpt-5.2"]),
|
||||||
|
})
|
||||||
|
|
||||||
|
const sessionID = "test-session-info-parts-auto-retry"
|
||||||
|
SessionCategoryRegistry.register(sessionID, "test")
|
||||||
|
|
||||||
|
await hook.event({
|
||||||
|
event: {
|
||||||
|
type: "session.created",
|
||||||
|
properties: { info: { id: sessionID, model: "quotio/claude-opus-4-6" } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await hook.event({
|
||||||
|
event: {
|
||||||
|
type: "message.updated",
|
||||||
|
properties: {
|
||||||
|
info: {
|
||||||
|
sessionID,
|
||||||
|
role: "assistant",
|
||||||
|
model: "quotio/claude-opus-4-6",
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: "This request would exceed your account's rate limit. Please try again later. [retrying in 2s attempt #2]",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const signalLog = logCalls.find((c) => c.msg.includes("Detected provider auto-retry signal"))
|
||||||
|
expect(signalLog).toBeDefined()
|
||||||
|
|
||||||
|
const fallbackLog = logCalls.find((c) => c.msg.includes("Preparing fallback"))
|
||||||
|
expect(fallbackLog).toBeDefined()
|
||||||
|
expect(fallbackLog?.data).toMatchObject({ from: "quotio/claude-opus-4-6", to: "openai/gpt-5.2" })
|
||||||
|
})
|
||||||
|
|
||||||
test("should trigger fallback on session.status auto-retry signal", async () => {
|
test("should trigger fallback on session.status auto-retry signal", async () => {
|
||||||
const promptCalls: unknown[] = []
|
const promptCalls: unknown[] = []
|
||||||
const hook = createRuntimeFallbackHook(
|
const hook = createRuntimeFallbackHook(
|
||||||
|
|||||||
@@ -57,10 +57,20 @@ export function createMessageUpdateHandler(deps: HookDeps, helpers: AutoRetryHel
|
|||||||
return async (props: Record<string, unknown> | undefined) => {
|
return async (props: Record<string, unknown> | undefined) => {
|
||||||
const info = props?.info as Record<string, unknown> | undefined
|
const info = props?.info as Record<string, unknown> | undefined
|
||||||
const sessionID = info?.sessionID as string | undefined
|
const sessionID = info?.sessionID as string | undefined
|
||||||
const retrySignalResult = extractAutoRetrySignal(info)
|
|
||||||
const retrySignal = retrySignalResult?.signal
|
|
||||||
const timeoutEnabled = config.timeout_seconds > 0
|
const timeoutEnabled = config.timeout_seconds > 0
|
||||||
const parts = props?.parts as Array<{ type?: string; text?: string }> | undefined
|
const eventParts = props?.parts as Array<{ type?: string; text?: string }> | undefined
|
||||||
|
const infoParts = info?.parts as Array<{ type?: string; text?: string }> | undefined
|
||||||
|
const parts = eventParts && eventParts.length > 0 ? eventParts : infoParts
|
||||||
|
const retrySignalResult = extractAutoRetrySignal(info)
|
||||||
|
const partsText = (parts ?? [])
|
||||||
|
.filter((p) => typeof p?.text === "string")
|
||||||
|
.map((p) => (p.text ?? "").trim())
|
||||||
|
.filter((text) => text.length > 0)
|
||||||
|
.join("\n")
|
||||||
|
const retrySignalFromParts = partsText
|
||||||
|
? extractAutoRetrySignal({ message: partsText, status: partsText, summary: partsText })?.signal
|
||||||
|
: undefined
|
||||||
|
const retrySignal = retrySignalResult?.signal ?? retrySignalFromParts
|
||||||
const errorContentResult = containsErrorContent(parts)
|
const errorContentResult = containsErrorContent(parts)
|
||||||
const error = info?.error ??
|
const error = info?.error ??
|
||||||
(retrySignal && timeoutEnabled ? { name: "ProviderRateLimitError", message: retrySignal } : undefined) ??
|
(retrySignal && timeoutEnabled ? { name: "ProviderRateLimitError", message: retrySignal } : undefined) ??
|
||||||
|
|||||||
Reference in New Issue
Block a user