mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
aa7b3913862cf2f32a5cd7f09c8ffb9be87c19d0
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
20aa796d97 |
fix(sse): route task-aware defaults by intent, fix fitness pattern shadowing (#8602, #8603) (#8605)
* fix(sse): restore task-aware routing config on restart (#8601)
The T05 Task-Aware Smart Routing config was persisted to settings.taskRouting
by PUT /api/settings/task-routing but never read back, so it silently reverted
to enabled:false + the hardcoded default model map on every restart.
Two root causes, both fixed:
- No boot hydration existed. Adds hydrateTaskRoutingConfig(settings), wired into
src/instrumentation-node.ts next to the Thinking-Budget restore (#5312). It
accepts either the JSON string the route persists or an already-parsed object,
and fails open on malformed values. applyRuntimeSettings does not cover this
key, same as the Global System Prompt (#2470).
- The config lived in a plain module-level `let`, which is duplicated per module
graph — a boot hydration would have landed on the instrumentation graph's copy
and never reached the one src/sse/handlers/chat.ts reads. This is the exact
break #5312 fix-A hit on the VPS. Moves the store to the globalThis pattern
already used by thinkingBudget.ts and systemPrompt.ts.
Runtime stats are never restored from the persisted blob.
Note the hydration is wired into instrumentation-node.ts, not the unused
src/server-init.ts.
* docs(changelog): add fragment for #8604 task-routing boot restore
* fix(sse): route task-aware defaults by intent, guard fitness pattern order (#8602, #8603)
Two related defects in the hand-maintained model-quality tables.
#8602 — DEFAULT_TASK_MODEL_MAP hardcoded literal provider/model ids
(openai/gpt-4o, gemini/gemini-2.5-flash-lite, deepseek/deepseek-chat, ...).
Wrong twice over: the ids rotted by a generation or two, and applyTaskAwareRouting
overwrites body.model directly, so a literal target skipped auto-combo's 13-factor
scoring (quota, circuit-breaker health, cost, latency, stability), connection
cooldown and model lockout — hard-failing for any operator with no connection for
that provider. Refreshing the strings would only reset the rot clock, so the
defaults now name auto/* INTENTS that resolve against the operator's actually
connected backends:
coding -> auto/coding
analysis -> auto/reasoning
vision -> auto/vision
summarization -> auto/chat:fast
background -> auto/chat:cheap
creative and chat stay pass-through. Operators can still pin a specific model via
PUT /api/settings/task-routing; only the shipped defaults change. No provider/model
literal remains in the module.
#8603 — the pattern-shadowing fix LANDED UPSTREAM while this PR was open
(
|
||
|
|
eaddb6f0fa |
feat: improvements from 9router analysis (T01/T08-T13) (#351)
* fix: tool description null sanitization, clipboard HTTP fallback fixes T10 - Sanitize tool.description null in claude-to-openai translator - claude-to-openai.ts: tool.description defaults to empty string when null/undefined - claude-to-openai.ts: filter out tools with empty/missing names - Prevents 400 validation errors on providers like NVIDIA NIM (issue #276) T11 - Fix copy buttons to work on HTTP/non-HTTPS deployments - Add src/shared/utils/clipboard.ts with HTTPS+HTTP (execCommand) dual fallback - Migrate useCopyToClipboard.ts to use shared utility - Migrate ConsoleLogViewer.tsx, RequestLoggerV2.tsx to shared utility - Migrate HomePageClient.tsx, endpoint/page.tsx, GetStarted.tsx - Migrate DefaultToolCard.tsx to shared utility - Fixes copy buttons when OmniRoute runs behind HTTP proxy (issue #296) T02 - Verified SSE [DONE] sentinel handling already correct - sseParser.ts filters [DONE] on line 13 (no change needed) - stream.ts uses doneSent flag to prevent duplicate sentinel - bypassHandler.ts correctly separates streaming/non-streaming responses Issue triage comments posted to #340, #341, #344 * feat: DB read cache + Accept header stream negotiation (T09/T01) T09 - In-memory TTL cache for hot DB read paths - Add src/lib/db/readCache.ts with TTL cache (5s settings/connections, 30s pricing) - Eliminates redundant SQLite reads on concurrent requests - Integrate invalidation in settings.ts updateSettings() and updatePricing() - Integrate invalidation in providers.ts create/update/delete operations - Export getCachedSettings, getCachedPricing, getCachedProviderConnections, invalidateDbCache via localDb.ts for consumer migration - Cache auto-busts on any write, preserving data consistency T01 - Accept header stream negotiation - src/sse/handlers/chat.ts: detect Accept: text/event-stream header - Override body.stream=true when Accept header indicates streaming client - Enables curl, httpx and SDK clients that use HTTP headers instead of JSON body field to trigger streaming responses - Logs Accept override at DEBUG level for observability * fix: auto-advance quota window on expiry to prevent stale blocking (T08) T08 - Quota Window Rolling Auto-Advance - quotaCache.ts: add windowDurationMs field to QuotaCacheEntry interface (optional field that callers can set when they know the window duration) - Add advancedWindowResetAt() helper: if entry.nextResetAt is in the past, eagerly returns { exhausted: false } so requests are unblocked immediately - isAccountQuotaExhausted() now uses advancedWindowResetAt() instead of the previous inline date check, and optimistically clears entry.exhausted flag to avoid re-checking the same stale entry on the next request Before: exhausted accounts with an expired resetAt would wait up to 5 minutes for the background refresh before accepting new requests. After: the first request after resetAt passes will be immediately accepted and will trigger a quota refresh on the next background tick. * feat: manual OAuth token refresh UI (T12) T12 - Manual Token Refresh UI - Add POST /api/providers/[id]/refresh endpoint - Validates connection exists and is OAuth type - Calls getAccessToken() (same helper used in auto-refresh) - Persists new credentials via updateProviderCredentials() - Returns { success, expiresAt, refreshedAt } on success - Update providers/[id]/page.tsx - handleRefreshToken() with loading state (refreshingId) - Pass onRefreshToken + isRefreshing props to ConnectionRow - ConnectionRow: add optional onRefreshToken/isRefreshing props - ConnectionRow: tokenMinsLeft state via lazy init (Date.now() in getter fn, not in render body - satisfies react-hooks/purity) - Token expiry badge: red 'expired' | amber '~Xm' (<30min) | hidden - 'Token' button (amber) next to 'Retest' for OAuth connections - Add en.json i18n: tokenRefreshed, tokenRefreshFailed * Initial plan * feat: integrate wildcardRouter into model alias resolution (T13) T13 - Wildcard Model Routing - Import resolveWildcardAlias from wildcardRouter.ts into model.ts - In getModelInfoCore(), after exact alias check fails, try glob wildcard alias matching (e.g., 'claude-sonnet-*' alias → 'anthropic/claude-sonnet-4') - Returns { provider, model, extendedContext, wildcardPattern } on match - Falls back to MODEL_TO_PROVIDERS lookup and openai default as before * fix: clipboard cleanup and tool validation * feat: media page UX + T04 playground uploads + T03 HuggingFace/Vertex AI Media Page (MediaPageClient.tsx): - Render images inline (img tags from b64_json or url) - Show transcription as plain readable text (not raw JSON) - Amber banner for credential errors with link to /dashboard/providers - Detect empty transcription result and show credentials hint - Provider credential hint below selector for non-local providers - Extended provider/model lists: HuggingFace, Qwen TTS, Inworld, Cartesia, PlayHT, AssemblyAI T04 - Playground File Uploads (playground/page.tsx): - Audio file upload panel for transcription endpoint (multipart/form-data) - Image upload panel for vision models (gpt-4o, claude-3, gemini, pixtral, llava...) - Auto-detect vision models by name heuristic - Inject uploaded images as base64 image_url in chat messages - Inline image rendering for image generation results - Readable text view for transcription results with copy button - Preview thumbnails for attached images with individual remove T03 - HuggingFace + Vertex AI Providers: - HuggingFace: frontend providers.ts + backend providerRegistry.ts Uses HuggingFace Router OpenAI-compatible endpoint - Vertex AI: frontend providers.ts + backend providerRegistry.ts Uses gemini format with generateContent API (urlBuilder fallback) T07 - API Key Round-Robin: VERIFIED already implemented in auth.ts fill-first, round-robin, p2c, random, least-used, cost-optimized strategies * feat: T05 task-aware routing + fix #302 stream override + fix #73 claude provider fallback T05 - Task-Aware Smart Routing: - New open-sse/services/taskAwareRouter.ts: Detects 7 task types: coding, creative, analysis, vision, summarization, background, chat from system/user message content and images Configurable taskModelMap per task type, stats tracking applyTaskAwareRouting() integrates with existing chat pipeline - New src/app/api/settings/task-routing/route.ts: GET/PUT/POST API for task routing config + reset-stats + detect action Persists config via updateSettings('taskRouting') - Integration in src/sse/handlers/chat.ts: applyTaskAwareRouting() called after policy enforcement, before combo resolve Logs task type detection and model overrides Fix #302 - OpenAI SDK stream=False drops tool_calls: - src/sse/handlers/chat.ts T01 Accept header negotiation: Changed condition from 'body.stream !== true' to 'body.stream === undefined' OpenAI Python SDK sends 'Accept: application/json, text/event-stream' in every request, even stream=False — the old code was incorrectly forcing stream=true, causing tool_calls to be dropped from non-streaming responses Fix #73 - Claude Haiku routed to OpenAI provider instead of Antigravity: - open-sse/services/model.ts getModelInfoCore(): Added heuristic prefix detection before the blind 'openai' fallback: claude-* models → antigravity (Anthropic) provider gemini-*/gemma-* models → gemini provider Closes: #73, partially addresses #302 * fix: token counts 0 (#74), model import dup (#180), model route fallback (#73) fix #74 - Token counts always 0 for Antigravity/Claude streaming: - open-sse/utils/usageTracking.ts extractUsage(): Add handler for 'message_start' SSE event which carries INPUT tokens in Antigravity/Claude streaming: { type: 'message_start', message: { usage: { input_tokens: N } } } This event was completely unhandled, causing ALL input token counts to be dropped for every Antigravity/Claude streaming request fix #180 - Model import shows duplicates with no visual feedback: - src/shared/components/ModelSelectModal.tsx: Added addedModelValues prop (string[]) to receive already-added model values Models already in the combo now shown with ✓ indicator + green highlight Makes it visually clear which models are already added vs new - src/app/(dashboard)/dashboard/combos/page.tsx: Pass addedModelValues={models.map(m => m.model)} to ModelSelectModal * Harden clipboard UX and Claude tool normalization (#360) * Initial plan * chore: plan updates for clipboard and translator fixes * fix: clipboard cleanup, copy feedback, and claude tool validation --------- Co-authored-by: openai-code-agent[bot] <242516109+Codex@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: openai-code-agent[bot] <242516109+Codex@users.noreply.github.com> |