diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 72241f73e4..fc2cbeedda 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -10191,6 +10191,8 @@ "copied": "Copied!", "run": "Run", "running": "Running...", + "loading": "Loading...", + "retry": "Retry", "response": "Response", "tunnel": "Tunnel", "send": "Send", diff --git a/tests/unit/claude-code-rendering-fixes.test.ts b/tests/unit/claude-code-rendering-fixes.test.ts index 52e67fbb71..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 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); }); diff --git a/tests/unit/cli-ipv4-first-dns-2699.test.ts b/tests/unit/cli-ipv4-first-dns-2699.test.ts index 30aa2cd297..c5053a6751 100644 --- a/tests/unit/cli-ipv4-first-dns-2699.test.ts +++ b/tests/unit/cli-ipv4-first-dns-2699.test.ts @@ -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"], }, ]); diff --git a/tests/unit/telemetry-auto-cleanup-6848.test.ts b/tests/unit/telemetry-auto-cleanup-6848.test.ts index 3f214e022e..f1485de55e 100644 --- a/tests/unit/telemetry-auto-cleanup-6848.test.ts +++ b/tests/unit/telemetry-auto-cleanup-6848.test.ts @@ -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();