Commit Graph

86 Commits

Author SHA1 Message Date
Kfir Amar
3a3c7a7968 fix(logs): map numeric pino levels
Normalize numeric pino levels correctly in the console log API so the logger transport fix does not misclassify info, warn, and error entries in file-backed logs.

Add a targeted regression test for numeric log entries.
2026-03-15 01:51:59 +02:00
Kfir Amar
86105a547c fix(auth): clear stale state on non-chat success
Clear recovered provider error metadata after successful
credentialed requests in non-chat API routes as well.

Add route-level regression tests covering a Response-based
success path and a result-object success path.
2026-03-14 22:39:30 +02:00
Diego Rodrigues de Sa e Souza
db8d97b6de Merge pull request #366 from rexname/feature/codex-account-limit-rotation
Thanks @rexname (Maulana Hasanudin)! 🎉 

Codex account quota policy (5h/weekly) with auto-rotation is now merged. Highlights:
- Per-account policy toggles (5h + weekly ON/OFF) in the Provider dashboard
- Accounts automatically skipped when enabled quota window reaches 90% threshold
- Auto re-eligibility when resetAt timestamp passes (no manual intervention needed)
- Side-effect free `getQuotaWindowStatus` getter design
- Safe partial merge of `codexLimitPolicy` on provider updates

