200 lines
6.4 KiB
TypeScript
200 lines
6.4 KiB
TypeScript
// tests/unit/combo/auto-quota-cutoff.test.ts
|
|
// Regression coverage for auto routing quota cutoff: hard-cutoff candidates must be
|
|
// removed before scoring/fallback so an exhausted account cannot win by latency/model fit.
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { scoreAutoTargets } from "../../../open-sse/services/combo/autoStrategy.ts";
|
|
import { getConnectionStatusQuotaCutoffReason } from "../../../open-sse/services/combo.ts";
|
|
import type {
|
|
AutoProviderCandidate,
|
|
ResolvedComboTarget,
|
|
} from "../../../open-sse/services/combo/types.ts";
|
|
import type { ScoringWeights } from "../../../open-sse/services/autoCombo/scoring.ts";
|
|
|
|
const latencyOnlyWeights: ScoringWeights = {
|
|
quota: 0,
|
|
health: 0,
|
|
costInv: 0,
|
|
latencyInv: 1,
|
|
taskFit: 0,
|
|
stability: 0,
|
|
tierPriority: 0,
|
|
tierAffinity: 0,
|
|
specificityMatch: 0,
|
|
contextAffinity: 0,
|
|
resetWindowAffinity: 0,
|
|
connectionDensity: 0,
|
|
};
|
|
|
|
function target(provider: string, model: string, connectionId: string): ResolvedComboTarget {
|
|
return {
|
|
kind: "model",
|
|
stepId: `${provider}-${model}-${connectionId}`,
|
|
executionKey: `${provider}/${model}@${connectionId}`,
|
|
modelStr: `${provider}/${model}`,
|
|
provider,
|
|
providerId: null,
|
|
connectionId,
|
|
} as ResolvedComboTarget;
|
|
}
|
|
|
|
function candidate(
|
|
provider: string,
|
|
model: string,
|
|
connectionId: string,
|
|
overrides: Partial<AutoProviderCandidate> = {}
|
|
): AutoProviderCandidate {
|
|
return {
|
|
provider,
|
|
model,
|
|
stepId: `${provider}-${model}-${connectionId}`,
|
|
executionKey: `${provider}/${model}@${connectionId}`,
|
|
modelStr: `${provider}/${model}`,
|
|
connectionId,
|
|
quotaRemaining: 100,
|
|
quotaTotal: 100,
|
|
circuitBreakerState: "CLOSED",
|
|
costPer1MTokens: 1,
|
|
p95LatencyMs: 1000,
|
|
latencyStdDev: 10,
|
|
errorRate: 0,
|
|
resetWindowAffinity: 0.5,
|
|
connectionPoolSize: 1,
|
|
...overrides,
|
|
} as AutoProviderCandidate;
|
|
}
|
|
|
|
test("auto scoring skips GLM when its 2% remaining quota hit the hard cutoff", () => {
|
|
const targets = [target("glm", "glm-5.2", "glm-empty"), target("mcode", "mimo-auto", "mcode-ok")];
|
|
const ranked = scoreAutoTargets(
|
|
targets,
|
|
[
|
|
candidate("glm", "glm-5.2", "glm-empty", {
|
|
quotaRemaining: 2,
|
|
p95LatencyMs: 10,
|
|
quotaCutoffBlocked: true,
|
|
quotaCutoffReason: "quota_exhausted",
|
|
}),
|
|
candidate("mcode", "mimo-auto", "mcode-ok", {
|
|
quotaRemaining: 100,
|
|
p95LatencyMs: 5000,
|
|
}),
|
|
],
|
|
"coding",
|
|
latencyOnlyWeights
|
|
);
|
|
|
|
assert.equal(ranked.length, 1);
|
|
assert.equal(ranked[0]?.target.provider, "mcode");
|
|
assert.equal(ranked[0]?.target.connectionId, "mcode-ok");
|
|
});
|
|
|
|
test("blocked quota candidates are not included in the scoring pool", () => {
|
|
const targets = [
|
|
target("fast", "healthy", "fast-ok"),
|
|
target("slow", "healthy", "slow-ok"),
|
|
target("glm", "glm-5.2", "glm-empty"),
|
|
];
|
|
const ranked = scoreAutoTargets(
|
|
targets,
|
|
[
|
|
candidate("fast", "healthy", "fast-ok", { p95LatencyMs: 100 }),
|
|
candidate("slow", "healthy", "slow-ok", { p95LatencyMs: 1000 }),
|
|
candidate("glm", "glm-5.2", "glm-empty", {
|
|
quotaRemaining: 0,
|
|
p95LatencyMs: 10000,
|
|
quotaCutoffBlocked: true,
|
|
quotaCutoffReason: "quota_exhausted",
|
|
}),
|
|
],
|
|
"coding",
|
|
latencyOnlyWeights
|
|
);
|
|
|
|
assert.deepEqual(
|
|
ranked.map((entry) => entry.target.provider),
|
|
["fast", "slow"]
|
|
);
|
|
const slowScore = ranked.find((entry) => entry.target.provider === "slow")?.score;
|
|
assert.equal(
|
|
slowScore,
|
|
0,
|
|
"the blocked GLM latency must not inflate surviving candidates' scores"
|
|
);
|
|
});
|
|
|
|
test("connection terminal status maps to quota cutoff reason", () => {
|
|
assert.equal(
|
|
getConnectionStatusQuotaCutoffReason({ testStatus: "credits_exhausted" }),
|
|
"credits_exhausted"
|
|
);
|
|
assert.equal(getConnectionStatusQuotaCutoffReason({ testStatus: "expired" }), "expired");
|
|
assert.equal(getConnectionStatusQuotaCutoffReason({ testStatus: "active" }), undefined);
|
|
});
|
|
|
|
test("future unavailable connection maps to rate_limited quota cutoff reason", () => {
|
|
assert.equal(
|
|
getConnectionStatusQuotaCutoffReason({
|
|
testStatus: "unavailable",
|
|
rateLimitedUntil: new Date(Date.now() + 60_000).toISOString(),
|
|
}),
|
|
"rate_limited"
|
|
);
|
|
assert.equal(
|
|
getConnectionStatusQuotaCutoffReason({
|
|
testStatus: "unavailable",
|
|
rateLimitedUntil: new Date(Date.now() - 60_000).toISOString(),
|
|
}),
|
|
undefined
|
|
);
|
|
});
|
|
|
|
test("status-blocked candidates are removed before auto scoring", () => {
|
|
const targets = [
|
|
target("puter", "fast-free", "puter-empty"),
|
|
target("cerebras", "healthy", "cerebras-ok"),
|
|
];
|
|
const ranked = scoreAutoTargets(
|
|
targets,
|
|
[
|
|
candidate("puter", "fast-free", "puter-empty", {
|
|
quotaRemaining: 0,
|
|
p95LatencyMs: 5,
|
|
quotaCutoffBlocked: true,
|
|
quotaCutoffReason: "credits_exhausted",
|
|
}),
|
|
candidate("cerebras", "healthy", "cerebras-ok", {
|
|
quotaRemaining: 100,
|
|
p95LatencyMs: 5000,
|
|
}),
|
|
],
|
|
"coding",
|
|
latencyOnlyWeights
|
|
);
|
|
|
|
assert.equal(ranked.length, 1);
|
|
assert.equal(ranked[0]?.target.provider, "cerebras");
|
|
});
|
|
|
|
// --- Maintainer gate (#4592 review): terminal-status cutoff is opt-in (#4483) ---
|
|
// buildAutoCandidates only marks a terminal-status connection as quotaCutoffBlocked
|
|
// when the quota-cutoff opt-in is enabled. With the opt-in OFF, the connection must
|
|
// fall through to normal connection-cooldown / model-lockout handling instead of being
|
|
// hard-excluded here (which would surface a misleading "below quota cutoff" 429 when
|
|
// every candidate is merely transiently unavailable). This locks the gating expression
|
|
// `quotaCutoffEnabled ? getConnectionStatusQuotaCutoffReason(conn) : undefined`
|
|
// against accidental removal.
|
|
test("terminal-status cutoff is consulted only when quota cutoff is enabled", () => {
|
|
const terminalConn = { testStatus: "credits_exhausted" };
|
|
|
|
// Helper itself still classifies the terminal status (unchanged).
|
|
assert.equal(getConnectionStatusQuotaCutoffReason(terminalConn), "credits_exhausted");
|
|
|
|
// The gate: enabled → reason flows through; disabled → suppressed (fall-through).
|
|
const gated = (enabled: boolean) =>
|
|
enabled ? getConnectionStatusQuotaCutoffReason(terminalConn) : undefined;
|
|
|
|
assert.equal(gated(true), "credits_exhausted", "enabled: terminal status blocks the candidate");
|
|
assert.equal(gated(false), undefined, "disabled: terminal status must NOT pre-block (opt-in)");
|
|
});
|