fix: include provider and model name in billing error message (#20510)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 40dbdf62e8
Co-authored-by: echoVic <16428813+echoVic@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
青雲
2026-02-19 10:56:00 +08:00
committed by GitHub
parent 2bb8ead187
commit 3d4ef56044
9 changed files with 141 additions and 15 deletions

View File

@@ -518,6 +518,59 @@ describe("runEmbeddedPiAgent auth profile rotation", () => {
}
});
it("uses the active erroring model in billing failover errors", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-agent-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-workspace-"));
try {
await writeAuthStore(agentDir);
runEmbeddedAttemptMock.mockResolvedValueOnce(
makeAttempt({
assistantTexts: [],
lastAssistant: buildAssistant({
stopReason: "error",
errorMessage: "insufficient credits",
provider: "openai",
model: "mock-rotated",
}),
}),
);
let thrown: unknown;
try {
await runEmbeddedPiAgent({
sessionId: "session:test",
sessionKey: "agent:test:billing-failover-active-model",
sessionFile: path.join(workspaceDir, "session.jsonl"),
workspaceDir,
agentDir,
config: makeConfig({ fallbacks: ["openai/mock-2"] }),
prompt: "hello",
provider: "openai",
model: "mock-1",
authProfileId: "openai:p1",
authProfileIdSource: "user",
timeoutMs: 5_000,
runId: "run:billing-failover-active-model",
});
} catch (err) {
thrown = err;
}
expect(thrown).toMatchObject({
name: "FailoverError",
reason: "billing",
provider: "openai",
model: "mock-rotated",
});
expect(thrown).toBeInstanceOf(Error);
expect((thrown as Error).message).toContain("openai (mock-rotated) returned a billing error");
expect(runEmbeddedAttemptMock).toHaveBeenCalledTimes(1);
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
await fs.rm(workspaceDir, { recursive: true, force: true });
}
});
it("skips profiles in cooldown when rotating after failure", async () => {
vi.useFakeTimers();
try {