- Endpoint: per-API-key model allowlist (schema v3) enforced on chat (403) and /v1/models; Full-access toggle + multi-select picker in Keys UI. - Providers: honor x-connection-id in /v1/chat/completions — pinned requests no longer rotate to another account on failure. - Providers: strategy saves merge into stored enabled:false override; Test All groups match grid sections; 1-by-1 skips disabled connections. - Dashboard: provider-card toggle syncs from server on failure; grid toggles always visible; connection rows get clear-✕ for stale error banners. - Combo editor: on desktop (xl+) the Add-Model picker opens as a floating side panel beside the untouched combo popup instead of stacking on top; mobile keeps the full-screen overlay. - Long API-key overflow fixed in key rows + provider model sections.
42 lines
1.7 KiB
JavaScript
42 lines
1.7 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import { checkFallbackError, getQuotaCooldown } from "../../open-sse/services/accountFallback.js";
|
|
|
|
describe("checkFallbackError — request-scoped errors (P2)", () => {
|
|
it("classifies context-overflow messages as request-scoped: no fallback, no cooldown", () => {
|
|
const msgs = [
|
|
"This model's maximum context length is 16385 tokens",
|
|
"prompt is too long: 250000 tokens > 200000 maximum",
|
|
"input is too long for requested model",
|
|
"Invalid parameter: max_tokens exceed model limit",
|
|
"context_length_exceeded",
|
|
"Please reduce the length of the messages",
|
|
"Your request is too large for the context window",
|
|
];
|
|
for (const message of msgs) {
|
|
const r = checkFallbackError(400, message);
|
|
expect(r.shouldFallback, message).toBe(false);
|
|
expect(r.requestScoped, message).toBe(true);
|
|
expect(r.cooldownMs).toBe(0);
|
|
}
|
|
});
|
|
|
|
it("does NOT classify generic 4xx as request-scoped (legacy transient path preserved)", () => {
|
|
const r = checkFallbackError(400, "Invalid value for 'temperature'");
|
|
expect(r.requestScoped).toBeUndefined();
|
|
expect(r.shouldFallback).toBe(true);
|
|
expect(r.cooldownMs).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("rate-limit text still backs off with fallback", () => {
|
|
const r = checkFallbackError(429, "rate limit exceeded", 0);
|
|
expect(r.shouldFallback).toBe(true);
|
|
expect(r.cooldownMs).toBe(getQuotaCooldown(1));
|
|
});
|
|
|
|
it("no credentials still falls back with long cooldown", () => {
|
|
const r = checkFallbackError(403, "no credentials found for account");
|
|
expect(r.shouldFallback).toBe(true);
|
|
expect(r.cooldownMs).toBe(2 * 60 * 1000);
|
|
});
|
|
});
|