fix: remove hardcoded localhost default arg from GET /api/keys, unify coverage to single coverage/ dir, fix test to pass explicit Request

- Remove `new Request('http://localhost/api/keys')` default arg from GET handler in src/app/api/keys/route.ts (line 26)
- Fix api-key-reveal-route.test.mjs to pass explicit Request instead of calling GET() with no args
- Add --output-dir coverage to all c8 scripts in package.json
- Add coverage.reportsDirectory: 'coverage' to vitest.config.ts and vitest.mcp.config.ts
- Fix CHANGELOG.md structure (# Changelog + [Unreleased] to top)
- Remove 30+ stale coverage-* directories from project root
- Coverage: Statements 78.76% | Branches 72.75% | Functions 80.93% | Lines 78.76% (all thresholds passed)
This commit is contained in:
diegosouzapw
2026-04-05 23:21:08 -03:00
parent 9981394557
commit 592ca9b5c4
147 changed files with 24568 additions and 518 deletions

View File

@@ -71,21 +71,50 @@ jobs:
name: i18n-${{ matrix.lang }}
path: result.txt
security:
name: Security Audit
advanced-security:
name: Advanced Security Scans
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
# 1. TRUFFLEHOG OSS
- name: TruffleHog Secret Scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --only-verified
# 2. SONARQUBE SCAN
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v4
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
# 3. SNYK SCAN E VERIFICAÇÕES NATIVAS
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
# Mantendo as verificações nativas originais
- name: Dependency audit
run: npm audit --audit-level=high --omit=dev || true
- name: Check for known vulnerabilities
run: npx is-my-node-vulnerable || true
- name: Run Snyk Vulnerability checks
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
build:
name: Build
runs-on: ubuntu-latest
@@ -195,7 +224,7 @@ jobs:
if: always()
needs:
- lint
- security
- advanced-security
- build
- test-unit
- test-coverage
@@ -229,7 +258,7 @@ jobs:
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint | $(status '${{ needs.lint.result }}') |" >> $GITHUB_STEP_SUMMARY
echo "| Security Audit | $(status '${{ needs.security.result }}') |" >> $GITHUB_STEP_SUMMARY
echo "| Advanced Security | $(status '${{ needs.advanced-security.result }}') |" >> $GITHUB_STEP_SUMMARY
# 🔹 BUILD
echo "" >> $GITHUB_STEP_SUMMARY

2
.gitignore vendored
View File

@@ -21,9 +21,11 @@ node_modules/
!.yarn/releases
!.yarn/versions
.data/
.next-playwright/
# testing
coverage/
coverage**
# next.js
.next/

View File

@@ -1,13 +1,15 @@
# Changelog
## [Unreleased]
---
## [3.5.3] - 2026-04-05
### Fixed
- **Middleware:** Resolved infinite redirect loop on dashboard for fresh instances when requireLogin is disabled.
# Changelog
## [Unreleased]
---
## [3.5.2] — 2026-04-05

View File

@@ -1,9 +1,11 @@
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
const distDir = process.env.NEXT_DIST_DIR || ".next";
/** @type {import('next').NextConfig} */
const nextConfig = {
distDir,
// Turbopack config: redirect native modules to stubs at build time
turbopack: {
resolveAlias: {

View File

@@ -109,6 +109,53 @@ export function getCodexResetTime(quota: CodexQuotaSnapshot): number | null {
return Math.max(...times); // Use furthest-out reset to avoid premature unblock
}
/**
* T03 (Item 3): Compute the minimum-necessary cooldown based on which window
* is actually exhausted. Prevents over-blocking the account:
*
* - If 7d window >= threshold: cooldown until 7d reset (weekly window exhausted)
* - If 5h window >= threshold: cooldown until 5h reset only (short-term limit)
* - Otherwise: 0 (account is healthy, no cooldown needed)
*
* Called after parsing quota headers from a successful/429 response to
* mark the account accordingly without overly long cooldowns.
*
* @param quota - Parsed quota snapshot from response headers
* @param threshold - Fraction (0-1) that triggers cooldown (default: 0.95)
* @returns Cooldown duration in milliseconds (0 = no cooldown needed)
*/
export function getCodexDualWindowCooldownMs(
quota: CodexQuotaSnapshot,
threshold = 0.95
): { cooldownMs: number; window: "7d" | "5h" | "none" } {
const now = Date.now();
// Compute per-window usage ratios (0..1)
const ratio7d =
quota.limit7d > 0 && Number.isFinite(quota.limit7d) ? quota.usage7d / quota.limit7d : 0;
const ratio5h =
quota.limit5h > 0 && Number.isFinite(quota.limit5h) ? quota.usage5h / quota.limit5h : 0;
// 7d window takes priority — if the weekly budget is near-exhausted,
// we must wait until the weekly reset (not just 5h).
if (ratio7d >= threshold && quota.resetAt7d) {
const resetTime = new Date(quota.resetAt7d).getTime();
if (resetTime > now) {
return { cooldownMs: resetTime - now, window: "7d" };
}
}
// 5h window (primary short-term rate limit)
if (ratio5h >= threshold && quota.resetAt5h) {
const resetTime = new Date(quota.resetAt5h).getTime();
if (resetTime > now) {
return { cooldownMs: resetTime - now, window: "5h" };
}
}
return { cooldownMs: 0, window: "none" };
}
// Ordered list of effort levels from lowest to highest
const EFFORT_ORDER = ["none", "low", "medium", "high", "xhigh"] as const;
type EffortLevel = (typeof EFFORT_ORDER)[number];

View File

@@ -112,9 +112,9 @@ export class DefaultExecutor extends BaseExecutor {
if (stream) headers["Accept"] = "text/event-stream";
// Qwen header cleanup: Remove X-Dashscope-* headers since Qwen uses an OpenAI-compatible endpoint
// (e.g. portal.qwen.ai) via its DefaultExecutor buildUrl override, which rejects native DashScope headers.
if (this.provider === "qwen") {
// Qwen header cleanup: Remove X-Dashscope-* headers if using an API key (DashScope compatible mode).
// If using OAuth (Qwen Code), we MUST keep them for portal.qwen.ai to accept the request.
if (this.provider === "qwen" && effectiveKey) {
for (const key of Object.keys(headers)) {
if (key.toLowerCase().startsWith("x-dashscope-")) {
delete headers[key];

View File

@@ -64,7 +64,9 @@ import {
parseCodexQuotaHeaders,
getCodexResetTime,
getCodexModelScope,
getCodexDualWindowCooldownMs,
} from "../executors/codex.ts";
import { invalidateCodexQuotaCache } from "../services/codexQuotaFetcher.ts";
import { translateNonStreamingResponse } from "./responseTranslator.ts";
import { extractUsageFromResponse } from "./usageExtractor.ts";
import {
@@ -107,6 +109,7 @@ import {
import { resolveStreamFlag, stripMarkdownCodeFence } from "../utils/aiSdkCompat.ts";
import { generateRequestId } from "@/shared/utils/requestId";
import { normalizePayloadForLog } from "@/lib/logPayloads";
import { extractFacts } from "@/lib/memory/extraction";
import { injectMemory, shouldInjectMemory } from "@/lib/memory/injection";
import { retrieveMemories } from "@/lib/memory/retrieval";
import {
@@ -114,12 +117,42 @@ import {
getMemorySettings,
toMemoryRetrievalConfig,
} from "@/lib/memory/settings";
import { injectSkills } from "@/lib/skills/injection";
import { handleToolCallExecution } from "@/lib/skills/interception";
import {
buildClaudeCodeCompatibleRequest,
isClaudeCodeCompatibleProvider,
resolveClaudeCodeCompatibleSessionId,
} from "../services/claudeCodeCompatible.ts";
function extractMemoryTextFromResponse(
response: Record<string, unknown> | null | undefined
): string {
if (!response || typeof response !== "object") return "";
const openAIText = response?.choices?.[0]?.message?.content;
if (typeof openAIText === "string") {
return openAIText.trim();
}
if (Array.isArray(response?.content)) {
const contentText = response.content
.filter(
(part: Record<string, unknown>) => part?.type === "text" && typeof part?.text === "string"
)
.map((part: Record<string, unknown>) => String(part.text).trim())
.filter(Boolean)
.join("\n");
if (contentText) return contentText;
}
if (typeof response?.output_text === "string") {
return response.output_text.trim();
}
return "";
}
export function shouldUseNativeCodexPassthrough({
provider,
sourceFormat,
@@ -182,6 +215,53 @@ function restoreClaudePassthroughToolNames(
};
}
function materializeDeduplicatedExecutionResult<T extends Record<string, unknown>>(result: T): T {
const snapshot =
result && typeof result === "object"
? ((result as Record<string, unknown>)._dedupSnapshot as
| {
status: number;
statusText: string;
headers: [string, string][];
payload: string;
}
| undefined)
: undefined;
if (!snapshot) return result;
return {
...result,
response: new Response(snapshot.payload, {
status: snapshot.status,
statusText: snapshot.statusText,
headers: snapshot.headers,
}),
} as T;
}
function getSkillsProviderForFormat(format: string): "openai" | "anthropic" | "google" | "other" {
switch (format) {
case FORMATS.CLAUDE:
return "anthropic";
case FORMATS.GEMINI:
return "google";
default:
return "openai";
}
}
function getSkillsModelIdForFormat(format: string): string {
switch (format) {
case FORMATS.CLAUDE:
return "claude";
case FORMATS.GEMINI:
return "gemini";
default:
return "openai";
}
}
function getHeaderValueCaseInsensitive(
headers: Record<string, unknown> | null | undefined,
targetName: string
@@ -440,10 +520,11 @@ export async function handleChatCore({
};
// T03/T09: on 429, persist exact reset time per scope to avoid global over-blocking.
// Item 3: Use dual-window cooldown to distinguish 5h vs 7d exhaustion.
if (status === 429) {
const resetTimeMs = getCodexResetTime(quota);
if (resetTimeMs && resetTimeMs > Date.now()) {
const scopeUntil = new Date(resetTimeMs).toISOString();
const { cooldownMs, window: exhaustedWindow } = getCodexDualWindowCooldownMs(quota);
if (cooldownMs > 0) {
const scopeUntil = new Date(Date.now() + cooldownMs).toISOString();
const scopeMapRaw =
existingProviderData &&
typeof existingProviderData === "object" &&
@@ -456,6 +537,17 @@ export async function handleChatCore({
...(scopeMapRaw as Record<string, unknown>),
[scope]: scopeUntil,
};
nextProviderData.codexExhaustedWindow = exhaustedWindow;
log?.debug?.(
"CODEX",
`Quota exhaustion on ${exhaustedWindow} window, cooldown until ${scopeUntil}`
);
}
// Invalidate the preflight cache for this connection so the next
// isModelAvailable check fetches fresh quota data.
if (connectionId) {
invalidateCodexQuotaCache(connectionId);
}
}
@@ -563,6 +655,7 @@ export async function handleChatCore({
const targetFormat = modelTargetFormat || getTargetFormat(provider);
const noLogEnabled = apiKeyInfo?.noLog === true;
const detailedLoggingEnabled = !noLogEnabled && (await isDetailedLoggingEnabled());
const skillRequestId = generateRequestId();
const persistAttemptLogs = ({
status,
tokens,
@@ -716,6 +809,14 @@ export async function handleChatCore({
log?.debug?.("FORMAT", `${sourceFormat}${targetFormat} | stream=${stream}`);
// ── Common input sanitization (runs for ALL paths including passthrough) ──
// #994: Normalize max_output_tokens to max_tokens for universal compatibility
if (body.max_output_tokens !== undefined) {
if (body.max_tokens === undefined) {
body.max_tokens = body.max_output_tokens;
}
delete body.max_output_tokens;
}
// #291: Strip empty name fields from messages/input items
// Upstream providers (OpenAI, Codex) reject name:"" with 400 errors.
if (Array.isArray(body.messages)) {
@@ -780,6 +881,23 @@ export async function handleChatCore({
}
}
if (apiKeyInfo?.id && memorySettings?.skillsEnabled) {
const existingTools = Array.isArray(body.tools) ? body.tools : [];
const mergedTools = injectSkills({
provider: getSkillsProviderForFormat(sourceFormat),
existingTools,
apiKeyId: apiKeyInfo.id,
});
if (mergedTools.length > existingTools.length) {
body = {
...body,
tools: mergedTools,
};
log?.debug?.("SKILLS", `Injected ${mergedTools.length - existingTools.length} skills`);
}
}
// Translate request (pass reqLogger for intermediate logging)
let translatedBody = body;
const isClaudePassthrough = sourceFormat === FORMATS.CLAUDE && targetFormat === FORMATS.CLAUDE;
@@ -933,22 +1051,33 @@ export async function handleChatCore({
if (msg.role === "user" && Array.isArray(msg.content)) {
msg.content = (msg.content as Record<string, unknown>[]).flatMap(
(block: Record<string, unknown>) => {
if (block.type === "text" || block.type === "image_url" || block.type === "image") {
return [block];
}
// file / document → extract text content
if (block.type === "file" || block.type === "document") {
const fileContent =
(block.file as Record<string, unknown>)?.content ??
(block.file as Record<string, unknown>)?.text ??
block.content ??
block.text;
const fileName =
(block.file as Record<string, unknown>)?.name ?? block.name ?? "attachment";
if (typeof fileContent === "string" && fileContent.length > 0) {
return [{ type: "text", text: `[${fileName}]\n${fileContent}` }];
if (
block.type === "text" ||
block.type === "image_url" ||
block.type === "image" ||
block.type === "file_url" ||
block.type === "file" ||
block.type === "document"
) {
// Only extract text if it's explicitly a text-only representation without data
const fileData = (block.file_url ?? block.file ?? block.document) as any;
if (
(block.type === "file" || block.type === "document") &&
!fileData?.url &&
!fileData?.data
) {
const fileContent =
(block.file as Record<string, unknown>)?.content ??
(block.file as Record<string, unknown>)?.text ??
block.content ??
block.text;
const fileName =
(block.file as Record<string, unknown>)?.name ?? block.name ?? "attachment";
if (typeof fileContent === "string" && fileContent.length > 0) {
return [{ type: "text", text: `[${fileName}]\n${fileContent}` }];
}
}
return [];
return [block];
}
// (#527) tool_result → convert to text instead of dropping.
// When Claude Code + superpowers routes through Codex, it sends tool_result
@@ -1238,6 +1367,12 @@ export async function handleChatCore({
return {
...rawResult,
response: new Response(payload, { status, statusText, headers }),
_dedupSnapshot: {
status,
statusText,
headers,
payload,
},
};
};
@@ -1246,7 +1381,7 @@ export async function handleChatCore({
if (dedupResult.wasDeduplicated) {
log?.debug?.("DEDUP", `Joined in-flight request hash=${dedupHash}`);
}
return dedupResult.result;
return materializeDeduplicatedExecutionResult(dedupResult.result);
}
return execute();
@@ -1302,11 +1437,16 @@ export async function handleChatCore({
);
} catch (error) {
trackPendingRequest(model, provider, connectionId, false);
const failureStatus = error.name === "AbortError" ? 499 : HTTP_STATUS.BAD_GATEWAY;
const failureStatus =
error.name === "AbortError"
? 499
: error.name === "TimeoutError"
? HTTP_STATUS.GATEWAY_TIMEOUT
: HTTP_STATUS.BAD_GATEWAY;
const failureMessage =
error.name === "AbortError"
? "Request aborted"
: formatProviderError(error, provider, model, HTTP_STATUS.BAD_GATEWAY);
: formatProviderError(error, provider, model, failureStatus);
appendRequestLog({
model,
provider,
@@ -1325,11 +1465,11 @@ export async function handleChatCore({
return createErrorResult(499, "Request aborted");
}
persistFailureUsage(
HTTP_STATUS.BAD_GATEWAY,
failureStatus,
error instanceof Error && error.name ? error.name : "upstream_error"
);
console.log(`${COLORS.red}[ERROR] ${failureMessage}${COLORS.reset}`);
return createErrorResult(HTTP_STATUS.BAD_GATEWAY, failureMessage);
return createErrorResult(failureStatus, failureMessage);
}
// We need to peek at the error text if it's 400 for Qwen
let upstreamErrorParsed = false;
@@ -2029,6 +2169,35 @@ export async function handleChatCore({
}
}
const pipelineSessionId =
(clientRawRequest?.headers && typeof clientRawRequest.headers.get === "function"
? clientRawRequest.headers.get("x-omniroute-session-id")
: getHeaderValueCaseInsensitive(
clientRawRequest?.headers ?? null,
"x-omniroute-session-id"
)) || skillRequestId;
if (apiKeyInfo?.id && memorySettings?.enabled && memorySettings.maxTokens > 0) {
const memoryText = extractMemoryTextFromResponse(translatedResponse);
if (memoryText) {
extractFacts(memoryText, apiKeyInfo.id, pipelineSessionId);
}
}
if (apiKeyInfo?.id && memorySettings?.skillsEnabled) {
const skillSessionId = pipelineSessionId;
translatedResponse = await handleToolCallExecution(
translatedResponse,
getSkillsModelIdForFormat(sourceFormat),
{
apiKeyId: apiKeyInfo.id,
sessionId: skillSessionId,
requestId: skillRequestId,
}
);
}
// ── Phase 9.1: Cache store (non-streaming, temp=0) ──
if (isCacheable(body, clientRawRequest?.headers)) {
const signature = generateSignature(model, body.messages, body.temperature, body.top_p);

View File

@@ -226,85 +226,135 @@ export function translateNonStreamingResponse(
const root = toRecord(responseBody);
const response = toRecord(root.response ?? root);
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
if (candidates[0]) {
const candidate = toRecord(candidates[0]);
const content = toRecord(candidate.content);
const usage = toRecord(response.usageMetadata ?? root.usageMetadata);
let textContent = "";
const toolCalls: JsonRecord[] = [];
let reasoningContent = "";
if (Array.isArray(content.parts)) {
for (const part of content.parts) {
const partObj = toRecord(part);
if (partObj.thought === true && typeof partObj.text === "string") {
reasoningContent += partObj.text;
} else if (typeof partObj.text === "string") {
textContent += partObj.text;
}
if (partObj.functionCall) {
const fn = toRecord(partObj.functionCall);
toolCalls.push({
id: `call_${toString(fn.name, "unknown")}_${Date.now()}_${toolCalls.length}`,
type: "function",
function: {
name: toString(fn.name),
arguments: JSON.stringify(fn.args || {}),
},
});
}
}
}
const message: JsonRecord = { role: "assistant" };
if (textContent) {
message.content = textContent;
}
if (reasoningContent) {
message.reasoning_content = reasoningContent;
}
if (toolCalls.length > 0) {
message.tool_calls = toolCalls;
}
if (!message.content && !message.tool_calls) {
message.content = "";
}
let finishReason = toString(candidate.finishReason, "stop").toLowerCase();
if (finishReason === "stop" && toolCalls.length > 0) {
finishReason = "tool_calls";
}
const usage = toRecord(response.usageMetadata ?? root.usageMetadata);
const promptFeedback = toRecord(response.promptFeedback ?? root.promptFeedback);
if (candidates.length > 0 || Object.keys(promptFeedback).length > 0) {
const createdMs = Date.parse(toString(response.createTime));
const created = Number.isFinite(createdMs)
? Math.floor(createdMs / 1000)
: Math.floor(Date.now() / 1000);
const choices =
candidates.length > 0
? candidates.map((candidateValue, index) => {
const candidate = toRecord(candidateValue);
const content = toRecord(candidate.content);
let textContent = "";
const contentParts: JsonRecord[] = [];
const toolCalls: JsonRecord[] = [];
let reasoningContent = "";
if (Array.isArray(content.parts)) {
for (const part of content.parts) {
const partObj = toRecord(part);
if (partObj.thought === true && typeof partObj.text === "string") {
reasoningContent += partObj.text;
continue;
}
if (typeof partObj.text === "string") {
textContent += partObj.text;
contentParts.push({ type: "text", text: partObj.text });
}
const inlineData = toRecord(partObj.inlineData ?? partObj.inline_data);
if (typeof inlineData.data === "string" && inlineData.data.length > 0) {
const mimeType = toString(
inlineData.mimeType ?? inlineData.mime_type,
"image/png"
);
contentParts.push({
type: "image_url",
image_url: { url: `data:${mimeType};base64,${inlineData.data}` },
});
}
if (partObj.functionCall) {
const fn = toRecord(partObj.functionCall);
toolCalls.push({
id: `call_${toString(fn.name, "unknown")}_${Date.now()}_${toolCalls.length}`,
type: "function",
function: {
name: toString(fn.name),
arguments: JSON.stringify(fn.args || {}),
},
});
}
}
}
const message: JsonRecord = { role: "assistant" };
if (contentParts.length === 1 && contentParts[0].type === "text") {
message.content = contentParts[0].text;
} else if (contentParts.length > 0) {
message.content = contentParts;
} else if (textContent) {
message.content = textContent;
}
if (reasoningContent) {
message.reasoning_content = reasoningContent;
}
if (toolCalls.length > 0) {
message.tool_calls = toolCalls;
}
if (!message.content && !message.tool_calls) {
message.content = "";
}
let finishReason = toString(candidate.finishReason, "stop").toLowerCase();
if (finishReason === "max_tokens") {
finishReason = "length";
} else if (
finishReason === "safety" ||
finishReason === "recitation" ||
finishReason === "blocklist"
) {
finishReason = "content_filter";
} else if (finishReason === "stop" && toolCalls.length > 0) {
finishReason = "tool_calls";
}
return {
index,
message,
finish_reason: finishReason,
};
})
: [
{
index: 0,
message: { role: "assistant", content: "" },
finish_reason: "content_filter",
},
];
const result: JsonRecord = {
id: `chatcmpl-${toString(response.responseId, String(Date.now()))}`,
object: "chat.completion",
created,
model: toString(response.modelVersion, "gemini"),
choices: [
{
index: 0,
message,
finish_reason: finishReason,
},
],
choices,
};
if (Object.keys(usage).length > 0) {
const promptTokens = toNumber(usage.promptTokenCount, 0);
const reasoningTokens = toNumber(usage.thoughtsTokenCount, 0);
const completionTokens = toNumber(usage.candidatesTokenCount, 0) + reasoningTokens;
result.usage = {
prompt_tokens:
toNumber(usage.promptTokenCount, 0) + toNumber(usage.thoughtsTokenCount, 0),
completion_tokens: toNumber(usage.candidatesTokenCount, 0),
prompt_tokens: promptTokens,
completion_tokens: completionTokens,
total_tokens: toNumber(usage.totalTokenCount, 0),
};
if (toNumber(usage.thoughtsTokenCount, 0) > 0) {
if (reasoningTokens > 0) {
(result.usage as JsonRecord).completion_tokens_details = {
reasoning_tokens: toNumber(usage.thoughtsTokenCount, 0),
reasoning_tokens: reasoningTokens,
};
}
if (toNumber(usage.cachedContentTokenCount, 0) > 0) {
(result.usage as JsonRecord).prompt_tokens_details = {
cached_tokens: toNumber(usage.cachedContentTokenCount, 0),
};
}
}

View File

@@ -4,6 +4,11 @@
*/
export function extractUsageFromResponse(responseBody, provider) {
if (!responseBody || typeof responseBody !== "object") return null;
const providerId = typeof provider === "string" ? provider.toLowerCase() : "";
const isClaudeProvider =
providerId === "claude" ||
providerId === "anthropic" ||
providerId.startsWith("anthropic-compatible");
// OpenAI format (has prompt_tokens / completion_tokens)
if (
@@ -19,6 +24,29 @@ export function extractUsageFromResponse(responseBody, provider) {
};
}
// Claude format
if (
isClaudeProvider &&
responseBody.usage &&
typeof responseBody.usage === "object" &&
(responseBody.usage.input_tokens !== undefined ||
responseBody.usage.output_tokens !== undefined)
) {
const inputTokens = responseBody.usage.input_tokens || 0;
const cacheRead = responseBody.usage.cache_read_input_tokens || 0;
const cacheCreation = responseBody.usage.cache_creation_input_tokens || 0;
// Total prompt tokens = input + cache_read + cache_creation (per Claude API docs)
const promptTokens = inputTokens + cacheRead + cacheCreation;
return {
prompt_tokens: promptTokens,
completion_tokens: responseBody.usage.output_tokens || 0,
cache_read_input_tokens: cacheRead,
cache_creation_input_tokens: cacheCreation,
};
}
// OpenAI Responses API format (input_tokens / output_tokens)
const responsesUsage = responseBody.response?.usage || responseBody.usage;
if (
@@ -39,28 +67,6 @@ export function extractUsageFromResponse(responseBody, provider) {
};
}
// Claude format
if (
responseBody.usage &&
typeof responseBody.usage === "object" &&
(responseBody.usage.input_tokens !== undefined ||
responseBody.usage.output_tokens !== undefined)
) {
const inputTokens = responseBody.usage.input_tokens || 0;
const cacheRead = responseBody.usage.cache_read_input_tokens || 0;
const cacheCreation = responseBody.usage.cache_creation_input_tokens || 0;
// Total prompt tokens = input + cache_read + cache_creation (per Claude API docs)
const promptTokens = inputTokens + cacheRead + cacheCreation;
return {
prompt_tokens: promptTokens,
completion_tokens: responseBody.usage.output_tokens || 0,
cache_read_input_tokens: cacheRead,
cache_creation_input_tokens: cacheCreation,
};
}
// Gemini format
if (responseBody.usageMetadata && typeof responseBody.usageMetadata === "object") {
return {

View File

@@ -40,6 +40,7 @@ export const memoryTools = {
persistAcrossModels: false,
retentionDays: 30,
scope: "apiKey" as const,
query: args.query,
};
const memories = await retrieveMemories(args.apiKeyId, config);

View File

@@ -0,0 +1,266 @@
/**
* codexQuotaFetcher.ts — Codex Dual-Window Quota Fetcher
*
* Implements QuotaFetcher for the Codex provider (quotaPreflight.ts + quotaMonitor.ts).
*
* Codex has TWO independent quota windows:
* - Primary (5h): short-term rate limit, resets every 5 hours
* - Secondary (7d): weekly limit, resets every 7 days
*
* We return percentUsed = max(5h%, 7d%) so the system switches accounts when
* EITHER window approaches exhaustion (95% threshold).
*
* Cache: in-memory TTL (60s) to avoid hammering the usage API on every request.
* The connection pool is keyed by connectionId (providerConnection.id from DB).
*
* Registration: call registerCodexQuotaFetcher() once at server startup.
*/
import { registerQuotaFetcher, type QuotaInfo } from "./quotaPreflight.ts";
import { registerMonitorFetcher } from "./quotaMonitor.ts";
// Codex usage endpoint (same as usage.ts CODEX_CONFIG)
const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
// Cache TTL — short enough to be reactive, long enough to avoid rate limits
const CACHE_TTL_MS = 60_000; // 60 seconds
// Per-account quota window info (richer than QuotaInfo — includes both windows)
export interface CodexDualWindowQuota extends QuotaInfo {
window5h: { percentUsed: number; resetAt: string | null };
window7d: { percentUsed: number; resetAt: string | null };
limitReached: boolean;
}
interface CacheEntry {
quota: CodexDualWindowQuota;
fetchedAt: number;
}
// In-memory cache: connectionId → { quota, fetchedAt }
const quotaCache = new Map<string, CacheEntry>();
// Auto-cleanup stale entries every 5 minutes
const _cacheCleanup = setInterval(() => {
const now = Date.now();
for (const [key, entry] of quotaCache) {
if (now - entry.fetchedAt > CACHE_TTL_MS * 5) {
quotaCache.delete(key);
}
}
}, 5 * 60_000);
if (typeof _cacheCleanup === "object" && "unref" in _cacheCleanup) {
(_cacheCleanup as { unref?: () => void }).unref?.();
}
// ─── Connection registry ─────────────────────────────────────────────────────
// We need the accessToken + workspaceId to call the API.
// chatCore.ts registers connection metadata here before requests.
interface CodexConnectionMeta {
accessToken: string;
workspaceId?: string;
}
const connectionRegistry = new Map<string, CodexConnectionMeta>();
/**
* Register Codex connection metadata for quota fetching.
* Called by chatCore.ts when a Codex connection is resolved.
*
* @param connectionId - The connection ID from the DB (providerConnection.id)
* @param meta - Access token and optional workspace ID
*/
export function registerCodexConnection(connectionId: string, meta: CodexConnectionMeta): void {
connectionRegistry.set(connectionId, meta);
}
// ─── Core Fetcher ────────────────────────────────────────────────────────────
/**
* Fetch current quota for a Codex connection.
* Returns percentUsed = max(5h%, 7d%) — worst-case across both windows.
*
* @param connectionId - Connection ID from the DB (used to look up credentials)
* @returns QuotaInfo or null if fetch fails / no credentials
*/
export async function fetchCodexQuota(connectionId: string): Promise<QuotaInfo | null> {
// Check cache first
const cached = quotaCache.get(connectionId);
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
return cached.quota;
}
// Look up credentials
const meta = connectionRegistry.get(connectionId);
if (!meta?.accessToken) {
// No credentials registered — skip preflight gracefully
return null;
}
try {
const headers: Record<string, string> = {
Authorization: `Bearer ${meta.accessToken}`,
"Content-Type": "application/json",
Accept: "application/json",
};
if (meta.workspaceId) {
headers["chatgpt-account-id"] = meta.workspaceId;
}
const response = await fetch(CODEX_USAGE_URL, {
method: "GET",
headers,
signal: AbortSignal.timeout(8_000),
});
if (!response.ok) {
// Non-2xx: could be token expired or quota API down.
// Return null to proceed (fail-open — don't block on API errors).
if (response.status === 401 || response.status === 403) {
// Token expired — remove from cache so next call re-fetches
quotaCache.delete(connectionId);
connectionRegistry.delete(connectionId);
}
return null;
}
const data = await response.json();
const quota = parseCodexUsageResponse(data);
if (!quota) return null;
// Store in cache
quotaCache.set(connectionId, { quota, fetchedAt: Date.now() });
return quota;
} catch {
// Network error, timeout, etc. — fail open
return null;
}
}
// ─── Response Parser ─────────────────────────────────────────────────────────
function toNumber(value: unknown, fallback = 0): number {
if (typeof value === "number" && Number.isFinite(value)) return value;
if (typeof value === "string") {
const parsed = parseFloat(value);
if (Number.isFinite(parsed)) return parsed;
}
return fallback;
}
function toRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
}
function parseWindowReset(window: Record<string, unknown>): string | null {
const resetAt = toNumber(window["reset_at"] ?? window["resetAt"], 0);
if (resetAt > 0) {
return new Date(resetAt * 1000).toISOString();
}
const resetAfterSeconds = toNumber(
window["reset_after_seconds"] ?? window["resetAfterSeconds"],
0
);
if (resetAfterSeconds > 0) {
return new Date(Date.now() + resetAfterSeconds * 1000).toISOString();
}
return null;
}
function parseCodexUsageResponse(data: unknown): CodexDualWindowQuota | null {
const obj = toRecord(data);
const rateLimit = toRecord(obj["rate_limit"] ?? obj["rateLimit"]);
const primaryWindow = toRecord(rateLimit["primary_window"] ?? rateLimit["primaryWindow"]);
const secondaryWindow = toRecord(rateLimit["secondary_window"] ?? rateLimit["secondaryWindow"]);
// Require at least one window to be present
const hasPrimary = Object.keys(primaryWindow).length > 0;
const hasSecondary = Object.keys(secondaryWindow).length > 0;
if (!hasPrimary && !hasSecondary) return null;
// Parse 5h window
const usedPercent5h = hasPrimary
? toNumber(primaryWindow["used_percent"] ?? primaryWindow["usedPercent"], 0)
: 0;
const resetAt5h = hasPrimary ? parseWindowReset(primaryWindow) : null;
// Parse 7d window
const usedPercent7d = hasSecondary
? toNumber(secondaryWindow["used_percent"] ?? secondaryWindow["usedPercent"], 0)
: 0;
const resetAt7d = hasSecondary ? parseWindowReset(secondaryWindow) : null;
// Worst-case across both windows (triggers switch when EITHER is at 95%)
const worstPercentUsed = Math.max(usedPercent5h, usedPercent7d);
const percentUsedNormalized = worstPercentUsed / 100; // QuotaInfo uses 0..1
const limitReached = Boolean(rateLimit["limit_reached"] ?? rateLimit["limitReached"]);
return {
used: worstPercentUsed,
total: 100,
percentUsed: percentUsedNormalized,
window5h: { percentUsed: usedPercent5h / 100, resetAt: resetAt5h },
window7d: { percentUsed: usedPercent7d / 100, resetAt: resetAt7d },
limitReached,
};
}
// ─── Quota-Aware Reset Time ───────────────────────────────────────────────────
/**
* Get the cooldown duration (ms) for a Codex account based on its quota state.
*
* Logic:
* - If 7d window >= threshold → cooldown until 7d reset (longer)
* - If 5h window >= threshold → cooldown until 5h reset (shorter)
* - Otherwise → 0 (no cooldown)
*
* @param quota - The dual-window quota snapshot
* @param threshold - The fraction (0-1) that triggers a switch (default: 0.95)
* @returns Cooldown duration in milliseconds
*/
export function getCodexQuotaCooldownMs(quota: CodexDualWindowQuota, threshold = 0.95): number {
const now = Date.now();
// 7d window takes priority (if exhausted, must wait longer)
if (quota.window7d.percentUsed >= threshold && quota.window7d.resetAt) {
const resetTime = new Date(quota.window7d.resetAt).getTime();
if (resetTime > now) return resetTime - now;
}
// 5h window
if (quota.window5h.percentUsed >= threshold && quota.window5h.resetAt) {
const resetTime = new Date(quota.window5h.resetAt).getTime();
if (resetTime > now) return resetTime - now;
}
return 0;
}
// ─── Invalidation ────────────────────────────────────────────────────────────
/**
* Force-invalidate the cache for a connection (e.g., after receiving quota headers).
* Ensures the next preflight call fetches fresh data.
*/
export function invalidateCodexQuotaCache(connectionId: string): void {
quotaCache.delete(connectionId);
}
// ─── Registration ─────────────────────────────────────────────────────────────
/**
* Register the Codex quota fetcher with the preflight and monitor systems.
* Call this once at server startup (in chatCore.ts or app entry point).
*/
export function registerCodexQuotaFetcher(): void {
registerQuotaFetcher("codex", fetchCodexQuota);
registerMonitorFetcher("codex", fetchCodexQuota);
}

View File

@@ -961,6 +961,7 @@ interface RefreshLoggerLike {
export function isProviderBlocked(provider: string): boolean {
const state = _circuitBreaker[provider];
if (!state) return false;
if (!state.blockedUntil) return false;
if (state.blockedUntil > Date.now()) return true;
// Cooldown expired — reset
delete _circuitBreaker[provider];
@@ -1016,10 +1017,23 @@ function recordFailure(provider: string, log: RefreshLoggerLike | null = null) {
* Execute a function with a timeout.
*/
async function withTimeout<T>(fn: () => Promise<T>, timeoutMs: number): Promise<T | null> {
return Promise.race([
fn(),
new Promise<null>((resolve) => setTimeout(() => resolve(null), timeoutMs)),
]);
return await new Promise<T | null>((resolve, reject) => {
const timer = setTimeout(() => resolve(null), timeoutMs);
if (typeof timer === "object" && "unref" in timer) {
(timer as { unref?: () => void }).unref?.();
}
fn().then(
(result) => {
clearTimeout(timer);
resolve(result);
},
(error) => {
clearTimeout(timer);
reject(error);
}
);
});
}
export async function refreshWithRetry(

View File

@@ -75,17 +75,20 @@ export function convertOpenAIContentToParts(content) {
for (const item of content) {
if (item.type === "text") {
parts.push({ text: item.text });
} else if (item.type === "image_url" && item.image_url?.url?.startsWith("data:")) {
const url = item.image_url.url;
const commaIndex = url.indexOf(",");
if (commaIndex !== -1) {
const mimePart = url.substring(5, commaIndex); // skip "data:"
const data = url.substring(commaIndex + 1);
const mimeType = mimePart.split(";")[0];
} else {
const fileData =
item.image_url?.url || item.file_url?.url || item.file?.url || item.document?.url;
if (typeof fileData === "string" && fileData.startsWith("data:")) {
const commaIndex = fileData.indexOf(",");
if (commaIndex !== -1) {
const mimePart = fileData.substring(5, commaIndex); // skip "data:"
const data = fileData.substring(commaIndex + 1);
const mimeType = mimePart.split(";")[0];
parts.push({
inlineData: { mimeType, data },
});
parts.push({
inlineData: { mimeType, data },
});
}
}
}
}

View File

@@ -6,7 +6,8 @@ import { DEFAULT_MAX_TOKENS, DEFAULT_MIN_TOKENS } from "../../config/constants.t
* @returns {number} Adjusted max_tokens
*/
export function adjustMaxTokens(body) {
let maxTokens = body.max_tokens || DEFAULT_MAX_TOKENS;
const requestedMaxTokens = body.max_tokens ?? body.max_completion_tokens;
let maxTokens = requestedMaxTokens || DEFAULT_MAX_TOKENS;
// Auto-increase for tool calling to prevent truncated arguments
// Tool calls with large content (like writing files) need more tokens

View File

@@ -1,11 +1,22 @@
// OpenAI helper functions for translator
// Valid OpenAI content block types
export const VALID_OPENAI_CONTENT_TYPES = ["text", "image_url", "image"];
export const VALID_OPENAI_CONTENT_TYPES = [
"text",
"image_url",
"image",
"file_url",
"file",
"document",
];
export const VALID_OPENAI_MESSAGE_TYPES = [
"text",
"image_url",
"image",
"file_url",
"file",
"document",
"image",
"tool_calls",
"tool_result",
];

View File

@@ -27,6 +27,12 @@ export function claudeToOpenAIRequest(model, body, stream) {
if (body.temperature !== undefined) {
result.temperature = body.temperature;
}
if (body.top_p !== undefined) {
result.top_p = body.top_p;
}
if (body.stop_sequences !== undefined) {
result.stop = body.stop_sequences;
}
// System message
if (body.system) {
@@ -149,6 +155,7 @@ function convertClaudeMessage(msg) {
const parts = [];
const toolCalls = [];
const toolResults = [];
let reasoningContent = null;
for (const block of msg.content) {
switch (block.type) {
@@ -164,6 +171,23 @@ function convertClaudeMessage(msg) {
url: `data:${block.source.media_type};base64,${block.source.data}`,
},
});
} else if (block.source?.type === "url" && typeof block.source.url === "string") {
parts.push({
type: "image_url",
image_url: {
url: block.source.url,
},
});
}
break;
case "thinking":
reasoningContent = block.thinking || block.text || "";
break;
case "redacted_thinking":
if (reasoningContent == null) {
reasoningContent = "";
}
break;
@@ -217,20 +241,35 @@ function convertClaudeMessage(msg) {
result.content = parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts;
}
result.tool_calls = toolCalls;
if (reasoningContent !== null) {
result.reasoning_content = reasoningContent;
}
return result;
}
// Return content
if (parts.length > 0) {
return {
const result: JsonRecord = {
role,
content: parts.length === 1 && parts[0].type === "text" ? parts[0].text : parts,
};
if (reasoningContent !== null && role === "assistant") {
result.reasoning_content = reasoningContent;
}
return result;
}
// Empty content array
if (msg.content.length === 0) {
return { role, content: "" };
const result: JsonRecord = { role, content: "" };
if (reasoningContent !== null && role === "assistant") {
result.reasoning_content = reasoningContent;
}
return result;
}
if (reasoningContent !== null && role === "assistant") {
return { role, content: "", reasoning_content: reasoningContent };
}
}

View File

@@ -111,6 +111,12 @@ export function openaiToClaudeRequest(model, body, stream) {
if (body.temperature !== undefined) {
result.temperature = body.temperature;
}
if (body.top_p !== undefined) {
result.top_p = body.top_p;
}
if (body.stop !== undefined) {
result.stop_sequences = Array.isArray(body.stop) ? body.stop : [body.stop];
}
// Messages
const systemParts = [];
@@ -232,49 +238,42 @@ export function openaiToClaudeRequest(model, body, stream) {
}
}
// System with Claude Code prompt and cache_control
const claudeCodePrompt = { type: "text", text: CLAUDE_SYSTEM_PROMPT };
if (systemParts.length > 0) {
const systemText = systemParts.join("\n");
result.system = [
claudeCodePrompt,
{ type: "text", text: systemText, cache_control: { type: "ephemeral", ttl: "1h" } },
];
} else {
result.system = [claudeCodePrompt];
}
// Tools - convert from OpenAI format to Claude format with prefix for OAuth
if (body.tools && Array.isArray(body.tools)) {
result.tools = body.tools.map((tool) => {
const toolData = tool.type === "function" && tool.function ? tool.function : tool;
const originalName = toolData.name;
result.tools = body.tools
.map((tool) => {
const toolData = tool.type === "function" && tool.function ? tool.function : tool;
const originalName = typeof toolData.name === "string" ? toolData.name.trim() : "";
// Claude OAuth requires prefixed tool names to avoid conflicts
// When prefix is disabled (non-Claude backends), use original name
const toolName = disableToolPrefix ? originalName : CLAUDE_OAUTH_TOOL_PREFIX + originalName;
if (!originalName) {
return null;
}
// Store mapping for response translation (prefixed → original)
if (!disableToolPrefix) {
toolNameMap.set(toolName, originalName);
}
// Claude OAuth requires prefixed tool names to avoid conflicts
// When prefix is disabled (non-Claude backends), use original name
const toolName = disableToolPrefix ? originalName : CLAUDE_OAUTH_TOOL_PREFIX + originalName;
// Normalize input_schema: Anthropic requires `properties` when type is "object" (#595).
// MCP tools (e.g. pencil, computer_use) may omit properties on object-type schemas.
const rawSchema: Record<string, unknown> = toolData.parameters ||
toolData.input_schema || { type: "object", properties: {}, required: [] };
const normalizedSchema =
rawSchema.type === "object" && !rawSchema.properties
? { ...rawSchema, properties: {} }
: rawSchema;
// Store mapping for response translation (prefixed → original)
if (!disableToolPrefix) {
toolNameMap.set(toolName, originalName);
}
return {
name: toolName,
description: toolData.description || "",
input_schema: normalizedSchema,
};
});
// Normalize input_schema: Anthropic requires `properties` when type is "object" (#595).
// MCP tools (e.g. pencil, computer_use) may omit properties on object-type schemas.
const rawSchema: Record<string, unknown> = toolData.parameters ||
toolData.input_schema || { type: "object", properties: {}, required: [] };
const normalizedSchema =
rawSchema.type === "object" && !rawSchema.properties
? { ...rawSchema, properties: {} }
: rawSchema;
return {
name: toolName,
description: toolData.description || "",
input_schema: normalizedSchema,
};
})
.filter((tool): tool is ClaudeTool => Boolean(tool));
// Filter out tools with empty names (would cause Claude 400 error)
result.tools = result.tools.filter((tool) => tool.name && tool.name?.trim());
@@ -311,6 +310,19 @@ export function openaiToClaudeRequest(model, body, stream) {
}
}
// System with Claude Code prompt and cache_control
const claudeCodePrompt = { type: "text", text: CLAUDE_SYSTEM_PROMPT };
if (systemParts.length > 0) {
const systemText = systemParts.join("\n");
result.system = [
claudeCodePrompt,
{ type: "text", text: systemText, cache_control: { type: "ephemeral", ttl: "1h" } },
];
} else {
result.system = [claudeCodePrompt];
}
// Thinking configuration
if (body.thinking) {
result.thinking = {
@@ -399,6 +411,11 @@ function getContentBlocksFromMessage(msg, toolNameMap = new Map(), disableToolPr
type: "image",
source: { type: "base64", media_type: match[1], data: match[2] },
});
} else if (typeof url === "string" && url.trim()) {
blocks.push({
type: "image",
source: { type: "url", url },
});
}
} else if (part.type === "image" && part.source) {
blocks.push({ type: "image", source: part.source });

View File

@@ -90,7 +90,7 @@ function openaiToGeminiBase(model, body, stream) {
model: model,
contents: [],
generationConfig: {},
safetySettings: DEFAULT_SAFETY_SETTINGS,
safetySettings: body.safetySettings || DEFAULT_SAFETY_SETTINGS,
};
// Preserve cachedContent if provided by client (for explicit Gemini caching)
@@ -108,8 +108,12 @@ function openaiToGeminiBase(model, body, stream) {
if (body.top_k !== undefined) {
result.generationConfig.topK = body.top_k;
}
if (body.max_tokens !== undefined) {
result.generationConfig.maxOutputTokens = capMaxOutputTokens(model, body.max_tokens);
if (body.stop !== undefined) {
result.generationConfig.stopSequences = Array.isArray(body.stop) ? body.stop : [body.stop];
}
const requestedMaxOutputTokens = body.max_tokens ?? body.max_completion_tokens;
if (requestedMaxOutputTokens !== undefined) {
result.generationConfig.maxOutputTokens = capMaxOutputTokens(model, requestedMaxOutputTokens);
} else {
result.generationConfig.maxOutputTokens = capMaxOutputTokens(model);
}
@@ -146,10 +150,17 @@ function openaiToGeminiBase(model, body, stream) {
const content = msg.content;
if (role === "system" && body.messages.length > 1) {
result.systemInstruction = {
role: "user",
parts: [{ text: typeof content === "string" ? content : extractTextContent(content) }],
};
const systemText = typeof content === "string" ? content : extractTextContent(content);
if (systemText) {
if (!result.systemInstruction) {
result.systemInstruction = {
role: "user",
parts: [{ text: systemText }],
};
} else {
result.systemInstruction.parts.push({ text: systemText });
}
}
} else if (role === "user" || (role === "system" && body.messages.length === 1)) {
const parts = convertOpenAIContentToParts(content);
if (parts.length > 0) {

View File

@@ -4,7 +4,7 @@
*/
import { register } from "../registry.ts";
import { FORMATS } from "../formats.ts";
import { v4 as uuidv4 } from "uuid";
import { v4 as uuidv4, v5 as uuidv5 } from "uuid";
/**
* Convert OpenAI messages to Kiro format
@@ -252,7 +252,7 @@ function convertMessages(messages, tools, model) {
export function buildKiroPayload(model, body, stream, credentials) {
const messages = body.messages || [];
const tools = body.tools || [];
const maxTokens = 32000;
const maxTokens = body.max_tokens ?? body.max_completion_tokens ?? 32000;
const temperature = body.temperature;
const topP = body.top_p;
@@ -310,7 +310,6 @@ export function buildKiroPayload(model, body, stream, credentials) {
: finalContent;
// Use uuidv5 with the hash of the system prompt / first message to maintain AWS Builder ID context cache
const { v5: uuidv5 } = require("uuid");
payload.conversationState.conversationId = uuidv5(
(firstContent || "").substring(0, 4000),
NAMESPACE_KIRO

View File

@@ -8,10 +8,50 @@ export function geminiToOpenAIResponse(chunk, state) {
// Handle Antigravity wrapper
const response = chunk.response || chunk;
if (!response || !response.candidates?.[0]) return null;
if (!response) return null;
const results = [];
const candidate = response.candidates[0];
const candidate = response.candidates?.[0];
if (!candidate) {
const promptFeedback = response.promptFeedback || chunk.promptFeedback;
if (!promptFeedback) return null;
if (!state.messageId) {
state.messageId = response.responseId || `msg_${Date.now()}`;
state.model = response.modelVersion || "gemini";
results.push({
id: `chatcmpl-${state.messageId}`,
object: "chat.completion.chunk",
created: Math.floor(Date.now() / 1000),
model: state.model,
choices: [
{
index: 0,
delta: { role: "assistant" },
finish_reason: null,
},
],
});
}
results.push({
id: `chatcmpl-${state.messageId}`,
object: "chat.completion.chunk",
created: Math.floor(Date.now() / 1000),
model: state.model,
choices: [
{
index: 0,
delta: {},
finish_reason: "content_filter",
},
],
});
return results;
}
const content = candidate.content;
// Initialize state
@@ -238,6 +278,8 @@ export function geminiToOpenAIResponse(chunk, state) {
let finishReason = candidate.finishReason.toLowerCase();
if (finishReason === "stop" && state.toolCalls.size > 0) {
finishReason = "tool_calls";
} else if (finishReason === "max_tokens") {
finishReason = "length";
}
// Content blocked by Gemini safety filters — pass through as "content_filter"
// so downstream clients can distinguish from normal completion.

View File

@@ -20,7 +20,8 @@ import { formatSSE } from "./stream.ts";
* @returns {object|null} Bypass response or null to proceed normally
*/
export function handleBypassRequest(body, model, userAgent = "") {
if (!userAgent.includes("claude-cli")) return null;
const normalizedUserAgent = typeof userAgent === "string" ? userAgent : "";
if (!normalizedUserAgent.includes("claude-cli")) return null;
if (!body.messages?.length) return null;
const messages = body.messages;

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "omniroute",
"version": "3.5.2",
"version": "3.5.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "omniroute",
"version": "3.5.2",
"version": "3.5.3",
"hasInstallScript": true,
"license": "MIT",
"workspaces": [

View File

@@ -1,6 +1,6 @@
{
"name": "omniroute",
"version": "3.5.2",
"version": "3.5.3",
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
"type": "module",
"bin": {
@@ -72,10 +72,10 @@
"test:protocols:e2e": "node scripts/run-protocol-clients-tests.mjs",
"test:vitest": "vitest run --config vitest.mcp.config.ts",
"test:ecosystem": "node scripts/run-ecosystem-tests.mjs",
"test:coverage": "c8 --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 55 --lines 55 --functions 55 --branches 60 node --import tsx/esm --test tests/unit/*.test.mjs",
"test:coverage:legacy": "c8 --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx/esm --test tests/unit/*.test.mjs",
"coverage:report": "c8 report --exclude=tests/** --exclude=**/*.test.* --reporter=text --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov",
"coverage:report:legacy": "c8 report --exclude=open-sse --reporter=text --reporter=text-summary",
"test:coverage": "c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 55 --lines 55 --functions 55 --branches 60 node --import tsx/esm --test tests/unit/*.test.mjs",
"test:coverage:legacy": "c8 --output-dir coverage --exclude=open-sse --check-coverage --lines 50 --functions 50 --branches 50 node --import tsx/esm --test tests/unit/*.test.mjs",
"coverage:report": "c8 report --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov",
"coverage:report:legacy": "c8 report --output-dir coverage --exclude=open-sse --reporter=text --reporter=text-summary",
"test:all": "npm run test:unit && npm run test:vitest && npm run test:ecosystem && npm run test:e2e",
"check": "npm run lint && npm run test",
"prepublishOnly": "npm run build:cli",

View File

@@ -3,18 +3,20 @@ import { defineConfig, devices } from "@playwright/test";
const dashboardPort = process.env.DASHBOARD_PORT || process.env.PORT || "20128";
const dashboardBaseUrl = `http://localhost:${dashboardPort}`;
const webServerReadyUrl = `${dashboardBaseUrl}/api/monitoring/health`;
const playwrightServerMode = process.env.OMNIROUTE_PLAYWRIGHT_SERVER_MODE || "start";
export default defineConfig({
testDir: "./tests/e2e",
testMatch: ["**/*.spec.ts"],
fullyParallel: false,
timeout: 120_000,
timeout: 600_000,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1,
reporter: process.env.CI ? "github" : "html",
use: {
baseURL: dashboardBaseUrl,
navigationTimeout: 300_000,
trace: "on-first-retry",
screenshot: "only-on-failure",
},
@@ -25,11 +27,9 @@ export default defineConfig({
},
],
webServer: {
command: process.env.CI
? "node scripts/run-next-playwright.mjs start"
: "node scripts/run-next-playwright.mjs dev",
command: `node scripts/run-next-playwright.mjs ${playwrightServerMode}`,
url: webServerReadyUrl,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
timeout: 300_000,
},
});

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { existsSync, renameSync } from "node:fs";
import { join } from "node:path";
import {
@@ -8,6 +9,7 @@ import {
spawnWithForwardedSignals,
withRuntimePortEnv,
} from "./runtime-env.mjs";
import { bootstrapEnv } from "./bootstrap-env.mjs";
const mode = process.argv[2] === "start" ? "start" : "dev";
const cwd = process.cwd();
@@ -15,9 +17,16 @@ const appDir = join(cwd, "app");
const srcAppDir = join(cwd, "src", "app");
const appPage = join(appDir, "page.tsx");
const backupDir = join(cwd, "app.__qa_backup");
const buildScript = join(cwd, "scripts", "build-next-isolated.mjs");
const standaloneServer = join(cwd, testDistDir(), "standalone", "server.js");
const buildIdFile = join(cwd, testDistDir(), "BUILD_ID");
let appDirMoved = false;
function testDistDir() {
return process.env.NEXT_DIST_DIR || ".next";
}
function shouldMoveAppDir() {
return existsSync(appDir) && !existsSync(appPage) && existsSync(srcAppDir);
}
@@ -54,23 +63,93 @@ process.on("uncaughtException", (error) => {
prepareAppDir();
const runtimePorts = resolveRuntimePorts();
const bootstrapEnvVars = bootstrapEnv({ quiet: true });
const runtimePorts = resolveRuntimePorts(bootstrapEnvVars);
const testServerEnv = {
...sanitizeColorEnv(bootstrapEnvVars),
...sanitizeColorEnv(process.env),
NEXT_PUBLIC_OMNIROUTE_E2E_MODE: process.env.NEXT_PUBLIC_OMNIROUTE_E2E_MODE || "1",
OMNIROUTE_DISABLE_BACKGROUND_SERVICES: process.env.OMNIROUTE_DISABLE_BACKGROUND_SERVICES || "1",
OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK: process.env.OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK || "1",
OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK: process.env.OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK || "1",
OMNIROUTE_HIDE_HEALTHCHECK_LOGS: process.env.OMNIROUTE_HIDE_HEALTHCHECK_LOGS || "1",
};
const args = [
"./node_modules/next/dist/bin/next",
mode,
"--port",
String(runtimePorts.dashboardPort),
];
if (mode === "dev") {
args.splice(2, 0, "--webpack");
function runChild(command, args, env) {
return new Promise((resolve) => {
const child = spawn(command, args, {
stdio: "inherit",
env,
});
const forward = (signal) => {
if (!child.killed) child.kill(signal);
};
process.on("SIGINT", forward);
process.on("SIGTERM", forward);
child.on("exit", (code, signal) => {
process.off("SIGINT", forward);
process.off("SIGTERM", forward);
resolve({ code: code ?? 1, signal: signal ?? null });
});
});
}
spawnWithForwardedSignals(process.execPath, args, {
stdio: "inherit",
env: withRuntimePortEnv(testServerEnv, runtimePorts),
});
async function runBuildForStart() {
if (mode !== "start") return;
if (process.env.OMNIROUTE_PLAYWRIGHT_SKIP_BUILD === "1") return;
if (existsSync(buildIdFile)) return;
const buildEnv = withRuntimePortEnv(testServerEnv, runtimePorts);
const result = await runChild(process.execPath, [buildScript], buildEnv);
if (result.signal) {
process.kill(process.pid, result.signal);
return;
}
if (result.code !== 0) {
process.exit(result.code);
}
}
await runBuildForStart();
if (mode === "start") {
if (existsSync(standaloneServer)) {
spawnWithForwardedSignals(process.execPath, [standaloneServer], {
stdio: "inherit",
env: {
...withRuntimePortEnv(testServerEnv, runtimePorts),
PORT: String(runtimePorts.dashboardPort),
HOSTNAME: process.env.HOSTNAME || "127.0.0.1",
},
});
} else {
const args = [
"./node_modules/next/dist/bin/next",
"start",
"--port",
String(runtimePorts.dashboardPort),
];
spawnWithForwardedSignals(process.execPath, args, {
stdio: "inherit",
env: withRuntimePortEnv(testServerEnv, runtimePorts),
});
}
} else {
const args = [
"./node_modules/next/dist/bin/next",
mode,
"--webpack",
"--port",
String(runtimePorts.dashboardPort),
];
spawnWithForwardedSignals(process.execPath, args, {
stdio: "inherit",
env: withRuntimePortEnv(testServerEnv, runtimePorts),
});
}

View File

@@ -102,7 +102,7 @@ export default function MemorySkillsTab() {
if (loading) {
return (
<Card>
<Card data-testid="memory-settings-card">
<div className="flex items-center gap-3">
<div className="p-2 rounded-lg bg-violet-500/10 text-violet-500">
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
@@ -148,6 +148,7 @@ export default function MemorySkillsTab() {
<p className="text-xs text-text-muted mt-0.5">{t("memoryEnabledDesc")}</p>
</div>
<button
data-testid="memory-enabled-switch"
onClick={() => save({ enabled: !config.enabled })}
disabled={saving}
className={`relative w-11 h-6 rounded-full transition-colors ${
@@ -176,6 +177,7 @@ export default function MemorySkillsTab() {
</span>
</div>
<input
data-testid="memory-max-tokens-slider"
type="range"
min="0"
max="16000"
@@ -201,6 +203,7 @@ export default function MemorySkillsTab() {
</span>
</div>
<input
data-testid="memory-retention-slider"
type="range"
min="1"
max="90"
@@ -221,6 +224,7 @@ export default function MemorySkillsTab() {
<div className="grid grid-cols-3 gap-2">
{STRATEGIES.map((s) => (
<button
data-testid={`memory-strategy-${s.value}`}
key={s.value}
onClick={() => save({ strategy: s.value as "recent" | "semantic" | "hybrid" })}
disabled={loading || saving}
@@ -244,7 +248,7 @@ export default function MemorySkillsTab() {
</Card>
{/* Skills Settings (placeholder) */}
<Card>
<Card data-testid="skills-settings-card">
<div className="flex items-center gap-3 mb-5">
<div className="p-2 rounded-lg bg-amber-500/10 text-amber-500">
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
@@ -263,6 +267,7 @@ export default function MemorySkillsTab() {
<p className="text-xs text-text-muted mt-0.5">{t("skillsEnabledDesc")}</p>
</div>
<button
data-testid="skills-enabled-switch"
onClick={() => save({ skillsEnabled: !config.skillsEnabled })}
disabled={saving}
className={`relative w-11 h-6 rounded-full transition-colors ${

View File

@@ -137,7 +137,7 @@ export default function SkillsPage() {
if (!res.ok) {
setMpError(data.error || "Search failed");
} else {
setMpResults(data.skills || []);
setMpResults(Array.isArray(data) ? data : data.skills || []);
}
} catch (err) {
setMpError(err instanceof Error ? err.message : "Search failed");

View File

@@ -1,9 +1,13 @@
import { NextResponse } from "next/server";
import { getApiKeyById } from "@/lib/localDb";
import { isApiKeyRevealEnabled } from "@/lib/apiKeyExposure";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
// GET /api/keys/[id]/reveal - Reveal full API key for explicit copy actions
export async function GET(_request, { params }) {
export async function GET(request, { params }) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
if (!isApiKeyRevealEnabled()) {
return NextResponse.json({ error: "API key reveal is disabled" }, { status: 403 });

View File

@@ -9,9 +9,13 @@ import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { updateKeyPermissionsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
// GET /api/keys/[id] - Get single API key
export async function GET(request, { params }) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const { id } = await params;
const key = await getApiKeyById(id);
@@ -34,6 +38,9 @@ export async function GET(request, { params }) {
// PATCH /api/keys/[id] - Update API key permissions/privacy controls
export async function PATCH(request, { params }) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
let rawBody;
try {
rawBody = await request.json();
@@ -103,6 +110,9 @@ export async function PATCH(request, { params }) {
// DELETE /api/keys/[id] - Delete API key
export async function DELETE(request, { params }) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const { id } = await params;

View File

@@ -1,20 +1,47 @@
import { NextResponse } from "next/server";
import { getApiKeys, createApiKey, isCloudEnabled } from "@/lib/localDb";
import { getApiKeys, createApiKey, isCloudEnabled, updateApiKeyPermissions } from "@/lib/localDb";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { createKeySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { isApiKeyRevealEnabled, maskStoredApiKey } from "@/lib/apiKeyExposure";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
function parsePagination(request: Request) {
const url = new URL(request.url);
const limitValue = url.searchParams.get("limit");
const offsetValue = url.searchParams.get("offset");
const parsedLimit = limitValue ? Number.parseInt(limitValue, 10) : undefined;
const parsedOffset = offsetValue ? Number.parseInt(offsetValue, 10) : 0;
const limit =
Number.isInteger(parsedLimit) && parsedLimit && parsedLimit > 0 ? parsedLimit : null;
const offset = Number.isInteger(parsedOffset) && parsedOffset > 0 ? parsedOffset : 0;
return { limit, offset };
}
// GET /api/keys - List API keys
export async function GET() {
export async function GET(request: Request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const keys = await getApiKeys();
const maskedKeys = keys.map((k) => ({
...k,
key: maskStoredApiKey(k.key),
}));
return NextResponse.json({ keys: maskedKeys, allowKeyReveal: isApiKeyRevealEnabled() });
const { limit, offset } = parsePagination(request);
const pagedKeys =
limit === null ? maskedKeys.slice(offset) : maskedKeys.slice(offset, offset + limit);
return NextResponse.json({
keys: pagedKeys,
total: maskedKeys.length,
allowKeyReveal: isApiKeyRevealEnabled(),
});
} catch (error) {
console.log("Error fetching keys:", error);
return NextResponse.json({ error: "Failed to fetch keys" }, { status: 500 });
@@ -23,6 +50,9 @@ export async function GET() {
// POST /api/keys - Create new API key
export async function POST(request) {
const authError = await requireManagementAuth(request);
if (authError) return authError;
try {
const body = await request.json();
@@ -31,11 +61,14 @@ export async function POST(request) {
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const { name } = validation.data;
const { name, noLog } = validation.data;
// Always get machineId from server
const machineId = await getConsistentMachineId();
const apiKey = await createApiKey(name, machineId);
if (noLog === true) {
await updateApiKeyPermissions(apiKey.id, { noLog: true });
}
// Auto sync to Cloud if enabled
await syncKeysToCloudIfEnabled();
@@ -46,6 +79,7 @@ export async function POST(request) {
name: apiKey.name,
id: apiKey.id,
machineId: apiKey.machineId,
noLog: noLog === true,
},
{ status: 201 }
);

View File

@@ -20,6 +20,12 @@ function toHex(bytes: Uint8Array): string {
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
}
function isBackgroundServicesDisabled(): boolean {
const raw = process.env.OMNIROUTE_DISABLE_BACKGROUND_SERVICES;
if (!raw) return false;
return new Set(["1", "true", "yes", "on"]).has(raw.trim().toLowerCase());
}
async function ensureSecrets(): Promise<void> {
let getPersistedSecret = (_key: string): string | null => null;
let persistSecret = (_key: string, _value: string): void => {};
@@ -91,10 +97,12 @@ export async function registerNodejs(): Promise<void> {
initGracefulShutdown();
initApiBridgeServer();
startBackgroundRefresh();
console.log("[STARTUP] Quota cache background refresh started");
startProviderLimitsSyncScheduler();
console.log("[STARTUP] Provider limits sync scheduler started");
if (!isBackgroundServicesDisabled()) {
startBackgroundRefresh();
console.log("[STARTUP] Quota cache background refresh started");
startProviderLimitsSyncScheduler();
console.log("[STARTUP] Provider limits sync scheduler started");
}
try {
const [{ setCustomAliases }, { setDefaultFastServiceTierEnabled }] = await Promise.all([

View File

@@ -10,9 +10,13 @@ export async function requireManagementAuth(request: Request): Promise<Response
return null;
}
const authHeader = request.headers.get("authorization");
const hasBearerToken =
typeof authHeader === "string" && authHeader.trim().toLowerCase().startsWith("bearer ");
return createErrorResponse({
status: 401,
message: "Authentication required",
status: hasBearerToken ? 403 : 401,
message: hasBearerToken ? "Invalid management token" : "Authentication required",
type: "invalid_request",
});
}

View File

@@ -5,7 +5,16 @@ import "@/lib/tokenHealthCheck"; // Proactive token health-check scheduler
// Initialize background sync services when this module is imported
let initialized = false;
function isBackgroundServicesDisabled(): boolean {
const raw = process.env.OMNIROUTE_DISABLE_BACKGROUND_SERVICES;
if (!raw) return false;
return new Set(["1", "true", "yes", "on"]).has(raw.trim().toLowerCase());
}
export async function ensureCloudSyncInitialized() {
if (isBackgroundServicesDisabled()) {
return false;
}
if (!initialized) {
try {
await initializeCloudSync();

View File

@@ -31,6 +31,7 @@ const BACKOFF_SCHEDULE = [30_000, 60_000, 120_000, 300_000];
const CHECK_TIMEOUT_MS = 5_000;
const INITIAL_DELAY_MS = 15_000; // Wait for server boot before first sweep
const LOG_PREFIX = "[LocalHealthCheck]";
const TRUE_ENV_VALUES = new Set(["1", "true", "yes", "on"]);
// ── State (globalThis survives HMR re-evaluation) ───────────────────────
@@ -61,6 +62,16 @@ const healthCache = getLHCState().healthCache;
// ── Helpers ──────────────────────────────────────────────────────────────
function isEnvFlagEnabled(name: string): boolean {
const value = process.env[name];
if (!value) return false;
return TRUE_ENV_VALUES.has(value.trim().toLowerCase());
}
function isLocalHealthCheckDisabled(): boolean {
return isEnvFlagEnabled("OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK") || process.env.NODE_ENV === "test";
}
function isLocalhostUrl(baseUrl: string): boolean {
try {
const u = new URL(baseUrl);
@@ -212,7 +223,7 @@ export function getAllHealthStatuses(): Record<string, HealthStatus> {
/** Start the health check scheduler (idempotent). */
export function initLocalHealthCheck(): void {
const state = getLHCState();
if (state.initialized) return;
if (state.initialized || isLocalHealthCheckDisabled()) return;
state.initialized = true;
console.log(

View File

@@ -1,42 +1,50 @@
import { getDbInstance } from "../db/core";
interface MemoryCache {
key: string;
value: any;
timestamp: number;
ttl: number;
value: unknown;
expiresAt: number;
}
class MemoryCachingLayer {
private cache: Map<string, MemoryCache> = new Map();
private maxSize: number = 1000;
private defaultTtl: number = 300000;
private hits: number = 0;
private misses: number = 0;
async get(key: string): Promise<any | null> {
async get(key: string): Promise<unknown | null> {
const entry = this.cache.get(key);
if (!entry) return null;
if (Date.now() - entry.timestamp > entry.ttl) {
this.cache.delete(key);
if (!entry) {
this.misses += 1;
return null;
}
if (Date.now() > entry.expiresAt) {
this.cache.delete(key);
this.misses += 1;
return null;
}
this.hits += 1;
this.cache.delete(key);
this.cache.set(key, entry);
return entry.value;
}
async set(key: string, value: any, ttl?: number): Promise<void> {
if (this.cache.size >= this.maxSize) {
const oldest = Array.from(this.cache.entries()).sort(
(a, b) => a[1].timestamp - b[1].timestamp
)[0];
this.cache.delete(oldest[0]);
async set(key: string, value: unknown, ttl?: number): Promise<void> {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.maxSize) {
const oldestKey = this.cache.keys().next().value;
if (oldestKey) {
this.cache.delete(oldestKey);
}
}
const now = Date.now();
this.cache.set(key, {
key,
value,
timestamp: Date.now(),
ttl: ttl || this.defaultTtl,
expiresAt: now + (ttl ?? this.defaultTtl),
});
}
@@ -51,12 +59,16 @@ class MemoryCachingLayer {
async clear(): Promise<void> {
this.cache.clear();
this.hits = 0;
this.misses = 0;
}
stats() {
return {
size: this.cache.size,
maxSize: this.maxSize,
hits: this.hits,
misses: this.misses,
};
}
}

View File

@@ -2,6 +2,29 @@ import { getDbInstance } from "../db/core";
import { Memory, MemoryConfig, MemoryType } from "./types";
import { MemoryConfigSchema } from "./schemas";
interface MemoryRow {
id: string;
api_key_id?: string;
apiKeyId?: string;
session_id?: string | null;
sessionId?: string | null;
type: MemoryType;
key?: string | null;
content: string;
metadata?: string | null;
created_at?: string;
createdAt?: string;
updated_at?: string;
updatedAt?: string;
expires_at?: string | null;
expiresAt?: string | null;
}
interface RetrievalOptions extends Partial<MemoryConfig> {
query?: string;
sessionId?: string;
}
/**
* Simple token estimation function (roughly 1 token per 4 characters)
*/
@@ -10,12 +33,82 @@ export function estimateTokens(text: string): number {
return Math.ceil(text.length / 4);
}
function hasTable(tableName: string): boolean {
const db = getDbInstance();
const row = db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get(tableName) as { name?: string } | undefined;
return row?.name === tableName;
}
function parseMetadata(raw: unknown): Record<string, unknown> {
if (!raw || typeof raw !== "string") return {};
try {
const parsed = JSON.parse(raw);
return typeof parsed === "object" && parsed !== null ? parsed : {};
} catch {
return {};
}
}
function rowToMemory(row: MemoryRow): Memory {
const createdAt = row.created_at || row.createdAt || new Date().toISOString();
const updatedAt = row.updated_at || row.updatedAt || createdAt;
const expiresAt = row.expires_at ?? row.expiresAt ?? null;
return {
id: String(row.id),
apiKeyId: String(row.api_key_id || row.apiKeyId || ""),
sessionId: String(row.session_id ?? row.sessionId ?? ""),
type: row.type as MemoryType,
key: String(row.key || ""),
content: String(row.content || ""),
metadata: parseMetadata(row.metadata),
createdAt: new Date(createdAt),
updatedAt: new Date(updatedAt),
expiresAt: expiresAt ? new Date(String(expiresAt)) : null,
};
}
function getRelevanceScore(memory: Memory, query: string): number {
const normalizedQuery = query.trim().toLowerCase();
if (!normalizedQuery) return 0;
const haystacks = [
memory.content.toLowerCase(),
memory.key.toLowerCase(),
JSON.stringify(memory.metadata).toLowerCase(),
];
const tokens = normalizedQuery.split(/\s+/).filter(Boolean);
let score = 0;
for (const haystack of haystacks) {
if (haystack.includes(normalizedQuery)) {
score += 20;
}
for (const token of tokens) {
if (!token) continue;
if (haystack === memory.key.toLowerCase() && haystack.includes(token)) {
score += 6;
continue;
}
const matches = haystack.match(new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"));
score += (matches?.length || 0) * 3;
}
}
return score;
}
/**
* Retrieve memories with token budget enforcement
*/
export async function retrieveMemories(
apiKeyId: string,
config: Partial<MemoryConfig> = {}
config: RetrievalOptions = {}
): Promise<Memory[]> {
// Validate and normalize config
const normalizedConfig = MemoryConfigSchema.parse({
@@ -33,23 +126,45 @@ export async function retrieveMemories(
return [];
}
const maxTokens = Math.min(Math.max(normalizedConfig.maxTokens, 100), 8000);
const maxTokens = Math.min(Math.max(normalizedConfig.maxTokens, 1), 8000);
const strategy = normalizedConfig.retrievalStrategy;
const db = getDbInstance();
const memories: Memory[] = [];
const memories: Array<{ memory: Memory; score: number }> = [];
let totalTokens = 0;
const useModernTable = hasTable("memories");
const tableName = useModernTable ? "memories" : "memory";
const columns = useModernTable
? {
apiKeyId: "api_key_id",
sessionId: "session_id",
createdAt: "created_at",
expiresAt: "expires_at",
}
: {
apiKeyId: "apiKeyId",
sessionId: "sessionId",
createdAt: "createdAt",
expiresAt: "expiresAt",
};
// Build base query
let query =
"SELECT * FROM memory WHERE apiKeyId = ? AND (expiresAt IS NULL OR datetime(expiresAt) > datetime('now'))";
`SELECT * FROM ${tableName} WHERE ${columns.apiKeyId} = ? ` +
`AND (${columns.expiresAt} IS NULL OR datetime(${columns.expiresAt}) > datetime('now'))`;
const params: any[] = [apiKeyId];
if (normalizedConfig.scope === "session" && config.sessionId) {
query += ` AND ${columns.sessionId} = ?`;
params.push(config.sessionId);
}
if (normalizedConfig.retentionDays > 0) {
const cutoff = new Date(
Date.now() - normalizedConfig.retentionDays * 24 * 60 * 60 * 1000
).toISOString();
query += " AND datetime(createdAt) >= datetime(?)";
query += ` AND datetime(${columns.createdAt}) >= datetime(?)`;
params.push(cutoff);
}
@@ -57,15 +172,15 @@ export async function retrieveMemories(
switch (strategy) {
case "semantic":
// For now, semantic search is same as exact (FTS5 not implemented yet)
query += " ORDER BY createdAt DESC";
query += ` ORDER BY ${columns.createdAt} DESC`;
break;
case "hybrid":
// Hybrid is same as exact for now
query += " ORDER BY createdAt DESC";
query += ` ORDER BY ${columns.createdAt} DESC`;
break;
case "exact":
default:
query += " ORDER BY createdAt DESC";
query += ` ORDER BY ${columns.createdAt} DESC`;
}
// Add limit for performance
@@ -73,29 +188,23 @@ export async function retrieveMemories(
// Execute query
const stmt = db.prepare(query);
const rows = stmt.all(...params);
const rows = stmt.all(...params) as MemoryRow[];
const rankedRows = rows
.map((row) => {
const memory = rowToMemory(row);
const score = config.query ? getRelevanceScore(memory, config.query) : 0;
return { memory, score };
})
.filter((entry) => !config.query || entry.score > 0)
.sort((a, b) => {
if (b.score !== a.score) return b.score - a.score;
return b.memory.createdAt.getTime() - a.memory.createdAt.getTime();
});
// Process memories until budget exceeded
for (const row of rows) {
const memory: Memory = {
id: String((row as any).id),
apiKeyId: String((row as any).apiKeyId),
sessionId: String((row as any).sessionId),
type: (row as any).type as MemoryType,
key: String((row as any).key),
content: String((row as any).content),
metadata: (() => {
try {
return JSON.parse(String((row as any).metadata));
} catch {
return {};
}
})(),
createdAt: new Date(String((row as any).createdAt)),
updatedAt: new Date(String((row as any).updatedAt)),
expiresAt: (row as any).expiresAt ? new Date(String((row as any).expiresAt)) : null,
};
for (const entry of rankedRows) {
const memory = entry.memory;
// Estimate tokens for this memory
const memoryTokens = estimateTokens(memory.content);
@@ -103,16 +212,16 @@ export async function retrieveMemories(
if (totalTokens + memoryTokens > maxTokens) {
// If we haven't added any memories yet, add this one anyway
if (memories.length === 0) {
memories.push(memory);
memories.push(entry);
totalTokens += memoryTokens;
}
break;
}
// Add memory to results
memories.push(memory);
memories.push(entry);
totalTokens += memoryTokens;
}
return memories;
return memories.map((entry) => entry.memory);
}

View File

@@ -2,13 +2,27 @@
* Memory store - CRUD operations with prepared statements and caching
*/
import { getDbInstance, rowToCamel } from "../db/core";
import { getDbInstance } from "../db/core";
import { Memory, MemoryType } from "./types";
interface CacheEntry<T> {
value: T;
timestamp: number;
}
interface MemoryRow {
id: string;
api_key_id: string;
session_id: string | null;
type: MemoryType;
key: string | null;
content: string;
metadata: string | null;
created_at: string;
updated_at: string;
expires_at: string | null;
}
// Memory cache configuration
const MEMORY_CACHE_TTL = 300_000; // 5 minutes
const MEMORY_MAX_CACHE_SIZE = 10_000;
@@ -29,14 +43,10 @@ function parseJSON(value: unknown): Record<string, unknown> {
}
}
// Cache invalidation strategy
function invalidateMemoryCache(key: string) {
_memoryCache.delete(key);
}
/**
* Memory cache management with size control
*/
function evictIfNeeded<TKey, TValue>(cache: Map<TKey, TValue>) {
if (cache.size > MEMORY_MAX_CACHE_SIZE) {
// Remove oldest entries first
@@ -48,57 +58,19 @@ function evictIfNeeded<TKey, TValue>(cache: Map<TKey, TValue>) {
}
}
/**
* Get or compile regex for wildcard pattern
*/
function getWildcardRegex(pattern: string): RegExp {
// This function is copied from apiKeys.ts pattern
let regex = _regexCache.get(pattern);
if (!regex) {
const regexStr = pattern.replace(/\*/g, ".*");
regex = new RegExp(`^${regexStr}$`);
_regexCache.set(pattern, regex);
// Prevent unbounded growth
if (_regexCache.size > 100) {
const firstKey = _regexCache.keys().next().value;
if (firstKey) _regexCache.delete(firstKey);
}
}
return regex;
}
// Compiled regex cache for wildcard patterns
const _regexCache = new Map<string, RegExp>();
// Cache for memory validation (similar to apiKeys)
const _memoryValidationCache = new Map<string, { exists: boolean; timestamp: number }>();
const MEMORY_VALIDATION_CACHE_TTL = 60 * 1000; // 1 minute TTL
/**
* Check if memory exists with caching
*/
async function memoryExists(id: string): Promise<boolean> {
if (!id || typeof id !== "string") return false;
const now = Date.now();
// Check cache first
const cached = _memoryValidationCache.get(id);
if (cached && now - cached.timestamp < MEMORY_VALIDATION_CACHE_TTL) {
return cached.exists;
}
const db = getDbInstance();
const stmt = db.prepare("SELECT 1 FROM memory WHERE id = ?");
const row = stmt.get(id);
const exists = !!row;
// Cache the result to prevent cache pollution
if (exists) {
_memoryValidationCache.set(id, { exists: true, timestamp: now });
}
return exists;
function rowToMemory(row: MemoryRow): Memory {
return {
id: String(row.id),
apiKeyId: String(row.api_key_id),
sessionId: typeof row.session_id === "string" ? row.session_id : "",
type: row.type as MemoryType,
key: typeof row.key === "string" ? row.key : "",
content: String(row.content),
metadata: parseJSON(row.metadata),
createdAt: new Date(String(row.created_at)),
updatedAt: new Date(String(row.updated_at)),
expiresAt: row.expires_at ? new Date(String(row.expires_at)) : null,
};
}
/**
@@ -112,7 +84,7 @@ export async function createMemory(
const now = new Date().toISOString();
const stmt = db.prepare(
"INSERT INTO memory (id, apiKeyId, sessionId, type, key, content, metadata, createdAt, updatedAt, expiresAt) " +
"INSERT INTO memories (id, api_key_id, session_id, type, key, content, metadata, created_at, updated_at, expires_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
@@ -123,7 +95,7 @@ export async function createMemory(
memory.type,
memory.key,
memory.content,
JSON.stringify(memory.metadata),
JSON.stringify(memory.metadata ?? {}),
now,
now,
memory.expiresAt?.toISOString() ?? null
@@ -163,8 +135,8 @@ export async function getMemory(id: string): Promise<Memory | null> {
}
const db = getDbInstance();
const stmt = db.prepare("SELECT * FROM memory WHERE id = ?");
const row = stmt.get(id) as any;
const stmt = db.prepare("SELECT * FROM memories WHERE id = ?");
const row = stmt.get(id) as MemoryRow | undefined;
if (!row) {
// Cache negative result briefly to prevent repeated DB hits
@@ -173,18 +145,7 @@ export async function getMemory(id: string): Promise<Memory | null> {
return null;
}
const memory: Memory = {
id: String(row.id),
apiKeyId: String(row.apiKeyId),
sessionId: String(row.sessionId),
type: row.type as MemoryType,
key: String(row.key),
content: String(row.content),
metadata: parseJSON(row.metadata),
createdAt: new Date(String(row.createdAt)),
updatedAt: new Date(String(row.updatedAt)),
expiresAt: row.expiresAt ? new Date(String(row.expiresAt)) : null,
};
const memory = rowToMemory(row);
// Cache the result
evictIfNeeded(_memoryCache);
@@ -207,7 +168,7 @@ export async function updateMemory(
// Build dynamic update query
const fields: string[] = [];
const values: any[] = [];
const values: unknown[] = [];
if (updates.type !== undefined) {
fields.push("type = ?");
@@ -226,21 +187,17 @@ export async function updateMemory(
values.push(JSON.stringify(updates.metadata));
}
if (updates.expiresAt !== undefined) {
fields.push("expiresAt = ?");
fields.push("expires_at = ?");
values.push(updates.expiresAt?.toISOString() ?? null);
}
// Always update the updatedAt timestamp
fields.push("updatedAt = ?");
fields.push("updated_at = ?");
values.push(now);
if (fields.length === 0) {
return false; // No updates to apply
}
values.push(id); // For WHERE clause
const stmt = db.prepare(`UPDATE memory SET ${fields.join(", ")} WHERE id = ?`);
const stmt = db.prepare(`UPDATE memories SET ${fields.join(", ")} WHERE id = ?`);
const result = stmt.run(...values);
@@ -261,7 +218,7 @@ export async function deleteMemory(id: string): Promise<boolean> {
if (!id || typeof id !== "string") return false;
const db = getDbInstance();
const stmt = db.prepare("DELETE FROM memory WHERE id = ?");
const stmt = db.prepare("DELETE FROM memories WHERE id = ?");
const result = stmt.run(id);
if (result.changes === 0) {
@@ -287,12 +244,12 @@ export async function listMemories(filters: {
const db = getDbInstance();
// Build dynamic query
let query = "SELECT * FROM memory";
const params: any[] = [];
let query = "SELECT * FROM memories";
const params: unknown[] = [];
const whereClauses: string[] = [];
if (filters.apiKeyId) {
whereClauses.push("apiKeyId = ?");
whereClauses.push("api_key_id = ?");
params.push(filters.apiKeyId);
}
@@ -302,7 +259,7 @@ export async function listMemories(filters: {
}
if (filters.sessionId) {
whereClauses.push("sessionId = ?");
whereClauses.push("session_id = ?");
params.push(filters.sessionId);
}
@@ -311,7 +268,7 @@ export async function listMemories(filters: {
}
// Add ordering and pagination
query += " ORDER BY createdAt DESC";
query += " ORDER BY created_at DESC";
if (filters.limit !== undefined) {
query += " LIMIT ?";
@@ -319,6 +276,9 @@ export async function listMemories(filters: {
}
if (filters.offset !== undefined) {
if (filters.limit === undefined) {
query += " LIMIT -1";
}
query += " OFFSET ?";
params.push(filters.offset);
}
@@ -326,16 +286,5 @@ export async function listMemories(filters: {
const stmt = db.prepare(query);
const rows = stmt.all(...params);
return (rows as any[]).map((row: any) => ({
id: String(row.id),
apiKeyId: String(row.apiKeyId),
sessionId: String(row.sessionId),
type: row.type as MemoryType,
key: String(row.key),
content: String(row.content),
metadata: parseJSON(row.metadata),
createdAt: new Date(String(row.createdAt)),
updatedAt: new Date(String(row.updatedAt)),
expiresAt: row.expiresAt ? new Date(String(row.expiresAt)) : null,
}));
return (rows as MemoryRow[]).map(rowToMemory);
}

View File

@@ -91,7 +91,10 @@ function estimateTokens(text: string): number {
}
function generateSummary(content: string): string {
const sentences = content.split(/[.!?]+/).filter((s) => s.trim().length > 0);
const sentences = content
.split(/[.!?]+/)
.map((sentence) => sentence.trim())
.filter((sentence) => sentence.length > 0);
if (sentences.length <= 3) {
return content;
}

View File

@@ -235,6 +235,7 @@ export const PROVIDERS = {
QWEN: "qwen",
QODER: "qoder",
ANTIGRAVITY: "antigravity",
KIMI_CODING: "kimi-coding",
OPENAI: "openai",
GITHUB: "github",
KIRO: "kiro",

View File

@@ -31,9 +31,15 @@ export async function interceptToolCalls(
sessionId: context.sessionId,
});
const result =
execution.output ??
(execution.errorMessage
? { error: execution.errorMessage }
: { error: "Skill execution returned no output" });
return {
id: call.id,
result: execution.output,
result,
};
} catch (err) {
return {
@@ -51,12 +57,21 @@ export function extractToolCalls(response: any, modelId: string): ToolCall[] {
const provider = detectProvider(modelId);
switch (provider) {
case "openai":
return (response.tool_calls || []).map((tc: any) => ({
case "openai": {
const rootToolCalls = Array.isArray(response?.tool_calls) ? response.tool_calls : [];
const choiceToolCalls = Array.isArray(response?.choices)
? response.choices.flatMap((choice: any) =>
Array.isArray(choice?.message?.tool_calls) ? choice.message.tool_calls : []
)
: [];
const toolCalls = rootToolCalls.length > 0 ? rootToolCalls : choiceToolCalls;
return toolCalls.map((tc: any) => ({
id: tc.id || `call_${Date.now()}`,
name: tc.function?.name || "",
arguments: parseArguments(tc.function?.arguments || "{}"),
}));
}
case "anthropic":
return (response.content || [])

View File

@@ -7,14 +7,88 @@
* @module middleware/promptInjectionGuard
*/
import { sanitizeRequest } from "../shared/utils/inputSanitizer";
import { extractMessageContents, sanitizeRequest } from "../shared/utils/inputSanitizer";
/**
* @typedef {Object} GuardOptions
* @property {"block"|"warn"|"log"} [mode="warn"] - Action on detection
* @property {boolean} [enabled=true] - Whether the guard is active
* @property {"low"|"medium"|"high"} [blockThreshold="high"] - Minimum severity to block
* @property {Array<string|RegExp|{name?: string, pattern: string|RegExp, severity?: "low"|"medium"|"high"}>} [customPatterns]
* @property {Object} [logger] - Logger instance (defaults to console)
*/
const DEFAULT_GUARD_PATTERNS = [
{
name: "system_override_inline",
pattern: /\bsystem\s*:\s*override\b/i,
severity: "high",
},
{
name: "markdown_system_block",
pattern: /```+\s*system\b/i,
severity: "high",
},
];
const SEVERITY_SCORES = {
low: 1,
medium: 2,
high: 3,
};
function normalizePatternEntry(entry: any, index: number) {
if (entry instanceof RegExp) {
return {
name: `custom_${index}`,
pattern: entry,
severity: "high",
};
}
if (typeof entry === "string") {
return {
name: `custom_${index}`,
pattern: new RegExp(entry, "i"),
severity: "high",
};
}
if (!entry || (!(entry.pattern instanceof RegExp) && typeof entry.pattern !== "string")) {
return null;
}
return {
name: entry.name || `custom_${index}`,
pattern: entry.pattern instanceof RegExp ? entry.pattern : new RegExp(entry.pattern, "i"),
severity: entry.severity || "high",
};
}
function detectWithPatterns(text: string, patterns: any[]) {
const detections = [];
for (const rule of patterns) {
const match = text.match(rule.pattern);
if (match) {
detections.push({
pattern: rule.name,
severity: rule.severity,
match: match[0].slice(0, 50),
});
}
}
return detections;
}
function shouldBlock(detections: any[], threshold: string) {
const minimumSeverity = SEVERITY_SCORES[threshold as keyof typeof SEVERITY_SCORES] || 3;
return detections.some(
(d) => (SEVERITY_SCORES[d.severity as keyof typeof SEVERITY_SCORES] || 0) >= minimumSeverity
);
}
/**
* Create a prompt injection guard middleware.
*
@@ -22,8 +96,14 @@ import { sanitizeRequest } from "../shared/utils/inputSanitizer";
* @returns {(req: Request) => { blocked: boolean, result: Object }|null}
*/
export function createInjectionGuard(options: any = {}) {
const mode = options.mode || process.env.INJECTION_GUARD_MODE || "warn";
const mode =
options.mode || process.env.INJECTION_GUARD_MODE || process.env.INPUT_SANITIZER_MODE || "warn";
const enabled = options.enabled ?? process.env.INPUT_SANITIZER_ENABLED !== "false";
const blockThreshold = options.blockThreshold || options.threshold || "high";
const logger = options.logger || console;
const customPatterns = [...DEFAULT_GUARD_PATTERNS, ...(options.customPatterns || [])]
.map(normalizePatternEntry)
.filter(Boolean);
/**
* Check a request body for prompt injection.
@@ -32,28 +112,43 @@ export function createInjectionGuard(options: any = {}) {
* @returns {{ blocked: boolean, result: Object }}
*/
return function guardRequest(body: any) {
if (!body || typeof body !== "object") {
if (!enabled || !body || typeof body !== "object") {
return { blocked: false, result: { flagged: false, detections: [], piiDetections: [] } };
}
const result: any = sanitizeRequest(body, logger);
const contents = extractMessageContents(body);
const customDetections = detectWithPatterns(contents.join("\n"), customPatterns);
if (customDetections.length > 0) {
const existingDetections = new Set(
result.detections.map((d) => `${d.pattern}:${d.match}:${d.severity}`)
);
for (const detection of customDetections) {
const key = `${detection.pattern}:${detection.match}:${detection.severity}`;
if (!existingDetections.has(key)) {
result.detections.push(detection);
}
}
}
result.flagged = result.detections.length > 0 || result.piiDetections.length > 0;
// Check if any detections were found (sanitizeRequest returns .detections, NOT .flagged)
if (result.detections.length === 0 && result.piiDetections.length === 0) {
if (!result.flagged) {
return { blocked: false, result };
}
const highSeverity = result.detections.filter((d) => d.severity === "high");
if (mode === "block" && highSeverity.length > 0) {
logger.warn("[InjectionGuard] Blocked request with high-severity injection:", {
if (mode === "block" && shouldBlock(result.detections, blockThreshold)) {
logger.warn?.("[InjectionGuard] Blocked request with prompt injection:", {
detections: result.detections.map((d) => ({ pattern: d.pattern, severity: d.severity })),
});
return { blocked: true, result };
}
if (mode === "warn" || mode === "log") {
logger[mode === "warn" ? "warn" : "info"](
logger[mode === "warn" ? "warn" : "info"]?.(
"[InjectionGuard] Detected potential injection patterns:",
{
detections: result.detections.map((d) => ({ pattern: d.pattern, severity: d.severity })),

View File

@@ -19,6 +19,8 @@ import {
ANTHROPIC_COMPATIBLE_PREFIX,
} from "@/shared/constants/providers";
const isE2EMode = process.env.NEXT_PUBLIC_OMNIROUTE_E2E_MODE === "1";
function usePageInfo(pathname: string | null): {
title: string;
description: string;
@@ -213,8 +215,8 @@ export default function Header({ onMenuClick, showMenuButton = true }) {
<ThemeToggle />
{/* Degradation & Token health */}
<DegradationBadge />
<TokenHealthBadge />
{!isE2EMode && <DegradationBadge />}
{!isE2EMode && <TokenHealthBadge />}
{/* Logout button */}
<button

View File

@@ -18,6 +18,8 @@ import {
normalizeHiddenSidebarItems,
} from "@/shared/constants/sidebarVisibility";
const isE2EMode = process.env.NEXT_PUBLIC_OMNIROUTE_E2E_MODE === "1";
export default function Sidebar({
onClose,
collapsed = false,
@@ -282,7 +284,7 @@ export default function Sidebar({
})}
</nav>
<CloudSyncStatus collapsed={collapsed} />
{!isE2EMode && <CloudSyncStatus collapsed={collapsed} />}
<div
className={cn(

View File

@@ -8,6 +8,7 @@ import NotificationToast from "../NotificationToast";
import MaintenanceBanner from "../MaintenanceBanner";
const SIDEBAR_COLLAPSED_KEY = "sidebar-collapsed";
const isE2EMode = process.env.NEXT_PUBLIC_OMNIROUTE_E2E_MODE === "1";
export default function DashboardLayout({ children }) {
const [sidebarOpen, setSidebarOpen] = useState(false);
@@ -56,7 +57,7 @@ export default function DashboardLayout({ children }) {
className="flex flex-col flex-1 h-full min-w-0 relative transition-colors duration-300"
>
<Header onMenuClick={() => setSidebarOpen(true)} />
<MaintenanceBanner />
{!isE2EMode && <MaintenanceBanner />}
<div className="flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar p-4 sm:p-6 lg:p-10">
<div className="max-w-7xl mx-auto w-full">
<Breadcrumbs />

View File

@@ -58,6 +58,7 @@ export const createProviderSchema = z.object({
export const createKeySchema = z.object({
name: z.string().min(1, "Name is required").max(200),
noLog: z.boolean().optional(),
});
// ──── Combo Schemas ────

View File

@@ -62,6 +62,16 @@ import {
isFallbackDecision,
shouldUseFallback,
} from "@omniroute/open-sse/services/emergencyFallback.ts";
import {
registerCodexQuotaFetcher,
registerCodexConnection,
fetchCodexQuota,
} from "@omniroute/open-sse/services/codexQuotaFetcher.ts";
// Register Codex quota fetcher at module load (once per server start).
// This hooks into the quotaPreflight + quotaMonitor systems so that combos
// can proactively switch accounts before the 5h or 7d quota is exhausted.
registerCodexQuotaFetcher();
/**
* Handle chat completion request
@@ -262,6 +272,35 @@ export async function handleChat(request: any, clientRawRequest: any = null) {
modelInfo.model || modelString
);
if (!creds || creds.allRateLimited) return false;
// ── Codex Quota Preflight (Item 1-2) ──────────────────────────────────
// Proactively skip Codex accounts that have consumed >= 95% of either
// their 5h or 7d quota window. This prevents requests from failing with
// a 429 and then retrying — we switch accounts early instead.
if (provider === "codex" && creds.connectionId) {
// Register connection metadata so the fetcher can call the usage API
if (creds.accessToken) {
registerCodexConnection(creds.connectionId, {
accessToken: creds.accessToken,
workspaceId:
typeof creds.providerSpecificData?.workspaceId === "string"
? creds.providerSpecificData.workspaceId
: undefined,
});
}
const quotaInfo = await fetchCodexQuota(creds.connectionId);
if (quotaInfo && quotaInfo.percentUsed >= 0.95) {
const pct = (quotaInfo.percentUsed * 100).toFixed(1);
log.info(
"QUOTA_PREFLIGHT",
`Skipping Codex account ${creds.connectionId.slice(0, 8)}...: quota at ${pct}% (preflight)`
);
return false;
}
}
// ──────────────────────────────────────────────────────────────────────
return true;
};

View File

@@ -0,0 +1,236 @@
import { expect, test, type Page, type Route } from "@playwright/test";
const NAVIGATION_TIMEOUT_MS = 300_000;
const UI_STABILITY_TIMEOUT_MS = 120_000;
type ApiKeyRecord = {
id: string;
name: string;
key: string;
fullKey: string;
allowedModels: string[] | null;
allowedConnections: string[] | null;
createdAt: string;
};
async function fulfillJson(route: Route, body: unknown, status = 200) {
await route.fulfill({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
}
async function installClipboardMock(page: Page) {
await page.addInitScript(() => {
let clipboardValue = "";
Object.defineProperty(window, "__clipboardValue", {
configurable: true,
get: () => clipboardValue,
set: (value) => {
clipboardValue = typeof value === "string" ? value : String(value ?? "");
},
});
Object.defineProperty(navigator, "clipboard", {
configurable: true,
value: {
writeText: async (value: string) => {
(window as Window & { __clipboardValue?: string }).__clipboardValue = value;
},
readText: async () => clipboardValue,
},
});
});
}
async function readClipboard(page: Page) {
return page.evaluate(() => (window as Window & { __clipboardValue?: string }).__clipboardValue);
}
async function gotoOrSkip(page: Page, url: string) {
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await page.goto(url, { waitUntil: "commit", timeout: NAVIGATION_TIMEOUT_MS });
} catch (error) {
lastError = error;
}
try {
await page.waitForURL(/\/(login|dashboard)(\/.*)?$/, { timeout: NAVIGATION_TIMEOUT_MS });
await page.locator("body").waitFor({ state: "visible", timeout: NAVIGATION_TIMEOUT_MS });
lastError = null;
break;
} catch (error) {
lastError = error;
}
await page.waitForTimeout(1000);
}
if (lastError) throw lastError;
const redirectedToLogin = page.url().includes("/login");
test.skip(redirectedToLogin, "Authentication enabled without a login fixture.");
}
async function waitForPageToSettle(page: Page) {
try {
await page.waitForLoadState("networkidle", { timeout: 15_000 });
} catch {
// Some dashboard pages keep background requests alive; visibility assertions below
// are the authoritative readiness check for these E2E flows.
}
}
async function waitForNextDevCompileToFinish(page: Page) {
const nextDevToolsButton = page.getByRole("button", { name: /open next\.js dev tools/i });
if ((await nextDevToolsButton.count()) === 0) return;
await expect(nextDevToolsButton).not.toContainText(/compiling/i, { timeout: 120_000 });
}
test.describe("API keys flow", () => {
test.setTimeout(600_000);
test("creates, copies, reveals, revokes, and returns to the empty state", async ({ page }) => {
const state: {
keys: ApiKeyRecord[];
nextId: number;
revealCalls: number;
deleteCalls: number;
} = {
keys: [],
nextId: 1,
revealCalls: 0,
deleteCalls: 0,
};
await installClipboardMock(page);
await page.route("**/v1/models", async (route) => {
await fulfillJson(route, { data: [] });
});
await page.route("**/api/settings", async (route) => {
await fulfillJson(route, {});
});
await page.route("**/api/providers", async (route) => {
await fulfillJson(route, {
connections: [
{ id: "conn-openai", name: "OpenAI Main", provider: "openai", isActive: true },
],
});
});
await page.route(/\/api\/usage\/call-logs(?:\?.*)?$/, async (route) => {
await fulfillJson(route, []);
});
await page.route("**/api/sessions", async (route) => {
await fulfillJson(route, { byApiKey: {} });
});
await page.route(/\/api\/keys\/[^/]+\/reveal$/, async (route) => {
state.revealCalls += 1;
const keyId = route.request().url().split("/").slice(-2)[0];
const record = state.keys.find((key) => key.id === keyId);
await fulfillJson(route, { key: record?.fullKey ?? "" });
});
await page.route(/\/api\/keys\/[^/]+$/, async (route) => {
if (route.request().method() === "DELETE") {
state.deleteCalls += 1;
const keyId = route.request().url().split("/").pop() || "";
state.keys = state.keys.filter((key) => key.id !== keyId);
await fulfillJson(route, { success: true });
return;
}
await fulfillJson(route, { error: "Method not allowed in api key detail stub" }, 405);
});
await page.route("**/api/keys", async (route) => {
const method = route.request().method();
if (method === "GET") {
await fulfillJson(route, {
keys: state.keys.map(({ fullKey, ...record }) => record),
allowKeyReveal: true,
});
return;
}
if (method === "POST") {
const payload = (route.request().postDataJSON() as { name?: string }) || {};
const id = `key-${state.nextId++}`;
const suffix = String(1000 + state.nextId);
const fullKey = `sk-live-${suffix}-demo-secret`;
const maskedKey = `sk-live-****${suffix}`;
state.keys.push({
id,
name: payload.name || "New Key",
key: maskedKey,
fullKey,
allowedModels: null,
allowedConnections: null,
createdAt: new Date("2026-04-05T20:00:00.000Z").toISOString(),
});
await fulfillJson(route, { key: fullKey, id });
return;
}
await fulfillJson(route, { error: "Method not allowed in api keys stub" }, 405);
});
await gotoOrSkip(page, "/dashboard/api-manager");
await waitForPageToSettle(page);
await waitForNextDevCompileToFinish(page);
const createFirstKeyButton = page.getByRole("button", {
name: /create (your )?first key/i,
});
await expect(createFirstKeyButton).toBeVisible({ timeout: UI_STABILITY_TIMEOUT_MS });
await waitForPageToSettle(page);
await waitForNextDevCompileToFinish(page);
await createFirstKeyButton.click();
const createDialog = page.getByRole("dialog", { name: /create api key/i });
await expect(createDialog).toBeVisible({ timeout: UI_STABILITY_TIMEOUT_MS });
await createDialog.locator("input").first().fill("Team Key");
const createKeyButton = createDialog.getByRole("button", { name: /create api key/i });
await expect(createKeyButton).toBeEnabled({ timeout: UI_STABILITY_TIMEOUT_MS });
await createKeyButton.click({ force: true });
await expect.poll(() => state.keys.length).toBe(1);
const createdDialog = page.getByRole("dialog", { name: /api key created/i });
const createdKeyInput = createdDialog.locator("input[readonly]").first();
await expect(createdKeyInput).toHaveValue(/sk-live-/);
await createdDialog.getByRole("button", { name: /copy/i }).click();
await expect.poll(() => readClipboard(page)).toBeTruthy();
const createdClipboardValue = await readClipboard(page);
await expect(createdKeyInput).toHaveValue(createdClipboardValue || "");
await createdDialog.getByRole("button", { name: /done/i }).click();
await expect(page.getByText("Team Key")).toBeVisible();
await expect(page.getByText("sk-live-****1002")).toBeVisible();
const keyRow = page
.locator("div")
.filter({ has: page.getByText("Team Key", { exact: true }) })
.filter({ has: page.getByText("sk-live-****1002", { exact: true }) })
.first();
await keyRow.getByRole("button", { name: /copy/i }).click();
await expect.poll(() => state.revealCalls).toBe(1);
await expect.poll(() => readClipboard(page)).toBe("sk-live-1002-demo-secret");
page.once("dialog", async (dialog) => {
await dialog.accept();
});
await keyRow.locator("button[title]").last().click({ force: true });
await expect.poll(() => state.deleteCalls).toBe(1);
await expect(page.getByText("Team Key")).toHaveCount(0);
await expect(createFirstKeyButton).toBeVisible();
});
});

View File

@@ -0,0 +1,197 @@
import { expect, test, type Page, type Route } from "@playwright/test";
const NAVIGATION_TIMEOUT_MS = 300_000;
type MemoryConfig = {
enabled: boolean;
maxTokens: number;
retentionDays: number;
strategy: "recent" | "semantic" | "hybrid";
skillsEnabled: boolean;
};
type MemoryEntry = {
id: string;
apiKeyId: string;
sessionId: string | null;
type: "factual" | "episodic" | "procedural" | "semantic";
key: string;
content: string;
metadata: Record<string, unknown>;
createdAt: string;
updatedAt: string;
expiresAt: string | null;
};
async function fulfillJson(route: Route, body: unknown, status = 200) {
await route.fulfill({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
}
async function gotoOrSkip(page: Page, url: string) {
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await page.goto(url, { waitUntil: "commit", timeout: NAVIGATION_TIMEOUT_MS });
} catch (error) {
lastError = error;
}
try {
await page.waitForURL(/\/(login|dashboard)(\/.*)?$/, { timeout: NAVIGATION_TIMEOUT_MS });
await page.locator("body").waitFor({ state: "visible", timeout: NAVIGATION_TIMEOUT_MS });
lastError = null;
break;
} catch (error) {
lastError = error;
}
await page.waitForTimeout(1000);
}
if (lastError) throw lastError;
const redirectedToLogin = page.url().includes("/login");
test.skip(redirectedToLogin, "Authentication enabled without a login fixture.");
}
async function setRangeValue(page: Page, testId: string, value: number) {
await page.getByTestId(testId).evaluate((element, nextValue) => {
const input = element as HTMLInputElement;
const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
valueSetter?.call(input, String(nextValue));
input.dispatchEvent(new Event("input", { bubbles: true }));
input.dispatchEvent(new Event("change", { bubbles: true }));
}, value);
}
test.describe("Memory settings", () => {
test.setTimeout(600_000);
test("updates memory config in settings and deletes stored memory entries", async ({ page }) => {
const state: {
config: MemoryConfig;
settings: { skillsmpApiKey: string };
memories: MemoryEntry[];
updateCalls: number;
deleteCalls: number;
} = {
config: {
enabled: false,
maxTokens: 2000,
retentionDays: 30,
strategy: "hybrid",
skillsEnabled: false,
},
settings: {
skillsmpApiKey: "",
},
memories: [
{
id: "mem-1",
apiKeyId: "key-1",
sessionId: "session-a",
type: "factual",
key: "preferred_language",
content: "The user prefers answers in Portuguese.",
metadata: {},
createdAt: new Date("2026-04-05T20:00:00.000Z").toISOString(),
updatedAt: new Date("2026-04-05T20:00:00.000Z").toISOString(),
expiresAt: null,
},
],
updateCalls: 0,
deleteCalls: 0,
};
await page.route("**/api/settings", async (route) => {
const method = route.request().method();
if (method === "GET") {
await fulfillJson(route, state.settings);
return;
}
if (method === "PATCH") {
const payload = (route.request().postDataJSON() as Record<string, unknown>) || {};
state.settings = {
...state.settings,
...(typeof payload.skillsmpApiKey === "string"
? { skillsmpApiKey: payload.skillsmpApiKey }
: {}),
};
await fulfillJson(route, state.settings);
return;
}
await fulfillJson(route, { error: "Method not allowed in settings stub" }, 405);
});
await page.route("**/api/settings/memory", async (route) => {
const method = route.request().method();
if (method === "GET") {
await fulfillJson(route, state.config);
return;
}
if (method === "PUT") {
state.updateCalls += 1;
const payload = (route.request().postDataJSON() as Partial<MemoryConfig>) || {};
state.config = {
...state.config,
...payload,
};
await fulfillJson(route, state.config);
return;
}
await fulfillJson(route, { error: "Method not allowed in memory settings stub" }, 405);
});
await page.route("**/api/memory", async (route) => {
await fulfillJson(route, {
memories: state.memories,
stats: {
totalEntries: state.memories.length,
tokensUsed: state.memories.length * 24,
hitRate: state.memories.length > 0 ? 0.75 : 0,
},
});
});
await page.route(/\/api\/memory\/[^/]+$/, async (route) => {
state.deleteCalls += 1;
const memoryId = route.request().url().split("/").pop() || "";
state.memories = state.memories.filter((memory) => memory.id !== memoryId);
await fulfillJson(route, { success: true });
});
await gotoOrSkip(page, "/dashboard/settings?tab=ai");
await expect(page.getByTestId("memory-settings-card")).toBeVisible();
await expect(page.getByTestId("memory-enabled-switch")).toHaveAttribute(
"aria-checked",
"false"
);
await page.getByTestId("memory-enabled-switch").click();
await expect(page.getByTestId("memory-enabled-switch")).toHaveAttribute("aria-checked", "true");
await expect.poll(() => state.config.enabled).toBe(true);
await setRangeValue(page, "memory-retention-slider", 45);
await expect.poll(() => state.config.retentionDays).toBe(45);
await page.getByTestId("memory-strategy-recent").click();
await expect.poll(() => state.config.strategy).toBe("recent");
await expect.poll(() => state.updateCalls).toBeGreaterThanOrEqual(3);
await page.getByTestId("memory-enabled-switch").click();
await expect(page.getByTestId("memory-enabled-switch")).toHaveAttribute(
"aria-checked",
"false"
);
await expect.poll(() => state.config.enabled).toBe(false);
await gotoOrSkip(page, "/dashboard/memory");
await expect(page.getByText("preferred_language")).toBeVisible();
await page.getByRole("button", { name: /delete/i }).click();
await expect.poll(() => state.deleteCalls).toBe(1);
await expect(page.getByText("preferred_language")).toHaveCount(0);
});
});

View File

@@ -0,0 +1,330 @@
import { expect, test, type Page } from "@playwright/test";
const NAVIGATION_TIMEOUT_MS = 300_000;
type ProviderConnection = {
id: string;
provider: string;
name: string;
authType: "api_key";
isActive: boolean;
testStatus: string;
priority: number;
providerSpecificData: Record<string, unknown>;
lastError: string | null;
lastErrorAt: string | null;
lastErrorType: string | null;
lastErrorSource: string | null;
errorCode: string | null;
rateLimitedUntil: string | null;
};
async function installProviderFetchMock(page: Page) {
await page.addInitScript(() => {
const state = {
connections: [] as ProviderConnection[],
nextId: 1,
retestCalls: 0,
deleteCalls: 0,
validationCalls: 0,
forceInvalidValidation: false,
};
const clone = <T>(value: T): T => JSON.parse(JSON.stringify(value));
const jsonResponse = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), {
status,
headers: { "Content-Type": "application/json" },
});
const readJsonBody = async (request: Request): Promise<Record<string, unknown>> => {
try {
const rawBody = await request.clone().text();
if (!rawBody) return {};
const parsed = JSON.parse(rawBody);
return parsed && typeof parsed === "object" ? parsed : {};
} catch {
return {};
}
};
Object.defineProperty(window, "__providersTestState", {
configurable: true,
value: state,
});
const originalFetch = window.fetch.bind(window);
window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
const request = input instanceof Request ? input : new Request(input, init);
const url = new URL(request.url, window.location.origin);
const method = request.method.toUpperCase();
const path = url.pathname;
if (path === "/api/providers/expiration") {
return jsonResponse({
summary: { expired: 0, expiringSoon: 0 },
list: [],
});
}
if (path === "/api/provider-nodes") {
return jsonResponse({
nodes: [],
ccCompatibleProviderEnabled: false,
});
}
if (path === "/api/models/alias") {
if (method === "GET") {
return jsonResponse({ aliases: {} });
}
return jsonResponse({ success: true });
}
if (path === "/api/settings/proxy") {
if (url.searchParams.has("resolve")) {
return jsonResponse({ proxy: null, level: null });
}
return jsonResponse({ providers: {} });
}
if (path === "/api/provider-models") {
return jsonResponse({
models: [],
modelCompatOverrides: [],
});
}
if (path === "/api/rate-limits") {
return jsonResponse({ providers: [] });
}
if (path === "/api/providers/validate") {
state.validationCalls += 1;
const valid = !state.forceInvalidValidation;
return jsonResponse({ valid }, valid ? 200 : 400);
}
const testMatch = path.match(/^\/api\/providers\/([^/]+)\/test$/);
if (testMatch && method === "POST") {
state.retestCalls += 1;
const connectionId = testMatch[1];
state.connections = state.connections.map((connection) =>
connection.id === connectionId
? {
...connection,
testStatus: "active",
lastError: null,
lastErrorAt: null,
lastErrorType: null,
lastErrorSource: null,
errorCode: null,
rateLimitedUntil: null,
}
: connection
);
return jsonResponse({ valid: true });
}
const detailMatch = path.match(/^\/api\/providers\/([^/]+)$/);
if (detailMatch) {
const connectionId = detailMatch[1];
if (method === "PUT") {
const payload = await readJsonBody(request);
state.connections = state.connections.map((connection) =>
connection.id === connectionId
? {
...connection,
name:
typeof payload.name === "string" && payload.name.trim()
? payload.name.trim()
: connection.name,
priority:
typeof payload.priority === "number" ? payload.priority : connection.priority,
isActive:
typeof payload.isActive === "boolean" ? payload.isActive : connection.isActive,
providerSpecificData: {
...connection.providerSpecificData,
...(payload.providerSpecificData as Record<string, unknown> | undefined),
...(typeof payload.tag === "string" ? { tag: payload.tag } : {}),
...(typeof payload.validationModelId === "string"
? { validationModelId: payload.validationModelId }
: {}),
},
}
: connection
);
const updated = state.connections.find((connection) => connection.id === connectionId);
return jsonResponse({ connection: clone(updated) });
}
if (method === "DELETE") {
state.deleteCalls += 1;
state.connections = state.connections.filter(
(connection) => connection.id !== connectionId
);
return jsonResponse({ success: true });
}
}
if (path === "/api/providers") {
if (method === "GET") {
return jsonResponse({ connections: clone(state.connections) });
}
if (method === "POST") {
const payload = await readJsonBody(request);
const apiKey = typeof payload.apiKey === "string" ? payload.apiKey : "";
if (!apiKey || apiKey.includes("invalid")) {
return jsonResponse({ error: "Invalid API key" }, 400);
}
const connection: ProviderConnection = {
id: `conn-openai-${state.nextId++}`,
provider: String(payload.provider || "openai"),
name: String(payload.name || `OpenAI ${state.nextId}`),
authType: "api_key",
isActive: true,
testStatus: "active",
priority: typeof payload.priority === "number" ? payload.priority : 1,
providerSpecificData: {
tag: typeof payload.tag === "string" ? payload.tag : "",
validationModelId:
typeof payload.validationModelId === "string" ? payload.validationModelId : "",
},
lastError: null,
lastErrorAt: null,
lastErrorType: null,
lastErrorSource: null,
errorCode: null,
rateLimitedUntil: null,
};
state.connections.push(connection);
return jsonResponse({ connection: clone(connection) });
}
}
return originalFetch(input, init);
};
});
}
async function readProviderMockState(page: Page) {
return page.evaluate(
() =>
(
window as Window & {
__providersTestState: {
connections: ProviderConnection[];
nextId: number;
retestCalls: number;
deleteCalls: number;
validationCalls: number;
forceInvalidValidation: boolean;
};
}
).__providersTestState
);
}
async function gotoOrSkip(page: Page, url: string) {
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await page.goto(url, { waitUntil: "commit", timeout: NAVIGATION_TIMEOUT_MS });
} catch (error) {
lastError = error;
}
try {
await page.waitForURL(/\/(login|dashboard)(\/.*)?$/, { timeout: NAVIGATION_TIMEOUT_MS });
await page.locator("body").waitFor({ state: "visible", timeout: NAVIGATION_TIMEOUT_MS });
lastError = null;
break;
} catch (error) {
lastError = error;
}
await page.waitForTimeout(1000);
}
if (lastError) throw lastError;
const redirectedToLogin = page.url().includes("/login");
test.skip(redirectedToLogin, "Authentication enabled without a login fixture.");
}
test.describe("Providers management", () => {
test.setTimeout(600_000);
test("adds, edits, retests, deletes, and validates provider connections through the UI", async ({
page,
}) => {
await installProviderFetchMock(page);
await gotoOrSkip(page, "/dashboard/providers");
const openAiCard = page.locator('a[href="/dashboard/providers/openai"]').first();
await expect(openAiCard).toBeVisible();
await openAiCard.click();
await expect(page).toHaveURL(/\/dashboard\/providers\/openai$/);
await page.getByRole("button", { name: /^add$/i }).first().click();
const addDialog = page.getByRole("dialog");
await expect(addDialog).toBeVisible();
await addDialog.getByLabel(/name/i).fill("Primary OpenAI");
await addDialog.getByLabel(/api key/i).fill("sk-openai-valid");
await addDialog.getByRole("button", { name: /^save$/i }).click();
await expect
.poll(async () => (await readProviderMockState(page)).validationCalls)
.toBeGreaterThan(0);
await expect(page.getByText("Primary OpenAI")).toBeVisible();
await expect.poll(async () => (await readProviderMockState(page)).connections.length).toBe(1);
await page.getByTitle(/^edit$/i).click();
const editDialog = page.getByRole("dialog");
await editDialog.getByLabel(/name/i).fill("Primary OpenAI Edited");
await editDialog.getByLabel(/priority/i).fill("3");
await editDialog.getByRole("button", { name: /^save$/i }).click();
await expect(page.getByText("Primary OpenAI Edited")).toBeVisible();
await expect
.poll(async () => (await readProviderMockState(page)).connections[0]?.name)
.toBe("Primary OpenAI Edited");
await page.getByRole("button", { name: /retest/i }).click();
await expect.poll(async () => (await readProviderMockState(page)).retestCalls).toBe(1);
await page.evaluate(() => {
(
window as Window & { __providersTestState: { forceInvalidValidation: boolean } }
).__providersTestState.forceInvalidValidation = true;
});
await page.getByRole("button", { name: /^add$/i }).first().click();
const invalidDialog = page.getByRole("dialog");
await invalidDialog.getByLabel(/name/i).fill("Broken OpenAI");
await invalidDialog.getByLabel(/api key/i).fill("invalid-key");
await invalidDialog.getByRole("button", { name: /^save$/i }).click();
await expect(invalidDialog.getByText(/api key validation failed/i)).toBeVisible();
await expect
.poll(async () => (await readProviderMockState(page)).validationCalls)
.toBeGreaterThan(1);
await invalidDialog.getByRole("button", { name: /cancel/i }).click();
await page.evaluate(() => {
(
window as Window & { __providersTestState: { forceInvalidValidation: boolean } }
).__providersTestState.forceInvalidValidation = false;
});
page.once("dialog", async (dialog) => {
await dialog.accept();
});
await page.getByTitle(/^delete$/i).click();
await expect.poll(async () => (await readProviderMockState(page)).deleteCalls).toBe(1);
await expect(page.getByText("Primary OpenAI Edited")).toHaveCount(0);
await expect(page.getByText(/no connections yet/i)).toBeVisible();
});
});

View File

@@ -0,0 +1,224 @@
import { expect, test, type Page, type Route } from "@playwright/test";
const NAVIGATION_TIMEOUT_MS = 300_000;
type SkillRecord = {
id: string;
name: string;
version: string;
description: string;
enabled: boolean;
createdAt: string;
};
type MarketplaceSkill = {
name: string;
description: string;
version: string;
sourceUrl: string;
skillMdContent: string;
};
async function fulfillJson(route: Route, body: unknown, status = 200) {
await route.fulfill({
status,
contentType: "application/json",
body: JSON.stringify(body),
});
}
async function gotoOrSkip(page: Page, url: string) {
let lastError: unknown;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await page.goto(url, { waitUntil: "commit", timeout: NAVIGATION_TIMEOUT_MS });
} catch (error) {
lastError = error;
}
try {
await page.waitForURL(/\/(login|dashboard)(\/.*)?$/, { timeout: NAVIGATION_TIMEOUT_MS });
await page.locator("body").waitFor({ state: "visible", timeout: NAVIGATION_TIMEOUT_MS });
lastError = null;
break;
} catch (error) {
lastError = error;
}
await page.waitForTimeout(1000);
}
if (lastError) throw lastError;
const redirectedToLogin = page.url().includes("/login");
test.skip(redirectedToLogin, "Authentication enabled without a login fixture.");
}
test.describe("Skills marketplace", () => {
test.setTimeout(600_000);
test("searches, installs, toggles, and scrolls through skills in the dashboard", async ({
page,
}) => {
const state: {
skills: SkillRecord[];
marketplace: MarketplaceSkill[];
nextId: number;
toggleCalls: number;
marketplaceInstalls: number;
customInstalls: number;
} = {
skills: [
{
id: "skill-weather",
name: "lookupWeather",
version: "1.0.0",
description: "Returns current weather conditions.",
enabled: false,
createdAt: new Date("2026-04-05T20:00:00.000Z").toISOString(),
},
],
marketplace: Array.from({ length: 12 }, (_, index) => ({
name: index === 0 ? "Weather Pro" : `Skill Page ${index + 1}`,
description:
index === 0
? "Extended weather reports with severe alert support."
: `Marketplace skill result ${index + 1}.`,
version: `1.${index}.0`,
sourceUrl: `https://skillsmp.example/${index + 1}`,
skillMdContent: `# Skill ${index + 1}\n\nMarketplace content`,
})),
nextId: 2,
toggleCalls: 0,
marketplaceInstalls: 0,
customInstalls: 0,
};
await page.route("**/api/skills/executions", async (route) => {
await fulfillJson(route, { executions: [] });
});
await page.route(/\/api\/skills\/marketplace(?:\?.*)?$/, async (route) => {
const url = new URL(route.request().url());
const query = url.searchParams.get("q")?.toLowerCase() || "";
const results = state.marketplace.filter((skill) =>
query
? skill.name.toLowerCase().includes(query) ||
skill.description.toLowerCase().includes(query)
: true
);
await fulfillJson(route, { skills: results });
});
await page.route("**/api/skills/marketplace/install", async (route) => {
state.marketplaceInstalls += 1;
const payload = (route.request().postDataJSON() as Partial<MarketplaceSkill>) || {};
state.skills.push({
id: `skill-${state.nextId++}`,
name: payload.name || "marketplace-skill",
version: payload.version || "1.0.0",
description: payload.description || "Installed from marketplace",
enabled: true,
createdAt: new Date("2026-04-05T20:10:00.000Z").toISOString(),
});
await fulfillJson(route, { success: true });
});
await page.route("**/api/skills/install", async (route) => {
state.customInstalls += 1;
const payload = (route.request().postDataJSON() as Partial<SkillRecord>) || {};
state.skills.push({
id: `skill-${state.nextId++}`,
name: payload.name || "custom-skill",
version: payload.version || "1.0.0",
description: payload.description || "Custom installed skill",
enabled: true,
createdAt: new Date("2026-04-05T20:20:00.000Z").toISOString(),
});
await fulfillJson(route, {
success: true,
id: `skill-${state.nextId}`,
});
});
await page.route(/\/api\/skills\/skill-[^/?]+(?:\?.*)?$/, async (route) => {
if (route.request().method() !== "PUT") {
await fulfillJson(route, { error: "Method not allowed in skill detail stub" }, 405);
return;
}
state.toggleCalls += 1;
const skillId = route.request().url().split("/").pop() || "";
state.skills = state.skills.map((skill) =>
skill.id === skillId ? { ...skill, enabled: !skill.enabled } : skill
);
await fulfillJson(route, { success: true });
});
await page.route("**/api/skills", async (route) => {
await fulfillJson(route, { skills: state.skills });
});
await gotoOrSkip(page, "/dashboard/skills");
await expect(page.getByText("lookupWeather")).toBeVisible();
const weatherCard = page
.locator("div")
.filter({ has: page.getByText("lookupWeather") })
.first();
const weatherSwitch = weatherCard.getByRole("switch");
await expect(weatherSwitch).toHaveAttribute("aria-checked", "false");
await weatherSwitch.click();
await expect(weatherSwitch).toHaveAttribute("aria-checked", "true");
await expect.poll(() => state.toggleCalls).toBe(1);
await page.getByRole("button", { name: /marketplace/i }).click();
await expect(page.getByPlaceholder("Search skills...")).toBeVisible();
await page.getByPlaceholder("Search skills...").fill("weather");
await page.getByRole("button", { name: /search skillsmp/i }).click();
await expect(page.getByText("Weather Pro")).toBeVisible();
await page.getByRole("button", { name: /^install$/i }).click();
await expect.poll(() => state.marketplaceInstalls).toBe(1);
await page.getByPlaceholder("Search skills...").fill("");
await page.getByRole("button", { name: /search skillsmp/i }).click();
const lastMarketplaceSkill = page.getByText("Skill Page 12").last();
await lastMarketplaceSkill.scrollIntoViewIfNeeded();
await expect(lastMarketplaceSkill).toBeVisible();
await page.getByRole("button", { name: /^skills$/i }).click();
await expect(page.getByText("Weather Pro")).toBeVisible();
await page.getByRole("button", { name: /^install skill$/i }).click();
const installDialog = page
.locator("div.fixed.inset-0.z-50")
.filter({ has: page.getByRole("heading", { name: /^install skill$/i }) });
await expect(installDialog).toBeVisible();
await installDialog.locator("textarea").fill(
JSON.stringify(
{
name: "customMath",
version: "1.0.0",
description: "Custom calculator skill",
schema: { input: {}, output: {} },
handlerCode: "export default async () => ({ ok: true });",
},
null,
2
)
);
await installDialog.getByRole("button", { name: /^install$/i }).click();
await expect.poll(() => state.customInstalls).toBe(1);
await expect(installDialog.getByText(/skill installed/i)).toBeVisible();
await installDialog.getByRole("button", { name: /cancel/i }).click();
await expect(page.getByText("customMath")).toBeVisible();
const installedSwitch = page
.getByRole("heading", { name: "Weather Pro" })
.locator('xpath=ancestor::div[contains(@class, "flex items-center justify-between")][1]')
.getByRole("switch");
await expect(installedSwitch).toHaveAttribute("aria-checked", "true");
await installedSwitch.click();
await expect(installedSwitch).toHaveAttribute("aria-checked", "false");
await expect.poll(() => state.toggleCalls).toBe(2);
});
});

View File

@@ -0,0 +1,292 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
export async function createChatPipelineHarness(prefix) {
const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), `omniroute-${prefix}-`));
process.env.DATA_DIR = testDataDir;
process.env.REQUIRE_API_KEY = "false";
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const combosDb = await import("../../src/lib/db/combos.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const modelComboMappingsDb = await import("../../src/lib/db/modelComboMappings.ts");
const readCacheDb = await import("../../src/lib/db/readCache.ts");
const memoryStore = await import("../../src/lib/memory/store.ts");
const memoryToolsModule = await import("../../open-sse/mcp-server/tools/memoryTools.ts");
const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/settings.ts");
const { skillRegistry } = await import("../../src/lib/skills/registry.ts");
const { skillExecutor } = await import("../../src/lib/skills/executor.ts");
const builtinsModule = await import("../../src/lib/skills/builtins.ts");
const sandboxModule = await import("../../src/lib/skills/sandbox.ts");
const skillsRouteModule = await import("../../src/app/api/skills/route.ts");
const skillByIdRouteModule = await import("../../src/app/api/skills/[id]/route.ts");
const { handleChat } = await import("../../src/sse/handlers/chat.ts");
const { initTranslators } = await import("../../open-sse/translator/index.ts");
const { clearInflight } = await import("../../open-sse/services/requestDedup.ts");
const { BaseExecutor } = await import("../../open-sse/executors/base.ts");
const { resetAllAvailability, setModelUnavailable } =
await import("../../src/domain/modelAvailability.ts");
const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts");
const originalFetch = globalThis.fetch;
const originalRetryDelayMs = BaseExecutor.RETRY_CONFIG.delayMs;
function clearSkillState() {
skillRegistry.registeredSkills?.clear?.();
skillRegistry.versionCache?.clear?.();
skillExecutor.handlers?.clear?.();
}
function toPlainHeaders(headers) {
if (!headers) return {};
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
return Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, value == null ? "" : String(value)])
);
}
function buildRequest({
url = "http://localhost/v1/chat/completions",
body,
authKey = null,
headers = {},
} = {}) {
const requestHeaders = {
"Content-Type": "application/json",
...headers,
};
if (authKey) {
requestHeaders.Authorization = `Bearer ${authKey}`;
}
return new Request(url, {
method: "POST",
headers: requestHeaders,
body: typeof body === "string" ? body : JSON.stringify(body),
});
}
function buildOpenAIResponse(text = "ok", model = "gpt-4o-mini", usage = null) {
return new Response(
JSON.stringify({
id: "chatcmpl_json",
object: "chat.completion",
model,
choices: [
{
index: 0,
message: { role: "assistant", content: text },
finish_reason: "stop",
},
],
usage: usage || {
prompt_tokens: 4,
completion_tokens: 2,
total_tokens: 6,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildOpenAIToolCallResponse({
model = "gpt-4o-mini",
toolName = "lookupWeather@1.0.0",
toolCallId = "call_weather",
argumentsObject = { location: "Sao Paulo" },
} = {}) {
return new Response(
JSON.stringify({
id: "chatcmpl_tool",
object: "chat.completion",
model,
choices: [
{
index: 0,
message: {
role: "assistant",
content: "",
tool_calls: [
{
id: toolCallId,
type: "function",
function: {
name: toolName,
arguments: JSON.stringify(argumentsObject),
},
},
],
},
finish_reason: "tool_calls",
},
],
usage: {
prompt_tokens: 6,
completion_tokens: 4,
total_tokens: 10,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildClaudeResponse(text = "ok", model = "claude-3-5-sonnet-20241022") {
return new Response(
JSON.stringify({
id: "msg_json",
type: "message",
role: "assistant",
model,
content: [{ type: "text", text }],
stop_reason: "end_turn",
usage: {
input_tokens: 10,
output_tokens: 4,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildGeminiResponse(text = "ok", model = "gemini-2.5-flash") {
return new Response(
JSON.stringify({
responseId: "resp_gemini",
modelVersion: model,
createTime: "2026-04-05T12:00:00.000Z",
candidates: [
{
content: {
parts: [{ text }],
},
finishReason: "STOP",
},
],
usageMetadata: {
promptTokenCount: 5,
candidatesTokenCount: 7,
totalTokenCount: 12,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
async function waitFor(fn, timeoutMs = 1500) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
const result = await fn();
if (result) return result;
await new Promise((resolve) => setTimeout(resolve, 25));
}
return null;
}
async function resetStorage() {
globalThis.fetch = originalFetch;
clearInflight();
resetAllAvailability();
resetAllCircuitBreakers();
apiKeysDb.resetApiKeyState();
readCacheDb.invalidateDbCache();
invalidateMemorySettingsCache();
clearSkillState();
await new Promise((resolve) => setTimeout(resolve, 20));
core.resetDbInstance();
fs.rmSync(testDataDir, { recursive: true, force: true });
fs.mkdirSync(testDataDir, { recursive: true });
initTranslators();
}
async function cleanup() {
BaseExecutor.RETRY_CONFIG.delayMs = originalRetryDelayMs;
globalThis.fetch = originalFetch;
clearInflight();
clearSkillState();
resetAllAvailability();
resetAllCircuitBreakers();
core.resetDbInstance();
fs.rmSync(testDataDir, { recursive: true, force: true });
}
async function seedConnection(provider, overrides = {}) {
return providersDb.createProviderConnection({
provider,
authType: "apikey",
name: overrides.name || `${provider}-primary`,
apiKey: overrides.apiKey || `sk-${provider}-${Math.random().toString(16).slice(2, 10)}`,
isActive: overrides.isActive ?? true,
testStatus: overrides.testStatus || "active",
priority: overrides.priority,
rateLimitedUntil: overrides.rateLimitedUntil,
providerSpecificData: overrides.providerSpecificData || {},
});
}
async function seedApiKey({
name = `${prefix}-key`,
noLog = false,
allowedConnections,
allowedModels,
} = {}) {
const key = await apiKeysDb.createApiKey(name, "machine-test");
const updates = {};
if (noLog) updates.noLog = true;
if (allowedConnections) updates.allowedConnections = allowedConnections;
if (allowedModels) updates.allowedModels = allowedModels;
if (Object.keys(updates).length > 0) {
await apiKeysDb.updateApiKeyPermissions(key.id, updates);
}
return key;
}
initTranslators();
return {
TEST_DATA_DIR: testDataDir,
BaseExecutor,
apiKeysDb,
buildClaudeResponse,
buildGeminiResponse,
buildOpenAIResponse,
buildOpenAIToolCallResponse,
buildRequest,
builtinsModule,
cleanup,
combosDb,
core,
handleChat,
memoryStore,
memoryTools: memoryToolsModule.memoryTools,
modelComboMappingsDb,
originalRetryDelayMs,
resetStorage,
sandboxModule,
seedApiKey,
seedConnection,
setModelUnavailable,
settingsDb,
skillByIdRouteModule,
skillExecutor,
skillRegistry,
skillsRouteModule,
toPlainHeaders,
waitFor,
};
}

View File

@@ -0,0 +1,275 @@
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-api-keys-route-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = "test-api-key-secret";
const core = await import("../../src/lib/db/core.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const localDb = await import("../../src/lib/localDb.ts");
const compliance = await import("../../src/lib/compliance/index.ts");
const listRoute = await import("../../src/app/api/keys/route.ts");
const keyRoute = await import("../../src/app/api/keys/[id]/route.ts");
const revealRoute = await import("../../src/app/api/keys/[id]/reveal/route.ts");
const MACHINE_ID = "1234567890abcdef";
async function resetStorage() {
delete process.env.ALLOW_API_KEY_REVEAL;
delete process.env.INITIAL_PASSWORD;
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function enableManagementAuth() {
process.env.INITIAL_PASSWORD = "bootstrap-password";
await localDb.updateSettings({ requireLogin: true, password: "" });
}
async function createManagementKey() {
return apiKeysDb.createApiKey("management", MACHINE_ID);
}
function makeRequest(url, { method = "GET", token, body } = {}) {
const headers = new Headers();
if (token) {
headers.set("authorization", `Bearer ${token}`);
}
if (body !== undefined) {
headers.set("content-type", "application/json");
}
return new Request(url, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
});
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
await resetStorage();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("API keys routes require management auth when login protection is enabled", async () => {
await enableManagementAuth();
const unauthenticated = await listRoute.GET(new Request("http://localhost/api/keys"));
const invalidToken = await listRoute.GET(
new Request("http://localhost/api/keys", {
headers: { authorization: "Bearer sk-invalid" },
})
);
const unauthenticatedBody = await unauthenticated.json();
const invalidTokenBody = await invalidToken.json();
assert.equal(unauthenticated.status, 401);
assert.equal(unauthenticatedBody.error.message, "Authentication required");
assert.equal(invalidToken.status, 403);
assert.equal(invalidTokenBody.error.message, "Invalid management token");
});
test("POST /api/keys creates a key, preserves special characters, and persists noLog", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const response = await listRoute.POST(
makeRequest("http://localhost/api/keys", {
method: "POST",
token: authKey.key,
body: { name: "Key / Prod #1", noLog: true },
})
);
const body = await response.json();
const stored = await apiKeysDb.getApiKeyById(body.id);
assert.equal(response.status, 201);
assert.equal(body.name, "Key / Prod #1");
assert.equal(body.noLog, true);
assert.match(body.key, /^sk-[a-z0-9-]+/i);
assert.equal(stored?.noLog, true);
assert.equal(compliance.isNoLog(body.id), true);
});
test("POST /api/keys validates missing and oversized names", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const missingName = await listRoute.POST(
makeRequest("http://localhost/api/keys", {
method: "POST",
token: authKey.key,
body: {},
})
);
const oversizedName = await listRoute.POST(
makeRequest("http://localhost/api/keys", {
method: "POST",
token: authKey.key,
body: { name: "x".repeat(201) },
})
);
assert.equal(missingName.status, 400);
assert.equal(oversizedName.status, 400);
});
test("GET /api/keys lists masked keys with pagination and GET /api/keys/[id] stays masked", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const createdA = await apiKeysDb.createApiKey("Alpha", MACHINE_ID);
const createdB = await apiKeysDb.createApiKey("Beta", MACHINE_ID);
const listResponse = await listRoute.GET(
makeRequest("http://localhost/api/keys?limit=1&offset=1", {
token: authKey.key,
})
);
const getResponse = await keyRoute.GET(
makeRequest(`http://localhost/api/keys/${createdB.id}`, { token: authKey.key }),
{ params: Promise.resolve({ id: createdB.id }) }
);
const listBody = await listResponse.json();
const getBody = await getResponse.json();
assert.equal(listResponse.status, 200);
assert.equal(listBody.total, 3);
assert.equal(listBody.keys.length, 1);
assert.equal(listBody.keys[0].id, createdA.id);
assert.notEqual(listBody.keys[0].key, createdA.key);
assert.match(listBody.keys[0].key, /\*{4}/);
assert.equal(getResponse.status, 200);
assert.equal(getBody.id, createdB.id);
assert.notEqual(getBody.key, createdB.key);
assert.match(getBody.key, /\*{4}/);
});
test("GET /api/keys/[id] returns 404 for an unknown key and reveal is gated by the feature flag", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const created = await apiKeysDb.createApiKey("Reveal Target", MACHINE_ID);
const missingResponse = await keyRoute.GET(
makeRequest("http://localhost/api/keys/missing", { token: authKey.key }),
{ params: Promise.resolve({ id: "missing" }) }
);
const revealDisabled = await revealRoute.GET(
makeRequest(`http://localhost/api/keys/${created.id}/reveal`, { token: authKey.key }),
{ params: Promise.resolve({ id: created.id }) }
);
process.env.ALLOW_API_KEY_REVEAL = "true";
const revealEnabled = await revealRoute.GET(
makeRequest(`http://localhost/api/keys/${created.id}/reveal`, { token: authKey.key }),
{ params: Promise.resolve({ id: created.id }) }
);
const missingBody = await missingResponse.json();
const revealDisabledBody = await revealDisabled.json();
const revealEnabledBody = await revealEnabled.json();
assert.equal(missingResponse.status, 404);
assert.equal(missingBody.error, "Key not found");
assert.equal(revealDisabled.status, 403);
assert.equal(revealDisabledBody.error, "API key reveal is disabled");
assert.equal(revealEnabled.status, 200);
assert.equal(revealEnabledBody.key, created.key);
});
test("PATCH /api/keys/[id] updates permissions and rejects invalid payloads", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const created = await apiKeysDb.createApiKey("Mutable", MACHINE_ID);
const patchResponse = await keyRoute.PATCH(
makeRequest(`http://localhost/api/keys/${created.id}`, {
method: "PATCH",
token: authKey.key,
body: {
noLog: true,
allowedModels: ["gpt-4.1-mini"],
allowedConnections: [],
isActive: false,
maxSessions: 2,
},
}),
{ params: Promise.resolve({ id: created.id }) }
);
const invalidJsonResponse = await keyRoute.PATCH(
new Request(`http://localhost/api/keys/${created.id}`, {
method: "PATCH",
headers: {
authorization: `Bearer ${authKey.key}`,
"content-type": "application/json",
},
body: "{",
}),
{ params: Promise.resolve({ id: created.id }) }
);
const missingKeyResponse = await keyRoute.PATCH(
makeRequest("http://localhost/api/keys/missing", {
method: "PATCH",
token: authKey.key,
body: { noLog: false },
}),
{ params: Promise.resolve({ id: "missing" }) }
);
const patchBody = await patchResponse.json();
const invalidJsonBody = await invalidJsonResponse.json();
const missingKeyBody = await missingKeyResponse.json();
const updated = await apiKeysDb.getApiKeyById(created.id);
assert.equal(patchResponse.status, 200);
assert.equal(patchBody.noLog, true);
assert.equal(patchBody.isActive, false);
assert.equal(patchBody.maxSessions, 2);
assert.deepEqual(updated?.allowedModels, ["gpt-4.1-mini"]);
assert.equal(updated?.noLog, true);
assert.equal(updated?.isActive, false);
assert.equal(invalidJsonResponse.status, 400);
assert.equal(invalidJsonBody.error.message, "Invalid request");
assert.equal(missingKeyResponse.status, 404);
assert.equal(missingKeyBody.error, "Key not found");
});
test("DELETE /api/keys/[id] removes keys and reports missing resources", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const created = await apiKeysDb.createApiKey("Disposable", MACHINE_ID);
const deleteResponse = await keyRoute.DELETE(
makeRequest(`http://localhost/api/keys/${created.id}`, {
method: "DELETE",
token: authKey.key,
}),
{ params: Promise.resolve({ id: created.id }) }
);
const missingDeleteResponse = await keyRoute.DELETE(
makeRequest("http://localhost/api/keys/missing", {
method: "DELETE",
token: authKey.key,
}),
{ params: Promise.resolve({ id: "missing" }) }
);
const deleteBody = await deleteResponse.json();
const missingDeleteBody = await missingDeleteResponse.json();
assert.equal(deleteResponse.status, 200);
assert.equal(deleteBody.message, "Key deleted successfully");
assert.equal(await apiKeysDb.getApiKeyById(created.id), null);
assert.equal(missingDeleteResponse.status, 404);
assert.equal(missingDeleteBody.error, "Key not found");
});

View File

@@ -0,0 +1,302 @@
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-api-critical-routes-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = "test-api-key-secret";
const core = await import("../../src/lib/db/core.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const localDb = await import("../../src/lib/localDb.ts");
const proxiesRoute = await import("../../src/app/api/v1/management/proxies/route.ts");
const settingsProxyRoute = await import("../../src/app/api/settings/proxy/route.ts");
const v1ModelsRoute = await import("../../src/app/api/v1/models/route.ts");
const MACHINE_ID = "1234567890abcdef";
async function resetStorage() {
delete process.env.INITIAL_PASSWORD;
delete process.env.ENABLE_SOCKS5_PROXY;
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function enableManagementAuth() {
process.env.INITIAL_PASSWORD = "bootstrap-password";
await localDb.updateSettings({ requireLogin: true, password: "" });
}
async function createManagementKey() {
return apiKeysDb.createApiKey("management", MACHINE_ID);
}
function makeRequest(url, { method = "GET", token, body } = {}) {
const headers = new Headers();
if (token) {
headers.set("authorization", `Bearer ${token}`);
}
if (body !== undefined) {
headers.set("content-type", "application/json");
}
return new Request(url, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
});
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
await resetStorage();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("critical routes: v1 management proxies covers auth, lookup, where-used, patch, and delete branches", async () => {
await enableManagementAuth();
const authKey = await createManagementKey();
const unauthenticated = await proxiesRoute.GET(
new Request("http://localhost/api/v1/management/proxies")
);
const invalidToken = await proxiesRoute.GET(
new Request("http://localhost/api/v1/management/proxies", {
headers: { authorization: "Bearer sk-invalid" },
})
);
const createResponse = await proxiesRoute.POST(
makeRequest("http://localhost/api/v1/management/proxies", {
method: "POST",
token: authKey.key,
body: {
name: "Branch Proxy",
type: "http",
host: "branch.local",
port: 8080,
},
})
);
const created = await createResponse.json();
await localDb.assignProxyToScope("provider", "openai", created.id);
const getById = await proxiesRoute.GET(
makeRequest(`http://localhost/api/v1/management/proxies?id=${created.id}`, {
token: authKey.key,
})
);
const whereUsed = await proxiesRoute.GET(
makeRequest(`http://localhost/api/v1/management/proxies?id=${created.id}&where_used=1`, {
token: authKey.key,
})
);
const missingGet = await proxiesRoute.GET(
makeRequest("http://localhost/api/v1/management/proxies?id=missing", { token: authKey.key })
);
const invalidJsonPatch = await proxiesRoute.PATCH(
new Request("http://localhost/api/v1/management/proxies", {
method: "PATCH",
headers: {
authorization: `Bearer ${authKey.key}`,
"content-type": "application/json",
},
body: "{",
})
);
const invalidPatch = await proxiesRoute.PATCH(
makeRequest("http://localhost/api/v1/management/proxies", {
method: "PATCH",
token: authKey.key,
body: {},
})
);
const validPatch = await proxiesRoute.PATCH(
makeRequest("http://localhost/api/v1/management/proxies", {
method: "PATCH",
token: authKey.key,
body: { id: created.id, host: "patched.local", notes: "updated" },
})
);
const missingDelete = await proxiesRoute.DELETE(
makeRequest("http://localhost/api/v1/management/proxies", {
method: "DELETE",
token: authKey.key,
})
);
const conflictDelete = await proxiesRoute.DELETE(
makeRequest(`http://localhost/api/v1/management/proxies?id=${created.id}`, {
method: "DELETE",
token: authKey.key,
})
);
const forcedDelete = await proxiesRoute.DELETE(
makeRequest(`http://localhost/api/v1/management/proxies?id=${created.id}&force=1`, {
method: "DELETE",
token: authKey.key,
})
);
const unauthenticatedBody = await unauthenticated.json();
const invalidTokenBody = await invalidToken.json();
const getByIdBody = await getById.json();
const whereUsedBody = await whereUsed.json();
const missingGetBody = await missingGet.json();
const invalidJsonPatchBody = await invalidJsonPatch.json();
const invalidPatchBody = await invalidPatch.json();
const validPatchBody = await validPatch.json();
const missingDeleteBody = await missingDelete.json();
const conflictDeleteBody = await conflictDelete.json();
const forcedDeleteBody = await forcedDelete.json();
assert.equal(unauthenticated.status, 401);
assert.equal(unauthenticatedBody.error.message, "Authentication required");
assert.equal(invalidToken.status, 403);
assert.equal(invalidTokenBody.error.message, "Invalid management token");
assert.equal(createResponse.status, 201);
assert.equal(getById.status, 200);
assert.equal(getByIdBody.id, created.id);
assert.equal(whereUsed.status, 200);
assert.equal(whereUsedBody.count, 1);
assert.equal(whereUsedBody.assignments[0].proxyId, created.id);
assert.equal(missingGet.status, 404);
assert.equal(missingGetBody.error.message, "Proxy not found");
assert.equal(invalidJsonPatch.status, 400);
assert.equal(invalidJsonPatchBody.error.message, "Invalid JSON body");
assert.equal(invalidPatch.status, 400);
assert.equal(validPatch.status, 200);
assert.equal(validPatchBody.host, "patched.local");
assert.equal(missingDelete.status, 400);
assert.equal(missingDeleteBody.error.message, "id is required");
assert.equal(conflictDelete.status, 409);
assert.match(conflictDeleteBody.error.message, /force=true/i);
assert.equal(forcedDelete.status, 200);
assert.equal(forcedDeleteBody.success, true);
});
test("critical routes: settings proxy resolves config, validates payloads, and deletes scoped entries", async () => {
const connection = await localDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "critical-proxy-conn",
apiKey: "sk-critical",
});
const invalidJson = await settingsProxyRoute.PUT(
new Request("http://localhost/api/settings/proxy", {
method: "PUT",
headers: { "content-type": "application/json" },
body: "{",
})
);
const invalidProviders = await settingsProxyRoute.PUT(
makeRequest("http://localhost/api/settings/proxy", {
method: "PUT",
body: { providers: "not-an-object" },
})
);
const setProviderProxy = await settingsProxyRoute.PUT(
makeRequest("http://localhost/api/settings/proxy", {
method: "PUT",
body: {
level: "provider",
id: "openai",
proxy: {
type: "HTTP",
host: "provider.proxy.local",
port: 9000,
username: "alice",
},
},
})
);
const getProviderProxy = await settingsProxyRoute.GET(
new Request("http://localhost/api/settings/proxy?level=provider&id=openai")
);
const resolveProxy = await settingsProxyRoute.GET(
new Request(`http://localhost/api/settings/proxy?resolve=${connection.id}`)
);
const missingLevelDelete = await settingsProxyRoute.DELETE(
new Request("http://localhost/api/settings/proxy")
);
const deleteProviderProxy = await settingsProxyRoute.DELETE(
new Request("http://localhost/api/settings/proxy?level=provider&id=openai", {
method: "DELETE",
})
);
const getFullConfig = await settingsProxyRoute.GET(
new Request("http://localhost/api/settings/proxy")
);
const invalidJsonBody = await invalidJson.json();
const invalidProvidersBody = await invalidProviders.json();
const setProviderProxyBody = await setProviderProxy.json();
const getProviderProxyBody = await getProviderProxy.json();
const resolveProxyBody = await resolveProxy.json();
const missingLevelDeleteBody = await missingLevelDelete.json();
const deleteProviderProxyBody = await deleteProviderProxy.json();
const getFullConfigBody = await getFullConfig.json();
assert.equal(invalidJson.status, 400);
assert.equal(invalidJsonBody.error.message, "Invalid JSON body");
assert.equal(invalidProviders.status, 400);
assert.equal(invalidProvidersBody.error.message, "Invalid request");
assert.equal(setProviderProxy.status, 200);
assert.equal(setProviderProxyBody.providers.openai.type, "http");
assert.equal(getProviderProxy.status, 200);
assert.equal(getProviderProxyBody.proxy.type, "http");
assert.equal(resolveProxy.status, 200);
assert.equal(resolveProxyBody.level, "provider");
assert.equal(resolveProxyBody.proxy.host, "provider.proxy.local");
assert.equal(missingLevelDelete.status, 400);
assert.equal(missingLevelDeleteBody.error.message, "level is required");
assert.equal(deleteProviderProxy.status, 200);
assert.equal(deleteProviderProxyBody.providers.openai, undefined);
assert.equal(getFullConfig.status, 200);
assert.ok(Object.prototype.hasOwnProperty.call(getFullConfigBody, "providers"));
});
test("critical routes: settings proxy prefers registry assignment for global lookups", async () => {
const proxy = await localDb.createProxy({
name: "Global Registry Proxy",
type: "https",
host: "registry.proxy.local",
port: 443,
username: "global-user",
password: "global-pass",
});
await localDb.assignProxyToScope("global", null, proxy.id);
const response = await settingsProxyRoute.GET(
new Request("http://localhost/api/settings/proxy?level=global")
);
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.level, "global");
assert.equal(body.proxy.type, "https");
assert.equal(body.proxy.host, "registry.proxy.local");
assert.equal(body.proxy.username, "global-user");
});
test("critical routes: v1 models route exposes CORS and list contracts", async () => {
const options = await v1ModelsRoute.OPTIONS();
const response = await v1ModelsRoute.GET(
new Request("http://localhost/api/v1/models", { method: "GET" })
);
const body = await response.json();
assert.equal(options.status, 200);
assert.match(options.headers.get("Access-Control-Allow-Methods") || "", /GET/);
assert.equal(response.status, 200);
assert.equal(body.object, "list");
assert.ok(Array.isArray(body.data));
});

View File

@@ -0,0 +1,967 @@
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-chat-pipeline-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.REQUIRE_API_KEY = "false";
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const combosDb = await import("../../src/lib/db/combos.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const callLogsDb = await import("../../src/lib/usage/callLogs.ts");
const readCacheDb = await import("../../src/lib/db/readCache.ts");
const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/settings.ts");
const { skillRegistry } = await import("../../src/lib/skills/registry.ts");
const { skillExecutor } = await import("../../src/lib/skills/executor.ts");
const { handleChat } = await import("../../src/sse/handlers/chat.ts");
const { initTranslators } = await import("../../open-sse/translator/index.ts");
const { clearInflight } = await import("../../open-sse/services/requestDedup.ts");
const { BaseExecutor } = await import("../../open-sse/executors/base.ts");
const { resetAllAvailability, setModelUnavailable } =
await import("../../src/domain/modelAvailability.ts");
const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts");
const originalFetch = globalThis.fetch;
const originalRetryDelayMs = BaseExecutor.RETRY_CONFIG.delayMs;
function toPlainHeaders(headers) {
if (!headers) return {};
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
return Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, value == null ? "" : String(value)])
);
}
function buildRequest({
url = "http://localhost/v1/chat/completions",
body,
authKey = null,
headers = {},
} = {}) {
const requestHeaders = {
"Content-Type": "application/json",
...headers,
};
if (authKey) {
requestHeaders.Authorization = `Bearer ${authKey}`;
}
return new Request(url, {
method: "POST",
headers: requestHeaders,
body: typeof body === "string" ? body : JSON.stringify(body),
});
}
function buildOpenAIResponse(text = "ok", model = "gpt-4o-mini", usage = null) {
return new Response(
JSON.stringify({
id: "chatcmpl_json",
object: "chat.completion",
model,
choices: [
{
index: 0,
message: { role: "assistant", content: text },
finish_reason: "stop",
},
],
usage: usage || {
prompt_tokens: 4,
completion_tokens: 2,
total_tokens: 6,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildOpenAIToolCallResponse({
model = "gpt-4o-mini",
toolName = "lookupWeather@1.0.0",
toolCallId = "call_weather",
argumentsObject = { location: "Sao Paulo" },
} = {}) {
return new Response(
JSON.stringify({
id: "chatcmpl_tool",
object: "chat.completion",
model,
choices: [
{
index: 0,
message: {
role: "assistant",
content: "",
tool_calls: [
{
id: toolCallId,
type: "function",
function: {
name: toolName,
arguments: JSON.stringify(argumentsObject),
},
},
],
},
finish_reason: "tool_calls",
},
],
usage: {
prompt_tokens: 6,
completion_tokens: 4,
total_tokens: 10,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildClaudeResponse(text = "ok", model = "claude-3-5-sonnet-20241022") {
return new Response(
JSON.stringify({
id: "msg_json",
type: "message",
role: "assistant",
model,
content: [{ type: "text", text }],
stop_reason: "end_turn",
usage: {
input_tokens: 10,
output_tokens: 4,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildClaudeStreamResponse(text = "streamed from claude", model = "claude-sonnet-4-6") {
return new Response(
[
"event: message_start",
`data: ${JSON.stringify({
type: "message_start",
message: {
id: "msg_stream",
type: "message",
role: "assistant",
model,
usage: { input_tokens: 12, output_tokens: 0 },
},
})}`,
"",
"event: content_block_start",
`data: ${JSON.stringify({
type: "content_block_start",
index: 0,
content_block: { type: "text", text: "" },
})}`,
"",
"event: content_block_delta",
`data: ${JSON.stringify({
type: "content_block_delta",
index: 0,
delta: { type: "text_delta", text },
})}`,
"",
"event: message_delta",
`data: ${JSON.stringify({
type: "message_delta",
delta: { stop_reason: "end_turn" },
usage: { output_tokens: 3 },
})}`,
"",
"event: message_stop",
`data: ${JSON.stringify({ type: "message_stop" })}`,
"",
].join("\n"),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
function buildGeminiResponse(text = "ok", model = "gemini-2.5-flash") {
return new Response(
JSON.stringify({
responseId: "resp_gemini",
modelVersion: model,
createTime: "2026-04-05T12:00:00.000Z",
candidates: [
{
content: {
parts: [{ text }],
},
finishReason: "STOP",
},
],
usageMetadata: {
promptTokenCount: 5,
candidatesTokenCount: 7,
totalTokenCount: 12,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildOpenAIStreamResponse(text = "streamed from openai") {
return new Response(
[
`data: ${JSON.stringify({
id: "chatcmpl_stream",
object: "chat.completion.chunk",
choices: [{ index: 0, delta: { role: "assistant", content: text } }],
})}`,
"",
"data: [DONE]",
"",
].join("\n"),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
async function resetStorage() {
globalThis.fetch = originalFetch;
clearInflight();
resetAllAvailability();
resetAllCircuitBreakers();
apiKeysDb.resetApiKeyState();
readCacheDb.invalidateDbCache();
invalidateMemorySettingsCache();
await new Promise((resolve) => setTimeout(resolve, 20));
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
initTranslators();
}
async function seedConnection(provider, overrides = {}) {
return providersDb.createProviderConnection({
provider,
authType: "apikey",
name: overrides.name || `${provider}-primary`,
apiKey: overrides.apiKey || `sk-${provider}-${Math.random().toString(16).slice(2, 10)}`,
isActive: overrides.isActive ?? true,
testStatus: overrides.testStatus || "active",
priority: overrides.priority,
rateLimitedUntil: overrides.rateLimitedUntil,
providerSpecificData: overrides.providerSpecificData || {},
});
}
async function seedApiKey({
name = "chat-pipeline-key",
noLog = false,
allowedConnections,
allowedModels,
} = {}) {
const key = await apiKeysDb.createApiKey(name, "machine-test");
const updates = {};
if (noLog) updates.noLog = true;
if (allowedConnections) updates.allowedConnections = allowedConnections;
if (allowedModels) updates.allowedModels = allowedModels;
if (Object.keys(updates).length > 0) {
await apiKeysDb.updateApiKeyPermissions(key.id, updates);
}
return key;
}
function ensureLegacyMemoryTable() {
const db = core.getDbInstance();
db.exec(`
CREATE TABLE IF NOT EXISTS memory (
id TEXT PRIMARY KEY,
apiKeyId TEXT NOT NULL,
sessionId TEXT,
type TEXT NOT NULL,
key TEXT,
content TEXT NOT NULL,
metadata TEXT,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
expiresAt TEXT
)
`);
}
function insertLegacyMemory(apiKeyId, content) {
ensureLegacyMemoryTable();
const db = core.getDbInstance();
const now = new Date().toISOString();
db.prepare(
`
INSERT INTO memory (
id, apiKeyId, sessionId, type, key, content, metadata, createdAt, updatedAt, expiresAt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`
).run(
`mem_${Math.random().toString(16).slice(2, 10)}`,
apiKeyId,
"",
"factual",
"pref",
content,
"{}",
now,
now,
null
);
}
async function waitFor(fn, timeoutMs = 1500) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
const result = await fn();
if (result) return result;
await new Promise((resolve) => setTimeout(resolve, 25));
}
return null;
}
async function getLatestCallLog() {
const rows = await callLogsDb.getCallLogs({ limit: 5 });
if (!Array.isArray(rows) || rows.length === 0) return null;
return callLogsDb.getCallLogById(rows[0].id);
}
test.beforeEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = 0;
await resetStorage();
});
test.afterEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = originalRetryDelayMs;
await resetStorage();
});
test.after(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = originalRetryDelayMs;
globalThis.fetch = originalFetch;
clearInflight();
resetAllAvailability();
resetAllCircuitBreakers();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("chat pipeline handles OpenAI passthrough with valid API key auth", async () => {
await seedConnection("openai", { apiKey: "sk-openai-primary" });
const apiKey = await seedApiKey();
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
method: init.method || "GET",
headers: toPlainHeaders(init.headers),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildOpenAIResponse("OpenAI passthrough");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Hello OpenAI" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /\/chat\/completions$/);
assert.equal(fetchCalls[0].headers.Authorization, "Bearer sk-openai-primary");
assert.equal(fetchCalls[0].body.messages[0].content, "Hello OpenAI");
assert.equal(json.choices[0].message.content, "OpenAI passthrough");
});
test("chat pipeline translates OpenAI requests to Claude and returns OpenAI-shaped responses", async () => {
await seedConnection("claude", { apiKey: "sk-claude-primary" });
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildClaudeResponse("Claude translated reply");
};
const response = await handleChat(
buildRequest({
body: {
model: "claude/claude-3-5-sonnet-20241022",
stream: false,
messages: [{ role: "user", content: "Hello Claude" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /\?beta=true$/);
assert.equal(fetchCalls[0].headers["x-api-key"], "sk-claude-primary");
assert.equal(fetchCalls[0].body.messages[0].role, "user");
assert.equal(fetchCalls[0].body.messages[0].content[0].text, "Hello Claude");
assert.equal(json.object, "chat.completion");
assert.equal(json.choices[0].message.content, "Claude translated reply");
});
test("chat pipeline translates OpenAI requests to Gemini and returns OpenAI-shaped responses", async () => {
await seedConnection("gemini", { apiKey: "sk-gemini-primary" });
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildGeminiResponse("Gemini translated reply");
};
const response = await handleChat(
buildRequest({
body: {
model: "gemini/gemini-2.5-flash",
stream: false,
messages: [{ role: "user", content: "Hello Gemini" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /generateContent$/);
assert.equal(fetchCalls[0].headers["x-goog-api-key"], "sk-gemini-primary");
assert.equal(fetchCalls[0].body.contents[0].role, "user");
assert.equal(fetchCalls[0].body.contents[0].parts[0].text, "Hello Gemini");
assert.equal(json.object, "chat.completion");
assert.equal(json.choices[0].message.content, "Gemini translated reply");
});
test("chat pipeline translates Claude-format requests into OpenAI upstream and back to Claude", async () => {
await seedConnection("openai", { apiKey: "sk-openai-claude-route" });
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildOpenAIResponse("OpenAI answered Claude client");
};
const response = await handleChat(
buildRequest({
url: "http://localhost/v1/messages",
body: {
model: "openai/gpt-4o-mini",
stream: false,
max_tokens: 128,
system: [{ text: "Be brief" }],
messages: [{ role: "user", content: [{ type: "text", text: "Hello from Claude client" }] }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /\/chat\/completions$/);
assert.equal(fetchCalls[0].body.messages[0].role, "system");
assert.equal(fetchCalls[0].body.messages[0].content, "Be brief");
assert.equal(fetchCalls[0].body.messages[1].content, "Hello from Claude client");
assert.equal(json.type, "message");
assert.equal(json.role, "assistant");
assert.equal(json.content[0].text, "OpenAI answered Claude client");
});
test("chat pipeline converts Claude SSE streams into OpenAI SSE output", async () => {
await seedConnection("claude", { apiKey: "sk-claude-stream" });
globalThis.fetch = async () => buildClaudeStreamResponse("Streamed Claude chunk");
const response = await handleChat(
buildRequest({
body: {
model: "claude/claude-sonnet-4-6",
stream: true,
messages: [{ role: "user", content: "Stream this" }],
},
})
);
const raw = await response.text();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
assert.match(raw, /chat\.completion\.chunk/);
assert.match(raw, /Streamed Claude chunk/);
assert.match(raw, /\[DONE\]/);
});
test("chat pipeline rejects invalid API keys and malformed JSON bodies", async () => {
await seedConnection("openai", { apiKey: "sk-openai-invalid-key-path" });
const invalidKeyResponse = await handleChat(
buildRequest({
authKey: "does-not-exist",
body: {
model: "openai/gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
},
})
);
const invalidKeyJson = await invalidKeyResponse.json();
const invalidJsonResponse = await handleChat(
new Request("http://localhost/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: "{bad-json",
})
);
const invalidJson = await invalidJsonResponse.json();
assert.equal(invalidKeyResponse.status, 401);
assert.match(invalidKeyJson.error.message, /Invalid API key/i);
assert.equal(invalidJsonResponse.status, 400);
assert.match(invalidJson.error.message, /Invalid JSON body/i);
});
test("chat pipeline supports local mode without Authorization on explicit combos", async () => {
await seedConnection("openai", { apiKey: "sk-openai-local-combo" });
await combosDb.createCombo({
name: "local-router",
strategy: "priority",
models: ["openai/gpt-4o-mini"],
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
});
return buildOpenAIResponse("Local combo route");
};
const response = await handleChat(
buildRequest({
body: {
model: "local-router",
stream: false,
messages: [{ role: "user", content: "No auth header here" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.equal(json.choices[0].message.content, "Local combo route");
});
test("chat pipeline honors noLog by redacting persisted call log payloads", async () => {
await seedConnection("openai", { apiKey: "sk-openai-no-log" });
const apiKey = await seedApiKey({ noLog: true });
globalThis.fetch = async () => buildOpenAIResponse("No-log reply");
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Do not persist payloads" }],
},
})
);
assert.equal(response.status, 200);
const callLog = await waitFor(() => getLatestCallLog());
assert.ok(callLog, "expected a call log row to be created");
assert.equal(callLog.apiKeyId, apiKey.id);
assert.equal(callLog.requestBody, null);
assert.equal(callLog.responseBody, null);
assert.equal(callLog.artifactRelPath, null);
});
test("chat pipeline returns current no-credentials contract when no provider connection exists", async () => {
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Hello" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 400);
assert.match(json.error.message, /No credentials for provider: openai/);
});
test("chat pipeline returns 503 when the requested model is temporarily unavailable", async () => {
await seedConnection("openai", { apiKey: "sk-openai-unavailable" });
setModelUnavailable("openai", "gpt-4o-mini", 60000, "test cooldown");
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Provider unavailable" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 503);
assert.ok(Number(response.headers.get("Retry-After")) >= 1);
assert.match(json.error.message, /temporarily unavailable/i);
});
test("chat pipeline surfaces upstream 500 responses as structured errors", async () => {
await seedConnection("openai", { apiKey: "sk-openai-500" });
globalThis.fetch = async () =>
new Response(JSON.stringify({ error: { message: "provider exploded" } }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Trigger 500" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 500);
assert.match(json.error.message, /\[500\]: provider exploded/);
});
test("chat pipeline returns 429 with Retry-After when the upstream rate-limits the only account", async () => {
await seedConnection("openai", { apiKey: "sk-openai-429" });
let attempts = 0;
globalThis.fetch = async () => {
attempts += 1;
return new Response(
JSON.stringify({
error: {
message: "Rate limit exceeded. Your quota will reset after 30s.",
},
}),
{
status: 429,
headers: { "Content-Type": "application/json" },
}
);
};
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Trigger 429" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 429);
assert.ok(attempts >= 1, "expected at least one upstream attempt");
assert.ok(Number(response.headers.get("Retry-After")) >= 1);
assert.match(json.error.message, /\[openai\/gpt-4o-mini\]/);
});
test("chat pipeline maps upstream timeouts to 504 responses", async () => {
await seedConnection("openai", { apiKey: "sk-openai-timeout" });
globalThis.fetch = async () => {
const error = new Error("upstream timed out");
error.name = "TimeoutError";
throw error;
};
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Trigger timeout" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 504);
assert.match(json.error.message, /\[504\]: upstream timed out/);
});
test("chat pipeline injects memory context before sending the upstream request", async () => {
await seedConnection("openai", { apiKey: "sk-openai-memory" });
const apiKey = await seedApiKey();
await settingsDb.updateSettings({
memoryEnabled: true,
memoryMaxTokens: 400,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
invalidateMemorySettingsCache();
insertLegacyMemory(apiKey.id, "User prefers concise answers.");
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildOpenAIResponse("Memory-aware reply");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Summarize my preference" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].body.messages[0].role, "system");
assert.match(fetchCalls[0].body.messages[0].content, /User prefers concise answers/);
assert.equal(json.choices[0].message.content, "Memory-aware reply");
});
test("chat pipeline injects skills into tools and intercepts tool calls with skill output", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skills" });
const apiKey = await seedApiKey();
await settingsDb.updateSettings({ skillsEnabled: true });
invalidateMemorySettingsCache();
const handlerName = `weather-handler-${Date.now()}`;
skillExecutor.registerHandler(handlerName, async (input) => ({
forecast: `Sunny in ${input.location}`,
}));
await skillRegistry.register({
apiKeyId: apiKey.id,
name: "lookupWeather",
version: "1.0.0",
description: "Return a canned forecast",
schema: {
input: {
type: "object",
properties: {
location: { type: "string" },
},
},
output: {
type: "object",
},
},
handler: handlerName,
enabled: true,
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
body: init.body ? JSON.parse(String(init.body)) : null,
});
return buildOpenAIToolCallResponse();
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Check the weather" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.ok(Array.isArray(fetchCalls[0].body.tools));
assert.equal(fetchCalls[0].body.tools[0].function.name, "lookupWeather@1.0.0");
assert.equal(json.choices[0].finish_reason, "tool_calls");
assert.equal(json.tool_results[0].tool_call_id, "call_weather");
assert.equal(JSON.parse(json.tool_results[0].output).forecast, "Sunny in Sao Paulo");
});
test("chat pipeline falls back to the next account after a provider failure", async () => {
await seedConnection("openai", {
name: "openai-primary",
apiKey: "sk-openai-primary-fallback",
priority: 1,
});
await seedConnection("openai", {
name: "openai-secondary",
apiKey: "sk-openai-secondary-fallback",
priority: 2,
});
const seenAuthHeaders = [];
globalThis.fetch = async (url, init = {}) => {
const headers = toPlainHeaders(init.headers);
seenAuthHeaders.push(headers.Authorization);
if (seenAuthHeaders.length === 1) {
return new Response(JSON.stringify({ error: { message: "first account failed" } }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
return buildOpenAIResponse("Second account succeeded");
};
const response = await handleChat(
buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Use account fallback" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.deepEqual(seenAuthHeaders, [
"Bearer sk-openai-primary-fallback",
"Bearer sk-openai-secondary-fallback",
]);
assert.equal(json.choices[0].message.content, "Second account succeeded");
});
test("chat pipeline falls back across combo models when the first provider fails", async () => {
await seedConnection("openai", { apiKey: "sk-openai-combo-fail" });
await seedConnection("claude", { apiKey: "sk-claude-combo-fail" });
await combosDb.createCombo({
name: "combo-fallback",
strategy: "priority",
config: { maxRetries: 0, retryDelayMs: 0 },
models: ["openai/gpt-4o-mini", "claude/claude-3-5-sonnet-20241022"],
});
const attempts = [];
globalThis.fetch = async (url, init = {}) => {
const call = {
url: String(url),
headers: toPlainHeaders(init.headers),
};
attempts.push(call);
if (attempts.length === 1) {
return new Response(JSON.stringify({ error: { message: "openai combo miss" } }), {
status: 503,
headers: { "Content-Type": "application/json" },
});
}
return buildClaudeResponse("Claude combo fallback");
};
const response = await handleChat(
buildRequest({
body: {
model: "combo-fallback",
stream: false,
messages: [{ role: "user", content: "Use combo fallback" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(attempts.length, 2);
assert.match(attempts[0].url, /\/chat\/completions$/);
assert.match(attempts[1].url, /\?beta=true$/);
assert.equal(json.choices[0].message.content, "Claude combo fallback");
});
test("chat pipeline deduplicates concurrent identical non-stream requests", async () => {
await seedConnection("openai", { apiKey: "sk-openai-dedup" });
let fetchCount = 0;
globalThis.fetch = async () => {
fetchCount += 1;
await new Promise((resolve) => setTimeout(resolve, 25));
return buildOpenAIResponse("Deduplicated response");
};
const requestA = buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
temperature: 0,
messages: [{ role: "user", content: "Deduplicate this request" }],
},
});
const requestB = buildRequest({
body: {
model: "openai/gpt-4o-mini",
stream: false,
temperature: 0,
messages: [{ role: "user", content: "Deduplicate this request" }],
},
});
const [responseA, responseB] = await Promise.all([handleChat(requestA), handleChat(requestB)]);
const [jsonA, jsonB] = await Promise.all([responseA.json(), responseB.json()]);
assert.equal(responseA.status, 200);
assert.equal(responseB.status, 200);
assert.equal(fetchCount, 1);
assert.equal(jsonA.choices[0].message.content, "Deduplicated response");
assert.equal(jsonB.choices[0].message.content, "Deduplicated response");
});

View File

@@ -0,0 +1,302 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createChatPipelineHarness } from "./_chatPipelineHarness.mjs";
const harness = await createChatPipelineHarness("combo-routing");
const {
BaseExecutor,
buildClaudeResponse,
buildGeminiResponse,
buildOpenAIResponse,
buildRequest,
combosDb,
handleChat,
modelComboMappingsDb,
resetStorage,
seedConnection,
toPlainHeaders,
} = harness;
test.beforeEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = 0;
await resetStorage();
});
test.afterEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = harness.originalRetryDelayMs;
await resetStorage();
});
test.after(async () => {
await harness.cleanup();
});
function buildOpenAIChatBody(model, content = `Route ${model}`) {
return {
model,
stream: false,
messages: [{ role: "user", content }],
};
}
test("combo routes requests by exact combo name", async () => {
await seedConnection("openai", { apiKey: "sk-openai-combo-exact" });
await combosDb.createCombo({
name: "router-priority",
strategy: "priority",
models: ["openai/gpt-4o-mini"],
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
});
return buildOpenAIResponse("Exact combo route");
};
const response = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-priority"),
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /\/chat\/completions$/);
assert.equal(fetchCalls[0].headers.Authorization, "Bearer sk-openai-combo-exact");
assert.equal(json.choices[0].message.content, "Exact combo route");
});
test("round-robin combo cycles through three providers", async () => {
await seedConnection("openai", { apiKey: "sk-openai-rr" });
await seedConnection("claude", { apiKey: "sk-claude-rr" });
await seedConnection("gemini", { apiKey: "sk-gemini-rr" });
await combosDb.createCombo({
name: "router-rr",
strategy: "round-robin",
config: { maxRetries: 0, retryDelayMs: 0 },
models: ["openai/gpt-4o-mini", "claude/claude-3-5-sonnet-20241022", "gemini/gemini-2.5-flash"],
});
const seenProviders = [];
globalThis.fetch = async (url) => {
const target = String(url);
if (target.includes("/chat/completions")) {
seenProviders.push("openai");
return buildOpenAIResponse("OpenAI round-robin");
}
if (target.includes("?beta=true")) {
seenProviders.push("claude");
return buildClaudeResponse("Claude round-robin");
}
seenProviders.push("gemini");
return buildGeminiResponse("Gemini round-robin");
};
const first = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
const second = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
const third = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-rr") }));
assert.equal(first.status, 200);
assert.equal(second.status, 200);
assert.equal(third.status, 200);
assert.deepEqual(seenProviders, ["openai", "claude", "gemini"]);
});
test("priority combo sticks to the primary model while healthy", async () => {
await seedConnection("openai", { apiKey: "sk-openai-priority" });
await seedConnection("claude", { apiKey: "sk-claude-priority" });
await combosDb.createCombo({
name: "router-priority-healthy",
strategy: "priority",
models: ["openai/gpt-4o-mini", "claude/claude-3-5-sonnet-20241022"],
});
const seenTargets = [];
globalThis.fetch = async (url) => {
seenTargets.push(String(url));
return buildOpenAIResponse("Primary stayed active");
};
const first = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-priority-healthy", "Route priority first"),
})
);
const second = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-priority-healthy", "Route priority second"),
})
);
assert.equal(first.status, 200);
assert.equal(second.status, 200);
assert.equal(seenTargets.length, 2);
assert.ok(seenTargets.every((target) => target.includes("/chat/completions")));
});
test("priority combo falls back to the secondary model when the first one fails", async () => {
await seedConnection("openai", { apiKey: "sk-openai-fallback" });
await seedConnection("claude", { apiKey: "sk-claude-fallback" });
await combosDb.createCombo({
name: "router-fallback",
strategy: "priority",
config: { maxRetries: 0, retryDelayMs: 0 },
models: ["openai/gpt-4o-mini", "claude/claude-3-5-sonnet-20241022"],
});
const attempts = [];
globalThis.fetch = async (url) => {
const target = String(url);
attempts.push(target);
if (attempts.length === 1) {
return new Response(JSON.stringify({ error: { message: "primary down" } }), {
status: 503,
headers: { "Content-Type": "application/json" },
});
}
return buildClaudeResponse("Fallback answered");
};
const response = await handleChat(buildRequest({ body: buildOpenAIChatBody("router-fallback") }));
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(attempts.length, 2);
assert.match(attempts[0], /\/chat\/completions$/);
assert.match(attempts[1], /\?beta=true$/);
assert.equal(json.choices[0].message.content, "Fallback answered");
});
test("model combo mappings route explicit model ids through the configured combo", async () => {
await seedConnection("openai", { apiKey: "sk-openai-mapped" });
const combo = await combosDb.createCombo({
name: "mapped-router",
strategy: "priority",
models: ["openai/gpt-4o-mini"],
});
await modelComboMappingsDb.createModelComboMapping({
pattern: "tenant/mapped-model",
comboId: combo.id,
priority: 100,
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
});
return buildOpenAIResponse("Mapped combo route");
};
const response = await handleChat(
buildRequest({
body: buildOpenAIChatBody("tenant/mapped-model"),
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].headers.Authorization, "Bearer sk-openai-mapped");
assert.equal(json.choices[0].message.content, "Mapped combo route");
});
test("wildcard model combo mappings resolve arbitrary matching models", async () => {
await seedConnection("gemini", { apiKey: "sk-gemini-wild" });
const combo = await combosDb.createCombo({
name: "wild-router",
strategy: "priority",
models: ["gemini/gemini-2.5-flash"],
});
await modelComboMappingsDb.createModelComboMapping({
pattern: "tenant/*",
comboId: combo.id,
priority: 10,
});
const fetchCalls = [];
globalThis.fetch = async (url, init = {}) => {
fetchCalls.push({
url: String(url),
headers: toPlainHeaders(init.headers),
});
return buildGeminiResponse("Wildcard combo route");
};
const response = await handleChat(
buildRequest({
body: buildOpenAIChatBody("tenant/any-model-name"),
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].url, /generateContent$/);
assert.equal(fetchCalls[0].headers["x-goog-api-key"], "sk-gemini-wild");
assert.equal(json.choices[0].message.content, "Wildcard combo route");
});
test("unmapped custom model requests fail after combo resolution falls through", async () => {
const response = await handleChat(
buildRequest({
body: buildOpenAIChatBody("tenant/unmapped-model"),
})
);
const json = await response.json();
assert.equal(response.status, 400);
assert.match(json.error.message, /No credentials for provider: tenant/);
});
test("strategy updates take effect for later requests on the same combo name", async () => {
await seedConnection("openai", { apiKey: "sk-openai-update" });
await seedConnection("claude", { apiKey: "sk-claude-update" });
const combo = await combosDb.createCombo({
name: "router-dynamic",
strategy: "priority",
models: ["openai/gpt-4o-mini", "claude/claude-3-5-sonnet-20241022"],
});
const seenProviders = [];
globalThis.fetch = async (url) => {
const target = String(url);
if (target.includes("?beta=true")) {
seenProviders.push("claude");
return buildClaudeResponse("Claude after update");
}
seenProviders.push("openai");
return buildOpenAIResponse("OpenAI before update");
};
const initial = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-dynamic", "Route dynamic initial"),
})
);
await combosDb.updateCombo(combo.id, {
strategy: "round-robin",
config: { maxRetries: 0, retryDelayMs: 0 },
});
const second = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-dynamic", "Route dynamic second"),
})
);
const third = await handleChat(
buildRequest({
body: buildOpenAIChatBody("router-dynamic", "Route dynamic third"),
})
);
assert.equal(initial.status, 200);
assert.equal(second.status, 200);
assert.equal(third.status, 200);
assert.deepEqual(seenProviders, ["openai", "openai", "claude"]);
});

View File

@@ -0,0 +1,344 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createChatPipelineHarness } from "./_chatPipelineHarness.mjs";
const harness = await createChatPipelineHarness("memory-pipeline");
const {
BaseExecutor,
buildOpenAIResponse,
buildRequest,
handleChat,
memoryStore,
memoryTools,
resetStorage,
seedApiKey,
seedConnection,
settingsDb,
waitFor,
} = harness;
const { createMemory, listMemories } = memoryStore;
test.beforeEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = 0;
await resetStorage();
});
test.afterEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = harness.originalRetryDelayMs;
await resetStorage();
});
test.after(async () => {
await harness.cleanup();
});
async function enableMemory(maxTokens = 400) {
await settingsDb.updateSettings({
memoryEnabled: true,
memoryMaxTokens: maxTokens,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
}
test("first request proceeds without injected context when the store is empty", async () => {
await seedConnection("openai", { apiKey: "sk-openai-memory-empty" });
const apiKey = await seedApiKey();
await enableMemory();
const fetchCalls = [];
globalThis.fetch = async (_url, init = {}) => {
fetchCalls.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("No memory yet");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "First turn" }],
},
})
);
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].messages[0].role, "user");
assert.equal(fetchCalls[0].messages[0].content, "First turn");
});
test("successful responses extract facts and persist them as memories", async () => {
await seedConnection("openai", { apiKey: "sk-openai-extract" });
const apiKey = await seedApiKey();
await enableMemory();
globalThis.fetch = async () =>
buildOpenAIResponse("I prefer concise answers. I usually answer in bullet points.");
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
headers: { "x-omniroute-session-id": "session-extract" },
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Remember my preferences" }],
},
})
);
const memories = await waitFor(async () => {
const rows = await listMemories({ apiKeyId: apiKey.id });
return rows.length >= 2 ? rows : null;
});
assert.equal(response.status, 200);
assert.ok(memories, "expected extracted memories to be stored");
assert.ok(memories.some((memory) => /concise answers/i.test(memory.content)));
assert.ok(memories.some((memory) => /bullet points/i.test(memory.content)));
assert.ok(memories.every((memory) => memory.sessionId === "session-extract"));
});
test("later requests inject retrieved memories into upstream messages", async () => {
await seedConnection("openai", { apiKey: "sk-openai-inject" });
const apiKey = await seedApiKey();
await enableMemory();
await createMemory({
apiKeyId: apiKey.id,
sessionId: "session-inject",
type: "factual",
key: "preference:concise",
content: "User prefers concise answers.",
metadata: {},
expiresAt: null,
});
const fetchCalls = [];
globalThis.fetch = async (_url, init = {}) => {
fetchCalls.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("Memory injected");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
headers: { "x-omniroute-session-id": "session-inject" },
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "What do you remember?" }],
},
})
);
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.equal(fetchCalls[0].messages[0].role, "system");
assert.match(fetchCalls[0].messages[0].content, /User prefers concise answers/);
});
test("memory search ranks query-relevant memories first", async () => {
const apiKey = await seedApiKey();
await memoryTools.omniroute_memory_add.handler({
apiKeyId: apiKey.id,
sessionId: "search",
type: "factual",
key: "pref:language",
content: "The user writes TypeScript services every day.",
metadata: {},
});
await memoryTools.omniroute_memory_add.handler({
apiKeyId: apiKey.id,
sessionId: "search",
type: "factual",
key: "pref:hobby",
content: "The user enjoys gardening on weekends.",
metadata: {},
});
await memoryTools.omniroute_memory_add.handler({
apiKeyId: apiKey.id,
sessionId: "search",
type: "factual",
key: "pref:stack",
content: "TypeScript and Node.js are the preferred backend stack.",
metadata: {},
});
const result = await memoryTools.omniroute_memory_search.handler({
apiKeyId: apiKey.id,
query: "typescript backend",
limit: 2,
});
assert.equal(result.success, true);
assert.equal(result.data.count, 2);
assert.match(result.data.memories[0].content, /TypeScript/i);
assert.ok(result.data.memories.every((memory) => /TypeScript|backend/i.test(memory.content)));
});
test("memory injection respects the configured token budget", async () => {
await seedConnection("openai", { apiKey: "sk-openai-budget" });
const apiKey = await seedApiKey();
await enableMemory(20);
await createMemory({
apiKeyId: apiKey.id,
sessionId: "budget",
type: "factual",
key: "older",
content: "Older preference that should be trimmed when the context budget is tight.",
metadata: {},
expiresAt: null,
});
await new Promise((resolve) => setTimeout(resolve, 10));
await createMemory({
apiKeyId: apiKey.id,
sessionId: "budget",
type: "factual",
key: "newer",
content: "Newest preference should fit first.",
metadata: {},
expiresAt: null,
});
const fetchCalls = [];
globalThis.fetch = async (_url, init = {}) => {
fetchCalls.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("Budget respected");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Use only the relevant memory." }],
},
})
);
assert.equal(response.status, 200);
assert.equal(fetchCalls.length, 1);
assert.match(fetchCalls[0].messages[0].content, /Newest preference should fit first/);
assert.doesNotMatch(fetchCalls[0].messages[0].content, /Older preference that should be trimmed/);
});
test("disabled memory skips both extraction and injection", async () => {
await seedConnection("openai", { apiKey: "sk-openai-memory-off" });
const apiKey = await seedApiKey();
await settingsDb.updateSettings({
memoryEnabled: false,
memoryMaxTokens: 400,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
const fetchCalls = [];
globalThis.fetch = async (_url, init = {}) => {
fetchCalls.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("I prefer dark mode.");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "This should not be remembered." }],
},
})
);
const memories = await waitFor(async () => {
const rows = await listMemories({ apiKeyId: apiKey.id });
return rows.length > 0 ? rows : [];
});
assert.equal(response.status, 200);
assert.equal(fetchCalls[0].messages[0].role, "user");
assert.deepEqual(memories, []);
});
test("memory clear removes all stored memories for an API key", async () => {
const apiKey = await seedApiKey();
await memoryTools.omniroute_memory_add.handler({
apiKeyId: apiKey.id,
sessionId: "clear",
type: "factual",
key: "pref:one",
content: "First memory",
metadata: {},
});
await memoryTools.omniroute_memory_add.handler({
apiKeyId: apiKey.id,
sessionId: "clear",
type: "episodic",
key: "event:two",
content: "Second memory",
metadata: {},
});
const cleared = await memoryTools.omniroute_memory_clear.handler({
apiKeyId: apiKey.id,
});
const remaining = await listMemories({ apiKeyId: apiKey.id });
assert.equal(cleared.success, true);
assert.equal(cleared.data.deletedCount, 2);
assert.equal(remaining.length, 0);
});
test("extracted memories remain isolated by session id", async () => {
await seedConnection("openai", { apiKey: "sk-openai-session-memory" });
const apiKey = await seedApiKey();
await enableMemory();
globalThis.fetch = async () => buildOpenAIResponse("I prefer tea.");
await handleChat(
buildRequest({
authKey: apiKey.key,
headers: { "x-omniroute-session-id": "session-a" },
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Remember drink A" }],
},
})
);
globalThis.fetch = async () => buildOpenAIResponse("I prefer coffee.");
await handleChat(
buildRequest({
authKey: apiKey.key,
headers: { "x-omniroute-session-id": "session-b" },
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Remember drink B" }],
},
})
);
const sessionAMemories = await waitFor(async () => {
const rows = await listMemories({ apiKeyId: apiKey.id, sessionId: "session-a" });
return rows.length > 0 ? rows : null;
});
const sessionBMemories = await waitFor(async () => {
const rows = await listMemories({ apiKeyId: apiKey.id, sessionId: "session-b" });
return rows.length > 0 ? rows : null;
});
assert.ok(sessionAMemories, "expected session A memories");
assert.ok(sessionBMemories, "expected session B memories");
assert.ok(sessionAMemories.every((memory) => /tea/i.test(memory.content)));
assert.ok(sessionBMemories.every((memory) => /coffee/i.test(memory.content)));
});

View File

@@ -0,0 +1,362 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createChatPipelineHarness } from "./_chatPipelineHarness.mjs";
const harness = await createChatPipelineHarness("skills-pipeline");
const {
BaseExecutor,
buildOpenAIResponse,
buildOpenAIToolCallResponse,
buildRequest,
builtinsModule,
handleChat,
resetStorage,
sandboxModule,
seedApiKey,
seedConnection,
settingsDb,
skillByIdRouteModule,
skillExecutor,
skillRegistry,
skillsRouteModule,
} = harness;
const { registerBuiltinSkills } = builtinsModule;
const { sandboxRunner } = sandboxModule;
test.beforeEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = 0;
await resetStorage();
});
test.afterEach(async () => {
BaseExecutor.RETRY_CONFIG.delayMs = harness.originalRetryDelayMs;
await resetStorage();
});
test.after(async () => {
await harness.cleanup();
});
async function enableSkills() {
await settingsDb.updateSettings({ skillsEnabled: true });
}
async function registerSkill({
apiKeyId,
name,
version = "1.0.0",
handler,
enabled = true,
description = "Test skill",
}) {
return skillRegistry.register({
apiKeyId,
name,
version,
description,
schema: {
input: {
type: "object",
properties: {
location: { type: "string" },
path: { type: "string" },
},
},
output: {
type: "object",
},
},
handler,
enabled,
});
}
test("skills API lists registered skills", async () => {
const apiKey = await seedApiKey();
await registerSkill({
apiKeyId: apiKey.id,
name: "lookupWeather",
handler: "weather-handler-list",
});
const response = await skillsRouteModule.GET();
const json = await response.json();
assert.equal(response.status, 200);
assert.ok(Array.isArray(json.skills));
assert.ok(json.skills.some((skill) => skill.name === "lookupWeather"));
});
test("enabling a disabled skill makes it available in the request pipeline", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-enable" });
const apiKey = await seedApiKey();
await enableSkills();
const skill = await registerSkill({
apiKeyId: apiKey.id,
name: "lookupWeather",
handler: "weather-handler-enable",
enabled: false,
});
const updateResponse = await skillByIdRouteModule.PUT(
new Request("http://localhost/api/skills/id", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ enabled: true }),
}),
{ params: Promise.resolve({ id: skill.id }) }
);
const fetchBodies = [];
globalThis.fetch = async (_url, init = {}) => {
fetchBodies.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("Skill enabled");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "What tools do you have?" }],
},
})
);
assert.equal(updateResponse.status, 200);
assert.equal(response.status, 200);
assert.ok(Array.isArray(fetchBodies[0].tools));
assert.ok(fetchBodies[0].tools.some((tool) => tool.function.name === "lookupWeather@1.0.0"));
});
test("matching tool calls execute the registered skill and return tool results", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-exec" });
const apiKey = await seedApiKey();
await enableSkills();
skillExecutor.registerHandler("weather-handler-exec", async (input) => ({
forecast: `Sunny in ${input.location}`,
}));
await registerSkill({
apiKeyId: apiKey.id,
name: "lookupWeather",
handler: "weather-handler-exec",
});
globalThis.fetch = async () =>
buildOpenAIToolCallResponse({
toolName: "lookupWeather@1.0.0",
argumentsObject: { location: "Recife" },
});
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Check the weather" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(json.choices[0].finish_reason, "tool_calls");
assert.equal(json.tool_results[0].tool_call_id, "call_weather");
assert.equal(JSON.parse(json.tool_results[0].output).forecast, "Sunny in Recife");
});
test("non-matching responses fall through the pipeline normally", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-pass" });
const apiKey = await seedApiKey();
await enableSkills();
skillExecutor.registerHandler("noop-handler", async () => ({ ok: true }));
await registerSkill({
apiKeyId: apiKey.id,
name: "noopSkill",
handler: "noop-handler",
});
globalThis.fetch = async () => buildOpenAIResponse("Normal pipeline response");
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Just answer normally" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(json.choices[0].message.content, "Normal pipeline response");
assert.equal(json.tool_results, undefined);
});
test("sandbox-backed skill execution can be mocked through the executor", async () => {
const apiKey = await seedApiKey();
const originalRun = sandboxRunner.run.bind(sandboxRunner);
skillExecutor.registerHandler("sandbox-handler", async () => {
const result = await sandboxRunner.run("alpine", ["echo", "sandbox"], {});
return { stdout: result.stdout, exitCode: result.exitCode };
});
await registerSkill({
apiKeyId: apiKey.id,
name: "sandboxedSkill",
handler: "sandbox-handler",
});
sandboxRunner.run = async () => ({
id: "sandbox-1",
exitCode: 0,
stdout: "sandbox ok",
stderr: "",
duration: 12,
killed: false,
});
const execution = await skillExecutor.execute(
"sandboxedSkill@1.0.0",
{ command: "echo sandbox" },
{ apiKeyId: apiKey.id, sessionId: "sandbox-session" }
);
sandboxRunner.run = originalRun;
assert.equal(execution.status, "success");
assert.equal(execution.output.stdout, "sandbox ok");
assert.equal(execution.output.exitCode, 0);
});
test("skill execution errors are returned gracefully in tool results", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-error" });
const apiKey = await seedApiKey();
await enableSkills();
skillExecutor.registerHandler("broken-handler", async () => {
throw new Error("sandbox policy denied execution");
});
await registerSkill({
apiKeyId: apiKey.id,
name: "brokenSkill",
handler: "broken-handler",
});
globalThis.fetch = async () =>
buildOpenAIToolCallResponse({
toolName: "brokenSkill@1.0.0",
toolCallId: "call_broken",
});
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "Run the protected tool" }],
},
})
);
const json = await response.json();
assert.equal(response.status, 200);
assert.equal(json.tool_results[0].tool_call_id, "call_broken");
assert.match(JSON.parse(json.tool_results[0].output).error, /sandbox policy denied/);
});
test("disabling a skill removes it from request tool injection", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-disable" });
const apiKey = await seedApiKey();
await enableSkills();
const skill = await registerSkill({
apiKeyId: apiKey.id,
name: "lookupWeather",
handler: "weather-handler-disable",
});
const updateResponse = await skillByIdRouteModule.PUT(
new Request("http://localhost/api/skills/id", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ enabled: false }),
}),
{ params: Promise.resolve({ id: skill.id }) }
);
const fetchBodies = [];
globalThis.fetch = async (_url, init = {}) => {
fetchBodies.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("Skill disabled");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "What tools do you have now?" }],
},
})
);
assert.equal(updateResponse.status, 200);
assert.equal(response.status, 200);
assert.ok(!fetchBodies[0].tools || fetchBodies[0].tools.length === 0);
});
test("builtin and custom skills coexist in the injected tool list", async () => {
await seedConnection("openai", { apiKey: "sk-openai-skill-builtin" });
const apiKey = await seedApiKey();
await enableSkills();
registerBuiltinSkills(skillExecutor);
skillExecutor.registerHandler("custom-weather-handler", async () => ({
forecast: "Cloudy",
}));
await registerSkill({
apiKeyId: apiKey.id,
name: "webSearch",
handler: "web_search",
});
await registerSkill({
apiKeyId: apiKey.id,
name: "lookupWeather",
handler: "custom-weather-handler",
});
const fetchBodies = [];
globalThis.fetch = async (_url, init = {}) => {
fetchBodies.push(init.body ? JSON.parse(String(init.body)) : null);
return buildOpenAIResponse("Both skills available");
};
const response = await handleChat(
buildRequest({
authKey: apiKey.key,
body: {
model: "openai/gpt-4o-mini",
stream: false,
messages: [{ role: "user", content: "List my tools" }],
},
})
);
const toolNames = (fetchBodies[0].tools || []).map((tool) => tool.function.name).sort();
assert.equal(response.status, 200);
assert.deepEqual(toolNames, ["lookupWeather@1.0.0", "webSearch@1.0.0"]);
});

View File

@@ -0,0 +1,186 @@
import test from "node:test";
import assert from "node:assert/strict";
const accountFallback = await import("../../open-sse/services/accountFallback.ts");
const accountSelector = await import("../../open-sse/services/accountSelector.ts");
const { RateLimitReason, COOLDOWN_MS, PROVIDER_PROFILES } =
await import("../../open-sse/config/constants.ts");
const {
isOAuthInvalidToken,
parseRetryFromErrorText,
checkFallbackError,
filterAvailableAccounts,
getEarliestRateLimitedUntil,
formatRetryAfter,
applyErrorState,
lockModelIfPerModelQuota,
isModelLocked,
hasPerModelQuota,
getProviderProfile,
} = accountFallback;
const { selectAccount } = accountSelector;
function withMockedNow(now, fn) {
const originalNow = Date.now;
Date.now = () => now;
try {
return fn();
} finally {
Date.now = originalNow;
}
}
test("isOAuthInvalidToken detects refreshable oauth failures", () => {
assert.equal(
isOAuthInvalidToken("Invalid authentication credentials for this OAuth 2 session"),
true
);
assert.equal(isOAuthInvalidToken("plain rate limit"), false);
});
test("parseRetryFromErrorText parses both compact reset formats", () => {
assert.equal(parseRetryFromErrorText("Your quota will reset after 2h30m14s"), 9_014_000);
assert.equal(parseRetryFromErrorText("The pool will reset after 45m"), 2_700_000);
assert.equal(parseRetryFromErrorText("This will reset after 30s"), 30_000);
assert.equal(parseRetryFromErrorText("No reset metadata"), null);
});
test("checkFallbackError marks deactivated accounts as permanent auth failures", () => {
const result = checkFallbackError(401, "This account has been deactivated");
assert.equal(result.shouldFallback, true);
assert.equal(result.reason, RateLimitReason.AUTH_ERROR);
assert.equal(result.permanent, true);
assert.ok(result.cooldownMs >= 300 * 24 * 60 * 60 * 1000);
});
test("checkFallbackError treats exhausted credits as long quota cooldowns", () => {
const result = checkFallbackError(429, "credit_balance_too_low");
assert.equal(result.shouldFallback, true);
assert.equal(result.reason, RateLimitReason.QUOTA_EXHAUSTED);
assert.equal(result.creditsExhausted, true);
assert.equal(result.cooldownMs, COOLDOWN_MS.paymentRequired ?? 3600 * 1000);
});
test("checkFallbackError honors Retry-After header for rate limits", () => {
withMockedNow(1_700_000_000_000, () => {
const headers = new Headers({ "retry-after": "120" });
const result = checkFallbackError(429, "Rate limit hit", 3, null, "openai", headers);
assert.equal(result.shouldFallback, true);
assert.equal(result.reason, RateLimitReason.RATE_LIMIT_EXCEEDED);
assert.equal(result.newBackoffLevel, 0);
assert.equal(result.cooldownMs, 120_000);
});
});
test("checkFallbackError honors x-ratelimit-reset for transient 5xx errors", () => {
withMockedNow(1_700_000_000_000, () => {
const resetSeconds = Math.floor((Date.now() + 90_000) / 1000);
const headers = new Headers({ "x-ratelimit-reset": String(resetSeconds) });
const result = checkFallbackError(503, "upstream unavailable", 1, null, "openai", headers);
assert.equal(result.shouldFallback, true);
assert.equal(result.reason, RateLimitReason.SERVER_ERROR);
assert.equal(result.newBackoffLevel, 0);
assert.ok(result.cooldownMs >= 89_000);
assert.ok(result.cooldownMs <= 90_000);
});
});
test("checkFallbackError keeps generic 400 client errors terminal", () => {
const result = checkFallbackError(400, "bad request payload");
assert.deepEqual(result, {
shouldFallback: false,
cooldownMs: 0,
reason: RateLimitReason.UNKNOWN,
});
});
test("filterAvailableAccounts skips exclusion and active cooldowns but keeps recovered ones", () => {
withMockedNow(1_700_000_000_000, () => {
const accounts = [
{ id: "exclude-me" },
{ id: "cooling", rateLimitedUntil: new Date(Date.now() + 60_000).toISOString() },
{ id: "recovered", rateLimitedUntil: new Date(Date.now() - 1_000).toISOString() },
{ id: "healthy" },
];
const available = filterAvailableAccounts(accounts, "exclude-me");
assert.deepEqual(
available.map((account) => account.id),
["recovered", "healthy"]
);
});
});
test("getEarliestRateLimitedUntil returns the shortest future cooldown and formatRetryAfter humanizes it", () => {
withMockedNow(1_700_000_000_000, () => {
const earliest = getEarliestRateLimitedUntil([
{ id: "expired", rateLimitedUntil: new Date(Date.now() - 5_000).toISOString() },
{ id: "later", rateLimitedUntil: new Date(Date.now() + 90_000).toISOString() },
{ id: "earliest", rateLimitedUntil: new Date(Date.now() + 30_000).toISOString() },
]);
assert.equal(earliest, new Date(Date.now() + 30_000).toISOString());
assert.equal(formatRetryAfter(earliest), "reset after 30s");
});
});
test("applyErrorState and selectAccount advance to the next account after an auth failure", () => {
withMockedNow(1_700_000_000_000, () => {
const accounts = [
{ id: "conn-a", backoffLevel: 0 },
{ id: "conn-b", backoffLevel: 0 },
];
const firstSelection = selectAccount(accounts, "fill-first");
assert.equal(firstSelection.account.id, "conn-a");
const failedFirst = applyErrorState(firstSelection.account, 401, "Unauthorized", "claude");
assert.equal(failedFirst.status, "error");
assert.equal(failedFirst.lastError.reason, RateLimitReason.AUTH_ERROR);
const candidates = filterAvailableAccounts([failedFirst, accounts[1]], failedFirst.id);
const nextSelection = selectAccount(candidates, "fill-first");
assert.equal(nextSelection.account.id, "conn-b");
});
});
test("lockModelIfPerModelQuota only locks supported providers and real models", () => {
const geminiConnectionId = `gemini-${Date.now()}`;
const openAiConnectionId = `openai-${Date.now()}`;
assert.equal(hasPerModelQuota("gemini"), true);
assert.equal(hasPerModelQuota("openai"), false);
assert.equal(
lockModelIfPerModelQuota(
"gemini",
geminiConnectionId,
"gemini-2.5-pro",
RateLimitReason.RATE_LIMIT_EXCEEDED,
30_000
),
true
);
assert.equal(isModelLocked("gemini", geminiConnectionId, "gemini-2.5-pro"), true);
assert.equal(
lockModelIfPerModelQuota(
"openai",
openAiConnectionId,
"gpt-5-mini",
RateLimitReason.RATE_LIMIT_EXCEEDED,
30_000
),
false
);
assert.equal(isModelLocked("openai", openAiConnectionId, "gpt-5-mini"), false);
});
test("getProviderProfile differentiates oauth and api-key providers", () => {
assert.deepEqual(getProviderProfile("claude"), PROVIDER_PROFILES.oauth);
assert.deepEqual(getProviderProfile("openai"), PROVIDER_PROFILES.apikey);
});

View File

@@ -42,7 +42,7 @@ test("GET /api/keys stays masked even when reveal is enabled", async () => {
process.env.ALLOW_API_KEY_REVEAL = "true";
const created = await apiKeysDb.createApiKey("Primary Key", MACHINE_ID);
const response = await listRoute.GET();
const response = await listRoute.GET(new Request("http://localhost/api/keys"));
const body = await response.json();
assert.equal(response.status, 200);

View File

@@ -0,0 +1,209 @@
import test from "node:test";
import assert from "node:assert/strict";
const { handleAudioSpeech } = await import("../../open-sse/handlers/audioSpeech.ts");
test("handleAudioSpeech requires model", async () => {
const response = await handleAudioSpeech({
body: { input: "hello" },
credentials: { apiKey: "x" },
});
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "model is required");
});
test("handleAudioSpeech requires input text", async () => {
const response = await handleAudioSpeech({
body: { model: "openai/tts-1" },
credentials: { apiKey: "x" },
});
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "input is required");
});
test("handleAudioSpeech proxies OpenAI-compatible providers with defaults", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options = {}) => {
captured = {
url: String(url),
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
};
return new Response(new Uint8Array([1, 2, 3]), {
status: 200,
headers: { "content-type": "audio/opus" },
});
};
try {
const response = await handleAudioSpeech({
body: {
model: "openai/tts-1",
input: "hello world",
},
credentials: { apiKey: "openai-key" },
});
assert.equal(captured.url, "https://api.openai.com/v1/audio/speech");
assert.equal(captured.headers.Authorization, "Bearer openai-key");
assert.deepEqual(captured.body, {
model: "tts-1",
input: "hello world",
voice: "alloy",
response_format: "mp3",
speed: 1,
});
assert.equal(response.status, 200);
assert.equal(response.headers.get("content-type"), "audio/opus");
assert.ok(response.headers.get("access-control-allow-origin"));
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioSpeech routes Deepgram with Token auth and model query parameter", async () => {
const originalFetch = globalThis.fetch;
let capturedUrl;
let capturedHeaders;
globalThis.fetch = async (url, options = {}) => {
capturedUrl = String(url);
capturedHeaders = options.headers;
const body = JSON.parse(String(options.body || "{}"));
assert.deepEqual(body, { text: "deepgram text" });
return new Response(new Uint8Array([9, 8, 7]), {
status: 200,
headers: { "content-type": "audio/mpeg" },
});
};
try {
const response = await handleAudioSpeech({
body: {
model: "deepgram/aura-asteria-en",
input: "deepgram text",
},
credentials: { apiKey: "dg-key" },
});
const url = new URL(capturedUrl);
assert.equal(url.origin + url.pathname, "https://api.deepgram.com/v1/speak");
assert.equal(url.searchParams.get("model"), "aura-asteria-en");
assert.equal(capturedHeaders.Authorization, "Token dg-key");
assert.equal(response.status, 200);
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioSpeech rejects invalid ElevenLabs voice identifiers", async () => {
const originalFetch = globalThis.fetch;
let called = false;
globalThis.fetch = async () => {
called = true;
throw new Error("should not fetch");
};
try {
const response = await handleAudioSpeech({
body: {
model: "elevenlabs/eleven_turbo_v2_5",
input: "bad voice",
voice: "../secret",
},
credentials: { apiKey: "xi-key" },
});
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "Invalid voice ID");
assert.equal(called, false);
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioSpeech maps Cartesia voice and wav output settings", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (_url, options = {}) => {
captured = {
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
};
return new Response(new Uint8Array([4, 5, 6]), {
status: 200,
headers: { "content-type": "audio/wav" },
});
};
try {
const response = await handleAudioSpeech({
body: {
model: "cartesia/sonic-2",
input: "cartesia text",
voice: "voice-123",
response_format: "wav",
},
credentials: { apiKey: "cartesia-key" },
});
assert.equal(captured.headers["X-API-Key"], "cartesia-key");
assert.equal(captured.headers["Cartesia-Version"], "2024-06-10");
assert.deepEqual(captured.body, {
model_id: "sonic-2",
transcript: "cartesia text",
voice: { mode: "id", id: "voice-123" },
output_format: { container: "wav", sample_rate: 44100 },
});
assert.equal(response.headers.get("content-type"), "audio/wav");
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioSpeech maps PlayHT credentials, output format, and speed", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (_url, options = {}) => {
captured = {
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
};
return new Response(new Uint8Array([7, 7, 7]), {
status: 200,
headers: { "content-type": "audio/mpeg" },
});
};
try {
const response = await handleAudioSpeech({
body: {
model: "playht/Play3.0-mini",
input: "playht text",
response_format: "aac",
speed: 1.25,
},
credentials: { apiKey: "user-1:api-key-1" },
});
assert.equal(captured.headers["X-USER-ID"], "user-1");
assert.equal(captured.headers.Authorization, "Bearer api-key-1");
assert.equal(captured.body.voice_engine, "Play3.0-mini");
assert.equal(captured.body.output_format, "aac");
assert.equal(captured.body.speed, 1.25);
assert.equal(response.status, 200);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,227 @@
import test from "node:test";
import assert from "node:assert/strict";
const { handleAudioTranscription } = await import("../../open-sse/handlers/audioTranscription.ts");
function buildFile(contents, name, type) {
return new File([Buffer.from(contents)], name, { type });
}
test("handleAudioTranscription requires model", async () => {
const formData = new FormData();
formData.append("file", buildFile("abc", "audio.wav", "audio/wav"));
const response = await handleAudioTranscription({ formData, credentials: { apiKey: "x" } });
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "model is required");
});
test("handleAudioTranscription requires a file upload", async () => {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
const response = await handleAudioTranscription({ formData, credentials: { apiKey: "x" } });
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "file is required");
});
test("handleAudioTranscription proxies OpenAI-compatible multipart requests and forwards optional params", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options = {}) => {
const upstreamEntries = Array.from(options.body.entries());
captured = {
url: String(url),
headers: options.headers,
entries: upstreamEntries.map(([key, value]) => [
key,
value instanceof File ? { name: value.name, type: value.type } : value,
]),
};
return new Response(JSON.stringify({ text: "hello" }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.webm", "audio/webm"));
formData.append("language", "pt");
formData.append("prompt", "meeting");
formData.append("response_format", "verbose_json");
formData.append("temperature", "0.1");
formData.append("timestamp_granularities[]", "word");
const response = await handleAudioTranscription({
formData,
credentials: { apiKey: "openai-key" },
});
assert.equal(response.status, 200);
assert.equal(captured.url, "https://api.openai.com/v1/audio/transcriptions");
assert.equal(captured.headers.Authorization, "Bearer openai-key");
assert.deepEqual(captured.entries, [
["file", { name: "clip.webm", type: "audio/webm" }],
["model", "whisper-1"],
["language", "pt"],
["prompt", "meeting"],
["response_format", "verbose_json"],
["temperature", "0.1"],
["timestamp_granularities[]", "word"],
]);
assert.deepEqual(await response.json(), { text: "hello" });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranscription routes Deepgram with binary upload and language passthrough", async () => {
const originalFetch = globalThis.fetch;
let capturedUrl;
let capturedHeaders;
let capturedBody;
globalThis.fetch = async (url, options = {}) => {
capturedUrl = String(url);
capturedHeaders = options.headers;
capturedBody = options.body;
return new Response(
JSON.stringify({
results: {
channels: [{ alternatives: [{ transcript: "ola mundo" }] }],
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const formData = new FormData();
formData.append("model", "deepgram/nova-3");
formData.append("file", buildFile("abc", "clip.mp4", "video/mp4"));
formData.append("language", "pt-BR");
const response = await handleAudioTranscription({
formData,
credentials: { apiKey: "dg-key" },
});
const payload = await response.json();
const url = new URL(capturedUrl);
assert.equal(url.origin + url.pathname, "https://api.deepgram.com/v1/listen");
assert.equal(url.searchParams.get("model"), "nova-3");
assert.equal(url.searchParams.get("language"), "pt-BR");
assert.equal(url.searchParams.get("detect_language"), null);
assert.equal(capturedHeaders.Authorization, "Token dg-key");
assert.equal(capturedHeaders["Content-Type"], "audio/mp4");
assert.ok(capturedBody instanceof ArrayBuffer);
assert.deepEqual(payload, { text: "ola mundo", noSpeechDetected: false });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranscription marks noSpeechDetected when Deepgram returns no transcript", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(
JSON.stringify({
results: {
channels: [{ alternatives: [{ transcript: "" }] }],
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
try {
const formData = new FormData();
formData.append("model", "deepgram/nova-3");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranscription({
formData,
credentials: { apiKey: "dg-key" },
});
assert.deepEqual(await response.json(), { text: "", noSpeechDetected: true });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranscription normalizes Nvidia responses to text", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (_url, options = {}) => {
captured = {
headers: options.headers,
entries: Array.from(options.body.entries()).map(([key, value]) => [
key,
value instanceof File ? { name: value.name, type: value.type } : value,
]),
};
return new Response(JSON.stringify({ transcript: "nvidia text" }), {
status: 200,
headers: { "content-type": "application/json" },
});
};
try {
const formData = new FormData();
formData.append("model", "nvidia/nvidia/parakeet-ctc-1.1b-asr");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranscription({
formData,
credentials: { apiKey: "nvidia-key" },
});
assert.equal(captured.headers.Authorization, "Bearer nvidia-key");
assert.deepEqual(captured.entries, [
["file", { name: "clip.wav", type: "audio/wav" }],
["model", "nvidia/parakeet-ctc-1.1b-asr"],
]);
assert.deepEqual(await response.json(), { text: "nvidia text" });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleAudioTranscription rejects invalid HuggingFace model paths", async () => {
const formData = new FormData();
formData.append("model", "huggingface/../escape");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranscription({
formData,
credentials: { apiKey: "hf-key" },
});
const payload = await response.json();
assert.equal(response.status, 400);
assert.equal(payload.error.message, "Invalid model ID");
});
test("handleAudioTranscription requires credentials for authenticated providers", async () => {
const formData = new FormData();
formData.append("model", "openai/whisper-1");
formData.append("file", buildFile("abc", "clip.wav", "audio/wav"));
const response = await handleAudioTranscription({ formData, credentials: null });
const payload = await response.json();
assert.equal(response.status, 401);
assert.equal(payload.error.message, "No credentials for transcription provider: openai");
});

View File

@@ -0,0 +1,85 @@
import test from "node:test";
import assert from "node:assert/strict";
const { handleBypassRequest } = await import("../../open-sse/utils/bypassHandler.ts");
test("handleBypassRequest returns null for non-Claude clients or missing messages", () => {
assert.equal(handleBypassRequest({ messages: [] }, "gpt-5", "claude-cli/2.1.89"), null);
assert.equal(
handleBypassRequest(
{
messages: [{ role: "user", content: "Warmup" }],
},
"gpt-5",
{ broken: true }
),
null
);
assert.equal(
handleBypassRequest(
{
messages: [{ role: "user", content: "Warmup" }],
},
"gpt-5",
"curl/8.0"
),
null
);
});
test("handleBypassRequest returns a canned JSON response for warmup bypasses", async () => {
const result = handleBypassRequest(
{
stream: false,
messages: [{ role: "user", content: "Warmup" }],
},
"gpt-5-mini",
"claude-cli/2.1.89"
);
assert.ok(result);
assert.equal(result.success, true);
assert.equal(result.response.headers.get("content-type"), "application/json");
const payload = await result.response.json();
assert.equal(payload.model, "gpt-5-mini");
assert.equal(payload.choices[0].message.role, "assistant");
assert.match(payload.choices[0].message.content, /clear terminal/i);
});
test("handleBypassRequest returns an SSE response for title extraction bypasses", async () => {
const result = handleBypassRequest(
{
messages: [
{ role: "user", content: "ignored" },
{ role: "assistant", content: [{ type: "text", text: "{" }] },
],
},
"gpt-5",
"claude-cli/2.1.89"
);
assert.ok(result);
assert.equal(result.success, true);
assert.equal(result.response.headers.get("content-type"), "text/event-stream");
const body = await result.response.text();
assert.match(body, /data:/);
assert.match(body, /\[DONE\]/);
});
test("handleBypassRequest bypasses single-message count probes", async () => {
const result = handleBypassRequest(
{
stream: false,
messages: [{ role: "user", content: [{ type: "text", text: "count" }] }],
},
"gpt-4.1-mini",
"claude-cli/2.1.89"
);
assert.ok(result);
const payload = await result.response.json();
assert.equal(payload.usage.total_tokens, 2);
assert.equal(payload.choices[0].finish_reason, "stop");
});

View File

@@ -0,0 +1,397 @@
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-chatcore-sanitization-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const { createMemory } = await import("../../src/lib/memory/store.ts");
const { invalidateMemorySettingsCache } = await import("../../src/lib/memory/settings.ts");
const core = await import("../../src/lib/db/core.ts");
function noopLog() {
return {
debug() {},
info() {},
warn() {},
error() {},
};
}
function toPlainHeaders(headers) {
if (!headers) return {};
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
return Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, value == null ? "" : String(value)])
);
}
function buildUpstreamResponse(stream) {
if (stream) {
return new Response(
'data: {"id":"chatcmpl-stream","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"ok"}}]}\n\ndata: [DONE]\n\n',
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
return new Response(
JSON.stringify({
id: "chatcmpl-json",
object: "chat.completion",
model: "gpt-4o-mini",
choices: [
{
index: 0,
message: { role: "assistant", content: "ok" },
finish_reason: "stop",
},
],
usage: {
prompt_tokens: 1,
completion_tokens: 1,
total_tokens: 2,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function ensureLegacyMemoryTable() {
const db = core.getDbInstance();
db.exec(`
CREATE TABLE IF NOT EXISTS memory (
id TEXT PRIMARY KEY,
apiKeyId TEXT NOT NULL,
sessionId TEXT,
type TEXT NOT NULL,
key TEXT,
content TEXT NOT NULL,
metadata TEXT,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
expiresAt TEXT
)
`);
}
async function invokeChatCore({
body,
accept = "application/json",
provider = "openai",
model = "gpt-4o-mini",
endpoint = "/v1/chat/completions",
credentials = { apiKey: "sk-test", providerSpecificData: {} },
apiKeyInfo = null,
userAgent = "unit-test",
responseFactory,
} = {}) {
const originalFetch = globalThis.fetch;
const calls = [];
const resolvedStream =
body?.stream === true ||
(body?.stream === undefined && String(accept).toLowerCase().includes("text/event-stream"));
globalThis.fetch = async (url, init = {}) => {
const parsedBody = init.body ? JSON.parse(String(init.body)) : null;
const captured = {
url: String(url),
method: init.method || "GET",
headers: toPlainHeaders(init.headers),
body: parsedBody,
};
calls.push(captured);
return responseFactory ? responseFactory(captured) : buildUpstreamResponse(resolvedStream);
};
try {
const requestBody = structuredClone(body);
const result = await handleChatCore({
body: requestBody,
modelInfo: { provider, model, extendedContext: false },
credentials: structuredClone(credentials),
log: noopLog(),
clientRawRequest: {
endpoint,
body: structuredClone(body),
headers: new Headers({ accept }),
},
apiKeyInfo,
userAgent,
});
return { result, call: calls.at(-1), calls };
} finally {
globalThis.fetch = originalFetch;
}
}
test.after(() => {
try {
const db = core.getDbInstance();
db.close();
} catch {}
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("chatCore sanitization normalizes max_output_tokens into max_tokens", async () => {
const copied = await invokeChatCore({
body: {
model: "gpt-4o-mini",
max_output_tokens: 0,
messages: [{ role: "user", content: "hello" }],
},
});
const preserved = await invokeChatCore({
body: {
model: "gpt-4o-mini",
max_output_tokens: 64,
max_tokens: 7,
messages: [{ role: "user", content: "hello" }],
},
});
const untouched = await invokeChatCore({
body: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: "hello" }],
},
});
assert.equal(copied.call.body.max_tokens, 0);
assert.equal("max_output_tokens" in copied.call.body, false);
assert.equal(preserved.call.body.max_tokens, 7);
assert.equal("max_output_tokens" in preserved.call.body, false);
assert.equal("max_tokens" in untouched.call.body, false);
});
test("chatCore sanitization strips empty message and input names and filters empty tool names", async () => {
const { call } = await invokeChatCore({
body: {
model: "gpt-4o-mini",
messages: [
{ role: "user", content: "hello", name: "" },
{ role: "assistant", content: "world", name: "valid-name" },
],
input: [
{ role: "user", content: "input-1", name: "" },
{ role: "user", content: "input-2", name: "still-valid" },
],
tools: [
{ type: "function", function: { name: "lookup_weather", parameters: { type: "object" } } },
{ type: "function", function: { name: "", parameters: { type: "object" } } },
{ type: "function", function: { name: " ", parameters: { type: "object" } } },
{ name: "anthropic_lookup", input_schema: { type: "object" } },
{ name: "", input_schema: { type: "object" } },
],
},
});
assert.equal(call.body.messages[0].name, undefined);
assert.equal(call.body.messages[1].name, "valid-name");
assert.equal(call.body.input[0].name, undefined);
assert.equal(call.body.input[1].name, "still-valid");
assert.equal(call.body.tools.length, 2);
assert.equal(call.body.tools[0].function.name, "lookup_weather");
assert.equal(call.body.tools[1].function.name, "anthropic_lookup");
});
test("chatCore sanitization normalizes mixed content blocks and removes unsupported or empty ones", async () => {
const { call } = await invokeChatCore({
body: {
model: "gpt-4o-mini",
messages: [
{
role: "user",
content: [
{ type: "text", text: "keep me" },
{ type: "text", text: "" },
{ type: "image_url", image_url: { url: "https://example.com/image.png" } },
{ type: "image", source: { type: "base64", media_type: "image/png", data: "abc" } },
{ type: "file_url", file_url: { url: "data:text/plain;base64,SGk=" } },
{ type: "file", file: { name: "README.md", content: "Read me please." } },
{ type: "file", file: { name: "blob.bin", data: "AAEC" } },
{ type: "document", name: "notes.txt", text: "Meeting notes" },
{ type: "document", document: { url: "data:text/plain;base64,SGVsbG8=" } },
{ type: "tool_result", tool_use_id: "tool-1", content: "done" },
{
type: "tool_result",
tool_use_id: "tool-2",
content: [{ type: "text", text: "structured result" }],
},
{ type: "unknown_block", value: "drop me" },
],
},
],
},
});
const content = call.body.messages[0].content;
const textBlocks = content.filter((block) => block.type === "text");
assert.equal(
content.some((block) => block.type === "text" && block.text === ""),
false
);
assert.equal(
content.some((block) => block.type === "unknown_block"),
false
);
assert.equal(
content.some((block) => block.type === "image_url"),
true
);
assert.equal(
content.some((block) => block.type === "image"),
true
);
assert.equal(
content.some(
(block) => block.type === "file_url" && block.file_url.url.startsWith("data:text/plain")
),
true
);
assert.equal(
content.some((block) => block.type === "file" && block.file?.data === "AAEC"),
true
);
assert.equal(
content.some((block) => block.type === "document" && block.document?.url.startsWith("data:")),
true
);
assert.equal(
textBlocks.some((block) => block.text === "[README.md]\nRead me please."),
true
);
assert.equal(
textBlocks.some((block) => block.text === "[notes.txt]\nMeeting notes"),
true
);
assert.equal(
textBlocks.some((block) => block.text === "[Tool Result: tool-1]\ndone"),
true
);
assert.equal(
textBlocks.some((block) => block.text === "[Tool Result: tool-2]\nstructured result"),
true
);
});
test("chatCore resolves stream mode from body.stream and Accept header", async () => {
const explicitTrue = await invokeChatCore({
accept: "application/json",
body: { model: "gpt-4o-mini", stream: true, messages: [{ role: "user", content: "hello" }] },
});
const explicitFalse = await invokeChatCore({
accept: "text/event-stream",
body: { model: "gpt-4o-mini", stream: false, messages: [{ role: "user", content: "hello" }] },
});
const acceptDriven = await invokeChatCore({
accept: "text/event-stream",
body: { model: "gpt-4o-mini", messages: [{ role: "user", content: "hello" }] },
});
const jsonDefault = await invokeChatCore({
accept: "application/json",
body: { model: "gpt-4o-mini", messages: [{ role: "user", content: "hello" }] },
});
assert.equal(explicitTrue.call.headers.Accept, "text/event-stream");
assert.equal(explicitFalse.call.headers.Accept, undefined);
assert.equal(acceptDriven.call.headers.Accept, "text/event-stream");
assert.equal(jsonDefault.call.headers.Accept, undefined);
});
test("chatCore injects memories when enabled and memories are found", async () => {
await settingsDb.updateSettings({
memoryEnabled: true,
memoryMaxTokens: 1024,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
invalidateMemorySettingsCache();
ensureLegacyMemoryTable();
const apiKeyId = `key-memory-${Date.now()}`;
await createMemory({
apiKeyId,
sessionId: "session-1",
type: "factual",
key: "preference",
content: "User prefers concise Rust examples.",
metadata: {},
expiresAt: null,
});
const { call } = await invokeChatCore({
apiKeyInfo: { id: apiKeyId, name: "Memory Key" },
body: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Give me a snippet." }],
},
});
assert.equal(call.body.messages[0].role, "system");
assert.match(
call.body.messages[0].content,
/Memory context: User prefers concise Rust examples\./
);
assert.equal(call.body.messages[1].role, "user");
});
test("chatCore skips memory injection when memory is disabled or apiKeyInfo is missing", async () => {
await settingsDb.updateSettings({
memoryEnabled: false,
memoryMaxTokens: 0,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
invalidateMemorySettingsCache();
const disabled = await invokeChatCore({
apiKeyInfo: { id: `key-disabled-${Date.now()}`, name: "Disabled Key" },
body: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
},
});
const noApiKey = await invokeChatCore({
body: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
},
});
assert.equal(disabled.call.body.messages[0].role, "user");
assert.equal(disabled.call.body.messages[0].content, "Hello");
assert.equal(noApiKey.call.body.messages[0].role, "user");
assert.equal(noApiKey.call.body.messages[0].content, "Hello");
});
test("chatCore skips memory injection when shouldInjectMemory returns false for empty message lists", async () => {
await settingsDb.updateSettings({
memoryEnabled: true,
memoryMaxTokens: 1024,
memoryRetentionDays: 30,
memoryStrategy: "recent",
});
invalidateMemorySettingsCache();
const { call } = await invokeChatCore({
apiKeyInfo: { id: `key-empty-${Date.now()}`, name: "Empty Key" },
body: {
model: "gpt-4o-mini",
messages: [],
},
});
assert.deepEqual(call.body.messages, []);
});

View File

@@ -0,0 +1,698 @@
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-chatcore-translation-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const upstreamProxyDb = await import("../../src/lib/db/upstreamProxy.ts");
const { invalidateCacheControlSettingsCache } =
await import("../../src/lib/cacheControlSettings.ts");
const { handleChatCore } = await import("../../open-sse/handlers/chatCore.ts");
const { FORMATS } = await import("../../open-sse/translator/formats.ts");
const { register, getRequestTranslator } = await import("../../open-sse/translator/registry.ts");
const originalFetch = globalThis.fetch;
const originalResponsesToOpenAI = getRequestTranslator(FORMATS.OPENAI_RESPONSES, FORMATS.OPENAI);
function noopLog() {
return {
debug() {},
info() {},
warn() {},
error() {},
};
}
function toPlainHeaders(headers) {
if (!headers) return {};
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
return Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, value == null ? "" : String(value)])
);
}
function buildOpenAIResponse(stream, text = "ok") {
if (stream) {
return new Response(
`data: ${JSON.stringify({
id: "chatcmpl-stream",
object: "chat.completion.chunk",
choices: [{ index: 0, delta: { role: "assistant", content: text } }],
})}\n\ndata: [DONE]\n\n`,
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
return new Response(
JSON.stringify({
id: "chatcmpl-json",
object: "chat.completion",
model: "gpt-4o-mini",
choices: [
{
index: 0,
message: { role: "assistant", content: text },
finish_reason: "stop",
},
],
usage: {
prompt_tokens: 4,
completion_tokens: 2,
total_tokens: 6,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildClaudeResponse(stream, text = "ok") {
if (stream) {
return new Response(
[
"event: message_start",
`data: ${JSON.stringify({
type: "message_start",
message: {
id: "msg_stream",
type: "message",
role: "assistant",
model: "claude-sonnet-4-6",
usage: { input_tokens: 12, output_tokens: 0 },
},
})}`,
"",
"event: content_block_start",
`data: ${JSON.stringify({
type: "content_block_start",
index: 0,
content_block: { type: "text", text: "" },
})}`,
"",
"event: content_block_delta",
`data: ${JSON.stringify({
type: "content_block_delta",
index: 0,
delta: { type: "text_delta", text },
})}`,
"",
"event: message_delta",
`data: ${JSON.stringify({
type: "message_delta",
delta: { stop_reason: "end_turn" },
usage: { output_tokens: 3 },
})}`,
"",
"event: message_stop",
`data: ${JSON.stringify({ type: "message_stop" })}`,
"",
].join("\n"),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
}
return new Response(
JSON.stringify({
id: "msg_json",
type: "message",
role: "assistant",
model: "claude-sonnet-4-6",
content: [{ type: "text", text }],
stop_reason: "end_turn",
usage: {
input_tokens: 12,
output_tokens: 3,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function buildResponsesResponse(text = "ok") {
return new Response(
JSON.stringify({
id: "resp_123",
object: "response",
status: "completed",
model: "gpt-5.1-codex",
output: [
{
id: "msg_123",
type: "message",
role: "assistant",
content: [{ type: "output_text", text, annotations: [] }],
},
],
usage: {
input_tokens: 4,
output_tokens: 2,
total_tokens: 6,
},
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
}
function hasCacheControl(value) {
if (!value || typeof value !== "object") return false;
if (Array.isArray(value)) {
return value.some((item) => hasCacheControl(item));
}
if (Object.hasOwn(value, "cache_control")) return true;
return Object.values(value).some((item) => hasCacheControl(item));
}
function collectTextBlocks(messages) {
if (!Array.isArray(messages)) return [];
return messages.flatMap((message) =>
Array.isArray(message.content) ? message.content.filter((block) => block?.type === "text") : []
);
}
async function resetStorage() {
register(FORMATS.OPENAI_RESPONSES, FORMATS.OPENAI, originalResponsesToOpenAI, null);
invalidateCacheControlSettingsCache();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
async function invokeChatCore({
body,
provider = "openai",
model = "gpt-4o-mini",
endpoint = "/v1/chat/completions",
accept = "application/json",
userAgent = "unit-test",
credentials,
apiKeyInfo = null,
responseFormat = "openai",
responseFactory,
isCombo = false,
comboStrategy = null,
} = {}) {
const calls = [];
globalThis.fetch = async (url, init = {}) => {
const headers = toPlainHeaders(init.headers);
const captured = {
url: String(url),
method: init.method || "GET",
headers,
body: init.body ? JSON.parse(String(init.body)) : null,
};
calls.push(captured);
if (responseFactory) {
return responseFactory(captured, calls);
}
const upstreamStream = String(headers.accept || "")
.toLowerCase()
.includes("text/event-stream");
if (responseFormat === "claude") return buildClaudeResponse(upstreamStream);
if (responseFormat === "openai-responses") return buildResponsesResponse();
return buildOpenAIResponse(upstreamStream);
};
try {
const requestBody = structuredClone(body);
const result = await handleChatCore({
body: requestBody,
modelInfo: { provider, model, extendedContext: false },
credentials: credentials || {
apiKey: "sk-test",
providerSpecificData: {},
},
log: noopLog(),
clientRawRequest: {
endpoint,
body: structuredClone(body),
headers: new Headers({ accept }),
},
apiKeyInfo,
userAgent,
isCombo,
comboStrategy,
});
return { result, calls, call: calls.at(-1) };
} finally {
globalThis.fetch = originalFetch;
}
}
test.afterEach(async () => {
globalThis.fetch = originalFetch;
await resetStorage();
});
test.after(async () => {
globalThis.fetch = originalFetch;
await resetStorage();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("chatCore keeps Responses-native Codex payloads in native passthrough mode", async () => {
const { call, result } = await invokeChatCore({
provider: "codex",
model: "gpt-5.1-codex",
endpoint: "/v1/responses",
credentials: { accessToken: "codex-token", providerSpecificData: {} },
body: {
model: "gpt-5.1-codex",
input: "ship it",
instructions: "custom system prompt",
store: true,
metadata: { source: "codex-client" },
stream: false,
},
responseFormat: "openai-responses",
});
assert.equal(result.success, true);
assert.match(call.url, /\/responses$/);
assert.equal(call.body.input, "ship it");
assert.equal(call.body.instructions, "custom system prompt");
assert.equal(call.body.store, false);
assert.deepEqual(call.body.metadata, { source: "codex-client" });
assert.equal("messages" in call.body, false);
});
test("chatCore builds Claude Code-compatible upstream requests for CC providers", async () => {
const { call, result } = await invokeChatCore({
provider: "anthropic-compatible-cc-test",
model: "claude-sonnet-4-6",
endpoint: "/v1/chat/completions",
credentials: {
apiKey: "sk-test",
providerSpecificData: {
baseUrl: "https://proxy.example.com/v1/messages?beta=true",
chatPath: "/v1/messages?beta=true",
},
},
body: {
model: "claude-sonnet-4-6",
stream: false,
messages: [{ role: "user", content: "Ping" }],
},
responseFormat: "claude",
});
assert.equal(result.success, true);
assert.equal(call.headers.Accept ?? call.headers.accept, "text/event-stream");
assert.equal(call.body.stream, true);
assert.equal(call.body.context_management.edits[0].type, "clear_thinking_20251015");
assert.equal(typeof call.body.metadata.user_id, "string");
assert.equal(call.body.messages[0].role, "user");
assert.equal(call.body.messages[0].content[0].text, "Ping");
});
test("chatCore preserves cache_control automatically for Claude Code single-model requests", async () => {
await settingsDb.updateSettings({ alwaysPreserveClientCache: "auto" });
invalidateCacheControlSettingsCache();
const claudeBody = {
model: "claude-sonnet-4-6",
max_tokens: 64,
system: [{ type: "text", text: "system", cache_control: { type: "ephemeral", ttl: "5m" } }],
messages: [
{
role: "user",
content: [{ type: "text", text: "u1", cache_control: { type: "ephemeral" } }],
},
{
role: "assistant",
content: [{ type: "text", text: "a1", cache_control: { type: "ephemeral", ttl: "10m" } }],
},
{ role: "user", content: [{ type: "text", text: "u2" }] },
],
tools: [
{
name: "lookup_weather",
description: "Fetch weather",
input_schema: { type: "object" },
cache_control: { type: "ephemeral", ttl: "30m" },
},
],
};
const { call } = await invokeChatCore({
provider: "claude",
model: "claude-sonnet-4-6",
endpoint: "/v1/messages",
credentials: { apiKey: "claude-key", providerSpecificData: {} },
body: claudeBody,
userAgent: "Claude-Code/1.0.0",
responseFormat: "claude",
});
assert.equal(hasCacheControl(call.body), true);
assert.deepEqual(call.body.system[0].cache_control, { type: "ephemeral", ttl: "5m" });
assert.deepEqual(call.body.messages[0].content[0].cache_control, { type: "ephemeral" });
assert.deepEqual(call.body.tools[0].cache_control, { type: "ephemeral", ttl: "30m" });
});
test("chatCore auto cache policy becomes false for nondeterministic combos", async () => {
await settingsDb.updateSettings({ alwaysPreserveClientCache: "auto" });
invalidateCacheControlSettingsCache();
const { call } = await invokeChatCore({
provider: "claude",
model: "claude-sonnet-4-6",
endpoint: "/v1/messages",
credentials: { apiKey: "claude-key", providerSpecificData: {} },
body: {
model: "claude-sonnet-4-6",
max_tokens: 64,
system: [{ type: "text", text: "system", cache_control: { type: "ephemeral", ttl: "5m" } }],
messages: [{ role: "user", content: [{ type: "text", text: "u1" }] }],
},
userAgent: "Claude-Code/1.0.0",
isCombo: true,
comboStrategy: "latency-optimized",
responseFormat: "claude",
});
assert.equal(call.body.system[0].text.includes("You are Claude Code"), true);
assert.equal(
call.body.system.some((block) => block.cache_control?.ttl === "5m"),
false
);
assert.equal(call.body.system.at(-1).cache_control?.ttl, "1h");
});
test("chatCore always-preserve mode keeps cache_control even without Claude Code user-agent", async () => {
await settingsDb.updateSettings({ alwaysPreserveClientCache: "always" });
invalidateCacheControlSettingsCache();
const { call } = await invokeChatCore({
provider: "claude",
model: "claude-sonnet-4-6",
endpoint: "/v1/messages",
credentials: { apiKey: "claude-key", providerSpecificData: {} },
body: {
model: "claude-sonnet-4-6",
max_tokens: 64,
system: [{ type: "text", text: "system", cache_control: { type: "ephemeral", ttl: "5m" } }],
messages: [{ role: "user", content: [{ type: "text", text: "u1" }] }],
},
responseFormat: "claude",
});
assert.equal(hasCacheControl(call.body), true);
assert.deepEqual(call.body.system[0].cache_control, { type: "ephemeral", ttl: "5m" });
});
test("chatCore disables raw Claude passthrough when cache preservation is off and normalizes through OpenAI", async () => {
await settingsDb.updateSettings({ alwaysPreserveClientCache: "never" });
invalidateCacheControlSettingsCache();
const { call } = await invokeChatCore({
provider: "claude",
model: "claude-sonnet-4-6",
endpoint: "/v1/messages",
credentials: { apiKey: "claude-key", providerSpecificData: {} },
body: {
model: "claude-sonnet-4-6",
max_tokens: 64,
system: [{ type: "text", text: "system", cache_control: { type: "ephemeral", ttl: "5m" } }],
messages: [
{
role: "user",
content: [{ type: "text", text: "u1", cache_control: { type: "ephemeral" } }],
},
],
},
userAgent: "Claude-Code/1.0.0",
responseFormat: "claude",
});
assert.equal(call.body.system[0].text.includes("You are Claude Code"), true);
assert.equal(call.body.system.at(-1).cache_control?.ttl, "1h");
assert.equal(call.body.messages[0].content[0].cache_control, undefined);
assert.equal("_disableToolPrefix" in call.body, false);
});
test("chatCore default translation converts Claude requests to OpenAI and strips cache markers for non-Claude providers", async () => {
const { call } = await invokeChatCore({
provider: "openai",
model: "gpt-4o-mini",
endpoint: "/v1/messages",
body: {
model: "claude-sonnet-4-6",
max_tokens: 64,
system: [{ type: "text", text: "system", cache_control: { type: "ephemeral", ttl: "5m" } }],
messages: [
{
role: "user",
content: [{ type: "text", text: "u1", cache_control: { type: "ephemeral" } }],
},
],
},
userAgent: "Claude-Code/1.0.0",
responseFormat: "openai",
});
assert.equal(call.body.model, "gpt-4o-mini");
assert.equal(Array.isArray(call.body.messages), true);
assert.equal(call.body.messages[0].role, "system");
assert.equal(JSON.stringify(call.body).includes("cache_control"), false);
});
test("chatCore sets Claude tool prefix disabling, strips empty Anthropic text blocks, and cleans helper flags", async () => {
const { call } = await invokeChatCore({
provider: "claude",
model: "claude-sonnet-4-6",
endpoint: "/v1/chat/completions",
credentials: { apiKey: "claude-key", providerSpecificData: {} },
body: {
model: "ignored-client-model",
_toolNameMap: new Map([["proxy_Bash", "Bash"]]),
messages: [
{
role: "user",
content: [
{ type: "text", text: "" },
{ type: "text", text: "hello" },
],
},
],
tools: [
{
type: "function",
function: {
name: "Bash",
description: "Execute bash",
parameters: { type: "object" },
},
},
],
},
responseFormat: "claude",
});
assert.equal(call.body.model, "claude-sonnet-4-6");
assert.equal(call.body.tools[0].name, "Bash");
assert.equal(call.body.tools[0].name.startsWith("proxy_"), false);
assert.equal(call.body._toolNameMap, undefined);
assert.equal(call.body._disableToolPrefix, undefined);
assert.deepEqual(
collectTextBlocks(call.body.messages).map((block) => block.text),
["hello"]
);
});
test("chatCore strips unsupported reasoning params and caps provider token fields", async () => {
const { call } = await invokeChatCore({
provider: "openai",
model: "o3",
endpoint: "/v1/chat/completions",
body: {
model: "o3",
messages: [{ role: "user", content: "hello" }],
temperature: 0.7,
presence_penalty: 1,
max_tokens: 99999,
max_completion_tokens: 77777,
},
responseFormat: "openai",
});
assert.equal(call.body.temperature, undefined);
assert.equal(call.body.presence_penalty, undefined);
assert.equal(call.body.max_tokens, 16384);
assert.equal(call.body.max_completion_tokens, 16384);
});
test("chatCore surfaces translation errors with explicit status codes", async () => {
register(
FORMATS.OPENAI_RESPONSES,
FORMATS.OPENAI,
() => {
const error = new Error("responses translator rejected the payload");
error.statusCode = 409;
throw error;
},
null
);
const { result } = await invokeChatCore({
provider: "openai",
model: "gpt-4o-mini",
endpoint: "/v1/responses",
body: {
model: "gpt-4o-mini",
input: "hello",
},
});
assert.equal(result.success, false);
assert.equal(result.status, 409);
assert.equal(result.error, "responses translator rejected the payload");
});
test("chatCore surfaces typed translation errors with the declared error type", async () => {
register(
FORMATS.OPENAI_RESPONSES,
FORMATS.OPENAI,
() => {
const error = new Error("typed translator failure");
error.statusCode = 422;
error.errorType = "unsupported_feature";
throw error;
},
null
);
const { result } = await invokeChatCore({
provider: "openai",
model: "gpt-4o-mini",
endpoint: "/v1/responses",
body: {
model: "gpt-4o-mini",
input: "hello",
},
});
assert.equal(result.success, false);
assert.equal(result.status, 422);
const payload = await result.response.json();
assert.equal(payload.error.type, "unsupported_feature");
assert.equal(payload.error.code, "unsupported_feature");
});
test("chatCore returns 500 when translation throws a generic error", async () => {
register(
FORMATS.OPENAI_RESPONSES,
FORMATS.OPENAI,
() => {
throw new Error("unexpected translator crash");
},
null
);
const { result } = await invokeChatCore({
provider: "openai",
model: "gpt-4o-mini",
endpoint: "/v1/responses",
body: {
model: "gpt-4o-mini",
input: "hello",
},
});
assert.equal(result.success, false);
assert.equal(result.status, 500);
assert.equal(result.error, "unexpected translator crash");
});
test("chatCore uses the native executor when no upstream proxy mode is enabled", async () => {
const { call } = await invokeChatCore({
provider: "openai",
model: "gpt-4o-mini",
body: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: "hello" }],
},
responseFormat: "openai",
});
assert.match(call.url, /^https:\/\/api\.openai\.com\/v1\/chat\/completions$/);
});
test("chatCore routes providers through CLIProxyAPI in passthrough mode", async () => {
await upstreamProxyDb.upsertUpstreamProxyConfig({
providerId: "qoder",
mode: "cliproxyapi",
enabled: true,
});
const { call } = await invokeChatCore({
provider: "qoder",
model: "qoder-rome-30ba3b",
credentials: { apiKey: "qoder-token", providerSpecificData: {} },
body: {
model: "qoder-rome-30ba3b",
messages: [{ role: "user", content: "hello" }],
},
responseFormat: "openai",
});
assert.match(call.url, /^http:\/\/127\.0\.0\.1:8317\/v1\/chat\/completions$/);
assert.equal(call.headers.Authorization ?? call.headers.authorization, "Bearer qoder-token");
});
test("chatCore fallback proxy mode retries through CLIProxyAPI after retryable native failures", async () => {
await upstreamProxyDb.upsertUpstreamProxyConfig({
providerId: "github",
mode: "fallback",
enabled: true,
});
const { calls, result } = await invokeChatCore({
provider: "github",
model: "gpt-4o",
credentials: { accessToken: "gh-token", providerSpecificData: {} },
body: {
model: "gpt-4o",
messages: [{ role: "user", content: "hello" }],
},
responseFormat: "openai",
responseFactory(captured, seenCalls) {
if (seenCalls.length === 1) {
return new Response(JSON.stringify({ error: { message: "native failed" } }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
assert.match(captured.url, /^http:\/\/127\.0\.0\.1:8317\/v1\/chat\/completions$/);
return buildOpenAIResponse(false, "retried");
},
});
assert.equal(result.success, true);
assert.equal(calls.length, 2);
assert.match(calls[0].url, /^https:\/\/api\.githubcopilot\.com\/chat\/completions$/);
assert.match(calls[1].url, /^http:\/\/127\.0\.0\.1:8317\/v1\/chat\/completions$/);
});

View File

@@ -0,0 +1,82 @@
import test from "node:test";
import assert from "node:assert/strict";
const {
CLAUDE_CODE_COMPATIBLE_DEFAULT_CHAT_PATH,
CLAUDE_CODE_COMPATIBLE_DEFAULT_MODELS_PATH,
CLAUDE_CODE_COMPATIBLE_DEFAULT_MAX_TOKENS,
isClaudeCodeCompatibleProvider,
stripAnthropicMessagesSuffix,
stripClaudeCodeCompatibleEndpointSuffix,
joinBaseUrlAndPath,
joinClaudeCodeCompatibleUrl,
buildClaudeCodeCompatibleHeaders,
buildClaudeCodeCompatibleValidationPayload,
resolveClaudeCodeCompatibleSessionId,
} = await import("../../open-sse/services/claudeCodeCompatible.ts");
const { isClaudeCodeCompatible } = await import("../../open-sse/services/provider.ts");
test("Claude Code compatible provider detection matches the shared prefix contract", () => {
assert.equal(isClaudeCodeCompatibleProvider("anthropic-compatible-cc-demo"), true);
assert.equal(isClaudeCodeCompatible("anthropic-compatible-cc-demo"), true);
assert.equal(isClaudeCodeCompatibleProvider("anthropic-compatible-demo"), false);
assert.equal(isClaudeCodeCompatible(null), false);
});
test("base URL helpers strip messages suffixes and join canonical paths", () => {
const baseUrl = "https://cc.example.com/v1/messages?beta=true";
assert.equal(stripAnthropicMessagesSuffix(baseUrl), "https://cc.example.com/v1");
assert.equal(stripClaudeCodeCompatibleEndpointSuffix(baseUrl), "https://cc.example.com");
assert.equal(
joinBaseUrlAndPath(baseUrl, CLAUDE_CODE_COMPATIBLE_DEFAULT_MODELS_PATH),
"https://cc.example.com/v1/models"
);
assert.equal(
joinClaudeCodeCompatibleUrl(baseUrl, CLAUDE_CODE_COMPATIBLE_DEFAULT_CHAT_PATH),
"https://cc.example.com/v1/messages?beta=true"
);
});
test("buildClaudeCodeCompatibleHeaders emits stream-aware auth headers and session id", () => {
const streamHeaders = buildClaudeCodeCompatibleHeaders("sk-demo", true, "session-123");
const jsonHeaders = buildClaudeCodeCompatibleHeaders("sk-demo", false);
assert.equal(streamHeaders.Accept, "text/event-stream");
assert.equal(streamHeaders["x-api-key"], "sk-demo");
assert.equal(streamHeaders["X-Claude-Code-Session-Id"], "session-123");
assert.equal(jsonHeaders.Accept, "application/json");
assert.equal(jsonHeaders["X-Claude-Code-Session-Id"], undefined);
});
test("resolveClaudeCodeCompatibleSessionId prefers explicit session headers and generates a fallback id", () => {
const headers = new Headers({
"x-session-id": "legacy-session",
"x-claude-code-session-id": "preferred-session",
});
assert.equal(resolveClaudeCodeCompatibleSessionId(headers), "preferred-session");
assert.match(
resolveClaudeCodeCompatibleSessionId({}),
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
);
});
test("buildClaudeCodeCompatibleValidationPayload produces the expected smoke-test request", () => {
const payload = buildClaudeCodeCompatibleValidationPayload("claude-sonnet-4-6");
assert.equal(payload.model, "claude-sonnet-4-6");
assert.equal(payload.stream, true);
assert.equal(payload.max_tokens, 1);
assert.equal(payload.output_config.effort, "high");
assert.equal(payload.messages.length, 1);
assert.deepEqual(payload.messages[0], {
role: "user",
content: [{ type: "text", text: "ok" }],
});
assert.equal(payload.tools.length, 0);
assert.ok(JSON.parse(payload.metadata.user_id).session_id);
assert.ok(payload.system.some((block) => String(block.text).includes(process.cwd())));
assert.ok(CLAUDE_CODE_COMPATIBLE_DEFAULT_MAX_TOKENS > payload.max_tokens);
});

View File

@@ -0,0 +1,242 @@
import test from "node:test";
import assert from "node:assert/strict";
const {
CLAUDE_CODE_COMPATIBLE_DEFAULT_MAX_TOKENS,
stripClaudeCodeCompatibleEndpointSuffix,
joinBaseUrlAndPath,
joinClaudeCodeCompatibleUrl,
resolveClaudeCodeCompatibleSessionId,
resolveClaudeCodeCompatibleEffort,
resolveClaudeCodeCompatibleMaxTokens,
buildClaudeCodeCompatibleRequest,
} = await import("../../open-sse/services/claudeCodeCompatible.ts");
test("Claude Code compatible URL helpers cover empty values, version trimming and legacy session headers", () => {
assert.equal(stripClaudeCodeCompatibleEndpointSuffix(""), "");
assert.equal(
stripClaudeCodeCompatibleEndpointSuffix("https://api.example.com/v1/messages"),
"https://api.example.com"
);
assert.equal(
joinBaseUrlAndPath("https://api.example.com/v1", "v1/messages"),
"https://api.example.com/v1/messages"
);
assert.equal(
joinClaudeCodeCompatibleUrl("https://api.example.com/v1/messages", "models"),
"https://api.example.com/models"
);
assert.equal(
resolveClaudeCodeCompatibleSessionId({ "x-omniroute-session": " session-from-proxy " }),
"session-from-proxy"
);
});
test("Claude Code compatible effort and max token helpers cover priority fallbacks", () => {
assert.equal(resolveClaudeCodeCompatibleEffort({ reasoning_effort: "medium" }), "medium");
assert.equal(resolveClaudeCodeCompatibleEffort({ reasoning: { effort: "none" } }), "low");
assert.equal(resolveClaudeCodeCompatibleEffort({ output_config: { effort: "xhigh" } }), "high");
assert.equal(
resolveClaudeCodeCompatibleEffort({ output_config: { effort: "unexpected" } }),
"high"
);
assert.equal(resolveClaudeCodeCompatibleMaxTokens({ max_completion_tokens: "17" }), 17);
assert.equal(
resolveClaudeCodeCompatibleMaxTokens({ max_output_tokens: -1 }, { max_tokens: 9 }),
9
);
assert.equal(resolveClaudeCodeCompatibleMaxTokens({}, { max_output_tokens: "31.9" }), 31);
assert.equal(
resolveClaudeCodeCompatibleMaxTokens({}, {}),
CLAUDE_CODE_COMPATIBLE_DEFAULT_MAX_TOKENS
);
});
test("buildClaudeCodeCompatibleRequest covers normalized OpenAI-style messages, source tools and fallback text", () => {
const payload = buildClaudeCodeCompatibleRequest({
sourceBody: {
tools: [
null,
{
type: "function",
function: {
name: "lookup_account",
description: "Find account data",
parameters: { type: "object" },
defer_loading: true,
},
},
],
tool_choice: { type: "function", function: { name: "lookup_account" } },
reasoning: { effort: "disabled" },
max_completion_tokens: 19,
},
normalizedBody: {
messages: [
{ role: "assistant", content: [{ type: "text", text: "draft answer" }] },
{ role: "model", content: { text: "alternate answer" } },
{ role: "system", content: "system note" },
{ role: "developer", content: [{ type: "text", text: "developer note" }] },
{ role: "tool", content: "ignored" },
],
},
model: "claude-sonnet-4-6",
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
});
assert.deepEqual(payload.messages, [
{
role: "user",
content: [{ type: "text", text: "draft answer\nalternate answer" }],
},
]);
assert.equal(payload.system[3].text, "system note");
assert.equal(payload.system[4].text, "developer note");
assert.equal(payload.tools.length, 1);
assert.deepEqual(payload.tools[0], {
name: "lookup_account",
description: "Find account data",
input_schema: { type: "object", properties: {} },
defer_loading: true,
});
assert.deepEqual(payload.tool_choice, { type: "tool", name: "lookup_account" });
assert.equal(payload.output_config.effort, "low");
assert.equal(payload.max_tokens, 19);
});
test("buildClaudeCodeCompatibleRequest covers Claude-native bodies and cache-control stripping", () => {
const stripped = buildClaudeCodeCompatibleRequest({
claudeBody: {
system: [{ type: "text", text: "sys", cache_control: { type: "ephemeral" } }],
messages: [
{
role: "assistant",
content: [{ type: "text", text: "prefill", cache_control: { type: "ephemeral" } }],
},
{
role: "user",
content: [
{ type: "text", text: "ask", cache_control: { type: "ephemeral" } },
{
type: "image",
source: { type: "base64", media_type: "image/png", data: "abc" },
cache_control: { type: "ephemeral" },
},
],
},
{
role: "assistant",
content: [{ type: "text", text: "tail", cache_control: { type: "ephemeral" } }],
},
],
tools: [
{ name: "toolA", input_schema: { type: "object" }, cache_control: { type: "ephemeral" } },
],
thinking: { type: "enabled", budget_tokens: 12 },
},
model: "claude-sonnet-4-6",
preserveCacheControl: false,
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
stream: true,
sessionId: "explicit-session",
});
const preserved = buildClaudeCodeCompatibleRequest({
claudeBody: {
system: [{ type: "text", text: "sys", cache_control: { type: "ephemeral" } }],
messages: [
{
role: "assistant",
content: [{ type: "text", text: "prefill", cache_control: { type: "ephemeral" } }],
},
{
role: "user",
content: [{ type: "text", text: "ask", cache_control: { type: "ephemeral" } }],
},
],
tools: [
{ name: "toolA", input_schema: { type: "object" }, cache_control: { type: "ephemeral" } },
],
},
model: "claude-sonnet-4-6",
preserveCacheControl: true,
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
});
assert.equal(stripped.stream, true);
assert.equal(JSON.parse(stripped.metadata.user_id).session_id, "explicit-session");
assert.equal(stripped.messages.at(-1).role, "user");
assert.equal(stripped.messages[0].content[0].cache_control, undefined);
assert.equal(stripped.system.at(-1).cache_control, undefined);
assert.equal(stripped.tools[0].cache_control, undefined);
assert.equal(preserved.messages[0].content[0].cache_control.type, "ephemeral");
assert.equal(preserved.system.at(-1).cache_control.type, "ephemeral");
assert.equal(preserved.tools[0].cache_control.type, "ephemeral");
});
test("buildClaudeCodeCompatibleRequest omits tool choice when there are no tools", () => {
const payload = buildClaudeCodeCompatibleRequest({
normalizedBody: {
messages: [{ role: "user", content: "hello" }],
tool_choice: "required",
reasoning_effort: "high",
},
model: "claude-sonnet-4-6",
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
});
assert.equal(payload.tools.length, 0);
assert.equal("tool_choice" in payload, false);
assert.equal(payload.output_config.effort, "high");
});
test("buildClaudeCodeCompatibleRequest covers string system input, non-array Claude fields and tool choice variants", () => {
const anyChoice = buildClaudeCodeCompatibleRequest({
normalizedBody: {
messages: [{ role: "user", content: "hello" }],
tools: [
{
name: "direct_tool",
input_schema: { type: "object", properties: { q: { type: "string" } } },
},
{
type: "function",
function: {
name: "missing_description",
parameters: { type: "object", properties: { x: { type: "string" } } },
},
},
{ type: "function", function: { parameters: { type: "object" } } },
],
tool_choice: { type: "any" },
},
model: "claude-sonnet-4-6",
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
});
const stringSystem = buildClaudeCodeCompatibleRequest({
claudeBody: {
system: " custom system ",
messages: "not-an-array",
tools: "not-an-array",
thinking: "disabled",
},
model: "claude-sonnet-4-6",
cwd: "/tmp/claude-code-compatible",
now: new Date("2026-01-02T12:00:00.000Z"),
});
assert.deepEqual(anyChoice.tool_choice, { type: "any" });
assert.equal(anyChoice.tools.length, 2);
assert.equal(anyChoice.tools[0].input_schema.properties.q.type, "string");
assert.equal(anyChoice.tools[1].description, "");
assert.equal(stringSystem.messages.length, 0);
assert.equal(stringSystem.tools.length, 0);
assert.equal(stringSystem.system.at(-1).text, "custom system");
});

View File

@@ -0,0 +1,97 @@
import test from "node:test";
import assert from "node:assert/strict";
const { resolveComboConfig, getDefaultComboConfig } =
await import("../../open-sse/services/comboConfig.ts");
test("getDefaultComboConfig returns a fresh copy of the defaults", () => {
const first = getDefaultComboConfig();
const second = getDefaultComboConfig();
assert.notEqual(first, second);
assert.equal(first.strategy, "priority");
assert.equal(first.maxRetries, 1);
assert.equal(first.timeoutMs, 600000);
first.strategy = "weighted";
assert.equal(second.strategy, "priority");
});
test("resolveComboConfig applies the full cascade from defaults to combo overrides", () => {
const result = resolveComboConfig(
{
config: {
maxRetries: 4,
timeoutMs: 45000,
},
},
{
comboDefaults: {
strategy: "round-robin",
timeoutMs: 120000,
},
providerOverrides: {
openai: {
timeoutMs: 60000,
retryDelayMs: 500,
},
},
},
"openai"
);
assert.equal(result.strategy, "round-robin");
assert.equal(result.retryDelayMs, 500);
assert.equal(result.timeoutMs, 45000);
assert.equal(result.maxRetries, 4);
assert.equal(result.healthCheckEnabled, true);
});
test("resolveComboConfig ignores null and undefined overrides", () => {
const result = resolveComboConfig(
{
config: {
timeoutMs: null,
trackMetrics: false,
},
},
{
comboDefaults: {
timeoutMs: undefined,
queueTimeoutMs: 15000,
},
providerOverrides: {
openai: {
strategy: null,
concurrencyPerModel: 9,
},
},
},
"openai"
);
assert.equal(result.timeoutMs, 600000);
assert.equal(result.queueTimeoutMs, 15000);
assert.equal(result.concurrencyPerModel, 9);
assert.equal(result.trackMetrics, false);
assert.equal(result.strategy, "priority");
});
test("resolveComboConfig skips provider overrides when provider is absent", () => {
const result = resolveComboConfig(
{ config: {} },
{
comboDefaults: { strategy: "random" },
providerOverrides: {
openai: { strategy: "weighted" },
},
}
);
assert.equal(result.strategy, "random");
});
test("resolveComboConfig tolerates invalid or missing inputs and falls back to defaults", () => {
assert.deepEqual(resolveComboConfig(null, null, "openai"), getDefaultComboConfig());
assert.deepEqual(resolveComboConfig({}, { comboDefaults: null }, null), getDefaultComboConfig());
});

View File

@@ -0,0 +1,632 @@
import test from "node:test";
import assert from "node:assert/strict";
const {
getComboFromData,
getComboModelsFromData,
validateComboDAG,
resolveNestedComboModels,
handleComboChat,
} = await import("../../open-sse/services/combo.ts");
const { getComboMetrics, recordComboRequest, resetAllComboMetrics } =
await import("../../open-sse/services/comboMetrics.ts");
const { resetAllCircuitBreakers } = await import("../../src/shared/utils/circuitBreaker.ts");
const { acquire: acquireSemaphore, resetAll: resetAllSemaphores } =
await import("../../open-sse/services/rateLimitSemaphore.ts");
function createLog() {
const entries = [];
return {
info: (tag, msg) => entries.push({ level: "info", tag, msg }),
warn: (tag, msg) => entries.push({ level: "warn", tag, msg }),
error: (tag, msg) => entries.push({ level: "error", tag, msg }),
entries,
};
}
function okResponse(body = { choices: [{ message: { content: "ok" } }] }) {
return new Response(JSON.stringify(body), {
status: 200,
headers: { "content-type": "application/json" },
});
}
function errorResponse(status, message = `Error ${status}`) {
return new Response(JSON.stringify({ error: { message } }), {
status,
headers: { "content-type": "application/json" },
});
}
test.beforeEach(() => {
resetAllComboMetrics();
resetAllCircuitBreakers();
resetAllSemaphores();
});
test("getComboFromData and getComboModelsFromData resolve combos from array and object containers", () => {
const combos = [
{ name: "alpha", models: ["openai/gpt-4o-mini", { model: "claude/sonnet", weight: 2 }] },
];
const fromArray = getComboFromData("alpha", combos);
const fromObject = getComboFromData("alpha", { combos });
const models = getComboModelsFromData("alpha", { combos });
assert.equal(fromArray.name, "alpha");
assert.equal(fromObject.name, "alpha");
assert.deepEqual(models, ["openai/gpt-4o-mini", "claude/sonnet"]);
});
test("validateComboDAG rejects circular references and resolveNestedComboModels expands nested combos", () => {
const combos = [
{ name: "root", models: ["child-a", "openai/gpt-4o-mini"] },
{ name: "child-a", models: ["child-b", "claude/sonnet"] },
{ name: "child-b", models: ["groq/llama-3.3-70b"] },
];
validateComboDAG("root", combos);
assert.deepEqual(resolveNestedComboModels(combos[0], combos), [
"groq/llama-3.3-70b",
"claude/sonnet",
"openai/gpt-4o-mini",
]);
assert.throws(
() =>
validateComboDAG("loop-a", [
{ name: "loop-a", models: ["loop-b"] },
{ name: "loop-b", models: ["loop-a"] },
]),
/Circular combo reference detected/
);
});
test("validateComboDAG enforces maximum nesting depth", () => {
const combos = [
{ name: "c1", models: ["c2"] },
{ name: "c2", models: ["c3"] },
{ name: "c3", models: ["c4"] },
{ name: "c4", models: ["c5"] },
{ name: "c5", models: ["openai/gpt-4o-mini"] },
];
assert.throws(() => validateComboDAG("c1", combos), /Max combo nesting depth/);
});
test("handleComboChat priority strategy defaults to first model and records success metrics", async () => {
const calls = [];
const combo = {
name: "priority-default",
models: ["openai/gpt-4o-mini", "claude/sonnet"],
};
const result = await handleComboChat({
body: {},
combo,
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
const metrics = getComboMetrics("priority-default");
assert.equal(result.ok, true);
assert.deepEqual(calls, ["openai/gpt-4o-mini"]);
assert.equal(metrics.totalRequests, 1);
assert.equal(metrics.totalSuccesses, 1);
assert.equal(metrics.byModel["openai/gpt-4o-mini"].requests, 1);
assert.equal(metrics.strategy, "priority");
});
test("handleComboChat weighted strategy selects by weight and falls back in descending weight order", async () => {
const originalRandom = Math.random;
const calls = [];
Math.random = () => 0.95;
try {
const result = await handleComboChat({
body: {},
combo: {
name: "weighted-selection",
strategy: "weighted",
models: [
{ model: "openai/gpt-4o-mini", weight: 1 },
{ model: "claude/sonnet", weight: 9 },
],
config: { maxRetries: 0 },
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
if (modelStr === "claude/sonnet") return errorResponse(500, "temporary");
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(result.ok, true);
assert.deepEqual(calls, ["claude/sonnet", "openai/gpt-4o-mini"]);
} finally {
Math.random = originalRandom;
}
});
test("handleComboChat random strategy uses shuffled model order", async () => {
const originalRandom = Math.random;
const calls = [];
const sequence = [0.99, 0.0];
let idx = 0;
Math.random = () => sequence[idx++] ?? 0;
try {
await handleComboChat({
body: {},
combo: {
name: "random-order",
strategy: "random",
models: ["model-a", "model-b", "model-c"],
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(calls.length, 1);
assert.notEqual(calls[0], "model-a");
} finally {
Math.random = originalRandom;
}
});
test("handleComboChat least-used strategy prefers the model with fewer recorded requests", async () => {
recordComboRequest("least-used-combo", "model-a", {
success: true,
latencyMs: 100,
strategy: "least-used",
});
recordComboRequest("least-used-combo", "model-a", {
success: true,
latencyMs: 100,
strategy: "least-used",
});
recordComboRequest("least-used-combo", "model-b", {
success: true,
latencyMs: 100,
strategy: "least-used",
});
const calls = [];
await handleComboChat({
body: {},
combo: {
name: "least-used-combo",
strategy: "least-used",
models: ["model-a", "model-b", "model-c"],
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(calls[0], "model-c");
});
test("handleComboChat skips unavailable models and falls through to the next active target", async () => {
const calls = [];
const result = await handleComboChat({
body: {},
combo: {
name: "availability-skip",
strategy: "priority",
models: ["model-a", "model-b"],
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
return okResponse();
},
isModelAvailable: async (modelStr) => modelStr !== "model-a",
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(result.ok, true);
assert.deepEqual(calls, ["model-b"]);
});
test("handleComboChat falls through empty successful responses and records failure metrics before succeeding", async () => {
const calls = [];
const result = await handleComboChat({
body: {},
combo: {
name: "quality-fallback",
strategy: "priority",
models: ["model-a", "model-b"],
config: { maxRetries: 0 },
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
if (modelStr === "model-a") {
return okResponse({ choices: [{ message: { content: "" } }] });
}
return okResponse({ choices: [{ message: { content: "fallback ok" } }] });
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
const metrics = getComboMetrics("quality-fallback");
assert.equal(result.ok, true);
assert.deepEqual(calls, ["model-a", "model-b"]);
assert.equal(metrics.totalRequests, 2);
assert.equal(metrics.totalFailures, 1);
assert.equal(metrics.totalSuccesses, 1);
assert.equal(metrics.byModel["model-a"].lastStatus, "error");
assert.equal(metrics.byModel["model-b"].lastStatus, "ok");
});
test("handleComboChat preserves the first failure status but surfaces the last error message", async () => {
const result = await handleComboChat({
body: {},
combo: {
name: "all-fail",
strategy: "priority",
models: ["model-a", "model-b"],
config: { maxRetries: 0 },
},
handleSingleModel: async (_body, modelStr) => {
return errorResponse(modelStr === "model-a" ? 500 : 429, `fail:${modelStr}`);
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
const payload = await result.json();
assert.equal(result.status, 500);
assert.equal(payload.error.message, "fail:model-b");
});
test("handleComboChat round-robin rotates sequentially across requests", async () => {
const calls = [];
const combo = {
name: "rr-sequence",
strategy: "round-robin",
models: ["model-a", "model-b"],
config: { maxRetries: 0, concurrencyPerModel: 1, queueTimeoutMs: 1000 },
};
for (let i = 0; i < 3; i++) {
const result = await handleComboChat({
body: {},
combo,
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(result.ok, true);
}
assert.deepEqual(calls, ["model-a", "model-b", "model-a"]);
});
test("combo helpers short-circuit safely for missing combos, cycles, and excessive depth", () => {
assert.equal(getComboFromData("missing", null), null);
assert.equal(getComboModelsFromData("missing", { combos: [] }), null);
assert.doesNotThrow(() =>
validateComboDAG("ghost", {
combos: [{ name: "alpha", models: ["openai/gpt-4o-mini"] }],
})
);
assert.doesNotThrow(() => validateComboDAG("empty", [{ name: "empty" }]));
assert.deepEqual(
resolveNestedComboModels(
{ name: "loop", models: ["model-a", "model-b"] },
[],
new Set(["loop"])
),
[]
);
assert.deepEqual(
resolveNestedComboModels(
{ name: "deep", models: ["model-a", { model: "model-b", weight: 2 }] },
[],
new Set(),
99
),
["model-a", "model-b"]
);
});
test("handleComboChat accepts binary and Responses-style 200 bodies but falls through malformed success payloads", async () => {
const binaryResult = await handleComboChat({
body: {},
combo: {
name: "quality-binary",
strategy: "priority",
models: ["model-a"],
config: { maxRetries: 0 },
},
handleSingleModel: async () =>
new Response("binary-payload", {
status: 200,
headers: { "content-type": "application/octet-stream" },
}),
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(binaryResult.ok, true);
assert.equal(await binaryResult.text(), "binary-payload");
const responsesResult = await handleComboChat({
body: {},
combo: {
name: "quality-responses",
strategy: "priority",
models: ["model-a"],
config: { maxRetries: 0 },
},
handleSingleModel: async () =>
okResponse({
output: [{ type: "output_text", text: "done" }],
}),
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(responsesResult.ok, true);
const calls = [];
const malformedResult = await handleComboChat({
body: {},
combo: {
name: "quality-malformed",
strategy: "priority",
models: ["model-a", "model-b", "model-c"],
config: { maxRetries: 0 },
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
if (modelStr === "model-a") {
return new Response("", {
status: 200,
headers: { "content-type": "application/json" },
});
}
if (modelStr === "model-b") {
return okResponse({ choices: [{}] });
}
return okResponse({ choices: [{ message: { content: "recovered" } }] });
},
isModelAvailable: async () => true,
log: createLog(),
settings: null,
allCombos: null,
});
assert.equal(malformedResult.ok, true);
assert.deepEqual(calls, ["model-a", "model-b", "model-c"]);
});
test("handleComboChat returns the earliest retry-after when all priority targets are rate-limited", async () => {
const soon = new Date(Date.now() + 1_000).toISOString();
const later = new Date(Date.now() + 5_000).toISOString();
const result = await handleComboChat({
body: {},
combo: {
name: "priority-retry-after",
strategy: "priority",
models: ["model-a", "model-b"],
},
handleSingleModel: async (_body, modelStr) =>
new Response(
JSON.stringify({
error: { message: `limited:${modelStr}` },
retryAfter: modelStr === "model-a" ? later : soon,
}),
{
status: 429,
headers: { "content-type": "application/json" },
}
),
isModelAvailable: async () => true,
log: createLog(),
settings: {
comboDefaults: { maxRetries: 0, retryDelayMs: 1 },
},
allCombos: null,
});
const payload = await result.json();
assert.equal(result.status, 429);
assert.match(payload.error.message, /limited:model-b/);
assert.ok(Number(result.headers.get("Retry-After")) >= 1);
});
test("handleComboChat round-robin returns 503 when no models are configured", async () => {
const result = await handleComboChat({
body: {},
combo: {
name: "rr-empty",
strategy: "round-robin",
models: [],
},
handleSingleModel: async () => {
throw new Error("handleSingleModel should not run for empty round-robin combos");
},
isModelAvailable: async () => true,
log: createLog(),
settings: {
comboDefaults: {
concurrencyPerModel: 1,
queueTimeoutMs: 5,
maxRetries: 0,
retryDelayMs: 1,
},
},
allCombos: null,
});
assert.equal(result.status, 503);
assert.match((await result.json()).error.message, /Round-robin combo has no models/);
});
test("handleComboChat round-robin falls through semaphore timeouts and malformed success payloads", async () => {
const release = await acquireSemaphore("model-a", { maxConcurrency: 1, timeoutMs: 100 });
const calls = [];
try {
const result = await handleComboChat({
body: {},
combo: {
name: "rr-timeout-fallback",
strategy: "round-robin",
models: ["model-a", "model-b", "model-c"],
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
if (modelStr === "model-b") {
return okResponse({ choices: [{}] });
}
return okResponse({ choices: [{ message: { content: "rr ok" } }] });
},
isModelAvailable: async () => true,
log: createLog(),
settings: {
comboDefaults: {
concurrencyPerModel: 1,
queueTimeoutMs: 5,
maxRetries: 0,
retryDelayMs: 1,
},
},
allCombos: null,
});
assert.equal(result.ok, true);
assert.deepEqual(calls, ["model-b", "model-c"]);
} finally {
release();
}
});
test("handleComboChat round-robin surfaces retry-after metadata after exhausting all models", async () => {
const sooner = new Date(Date.now() + 1_500).toISOString();
const later = new Date(Date.now() + 7_000).toISOString();
const result = await handleComboChat({
body: {},
combo: {
name: "rr-retry-after",
strategy: "round-robin",
models: ["model-a", "model-b"],
},
handleSingleModel: async (_body, modelStr) =>
new Response(
JSON.stringify({
error: { message: `rr-limited:${modelStr}` },
retryAfter: modelStr === "model-a" ? later : sooner,
}),
{
status: 429,
headers: { "content-type": "application/json" },
}
),
isModelAvailable: async () => true,
log: createLog(),
settings: {
comboDefaults: {
concurrencyPerModel: 1,
queueTimeoutMs: 5,
maxRetries: 0,
retryDelayMs: 1,
},
},
allCombos: null,
});
const payload = await result.json();
assert.equal(result.status, 429);
assert.match(payload.error.message, /rr-limited:model-b/);
assert.ok(Number(result.headers.get("Retry-After")) >= 1);
});
test("handleComboChat round-robin keeps generic 400 errors terminal", async () => {
const calls = [];
const result = await handleComboChat({
body: {},
combo: {
name: "rr-terminal-400",
strategy: "round-robin",
models: ["model-a", "model-b"],
},
handleSingleModel: async (_body, modelStr) => {
calls.push(modelStr);
if (modelStr === "model-a") {
return new Response(JSON.stringify({ error: { message: "generic bad request" } }), {
status: 400,
headers: { "content-type": "application/json" },
});
}
return okResponse();
},
isModelAvailable: async () => true,
log: createLog(),
settings: {
comboDefaults: {
concurrencyPerModel: 1,
queueTimeoutMs: 5,
maxRetries: 0,
retryDelayMs: 1,
},
},
allCombos: null,
});
assert.equal(result.status, 400);
assert.deepEqual(calls, ["model-a"]);
assert.match((await result.json()).error.message, /generic bad request/);
});

View File

@@ -0,0 +1,222 @@
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-compliance-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.APP_LOG_RETENTION_DAYS = "10";
process.env.CALL_LOG_RETENTION_DAYS = "5";
const core = await import("../../src/lib/db/core.ts");
const compliance = await import("../../src/lib/compliance/index.ts");
function resetDb() {
core.resetDbInstance();
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(() => {
resetDb();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("compliance audit log initialization, writes and filtered reads work end to end", () => {
compliance.initAuditLog();
compliance.logAuditEvent({
action: "settings.update",
actor: "admin",
target: "system-settings",
details: { changed: ["theme"] },
ipAddress: "127.0.0.1",
});
compliance.logAuditEvent({
action: "apiKey.create",
details: '"manual note"',
});
const all = compliance.getAuditLog();
const filtered = compliance.getAuditLog({
action: "settings.update",
actor: "admin",
limit: 1,
offset: 0,
});
assert.equal(all.length, 2);
assert.equal(all[0].action, "apiKey.create");
assert.equal(all[0].actor, "system");
assert.equal(all[0].details, "manual note");
assert.deepEqual(filtered, [
{
...filtered[0],
action: "settings.update",
actor: "admin",
target: "system-settings",
details: { changed: ["theme"] },
ip_address: "127.0.0.1",
},
]);
});
test("compliance noLog helpers cover missing ids, in-memory overrides and persisted DB values", () => {
const db = core.getDbInstance();
const now = new Date().toISOString();
db.prepare(
"INSERT INTO api_keys (id, name, key, machine_id, allowed_models, no_log, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
).run("persisted-no-log", "Persisted", "sk-persisted", null, "[]", 1, now);
assert.equal(compliance.isNoLog(""), false);
assert.equal(compliance.isNoLog("persisted-no-log"), true);
compliance.setNoLog("manual-no-log", true);
assert.equal(compliance.isNoLog("manual-no-log"), true);
compliance.setNoLog("manual-no-log", false);
assert.equal(compliance.isNoLog("manual-no-log"), false);
assert.deepEqual(compliance.getRetentionDays(), { app: 10, call: 5 });
});
test("cleanupExpiredLogs removes stale rows across all log tables and records an audit entry", () => {
compliance.initAuditLog();
const db = core.getDbInstance();
const oldCallTs = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString();
const oldAppTs = new Date(Date.now() - 12 * 24 * 60 * 60 * 1000).toISOString();
const freshTs = new Date().toISOString();
db.prepare("INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)").run(
"openai",
"gpt-4o",
oldCallTs
);
db.prepare("INSERT INTO usage_history (provider, model, timestamp) VALUES (?, ?, ?)").run(
"openai",
"gpt-4o",
freshTs
);
db.prepare("INSERT INTO call_logs (id, timestamp, method, path) VALUES (?, ?, ?, ?)").run(
"call-old",
oldCallTs,
"POST",
"/v1/chat/completions"
);
db.prepare("INSERT INTO call_logs (id, timestamp, method, path) VALUES (?, ?, ?, ?)").run(
"call-new",
freshTs,
"POST",
"/v1/chat/completions"
);
db.prepare("INSERT INTO proxy_logs (id, timestamp, status, proxy_type) VALUES (?, ?, ?, ?)").run(
"proxy-old",
oldCallTs,
"ok",
"http"
);
db.prepare("INSERT INTO proxy_logs (id, timestamp, status, proxy_type) VALUES (?, ?, ?, ?)").run(
"proxy-new",
freshTs,
"ok",
"http"
);
db.prepare("INSERT INTO request_detail_logs (id, call_log_id, timestamp) VALUES (?, ?, ?)").run(
"rdl-old",
"call-old",
oldCallTs
);
db.prepare("INSERT INTO request_detail_logs (id, call_log_id, timestamp) VALUES (?, ?, ?)").run(
"rdl-new",
"call-new",
freshTs
);
db.prepare("INSERT INTO mcp_tool_audit (tool_name, created_at) VALUES (?, ?)").run(
"memory_search",
oldAppTs
);
db.prepare("INSERT INTO mcp_tool_audit (tool_name, created_at) VALUES (?, ?)").run(
"memory_add",
freshTs
);
compliance.logAuditEvent({
action: "admin.cleanup.seed",
actor: "admin",
details: { seeded: true },
});
db.prepare("UPDATE audit_log SET timestamp = ? WHERE action = ?").run(
oldAppTs,
"admin.cleanup.seed"
);
const result = compliance.cleanupExpiredLogs();
const usageCount = db.prepare("SELECT COUNT(*) as count FROM usage_history").get().count;
const callCount = db.prepare("SELECT COUNT(*) as count FROM call_logs").get().count;
const proxyCount = db.prepare("SELECT COUNT(*) as count FROM proxy_logs").get().count;
const requestDetailCount = db
.prepare("SELECT COUNT(*) as count FROM request_detail_logs")
.get().count;
const mcpAuditCount = db.prepare("SELECT COUNT(*) as count FROM mcp_tool_audit").get().count;
const auditActions = compliance.getAuditLog().map((entry) => entry.action);
assert.deepEqual(result, {
deletedUsage: 1,
deletedCallLogs: 1,
deletedProxyLogs: 1,
deletedRequestDetailLogs: 1,
deletedAuditLogs: 1,
deletedMcpAuditLogs: 1,
appRetentionDays: 10,
callRetentionDays: 5,
});
assert.equal(usageCount, 1);
assert.equal(callCount, 1);
assert.equal(proxyCount, 1);
assert.equal(requestDetailCount, 1);
assert.equal(mcpAuditCount, 1);
assert.ok(auditActions.includes("compliance.cleanup"));
});
test("cleanupExpiredLogs tolerates missing tables and logAuditEvent failures without breaking", () => {
compliance.initAuditLog();
const db = core.getDbInstance();
db.exec(`
DROP TABLE usage_history;
DROP TABLE call_logs;
DROP TABLE proxy_logs;
DROP TABLE request_detail_logs;
DROP TABLE audit_log;
DROP TABLE mcp_tool_audit;
`);
compliance.logAuditEvent({
action: "will.fail.silently",
details: { reason: "table dropped" },
});
const result = compliance.cleanupExpiredLogs();
assert.deepEqual(result, {
deletedUsage: 0,
deletedCallLogs: 0,
deletedProxyLogs: 0,
deletedRequestDetailLogs: 0,
deletedAuditLogs: 0,
deletedMcpAuditLogs: 0,
appRetentionDays: 10,
callRetentionDays: 5,
});
});

View File

@@ -23,7 +23,7 @@ test("getTokenLimit: detects claude", () => {
});
test("getTokenLimit: detects gemini", () => {
assert.equal(getTokenLimit("gemini", "gemini-2.5-pro"), 1048576);
assert.equal(getTokenLimit("gemini", "gemini-2.5-pro"), 1000000);
});
test("getTokenLimit: default fallback", () => {

View File

@@ -0,0 +1,150 @@
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-db-apikeys-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "task-303-api-key-secret";
const core = await import("../../src/lib/db/core.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
async function resetStorage() {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("createApiKey requires machineId and returns a persisted key with defaults", async () => {
await assert.rejects(
() => apiKeysDb.createApiKey("missing-machine", ""),
/machineId is required/
);
const created = await apiKeysDb.createApiKey("Primary Key", "machine-303");
const allKeys = await apiKeysDb.getApiKeys();
const byId = await apiKeysDb.getApiKeyById(created.id);
assert.match(created.key, /^sk-machine-303-/);
assert.equal(allKeys.length, 1);
assert.equal(allKeys[0].name, "Primary Key");
assert.deepEqual(allKeys[0].allowedModels, []);
assert.deepEqual(byId.allowedConnections, []);
assert.equal(byId.noLog, false);
assert.equal(byId.autoResolve, false);
assert.equal(byId.isActive, true);
assert.equal(byId.maxSessions, 0);
});
test("updateApiKeyPermissions persists settings, schedule and rate limits", async () => {
const created = await apiKeysDb.createApiKey("Scoped Key", "machine-303");
const schedule = {
enabled: true,
from: "09:00",
until: "18:00",
days: [1, 2, 3, 4, 5],
tz: "America/Sao_Paulo",
};
const updated = await apiKeysDb.updateApiKeyPermissions(created.id, {
name: "Scoped Key v2",
allowedModels: ["openai/*", "anthropic/claude-*"],
allowedConnections: ["550e8400-e29b-41d4-a716-446655440000"],
noLog: true,
autoResolve: true,
isActive: false,
accessSchedule: schedule,
maxRequestsPerDay: 1000,
maxRequestsPerMinute: 15,
maxSessions: -3,
});
const row = await apiKeysDb.getApiKeyById(created.id);
const metadata = await apiKeysDb.getApiKeyMetadata(created.key);
assert.equal(updated, true);
assert.equal(row.name, "Scoped Key v2");
assert.deepEqual(row.allowedModels, ["openai/*", "anthropic/claude-*"]);
assert.deepEqual(row.allowedConnections, ["550e8400-e29b-41d4-a716-446655440000"]);
assert.equal(row.noLog, true);
assert.equal(row.autoResolve, true);
assert.equal(row.isActive, false);
assert.deepEqual(row.accessSchedule, schedule);
assert.equal(metadata.maxRequestsPerDay, 1000);
assert.equal(metadata.maxRequestsPerMinute, 15);
assert.equal(metadata.maxSessions, 0);
});
test("validateApiKey and deleteApiKey stay consistent after cache invalidation", async () => {
const created = await apiKeysDb.createApiKey("Delete Me", "machine-303");
assert.equal(await apiKeysDb.validateApiKey(created.key), true);
assert.equal(await apiKeysDb.deleteApiKey("missing-id"), false);
assert.equal(await apiKeysDb.deleteApiKey(created.id), true);
assert.equal(await apiKeysDb.validateApiKey(created.key), false);
assert.equal(await apiKeysDb.getApiKeyById(created.id), null);
assert.equal(await apiKeysDb.getApiKeyMetadata(created.key), null);
});
test("isModelAllowedForKey supports exact, prefix and wildcard rules", async () => {
const unrestricted = await apiKeysDb.createApiKey("Unrestricted", "machine-303");
const restricted = await apiKeysDb.createApiKey("Restricted", "machine-303");
await apiKeysDb.updateApiKeyPermissions(restricted.id, {
allowedModels: ["openai/*", "anthropic/claude-*", "o*-mini"],
});
assert.equal(await apiKeysDb.isModelAllowedForKey(null, "any/model"), true);
assert.equal(await apiKeysDb.isModelAllowedForKey(restricted.key, null), false);
assert.equal(await apiKeysDb.isModelAllowedForKey("sk-invalid", "openai/gpt-4.1"), false);
assert.equal(await apiKeysDb.isModelAllowedForKey(unrestricted.key, "provider/any-model"), true);
assert.equal(await apiKeysDb.isModelAllowedForKey(restricted.key, "openai/gpt-4.1"), true);
assert.equal(
await apiKeysDb.isModelAllowedForKey(restricted.key, "anthropic/claude-3-7-sonnet"),
true
);
assert.equal(await apiKeysDb.isModelAllowedForKey(restricted.key, "o3-mini"), true);
assert.equal(
await apiKeysDb.isModelAllowedForKey(restricted.key, "gemini/gemini-2.5-pro"),
false
);
});
test("getApiKeyMetadata ignores malformed stored schedule payloads", async () => {
const created = await apiKeysDb.createApiKey("Malformed Schedule", "machine-303");
const db = core.getDbInstance();
db.prepare("UPDATE api_keys SET access_schedule = ? WHERE id = ?").run("not-json", created.id);
apiKeysDb.clearApiKeyCaches();
const metadata = await apiKeysDb.getApiKeyMetadata(created.key);
assert.equal(metadata.accessSchedule, null);
});

View File

@@ -0,0 +1,103 @@
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-db-combos-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const combosDb = await import("../../src/lib/db/combos.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("createCombo stores default strategy and supports lookup by id and name", async () => {
const combo = await combosDb.createCombo({
name: "Priority Combo",
models: [{ provider: "openai", model: "gpt-4.1" }],
});
assert.equal(combo.strategy, "priority");
assert.deepEqual(await combosDb.getComboById(combo.id), combo);
assert.deepEqual(await combosDb.getComboByName("Priority Combo"), combo);
});
test("getCombos returns parsed combos sorted by name", async () => {
await combosDb.createCombo({
name: "Zulu",
models: [{ provider: "openai", model: "gpt-4.1" }],
});
await combosDb.createCombo({
name: "Alpha",
models: [{ provider: "anthropic", model: "claude-3-7-sonnet" }],
});
const combos = await combosDb.getCombos();
assert.deepEqual(
combos.map((combo) => combo.name),
["Alpha", "Zulu"]
);
});
test("updateCombo merges fields while preserving immutable data", async () => {
const combo = await combosDb.createCombo({
name: "Routing Combo",
models: [{ provider: "openai", model: "gpt-4.1" }],
config: { retries: 1 },
});
const updated = await combosDb.updateCombo(combo.id, {
strategy: "round-robin",
config: { retries: 3, timeoutMs: 2000 },
isHidden: true,
});
assert.equal(updated.id, combo.id);
assert.equal(updated.name, "Routing Combo");
assert.deepEqual(updated.models, combo.models);
assert.deepEqual(updated.config, { retries: 3, timeoutMs: 2000 });
assert.equal(updated.strategy, "round-robin");
assert.equal(updated.isHidden, true);
assert.deepEqual(await combosDb.getComboById(combo.id), updated);
});
test("deleteCombo reports missing ids and removes existing rows", async () => {
const combo = await combosDb.createCombo({
name: "Delete Me",
models: [{ provider: "openai", model: "gpt-4.1-mini" }],
});
assert.equal(await combosDb.deleteCombo("missing-combo"), false);
assert.equal(await combosDb.deleteCombo(combo.id), true);
assert.equal(await combosDb.getComboById(combo.id), null);
});

View File

@@ -0,0 +1,401 @@
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";
import { pathToFileURL } from "node:url";
import Database from "better-sqlite3";
const serial = { concurrency: false };
const originalEnv = {
DATA_DIR: process.env.DATA_DIR,
NEXT_PHASE: process.env.NEXT_PHASE,
HOME: process.env.HOME,
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,
APPDATA: process.env.APPDATA,
};
function restoreEnv() {
for (const [key, value] of Object.entries(originalEnv)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
function cleanupGlobalDb() {
try {
if (globalThis.__omnirouteDb?.open) {
globalThis.__omnirouteDb.close();
}
} catch {}
delete globalThis.__omnirouteDb;
}
function makeTempDir(prefix) {
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
}
function removePath(targetPath) {
fs.rmSync(targetPath, { recursive: true, force: true });
}
async function importFresh(modulePath) {
const url = pathToFileURL(path.resolve(modulePath)).href;
return import(`${url}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`);
}
async function withEnv(overrides, fn) {
const snapshot = {};
for (const key of Object.keys(overrides)) {
snapshot[key] = process.env[key];
const value = overrides[key];
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
try {
return await fn();
} finally {
for (const [key, value] of Object.entries(snapshot)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
}
function createLegacySchemaDb(sqliteFile, { withData = false } = {}) {
const seedDb = new Database(sqliteFile);
seedDb.exec(`
CREATE TABLE schema_migrations (version TEXT);
CREATE TABLE provider_connections (
id TEXT PRIMARY KEY,
provider TEXT NOT NULL,
auth_type TEXT,
name TEXT,
email TEXT,
priority INTEGER DEFAULT 0,
is_active INTEGER DEFAULT 1,
access_token TEXT,
refresh_token TEXT,
expires_at TEXT,
token_expires_at TEXT,
scope TEXT,
project_id TEXT,
test_status TEXT,
error_code TEXT,
last_error TEXT,
last_error_at TEXT,
last_error_type TEXT,
last_error_source TEXT,
backoff_level INTEGER DEFAULT 0,
rate_limited_until TEXT,
health_check_interval INTEGER,
last_health_check_at TEXT,
last_tested TEXT,
api_key TEXT,
id_token TEXT,
provider_specific_data TEXT,
expires_in INTEGER,
display_name TEXT,
global_priority INTEGER,
default_model TEXT,
token_type TEXT,
consecutive_use_count INTEGER DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX idx_pc_provider ON provider_connections(provider);
CREATE INDEX idx_pc_active ON provider_connections(is_active);
CREATE INDEX idx_pc_priority ON provider_connections(provider, priority);
`);
if (withData) {
const now = new Date().toISOString();
seedDb
.prepare(
"INSERT INTO provider_connections (id, provider, auth_type, name, is_active, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
)
.run("legacy-openai", "openai", "apikey", "Legacy", 1, now, now);
}
seedDb.close();
}
test.beforeEach(() => {
restoreEnv();
cleanupGlobalDb();
});
test.afterEach(() => {
cleanupGlobalDb();
restoreEnv();
});
test.after(() => {
cleanupGlobalDb();
restoreEnv();
});
test("getDbInstance creates sqlite schema, metadata and applies migrations", serial, async () => {
const dataDir = makeTempDir("omniroute-db-core-");
try {
await withEnv({ DATA_DIR: dataDir, NEXT_PHASE: undefined }, async () => {
const core = await importFresh("src/lib/db/core.ts");
const db = core.getDbInstance();
assert.equal(fs.existsSync(core.SQLITE_FILE), true);
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("provider_connections")
);
assert.deepEqual(db.prepare("SELECT value FROM db_meta WHERE key = 'schema_version'").get(), {
value: "1",
});
const versions = db
.prepare("SELECT version FROM _omniroute_migrations ORDER BY version")
.all()
.map((row) => row.version);
assert.equal(versions[0], "001");
assert.ok(versions.includes("017"));
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("version_manager")
);
core.resetDbInstance();
});
} finally {
removePath(dataDir);
}
});
test("getDbInstance reuses the singleton and closeDbInstance resets it", serial, async () => {
const dataDir = makeTempDir("omniroute-db-core-");
try {
await withEnv({ DATA_DIR: dataDir, NEXT_PHASE: undefined }, async () => {
const core = await importFresh("src/lib/db/core.ts");
const firstDb = core.getDbInstance();
const secondDb = core.getDbInstance();
assert.strictEqual(secondDb, firstDb);
assert.equal(core.closeDbInstance(), true);
assert.equal(firstDb.open, false);
assert.equal(core.closeDbInstance(), false);
const reopenedDb = core.getDbInstance();
assert.notStrictEqual(reopenedDb, firstDb);
core.resetDbInstance();
});
} finally {
removePath(dataDir);
}
});
test("local sqlite configuration enables WAL and sane pragmas", serial, async () => {
const dataDir = makeTempDir("omniroute-db-core-");
try {
await withEnv({ DATA_DIR: dataDir, NEXT_PHASE: undefined }, async () => {
const core = await importFresh("src/lib/db/core.ts");
const db = core.getDbInstance();
assert.equal(db.pragma("journal_mode", { simple: true }), "wal");
assert.equal(db.pragma("busy_timeout", { simple: true }), 5000);
assert.equal(db.pragma("synchronous", { simple: true }), 1);
assert.equal(core.closeDbInstance({ checkpointMode: null }), true);
});
} finally {
removePath(dataDir);
}
});
test("module exports honor DATA_DIR from the environment", serial, async () => {
const dataDir = makeTempDir("omniroute-db-core-env-");
try {
await withEnv({ DATA_DIR: dataDir }, async () => {
const core = await importFresh("src/lib/db/core.ts");
assert.equal(core.DATA_DIR, path.resolve(dataDir));
assert.equal(core.SQLITE_FILE, path.join(path.resolve(dataDir), "storage.sqlite"));
assert.equal(core.DB_BACKUPS_DIR, path.join(path.resolve(dataDir), "db_backups"));
});
} finally {
removePath(dataDir);
}
});
test(
"module falls back to the default home data directory when DATA_DIR is absent",
serial,
async () => {
const fakeHome = makeTempDir("omniroute-home-");
try {
await withEnv(
{
DATA_DIR: undefined,
XDG_CONFIG_HOME: undefined,
HOME: fakeHome,
APPDATA: undefined,
},
async () => {
const core = await importFresh("src/lib/db/core.ts");
const expectedDir =
process.platform === "win32"
? path.join(fakeHome, "AppData", "Roaming", "omniroute")
: path.join(fakeHome, ".omniroute");
assert.equal(core.DATA_DIR, expectedDir);
assert.equal(core.SQLITE_FILE, path.join(expectedDir, "storage.sqlite"));
}
);
} finally {
removePath(fakeHome);
}
}
);
test("build phase uses an in-memory database without creating sqlite files", serial, async () => {
const dataDir = makeTempDir("omniroute-db-build-");
try {
await withEnv(
{
DATA_DIR: dataDir,
NEXT_PHASE: "phase-production-build",
},
async () => {
const core = await importFresh("src/lib/db/core.ts");
const db = core.getDbInstance();
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("provider_connections")
);
assert.equal(fs.existsSync(path.join(dataDir, "storage.sqlite")), false);
assert.equal(db.pragma("journal_mode", { simple: true }), "memory");
core.resetDbInstance();
}
);
} finally {
removePath(dataDir);
}
});
test("getDbInstance surfaces invalid DATA_DIR paths as sqlite open failures", serial, async () => {
const sandboxDir = makeTempDir("omniroute-db-bad-path-");
const fileAsDir = path.join(sandboxDir, "not-a-directory");
fs.writeFileSync(fileAsDir, "blocked");
try {
await withEnv({ DATA_DIR: fileAsDir }, async () => {
const core = await importFresh("src/lib/db/core.ts");
assert.throws(
() => core.getDbInstance(),
/unable to open database file|ENOTDIR|not a directory/i
);
assert.equal(core.closeDbInstance(), false);
});
} finally {
removePath(sandboxDir);
}
});
test(
"legacy empty schema databases are renamed before a fresh sqlite database is created",
serial,
async () => {
const dataDir = makeTempDir("omniroute-db-legacy-empty-");
const sqliteFile = path.join(dataDir, "storage.sqlite");
createLegacySchemaDb(sqliteFile);
try {
await withEnv({ DATA_DIR: dataDir }, async () => {
const core = await importFresh("src/lib/db/core.ts");
const db = core.getDbInstance();
assert.equal(fs.existsSync(`${sqliteFile}.old-schema`), true);
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("_omniroute_migrations")
);
assert.equal(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("schema_migrations"),
undefined
);
core.resetDbInstance();
});
} finally {
removePath(dataDir);
}
}
);
test(
"legacy databases with data preserve rows while removing the old migration table",
serial,
async () => {
const dataDir = makeTempDir("omniroute-db-legacy-data-");
const sqliteFile = path.join(dataDir, "storage.sqlite");
createLegacySchemaDb(sqliteFile, { withData: true });
try {
await withEnv({ DATA_DIR: dataDir }, async () => {
const core = await importFresh("src/lib/db/core.ts");
const db = core.getDbInstance();
assert.deepEqual(
db
.prepare("SELECT id, provider FROM provider_connections WHERE id = ?")
.get("legacy-openai"),
{ id: "legacy-openai", provider: "openai" }
);
assert.equal(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("schema_migrations"),
undefined
);
assert.ok(
db
.prepare("SELECT name FROM pragma_table_info('provider_connections') WHERE name = ?")
.get("rate_limit_protection")
);
assert.ok(
db
.prepare("SELECT name FROM pragma_table_info('provider_connections') WHERE name = ?")
.get("last_used_at")
);
core.resetDbInstance();
});
} finally {
removePath(dataDir);
}
}
);

View File

@@ -0,0 +1,193 @@
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-db-detailed-logs-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const ORIGINAL_PII_ENABLED = process.env.PII_RESPONSE_SANITIZATION;
const ORIGINAL_PII_MODE = process.env.PII_RESPONSE_SANITIZATION_MODE;
process.env.PII_RESPONSE_SANITIZATION = "true";
process.env.PII_RESPONSE_SANITIZATION_MODE = "redact";
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "task-303-detailed-secret";
const core = await import("../../src/lib/db/core.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
const detailedLogsDb = await import("../../src/lib/db/detailedLogs.ts");
const { createStructuredSSECollector } =
await import("../../open-sse/utils/streamPayloadCollector.ts");
async function resetStorage() {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_PII_ENABLED === undefined) {
delete process.env.PII_RESPONSE_SANITIZATION;
} else {
process.env.PII_RESPONSE_SANITIZATION = ORIGINAL_PII_ENABLED;
}
if (ORIGINAL_PII_MODE === undefined) {
delete process.env.PII_RESPONSE_SANITIZATION_MODE;
} else {
process.env.PII_RESPONSE_SANITIZATION_MODE = ORIGINAL_PII_MODE;
}
});
test("isDetailedLoggingEnabled follows the stored setting", async () => {
assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), false);
await settingsDb.updateSettings({ call_log_pipeline_enabled: "true" });
assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), true);
});
test("saveRequestDetailLog persists protected payloads and compacted stream summaries", () => {
const collector = createStructuredSSECollector({ stage: "provider-response" });
collector.push({
type: "response.output_text.delta",
delta: "Hello",
});
const providerStream = collector.build({
id: "resp_123",
object: "response",
output_text: "Hello world",
});
detailedLogsDb.saveRequestDetailLog({
id: "detail-1",
call_log_id: "call-1",
timestamp: "2026-04-05T18:00:00.000Z",
client_request: { email: "john@example.com", token: "super-secret" },
translated_request: '{"message":"hello"}',
provider_response: providerStream,
client_response: "plain text response",
provider: "openai",
model: "gpt-4.1",
source_format: "openai",
target_format: "gemini",
duration_ms: 321,
});
const row = detailedLogsDb.getRequestDetailLogById("detail-1");
assert.equal(row.call_log_id, "call-1");
assert.deepEqual(row.client_request, {
email: "[EMAIL_REDACTED]",
token: "[REDACTED]",
});
assert.deepEqual(row.translated_request, { message: "hello" });
assert.equal(row.provider_response.id, "resp_123");
assert.equal(row.provider_response.output_text, "Hello world");
assert.deepEqual(row.provider_response._omniroute_stream, {
format: "sse-json",
stage: "provider-response",
eventCount: 1,
});
assert.deepEqual(row.client_response, { _rawText: "plain text response" });
assert.equal(row.duration_ms, 321);
});
test("latest log lookup by call_log_id and paginated listing use newest-first ordering", () => {
detailedLogsDb.saveRequestDetailLog({
id: "older",
call_log_id: "call-2",
timestamp: "2026-04-05T18:00:00.000Z",
provider: "openai",
model: "gpt-4.1",
});
detailedLogsDb.saveRequestDetailLog({
id: "newer",
call_log_id: "call-2",
timestamp: "2026-04-05T18:00:02.000Z",
provider: "anthropic",
model: "claude-3-7-sonnet",
});
detailedLogsDb.saveRequestDetailLog({
id: "latest",
call_log_id: "call-3",
timestamp: "2026-04-05T18:00:03.000Z",
provider: "gemini",
model: "gemini-2.5-pro",
});
const firstPage = detailedLogsDb.getRequestDetailLogs(2, 0);
const secondPage = detailedLogsDb.getRequestDetailLogs(1, 1);
assert.equal(detailedLogsDb.getRequestDetailLogByCallLogId("call-2").id, "newer");
assert.deepEqual(
firstPage.map((row) => row.id),
["latest", "newer"]
);
assert.deepEqual(
secondPage.map((row) => row.id),
["newer"]
);
assert.equal(detailedLogsDb.getRequestDetailLogCount(), 3);
});
test("logs are skipped when the associated API key is marked as no_log", async () => {
const apiKey = await apiKeysDb.createApiKey("No Log Key", "machine-303");
await apiKeysDb.updateApiKeyPermissions(apiKey.id, { noLog: true });
detailedLogsDb.saveRequestDetailLog({
id: "should-not-persist",
api_key_id: apiKey.id,
provider: "openai",
model: "gpt-4.1",
no_log: false,
});
assert.equal(detailedLogsDb.getRequestDetailLogCount(), 0);
assert.equal(detailedLogsDb.getRequestDetailLogById("should-not-persist"), null);
});
test("request_detail_logs trigger keeps only the latest 500 rows", () => {
for (let i = 0; i < 505; i += 1) {
detailedLogsDb.saveRequestDetailLog({
id: `ring-${i}`,
timestamp: new Date(Date.UTC(2026, 3, 5, 18, 0, 0, i)).toISOString(),
provider: "openai",
model: "gpt-4.1",
});
}
const rows = detailedLogsDb.getRequestDetailLogs(600, 0);
assert.equal(detailedLogsDb.getRequestDetailLogCount(), 500);
assert.equal(detailedLogsDb.getRequestDetailLogById("ring-0"), null);
assert.equal(detailedLogsDb.getRequestDetailLogById("ring-4"), null);
assert.equal(detailedLogsDb.getRequestDetailLogById("ring-5")?.id, "ring-5");
assert.equal(rows[0].id, "ring-504");
assert.equal(rows.at(-1)?.id, "ring-5");
});

View File

@@ -0,0 +1,79 @@
import test from "node:test";
import assert from "node:assert/strict";
import path from "node:path";
import { pathToFileURL } from "node:url";
const ORIGINAL_STORAGE_KEY = process.env.STORAGE_ENCRYPTION_KEY;
async function importFresh(modulePath) {
const url = pathToFileURL(path.resolve(modulePath)).href;
return import(`${url}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`);
}
test.after(() => {
if (ORIGINAL_STORAGE_KEY === undefined) {
delete process.env.STORAGE_ENCRYPTION_KEY;
} else {
process.env.STORAGE_ENCRYPTION_KEY = ORIGINAL_STORAGE_KEY;
}
});
test("encryption stays in passthrough mode when no storage key is configured", async () => {
delete process.env.STORAGE_ENCRYPTION_KEY;
const encryption = await importFresh("src/lib/db/encryption.ts");
assert.equal(encryption.isEncryptionEnabled(), false);
assert.equal(encryption.encrypt("plain-text"), "plain-text");
assert.equal(encryption.decrypt("plain-text"), "plain-text");
assert.equal(encryption.encrypt(""), "");
assert.equal(encryption.decrypt(null), null);
assert.equal(encryption.decrypt(undefined), undefined);
});
test("encrypt/decrypt round-trip uses the expected serialized format", async () => {
process.env.STORAGE_ENCRYPTION_KEY = "task-304-secret-a";
const encryption = await importFresh("src/lib/db/encryption.ts");
const encrypted = encryption.encrypt("hello world");
const decrypted = encryption.decrypt(encrypted);
assert.equal(encryption.isEncryptionEnabled(), true);
assert.match(encrypted, /^enc:v1:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$/);
assert.equal(decrypted, "hello world");
assert.equal(encryption.encrypt(encrypted), encrypted);
});
test("connection field helpers encrypt and decrypt all supported credential fields", async () => {
process.env.STORAGE_ENCRYPTION_KEY = "task-304-secret-b";
const encryption = await importFresh("src/lib/db/encryption.ts");
const connection = {
apiKey: "sk-123",
accessToken: "access-123",
refreshToken: "refresh-123",
idToken: "id-123",
untouched: "keep-me",
};
const encrypted = encryption.encryptConnectionFields({ ...connection });
const decrypted = encryption.decryptConnectionFields(encrypted);
assert.notEqual(encrypted.apiKey, connection.apiKey);
assert.match(encrypted.apiKey, /^enc:v1:/);
assert.match(encrypted.accessToken, /^enc:v1:/);
assert.match(encrypted.refreshToken, /^enc:v1:/);
assert.match(encrypted.idToken, /^enc:v1:/);
assert.deepEqual(decrypted, connection);
});
test("decrypt returns the original ciphertext when the value is malformed or the key is wrong", async () => {
process.env.STORAGE_ENCRYPTION_KEY = "task-304-secret-c";
const firstModule = await importFresh("src/lib/db/encryption.ts");
const encrypted = firstModule.encrypt("top-secret");
process.env.STORAGE_ENCRYPTION_KEY = "task-304-secret-d";
const secondModule = await importFresh("src/lib/db/encryption.ts");
assert.equal(secondModule.decrypt(encrypted), encrypted);
assert.equal(secondModule.decrypt("enc:v1:not-valid"), "enc:v1:not-valid");
});

View File

@@ -0,0 +1,348 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import Database from "better-sqlite3";
const serial = { concurrency: false };
async function importFresh(modulePath) {
const url = pathToFileURL(path.resolve(modulePath)).href;
return import(`${url}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`);
}
function withMockedMigrationFs(files, fn) {
const originalExistsSync = fs.existsSync;
const originalReaddirSync = fs.readdirSync;
const originalReadFileSync = fs.readFileSync;
const isMigrationDir = (target) =>
String(target).replaceAll("\\", "/").endsWith("/src/lib/db/migrations") ||
String(target).replaceAll("\\", "/").endsWith("/migrations");
fs.existsSync = (target) => {
if (files === null && isMigrationDir(target)) return false;
if (files && isMigrationDir(target)) return true;
const fileName = path.basename(String(target));
if (files && Object.hasOwn(files, fileName)) return true;
return originalExistsSync(target);
};
fs.readdirSync = (target, options) => {
if (files && isMigrationDir(target)) {
return Object.keys(files);
}
return originalReaddirSync(target, options);
};
fs.readFileSync = (target, options) => {
const fileName = path.basename(String(target));
if (files && Object.hasOwn(files, fileName)) {
return files[fileName];
}
return originalReadFileSync(target, options);
};
try {
return fn();
} finally {
fs.existsSync = originalExistsSync;
fs.readdirSync = originalReaddirSync;
fs.readFileSync = originalReadFileSync;
}
}
function createDb() {
return new Database(":memory:");
}
test("runMigrations applies pending files sequentially in version order", serial, async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
const appliedCount = withMockedMigrationFs(
{
"010_last.sql": "CREATE TABLE migration_last (id INTEGER);",
"002_middle.sql": "CREATE TABLE migration_middle (id INTEGER);",
"001_first.sql": "CREATE TABLE migration_first (id INTEGER);",
},
() => runner.runMigrations(db)
);
assert.equal(appliedCount, 3);
assert.deepEqual(
db.prepare("SELECT version FROM _omniroute_migrations ORDER BY version").all(),
[{ version: "001" }, { version: "002" }, { version: "010" }]
);
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("migration_first")
);
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("migration_last")
);
} finally {
db.close();
}
});
test("runMigrations skips versions that are already tracked as applied", serial, async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE skip_first (id INTEGER);",
"002_second.sql": "CREATE TABLE skip_second (id INTEGER);",
},
() => runner.runMigrations(db)
);
const secondRun = withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE skip_first (id INTEGER);",
"002_second.sql": "CREATE TABLE skip_second (id INTEGER);",
},
() => runner.runMigrations(db)
);
assert.equal(secondRun, 0);
assert.equal(
db.prepare("SELECT COUNT(*) AS count FROM _omniroute_migrations WHERE version = ?").get("001")
.count,
1
);
assert.equal(
db.prepare("SELECT COUNT(*) AS count FROM _omniroute_migrations WHERE version = ?").get("002")
.count,
1
);
} finally {
db.close();
}
});
test("getMigrationStatus reports applied and pending migrations", serial, async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
db.exec(`
CREATE TABLE _omniroute_migrations (
version TEXT PRIMARY KEY,
name TEXT NOT NULL,
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
db.prepare("INSERT INTO _omniroute_migrations (version, name) VALUES (?, ?)").run(
"001",
"first"
);
const status = withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE status_first (id INTEGER);",
"002_second.sql": "CREATE TABLE status_second (id INTEGER);",
"003_third.sql": "CREATE TABLE status_third (id INTEGER);",
},
() => runner.getMigrationStatus(db)
);
assert.deepEqual(
status.applied.map((row) => row.version),
["001"]
);
assert.deepEqual(
status.pending.map((row) => row.version),
["002", "003"]
);
} finally {
db.close();
}
});
test(
"failed migrations roll back their transaction and do not record the version",
serial,
async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
assert.throws(
() =>
withMockedMigrationFs(
{
"001_ok.sql": "CREATE TABLE rollback_ok (id INTEGER);",
"002_broken.sql":
"CREATE TABLE rollback_broken (id INTEGER); INSERT INTO missing_table VALUES (1);",
},
() => runner.runMigrations(db)
),
/missing_table/i
);
assert.ok(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("rollback_ok")
);
assert.equal(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("rollback_broken"),
undefined
);
assert.equal(
db
.prepare("SELECT COUNT(*) AS count FROM _omniroute_migrations WHERE version = ?")
.get("002").count,
0
);
} finally {
db.close();
}
}
);
test("missing or empty migration directories are treated as a no-op", serial, async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const missingDb = createDb();
const emptyDb = createDb();
try {
assert.equal(
withMockedMigrationFs(null, () => runner.runMigrations(missingDb)),
0
);
assert.equal(
withMockedMigrationFs({}, () => runner.runMigrations(emptyDb)),
0
);
assert.deepEqual(
withMockedMigrationFs({}, () => runner.getMigrationStatus(emptyDb)),
{
applied: [],
pending: [],
}
);
} finally {
missingDb.close();
emptyDb.close();
}
});
test("invalid file names are ignored while valid migrations still run", serial, async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
const count = withMockedMigrationFs(
{
"README.md": "# ignored",
"not-a-migration.sql": "CREATE TABLE should_not_exist (id INTEGER);",
"003_valid.sql": "CREATE TABLE valid_migration (id INTEGER);",
},
() => runner.runMigrations(db)
);
assert.equal(count, 1);
assert.deepEqual(
db.prepare("SELECT version, name FROM _omniroute_migrations ORDER BY version").all(),
[{ version: "003", name: "valid" }]
);
assert.equal(
db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?")
.get("should_not_exist"),
undefined
);
} finally {
db.close();
}
});
test(
"new migrations are detected on subsequent runs without replaying old ones",
serial,
async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE rerun_first (id INTEGER);",
"002_second.sql": "CREATE TABLE rerun_second (id INTEGER);",
},
() => runner.runMigrations(db)
);
const count = withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE rerun_first (id INTEGER);",
"002_second.sql": "CREATE TABLE rerun_second (id INTEGER);",
"003_third.sql": "CREATE TABLE rerun_third (id INTEGER);",
},
() => runner.runMigrations(db)
);
assert.equal(count, 1);
assert.deepEqual(
db.prepare("SELECT version FROM _omniroute_migrations ORDER BY version").all(),
[{ version: "001" }, { version: "002" }, { version: "003" }]
);
} finally {
db.close();
}
}
);
test(
"unknown rows in the migration table do not block pending real migrations",
serial,
async () => {
const runner = await importFresh("src/lib/db/migrationRunner.ts");
const db = createDb();
try {
db.exec(`
CREATE TABLE _omniroute_migrations (
version TEXT PRIMARY KEY,
name TEXT NOT NULL,
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
db.prepare("INSERT INTO _omniroute_migrations (version, name) VALUES (?, ?)").run(
"999",
"ghost"
);
const count = withMockedMigrationFs(
{
"001_first.sql": "CREATE TABLE recover_first (id INTEGER);",
"002_second.sql": "CREATE TABLE recover_second (id INTEGER);",
},
() => runner.runMigrations(db)
);
assert.equal(count, 2);
assert.deepEqual(
db.prepare("SELECT version FROM _omniroute_migrations ORDER BY version").all(),
[{ version: "001" }, { version: "002" }, { version: "999" }]
);
} finally {
db.close();
}
}
);

View File

@@ -0,0 +1,217 @@
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-db-models-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const modelsDb = await import("../../src/lib/db/models.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("model aliases can be created, listed and deleted", async () => {
await modelsDb.setModelAlias("fast-default", { provider: "openai", model: "gpt-4.1-mini" });
await modelsDb.setModelAlias("reasoning", { provider: "anthropic", model: "claude-3-7-sonnet" });
const aliases = await modelsDb.getModelAliases();
assert.deepEqual(aliases["fast-default"], {
provider: "openai",
model: "gpt-4.1-mini",
});
assert.deepEqual(aliases.reasoning, {
provider: "anthropic",
model: "claude-3-7-sonnet",
});
await modelsDb.deleteModelAlias("fast-default");
assert.equal((await modelsDb.getModelAliases())["fast-default"], undefined);
});
test("MITM aliases support per-tool lookup and aggregated reads", async () => {
await modelsDb.setMitmAliasAll("cursor", {
"gpt-4.1": "cursor/gpt-4.1",
});
await modelsDb.setMitmAliasAll("codex", {
"gpt-4.1-mini": "codex/gpt-4.1-mini",
});
assert.deepEqual(await modelsDb.getMitmAlias("cursor"), {
"gpt-4.1": "cursor/gpt-4.1",
});
assert.deepEqual(await modelsDb.getMitmAlias(), {
cursor: { "gpt-4.1": "cursor/gpt-4.1" },
codex: { "gpt-4.1-mini": "codex/gpt-4.1-mini" },
});
});
test("custom models can be added once and queried by provider", async () => {
const created = await modelsDb.addCustomModel(
"openrouter",
"anthropic/claude-3.7-sonnet",
"Claude 3.7 Sonnet",
"manual",
"responses",
["chat", "responses"]
);
const duplicate = await modelsDb.addCustomModel(
"openrouter",
"anthropic/claude-3.7-sonnet",
"Claude 3.7 Sonnet"
);
const providerModels = await modelsDb.getCustomModels("openrouter");
const allModels = await modelsDb.getAllCustomModels();
assert.equal(duplicate.id, created.id);
assert.equal(providerModels.length, 1);
assert.deepEqual(providerModels[0], created);
assert.equal(allModels.openrouter.length, 1);
});
test("replaceCustomModels preserves compat fields and respects the empty-list guard", async () => {
await modelsDb.addCustomModel("openai", "gpt-4.1", "GPT-4.1");
await modelsDb.updateCustomModel("openai", "gpt-4.1", {
normalizeToolCallId: true,
preserveOpenAIDeveloperRole: false,
upstreamHeaders: {
"X-Test": " enabled ",
Host: "should-be-removed",
},
});
const replaced = await modelsDb.replaceCustomModels("openai", [
{
id: "gpt-4.1",
name: "GPT-4.1 Refreshed",
source: "api-sync",
supportsThinking: true,
},
]);
const guarded = await modelsDb.replaceCustomModels("openai", []);
assert.equal(replaced[0].normalizeToolCallId, true);
assert.equal(replaced[0].preserveOpenAIDeveloperRole, false);
assert.deepEqual(replaced[0].upstreamHeaders, { "X-Test": "enabled" });
assert.equal(replaced[0].supportsThinking, true);
assert.equal(guarded.length, 1);
await modelsDb.replaceCustomModels("openai", [], { allowEmpty: true });
assert.deepEqual(await modelsDb.getCustomModels("openai"), []);
});
test("removing a custom model also removes its compat override", async () => {
await modelsDb.addCustomModel("anthropic", "claude-3-haiku", "Claude 3 Haiku");
modelsDb.mergeModelCompatOverride("anthropic", "claude-3-haiku", {
normalizeToolCallId: true,
isHidden: true,
});
assert.equal(await modelsDb.removeCustomModel("anthropic", "claude-3-haiku"), true);
assert.equal(await modelsDb.removeCustomModel("anthropic", "claude-3-haiku"), false);
assert.deepEqual(await modelsDb.getCustomModels("anthropic"), []);
assert.deepEqual(modelsDb.getModelCompatOverrides("anthropic"), []);
});
test("synced available models are unioned across connections and cleaned per connection", async () => {
await modelsDb.replaceSyncedAvailableModelsForConnection("openai", "conn-a", [
{ id: "gpt-4.1", name: "GPT-4.1", source: "api-sync" },
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", source: "api-sync" },
]);
const union = await modelsDb.replaceSyncedAvailableModelsForConnection("openai", "conn-b", [
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", source: "api-sync" },
{ id: "o3-mini", name: "o3-mini", source: "api-sync" },
]);
const remaining = await modelsDb.deleteSyncedAvailableModelsForConnection("openai", "conn-a");
const allProviders = await modelsDb.getAllSyncedAvailableModels();
assert.deepEqual(union.map((model) => model.id).sort(), ["gpt-4.1", "gpt-4.1-mini", "o3-mini"]);
assert.deepEqual(remaining.map((model) => model.id).sort(), ["gpt-4.1-mini", "o3-mini"]);
assert.deepEqual(allProviders.openai.map((model) => model.id).sort(), [
"gpt-4.1-mini",
"o3-mini",
]);
});
test("compat overrides expose per-protocol getters and removable extra headers", async () => {
modelsDb.mergeModelCompatOverride("openai", "gpt-4.1", {
normalizeToolCallId: true,
preserveOpenAIDeveloperRole: false,
isHidden: true,
upstreamHeaders: {
"X-Top": "1",
"bad header": "skip",
},
compatByProtocol: {
openai: {
normalizeToolCallId: false,
preserveOpenAIDeveloperRole: true,
upstreamHeaders: {
"X-Proto": "yes",
},
},
},
});
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1"), true);
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1", "openai"), false);
assert.equal(modelsDb.getModelPreserveOpenAIDeveloperRole("openai", "gpt-4.1"), false);
assert.equal(modelsDb.getModelPreserveOpenAIDeveloperRole("openai", "gpt-4.1", "openai"), true);
assert.equal(modelsDb.getModelIsHidden("openai", "gpt-4.1"), true);
assert.deepEqual(modelsDb.getModelUpstreamExtraHeaders("openai", "gpt-4.1", "openai"), {
"X-Top": "1",
"X-Proto": "yes",
});
modelsDb.removeModelCompatOverride("openai", "gpt-4.1");
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1"), false);
assert.deepEqual(modelsDb.getModelCompatOverrides("openai"), []);
});
test("sanitizeUpstreamHeadersMap keeps only safe trimmed headers", () => {
const sanitized = modelsDb.sanitizeUpstreamHeadersMap({
"X-First": " one ",
Host: "blocked",
"Bad Header": "blocked",
"X-Newline": "bad\nvalue",
"X-Second": 42,
});
assert.deepEqual(sanitized, {
"X-First": "one",
"X-Second": "42",
});
});

View File

@@ -0,0 +1,293 @@
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-db-providers-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("createProviderConnection assigns provider-scoped priorities and supports filtered reads", async () => {
const first = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Primary",
apiKey: "sk-primary",
group: "team-b",
});
const second = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Secondary",
apiKey: "sk-secondary",
isActive: false,
group: "team-a",
});
const openAiConnections = await providersDb.getProviderConnections({ provider: "openai" });
const activeConnections = await providersDb.getProviderConnections({
provider: "openai",
isActive: true,
});
assert.deepEqual(
openAiConnections.map((connection) => ({
name: connection.name,
priority: connection.priority,
})),
[
{ name: "Primary", priority: 1 },
{ name: "Secondary", priority: 2 },
]
);
assert.deepEqual(
activeConnections.map((connection) => connection.id),
[first.id]
);
assert.deepEqual(await providersDb.getDistinctGroups(), ["team-a", "team-b"]);
assert.equal(second.isActive, false);
});
test("oauth connections upsert by provider and email instead of duplicating rows", async () => {
const original = await providersDb.createProviderConnection({
provider: "claude",
authType: "oauth",
email: "dev@example.com",
accessToken: "token-a",
refreshToken: "refresh-a",
testStatus: "ok",
});
const updated = await providersDb.createProviderConnection({
provider: "claude",
authType: "oauth",
email: "dev@example.com",
accessToken: "token-b",
refreshToken: "refresh-b",
lastError: "expired",
testStatus: "retrying",
});
const rows = await providersDb.getProviderConnections({ provider: "claude" });
assert.equal(updated.id, original.id);
assert.equal(rows.length, 1);
assert.equal(rows[0].accessToken, "token-b");
assert.equal(rows[0].lastError, "expired");
assert.equal(rows[0].testStatus, "retrying");
});
test("codex workspace uniqueness uses workspaceId alongside email", async () => {
const workspaceA = await providersDb.createProviderConnection({
provider: "codex",
authType: "oauth",
email: "workspace@example.com",
providerSpecificData: { workspaceId: "ws-a" },
});
const workspaceAUpdate = await providersDb.createProviderConnection({
provider: "codex",
authType: "oauth",
email: "workspace@example.com",
providerSpecificData: { workspaceId: "ws-a" },
accessToken: "updated-token",
});
const workspaceB = await providersDb.createProviderConnection({
provider: "codex",
authType: "oauth",
email: "workspace@example.com",
providerSpecificData: { workspaceId: "ws-b" },
});
const rows = await providersDb.getProviderConnections({ provider: "codex" });
assert.equal(workspaceAUpdate.id, workspaceA.id);
assert.notEqual(workspaceB.id, workspaceA.id);
assert.equal(rows.length, 2);
assert.deepEqual(rows.map((row) => row.providerSpecificData.workspaceId).sort(), [
"ws-a",
"ws-b",
]);
});
test("updateProviderConnection reorders priorities and returns decrypted payloads", async () => {
const first = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "First",
apiKey: "first-key",
});
const second = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Second",
apiKey: "second-key",
});
const third = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Third",
apiKey: "third-key",
});
const updated = await providersDb.updateProviderConnection(third.id, {
priority: 0,
providerSpecificData: { region: "us-east-1" },
rateLimitProtection: true,
});
const ordered = await providersDb.getProviderConnections({ provider: "openai" });
assert.equal(updated.providerSpecificData.region, "us-east-1");
assert.equal(updated.rateLimitProtection, true);
assert.deepEqual(
ordered.map((connection) => ({
id: connection.id,
priority: connection.priority,
})),
[
{ id: third.id, priority: 1 },
{ id: first.id, priority: 2 },
{ id: second.id, priority: 3 },
]
);
});
test("deleteProviderConnection reorders remaining rows and bulk delete reports changes", async () => {
const first = await providersDb.createProviderConnection({
provider: "anthropic",
authType: "apikey",
name: "One",
apiKey: "one",
});
const second = await providersDb.createProviderConnection({
provider: "anthropic",
authType: "apikey",
name: "Two",
apiKey: "two",
});
const third = await providersDb.createProviderConnection({
provider: "anthropic",
authType: "apikey",
name: "Three",
apiKey: "three",
});
assert.equal(await providersDb.deleteProviderConnection(second.id), true);
const reordered = await providersDb.getProviderConnections({ provider: "anthropic" });
const deletedCount = await providersDb.deleteProviderConnectionsByProvider("anthropic");
assert.deepEqual(
reordered.map((connection) => ({
id: connection.id,
priority: connection.priority,
})),
[
{ id: first.id, priority: 1 },
{ id: third.id, priority: 2 },
]
);
assert.equal(deletedCount, 2);
assert.deepEqual(await providersDb.getProviderConnections({ provider: "anthropic" }), []);
});
test("provider node CRUD supports filter, update and delete", async () => {
const customNode = await providersDb.createProviderNode({
type: "custom",
name: "Custom Gateway",
prefix: "custom-",
baseUrl: "https://custom.example.com",
});
const openAiNode = await providersDb.createProviderNode({
type: "openai",
name: "OpenAI Native",
baseUrl: "https://api.openai.com",
});
const filtered = await providersDb.getProviderNodes({ type: "custom" });
const updated = await providersDb.updateProviderNode(customNode.id, {
name: "Custom Gateway v2",
chatPath: "/v1/chat/completions",
modelsPath: "/v1/models",
});
const deleted = await providersDb.deleteProviderNode(openAiNode.id);
assert.deepEqual(
filtered.map((node) => node.id),
[customNode.id]
);
assert.equal(updated.name, "Custom Gateway v2");
assert.equal(updated.chatPath, "/v1/chat/completions");
assert.deepEqual(await providersDb.getProviderNodeById(customNode.id), updated);
assert.equal(deleted.id, openAiNode.id);
assert.equal(await providersDb.getProviderNodeById(openAiNode.id), null);
});
test("rate-limit helpers persist cooldown state in the database", async () => {
const connection = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Rate Limited",
apiKey: "rate-key",
});
const future = Date.now() + 90_000;
providersDb.setConnectionRateLimitUntil(connection.id, future);
assert.equal(providersDb.isConnectionRateLimited(connection.id), true);
assert.deepEqual(
providersDb
.getRateLimitedConnections("openai")
.map((entry) => ({ ...entry, rateLimitedUntil: Number(entry.rateLimitedUntil) })),
[{ id: connection.id, rateLimitedUntil: future }]
);
providersDb.setConnectionRateLimitUntil(connection.id, null);
assert.equal(providersDb.isConnectionRateLimited(connection.id), false);
assert.deepEqual(providersDb.getRateLimitedConnections("openai"), []);
});
test("quota helpers zero stale windows and format countdowns", () => {
const past = Date.now() - 1_000;
const future = Date.now() + 65_000;
assert.equal(providersDb.getEffectiveQuotaUsage(120, past), 0);
assert.equal(providersDb.getEffectiveQuotaUsage(120, "not-a-date"), 120);
assert.equal(providersDb.getEffectiveQuotaUsage(120, null), 120);
assert.match(providersDb.formatResetCountdown(future), /1m \d+s/);
assert.equal(providersDb.formatResetCountdown(past), null);
});

View File

@@ -0,0 +1,207 @@
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-db-proxies-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const proxiesDb = await import("../../src/lib/db/proxies.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("proxy CRUD redacts secrets by default and preserves stored credentials on blank update", async () => {
const created = await proxiesDb.createProxy({
name: "Primary Proxy",
type: "http",
host: "proxy.local",
port: 8080,
username: "user-a",
password: "pass-a",
region: "sa-east-1",
});
assert.equal(created.username, "***");
assert.equal(created.password, "***");
const withSecrets = await proxiesDb.getProxyById(created.id, { includeSecrets: true });
const updated = await proxiesDb.updateProxy(created.id, {
host: "proxy-updated.local",
username: "",
password: "",
notes: "updated",
});
const updatedWithSecrets = await proxiesDb.getProxyById(created.id, { includeSecrets: true });
const listed = await proxiesDb.listProxies();
assert.equal(withSecrets.username, "user-a");
assert.equal(withSecrets.password, "pass-a");
assert.equal(updated.host, "proxy-updated.local");
assert.equal(updated.notes, "updated");
assert.equal(updatedWithSecrets.username, "user-a");
assert.equal(updatedWithSecrets.password, "pass-a");
assert.equal(listed.length, 1);
assert.equal(listed[0].username, "***");
assert.equal(listed[0].password, "***");
});
test("proxy assignments resolve by account, provider and global scope", async () => {
const connection = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Proxy Target",
apiKey: "sk-proxy",
});
const globalProxy = await proxiesDb.createProxy({
name: "Global",
type: "http",
host: "global.local",
port: 8080,
});
const providerProxy = await proxiesDb.createProxy({
name: "Provider",
type: "https",
host: "provider.local",
port: 443,
});
const accountProxy = await proxiesDb.createProxy({
name: "Account",
type: "socks5",
host: "account.local",
port: 1080,
});
await proxiesDb.assignProxyToScope("global", null, globalProxy.id);
await proxiesDb.assignProxyToScope("provider", "openai", providerProxy.id);
const providerResolved = await proxiesDb.resolveProxyForProvider("openai");
const beforeAccount = await proxiesDb.resolveProxyForConnectionFromRegistry(connection.id);
await proxiesDb.assignProxyToScope("key", connection.id, accountProxy.id);
const assignmentsForAccountProxy = await proxiesDb.getProxyAssignments({
proxyId: accountProxy.id,
});
const accountResolved = await proxiesDb.resolveProxyForConnectionFromRegistry(connection.id);
const usage = await proxiesDb.getProxyWhereUsed(accountProxy.id);
assert.equal(providerResolved.host, "provider.local");
assert.equal(beforeAccount.level, "provider");
assert.equal(assignmentsForAccountProxy.length, 1);
assert.equal(assignmentsForAccountProxy[0].scope, "account");
assert.equal(accountResolved.level, "account");
assert.equal(accountResolved.proxy.host, "account.local");
assert.equal(usage.count, 1);
});
test("bulk assignment deduplicates scope ids and reports failures for missing proxies", async () => {
const first = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Bulk One",
apiKey: "sk-bulk-1",
});
const second = await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Bulk Two",
apiKey: "sk-bulk-2",
});
const proxy = await proxiesDb.createProxy({
name: "Bulk Proxy",
type: "http",
host: "bulk.local",
port: 8080,
});
const success = await proxiesDb.bulkAssignProxyToScope(
"account",
[first.id, second.id, first.id, " "],
proxy.id
);
const failure = await proxiesDb.bulkAssignProxyToScope(
"account",
[first.id, second.id],
"missing-proxy"
);
assert.equal(success.updated, 2);
assert.deepEqual(success.failed, []);
assert.equal(failure.updated, 0);
assert.equal(failure.failed.length, 2);
assert.match(failure.failed[0].reason, /Proxy not found/);
});
test("proxy health stats aggregate proxy_logs and force delete removes assignments", async () => {
const proxy = await proxiesDb.createProxy({
name: "Stats Proxy",
type: "http",
host: "stats.local",
port: 8080,
});
await proxiesDb.assignProxyToScope("global", null, proxy.id);
const db = core.getDbInstance();
const now = new Date().toISOString();
const insertLog = db.prepare(`
INSERT INTO proxy_logs (
id, timestamp, status, proxy_type, proxy_host, proxy_port, latency_ms
) VALUES (?, ?, ?, ?, ?, ?, ?)
`);
insertLog.run("proxy-log-1", now, "success", "http", "stats.local", 8080, 100);
insertLog.run("proxy-log-2", now, "error", "http", "stats.local", 8080, 250);
insertLog.run("proxy-log-3", now, "timeout", "http", "stats.local", 8080, 400);
const stats = await proxiesDb.getProxyHealthStats({ hours: 2 });
assert.deepEqual(stats[0], {
proxyId: proxy.id,
name: "Stats Proxy",
type: "http",
host: "stats.local",
port: 8080,
totalRequests: 3,
successCount: 1,
errorCount: 1,
timeoutCount: 1,
successRate: 33.33,
avgLatencyMs: 250,
lastSeenAt: now,
});
assert.equal(await proxiesDb.deleteProxyById(proxy.id, { force: true }), true);
assert.equal((await proxiesDb.getProxyAssignments()).length, 0);
assert.equal(await proxiesDb.getProxyById(proxy.id), null);
});

View File

@@ -0,0 +1,165 @@
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";
import { pathToFileURL } from "node:url";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-db-read-cache-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
async function importFresh(modulePath) {
const url = pathToFileURL(path.resolve(modulePath)).href;
return import(`${url}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`);
}
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("getCachedSettings returns cached data until TTL expires or cache is invalidated", async () => {
const readCache = await importFresh("src/lib/db/readCache.ts");
const db = core.getDbInstance();
await settingsDb.updateSettings({ label: "initial" });
assert.equal((await readCache.getCachedSettings()).label, "initial");
db.prepare("INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"settings",
"label",
JSON.stringify("stale-write")
);
assert.equal((await readCache.getCachedSettings()).label, "initial");
const originalNow = Date.now;
try {
Date.now = () => originalNow() + 6_000;
assert.equal((await readCache.getCachedSettings()).label, "stale-write");
} finally {
Date.now = originalNow;
}
db.prepare("INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"settings",
"label",
JSON.stringify("after-invalidate")
);
readCache.invalidateDbCache("settings");
assert.equal((await readCache.getCachedSettings()).label, "after-invalidate");
});
test("getCachedPricing caches results and refreshes after invalidation", async () => {
const readCache = await importFresh("src/lib/db/readCache.ts");
const db = core.getDbInstance();
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"pricing",
"cache-provider",
JSON.stringify({
"model-a": { prompt: 1 },
})
);
assert.equal((await readCache.getCachedPricing())["cache-provider"]["model-a"].prompt, 1);
db.prepare("UPDATE key_value SET value = ? WHERE namespace = ? AND key = ?").run(
JSON.stringify({
"model-a": { prompt: 9 },
}),
"pricing",
"cache-provider"
);
assert.equal((await readCache.getCachedPricing())["cache-provider"]["model-a"].prompt, 1);
readCache.invalidateDbCache("pricing");
assert.equal((await readCache.getCachedPricing())["cache-provider"]["model-a"].prompt, 9);
});
test("getCachedProviderConnections caches only the unfiltered query", async () => {
const readCache = await importFresh("src/lib/db/readCache.ts");
const db = core.getDbInstance();
const now = new Date().toISOString();
await providersDb.createProviderConnection({
provider: "openai",
authType: "apikey",
name: "Primary",
apiKey: "sk-primary",
});
const firstRead = await readCache.getCachedProviderConnections();
db.prepare(
`
INSERT INTO provider_connections (
id, provider, auth_type, name, is_active, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?)
`
).run("direct-insert", "openai", "apikey", "Secondary", 1, now, now);
const cachedAll = await readCache.getCachedProviderConnections();
const filtered = await readCache.getCachedProviderConnections({ provider: "openai" });
assert.equal(firstRead.length, 1);
assert.equal(cachedAll.length, 1);
assert.equal(filtered.length, 2);
readCache.invalidateDbCache("connections");
assert.equal((await readCache.getCachedProviderConnections()).length, 2);
});
test("cached LKGP values refresh only after the specific key is invalidated", async () => {
const readCache = await importFresh("src/lib/db/readCache.ts");
const db = core.getDbInstance();
const comboName = `combo-${Date.now()}`;
const modelId = `model-${Date.now()}`;
const lkgpKey = `${comboName}:${modelId}`;
await settingsDb.setLKGP(comboName, modelId, "openai");
assert.equal(await readCache.getCachedLKGP(comboName, modelId), "openai");
db.prepare("UPDATE key_value SET value = ? WHERE namespace = 'lkgp' AND key = ?").run(
JSON.stringify("anthropic"),
lkgpKey
);
assert.equal(await readCache.getCachedLKGP(comboName, modelId), "openai");
await readCache.setCachedLKGP(comboName, modelId, "gemini");
assert.equal(await readCache.getCachedLKGP(comboName, modelId), "gemini");
});

View File

@@ -0,0 +1,69 @@
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-db-secrets-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const secretsDb = await import("../../src/lib/db/secrets.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("getPersistedSecret returns null for missing keys", () => {
assert.equal(secretsDb.getPersistedSecret("missing"), null);
});
test("persistSecret stores and reads secrets from the key_value table", () => {
secretsDb.persistSecret("oauth_token", "secret-value");
assert.equal(secretsDb.getPersistedSecret("oauth_token"), "secret-value");
});
test("persistSecret does not overwrite an existing secret because storage is insert-only", () => {
secretsDb.persistSecret("api_token", "first-value");
secretsDb.persistSecret("api_token", "second-value");
assert.equal(secretsDb.getPersistedSecret("api_token"), "first-value");
});
test("malformed persisted rows are treated as missing secrets", () => {
const db = core.getDbInstance();
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"secrets",
"broken",
"not-json"
);
assert.equal(secretsDb.getPersistedSecret("broken"), null);
});

View File

@@ -0,0 +1,273 @@
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-db-settings-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD;
const core = await import("../../src/lib/db/core.ts");
const settingsDb = await import("../../src/lib/db/settings.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
delete process.env.INITIAL_PASSWORD;
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_INITIAL_PASSWORD === undefined) {
delete process.env.INITIAL_PASSWORD;
} else {
process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD;
}
});
test("getSettings exposes defaults and updateSettings persists typed values", async () => {
const defaults = await settingsDb.getSettings();
const updated = await settingsDb.updateSettings({
requireLogin: false,
cloudEnabled: true,
stickyRoundRobinLimit: 7,
label: "task-303",
});
assert.equal(defaults.cloudEnabled, false);
assert.equal(defaults.requireLogin, true);
assert.deepEqual(defaults.hiddenSidebarItems, []);
assert.equal(defaults.idempotencyWindowMs, 5000);
assert.equal(updated.requireLogin, false);
assert.equal(updated.cloudEnabled, true);
assert.equal(updated.stickyRoundRobinLimit, 7);
assert.equal(updated.label, "task-303");
assert.equal(await settingsDb.isCloudEnabled(), true);
});
test("INITIAL_PASSWORD marks onboarding as complete on first read", async () => {
process.env.INITIAL_PASSWORD = "bootstrap-secret";
const settings = await settingsDb.getSettings();
const stored = await settingsDb.getSettings();
assert.equal(settings.setupComplete, true);
assert.equal(settings.requireLogin, true);
assert.equal(stored.setupComplete, true);
});
test("pricing layers merge synced, models.dev and user overrides", async () => {
const db = core.getDbInstance();
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"pricing_synced",
"layered-provider",
JSON.stringify({
"model-a": { prompt: 1, completion: 2 },
})
);
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"models_dev_pricing",
"layered-provider",
JSON.stringify({
"model-a": { completion: 5, cached: 3 },
})
);
await settingsDb.updatePricing({
"layered-provider": {
"model-a": { prompt: 9, custom: 42 },
"model-b": { prompt: 7 },
},
});
const pricing = await settingsDb.getPricing();
const direct = await settingsDb.getPricingForModel("layered-provider", "model-a");
const cnFallback = await settingsDb.getPricingForModel("openai-cn", "gpt-4o");
assert.deepEqual(pricing["layered-provider"]["model-a"], {
prompt: 9,
completion: 5,
cached: 3,
custom: 42,
});
assert.deepEqual(direct, {
prompt: 9,
completion: 5,
cached: 3,
custom: 42,
});
assert.ok(cnFallback);
const afterModelReset = await settingsDb.resetPricing("layered-provider", "model-a");
assert.equal(afterModelReset["layered-provider"]["model-a"], undefined);
const afterProviderReset = await settingsDb.resetPricing("layered-provider");
assert.equal(afterProviderReset["layered-provider"], undefined);
await settingsDb.updatePricing({
temp: { model: { prompt: 1 } },
});
assert.deepEqual(await settingsDb.resetAllPricing(), {});
});
test("LKGP values can be set, read and cleared", async () => {
assert.equal(await settingsDb.getLKGP("combo-a", "model-a"), null);
await settingsDb.setLKGP("combo-a", "model-a", "openai");
await settingsDb.setLKGP("combo-a", "model-b", "anthropic");
assert.equal(await settingsDb.getLKGP("combo-a", "model-a"), "openai");
assert.equal(await settingsDb.getLKGP("combo-a", "model-b"), "anthropic");
settingsDb.clearAllLKGP();
assert.equal(await settingsDb.getLKGP("combo-a", "model-a"), null);
});
test("proxy config migrates legacy strings and supports bulk merge updates", async () => {
const db = core.getDbInstance();
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"proxyConfig",
"global",
JSON.stringify("http://user:pass@global.local:8080")
);
db.prepare("INSERT INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"proxyConfig",
"providers",
JSON.stringify({
openai: "https://provider.local:8443",
})
);
const migrated = await settingsDb.getProxyConfig();
assert.deepEqual(migrated.global, {
type: "http",
host: "global.local",
port: "8080",
username: "user",
password: "pass",
});
assert.deepEqual(migrated.providers.openai, {
type: "https",
host: "provider.local",
port: "8443",
username: "",
password: "",
});
const merged = await settingsDb.setProxyConfig({
providers: {
openai: null,
anthropic: {
type: "http",
host: "anthropic.local",
port: 9000,
},
},
keys: {
key123: {
type: "socks5",
host: "key.local",
port: 1080,
},
},
});
assert.equal(merged.providers.openai, undefined);
assert.equal(merged.providers.anthropic.host, "anthropic.local");
assert.equal((await settingsDb.getProxyForLevel("key", "key123")).host, "key.local");
await settingsDb.deleteProxyForLevel("key", "key123");
assert.equal(await settingsDb.getProxyForLevel("key", "key123"), null);
});
test("cache metrics, trend and no-op update/reset methods read from usage_history", async () => {
const db = core.getDbInstance();
const now = new Date().toISOString();
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
const insertUsage = db.prepare(`
INSERT INTO usage_history (
provider, model, connection_id, api_key_id, api_key_name,
tokens_input, tokens_output, tokens_cache_read, tokens_cache_creation,
tokens_reasoning, status, success, latency_ms, ttft_ms, error_code, timestamp
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
insertUsage.run(
"openai",
"gpt-4.1",
"conn-1",
"key-1",
"Primary",
1000,
400,
300,
120,
0,
"200",
1,
100,
40,
null,
oneHourAgo
);
insertUsage.run(
"anthropic",
"claude-3-7-sonnet",
"conn-2",
"key-2",
"Secondary",
700,
280,
200,
80,
0,
"200",
1,
90,
30,
null,
now
);
const metrics = await settingsDb.getCacheMetrics();
const trend = await settingsDb.getCacheTrend(4);
const updateNoOp = await settingsDb.updateCacheMetrics({ anything: true });
const resetNoOp = await settingsDb.resetCacheMetrics();
assert.ok(metrics.totalRequests >= 2);
assert.ok(metrics.requestsWithCacheControl >= 2);
assert.ok(metrics.byProvider.openai);
assert.ok(metrics.byProvider.anthropic);
assert.ok(trend.length >= 1);
assert.equal(updateNoOp.totalCachedTokens, metrics.totalCachedTokens);
assert.equal(resetNoOp.totalCachedTokens, metrics.totalCachedTokens);
});

View File

@@ -0,0 +1,506 @@
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-domain-hardening-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const costRules = await import("../../src/domain/costRules.ts");
const fallbackPolicy = await import("../../src/domain/fallbackPolicy.ts");
const lockoutPolicy = await import("../../src/domain/lockoutPolicy.ts");
const modelAvailability = await import("../../src/domain/modelAvailability.ts");
const providerExpiration = await import("../../src/domain/providerExpiration.ts");
const quotaCache = await import("../../src/domain/quotaCache.ts");
const comboResolver = await import("../../src/domain/comboResolver.ts");
const policyEngineModule = await import("../../src/domain/policyEngine.ts");
const domainState = await import("../../src/lib/db/domainState.ts");
const originalDateNow = Date.now;
const originalMathRandom = Math.random;
function isoFromNow(offsetMs) {
return new Date(Date.now() + offsetMs).toISOString();
}
async function resetStorage() {
costRules.resetCostData();
fallbackPolicy.resetAllFallbacks();
modelAvailability.resetAllAvailability();
providerExpiration.resetExpirations();
quotaCache.stopBackgroundRefresh();
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
Date.now = originalDateNow;
Math.random = originalMathRandom;
await resetStorage();
});
test.after(async () => {
Date.now = originalDateNow;
Math.random = originalMathRandom;
quotaCache.stopBackgroundRefresh();
costRules.resetCostData();
fallbackPolicy.resetAllFallbacks();
modelAvailability.resetAllAvailability();
providerExpiration.resetExpirations();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("resolveComboModel covers empty combos, priority, round-robin, random, least-used and default fallback", () => {
assert.throws(
() => comboResolver.resolveComboModel({ name: "empty", models: [] }),
/has no models configured/
);
assert.deepEqual(
comboResolver.resolveComboModel({
id: "priority-combo",
models: ["model-a", "model-b"],
strategy: "priority",
}),
{ model: "model-a", index: 0 }
);
const rrCombo = {
id: "rr-combo",
models: ["m1", "m2"],
strategy: "round-robin",
};
assert.deepEqual(comboResolver.resolveComboModel(rrCombo), { model: "m1", index: 0 });
assert.deepEqual(comboResolver.resolveComboModel(rrCombo), { model: "m2", index: 1 });
assert.deepEqual(comboResolver.resolveComboModel(rrCombo), { model: "m1", index: 0 });
Math.random = () => 0.9;
assert.deepEqual(
comboResolver.resolveComboModel({
name: "random-combo",
strategy: "random",
models: [
{ model: "small", weight: 1 },
{ model: "large", weight: 9 },
],
}),
{ model: "large", index: 1 }
);
Math.random = () => Number.NaN;
assert.deepEqual(
comboResolver.resolveComboModel({
name: "random-fallback",
strategy: "random",
models: ["fallback-a", "fallback-b"],
}),
{ model: "fallback-a", index: 0 }
);
assert.deepEqual(
comboResolver.resolveComboModel(
{
name: "least-used",
strategy: "least-used",
models: ["used-a", "used-b", "used-c"],
},
{ modelUsageCounts: { "used-a": 5, "used-b": 1 } }
),
{ model: "used-c", index: 2 }
);
assert.deepEqual(
comboResolver.resolveComboModel({
name: "unknown-strategy",
strategy: "not-real",
models: [
{ model: "default-a", weight: 2 },
{ model: "default-b", weight: 1 },
],
}),
{ model: "default-a", index: 0 }
);
assert.deepEqual(
comboResolver.getComboFallbacks(
{
models: ["alpha", { model: "beta" }, "gamma"],
},
1
),
["gamma", "alpha"]
);
});
test("resolveComboModel also covers implicit defaults and missing optional fields", () => {
assert.throws(() => comboResolver.resolveComboModel({}), /has no models configured/);
assert.deepEqual(comboResolver.resolveComboModel({ models: ["implicit-a", "implicit-b"] }), {
model: "implicit-a",
index: 0,
});
const anonymousRoundRobin = {
strategy: "round-robin",
models: ["rr-a", "rr-b"],
};
assert.deepEqual(comboResolver.resolveComboModel(anonymousRoundRobin), {
model: "rr-a",
index: 0,
});
assert.deepEqual(comboResolver.resolveComboModel(anonymousRoundRobin), {
model: "rr-b",
index: 1,
});
Math.random = () => 0.9;
assert.deepEqual(
comboResolver.resolveComboModel({
strategy: "random",
models: [{ model: "weighted-default-a" }, { model: "weighted-default-b" }],
}),
{ model: "weighted-default-b", index: 1 }
);
assert.deepEqual(
comboResolver.resolveComboModel({
strategy: "least-used",
models: ["least-default-a", "least-default-b"],
}),
{ model: "least-default-a", index: 0 }
);
assert.deepEqual(comboResolver.getComboFallbacks({}, 0), []);
});
test("modelAvailability tracks missing, active and expired cooldowns", () => {
let now = 1_000;
Date.now = () => now;
assert.equal(modelAvailability.isModelAvailable("openai", "gpt-4o"), true);
modelAvailability.setModelUnavailable("openai", "gpt-4o", 100, undefined);
modelAvailability.setModelUnavailable("anthropic", "claude-sonnet", 500, "capacity");
assert.equal(modelAvailability.isModelAvailable("openai", "gpt-4o"), false);
assert.equal(modelAvailability.getUnavailableCount(), 2);
const report = modelAvailability.getAvailabilityReport();
assert.equal(report.length, 2);
assert.equal(report[0].reason, "unknown");
assert.equal(report[1].reason, "capacity");
now += 150;
assert.equal(modelAvailability.isModelAvailable("openai", "gpt-4o"), true);
assert.equal(modelAvailability.clearModelUnavailability("openai", "gpt-4o"), false);
assert.equal(modelAvailability.clearModelUnavailability("anthropic", "claude-sonnet"), true);
assert.equal(modelAvailability.getUnavailableCount(), 0);
});
test("providerExpiration derives status, sorting, summary and header-based expiration hints", () => {
const expired = providerExpiration.setExpiration(
"conn-expired",
"claude",
"Claude",
isoFromNow(-60_000),
"oauth_token"
);
const soon = providerExpiration.setExpiration(
"conn-soon",
"openai",
"OpenAI",
isoFromNow(2 * 24 * 60 * 60 * 1000),
"subscription",
{ alertDays: 7 }
);
const active = providerExpiration.setExpiration(
"conn-active",
"gemini",
"Gemini",
isoFromNow(20 * 24 * 60 * 60 * 1000),
"api_credits",
{ alertDays: 3, note: "healthy" }
);
providerExpiration.setExpiration("conn-unknown", "cursor", "Cursor", null, "subscription");
providerExpiration.setExpiration("conn-invalid", "kimi", "Kimi", "not-a-date", "free_tier_reset");
assert.equal(expired.status, "expired");
assert.equal(soon.status, "expiring_soon");
assert.equal(active.status, "active");
assert.equal(providerExpiration.getExpiration("missing-connection"), null);
assert.equal(providerExpiration.getExpiration("conn-active")?.note, "healthy");
assert.deepEqual(
providerExpiration.getAllExpirations().map((entry) => entry.connectionId),
["conn-expired", "conn-soon", "conn-active", "conn-unknown", "conn-invalid"]
);
assert.deepEqual(
providerExpiration.getExpiringSoon().map((entry) => entry.connectionId),
["conn-expired", "conn-soon"]
);
const summary = providerExpiration.getExpirationSummary();
assert.equal(summary.total, 5);
assert.equal(summary.active, 1);
assert.equal(summary.expiringSoon, 1);
assert.equal(summary.expired, 1);
assert.equal(summary.unknown, 2);
assert.equal(summary.nextExpiration?.connectionId, "conn-soon");
const detected401 = providerExpiration.detectExpirationFromResponse("claude", 401, {});
assert.equal(detected401.expiryType, "oauth_token");
const detected402 = providerExpiration.detectExpirationFromResponse("openai", 402, {});
assert.equal(detected402.expiryType, "subscription");
const retryAfterSeconds = providerExpiration.detectExpirationFromResponse("gemini", 429, {
"retry-after": "120",
});
assert.equal(retryAfterSeconds.expiryType, "free_tier_reset");
assert.ok(new Date(retryAfterSeconds.expiresAt).getTime() > Date.now());
const epochSeconds = Math.floor((Date.now() + 60_000) / 1000);
const ratelimitReset = providerExpiration.detectExpirationFromResponse("openai", 429, {
"x-ratelimit-reset": String(epochSeconds),
});
assert.equal(ratelimitReset.expiryType, "free_tier_reset");
assert.equal(
providerExpiration.detectExpirationFromResponse("openai", 429, { "retry-after": "nope" }),
null
);
assert.equal(providerExpiration.detectExpirationFromResponse("openai", 500, {}), null);
assert.equal(providerExpiration.removeExpiration("conn-active"), true);
assert.equal(providerExpiration.removeExpiration("conn-active"), false);
providerExpiration.resetExpirations();
assert.deepEqual(providerExpiration.getAllExpirations(), []);
});
test("quotaCache covers normalized windows, stale exhaustion, stats and refresh timer lifecycle", () => {
let now = 10_000;
Date.now = () => now;
const activeConnectionId = "quota-active-connection";
quotaCache.setQuotaCache(activeConnectionId, "cursor", {
daily: { remainingPercentage: 125, resetAt: isoFromNow(60_000) },
"weekly (7d)": { total: 100, used: 90, resetAt: isoFromNow(120_000) },
ignored: null,
});
assert.equal(quotaCache.getQuotaCache("missing"), null);
assert.equal(quotaCache.isAccountQuotaExhausted("missing"), false);
assert.equal(quotaCache.getQuotaWindowStatus("missing", "daily"), null);
const weekly = quotaCache.getQuotaWindowStatus(activeConnectionId, "weekly", 80);
assert.deepEqual(weekly, {
remainingPercentage: 10,
usedPercentage: 90,
resetAt: isoFromNow(120_000),
reachedThreshold: true,
});
const daily = quotaCache.getQuotaWindowStatus(activeConnectionId, "daily", 99);
assert.deepEqual(daily, {
remainingPercentage: 100,
usedPercentage: 0,
resetAt: isoFromNow(60_000),
reachedThreshold: false,
});
const expiredWindowId = "quota-expired-window";
quotaCache.setQuotaCache(expiredWindowId, "cursor", {
session: { remainingPercentage: 5, resetAt: isoFromNow(-1_000) },
});
assert.deepEqual(quotaCache.getQuotaWindowStatus(expiredWindowId, "session", 90), {
remainingPercentage: 5,
usedPercentage: 95,
resetAt: null,
reachedThreshold: false,
});
assert.equal(quotaCache.getQuotaWindowStatus(expiredWindowId, "", 90), null);
const exhaustedWithResetId = "quota-exhausted-reset";
quotaCache.setQuotaCache(exhaustedWithResetId, "cursor", {
daily: { remainingPercentage: 0, resetAt: isoFromNow(60_000) },
});
assert.equal(quotaCache.isAccountQuotaExhausted(exhaustedWithResetId), true);
now += 61_000;
assert.equal(quotaCache.isAccountQuotaExhausted(exhaustedWithResetId), false);
const exhausted429Id = "quota-exhausted-429";
quotaCache.markAccountExhaustedFrom429(exhausted429Id, "cursor");
assert.equal(quotaCache.isAccountQuotaExhausted(exhausted429Id), true);
now += 5 * 60 * 1000 + 1;
assert.equal(quotaCache.isAccountQuotaExhausted(exhausted429Id), false);
const stats = quotaCache.getQuotaCacheStats();
assert.ok(stats.total >= 3);
assert.ok(stats.entries.some((entry) => entry.connectionId === "quota-ac..."));
quotaCache.startBackgroundRefresh();
quotaCache.startBackgroundRefresh();
quotaCache.stopBackgroundRefresh();
quotaCache.stopBackgroundRefresh();
});
test("quotaCache covers empty quotas, invalid dates and fallback percentage normalization", () => {
let now = 100_000;
Date.now = () => now;
quotaCache.setQuotaCache("quota-empty", "cursor", {});
assert.equal(quotaCache.getQuotaCache("quota-empty")?.exhausted, false);
assert.equal(quotaCache.isAccountQuotaExhausted("quota-empty"), false);
quotaCache.setQuotaCache("quota-zero-total", "cursor", {
daily: { total: 0, used: 25 },
"###": { remainingPercentage: 50 },
});
assert.deepEqual(quotaCache.getQuotaWindowStatus("quota-zero-total", "daily", 10), {
remainingPercentage: 0,
usedPercentage: 100,
resetAt: null,
reachedThreshold: true,
});
assert.equal(quotaCache.getQuotaWindowStatus("quota-zero-total", "unknown"), null);
quotaCache.setQuotaCache("quota-invalid-reset", "cursor", {
daily: { remainingPercentage: Number.POSITIVE_INFINITY, resetAt: "not-a-date" },
});
assert.deepEqual(quotaCache.getQuotaWindowStatus("quota-invalid-reset", "daily", 10), {
remainingPercentage: 0,
usedPercentage: 100,
resetAt: "not-a-date",
reachedThreshold: true,
});
quotaCache.setQuotaCache("quota-invalid-exhausted", "cursor", {
daily: { remainingPercentage: 0, resetAt: "still-not-a-date" },
});
assert.equal(quotaCache.isAccountQuotaExhausted("quota-invalid-exhausted"), true);
});
test("policyEngine evaluates lockout, budget, fallback chains and policy class actions", () => {
const lockConfig = {
maxAttempts: 1,
lockoutDurationMs: 500,
attemptWindowMs: 1_000,
};
let now = 50_000;
Date.now = () => now;
lockoutPolicy.recordFailedAttempt("10.0.0.1", lockConfig);
const locked = policyEngineModule.evaluateRequest({
model: "claude-sonnet",
clientIp: "10.0.0.1",
});
assert.equal(locked.allowed, false);
assert.equal(locked.policyPhase, "lockout");
lockoutPolicy.recordSuccess("10.0.0.1");
Date.now = originalDateNow;
costRules.setBudget("key-budget", { dailyLimitUsd: 5, warningThreshold: 0.5 });
costRules.recordCost("key-budget", 6);
const overBudget = policyEngineModule.evaluateRequest({
model: "claude-sonnet",
apiKeyId: "key-budget",
});
assert.equal(overBudget.allowed, false);
assert.equal(overBudget.policyPhase, "budget");
fallbackPolicy.registerFallback("claude-sonnet", [
{ provider: "vertex", priority: 2 },
{ provider: "bedrock", priority: 3 },
]);
const passed = policyEngineModule.evaluateRequest({
model: "claude-sonnet",
apiKeyId: "missing-key",
});
assert.equal(passed.allowed, true);
assert.deepEqual(passed.adjustments.fallbackChain, [
{ provider: "vertex", priority: 2, enabled: true },
{ provider: "bedrock", priority: 3, enabled: true },
]);
const firstAllowed = policyEngineModule.evaluateFirstAllowed(["claude-sonnet", "gpt-4o"], {
clientIp: "10.0.0.2",
});
assert.equal(firstAllowed.model, "claude-sonnet");
assert.equal(firstAllowed.verdict.allowed, true);
const engine = new policyEngineModule.PolicyEngine();
engine.loadPolicies([
{
id: "disabled",
name: "Disabled Policy",
type: "routing",
enabled: false,
priority: 1,
actions: { prefer_provider: ["ignored"] },
},
{
id: "routing",
name: "Prefer Vertex",
type: "routing",
enabled: true,
priority: 2,
conditions: { model_pattern: "claude-*" },
actions: { prefer_provider: ["vertex", "bedrock"] },
},
{
id: "budget",
name: "Token Cap",
type: "budget",
enabled: true,
priority: 3,
conditions: { model_pattern: "claude-*" },
actions: { max_tokens: 4096 },
},
]);
const routed = engine.evaluate({ model: "claude-sonnet-4" });
assert.deepEqual(routed.preferredProviders, ["vertex", "bedrock"]);
assert.equal(routed.maxTokens, 4096);
assert.deepEqual(routed.appliedPolicies, ["Prefer Vertex", "Token Cap"]);
engine.addPolicy({
id: "access",
name: "Block Claude Sonnet",
type: "access",
enabled: true,
priority: 0,
actions: { block_model: ["claude-sonnet-*"] },
});
const blocked = engine.evaluate({ model: "claude-sonnet-4" });
assert.equal(blocked.allowed, false);
assert.match(blocked.reason, /blocked by policy/);
assert.deepEqual(blocked.appliedPolicies, ["Block Claude Sonnet"]);
engine.removePolicy("access");
assert.equal(
engine.getPolicies().some((policy) => policy.id === "access"),
false
);
});

View File

@@ -0,0 +1,161 @@
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-domain-cost-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const costRules = await import("../../src/domain/costRules.ts");
const domainState = await import("../../src/lib/db/domainState.ts");
async function resetStorage() {
costRules.resetCostData();
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
costRules.resetCostData();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("setBudget normalizes defaults and getBudget returns the stored config", () => {
costRules.setBudget("key-budget", { dailyLimitUsd: 12.5 });
assert.deepEqual(costRules.getBudget("key-budget"), {
dailyLimitUsd: 12.5,
monthlyLimitUsd: 0,
warningThreshold: 0.8,
});
assert.equal(costRules.getBudget("missing-key"), null);
});
test("checkBudget reports warning and blocks when projected spend exceeds the daily cap", () => {
costRules.setBudget("key-warning", {
dailyLimitUsd: 10,
warningThreshold: 0.6,
});
costRules.recordCost("key-warning", 5);
const warning = costRules.checkBudget("key-warning", 1);
const denied = costRules.checkBudget("key-warning", 6);
assert.deepEqual(warning, {
allowed: true,
dailyUsed: 5,
dailyLimit: 10,
warningReached: true,
});
assert.equal(denied.allowed, false);
assert.equal(denied.warningReached, true);
assert.match(denied.reason, /Daily budget exceeded/);
});
test("getDailyTotal and getCostSummary split daily and monthly totals correctly", () => {
costRules.setBudget("key-summary", {
dailyLimitUsd: 50,
monthlyLimitUsd: 100,
warningThreshold: 0.75,
});
const now = Date.now();
const today = now - 1_000;
const yesterday = now - 24 * 60 * 60 * 1000;
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
domainState.saveCostEntry("key-summary", 2.5, today);
domainState.saveCostEntry("key-summary", 1.5, yesterday);
domainState.saveCostEntry("key-summary", 9.9, lastMonth.getTime());
assert.equal(costRules.getDailyTotal("key-summary"), 2.5);
assert.deepEqual(costRules.getCostSummary("key-summary"), {
dailyTotal: 2.5,
monthlyTotal: 4,
totalEntries: 2,
budget: {
dailyLimitUsd: 50,
monthlyLimitUsd: 100,
warningThreshold: 0.75,
},
});
});
test("costRules covers DB-loaded budgets, malformed entries and storage failure fallbacks", () => {
domainState.saveBudget("db-loaded", {
dailyLimitUsd: 7,
monthlyLimitUsd: 21,
warningThreshold: 0.7,
});
assert.deepEqual(costRules.getBudget("db-loaded"), {
dailyLimitUsd: 7,
monthlyLimitUsd: 21,
warningThreshold: 0.7,
});
assert.deepEqual(costRules.checkBudget("missing-budget"), {
allowed: true,
dailyUsed: 0,
dailyLimit: 0,
warningReached: false,
});
const db = core.getDbInstance();
const now = Date.now();
db.prepare("INSERT INTO domain_cost_history (api_key_id, cost, timestamp) VALUES (?, ?, ?)").run(
"malformed-costs",
"2.25",
String(now)
);
db.prepare("INSERT INTO domain_cost_history (api_key_id, cost, timestamp) VALUES (?, ?, ?)").run(
"malformed-costs",
"not-a-number",
now
);
db.prepare("INSERT INTO domain_cost_history (api_key_id, cost, timestamp) VALUES (?, ?, ?)").run(
"malformed-costs",
4,
"not-a-timestamp"
);
assert.equal(costRules.getDailyTotal("malformed-costs"), 2.25);
assert.deepEqual(costRules.getCostSummary("malformed-costs"), {
dailyTotal: 2.25,
monthlyTotal: 2.25,
totalEntries: 1,
budget: null,
});
db.exec("DROP TABLE domain_cost_history");
assert.equal(costRules.getDailyTotal("malformed-costs"), 0);
assert.deepEqual(costRules.getCostSummary("malformed-costs"), {
dailyTotal: 0,
monthlyTotal: 0,
totalEntries: 0,
budget: null,
});
});

View File

@@ -0,0 +1,252 @@
import test from "node:test";
import assert from "node:assert/strict";
const degradation = await import("../../src/domain/degradation.ts");
test.beforeEach(() => {
degradation.resetDegradationRegistry();
});
test.after(() => {
degradation.resetDegradationRegistry();
});
test("withDegradation returns full capability when the primary path succeeds", async () => {
const result = await degradation.withDegradation(
"semantic-search",
async () => "primary-result",
async () => "fallback-result",
"safe-default"
);
assert.equal(result.result, "primary-result");
assert.deepEqual(result.status, {
level: "full",
feature: "semantic-search",
capability: "Full capability",
reason: "",
since: result.status.since,
});
assert.deepEqual(degradation.getFeatureStatus("semantic-search"), result.status);
assert.equal(degradation.hasAnyDegradation(), false);
assert.deepEqual(degradation.getDegradationSummary(), {
full: 1,
reduced: 0,
minimal: 0,
default: 0,
});
});
test("withDegradation reports reduced capability, calls onDegrade, and preserves since across repeated degradation", async () => {
const seen = [];
const first = await degradation.withDegradation(
"rate-limit-cache",
async () => {
throw new Error("redis unavailable");
},
async () => "memory-fallback",
"safe-default",
{
reducedCapability: "In-memory fallback",
onDegrade: (status) => seen.push(status),
}
);
await new Promise((resolve) => setTimeout(resolve, 10));
const second = await degradation.withDegradation(
"rate-limit-cache",
async () => {
throw new Error("redis unavailable");
},
async () => "memory-fallback-again",
"safe-default",
{
reducedCapability: "In-memory fallback",
onDegrade: (status) => seen.push(status),
}
);
assert.equal(first.result, "memory-fallback");
assert.equal(first.status.level, "reduced");
assert.equal(first.status.capability, "In-memory fallback");
assert.equal(first.status.reason, "redis unavailable");
assert.equal(second.status.level, "reduced");
assert.equal(second.status.since, first.status.since);
assert.equal(seen.length, 2);
assert.equal(degradation.hasAnyDegradation(), true);
});
test("withDegradation falls back to the safe default when both implementations fail and the report sorts worst-first", async () => {
await degradation.withDegradation(
"cache-layer",
async () => {
throw new Error("cache offline");
},
async () => "memory-fallback",
"safe-default"
);
const finalFallback = await degradation.withDegradation(
"billing-export",
async () => {
throw new Error("primary offline");
},
async () => {
throw new Error("fallback offline");
},
{ exported: false },
{
defaultCapability: "Disabled export",
}
);
assert.deepEqual(finalFallback.result, { exported: false });
assert.equal(finalFallback.status.level, "default");
assert.equal(finalFallback.status.capability, "Disabled export");
assert.equal(finalFallback.status.reason, "primary offline → fallback offline");
assert.deepEqual(
degradation.getDegradationReport().map((entry) => ({
feature: entry.feature,
level: entry.level,
})),
[
{ feature: "billing-export", level: "default" },
{ feature: "cache-layer", level: "reduced" },
]
);
});
test("withDegradationSync supports reduced and default modes and reset clears the registry", () => {
const reduced = degradation.withDegradationSync(
"sync-feature",
() => {
throw new Error("primary failed");
},
() => "fallback-result",
"safe-default",
{
reducedCapability: "Fallback mode",
}
);
const fallback = degradation.withDegradationSync(
"sync-default",
() => {
throw new Error("primary failed");
},
() => {
throw new Error("fallback failed");
},
"safe-default"
);
assert.equal(reduced.result, "fallback-result");
assert.equal(reduced.status.level, "reduced");
assert.equal(reduced.status.capability, "Fallback mode");
assert.equal(fallback.result, "safe-default");
assert.equal(fallback.status.level, "default");
assert.match(fallback.status.reason, /primary failed/);
degradation.resetDegradationRegistry();
assert.equal(degradation.getFeatureStatus("sync-feature"), null);
assert.deepEqual(degradation.getDegradationReport(), []);
});
test("degradation helpers cover custom capabilities and primitive error values", async () => {
const seen = [];
const full = await degradation.withDegradation(
"custom-full",
async () => "primary",
async () => "fallback",
"safe-default",
{
fullCapability: "Primary path available",
}
);
const reduced = await degradation.withDegradation(
"custom-reduced",
async () => {
throw "primary-string-error";
},
async () => "fallback",
"safe-default",
{
reducedCapability: "Secondary path available",
onDegrade: (status) => seen.push(status.feature),
}
);
const fallback = await degradation.withDegradation(
"custom-default",
async () => {
throw "primary-primitive";
},
async () => {
throw "fallback-primitive";
},
"safe-default",
{
defaultCapability: "Static safe mode",
onDegrade: (status) => seen.push(status.feature),
}
);
const fullSync = degradation.withDegradationSync(
"sync-custom-full",
() => "sync-primary",
() => "sync-fallback",
"sync-safe",
{
fullCapability: "Sync primary path",
}
);
const reducedSync = degradation.withDegradationSync(
"sync-custom-reduced",
() => {
throw "sync-primary-error";
},
() => "sync-fallback",
"sync-safe",
{
reducedCapability: "Sync fallback path",
onDegrade: (status) => seen.push(status.feature),
}
);
const defaultSync = degradation.withDegradationSync(
"sync-custom-default",
() => {
throw "sync-primary-primitive";
},
() => {
throw "sync-fallback-primitive";
},
"sync-safe",
{
defaultCapability: "Sync safe mode",
onDegrade: (status) => seen.push(status.feature),
}
);
assert.equal(full.status.capability, "Primary path available");
assert.equal(reduced.status.capability, "Secondary path available");
assert.equal(reduced.status.reason, "primary-string-error");
assert.equal(fallback.status.capability, "Static safe mode");
assert.equal(fallback.status.reason, "primary-primitive → fallback-primitive");
assert.equal(fullSync.status.capability, "Sync primary path");
assert.equal(reducedSync.status.capability, "Sync fallback path");
assert.equal(reducedSync.status.reason, "sync-primary-error");
assert.equal(defaultSync.status.capability, "Sync safe mode");
assert.equal(defaultSync.status.reason, "sync-primary-primitive → sync-fallback-primitive");
assert.deepEqual(seen, [
"custom-reduced",
"custom-default",
"sync-custom-reduced",
"sync-custom-default",
]);
});

View File

@@ -0,0 +1,87 @@
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-domain-fallback-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const fallbackPolicy = await import("../../src/domain/fallbackPolicy.ts");
async function resetStorage() {
fallbackPolicy.resetAllFallbacks();
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(async () => {
await resetStorage();
});
test.after(async () => {
fallbackPolicy.resetAllFallbacks();
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("registerFallback sorts by priority and defaults missing flags to enabled", () => {
fallbackPolicy.registerFallback("gpt-4o-mini", [
{ provider: "azure", priority: 20 },
{ provider: "openai" },
{ provider: "github", priority: 10, enabled: false },
]);
assert.deepEqual(fallbackPolicy.resolveFallbackChain("gpt-4o-mini"), [
{ provider: "openai", priority: 0, enabled: true },
{ provider: "azure", priority: 20, enabled: true },
]);
assert.equal(fallbackPolicy.hasFallback("gpt-4o-mini"), true);
});
test("resolveFallbackChain and getNextFallback respect exclusions and disabled providers", () => {
fallbackPolicy.registerFallback("claude-sonnet", [
{ provider: "anthropic", priority: 1, enabled: false },
{ provider: "vertex", priority: 2, enabled: true },
{ provider: "bedrock", priority: 3, enabled: true },
]);
assert.deepEqual(fallbackPolicy.resolveFallbackChain("claude-sonnet", ["vertex"]), [
{ provider: "bedrock", priority: 3, enabled: true },
]);
assert.equal(fallbackPolicy.getNextFallback("claude-sonnet"), "vertex");
assert.equal(fallbackPolicy.getNextFallback("claude-sonnet", ["vertex", "bedrock"]), null);
});
test("removeFallback and resetAllFallbacks clear registered chains", () => {
fallbackPolicy.registerFallback("model-a", [{ provider: "provider-a", priority: 1 }]);
fallbackPolicy.registerFallback("model-b", [{ provider: "provider-b", priority: 1 }]);
assert.deepEqual(Object.keys(fallbackPolicy.getAllFallbackChains()).sort(), [
"model-a",
"model-b",
]);
assert.equal(fallbackPolicy.removeFallback("model-a"), true);
assert.equal(fallbackPolicy.removeFallback("model-a"), false);
assert.equal(fallbackPolicy.hasFallback("model-a"), false);
fallbackPolicy.resetAllFallbacks();
assert.deepEqual(fallbackPolicy.getAllFallbackChains(), {});
});

View File

@@ -0,0 +1,154 @@
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-domain-lockout-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const lockoutPolicy = await import("../../src/domain/lockoutPolicy.ts");
async function resetStorage() {
core.resetDbInstance();
for (let attempt = 0; attempt < 10; attempt++) {
try {
if (fs.existsSync(TEST_DATA_DIR)) {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
}
break;
} catch (error) {
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
} else {
throw error;
}
}
}
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
const originalDateNow = Date.now;
test.beforeEach(async () => {
Date.now = originalDateNow;
await resetStorage();
});
test.after(async () => {
Date.now = originalDateNow;
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("checkLockout starts unlocked and locks after reaching the configured threshold", () => {
let now = 1_000;
Date.now = () => now;
const id = "lockout-threshold";
const config = {
maxAttempts: 3,
lockoutDurationMs: 500,
attemptWindowMs: 200,
};
assert.deepEqual(lockoutPolicy.checkLockout(id, config), {
locked: false,
attempts: 0,
});
assert.deepEqual(lockoutPolicy.recordFailedAttempt(id, config), { locked: false });
now += 50;
assert.deepEqual(lockoutPolicy.recordFailedAttempt(id, config), { locked: false });
now += 50;
assert.deepEqual(lockoutPolicy.recordFailedAttempt(id, config), {
locked: true,
remainingMs: 500,
});
const locked = lockoutPolicy.checkLockout(id, config);
assert.equal(locked.locked, true);
assert.equal(locked.attempts, 3);
assert.equal(locked.remainingMs, 500);
});
test("expired lockouts are cleared and stale attempts outside the window are pruned", () => {
let now = 10_000;
Date.now = () => now;
const id = "lockout-expiry";
const config = {
maxAttempts: 2,
lockoutDurationMs: 100,
attemptWindowMs: 50,
};
lockoutPolicy.recordFailedAttempt(id, config);
now += 60;
assert.deepEqual(lockoutPolicy.recordFailedAttempt(id, config), { locked: false });
now += 10;
assert.deepEqual(lockoutPolicy.recordFailedAttempt(id, config), {
locked: true,
remainingMs: 100,
});
now += 120;
assert.deepEqual(lockoutPolicy.checkLockout(id, config), {
locked: false,
attempts: 0,
});
});
test("recordSuccess and forceUnlock remove tracked identifiers", () => {
const config = {
maxAttempts: 1,
lockoutDurationMs: 1_000,
attemptWindowMs: 1_000,
};
lockoutPolicy.recordFailedAttempt("unlock-success", config);
assert.equal(lockoutPolicy.checkLockout("unlock-success", config).locked, true);
lockoutPolicy.recordSuccess("unlock-success");
assert.deepEqual(lockoutPolicy.checkLockout("unlock-success", config), {
locked: false,
attempts: 0,
});
lockoutPolicy.recordFailedAttempt("unlock-force", config);
assert.equal(lockoutPolicy.checkLockout("unlock-force", config).locked, true);
lockoutPolicy.forceUnlock("unlock-force");
assert.deepEqual(lockoutPolicy.checkLockout("unlock-force", config), {
locked: false,
attempts: 0,
});
});
test("getLockedIdentifiers returns active lockouts and filters expired ones", () => {
let now = 20_000;
Date.now = () => now;
const shortConfig = {
maxAttempts: 1,
lockoutDurationMs: 50,
attemptWindowMs: 500,
};
const longConfig = {
maxAttempts: 1,
lockoutDurationMs: 500,
attemptWindowMs: 500,
};
lockoutPolicy.recordFailedAttempt("expired-id", shortConfig);
lockoutPolicy.recordFailedAttempt("active-id", longConfig);
now += 100;
const locked = lockoutPolicy.getLockedIdentifiers();
assert.ok(locked.some((entry) => entry.identifier === "active-id"));
assert.ok(!locked.some((entry) => entry.identifier === "expired-id"));
assert.ok(locked.find((entry) => entry.identifier === "active-id").remainingMs > 0);
});

View File

@@ -14,6 +14,24 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
function raceDelays(firstMs, secondMs) {
return new Promise((resolve) => {
let settled = false;
const first = setTimeout(() => {
if (settled) return;
settled = true;
clearTimeout(second);
resolve(firstMs);
}, firstMs);
const second = setTimeout(() => {
if (settled) return;
settled = true;
clearTimeout(first);
resolve(secondMs);
}, secondMs);
});
}
// ─── URL Validation Tests ────────────────────────────────────
describe("Electron URL Validation", () => {
@@ -207,20 +225,14 @@ describe("Restart Timeout Logic", () => {
it("should resolve even if process doesn't exit", async () => {
// Simulate the timeout race
const start = Date.now();
await Promise.race([
new Promise((r) => setTimeout(r, 100000)), // simulates hung process
new Promise((r) => setTimeout(r, 50)), // timeout
]);
await raceDelays(100000, 50);
const elapsed = Date.now() - start;
assert.ok(elapsed < 200, "Should resolve in ~50ms via timeout");
});
it("should resolve immediately if process exits first", async () => {
const start = Date.now();
await Promise.race([
new Promise((r) => setTimeout(r, 10)), // simulates fast exit
new Promise((r) => setTimeout(r, 5000)), // timeout
]);
await raceDelays(10, 5000);
const elapsed = Date.now() - start;
assert.ok(elapsed < 200, "Should resolve in ~10ms via exit");
});

View File

@@ -0,0 +1,174 @@
import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
process.env.DATA_DIR = mkdtempSync(join(tmpdir(), "omniroute-embeddings-"));
const { handleEmbedding } = await import("../../open-sse/handlers/embeddings.ts");
test("handleEmbedding routes prefixed models and forwards optional fields", async () => {
const originalFetch = globalThis.fetch;
const calls = [];
globalThis.fetch = async (url, options = {}) => {
calls.push({
url: String(url),
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
});
return new Response(
JSON.stringify({
data: [{ object: "embedding", embedding: [0.1, 0.2], index: 0 }],
usage: { prompt_tokens: 3, total_tokens: 3 },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const result = await handleEmbedding({
body: {
model: "openai/text-embedding-3-large",
input: "hello world",
dimensions: 512,
encoding_format: "float",
user: "user-123",
},
credentials: { apiKey: "openai-key" },
log: null,
});
assert.equal(result.success, true);
assert.equal(calls.length, 1);
assert.equal(calls[0].url, "https://api.openai.com/v1/embeddings");
assert.equal(calls[0].headers.Authorization, "Bearer openai-key");
assert.deepEqual(calls[0].body, {
model: "text-embedding-3-large",
input: "hello world",
dimensions: 512,
encoding_format: "float",
user: "user-123",
});
assert.equal(result.data.model, "openai/text-embedding-3-large");
assert.deepEqual(result.data.usage, { prompt_tokens: 3, total_tokens: 3 });
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleEmbedding supports resolved local providers without auth and preserves array input", async () => {
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options = {}) => {
captured = {
url: String(url),
headers: options.headers,
body: JSON.parse(String(options.body || "{}")),
};
return new Response(
JSON.stringify({
data: [
{ object: "embedding", embedding: [1, 2], index: 0 },
{ object: "embedding", embedding: [3, 4], index: 1 },
],
usage: { total_tokens: 10 },
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
};
try {
const result = await handleEmbedding({
body: {
model: "localembed/my-model",
input: ["alpha", "beta"],
},
credentials: null,
resolvedProvider: {
id: "localembed",
baseUrl: "http://localhost:11434/embeddings",
authType: "none",
authHeader: "none",
models: [],
},
resolvedModel: "my-model",
log: null,
});
assert.equal(result.success, true);
assert.equal(captured.url, "http://localhost:11434/embeddings");
assert.equal(captured.headers.Authorization, undefined);
assert.deepEqual(captured.body, {
model: "my-model",
input: ["alpha", "beta"],
});
assert.equal(result.data.usage.total_tokens, 10);
} finally {
globalThis.fetch = originalFetch;
}
});
test("handleEmbedding rejects invalid model strings without provider prefix", async () => {
const result = await handleEmbedding({
body: { model: "not-a-known-embedding-model", input: "hello" },
credentials: { apiKey: "x" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 400);
assert.match(result.error, /Invalid embedding model/);
});
test("handleEmbedding rejects unknown providers", async () => {
const result = await handleEmbedding({
body: { model: "mystery/model-1", input: "hello" },
credentials: { apiKey: "x" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 400);
assert.match(result.error, /Unknown embedding provider: mystery/);
});
test("handleEmbedding requires credentials for authenticated providers", async () => {
const result = await handleEmbedding({
body: { model: "openai/text-embedding-3-small", input: "hello" },
credentials: null,
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 401);
assert.match(result.error, /No valid authentication token/);
});
test("handleEmbedding surfaces upstream failures", async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response("provider unavailable", {
status: 503,
headers: { "content-type": "text/plain" },
});
try {
const result = await handleEmbedding({
body: { model: "mistral/mistral-embed", input: "hello" },
credentials: { apiKey: "mistral-key" },
log: null,
});
assert.equal(result.success, false);
assert.equal(result.status, 503);
assert.equal(result.error, "provider unavailable");
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,79 @@
import test from "node:test";
import assert from "node:assert/strict";
const { EMERGENCY_FALLBACK_CONFIG, shouldUseFallback, isFallbackDecision } =
await import("../../open-sse/services/emergencyFallback.ts");
test("shouldUseFallback returns disabled when the feature flag is off", () => {
const result = shouldUseFallback(402, "payment required", false, {
...EMERGENCY_FALLBACK_CONFIG,
enabled: false,
});
assert.deepEqual(result, {
shouldFallback: false,
reason: "emergency fallback disabled",
});
assert.equal(isFallbackDecision(result), false);
});
test("shouldUseFallback skips tool requests when configured", () => {
const result = shouldUseFallback(402, "payment required", true);
assert.deepEqual(result, {
shouldFallback: false,
reason: "skipped: request has tools",
});
});
test("shouldUseFallback triggers on HTTP 402", () => {
const result = shouldUseFallback(402, "", false);
assert.equal(result.shouldFallback, true);
assert.equal(result.provider, EMERGENCY_FALLBACK_CONFIG.provider);
assert.equal(result.model, EMERGENCY_FALLBACK_CONFIG.model);
assert.equal(result.maxOutputTokens, EMERGENCY_FALLBACK_CONFIG.maxOutputTokens);
assert.equal(isFallbackDecision(result), true);
});
test("shouldUseFallback matches budget keywords case-insensitively", () => {
const result = shouldUseFallback(500, "Billing hard stop: OUT OF CREDITS", false);
assert.equal(result.shouldFallback, true);
assert.match(result.reason, /budget error detected/i);
assert.match(result.reason, /(billing|out of credits)/i);
});
test("shouldUseFallback ignores keywords when keyword matching is disabled", () => {
const result = shouldUseFallback(500, "quota_exceeded", false, {
...EMERGENCY_FALLBACK_CONFIG,
triggerOnBudgetKeywords: false,
});
assert.deepEqual(result, {
shouldFallback: false,
reason: "no budget error detected",
});
});
test("shouldUseFallback ignores HTTP 402 when status-trigger fallback is disabled", () => {
const result = shouldUseFallback(402, "", false, {
...EMERGENCY_FALLBACK_CONFIG,
triggerOn402: false,
});
assert.deepEqual(result, {
shouldFallback: false,
reason: "no budget error detected",
});
});
test("shouldUseFallback returns no fallback for unrelated errors", () => {
const result = shouldUseFallback(500, "temporary upstream timeout", false);
assert.deepEqual(result, {
shouldFallback: false,
reason: "no budget error detected",
});
assert.equal(isFallbackDecision(result), false);
});

View File

@@ -0,0 +1,155 @@
import test from "node:test";
import assert from "node:assert/strict";
import { AntigravityExecutor } from "../../open-sse/executors/antigravity.ts";
test("AntigravityExecutor.buildUrl always targets the streaming endpoint", () => {
const executor = new AntigravityExecutor();
assert.match(
executor.buildUrl("gemini-2.5-flash", true),
/\/v1internal:streamGenerateContent\?alt=sse$/
);
assert.equal(
executor.buildUrl("gemini-2.5-flash", false),
executor.buildUrl("gemini-2.5-flash", true)
);
});
test("AntigravityExecutor.buildHeaders includes auth and SSE accept", () => {
const executor = new AntigravityExecutor();
const headers = executor.buildHeaders({ accessToken: "ag-token" }, false);
assert.equal(headers.Authorization, "Bearer ag-token");
assert.equal(headers.Accept, "text/event-stream");
assert.equal(headers["X-OmniRoute-Source"], "omniroute");
});
test("AntigravityExecutor.transformRequest normalizes model, project and contents", async () => {
const executor = new AntigravityExecutor();
const body = {
request: {
contents: [
{
role: "model",
parts: [
{ thought: true, text: "skip me" },
{ thoughtSignature: "sig-only" },
{ text: "keep me" },
],
},
{
role: "model",
parts: [{ functionResponse: { name: "read_file", response: {} } }],
},
],
tools: [{ functionDeclarations: [{ name: "read_file" }] }],
},
};
const result = await executor.transformRequest("antigravity/gemini-3.1-pro", body, true, {
projectId: "project-1",
});
assert.equal(result.project, "project-1");
assert.equal(result.model, "gemini-3.1-pro-low");
assert.equal(result.userAgent, "antigravity");
assert.ok(result.request.sessionId);
assert.deepEqual(result.request.toolConfig, {
functionCallingConfig: { mode: "VALIDATED" },
});
assert.deepEqual(result.request.contents[0].parts, [{ text: "keep me" }]);
assert.equal(result.request.contents[1].role, "user");
});
test("AntigravityExecutor.transformRequest returns a structured error response when projectId is missing", async () => {
const executor = new AntigravityExecutor();
const result = await executor.transformRequest(
"gemini-2.5-flash",
{ request: { contents: [] } },
true,
{}
);
const payload = await result.json();
assert.equal(result.status, 422);
assert.equal(payload.error.code, "missing_project_id");
assert.match(payload.error.message, /Missing Google projectId/);
});
test("AntigravityExecutor parses retry timing from headers and error strings", () => {
const executor = new AntigravityExecutor();
const headers = new Headers({
"retry-after": "120",
"x-ratelimit-reset-after": "30",
});
assert.equal(executor.parseRetryHeaders(headers), 120_000);
assert.equal(
executor.parseRetryFromErrorMessage("Your quota will reset after 2h7m23s"),
7_643_000
);
});
test("AntigravityExecutor.collectStreamToResponse turns SSE Gemini chunks into a chat completion", async () => {
const executor = new AntigravityExecutor();
const response = new Response(
[
'data: {"response":{"candidates":[{"content":{"parts":[{"text":"Hello "}]},"finishReason":"STOP"}]}}\n\n',
'data: {"response":{"candidates":[{"content":{"parts":[{"text":"world"}]},"finishReason":"STOP"}],"usageMetadata":{"promptTokenCount":5,"candidatesTokenCount":3,"totalTokenCount":8}}}\n\n',
].join(""),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
const result = await executor.collectStreamToResponse(
response,
"gemini-2.5-flash",
"https://example.com",
{ Authorization: "Bearer ag-token" },
{ request: {} }
);
const payload = await result.response.json();
assert.equal(result.response.status, 200);
assert.equal(payload.object, "chat.completion");
assert.equal(payload.choices[0].message.content, "Hello world");
assert.equal(payload.choices[0].finish_reason, "stop");
assert.deepEqual(payload.usage, {
prompt_tokens: 5,
completion_tokens: 3,
total_tokens: 8,
});
});
test("AntigravityExecutor.refreshCredentials refreshes Google OAuth tokens", async () => {
const executor = new AntigravityExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
assert.match(String(url), /oauth2\.googleapis\.com\/token$/);
return new Response(
JSON.stringify({
access_token: "new-token",
refresh_token: "new-refresh",
expires_in: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
const result = await executor.refreshCredentials(
{ refreshToken: "refresh", projectId: "project-1" },
null
);
assert.deepEqual(result, {
accessToken: "new-token",
refreshToken: "new-refresh",
expiresIn: 3600,
projectId: "project-1",
});
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,132 @@
import test from "node:test";
import assert from "node:assert/strict";
import { CloudflareAIExecutor } from "../../open-sse/executors/cloudflare-ai.ts";
test("CloudflareAIExecutor.buildUrl prefers providerSpecificData.accountId", () => {
const executor = new CloudflareAIExecutor();
const url = executor.buildUrl("@cf/meta/llama-3.3-70b-instruct", true, 0, {
accountId: "top-level-id",
providerSpecificData: { accountId: "provider-id" },
});
assert.equal(
url,
"https://api.cloudflare.com/client/v4/accounts/provider-id/ai/v1/chat/completions"
);
});
test("CloudflareAIExecutor.buildUrl falls back to top-level credentials and environment", () => {
const executor = new CloudflareAIExecutor();
const originalAccountId = process.env.CLOUDFLARE_ACCOUNT_ID;
process.env.CLOUDFLARE_ACCOUNT_ID = "env-account-id";
try {
const fromTopLevel = executor.buildUrl("@cf/meta/llama-3.3-70b-instruct", false, 0, {
accountId: "top-level-id",
});
const fromEnv = executor.buildUrl("@cf/meta/llama-3.3-70b-instruct", false, 0, {});
assert.equal(
fromTopLevel,
"https://api.cloudflare.com/client/v4/accounts/top-level-id/ai/v1/chat/completions"
);
assert.equal(
fromEnv,
"https://api.cloudflare.com/client/v4/accounts/env-account-id/ai/v1/chat/completions"
);
} finally {
if (originalAccountId === undefined) delete process.env.CLOUDFLARE_ACCOUNT_ID;
else process.env.CLOUDFLARE_ACCOUNT_ID = originalAccountId;
}
});
test("CloudflareAIExecutor.buildUrl throws when account ID is missing", () => {
const executor = new CloudflareAIExecutor();
const originalAccountId = process.env.CLOUDFLARE_ACCOUNT_ID;
delete process.env.CLOUDFLARE_ACCOUNT_ID;
try {
assert.throws(
() => executor.buildUrl("@cf/meta/llama-3.3-70b-instruct", true, 0, {}),
/Account ID/
);
} finally {
if (originalAccountId === undefined) delete process.env.CLOUDFLARE_ACCOUNT_ID;
else process.env.CLOUDFLARE_ACCOUNT_ID = originalAccountId;
}
});
test("CloudflareAIExecutor.buildHeaders uses API key or access token and stream accept", () => {
const executor = new CloudflareAIExecutor();
const apiKeyHeaders = executor.buildHeaders({ apiKey: "cf-api-token" }, true);
const accessTokenHeaders = executor.buildHeaders({ accessToken: "cf-access-token" }, false);
assert.deepEqual(apiKeyHeaders, {
"Content-Type": "application/json",
Authorization: "Bearer cf-api-token",
Accept: "text/event-stream",
});
assert.deepEqual(accessTokenHeaders, {
"Content-Type": "application/json",
Authorization: "Bearer cf-access-token",
});
});
test("CloudflareAIExecutor.transformRequest is a passthrough for full model paths", () => {
const executor = new CloudflareAIExecutor();
const body = {
model: "@cf/meta/llama-3.3-70b-instruct",
messages: [{ role: "user", content: "hi" }],
};
assert.equal(executor.transformRequest("@cf/meta/llama-3.3-70b-instruct", body, true, {}), body);
});
test("CloudflareAIExecutor.execute uses inherited BaseExecutor flow successfully", async () => {
const executor = new CloudflareAIExecutor();
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options) => {
captured = { url: String(url), options };
return new Response(
JSON.stringify({
id: "chatcmpl-cf",
object: "chat.completion",
choices: [{ index: 0, message: { role: "assistant", content: "ok" } }],
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
};
try {
const body = {
model: "@cf/meta/llama-3.3-70b-instruct",
messages: [{ role: "user", content: "hello" }],
};
const result = await executor.execute({
model: "@cf/meta/llama-3.3-70b-instruct",
body,
stream: false,
credentials: {
apiKey: "cf-api-token",
providerSpecificData: { accountId: "account-123" },
},
});
assert.equal(result.response.status, 200);
assert.equal(
result.url,
"https://api.cloudflare.com/client/v4/accounts/account-123/ai/v1/chat/completions"
);
assert.equal(result.transformedBody, body);
assert.equal(captured.options.headers.Authorization, "Bearer cf-api-token");
assert.equal(captured.options.body, JSON.stringify(body));
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,153 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
CodexExecutor,
getCodexModelScope,
getCodexRateLimitKey,
getCodexResetTime,
parseCodexQuotaHeaders,
setDefaultFastServiceTierEnabled,
} from "../../open-sse/executors/codex.ts";
test("Codex helper functions isolate rate-limit scopes and parse quota headers", () => {
const quota = parseCodexQuotaHeaders(
new Headers({
"x-codex-5h-usage": "100",
"x-codex-5h-limit": "500",
"x-codex-5h-reset-at": new Date(Date.now() + 60_000).toISOString(),
"x-codex-7d-usage": "1000",
"x-codex-7d-limit": "5000",
"x-codex-7d-reset-at": new Date(Date.now() + 120_000).toISOString(),
})
);
assert.equal(getCodexModelScope("codex-spark-mini"), "spark");
assert.equal(getCodexModelScope("gpt-5.3-codex"), "codex");
assert.equal(getCodexRateLimitKey("acct-1", "codex-spark-mini"), "acct-1:spark");
assert.equal(quota.usage5h, 100);
assert.equal(quota.limit7d, 5000);
assert.ok(getCodexResetTime(quota) >= new Date(quota.resetAt7d).getTime());
});
test("CodexExecutor.buildUrl honors /responses subpaths and compact mode", () => {
const executor = new CodexExecutor();
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, {}),
"https://chatgpt.com/backend-api/codex/responses"
);
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, { requestEndpointPath: "/responses" }),
"https://chatgpt.com/backend-api/codex/responses"
);
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, { requestEndpointPath: "/responses/compact" }),
"https://chatgpt.com/backend-api/codex/responses/compact"
);
});
test("CodexExecutor.buildHeaders binds workspace ids and disables SSE accept for compact responses", () => {
const executor = new CodexExecutor();
const standardHeaders = executor.buildHeaders(
{
accessToken: "codex-token",
providerSpecificData: { workspaceId: "workspace-1" },
},
true
);
const compactHeaders = executor.buildHeaders(
{
accessToken: "codex-token",
requestEndpointPath: "/responses/compact",
},
true
);
assert.equal(standardHeaders.Authorization, "Bearer codex-token");
assert.equal(standardHeaders.Accept, "text/event-stream");
assert.equal(standardHeaders["chatgpt-account-id"], "workspace-1");
assert.equal(compactHeaders.Accept, undefined);
});
test("CodexExecutor.transformRequest injects default instructions, clamps reasoning and strips unsupported fields", () => {
const executor = new CodexExecutor();
const body = {
model: "gpt-5-mini",
messages: [{ role: "user", content: "hello" }],
prompt: "legacy",
stream_options: { include_usage: true },
instructions: "",
reasoning_effort: "xhigh",
service_tier: "fast",
temperature: 0.4,
user: "cursor",
};
const result = executor.transformRequest("gpt-5-mini-xhigh", body, false, {
requestEndpointPath: "/responses",
});
assert.equal(result.stream, true);
assert.equal(result.store, false);
assert.equal(result.instructions.length > 0, true);
assert.equal(result.reasoning.effort, "high");
assert.equal(result.service_tier, "priority");
assert.equal(result.messages, undefined);
assert.equal(result.prompt, undefined);
assert.equal(result.temperature, undefined);
assert.equal(result.user, undefined);
assert.equal(result.stream_options, undefined);
});
test("CodexExecutor.transformRequest preserves compact requests and native passthrough semantics", () => {
const executor = new CodexExecutor();
setDefaultFastServiceTierEnabled(true);
try {
const body = {
_nativeCodexPassthrough: true,
instructions: "keep this",
stream: false,
};
const result = executor.transformRequest("gpt-5.3-codex", body, false, {
requestEndpointPath: "/responses/compact",
});
assert.equal(result._nativeCodexPassthrough, undefined);
assert.equal(result.stream, undefined);
assert.equal(result.service_tier, "priority");
assert.equal(result.store, false);
assert.equal(result.instructions, "keep this");
} finally {
setDefaultFastServiceTierEnabled(false);
}
});
test("CodexExecutor.refreshCredentials refreshes OAuth tokens and returns null without a refresh token", async () => {
const executor = new CodexExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
assert.match(String(url), /auth\.openai\.com\/oauth\/token$/);
return new Response(
JSON.stringify({
access_token: "new-token",
refresh_token: "new-refresh",
expires_in: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
assert.equal(await executor.refreshCredentials({}, null), null);
const refreshed = await executor.refreshCredentials({ refreshToken: "refresh-me" }, null);
assert.deepEqual(refreshed, {
accessToken: "new-token",
refreshToken: "new-refresh",
expiresIn: 3600,
});
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,320 @@
import test from "node:test";
import assert from "node:assert/strict";
import { CursorExecutor } from "../../open-sse/executors/cursor.ts";
import {
decodeMessage,
encodeField,
parseConnectRPCFrame,
wrapConnectRPCFrame,
} from "../../open-sse/utils/cursorProtobuf.ts";
import {
generateCursorChecksum,
generateHashed64Hex,
generateSessionId,
} from "../../open-sse/utils/cursorChecksum.ts";
const LEN = 2;
const VARINT = 0;
const TOP_LEVEL_TOOL_CALL = 1;
const TOP_LEVEL_RESPONSE = 2;
const RESPONSE_TEXT = 1;
const TOOL_ID = 3;
const TOOL_NAME = 9;
const TOOL_RAW_ARGS = 10;
const TOOL_IS_LAST = 11;
function concatArrays(...arrays) {
const total = arrays.reduce((sum, array) => sum + array.length, 0);
const result = new Uint8Array(total);
let offset = 0;
for (const array of arrays) {
result.set(array, offset);
offset += array.length;
}
return result;
}
function buildTextFrame(text) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(TOP_LEVEL_RESPONSE, LEN, encodeField(RESPONSE_TEXT, LEN, text)),
false
)
);
}
function buildToolCallFrame({ id, name, args, isLast }) {
return Buffer.from(
wrapConnectRPCFrame(
encodeField(
TOP_LEVEL_TOOL_CALL,
LEN,
concatArrays(
encodeField(TOOL_ID, LEN, id),
encodeField(TOOL_NAME, LEN, name),
encodeField(TOOL_RAW_ARGS, LEN, args),
encodeField(TOOL_IS_LAST, VARINT, isLast ? 1 : 0)
)
),
false
)
);
}
function buildJsonErrorFrame(error) {
return Buffer.from(wrapConnectRPCFrame(new TextEncoder().encode(JSON.stringify(error)), false));
}
test("CursorExecutor.buildUrl uses the configured Cursor endpoint", () => {
const executor = new CursorExecutor();
assert.equal(
executor.buildUrl(),
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
});
test("CursorExecutor.buildHeaders strips token prefixes and derives checksum/session headers", () => {
const executor = new CursorExecutor();
const originalDateNow = Date.now;
Date.now = () => 1_700_000_000_000;
try {
const headers = executor.buildHeaders({
accessToken: "prefix::real-token",
providerSpecificData: { machineId: "machine-1", ghostMode: false },
});
assert.equal(headers.authorization, "Bearer real-token");
assert.equal(headers["x-client-key"], generateHashed64Hex("real-token"));
assert.equal(headers["x-session-id"], generateSessionId("real-token"));
assert.equal(headers["x-cursor-checksum"], generateCursorChecksum("machine-1"));
assert.equal(headers["x-ghost-mode"], "false");
assert.equal(headers["connect-protocol-version"], "1");
assert.match(headers["x-amzn-trace-id"], /^Root=/);
assert.ok(headers["x-request-id"]);
} finally {
Date.now = originalDateNow;
}
});
test("CursorExecutor.buildHeaders requires a machine ID", () => {
const executor = new CursorExecutor();
assert.throws(
() => executor.buildHeaders({ accessToken: "real-token", providerSpecificData: {} }),
/Machine ID is required/
);
});
test("CursorExecutor.transformRequest produces a framed protobuf payload", () => {
const executor = new CursorExecutor();
const transformed = executor.transformRequest(
"claude-3.5-sonnet",
{ messages: [{ role: "user", content: "Hello" }], tools: [] },
true,
{}
);
const frame = parseConnectRPCFrame(transformed);
const fields = decodeMessage(frame.payload);
assert.ok(transformed instanceof Uint8Array);
assert.equal(frame.flags, 0);
assert.equal(frame.consumed, transformed.length);
assert.equal(fields.has(1), true);
});
test("CursorExecutor.transformProtobufToJSON aggregates text and split tool call arguments", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToJSON(buffer, "cursor-small", body);
const payload = await response.json();
assert.equal(response.status, 200);
assert.equal(payload.object, "chat.completion");
assert.equal(payload.model, "cursor-small");
assert.equal(payload.choices[0].message.content, "Hello ");
assert.equal(payload.choices[0].finish_reason, "tool_calls");
assert.equal(payload.choices[0].message.tool_calls[0].function.name, "read_file");
assert.equal(payload.choices[0].message.tool_calls[0].function.arguments, '{"path":"/tmp/a"}');
assert.equal(payload.usage.estimated, true);
});
test("CursorExecutor.transformProtobufToSSE emits assistant chunks, tool deltas and DONE marker", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const buffer = Buffer.concat([
buildTextFrame("Hello "),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '{"path":',
isLast: false,
}),
buildToolCallFrame({
id: "call_1",
name: "read_file",
args: '"/tmp/a"}',
isLast: true,
}),
]);
const response = executor.transformProtobufToSSE(buffer, "cursor-small", body);
const text = await response.text();
assert.equal(response.status, 200);
assert.equal(response.headers.get("Content-Type"), "text/event-stream");
assert.match(text, /"role":"assistant","content":"Hello "/);
assert.match(text, /"tool_calls":\[/);
assert.match(text, /"name":"read_file"/);
assert.match(text, /"finish_reason":"tool_calls"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.transformProtobufToSSE converts JSON error frames into rate-limit responses", async () => {
const executor = new CursorExecutor();
const response = executor.transformProtobufToSSE(
buildJsonErrorFrame({
error: {
code: "resource_exhausted",
message: "rate limited",
details: [{ debug: { error: "LIMIT", details: { title: "Limit", detail: "Slow down" } } }],
},
}),
"cursor-small",
{ messages: [{ role: "user", content: "hi" }] }
);
const payload = await response.json();
assert.equal(response.status, 429);
assert.equal(payload.error.type, "rate_limit_error");
assert.equal(payload.error.message, "Limit");
assert.equal(payload.error.code, "LIMIT");
});
test("CursorExecutor.execute returns transformed JSON for non-stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello from Cursor")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(
result.url,
"https://api2.cursor.sh/aiserver.v1.ChatService/StreamUnifiedChatWithTools"
);
assert.equal(result.transformedBody, body);
assert.equal(result.headers.authorization, "Bearer token");
assert.equal(payload.object, "chat.completion");
assert.equal(payload.choices[0].message.content, "Hello from Cursor");
assert.equal(payload.choices[0].finish_reason, "stop");
});
test("CursorExecutor.execute returns transformed SSE for stream responses", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
const responseBuffer = Buffer.concat([buildTextFrame("Hello stream")]);
executor.makeHttp2Request = async () => ({
status: 200,
headers: {},
body: responseBuffer,
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: true,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const text = await result.response.text();
assert.equal(result.response.status, 200);
assert.match(text, /"content":"Hello stream"/);
assert.match(text, /\[DONE\]/);
});
test("CursorExecutor.execute maps non-200 upstream responses to OpenAI-style errors", async () => {
const executor = new CursorExecutor();
const body = { messages: [{ role: "user", content: "hi" }] };
executor.makeHttp2Request = async () => ({
status: 403,
headers: {},
body: Buffer.from("denied"),
});
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body,
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(result.response.status, 403);
assert.equal(payload.error.type, "invalid_request_error");
assert.match(payload.error.message, /\[403\]: denied/);
});
test("CursorExecutor.execute maps transport failures to connection_error and refreshCredentials returns null", async () => {
const executor = new CursorExecutor();
executor.makeHttp2Request = async () => {
throw new Error("socket hang up");
};
executor.makeFetchRequest = executor.makeHttp2Request;
const result = await executor.execute({
model: "cursor-small",
body: { messages: [{ role: "user", content: "hi" }] },
stream: false,
credentials: {
accessToken: "token",
providerSpecificData: { machineId: "machine-1" },
},
});
const payload = await result.response.json();
assert.equal(result.response.status, 500);
assert.equal(payload.error.type, "connection_error");
assert.equal(payload.error.message, "socket hang up");
assert.equal(await executor.refreshCredentials(), null);
});

View File

@@ -0,0 +1,470 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
applyConfiguredUserAgent,
BaseExecutor,
getCustomUserAgent,
mergeAbortSignals,
mergeUpstreamExtraHeaders,
setUserAgentHeader,
} from "../../open-sse/executors/base.ts";
import { DefaultExecutor } from "../../open-sse/executors/default.ts";
import { PROVIDERS } from "../../open-sse/config/constants.ts";
import {
CLAUDE_CODE_COMPATIBLE_ANTHROPIC_VERSION,
CLAUDE_CODE_COMPATIBLE_DEFAULT_CHAT_PATH,
} from "../../open-sse/services/claudeCodeCompatible.ts";
class TestExecutor extends BaseExecutor {
constructor(config = {}) {
super("test-provider", {
baseUrls: [
"https://primary.example/v1/chat/completions",
"https://fallback.example/v1/chat/completions",
],
headers: { "X-Test-Header": "base" },
...config,
});
}
async transformRequest(model, body, stream) {
return { ...body, transformed: true, model, stream };
}
}
test("BaseExecutor: openai-compatible buildUrl sanitizes custom chat paths", () => {
const executor = new BaseExecutor("openai-compatible-test", {});
const valid = executor.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: {
baseUrl: "https://proxy.example/v1/",
chatPath: "/custom/chat/completions",
},
});
const invalid = executor.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: {
baseUrl: "https://proxy.example/v1/",
chatPath: "../evil",
},
});
const invalidNullByte = executor.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: {
baseUrl: "https://proxy.example/v1/",
chatPath: "/ok\0evil",
},
});
assert.equal(valid, "https://proxy.example/v1/custom/chat/completions");
assert.equal(invalid, "https://proxy.example/v1/chat/completions");
assert.equal(invalidNullByte, "https://proxy.example/v1/chat/completions");
});
test("DefaultExecutor.buildUrl handles Gemini, Claude and Qwen variants", () => {
const gemini = new DefaultExecutor("gemini");
const claude = new DefaultExecutor("claude");
const qwen = new DefaultExecutor("qwen");
assert.equal(
gemini.buildUrl("gemini-2.5-flash", false),
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent"
);
assert.equal(
gemini.buildUrl("gemini-2.5-flash", true),
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse"
);
assert.equal(claude.buildUrl("claude-sonnet-4", true), `${PROVIDERS.claude.baseUrl}?beta=true`);
assert.equal(qwen.buildUrl("qwen3-coder", true), "https://portal.qwen.ai/v1/chat/completions");
assert.equal(
qwen.buildUrl("qwen3-coder", true, 0, {
providerSpecificData: { resourceUrl: "custom.qwen.ai" },
}),
"https://custom.qwen.ai/v1/chat/completions"
);
});
test("DefaultExecutor.buildUrl handles openai-compatible and anthropic-compatible providers", () => {
const openAICompat = new DefaultExecutor("openai-compatible-test");
const openAIResponsesCompat = new DefaultExecutor("openai-compatible-responses-test");
const anthropicCompat = new DefaultExecutor("anthropic-compatible-test");
const anthropicCcCompat = new DefaultExecutor("anthropic-compatible-cc-test");
assert.equal(
openAICompat.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: { baseUrl: "https://proxy.example/v1/" },
}),
"https://proxy.example/v1/chat/completions"
);
assert.equal(
openAICompat.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: {
baseUrl: "https://proxy.example/v1/",
chatPath: "/custom/chat",
},
}),
"https://proxy.example/v1/custom/chat"
);
assert.equal(
openAIResponsesCompat.buildUrl("gpt-4.1", true, 0, {
providerSpecificData: { baseUrl: "https://proxy.example/v1/" },
}),
"https://proxy.example/v1/responses"
);
assert.equal(
anthropicCompat.buildUrl("claude-sonnet-4", true, 0, {
providerSpecificData: { baseUrl: "https://anthropic.example/v1/" },
}),
"https://anthropic.example/v1/messages"
);
assert.equal(
anthropicCompat.buildUrl("claude-sonnet-4", true, 0, {
providerSpecificData: {
baseUrl: "https://anthropic.example/v1/",
chatPath: "/custom/messages",
},
}),
"https://anthropic.example/v1/custom/messages"
);
assert.equal(
anthropicCcCompat.buildUrl("claude-sonnet-4", true, 0, {
providerSpecificData: {
baseUrl: "https://cc.example/v1/messages",
},
}),
`https://cc.example${CLAUDE_CODE_COMPATIBLE_DEFAULT_CHAT_PATH}`
);
});
test("DefaultExecutor.buildUrl falls back to OpenAI config for unknown providers", () => {
const executor = new DefaultExecutor("unknown-provider");
assert.equal(executor.config.baseUrl, PROVIDERS.openai.baseUrl);
assert.equal(executor.buildUrl("gpt-4.1", true), PROVIDERS.openai.baseUrl);
});
test("DefaultExecutor.buildHeaders handles Gemini and Claude auth modes", () => {
const gemini = new DefaultExecutor("gemini");
const claude = new DefaultExecutor("claude");
const geminiApiKeyHeaders = gemini.buildHeaders({ apiKey: "gem-key" }, true);
const geminiOAuthHeaders = gemini.buildHeaders({ accessToken: "gem-token" }, false);
const claudeApiKeyHeaders = claude.buildHeaders({ apiKey: "claude-key" }, true);
const claudeOAuthHeaders = claude.buildHeaders({ accessToken: "claude-token" }, false);
assert.equal(geminiApiKeyHeaders["x-goog-api-key"], "gem-key");
assert.equal(geminiApiKeyHeaders.Accept, "text/event-stream");
assert.equal(geminiApiKeyHeaders.Authorization, undefined);
assert.equal(geminiOAuthHeaders.Authorization, "Bearer gem-token");
assert.equal(claudeApiKeyHeaders["x-api-key"], "claude-key");
assert.equal(claudeApiKeyHeaders.Accept, "text/event-stream");
assert.equal(claudeOAuthHeaders.Authorization, "Bearer claude-token");
assert.equal(claudeOAuthHeaders["x-api-key"], undefined);
});
test("DefaultExecutor.buildHeaders handles GLM, default auth and anthropic-compatible headers", () => {
const glm = new DefaultExecutor("glm");
const openai = new DefaultExecutor("openai");
const anthropicCompat = new DefaultExecutor("anthropic-compatible-test");
const glmHeaders = glm.buildHeaders({ accessToken: "glm-token" }, false);
const openaiHeaders = openai.buildHeaders({ apiKey: "sk-openai" }, true);
const anthropicHeaders = anthropicCompat.buildHeaders({ apiKey: "anth-key" }, true);
assert.equal(glmHeaders["x-api-key"], "glm-token");
assert.equal(openaiHeaders.Authorization, "Bearer sk-openai");
assert.equal(openaiHeaders.Accept, "text/event-stream");
assert.equal(anthropicHeaders["x-api-key"], "anth-key");
assert.equal(anthropicHeaders["anthropic-version"], "2023-06-01");
assert.equal(anthropicHeaders.Accept, "text/event-stream");
});
test("DefaultExecutor.buildHeaders strips DashScope headers for Qwen API keys and preserves them for OAuth", () => {
const executor = new DefaultExecutor("qwen");
const apiKeyHeaders = executor.buildHeaders({ apiKey: "dash-key" }, true);
const oauthHeaders = executor.buildHeaders({ accessToken: "oauth-token" }, true);
assert.equal(apiKeyHeaders.Authorization, "Bearer dash-key");
assert.equal(
Object.keys(apiKeyHeaders).some((key) => key.toLowerCase().startsWith("x-dashscope-")),
false
);
assert.equal(oauthHeaders.Authorization, "Bearer oauth-token");
assert.equal(oauthHeaders["X-Dashscope-AuthType"], "qwen-oauth");
assert.equal(oauthHeaders["X-Dashscope-CacheControl"], "enable");
});
test("DefaultExecutor.buildHeaders rotates extra API keys and builds Claude Code compatible headers", () => {
const openai = new DefaultExecutor("openai");
const cc = new DefaultExecutor("anthropic-compatible-cc-test");
const first = openai.buildHeaders(
{
apiKey: "primary",
connectionId: "conn-rotation",
providerSpecificData: { extraApiKeys: ["extra-1", "extra-2"] },
},
false
);
const second = openai.buildHeaders(
{
apiKey: "primary",
connectionId: "conn-rotation",
providerSpecificData: { extraApiKeys: ["extra-1", "extra-2"] },
},
false
);
const ccHeaders = cc.buildHeaders(
{
apiKey: "cc-key",
providerSpecificData: { ccSessionId: "session-1" },
},
true
);
assert.equal(first.Authorization, "Bearer primary");
assert.equal(second.Authorization, "Bearer extra-1");
assert.equal(ccHeaders["x-api-key"], "cc-key");
assert.equal(ccHeaders["anthropic-version"], CLAUDE_CODE_COMPATIBLE_ANTHROPIC_VERSION);
assert.equal(ccHeaders["X-Claude-Code-Session-Id"], "session-1");
assert.equal(ccHeaders.Accept, "text/event-stream");
});
test("DefaultExecutor.transformRequest is a passthrough and preserves model ids with slashes", () => {
const executor = new DefaultExecutor("openai");
const body = { model: "zai-org/GLM-5-FP8", messages: [{ role: "user", content: "hi" }] };
const result = executor.transformRequest("zai-org/GLM-5-FP8", body, true, {});
assert.equal(result, body);
assert.equal(result.model, "zai-org/GLM-5-FP8");
});
test("BaseExecutor helpers manage custom user agents and upstream extra headers", () => {
const headers = { "user-agent": "old", Authorization: "Bearer old" };
assert.equal(getCustomUserAgent({ customUserAgent: " MyAgent/1.0 " }), "MyAgent/1.0");
assert.equal(getCustomUserAgent({ customUserAgent: " " }), null);
setUserAgentHeader(headers, "MyAgent/2.0");
assert.equal(headers["User-Agent"], "MyAgent/2.0");
assert.equal(headers["user-agent"], "MyAgent/2.0");
applyConfiguredUserAgent(headers, { customUserAgent: "MyAgent/3.0" });
assert.equal(headers["User-Agent"], "MyAgent/3.0");
mergeUpstreamExtraHeaders(headers, {
Authorization: "Bearer override",
"user-agent": "Merged/4.0",
"X-Upstream": "1",
});
assert.equal(headers.Authorization, "Bearer override");
assert.equal(headers["User-Agent"], "Merged/4.0");
assert.equal(headers["user-agent"], "Merged/4.0");
assert.equal(headers["X-Upstream"], "1");
});
test("BaseExecutor.mergeAbortSignals aborts when either source signal aborts", () => {
const primary = new AbortController();
const secondary = new AbortController();
const merged = mergeAbortSignals(primary.signal, secondary.signal);
assert.equal(merged.aborted, false);
primary.abort();
assert.equal(merged.aborted, true);
const otherPrimary = new AbortController();
const otherSecondary = new AbortController();
const merged2 = mergeAbortSignals(otherPrimary.signal, otherSecondary.signal);
otherSecondary.abort();
assert.equal(merged2.aborted, true);
});
test("BaseExecutor.needsRefresh returns true only when expiry is near", () => {
const executor = new TestExecutor();
const soon = new Date(Date.now() + 60_000).toISOString();
const later = new Date(Date.now() + 60 * 60 * 1000).toISOString();
assert.equal(executor.needsRefresh({ expiresAt: soon }), true);
assert.equal(executor.needsRefresh({ expiresAt: later }), false);
assert.equal(executor.needsRefresh({}), false);
});
test("DefaultExecutor.refreshCredentials returns null without refresh token", async () => {
const executor = new DefaultExecutor("gemini");
const result = await executor.refreshCredentials({}, null);
assert.equal(result, null);
});
test("DefaultExecutor.refreshCredentials delegates to OAuth refresh and returns new tokens", async () => {
const executor = new DefaultExecutor("gemini");
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => {
assert.match(String(url), /oauth2\.googleapis\.com/);
assert.equal(options.method, "POST");
return new Response(
JSON.stringify({
access_token: "new-access-token",
refresh_token: "new-refresh-token",
expires_in: 3600,
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
};
try {
const result = await executor.refreshCredentials({ refreshToken: "refresh-me" }, null);
assert.deepEqual(result, {
accessToken: "new-access-token",
refreshToken: "new-refresh-token",
expiresIn: 3600,
});
} finally {
globalThis.fetch = originalFetch;
}
});
test("DefaultExecutor.refreshCredentials swallows refresh errors and logs them", async () => {
const executor = new DefaultExecutor("gemini");
const originalFetch = globalThis.fetch;
const messages = [];
globalThis.fetch = async () => {
throw new Error("network down");
};
try {
const result = await executor.refreshCredentials(
{ refreshToken: "refresh-me" },
{ error: (tag, message) => messages.push({ tag, message }) }
);
assert.equal(result, null);
assert.equal(messages.length, 1);
assert.match(messages[0].message, /refresh error: network down/);
} finally {
globalThis.fetch = originalFetch;
}
});
test("BaseExecutor.execute returns response metadata and merges headers", async () => {
const executor = new TestExecutor();
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options) => {
captured = { url, options };
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
try {
const result = await executor.execute({
model: "gpt-4.1",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: {
apiKey: "base-key",
providerSpecificData: { customUserAgent: "CredsAgent/1.0" },
},
upstreamExtraHeaders: {
Authorization: "Bearer override",
"user-agent": "UpstreamAgent/2.0",
"X-Trace-Id": "trace-1",
},
});
assert.equal(result.url, "https://primary.example/v1/chat/completions");
assert.equal(result.response.status, 200);
assert.equal(result.transformedBody.transformed, true);
assert.equal(result.transformedBody.model, "gpt-4.1");
assert.equal(result.headers.Authorization, "Bearer override");
assert.equal(result.headers["User-Agent"], "UpstreamAgent/2.0");
assert.equal(result.headers["user-agent"], undefined);
assert.equal(result.headers["X-Trace-Id"], "trace-1");
assert.equal(result.headers.Accept, "text/event-stream");
assert.equal(captured.options.body.includes('"transformed":true'), true);
} finally {
globalThis.fetch = originalFetch;
}
});
test("BaseExecutor.execute falls back to the next base URL after a transport error", async () => {
const executor = new TestExecutor();
const originalFetch = globalThis.fetch;
const calls = [];
globalThis.fetch = async (url) => {
calls.push(String(url));
if (calls.length === 1) {
throw new Error("first node down");
}
return new Response("ok", { status: 200 });
};
try {
const result = await executor.execute({
model: "gpt-4.1",
body: { hello: "world" },
stream: false,
credentials: {},
});
assert.deepEqual(calls, [
"https://primary.example/v1/chat/completions",
"https://fallback.example/v1/chat/completions",
]);
assert.equal(result.url, "https://fallback.example/v1/chat/completions");
} finally {
globalThis.fetch = originalFetch;
}
});
test("BaseExecutor.execute throws the last error when all URLs fail", async () => {
const executor = new TestExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => {
throw new Error("still down");
};
try {
await assert.rejects(
executor.execute({
model: "gpt-4.1",
body: {},
stream: false,
credentials: {},
}),
/still down/
);
} finally {
globalThis.fetch = originalFetch;
}
});
test("BaseExecutor.execute propagates aborted requests through the merged signal", async () => {
const executor = new TestExecutor({ baseUrls: ["https://single.example/v1/chat/completions"] });
const controller = new AbortController();
controller.abort();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => {
assert.equal(options.signal.aborted, true);
const error = new Error(`aborted ${url}`);
error.name = "AbortError";
throw error;
};
try {
await assert.rejects(
executor.execute({
model: "gpt-4.1",
body: {},
stream: false,
credentials: {},
signal: controller.signal,
}),
/aborted/
);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,97 @@
import test from "node:test";
import assert from "node:assert/strict";
import { GeminiCLIExecutor } from "../../open-sse/executors/gemini-cli.ts";
test("GeminiCLIExecutor.buildUrl and buildHeaders match the native Gemini CLI fingerprint", () => {
const executor = new GeminiCLIExecutor();
assert.equal(
executor.buildUrl("gemini-2.5-flash", true),
"https://cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse"
);
assert.equal(
executor.buildUrl("gemini-2.5-flash", false),
"https://cloudcode-pa.googleapis.com/v1internal:generateContent"
);
const headers = executor.buildHeaders({ accessToken: "gcli-token" }, true);
assert.equal(headers.Authorization, "Bearer gcli-token");
assert.equal(headers.Accept, "text/event-stream");
assert.match(headers["User-Agent"], /GeminiCLI/);
assert.match(headers["X-Goog-Api-Client"], /google-genai-sdk/);
});
test("GeminiCLIExecutor.refreshProject caches loadCodeAssist lookups and transformRequest updates body.project", async () => {
const executor = new GeminiCLIExecutor();
const originalFetch = globalThis.fetch;
let calls = 0;
globalThis.fetch = async (url) => {
calls += 1;
assert.match(String(url), /loadCodeAssist$/);
return new Response(JSON.stringify({ cloudaicompanionProject: "fresh-project-id" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
try {
const first = await executor.refreshProject("access-token-1");
const second = await executor.refreshProject("access-token-1");
const body = { project: "stale-project", request: { contents: [] } };
const transformed = await executor.transformRequest("gemini-2.5-flash", body, true, {
accessToken: "access-token-1",
});
assert.equal(first, "fresh-project-id");
assert.equal(second, "fresh-project-id");
assert.equal(calls, 1);
assert.equal(transformed.project, "fresh-project-id");
} finally {
globalThis.fetch = originalFetch;
}
});
test("GeminiCLIExecutor.refreshProject returns null on failed loadCodeAssist responses", async () => {
const executor = new GeminiCLIExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async () => new Response("forbidden", { status: 403 });
try {
assert.equal(await executor.refreshProject("access-token-2"), null);
} finally {
globalThis.fetch = originalFetch;
}
});
test("GeminiCLIExecutor.refreshCredentials exchanges refresh tokens via Google OAuth", async () => {
const executor = new GeminiCLIExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
assert.match(String(url), /oauth2\.googleapis\.com\/token$/);
return new Response(
JSON.stringify({
access_token: "new-access-token",
refresh_token: "new-refresh-token",
expires_in: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
const result = await executor.refreshCredentials(
{ refreshToken: "refresh", projectId: "project-1" },
null
);
assert.deepEqual(result, {
accessToken: "new-access-token",
refreshToken: "new-refresh-token",
expiresIn: 3600,
projectId: "project-1",
});
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,221 @@
import test from "node:test";
import assert from "node:assert/strict";
import { GithubExecutor } from "../../open-sse/executors/github.ts";
import { PROVIDER_MODELS } from "../../open-sse/config/providerModels.ts";
function registerModel(provider, model) {
PROVIDER_MODELS[provider] = [...(PROVIDER_MODELS[provider] || []), model];
}
test("GithubExecutor.buildUrl routes response-format models to /responses", () => {
const originalModels = [...(PROVIDER_MODELS.gh || [])];
registerModel("gh", {
id: "gpt-4.1-responses",
name: "GPT 4.1 Responses",
targetFormat: "openai-responses",
});
try {
const executor = new GithubExecutor();
const url = executor.buildUrl("gpt-4.1-responses", true);
assert.equal(url, "https://api.githubcopilot.com/responses");
} finally {
PROVIDER_MODELS.gh = originalModels;
}
});
test("GithubExecutor.transformRequest injects JSON response instructions for Claude and strips reasoning fields", () => {
const executor = new GithubExecutor();
const body = {
response_format: {
type: "json_object",
},
messages: [
{ role: "user", content: "Return JSON" },
{
role: "assistant",
content: "draft",
reasoning_text: "internal",
reasoning_content: "internal",
},
],
};
const result = executor.transformRequest("claude-sonnet-4", body, true, {});
assert.equal(result.response_format, undefined);
assert.equal(result.messages[0].role, "system");
assert.match(result.messages[0].content, /Respond only with valid JSON/);
assert.equal(result.messages[2].reasoning_text, undefined);
assert.equal(result.messages[2].reasoning_content, undefined);
});
test("GithubExecutor.buildHeaders prefers Copilot token and sets GitHub-specific headers", () => {
const executor = new GithubExecutor();
const headers = executor.buildHeaders(
{
accessToken: "gh-access-token",
providerSpecificData: { copilotToken: "copilot-token" },
},
true
);
assert.equal(headers.Authorization, "Bearer copilot-token");
assert.equal(headers.Accept, "text/event-stream");
assert.equal(headers["x-github-api-version"], "2025-04-01");
assert.equal(headers["openai-intent"], "conversation-panel");
assert.ok(headers["x-request-id"]);
});
test("GithubExecutor.refreshCredentials returns Copilot token directly when available", async () => {
const executor = new GithubExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => {
assert.match(String(url), /copilot_internal\/v2\/token$/);
assert.equal(options.headers.Authorization, "token gh-access-token");
return new Response(
JSON.stringify({
token: "copilot-token",
expires_at: 1_777_777_777,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
const result = await executor.refreshCredentials({ accessToken: "gh-access-token" }, null);
assert.deepEqual(result, {
accessToken: "gh-access-token",
refreshToken: undefined,
copilotToken: "copilot-token",
copilotTokenExpiresAt: 1_777_777_777,
providerSpecificData: {
copilotToken: "copilot-token",
copilotTokenExpiresAt: 1_777_777_777,
},
});
} finally {
globalThis.fetch = originalFetch;
}
});
test("GithubExecutor.refreshCredentials falls back to GitHub OAuth refresh before retrying Copilot", async () => {
const executor = new GithubExecutor();
const originalFetch = globalThis.fetch;
const calls = [];
globalThis.fetch = async (url, options = {}) => {
calls.push(String(url));
if (String(url).includes("/copilot_internal/v2/token") && calls.length === 1) {
return new Response("unauthorized", { status: 401 });
}
if (String(url).includes("/oauth/access_token")) {
return new Response(
JSON.stringify({
access_token: "new-gh-token",
refresh_token: "new-refresh-token",
expires_in: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
if (String(url).includes("/copilot_internal/v2/token")) {
assert.equal(options.headers.Authorization, "token new-gh-token");
return new Response(
JSON.stringify({
token: "new-copilot-token",
expires_at: 1_888_888_888,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
}
throw new Error(`unexpected url: ${url}`);
};
try {
const result = await executor.refreshCredentials(
{
accessToken: "old-gh-token",
refreshToken: "refresh-token",
},
null
);
assert.deepEqual(result, {
accessToken: "new-gh-token",
refreshToken: "new-refresh-token",
expiresIn: 3600,
copilotToken: "new-copilot-token",
copilotTokenExpiresAt: 1_888_888_888,
providerSpecificData: {
copilotToken: "new-copilot-token",
copilotTokenExpiresAt: 1_888_888_888,
},
});
} finally {
globalThis.fetch = originalFetch;
}
});
test("GithubExecutor.needsRefresh checks missing and expiring Copilot tokens", () => {
const executor = new GithubExecutor();
assert.equal(executor.needsRefresh({}), true);
assert.equal(
executor.needsRefresh({
providerSpecificData: {
copilotToken: "copilot-token",
copilotTokenExpiresAt: Math.floor((Date.now() + 60_000) / 1000),
},
}),
true
);
assert.equal(
executor.needsRefresh({
providerSpecificData: {
copilotToken: "copilot-token",
copilotTokenExpiresAt: Math.floor((Date.now() + 60 * 60 * 1000) / 1000),
},
}),
false
);
});
test("GithubExecutor.execute strips terminal [DONE] frames from SSE responses", async () => {
const executor = new GithubExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async () =>
new Response(
new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode('data: {"chunk":"one"}\n\n'));
controller.enqueue(new TextEncoder().encode("data: [DONE]\n\n"));
controller.close();
},
}),
{
status: 200,
headers: { "Content-Type": "text/event-stream" },
}
);
try {
const result = await executor.execute({
model: "gpt-4.1",
body: { messages: [{ role: "user", content: "hi" }] },
stream: true,
credentials: { accessToken: "gh-access-token" },
});
const text = await result.response.text();
assert.match(text, /"chunk":"one"/);
assert.doesNotMatch(text, /\[DONE\]/);
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,109 @@
import test from "node:test";
import assert from "node:assert/strict";
import { KiroExecutor } from "../../open-sse/executors/kiro.ts";
test("KiroExecutor.buildHeaders includes Kiro-specific auth and metadata", () => {
const executor = new KiroExecutor();
const headers = executor.buildHeaders({ accessToken: "kiro-token" }, true);
assert.equal(headers.Authorization, "Bearer kiro-token");
assert.equal(headers["anthropic-beta"], "prompt-caching-2024-07-31");
assert.equal(headers["x-amzn-bedrock-cache-control"], "enable");
assert.ok(headers["Amz-Sdk-Invocation-Id"]);
});
test("KiroExecutor.transformRequest removes the top-level model field", () => {
const executor = new KiroExecutor();
const body = {
model: "kiro-model",
conversationState: {
currentMessage: {
userInputMessage: {
modelId: "kiro-model",
},
},
},
};
const result = executor.transformRequest("kiro-model", body, true, {});
assert.equal("model" in result, false);
assert.equal(result.conversationState.currentMessage.userInputMessage.modelId, "kiro-model");
});
test("KiroExecutor.execute returns upstream errors directly and transforms successful streams", async () => {
const executor = new KiroExecutor();
const originalFetch = globalThis.fetch;
const rawResponse = new Response("ok", { status: 200 });
let transformed = null;
executor.transformEventStreamToSSE = (response, model) => {
transformed = { response, model };
return new Response("data: [DONE]\n\n", {
status: 200,
headers: { "Content-Type": "text/event-stream" },
});
};
globalThis.fetch = async () => new Response("upstream error", { status: 429 });
try {
const errorResult = await executor.execute({
model: "kiro-model",
body: { conversationState: {} },
stream: true,
credentials: { accessToken: "kiro-token" },
});
assert.equal(errorResult.response.status, 429);
} finally {
globalThis.fetch = originalFetch;
}
globalThis.fetch = async () => rawResponse;
try {
const successResult = await executor.execute({
model: "kiro-model",
body: { conversationState: {} },
stream: true,
credentials: { accessToken: "kiro-token" },
});
assert.equal(successResult.response.status, 200);
assert.equal(transformed.response, rawResponse);
assert.equal(transformed.model, "kiro-model");
} finally {
globalThis.fetch = originalFetch;
}
});
test("KiroExecutor.refreshCredentials handles missing and AWS-style refresh tokens", async () => {
const executor = new KiroExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
assert.match(String(url), /oidc\.us-east-1\.amazonaws\.com\/token$/);
return new Response(
JSON.stringify({
accessToken: "new-access-token",
refreshToken: "new-refresh-token",
expiresIn: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
assert.equal(await executor.refreshCredentials({}, null), null);
const result = await executor.refreshCredentials(
{
refreshToken: "refresh",
providerSpecificData: { clientId: "client", clientSecret: "secret" },
},
null
);
assert.deepEqual(result, {
accessToken: "new-access-token",
refreshToken: "new-refresh-token",
expiresIn: 3600,
});
} finally {
globalThis.fetch = originalFetch;
}
});

View File

@@ -0,0 +1,34 @@
import test from "node:test";
import assert from "node:assert/strict";
import { PollinationsExecutor } from "../../open-sse/executors/pollinations.ts";
test("PollinationsExecutor.buildUrl uses the free Pollinations endpoint", () => {
const executor = new PollinationsExecutor();
assert.equal(
executor.buildUrl("openai", true),
"https://text.pollinations.ai/openai/chat/completions"
);
});
test("PollinationsExecutor.buildHeaders omits auth when no key is present", () => {
const executor = new PollinationsExecutor();
assert.deepEqual(executor.buildHeaders({}, true), {
"Content-Type": "application/json",
Accept: "text/event-stream",
});
});
test("PollinationsExecutor.buildHeaders supports optional API auth", () => {
const executor = new PollinationsExecutor();
assert.deepEqual(executor.buildHeaders({ apiKey: "poll-key" }, false), {
"Content-Type": "application/json",
Authorization: "Bearer poll-key",
});
});
test("PollinationsExecutor.transformRequest is a passthrough for alias models", () => {
const executor = new PollinationsExecutor();
const body = { model: "claude", messages: [{ role: "user", content: "hello" }] };
assert.equal(executor.transformRequest("claude", body, true, {}), body);
});

View File

@@ -0,0 +1,71 @@
import test from "node:test";
import assert from "node:assert/strict";
import { PuterExecutor } from "../../open-sse/executors/puter.ts";
test("PuterExecutor.buildUrl always uses Puter OpenAI endpoint", () => {
const executor = new PuterExecutor();
assert.equal(
executor.buildUrl("gpt-4.1", true),
"https://api.puter.com/puterai/openai/v1/chat/completions"
);
});
test("PuterExecutor.buildHeaders supports API key, access token and optional SSE accept", () => {
const executor = new PuterExecutor();
const apiKeyHeaders = executor.buildHeaders({ apiKey: "puter-key" }, true);
const accessTokenHeaders = executor.buildHeaders({ accessToken: "puter-token" }, false);
assert.deepEqual(apiKeyHeaders, {
"Content-Type": "application/json",
Authorization: "Bearer puter-key",
Accept: "text/event-stream",
});
assert.deepEqual(accessTokenHeaders, {
"Content-Type": "application/json",
Authorization: "Bearer puter-token",
});
});
test("PuterExecutor.transformRequest is a passthrough", () => {
const executor = new PuterExecutor();
const body = {
model: "google/gemini-2.5-pro",
messages: [{ role: "user", content: "hello" }],
};
assert.equal(executor.transformRequest(body.model, body, true, {}), body);
});
test("PuterExecutor.execute uses inherited BaseExecutor flow", async () => {
const executor = new PuterExecutor();
const originalFetch = globalThis.fetch;
let captured;
globalThis.fetch = async (url, options) => {
captured = { url: String(url), options };
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
};
try {
const body = {
model: "google/gemini-2.5-pro",
messages: [{ role: "user", content: "hello" }],
};
const result = await executor.execute({
model: body.model,
body,
stream: false,
credentials: { apiKey: "puter-key" },
});
assert.equal(result.response.status, 200);
assert.equal(result.transformedBody, body);
assert.equal(result.url, "https://api.puter.com/puterai/openai/v1/chat/completions");
assert.equal(captured.options.headers.Authorization, "Bearer puter-key");
assert.equal(captured.options.body, JSON.stringify(body));
} finally {
globalThis.fetch = originalFetch;
}
});

Some files were not shown because too many files have changed in this diff Show More