mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 01:32:22 +03:00
Compare commits
5 Commits
feat/9490-
...
fix/releas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f9cfc4638 | ||
|
|
b87b232267 | ||
|
|
2cac57f39b | ||
|
|
599c880ac5 | ||
|
|
41dc3781cf |
@@ -121,6 +121,9 @@ export const PACK_ARTIFACT_ROOT_ALLOWED_EXACT_PATHS: string[] = [
|
||||
// shipped via package.json "files", so it must be allowed in the tarball.
|
||||
"open-sse/utils/setupPolyfill.ts",
|
||||
"package.json",
|
||||
"scripts/build/assembleStandalone.mjs",
|
||||
"scripts/build/backendOnlyPages.mjs",
|
||||
"scripts/build/build-tproxy-native.mjs",
|
||||
"scripts/build/build-next-isolated.mjs",
|
||||
"scripts/check/check-supported-node-runtime.ts",
|
||||
"scripts/build/native-binary-compat.mjs",
|
||||
|
||||
@@ -10191,6 +10191,8 @@
|
||||
"copied": "Copied!",
|
||||
"run": "Run",
|
||||
"running": "Running...",
|
||||
"loading": "Loading...",
|
||||
"retry": "Retry",
|
||||
"response": "Response",
|
||||
"tunnel": "Tunnel",
|
||||
"send": "Send",
|
||||
|
||||
@@ -10191,6 +10191,8 @@
|
||||
"copied": "Copiado!",
|
||||
"run": "Executar",
|
||||
"running": "Executando...",
|
||||
"loading": "Carregando...",
|
||||
"retry": "Tentar novamente",
|
||||
"response": "Resposta",
|
||||
"tunnel": "Tunnel",
|
||||
"send": "Enviar",
|
||||
|
||||
@@ -10191,6 +10191,8 @@
|
||||
"copied": "Đã sao chép!",
|
||||
"run": "Chạy",
|
||||
"running": "Đang chạy...",
|
||||
"loading": "Đang tải...",
|
||||
"retry": "Thử lại",
|
||||
"response": "Phản hồi",
|
||||
"tunnel": "Đường hầm",
|
||||
"send": "Gửi",
|
||||
|
||||
@@ -17,12 +17,6 @@ import { getDbInstance } from "./core";
|
||||
const quotaComboMaintenance = new Map<string, Promise<unknown>>();
|
||||
const deletingPools = new Set<string>();
|
||||
|
||||
/** Reset module-level state for test isolation. Call in test.after() hooks. */
|
||||
export function resetQuotaPoolsModuleState(): void {
|
||||
deletingPools.clear();
|
||||
quotaComboMaintenance.clear();
|
||||
}
|
||||
|
||||
function serializeQuotaComboMaintenance<T>(
|
||||
poolId: string,
|
||||
operation: () => Promise<T>
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"tests/unit/anthropic-thinking-signature-recovery.test.ts",
|
||||
"tests/unit/antigravity-429-quota-tdd.test.ts",
|
||||
"tests/unit/antigravity-prefer-stored-project.test.ts",
|
||||
"tests/unit/api-key-policy-noauth-allowed-connections.test.ts",
|
||||
"tests/unit/api-key-rotator-health.test.ts",
|
||||
"tests/unit/appearance-widget-settings-schema.test.ts",
|
||||
"tests/unit/auth-antigravity-account-retry-v2.test.ts",
|
||||
@@ -213,6 +214,7 @@
|
||||
"tests/unit/executor-web-cookie-sweep.test.ts",
|
||||
"tests/unit/format-provider-error-cause.test.ts",
|
||||
"tests/unit/forwarded-header-budget.test.ts",
|
||||
"tests/unit/gemini-web-capabilities-9356.test.ts",
|
||||
"tests/unit/gemini-web-missing-browser-3516.test.ts",
|
||||
"tests/unit/grok-cli-oauth.test.ts",
|
||||
"tests/unit/guardrails-api-3496.test.ts",
|
||||
@@ -273,6 +275,7 @@
|
||||
"tests/unit/rate-limit-manager.test.ts",
|
||||
"tests/unit/rate-limit-queue-timeout-lockout.test.ts",
|
||||
"tests/unit/repro-7503-no-choices.test.ts",
|
||||
"tests/unit/repro-9486.test.ts",
|
||||
"tests/unit/repro-9630-combo-false-503.test.ts",
|
||||
"tests/unit/repro-antigravity-404-family-cooldown-hijack.test.ts",
|
||||
"tests/unit/responses-handler.test.ts",
|
||||
|
||||
@@ -255,10 +255,7 @@ test("buildAdobeImagePayload attaches referenceBlobs like live adobe_atach_image
|
||||
{ id: "2a4f1025-e0dc-4671-a11a-7dfd3c07bd94", usage: "general" },
|
||||
{ id: "84c11d1a-e798-4300-a63e-c06504ca2068", usage: "general" },
|
||||
]);
|
||||
assert.equal(
|
||||
(nano.generationMetadata as Record<string, unknown>).module,
|
||||
"text2image"
|
||||
);
|
||||
assert.equal((nano.generationMetadata as Record<string, unknown>).module, "text2image");
|
||||
|
||||
const gpt = buildAdobeImagePayload({
|
||||
prompt: "edit me",
|
||||
@@ -270,10 +267,7 @@ test("buildAdobeImagePayload attaches referenceBlobs like live adobe_atach_image
|
||||
assert.deepEqual(gpt.referenceBlobs, [
|
||||
{ id: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee", usage: "subject" },
|
||||
]);
|
||||
assert.equal(
|
||||
(gpt.generationMetadata as Record<string, unknown>).module,
|
||||
"image2image"
|
||||
);
|
||||
assert.equal((gpt.generationMetadata as Record<string, unknown>).module, "image2image");
|
||||
|
||||
// gpt-image: only first 2 subject refs survive (extra screenshots hang colligo).
|
||||
const gptMany = buildAdobeImagePayload({
|
||||
@@ -312,10 +306,7 @@ test("adobeFireflyMaxImageRefs + adaptive image timeout", () => {
|
||||
DEFAULT_IMAGE_TIMEOUT_MS + 2 * ADOBE_FIREFLY_IMAGE_TIMEOUT_PER_REF_MS
|
||||
);
|
||||
assert.equal(adobeFireflyImageTimeoutMs({ timeoutMs: 120_000, refCount: 5 }), 120_000);
|
||||
assert.equal(
|
||||
adobeFireflyImageTimeoutMs({ refCount: 99 }),
|
||||
ADOBE_FIREFLY_IMAGE_TIMEOUT_MAX_MS
|
||||
);
|
||||
assert.equal(adobeFireflyImageTimeoutMs({ refCount: 99 }), ADOBE_FIREFLY_IMAGE_TIMEOUT_MAX_MS);
|
||||
});
|
||||
|
||||
test("extractAdobeSourceImageSources reads Media page image fields", () => {
|
||||
@@ -369,10 +360,10 @@ test("resolveAdobeSourceImageIds uploads data URLs then returns blob ids", async
|
||||
const headers = init?.headers as Record<string, string>;
|
||||
assert.match(String(headers["content-type"] || headers["Content-Type"] || ""), /image\//);
|
||||
assert.ok(init?.body);
|
||||
return new Response(
|
||||
JSON.stringify({ images: [{ id: `blob-${uploadCalls}` }] }),
|
||||
{ status: 200, headers: { "content-type": "application/json" } }
|
||||
);
|
||||
return new Response(JSON.stringify({ images: [{ id: `blob-${uploadCalls}` }] }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}
|
||||
throw new Error(`unexpected fetch ${u}`);
|
||||
};
|
||||
@@ -476,8 +467,7 @@ test("buildAdobeSubmitNonce is sha256(user_id + prompt[:256])", async () => {
|
||||
type: "access_token",
|
||||
client_id: "clio-playground-web",
|
||||
})
|
||||
)
|
||||
.toString("base64url");
|
||||
).toString("base64url");
|
||||
const header = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url");
|
||||
const token = `${header}.${payload}.${"x".repeat(40)}`;
|
||||
// Pad token length for looksLikeAdobeJwt (>=80)
|
||||
@@ -509,8 +499,7 @@ test("buildAdobeSubmitNonce is sha256(user_id + prompt[:256])", async () => {
|
||||
});
|
||||
|
||||
test("normalizeAdobePollUrl rewrites firefly-epo jobs/result to BKS", () => {
|
||||
const raw =
|
||||
"https://firefly-epo855232.adobe.io/jobs/result/4ae9fd2a-0864-46dd-9834-cfc16e91faa6";
|
||||
const raw = "https://firefly-epo855232.adobe.io/jobs/result/4ae9fd2a-0864-46dd-9834-cfc16e91faa6";
|
||||
const out = normalizeAdobePollUrl(raw);
|
||||
assert.match(out, /^https:\/\/bks-epo8552\.adobe\.io\/v2\/jobs\/result\/4ae9fd2a/);
|
||||
assert.match(out, /host=firefly-epo855232\.adobe\.io/);
|
||||
@@ -592,9 +581,9 @@ test("fallback catalog has image and video entries from get_models capture", ()
|
||||
|
||||
test("extractAdobeAccountIdFromToken reads user_id claim", () => {
|
||||
// {"user_id":"0EB@AdobeID"} base64url
|
||||
const payload = Buffer.from(JSON.stringify({ user_id: "0EB@AdobeID", type: "access_token" })).toString(
|
||||
"base64url"
|
||||
);
|
||||
const payload = Buffer.from(
|
||||
JSON.stringify({ user_id: "0EB@AdobeID", type: "access_token" })
|
||||
).toString("base64url");
|
||||
const jwt = `eyJhbGciOiJub25lIn0.${payload}.sig`;
|
||||
assert.equal(extractAdobeAccountIdFromToken(jwt), "0EB@AdobeID");
|
||||
});
|
||||
@@ -602,18 +591,7 @@ test("extractAdobeAccountIdFromToken reads user_id claim", () => {
|
||||
// --- Handlers (mocked fetch) ----------------------------------------------
|
||||
|
||||
function jsonResponse(status: number, body: unknown, headerMap: Record<string, string> = {}) {
|
||||
return {
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
headers: {
|
||||
get: (name: string) => {
|
||||
const key = Object.keys(headerMap).find((k) => k.toLowerCase() === name.toLowerCase());
|
||||
return key ? headerMap[key] : null;
|
||||
},
|
||||
},
|
||||
json: async () => body,
|
||||
text: async () => JSON.stringify(body),
|
||||
} as unknown as Response;
|
||||
return new Response(JSON.stringify(body) ?? null, { status, headers: headerMap });
|
||||
}
|
||||
|
||||
test("handleAdobeFireflyImageGeneration returns 400 when prompt is missing", async () => {
|
||||
@@ -779,13 +757,19 @@ test("guest JWT without AdobeID is detected", () => {
|
||||
const emptyPayload = Buffer.from("{}").toString("base64url");
|
||||
const guestJwt = `eyJhbGciOiJub25lIn0.${emptyPayload}.sig`;
|
||||
// Pad to lookLikeAdobeJwt length if needed
|
||||
const longGuest = `eyJhbGciOiJSUzI1NiJ9.${Buffer.from(JSON.stringify({ client_id: "clio-playground-web" })).toString("base64url")}.` + "x".repeat(40);
|
||||
const longGuest =
|
||||
`eyJhbGciOiJSUzI1NiJ9.${Buffer.from(JSON.stringify({ client_id: "clio-playground-web" })).toString("base64url")}.` +
|
||||
"x".repeat(40);
|
||||
assert.equal(isAdobeGuestAccessToken(longGuest), true);
|
||||
const userJwt =
|
||||
`eyJhbGciOiJSUzI1NiJ9.` +
|
||||
Buffer.from(JSON.stringify({ user_id: "0EB@AdobeID", type: "access_token", client_id: "clio-playground-web" })).toString(
|
||||
"base64url"
|
||||
) +
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
user_id: "0EB@AdobeID",
|
||||
type: "access_token",
|
||||
client_id: "clio-playground-web",
|
||||
})
|
||||
).toString("base64url") +
|
||||
`.` +
|
||||
"y".repeat(40);
|
||||
assert.equal(isAdobeGuestAccessToken(userJwt), false);
|
||||
@@ -832,7 +816,13 @@ test("cookie exchange rejects guest IMS tokens", async () => {
|
||||
});
|
||||
|
||||
test("isAdobeTransientSubmitError detects 408 system under load", () => {
|
||||
assert.equal(isAdobeTransientSubmitError(408, '{"error_code":"timeout_error","message":"system under load"}'), true);
|
||||
assert.equal(
|
||||
isAdobeTransientSubmitError(
|
||||
408,
|
||||
'{"error_code":"timeout_error","message":"system under load"}'
|
||||
),
|
||||
true
|
||||
);
|
||||
assert.equal(isAdobeTransientSubmitError(429, "rate"), true);
|
||||
assert.equal(isAdobeTransientSubmitError(400, "bad request"), false);
|
||||
assert.ok(generateAdobeNonce().length === 64);
|
||||
@@ -880,11 +870,7 @@ test("image submit retries on 408 then succeeds", async () => {
|
||||
if (submits < 3) {
|
||||
return jsonResponse(408, { error_code: "timeout_error", message: "system under load" });
|
||||
}
|
||||
return jsonResponse(
|
||||
200,
|
||||
{ links: { result: { href: "https://poll.example/job/r1" } } },
|
||||
{}
|
||||
);
|
||||
return jsonResponse(200, { links: { result: { href: "https://poll.example/job/r1" } } }, {});
|
||||
}
|
||||
if (u.includes("poll.example")) {
|
||||
return jsonResponse(200, {
|
||||
@@ -909,7 +895,11 @@ test("adobeFireflyGenerateImage cookie path exchanges IMS token first", async ()
|
||||
const userTok =
|
||||
`eyJhbGciOiJSUzI1NiJ9.` +
|
||||
Buffer.from(
|
||||
JSON.stringify({ user_id: "0EB@AdobeID", type: "access_token", client_id: "clio-playground-web" })
|
||||
JSON.stringify({
|
||||
user_id: "0EB@AdobeID",
|
||||
type: "access_token",
|
||||
client_id: "clio-playground-web",
|
||||
})
|
||||
).toString("base64url") +
|
||||
`.` +
|
||||
"s".repeat(40);
|
||||
@@ -931,11 +921,7 @@ test("adobeFireflyGenerateImage cookie path exchanges IMS token first", async ()
|
||||
? (init.headers as Record<string, string>).Authorization
|
||||
: auth;
|
||||
assert.equal(headerAuth, `Bearer ${userTok}`);
|
||||
return jsonResponse(
|
||||
200,
|
||||
{},
|
||||
{ "x-override-status-link": "https://poll.example/job/c1" }
|
||||
);
|
||||
return jsonResponse(200, {}, { "x-override-status-link": "https://poll.example/job/c1" });
|
||||
}
|
||||
if (String(url).includes("poll.example")) {
|
||||
return jsonResponse(200, {
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-claude-rendering-"));
|
||||
const previousDataDir = process.env.DATA_DIR;
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const { openaiResponsesToOpenAIResponse } =
|
||||
await import("../../open-sse/translator/response/openai-responses.ts");
|
||||
const { FORMATS } = await import("../../open-sse/translator/formats.ts");
|
||||
const { createSSETransformStreamWithLogger } = await import("../../open-sse/utils/stream.ts");
|
||||
const { resetDbInstance } = await import("../../src/lib/db/core.ts");
|
||||
|
||||
test.after(() => {
|
||||
resetDbInstance();
|
||||
if (previousDataDir === undefined) delete process.env.DATA_DIR;
|
||||
else process.env.DATA_DIR = previousDataDir;
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("Responses->Chat: output_item.done emits arguments when no delta chunks were sent", () => {
|
||||
const state = {
|
||||
@@ -38,7 +53,7 @@ test("Responses->Chat: output_item.done emits arguments when no delta chunks wer
|
||||
assert.equal(state.toolCallIndex, 1);
|
||||
});
|
||||
|
||||
test("Responses->Chat: output_item.done does not re-emit arguments already streamed via deltas", () => {
|
||||
test("Responses->Chat: buffered argument deltas emit once at output_item.done", () => {
|
||||
const state = {
|
||||
started: true,
|
||||
chatId: "chatcmpl-test",
|
||||
@@ -46,9 +61,19 @@ test("Responses->Chat: output_item.done does not re-emit arguments already strea
|
||||
toolCallIndex: 0,
|
||||
finishReasonSent: false,
|
||||
currentToolCallId: "call_abc",
|
||||
currentToolCallArgsBuffer: '{"query":"search"}',
|
||||
currentToolCallArgsBuffer: "",
|
||||
};
|
||||
|
||||
const deltaResult = openaiResponsesToOpenAIResponse(
|
||||
{
|
||||
type: "response.function_call_arguments.delta",
|
||||
delta: '{"query":"search"}',
|
||||
},
|
||||
state
|
||||
);
|
||||
|
||||
assert.equal(deltaResult, null);
|
||||
|
||||
const chunk = {
|
||||
type: "response.output_item.done",
|
||||
item: {
|
||||
@@ -62,7 +87,8 @@ test("Responses->Chat: output_item.done does not re-emit arguments already strea
|
||||
|
||||
const result = openaiResponsesToOpenAIResponse(chunk, state);
|
||||
|
||||
assert.equal(result, null);
|
||||
assert.ok(result);
|
||||
assert.equal(result.choices[0].delta.tool_calls[0].function.arguments, '{"query":"search"}');
|
||||
assert.equal(state.toolCallIndex, 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ test("ServerSupervisor starts Node with IPv4-first DNS", async () => {
|
||||
|
||||
assert.deepEqual(spawnCalls, [
|
||||
{
|
||||
command: "node",
|
||||
command: process.execPath,
|
||||
args: ["--dns-result-order=ipv4first", "--max-old-space-size=2048", "/app/server.js"],
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -97,6 +97,21 @@ test("package.json files[] excludes nested node_modules from the published packa
|
||||
);
|
||||
});
|
||||
|
||||
test("build-next-isolated sibling imports are allowed in the published package", () => {
|
||||
const buildDependencies = [
|
||||
"scripts/build/assembleStandalone.mjs",
|
||||
"scripts/build/backendOnlyPages.mjs",
|
||||
"scripts/build/build-tproxy-native.mjs",
|
||||
];
|
||||
|
||||
const unexpectedPaths = findUnexpectedArtifactPaths(buildDependencies, {
|
||||
exactPaths: PACK_ARTIFACT_ALLOWED_EXACT_PATHS,
|
||||
prefixPaths: PACK_ARTIFACT_ALLOWED_PATH_PREFIXES,
|
||||
});
|
||||
|
||||
assert.deepEqual(unexpectedPaths, []);
|
||||
});
|
||||
|
||||
test("webdav-handler.mjs is allowed in staging dist/ (server-ws.mjs dependency, missed in 3.8.22 build)", () => {
|
||||
const unexpectedPaths = findUnexpectedArtifactPaths(["webdav-handler.mjs"], {
|
||||
exactPaths: APP_STAGING_ALLOWED_EXACT_PATHS,
|
||||
|
||||
@@ -13,22 +13,18 @@ test("#7754 auto/best-free never leaks the combo name as a model", async () => {
|
||||
// The combo id is the modelStr by design (routing resolves it back), but the
|
||||
// models array must never contain it as a target model.
|
||||
const leak = models.filter(
|
||||
(m: any) =>
|
||||
(m) =>
|
||||
(m.id || "") === "auto/best-free" ||
|
||||
(m.model || "") === "auto/best-free" ||
|
||||
(m.modelStr || "") === "auto/best-free"
|
||||
);
|
||||
assert.equal(
|
||||
leak.length,
|
||||
0,
|
||||
`combo name leaked as a target model: ${JSON.stringify(leak)}`
|
||||
);
|
||||
assert.equal(leak.length, 0, `combo name leaked as a target model: ${JSON.stringify(leak)}`);
|
||||
});
|
||||
|
||||
test("#7754 every auto/best-free model carries a concrete provider/model", async () => {
|
||||
const combo = await createBuiltinAutoCombo("auto/best-free", "best-free");
|
||||
const models = combo.models || [];
|
||||
for (const m of models as any[]) {
|
||||
for (const m of models) {
|
||||
assert.ok(
|
||||
m.model && m.model !== "auto/best-free",
|
||||
`model missing concrete id: ${JSON.stringify(m)}`
|
||||
@@ -51,7 +47,7 @@ test("#7754 empty free-tier pool degrades with a clear 503, not a name leak", as
|
||||
assert.equal(combo.candidatePool?.length || 0, 0);
|
||||
} else {
|
||||
// Non-empty pool must not leak.
|
||||
const leak = models.filter((m: any) => (m.model || "") === "auto/best-free");
|
||||
const leak = models.filter((m) => (m.model || "") === "auto/best-free");
|
||||
assert.equal(leak.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,15 +9,29 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(__dirname, "../..");
|
||||
const WORKFLOW = resolve(repoRoot, ".github/workflows/quality.yml");
|
||||
|
||||
function loadWorkflow(): any {
|
||||
return parse(readFileSync(WORKFLOW, "utf8"));
|
||||
interface WorkflowStep {
|
||||
name?: string;
|
||||
run?: string;
|
||||
"continue-on-error"?: boolean;
|
||||
}
|
||||
|
||||
interface WorkflowDocument {
|
||||
jobs?: Record<string, { steps?: WorkflowStep[] }>;
|
||||
}
|
||||
|
||||
function loadWorkflow(): WorkflowDocument {
|
||||
return parse(readFileSync(WORKFLOW, "utf8")) as WorkflowDocument;
|
||||
}
|
||||
|
||||
function invokesGate(run: string): boolean {
|
||||
if (!run) return false;
|
||||
return /npm run (check:|typecheck:)/.test(run) || /npm run "check/.test(run) || /npm run \\"check/.test(run);
|
||||
return (
|
||||
/npm run (check:|typecheck:)/.test(run) ||
|
||||
/npm run "check/.test(run) ||
|
||||
/npm run \\"check/.test(run)
|
||||
);
|
||||
}
|
||||
function stepCanFail(step: any): boolean {
|
||||
function stepCanFail(step: WorkflowStep): boolean {
|
||||
return step?.["continue-on-error"] !== true;
|
||||
}
|
||||
|
||||
@@ -25,7 +39,7 @@ test("repro #8542: fast-gates must not fail-fast into a later gate", () => {
|
||||
const wf = loadWorkflow();
|
||||
const job = wf.jobs?.["fast-gates"];
|
||||
assert.ok(job, "fast-gates job must exist");
|
||||
const steps: any[] = job.steps ?? [];
|
||||
const steps: WorkflowStep[] = job.steps ?? [];
|
||||
assert.ok(steps.length >= 5, `fast-gates must have >=5 steps, got ${steps.length}`);
|
||||
|
||||
const gateSteps = steps.map((s, i) => ({ s, i })).filter(({ s }) => invokesGate(s?.run ?? ""));
|
||||
@@ -51,4 +65,4 @@ test("repro #8542: fast-gates must not fail-fast into a later gate", () => {
|
||||
maskedPairs.slice(0, 12).join("\n") +
|
||||
(maskedPairs.length > 12 ? `\n... (+${maskedPairs.length - 12} more)` : "")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,7 +47,8 @@ test.after(() => {
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const DAY = 86_400; // seconds
|
||||
const DAY_SECONDS = 86_400;
|
||||
const DAY_MS = 86_400_000;
|
||||
|
||||
/** Ensure compression_run_telemetry table exists (created lazily in production). */
|
||||
function ensureTelemetryTable(): void {
|
||||
@@ -75,17 +76,17 @@ function ensureTelemetryTable(): void {
|
||||
|
||||
test("#6848 cleanupDomainCostHistory: deletes rows older than retention window", async () => {
|
||||
const db = getDbInstance()!;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const now = Date.now();
|
||||
const insert = db.prepare(
|
||||
"INSERT INTO domain_cost_history (api_key_id, cost, timestamp) VALUES (?, ?, ?)"
|
||||
);
|
||||
|
||||
// 3 old (40 days ago), 2 recent (5 days ago)
|
||||
insert.run("key1", 1.0, now - 40 * DAY);
|
||||
insert.run("key1", 2.0, now - 40 * DAY);
|
||||
insert.run("key1", 3.0, now - 40 * DAY);
|
||||
insert.run("key1", 4.0, now - 5 * DAY);
|
||||
insert.run("key1", 5.0, now - 5 * DAY);
|
||||
insert.run("key1", 1.0, now - 40 * DAY_MS);
|
||||
insert.run("key1", 2.0, now - 40 * DAY_MS);
|
||||
insert.run("key1", 3.0, now - 40 * DAY_MS);
|
||||
insert.run("key1", 4.0, now - 5 * DAY_MS);
|
||||
insert.run("key1", 5.0, now - 5 * DAY_MS);
|
||||
|
||||
const result = await cleanupDomainCostHistory();
|
||||
|
||||
@@ -100,8 +101,8 @@ test("#6848 cleanupDomainCostHistory: deletes rows older than retention window",
|
||||
|
||||
test("#6848 cleanupCompressionCacheStats: deletes rows older than retention window", async () => {
|
||||
const db = getDbInstance()!;
|
||||
const oldDate = new Date(Date.now() - 40 * DAY * 1000).toISOString();
|
||||
const recentDate = new Date(Date.now() - 5 * DAY * 1000).toISOString();
|
||||
const oldDate = new Date(Date.now() - 40 * DAY_MS).toISOString();
|
||||
const recentDate = new Date(Date.now() - 5 * DAY_MS).toISOString();
|
||||
const insert = db.prepare(
|
||||
"INSERT INTO compression_cache_stats (provider, compression_mode, created_at) VALUES (?, ?, ?)"
|
||||
);
|
||||
@@ -123,8 +124,8 @@ test("#6848 cleanupCompressionCacheStats: deletes rows older than retention wind
|
||||
|
||||
test("#6848 cleanupXpAuditLog: deletes rows older than retention window", async () => {
|
||||
const db = getDbInstance()!;
|
||||
const oldDate = new Date(Date.now() - 40 * DAY * 1000).toISOString();
|
||||
const recentDate = new Date(Date.now() - 5 * DAY * 1000).toISOString();
|
||||
const oldDate = new Date(Date.now() - 40 * DAY_MS).toISOString();
|
||||
const recentDate = new Date(Date.now() - 5 * DAY_MS).toISOString();
|
||||
const insert = db.prepare(
|
||||
"INSERT INTO xp_audit_log (api_key_id, action, xp_earned, created_at) VALUES (?, ?, ?, ?)"
|
||||
);
|
||||
@@ -151,9 +152,9 @@ test("#6848 cleanupCompressionRunTelemetry: deletes rows older than retention wi
|
||||
"INSERT INTO compression_run_telemetry (timestamp, tokens_before, tokens_after) VALUES (?, ?, ?)"
|
||||
);
|
||||
|
||||
insert.run(now - 40 * DAY, 1000, 500);
|
||||
insert.run(now - 40 * DAY, 2000, 800);
|
||||
insert.run(now - 5 * DAY, 1500, 600);
|
||||
insert.run(now - 40 * DAY_SECONDS, 1000, 500);
|
||||
insert.run(now - 40 * DAY_SECONDS, 2000, 800);
|
||||
insert.run(now - 5 * DAY_SECONDS, 1500, 600);
|
||||
|
||||
const result = await cleanupCompressionRunTelemetry();
|
||||
|
||||
@@ -169,13 +170,14 @@ test("#6848 cleanupCompressionRunTelemetry: deletes rows older than retention wi
|
||||
test("#6848 no rows deleted when all data is within retention window (calls all 4 real functions)", async () => {
|
||||
ensureTelemetryTable();
|
||||
const db = getDbInstance()!;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const nowSeconds = Math.floor(Date.now() / 1000);
|
||||
const nowMilliseconds = Date.now();
|
||||
const recentISO = new Date().toISOString();
|
||||
|
||||
db.prepare("INSERT INTO domain_cost_history (api_key_id, cost, timestamp) VALUES (?, ?, ?)").run(
|
||||
"k",
|
||||
1,
|
||||
now - DAY
|
||||
nowMilliseconds - DAY_MS
|
||||
);
|
||||
db.prepare(
|
||||
"INSERT INTO compression_cache_stats (provider, compression_mode, created_at) VALUES (?, ?, ?)"
|
||||
@@ -185,7 +187,7 @@ test("#6848 no rows deleted when all data is within retention window (calls all
|
||||
).run("k", "a", 5, recentISO);
|
||||
db.prepare(
|
||||
"INSERT INTO compression_run_telemetry (timestamp, tokens_before, tokens_after) VALUES (?, ?, ?)"
|
||||
).run(now - DAY, 100, 50);
|
||||
).run(nowSeconds - DAY_SECONDS, 100, 50);
|
||||
|
||||
const r1 = await cleanupDomainCostHistory();
|
||||
const r2 = await cleanupCompressionCacheStats();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { openaiResponsesToOpenAIRequest } from "../../open-sse/translator/request/openai-responses.ts";
|
||||
import { detectSupportedThinkingEfforts } from "../../src/lib/providerModels/modelDiscovery.ts";
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return value as Record<string, unknown>;
|
||||
@@ -42,7 +43,6 @@ test("non-GPT-5.6 models still get max downgraded to xhigh", () => {
|
||||
)
|
||||
);
|
||||
assert.equal(translated.reasoning_effort, "xhigh");
|
||||
<<<<<<< HEAD
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
@@ -61,12 +61,10 @@ test("#9142 Anthropic top-level system prompts must trigger background detection
|
||||
"system_prompt_pattern"
|
||||
);
|
||||
});
|
||||
=======
|
||||
|
||||
// #9140 — VS Code routes filter out built-in auto models
|
||||
const { isUsableChatModel } = await import(
|
||||
"../../src/app/api/v1/vscode/[token]/usableChatModel.ts"
|
||||
);
|
||||
const { isUsableChatModel } =
|
||||
await import("../../src/app/api/v1/vscode/[token]/usableChatModel.ts");
|
||||
|
||||
test("#9140 VS Code listing must accept built-in auto routing entries", () => {
|
||||
assert.equal(
|
||||
@@ -79,14 +77,10 @@ test("#9140 VS Code listing must accept built-in auto routing entries", () => {
|
||||
false,
|
||||
"operator-created combo should still be rejected"
|
||||
);
|
||||
>>>>>>> origin/release/v3.8.50
|
||||
|
||||
|
||||
});
|
||||
|
||||
// ── #9160 model discovery: capabilities.effort_tiers ────────────────────────
|
||||
|
||||
// #9160: model discovery must ingest capabilities.effort_tiers
|
||||
test("#9160 model discovery must ingest capabilities.effort_tiers", () => {
|
||||
assert.deepEqual(
|
||||
detectSupportedThinkingEfforts({
|
||||
@@ -103,4 +97,4 @@ test("#9160 capabilities.effort_tiers with duplicate and synonym", () => {
|
||||
}),
|
||||
["low", "xhigh"]
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user