fix(agents): preserve failover assistant fallback

This commit is contained in:
Altay
2026-04-11 18:23:32 +01:00
parent d04e778f90
commit 06a3a82816
2 changed files with 65 additions and 1 deletions

View File

@@ -107,4 +107,68 @@ describe("runEmbeddedPiAgent cross-provider fallback error handling", () => {
}),
);
});
it("falls back to the session assistant when compaction removes the current attempt slice", async () => {
mockedIsFailoverAssistantError.mockImplementation((...args: unknown[]) => {
const assistant = args[0];
return isCurrentAttemptAssistant(assistant) && assistant.provider === "deepseek";
});
mockedIsRateLimitAssistantError.mockImplementation((...args: unknown[]) => {
const assistant = args[0];
return isCurrentAttemptAssistant(assistant) && assistant.provider === "deepseek";
});
let lastFormattedAssistant: unknown;
mockedFormatAssistantErrorText.mockImplementation((...args: unknown[]) => {
lastFormattedAssistant = args[0];
if (!isCurrentAttemptAssistant(lastFormattedAssistant)) {
return String(lastFormattedAssistant);
}
return `${lastFormattedAssistant.provider}/${lastFormattedAssistant.model}: ${lastFormattedAssistant.errorMessage}`;
});
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
makeAttemptResult({
assistantTexts: [],
lastAssistant: makeAssistantMessageFixture({
stopReason: "error",
errorMessage: "429 deepseek rate limit",
provider: "deepseek",
model: "deepseek-chat",
content: [],
}),
currentAttemptAssistant: undefined,
}),
);
const promise = runEmbeddedPiAgent({
...overflowBaseRunParams,
runId: "run-compaction-fallback-error-context",
config: makeModelFallbackCfg({
agents: {
defaults: {
model: {
primary: "openai-codex/gpt-5.4",
fallbacks: ["deepseek/deepseek-chat", "google/gemini-2.5-flash"],
},
},
},
}),
});
await expect(promise).rejects.toBeInstanceOf(MockedFailoverError);
await expect(promise).rejects.toThrow("deepseek/deepseek-chat: 429 deepseek rate limit");
expect(mockedIsRateLimitAssistantError).toHaveBeenCalledWith(
expect.objectContaining({
provider: "deepseek",
model: "deepseek-chat",
errorMessage: "429 deepseek rate limit",
}),
);
expect(lastFormattedAssistant).toEqual(
expect.objectContaining({
provider: "deepseek",
model: "deepseek-chat",
errorMessage: "429 deepseek rate limit",
}),
);
});
});

View File

@@ -1340,7 +1340,7 @@ export async function runEmbeddedPiAgent(
throw promptError;
}
const assistantForFailover = currentAttemptAssistant;
const assistantForFailover = currentAttemptAssistant ?? sessionLastAssistant;
const fallbackThinking = pickFallbackThinkingLevel({
message: assistantForFailover?.errorMessage,
attempted: attemptedThinking,