77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const {
|
|
classifyModelScope429,
|
|
getModelScopeRetryDelayMs,
|
|
isModelScopeProvider,
|
|
parseModelScopeRateLimitHeaders,
|
|
} = await import("../../open-sse/services/modelscopePolicy.ts");
|
|
const { normalizeHeaders } = await import("../../open-sse/utils/headers.ts");
|
|
|
|
test("ModelScope policy detects provider ids and ModelScope host markers", () => {
|
|
assert.equal(isModelScopeProvider("modelscope"), true);
|
|
assert.equal(
|
|
isModelScopeProvider("openai-compatible-custom", {
|
|
baseUrl: "https://api-inference.modelscope.cn/v1",
|
|
}),
|
|
true
|
|
);
|
|
assert.equal(isModelScopeProvider("openai", { baseUrl: "https://api.openai.com/v1" }), false);
|
|
});
|
|
|
|
test("ModelScope policy parses per-model and total rate-limit headers", () => {
|
|
const snapshot = parseModelScopeRateLimitHeaders({
|
|
"modelscope-ratelimit-model-requests-remaining": "0",
|
|
"modelscope-ratelimit-model-requests-limit": "10",
|
|
"modelscope-ratelimit-requests-remaining": "17",
|
|
"modelscope-ratelimit-requests-limit": "20",
|
|
});
|
|
|
|
assert.deepEqual(snapshot, {
|
|
modelRemaining: 0,
|
|
modelLimit: 10,
|
|
totalRemaining: 17,
|
|
totalLimit: 20,
|
|
});
|
|
});
|
|
|
|
test("ModelScope policy keeps temporary 429 headers retryable", () => {
|
|
const decision = classifyModelScope429(
|
|
"Throttling: current batch requests reached the limit",
|
|
{
|
|
"modelscope-ratelimit-model-requests-remaining": "0",
|
|
"modelscope-ratelimit-model-requests-limit": "10",
|
|
}
|
|
);
|
|
|
|
assert.equal(decision.kind, "rate_limited");
|
|
assert.equal(decision.retryable, true);
|
|
assert.equal(decision.snapshot.modelRemaining, 0);
|
|
});
|
|
|
|
test("ModelScope policy treats explicit free quota exhaustion as terminal", () => {
|
|
const decision = classifyModelScope429("Free allocated quota exceeded", {});
|
|
|
|
assert.equal(decision.kind, "quota_exhausted");
|
|
assert.equal(decision.retryable, false);
|
|
});
|
|
|
|
test("ModelScope retry delay respects Retry-After seconds before backoff fallback", () => {
|
|
assert.equal(getModelScopeRetryDelayMs({ "retry-after": "2.5" }, 0), 2500);
|
|
assert.equal(getModelScopeRetryDelayMs({}, 1), 6000);
|
|
});
|
|
|
|
test("ModelScope policy accepts headers normalized via normalizeHeaders (Node 24 undici interop)", () => {
|
|
// Simulate a Headers object from a different undici instance via the helper.
|
|
const upstreamHeaders = new Headers({
|
|
"modelscope-ratelimit-model-requests-remaining": "3",
|
|
"retry-after": "1.5",
|
|
});
|
|
const normalized = normalizeHeaders(upstreamHeaders);
|
|
|
|
const snapshot = parseModelScopeRateLimitHeaders(normalized);
|
|
assert.equal(snapshot.modelRemaining, 3);
|
|
assert.equal(getModelScopeRetryDelayMs(normalized, 0), 1500);
|
|
});
|