diff --git a/scripts/build/pack-artifact-policy.ts b/scripts/build/pack-artifact-policy.ts index a464cd516b..740bbe9a45 100644 --- a/scripts/build/pack-artifact-policy.ts +++ b/scripts/build/pack-artifact-policy.ts @@ -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", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index 0b169975fc..0891717f3a 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -10191,6 +10191,8 @@ "copied": "Copiado!", "run": "Executar", "running": "Executando...", + "loading": "Carregando...", + "retry": "Tentar novamente", "response": "Resposta", "tunnel": "Tunnel", "send": "Enviar", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index ab6703f848..3eb1f46e4c 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -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", diff --git a/src/lib/db/quotaPools.ts b/src/lib/db/quotaPools.ts index f7a911d069..eba19be453 100644 --- a/src/lib/db/quotaPools.ts +++ b/src/lib/db/quotaPools.ts @@ -17,12 +17,6 @@ import { getDbInstance } from "./core"; const quotaComboMaintenance = new Map>(); const deletingPools = new Set(); -/** Reset module-level state for test isolation. Call in test.after() hooks. */ -export function resetQuotaPoolsModuleState(): void { - deletingPools.clear(); - quotaComboMaintenance.clear(); -} - function serializeQuotaComboMaintenance( poolId: string, operation: () => Promise diff --git a/stryker.conf.json b/stryker.conf.json index a49dd781cf..0b177926cd 100644 --- a/stryker.conf.json +++ b/stryker.conf.json @@ -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/api-key-policy-noauth-allowed-connections.test.ts", "tests/unit/appearance-widget-settings-schema.test.ts", @@ -214,6 +215,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/gemini-web-capabilities-9356.test.ts", "tests/unit/grok-cli-oauth.test.ts", @@ -275,6 +277,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-9486.test.ts", "tests/unit/repro-antigravity-404-family-cooldown-hijack.test.ts", diff --git a/tests/unit/adobe-firefly.test.ts b/tests/unit/adobe-firefly.test.ts index 0e8f75d277..549df4b95b 100644 --- a/tests/unit/adobe-firefly.test.ts +++ b/tests/unit/adobe-firefly.test.ts @@ -591,7 +591,7 @@ test("extractAdobeAccountIdFromToken reads user_id claim", () => { // --- Handlers (mocked fetch) ---------------------------------------------- function jsonResponse(status: number, body: unknown, headerMap: Record = {}) { - return new Response(JSON.stringify(body), { status, headers: headerMap }); + return new Response(JSON.stringify(body) ?? null, { status, headers: headerMap }); } test("handleAdobeFireflyImageGeneration returns 400 when prompt is missing", async () => { diff --git a/tests/unit/claude-code-rendering-fixes.test.ts b/tests/unit/claude-code-rendering-fixes.test.ts index 07e83b96e0..fe50f4e426 100644 --- a/tests/unit/claude-code-rendering-fixes.test.ts +++ b/tests/unit/claude-code-rendering-fixes.test.ts @@ -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 emits the arguments buffered from deltas exactly once", () => { +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 emits the arguments buffered from deltas 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: { diff --git a/tests/unit/pack-artifact-policy.test.ts b/tests/unit/pack-artifact-policy.test.ts index 902504b237..8c52f5fe9e 100644 --- a/tests/unit/pack-artifact-policy.test.ts +++ b/tests/unit/pack-artifact-policy.test.ts @@ -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, diff --git a/tests/unit/telemetry-auto-cleanup-6848.test.ts b/tests/unit/telemetry-auto-cleanup-6848.test.ts index 03e95f8d4f..2952304628 100644 --- a/tests/unit/telemetry-auto-cleanup-6848.test.ts +++ b/tests/unit/telemetry-auto-cleanup-6848.test.ts @@ -47,8 +47,8 @@ test.after(() => { fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); }); -const DAY = 86_400; // seconds -const DAY_MS = DAY * 1000; +const DAY_SECONDS = 86_400; +const DAY_MS = 86_400_000; /** Ensure compression_run_telemetry table exists (created lazily in production). */ function ensureTelemetryTable(): void { @@ -114,8 +114,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 (?, ?, ?)" ); @@ -137,8 +137,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 (?, ?, ?, ?)" ); @@ -166,9 +166,9 @@ test("#6848 cleanupCompressionRunTelemetry: deletes rows older than retention wi "INSERT INTO compression_run_telemetry (timestamp, tokens_before, tokens_after) VALUES (?, ?, ?)" ); - insert.run(nowSeconds - 40 * DAY, 1000, 500); - insert.run(nowSeconds - 40 * DAY, 2000, 800); - insert.run(nowSeconds - 5 * DAY, 1500, 600); + insert.run(nowSeconds - 40 * DAY_SECONDS, 1000, 500); + insert.run(nowSeconds - 40 * DAY_SECONDS, 2000, 800); + insert.run(nowSeconds - 5 * DAY_SECONDS, 1500, 600); const result = await cleanupCompressionRunTelemetry(); @@ -184,14 +184,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 = Date.now(); - const nowSeconds = Math.floor(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_MS + nowMilliseconds - DAY_MS ); db.prepare( "INSERT INTO compression_cache_stats (provider, compression_mode, created_at) VALUES (?, ?, ?)" @@ -201,7 +201,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(nowSeconds - DAY, 100, 50); + ).run(nowSeconds - DAY_SECONDS, 100, 50); const r1 = await cleanupDomainCostHistory(); const r2 = await cleanupCompressionCacheStats(); diff --git a/tests/unit/triage-bugs-2026-08-02.test.ts b/tests/unit/triage-bugs-2026-08-02.test.ts index 20fb823786..0c329c24d8 100644 --- a/tests/unit/triage-bugs-2026-08-02.test.ts +++ b/tests/unit/triage-bugs-2026-08-02.test.ts @@ -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 { return value as Record; @@ -76,3 +77,22 @@ test("#9140 VS Code listing must accept built-in auto routing entries", () => { "operator-created combo should still be rejected" ); }); +// ── #9160 model discovery: capabilities.effort_tiers ──────────────────────── + +test("#9160 model discovery must ingest capabilities.effort_tiers", () => { + assert.deepEqual( + detectSupportedThinkingEfforts({ + capabilities: { effort_tiers: ["low", "medium", "high", "xhigh"] }, + }), + ["low", "medium", "high", "xhigh"] + ); +}); + +test("#9160 capabilities.effort_tiers with duplicate and synonym", () => { + assert.deepEqual( + detectSupportedThinkingEfforts({ + capabilities: { effort_tiers: ["low", "low", "max"] }, + }), + ["low", "xhigh"] + ); +});