1bcf08c27f
- Classified model_not_available_for_integrator as a permanent entitlement denial instead of transient fleet skew. - Preserved the provider response and Available models list while retaining model_not_supported fleet retries. Fixes #7819
74 lines
2.9 KiB
TypeScript
74 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "bun:test";
|
|
import { rewriteCopilotError } from "@oh-my-pi/pi-ai/utils/http-inspector";
|
|
|
|
function errorWithStatus(
|
|
status: number,
|
|
options: { message?: string; code?: string } = {},
|
|
): Error & { status: number; code?: string } {
|
|
return Object.assign(new Error(options.message ?? `${status} Unauthorized`), {
|
|
status,
|
|
...(options.code === undefined ? {} : { code: options.code }),
|
|
});
|
|
}
|
|
|
|
describe("rewriteCopilotError", () => {
|
|
it("returns original message for non-copilot providers", () => {
|
|
const err = errorWithStatus(401);
|
|
expect(rewriteCopilotError("some error", err, "openai")).toBe("some error");
|
|
});
|
|
|
|
it("returns original message for non-401/403 errors", () => {
|
|
const err = errorWithStatus(500);
|
|
expect(rewriteCopilotError("server error", err, "github-copilot")).toBe("server error");
|
|
});
|
|
|
|
it("rewrites message for 401 with github-copilot provider", () => {
|
|
const err = errorWithStatus(401);
|
|
const result = rewriteCopilotError("401 Unauthorized: ...", err, "github-copilot");
|
|
expect(result).toContain("GitHub Copilot authentication failed (HTTP 401)");
|
|
expect(result).toContain("/login github-copilot");
|
|
});
|
|
|
|
it("rewrites 403 with access-denied message (not auth-failed, to avoid credential removal)", () => {
|
|
const err = errorWithStatus(403);
|
|
const result = rewriteCopilotError("403 Forbidden", err, "github-copilot");
|
|
expect(result).toContain("GitHub Copilot access denied (HTTP 403)");
|
|
expect(result).not.toContain("GitHub Copilot authentication failed");
|
|
expect(result).not.toContain("/login github-copilot");
|
|
});
|
|
|
|
it("rewrites 400 model_not_supported with fleet-skew guidance", () => {
|
|
const err = errorWithStatus(400, {
|
|
message: "400 The requested model is not supported.",
|
|
code: "model_not_supported",
|
|
});
|
|
const result = rewriteCopilotError("original", err, "github-copilot");
|
|
expect(result).toContain("HTTP 400");
|
|
expect(result).toContain("only part of its fleet");
|
|
expect(result).not.toContain("authentication failed");
|
|
});
|
|
|
|
it("preserves per-integrator entitlement details and available models", () => {
|
|
const message =
|
|
'400 The requested model is not available for integrator "opencode". Available models: [gpt-4.1 claude-opus-4.7 gpt-5.5]';
|
|
const err = errorWithStatus(400, { message, code: "model_not_available_for_integrator" });
|
|
expect(rewriteCopilotError(message, err, "github-copilot")).toBe(message);
|
|
});
|
|
|
|
it("leaves non-copilot 400 model_not_supported untouched", () => {
|
|
const err = errorWithStatus(400, {
|
|
message: "400 model_not_supported",
|
|
code: "model_not_supported",
|
|
});
|
|
expect(rewriteCopilotError("orig", err, "openai")).toBe("orig");
|
|
});
|
|
|
|
it("leaves 400 without model_not_supported code untouched", () => {
|
|
const err = errorWithStatus(400, {
|
|
message: "400 invalid request",
|
|
code: "invalid_request_body",
|
|
});
|
|
expect(rewriteCopilotError("orig", err, "github-copilot")).toBe("orig");
|
|
});
|
|
});
|