Merged on top of main (v2.5.0) with no conflicts. Analytics label fix (#356) included. Thanks for the excellent quality and the 2-commit cleanup round! 🙏
2026-03-14 15:54:07 -03:00
Diego Rodrigues de Sa e Souza
27d66e4b3e Merge pull request #367 from kfiramar/feat-codex-fast-toggle
Thanks @kfiramar! Codex fast-tier toggle merged 🎉 — default-off, full stack (UI tab + API + executor injection + translator passthrough + startup restore). 48 tests passing. Users can now enable flex tier in Dashboard → Settings → Codex Service Tier.
2026-03-14 15:49:56 -03:00
Kfir Amar
c009c993c3 fix(codex): persist fast-tier toggle before applying runtime state 2026-03-14 20:48:19 +02:00
Kfir Amar
00188f75ae feat(codex): add fast tier settings toggle
Add a default-off dashboard setting that injects Codex fast service tier only when the request did not already specify one.

Also preserve service_tier through OpenAI-to-Responses translation and restore the setting at startup.
2026-03-14 20:41:49 +02:00
rexname
0e30d15c01 feat(codex): add account-level 5h/weekly quota policy and auto-rotation
- add quota window status helper for Codex session (5h) and weekly windows
- enforce policy-based account filtering when enabled windows reach threshold
- return all-rate-limited metadata when no Codex account is eligible
- add per-account dashboard toggles for 5h and weekly policy controls
- merge codexLimitPolicy safely on provider updates to preserve partial settings
- document purpose and usage scenarios in README (EN + ID + i18n note)
2026-03-15 01:33:44 +07:00
diegosouzapw
11c0cff4ef merge: bug fixes for #355 #350 #346 into main 2026-03-14 15:30:36 -03:00
diegosouzapw
4fbe45f30a fix: stream timeout, combo test auth, and empty tool name (#355 #350 #346)
- fix #355: increase STREAM_IDLE_TIMEOUT_MS from 60s to 300s to prevent
  premature stream abortion for extended-thinking models (claude-opus-4-6,
  o3, etc.) that can pause >60s during reasoning phases. Configurable via
  STREAM_IDLE_TIMEOUT_MS env var.

- fix #350: combo health check test now bypasses REQUIRE_API_KEY=true by
  sending X-Internal-Test header, recognized in chat.ts auth pipeline to
  skip API key validation for internal admin-side combo tests. Also
  extended test timeout from 15s to 20s. Uses OpenAI-compatible format
  universally (not Claude-style).

- fix #346: filter out tools with empty function.name before forwarding
  to upstream providers. Claude Code sends empty-name tool definitions
  that cause '400 Invalid input[N].name: empty string' on OpenAI-compat
  providers. Extends existing message/input empty-name filter.
2026-03-14 15:28:53 -03:00
Regis
7db280ee64 fix(api): address review feedback on pricing sync
- Add .catch() to initial and periodic sync promises (Gemini, Kilo)
- Wrap JSON.parse in try-catch for corrupted DB data (Kilo)
- Wrap response.json() in try-catch for invalid LiteLLM JSON (Kilo)
- Validate PRICING_SYNC_INTERVAL (guard against NaN/0 → tight loop) (Copilot)
- Validate and allowlist sources — reject unknown, prevent empty sync
  from clearing pricing_synced data (Copilot, Kilo)
- Extract merge loop into shared iteration to reduce duplication (Gemini)
- Add data/warnings fields to MCP output schema (Copilot)
- Remove unused z import in vitest (Copilot)
- Filter non-string entries from sources array in API route (Copilot)
- Track active interval for accurate getSyncStatus().nextSync (Copilot)
2026-03-14 19:01:27 +01:00
Regis
192c06cadf feat(api): add external pricing sync with LiteLLM source
Add a 3-tier pricing resolution system: user overrides > synced external > hardcoded defaults.

New files:
- src/lib/pricingSync.ts: sync engine (fetch LiteLLM, transform, store in pricing_synced namespace)
- src/app/api/pricing/sync/route.ts: POST (trigger sync), GET (status), DELETE (clear synced)
- tests/unit/pricing-sync.test.mjs: 12 unit tests for transform logic
- open-sse/mcp-server/__tests__/pricingSync.test.ts: 11 vitest tests for MCP schema

Modified files:
- src/lib/db/settings.ts: getPricing() now merges 3 layers (defaults → synced → user)
- src/server-init.ts: init pricing sync on startup when PRICING_SYNC_ENABLED=true
- src/lib/localDb.ts: re-export pricing sync functions
- open-sse/mcp-server/schemas/tools.ts: add omniroute_sync_pricing tool definition
- open-sse/mcp-server/tools/advancedTools.ts: add handleSyncPricing handler
- open-sse/mcp-server/server.ts: register omniroute_sync_pricing tool

Opt-in (PRICING_SYNC_ENABLED=false by default), user overrides are never touched,
graceful fallback on fetch failure, zero new dependencies.
2026-03-14 18:49:35 +01:00
Diego Rodrigues de Sa e Souza
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>
2026-03-14 10:59:15 -03:00
diegosouzapw
2b6c88cd26 fix: iFlow OAuth secret, MITM server compile, GeminiCLI projectId, model catalog, electron version, tierPriority schema
- fix(oauth): restore iFlow clientSecret default — was empty string, now uses the valid public key (#339)
- fix(mitm): compile src/mitm/*.ts to JS during prepublish so server.js exists in npm bundle (#335)
- fix(gemini-cli): graceful projectId fallback — warn + empty string instead of hard 500 error (#338)
- feat(models): add gpt5.4 to Codex; add claude-sonnet-4, claude-opus-4.6, deepseek-v3.2, minimax-m2.1, qwen3-coder-next, auto to Kiro (#334)
- fix(electron): sync electron/package.json version to 2.3.13 (#323)
- feat(scoring): add tierPriority (0.05) to ScoringWeights Zod schema and combos/auto API route
2026-03-13 10:18:44 -03:00
jack
55a9e31932 fix(auth): use timing-safe compare for INITIAL_PASSWORD check 2026-03-12 17:28:04 +00:00
jack
e62be7e6b3 fix(auth): require explicit INITIAL_PASSWORD match on first password change 2026-03-12 17:04:26 +00:00
jack
daaa3a8782 fix(auth): allow INITIAL_PASSWORD when updating first password 2026-03-12 17:00:01 +00:00
diegosouzapw
1d7bc5fed7 feat: add /v1/completions legacy endpoint + show all 3 OpenAI endpoints in dashboard
- New route /v1/completions: accepts prompt string (legacy) + messages array
  Normalizes prompt format to chat/completions format automatically
- EndpointPageClient: Added 3rd card (Completions Legacy) in Core APIs section
  Dashboard now shows: /v1/chat/completions, /v1/responses, /v1/completions
- i18n: completionsLegacy/completionsLegacyDesc synced to 30 languages
2026-03-12 12:57:31 -03:00
diegosouzapw
2042dcf991 fix: Cline OAuth base64 parsing + name=email fallback for all OAuth accounts
- cline.ts: add decodeURIComponent before base64 decode to handle URL-encoded codes
- cline.ts: populate name = firstName+lastName || email in mapTokens
- oauth/exchange route: normalize name=email for all providers on exchange/poll/poll-callback
- Fixes: accounts showing Account #ID instead of email in providers dashboard
2026-03-12 12:22:20 -03:00
jack
6cad4fae8e fix(providers): persist supported endpoints with explicit save for custom models 2026-03-11 11:20:25 +00:00
Diego Rodrigues de Sa e Souza
ce560ebe9d fix: resolve issues #273, #276, #277 — image routing, models route, missing-key error (#282)
Squash merge PR #282: bug fixes for #273 (Gemini image routing), #276 (Ollama Cloud models), #277 (missing apiKey error), lint fix, and all security code-scanning patches.
2026-03-10 09:48:50 -03:00
Diego Rodrigues de Sa e Souza
44ee62e391 feat(#248,#260): TTS provider support + friendly display names (#262)
* feat(#248,#260): TTS provider support + friendly display names

## #248 — Text to Speech endpoint expansion
- audioRegistry: add Inworld, Cartesia, PlayHT providers with correct auth/format tags
- audioSpeech handler: add handleInworldSpeech (base64 decode), handleCartesiaSpeech (X-API-Key + transcript), handlePlayHtSpeech (X-USER-ID)
- /dashboard/media: add Speech tab with voice selector, format selector, and inline <audio> player (Blob URL)
- /dashboard/playground: add Text to Speech option; detect audio/* Content-Type and render inline audio player

## #260 — Friendly provider/account display names
- src/lib/display/names.ts: new centralized helper module with getAccountDisplayName() and getProviderDisplayName()
- src/lib/usage/usageStats.ts: replace raw connectionId.slice(0,8) fallbacks with getAccountDisplayName()
- src/app/api/rate-limits/route.ts: replace raw connectionId.slice(0,8) fallback with getAccountDisplayName()

* feat(#248,#261): ElevenLabs voice presets + mobile UX fixes

## #248 — ElevenLabs/Cartesia/Deepgram/Inworld voice presets
- MediaPageClient: replace static SPEECH_VOICES with provider-aware PROVIDER_VOICE_PRESETS
  - ElevenLabs: 9 premade voices with name+type (Rachel, Domi, Bella, Antoni, Elli, Josh, Arnold, Adam, Sam)
  - Cartesia: 3 built-in voices (Barbershop Man, Friendly Reading Man, California Girl)
  - Deepgram: 5 Aura voices (Asteria, Luna, Stella, Zeus, Orion)
  - Inworld: 2 voices (Eva, Marcus)
  - default: OpenAI 6 standard voices (alloy, echo, fable, onyx, nova, shimmer)
- Voice dropdown updates automatically when model input prefix changes

## #261 — Mobile UX improvements
- DashboardLayout: add h-dvh to mobile sidebar wrapper for proper scroll containment
- Sidebar: add h-full to aside element so nav can scroll on short screens
- ProvidersPage: change all 4 section headers from flex justify-between to flex flex-wrap so actions wrap on narrow screens instead of overflowing

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-03-09 13:43:48 -03:00
diegosouzapw
74a0585683 fix: add Ollama Cloud provider + security hardening (#255 #258)
feat(#255): add Ollama Cloud provider (api.ollama.com/v1)
- New registry entry 'ollama-cloud' (alias: ollamacloud)
- OpenAI-compatible, Bearer API key auth
- 7 pre-populated models: Gemma 3 27B, Llama 3.3 70B, Qwen3 72B,
  Devstral 24B, DeepSeek R2 671B, Phi 4 14B, Mistral Small 3.2 24B
- passthroughModels: true for dynamic model names

fix(#258): security hardening — all 9 findings addressed
- [CRITICAL] db-backups/export: add isAuthRequired + isAuthenticated guard
- [CRITICAL] db-backups/import: add isAuthRequired + isAuthenticated guard
- [HIGH] oauth/cursor/auto-import: add isAuthRequired + isAuthenticated guard
- [HIGH] oauth/kiro/auto-import: add isAuthRequired + isAuthenticated guard
- [LOW x4] oauth/[provider]/[action]: replace === with safeEqual()
  using crypto.timingSafeEqual() for CWE-208 (timing-oracle attacks)
  on email and workspaceId comparisons across all 3 handler branches
- [FALSE POSITIVE] Finding #1 (package.json 'reset-password' binary name)
  is not a hardcoded credential — no change needed

Tests: 590/594 pass (4 pre-existing failures in combo-circuit-breaker)
2026-03-09 12:42:17 -03:00
diegosouzapw
62995b640d fix(ci): correct security test import, add validateBody to acp/agents, deploy-vps continue-on-error
fix(test): security-fase01.test.mjs imports inputSanitizer.js → .ts
  - The file is TypeScript-only (no compiled .js). Node was failing with
    ERR_MODULE_NOT_FOUND in CI because the import path pointed to a
    non-existent .js file.

fix(acp): add validateBody(jsonObjectSchema) to POST /api/acp/agents
  - Satisfies check:route-validation:t06 lint rule that requires all
    routes using request.json() to go through validateBody().
  - Uses jsonObjectSchema (passthrough) since body shape varies between
    the 'refresh' action and the custom agent creation payload.
  - Manual field validation below remains unchanged.
  - All 139 routes now pass the route-validation lint check.

fix(deploy-vps): add continue-on-error on SSH step + command_timeout
  - SSH connection failures (host unreachable / secrets not set) no
    longer mark the workflow run as failed.
  - The DEPLOY_ENABLED guard still prevents the job from running when
    the variable is not set to 'true'.
2026-03-08 17:58:42 -03:00
diegosouzapw
1c2f553a7c feat: features 07/09/04/06 — codex clamp, openrouter cache, quota preflight & monitor
feat(codex): clamp reasoning effort per model (feature-07)
- Add MAX_EFFORT_BY_MODEL table in CodexExecutor
- Add clampEffort() applied after effort derivation
- Logs debug when clamp is applied

feat(catalog): OpenRouter catalog with persistent cache (feature-09)
- New src/lib/catalog/openrouterCatalog.ts with TTL 24h + stale-if-error
- New GET /api/models/openrouter-catalog endpoint (authenticated)
- Reduces redundant OpenRouter API calls from dashboard

feat(quota): quota preflight with per-provider toggle (feature-04)
- New open-sse/services/quotaPreflight.ts
- Toggle: providerSpecificData.quotaPreflightEnabled (default: false)
- Extensible via registerQuotaFetcher() pattern
- Graceful degradation when no fetcher registered

feat(quota): quota session monitor with per-provider toggle (feature-06)
- New open-sse/services/quotaMonitor.ts
- Toggle: providerSpecificData.quotaMonitorEnabled (default: false)
- Adaptive polling: 60s normal / 15s critical
- Alert deduplication (5min suppression window)
- timer.unref() ensures clean process exit

feat(providers): support providerSpecificData patch in PUT /api/providers/[id]
- Partial merge of providerSpecificData (preserves existing keys)
- Schema updated to accept providerSpecificData in updateProviderConnectionSchema
2026-03-08 17:36:17 -03:00
diegosouzapw
e4a11bd6d0 feat: ACP Agents dashboard + themeCoral i18n fix
- Add Dashboard > Debug > Agents page: grid of 14 built-in CLI agents
  with installation status, version detection, protocol badges
- Add custom agent support: users can register any CLI tool via form
- Expand registry from 5 to 14 built-in agents (aider, opencode, cline,
  qwen-code, forge, amazon-q, interpreter, cursor-cli, warp)
- Add 60-second detection cache to avoid repeated execSync calls
- API: GET lists all agents, POST adds custom/refreshes, DELETE removes
- Settings schema: add customAgents array field
- Fix missing themeCoral in settings namespace for all 30 languages
- Add agents sidebar key in all 30 languages
- Add agents page i18n namespace (en + pt-BR)
2026-03-07 11:19:12 -03:00
diegosouzapw
2d8091340f feat: CLI fingerprint UI toggle + fix playground i18n (#223)
- Add CLI Fingerprint Matching card in Settings > Security tab
  - Per-provider toggle chips (codex, claude, github, antigravity)
  - Emerald-themed UI with fingerprint icon and active count
  - Settings synced to runtime cache via API
- Fix playground i18n missing from 29 non-English sidebar translations
- Add cliCompatProviders to settings schema (Zod validation)
- Add setCliCompatProviders/getCliCompatProviders to cliFingerprints.ts
- Add i18n keys for CLI fingerprint settings (en + pt-BR)
2026-03-07 10:56:58 -03:00
diegosouzapw
ac89069671 feat: playground, CLI fingerprints, ACP support (#234, #223, #235)
- Add model playground page to dashboard (provider/model/endpoint selectors, Monaco editor, streaming, abort)
- Add CLI fingerprint matching (per-provider header/body ordering to match native CLI binaries)
- Add ACP module (CLI agent discovery, process spawner, session manager, API endpoint)
- Add playground to sidebar debug section with i18n support
- Close #192 and #200 as stale (v1.8.1, no repro info)
2026-03-07 10:24:43 -03:00
diegosouzapw
4b5824babc fix: pass resolved provider to image handler for custom models (#238) 2026-03-07 10:03:48 -03:00
diegosouzapw
10b23b15ae fix: custom image model routing + Codex OAuth workspace isolation (#232, #236) 2026-03-07 06:56:09 -03:00
Diego Rodrigues de Sa e Souza
a5cf51c0b9 Merge pull request #214 from DavyMassoneto/fix/claude-oauth-usage-endpoint
fix: harden quota system — code review fixes + build fix
2026-03-05 21:55:23 -03:00
DavyMassoneto
bfe495931f fix(claude): correct utilization semantics, harden quota cache, fix premature model unavailability
- Fix inverted Claude OAuth utilization (remaining, not used)
- Add hasUtilization() guard to prevent false exhaustion from empty responses
- Centralize anthropic-version into CLAUDE_CONFIG.apiVersion
- Add parseDate() for safe date validation in quota cache
- Batch background refresh with MAX_CONCURRENT_REFRESHES=5
- Move setModelUnavailable to after all accounts exhausted, not first 429
- Extract safePercentage() to shared utils (dedup)
- Use isRecord() type guard in usage API route
- Exclude binary files from Tailwind v4 source scanning
2026-03-05 19:39:59 -03:00
DavyMassoneto
11bcdd810a feat: quota-aware account selection + fix premature model unavailability
- Move setModelUnavailable from per-account loop to all-accounts-exhausted path
- Clear model unavailability on successful fallback
- Add in-memory quota cache with background refresh (5min active, 20min exhausted)
- Integrate quota cache in account selection to skip exhausted accounts
- Mark accounts as exhausted from 429 when no cached quota data exists
- Populate quota cache from dashboard usage endpoint
2026-03-05 18:49:56 -03:00
diegosouzapw
228ebf436e feat: endpoint-aware model management + fix 3 bugs (#212, #213, #200)
Bug Fixes:
- #212: Auto-generate API_KEY_SECRET at startup (like JWT_SECRET)
- #213: Circuit breaker now scoped per-model instead of per-provider
- #200: Connectivity fallback for custom providers (Ollama, LM Studio)

Features:
- #204: API Format selector (Chat Completions / Responses API) for custom models
- #205: Combo endpoint field (chat / embeddings / images) in schema
- #206: Supported Endpoints checkboxes (chat, embeddings, images, audio)
- Custom models with endpoint tags appear in /v1/embeddings and /v1/images/generations
- Model catalog includes api_format, type, and supported_endpoints metadata
- Provider detail page shows badges for non-default endpoint configurations

Files changed: instrumentation.ts, combo.ts, validation.ts, models.ts,
schemas.ts, provider-models/route.ts, providers/[id]/page.tsx,
catalog.ts, embeddings/route.ts, images/generations/route.ts
2026-03-05 18:49:07 -03:00
diegosouzapw
e09d4a02a2 feat: add MCP multi-transport (stdio + SSE + Streamable HTTP)
- Created httpTransport.ts with singleton MCP server and WebStandard
  Streamable HTTP transport running inside Next.js process
- Added /api/mcp/sse route (GET+POST) for SSE transport
- Added /api/mcp/stream route (GET+POST+DELETE) for Streamable HTTP
- Added mcpTransport enum to settingsSchemas (stdio|sse|streamable-http)
- Updated /api/mcp/status to report HTTP transport state
- Added TransportSelector UI with mode buttons and connection URL display
- Routes guard against disabled MCP or wrong transport mode
2026-03-05 17:45:44 -03:00
diegosouzapw
3de8b4371a fix: extract updateSettingsSchema to bypass webpack barrel-file bug
- Created settingsSchemas.ts with updateSettingsSchema to avoid webpack
  tree-shaking the schema from the 908-line schemas.ts barrel file
- Updated settings/route.ts import to use new dedicated file
- Fixed focusRingColor lint error in ServiceToggle
2026-03-05 17:19:48 -03:00
diegosouzapw
084b206ae6 fix: CORS headers on early-return error responses + auto-combo validation (#208, #209)
- Added CORS_HEADERS spread to 400/503 responses in chat/completions route
- Added createAutoComboSchema with Zod validation to /api/combos/auto
- Isolated JSON parsing errors with structured 400 response
- Prevented String(err) leakage on 500 errors
2026-03-05 15:56:17 -03:00
diegosouzapw
21135407af feat: Introduce new A2A and MCP API routes, enhance dashboard UI, update READMEs, and add E2E tests. 2026-03-05 11:16:56 -03:00
Diego Rodrigues de Sa e Souza
63114af08d Update src/app/api/auth/login/route.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 08:42:04 -03:00
diegosouzapw
751ff77b7c fix: extract validation helpers to fix webpack barrel-file resolution bug
Extracted validateBody, isValidationFailure, and loginSchema from the
935-line schemas.ts barrel file into a dedicated helpers.ts module.
Updated 70 API route files to import directly from helpers.ts.

Root cause: webpack on certain environments fails to resolve exports
from the bottom of large barrel files (schemas.ts), causing
'(0, O.Jb) is not a function' errors in production builds.

Fix: Split validation helpers into a small dedicated module (helpers.ts)
so webpack can correctly resolve all exports regardless of file size.

- TypeScript compiles with 0 errors
- All API routes updated to import from helpers.ts
- schemas.ts re-exports from helpers.ts for backward compatibility
2026-03-05 08:05:58 -03:00
diegosouzapw
baa0208fa9 feat: v2.0.0 - MCP server, A2A agent, proxy improvements and docs update 2026-03-05 01:16:56 -03:00
diegosouzapw
3510d8c0bc feat: add A2A protocol support and refactor API validation layer
Implement Agent-to-Agent (A2A) JSON-RPC 2.0 endpoint with smart routing
and quota management skills, SSE streaming, and task lifecycle management.

- Add /a2a route with message/send, message/stream, tasks/get, tasks/cancel
- Add /.well-known/agent.json agent card endpoint
- Introduce Zod-based request validation schemas for all v1 API routes
- Extract shared getUnifiedModelsResponse to reduce duplication across
  /models, /v1/models, and /a2a model listing
- Refactor chat, embeddings, moderations, and models routes to use
  centralized validation and error handling
- Add A2A task manager, routing logger, and streaming utilities
2026-03-04 18:52:25 -03:00
diegosouzapw
8dca8fba6b fix: route usage API quota fetches through configured proxy (#194) 2026-03-03 12:04:59 -03:00
diegosouzapw
7ba57634c1 feat: add blackbox.ai to dashboard frontend (#175)
- Added blackbox provider to APIKEY_PROVIDERS in providers.ts
- Added blackbox pricing entries in pricing.ts
- Added blackbox to ProviderId typedef in types.ts
- Added blackbox models endpoint config in models/route.ts
2026-03-02 18:46:48 -03:00
diegosouzapw
527c542d6d fix: cloud proxy endpoint shows undefined/v1 when env var not set (#171)
- syncAndVerify now returns cloudUrl in API response for frontend to use
- EndpointPageClient uses dynamic cloudBaseUrl state instead of relying on env var
- Falls back gracefully when NEXT_PUBLIC_CLOUD_URL is not set (Docker deployments)
- Fixed setInterval in accountFallback.ts global scope for Cloudflare Workers compat
2026-03-02 10:18:21 -03:00
diegosouzapw
4d2a5efd12 fix: OAuth re-auth now updates existing connection instead of creating duplicates (#170)
- Modified OAuth exchange route to use upsert logic at all 3 connection-save locations
- Before creating a new connection, checks for existing connections with same provider+email+authType
- If match found, calls updateProviderConnection() to refresh tokens instead of creating duplicate
- Falls back to createProviderConnection() for genuinely new connections
- Fixes: re-auth button creating new account entries instead of refreshing existing ones
2026-03-02 00:37:50 -03:00
diegosouzapw
4a1acb1446 feat(release): v1.7.3 — model deprecation, background degradation, rate limit persistence, thinking improvements, circuit breaker
Features:
- Model Deprecation Auto-Forward (10+ built-in aliases + custom via UI)
- Background Task Smart Degradation (19 patterns, degradation map)
- Rate Limit Persistence (SQLite, 60s debounce, 24h staleness)
- thinkingLevel string → budget conversion (high/medium/low/none)
- Claude -thinking model auto-injection
- Gemini 3.0/3.1 model registry distinction
- Token Refresh Circuit Breaker (5 failures → 30min cooldown)

Tests: 561 total (40+ new), 0 failures
2026-03-01 21:42:39 -03:00
Diego Rodrigues de Sa e Souza
3f10430150 Merge pull request #167 from ken2190/feat/new-providers-and-modalities
Approved — adds multi-modal support with new TTS/STT/Image/Video/Music providers. Follow-up commits will add frontend pages, unit tests, and configurable local provider URLs.
2026-03-01 07:03:14 -03:00
diegosouzapw
163c5feccc fix: strip models/ prefix from Gemini imported model IDs (#163) 2026-03-01 06:47:46 -03:00
duongvdo
d97a11a54f fix: address code review issues (SSRF, saveCallLog, deduplication)
- Add path traversal validation for ElevenLabs voice_id and HuggingFace
  model_id URL concatenation (prevents SSRF via ../ sequences)
- Add saveCallLog usage tracking to video and music handlers for
  consistent analytics with imageGeneration.ts
- Extract shared upstreamErrorResponse() and audioStreamResponse()
  helpers to reduce error handling duplication in audioSpeech.ts
- Extract shared upstreamErrorResponse() and isValidPathSegment()
  helpers in audioTranscription.ts
- Add explicit format: "openai" to qwen TTS and STT provider entries
- Remove unused modelId parameter from handleCoquiSpeech and
  handleTortoiseSpeech
- Filter cloud video/music providers by active status in models route
  (local providers with authType: "none" always listed)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:34:10 +07:00
duongvdo
4a779dfe3c feat: add new providers & modalities (TTS, STT, Image, Video, Music)
Add 6 TTS providers (Nvidia NIM, ElevenLabs, HuggingFace, Coqui, Tortoise,
Qwen3), 3 STT providers (Nvidia NIM, HuggingFace, Qwen3), 2 local image
providers (SD WebUI, ComfyUI), and two new modalities — Text-to-Video
(/v1/videos/generations) and Text-to-Music (/v1/music/generations).

Key design decisions:
- Format-based unified providers: local providers grouped by API format
  (comfyui, sdwebui, coqui, tortoise, openai-compatible) with configurable
  base URLs and expandable model lists
- Cloud providers kept separate (unique auth and API shapes)
- Local providers use authType: "none" — credential checks bypassed at both
  route and handler level
- Shared ComfyUI client (comfyuiClient.ts) reused across image/video/music
- Shared registry utilities (registryUtils.ts) for model parsing and listing
- Qwen3 TTS/ASR use format: "openai" — no custom handler needed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:31:29 +07:00