From 1dc2e4fffd4de65acc0a4e6331ec77f391441daf Mon Sep 17 00:00:00 2001 From: backryun Date: Wed, 12 Aug 2026 03:43:08 -0300 Subject: [PATCH] fix(ci): clear base-red typecheck + migration collisions on release/v3.8.50 Resolve 13 typecheck:core errors (deepai executor/import, responseSanitizer cached_tokens typing, search.ts token headers, usageTracking duplicate props, modelCapabilityOverrideKey max_token, executeWebSearch null) and remove the stale duplicate 143_job_registry.sql (canonical is 146_job_registry per RENAMED_MIGRATION_COMPATIBILITY), freeing the 147 KNOWN_GAPS entry. Base-reds tracked by #9985. --- .../config/providers/registry/deepai/index.ts | 3 +- open-sse/handlers/responseSanitizer.ts | 4 +- open-sse/handlers/search.ts | 6 +-- open-sse/utils/usageTracking.ts | 2 - scripts/check/check-migration-numbering.mjs | 2 +- src/lib/db/migrations/143_job_registry.sql | 48 ------------------- src/lib/db/modelCapabilityOverrides.ts | 4 +- src/lib/search/executeWebSearch.ts | 2 +- 8 files changed, 11 insertions(+), 60 deletions(-) delete mode 100644 src/lib/db/migrations/143_job_registry.sql diff --git a/open-sse/config/providers/registry/deepai/index.ts b/open-sse/config/providers/registry/deepai/index.ts index 67442a56f0..545d4ef6f4 100644 --- a/open-sse/config/providers/registry/deepai/index.ts +++ b/open-sse/config/providers/registry/deepai/index.ts @@ -1,4 +1,4 @@ -import type { RegistryEntry } from "../shared"; +import type { RegistryEntry } from "../../shared"; export const deepaiProvider: RegistryEntry = { id: "deepai", @@ -7,6 +7,7 @@ export const deepaiProvider: RegistryEntry = { baseUrl: "https://api.deepai.org", authType: "apikey", authHeader: "api-key", + executor: "default", models: [ { id: "text2img", name: "Text to Image" }, ], diff --git a/open-sse/handlers/responseSanitizer.ts b/open-sse/handlers/responseSanitizer.ts index 4ef3e20973..fcaa5677fb 100644 --- a/open-sse/handlers/responseSanitizer.ts +++ b/open-sse/handlers/responseSanitizer.ts @@ -537,7 +537,7 @@ function sanitizeResponsesUsage(usage: unknown): unknown { // DeepSeek native API: map flat prompt_cache_hit_tokens into input_tokens_details if ( normalized.prompt_cache_hit_tokens !== undefined && - !normalized.input_tokens_details?.cached_tokens + !(toRecord(normalized.input_tokens_details) ?? {}).cached_tokens ) { normalized.input_tokens_details = { ...(normalized.input_tokens_details as Record || {}), @@ -549,7 +549,7 @@ function sanitizeResponsesUsage(usage: unknown): unknown { if ( normalized.cache_read_input_tokens !== undefined && normalized.cache_read_input_tokens !== 0 && - !normalized.input_tokens_details?.cached_tokens + !(toRecord(normalized.input_tokens_details) ?? {}).cached_tokens ) { normalized.input_tokens_details = { ...(normalized.input_tokens_details as Record || {}), diff --git a/open-sse/handlers/search.ts b/open-sse/handlers/search.ts index bad08b9998..366ae0014d 100644 --- a/open-sse/handlers/search.ts +++ b/open-sse/handlers/search.ts @@ -304,7 +304,7 @@ function buildSerperRequest( url: `${config.baseUrl}${endpoint}`, init: { method: "POST", - headers: { "Content-Type": "application/json", "X-API-Key": params.token }, + headers: { "Content-Type": "application/json", ...(params.token ? { "X-API-Key": params.token } : {}) }, body: JSON.stringify(body), }, }; @@ -322,7 +322,7 @@ function buildBraveRequest( url: `${config.baseUrl}${endpoint}?${qp}`, init: { method: "GET", - headers: { Accept: "application/json", "X-Subscription-Token": params.token }, + headers: { Accept: "application/json", ...(params.token ? { "X-Subscription-Token": params.token } : {}) }, }, }; } @@ -348,7 +348,7 @@ function buildExaRequest( url: config.baseUrl, init: { method: "POST", - headers: { "Content-Type": "application/json", "x-api-key": params.token }, + headers: { "Content-Type": "application/json", ...(params.token ? { "x-api-key": params.token } : {}) }, body: JSON.stringify(body), }, }; diff --git a/open-sse/utils/usageTracking.ts b/open-sse/utils/usageTracking.ts index e2abc2a67d..b2360f7d58 100644 --- a/open-sse/utils/usageTracking.ts +++ b/open-sse/utils/usageTracking.ts @@ -665,8 +665,6 @@ export function extractUsage(chunk) { chunk.usage.reasoning_tokens, // xAI's exact provider-reported cost (port of decolua/9router#2453, capability A). cost_in_usd_ticks: chunk.usage.cost_in_usd_ticks, - cache_read_input_tokens: chunk.usage.cache_read_input_tokens, - cache_creation_input_tokens: chunk.usage.cache_creation_input_tokens, }); } diff --git a/scripts/check/check-migration-numbering.mjs b/scripts/check/check-migration-numbering.mjs index 9a64c2da33..9944b49f0a 100644 --- a/scripts/check/check-migration-numbering.mjs +++ b/scripts/check/check-migration-numbering.mjs @@ -51,7 +51,7 @@ export const KNOWN_DUPLICATE_VERSIONS = new Set([ // O stale-enforcement exige que cada reserva seja removida quando os arquivos // correspondentes aterrissarem na release. // --------------------------------------------------------------------------- -export const KNOWN_GAPS = new Set(["026", "055", "121", "144", "145", "147", "148", "149"]); // 121: número queimado no ciclo v3.8.47 — 122 (#6909) mergeou antes e 121 nunca aterrissou (validação e2e 2026-07-12) +export const KNOWN_GAPS = new Set(["026", "055", "121", "144", "145", "148", "149"]); // 121: número queimado no ciclo v3.8.47 — 122 (#6909) mergeou antes e 121 nunca aterrissou (validação e2e 2026-07-12) function pad3(n) { return String(n).padStart(3, "0"); diff --git a/src/lib/db/migrations/143_job_registry.sql b/src/lib/db/migrations/143_job_registry.sql deleted file mode 100644 index 3bf29ac3d2..0000000000 --- a/src/lib/db/migrations/143_job_registry.sql +++ /dev/null @@ -1,48 +0,0 @@ --- Migration 139: generic job registry (jobs + job_runs tables) --- Job registry (#8848): centralized periodic-job scheduling + run history. --- --- jobs: one row per registered job (interval or cron), with env-flag gating --- job_runs: one row per execution (running/success/failure), pruned by count + age - -CREATE TABLE IF NOT EXISTS jobs ( - id TEXT PRIMARY KEY, - type TEXT NOT NULL DEFAULT 'interval' CHECK(type IN ('interval', 'cron')), - cron TEXT, -- cron expression (type='cron'); NULL for interval jobs - interval_ms INTEGER, -- interval in ms (type='interval'); NULL for cron jobs - enabled INTEGER NOT NULL DEFAULT 1, -- 0=disabled, 1=enabled - env_flag TEXT, -- env var name (boolean gate), e.g. 'OMNIROUTE_WARMUP_ENABLED'; NULL = no gate - config TEXT NOT NULL DEFAULT '{}', -- JSON config (concurrency, timezone, envDefault, ...) - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')) -); - -CREATE TABLE IF NOT EXISTS job_runs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE, - started_at TEXT NOT NULL, -- ISO-8601, written explicitly by recordRun (no DB default) - finished_at TEXT, -- ISO-8601; NULL while running - status TEXT NOT NULL DEFAULT 'running', -- 'running' | 'success' | 'failure' - error_message TEXT, -- sanitized error message (no stack trace) - records_affected INTEGER DEFAULT 0, -- job-specific meaning (see below) - duration_ms INTEGER, -- execution duration in ms - created_at TEXT NOT NULL DEFAULT (datetime('now')) -); -CREATE INDEX IF NOT EXISTS idx_jr_job_id ON job_runs(job_id, started_at DESC); -CREATE INDEX IF NOT EXISTS idx_jr_started_at ON job_runs(started_at); - --- Built-in job registration (idempotent - INSERT OR IGNORE). --- env_flag = NULL means "no registry-level boolean gate"; per-job disable semantics --- live inside the handler itself (see token_health_check wrapper). --- 'warmup' is seeded disabled because its handler is not part of this change. --- startAll() filters on enabled before it looks for a handler, so a disabled row --- stays quiet instead of warning on every boot; the change that brings the warmup --- handler flips it on. -INSERT OR IGNORE INTO jobs (id, type, cron, interval_ms, enabled, env_flag, config) VALUES - ('budget_reset', 'interval', NULL, 600000, 1, NULL, '{}'), - ('warmup', 'cron', '0 7 * * *', NULL, 0, 'OMNIROUTE_WARMUP_ENABLED', '{"timezone":"America/Los_Angeles","envDefault":false}'), - ('token_health_check', 'interval', NULL, 60000, 1, NULL, '{}'); - --- records_affected semantics: --- budget_reset = number of budget records reset (UPDATE ... SET budget_used=0 row count) --- warmup = number of connections attempted for warmup --- token_health_check = number of connections swept by the health check diff --git a/src/lib/db/modelCapabilityOverrides.ts b/src/lib/db/modelCapabilityOverrides.ts index 686bf71228..689648568a 100644 --- a/src/lib/db/modelCapabilityOverrides.ts +++ b/src/lib/db/modelCapabilityOverrides.ts @@ -1,7 +1,7 @@ import { getDbInstance } from "./core"; import { invalidateDbCache } from "./readCache"; -export type ModelCapabilityOverrideKey = "max_input_tokens" | "max_output_tokens"; +export type ModelCapabilityOverrideKey = "max_input_tokens" | "max_output_tokens" | "max_token"; export interface ModelCapabilityOverride { provider: string; @@ -21,7 +21,7 @@ interface OverrideRow { } function isSupportedKey(value: unknown): value is ModelCapabilityOverrideKey { - return value === "max_input_tokens" || value === "max_output_tokens"; + return value === "max_input_tokens" || value === "max_output_tokens" || value === "max_token"; } function isPositiveInteger(value: unknown): value is number { diff --git a/src/lib/search/executeWebSearch.ts b/src/lib/search/executeWebSearch.ts index d712e6dbde..a39f343437 100644 --- a/src/lib/search/executeWebSearch.ts +++ b/src/lib/search/executeWebSearch.ts @@ -222,7 +222,7 @@ export async function executeWebSearch( .filter((provider) => supportsSearchType(provider, searchType)) .sort((a, b) => a.costPerQuery - b.costPerQuery) .map((provider) => provider.id) - .filter((providerId) => providerId !== providerConfig.id); + .filter((providerId) => providerId !== providerConfig!.id); for (const providerId of otherIds) { const creds = await resolveSearchCredentials(providerId);