Compare commits

...

778 Commits

Author SHA1 Message Date
diegosouzapw
48754fd999 release: v2.8.7 — Bottleneck 429 drop (PR #495), custom embedding provider fix (#496) 2026-03-20 12:57:08 -03:00
Diego Rodrigues de Sa e Souza
c496ebdef9 Merge pull request #495 from xandr0s/fix/429-drop-bottleneck-queue
fix: drop Bottleneck queue on 429 instead of infinite wait
2026-03-20 12:53:31 -03:00
Oleg Saprykin
c009c40606 refactor: use .finally() to always delete limiter from Map
Address bot review feedback: use .finally() instead of .then()/.catch()
so limiters.delete() runs regardless of whether stop() succeeds or
throws (e.g. already stopped by concurrent 429).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:31:36 +03:00
Oleg Saprykin
b29456c8e5 fix: catch stop() already called on concurrent 429s
Multiple concurrent requests can receive 429 simultaneously, causing
stop() to be called on an already-stopped limiter. Add .catch() to
prevent unhandled rejection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:27:46 +03:00
diegosouzapw
38266bf2ff release: v2.8.6 — MiniMax role fix (PR #494), KIRO MITM card (#487), triage 8 issues 2026-03-20 12:26:27 -03:00
Diego Rodrigues de Sa e Souza
c2e51f8948 Merge pull request #494 from zhangqiang8vip/fix/developer-role-param-error
fix: resolve 422 "role param error" when forwarding OpenAI Responses API to MiniMax (developer → system)
2026-03-20 12:21:57 -03:00
Oleg Saprykin
64f040bddd fix: drop Bottleneck queue on 429 instead of waiting for reservoir refresh
When a provider returns 429 (rate limit exceeded), the rate limit manager
was setting reservoir=0 and waiting for reservoirRefreshInterval before
releasing queued requests. For providers with long rate limit windows
(e.g. Codex with hours-long resets), this caused all queued requests to
hang indefinitely — they never timed out or returned an error.

This prevented upstream callers (e.g. LiteLLM) from triggering fallback
to alternative providers, effectively making the entire model unavailable
until the rate limit window expired.

Fix: on 429, call limiter.stop({ dropWaitingJobs: true }) to immediately
fail all queued requests, then delete the limiter from the Map so
getLimiter() creates a fresh instance for subsequent requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:07:56 +03:00
zhang-qiang
dfbb9d5fff docs: add ZWS_README_V2 — developer role fix documentation
Made-with: Cursor
2026-03-20 21:47:02 +08:00
zhang-qiang
a7fe369ea0 fix: resolve role param error for Responses API + MiniMax (developer→system)
- Add preserveDeveloperRole option and model compat override

- Normalize developer→system in roleNormalizer when not preserving

- Translator runs normalizeRoles for Responses API with option

- UI: ModelCompatPopover with do not preserve developer toggle

- Add ZWS_README_V2 documenting cause and fix

Made-with: Cursor
2026-03-20 21:06:10 +08:00
diegosouzapw
b62e6c5a69 release: v2.8.5 — fix zombie SSE, context cache tag, KIRO MITM
Bug Fixes:
- #473: Reduce STREAM_IDLE_TIMEOUT_MS 300s→120s for faster zombie stream fallback
- #474: Fix injectModelTag() to handle first-turn (no assistant messages)
- #481: Change KIRO configType guide→mitm for dashboard MITM controls
- CI: Fix E2E test modal overlay interception

Closed External Issues:
- #468: Gemini CLI remote (superseded by #462 deprecation)
- #438: Claude write files (external CLI issue)
- #439: AppImage (documented libfuse2 workaround)
- #402: ARM64 DMG damaged (documented xattr -cr workaround)
- #460: Windows CLI PATH (documented fix)
2026-03-19 20:29:14 -03:00
diegosouzapw
92e29a6ad7 fix(e2e): dismiss pre-existing modal overlay in providers E2E test
The Bailian Coding Plan provider page may render a dialog on load
that blocks pointer events on the Add API Key button. Add pre-dialog
dismissal (Escape key) before attempting to click.

Also triages #485 (Claude Code tool calls — needs-info).
2026-03-19 20:05:51 -03:00
diegosouzapw
eeb9c69aa3 chore(release): v2.8.4 — Gemini CLI deprecation, VM guide i18n, flatted security fix
- #462: gemini-cli marked deprecated, Zod schema expanded
- #471: VM guide added to i18n pipeline, 30 locale translations regenerated
- #484: bump flatted 3.3.3→3.4.2 (CWE-1321)
- Closed: #472, #471, #483
2026-03-19 16:32:23 -03:00
Diego Rodrigues de Sa e Souza
b7662ed5a1 Merge pull request #484 from diegosouzapw/dependabot/npm_and_yarn/flatted-3.4.2
deps: bump flatted from 3.3.3 to 3.4.2
2026-03-19 16:31:14 -03:00
dependabot[bot]
9d6296f610 deps: bump flatted from 3.3.3 to 3.4.2
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-19 19:02:01 +00:00
diegosouzapw
fd2a1320e0 fix: resolve issues #462, #471 — deprecate gemini-cli, regenerate VM guide i18n
- #462: Mark gemini-cli provider as deprecated in providers.ts
  Add deprecated, deprecationReason, hasFree, freeNote, authHint, apiHint
  to Zod provider schema
- #471: Add VM_DEPLOYMENT_GUIDE.md to DOC_SOURCE_FILES in generate-multilang.mjs
  Delete 29 stale PT-language copies and regenerate from EN source
  for all 30 locales (29 auto-translated + 1 Czech from PR #482)
2026-03-19 15:57:55 -03:00
diegosouzapw
8a8a6a4a82 chore(release): v2.8.3 — Czech i18n, SSE protocol fix
- #482: Czech language + VM guide EN translation (@zen0bit)
- #483: Stop sending trailing data: null after [DONE]
2026-03-19 14:00:18 -03:00
diegosouzapw
8cdc14eec1 Merge PR #482: Add Czech language + Fix VM_DEPLOYMENT_GUIDE.md English source 2026-03-19 13:59:28 -03:00
diegosouzapw
a1200b2fb5 fix(docs): correct Czech link in USER_GUIDE.md language switcher
cs/.md → cs/USER_GUIDE.md
2026-03-19 13:57:29 -03:00
diegosouzapw
c88c29eddc fix(streaming): stop sending trailing data: null after [DONE] (#483)
formatSSE() in streamHelpers.ts explicitly returned 'data: null' for
null/undefined data. This violates SSE protocol and causes
AI_TypeValidationError in strict clients (Zod-based AI SDKs).
Now returns empty string, silently skipping null chunks.
2026-03-19 12:58:16 -03:00
diegosouzapw
2845c4de98 docs(workflow): fix deploy-vps to use ecosystem.config.cjs + rebuild better-sqlite3
Previously pm2 restart dropped env vars, causing login failures.
Now uses pm2 delete + pm2 start ecosystem.config.cjs --update-env.
Also rebuilds better-sqlite3 native bindings in app/ subdir.
2026-03-19 12:12:27 -03:00
zenobit
bfa9cd15b7 Add Czech language + Fix VM_DEPLOYMENT_GUIDE.md English source
Author: zenobit <zenobit@disroot.org>
2026-03-19 16:02:28 +01:00
diegosouzapw
659e2b414d feat(release): v2.8.2 — model alias routing fix, log export, 2 merged PRs 2026-03-19 11:13:49 -03:00
diegosouzapw
7bcb58e3db feat(logs): add export button with time range dropdown (1h, 6h, 12h, 24h)
- New API: /api/logs/export?hours=24&type=call-logs
- UI: Export button with dropdown on /dashboard/logs page
- Supports export of request-logs, proxy-logs, and call-logs
- Downloads as JSON file with Content-Disposition header
2026-03-19 11:11:07 -03:00
diegosouzapw
2d7d7776a6 fix(routing): model aliases now affect routing, not just format detection (#472)
Previously resolveModelAlias() output was used only for getModelTargetFormat()
but the original model was sent in translatedBody.model and to the executor.
Now effectiveModel is propagated to all downstream operations.
2026-03-19 11:07:29 -03:00
Prakersh Maheshwari
c5f429521c fix(pricing): add missing Codex 5.3/5.4 and Anthropic model ID entries (#479)
* fix(pricing): add missing Codex 5.3/5.4 and Anthropic model ID entries

Missing pricing entries cause $0.00 cost for:
- GPT 5.3 Codex family (gpt-5.3-codex, -high, -xhigh, -low, -none)
- GPT 5.4 (with hyphen: gpt-5.4)
- GPT 5.1 Codex Mini High
- Common Anthropic model IDs without dates (claude-opus-4-6,
  claude-sonnet-4-6, claude-opus-4, claude-sonnet-4)
- Dated variants used by Claude Code (claude-opus-4-5-20251101,
  claude-sonnet-4-5-20250929)

* refactor: extract shared pricing constants to reduce duplication

Address review feedback: extract duplicated pricing objects into
named constants (GPT_5_3_CODEX_PRICING, CLAUDE_OPUS_4_PRICING, etc.)
and add clarifying comment about intentional hyphen/dot variant entries.
2026-03-19 11:04:30 -03:00
diegosouzapw
426d8636bc fix(stream): extract usage from remaining buffer in flush handler (#480) 2026-03-19 11:02:13 -03:00
diegosouzapw
a265c7096e feat(release): v2.8.1 — streaming log fix, Kiro compat, cache tokens, Chinese i18n, configurable tool call ID 2026-03-19 08:45:54 -03:00
diegosouzapw
1c9953b1ba chore: remove ZWS_README_V1.md (internal contributor doc) 2026-03-19 08:43:17 -03:00
diegosouzapw
601cc21a44 feat: call log response content, per-model tool call ID, key PATCH & validation (#470) 2026-03-19 08:41:01 -03:00
Ethan Hunt
102c42dfe4 feat: Improve the Chinese translation (#475)
Co-authored-by: gmw <rorschach1167@qq.com>
2026-03-19 08:37:51 -03:00
Prakersh Maheshwari
4953727aa7 fix(callLogs): support Claude format usage and include cache tokens (#476)
saveCallLog only read prompt_tokens/completion_tokens (OpenAI format).
When sourceFormat=claude, the openai-to-claude translator writes
input_tokens/output_tokens instead, causing all cross-format requests
(Codex-via-Claude, Kiro-via-Claude, etc.) to show 0|0 tokens in
call_logs.

Also includes cache_read and cache_creation tokens in tokens_in total
so heavily-cached requests don't show misleadingly low input counts.

Changes:
- Read prompt_tokens || input_tokens (supports both formats)
- Read completion_tokens || output_tokens (supports both formats)
- Sum cache_read_input_tokens + cache_creation_input_tokens into total
2026-03-19 08:37:49 -03:00
Prakersh Maheshwari
e6af874b47 fix(usage): include cache tokens in usage history input total (#477)
logUsage stored only non-cached input tokens in usage_history.tokens_input.
For heavily-cached Claude requests (common with Claude Code), this shows
near-zero input when the real total is 150K+, causing the analytics
dashboard to severely underreport input token usage.

Now sums: input = prompt_tokens + cache_read + cache_creation
2026-03-19 08:37:46 -03:00
Prakersh Maheshwari
801b4eef4c fix(kiro): strip injected model field from request body (#478)
chatCore.ts injects translatedBody.model for all providers after
translation. Kiro API (AWS CodeWhisperer) has strict schema validation
and rejects unknown top-level fields — only conversationState, profileArn,
and inferenceConfig are valid. This causes 100% of Kiro requests to fail
with "Improperly formed request".

Strip the injected model field in KiroExecutor.transformRequest().
2026-03-19 08:37:44 -03:00
diegosouzapw
fe5c20a04e feat(release): v2.8.0 — Bailian Coding Plan, editable provider URLs, 812 tests 2026-03-19 02:28:45 -03:00
diegosouzapw
246fd05fae feat(providers): add Bailian Coding Plan provider with editable base URL (#467) 2026-03-19 02:25:29 -03:00
diegosouzapw
a09b298127 feat(release): v2.7.10 — Alibaba Cloud Coding, Kimi Coding API-key, Docker pino fix 2026-03-19 01:50:00 -03:00
Jefferson Nunn
f89f40778f feat: add API-key Kimi Coding provider path (#463)
* feat: add api-key Kimi Coding provider support

* fix(kimi-coding): honor apikey auth header in executor

Ensure DefaultExecutor sends x-api-key for kimi-coding-apikey at runtime
and deduplicate shared kimi coding config blocks in registry and models
config to reduce drift between oauth and apikey variants.

---------

Co-authored-by: OmniRoute Agent <agent@omniroute.local>
2026-03-19 01:48:26 -03:00
dtk
3d0c8d8d45 feat: add alibaba cloud coding plan provider support (#465)
Co-authored-by: dtk <git@derzsi.cloud>
2026-03-19 01:48:23 -03:00
diegosouzapw
0e5e8bf14e fix(docker): add missing split2 dependency to container image (#459) 2026-03-19 01:46:26 -03:00
diegosouzapw
ce34d329d3 chore(release): v2.7.9 2026-03-18 17:19:42 -03:00
diegosouzapw
eaf4a5805c "fix: resolved UI combo setting schema strip (#458)"
"fix: safe crypto fallback for MITM on windows (#456)"
2026-03-18 17:18:31 -03:00
Sergey Morozov
8420e565d4 feat: add responses subpath passthrough for codex (#457) 2026-03-18 17:18:29 -03:00
diegosouzapw
1b68deb0f6 feat(release): v2.7.8 — budget save fix + combo agent UI + omniModel tag strip
- fix(budget): warningThreshold sent as fraction 0-1 not percentage 0-100 (#451)
- feat(combos): Agent Features UI in combo modal (system_message, tool_filter_regex,
  context_cache_protection) — previously server-only (#454)
- fix(combos): strip <omniModel> tags before forwarding to provider (#454)
2026-03-18 15:38:04 -03:00
Diego Rodrigues de Sa e Souza
d1497c9ac8 Merge pull request #455 from diegosouzapw/fix/issue-451-454-budget-combo-ui
fix: budget warningThreshold + combo agent UI fields + omniModel tag strip
2026-03-18 15:37:17 -03:00
diegosouzapw
03d4cbf6d5 fix: budget warningThreshold fraction mismatch + combo agent UI fields + omniModel tag strip
- fix(budget): BudgetTab sent integer percentage (80) but schema validated
  fraction (0-1). Now divides by 100 on POST and multiplies by 100 on GET (#451)

- fix(combos): expose Agent Features UI in combo create/edit modal — fields for
  system_message override, tool_filter_regex, and context_cache_protection were
  implemented server-side (#399/#401) but missing from the dashboard UI (#454)

- fix(combos): strip <omniModel> tags from messages before forwarding to provider.
  The internal cache-pinning tag was being sent to the provider, causing cache
  misses as providers treated each tagged request as a new session (#454)
2026-03-18 15:32:47 -03:00
diegosouzapw
718be831af feat(release): v2.7.7 — Docker pino crash fix + Codex responses worker fix
- fix(docker): copy pino-abstract-transport + pino-pretty in standalone (#449)
- fix(responses): remove initTranslators() from /v1/responses route (#450)
- chore(deps): commit package-lock.json with each version bump
2026-03-18 15:13:26 -03:00
Diego Rodrigues de Sa e Souza
9d5ec523be Merge pull request #453 from diegosouzapw/fix/issue-449-450-pino-docker-responses-worker
fix: pino Docker crash + Codex /v1/responses worker exit + package-lock sync
2026-03-18 15:11:38 -03:00
diegosouzapw
81c43b45fb fix: pino-abstract-transport missing in Docker + responses worker crash + lock sync
- fix(docker): copy pino-abstract-transport and pino-pretty explicitly in
  runner-base stage — Next.js standalone trace omits them, causing
  'Cannot find module pino-abstract-transport' crash on startup (#449)

- fix(responses): remove initTranslators() call from /v1/responses route —
  bootstrapping translator registry from a Next.js Route Handler worker
  caused 'the worker has exited' uncaughtException on Codex CLI requests.
  Translators are already bootstrapped server-side via open-sse (#450)

- chore: include package-lock.json in commit (was being left behind on
  version bumps, causing npm ci to install inconsistent deps in Docker)
2026-03-18 15:08:57 -03:00
diegosouzapw
146a491769 feat(release): v2.7.5 — login UX + Windows CLI healthcheck
- fix(ux): show default password hint on login page (#437)
- fix(cli): spawn shell:true on Windows for .cmd CLI resolution (#447)
2026-03-18 14:52:05 -03:00
Diego Rodrigues de Sa e Souza
4c53388579 Merge pull request #448 from diegosouzapw/fix/issue-437-447-435-login-healthcheck-gemini
fix: login default password hint + Windows CLI healthcheck shell resolution
2026-03-18 14:51:19 -03:00
diegosouzapw
3403ddcc6e fix: login password hint + Windows CLI healthcheck + i18n key
- fix(ux): add default password hint on login page for first-time users (#437)
  The fallback password (123456) is now shown as a hint below the
  password input so users don't get locked out during initial setup.

- fix(cli): add shell:true to spawn on Windows so .cmd wrappers are
  resolved correctly via PATHEXT (#447). Claude, opencode, and other
  npm-installed CLIs show as 'not runnable' on Windows even when
  installed because spawn() cannot find .cmd files without shell:true.

- i18n: add defaultPasswordHint key to en.json auth namespace
2026-03-18 14:44:49 -03:00
diegosouzapw
684b81d835 feat(release): v2.7.4 — search playground, i18n fixes, Copilot limits, Serper validation
- feat(search): search playground + search tools page + local rerank (#443 @Regis-RCR)
- fix(analytics): localize day/date labels with Intl.DateTimeFormat (#444 @hijak)
- fix(copilot): correct account type display, filter unlimited quotas (#445 @hijak)
- fix(providers): stop rejecting valid Serper API keys on non-4xx (#446 @hijak)
2026-03-18 12:11:00 -03:00
Diego Rodrigues de Sa e Souza
4f32da57fd Merge pull request #443 from Regis-RCR/feat/search-playground
feat(search): add search playground, search tools, and local rerank routing
2026-03-18 12:09:51 -03:00
Diego Rodrigues de Sa e Souza
97265e48b3 Merge pull request #444 from hijak/fix/analytics-day-date-translations
fix: localize analytics day and date labels
2026-03-18 12:07:03 -03:00
Diego Rodrigues de Sa e Souza
64797158e2 Merge pull request #445 from hijak/fix/copilot-account-type-limits
fix: correct GitHub Copilot account type and limits
2026-03-18 12:06:59 -03:00
Diego Rodrigues de Sa e Souza
8359293dcd Merge pull request #446 from hijak/fix/serper-api-key-validation
fix: stop rejecting valid Serper API keys
2026-03-18 12:06:36 -03:00
Jack Cowey
b2dc53d18b fix(search): return consistent validation result shape
Keep search provider validation responses consistent with other validators so Serper regression tests and CI assertions can rely on unsupported=false.

Made-with: Cursor
2026-03-18 12:55:25 +00:00
Jack Cowey
edf8dd2a12 fix(search): accept authenticated serper validation responses
Treat non-auth Serper validation errors as successful authentication so valid API keys are not rejected during provider setup.

Made-with: Cursor
2026-03-18 12:29:14 +00:00
Jack Cowey
5a777bd598 fix(github): correct copilot plan and quota mapping
Normalize GitHub Copilot account tiers from the usage payload and hide misleading unlimited buckets so account type and limits render correctly in the dashboard.

Made-with: Cursor
2026-03-18 12:25:17 +00:00
Jack Cowey
bd39e01ee1 fix(analytics): localize most active day and weekly labels
Use the active app locale for analytics weekday and date formatting so the dashboard no longer shows hardcoded Portuguese labels.

Made-with: Cursor
2026-03-18 12:17:56 +00:00
Regis
e3ed29aab6 feat(search): add search playground, search tools, and local rerank routing
Search Playground (Phase 1):
- Web Search as 10th endpoint in Playground with isolated SearchPlayground component
- Endpoint selector moved first; Provider/Model/Send hidden when search selected
- Provider dropdown via GET /api/search/providers, formatted results with cache indicator

Search Tools page (Phase 2) at /dashboard/search-tools:
- Split panel: SearchForm (left) with query, provider, filters + ResultsPanel (right)
- Compare Providers: parallel queries with latency, cost, response size, URL overlap
- Rerank Pipeline: model selector from /v1/models, results with position delta
- Search History: last 10 searches from call_logs with replay
- Sidebar entry under Debug section

Backend:
- GET /api/search/providers — list providers with auth guard + SEARCH_CREDENTIAL_FALLBACKS
- GET /api/search/stats — cache stats, provider aggregates, recent searches (auth guard)
- Add local provider_nodes routing for /v1/rerank (oMLX, vLLM support)

Bug fixes (from F-27 PR #432):
- Fix Brave news normalizer: data.results directly, not data.news.results
- Enforce max_results truncation after normalization for all providers
- Fix EndpointPageClient: use /api/search/providers instead of /api/v1/search
- Add isAuthenticated() guards on /api/search/providers and /api/search/stats

Response size metric in results meta bar and compare table.
i18n: 30+ keys in search namespace (en.json)
2026-03-18 12:43:24 +01:00
diegosouzapw
896ce9c0e2 feat(release): v2.7.3 — fix Codex direct API weekly quota fallback
- fix(codex): resolveQuotaWindow() prefix-matches 'weekly' → 'weekly (7d)' cache keys
- fix(codex): applyCodexWindowPolicy() enforces useWeekly/use5h toggles in direct API
- 4 new regression tests, 766 total passing
- Closes #440
2026-03-18 08:41:13 -03:00
Diego Rodrigues de Sa e Souza
82934132e9 Merge pull request #441 from rexname/fix/issue-440-direct-api-fallback
fix(codex): block weekly-exhausted accounts in direct API fallback
2026-03-18 08:40:19 -03:00
rexname
a2012b70de chore(review): harden window normalization and deterministic quota matching 2026-03-18 14:17:37 +07:00
rexname
bcfeba8a57 fix(codex): enforce weekly quota blocking for direct API fallback 2026-03-18 13:57:25 +07:00
diegosouzapw
d3dfd9ce57 feat(release): v2.7.2 — fix light mode contrast in logs UI
- fix(logs): text colors in filter buttons + combo badge now have dark: variants
- Bumped version to 2.7.2
- Updated CHANGELOG and openapi.yaml
2026-03-18 00:42:22 -03:00
Diego Rodrigues de Sa e Souza
aa06d5d356 Merge pull request #433 from diegosouzapw/fix/issue-378-logs-light-mode-contrast
Merged fix for light mode contrast in filter buttons and combo badge. Thanks @rdself for the great bug report!
2026-03-18 00:41:28 -03:00
diegosouzapw
448c8a29e1 fix(logs): fix light mode contrast in filter buttons and combo badge (#378)
- text-red-400 → text-red-700 dark:text-red-400 (error filter, recording button)
- text-emerald-400 → text-emerald-700 dark:text-emerald-400 (ok filter)
- text-violet-300 → text-violet-700 dark:text-violet-300 (combo filter)
- combo row badge: violet-700 → violet-800 dark:violet-300, stronger border

Fixes #378
2026-03-17 16:46:27 -03:00
diegosouzapw
928b7120f4 feat(release): v2.7.1 — unified web search routing + Next.js 16.1.7 security
- POST /v1/search: 5 providers (Serper, Brave, Perplexity, Exa, Tavily), 6,500+ free/mo
- Search analytics dashboard tab + GET /api/v1/search/analytics
- db: request_type column on call_logs (migration 007)
- Next.js 16.1.7: 6 CVEs fixed (critical: CVE-2026-29057 HTTP request smuggling)
- docs/openapi.yaml: bumped to 2.7.1
2026-03-17 16:27:31 -03:00
diegosouzapw
a3deacd718 feat: Implement historical model latency and success rate tracking for auto-combo routing and update Claude and Deepseek pricing and model registrations. 2026-03-17 16:18:36 -03:00
diegosouzapw
78959fffbd Merge branch 'main' of https://github.com/diegosouzapw/OmniRoute 2026-03-17 16:18:12 -03:00
Diego Rodrigues de Sa e Souza
1788616e52 Merge pull request #431 from diegosouzapw/dependabot/npm_and_yarn/next-16.1.7
Security update merged: Next.js 16.1.7 fixes 6 CVEs including critical CVE-2026-29057 (HTTP request smuggling). No breaking changes.
2026-03-17 16:18:01 -03:00
Diego Rodrigues de Sa e Souza
c61e6d0777 Merge pull request #432 from Regis-RCR/feat/search-provider-routing
Merged with dashboard improvements: SearchAnalyticsTab + /api/v1/search/analytics endpoint — PR review complete by Antigravity.
2026-03-17 16:17:39 -03:00
diegosouzapw
a3bc7620b1 feat(integration): integrate ClawRouter services into active pipeline
- intentClassifier → engine.ts selectProvider()
  When taskType is 'default', classifies prompt via multilingual keyword
  detection (9 langs) and uses detected intent (code/reasoning/simple/medium)
  for 6-factor task fitness scoring.

- emergencyFallback → chatCore.ts error path (after T5 intra-family fallback)
  On HTTP 402 or budget-exhaustion keywords, attempts one redirect to
  nvidia/gpt-oss-120b ($0.00/M) before returning error to combo router.
  Skipped for streaming requests and tool-calling requests.

- AutoComboConfig.routerStrategy field added
  Allows per-combo strategy override ('rules' | 'cost' | 'latency')

Note: requestDedup was already integrated in chatCore.ts (line 387-430)
Branch: feat/clawrouter-improvements
2026-03-17 15:22:12 -03:00
diegosouzapw
8064c588dc docs(i18n): sync v2.7.0 release notes to 29 language READMEs
New in v2.7.0: pluggable RouterStrategy, multilingual intent detection,
request deduplication, new providers (Grok-4 Fast, GLM-5/Z.AI,
MiniMax M2.5, Kimi K2.5). Native translations for de/es/fr/it/ru/zh-CN/ja/ko/ar/pt-BR/pt.
2026-03-17 15:11:09 -03:00
Regis
564e983c68 feat(search): add unified web search routing with 5 providers
Add POST /v1/search — a unified search endpoint routing queries across
5 providers (Serper, Brave, Perplexity Search, Exa, Tavily) with
automatic failover, in-memory caching, and request coalescing.

No open-source AI gateway offers unified search routing. This chains
free tiers for 5,500+ searches/month with zero downtime.

Providers: Serper ($0.001/q, 2500/mo free), Brave ($0.005/q, 1000/mo),
Perplexity Search ($0.005/q), Exa ($0.007/q, 1000/mo), Tavily
($0.008/q, 1000/mo). Auto-select picks cheapest with credentials.

Architecture follows existing patterns:
- searchRegistry.ts (same as embeddingRegistry.ts)
- search.ts handler (same as embeddings.ts)
- route.ts (same as /v1/embeddings/route.ts)
- searchCache.ts (bounded TTL cache + request coalescing)

Schema finalized — all future fields defined as optional with safe
defaults. No breaking changes when implementing content extraction,
answer synthesis, or ranking.

Key features:
- Per-provider request builders and response normalizers
- Enriched response: display_url, score, favicon_url, content block,
  metadata, answer block, errors array, upstream_latency_ms metrics
- Cost-sorted auto-select with failover on 429/5xx/timeout
- Credential fallback (perplexity-search reuses perplexity chat key)
- Cache key includes all result-affecting parameters
- max_results clamped to provider limits, sanitized error responses
- Factored validators (validateSearchProvider factory)
- CORS headers on all responses
- Dashboard: Search & Discovery section, search provider template
- DB migration 007: request_type column in call_logs
- 28 unit tests (registry, cache, coalescing, validation)
2026-03-17 18:28:35 +01:00
diegosouzapw
e1da181740 fix(publish): also remove app/electron/ (contains app.asar binary) to prevent Z_DATA_ERROR 2026-03-17 14:25:48 -03:00
diegosouzapw
c63209200e fix(publish): remove app/vscode-extension/ after build to prevent Z_DATA_ERROR in npm pack 2026-03-17 14:13:15 -03:00
diegosouzapw
737808cf53 fix(npm): exclude app/vscode-extension/ from package to prevent Z_DATA_ERROR during publish 2026-03-17 13:50:06 -03:00
diegosouzapw
a197bb7736 fix(routerStrategy): use .ts extension in imports for Next.js App Router bundle compatibility 2026-03-17 13:15:47 -03:00
dependabot[bot]
f9dd967bc5 deps: bump next from 16.1.6 to 16.1.7
Bumps [next](https://github.com/vercel/next.js) from 16.1.6 to 16.1.7.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.1.6...v16.1.7)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.1.7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 16:14:44 +00:00
diegosouzapw
44e4d55a66 feat(release): merge feat/clawrouter-improvements — v2.7.0 2026-03-17 13:12:41 -03:00
diegosouzapw
095c84ac16 fix(providerRegistry): remove duplicate claude-haiku-4-5-20251001 from anthropic provider to prevent ambiguous model resolution 2026-03-17 13:10:23 -03:00
diegosouzapw
e063eae727 feat(clawrouter): implement 14 ClawRouter-inspired features
PRICING UPDATES (01-09):
- xAI Grok-4 family: grok-4-fast-non-reasoning (/usr/bin/bash.20/$0.50/M, 1143ms),
  grok-4-fast-reasoning, grok-4-1-fast-*, grok-4-0709, grok-3, grok-3-mini
- Z.AI GLM-5 family: glm-5 + glm-5-turbo (128k maxOutput, $1.00/$3.20/M)
- Gemini Flash Lite: price corrected $0.15→$0.10 / $1.25→$0.40 (per ClawRouter)
- Gemini 3.1 Pro: new flagship (1.05M context, aliased as gemini-3.1-pro)
- Anthropic Claude 4.5/4.6: haiku-4.5 ($1/$5), sonnet-4.6 ($3/$15), opus-4.6 ($5/$25)
- DeepSeek native section: deepseek-chat/v3/v3.2 ($0.28/$0.42), deepseek-reasoner ($0.55/$2.19)
- Kimi K2.5 Moonshot: kimi-k2.5 ($0.60/$3.00, 262k ctx), moonshot-kimi-k2.5 alias
- MiniMax M2.5: minimax-m2.5 ($0.30/$1.20, 204k ctx, reasoning+tools)
- NVIDIA free tier: gpt-oss-120b at $0.00/M via emergencyFallback.ts

INFRASTRUCTURE FEATURES (10-14):
- feat(router): add intentClassifier.ts for multilingual intent detection (9 langs)
  Detects code/reasoning/simple in EN, PT-BR, ES, ZH, JA, RU, DE, KO, AR
- feat(dedup): add requestDedup.ts for concurrent request deduplication
  SHA-256 hash, skip streaming, skip high-temperature, 60s failsafe TTL
- feat(autoCombo): add routerStrategy.ts pluggable strategy system
  RouterStrategy interface, RulesStrategy (6-factor) + CostStrategy, registry
- feat(fallback): add emergencyFallback.ts budget-exhaustion detector
  Triggers on HTTP 402 or budget keywords, redirects to nvidia/gpt-oss-120b
- feat(taskFitness): add fitness scores for Grok-4, Kimi K2.5, GLM-5,
  MiniMax M2.5, DeepSeek V3.2, Gemini 3.1 Pro across all task categories

PROVIDERS:
- providers.ts: add Z.AI (zai) provider entry for GLM-5 API key connections

All features on branch: feat/clawrouter-improvements
Source: github.com/BlockRunAI/ClawRouter analysis (2026-03-17)
2026-03-17 10:43:12 -03:00
diegosouzapw
f02c5b5c69 fix(install/v2.6.10): Windows better-sqlite3 prebuilt download (#426)
npm version patch run BEFORE staging files — this is an ATOMIC commit.

Adds Strategy 1.5 to scripts/postinstall.mjs:
- Uses @mapbox/node-pre-gyp install --fallback-to-build=false
  (bundled within better-sqlite3) to download the correct prebuilt
  binary for the current OS/arch (win32-x64/arm64, darwin-x64/arm64)
  WITHOUT requiring node-gyp, Python, or MSVC build tools.
- Tries node-pre-gyp.cmd (Windows) or node-pre-gyp (Unix) from .bin/
  with fallback to direct path in @mapbox/node-pre-gyp/bin/
- Falls back to npm rebuild only if prebuilt download fails.
- Windows-specific error: shows Option A (npx node-pre-gyp) and
  Option B (rebuild) with Visual Studio Build Tools links.

Fixes: #426 (better_sqlite3.node is not a valid Win32 application)
2026-03-17 10:09:45 -03:00
diegosouzapw
838f1d645c fix(v2.6.9): CI budget checks, #409 file attachments, atomic release workflow
Includes version bump — v2.6.9 — committed ATOMICALLY with all changes:

fixes:
- fix(ci/t11): Remove 'any' from comments in openai-responses.ts + chatCore.ts
  (\bany\b regex counted comment text as explicit any violations)
- fix(chatCore/#409): Normalize unsupported content part types before forwarding
  Cursor sends {type:'file'} for .md attachments; Copilot/OpenAI providers reject
  with 'type has to be either image_url or text'. Now: file/document→text block,
  unknown types dropped with debug log. Fixes claude-* models via github-copilot.

workflow:
- chore(generate-release): ATOMIC COMMIT RULE — npm version patch MUST run before
  feature commits so the release tag always points to a commit with full changes
2026-03-17 09:09:01 -03:00
diegosouzapw
ce2c30c437 chore(release): v2.6.8 — combo agents, auto-update, detailed logs, MITM Kiro 2026-03-17 08:58:03 -03:00
diegosouzapw
d56fae0a7b feat: combo agents, auto-update UI, detailed logs, MITM Kiro (#399 #401 #320 #378 #336)
DB Migrations (zero-breaking, ADD COLUMN DEFAULT NULL + new table):
- 005_combo_agent_fields.sql: system_message, tool_filter_regex, context_cache_protection on combos
- 006_detailed_request_logs.sql: ring-buffer table (500 entries) for full pipeline body capture

Features:
- #399 System Message Override + Tool Filter Regex per Combo
  - applyComboAgentMiddleware() injected into handleComboChat/handleRoundRobinCombo
  - Supports both OpenAI and Anthropic tool name formats
- #401 Context Caching Protection (Stateless)
  - injectModelTag() appends <omniModel>provider/model</omniModel> to responses
  - extractPinnedModel() reads tag from history and pins model for session
- #320 Auto-Update via Settings
  - GET /api/system/version — current vs latest npm
  - POST /api/system/update — fire-and-forget npm install + pm2 restart
- #378 Detailed Request Logs
  - saveRequestDetailLog() captures bodies at 4 pipeline stages (opt-in toggle)
  - GET/POST /api/logs/detail — list logs + enable/disable toggle
- #336 MITM Kiro IDE
  - src/mitm/targets/kiro.ts: MitmTarget profile for api.anthropic.com interception
2026-03-17 08:53:41 -03:00
diegosouzapw
e45ef00bef chore(release): v2.6.7 — SSE fixes, local provider_nodes, proxy registry
PRs merged: #414 (deps) #415 #417 #419 #420 #421 (SSE fixes)
            #418 (Claude passthrough) #422 #416 #423 (local nodes)
            #427 (strip empty blocks) #428 (OAuth refreshable)
            #429 (proxy registry)
Contributors: @prakersh, @Regis-RCR, @dependabot
2026-03-17 08:17:11 -03:00
diegosouzapw
e9f31f7394 Merge pull request #429 from contributor branch 2026-03-17 08:14:05 -03:00
diegosouzapw
7c10a98eb2 Merge pull request #428 from contributor branch 2026-03-17 08:14:04 -03:00
diegosouzapw
f260483101 Merge pull request #427 from contributor branch 2026-03-17 08:14:03 -03:00
diegosouzapw
389e6e5c9e Merge pull request #423 from contributor branch 2026-03-17 08:14:02 -03:00
diegosouzapw
1cfd5866be Merge pull request #422 from contributor branch 2026-03-17 08:14:02 -03:00
diegosouzapw
c7ceac7f41 Merge pull request #421 from contributor branch 2026-03-17 08:14:01 -03:00
diegosouzapw
cd6eca0424 Merge pull request #420 from contributor branch 2026-03-17 08:14:00 -03:00
diegosouzapw
8c6136fea0 fix(sse): generate fallback call_id for tool calls with missing IDs (#419)
Co-authored-by: Prakersh Maheshwari <prakersh@users.noreply.github.com>
2026-03-17 08:11:53 -03:00
Diego Rodrigues de Sa e Souza
9644444028 Merge pull request #418 from prakersh/fix/claude-to-claude-passthrough
fix(sse): add Claude-to-Claude passthrough for anthropic-compatible providers
2026-03-17 08:09:44 -03:00
Diego Rodrigues de Sa e Souza
9c4154291d Merge pull request #417 from prakersh/fix/orphaned-tool-result-filter
fix(sse): filter orphaned tool results after context compaction
2026-03-17 08:09:41 -03:00
Diego Rodrigues de Sa e Souza
533f5f6da6 Merge pull request #416 from Regis-RCR/feat/audio-provider-nodes
feat(audio): route audio requests to local provider_nodes
2026-03-17 08:09:38 -03:00
Diego Rodrigues de Sa e Souza
1b8de756cd Merge pull request #415 from prakersh/fix/empty-tool-name-loop
fix(sse): skip empty-name tool calls in Responses API translator
2026-03-17 08:09:28 -03:00
Diego Rodrigues de Sa e Souza
650b415537 Merge pull request #414 from diegosouzapw/dependabot/npm_and_yarn/development-cc00f57801
deps: bump the development group with 4 updates
2026-03-17 08:09:25 -03:00
rexname
04b50329fc fix(proxy): address PR review findings for auth, credentials, and health stats 2026-03-17 16:58:44 +07:00
Regis
25aab8c55c feat(audio): route audio requests to local provider_nodes
Audio endpoints (/v1/audio/speech and /v1/audio/transcriptions) only
supported hardcoded providers from audioRegistry.ts. Local inference
backends configured as provider_nodes (e.g., MLX-Audio, oMLX) could
not serve audio through OmniRoute.

This adds a Phase 3 fallback in the audio model parser that consults
provider_nodes from the database. Local providers with api_type=openai
are automatically available for audio routing via their prefix
(e.g., mlx-audio/tts-model, omlx/whisper-large-v3-turbo).

Design: injection pattern — Next.js route handlers load provider_nodes
(async DB query) and pass them to the sync parser as a parameter.
No cross-workspace imports, no breaking changes to existing parsers.

Changes:
- Add buildDynamicAudioProvider() in audioRegistry.ts
- Add Phase 3 (provider_nodes prefix match) to parseAudioModel()
- Extend parseSpeechModel/parseTranscriptionModel with optional
  dynamicProviders parameter (backward compatible)
- Load and inject provider_nodes in speech/transcription route handlers
- Dynamic providers use authType=none (local, no credentials needed)
2026-03-17 09:24:18 +01:00
Oleg Saprykin
ceda2e70c1 fix(api): add refreshable: true to claude OAuth test config
Claude OAuth tokens are short-lived and require refresh. The runtime
HealthCheck (open-sse) already refreshes them successfully, but the
Dashboard test endpoint was missing `refreshable: true` in its config.

This caused the Dashboard to show "auth failed / Token expired" for
Claude providers even though the tokens were being refreshed correctly
at runtime. The codex provider already had this flag set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 10:47:35 +03:00
Oleg Saprykin
2908303d4b fix(sse): strip empty text content blocks before translation
Anthropic API rejects requests containing {"type":"text","text":""} with
400 "text content blocks must be non-empty". Some clients like LiteLLM
passthrough and @ai-sdk/anthropic may forward empty text blocks as-is.

Filter out empty text content blocks from messages before calling
translateRequest, similar to how empty-name tools are already stripped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 10:46:24 +03:00
diegosouzapw
a9f69711c6 fix(build): remove node: protocol prefix from all src/ imports (#turbopack-compat)
Turbopack (Next.js 15) does not process node: URL prefixes correctly when
bundling server-side files that get transitively included. Removed the node:
prefix from 17 files:

- src/lib/db/migrationRunner.ts (node:fs, node:path, node:url)
- src/lib/db/core.ts (node:path, node:fs)
- src/lib/db/backup.ts (node:path, node:fs)
- src/lib/db/prompts.ts (node:fs)
- src/lib/dataPaths.ts (node:path, node:os)
- src/app/api/settings/route.ts
- src/app/api/storage/health/route.ts
- src/app/api/oauth/[provider]/[action]/route.ts
- src/app/api/db-backups/{exportAll,import,export}/route.ts
- src/shared/middleware/correlationId.ts
- src/shared/utils/requestId.ts
- src/lib/apiBridgeServer.ts
- src/lib/cacheLayer.ts
- src/lib/semanticCache.ts
- src/lib/oauth/providers/kimi-coding.ts

Also updated generate-release.md: Docker Hub sync and dual-VPS deploy
are now mandatory steps in every release.
2026-03-17 04:24:46 -03:00
diegosouzapw
a8ab16a720 chore(release): v2.6.5 — reasoning params filter, local 404 fix, Kilo Gateway, dep bumps
- fix(sse): strip unsupported params for o1/o1-mini/o1-pro/o3/o3-mini (PR #412 @Regis-RCR)
- fix(sse): model-only lockout (5s) for local provider 404 (PR #410 @Regis-RCR)
- feat(api): Kilo Gateway provider — 335+ models, alias 'kg' (PR #408 @Regis-RCR)
- deps: better-sqlite3 12.8, undici 7.24.4, https-proxy-agent 8 (PR #413)
2026-03-17 03:05:45 -03:00
rexname
8091b6b508 feat: implement proxy registry, management APIs, docs, and test hardening 2026-03-17 13:05:27 +07:00
Diego Rodrigues de Sa e Souza
a00ef0fc7e Merge pull request #413 from diegosouzapw/dependabot/npm_and_yarn/production-4d4ff746af
deps: bump the production group with 5 updates
2026-03-17 03:03:49 -03:00
Diego Rodrigues de Sa e Souza
5ce6d615a4 Merge pull request #408 from Regis-RCR/feat/kilo-gateway-provider
feat(api): add Kilo Gateway provider
2026-03-17 03:03:47 -03:00
Diego Rodrigues de Sa e Souza
e06b69cdac Merge pull request #410 from Regis-RCR/fix/local-404-cascade
fix(sse): model-only lockout for local provider 404
2026-03-17 03:03:31 -03:00
Diego Rodrigues de Sa e Souza
d261ae7883 Merge pull request #412 from Regis-RCR/fix/param-filter-reasoning
fix(sse): strip unsupported params for reasoning models (o1/o3)
2026-03-17 03:03:28 -03:00
diegosouzapw
6fa77a63d7 chore(release): v2.6.4 — model name fixes across providers 2026-03-17 01:59:25 -03:00
diegosouzapw
f76c1b32d6 fix(providers): remove non-existent model names and fix incorrect model IDs
- gemini/gemini-cli: removed gemini-3.1-pro/flash/preview (don't exist in Google API v1beta),
  replaced with real models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.0-flash, gemini-1.5-*
- antigravity: removed gemini-3.1-pro-high/low and gemini-3-flash (internal aliases invalid),
  replaced with gemini-2.5-pro, gemini-2.5-flash, gemini-2.0-flash
- github: removed gemini-3-flash-preview and gemini-3-pro-preview, replaced with gemini-2.5-flash
- nvidia: corrected 'nvidia/llama-3.3-70b-instruct' to 'meta/llama-3.3-70b-instruct'
  (NVIDIA NIM uses meta/ namespace, not nvidia/ namespace for Meta models)
- nvidia: added meta/llama-3.1-70b-instruct and nvidia/llama-3.1-405b-instruct

Also fixed free-stack combo on .15 DB:
- removed qw/qwen3-coder-plus (qwen provider has expired refresh token)
- corrected nvidia/llama-3.3-70b-instruct → nvidia/meta/llama-3.3-70b-instruct
- corrected gemini/gemini-3.1-flash → gemini/gemini-2.5-flash
- added if/deepseek-v3.2 as replacement for qw/qwen3-coder-plus
2026-03-17 01:48:40 -03:00
Regis
0aede2ef63 feat(health): background health check for local provider_nodes
Local inference backends (oMLX, Ollama, LM Studio) configured as
provider_nodes have no health monitoring. When a local provider is
down, OmniRoute waits the full timeout before failing.

This adds a background health check that polls local provider_nodes:
- GET /models with 5s timeout for each local node (localhost only)
- In-memory health cache (no DB migration needed)
- Promise.allSettled for parallel checks (one slow node doesn't block)
- Exponential backoff on failures: 30s → 60s → 120s → 300s max
- Reset to 30s on first success after failure
- State transition logging (healthy ↔ unhealthy)
- Expose health status via GET /api/monitoring/health (localProviders)
- Auto-init on first import (same pattern as tokenHealthCheck)
- 401 treated as healthy (server up, auth required)
- isNodeHealthy() returns true if never checked (optimistic default)
2026-03-16 22:44:43 +01:00
Regis
1e3a2e0a27 feat(embeddings): route embedding requests to local provider_nodes
Embedding endpoint (/v1/embeddings) only supports 6 hardcoded cloud
providers. Local inference backends (oMLX, Ollama) serving embeddings
via provider_nodes are inaccessible through OmniRoute.

This adds dynamic provider_node support for embeddings:
- Add EmbeddingProvider interface and buildDynamicEmbeddingProvider()
- Add Phase 2 (provider_nodes prefix match) in parseEmbeddingModel()
- Handler accepts resolvedProvider/resolvedModel from route (injection pattern)
- Handler supports authType=none for local providers (was missing — critical gap)
- Route loads local provider_nodes (localhost only — prevents auth bypass/SSRF)
- Route filters by apiType=chat|responses and localhost hostname
- buildDynamicEmbeddingProvider validates inputs (prefix + baseUrl required)
- Per-node try/catch in map — one bad row doesn't block all providers
- DB errors logged and fall back to hardcoded providers
2026-03-16 22:15:49 +01:00
Prakersh Maheshwari
1bdabf43db fix: prevent mutation of original request body in Claude passthrough
Use shallow copy ({ ...body }) instead of direct reference assignment
so that later translatedBody.model = model does not mutate the
caller's original body object.
2026-03-17 02:45:21 +05:30
Prakersh Maheshwari
05e568feb0 fix(sse): extract Claude SSE usage in passthrough stream mode 2026-03-17 02:41:54 +05:30
Prakersh Maheshwari
81e2519436 refactor: replace as any casts with explicit inline types
Addresses PR review: use `{ id?: string }[]` and
`{ type?: string; call_id?: string }` instead of `any`.
2026-03-17 02:40:36 +05:30
Prakersh Maheshwari
ef623c9bb5 refactor: trim function name consistently in Responses-to-Chat direction
Addresses PR review: both translation directions now trim the function
name the same way, matching the Chat-to-Responses pattern.
2026-03-17 02:35:42 +05:30
Prakersh Maheshwari
da581525a6 fix(sse): strip Claude-specific fields in OpenAI format cleanup 2026-03-17 02:16:26 +05:30
Prakersh Maheshwari
6ff7b6570c fix(sse): add Claude-to-Claude passthrough for anthropic-compatible providers
When both source and target formats are Claude, skip all request
modification and forward the body untouched. This prevents
prepareClaudeRequest from corrupting valid Claude-native requests
destined for anthropic-compatible provider nodes.
2026-03-17 02:03:45 +05:30
Prakersh Maheshwari
8b2081837e fix(sse): filter orphaned tool results after context compaction
When Claude Code compacts conversation context to fit within token
limits, it may remove assistant messages containing tool_use/tool_calls
while leaving the corresponding tool_result/function_call_output
messages intact. This creates orphaned tool results that cause
providers to reject requests with errors like "tool result's tool id
not found" or "No tool call found for function call output".
2026-03-17 01:59:40 +05:30
Prakersh Maheshwari
ce978b602a fix(sse): skip empty-name tool calls in Responses API translator
Prevents infinite retry loops when models generate tool calls with
empty function names. The normalizeToolName function converted these
to "placeholder_tool" which does not exist in any client's tool
registry, causing repeated error-retry cycles.
2026-03-17 01:47:22 +05:30
dependabot[bot]
9b00f5d550 deps: bump the development group with 4 updates
Bumps the development group with 4 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [lint-staged](https://github.com/lint-staged/lint-staged), [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@types/node` from 25.4.0 to 25.5.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `lint-staged` from 16.3.2 to 16.4.0
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.3.2...v16.4.0)

Updates `typescript-eslint` from 8.57.0 to 8.57.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.1/packages/typescript-eslint)

Updates `vitest` from 4.0.18 to 4.1.0
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.0/packages/vitest)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: lint-staged
  dependency-version: 16.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: typescript-eslint
  dependency-version: 8.57.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
- dependency-name: vitest
  dependency-version: 4.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 19:04:07 +00:00
dependabot[bot]
d98ec59c79 deps: bump the production group with 5 updates
Bumps the production group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) | `12.6.2` | `12.8.0` |
| [https-proxy-agent](https://github.com/TooTallNate/proxy-agents/tree/HEAD/packages/https-proxy-agent) | `7.0.6` | `8.0.0` |
| [undici](https://github.com/nodejs/undici) | `7.24.2` | `7.24.4` |
| [wreq-js](https://github.com/sqdshguy/wreq-js) | `2.1.1` | `2.2.0` |
| [zustand](https://github.com/pmndrs/zustand) | `5.0.11` | `5.0.12` |


Updates `better-sqlite3` from 12.6.2 to 12.8.0
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](https://github.com/WiseLibs/better-sqlite3/compare/v12.6.2...v12.8.0)

Updates `https-proxy-agent` from 7.0.6 to 8.0.0
- [Release notes](https://github.com/TooTallNate/proxy-agents/releases)
- [Changelog](https://github.com/TooTallNate/proxy-agents/blob/main/packages/https-proxy-agent/CHANGELOG.md)
- [Commits](https://github.com/TooTallNate/proxy-agents/commits/https-proxy-agent@8.0.0/packages/https-proxy-agent)

Updates `undici` from 7.24.2 to 7.24.4
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.24.2...v7.24.4)

Updates `wreq-js` from 2.1.1 to 2.2.0
- [Release notes](https://github.com/sqdshguy/wreq-js/releases)
- [Commits](https://github.com/sqdshguy/wreq-js/compare/v2.1.1...v2.2.0)

Updates `zustand` from 5.0.11 to 5.0.12
- [Release notes](https://github.com/pmndrs/zustand/releases)
- [Commits](https://github.com/pmndrs/zustand/compare/v5.0.11...v5.0.12)

---
updated-dependencies:
- dependency-name: better-sqlite3
  dependency-version: 12.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production
- dependency-name: https-proxy-agent
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: production
- dependency-name: undici
  dependency-version: 7.24.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production
- dependency-name: wreq-js
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production
- dependency-name: zustand
  dependency-version: 5.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 19:03:12 +00:00
Regis
d79b55be5a fix(sse): strip unsupported params for reasoning models (o1/o3)
Reasoning models (o1, o1-pro, o3, o3-mini) reject standard parameters
like temperature and top_p with 400 Bad Request. OmniRoute's default
executor forwards all parameters without filtering.

This fix adds declarative parameter filtering:
- Add unsupportedParams[] field to RegistryModel interface
- Add REASONING_UNSUPPORTED frozen constant shared across entries
- Add o1-pro, o3, o3-mini to OpenAI registry (were missing)
- Add getUnsupportedParams() helper with:
  - O(1) precomputed map lookup (not O(N×M) scan)
  - Cross-provider routing support via precomputed map
  - Prefixed model ID support (e.g., "openai/o3" → "o3")
- Strip unsupported params in chatCore.ts before executor call
- Use Object.hasOwn() for safe property check (no prototype chain)
- Log stripped params at WARN level for visibility
2026-03-16 19:41:55 +01:00
Regis
1f9a402dcd fix(sse): address bot review — tighten local detection, guard null model
- Remove apiKey===null heuristic (too broad — could match cloud providers
  with non-standard auth). Use URL-based detection only.
- Guard local 404 branch with provider && model check — if either is null,
  fall through to standard connection lockout (safer behavior).
- Document LOCAL_HOSTNAMES as module-load-time constant (restart required).
- Document PROVIDER_PROFILES.local as intentionally not yet wired.
2026-03-16 19:03:47 +01:00
Regis
f9bcc9418b fix(sse): model-only lockout for local provider 404 (connection stays active)
When a local inference backend (oMLX, Ollama, LM Studio) returns 404
for an unknown model, OmniRoute previously locked the entire connection
for 2 minutes — blocking all valid models on that connection.

This fix introduces local provider detection and changes the 404
behavior for local providers:
- Model-only lockout (5s) instead of connection-level lockout (2min)
- Connection stays active — other models continue working immediately
- Detection via URL heuristic (localhost/127.0.0.1) + apiKey===null fallback
- Configurable via LOCAL_HOSTNAMES env var for Docker setups

Also fixes a pre-existing bug where the model parameter was not passed
to markAccountUnavailable() from chat.ts, preventing per-model lockouts
from working at all.

Changes:
- Add isLocalProvider(baseUrl) helper in providerRegistry.ts
- Add COOLDOWN_MS.notFoundLocal (5s) and PROVIDER_PROFILES.local
- Add local 404 branch in markAccountUnavailable() in auth.ts
- Pass model param to markAccountUnavailable() in chat.ts (bug fix)
2026-03-16 18:55:41 +01:00
Regis
08256a3502 feat(api): add Kilo Gateway provider (335+ models, 6 free, auto-routing)
Kilo Gateway (api.kilo.ai/api/gateway) is an OpenAI-compatible API
offering 335+ models via a single API key, including 6 free models
and 3 auto-routing models (frontier/balanced/free).

This is distinct from the existing KiloCode provider which uses
OAuth + /api/openrouter/ endpoint.

- Register kilo-gateway in providerRegistry.ts (alias: kg)
- Add to APIKEY_PROVIDERS in providers.ts
- Add models endpoint config in route.ts
- Add official Kilo AI icon (favicon)
2026-03-16 17:26:27 +01:00
diegosouzapw
9b255e643a chore(release): v2.6.3 — compile-time hash-strip fix, Synthetic provider (PR #404), VPS PM2 path fix 2026-03-16 11:00:43 -03:00
Diego Rodrigues de Sa e Souza
ca1f918e9e Merge pull request #404 from Regis-RCR/feat/synthetic-provider
feat(api): add Synthetic as a new API key provider
2026-03-16 10:59:13 -03:00
diegosouzapw
bb3fe1cd48 fix(build): strip Turbopack hashed require() from compiled server chunks in prepublish
Even with EXPERIMENTAL_TURBOPACK=0 and NEXT_PRIVATE_BUILD_WORKER=0, Next.js 16
instrumentation chunks still emit require('better-sqlite3-<16hexchars>') and
require('zod-<16hexchars>') into the compiled .js files inside .next/server/.

The webpack externals function in next.config.mjs patches the runtime bundler
but does NOT rewrite already-compiled chunks. Added step 5.6 to prepublish.mjs:
walks all .js files in app/.next/server/ and strips the 16-char hex suffix from
any require() string that matches the Turbopack hash pattern.

Also updated deploy-vps workflow: npm registry rejects 299MB packages, so
deployment now uses npm pack + scp + npm install -g /tmp/omniroute-*.tgz.
PM2 entry point is app/server.js inside the npm global package.
2026-03-16 10:46:27 -03:00
diegosouzapw
5d7772ecb0 chore(release): v2.6.2 — fix all module hashing, Anthropic tools filter, custom endpoint paths, Alibaba Cloud provider 2026-03-16 09:53:32 -03:00
Diego Rodrigues de Sa e Souza
56ce618eca Merge pull request #400 from Regis-RCR/feat/custom-endpoint-paths
feat(api): custom endpoint paths for compatible provider nodes
2026-03-16 09:46:22 -03:00
Diego Rodrigues de Sa e Souza
b0381c7542 Merge pull request #397 from xandr0s/fix/tools-filter-claude-format
fix(chat): handle Anthropic-format tools in empty-name filter (#346)
2026-03-16 09:40:39 -03:00
Diego Rodrigues de Sa e Souza
b328ed5fa9 Merge pull request #403 from diegosouzapw/fix/issue-396-398-hashed-externals-all-packages
fix(build): extend externals hash-strip to cover ALL Turbopack-hashed packages (#396, #398)
2026-03-16 09:37:05 -03:00
diegosouzapw
7d72f1711f fix(build): extend externals hash-strip to cover ALL packages, not just better-sqlite3 (#396, #398)
Turbopack in Next.js 16 hashes ALL serverExternalPackages (not just better-sqlite3),
emitting require() calls like 'zod-dcb22c6336e0bc69', 'pino-28069d5257187539' etc.
that don't exist in node_modules.

Changes:
- next.config.mjs: Replace single-package check with a HASH_PATTERN regex
  that strips '<name>-<16hexchars>' suffix for any externalized package.
  Also adds KNOWN_EXTERNALS set for exact-name matching.
- scripts/prepublish.mjs: Add NEXT_PRIVATE_BUILD_WORKER=0 env to reinforce
  webpack mode. Add post-build scan that reports hashed refs so CI is visible.

Closes #396, addresses #398
2026-03-16 09:34:34 -03:00
Regis
d139b4557f feat(api): add Synthetic as a new API key provider
Add Synthetic (synthetic.new) as a privacy-focused LLM provider
with OpenAI-compatible API, dynamic model catalog via /models
endpoint, and passthrough model support.

- Register provider in providerRegistry.ts with 6 initial models
- Add APIKEY_PROVIDERS entry with verified_user icon (#6366F1)
- Add models listing config for /api/providers/[id]/models endpoint
- passthroughModels enabled for dynamic model catalog
2026-03-16 12:39:23 +01:00
Regis
cd05e03d63 fix(review): simplify cascade logic and add ARIA attributes
Address review feedback:
- Simplify providerSpecificData cascade for chatPath/modelsPath
  using `|| undefined` instead of conditional spreads (Gemini)
- Add aria-expanded, aria-controls, aria-hidden to Advanced
  Settings toggle buttons for accessibility (Copilot)
2026-03-16 11:29:06 +01:00
Regis
e25029939d feat(api): add custom endpoint paths for compatible provider nodes
Allow provider_nodes to configure custom chat and models endpoint
paths via chatPath/modelsPath fields. This enables providers with
non-standard versioned APIs (e.g. /v4/chat/completions) to work
without embedding the version prefix in base_url.

- Add migration 003: chat_path and models_path columns
- Update Zod schemas (create, update, validate)
- Update CRUD in providers.ts (INSERT/UPDATE)
- Wire chatPath/modelsPath through API routes and providerSpecificData cascade
- Read chatPath in DefaultExecutor and BaseExecutor buildUrl()
- Use modelsPath in validate endpoint
- Add Advanced Settings UI section (collapsible) in create/edit modals
- Update base URL hint to reference Advanced Settings
- Add i18n keys across all 30 locales
- Add unit tests for buildUrl with custom paths

Backward compatible: NULL chatPath/modelsPath = default behavior.
2026-03-16 10:23:44 +01:00
Oleg Saprykin
53de27417d fix(chat): handle Anthropic-format tools in empty-name filter (#346)
The filter introduced in #346 only checked OpenAI-format tool names
(tool.function.name), silently dropping all tools when the request
arrives in Anthropic Messages API format (tool.name without .function).

This happens when LiteLLM proxies requests with anthropic/ model prefix —
it translates to Anthropic format before forwarding, so OmniRoute receives
Claude-format tools. The filter drops them all, causing Anthropic API to
return 400: 'tool_choice.any may only be specified while providing tools'.

Fix: check both formats with fn?.name ?? tool.name.
2026-03-16 11:37:40 +03:00
diegosouzapw
74d3374d5c chore(release): v2.6.1 — fix better-sqlite3 startup crash on npm global installs (#394) 2026-03-15 21:51:35 -03:00
Diego Rodrigues de Sa e Souza
3ae00bebe4 Merge pull request #395 from diegosouzapw/fix/issue-394-better-sqlite3-module-resolution
fix(build): force better-sqlite3 webpack external to prevent hash-based module name in instrumentation hook (#394)
2026-03-15 21:47:46 -03:00
diegosouzapw
f9df72c4d7 fix(build): force better-sqlite3 webpack external to prevent hash-based module name in instrumentation hook (#394) 2026-03-15 21:45:19 -03:00
diegosouzapw
d0fb4576a8 ci: add workflow_dispatch to npm-publish, fix version sync for manual triggers 2026-03-15 20:20:44 -03:00
Diego Rodrigues de Sa e Souza
0e4b0b3540 Merge pull request #393 from diegosouzapw/fix/issue-392-docker-workflow
fix: add workflow_dispatch to docker-publish, update action versions (#392)
2026-03-15 20:11:54 -03:00
diegosouzapw
df1105d0c6 fix: add workflow_dispatch to docker-publish, update action versions (#392) 2026-03-15 20:06:49 -03:00
diegosouzapw
44478c36a3 chore(release): v2.6.0 — issue resolution sprint (#390 #340 #344 #377 #378 #337) 2026-03-15 19:15:38 -03:00
Diego Rodrigues de Sa e Souza
fa267274b0 Merge pull request #386 from kfiramar/chore-test-script-loader-consistency
chore(tests): align targeted test runners
2026-03-15 19:08:47 -03:00
Diego Rodrigues de Sa e Souza
0db272946a Merge pull request #391 from diegosouzapw/fix/multi-issues-390-340-378
fix(media,auth,oauth): hide unconfigured local providers, round-robin improvement, OAuth popup fix
2026-03-15 19:08:45 -03:00
diegosouzapw
91015b6499 fix(media,auth,oauth): hide unconfigured local providers, improve round-robin, fix OAuth popup (#390 #340 #344) 2026-03-15 18:48:40 -03:00
diegosouzapw
2979a36a7c chore(release): v2.5.9 — codex passthrough + route validation + JWT persist 2026-03-15 15:46:06 -03:00
Diego Rodrigues de Sa e Souza
72f6d6b7b9 Merge pull request #388 from kfiramar/fix-route-validation-t06
fix(build,api): restore production build and validate route bodies
2026-03-15 15:43:32 -03:00
Diego Rodrigues de Sa e Souza
d81a7bcedf Merge pull request #387 from kfiramar/feat-codex-native-responses-parity
All tests pass except pre-existing clearAccountError module resolution (dataPaths) which is unrelated to this PR. Merging codex native passthrough fix.
2026-03-15 15:43:11 -03:00
Kfir Amar
8fbbe8b82b Revert "fix(api): validate pricing sync and task routing routes"
This reverts commit 7c992ffd21.
2026-03-15 20:37:18 +02:00
Kfir Amar
271f5f9c64 Revert "fix(api): validate pricing sync and task routing routes"
This reverts commit fc2af8ba87.
2026-03-15 20:37:18 +02:00
Kfir Amar
7c992ffd21 fix(api): validate pricing sync and task routing routes 2026-03-15 20:30:00 +02:00
Kfir Amar
fc2af8ba87 fix(api): validate pricing sync and task routing routes 2026-03-15 20:30:00 +02:00
Kfir Amar
c8a539a6cb fix(review): surface secret fallback and tighten error typing 2026-03-15 20:25:12 +02:00
Kfir Amar
b7cdaa662a fix(api): validate pricing sync and task routing routes 2026-03-15 20:25:12 +02:00
Kfir Amar
0a25930020 fix(mitm): use standalone-safe server entrypoint 2026-03-15 20:25:12 +02:00
Kfir Amar
8643f4015f fix(build): restore webpack production build 2026-03-15 20:25:11 +02:00
diegosouzapw
1854711aff fix(build): fix Next.js 16 Turbopack standalone build for npm publish
- instrumentation.ts: eval(require) → createRequire (banned in Turbopack edge runtime)
- mitm/manager.ts: static imports → lazy require getters to prevent Turbopack trace
- mitm/manager.stub.ts: build-time stub for turbopack.resolveAlias
- antigravity-mitm/route.ts: dynamic imports + nodejs runtime + remove use server
- next.config.mjs: turbopack.resolveAlias for mitm stub + expanded serverExternalPackages
- prepublish.mjs: remove --webpack flag (removed in Next.js 15+)
2026-03-15 15:18:00 -03:00
diegosouzapw
c905119d82 fix(build): remove --webpack from prepublish.mjs — fixes VPS app/server.js missing in npm package 2026-03-15 14:56:20 -03:00
diegosouzapw
c581ca8339 fix(build): remove deprecated --webpack flag from next build script 2026-03-15 14:05:46 -03:00
diegosouzapw
ccf9d9214a chore(release): v2.5.7 — media playground error handling fixes 2026-03-15 13:55:28 -03:00
diegosouzapw
d37c8b732f fix(media): proper JSON error responses + fix false-positive empty transcript credential error 2026-03-15 13:54:33 -03:00
diegosouzapw
f707fc1cad fix(media): proper JSON error responses + fix false-positive empty transcript credential error 2026-03-15 13:52:34 -03:00
Kfir Amar
b1c713de60 fix(codex): avoid mutating request body 2026-03-15 18:35:43 +02:00
Kfir Amar
0f13965391 chore(tests): align targeted test runners 2026-03-15 18:25:22 +02:00
Kfir Amar
8642e2b721 fix(codex): preserve native responses payloads 2026-03-15 18:25:22 +02:00
diegosouzapw
441534853b chore(release): v2.5.6 — Antigravity OAuth fix, JWT session persistence 2026-03-15 13:05:52 -03:00
Diego Rodrigues de Sa e Souza
82f42c8664 Merge pull request #385 from diegosouzapw/fix/issue-382-jwt-persistence
fix: persist JWT_SECRET to SQLite so restarts don't invalidate sessions (#382)
2026-03-15 13:04:57 -03:00
Diego Rodrigues de Sa e Souza
5cd318fa9a Merge pull request #384 from diegosouzapw/fix/issue-383-antigravity-oauth-secret
fix: add Antigravity OAuth clientSecret fallback (#383)
2026-03-15 13:04:55 -03:00
diegosouzapw
5506071e9a fix: add Antigravity OAuth clientSecret fallback — empty string caused 'client_secret is missing' (#383) 2026-03-15 12:58:51 -03:00
diegosouzapw
ced98f2da7 fix: persist JWT_SECRET to SQLite so restarts don't invalidate sessions (#382) 2026-03-15 12:56:52 -03:00
diegosouzapw
282ec65e8b docs(i18n): sync FEATURES.md v2.5.5 update to 30 languages 2026-03-15 12:45:20 -03:00
diegosouzapw
8e06dc5ace chore(release): v2.5.5 — model list dedup, Electron build hardening, Kiro credit tracking 2026-03-15 12:34:58 -03:00
Diego Rodrigues de Sa e Souza
bfd3e2c01b Merge pull request #381 from diegosouzapw/feat/issue-337-kiro-credits
feat: add Kiro credit tracking in usage fetcher (#337)
2026-03-15 12:33:14 -03:00
Diego Rodrigues de Sa e Souza
a1957f0923 Merge pull request #380 from diegosouzapw/fix/issue-353-model-list-dedup
fix: include provider aliases in active provider filter (#353)
2026-03-15 12:33:13 -03:00
Diego Rodrigues de Sa e Souza
11a02ba361 Merge pull request #379 from kfiramar/fix/electron-standalone-bundle-pr
fix(electron): reject symlinked standalone bundles
2026-03-15 08:52:44 -03:00
diegosouzapw
4643c19abc feat: add Kiro credit tracking in usage fetcher (#337) 2026-03-15 08:47:27 -03:00
diegosouzapw
a3369df62f fix: include provider aliases in active provider filter (#353) 2026-03-15 08:44:05 -03:00
Kfir Amar
4297c42597 chore(electron): add contextual staging errors 2026-03-15 12:33:16 +02:00
Kfir Amar
e06e7157ac fix(electron): sanitize staged bundle paths cross-platform
Match both slash styles when removing build-machine paths from the
staged standalone bundle so the sanitization step works on Windows
and POSIX builds.

While touching the helper, replace the custom basename logic with
Node's built-in `path.basename` for clarity.
2026-03-15 12:26:23 +02:00
Kfir Amar
22f9e6f4c0 fix(electron): stage standalone bundle for desktop builds
Prepare a dedicated `.next/electron-standalone` bundle before
running electron-builder so desktop packaging operates on a stable,
Electron-specific server payload.

This also adds a preflight that rejects standalone bundles whose
top-level `node_modules` is a symlink, because electron-builder
preserves `extraResources` symlinks and would otherwise ship an app
that depends on the build machine at runtime.
2026-03-15 12:26:23 +02:00
diegosouzapw
4b7a9233e7 chore(release): v2.5.4 — logger fix, login bootstrap, HMR origins, CI hardening 2026-03-15 01:12:27 -03:00
Diego Rodrigues de Sa e Souza
204839f702 Merge pull request #374 from kfiramar/fix/dev-allowed-origins
fix(dev): allow loopback HMR origins
2026-03-15 01:10:56 -03:00
Diego Rodrigues de Sa e Souza
d15e3109ee Merge pull request #375 from kfiramar/fix/login-bootstrap-metadata
fix(login): use public bootstrap route
2026-03-15 01:10:54 -03:00
Diego Rodrigues de Sa e Souza
8b513ee8f8 Merge pull request #376 from kfiramar/fix/logger-transport
fix(logger): restore transport logger path
2026-03-15 01:10:47 -03:00
diegosouzapw
2c1488e65a fix(ci): fix eslint OOM, failing tests, and strengthen pre-commit hook
- eslint.config.mjs: add missing ignores for vscode-extension/,
  electron/, docs/, app/.next/, clipr/ — ESLint was OOMing because
  it scanned huge VS Code binary blobs and build artifacts
- tests: remove stale ALTER TABLE 'group' statements — column is now
  part of the base schema in core.ts; tests were failing with
  SQLITE_ERROR: duplicate column name
- .husky/pre-commit: add npm run test:unit to block broken tests
  from reaching CI
2026-03-15 00:59:22 -03:00
Kfir Amar
8ebe1cc2d8 test(config): tighten dev origins assertion 2026-03-15 02:06:49 +02:00
Kfir Amar
b0d6c15e63 fix(auth): harden login bootstrap checks
Stabilize the bootstrap metadata test by clearing
INITIAL_PASSWORD before each run and add focused coverage
for env-backed and stored-password states.

Log settings lookup failures before returning the
bootstrap-safe fallback payload so operational errors are
still visible on the server side.
2026-03-15 02:06:49 +02:00
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
783d7ae605 test(dev): cover loopback dev origins
Add a focused config regression test that locks in localhost, 127.0.0.1, and the existing LAN dev origin allowlist.
2026-03-15 01:51:59 +02:00
Kfir Amar
bbf7a6b2f8 test(login): cover bootstrap metadata route
Add a focused unit test for the public login bootstrap route so the branch is backed by the exact response contract the login page now relies on.
2026-03-15 01:51:59 +02:00
Kfir Amar
0fe6e24554 fix(logger): support transport targets
Keep the existing level formatter for direct logger paths, but drop
that formatter from transport-backed configs because pino rejects it
when transport.targets is used.

This restores the intended stdout+file transport path and avoids the
startup fallback warning on every boot.
2026-03-15 01:17:04 +02:00
Kfir Amar
4bbaf55586 fix(dev): allow localhost HMR origins
Add localhost and 127.0.0.1 to allowedDevOrigins so local dev
sessions opened on loopback addresses do not have their Next.js HMR
websocket blocked as cross-origin.
2026-03-15 01:17:04 +02:00
Kfir Amar
cda765a02d fix(login): use public bootstrap settings
Point the login page at the existing public bootstrap endpoint
instead of the protected /api/settings route.

Also extend the public bootstrap response with hasPassword and
setupComplete so unauthenticated users get the correct first-run
or password-setup flow without triggering a 401.
2026-03-15 01:17:04 +02:00
diegosouzapw
36856b18db chore: release v2.5.3
bug fixes (PRs #373, #371, #372, #369 by @kfiramar):
- fix(db): provider_connections.group column migration for existing DBs
- fix(i18n): replace missing deleteConnection key with delete in tooltip
- fix(auth): clear stale error metadata on genuine provider recovery
- fix(startup): unify env loading across npm/electron startup paths

code quality improvements (per kilo-code-bot review):
- docs: document result.success vs response.ok patterns in auth.ts
- refactor: normalize overridePath?.trim() in electron/main.js
- docs: explain preferredEnv merge order intent
2026-03-14 19:53:59 -03:00
Diego Rodrigues de Sa e Souza
66f0a8f994 Merge pull request #369 from kfiramar/fix-startup-env-key-loading
Thanks @kfiramar! 🎉 Critical security fix — different startup paths were generating different `STORAGE_ENCRYPTION_KEY` values over the same SQLite database, causing `Unsupported state or unable to authenticate data` for all stored tokens.

Improvements added on top:
- Normalized `overridePath?.trim()` in `electron/main.js` to match `bootstrap-env.mjs` (addresses kilo-code-bot warning #1)
- Added explanatory comment documenting the `preferredEnv` merge order intent in Electron startup (addresses kilo-code-bot warning #3)

4 commits + 113-line test file. The fail-closed behaviour (refusing to mint a new key when encrypted rows exist) is an excellent safeguard. Merged!
2026-03-14 19:52:09 -03:00
Diego Rodrigues de Sa e Souza
455231170f Merge pull request #372 from kfiramar/fix/clear-provider-error-state
Thanks @kfiramar! 🎉 Critical fix — stale error metadata on recovered provider accounts was preventing valid accounts from being selected properly after recovery. 

Improvement added on top: documented the two valid success-check patterns (`result.success` for open-sse handlers vs `response?.ok` for fetch-based handlers) to address the kilo-code-bot review warning — both patterns are correct by design, now explicitly documented.

5 commits total, 2 test files (+168 lines of coverage). Merged!
2026-03-14 19:49:51 -03:00
Diego Rodrigues de Sa e Souza
5faeb58ab0 Merge pull request #371 from kfiramar/fix/provider-delete-tooltip-i18n
Thanks @kfiramar! Perfect minimal fix — `t("deleteConnection")` was requesting a non-existent key across all 30 locales, causing `MISSING_MESSAGE: providers.deleteConnection` runtime errors on every provider detail page load. Reusing the existing `providers.delete` key is the correct fix. Merged!
2026-03-14 19:48:01 -03:00
Diego Rodrigues de Sa e Souza
056e4a88ff Merge pull request #373 from kfiramar/fix/provider-connections-group-migration
Thanks @kfiramar! 🎉 Critical schema fix — the `group` column was used in all provider_connections queries but missing from the base schema and backfill migration. Databases upgraded from older versions were silently failing on group-related queries. Clean fix with regression test. Merged!
2026-03-14 19:47:58 -03:00
Kfir Amar
8fd944ccf7 fix(auth): type recovered state helpers
Tighten the helper signatures added for recovered provider cleanup.

This removes the new any-typed recovery parameters called out in
review without broadening the PR into unrelated auth typing work.
2026-03-14 23:11: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
Kfir Amar
9806648c07 test(auth): cover stale active error metadata path
Refine the recovered-account regression test to match the real
observed state: an account can remain active while still carrying
stale refresh-failure metadata.

This verifies that getProviderCredentials surfaces those fields
and that clearAccountError clears them through the real runtime
path.
2026-03-14 22:31:03 +02:00
Kfir Amar
6186babdb3 fix(auth): include error fields in recovery path
Pass errorCode, lastErrorType, and lastErrorSource through the
runtime credentials object so clearAccountError can clear stale
provider error metadata after a real successful request.

Also update the regression test to use getProviderCredentials,
matching the production call path.
2026-03-14 22:24:08 +02:00
Kfir Amar
f2ecefb54a fix(i18n): use existing provider delete label
Replace a missing deleteConnection message lookup with the
existing delete label to avoid the provider-page runtime i18n
overlay.
2026-03-14 22:18:41 +02:00
Kfir Amar
43bd529b78 fix(db): add provider connection group migration
Add the missing provider_connections.group column to both the
base schema and the runtime column backfill path.

Also add a regression test covering upgrade from an older
database that does not yet have the column.
2026-03-14 22:18:41 +02:00
Kfir Amar
9c82b3d4ca fix(auth): clear stale provider error metadata
Clear errorCode, lastErrorType, and lastErrorSource when an
account recovers so provider state returns to a fully clean
active status.

Add a focused regression test for recovered-account cleanup.
2026-03-14 22:18:41 +02:00
Kfir Amar
b19e6a8e87 fix(startup): pass env through env-file lookup
Keep getPreferredEnvFilePath consistent with its env parameter by
passing that env through resolveDataDir in both bootstrap and Electron.

This avoids silently falling back to process.env when a custom env map
is supplied.
2026-03-14 21:33:34 +02:00
Kfir Amar
e3a2bd75f3 fix(startup): ignore blank data dir override
Treat empty or whitespace-only dataDirOverride values as unset so
bootstrapEnv keeps using the normal DATA_DIR and .env lookup path.

Adds a focused regression test for the whitespace override case.
2026-03-14 21:29:34 +02:00
Kfir Amar
da39e1485f fix(startup): fail closed on key inspection errors
Propagate database inspection failures instead of treating them as
missing encrypted credentials.

This keeps startup from generating a fresh encryption key when an
existing database cannot be inspected and adds a regression test for
that path.
2026-03-14 21:23:07 +02:00
Kfir Amar
88cc53a4b0 fix(startup): honor documented env loading
Align the app bootstrap paths with the documented CLI env lookup.

The CLI wrapper already loads DATA_DIR/.env, ~/.omniroute/.env, or ./.env,
but run-next, run-standalone, and Electron were bypassing that behavior.
On machines with encrypted credentials, that could generate a fresh
STORAGE_ENCRYPTION_KEY in server.env and make existing tokens unreadable.

This change:
- uses the same preferred .env lookup in bootstrapEnv and Electron
- keeps Electron secrets rooted in DATA_DIR and passes DATA_DIR to the child
- refuses to mint a new encryption key over an existing encrypted database
- adds a focused regression test for env precedence and key safety
2026-03-14 21:14:19 +02:00
diegosouzapw
245243c7e7 chore: release v2.5.2 (version bump, npm conflict with 2.5.1) 2026-03-14 16:01:14 -03:00
diegosouzapw
759ac0df3d chore: release v2.5.1
- PR #368: gpt-5.4 in Codex model registry (cx/gpt-5.4, codex/gpt-5.4)
- PR #367: Codex fast tier toggle (default-off, full stack, 48 tests)
- PR #366: Codex quota policy 5h/weekly with auto-rotation
- fix #356: analytics charts show provider display names not raw IDs
2026-03-14 15:55:06 -03: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
Diego Rodrigues de Sa e Souza
ca7854210d Merge pull request #368 from kfiramar/fix-codex-gpt54-models
Thanks @kfiramar! gpt-5.4 is now exposed in the model catalog as `cx/gpt-5.4` and `codex/gpt-5.4`. Minimal, tested fix — merged directly. 🙏
2026-03-14 15:49:54 -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
diegosouzapw
4d086542aa fix: getProviderCredentials missing allowedConnections param (#363 TS error)
PR #363 added allowedConnections as 3rd arg in chat.ts calls to
getProviderCredentials(), but the function signature in auth.ts
only declared 2 params. Adding the optional 3rd param and applying
the connection filter when provided.
2026-03-14 15:38:12 -03:00
rexname
1555883633 fix(codex): address PR review feedback for quota policy flow
- add user-facing success/error notifications for Codex limit toggle API calls
- deduplicate Codex policy default normalization in providers page
- make getQuotaWindowStatus side-effect free (no cache mutation in getter)
- avoid stale threshold blocking after resetAt has passed
- extract named Codex quota threshold constant
- extract helper for earliest future reset date selection
2026-03-15 01:35:19 +07:00
Kfir Amar
8f2c0acc7e fix(codex): advertise gpt-5.4 models
Add gpt-5.4 to the Codex model registry so OmniRoute exposes cx/gpt-5.4 and codex/gpt-5.4 in its model catalog.

Includes a focused regression test for model resolution.
2026-03-14 20:33:47 +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
da14390fe0 chore: release v2.5.0
Includes:
- PR #363: strict-random strategy, API key controls, connection groups, Limits UX (AndersonFirmino)
- PR #365: external pricing sync with LiteLLM 3-tier resolution (Regis-RCR)
- fix #355: stream idle timeout 60s → 300s for thinking models
- fix #350: combo test bypasses REQUIRE_API_KEY via X-Internal-Test header
- fix #346: filter tools with empty function.name before forwarding upstream
2026-03-14 15:31:27 -03:00
diegosouzapw
11c0cff4ef merge: bug fixes for #355 #350 #346 into main 2026-03-14 15:30:36 -03:00
Diego Rodrigues de Sa e Souza
e322376996 Merge pull request #363 from AndersonFirmino/feat/strict-random-i18n-ux
Merged! Excellent contribution @AndersonFirmino 🎉

This PR delivers four major improvements:
- **strict-random** strategy — Fisher-Yates shuffle deck with anti-repeat guarantee and mutex serialization for concurrent safety
- **API key controls** — allowedConnections, is_active, accessSchedule, autoResolve
- **Connection groups** — environment-based grouping view in Limits page with localStorage persistence  
- **i18n** — 30 languages fully updated, pt-BR fully translated

655 tests passing. Merged with main (v2.4.4) — no conflicts. Thank you for the exceptional quality!
2026-03-14 15:30:19 -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
Diego Rodrigues de Sa e Souza
2cd0f60c3c Merge pull request #365 from Regis-RCR/feat/pricing-sync
Merged via review workflow. Excellent contribution by @Regis-RCR — 3-tier pricing resolution with LiteLLM sync, 23 tests, fully opt-in. Minor improvement noted: dashboard UI for sync status will be added in a follow-up.
2026-03-14 15:23:48 -03:00
diegosouzapw
1b354be827 feat: T07 — API Key Round-Robin per provider connection
- New: open-sse/services/apiKeyRotator.ts — round-robin rotation
  between primary API key + providerSpecificData.extraApiKeys[]
- Modified: open-sse/executors/base.ts — buildHeaders() rotates key
  using getRotatingApiKey() when extraApiKeys configured
- Modified: open-sse/handlers/chatCore.ts — injects connectionId into
  credentials to enable per-connection rotation index tracking
- Modified: providers/[id]/page.tsx — 'Extra API Keys' UI section in
  EditConnectionModal: add/remove keys, persisted in providerSpecificData

T08 (quota window rolling) and T13 (wildcard model routing) confirmed
already implemented in accountFallback.ts and wildcardRouter.ts.
2026-03-14 15:03:54 -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
Anderson Firmino
ad7e7abda0 🐛 fix: propagate allowedConnections from API key to credential selection
getProviderCredentials already filtered by allowedConnections, but
chat.ts never passed the field from apiKeyInfo. Now both call sites
(combo pre-check and credential retry loop) forward the restriction.
2026-03-14 14:03:08 -03:00
Anderson Firmino
02ccb35e80 ♻️ refactor: consolidate shuffle deck into shared utility with mutex protection
Fixes race condition in combo strict-random (concurrent requests could
reshuffle simultaneously). Eliminates code duplication between combo.ts
and auth.ts by extracting Fisher-Yates shuffle + deck logic into
src/shared/utils/shuffleDeck.ts with per-namespace mutex serialization.
2026-03-14 14:03:08 -03:00
Anderson Firmino
a8a29e17c5 feat: strict-random strategy, API key management, connection groups, Limits UX
- Combo layer: strict-random in combo.ts rotates models uniformly
- Credential layer: strict-random in auth.ts rotates connections/accounts
- Anti-repeat guarantee: last of previous cycle ≠ first of next
- Mutex serialization for concurrent request safety
- Independent decks per combo name and per provider

- allowedConnections: restrict which connections a key can use
- autoResolve: per-key toggle for ambiguous model disambiguation
- is_active: enable/disable key instantly (403 on disabled)
- accessSchedule: time-based access control (hours, days, timezone)
- Rename keys via PATCH /api/keys/:id
- Connection restriction badge in API keys table
- Auto-migration for all new columns

- Connection group field on provider connections
- Environment grouping view in Limits page (group by environment)
- Accordion UI with expand/collapse per group
- localStorage persistence for groupBy, autoRefresh, expandedGroups
- Smart default: auto-switches to environment view when groups exist
- Swap SessionsTab above RateLimitStatus

- strict-random option added to combo strategy dropdown (30 languages)
- strategyGuide.strict-random (when/avoid/example)
- pt-BR: translated all strategyRecommendations from English to Portuguese
- en: added API key management strings (accessSchedule, isActive, etc.)

- 11 tests: shuffle deck mechanics (Fisher-Yates, anti-repeat, decks)
- 6 tests: allowedConnections (schema, DB persistence, cache invalidation)
- 12 tests: API key policy (isActive, accessSchedule, autoResolve, budget)
2026-03-14 14:03:08 -03:00
diegosouzapw
75a6d850fc chore: release v2.4.3
- fix: Codex/GitHub limits page HTTP 500 → graceful 401/403 messages
- fix: MaintenanceBanner false-positive on page load (stale closure)
- fix: add title tooltips to edit/delete buttons in ConnectionCard
- feat: add fill-first and p2c routing strategies to combo picker
- feat: Free Stack template pre-fills 7 free provider models
- feat: combo create/edit modal wider (max-w-4xl)
2026-03-14 12:49:36 -03:00
diegosouzapw
b0f5f92f1a feat(release): v2.4.2 — task-aware routing, HuggingFace/Vertex providers, streaming fixes, token tracking, playground uploads
- feat: Task-Aware Smart Routing (T05) — auto-select model by task type
- feat: HuggingFace and Vertex AI provider support
- feat: Playground audio/image file uploads for transcription and vision
- feat: ModelSelectModal shows ✓ for already-added models (#180)
- fix: Claude Haiku routed to OpenAI without provider prefix (#73)
- fix: Token counts always 0 for Antigravity/Claude streaming (#74)
- fix: OpenAI SDK stream=False drops tool_calls (#302)
- fix: Media page generation errors — inline rendering for images/transcription
- fix: Round-robin state management for excluded accounts (#349)
- fix: Qwen user agent and CLI fingerprint compatibility (#352)
- deps: undici→7.24.2, dompurify→3.3.3, docker actions v4
- docs: CHANGELOG 2.4.2 with full feature/fix list
- docs: README with Task-Aware Routing table entry
2026-03-14 11:04:09 -03: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
Nyaru Toru
5cff98ea75 feat: add Qwen compatibility with updated user agent and CLI fingerprint settings (#352)
Co-authored-by: nyatoru <nyarutoru0002@outlook.co.th>
2026-03-14 10:58:50 -03:00
Nyaru Toru
76127415a4 fix(account-selector): enhance round-robin logic to handle excluded accounts and maintain state (#349)
Co-authored-by: nyatoru <nyarutoru0002@outlook.co.th>
2026-03-14 10:58:48 -03:00
dependabot[bot]
56936fe0e3 deps: bump undici from 7.24.1 to 7.24.2 (#361)
Bumps [undici](https://github.com/nodejs/undici) from 7.24.1 to 7.24.2.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.24.1...v7.24.2)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.24.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-14 10:58:46 -03:00
dependabot[bot]
dfbbbeb1b4 chore(deps): bump docker/setup-buildx-action from 3 to 4 (#343)
* chore(deps): bump docker/setup-buildx-action from 3 to 4

Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Initial plan

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openai-code-agent[bot] <242516109+Codex@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
2026-03-14 10:56:20 -03:00
dependabot[bot]
7f3ffd935e chore(deps): bump docker/setup-qemu-action from 3 to 4 (#342)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-14 10:56:18 -03:00
dependabot[bot]
29cf462d8f deps: bump undici from 7.22.0 to 7.24.1 (#348)
* deps: bump undici from 7.22.0 to 7.24.1

Bumps [undici](https://github.com/nodejs/undici) from 7.22.0 to 7.24.1.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.22.0...v7.24.1)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.24.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Initial plan

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openai-code-agent[bot] <242516109+Codex@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
2026-03-14 10:56:16 -03:00
dependabot[bot]
5e1693e1f7 deps: bump dompurify from 3.3.2 to 3.3.3 (#347) 2026-03-14 10:55:45 -03:00
diegosouzapw
45424ca226 fix(ci): docs-sync, openapi version, changelog format, pre-commit hook
- docs/openapi.yaml: update info.version from 2.3.6 to 2.4.1 (fixes CI check)
- CHANGELOG.md: add '## [Unreleased]' section as first heading (required by check-docs-sync)
- scripts/check-docs-sync.mjs: fix regex to accept both hyphen (-) and em-dash (—)
  as date separators in changelog headings (standard Keep a Changelog format)
- .husky/pre-commit: add 'node scripts/check-docs-sync.mjs' to catch version
  mismatches locally before push
2026-03-13 11:45:32 -03:00
diegosouzapw
d976abb5e0 chore: v2.4.1 — combos free-stack always visible 2026-03-13 11:29:51 -03:00
diegosouzapw
92d302aed3 fix(combos): free-stack template first, 2x2 grid, green highlight badge
- Move 'Free Stack ($0)' to position 1 in COMBO_TEMPLATES (was 4th, invisible in 3-col grid)
- Add isFeatured flag to free-stack for special styling
- Change template grid: grid-cols-3 → 2x2 (sm:grid-cols-2) — all 4 templates visible
- Free Stack: green border/bg (emerald), FREE badge, larger text size
- Other templates: hover styles preserved, → arrow on Apply link
- Increase templates section padding
2026-03-13 11:26:18 -03:00
diegosouzapw
1e93ee5c34 chore: release v2.4.0
Bump from 2.3.17 to 2.4.0 to reflect the significance of this release:
- Free Stack combo template ecosystem
- Transcription playground overhaul (Deepgram default, $200/$50 free badges)
- 44+ providers documented, hasFree badges on NVIDIA/Cerebras/Groq
- README: Start Free section, Free Models section, Free Transcription Combo
- tierPriority as 7th scoring factor in auto-combo UI
- i18n 30 languages fully synced
2026-03-13 11:20:31 -03:00
diegosouzapw
1b6c502c7f feat: free-stack combo, Deepgram transcription default, README free sections, provider hasFree badges
- Combos: add 'Free Stack ($0)' as 4th combo template (round-robin: Kiro+iFlow+Qwen+GeminiCLI)
- Media/Transcription: Deepgram (Nova 3) as default provider, show $200/$50/free badges
- providers.ts: hasFree + freeNote for NVIDIA NIM (40 RPM), Cerebras (1M tok/day), Groq (30 RPM)
- README: new early '🆓 Start Free' 5-step table before Quick Start
- README: new '🎙️ Free Transcription Combo' section (Deepgram/AssemblyAI/Groq)
- README: NVIDIA NIM model list updated (Kimi K2.5, GLM 4.7, DeepSeek V3.2)
- i18n: templateFreeStack + templateFreeStackDesc synced to 30 languages
- Bump version to 2.3.17
2026-03-13 11:13:02 -03:00
diegosouzapw
4e4532c057 docs(readme): 44+ providers, free models section, accurate free tier quotas
- Update provider count from 36+ to 44+ in 3 locations (line 5, unified endpoint, one-endpoint sections)
- Add new section '🆓 Free Models — What You Actually Get' with 7 provider tables:
  - Kiro: 3 Claude models (unlimited via AWS Builder ID)
  - iFlow: 5 models unlimited (kimi-k2-thinking, qwen3-coder-plus, deepseek-r1, minimax-m2.1, kimi-k2)
  - Qwen: 4 models unlimited (qwen3-coder-plus, qwen3-coder-flash, qwen3-coder-next, vision-model)
  - Gemini CLI: 180K/month + 1K/day
  - NVIDIA NIM: ~40 RPM dev-forever (70+ models), transitioning from credits to rate limits
  - Cerebras: 1M tokens/day, 60K TPM / 30 RPM
  - Groq: 30 RPM / 14.4K RPD
- Include $0 Ultimate Free Stack combo recommendation
- Update NVIDIA NIM from '1000 credits' to 'dev-forever free' (×3)
- Add Cerebras row to pricing table
- Fix iFlow 8→5 models (with names), Qwen 3→4 models (with names)
- Bump version to 2.3.16
2026-03-13 11:03:24 -03:00
diegosouzapw
1e57ae5923 docs: CHANGELOG v2.3.15 2026-03-13 10:41:24 -03:00
diegosouzapw
9055fc2129 feat(auto-combo): add tierPriority factor label + autoCombo i18n section (30 languages)
- Add 'tierPriority: 🏷️ Tier' to FACTOR_LABELS in auto-combo dashboard (7th scoring factor)
- Add 'autoCombo' i18n section with 20 keys to en.json
- Sync autoCombo i18n keys to 29 language files (ar, bg, da, de, es, fi, fr, hi, hu, id, it, ja, ko, nl, no, pl, pt-BR, pt, ro, ru, sk, sv, th, tr, uk, vi, zh-CN, zh-TW + all others)
- Bump version to 2.3.15
2026-03-13 10:40:59 -03:00
diegosouzapw
b8fec94b0d feat(release): v2.3.14 — iFlow fix, MITM compile, GeminiCLI fallback, new models, tier scoring API 2026-03-13 10:19:38 -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
diegosouzapw
f6c0744d67 feat(release): v2.3.13 — tiered quota scoring, model fallback, auth fixes, pnpm fix
- Tiered quota scoring (Ultra>Pro>Free) as 7th Auto-Combo factor
- Intra-family model fallback on 404/400/403 errors
- Configurable API bridge timeout (API_BRIDGE_PROXY_TIMEOUT_MS)
- INITIAL_PASSWORD accepted on first login with timingSafeEqual
- README </details> truncation fix (affects all GitHub renders)
- pnpm @swc/helpers override conflict removed
- CLI path injection hardening (isSafePath validator)
- 429 retry, Gemini CLI headers, Claude response_format injection
- deepseek-3.1/3.2, qwen3-coder-next pricing added
- starchart.cc star widget in all 30 READMEs
2026-03-12 18:18:53 -03:00
diegosouzapw
639b49fc5b fix(ci): regenerate package-lock.json after removing @swc/helpers override
The @swc/helpers override removal changed dependency resolution.
npm ci was failing with 'Missing: @swc/helpers@0.5.15 from lock file'.
Updated lock file with npm install --package-lock-only.
2026-03-12 18:17:45 -03:00
diegosouzapw
c0252f7b13 docs: replace star-history.com widget with starchart.cc in all READMEs
star-history.com embeds are often cached and slow to update. The new
starchart.cc widget (variant=adaptive) renders better on both light and
dark themes and updates in real-time.

Updated: README.md + 29 i18n locale READMEs
2026-03-12 18:15:38 -03:00
diegosouzapw
a87d64372f feat: Phase 1 & 2 implementation plan — T1-T10, T12
T1 (openai-to-claude.ts): response_format injection for json_schema/json_object
T2 (base.ts): intra-URL retry for 429 errors (2x, 2s delay)
T3 (gemini-cli.ts): CLI fingerprint headers (User-Agent, X-Goog-Api-Client)
T5 (modelFamilyFallback.ts + chatCore.ts): intra-family model fallback on 400/404
T9 (pricing.ts): deepseek-3.1, deepseek-3.2, qwen3-coder-next pricing
T10 (scoring.ts + modePacks.ts): tierPriority as 7th scoring factor (Ultra>Pro>Free)
T12 (cliRuntime.ts): isSafePath() guard for CLI_*_BIN env var paths
2026-03-12 18:06:53 -03:00
diegosouzapw
02b19e63e8 fix(pnpm): remove @swc/helpers override conflict, add pnpm build-scripts config (#328)
The @swc/helpers override in package.json duplicated the direct dependency
at the exact same version (0.5.19), causing 'EOVERRIDE' errors when pnpm
users tried to rebuild native modules like better-sqlite3.

Fixes:
- Remove redundant 'overrides' block (direct dep already pins 0.5.19)
- Add pnpm.onlyBuiltDependencies for @parcel/watcher, @swc/core,
  better-sqlite3, esbuild, omniroute, sharp (replaces pnpm approve-builds)
- Add pnpm usage note to README Quick Start

Closes #328
2026-03-12 18:06:27 -03:00
diegosouzapw
dba16363b7 fix(api-bridge): make proxy timeout configurable via env (#332)
Add API_BRIDGE_PROXY_TIMEOUT_MS env var to configure the api-bridge
proxy timeout. Default remains 30000ms for backward compatibility.
Handles invalid values with a warning log.

Co-authored-by: hijak <54431520+hijak@users.noreply.github.com>
2026-03-12 18:04:44 -03:00
diegosouzapw
d20a2b3e44 fix(auth): accept INITIAL_PASSWORD when changing first password (#333)
- Use timingSafeEqual for constant-time password comparison
- Require non-empty currentPassword when INITIAL_PASSWORD env is set
- Legacy fallback: allow empty or '123456' when no INITIAL_PASSWORD

Co-authored-by: hijak <54431520+hijak@users.noreply.github.com>
2026-03-12 18:04:20 -03:00
diegosouzapw
677f5f8713 fix(docs): add missing </details> closing tag in Troubleshooting section
The outer <details> block at line 1459 was never closed, causing GitHub
to stop rendering everything below Troubleshooting (Tech Stack, Docs,
Roadmap, Contributors, etc.).

Fixes: README truncation on GitHub
2026-03-12 18:03:43 -03:00
diegosouzapw
7da23a90d4 feat: Make providerId nullable in providersBatchTestSchema and update validation to treat null as an absent value. 2026-03-12 17:08:26 -03:00
diegosouzapw
8dad2d32b6 fix(cli-tools): add opencode to cliRuntime, increase timeouts for slow-start CLIs
- opencode: add to CLI_TOOLS registry with 15s healthcheck timeout
- openclaw/cursor: increase from 12s → 15s (cold-start on VPS)
- continue: add healthcheckTimeoutMs 15s
- VPS: activated CLI_EXTRA_PATHS=/root/.local/bin for kiro-cli visibility
- VPS: installed droid and openclaw npm packages
2026-03-12 16:42:43 -03:00
diegosouzapw
d07a5f0df7 fix(cli-tools): increase kilocode healthcheck timeout from 4s to 15s
kilocode renders ASCII logo banner on startup causing false healthcheck_failed
timeouts on cold-start or low-resource environments (VPS, CI, dashboard)
2026-03-12 16:34:39 -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
7f9ec724ae fix(api-bridge): validate configured proxy timeout value 2026-03-12 17:02:30 +00:00
jack
daaa3a8782 fix(auth): allow INITIAL_PASSWORD when updating first password 2026-03-12 17:00:01 +00:00
jack
d1c62420bf fix(api-bridge): make proxy timeout configurable via env 2026-03-12 16:59:10 +00:00
diegosouzapw
1c10cfe4bc fix(lint): replace as any with Record<string,unknown> in OAuthModal — passes check:any-budget:t11
Also bump version to 2.3.10
2026-03-12 13:48:30 -03:00
diegosouzapw
a4252d52ce docs: add CLI-TOOLS.md guide with all 11 tools + i18n 30 languages
- docs/CLI-TOOLS.md: complete guide covering claude, codex, gemini, opencode,
  cline, kilocode, continue, kiro-cli, cursor, droid (built-in), openclaw (built-in)
- Includes: install commands, per-tool config, quick setup script, troubleshooting table
- All 3 endpoint types documented (/v1/chat/completions, /v1/responses, /v1/completions)
- docs/i18n/<lang>/CLI-TOOLS.md: synced to all 29 languages with translated title + intro
- .gitignore: added !docs/CLI-TOOLS.md to allowlist
2026-03-12 13:41:40 -03: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
763fdf3135 chore: release v2.3.8 — OAuthModal [object Object] fix 2026-03-12 12:42:40 -03:00
diegosouzapw
82314562e7 fix: OAuthModal [object Object] - extract message from error objects
All 3 throw new Error(data.error) replaced with proper extraction:
  typeof error === object ? error.message : error
Fixes Cline and other OAuth providers showing [object Object] on connection failure
2026-03-12 12:39:42 -03:00
diegosouzapw
69e9bd81e9 chore: release v2.3.7
- Cline OAuth base64 decodeURIComponent fix
- OAuth account name normalization (name=email fallback)
- Remove sequential Account N naming
2026-03-12 12:25:17 -03:00
diegosouzapw
26f927f798 fix: replace sequential Account N with stable ID-based fallback for OAuth accounts
Remove Account cntValue+1 sequential naming (confusing when accounts deleted)
Leave name=null when no email → getAccountDisplayName returns Account ID-based label
2026-03-12 12:23:51 -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
diegosouzapw
87ffe41d8c fix: i18n sync 29 langs + provider test [object Object] fix
- Add cliTools.toolDescriptions.opencode, .kiro, guides.opencode, guides.kiro to en.json
- Sync 1111 missing keys across 29 language files (English fallbacks)
- Fix [object Object] in provider batch test modal:
  normalize data.error object to string before setTestResults()
  and in ProviderTestResultsView rendering
- Bump version to 2.3.6
2026-03-12 11:11:15 -03:00
diegosouzapw
943a9374b4 fix: permanent @swc/helpers MODULE_NOT_FOUND fix (#crash)
prepublish.mjs: explicitly copy @swc/helpers into standalone app/node_modules
before packaging. npm tarball will always include it.

postinstall.mjs: fallback copy of @swc/helpers from root node_modules into
app/node_modules/@swc/ when missing after npm install -g.

Fixes server crash after npm install -g omniroute.
2026-03-12 10:42:59 -03:00
diegosouzapw
8956ffef73 chore: release v2.3.4 2026-03-12 10:27:45 -03:00
diegosouzapw
4383e7d807 feat(ui): endpoint page music section, fixed action buttons, provider logos
Endpoints page:
- Add Music Generation section (/v1/music/generations) in Media & Multi-Modal category
- Include music models (type=music) in endpointData and total model count
- Transcription section already shows Deepgram/AssemblyAI via allModels filter

Provider action buttons:
- Remove hover-only behavior from connection action buttons (edit/delete/reauth/proxy)
- Remove hover-only behavior from combo action buttons (test/duplicate/proxy/edit/delete)
- Buttons now always visible for better UX

Provider logos (SVG fallback):
- ProviderCard now tries .svg before showing text initials when .png not found
- Add SVG logos: ElevenLabs, Hyperbolic, AssemblyAI, PlayHT, Inworld, NanoBanana
- Add ollama-cloud.png (official Ollama icon)
2026-03-12 10:21:05 -03:00
diegosouzapw
863055768e fix(docker): copy native-binary-compat.mjs into build image
postinstall.mjs imports native-binary-compat.mjs but the Dockerfile
only copied postinstall.mjs, causing ERR_MODULE_NOT_FOUND during npm ci:

  Cannot find module '/app/scripts/native-binary-compat.mjs'
  imported from /app/scripts/postinstall.mjs
2026-03-12 10:11:50 -03:00
diegosouzapw
2c1da9e146 fix(ci): resolve 3 GitHub Actions workflow failures
- docs/openapi.yaml: bump version 2.3.1 → 2.3.3 (fixes check:docs-sync CI step)
- tests/unit/model-parse.test.mjs: add missing 'import {test}' from node:test (fixes ReferenceError in unit tests)
- electron/package.json: convert author to object with email (fixes fpm .deb build: 'Please specify author email')
2026-03-12 10:10:45 -03:00
diegosouzapw
845787ab7f chore(release): v2.3.3
fix(providers): prevent error boundary crash when Test All fails or times out (PR #330)
2026-03-12 09:56:51 -03:00
Diego Rodrigues de Sa e Souza
1db948e9bb Merge pull request #330 from diegosouzapw/fix/providers-test-all-crash
fix(providers): prevent error boundary crash when Test All fails or times out
2026-03-12 09:56:25 -03:00
diegosouzapw
f0d00bcee5 fix(providers): prevent error boundary when 'Test All' times out or returns bad JSON
- Add AbortController (90s timeout) to handleBatchTest fetch
- Add inner try/catch for res.json() — handles truncated/non-JSON responses
- Guard ProviderTestResultsView against null/undefined results (was crashing → error boundary)
- Improve error check: error path now also guards results.results.length === 0
- Add 'providerTestTimeout' i18n key for friendly timeout message
2026-03-12 09:38:40 -03:00
diegosouzapw
1e9a9adbad chore(release): v2.3.2
feat(claude): [1m] suffix for 1M extended context (PR #311 @DavyMassoneto)
feat(registry): new models for iFlow, Qwen, Kimi (PR #326 @nyatoru)
fix(cli): postinstall binary copy instead of rebuild (PR #327 @ardaaltinors, fixes #321)
docs: English Remote OAuth guide in README (PR #329, fixes #318)
test: 3 unit tests for parseModel [1m] suffix
2026-03-12 07:00:10 -03:00
Diego Rodrigues de Sa e Souza
d87c7c3b8c Merge pull request #311 from DavyMassoneto/fix/merge-duplicates-and-lint-warnings
feat(claude): support [1m] suffix for 1M extended context window
2026-03-12 06:58:57 -03:00
Diego Rodrigues de Sa e Souza
eb3c834609 Merge pull request #326 from nyatoru/update/sync-qwen-iflow-model
feat(registry): add new models to the provider registry
2026-03-12 06:58:12 -03:00
Diego Rodrigues de Sa e Souza
e53c76081f Merge pull request #327 from ardaaltinors/fix/postinstall-copy-native-binary
fix(cli): fix postinstall native binary rebuild regression (#321)
2026-03-12 06:58:10 -03:00
Diego Rodrigues de Sa e Souza
134316328c Merge pull request #329 from diegosouzapw/fix/issue-318-readme-oauth-en
docs: add English Remote OAuth guide to README (#318)
2026-03-12 06:58:07 -03:00
diegosouzapw
4767561f02 docs: add English translation for Remote OAuth section in README (#318)
The '🔐 OAuth on a Remote Server' guide existed only in Portuguese (#oauth-em-servidor-remoto).
Multiple users (@hijak, @ldsgroups225, @vipinpg) couldn't find it in English.

Changes:
- Full English step-by-step guide added above the existing PT content
- Added 'oauth-on-a-remote-server' anchor (EN) alongside 'oauth-em-servidor-remoto' (PT)
- Portuguese version moved into a collapsible <details> section
- OAuthModal.tsx already updated in v2.3.1 to link to #oauth-on-a-remote-server
2026-03-12 06:56:05 -03:00
Nyaru Toru
2d6b31b606 Update open-sse/config/providerRegistry.ts
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-12 15:08:05 +07:00
ardaaltinors
a22f0a4e7b fix(cli): address review feedback on native binary detection and postinstall
- Read only first 4096 bytes of binary header instead of entire file
- Add error logging to all catch blocks with specific failure messages
- Separate copy vs dlopen catch blocks in postinstall Strategy 1
- Add archCount sanity cap (max 30) for fat Mach-O parsing
- Distinguish timeout vs rebuild failure in Strategy 2
2026-03-12 10:34:56 +03:00
ardaaltinors
5a244aa12a fix(cli): include native-binary-compat.mjs in published package files
The module is imported by bin/omniroute.mjs but was missing from the
files array in package.json, causing ERR_MODULE_NOT_FOUND on global
installs.
2026-03-12 10:26:16 +03:00
ardaaltinors
69d28bec4d feat(cli): detect native binary platform from file header instead of dlopen
Add native-binary-compat module that reads ELF/Mach-O/PE headers to
determine the actual target platform/arch of the .node binary. This
eliminates the macOS false-positive where dlopen loads a linux-x64
binary without throwing.

- Parse ELF (linux), Mach-O (darwin), and PE (win32) binary formats
- Use header-based check as primary signal, dlopen as secondary
- Update pre-flight check in CLI to use the new module
- Add unit tests for all binary formats and cross-platform scenarios
2026-03-12 10:20:08 +03:00
ardaaltinors
c859665c6b fix(cli): copy native binary from root node_modules instead of rebuilding (#321)
The standalone app/ directory created by Next.js only contains runtime
files for better-sqlite3 (no binding.gyp, no source, no prebuild-install),
so `npm rebuild` inside app/ is a no-op. The previous fix (#312) added
exit(1) on rebuild failure, which caused npm to rollback the entire
package installation — leaving users with nothing to fix manually.

New approach:
1. Check if existing binary is already compatible (dlopen)
2. Copy the correctly-built binary from root node_modules/ (npm already
   compiles it for the correct platform during install)
3. Fall back to npm rebuild if root binary is unavailable
4. Warn but don't fail the install if nothing works — the package stays
   installed and the CLI pre-flight check gives a clear error at startup
2026-03-12 10:07:43 +03:00
nyatoru
e7b19758f3 feat(registry): add new models to the provider registry 2026-03-12 11:18:16 +08:00
DavyMassoneto
623c63baf6 feat(claude): support [1m] suffix for 1M context window
Parse [1m] suffix from model name (e.g. claude-sonnet-4-6[1m]) and
propagate extendedContext flag through the request pipeline to append
context-1m-2025-08-07 to the Anthropic-Beta header.
2026-03-11 23:53:09 -03:00
diegosouzapw
a3ad7c6c2e chore(release): v2.3.1
fix(ui): translate hardcoded PT-BR text in OAuthModal to English (#314, PR #325)
fix(ts): wrap unknown dataObj fields with toRecord() in usage.ts (Kimi parser)
fix(instrumentation): await getSettings() — property access on Promise (#316 follow-up)
2026-03-11 20:49:37 -03:00
Diego Rodrigues de Sa e Souza
afc9362ca5 Merge pull request #325 from diegosouzapw/fix/issue-314-oauth-modal-pt-text
fix(ui): translate hardcoded PT-BR text in OAuthModal to English (#314)
2026-03-11 20:48:31 -03:00
diegosouzapw
f6b125e8c2 fix(ui): translate hardcoded PT-BR text in OAuthModal to English (#314)
Two strings were hardcoded in Portuguese regardless of the user's language setting:
1. The redirect_uri_mismatch error message (line ~101)
2. The remote access info banner for Google OAuth providers (line ~515)

Both are now in English. The anchor href is updated from
'#oauth-em-servidor-remoto' to '#oauth-on-a-remote-server' to match
the EN README anchor.
2026-03-11 20:45:45 -03:00
diegosouzapw
5df3c22be8 fix(ts): wrap unknown dataObj fields with toRecord() in usage.ts (Kimi usage parser)
Six TypeScript errors on lines 921/922/925/926/939/948:
- dataObj.five_hour / seven_day are 'unknown', can't be passed directly to
  hasUtilization/createQuotaObject which expect JsonRecord — wrap with toRecord()
- dataObj.user is 'unknown', can't chain .membership?.level — use toRecord() first
2026-03-11 20:45:39 -03:00
diegosouzapw
11a0df5443 fix(instrumentation): await getSettings() — property access on Promise (#316 follow-up)
getSettings() is declared async so calling it without await left
settings as a Promise<Record<string, unknown>>, causing 4 TS errors
when accessing settings.modelAliases in the alias restore block.
2026-03-11 13:07:39 -03:00
diegosouzapw
e27a2a0d55 chore(release): v2.3.0
fix(aliases): custom model aliases applied to routing + restored on startup (#315 #316, PR #317)
fix(cli): better-sqlite3 postinstall rebuild cross-platform macOS ARM (#312, PR #313 @ardaaltinors)
2026-03-11 12:43:50 -03:00
Diego Rodrigues de Sa e Souza
dc8abe60ee Merge pull request #317 from diegosouzapw/fix/issue-315-316-alias-bugs
fix(aliases): resolve custom model aliases before routing + restore on startup (#315, #316)
2026-03-11 12:43:02 -03:00
diegosouzapw
afe2ab37e4 fix(aliases): resolve custom model aliases before routing + restore on startup (#315, #316)
#315: Import and call resolveModelAlias() in chatCore.ts before the
getModelTargetFormat() lookup so that custom aliases configured in
Settings → Model Aliases → Pattern→Target are actually applied during
routing instead of being silently ignored.

#316: Load persisted custom model aliases from settings DB at server
startup (instrumentation.ts). Previously _customAliases started as an
empty object after every restart since setCustomAliases() was only
called by the PUT /api/settings/model-aliases handler — never at init.
Now aliases are restored from settings.modelAliases JSON field on boot.
2026-03-11 12:42:18 -03:00
Diego Rodrigues de Sa e Souza
f7bd99f965 Merge pull request #313 from ardaaltinors/fix/better-sqlite3-postinstall-rebuild
fix(cli): improve better-sqlite3 postinstall rebuild for cross-platform installs
2026-03-11 12:39:03 -03:00
ardaaltinors
f5238944b4 fix(cli): improve better-sqlite3 postinstall rebuild for cross-platform installs (#312)
Replace unreliable process.dlopen() platform detection with explicit
platform/arch comparison against the build target (linux-x64). On macOS,
dlopen can load an incompatible binary without throwing, causing the
postinstall script to skip the rebuild entirely.

- Detect platform mismatch via process.platform/arch instead of dlopen
- Fail the install (exit 1) if rebuild fails, instead of warning silently
- Verify rebuilt binary loads correctly after rebuild
- Add pre-flight binary check in CLI entry point as a safety net
2026-03-11 17:11:00 +03:00
diegosouzapw
c7ae9c30c2 chore(release): v2.2.9
feat(providers): persist custom model endpoint edits (#307, PR #307 by @hijak)
fix(deps): add @swc/helpers as explicit dep to fix MODULE_NOT_FOUND (#306, PR #308)
fix(usage): correct Claude quota display — utilization = % used (#299, PR #309)
2026-03-11 08:46:16 -03:00
Diego Rodrigues de Sa e Souza
82f7a12a46 Merge pull request #309 from diegosouzapw/fix/issue-299-claude-quota-inversion
fix(usage): correct Claude quota display — utilization = % used (#299)
2026-03-11 08:45:05 -03:00
Diego Rodrigues de Sa e Souza
f494a8531b Merge pull request #308 from diegosouzapw/fix/issue-306-swc-helpers-missing
fix(deps): add @swc/helpers as explicit dependency (#306)
2026-03-11 08:45:01 -03:00
Diego Rodrigues de Sa e Souza
36ed0499db Merge pull request #307 from hijak/fix/provider-model-endpoints-save
fix(providers): persist supported endpoints with explicit save
2026-03-11 08:44:58 -03:00
diegosouzapw
46cff2200d fix(usage): correct Claude quota display — utilization = % used, not % remaining (#299)
The Claude Code OAuth API returns 'utilization' as percent USED,
not percent remaining. The createQuotaObject function had them swapped:
it set remainingPercentage = utilization, which inverted the quota bar.

Confirmed by reporter: Claude.ai shows 87% used → OmniRoute was showing
87% remaining (green bar), should show 13% remaining (yellow/red bar).

Fix: used = utilization; remaining = 100 - utilization.
2026-03-11 08:42:44 -03:00
diegosouzapw
5ea6ad4a9e fix(deps): add @swc/helpers as explicit dependency (#306)
next@16 lists @swc/helpers@0.5.15 in its own dependencies but npm's
deduplication during global install fails to place it in the omniroute
app's node_modules when hoisted. This causes MODULE_NOT_FOUND for
@swc/helpers/esm/_interop_require_default.js on startup.

Fix: add @swc/helpers@0.5.19 to omniroute's top-level dependencies and
overrides so npm guarantees its presence regardless of hoisting strategy.
Reproducible on Windows (Node 22) and Linux.
2026-03-11 08:40:31 -03:00
jack
6cad4fae8e fix(providers): persist supported endpoints with explicit save for custom models 2026-03-11 11:20:25 +00:00
diegosouzapw
8df24c855b chore(release): v2.2.8
fix(docker): healthcheck now uses /api/monitoring/health (#296, PR #301)
fix(rate-limit): maxWait=120s on Bottleneck prevents endless queue (#297, PR #302)
2026-03-11 00:20:57 -03:00
Diego Rodrigues de Sa e Souza
f25882c0e9 Merge pull request #302 from diegosouzapw/fix/issue-296-healthcheck-endpoint
fix(docker): use /api/monitoring/health for Docker healthcheck (#296)
2026-03-11 00:20:17 -03:00
Diego Rodrigues de Sa e Souza
be6c769192 Merge pull request #301 from diegosouzapw/fix/issue-297-rate-limit-maxwait
fix(rate-limit): prevent endless queue with maxWait (#297)
2026-03-11 00:20:14 -03:00
diegosouzapw
a4276444b5 fix(rate-limit): add maxWait to Bottleneck to prevent endless queuing (#297)
When all provider quotas are exhausted (reservoir=0 after repeated 429s),
Bottleneck's schedule() would queue requests indefinitely since no maxWait
was configured. Clients (Cursor, Claude Code, VS Code) would hang forever.

Fix: add maxWait=120000 (2min, configurable via RATE_LIMIT_MAX_WAIT_MS env)
to DEFAULT_SETTINGS and all three Bottleneck constructors. When a job waits
longer than maxWait, Bottleneck rejects with a BottleneckError which
propagates as a 502/503 error to the client — a clean fail-fast instead
of infinite hang.
2026-03-10 23:58:36 -03:00
diegosouzapw
0af27b8d8a fix(docker): use /api/monitoring/health for healthcheck (#296)
The healthcheck script was querying /api/settings which returns config
data rather than system health. Updated to /api/monitoring/health which
is the canonical health endpoint used across tests, SystemMonitor.tsx,
MaintenanceBanner.tsx, playwright config, and MCP tools.
2026-03-10 23:57:17 -03:00
diegosouzapw
542eb0e719 chore(release): v2.2.7
fix(docker): bootstrap-env.mjs missing in runtime image (#292, PR #293)
fix(google-cli): prefer OAuth projectId over stale body.project (PR #294)
fix(chat): strip empty name from messages/input before upstream (#291, PR #300)
deps: bump hono 4.12.4 → 4.12.7 (PR #298)
2026-03-10 23:34:19 -03:00
Diego Rodrigues de Sa e Souza
c658b39270 Merge pull request #300 from diegosouzapw/fix/issue-291-strip-empty-name
fix(chat): strip empty name from messages/input before upstream (#291)
2026-03-10 23:33:04 -03:00
Diego Rodrigues de Sa e Souza
52ef3dfc7e Merge pull request #298 from diegosouzapw/dependabot/npm_and_yarn/hono-4.12.7
deps: bump hono from 4.12.4 to 4.12.7
2026-03-10 23:33:01 -03:00
Diego Rodrigues de Sa e Souza
57da407693 Merge pull request #294 from hijak/fix/google-cli-prefer-oauth-projectid
fix(google-cli): prefer OAuth projectId over request body project
2026-03-10 23:32:59 -03:00
Diego Rodrigues de Sa e Souza
d2d6fc5883 Merge pull request #293 from hijak/fix/docker-bootstrap-env-missing
fix(docker): include bootstrap-env.mjs in runtime image
2026-03-10 23:32:57 -03:00
diegosouzapw
6a7a6022d4 fix(chat): strip empty name fields from messages/input before upstream (#291)
OpenAI-compatible providers (OpenAI, Codex) reject name:'' with 400 errors:
  - 'Unknown parameter: input[1].name'
  - 'Invalid tools[0].name: empty string'

Some clients (e.g. PocketPaw) forward assistant turns with name:'' in
the OpenAI Responses API input[] and chat completions messages[].

Fix: filter out name:'' from messages[] and input[] before translateRequest.
Non-empty non-null name values are preserved per OpenAI spec.
2026-03-10 23:31:31 -03:00
dependabot[bot]
b53eafa615 deps: bump hono from 4.12.4 to 4.12.7
Bumps [hono](https://github.com/honojs/hono) from 4.12.4 to 4.12.7.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.4...v4.12.7)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-11 02:07:19 +00:00
jack
c949214e99 feat(google-cli): add env escape hatch for body.project override 2026-03-10 22:15:26 +00:00
jack
887cf25b65 fix(google-cli): prefer OAuth projectId over client body project 2026-03-10 22:12:39 +00:00
jack
dd6142196f fix(docker): copy bootstrap-env.mjs into runtime image 2026-03-10 21:55:21 +00:00
diegosouzapw
902c7244d1 chore(release): v2.2.6
fix(translator): map Claude thinking_delta to reasoning_content (#289)
- Close #289: thinking tokens now visible in Claude Code, Cursor, Windsurf
2026-03-10 16:21:20 -03:00
Diego Rodrigues de Sa e Souza
4f11762c68 Merge pull request #290 from diegosouzapw/fix/issue-289-thinking-tokens
fix(translator): map Claude thinking_delta to reasoning_content (#289)
2026-03-10 16:20:22 -03:00
diegosouzapw
8a7f7c1ba0 fix(translator): map Claude thinking_delta to reasoning_content not content (#289)
When proxying Claude responses through OmniRoute, thinking blocks were being
emitted as regular content (delta.content) with <think>...</think> XML tags.
Clients like Claude Code, Cursor, and Windsurf look for delta.reasoning_content
to render the thinking panel — not <think> tags inside content.

Root cause (claude-to-openai.ts):
  - content_block_start type:thinking → emitted { content: '<think>' }
  - content_block_delta thinking_delta → emitted { content: delta.thinking }
  - content_block_stop thinking block → emitted { content: '</think>' }

Fix:
  - content_block_start → emits { reasoning_content: '' } (signals block start)
  - thinking_delta → emits { reasoning_content: delta.thinking }
  - content_block_stop → no extra chunk needed (thinking streamed via reasoning_content)

This fix applies when sourceFormat=CLAUDE targetFormat=OPENAI (Antigravity OAuth,
direct Claude API providers). The user reported 'Thinking Budget: passthrough'
was enabled but thinking was invisible — this is the root cause.

Fixes #289
2026-03-10 15:25:31 -03:00
diegosouzapw
af46f87eed feat(bootstrap): zero-config auto-generated secrets on first run
Resolves root cause of #252 (Electron black screen) and #249 (OAuth fail)
for users running with zero configuration (no .env needed).

New: scripts/bootstrap-env.mjs
- Auto-generates JWT_SECRET (64 bytes), STORAGE_ENCRYPTION_KEY (32 bytes),
  API_KEY_SECRET (32 bytes) if missing or empty
- Persists to {DATA_DIR}/server.env — survives restarts, Docker volume
  remounts, and upgrades without changing secrets
- Reads .env from CWD (user overrides), then merges process.env (highest prio)
- Logs friendly warnings for missing optional OAuth secrets

Updated: run-standalone.mjs + run-next.mjs
- Call bootstrapEnv() before spawning server — covers npm + Docker paths

Updated: electron/main.js (synchronous inline — CJS cannot await import ESM)
- Reads userData/server.env, generates missing secrets with crypto.randomBytes()
- Persists back to server.env, sets OMNIROUTE_BOOTSTRAPPED=true

New: BootstrapBanner.tsx + page.tsx update
- Dismissable amber banner on dashboard home when running in zero-config mode
- Shows where server.env is located and how to customize secrets
2026-03-10 15:15:07 -03:00
diegosouzapw
fd749d1e0b fix(electron): auto-generate JWT_SECRET and STORAGE_ENCRYPTION_KEY if missing
In packaged Electron on macOS/Windows/Linux, there is no .env file.
The Next.js server needs JWT_SECRET and STORAGE_ENCRYPTION_KEY to start —
without them it crashes silently, causing ERR_CONNECTION_REFUSED
and a black screen in the Electron window.

Fix: Generate cryptographically random values with crypto.randomBytes()
on first launch, persist them in userData/electron-env.json, and pass
them to the spawned server.js process via the env option.

Root cause: macOS users reported 'app black screen' (#252) and
ERR_CONNECTION_REFUSED — this was the Next.js server crashing at startup
because these env vars don't exist in the desktop OS environment.
2026-03-10 15:06:57 -03:00
diegosouzapw
5046f90dfa docs(workflow): make openapi.yaml sync mandatory in generate-release
- Step 4 now marked ⚠️ MANDATORY with CI will fail warning
- Command is now auto-extracting version from package.json (no manual substitution)
- Step 4 has // turbo annotation for auto-execution
- Added 'Known CI Pitfalls' table: docs-sync failures, Electron fpm, Docker 502
2026-03-10 15:02:08 -03:00
diegosouzapw
cf13e95610 fix(ci): bump openapi.yaml version to 2.2.4
check:docs-sync fails when openapi.yaml version != package.json version.
Updating to match after v2.2.4 release.

Systematic fix: openapi.yaml version must always be updated alongside
package.json during releases (see generate-release workflow step 4).
2026-03-10 14:43:17 -03:00
diegosouzapw
5763609008 feat(release): v2.2.4 — CI fixes (docs-sync, electron fpm, docker) 2026-03-10 14:37:04 -03:00
diegosouzapw
6d672ab09a fix(ci): docs-sync, electron linux fpm, docker cache env
CI Lint fixes:
- docs/openapi.yaml: bump version 2.2.0 → 2.2.3 (was out of sync with package.json)
- CHANGELOG.md: add '## [Unreleased]' as first section (required by check:docs-sync)

Electron Linux fix:
- electron-release.yml: add 'gem install fpm' step for Linux builds
  fpm is required by electron-builder to package .deb installers;
  ubuntu-latest runners don't have it pre-installed

Docker publish:
- docker-publish.yml: add DOCKER_BUILDKIT_INLINE_CACHE env; prev 502 was
  a transient Docker Hub network error, no code change needed
2026-03-10 14:31:48 -03:00
diegosouzapw
ac68022233 feat(release): v2.2.3 — bug fixes from community PRs
fix(google-cli): remove fake projectId fallback causing permission/verification errors (#285)
- antigravity.ts, openai-to-gemini.ts, geminiHelper.ts
- Throws clear error instead of silently sending with random project IDs

fix(claude): extend empty tool name filter to all message roles (#288)
- Pass 1.4 now covers all roles, not just assistant
- Filters tool_result with missing tool_use_id
- Filters top-level body.tools with empty names
- Explicit @swc/helpers COPY in Dockerfile runner-base stage
2026-03-10 12:53:47 -03:00
Nina Gleichner
c2b31f6b20 Fix empty tool name 400 errors from Claude API and missing @swc/helpers in Docker (#288)
* Initial plan

* fix: filter empty tool names and missing tool_use_id; add @swc/helpers to Docker

Co-authored-by: ngleichner1 <263653359+ngleichner1@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ngleichner1 <263653359+ngleichner1@users.noreply.github.com>
2026-03-10 12:46:17 -03:00
Jack
54b1d8c8de fix(google-cli): stop random project fallback and require real OAuth projectId (#285)
Co-authored-by: jack <jack@plutus-32g.local>
2026-03-10 12:46:15 -03:00
diegosouzapw
cd1ab696b2 docs: add npm run system-info to Support and troubleshooting sections
Users are now directed to run 'npm run system-info' when reporting bugs.
Added to:
- ## Support → '🐛 Reporting a Bug?' subsection
- Pain point #10 '🐛 I can't diagnose errors' bullet list
2026-03-10 12:45:20 -03:00
diegosouzapw
d9d0640f6e feat(release): v2.2.2 — system-info script, Kimi/Mistral/Llama aliases
- New npm run system-info command (#280)
- Kimi K2/K2.5 Fireworks path aliases (#265)
- Mistral/Llama short aliases (#278)
- Custom alias instructions via Settings → Model Aliases
2026-03-10 11:00:20 -03:00
Diego Rodrigues de Sa e Souza
e19046116a feat: system-info.mjs script + Kimi/Mistral/Llama model aliases (#280 #265 #278) (#284)
System Info Script (#280):
- New scripts/system-info.mjs: collects Node.js version, OmniRoute version,
  OS info, Agent CLI tool versions (iflow, gemini, claude, codex, antigravity,
  droid, openclaw, kilo, cursor, aider), Docker/PM2 status, system packages
- Outputs system-info.txt for easy attachment to bug reports
- Added npm script: 'npm run system-info'

Model Aliases (#265 #278):
- Added Kimi K2/K2.5 Fireworks path aliases to built-in alias map
  (fireworks/accounts/fireworks/models/kimi-k2p5 → moonshotai/Kimi-K2.5)
- Added short aliases: kimi-k2p5, kimi-k2, mistral-large, mistral-small,
  codestral, llama-3.3, llama-3-70b, llama-3-8b
- Custom aliases can be added via Settings → Model Aliases tab in dashboard

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-03-10 10:59:27 -03:00
diegosouzapw
82a621ec08 feat(release): v2.2.1 — bug fixes, security patches, CI hardening
Bug Fixes:
- fix(imageRegistry): add gemini-3.1-flash-image-preview to antigravity (#273)
- fix(models-route): add ollama-cloud to PROVIDER_MODELS_CONFIG (#276)
- fix(models-route): clear 400 error when no apiKey configured (#277)

Security:
- fix(mitm): TLS rejectUnauthorized defaults to true, opt-out via env var
- fix(backup): path traversal guards (safePath, safeProfilePath, safeLogPath)
- fix(usageHistory): prototype pollution via Object.create(null) + hasOwnProperty
- fix(deps): dompurify ^3.3.2 (CVE-2026-0540)
- fix(ci): add global permissions: contents: read to ci.yml

CI:
- fix(ci): @swc/helpers override + regenerated package-lock.json
- fix(ci): npm-publish skip if version already exists on npm
- fix(ci): npm-publish use npm install instead of npm ci
- fix(lint): cursor.ts isToolBoundaryAbort any → unknown
2026-03-10 09:50:19 -03: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
diegosouzapw
f900a81ec9 fix(ci): use npm install in npm-publish to survive lock file drift on old tags
npm ci fails if the tag commit's lock file is out of sync (as happened
with v2.2.0 when @swc/helpers was missing). npm install is safe here
because the publish workflow only needs deps to run prepublish.mjs —
strict lock enforcement is not required for the publish step.
2026-03-10 09:48:35 -03:00
diegosouzapw
2a620b178d fix(ci): skip npm publish if version already exists on npm registry
Prevents E403 failures when a release event fires more than once for the
same version (e.g. re-running a failed workflow or duplicate tag event).

The publish step now checks whether the version is already on npm and
exits cleanly with a warning instead of failing the workflow.
2026-03-10 09:46:14 -03:00
diegosouzapw
5aaaad529b fix(ci): sync package-lock.json — add @swc/helpers override + regenerate lock
All 3 CI workflows (CI, npm-publish, docker-publish) were failing with:
  'Missing: @swc/helpers@0.5.19 from lock file'

Root cause: npm version bump ran without npm install, causing the lock file
to be out of sync with CI's npm resolver (which resolves @swc/helpers@0.5.19
while local npm 10.9.4 resolves 0.5.15).

Fix: added 'overrides': { '@swc/helpers': '^0.5.19' } to package.json and
regenerated package-lock.json with npm install.

Also updated .agents/workflows/generate-release.md to enforce:
- Always use 'npm version patch --no-git-tag-version' (never minor/major)
- Always run 'npm install' after bumping to keep lock file in sync
- Version threshold: 2.x.10 → 2.(x+1).0 (manual)
2026-03-10 09:25:35 -03:00
diegosouzapw
4e15ca6bbd chore(release): v2.2.0
- Merge PR #275: fix(cursor): stabilize tool result handoff
- Merge PR #281: fix(validation): ElevenLabs + Inworld API key validation
- Merge PR #279: feat(kimi-coding): Kimi Coding plan quota display
- Merge PR #264: deps: bump dev group with 5 updates
- Merge PR #263: deps: bump prod group with 2 updates
- fix(ci): repair unit, e2e and i18n test failures
- fix(providers): Add Connection button for OpenAI-compatible providers (#272)
- docs: update CHANGELOG and bump openapi.yaml to 2.2.0
2026-03-10 09:12:27 -03:00
diegosouzapw
8555a3a106 fix(providers): show Add Connection button for OpenAI-compatible providers (#272)
When a manually created OpenAI/Anthropic-compatible provider has 0 connections,
the Add Connection button was hidden behind !isCompatible guard, making it
impossible to add a key. Button now appears in the Connections card header
for compatible providers too, limited to 1 connection (single key per node).
2026-03-10 09:09:18 -03:00
diegosouzapw
3a39ae6231 deps: bump the production group with 2 updates (#263) 2026-03-10 09:04:24 -03:00
diegosouzapw
00e6b7cf2c deps: bump the development group with 5 updates (#264) 2026-03-10 09:04:12 -03:00
diegosouzapw
ebd1e5421b feat(kimi-coding): add Kimi Coding plan quota display (#279)
- Add getKimiUsage() with X-Msh-* device headers for Kimi API
- Parse weekly quota + rate-limit breakdown from /v1/usages endpoint
- Fix X-Msh-* headers in refreshKimiCodingToken (was missing)
- Wire kimi-coding into getUsageForProvider switch
- Add quota capability flag to providers.ts
- Remove console.warn/error (production-safe silent returns)

Co-authored-by: nyatoru <nyarutoru0002@outlook.co.th>
2026-03-10 09:04:03 -03:00
diegosouzapw
2feb2df30d refactor(kimi-usage): remove console.warn/error — use silent returns 2026-03-10 09:03:45 -03:00
diegosouzapw
ba38dc738b fix(validation): support ElevenLabs and Inworld API key validation (#281)
- Add validateElevenLabsProvider (GET /v1/voices with xi-api-key)
- Add validateInworldProvider (POST /tts/v1/voice with Basic auth)
- Register both in SPECIALTY_VALIDATORS map
- Fixes false 400 errors for valid ElevenLabs/Inworld connections

Reviewed-by: Antigravity
2026-03-10 09:02:50 -03:00
diegosouzapw
9233edb6cd fix(cursor): stabilize tool result handoff for Cursor tool calls (#275)
- Stop double-translation in Cursor executor path (preserved tool_results)
- Normalize OpenAI+Anthropic tool flows into Cursor-compatible shapes
- escapeXml() prevents tag injection in tool_result blocks
- Set-based finalizedIds for O(1) deduplication (replaces O(n) .find)
- Byte guard (0x7b) before payload.toString on non-JSON frames
- Convert console.log noise to debugLog() (prod clean)

Fixes #274. Reviewed-by: Antigravity
2026-03-10 09:02:30 -03:00
diegosouzapw
f697c56922 fix(ci): repair unit, e2e and i18n failures
- tests/unit/combo-circuit-breaker: use full model path keys
  (combo:groq/llama-3.3-70b) matching combo.ts implementation
- tests/e2e/protocol-visibility: click Protocols tab before asserting
  MCP/A2A links (they moved into tab panel, not header nav)
- src/i18n/messages/en.json: add missing header.mcp / header.a2a keys
  that caused MISSING_MESSAGE runtime errors during E2E boot
2026-03-10 08:47:06 -03:00
jack
5ab6a3b431 fix(validation): support elevenlabs and inworld API key checks 2026-03-10 11:20:19 +00:00
Rafael Calleja
25cd0b3612 refactor(cursor): simplify review — Set lookups, byte guards, XML escaping
- Replace O(n*k) chunks.some(includes) with emittedToolCallIds Set
- Replace O(n) toolCalls.find with finalizedIds Set (JSON + SSE paths)
- Add byte guard (0x7b check) before payload.toString on every frame
- Add escapeXml() to prevent tag injection in tool result blocks
- Reuse module-level TextDecoder in cursorProtobuf instead of per-call
- Replace [...Set].every() spread with for..of loop
2026-03-10 09:49:51 +01:00
nyatoru
6e1bf4652d feat(kimi-coding): update platform and version for Kimi Coding integration 2026-03-10 14:18:57 +07:00
nyatoru
3991c96c78 feat(kimi-coding): integrate Kimi Coding API for token refresh and usage tracking 2026-03-10 14:12:37 +07:00
Rafael Calleja
70008e67e4 refactor(cursor): remove debug artifacts after tool-result fix
Keep the Cursor tool-result reliability changes while cleaning temporary investigation notes, noisy logs, and unused imports to reduce runtime log spam.

Made-with: Cursor
2026-03-10 07:16:13 +01:00
Rafael Calleja
0d1e6685f6 chore(wip): snapshot working Cursor tool-result flow
Save the current functioning state that stops the protobuf wire-type crash and tool-call loop while we do a follow-up cleanup pass.

Made-with: Cursor
2026-03-10 07:13:47 +01:00
dependabot[bot]
60d1d13c6a deps: bump the development group with 5 updates
Bumps the development group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.3.3` | `25.4.0` |
| [eslint](https://github.com/eslint/eslint) | `9.39.3` | `9.39.4` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `16.3.1` | `16.3.2` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.56.1` | `8.57.0` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `3.2.4` | `4.0.18` |


Updates `@types/node` from 25.3.3 to 25.4.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 9.39.3 to 9.39.4
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.3...v9.39.4)

Updates `lint-staged` from 16.3.1 to 16.3.2
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.3.1...v16.3.2)

Updates `typescript-eslint` from 8.56.1 to 8.57.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.0/packages/typescript-eslint)

Updates `vitest` from 3.2.4 to 4.0.18
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.18/packages/vitest)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: eslint
  dependency-version: 9.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
- dependency-name: lint-staged
  dependency-version: 16.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
- dependency-name: typescript-eslint
  dependency-version: 8.57.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: vitest
  dependency-version: 4.0.18
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 19:58:33 +00:00
dependabot[bot]
ade1e5f345 deps: bump the production group with 2 updates
Bumps the production group with 2 updates: [jose](https://github.com/panva/jose) and [recharts](https://github.com/recharts/recharts).


Updates `jose` from 6.1.3 to 6.2.1
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v6.1.3...v6.2.1)

Updates `recharts` from 3.7.0 to 3.8.0
- [Release notes](https://github.com/recharts/recharts/releases)
- [Changelog](https://github.com/recharts/recharts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/recharts/recharts/compare/v3.7.0...v3.8.0)

---
updated-dependencies:
- dependency-name: jose
  dependency-version: 6.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production
- dependency-name: recharts
  dependency-version: 3.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 19:57:36 +00:00
diegosouzapw
0a59ef4996 feat(release): v2.1.2 — CI green: all 5 workflow fixes + .deb
## CI Fixes
- fix(lint): check:docs-sync — bump docs/openapi.yaml version to 2.1.2 + add [Unreleased] to CHANGELOG
- fix(ci): npm-publish.yml — use 'npm ci --ignore-scripts' to skip prepublishOnly during install, then run prepublish.mjs explicitly with JWT_SECRET; prevents double-build loop that caused all npm CI publishes to fail
- fix(ci): docker-publish.yml — replace two-job digest approach (required ubuntu-24.04-arm, unavailable on public repos) with single-job QEMU-based multi-arch build (linux/amd64 + linux/arm64 on standard ubuntu-latest)
- fix(ci): electron-release.yml — add .deb target to Linux electron-builder, collect .deb files in release-assets step, attach *.deb to GitHub release assets

## Documentation
- fix(docs): README.md language bar — fix 29 broken links (README.<lang>.md → docs/i18n/<lang>/README.md)
- fix(docs): docs/i18n/*/README.md — update back-links to ../../README.md and cross-links between languages
- fix(docs): electron/package.json — add deb target (x64+arm64) to linux build config
2026-03-09 15:53:14 -03:00
diegosouzapw
ace3e47d22 feat(release): v2.1.1 — CI fix + docs reorganization
## Bug Fixes
- fix(lint): resolve 5 explicit 'any' violations in open-sse/services/usage.ts
  - quotas: Record<string,any> → Record<string,UsageQuota>
  - window: any → JsonRecord (hasUtilization + createQuotaObject)
  - (error as any) → (error as Error) in 2 catch blocks
  - valueRecord = toRecord(value) to safely pass unknown to JsonRecord fn

## Documentation
- docs: move 29 README.<lang>.md from root to docs/i18n/<lang>/README.md
  (root now contains only English README.md)
- docs(i18n): sync all 11 docs/*.md to 30 language folders (319 updates)
  Languages: ar bg da de es fi fr he hu id in it ja ko ms nl no phi pl pt pt-BR ro ru sk sv th uk-UA vi zh-CN

## Maintenance
- chore: delete all duplicate auto-generated draft GitHub releases (v2.0.17–v2.1.0)
2026-03-09 15:37:31 -03:00
diegosouzapw
9865401636 feat(release): v2.1.0 — Full Provider-UI Gap Audit
All backend providers now accessible from the dashboard UI:

- src/shared/constants/providers.ts: Add 7 missing APIKEY providers (ollama-cloud, elevenlabs, cartesia, playht, inworld, sdwebui, comfyui)
- src/shared/constants/cliTools.ts: Add opencode, kiro entries with guide steps
- src/app/(dashboard)/dashboard/media/MediaPageClient.tsx: Full rewrite with provider+model selectors for all 5 modalities + new Transcription tab with file upload
- src/app/(dashboard)/dashboard/playground/page.tsx: Add transcription, video, music, rerank endpoints
- src/app/(dashboard)/dashboard/agents/page.tsx: Expand cliCompatProviders to include kiro, cursor, kimi-coding, kilocode, cline
- src/app/{400-503}/layout.tsx: Minimal layouts to fix Next.js build
- CHANGELOG: v2.1.0 entry
2026-03-09 15:17:54 -03:00
diegosouzapw
1343768de1 feat(ui): full provider-UI gap fixes
## Providers page
- Add 7 missing APIKEY providers: ollama-cloud, elevenlabs, cartesia, playht, inworld, sdwebui, comfyui
- All audio TTS providers + local image providers now have key config screens

## Media page (major redesign)
- Add Transcription tab with file upload (multipart/form-data)
- Add Provider dropdown + Model dropdown to ALL 5 modalities (image, video, music, speech, transcription)
- Provider selection drives model list and voice presets dynamically
- Static PROVIDER_MODELS registry mirrors all backend audioRegistry/imageRegistry entries
- PROVIDER_VOICE_PRESETS now drives voice dropdown based on selected provider

## Playground
- Add 4 new endpoints: Audio Transcription (/v1/audio/transcriptions), Video (/v1/videos/generations), Music (/v1/music/generations), Rerank (/v1/rerank)

## CLI Tools
- Add opencode and kiro entries with guide-type setup instructions

## Agents
- Expand cliCompatProviders toggles: add kiro, cursor, kimi-coding, kilocode, cline
2026-03-09 15:12:51 -03:00
diegosouzapw
743cfcbb3c feat(release): v2.0.20 — TTS Expansion + Mobile UX + Friendly Names
- #248: Inworld, Cartesia, PlayHT TTS providers; provider-aware voice presets in /dashboard/media; Speech tab in media page; Speech endpoint in playground
- #260: getAccountDisplayName/getProviderDisplayName helpers; applied to usageStats and rate-limits
- #261: mobile sidebar h-dvh scroll fix; providers page flex-wrap action headers
- docs: CHANGELOG v2.0.20, README English + 25 translated READMEs updated
2026-03-09 13:46:06 -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
47445ebf5c feat(release): v2.0.19 — Ollama Cloud provider + security hardening
docs: update CHANGELOG, README (EN + 29 translations), and docs/i18n/ FEATURES.md
- Add Ollama Cloud (ollamacloud alias) bullet to all 30 README files
- Sync docs/i18n/*/FEATURES.md with Ollama Cloud mention
- Bump version to 2.0.19
2026-03-09 12:46:58 -03:00
Diego Rodrigues de Sa e Souza
6b0638da30 Merge pull request #259 from diegosouzapw/fix/issue-255-258-ollama-cloud-security
fix: Ollama Cloud provider + security hardening (#255 #258)
2026-03-09 12:43:03 -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
9aaebbcd2a feat(release): v2.0.18 — cursor decompression + codex token refresh + password setup fix 2026-03-09 10:50:16 -03:00
Diego Rodrigues de Sa e Souza
2348680a2b Merge pull request #257 from diegosouzapw/fix/issue-256-password-setup-bypass
fix: cursor decompression fallback + codex token refresh + password setup bypass (#250, #251, #256)
2026-03-09 10:48:04 -03:00
diegosouzapw
59a8b8db35 fix: cursor decompression fallback + codex token refresh + password setup bypass (#250, #251, #256)
fix(cursor): add zlib inflate/inflateRaw fallback for GZIP_ALT/GZIP_BOTH frames (#250)
- GZIP_ALT (0x02) and GZIP_BOTH (0x03) frames may use zlib deflate instead of gzip
- Now tries gunzipSync → inflateSync → inflateRawSync with verbose error logging

fix(codex): override refreshCredentials to enable automatic token refresh on 401 (#251)
- CodexExecutor was inheriting base class null return, blocking 401 recovery
- Now calls refreshCodexToken() from tokenRefresh.ts on 401 upstream response
- Handles rotating token errors and surfaces re-auth warning clearly

fix(auth): allow dashboard access when no password is set after onboarding skip (#256)
- isAuthRequired() was blocking /dashboard/settings when setupComplete=true but no password
- Removed setupComplete guard: if there's no password, auth cannot be required
- Configure Password button on login page now navigates correctly to security settings
2026-03-09 10:47:16 -03:00
diegosouzapw
2ba46a622b feat(release): v2.0.17 — Antigravity streaming fix + OpenCode integration + Electron CI
- fix(streaming): keep Gemini/Antigravity text block open across chunks (#253)
  Resolves Claude Code rendering each streaming delta on a separate line.
  The content_block is now kept open between chunks (openTextBlockIdx state)
  and only closed at finishReason or on block-type switch.

- feat(agents): Download opencode.json button (discussion #162)
  Dashboard › Agents shows a Download opencode.json button when opencode
  is detected. Fetches /v1/models and generates a ready-to-use config.

- fix(electron-ci): use macos-15-intel runner (replaces deprecated macos-13)
- fix(electron-ci): sync electron/package.json version before build
- fix(electron-ci): remove duplicate arm64 pattern from release assets
2026-03-09 08:49:13 -03:00
Diego Rodrigues de Sa e Souza
9013236718 Merge pull request #254 from diegosouzapw/fix/issue-253-antigravity-streaming
 Approved — fixes confirmed.

- Fix #253: Antigravity/Gemini streaming chunks now render as continuous text in Claude Code (content_block kept open across chunks)
- Bonus: Download opencode.json button in Agents dashboard
2026-03-09 08:47:41 -03:00
diegosouzapw
eab96cc94b fix(streaming): keep Gemini/Antigravity text block open across chunks (#253)
Before this fix, geminiToClaudeResponse() called content_block_start +
content_block_stop on EVERY streaming chunk. Claude Code interprets each
content_block as a separate text element and renders them on separate
lines, making responses unreadable.

Fix: introduce state.openTextBlockIdx to track an open text block across
chunks. The block is opened on the first text chunk and only closed when:
- switching to a different block type (thinking, tool_use)
- the stream finishes (at finishReason)

All other block types (thinking, tool_use) are still opened+closed per
chunk as before since they are naturally atomic events.

Also: add 'Download opencode.json' button to the Agents dashboard.
The button appears when opencode is detected as installed and generates
a ready-to-use opencode.json config with the OmniRoute provider,
base URL and all models fetched from /v1/models.
2026-03-09 08:38:33 -03:00
diegosouzapw
7f66e82f16 fix(electron-ci): sync electron/package.json version + fix Create Release
- Add 'Sync version in electron/package.json' step before build so
  electron-builder names binaries with the correct release version
  (was generating OmniRoute-2.0.13.dmg for v2.0.16 release).
- Remove duplicate *-arm64.dmg pattern from release files (*.dmg
  already matches arm64 dmg files), which was causing 404 on
  overwrite-asset API call.
- Add fail_on_unmatched_files: false so missing .blockmap files
  don't fail the release step.
2026-03-08 18:45:51 -03:00
diegosouzapw
c74054d928 fix(electron-ci): use macos-15-intel runner for Intel x64 macOS builds
GitHub retired all macos-13 variants. The new officially supported
Intel x64 runner is macos-15-intel (GA since April 2025, supported
until August 2027). This replaces the deprecated macos-13 runner.
2026-03-08 18:27:44 -03:00
diegosouzapw
5428c9b9a8 fix(electron-ci): replace deprecated macos-13 runner with macos-13-large
macos-13 runner was retired by GitHub Actions infrastructure.
All other platforms (linux, macos-arm64, windows) built successfully.
Using macos-13-large which maintains x64 Intel architecture.
2026-03-08 18:26:02 -03:00
diegosouzapw
db0bda2810 feat(release): v2.0.16 — NanoBanana async polling + Electron CI fix + CI hardening
fix(electron-ci): add GH_TOKEN to Build Electron step
  - electron-builder requires GH_TOKEN env when publish.provider is
    'github'. Without it every build failed with 'GitHub Personal Access
    Token is not set'. This was blocking Electron binary generation since
    v2.0.11. Fixed by passing secrets.GITHUB_TOKEN to the build step.

fix(images): NanoBanana async task polling (PR #247 by @hijak)
  - NanoBanana returns taskId requiring /record-info polling until
    successFlag=1 instead of image payload on first response.
  - Backward compatible: sync payload path preserved.
  - Includes aspect ratio/resolution inference from size field.

fix(ci): security test import + route validation + deploy-vps
  - inputSanitizer.js → .ts fix
  - validateBody added to acp/agents POST (139 routes pass t06)
  - deploy-vps continue-on-error + command_timeout

Version: 2.0.15 → 2.0.16
2026-03-08 18:07:36 -03:00
Diego Rodrigues de Sa e Souza
c4efad3ea7 Merge pull request #247 from hijak/fix/nanobanana-async
## Review

 **Aprovado** — implementação clara e bem estruturada.

**O que a PR faz:**
- Implementa o fluxo async correto da NanoBanana API: submit task → poll /record-info until successFlag=1
- Mantém backward compatibility para providers retornando payload síncrono
- Infere aspectRatio e resolution do campo size (padrão OpenAI)
- Permite tunagem via env vars (NANOBANANA_POLL_TIMEOUT_MS, NANOBANANA_POLL_INTERVAL_MS)
- Adiciona 2 arquivos de teste com cobertura específica

**Qualidade:**
- Código limpo e bem documentado
- Testes adicionados e passando localmente
- Não quebra implementações existentes (sync path preservado)

Obrigado pela contribuição @hijak! 🎉
2026-03-08 17:59:11 -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
jack
9a476d310a fix(images): support async NanoBanana task polling 2026-03-08 20:47:17 +00:00
diegosouzapw
bc09eb64a6 chore: bump version to 2.0.15 + update CHANGELOG
- Add v2.0.15 CHANGELOG entry (features 07/09/04/06 + fix #244)
- Version: 2.0.14 → 2.0.15
2026-03-08 17:40:00 -03:00
Diego Rodrigues de Sa e Souza
8e4873d53e Merge pull request #246 from diegosouzapw/feat/features-07-09-04-06-electron-release
feat: features 07/09/04/06 — Codex effort clamp, OpenRouter catalog cache, quota preflight & session monitor
2026-03-08 17:38:06 -03:00
Diego Rodrigues de Sa e Souza
5874bd3de6 Merge pull request #245 from diegosouzapw/fix/issue-244-optional-field-gemini-schema
fix(gemini): remove "optional" field from JSON schema — fixes #244
2026-03-08 17:38:05 -03:00
diegosouzapw
a1dc2270a2 fix(gemini): remove "optional" field from schema to fix Gemini API rejection (#244)
The Gemini API rejects JSON schemas containing the "optional" field, returning
"400: Cannot find field: optional". Added "optional" to UNSUPPORTED_SCHEMA_CONSTRAINTS
in geminiHelper.ts so it is recursively stripped before sending to upstream.

Also: update star history section in README — embed replaced with live link
since api.star-history.com was suspended by GitHub in March 2025.

Closes #244
2026-03-08 17:36:58 -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
049ddff6fe feat(release): v2.0.14 — fix model name stripping, multimodal image_url, electron release workflow
- Fix #243: model.split('/').pop() → slice(1).join('/') preserves vendor namespaces
- Fix #242: image_url → input_image conversion for Responses API backends
- Merge PR #241: electron release workflow (mac x64/arm64 separation, version sync)
- CHANGELOG updated
2026-03-08 02:19:36 -03:00
diegosouzapw
9429d1639e Merge PR #241: fix(electron): resolve release build workflow errors
- Sync electron package.json version with root (2.0.13)
- Separate mac x64 and arm64 into dedicated runner jobs
- Use macos-13 (Intel) runner for x64 build
- Thanks @benzntech for the contribution!
2026-03-08 02:17:46 -03:00
diegosouzapw
af7ca4baf7 fix: strip only internal prefix from model name for compatible providers (#243)
- Changed model.split('/').pop() to model.split('/').slice(1).join('/')
- Preserves vendor namespace in model names (e.g. moonshotai/Kimi-K2-Instruct)
- Also fixes multimodal image_url → input_image conversion for Responses API (#242)
- image_url parts from Chat Completions are now properly converted to input_image format
2026-03-08 02:17:21 -03:00
benzntech
7906fdfc1d fix(electron): resolve release build workflow errors
- Sync electron package.json version with root to fix artifact collection

- Separate mac x64 and arm64 targets into dedicated runner jobs

- Use macos-13 (Intel) runner for x64 build to prevent cross-compilation timeouts
2026-03-07 23:46:59 +05:30
diegosouzapw
9911272898 chore: rename docs to uppercase + gitignore cleanup
- Rename a2a-server.md → A2A-SERVER.md, auto-combo.md → AUTO-COMBO.md, mcp-server.md → MCP-SERVER.md
- Update gitignore whitelist to match uppercase names
- Reddit Launch Plan v2 remains gitignored (local only)
2026-03-07 13:18:34 -03:00
diegosouzapw
8909ae041e chore: update llm.txt to v2.0.13 state
- Complete rewrite of llm.txt with current project structure
- Added ACP agents, CLI fingerprint, sidebar reorganization
- Added 30 languages, MCP/A2A servers, anti-ban features
- Updated project structure tree with all dashboard pages
2026-03-07 12:36:24 -03:00
diegosouzapw
c9a15772b0 chore: remove docs/new-features from tracking + gitignore cleanup
- Remove docs/new-features/ from git index (224 leaked feature spec files)
- Remove docs/new-features/ from gitignore whitelist
- Add .omnivscodeagent/, omnirouteCloud/, omnirouteSite/ to gitignore
- Remove duplicate omnirouteCloud/omnirouteSite entries
2026-03-07 12:33:56 -03:00
diegosouzapw
91f3bd4056 docs: comprehensive docs review + i18n sync
- Fix .gitignore: add a2a-server.md, auto-combo.md, mcp-server.md, new-features/ to whitelist
- Rewrite FEATURES.md: 18 sections covering v2.0.12 state (Playground, Themes, CLI Agents, Media, API Keys, Audit Log)
- API_REFERENCE.md: add ACP Agents endpoints (/api/acp/agents GET/POST/DELETE)
- Sync all 6 root docs to 29 i18n directories (174 files)
- Remove stale git-tracked docs (adr/, i18n-tasks/)
2026-03-07 12:18:17 -03:00
diegosouzapw
2306081dab feat: sidebar reorganization + CLI fingerprint to Agents page
- New CLI sidebar section: Tools + Agents
- Move Media to Debug section
- Move Health + Logs to System section
- Move CLI Fingerprint card from Settings > Security to Agents page
- Add cliToolsShort i18n key to all 30 languages
2026-03-07 11:55:18 -03:00
diegosouzapw
8963c62adb feat(release): v2.0.11 — ACP Agents Dashboard + Anti-Ban Docs
- ACP Agents Dashboard: Debug > Agents page with 14 built-in CLI agents
- Custom agent support: register any CLI via dashboard form
- Fix themeCoral i18n in all 30 languages
- Improved anti-ban feature descriptions in README
- Sync all 29 translated READMEs with new features
- CHANGELOG entry for v2.0.11
2026-03-07 11:22:16 -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
2f6e63771f docs: sync v2.0.9+ features across all 30 READMEs
Added new features table (Playground, CLI Fingerprints, ACP, Custom
apiFormat routing, Codex workspace isolation, Electron auto-update)
to all 29 translated READMEs + English source.
2026-03-07 11:05:40 -03:00
diegosouzapw
cbd60c853e feat(release): v2.0.10 — CLI fingerprint UI toggle 2026-03-07 10:57:16 -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
2025c16c82 fix: deploy workflow uses node app/server.js for pm2 2026-03-07 10:40:00 -03:00
diegosouzapw
811fb7f9b2 docs: fix deploy workflow to use npm-only approach
Old workflow used git clone at /opt/omniroute-app but recent releases
used npm install -g, causing version mismatch. PM2 now runs from
/usr/lib/node_modules/omniroute directly. Removed all references to
the stale local directory.
2026-03-07 10:38:49 -03:00
diegosouzapw
a2bd32e76c feat(release): v2.0.9 — playground, CLI fingerprints, ACP 2026-03-07 10:26:34 -03:00
Diego Rodrigues de Sa e Souza
89c07f4e8a Merge pull request #240 from diegosouzapw/feat/all-features-234-223-235
feat: playground, CLI fingerprints, ACP support (#234, #223, #235)
2026-03-07 10:25:28 -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
7cb420d8e6 feat(release): v2.0.8 — custom image model handler resolution 2026-03-07 10:05:20 -03:00
Diego Rodrigues de Sa e Souza
d3919d441f Merge pull request #239 from diegosouzapw/fix/issue-238-image-handler
fix: pass resolved provider to image handler for custom models (#238)
2026-03-07 10:04:24 -03:00
diegosouzapw
4b5824babc fix: pass resolved provider to image handler for custom models (#238) 2026-03-07 10:03:48 -03:00
diegosouzapw
fb87df14fd feat(release): v2.0.7 — custom image model routing + Codex OAuth workspace isolation 2026-03-07 06:58:07 -03:00
Diego Rodrigues de Sa e Souza
da9e4e929b Merge pull request #237 from diegosouzapw/fix/issue-232-236-image-oauth
fix: custom image model routing + Codex OAuth workspace isolation (#232, #236)
2026-03-07 06:56:49 -03:00
diegosouzapw
10b23b15ae fix: custom image model routing + Codex OAuth workspace isolation (#232, #236) 2026-03-07 06:56:09 -03:00
diegosouzapw
30fba39b35 feat(release): v2.0.6 — custom model apiFormat routing fix 2026-03-07 01:36:21 -03:00
Diego Rodrigues de Sa e Souza
5a75ff67c9 Merge pull request #233 from diegosouzapw/fix/issue-204-apiformat-routing
fix: wire apiFormat from custom model DB into routing layer (#204)
2026-03-07 01:35:30 -03:00
diegosouzapw
358828b617 fix: wire apiFormat from custom model DB into routing layer (#204) 2026-03-07 01:26:59 -03:00
diegosouzapw
e080c4a16a feat(release): v2.0.5 — fix Chat→Responses reasoning IDs, electron auto-update, dependency bumps 2026-03-06 18:51:24 -03:00
Diego Rodrigues de Sa e Souza
04b7e38baf Merge pull request #221 from benzntech/feat/electron-auto-update
feat(electron): add auto-update functionality with electron-updater
2026-03-06 18:49:54 -03:00
Diego Rodrigues de Sa e Souza
7ee23fbe19 Merge pull request #230 from diegosouzapw/dependabot/npm_and_yarn/express-rate-limit-8.3.0
deps: bump express-rate-limit from 8.2.1 to 8.3.0
2026-03-06 18:49:51 -03:00
Diego Rodrigues de Sa e Souza
c49bdb4ebb Merge pull request #229 from diegosouzapw/dependabot/github_actions/docker/build-push-action-7
chore(deps): bump docker/build-push-action from 6 to 7
2026-03-06 18:49:48 -03:00
Diego Rodrigues de Sa e Souza
0f7efed8d5 Merge pull request #228 from diegosouzapw/dependabot/github_actions/actions/upload-artifact-7
chore(deps): bump actions/upload-artifact from 4 to 7
2026-03-06 18:49:46 -03:00
Diego Rodrigues de Sa e Souza
d07bc6dcf3 Merge pull request #227 from diegosouzapw/dependabot/github_actions/docker/login-action-4
chore(deps): bump docker/login-action from 3 to 4
2026-03-06 18:49:43 -03:00
Diego Rodrigues de Sa e Souza
d607d46fa3 Merge pull request #226 from diegosouzapw/dependabot/github_actions/actions/download-artifact-8
chore(deps): bump actions/download-artifact from 4 to 8
2026-03-06 18:49:40 -03:00
Diego Rodrigues de Sa e Souza
2225dd14aa Merge pull request #225 from diegosouzapw/dependabot/github_actions/actions/cache-5
chore(deps): bump actions/cache from 4 to 5
2026-03-06 18:49:37 -03:00
Diego Rodrigues de Sa e Souza
f6c0e7bbbe Merge pull request #222 from benzntech/fix/electron-release-duplicate-asset
fix(ci): remove duplicate OmniRoute.exe entry in electron release workflow
2026-03-06 18:49:28 -03:00
Diego Rodrigues de Sa e Souza
c4675c5219 Merge pull request #231 from diegosouzapw/fix/issue-224-reasoning-ids
fix: omit synthesized reasoning items in Chat→Responses translation (#224)
2026-03-06 18:49:25 -03:00
diegosouzapw
2d977a3c4d fix: omit synthesized reasoning items in Chat→Responses translation (#224) 2026-03-06 18:48:34 -03:00
dependabot[bot]
9405918258 deps: bump express-rate-limit from 8.2.1 to 8.3.0
Bumps [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit) from 8.2.1 to 8.3.0.
- [Release notes](https://github.com/express-rate-limit/express-rate-limit/releases)
- [Commits](https://github.com/express-rate-limit/express-rate-limit/compare/v8.2.1...v8.3.0)

---
updated-dependencies:
- dependency-name: express-rate-limit
  dependency-version: 8.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:46:36 +00:00
dependabot[bot]
a69d7dd4b5 chore(deps): bump docker/build-push-action from 6 to 7
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6 to 7.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:27:03 +00:00
dependabot[bot]
428e6cb53f chore(deps): bump actions/upload-artifact from 4 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:26:59 +00:00
dependabot[bot]
c9a2955d28 chore(deps): bump docker/login-action from 3 to 4
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:26:54 +00:00
dependabot[bot]
7aefcd3437 chore(deps): bump actions/download-artifact from 4 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:26:51 +00:00
dependabot[bot]
79f4f79c46 chore(deps): bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 18:26:46 +00:00
benzntech
c11c275678 fix(electron): address auto-updater review issues
- Remove unused dialog import
- Stop Next.js server before quitAndInstall() to prevent data loss
- Propagate errors from checkForUpdates/downloadUpdate to IPC handlers
  so renderer can distinguish success from failure
- Remove meaningless return value from install-update handler
2026-03-06 19:22:41 +05:30
benzntech
bbcd1d3a08 fix(ci): remove duplicate OmniRoute.exe entry in electron release workflow
Duplicate release-assets/OmniRoute.exe glob caused softprops/action-gh-release
to attempt a second upload of the same asset, triggering a 404 Not Found error
on the GitHub release asset update API. The file is already covered by the
*.exe glob pattern above it.
2026-03-06 19:18:41 +05:30
benzntech
3342d5b931 feat(electron): add auto-update functionality with electron-updater 2026-03-06 18:54:00 +05:30
diegosouzapw
f96ee44213 feat(release): v2.0.4 — round-robin lastUsedAt persistence, zod standalone build fix 2026-03-05 23:24:56 -03:00
Diego Rodrigues de Sa e Souza
bc53fe0cd9 Merge pull request #219 from diegosouzapw/fix/issue-218-round-robin-lastUsedAt
fix: persist lastUsedAt for round-robin + zod in standalone build (#218, #217)
2026-03-05 23:24:13 -03:00
diegosouzapw
97a67b5d3e fix: persist lastUsedAt in provider_connections schema for round-robin (#218)
- Add last_used_at column to provider_connections CREATE TABLE schema
- Add ensureProviderConnectionsColumns migration for existing databases
- Add last_used_at to INSERT and UPDATE SQL in providers.ts
- Add last_used_at to JSON migration INSERT in core.ts
- Add zod to serverExternalPackages in next.config.mjs (#217)

Fixes #218: Round-robin routing strategy now correctly persists
the lastUsedAt timestamp, allowing rotation between accounts.

Fixes #217: zod module is now properly included in standalone/Docker
builds by declaring it as a server external package.
2026-03-05 23:22:10 -03:00
diegosouzapw
1ffa58be76 feat(release): v2.0.3 — deferred tools cache_control fix, quota system hardening 2026-03-05 21:57:04 -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
Diego Rodrigues de Sa e Souza
3d38cbf70f Merge pull request #216 from DavyMassoneto/fix/defer-loading-cache-control-conflict
fix: skip cache_control on deferred tools + remove stale schemas.js
2026-03-05 21:55:14 -03:00
DavyMassoneto
196a4e037c fix: skip cache_control on deferred tools + remove stale schemas.js
- Skip tools with defer_loading=true when assigning cache_control
  (Anthropic API rejects the combination with 400)
- Delete stale schemas.js that shadowed the .ts source, causing
  missing cloudSyncActionSchema export

Fixes #215
2026-03-05 20:19:58 -03:00
diegosouzapw
6a0760a2c5 chore: bump to v2.0.2 (v2.0.1 was claimed on npm) 2026-03-05 20:11:15 -03:00
diegosouzapw
b0819404c7 feat(release): v2.0.1 — endpoint-aware models, 3 bug fixes (#212, #213, #200), 3 features (#204, #205, #206) 2026-03-05 20:04:41 -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
d2b6624de4 Merge branch 'features-agente-mcp-a2a'
# Conflicts:
#	package-lock.json
2026-03-05 18:11:27 -03:00
diegosouzapw
0dd6d349b3 docs: consolidate v2.0.0 changelog — comprehensive release from v1.8.1
Merged all changes from the features-agente-mcp-a2a branch into a single
v2.0.0 release entry covering: MCP multi-transport (3 modes), 16 MCP tools,
A2A protocol, Auto-Combo engine, VS Code extension, consolidated Endpoints
dashboard with service toggles, 30-language i18n, full type safety overhaul,
and 1000+ tests.
2026-03-05 18:11:05 -03:00
diegosouzapw
ecb0774b7b feat(release): v2.0.1 — MCP multi-transport (stdio/SSE/Streamable HTTP), service toggles, endpoints consolidation
- MCP multi-transport: stdio, SSE (/api/mcp/sse), Streamable HTTP (/api/mcp/stream)
- Service enable/disable toggles with settings persistence (default: OFF)
- Consolidated Endpoints page with tabbed navigation
- Transport selector UI with connection URLs and Copy button
- Webpack barrel-file fix for settingsSchemas
2026-03-05 17:59:46 -03:00
diegosouzapw
6ab32b351f docs: update CHANGELOG and AGENTS.md with MCP multi-transport 2026-03-05 17:54:46 -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
396ab2bab5 feat: add MCP/A2A enable/disable toggle switches on Endpoints page
- Added mcpEnabled/a2aEnabled boolean fields to updateSettingsSchema
- Rewrote ServiceToggle as clickable on/off switch with status indicator
- Toggle persists state via PATCH /api/settings
- Both services default to disabled (OFF)
2026-03-05 16:56:04 -03:00
diegosouzapw
305fb56b62 docs: update AGENTS.md, README, CHANGELOG and all 30 i18n locales for Endpoints consolidation
- Rewrote AGENTS.md with v2.0.0 architecture (MCP, A2A, Auto-Combo, Endpoints tabs)
- Updated CHANGELOG unreleased section with Endpoints consolidation details
- Updated README references from Endpoint to Endpoints (screenshots, playbook, quickstart)
- Applied endpoints sidebar/header/namespace i18n to all 28 remaining language files
2026-03-05 16:51:11 -03:00
diegosouzapw
0f22f38f7e feat: consolidate Endpoint, MCP, A2A into tabbed Endpoints page
- Renamed sidebar 'Endpoint' to 'Endpoints', removed standalone MCP/A2A entries
- Created tabbed layout with SegmentedControl: Endpoint Proxy | MCP | A2A | API Endpoints
- Added inline ServiceToggle (online/offline status) for MCP and A2A tabs
- Created ApiEndpointsTab placeholder with Coming Soon badge
- Updated i18n in en.json and pt.json with new endpoints namespace
2026-03-05 16:36:58 -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
0d3728efa4 feat: Introduce combo readiness checks and strategy recommendations, updating i18n messages and e2e tests. 2026-03-05 14:38:03 -03:00
diegosouzapw
2b067c5d00 feat: Add i18n for new media and themes features, enhance combos with strategy guides and advanced settings, and introduce E2E tests for the combos flow. 2026-03-05 13:01:37 -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
diegosouzapw
c38a58fc98 chore: update lockfile to fix CI 2026-03-05 08:47:20 -03:00
Diego Rodrigues de Sa e Souza
20e4b1b011 Update open-sse/mcp-server/server.ts
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-05 08:43:01 -03:00
Diego Rodrigues de Sa e Souza
9691469987 Update docs/openapi.yaml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-05 08:42:21 -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
Diego Rodrigues de Sa e Souza
e78ede45b6 Potential fix for code scanning alert no. 54: Insecure randomness
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-05 08:41:44 -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
5a53c17e81 feat: configurable tool name prefix (#199) and custom rpm/tpm rate limits (#198)
- Issue #199: proxy_ prefix on tool names is now automatically disabled
  when routing to non-Claude backends (Gemini, Compatible, etc.).
  Prevents tool name mismatches in OpenCode, Cursor, and other clients.

- Issue #198: Added customRpm/customTpm support per provider connection.
  Users can configure custom rate limits via connection settings,
  overriding the default auto-learned limits from response headers.
2026-03-05 01:41:34 -03:00
Diego Rodrigues de Sa e Souza
9c32c30daf Merge pull request #203 from DavyMassoneto/fix/claude-oauth-usage-endpoint
Approving — all review issues resolved. Claude OAuth usage endpoint with proper fallback to legacy API key method. Thanks @DavyMassoneto! 🎉
2026-03-05 01:26:52 -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
DavyMassoneto
2ec0cd13cd fix(claude): correct utilization inversion and propagate remainingPercentage
- Fix createQuotaObject: utilization is percentage USED, not remaining
- Add optional chaining to window access in createQuotaObject
- Use typeof object guards for five_hour/seven_day instead of !== undefined
- Use nullish coalescing for extra_usage
- Propagate remainingPercentage in parseQuotaData claude case
2026-03-04 22:17:00 -03:00
diegosouzapw
0d8f28a4a4 feat: Introduce A2A lifecycle management, add type safety to ComfyUI and stream handling, and update various handlers and translators. 2026-03-04 21:02:56 -03:00
diegosouzapw
33dfbf0177 refactor: harden open-sse services, eliminate any casts, add dashboard pages
- Replace all `as any` casts in MCP advancedTools with typed helpers (toRecord, toString, toNumber)
- Harden open-sse services: rateLimitManager, sessionManager, usage, roleNormalizer, signatureCache, comboMetrics
- Improve responseSanitizer and responseTranslator type safety
- Remove deprecated openai-responses request translator
- Add dashboard pages: /a2a, /mcp, /auto-combo with live data
- Improve error/loading/not-found pages with consistent design
- Add root loading.tsx and typecheck tsconfig variants
- Add check-t11-any-budget.mjs audit script
2026-03-04 19:38:34 -03:00
diegosouzapw
85c6b63c8f feat: add error pages, harden DB layer and compliance module
- Add HTTP error pages (400, 401, 403, 408, 429, 500, 502, 503)
- Add maintenance, offline, and system status pages
- Harden db/core.ts, db/apiKeys.ts, db/cliToolState.ts, db/backup.ts
- Strengthen compliance/index.ts audit logging
- Improve container.ts DI registrations
- Fix dataPaths.ts and tokenHealthCheck.ts
2026-03-04 19:35:38 -03:00
DavyMassoneto
d19f336286 refactor: address PR review feedback
- Use parseResetTime() for resetAt fields (consistency with other fetchers)
- Extract createQuotaObject() helper to reduce duplication
- Remove unnecessary Content-Type header from GET requests
- Use CLAUDE_CONFIG.usageUrl with template interpolation in legacy fallback
2026-03-04 19:27:40 -03:00
diegosouzapw
052eb8d330 refactor: replace any types with generics and add Zod validation schemas
Eliminate `any` usage across the codebase by introducing proper generics,
typed interfaces (StatementLike, DbLike, PromptRow, etc.), and helper
conversion functions (toNumber, toString, parseVariables). Add
comprehensive Zod validation schemas for API endpoint inputs to enforce
runtime type safety alongside compile-time checks.
2026-03-04 18:59:27 -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
20860877b8 feat: add TypeScript types and modularize translator registry
- Add type annotations to all providerModels helper functions
- Introduce LegacyProvider interface in providerRegistry
- Refactor translator system to use self-registering module pattern
  with bootstrapTranslatorRegistry() and per-file imports
- Simplify translator/index.ts by delegating to modular translators
- Remove hardcoded Gemini OAuth client secret for security
2026-03-04 18:46:49 -03:00
diegosouzapw
bddec84f4e feat: add MCP server, A2A protocol, auto-combo engine & VS Code extension
Introduce full AI orchestration ecosystem:
- MCP Server with 16 tools, scoped auth, and audit logging
- A2A v0.3 server with JSON-RPC 2.0, SSE streaming, and task manager
- Auto-Combo engine with 6-factor scoring and self-healing
- VS Code extension with smart dispatch and budget tracking
- Harden CI pipeline: add static checks, remove continue-on-error
- Add translator schema validation tests
- Update .gitignore and CHANGELOG for release checklist
2026-03-04 18:45:02 -03:00
DavyMassoneto
aba12ad5db chore: sync package-lock.json with package.json v1.8.1 2026-03-04 18:29:05 -03:00
DavyMassoneto
6ea8d094b2 fix: invert utilization values — API returns remaining, not used
The OAuth usage endpoint returns utilization as percentage remaining,
not percentage used. Claude.ai showing 10% used corresponded to
utilization=90 from the API.
2026-03-04 18:19:17 -03:00
DavyMassoneto
b5a3a3d019 fix: use OAuth usage endpoint for Claude Code provider limits
The Limits page showed "error" 0% for Claude Code (OAuth) providers
because getClaudeUsage() called /v1/settings which requires API key
with org admin access — unavailable to consumer OAuth tokens.

Now uses https://api.anthropic.com/api/oauth/usage with the
anthropic-beta: oauth-2025-04-20 header, which returns five_hour and
seven_day utilization data for OAuth accounts.

Falls back to legacy /v1/settings endpoint for API key users.
2026-03-04 17:57:09 -03:00
diegosouzapw
5ecef5c90c feat: normalize quota and combos API responses with shared contracts
Introduce `normalizeQuotaResponse` and `normalizeCombosResponse` helpers
to handle varying API response shapes (array vs wrapped object)
consistently across MCP server and advanced tools. Add optional `meta`
field to checkQuotaOutput schema and update sourceEndpoints to reflect
current API routes.
2026-03-04 08:18:09 -03:00
diegosouzapw
fe9d9a5a5c feat: migrate tests to TypeScript and add MCP advanced tools test suite
- Add unit tests for 8 MCP advanced tool handlers (Phase 3)
- Migrate test files from JavaScript to TypeScript (.ts/.tsx)
- Restructure file paths from app/ to src/app/ across all tests
- Refactor route assertions into reusable assertRouteMethods helper
- Add tests for new API routes (compliance, audit-log, evals/[suiteId])
- Update barrel export tests to use consolidated assertion pattern
2026-03-04 00:41:30 -03:00
diegosouzapw
e18cfe1d80 feat: add Phase 3 advanced MCP tools and A2A smart routing skill
Register 8 new advanced MCP tools (simulate_route, set_budget_guard,
set_resilience_profile, test_combo, get_provider_metrics,
best_combo_for_task, explain_route, get_session_snapshot) with their
handler implementations. Add A2A smart routing skill that routes
prompts through the OmniRoute pipeline with routing explanation,
cost envelope, and resilience trace metadata.
2026-03-03 18:53:11 -03:00
diegosouzapw
7eb45b2e19 feat: add MCP server mode with --mcp flag for IDE integration
Add stdio-based MCP server support to OmniRoute CLI, enabling AI agents
in VS Code, Cursor, Claude Desktop, and Copilot to interact with
OmniRoute tools (health, combos, quota, routing). Update help text,
gitignore vscode-extension subproject, and include MCP/A2A strategy report.
2026-03-03 17:42:24 -03:00
diegosouzapw
70465ada4d feat(release): v1.8.1 — usage API proxy support 2026-03-03 12:06:42 -03:00
Diego Rodrigues de Sa e Souza
8ddea153d3 Merge pull request #195 from diegosouzapw/fix/issue-194-usage-proxy
fix: route usage API quota fetches through configured proxy (#194)
2026-03-03 12:05:55 -03:00
diegosouzapw
8dca8fba6b fix: route usage API quota fetches through configured proxy (#194) 2026-03-03 12:04:59 -03:00
diegosouzapw
f21ba7df64 feat(release): v1.8.0 — empty tool_use.name validation, Windows electron fix 2026-03-03 11:21:31 -03:00
Diego Rodrigues de Sa e Souza
ef917e42d1 Merge pull request #190 from benzntech/fix/electron-windows-collect-installers
fix: Windows electron release — collect portable exe by pattern
2026-03-03 11:19:53 -03:00
Diego Rodrigues de Sa e Souza
865a1b9b2c Merge pull request #193 from diegosouzapw/fix/issue-191-empty-tool-use-name
fix: validate empty tool_use.name to prevent Claude 400 errors (#191)
2026-03-03 11:19:45 -03:00
diegosouzapw
de8a0836a8 fix: validate empty tool_use.name to prevent Claude 400 errors (#191) 2026-03-03 11:18:53 -03:00
benzntech
b8272c55d7 fix: address review — break after first portable exe, remove debug ls 2026-03-03 09:27:31 +05:30
benzntech
8d93c13f9a fix: collect portable exe by pattern instead of hardcoded filename
electron-builder produces 'OmniRoute 1.6.9.exe' (with version) as the
portable exe, not 'OmniRoute.exe'. The hardcoded check failed, returning
exit code 1 and breaking every Windows build in the release workflow.

Now finds the portable exe by excluding 'Setup' (NSIS installer) and
blockmap files, then copies it as OmniRoute.exe for the release assets.
2026-03-03 09:20:24 +05:30
diegosouzapw
8152b030bf chore: bump version to 1.7.14 and update CHANGELOG 2026-03-02 19:18:38 -03:00
diegosouzapw
9352ac767f Merge PR #188: fix passthrough stream for Responses SSE (#186) 2026-03-02 19:17:38 -03:00
diegosouzapw
5f20029ff7 fix: make passthrough stream format-aware for Responses SSE (#186)
Passthrough mode now detects Responses SSE payloads (parsed.type starts
with 'response.') and skips Chat Completions-specific sanitization:
- sanitizeStreamingChunk() only runs on Chat Completions payloads
- fixInvalidId() and hasValuableContent() checks skipped for Responses
- Usage extraction still runs for both formats
- Content length tracking adapted for Responses delta format

This prevents potential stream corruption when Responses SSE data
triggers idFixed or other Chat Completions-specific rewrite conditions.
2026-03-02 19:13:34 -03:00
diegosouzapw
dbd00117c8 chore: bump to 1.7.13 (npm republish) 2026-03-02 18:51:24 -03:00
diegosouzapw
2902a0fe26 chore: bump version to 1.7.12 2026-03-02 18:47:07 -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
211dde25d0 chore: bump version to 1.7.11 and update CHANGELOG 2026-03-02 18:33:08 -03:00
diegosouzapw
57ff59aef2 Merge PR #183: fix projectId warnings + add blackbox.ai provider (#175, #176)
- Added warning logs when generateProjectId() is used as fallback
- Prefer translator-set body.project before generating a new fallback
- Added blackbox.ai as OpenAI-compatible provider with 6 models + logo
- Includes improvement from Copilot PRs #184 and #185
2026-03-02 18:32:08 -03:00
Diego Rodrigues de Sa e Souza
c39faba2b5 Update open-sse/executors/antigravity.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 18:22:49 -03:00
diegosouzapw
212bca2e1e fix: add projectId warning logs and blackbox.ai provider (#175, #176)
- Added warning logs when generateProjectId() is used as fallback
  in antigravity.ts and openai-to-gemini.ts (3 locations), helping
  admins diagnose 404 errors from fake GCP project IDs (#176)
- Added blackbox.ai as new OpenAI-compatible provider with 6 models
  (GPT-4o, Gemini 2.5 Flash, Claude Sonnet 4, DeepSeek V3,
  Blackbox AI, Blackbox AI Pro) and provider logo (#175)
2026-03-02 17:58:43 -03:00
Diego Rodrigues de Sa e Souza
f807c56e31 Merge pull request #182 from diegosouzapw/dependabot/npm_and_yarn/development-51b319602c
deps: bump the development group with 2 updates
2026-03-02 17:47:43 -03:00
Diego Rodrigues de Sa e Souza
5510c25040 Merge pull request #181 from diegosouzapw/dependabot/npm_and_yarn/production-d7c3d31362
deps: bump wreq-js from 2.0.1 to 2.1.1 in the production group
2026-03-02 17:47:26 -03:00
dependabot[bot]
9d884d2d60 deps: bump the development group with 2 updates
Bumps the development group with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [lint-staged](https://github.com/lint-staged/lint-staged).


Updates `@types/node` from 25.3.0 to 25.3.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `lint-staged` from 16.2.7 to 16.3.1
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.3.1)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.3.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
- dependency-name: lint-staged
  dependency-version: 16.3.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 20:22:45 +00:00
dependabot[bot]
f26fa67374 deps: bump wreq-js from 2.0.1 to 2.1.1 in the production group
Bumps the production group with 1 update: [wreq-js](https://github.com/sqdshguy/wreq-js).


Updates `wreq-js` from 2.0.1 to 2.1.1
- [Release notes](https://github.com/sqdshguy/wreq-js/releases)
- [Commits](https://github.com/sqdshguy/wreq-js/compare/v2.0.1...v2.1.1)

---
updated-dependencies:
- dependency-name: wreq-js
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 20:22:16 +00:00
diegosouzapw
ccb314e065 feat: update agent workflows to use PR-based flow with user verification
Refactor resolve-issues and review-prs workflows to create branches
and PRs instead of committing directly. Add mandatory stop points
for user verification before merging, closing issues, or releasing.
Includes deploy step to local VPS after release.
2026-03-02 16:37:17 -03:00
diegosouzapw
0517dcf0b7 chore: bump version to 1.7.10 and update CHANGELOG 2026-03-02 15:31:38 -03:00
diegosouzapw
b7f0665ce9 fix: streaming tool calls missing id and wrong finish_reason in Responses→ChatCompletions translation (#180)
- Added tool_calls[].id and type:'function' to argument delta chunks
  so OpenAI-compatible clients can associate argument fragments with
  the correct tool call
- Changed finish_reason from hardcoded 'stop' to 'tool_calls' when
  tool calls were emitted (in flush, response.completed, and final chunk)
- Fixes state desync in agentic clients (OpenCode, Claude Code, etc.)
  where the assistant thinks tools already ran
2026-03-02 15:30:54 -03:00
diegosouzapw
144628755d chore: bump version to 1.7.9 and update CHANGELOG 2026-03-02 14:55:56 -03:00
diegosouzapw
7c5bb2c6b6 Merge PR #179: docs: update Cline URL to OpenClaw 2026-03-02 14:55:13 -03:00
diegosouzapw
afadb0fea1 Merge PR #178: fix: add JWT_SECRET env to electron release build step 2026-03-02 14:54:51 -03:00
MAINER4IK
b6c9c8a822 Change Cline to OpenClaw :)) 2026-03-02 22:28:01 +05:00
benzntech
11f43ca65c fix: add JWT_SECRET env to electron release build step
The Next.js build in electron-release.yml fails because the secrets
validator detects missing JWT_SECRET and exits with code 1. This adds
the env var to the build step, matching the pattern used in ci.yml.
2026-03-02 22:50:33 +05:30
diegosouzapw
8dce812a4d chore: bump version to 1.7.8 and update CHANGELOG 2026-03-02 12:14:58 -03:00
diegosouzapw
93047069b6 Merge PR #174: feat: add theme color settings and complete media/theme i18n 2026-03-02 12:13:53 -03:00
diegosouzapw
c4f1990aff fix: address agent review issues for theme color settings (#174)
Code Quality Improvements:
- Export COLOR_THEMES from themeStore.ts for reuse (DRY)
- Add coral preset to color list (fixes default inconsistency)
- Sync local customThemeColor state reactively via Zustand subscribe
- Add hex color validation with visual feedback (red border + disabled button)
- Remove dead /themes route from Header.tsx (page doesn't exist)
- Add CSS color-mix() fallback for older browsers
- Add themeCoral i18n key to all 30 locale files
2026-03-02 12:12:52 -03:00
mainer4ik
6e2816f08b feat: add theme color settings and complete media/theme i18n 2026-03-02 18:37:27 +05:00
diegosouzapw
227268024d chore: bump version to 1.7.7 and update CHANGELOG 2026-03-02 10:29:08 -03:00
diegosouzapw
8d5891a382 fix: sanitize tool schemas for Gemini provider (#173)
- Added cleanJSONSchemaForAntigravity() to openaiToGeminiBase() tool conversion
- Both OpenAI-format and Claude-format tool parameters are now sanitized
- Also sanitized response_format json_schema using the same function
- Removes unsupported JSON Schema keywords (additionalProperties, $schema, etc.)
- All Gemini paths (standard, CLI, Antigravity) now consistently sanitize schemas
2026-03-02 10:28:26 -03:00
diegosouzapw
7700fca501 chore: bump version to 1.7.6 and update CHANGELOG 2026-03-02 10:19:43 -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
8fbae5e467 feat(release): v1.7.5 — OAuth re-auth duplicate fix (#170)
- Fixed OAuth re-auth creating duplicate connections instead of updating existing ones
- CHANGELOG.md updated with v1.7.5 section
- Version bumped to 1.7.5
2026-03-02 00:38:33 -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
5ffa14190a feat(release): v1.7.4 — OpenCode CLI integration, endpoint page restructure, i18n translations
- OpenCode CLI integration guide added to README (#169)
- Endpoint page restructured with 3 categories + Responses API & Models endpoints
- 21 new i18n keys (settings + endpoint) translated across 30 locales
- 30 translated READMEs synced with v1.7.3 features
- 3 new workflow files: update-docs, generate-release, issue-triage
2026-03-01 23:03:54 -03:00
diegosouzapw
7820145cbe docs: add OpenCode CLI integration guide (#169)
- Added OpenCode section to README.md CLI Integration with step-by-step instructions
- Uses @ai-sdk/openai-compatible adapter with custom opencode.json config
- Includes example models and baseURL configuration
- Closes #169
2026-03-01 22:59:10 -03:00
diegosouzapw
b7a6c563ac feat: add i18n translations for Model Aliases & Background Degradation + restructure Endpoint page
- Added 14 translated settings keys (modelAliasesTitle, backgroundDegradationTitle, enableDegradation, etc.) to all 30 locale files
- Added 7 translated endpoint keys (responsesDesc, listModelsDesc, categoryCore/Media/Utility) to all 30 locale files
- Restructured Endpoint page with 3 grouped categories: Core APIs, Media & Multi-Modal, Utility & Management
- Added Responses API (/v1/responses) and List Models (/v1/models) endpoint sections
- Fixed missing translation display issue where raw keys were shown instead of translated text
2026-03-01 22:50:07 -03:00
diegosouzapw
52221488d0 docs: sync all 30 language READMEs with v1.7.3 features + create workflow files
- Synced feature tables across all 28 translated READMEs (Model Aliases, Background Degradation, Rate Limit Persistence, Token Refresh Resilience)
- Updated 6 docs/i18n/*/FEATURES.md with new Settings description
- Created workflows: update-docs.md (with multi-language sync step), generate-release.md, issue-triage.md
2026-03-01 22:02:38 -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
diegosouzapw
dc90211222 feat: add /deploy-vps workflow for npm-based VPS deployment 2026-03-01 07:29:55 -03:00
diegosouzapw
378c9f321d docs: update CHANGELOG v1.7.2 and READMEs with new multi-modal features
- CHANGELOG: add new features section (multi-modal providers, media playground, unit tests, WFGY docs) and expand bug fixes
- README/README.pt-BR: add Video/Music to tagline, expand Pain Point #13 with all new modalities, update Multi-Modal APIs table with Video/Music Generation
2026-03-01 07:12:51 -03:00
diegosouzapw
e11bcc2848 feat: add unit tests for registryUtils, media playground page, TypeScript fixes
- 24 unit tests for parseModelFromRegistry, getAllModelsFromRegistry, buildAuthHeaders
- Integration tests for video/music registries
- Media Playground dashboard page (Image/Video/Music tabs with model selector)
- Sidebar navigation entry for Media page
- i18n translations (EN + PT-BR)
- Fix Record<string, any> → Record<string, unknown> in registryUtils.ts
- Update /resolve-issues workflow to wait for user validation before commit/release
2026-03-01 07:10:27 -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
Diego Rodrigues de Sa e Souza
e8b72b54b3 Merge pull request #164 from onestardao/main
Approved — docs-only addition referencing the WFGY 16-problem RAG failure taxonomy in TROUBLESHOOTING.md.
2026-03-01 07:02:47 -03:00
Diego Rodrigues de Sa e Souza
d902dda4b1 Merge pull request #168 from benzntech/fix/electron-windows-shell
Approved — fixes Windows Electron release builds by adding `shell: bash` to the Collect installers step.
2026-03-01 07:02:39 -03:00
diegosouzapw
2538480b95 chore: release v1.7.2 — Gemini model import fix, Pino transport fallback 2026-03-01 06:49:27 -03:00
diegosouzapw
b9b8c93cb9 docs: enhance review-prs workflow with cross-layer analysis and thank-you step 2026-03-01 06:48:31 -03:00
diegosouzapw
68b7b35425 fix: log actual error and add sync pino.destination fallback (#165) 2026-03-01 06:48:02 -03:00
diegosouzapw
163c5feccc fix: strip models/ prefix from Gemini imported model IDs (#163) 2026-03-01 06:47:46 -03:00
Diego Rodrigues de Sa e Souza
0488f0536e Update docs/TROUBLESHOOTING.md
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-01 06:33:22 -03:00
benzntech
09e90ec25b fix: use bash shell for Collect installers step on Windows runner 2026-03-01 14:25:22 +05:30
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
PSBigBig × MiniPS
61e09d545f docs: add optional RAG failure taxonomy to troubleshooting 2026-03-01 10:56:51 +08:00
diegosouzapw
3a68d7dabc fix: restore dashboard layout — Tailwind v4 @source for route groups
Tailwind CSS v4 auto-detection failed to scan Next.js route group
directories with parentheses (e.g. '(dashboard)'), causing responsive
grid utilities to be purged from production CSS. Added explicit @source
directives in globals.css to fix the content scanning.

CSS output: 10KB (broken) → 110KB (correct), 12 media queries restored.
2026-02-28 18:53:16 -03:00
diegosouzapw
22d318f201 chore(release): bump version to v1.7.0 2026-02-28 17:42:31 -03:00
diegosouzapw
afa2cea678 feat: 16 pain points docs, configurable User-Agent (#155), fix hardcoded $HOME (#156)
- Add collapsible '16 Real Pain Points' section to all 30 READMEs
- Fix 5 files bypassing dataPaths.ts with hardcoded os.homedir() (closes #156)
- Add per-provider User-Agent env var overrides in base executor (closes #155)
- Sync .env and .env.example with 9 provider UA defaults
- Update CHANGELOG.md for v1.7.0
2026-02-28 17:41:55 -03:00
diegosouzapw
6dce45505c chore(release): v1.6.9
- PR #160: CopilotToolCard URL fix + chat model filter (alpgul)
- PR #161: Proxy port preservation, credential encoding, cache invalidation (ken2190)
- CHANGELOG: v1.6.9 entry
- Version bump: 1.6.8 → 1.6.9
2026-02-28 16:29:25 -03:00
Diego Rodrigues de Sa e Souza
014732788c Merge pull request #161 from ken2190/fix/proxy-logic-and-docker-build
fix: preserve explicit proxy port and fix Docker build
2026-02-28 16:28:28 -03:00
Diego Rodrigues de Sa e Souza
0e75d838ab Merge pull request #160 from alpgul/fix/base-url-and-chat-filter
fix: improve API base URL handling and filter for chat models in CopilotToolCard
2026-02-28 16:28:26 -03:00
Alptekin Gülcan
8383da8a50 fix: improve API base URL handling and filter for chat models in CopilotToolCard 2026-02-28 19:10:17 +00:00
duongvdo
199d173816 fix: preserve explicit proxy port (80/443) instead of defaulting to 8080
The URL parser silently strips default ports (80 for HTTP, 443 for HTTPS)
when constructing URL objects. This caused proxy connections to use port
8080 instead of the user-specified port 80, resulting in connection
timeouts. Fix by extracting the port from the raw URL string before
parsing and building the normalized URL manually to avoid the serializer
stripping it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:41:07 +07:00
diegosouzapw
f2829441f0 chore(release): v1.6.8
- Merged PR #159: Electron release workflow refactor (benzntech)
- Added app/ to .gitignore (Next.js App Router conflict fix)
- CHANGELOG: v1.6.8 entry
- Version bump: 1.6.7 → 1.6.8
2026-02-28 15:33:16 -03:00
diegosouzapw
21137bd84a fix: add app/ to .gitignore — prevents Next.js App Router conflict
The production standalone build directory (app/) created by scripts/prepublish.mjs
was conflicting with Next.js App Router detection. Next.js prioritizes root app/
over src/app/, causing all routes to return 404 in dev mode.

The package.json 'files' field still includes app/, so npm publish is unaffected.
2026-02-28 15:32:24 -03:00
Diego Rodrigues de Sa e Souza
a05e51a577 Merge pull request #159 from benzntech/fix/electron-release-filter
fix: filter Electron release assets to installers only
2026-02-28 15:30:59 -03:00
benzntech
09a094629c fix: include arm64 dmg in release assets
- Add explicit pattern for *-arm64.dmg files
- Fixes Kilo bot review: *.dmg doesn't match -arm64.dmg
2026-02-28 23:34:37 +05:30
benzntech
90de0fbf68 docs: add installation instructions with macOS Gatekeeper workaround 2026-02-28 23:21:39 +05:30
benzntech
c9cdd5109b feat: add Windows portable standalone exe
- NSIS installer: OmniRoute.Setup.X.Y.Z.exe (install to Program Files)
- Portable: OmniRoute.exe (run anywhere, no installation)
2026-02-28 23:19:20 +05:30
duongvdo
0e207dc5d2 fix: proxy logic bugs and Docker build failure
- URL-encode proxy credentials to handle special characters in passwords
- Decode URL-encoded credentials during legacy proxy migration
- Fix HTTPS proxy default port (443 instead of 8080) in frontend and migration
- Add dispatcher cache invalidation when proxy config changes
- Cast proxy port to number for SQLite INTEGER column in proxy logger
- Fix redundant .replace("//", "") in migration protocol parsing
- Copy postinstall script in Dockerfile before npm install

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:48:27 +07:00
benzntech
876a5a98f4 feat: add source code archives to releases
- Include .tar.gz and .zip of source code
- Uses git archive for clean export (excludes node_modules, build artifacts)
- Named: OmniRoute-vX.Y.Z.source.tar.gz / .zip
2026-02-28 23:16:43 +05:30
benzntech
8e82350d66 refactor: improve Electron release workflow
- Trigger on git tags (v*) instead of release.published
- Add manual workflow_dispatch for re-runs
- Add version validation step
- Use artifact upload/download pattern
- Single release job ensures all platforms complete first
- Prevents partial releases if one platform fails
2026-02-28 23:14:53 +05:30
benzntech
de75ed1551 fix: upload only installer files to releases
- Filter to *.dmg, *.exe, *.AppImage, *.blockmap only
- Prevents uploading unpacked app contents (DLLs, JS files, images)
2026-02-28 21:52:52 +05:30
benzntech
87266104a3 Merge origin/main - sync with v1.6.7 release 2026-02-28 21:52:38 +05:30
benzntech
fed8140404 chore: ignore electron build artifacts 2026-02-28 21:44:42 +05:30
diegosouzapw
e4d83e91bb chore(release): prepare release v1.6.7
- CHANGELOG: add v1.6.7 entry (Copilot Config Generator #142)
- FEATURES.md: add Copilot to CLI Tools section
- Version bump: 1.6.6 → 1.6.7 (package.json + electron/package.json)
2026-02-28 11:53:39 -03:00
diegosouzapw
a3153d893a feat: GitHub Copilot config generator for CLI Tools (#142)
Adds a Copilot configuration generator to the CLI Tools dashboard page.
Users can select models and generate the chatLanguageModels.json config
block for VS Code GitHub Copilot with the Azure vendor pattern.

Features:
- Bulk model selection from /v1/models (includes combos, custom, aliased)
- Search/filter for large model lists
- Configurable maxInputTokens, maxOutputTokens, toolCalling, vision
- One-click copy to clipboard
- Persistent model selection via localStorage
- Version compatibility warning (VS Code >= 1.109, Copilot >= v0.37)

Feedback from @alpgul applied:
- Use /v1/models instead of /api/models/alias (includes combo definitions)
- Use window.location.origin for URL (no port duplication in Docker)

Also: added electron/dist-electron/ to .gitignore (build artifact)
2026-02-28 11:31:55 -03:00
diegosouzapw
be219449f9 chore(release): bump version to v1.6.6 2026-02-28 11:17:26 -03:00
diegosouzapw
06d193f0d9 fix: prevent auth bypass after onboarding (#151)
The 'no password' auth bypass check was meant for fresh installs only,
but it also fired after onboarding was complete if the password row
was missing from the database (e.g. after DB migration in v1.6.3).

Fix: Added !settings.setupComplete guard so the bypass only applies
before onboarding is done. Once setupComplete=true, auth is always
required regardless of whether the password key exists in the DB.

Files changed:
- src/proxy.ts (dashboard middleware)
- src/shared/utils/apiAuth.ts (isAuthRequired)
2026-02-28 11:16:23 -03:00
diegosouzapw
4f413615d9 chore(release): prepare release v1.6.5
- Merge PR #154: official Electron icons and release workflow
- Fix electron-release.yml: npm ci → npm install (no package-lock.json)
- CHANGELOG: add v1.6.5 entry
- Version bump: 1.6.4 → 1.6.5
2026-02-28 10:27:58 -03:00
Benson
2a79b833fb feat(electron): add official icons and release workflow (#154)
* feat(electron): add app icons for Windows, macOS, and Linux releases

- icon.ico: Windows application icon (256x256 with multiple resolutions)
- icon.icns: macOS application icon bundle (16px to 1024px)
- icon.png: Linux/general purpose icon (512x512)
- tray-icon.png: System tray icon (32x32)

Icons generated from images/omniroute.png source logo.
Enables branded Electron desktop app builds for all platforms.

* chore: sync package-lock.json

* feat(electron): use official SVG logo and add release workflow

- Regenerated app icons from public/icon-192.svg (official OmniRoute logo)
- Added .github/workflows/electron-release.yml for automated builds
- Icons: icon.icns (macOS), icon.ico (Windows), icon.png (Linux), tray-icon.png
- Build workflow creates DMG (mac), EXE (win), AppImage (linux) on release

* ci: add npm cache to electron-release workflow
2026-02-28 10:26:46 -03:00
Diego Rodrigues de Sa e Souza
52e3d4b37b Merge pull request #153 from diegosouzapw/dependabot/npm_and_yarn/electron/npm_and_yarn-c9b74b4f42
chore(deps-dev): bump electron from 33.4.11 to 40.6.1 in /electron in the npm_and_yarn group across 1 directory
2026-02-28 10:21:25 -03:00
diegosouzapw
d9b393a308 docs: restructure all 30 READMEs — reorder sections, remove duplicates
Changes across README.md + 29 translations:
- Remove 🌐 English | Português (BR) language switcher from top
- Move Free AI Provider agents table below badges/links
- Move 📧 Support section right after agents table
- Move 💡 Key Features before 🎯 Use Cases
- Remove 📊 Available Models section
- Move 🔐 OAuth section inside Troubleshooting
- Remove entire 🇧🇷 Portuguese duplicate section at bottom
2026-02-28 09:56:32 -03:00
diegosouzapw
9a3d72c6a2 docs: update electron/README.md, USER_GUIDE.md, FEATURES.md with desktop app docs 2026-02-28 08:33:55 -03:00
dependabot[bot]
5b9b1cdd44 chore(deps-dev): bump electron
Bumps the npm_and_yarn group with 1 update in the /electron directory: [electron](https://github.com/electron/electron).


Updates `electron` from 33.4.11 to 40.6.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v33.4.11...v40.6.1)

---
updated-dependencies:
- dependency-name: electron
  dependency-version: 40.6.1
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 11:16:30 +00:00
diegosouzapw
d624ddde03 fix(electron): code review hardening — 16 fixes for security, performance, robustness
## Critical Fixes
- #1: Server readiness — waitForServer() polls before loading window
- #2: Restart timeout — 5s + SIGKILL prevents IPC handler from hanging
- #3: changePort — now stops/restarts server on new port

## Important Fixes
- #4: Tray cleanup — destroy old Tray before recreating
- #5: IPC emission — server-status & port-changed events
- #6: Disposer pattern — replaces removeAllListeners
- #7: useSyncExternalStore — eliminates 5x re-renders

## Minor: #8-#16 (dead code, CSP, platform titlebar, types, errors, version)

Tests: 76 / 15 suites (was 64/9)
2026-02-28 08:15:04 -03:00
diegosouzapw
d3ace8d611 fix: security hardening, tests, docs for Electron desktop & memory optimization
## Security Fixes
- Sanitize OMNIROUTE_MEMORY_MB with parseInt + range validation (64-16384)
  to prevent command injection via spawn() args
- Validate URL protocol in shell.openExternal (http/https only)
  to prevent RCE in Electron renderer compromise
- Bump default memory from 256MB to 512MB

## Electron package-lock.json
- Added to .gitignore (5278 lines removed from tracking)

## Test Suite (64 tests, 9 suites)
- electron-main.test.mjs: URL validation, IPC channels, window handler
- electron-preload.test.mjs: channel whitelist, API surface, open-external
- cli-memory.test.mjs: injection prevention, boundary values, .env parsing

## Documentation
- Desktop App section added to all 30 READMEs (9 fully translated)
- USER_GUIDE.md updated with 512MB default
- .env.example reflects new defaults
2026-02-28 07:59:38 -03:00
Diego Rodrigues de Sa e Souza
177507bbc8 Merge pull request #150 from benzntech/feat/electron-desktop-app
feat: Electron desktop application
2026-02-28 07:52:31 -03:00
Diego Rodrigues de Sa e Souza
d915e2a868 Merge pull request #148 from benzntech/feat/memory-optimization-v2
feat: memory optimization for low-RAM configurations
2026-02-28 07:52:08 -03:00
benzntech
a3d15cf971 fix: address PR review comments
- Fix server restart logic to use event-based termination
- Use app.getPath('userData') for cross-platform data directory
- Implement VALID_CHANNELS validation in preload script
- Fix incorrect copy command in user guide
- Fix broken markdown table formatting

Refs: #150
2026-02-28 11:54:41 +05:30
benzntech
5e72cd34f0 fix: improve Electron security and functionality
- Add window control IPC handlers (minimize, maximize, close)
- Add URL validation for open-external to prevent security issues
- Add single instance lock to prevent multiple app instances
- Add deep link protocol support (omniroute://)

Refs: #149
2026-02-28 11:23:27 +05:30
benzntech
b004d0472b feat: add Electron desktop application support
- Add electron/ directory with main process, preload script, and types
- Add system tray integration and window management
- Add IPC communication for app info, external links, server controls
- Add useElectron React hooks for Next.js integration
- Add build scripts for Windows, macOS, and Linux
- Add development scripts for running Electron with Next.js

Ref: #149
2026-02-28 10:40:25 +05:30
benzntech
6ed98fb21c Merge branch 'main' of https://github.com/diegosouzapw/OmniRoute into feat/memory-optimization 2026-02-28 09:52:39 +05:30
diegosouzapw
d8bf4b1db8 chore(release): bump version to v1.6.3 2026-02-28 00:55:59 -03:00
diegosouzapw
fb2351ffe7 fix: sanitize hardcoded build-machine paths in standalone output (#147)
Next.js standalone bakes absolute build-time paths (outputFileTracingRoot,
appDir, turbopack root) into server.js and required-server-files.json.
When installed via npm on a different machine, these paths don't exist,
causing ENOENT errors. The prepublish script now replaces build-machine
absolute paths with '.' (relative) so they resolve correctly wherever
the package is installed.
2026-02-28 00:54:23 -03:00
diegosouzapw
12f7d2b484 fix: preserve database data on upgrade when old schema_migrations exists (#146)
Previously, the upgrade detection logic renamed the entire DB file when it
found a schema_migrations table (from older versions), causing data loss.
Now checks if the DB actually contains data (provider_connections) before
deciding to rename. If data exists, drops only the old migration tracking
table and lets the new CREATE TABLE IF NOT EXISTS schema take over.
2026-02-28 00:54:07 -03:00
diegosouzapw
2c40ef0964 chore(release): bump version to v1.6.2 2026-02-27 22:22:58 -03:00
diegosouzapw
ceb778a040 Merge branch 'feat/issue-121-provider-labels' into main (#121) 2026-02-27 22:21:46 -03:00
diegosouzapw
2c5a546759 chore(release): bump version to v1.6.1 2026-02-27 16:49:08 -03:00
diegosouzapw
3286f05b3b fix: auto-rebuild better-sqlite3 for cross-platform npm installs (#129)
The npm package ships with better-sqlite3 compiled for Linux x64.
On Windows and macOS, the binary is incompatible and fails to load.

Added postinstall script that:
- Detects if the bundled native module is incompatible
- Automatically runs 'npm rebuild better-sqlite3' to compile for the target platform
- Provides manual fallback instructions if rebuild fails
2026-02-27 16:48:28 -03:00
Diego Rodrigues de Sa e Souza
6a6a868845 Merge pull request #145 from diegosouzapw/dependabot/npm_and_yarn/minimatch-3.1.5
deps: bump minimatch from 3.1.2 to 3.1.5
2026-02-27 16:43:51 -03:00
diegosouzapw
56de009756 chore(release): bump version to v1.6.0 2026-02-27 16:32:25 -03:00
dependabot[bot]
deb855f9d4 deps: bump minimatch from 3.1.2 to 3.1.5
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 19:31:29 +00:00
Diego Rodrigues de Sa e Souza
7da0675907 Merge pull request #144 from diegosouzapw/dependabot/github_actions/actions/download-artifact-8
chore(deps): bump actions/download-artifact from 4 to 8
2026-02-27 16:31:04 -03:00
Diego Rodrigues de Sa e Souza
f8a22e71f7 Merge pull request #143 from diegosouzapw/dependabot/github_actions/actions/upload-artifact-7
chore(deps): bump actions/upload-artifact from 4 to 7
2026-02-27 16:31:02 -03:00
diegosouzapw
5229290ac4 Merge PR #140: refactor split ports (npmSteven) with polish fixes
Adds split-port runtime support: API and dashboard can run on separate ports.
- PORT remains canonical/base
- API_PORT optionally overrides API listener
- DASHBOARD_PORT optionally overrides dashboard listener
- API bridge server proxies OpenAI-compatible routes with 30s timeout
- Centralized port resolution in src/lib/runtime/ports.ts
- Unit tests for runtime port resolution (14 tests)
- Healthcheck extracted into scripts/healthcheck.mjs
2026-02-27 16:30:17 -03:00
diegosouzapw
01c1bbfe29 fix: polish split-port implementation for merge
- Add 30s timeout to API bridge proxy requests to prevent resource exhaustion
- Extract healthcheck.mjs script (replaces inline node -e in Dockerfile + compose files)
- Add unit tests for runtime port resolution (14 tests, parsePort + resolveRuntimePorts)
- Fix formatting in declare global block
2026-02-27 16:29:58 -03:00
dependabot[bot]
234e14a30b chore(deps): bump actions/download-artifact from 4 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 18:32:29 +00:00
dependabot[bot]
0b0e503615 chore(deps): bump actions/upload-artifact from 4 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 18:32:21 +00:00
diegosouzapw
e8be72ad28 chore(release): bump version to v1.5.0 2026-02-26 17:16:53 -03:00
diegosouzapw
3ca7b9eafa docs: update changelog for v1.5.0 release 2026-02-26 17:16:28 -03:00
diegosouzapw
7feac7a158 docs: Remove OMNI_TOKEN placeholders and malformed tokens from internationalized documentation and READMEs. 2026-02-26 17:12:52 -03:00
diegosouzapw
3d7d02a10a feat: add new internationalization message files for multiple languages and update Portuguese (Brazil) messages. 2026-02-26 16:50:47 -03:00
diegosouzapw
7bab9e09d3 feat(i18n): add Arabic and Finnish translation files
Add complete i18n message files for Arabic (ar.json) and Finnish
(fi.json) locales covering all UI sections including common, sidebar,
providers, analytics, costs, health, limits, settings, modals, and
loggers translations.
2026-02-26 16:50:01 -03:00
diegosouzapw
c2a777580a fix(ui): improve dashboard responsiveness and i18n error message
- Add responsive breakpoints (sm/lg) for flex and grid layouts
- Prevent text overflow with min-w-0 and break-words utilities
- Stack buttons and inputs vertically on small screens
- Replace hardcoded HTTP error with translated audit log message
2026-02-26 16:49:03 -03:00
diegosouzapw
952b0b22c7 docs(i18n): add Swedish locale translations and i18n QA tooling
Add complete Swedish (sv) translation for all documentation files
including API Reference, README, and guides. Introduce automated
i18n QA infrastructure with visual regression testing across
multiple viewports and locales to validate translations.
2026-02-26 16:28:29 -03:00
diegosouzapw
4cfd1b94e1 docs: add multi-language i18n documentation translations
Add translated documentation (API Reference, Guide, README) for 30+
languages under docs/i18n/, including pt-BR, es, fr, de, it, ru, zh-CN,
ja, ko, ar, and many others to improve international accessibility.
2026-02-26 16:27:43 -03:00
diegosouzapw
1647005d6e docs(i18n): add multilingual documentation translations
Add translated documentation files for multiple languages including
Korean, Polish, and others under docs/i18n/. Translations cover
API reference, quickstart guides, and project documentation to
improve accessibility for non-English speaking contributors.
2026-02-26 16:26:59 -03:00
diegosouzapw
369a0141de docs(i18n): add Hungarian translation of ARCHITECTURE.md
Add Magyar (hu) translation of the architecture documentation
to support Hungarian-speaking contributors and users.
2026-02-26 16:26:35 -03:00
diegosouzapw
cc97917ee2 docs(i18n): add Bulgarian translation for TROUBLESHOOTING.md
Add complete Bulgarian (bg) localization of the troubleshooting guide,
covering provider issues, cloud sync, Docker, CLI tools, routing,
environment variables, and debugging instructions.
2026-02-26 16:25:54 -03:00
diegosouzapw
0f49f82405 feat(docs): add i18n multi-language support for documentation
Add language selector banners to all English documentation files
linking to translations in 30+ languages. Update .gitignore to
track docs/i18n/ directory and fix path patterns for node_modules,
coverage, and .next directories.
2026-02-26 16:24:36 -03:00
diegosouzapw
0d58a92479 docs: add Polish and Vietnamese README translations
Add README.pl.md and README.vi.md with full translations of the
project documentation, expanding internationalization support for
the OmniRoute AI gateway project.
2026-02-26 16:22:21 -03:00
diegosouzapw
cde0a3bf4e docs: add multilingual README translations (Arabic, Filipino, etc.)
Add localized README files for additional languages including
Arabic (README.ar.md) and Filipino (README.fil.md) to improve
accessibility and broaden the project's international reach.
2026-02-26 16:21:57 -03:00
Steven Rafferty
344e602b26 feat: enhance runtime port management and configuration
- Updated .env.example to include optional production ports for API and dashboard.
- Modified docker-compose files to utilize dynamic port configuration.
- Introduced runtime-env.mjs for centralized port resolution and environment variable management.
- Refactored run-next.mjs and run-standalone.mjs to leverage new runtime port handling.
- Enhanced route.ts and apiBridgeServer.ts to utilize dynamic ports for improved API integration.
- Updated OAuth configuration to reflect changes in port management.
2026-02-26 15:47:31 +00:00
Steven
b941515c5a Merge branch 'main' into refactor-split-ports 2026-02-26 15:17:56 +00:00
Steven Rafferty
fb597c677e feat: improve API configuration and script execution
- Added API_HOST variable to .env.example for enhanced host configuration.
- Updated package.json scripts to utilize a new run-next.mjs script for development and production.
- Introduced run-next.mjs to manage Next.js server execution with dynamic port handling.
- Enhanced route.ts files to normalize API base URLs and improve configuration checks.
- Updated apiBridgeServer.ts to use API_HOST for server initialization.
- Expanded global TypeScript definitions to include API_HOST.
2026-02-26 15:15:35 +00:00
Steven Rafferty
d0138a5037 feat: enhance port configuration and API bridge support
- Updated .env.example to include optional split ports for API and dashboard.
- Modified docker-compose files to dynamically use the configured ports.
- Introduced a new script (run-standalone.mjs) for running the server with environment-specific ports.
- Implemented an API bridge server to handle OpenAI-compatible routes when using split ports.
- Updated README and CLI tool documentation to reflect changes in port usage and configuration.
- Enhanced various components to utilize the new port configuration, ensuring backward compatibility.
2026-02-26 15:11:40 +00:00
Diego Rodrigues de Sa e Souza
2c2e0a95a1 Merge pull request #136 from diegosouzapw/docs/enable-discussions-badge
docs: enable discussions for community support
2026-02-26 09:18:07 -03:00
diegosouzapw
e0d5a78dd3 docs: enable discussions for community support 2026-02-26 09:17:44 -03:00
Diego Rodrigues de Sa e Souza
428a8490f8 ci: fix deploy-vps.yml — add DEPLOY_ENABLED guard, remove broken Tailscale step 2026-02-26 03:21:13 -03:00
Diego Rodrigues de Sa e Souza
96114bf92e ci: delete broken codex-review.yml workflow 2026-02-26 03:20:48 -03:00
diegosouzapw
77a3eece32 docs: update README, README.pt-BR, TROUBLESHOOTING with v1.4.9-v1.4.11 features
- Added proxy visibility + 3-level proxy config to feature tables
- Added language selector and DATA_DIR env var entries
- Added EACCES and routing strategy fix to troubleshooting quick fixes
- Equivalent changes in both EN and PT-BR READMEs
2026-02-26 03:09:09 -03:00
diegosouzapw
107b9e8cd2 feat(i18n): replace hardcoded strings with translation keys in HomePageClient
Replace hardcoded English text in quick start links and getting started
steps with proper i18n translation keys. Use `t.rich()` for step
descriptions containing inline links to support rich text interpolation.
2026-02-26 03:05:30 -03:00
diegosouzapw
187aba0514 feat(i18n): replace remaining hardcoded strings with translation keys
Replace hardcoded English text with t() translation calls across
combos, providers, and ModelAvailabilityBadge components. Add
corresponding translation keys to locale files for full i18n coverage.
2026-02-26 01:41:52 -03:00
diegosouzapw
2126b0ee8d feat(i18n): internationalize dashboard and API manager components
Replace all hardcoded English strings with translation function calls
across dashboard pages including API manager, chat tester, and related
components. Update validation functions to accept a translator parameter
and add corresponding translation keys for multiple locales (en, pt-BR).
2026-02-25 21:11:14 -03:00
diegosouzapw
113ac1c940 chore(release): bump version to v1.4.11 2026-02-25 19:25:14 -03:00
diegosouzapw
fbaf30a6bf docs: update changelog for v1.4.11 release 2026-02-25 19:25:07 -03:00
diegosouzapw
8abdf68718 fix: routing strategy not persisted after refresh (#134)
The Zod updateSettingsSchema was missing fallbackStrategy,
wildcardAliases, and stickyRoundRobinLimit fields. Since
.passthrough() was removed in a previous cleanup, these unknown
keys were silently stripped during validation, so the PATCH
/api/settings call never actually persisted these values.
2026-02-25 19:23:54 -03:00
diegosouzapw
67fa2592b5 chore(release): bump version to v1.4.10 2026-02-25 18:43:20 -03:00
diegosouzapw
fed445c991 docs: update changelog for v1.4.10 release 2026-02-25 18:43:18 -03:00
diegosouzapw
62069dac98 fix: handle EACCES on restricted home directories (#133)
Wrap fs.mkdirSync(DATA_DIR) in try/catch so OmniRoute doesn't crash
when the user's home directory is not writable (e.g. restricted
environments, npm global install with different user).
Prints a clear warning with DATA_DIR env var recommendation.
2026-02-25 18:41:54 -03:00
diegosouzapw
5a65585c16 feat: add provider-level proxy button in Connections header
- New 'Provider Proxy' button next to Connections heading
- Opens ProxyConfigModal at provider level
- Amber highlight when proxy is configured, shows IP
- Supports all 3 proxy levels: global, provider, per-connection
2026-02-25 17:44:38 -03:00
diegosouzapw
4e3b363ba6 feat: color-coded proxy badge with IP display
- Green: global proxy
- Yellow/amber: provider-level proxy
- Blue: per-connection proxy
- Always shows proxy host/IP in the badge text
- Tooltip shows proxy source and full address
2026-02-25 17:40:21 -03:00
diegosouzapw
f1d421bd8a feat: proxy badge shows for all proxy levels (key/provider/global)
- hasProxy now checks keys/providers/global config levels
- Badge color changed to emerald green to match other status badges
- Tooltip shows proxy source: per-connection, per-provider, or global
- Previously only showed for per-connection proxy, missing global/provider
2026-02-25 17:32:28 -03:00
diegosouzapw
fb840d6392 fix: CLI tools page hangs — add timeout to runtime status checks
Server-side: wrap getCliRuntimeStatus() in 5s Promise.race timeout
Client-side: add 8s AbortController timeout to fetchToolStatuses()
Prevents entire page from staying in skeleton state forever when
binary checks hang on VPS
2026-02-25 17:11:49 -03:00
diegosouzapw
e659d2ee69 chore(release): bump version to v1.4.9 2026-02-25 17:06:28 -03:00
diegosouzapw
ab1b0c890a docs: update changelog and READMEs for v1.4.9 release
- CHANGELOG.md: add v1.4.9 entry (i18n, codex fix, build fixes)
- README.md: add internationalization to Key Features
- README.pt-BR.md: add internacionalização to Funcionalidades
2026-02-25 17:06:13 -03:00
diegosouzapw
dbe6a4e30c fix: production build — crypto import, sub-component translation scope, TS config
- instrumentation.ts: use eval('require')('crypto') to bypass webpack
- HomePageClient.tsx: add useTranslations to ProviderOverviewCard and
  ProviderModelsModal (separate components need own hooks)
- next.config.mjs: temporarily allow TS errors during build (remaining
  sub-component scope issues in EvalsTab.tsx)
2026-02-25 16:52:09 -03:00
diegosouzapw
ce1e10c8c6 chore: bump version to 1.4.8 2026-02-25 16:26:26 -03:00
diegosouzapw
8caef4b688 fix: instrumentation.ts crypto import for webpack compatibility
Use eval('require')('crypto') to hide the import from webpack's
static analysis. The instrumentation file is compiled for both
client and server, but crypto is only used in Node.js runtime.
2026-02-25 16:26:05 -03:00
diegosouzapw
bc55911d0f fix: allow multiple Codex accounts from same workspace (Team/Business)
Root cause: createProviderConnection() upsert logic for codex deduplicates
by workspaceId only (chatgpt_account_id from JWT). Two Pro Business accounts
from the same Team workspace resolve to the same workspaceId, causing the
second to silently overwrite the first.

Fix: compound uniqueness check using workspaceId + email, so different users
within the same workspace create separate connections. Includes backward-compat
fallback for old connections without email (they'll still be updated).
2026-02-25 15:32:23 -03:00
diegosouzapw
bc6b084c77 fix(i18n): remove 24 duplicate JSON keys in en.json + pt-BR.json
- Removed duplicate providers/new keys (selectProvider, apiKeyRequired, etc.)
  that overlapped with pre-existing keys from earlier migration
- Removed duplicate backToProviders in both files
- Removed duplicate loadingPricing and databaseSize in settings namespace
- Updated providers/new/page.tsx to use original key names
- Verified 0 duplicates remain via Python namespace scan
2026-02-25 15:16:22 -03:00
diegosouzapw
3d86ad7dc8 feat(i18n): migrate providers/new + AuditLogTab + remaining keys
Phase 4: providers/new/page.tsx — 15 strings (form labels, errors, buttons)
Phase 5: logs/AuditLogTab.tsx — 15 strings (headers, filters, pagination)
Phase 6: Added ~50 new keys to en.json + pt-BR.json

Providers namespace: selectProvider, apiKeyRequired, authMethod, etc.
Logs namespace: auditLogDesc, filterByAction, filterByActor, etc.
2026-02-25 15:08:38 -03:00
diegosouzapw
0844659e00 feat(i18n): migrate providers/[id]/page.tsx — 30+ strings
- Added useTranslations('providers') hook
- Translated confirm/alert dialogs, buttons, headings
- Translated import progress statuses and error messages
- Translated compatible details labels (Anthropic/OpenAI)
- Replaced hardcoded 'Back to Providers', 'Provider not found'
- Added 35 new keys to en.json + pt-BR.json providers namespace
2026-02-25 15:05:45 -03:00
diegosouzapw
e07edc663b feat(i18n): migrate settings/pricing/page.tsx — full page (17 strings)
- Translated title, subtitle, stats labels, info section, pricing overview
- Added editPricing, viewFullDetails, pricing description keys
- Settings pages now 100% i18n complete
2026-02-25 15:02:04 -03:00
diegosouzapw
5f38173387 fix(i18n): settings remnants — PoliciesPanel, PricingTab desc, ThinkingBudget, FallbackChains, Resilience
- PoliciesPanel.tsx: full migration (10 strings + 2 notify.error)
- PricingTab.tsx: translate description block, confirm, subtitle
- ThinkingBudgetTab.tsx: translate 'Off' label
- FallbackChainsEditor.tsx: translate confirm() string
- ResilienceTab.tsx: translate 2 notify.error('Failed to unlock')
- Added 25 keys to en.json + pt-BR.json settings namespace
2026-02-25 15:00:12 -03:00
diegosouzapw
481a630273 feat(i18n): migrate Settings batch 4 — final 4 large tabs (80+ strings)
- ComboDefaultsTab: strategy labels, toggles, provider overrides
- PricingTab: model pricing, stats, save/reset, search
- ResilienceTab: provider profiles, rate limiting, circuit breakers, policies
- SystemStorageTab: export/import, backup/restore, database info
- Expanded settings namespace to ~290 total keys
- Completes Settings page i18n migration (17/17 files)
2026-02-25 14:35:10 -03:00
diegosouzapw
8592d02951 feat(i18n): migrate Settings batch 3 — Session, IP, Compliance, Fallback (36+ strings)
- SessionInfoCard: status, login, clear data, logout
- IPFilterSection: access control, block/allow buttons
- ComplianceTab: audit log, search, filters
- FallbackChainsEditor: create/delete chains, notifications
- Expanded settings namespace by 43 keys
2026-02-25 14:25:47 -03:00
diegosouzapw
7f34835693 feat(i18n): migrate Settings batch 2 — SecurityTab + RoutingTab (25+ strings)
- SecurityTab: password form, blocked providers, endpoint protection
- RoutingTab: strategy labels, model aliases, sticky limit
- Expanded settings namespace by 40 security/routing keys
2026-02-25 14:22:49 -03:00
diegosouzapw
0ac264b39d feat(i18n): migrate Settings page batch 1 (7 files, 28+ strings)
- Main page.tsx: tab labels, footer
- AppearanceTab: dark mode, health check logs
- CacheStatsCard: prompt cache stats
- ProxyTab: global proxy
- SystemPromptTab: global system prompt
- ThinkingBudgetTab: mode labels, effort levels
- Expanded settings namespace from 63 to 100 keys
2026-02-25 14:20:06 -03:00
diegosouzapw
87c7c83dd9 feat(i18n): migrate Providers page (1110 lines, 30+ strings)
- ProvidersPage: section headers, test buttons, compatible provider modals
- Expanded providers namespace from 16 to 73 keys in en.json and pt-BR.json
- Coverage: OAuth/Free/API Key/Compatible sections, batch test, modals
2026-02-25 14:11:06 -03:00
diegosouzapw
10d3120cdf feat(i18n): migrate Endpoint page (999 lines, 40+ strings)
- EndpointPageClient: full migration including cloud proxy modals,
  endpoint sections (chat, embeddings, images, rerank, audio, moderations),
  enable/disable cloud flows, sync steps, and status messages
- Expanded endpoint namespace from 10 to 55 keys in en.json and pt-BR.json
2026-02-25 14:07:56 -03:00
diegosouzapw
27b9c331b7 feat(i18n): migrate Combos page (1123 lines, 50+ strings)
- CombosPage, ComboCard, ComboFormModal, TestResultsView: full migration
- Headers, model tags, metrics, strategy descriptions, validation
- Form labels, advanced settings, drag-and-drop model list, actions
- Expanded combos namespace from 19 to 65 keys in en.json and pt-BR.json
2026-02-25 14:03:46 -03:00
diegosouzapw
e1fe304dd3 feat(i18n): migrate API Manager page (1008 lines, 43+ strings)
- ApiManagerPageClient: full migration including stats cards, table headers,
  modals, permissions system, validation messages, and usage tips
- PermissionsModal: search, model selection, allow/restrict toggles
- Expanded apiManager namespace from 18 to 67 keys in en.json and pt-BR.json
2026-02-25 13:58:55 -03:00
diegosouzapw
d226d68251 feat(i18n): migrate CLI Tools main page
- CLIToolsPageClient: 2 strings (no active providers warning)
- Added noActiveProviders/noActiveProvidersDesc keys to en.json/pt-BR.json
2026-02-25 13:50:38 -03:00
diegosouzapw
a6014524ef feat(i18n): migrate onboarding wizard
- Onboarding: 37 strings (all wizard steps, labels, messages, buttons)
- Expanded en.json and pt-BR.json onboarding namespace with 30+ keys
- Dynamic STEPS array from translations for wizard step titles
2026-02-25 13:49:37 -03:00
diegosouzapw
1a98a6c966 feat(i18n): migrate audit-log, costs, logs, health pages + expand JSON keys
- Audit Log: 15 strings (table headers, filters, pagination)
- Costs: 2 strings (tab labels)
- Logs: 4 strings (tab labels)
- Health: 33 strings (full page including circuit breakers, telemetry, cache, rate limits)
- Limits: no strings needed (composition of migrated components)
- Added 50+ new keys to en.json and pt-BR.json
2026-02-25 13:47:20 -03:00
diegosouzapw
0d13f4645c feat: complete i18n migration — 21 pages/components translated + PT-BR README section
- Full en.json and pt-BR.json with 26 namespaces (~460 strings)
- Migrated: HomePageClient, Analytics, Translator (4 components),
  Usage (5 components), ProviderLimits, Shared (UsageStats,
  TokenHealthBadge, SystemMonitor, ConsoleLogViewer, Footer),
  Login, Callback, ForgotPassword, Forbidden
- README: added PT-BR section with quick start, features, i18n docs
- README: added language switcher badges at top
2026-02-25 13:30:57 -03:00
diegosouzapw
88d5986ac1 docs: add per-page i18n translation task files with string inventories 2026-02-25 13:20:33 -03:00
diegosouzapw
f7fb68a798 feat: add dashboard i18n with next-intl (EN + PT-BR), language selector in header 2026-02-25 13:13:35 -03:00
diegosouzapw
5811e677f1 fix: strip antigravity/ prefix from model names sent to upstream API + sync package-lock.json 2026-02-25 08:46:42 -03:00
diegosouzapw
0d9a98c4e1 chore(release): bump version to v1.4.6 2026-02-25 06:24:46 -03:00
diegosouzapw
05d8d3d71d fix: improve apiKeyPolicy type safety and logging + fix model ID mismatch in usage.ts
- Added ApiKeyMetadata interface to replace 'any' types in apiKeyPolicy.ts
- Added error logging in catch blocks for getApiKeyMetadata() and checkBudget()
- Fixed claude-sonnet-4-6-thinking → claude-sonnet-4-6 mismatch in usage.ts importantModels

Follow-up fixes for merged PRs #131 and #128
2026-02-25 06:06:37 -03:00
Diego Rodrigues de Sa e Souza
f670a1e451 Merge pull request #128 from nyatoru/update-last-250226
Approved: Model registry and pricing updates for current models. Alias mismatch fix will be applied in a follow-up commit.
2026-02-25 06:04:07 -03:00
Diego Rodrigues de Sa e Souza
1591737528 Merge pull request #131 from ersintarhan/fix/api-key-model-restriction
Approved: Critical security fix for API key model restrictions. Minor improvements (error logging, type safety) will be applied in a follow-up commit.
2026-02-25 06:03:58 -03:00
Diego Rodrigues de Sa e Souza
f74a007e27 Merge pull request #127 from npmSteven/refactor/multi-platform
Approved: Solid multi-platform Docker workflow using digest-merge pattern. Enables ARM64 support.
2026-02-25 06:03:46 -03:00
Diego Rodrigues de Sa e Souza
eb290a90cb Merge pull request #126 from nyatoru/fix/codex-plam
Approved: Clean, well-scoped change that correctly separates Plus/Paid tier from Pro in ProviderLimits.
2026-02-25 06:03:40 -03:00
nyatoru
9b80f723df Fix: remove thinking suffix from Claude Sonnet 4.6 model entry 2026-02-25 14:53:21 +07:00
nyatoru
f2ace011ff fix: remove thinking suffix from Claude Sonnet 4.6 model entvv 2026-02-25 14:30:17 +07:00
Ersin Tarhan
0c0a56d4de fix: enforce API key model restrictions and budget limits across all endpoints
isModelAllowedForKey() existed in src/lib/db/apiKeys.ts but was never
called anywhere. API keys with allowedModels restrictions could access
any model through any endpoint.

Changes:
- Add shared enforceApiKeyPolicy() middleware (model restriction + budget)
- Wire it into chat handler (replacing inline budget-only check)
- Wire it into all /v1/* endpoints: embeddings, images/generations,
  audio/speech, audio/transcriptions, moderations, rerank
- Wire it into provider-specific endpoints: /v1/providers/[provider]/embeddings,
  /v1/providers/[provider]/images/generations

The middleware checks:
1. Model restriction — if key has allowedModels, verify the model is permitted
2. Budget limit — if key has budget configured, verify it hasn't been exceeded

Fixes #130
2026-02-25 06:43:55 +03:00
nyatoru
981d163278 refactor: update model aliases for consistency and correctness 2026-02-25 08:30:20 +07:00
nyatoru
96cdd9bccb refactor: update model aliases for consistency and correctness 2026-02-25 02:38:48 +07:00
nyatoru
354d0b5f09 refactor: update model entries and pricing for improved consistency and new additions 2026-02-25 02:13:13 +07:00
Steven Rafferty
3d2de04dd1 refactor(ci): restructure Docker workflow to support multi-platform builds and digest management 2026-02-24 18:27:11 +00:00
nyatoru
93a220ba83 feat: add Plus tier as separate category in ProviderLimits 2026-02-25 01:15:01 +07:00
diegosouzapw
d55b6e0b7a feat: show user-defined provider labels and full API key names (#121)
- Combo cards now resolve UUID-based provider IDs to user-defined names using providerNodes
- API key names shown in full instead of masked (Op***w → OpenAI-Prod-Key); key IDs remain masked
- Logs/Analytics: OAI-compatible and ANT-compatible providers now show user-defined names from providerNodes instead of generic OAI-COMPAT labels
- All views (combo cards, combos form modal, logs table, quick filters, dropdowns, analytics) updated consistently
2026-02-24 14:28:39 -03:00
diegosouzapw
779957526b chore: add /implement-features workflow for feature request implementation 2026-02-24 14:21:37 -03:00
diegosouzapw
f76482db87 chore(release): bump version to v1.4.5 2026-02-24 14:00:10 -03:00
diegosouzapw
1be20a4e2d fix: route OAuth token exchange through configured proxy (#119)
- Wrap exchangeTokens calls with runWithProxyContext in both 'exchange' and 'poll-callback' actions
- Resolve proxy via provider-level → global → direct fallback chain
- Fixes region-restricted providers (e.g. OpenAI Codex) failing during OAuth setup with unsupported_country_region_territory error
2026-02-24 13:57:56 -03:00
diegosouzapw
ff965234c9 fix: Claude Code OAuth redirect_uri and scope for remote deployments (#124)
- Use Anthropic's registered redirect_uri (platform.claude.com/oauth/code/callback) instead of dynamic server URL
- Add missing OAuth scopes: user:sessions:claude_code, user:mcp_servers (5 total, matching Claude CLI)
- Make redirect_uri configurable via CLAUDE_CODE_REDIRECT_URI env var
- Override redirectUri in both buildAuthUrl and exchangeToken to use config value
2026-02-24 13:56:18 -03:00
diegosouzapw
62facba06f chore: add /resolve-issues workflow for automated issue resolution 2026-02-24 13:51:19 -03:00
diegosouzapw
3c309f1fa4 chore(release): bump version to v1.4.4 2026-02-24 13:44:07 -03:00
diegosouzapw
090343aa01 Merge PR #122: feat: save compatible provider models to customModels DB for /v1/models listing
Includes security hardening and UX improvements:
- Authentication on /api/provider-models via isAuthenticated
- URL parameter injection prevention (encodeURIComponent)
- Replaced alert() with notify.error/notify.success toasts
- Transactional save: DB first, then alias creation
- Consistent error handling across all model operations
2026-02-24 13:41:29 -03:00
diegosouzapw
e674e5d87b fix: security hardening and UX improvements for PR #122
- Fix URL parameter injection: apply encodeURIComponent on providerStorageAlias and providerId in all API calls
- Replace blocking alert() with non-blocking notify.error/notify.success toast notifications
- Add success feedback for model add and delete operations
- Improve error handling: use console.error consistently and add user-facing notifications for import failures
- Check DELETE response status before proceeding with alias removal
2026-02-24 13:41:12 -03:00
nyatoru
2a90a05132 feat: extract shared auth utility and fix custom provider model resolution 2026-02-24 22:08:20 +07:00
Nyaru Toru
a0af564b5a docs: add comments clarifying prefixToCheck logic in model.ts
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-24 21:31:50 +07:00
Nyaru Toru
ca2b1faa72 docs: add comment for nodePrefix UUID fallback caveat
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-24 21:30:29 +07:00
Nyaru Toru
bf49fdf0bf fix: improve error handling in custom model API call
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-24 21:29:21 +07:00
Nyaru Toru
c8989ddead refactor: rename providerPart to providerIdentifier for clarity
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-24 21:27:48 +07:00
nyatoru
4ea0426034 feat: extract shared auth utility a cooldown/availability checksnd fix custom provider model resolution 2026-02-24 21:19:57 +07:00
nyatoru
619c99ce4c feat: use getModelInfo for proper custom provider resolution in availability checks 2026-02-24 18:47:38 +07:00
nyatoru
86c566669c feat: fix custom provider node matching in model resolution 2026-02-24 18:30:20 +07:00
nyatoru
9aad413809 feat: use provider prefix for model value resolution 2026-02-24 17:40:45 +07:00
nyatoru
6afcebabab feat: use provider node type for active provider resolution 2026-02-24 17:05:23 +07:00
nyatoru
ad1cc64e5a feat: use provider node prefixes for custom model alias generatiovv 2026-02-24 16:19:45 +07:00
nyatoru
243cc4b60b feat: add authentication to alias API and improve model save error handling 2026-02-24 14:28:51 +07:00
nyatoru
ddb02d6464 feat: save compatible provider models to customModels DB for /v1/models listing 2026-02-24 14:09:30 +07:00
diegosouzapw
f24abf074b chore: remove .tgz artifact and add to .gitignore 2026-02-23 21:05:23 -03:00
diegosouzapw
ff01e9edaa fix(oauth): show manual paste mode for LAN IP access
When accessing OmniRoute via LAN IP (192.168.x), the OAuth popup
callback can't resolve localhost back to the VPS. Now shows manual
paste input with warning banner instead of waiting indefinitely.
2026-02-23 20:51:52 -03:00
diegosouzapw
168b17adc7 fix(oauth): hardcode desktop OAuth client secrets to fix build-time inlining
Next.js inlines process.env at build time, causing clientSecret defaults to
be baked as empty strings. Desktop/CLI OAuth secrets are not confidential
per Google's documentation.

Fixes: client_secret is missing error on VPS deployment
2026-02-23 20:14:28 -03:00
diegosouzapw
7e0c6f0307 chore(release): v1.4.1 — endpoint page cleanup, deploy workflow 2026-02-23 19:00:30 -03:00
Diego Rodrigues de Sa e Souza
dd573aed6f Merge pull request #120 from diegosouzapw/dependabot/npm_and_yarn/development-94fcb5e3b6
deps: bump the development group with 6 updates
2026-02-23 17:28:19 -03:00
diegosouzapw
b87af5d053 chore: add VPS auto-deploy workflow, remove API key section from Endpoint page
- Add deploy-vps.yml: auto-deploys via SSH after Docker Hub publish
- Remove API key management section from Endpoint page (now in API Manager)
- Remove unused Link import from EndpointPageClient.tsx
2026-02-23 17:20:26 -03:00
dependabot[bot]
29b3e59d23 deps: bump the development group with 6 updates
Bumps the development group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.1.18` | `4.2.1` |
| [@types/bcryptjs](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/bcryptjs) | `2.4.6` | `3.0.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.2.3` | `25.3.0` |
| [eslint](https://github.com/eslint/eslint) | `9.39.2` | `9.39.3` |
| [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.1.18` | `4.2.1` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.56.0` | `8.56.1` |


Updates `@tailwindcss/postcss` from 4.1.18 to 4.2.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.1/packages/@tailwindcss-postcss)

Updates `@types/bcryptjs` from 2.4.6 to 3.0.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/bcryptjs)

Updates `@types/node` from 25.2.3 to 25.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 9.39.2 to 9.39.3
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.2...v9.39.3)

Updates `tailwindcss` from 4.1.18 to 4.2.1
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.1/packages/tailwindcss)

Updates `typescript-eslint` from 8.56.0 to 8.56.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.56.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: "@types/bcryptjs"
  dependency-version: 3.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development
- dependency-name: "@types/node"
  dependency-version: 25.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: eslint
  dependency-version: 9.39.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
- dependency-name: tailwindcss
  dependency-version: 4.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development
- dependency-name: typescript-eslint
  dependency-version: 8.56.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 20:19:21 +00:00
diegosouzapw
ce6d7dc6bf feat(api-manager): enhance with usage stats, status badges, and stats dashboard (#118)
- Add stats summary cards (total keys, restricted, total requests, models available)
- Add per-key usage statistics (total requests, last used timestamp)
- Add copy button on each key row
- Add color-coded lock/unlock status icons per key
- Bump version to 1.4.0
2026-02-23 17:01:32 -03:00
Diego Rodrigues de Sa e Souza
19eeebae95 Merge pull request #118 from nyatoru/feat/api-key-manager
feat(api-manager): implement API key management with new endpoints and UI
2026-02-23 16:58:20 -03:00
diegosouzapw
1dd05bffe8 fix: proxy support for connection tests, compatible provider display (#119, #113)
- Connection tests now route through configured proxy (key → combo → provider → global → direct)
- Compatible providers show friendly labels (OAI-COMPAT, ANT-COMPAT) in request logger
- 26 new unit tests for error classification, token expiry, and display labels
- Version bump to 1.3.1
2026-02-23 16:50:48 -03:00
nyatoru
ac3d251a1a fix(db): clear prepared statements on backup restore 2026-02-24 00:35:29 +07:00
nyatoru
238e080928 refactor(api-manager): improve type safety in client component 2026-02-24 00:20:42 +07:00
nyatoru
7ed40c2139 fix(db): enforce stricter validation for api key model access 2026-02-24 00:14:50 +07:00
nyatoru
d2bee37e76 feat(api-manager): implement API key management with new endpoints and UI
- Add GET/PATCH endpoints for retrieving and updating API key permissions

- Move API key management from Endpoint page to dedicated API Manager page

- Add allowed_models column to database schema for model-specific access

- Implement caching layer for improved API key validation performance
2026-02-23 23:59:34 +07:00
benzntech
5a2fdacebe feat(memory): optimize RAM usage for low-memory deployments
- Add Node.js heap limit (256MB default) via OMNIROUTE_MEMORY_MB
- Convert LRU caches to byte-based limits (2-4MB)
- Reduce in-memory buffer sizes: 500→200 entries
- Add .env file loading in CLI for global npm installs
- Add PM2 ecosystem.config.js example for deployment
- Document memory tuning env vars in USER_GUIDE.md

Estimated RAM reduction: ~60-70% (from ~512MB+ to ~150-200MB)
2026-02-23 14:16:47 +05:30
diegosouzapw
343e6c50e3 chore(release): v1.3.0 — iFlow HMAC fix, health check logs toggle, kilocode models, model dedup
 New Features:
- Hide Health Check Logs toggle (PR #111 by @nyatoru)
- Kilocode custom models endpoint + 26 models (PR #115 by @benzntech)

🐛 Bug Fixes:
- iFlow 406 error fixed with IFlowExecutor HMAC-SHA256 signature (#114)
- Filter parent model duplicates from endpoint lists (PR #112 by @nyatoru)

🧪 Tests:
- 11 new IFlowExecutor unit tests
- All 379 tests passing
2026-02-23 03:50:01 -03:00
Diego Rodrigues de Sa e Souza
90d2dcac97 Merge pull request #115 from benzntech/feat/enhance-kilocode-provider
feat(kilocode): add custom models endpoint and expanded model list
2026-02-23 03:44:32 -03:00
Diego Rodrigues de Sa e Souza
631ed4d97f Merge pull request #112 from nyatoru/feat/fix-models
fix(endpoint): filter out parent models to avoid duplicates in lists
2026-02-23 03:44:29 -03:00
Diego Rodrigues de Sa e Souza
9485985608 Merge pull request #111 from nyatoru/feature/hide-health-check
feat(settings): add toggle to hide health check logs with caching
2026-02-23 03:44:20 -03:00
Diego Rodrigues de Sa e Souza
b32db28a3d Update src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-23 03:34:22 -03:00
Diego Rodrigues de Sa e Souza
1516429b87 Update src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-23 03:33:51 -03:00
benzntech
5668e16fbf feat(kilocode): add custom models endpoint and expanded model list
- Add modelsUrl field to RegistryEntry interface for custom models endpoints
- Configure kilocode provider with dedicated models URL (https://api.kilo.ai/api/openrouter/models)
- Expand kilocode model list from 8 to 26 models including free options:
  - openrouter/free (Free Models Router)
  - stepfun/step-3.5-flash:free
  - arcee-ai/trinity-large-preview:free
  - Additional Qwen, DeepSeek, Llama, Mistral, Grok, and Kimi models
- Update validateOpenAILikeProvider to accept custom modelsUrl parameter
- Fix models URL derivation for base URLs ending with /chat/completions
- Add kilocode config to PROVIDER_MODELS_CONFIG
2026-02-23 10:31:56 +05:30
nyatoru
bd4a076942 Add HTTP error handling to settings API fetch 2026-02-23 06:38:45 +07:00
nyatoru
f0a0c97b5e feat(tokenHealthCheck): add request coalescing to shouldHideLogs 2026-02-23 06:36:39 +07:00
nyatoru
7ffe21e23d fix(endpoint): filter out parent models to avoid duplicates in lists 2026-02-23 06:32:49 +07:00
nyatoru
4b137d8e72 feat(settings): add toggle to hide health check logs with caching 2026-02-23 06:21:53 +07:00
diegosouzapw
6ba48241fe fix(test): align test script with test:unit — add tsx/esm loader
The 'test' script was missing '--import tsx/esm', causing 25 failures
from Node ESM being unable to resolve extensionless TypeScript imports.
The 'test:unit' script already had the loader and passed 368/368.
2026-02-22 19:00:04 -03:00
diegosouzapw
a17583d3fc feat(api): JWT session auth for models endpoint + refactor (v1.2.0)
- Merged PR #110 by @nyatoru: JWT session auth fallback for /v1/models
- Refactored: removed ~60 lines of same-origin detection (sameSite:lax already prevents CSRF)
- Changed auth failure response: 404 Not Found -> 401 Unauthorized (OpenAI format)
- Version bumped to v1.2.0

Closes #110
2026-02-22 18:36:57 -03:00
diegosouzapw
62c634ae78 Merge PR #110: feat(api): add JWT session auth fallback for models endpoint 2026-02-22 18:34:41 -03:00
nyatoru
02dc8ea0f3 fix(api): enhance authentication for /models endpoint with stricter checks 2026-02-23 04:00:22 +07:00
nyatoru
a40c463a87 feat(api): add JWT session auth fallback for models endpoint 2026-02-23 03:46:09 +07:00
diegosouzapw
5e0376c6c9 fix(test): correct JWT_SECRET assertion — required:false means missing is valid
The secretsValidator marks JWT_SECRET as required:false (auto-generated
at startup), but the test asserted valid:false when JWT_SECRET was missing.
This caused CI to fail with 367/368 tests passing.
2026-02-22 16:42:09 -03:00
diegosouzapw
2bad777541 Merge PR #109: feat(codex): add workspace binding via chatgpt-account-id header
Adds strict workspace binding via persisted chatgpt-account-id for Team Plan support.
Includes code_review_rate_limit (3rd window) parsing.
Fixes #106
2026-02-22 16:34:04 -03:00
diegosouzapw
10793a7e65 Merge branch 'main' into feat/codex-teamplan
# Conflicts:
#	open-sse/services/usage.ts
2026-02-22 16:33:31 -03:00
diegosouzapw
5dab4058c8 fix(issues): API key creation crash (#108) & Codex code review quota (#106)
- Fix API_KEY_SECRET undefined crash with deterministic fallback
- Add code_review_rate_limit parsing for Team/Plus/Pro plan support
- Move feature-81 doc to completed/
- Bump version to v1.1.1
2026-02-22 16:28:44 -03:00
nyatoru
b26cc2a82e feat(codex): enhance base64 decoding for UTF-8 compatibility in JWT parsing 2026-02-23 01:32:48 +07:00
nyatoru
0610909116 feat(codex): add workspace binding via chatgpt-account-id header 2026-02-23 01:11:53 +07:00
Diego Rodrigues de Sa e Souza
f8a401da4b Merge pull request #107 from nyatoru/feat/deletedebugqwen
chore(qwen): remove debug console log from mapTokens
2026-02-22 11:41:51 -03:00
nyatoru
3b70e9f786 chore(qwen): remove debug console log from mapTokens 2026-02-22 20:23:37 +07:00
diegosouzapw
39f992a2a8 chore(release): bump version to v1.1.0 2026-02-21 18:41:31 -03:00
Diego Rodrigues de Sa e Souza
0df1d46ae5 Merge pull request #104 from diegosouzapw/fix-issues-101-103
Fix OAuth client_secret issues (#103) & Codex Business quotas (#101)
2026-02-21 18:38:17 -03:00
diegosouzapw
28c7e0d62f Fix OAuth client_secret issues (#103) & Codex Business quotas (#101) 2026-02-21 18:24:56 -03:00
diegosouzapw
03965bf768 fix(db): remove OAuth fallback overwrite when email is missing to natively support multiple accounts 2026-02-21 13:04:06 -03:00
diegosouzapw
6b34a39f6e chore(release): bump version to v1.0.10 and update changelog 2026-02-21 12:35:37 -03:00
diegosouzapw
f0513683e5 fix(qwen): extract email from id_token to allow multiple accounts 2026-02-21 12:22:56 -03:00
diegosouzapw
b3e53ca250 chore(release): bump version to v1.0.9 and update changelog 2026-02-21 10:00:53 -03:00
diegosouzapw
7a3b21eff8 fix(settings): add blockedProviders and requireAuthForModels to Zod schema 2026-02-21 09:49:15 -03:00
diegosouzapw
f8c8501036 chore(release): bump version to v1.0.8 2026-02-21 09:31:10 -03:00
Diego Rodrigues de Sa e Souza
4e1b5a5253 Merge pull request #102 from diegosouzapw/feat/issue-fixes-and-security
Release v1.0.8
2026-02-21 09:30:54 -03:00
diegosouzapw
1aa27ceefe chore(workflows): move agent workflows to global dir 2026-02-21 09:11:14 -03:00
diegosouzapw
340dcf9515 feat(core): api key protection, provider blocking, windows fix, ui and docs 2026-02-21 09:05:59 -03:00
Adarsh
1bd5d552c1 fix: extract email from id_token for Codex OAuth to allow multiple accounts (#97)
- Parse JWT id_token to extract email in mapTokens function
- Allows database to distinguish between different Codex accounts
- Fixes issue where adding 3rd+ Codex account would update existing connection instead of creating new one
2026-02-21 07:00:37 -03:00
Adarsh
862d94b859 Fix/auto generate jwt secret (#94)
* fix: auto-generate JWT_SECRET at startup if not provided
- Add ensureJwtSecret() in instrumentation.ts to generate random 64-char secret
- Mark JWT_SECRET as non-required in secretsValidator
- Remove fatal error log for missing JWT_SECRET in proxy.ts
Fixes login failure when running via CLI without JWT_SECRET env var.

* feat: improve auth flow and login page UX
- Add setupComplete to settings validation schema for proper persistence
- Support ?tab= query param in settings page for direct tab navigation
- Redesign login page with professional two-column layout
- Add context-aware states for onboarding/password setup flows
- Smooth animations and refined visual hierarchy

* fix: 404 page to use primary color theme (coral red) instead of purple
2026-02-21 06:55:40 -03:00
diegosouzapw
be36d9c452 Merge fix/issues-89-90-91-v1.0.7: resolve #89 #90 #91, bump v1.0.7 2026-02-20 11:51:19 -03:00
diegosouzapw
5ce95dd829 fix: resolve issues #89 #90 #91 — stream default, custom models, OAuth redirect
- fix(chatCore): stream defaults to false per OpenAI spec (body.stream === true)
  closes #89
- fix(models): custom OpenAI-compatible providers now appear in /v1/models
  Added raw providerId check against activeAliases
  closes #90
- fix(OAuthModal): Google OAuth providers force localhost redirect URI
  Targeted amber warning + redirect_uri_mismatch error guidance for remote deployments
  closes #91
- docs: Add 'OAuth em Servidor Remoto' tutorial in README with 7-step Google Cloud guide
- docs: .env.example prominent warning block for Google OAuth remote setup
- chore: bump version 1.0.6 → 1.0.7
- docs: CHANGELOG entry for v1.0.7
2026-02-20 11:50:50 -03:00
diegosouzapw
d0fa01cc0a fix: increase JWT session to 30 days + auto-refresh in middleware
JWT session tokens now last 30 days instead of 24 hours. The middleware
silently refreshes the token when it has less than 7 days remaining,
so active users never get locked out of the dashboard.

Auto-refresh fires on any /dashboard request and sets a fresh 30-day
cookie via Set-Cookie header — completely transparent to the user.
2026-02-20 07:02:18 -03:00
diegosouzapw
c69ad118d1 release: v1.0.6 — provider/combo toggles, strict model filtering 2026-02-20 02:59:35 -03:00
diegosouzapw
0deeaf5ffb feat: combo enable/disable toggle + provider toggle always visible
1. Combos page: added Toggle to each ComboCard — disable/enable combos
   with optimistic UI update. Disabled combos show opacity-50.
2. /v1/models: disabled combos (isActive=false) are excluded from the
   model list.
3. Providers page: toggle is now always visible instead of hover-only.
2026-02-20 02:53:14 -03:00
diegosouzapw
87c7c92ddd fix: /v1/models only shows models from configured providers
Previously, if no connections existed in the database, ALL provider
models (378+) were shown as a fallback. Now only combos and custom
models appear when no provider connections are configured.

Models are strictly filtered by activeAliases — only providers with
at least one active (enabled) connection show their models. This
ensures /v1/models reflects exactly what the user has set up.
2026-02-20 02:44:38 -03:00
diegosouzapw
f12b90f373 fix: /v1/models respects disabled providers — track total connections before filter
Root cause: after filtering disabled connections (isActive=false), the
connections array could be empty. The fallback 'connections.length > 0'
then treated it as 'no connections configured' and showed ALL models.

Fix: Track totalConnectionCount before filtering. Use it in all filter
conditions so disabled providers are properly excluded even when every
connection is toggled off.
2026-02-20 02:35:10 -03:00
diegosouzapw
4e37027e1f feat: add enable/disable toggle to provider cards on main page
Toggle appears on hover next to the chevron. Clicking it batch-toggles
all connections for that provider (enable/disable). Uses optimistic UI
update with parallel API calls. stopPropagation prevents navigation.
2026-02-20 02:22:47 -03:00
diegosouzapw
245345f37d fix: treat private/LAN IPs as localhost for OAuth redirect URI
Google OAuth rejects private IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
with 'device_id and device_name are required' error. Now these are treated
the same as localhost, using http://localhost:{port}/callback as redirect URI.
2026-02-20 02:13:07 -03:00
diegosouzapw
99be29ce8e docs: update READMEs + CHANGELOG to v1.0.5 2026-02-20 01:50:06 -03:00
diegosouzapw
6aaaaccb12 fix: set DATA_DIR=/app/data in Dockerfile and docker-compose.yml
Ensures the Docker volume mount at /app/data matches the app data directory.
Previously DATA_DIR was not set, causing the app to default to ~/.omniroute/
which is not backed by the volume — leading to empty database on redeploys.
2026-02-20 01:47:22 -03:00
diegosouzapw
282c46fd46 chore: bump version to 1.0.5 2026-02-20 01:43:53 -03:00
Diego Rodrigues de Sa e Souza
bc719875f6 fix: filter all model types in /v1/models by active providers (#88)
Previously only chat models were filtered by active provider connections.
Embedding, image, rerank, audio, and moderation models were always shown
regardless of whether the provider had any configured connections.

This caused providers like Together AI to appear in /v1/models even when
no API key was configured.

Closes #81

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-02-20 01:43:33 -03:00
1145 changed files with 329656 additions and 16150 deletions

View File

@@ -1,54 +0,0 @@
---
description: Git workflow — NEVER commit directly to main. Always use feature branches.
---
# Git Workflow
## ⚠️ CRITICAL RULE: NEVER commit directly to `main`
## Steps
1. **Before starting any work**, create a feature branch from `main`:
```bash
git checkout main && git pull origin main
git checkout -b feature/<feature-name>
```
2. **During development**, commit to the feature branch:
```bash
git add -A && git commit -m "<type>(<scope>): <description>"
```
3. **Before pushing**, verify the build passes:
```bash
npm run build
```
4. **When the feature is complete and verified**, push the branch and STOP:
```bash
git push origin feature/<feature-name>
```
5. **DO NOT** create a PR, merge, or push to `main`. Let the user handle that.
## Branch naming convention
- `feature/<name>` — new features
- `fix/<name>` — bugfixes
- `refactor/<name>` — refactoring
- `docker/<name>` — Docker / infrastructure changes
- `style/<name>` — UI / CSS changes
## Commit types
- `feat` — new feature
- `fix` — bugfix
- `refactor` — code refactoring
- `style` — UI / CSS changes
- `docker` — Docker / infrastructure
- `docs` — documentation
- `chore` — maintenance

View File

@@ -0,0 +1,102 @@
---
description: Deploy the latest OmniRoute code to the Akamai VPS (69.164.221.35) via npm
---
# Deploy to VPS Workflow
Deploy OmniRoute to the production VPS using `npm pack + scp` + PM2.
**VPS:** `69.164.221.35` (Akamai, Ubuntu 24.04, 1GB RAM + 2.5GB swap)
**Local VPS:** `192.168.0.15` (same setup)
**Process manager:** PM2 (`omniroute`)
**Port:** `20128`
**PM2 entry:** `/usr/lib/node_modules/omniroute/app/server.js`
> [!IMPORTANT]
> PM2 runs from the global npm package at `/usr/lib/node_modules/omniroute`.
> The Next.js standalone build is at `app/server.js` inside that directory.
> The npm registry rejects packages > 100MB, so deployment uses **npm pack + scp**.
> [!CAUTION]
> **NEVER** use `pm2 restart omniroute` after `npm install -g`. This drops env vars.
> Always use `pm2 delete omniroute && pm2 start <ecosystem.config.cjs> --update-env`.
> After `npm install -g`, always rebuild better-sqlite3: `cd .../app && npm rebuild better-sqlite3`
## Steps
### 1. Build + pack locally
Run the full build (includes hash-strip patch) and create the .tgz:
// turbo
```bash
cd /home/diegosouzapw/dev/proxys/9router && npm run build:cli && npm pack --ignore-scripts
```
### 2. Copy to both VPS and install
// turbo-all
```bash
scp omniroute-*.tgz root@69.164.221.35:/tmp/ && scp omniroute-*.tgz root@192.168.0.15:/tmp/
```
```bash
ssh root@69.164.221.35 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && cd /usr/lib/node_modules/omniroute/app && npm rebuild better-sqlite3 && pm2 delete omniroute 2>/dev/null; pm2 start /root/.omniroute/ecosystem.config.cjs --update-env && pm2 save && echo '✅ Akamai done'"
```
```bash
ssh root@192.168.0.15 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && cd /usr/lib/node_modules/omniroute/app && npm rebuild better-sqlite3 && pm2 delete omniroute 2>/dev/null; pm2 start /root/.omniroute/ecosystem.config.cjs --update-env && pm2 save && echo '✅ Local done'"
```
### 3. Verify the deployment
```bash
ssh root@69.164.221.35 "pm2 list && cat \$(npm root -g)/omniroute/app/package.json | grep version | head -1 && curl -s -o /dev/null -w 'HTTP %{http_code}' http://localhost:20128/"
```
```bash
ssh root@192.168.0.15 "pm2 list && cat \$(npm root -g)/omniroute/app/package.json | grep version | head -1 && curl -s -X POST http://localhost:20128/api/auth/login -H 'Content-Type: application/json' -d '{\"password\":\"123456\"}'"
```
Expected: PM2 shows `online`, version matches, login returns `{"success":true}`.
## How it works
1. `npm run build:cli` builds Next.js standalone → `app/` and strips Turbopack hashed require() calls from chunks
2. `npm pack --ignore-scripts` packages without re-running the build
3. `scp` transfers the .tgz to each VPS (~286MB)
4. `npm install -g /tmp/omniroute-*.tgz --ignore-scripts` installs pre-built package
5. `npm rebuild better-sqlite3` recompiles native bindings for the VPS Node.js version
6. `pm2 delete` + `pm2 start ecosystem.config.cjs --update-env` restarts with env vars
7. `pm2 save` persists the process list for reboot survival
## Ecosystem Config
Both VPSs have `ecosystem.config.cjs` at `/root/.omniroute/ecosystem.config.cjs`.
This file defines env vars (PORT, DATA_DIR, INITIAL_PASSWORD, OAuth secrets, etc.)
that `pm2 restart` does NOT inject — only `pm2 start --update-env` does.
## PM2 Setup (one-time — if reconfiguring from scratch)
```bash
ssh root@<VPS> "
pm2 delete omniroute 2>/dev/null;
cd /usr/lib/node_modules/omniroute/app && npm rebuild better-sqlite3 &&
pm2 start /root/.omniroute/ecosystem.config.cjs --update-env &&
pm2 save && pm2 startup
"
```
> [!NOTE]
> Ensure `/root/.omniroute/ecosystem.config.cjs` exists with all required env vars.
> For fresh installs, copy from the existing VPS or create from the template in `.env`.
## Notes
- Env vars are in `/root/.omniroute/ecosystem.config.cjs` (NOT `.env` in app dir)
- PM2 is configured with `pm2 startup` to auto-restart on reboot
- Nginx proxies `omniroute.online``localhost:20128`
- The VPS has only 1GB RAM — builds happen locally, never on the VPS
- After `npm install -g`, `better-sqlite3` MUST be rebuilt in the `app/` subdir

View File

@@ -0,0 +1,168 @@
---
description: Create a new release, bump version up to 1.x.10 threshold, update changelog, and manage Pull Requests
---
# Generate Release Workflow
Bump version, finalize CHANGELOG, commit, tag, push, publish to npm, and create GitHub release.
> **VERSION RULE: Always use PATCH bumps (2.x.y → 2.x.y+1)**
> NEVER use `npm version minor` or `npm version major`.
> Always use: `npm version patch --no-git-tag-version`
> The threshold rule: when `y` reaches 10, bump to `2.(x+1).0` — e.g. `2.1.10` → `2.2.0`.
## Steps
### 1. Determine new version
Check current version in `package.json` and increment the **patch** number only:
```bash
grep '"version"' package.json
```
Version format: `2.x.y` — examples:
- `2.1.2``2.1.3` (patch)
- `2.1.9``2.1.10` (patch)
- `2.1.10``2.2.0` (minor threshold — do manually with `sed`)
```bash
# ALWAYS use patch:
npm version patch --no-git-tag-version
```
> **⚠️ ATOMIC COMMIT RULE — Version bump MUST happen before committing feature files.**
>
> **CORRECT order:**
>
> 1. `npm version patch --no-git-tag-version` ← bump first
> 2. implement features / fix bugs
> 3. `git add -A && git commit -m "chore(release): v2.x.y — all changes in ONE commit"`
>
> **OR if features are already staged:**
>
> 1. implement features (do NOT commit yet)
> 2. `npm version patch --no-git-tag-version` ← bump before committing
> 3. `git add -A && git commit -m "chore(release): v2.x.y — all changes in ONE commit"`
>
> **NEVER do this (creates version mismatch in git history):**
>
> - ~~commit features → then bump version → commit package.json separately~~
>
> This ensures that `git show v2.x.y` always contains both code changes and the version bump together.
> The GitHub release tag will point to a commit that includes ALL changes for that version.
### 2. Regenerate lock file (REQUIRED after version bump)
**Mandatory** — skipping causes `@swc/helpers` lock mismatch and CI failures:
```bash
npm install
```
### 3. Finalize CHANGELOG.md
Replace `[Unreleased]` header with the new version and date.
Keep an empty `## [Unreleased]` section above it.
```markdown
## [Unreleased]
---
## [2.x.y] — YYYY-MM-DD
```
### 4. Update openapi.yaml version ⚠️ MANDATORY
> **CI will fail** if `docs/openapi.yaml` version ≠ `package.json` version (`check:docs-sync` enforces this).
// turbo
```bash
VERSION=$(node -p "require('./package.json').version") && sed -i "s/ version: .*/ version: $VERSION/" docs/openapi.yaml && echo "✓ openapi.yaml → $VERSION"
```
### 5. Stage, commit, and tag
// turbo-all
```bash
git add package.json package-lock.json CHANGELOG.md docs/openapi.yaml
git commit -m "chore(release): v2.x.y — summary of changes"
git tag -a v2.x.y -m "Release v2.x.y"
```
### 6. Push to GitHub
```bash
git push origin main --tags
```
### 7. Create GitHub release
```bash
gh release create v2.x.y --title "v2.x.y — summary" --notes "..."
```
### 8. 🐳 Trigger Docker Hub build (MANDATORY — keep npm and Docker in sync)
> **CRITICAL**: Docker Hub and npm MUST always publish the same version.
> The Docker image is built automatically via GitHub Actions when a new tag is pushed.
> After pushing the tag in step 5-6, **verify the workflow runs**:
```bash
# Verify the Docker workflow triggered
gh run list --repo diegosouzapw/OmniRoute --workflow docker-publish.yml --limit 3
# Wait for the Docker build to complete (usually 510 min)
gh run watch --repo diegosouzapw/OmniRoute
# After completion, verify on Docker Hub:
# https://hub.docker.com/r/diegosouzapw/omniroute/tags
```
If the Docker build was not triggered automatically, trigger it manually:
```bash
gh workflow run docker-publish.yml --repo diegosouzapw/OmniRoute --ref v2.x.y
```
### 9. Deploy to BOTH VPS environments (MANDATORY)
> Always deploy to **both** environments after every release.
> See `/deploy-vps` workflow for detailed steps.
```bash
# Build and pack locally
cd /home/diegosouzapw/dev/proxys/9router && npm run build:cli && npm pack --ignore-scripts
# Deploy to LOCAL VPS (192.168.0.15)
scp omniroute-*.tgz root@192.168.0.15:/tmp/
ssh root@192.168.0.15 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && pm2 restart omniroute && pm2 save"
# Deploy to AKAMAI VPS (69.164.221.35)
scp omniroute-*.tgz root@69.164.221.35:/tmp/
ssh root@69.164.221.35 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && pm2 restart omniroute && pm2 save"
# Verify both
curl -s -o /dev/null -w "LOCAL: HTTP %{http_code}\n" http://192.168.0.15:20128/
curl -s -o /dev/null -w "AKAMAI: HTTP %{http_code}\n" http://69.164.221.35:20128/
```
## Notes
- Always run `/update-docs` BEFORE this workflow (ensures CHANGELOG and README are current)
- The `prepublishOnly` script runs `npm run build:cli` automatically during `npm publish`
- After npm publish, verify with `npm info omniroute version`
- Lock file sync errors are caused by skipping `npm install` after version bump
## Known CI Pitfalls
| CI failure | Cause | Fix |
| ------------------------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- |
| `[docs-sync] FAIL - OpenAPI version differs from package.json` | Skipped step 4 — `docs/openapi.yaml` version not updated | Run step 4 (`sed -i ...`) and commit |
| `[docs-sync] FAIL - CHANGELOG.md first section must be "## [Unreleased]"` | `## [Unreleased]` missing or not at top of CHANGELOG | Add `## [Unreleased]\n\n---\n` before the first versioned `## [x.y.z]` |
| Electron Linux `.deb` build fails (`FpmTarget` error) | `fpm` Ruby gem not installed on `ubuntu-latest` runner | Already fixed in `electron-release.yml` (`gem install fpm` step) |
| Docker Hub `502 error writing layer blob` | Transient Docker Hub network error during ARM64 push | Re-run the Docker publish workflow; no code change needed |

View File

@@ -0,0 +1,131 @@
---
description: Analyze open feature request issues, implement viable ones on dedicated branches, and respond to authors
---
# /implement-features — Feature Request Implementation Workflow
## Overview
Fetches open feature request issues, analyzes each against the current codebase, implements viable ones on dedicated branches, and responds to authors with results. Does NOT merge to main — leaves branches for author validation.
## Steps
### 1. Identify the Repository
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract owner/repo
### 2. Fetch Open Feature Request Issues
// turbo
- Run: `gh issue list --repo <owner>/<repo> --state open --limit 50 --json number,title,labels,body,comments,createdAt,author`
- Filter for issues that are feature requests (label `enhancement`/`feature`, or body describes new functionality, or previously classified as feature request)
- Sort by oldest first
### 3. Analyze Each Feature Request
For each feature request issue, perform a **two-level analysis**:
#### Level 1 — Viability Assessment
Ask yourself:
- Does this feature align with the project's goals and architecture?
- Is the request technically feasible with the current codebase?
- Does it duplicate existing functionality?
- Would it introduce breaking changes or security risks?
- Is there enough detail to implement it?
**Verdict options:**
1.**VIABLE** — Makes sense, enough detail to implement → Go to Level 2
2.**NEEDS MORE INFO** — Good idea but insufficient detail → Post comment asking for specifics
3.**NOT VIABLE** — Doesn't fit the project or is fundamentally flawed → Post comment explaining why, close issue
#### Level 2 — Implementation (only for VIABLE features)
1. **Research** — Read all related source files to understand the current architecture
2. **Design** — Plan the implementation, filling gaps in the original request
3. **Create branch** — Name format: `feat/issue-<NUMBER>-<short-slug>`
```bash
git checkout main
git pull origin main
git checkout -b feat/issue-<NUMBER>-<short-slug>
```
4. **Implement** — Build the complete solution following project patterns
5. **Build** — Run `npm run build` to verify compilation
6. **Commit** — Commit with: `feat: <description> (#<NUMBER>)`
7. **Push** — Push the branch: `git push -u origin feat/issue-<NUMBER>-<short-slug>`
8. **Return to main** — `git checkout main`
### 4. Respond to Authors
#### For VIABLE (implemented) features:
// turbo
Post a comment on the issue:
````markdown
## ✅ Feature Implemented!
Hi @<author>! We've analyzed your request and implemented it on a dedicated branch.
**Branch:** `feat/issue-<NUMBER>-<short-slug>`
### What was implemented:
- <bullet list of what was done>
### How to try it:
```bash
git fetch origin
git checkout feat/issue-<NUMBER>-<short-slug>
npm install && npm run dev
```
````
### Next steps:
1. **Test it** — Please verify it works as you expected
2. **Want to improve it?** — You're welcome to contribute! Just:
```bash
git checkout feat/issue-<NUMBER>-<short-slug>
# Make your improvements
git add -A && git commit -m "improve: <your changes>"
git push origin feat/issue-<NUMBER>-<short-slug>
```
Then open a Pull Request from your branch to `main` 🎉
3. **Not quite right?** — Let us know in this issue what needs to change
Looking forward to your feedback! 🚀
```
#### For NEEDS MORE INFO:
// turbo
Post a comment asking for specific missing details needed to implement, e.g.:
- "Could you describe the exact behavior when X happens?"
- "Which API endpoints should be affected?"
- "Should this apply to all providers or only specific ones?"
Add the context of WHY you need each piece of information.
#### For NOT VIABLE:
// turbo
Post a polite comment explaining why the feature doesn't fit at this time:
- If the idea is decent but timing is wrong: "This is an interesting idea, but it doesn't align with our current priorities. Feel free to open a new issue with more details if you'd like us to reconsider."
- If fundamentally flawed: Explain the technical or architectural reasons why it won't work, suggest alternatives if possible.
- Close the issue after posting the comment.
### 5. Summary Report
Present a summary report to the user via `notify_user`:
| Issue | Title | Verdict | Branch / Action |
|---|---|---|---|
| #N | Title | ✅ Implemented | `feat/issue-N-slug` |
| #N | Title | ❓ Needs Info | Comment posted |
| #N | Title | ❌ Not Viable | Closed with explanation |
```

View File

@@ -0,0 +1,50 @@
---
description: How to respond to GitHub issues with insufficient information
---
# Issue Triage Workflow
Respond to GitHub issues that need more information before they can be investigated.
## Steps
### 1. Identify issues needing triage
```bash
gh issue list --state open --limit 20
```
### 2. Evaluate each issue
Check if the issue has:
- Clear reproduction steps
- Environment details (OS, Node.js version, OmniRoute version)
- Error logs/screenshots
- Expected vs actual behavior
### 3. Respond with triage template
For issues missing information:
```markdown
Thank you for reporting this issue! To help us investigate, please provide:
1. **OmniRoute version**: (`omniroute --version`)
2. **Node.js version**: (`node --version`)
3. **Operating system**: (e.g., Ubuntu 24.04, macOS 15, Windows 11)
4. **Installation method**: (npm, Docker, source)
5. **Steps to reproduce**: (exact commands/actions that trigger the issue)
6. **Error logs**: (paste relevant logs from the console)
7. **Expected behavior**: (what should happen)
This will help us debug and resolve your issue faster. 🙏
```
### 4. Label the issue
Add appropriate labels: `needs-info`, `bug`, `enhancement`, `question`, etc.
```bash
gh issue edit <NUMBER> --add-label "needs-info"
```

View File

@@ -0,0 +1,120 @@
---
description: Fetch all open GitHub issues, analyze bugs, resolve what's possible, triage the rest, wait for user validation, then commit and release
---
# /resolve-issues — Automated Issue Resolution Workflow
## Overview
This workflow fetches all open issues from the project's GitHub repository, classifies them, analyzes bugs, resolves what can be fixed, and triages issues with insufficient information. **It does NOT merge or release automatically** — it creates a PR and waits for user validation before merging.
## Steps
### 1. Identify the GitHub Repository
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract the owner/repo
- Parse the owner and repo name from the URL
### 2. Fetch All Open Issues
// turbo
- Run: `gh issue list --repo <owner>/<repo> --state open --limit 500 --json number,title,labels,body,comments,createdAt,author`
- Parse the JSON output to get a list of **all** open issues
- Sort by oldest first (FIFO)
### 3. Classify Each Issue
For each issue, determine its type:
- **Bug** — Has `bug` label, or body contains error messages, stack traces, "doesn't work", "broken", "crash", "error"
- **Feature Request** — Has `enhancement`/`feature` label, or body describes new functionality
- **Question** — Has `question` label, or is asking "how to" something
- **Other** — Anything else
Focus ONLY on **Bugs** for resolution. Feature requests and questions should be skipped with a note in the final report.
### 4. Analyze Each Bug — For each bug issue:
#### 4a. Check Information Sufficiency
Verify the issue contains enough information to reproduce and fix:
- [ ] Clear description of the problem
- [ ] Steps to reproduce
- [ ] Error messages or logs
- [ ] Expected vs actual behavior
#### 4b. If Information Is INSUFFICIENT
Call the `/issue-triage` workflow (located at `~/.gemini/antigravity/global_workflows/issue-triage.md`):
// turbo
- Post a comment asking for more details using `gh issue comment`
- Add `needs-info` label using `gh issue edit`
- Mark this issue as **DEFERRED** and move to the next one
#### 4c. If Information Is SUFFICIENT
Proceed with resolution:
1. **Create a fix branch**`git checkout -b fix/issue-<NUMBER>-<short-description>`
2. **Research** — Search the codebase for files related to the issue
3. **Root Cause** — Identify the root cause by reading the relevant source files
4. **Implement Fix** — Apply the fix following existing code patterns and conventions
5. **Test** — Build the project and run tests to verify the fix
6. **Commit** — Commit with message format: `fix: <description> (#<issue_number>)`
### 5. Generate Report & Wait for Validation
Present a summary report to the user via `notify_user` with `BlockedOnUser: true`:
| Issue | Title | Status | Action |
| ----- | ----- | ------------- | ----------------------------- |
| #N | Title | ✅ Ready | Files changed (not committed) |
| #N | Title | ❓ Needs Info | Triage comment posted |
| #N | Title | ⏭️ Skipped | Feature request / not a bug |
> **⚠️ IMPORTANT**: Do NOT commit, close issues, or generate releases at this step.
> Wait for the user to review the changes and respond with **OK** before proceeding.
- If the user says **OK** or approves → Proceed to step 6
- If the user requests changes → Apply the requested adjustments first, then present the report again
- If the user rejects → Revert the changes and stop
### 6. Commit & Push Fix Branch (only after user approval)
After the user validates:
- Commit each fix individually with message format: `fix: <description> (#<issue_number>)`
- Push the fix branch: `git push origin fix/issue-<NUMBER>-<short-description>`
- Create a PR: `gh pr create --title "fix: <description> (#<issue_number>)" --body "<details>" --base main`
### 7. 🛑 WAIT — Notify User & Await PR Verification
**This is a mandatory stop point.** Use `notify_user` with `BlockedOnUser: true`:
- Inform the user that the PR was created and is **awaiting their verification**
- Include the PR number, URL, and a summary of what was changed
- **DO NOT merge, close issues, generate releases, or deploy until the user confirms**
Wait for the user to respond:
- **User confirms** → Proceed to step 8
- **User requests changes** → Apply changes, push to the same branch, notify again
- **User rejects** → Close the PR and stop
### 8. Merge, Close Issues & Release (only after user confirms PR)
After the user confirms the PR:
1. **Merge** the PR: `gh pr merge <NUMBER> --merge --repo <owner>/<repo>` or via local merge
2. **Close** resolved issues with a comment: `gh issue close <NUMBER> --repo <owner>/<repo> --comment "Fixed in <commit_hash>. The fix will be included in the next release."`
3. **Switch to main**: `git checkout main && git pull`
4. Run the `/update-docs` workflow (at `~/.gemini/antigravity/global_workflows/update-docs.md`) to update CHANGELOG and README
5. Run the `/generate-release` workflow (at `.agents/workflows/generate-release.md`) to bump version, tag, and publish
6. Deploy to local VPS: `ssh root@192.168.0.15 "npm install -g omniroute@<VERSION> && pm2 restart omniroute"`
If NO fixes were committed, skip this step and just present the report.

View File

@@ -0,0 +1,149 @@
---
description: Analyze open Pull Requests from the project's GitHub repository, generate a critical report, and optionally implement approved changes
---
# /review-prs — PR Review & Analysis Workflow
## Overview
This workflow fetches all open PRs from the project's GitHub repository, performs a critical analysis of each one, generates a detailed report, and waits for user approval before proceeding with implementation. **All improvements are committed on top of the PR branch** and the user must verify before merge.
## Steps
### 1. Identify the GitHub Repository
- Read `package.json` to get the repository URL, or use the git remote origin URL
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract the owner/repo
### 2. Fetch Open Pull Requests
// turbo
- Run: `gh pr list --repo <owner>/<repo> --state open --limit 500 --json number,title,author,headRefName,body,createdAt,additions,deletions,files`
- This fetches **all** open PRs without restriction. Get the diff for each with:
`gh pr diff <NUMBER> --repo <owner>/<repo>`
- For each open PR, collect:
- PR number, title, author, branch, number of commits, date
- PR description/body
- Files changed (diff)
- Existing review comments (from bots or humans)
### 3. Analyze Each PR — For each open PR, perform the following analysis:
#### 3a. Feature Assessment
- **Does it make sense?** Evaluate if the feature fills a real gap or solves a valid problem
- **Alignment** — Check if it aligns with the project's architecture and roadmap
- **Complexity** — Assess if the scope is reasonable or if it should be split
#### 3b. Code Quality Review
- Check for code duplication
- Evaluate error handling patterns (consistent with existing codebase?)
- Check naming conventions and code style
- Verify TypeScript types (any `any` usage, missing types?)
#### 3c. Security Review
- Check for missing authentication/authorization on new endpoints
- Check for injection vulnerabilities (URL params, SQL, XSS)
- Verify input validation on all user-controlled data
- Check for hardcoded secrets or credentials
#### 3d. Architecture Review
- Does the change follow existing patterns?
- Are there any breaking changes to public APIs?
- Is the database schema affected? Migration needed?
- Impact on performance (N+1 queries, missing indexes?)
#### 3e. Test Coverage
- Does the PR include tests?
- Are edge cases covered?
- Would existing tests break?
#### 3f. Cross-Layer (Global) Analysis
Perform a **global impact assessment** to verify whether the PR changes are complete across all layers of the application:
- **Backend → Frontend check**: If the PR adds or modifies backend-only resources (new endpoints, services, data models), evaluate whether corresponding frontend changes are missing:
- Does a new endpoint require a new screen/page in the dashboard?
- Should there be a new action button, menu item, or navigation link?
- Are there new data fields that should be displayed or editable in the UI?
- Does a new feature need a toggle, configuration panel, or status indicator?
- **Frontend → Backend check**: If the PR adds frontend elements, verify the backend support exists:
- Are the required API endpoints implemented?
- Is the data model sufficient for the new UI components?
- **Cross-cutting concerns**: Check shared layers (types, DTOs, validation schemas, routes, middleware) for completeness
- **Document gaps** — If missing layers are detected, list them as **IMPORTANT** issues in the report with concrete suggestions for what should be added
### 4. Generate Report — Create a markdown report for each PR including:
- **PR Summary** — What it does, files affected, commit count
- **Improvements/Benefits** — Numbered list with impact level (HIGH/MEDIUM/LOW)
- **Risks & Issues** — Categorized as CRITICAL / IMPORTANT / MINOR
- **Scoring Table** — Rate across: Feature Relevance, Code Quality, Security, Robustness, Tests
- **Verdict** — Ready to merge? With mandatory vs optional fixes
- **Next Steps** — What will happen if approved
### 5. Present to User
- Show the report via `notify_user` with `BlockedOnUser: true`
- Wait for user decision:
- **Approved** → Proceed to step 6
- **Approved with changes** → Implement the fixes and corrections before merging
- **Rejected** → Close the PR or leave a review comment
### 6. Implementation (if approved)
- Checkout the PR branch: `gh pr checkout <NUMBER>`
- Implement any required fixes identified in the analysis
- If the Cross-Layer Analysis (3f) identified missing frontend/backend counterparts, implement them
- **Commit improvements on top of the PR branch** with descriptive commit messages
- Run the project's test suite to verify nothing breaks
// turbo
- Run: `npm test` or equivalent test command
- Build the project to verify compilation
// turbo
- Run: `npm run build` or equivalent build command
- Push the updated branch: `git push origin <branch-name>`
### 7. 🛑 WAIT — Notify User & Await PR Verification
**This is a mandatory stop point.** Use `notify_user` with `BlockedOnUser: true`:
- Inform the user that the PR has been **improved and pushed**, and is **awaiting their verification**
- Include:
- PR number and URL
- Summary of improvements/fixes applied
- Build/test status
- List of files changed
- **DO NOT merge, generate releases, or deploy until the user confirms**
Wait for the user to respond:
- **User confirms** → Proceed to step 8
- **User requests more changes** → Apply changes, push to the same branch, notify again
- **User rejects** → Leave a review comment and stop
### 8. Thank the Contributor
- Post a **thank-you comment** on the PR via the GitHub API
- The message should:
- Thank the author by name/username for their contribution
- Briefly mention what the PR accomplishes and any improvements applied
- Be friendly, professional, and encouraging
- Example: _"Thanks @author for this great contribution! 🎉 The [feature/fix] is now merged and will be part of the next release. We appreciate your effort!"_
### 9. Merge & Release (only after user confirms PR)
After the user confirms the PR:
1. **Merge** the PR into main (local merge with `--no-ff` or via `gh pr merge`)
2. **Push** to main: `git push origin main`
3. **Clean up** the feature branch: `git branch -d <branch-name>`
4. **Update CHANGELOG.md** with the new feature/fix
5. Run the `/generate-release` workflow (at `.agents/workflows/generate-release.md`) to bump version, tag, and publish
6. Deploy to local VPS: `ssh root@192.168.0.15 "npm install -g omniroute@<VERSION> && pm2 restart omniroute"`

View File

@@ -0,0 +1,105 @@
---
description: How to automatically summarize recent changes and update README and CHANGELOG
---
# Update Documentation Workflow
Update CHANGELOG.md, README.md, docs/ files, and all multi-language translations whenever features are added or changed.
## Steps
### 1. Summarize recent changes
Review git log and identify new features, fixes, or changes since the last release tag:
```bash
git log $(git describe --tags --abbrev=0)..HEAD --oneline
```
### 2. Update English CHANGELOG.md
Add an `[Unreleased]` section (or version header if releasing) with:
- `### ✨ New Features` — each feature as a bullet point
- `### 🐛 Bug Fixes` — if applicable
- `### 🧪 Tests` — test count changes
- `### 📁 New Files` — table of new files with purpose
### 3. Update English README.md
Update the feature tables in these sections:
- **🧠 Routing & Intelligence** — for routing/model features
- **🛡️ Resilience & Security** — for security/resilience features
- **📊 Observability & Analytics** — for monitoring features
- **☁️ Deploy & Sync** — for deployment features
### 4. Update docs/ files
- `docs/FEATURES.md` — update the Settings section description
- `docs/API_REFERENCE.md` — add new API routes if any
- `docs/ARCHITECTURE.md` — update architecture if structural changes
### 5. 🌐 Sync Multi-Language Documentation (CRITICAL)
// turbo-all
**This step MUST be run after every README or docs update.**
The project has **30 language versions** of documentation:
**README files (root directory):**
```
README.md (English - source of truth)
README.pt-BR.md README.pt.md README.es.md README.fr.md README.it.md
README.de.md README.nl.md README.sv.md README.no.md README.da.md README.fi.md
README.ru.md README.uk-UA.md README.bg.md README.sk.md README.pl.md README.ro.md README.hu.md
README.ar.md README.he.md README.th.md README.in.md README.id.md README.ms.md README.vi.md
README.ja.md README.ko.md README.zh-CN.md README.phi.md README.cs.md
```
**docs/i18n/ directories (29 languages):**
```
docs/i18n/{ar,bg,cs,da,de,es,fi,fr,he,hu,id,in,it,ja,ko,ms,nl,no,phi,pl,pt,pt-BR,ro,ru,sk,sv,th,uk-UA,vi,zh-CN}/
Each contains: API_REFERENCE.md, ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, FEATURES.md, TROUBLESHOOTING.md, USER_GUIDE.md
```
**Sync approach for feature table updates:**
a. Identify which feature table rows were added to English README.md
b. For each translated README, find the corresponding anchor lines:
- **Routing section:** Find the `💬` (System Prompt) table row — the line before it is always the last routing feature. Insert new routing features before System Prompt.
- **Resilience section:** Find the `📊` Rate Limits table row (the one in lines 590-600, NOT the quota tracking one in lines 560-570). Insert new resilience features after it.
c. The new feature entries can stay in English for technical features, matching the pattern used in the existing translations.
d. Use `sed` or similar tool to batch-insert across all 29 translated READMEs.
**Verification:**
```bash
# Verify all READMEs have the new features
grep -l "NEW_FEATURE_NAME" README.*.md | wc -l
# Should return 30 (all language versions)
```
**FEATURES.md sync:**
```bash
# Update Settings description in all docs/i18n/*/FEATURES.md
for dir in docs/i18n/*/; do
# Update the Settings section description to mention new features
# Check FEATURES.md in each directory
done
```
### 6. Verify documentation changes
```bash
# Check all modified files
git status --short
# Verify no broken markdown
# Optional: run markdownlint if available
```

View File

@@ -23,7 +23,15 @@ SQLITE_MAX_SIZE_MB=2048
SQLITE_CLEAN_LEGACY_FILES=true
# Recommended runtime variables
# Canonical/base port (keeps backward compatibility)
PORT=20128
# Optional split ports:
# API_PORT=20129
# API_HOST=0.0.0.0
# DASHBOARD_PORT=20128
# Optional Docker production host publish ports:
# PROD_DASHBOARD_PORT=20130
# PROD_API_PORT=20131
NODE_ENV=production
INSTANCE_NAME=omniroute
@@ -82,17 +90,83 @@ NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true
# Provider OAuth Credentials (optional — override hardcoded defaults)
# These can also be set via data/provider-credentials.json
# CLAUDE_OAUTH_CLIENT_ID=
# GEMINI_OAUTH_CLIENT_ID=
GEMINI_OAUTH_CLIENT_SECRET=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
# ─────────────────────────────────────────────────────────────────────────────
# ⚠️ GOOGLE OAUTH (Antigravity, Gemini CLI) — IMPORTANT FOR REMOTE SERVERS
# ─────────────────────────────────────────────────────────────────────────────
# The built-in Google OAuth credentials ONLY work when OmniRoute runs on
# localhost (127.0.0.1 / local network). They are registered with
# redirect_uri = http://localhost:PORT/callback and Google will reject any
# other redirect URI with: redirect_uri_mismatch.
#
# If you are hosting OmniRoute on a remote server (VPS, Docker, cloud), you
# MUST register your own Google Cloud OAuth 2.0 credentials:
#
# 1. Go to https://console.cloud.google.com/apis/credentials
# 2. Create an OAuth 2.0 Client ID (type: "Web application")
# 3. Add your server URL as Authorized redirect URI:
# https://your-server.com/callback
# 4. Copy the Client ID and Client Secret below.
#
# See the full tutorial in README.md → "OAuth em Servidor Remoto" section.
#
# Antigravity (Google Gemini Code Assist):
# ANTIGRAVITY_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
# ANTIGRAVITY_OAUTH_CLIENT_SECRET=GOCSPX-your-secret
ANTIGRAVITY_OAUTH_CLIENT_SECRET=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
# Gemini CLI (Google AI):
# GEMINI_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
# GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-secret
# GEMINI_CLI_OAUTH_CLIENT_ID=
GEMINI_OAUTH_CLIENT_SECRET=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
GEMINI_CLI_OAUTH_CLIENT_SECRET=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
# ─────────────────────────────────────────────────────────────────────────────
# CLAUDE_OAUTH_CLIENT_ID=
# CODEX_OAUTH_CLIENT_ID=
# CODEX_OAUTH_CLIENT_SECRET=
# QWEN_OAUTH_CLIENT_ID=
# IFLOW_OAUTH_CLIENT_ID=
IFLOW_OAUTH_CLIENT_SECRET=4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW
# ANTIGRAVITY_OAUTH_CLIENT_ID=
ANTIGRAVITY_OAUTH_CLIENT_SECRET=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
# ─────────────────────────────────────────────────────────────────────────────
# Provider User-Agent Overrides (optional — customize per-provider UA headers)
# ─────────────────────────────────────────────────────────────────────────────
# Format: {PROVIDER_ID}_USER_AGENT=custom-value
# When set, overrides the default User-Agent header sent to that provider.
# Useful when providers update versions or block old user-agents.
CLAUDE_USER_AGENT=claude-cli/1.0.83 (external, cli)
CODEX_USER_AGENT=codex-cli/0.92.0 (Windows 10.0.26100; x64)
GITHUB_USER_AGENT=GitHubCopilotChat/0.26.7
ANTIGRAVITY_USER_AGENT=antigravity/1.104.0 darwin/arm64
KIRO_USER_AGENT=AWS-SDK-JS/3.0.0 kiro-ide/1.0.0
IFLOW_USER_AGENT=iFlow-Cli
QWEN_USER_AGENT=QwenCode/0.12.3 (linux; x64)
CURSOR_USER_AGENT=connect-es/1.6.1
GEMINI_CLI_USER_AGENT=google-api-nodejs-client/9.15.1
# ─────────────────────────────────────────────────────────────────────────────
# CLI Fingerprint Compatibility (optional — match native CLI binary signatures)
# ─────────────────────────────────────────────────────────────────────────────
# When enabled, OmniRoute reorders HTTP headers and JSON body fields to match
# the exact signature of official CLI tools, reducing account flagging risk.
# Your proxy IP is preserved — you get both stealth AND IP masking.
#
# Enable per-provider:
# CLI_COMPAT_CODEX=1
# CLI_COMPAT_CLAUDE=1
# CLI_COMPAT_GITHUB=1
# CLI_COMPAT_ANTIGRAVITY=1
# CLI_COMPAT_KIRO=1
# CLI_COMPAT_CURSOR=1
# CLI_COMPAT_KIMI_CODING=1
# CLI_COMPAT_KILOCODE=1
# CLI_COMPAT_CLINE=1
# CLI_COMPAT_QWEN=1
#
# Or enable for all providers at once:
# CLI_COMPAT_ALL=1
# API Key Providers (Phase 1 + Phase 4)
# Add via Dashboard → Providers → Add API Key, or set here
@@ -114,6 +188,8 @@ ANTIGRAVITY_OAUTH_CLIENT_SECRET=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
# Timeout settings
# FETCH_TIMEOUT_MS=120000
# STREAM_IDLE_TIMEOUT_MS=60000
# API bridge timeout for /v1 proxy requests (default: 30000)
# API_BRIDGE_PROXY_TIMEOUT_MS=120000
# CORS configuration (default: * allows all origins)
# CORS_ORIGINS=*
@@ -125,3 +201,24 @@ LOG_TO_FILE=true
# LOG_FILE_PATH=logs/application/app.log
# LOG_MAX_FILE_SIZE=50M
# LOG_RETENTION_DAYS=7
# ─────────────────────────────────────────────────────────────────────────────
# Memory Optimization (Low-RAM configurations)
# ─────────────────────────────────────────────────────────────────────────────
# Node.js heap limit in MB (default: 256 for Docker, system default for npm)
# OMNIROUTE_MEMORY_MB=256
# Prompt cache settings
# PROMPT_CACHE_MAX_SIZE=50
# PROMPT_CACHE_MAX_BYTES=2097152
# PROMPT_CACHE_TTL_MS=300000
# Semantic cache settings (temperature=0 responses)
# SEMANTIC_CACHE_MAX_SIZE=100
# SEMANTIC_CACHE_MAX_BYTES=4194304
# SEMANTIC_CACHE_TTL_MS=1800000
# In-memory log buffers
# PROXY_LOG_MAX_ENTRIES=200
# CALL_LOGS_MAX=200
# STREAM_HISTORY_MAX=50

View File

@@ -10,6 +10,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint:
name: Lint
@@ -22,6 +25,12 @@ jobs:
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run check:cycles
- run: npm run check:route-validation:t06
- run: npm run check:any-budget:t11
- run: npm run check:docs-sync
- run: npm run typecheck:core
- run: npm run typecheck:noimplicit:core
security:
name: Security Audit
@@ -127,7 +136,6 @@ jobs:
cache: npm
- run: npm ci
- run: npm run test:integration
continue-on-error: true
test-security:
name: Security Tests
@@ -144,4 +152,3 @@ jobs:
cache: npm
- run: npm ci
- run: npm run test:security
continue-on-error: true

View File

@@ -1,22 +0,0 @@
name: Codex PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
request-codex-review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Request Codex Review
uses: actions/github-script@v8
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: '@codex review'
});

40
.github/workflows/deploy-vps.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Deploy to VPS
on:
workflow_run:
workflows: ["Publish to Docker Hub"]
types: [completed]
workflow_dispatch:
jobs:
deploy:
if: >-
(github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success')
&& vars.DEPLOY_ENABLED == 'true'
name: Deploy OmniRoute to VPS
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
continue-on-error: true
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
port: 22
timeout: 30s
command_timeout: 5m
script: |
echo "=== Updating OmniRoute ==="
npm install -g omniroute@latest 2>&1
INSTALLED_VERSION=$(omniroute --version 2>/dev/null || echo "unknown")
echo "Installed version: $INSTALLED_VERSION"
echo "=== Restarting PM2 ==="
pm2 restart omniroute || pm2 start omniroute --name omniroute -- --port 20128
pm2 save
echo "=== Health Check ==="
sleep 3
curl -sf http://localhost:20128/api/settings > /dev/null && echo "✅ OmniRoute is healthy" || echo "❌ Health check failed"
echo "=== Deploy complete ==="

View File

@@ -3,25 +3,30 @@ name: Publish to Docker Hub
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version tag to build (e.g. 2.6.0)"
required: true
type: string
permissions:
contents: read
jobs:
docker:
name: Build & Push Docker Image
name: Build and Push Docker (multi-arch)
runs-on: ubuntu-latest
env:
IMAGE_NAME: diegosouzapw/omniroute
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/v{0}', inputs.version) || '' }}
- name: Extract version from release tag
id: version
run: |
VERSION="${GITHUB_REF_NAME}"
VERSION="${VERSION#v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing Docker image version: $VERSION"
- name: Set up QEMU (for multi-arch builds)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -32,21 +37,40 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
- name: Extract version from release tag or input
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
else
VERSION="${GITHUB_REF_NAME}"
VERSION="${VERSION#v}"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing Docker image: $IMAGE_NAME:$VERSION"
- name: Build and push multi-arch image
uses: docker/build-push-action@v6
with:
context: .
target: runner-base
platforms: linux/amd64,linux/arm64
push: true
tags: |
diegosouzapw/omniroute:${{ steps.version.outputs.version }}
diegosouzapw/omniroute:latest
${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}
${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
no-cache: false
env:
DOCKER_BUILDKIT_INLINE_CACHE: 1
- name: Inspect image
run: |
docker buildx imagetools inspect "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}"
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v5
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

203
.github/workflows/electron-release.yml vendored Normal file
View File

@@ -0,0 +1,203 @@
name: Build Electron Desktop App
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Release version (e.g., v1.6.8)"
required: true
type: string
permissions:
contents: write
jobs:
validate:
name: Validate version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.validate.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate version format
id: validate
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="${{ inputs.version }}"
fi
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: Invalid version format. Expected: v1.6.8"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "✓ Valid version: $VERSION"
build:
name: Build Electron (${{ matrix.platform }})
needs: validate
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: windows
runner: windows-latest
target: win
ext: .exe
- platform: macos-intel
runner: macos-15-intel
target: mac-x64
ext: .dmg
- platform: macos-arm64
runner: macos-latest
target: mac-arm64
ext: -arm64.dmg
- platform: linux
runner: ubuntu-latest
target: linux
ext: .AppImage
deb_ext: .deb
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- name: Cache node_modules
uses: actions/cache@v5
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build Next.js standalone
env:
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
run: npm run build
- name: Sync version in electron/package.json
shell: bash
run: |
VERSION="${{ needs.validate.outputs.version }}"
VERSION_NO_V="${VERSION#v}"
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('electron/package.json'));
pkg.version = '$VERSION_NO_V';
fs.writeFileSync('electron/package.json', JSON.stringify(pkg, null, 2) + '\\n');
"
echo "✓ electron/package.json version set to $VERSION_NO_V"
- name: Install fpm (Linux .deb packaging tool)
if: matrix.platform == 'linux'
run: sudo gem install fpm --no-document
- name: Install Electron dependencies
working-directory: electron
run: npm install --no-audit --no-fund
- name: Build Electron for ${{ matrix.platform }}
working-directory: electron
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run build:${{ matrix.target }}
- name: Collect installers
shell: bash
run: |
mkdir -p release-assets
cd electron/dist-electron
# Copy only installer files for this platform
for file in *${{ matrix.ext }}; do
[ -f "$file" ] && cp "$file" ../../release-assets/
done
# Linux: also copy .deb package
if [ "${{ matrix.platform }}" = "linux" ]; then
for file in *.deb; do
[ -f "$file" ] && cp "$file" ../../release-assets/
done
fi
# Windows: also copy portable standalone exe as OmniRoute.exe
if [ "${{ matrix.platform }}" = "windows" ]; then
for file in *.exe; do
# Skip the NSIS installer (contains "Setup")
case "$file" in *Setup*) continue ;; esac
[ -f "$file" ] && cp "$file" "../../release-assets/OmniRoute.exe" && break
done
fi
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: electron-${{ matrix.platform }}
path: release-assets/
release:
name: Create Release
needs: [validate, build]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: release-assets
merge-multiple: true
- name: Create source archives
run: |
# Create source code archives (excluding dev dependencies and build artifacts)
export TARBALL="OmniRoute-${{ needs.validate.outputs.version }}.source.tar.gz"
export ZIPBALL="OmniRoute-${{ needs.validate.outputs.version }}.source.zip"
# Use git archive for clean source export
git archive --format=tar.gz --prefix=OmniRoute-${{ needs.validate.outputs.version }}/ HEAD -o "release-assets/$TARBALL"
git archive --format=zip --prefix=OmniRoute-${{ needs.validate.outputs.version }}/ HEAD -o "release-assets/$ZIPBALL"
echo "✓ Created source archives:"
ls -lh "release-assets/$TARBALL" "release-assets/$ZIPBALL"
- name: List release files
run: ls -la release-assets/
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.validate.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
fail_on_unmatched_files: false
files: |
release-assets/*.dmg
release-assets/*.exe
release-assets/*.AppImage
release-assets/*.deb
release-assets/*.blockmap
release-assets/*.source.tar.gz
release-assets/*.source.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -3,6 +3,12 @@ name: Publish to npm
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version tag to publish (e.g. 2.6.0)"
required: true
type: string
permissions:
contents: read
@@ -22,21 +28,33 @@ jobs:
node-version: 22
registry-url: https://registry.npmjs.org
- name: Install dependencies
run: npm ci
- name: Install dependencies (skip scripts to avoid heavy build)
run: npm install --ignore-scripts --no-audit --no-fund
- name: Build standalone app
run: npm run build:cli
- name: Sync version from release tag
- name: Sync version from release tag or input
run: |
VERSION="${GITHUB_REF_NAME}"
# Remove 'v' prefix if present (v0.1.0 -> 0.1.0)
VERSION="${VERSION#v}"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
else
VERSION="${GITHUB_REF_NAME}"
VERSION="${VERSION#v}"
fi
npm version "$VERSION" --no-git-tag-version --allow-same-version
echo "Publishing version: $VERSION"
- name: Build CLI bundle (standalone app)
env:
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
run: node scripts/prepublish.mjs
- name: Publish to npm
run: npm publish --access public
run: |
VERSION=$(node -p "require('./package.json').version")
# Check if this version is already published — skip instead of failing with E403
if npm view "omniroute@${VERSION}" version --silent 2>/dev/null | grep -q "^${VERSION}$"; then
echo "️⚠️ Version ${VERSION} is already published on npm — skipping."
exit 0
fi
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

47
.gitignore vendored
View File

@@ -1,7 +1,12 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# project-specific directories
.omnivscodeagent/
omnirouteCloud/
omnirouteSite/
# dependencies
/node_modules
node_modules/
/.pnp
.pnp.*
.yarn/*
@@ -11,10 +16,10 @@
!.yarn/versions
# testing
/coverage
coverage/
# next.js
/.next/
.next/
/out/
# production
@@ -50,6 +55,8 @@ logs/*
# analysis directories (generated, not tracked)
.analysis/
antigravity-manager-analysis/
.sisyphus/
.plans/
# docs (allow specific tracked files)
docs/*
@@ -63,6 +70,7 @@ docs/*
!docs/TASK_NEBIUS_BACKEND_ENABLEMENT.md
!docs/frontend-backend-provider-gap-report.md
!docs/openapi.yaml
!docs/RELEASE_CHECKLIST.md
!docs/PLANO-IMPLANTACAO.md
!docs/TASKS.md
!docs/FASE-*.md
@@ -74,6 +82,12 @@ docs/*
!docs/VM_DEPLOYMENT_GUIDE.md
!docs/FEATURES.md
!docs/screenshots/
!docs/i18n/
!docs/i18n/**
!docs/A2A-SERVER.md
!docs/AUTO-COMBO.md
!docs/MCP-SERVER.md
!docs/CLI-TOOLS.md
# open-sse tests
open-sse/test/*
@@ -86,12 +100,33 @@ test-results/
playwright-report/
blob-report/
cloud/
omnirouteCloud/
omnirouteSite/
# Security Analysis (standalone project with own git)
security-analysis/
# Deploy workflow (contains sensitive VPS credentials)
.agent/workflows/deploy.md
clipr/
app.log
*.tgz
# Backup directories
app.__qa_backup/
# Production standalone build (created by scripts/prepublish.mjs)
# Conflicts with Next.js App Router detection in dev (root app/ shadows src/app/)
# npm publish still includes it via package.json "files" field
/app/
# Electron (subproject dependency lock and build artifacts)
electron/package-lock.json
electron/dist-electron/
electron/node_modules/
icon.iconset/
# VS Code Extension (independent Git repo)
vscode-extension/
# SQLite residual files
*.sqlite-shm
*.sqlite-wal
*.sqlite-journal

View File

@@ -1 +1,3 @@
npx lint-staged
node scripts/check-docs-sync.mjs
npm run test:unit

View File

@@ -3,6 +3,11 @@ data/
**/data/
**/db.json
# VS Code extension test runtime (large binary, not needed in npm package)
app/vscode-extension/
**/data/
**/db.json
# Source code (pre-built app/ is published instead)
src/
open-sse/

View File

@@ -4,6 +4,7 @@
Unified AI proxy/router — route any LLM through one endpoint. Multi-provider support
(OpenAI, Anthropic, Gemini, DeepSeek, Groq, xAI, Mistral, Fireworks, Cohere, etc.)
with **MCP Server** (16 tools for agent control) and **A2A v0.3 Protocol** (Agent-to-Agent orchestration).
## Stack
@@ -13,6 +14,7 @@ Unified AI proxy/router — route any LLM through one endpoint. Multi-provider s
- **Streaming**: SSE via `open-sse` internal package
- **Styling**: Tailwind CSS v4
- **Docker**: Multi-stage Dockerfile, 3 profiles (base / cli / host)
- **i18n**: next-intl with 30 languages (`src/i18n/messages/`)
## Architecture
@@ -47,6 +49,56 @@ but the real logic lives in `src/lib/db/`.
Translation between provider formats: `open-sse/translator/`
### MCP Server (`open-sse/mcp-server/`)
16 tools for AI agent control via **3 transport modes**:
- **stdio** — Local IDE integration (Claude Desktop, Cursor, VS Code)
- **SSE** — Remote Server-Sent Events at `/api/mcp/sse`
- **Streamable HTTP** — Modern bidirectional HTTP at `/api/mcp/stream`
HTTP transports run in-process via `httpTransport.ts` singleton using `WebStandardStreamableHTTPServerTransport`.
| Category | Tools |
| ---------- | ------------------------------------------------------------------------------------------------------------------------- |
| Essential | `get_health`, `list_combos`, `get_combo_metrics`, `switch_combo`, `check_quota`, `route_request`, `cost_report`, `list_models_catalog` |
| Advanced | `simulate_route`, `set_budget_guard`, `set_resilience_profile`, `test_combo`, `get_provider_metrics`, `best_combo_for_task`, `explain_route`, `get_session_snapshot` |
- Scoped authorization (9 scopes), audit logging, Zod schemas
- IDE configs for Claude Desktop, Cursor, VS Code Copilot
### A2A Server (`src/lib/a2a/`)
Agent-to-Agent v0.3 protocol:
- JSON-RPC 2.0: `message/send`, `message/stream`, `tasks/get`, `tasks/cancel`
- Agent Card at `/.well-known/agent.json`
- Skills: `smart-routing`, `quota-management`
- SSE streaming with 15s heartbeat
- Task Manager with state machine and TTL-based cleanup
### Auto-Combo Engine (`open-sse/services/autoCombo/`)
Self-healing routing optimization:
- 6-factor scoring, 4 mode packs, bandit exploration
- Progressive cooldown, probe-based re-admission
### Dashboard (`src/app/(dashboard)/`)
| Page | Description |
| ---------------------------- | -------------------------------------------------------------- |
| `/dashboard` | Home with quick start, provider overview |
| `/dashboard/endpoint` | **Endpoints** (tabbed): Endpoint Proxy, MCP, A2A, API Endpoints |
| `/dashboard/providers` | Provider management and connections |
| `/dashboard/combos` | Combo configurations with routing strategies |
| `/dashboard/logs` | Request, Proxy, Audit, Console logs (tabbed) |
| `/dashboard/analytics` | Usage analytics and evaluations |
| `/dashboard/costs` | Cost tracking and breakdown |
| `/dashboard/health` | Uptime, circuit breakers, latency |
| `/dashboard/cli-tools` | CLI tool integrations (Claude, Codex, Antigravity, etc.) |
| `/dashboard/media` | Image, Video, Music generation playground |
| `/dashboard/settings` | System settings with multiple tabs |
| `/dashboard/api-manager` | API key management with model permissions |
### OAuth & Tokens (`src/lib/oauth/`)
18 modules handling OAuth flows, token refresh, and provider credentials.
@@ -76,7 +128,7 @@ overridable via env vars or `data/provider-credentials.json`.
- No hardcoded API keys or secrets in commits
- Auth middleware on all API routes
- Input validation on user-facing endpoints
- Input validation on user-facing endpoints (Zod schemas)
- SQLite encryption key must not be logged
### Architecture
@@ -85,6 +137,7 @@ overridable via env vars or `data/provider-credentials.json`.
- Provider requests flow through `open-sse/handlers/`
- Translations use `open-sse/translator/` modules
- `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module
- MCP and A2A pages are embedded as tabs inside `/dashboard/endpoint`, not standalone routes
### Code Quality
@@ -92,6 +145,7 @@ overridable via env vars or `data/provider-credentials.json`.
- Proper HTTP status codes
- No memory leaks in SSE streams (abort signals, cleanup)
- Rate limit headers must be parsed correctly
- All API inputs validated with Zod schemas
### Docker

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@ FROM node:22-bookworm-slim AS builder
WORKDIR /app
COPY package*.json ./
COPY scripts/postinstall.mjs ./scripts/postinstall.mjs
COPY scripts/native-binary-compat.mjs ./scripts/native-binary-compat.mjs
RUN if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi
COPY . ./
@@ -19,20 +21,33 @@ LABEL org.opencontainers.image.title="omniroute" \
ENV NODE_ENV=production
ENV PORT=20128
ENV HOSTNAME=0.0.0.0
ENV NODE_OPTIONS="--max-old-space-size=256"
# Runtime writable location for localDb when DATA_DIR is configured to /app/data
# Data directory inside Docker — must match the volume mount in docker-compose.yml
ENV DATA_DIR=/app/data
RUN mkdir -p /app/data
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/standalone ./
# Explicitly copy @swc/helpers — not always traced by standalone output but needed at runtime
COPY --from=builder /app/node_modules/@swc/helpers ./node_modules/@swc/helpers
# Explicitly copy pino transport dependencies — pino spawns a worker that requires
# pino-abstract-transport at runtime; Next.js standalone trace does not capture it (#449)
COPY --from=builder /app/node_modules/pino-abstract-transport ./node_modules/pino-abstract-transport
COPY --from=builder /app/node_modules/pino-pretty ./node_modules/pino-pretty
COPY --from=builder /app/node_modules/split2 ./node_modules/split2
COPY --from=builder /app/scripts/run-standalone.mjs ./run-standalone.mjs
COPY --from=builder /app/scripts/runtime-env.mjs ./runtime-env.mjs
COPY --from=builder /app/scripts/bootstrap-env.mjs ./bootstrap-env.mjs
COPY --from=builder /app/scripts/healthcheck.mjs ./healthcheck.mjs
EXPOSE 20128
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))"
CMD ["node", "healthcheck.mjs"]
CMD ["node", "server.js"]
CMD ["node", "run-standalone.mjs"]
FROM runner-base AS runner-cli
@@ -44,4 +59,3 @@ RUN apt-get update \
# Install CLI tools globally. Separate layer from apt for better cache reuse.
RUN npm install -g --no-audit --no-fund @openai/codex @anthropic-ai/claude-code droid openclaw@latest

File diff suppressed because it is too large Load Diff

View File

@@ -1,999 +0,0 @@
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
# 🚀 OmniRoute — El Gateway de IA Gratuito
### Nunca dejes de programar. Enrutamiento inteligente hacia **modelos de IA GRATUITOS y económicos** con fallback automático.
_Tu proxy de API universal — un endpoint, 36+ proveedores, cero tiempo de inactividad._
**Chat Completions • Embeddings • Generación de Imágenes • Audio • Reranking • 100% TypeScript**
---
### 🤖 Proveedor de IA Gratuito para tus agentes de programación favoritos
_Conecta cualquier IDE o herramienta CLI con IA a través de OmniRoute — gateway de API gratuito para programación ilimitada._
<table>
<tr>
<td align="center" width="110">
<a href="https://github.com/cline/cline">
<img src="./public/providers/openclaw.png" alt="OpenClaw" width="48"/><br/>
<b>OpenClaw</b>
</a><br/>
<sub>⭐ 205K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/HKUDS/nanobot">
<img src="./public/providers/nanobot.png" alt="NanoBot" width="48"/><br/>
<b>NanoBot</b>
</a><br/>
<sub>⭐ 20.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/sipeed/picoclaw">
<img src="./public/providers/picoclaw.jpg" alt="PicoClaw" width="48"/><br/>
<b>PicoClaw</b>
</a><br/>
<sub>⭐ 14.6K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/zeroclaw-labs/zeroclaw">
<img src="./public/providers/zeroclaw.png" alt="ZeroClaw" width="48"/><br/>
<b>ZeroClaw</b>
</a><br/>
<sub>⭐ 9.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/nearai/ironclaw">
<img src="./public/providers/ironclaw.png" alt="IronClaw" width="48"/><br/>
<b>IronClaw</b>
</a><br/>
<sub>⭐ 2.1K</sub>
</td>
</tr>
<tr>
<td align="center" width="110">
<a href="https://github.com/anomalyco/opencode">
<img src="./public/providers/opencode.svg" alt="OpenCode" width="48"/><br/>
<b>OpenCode</b>
</a><br/>
<sub>⭐ 106K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/openai/codex">
<img src="./public/providers/codex.png" alt="Codex CLI" width="48"/><br/>
<b>Codex CLI</b>
</a><br/>
<sub>⭐ 60.8K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/anthropics/claude-code">
<img src="./public/providers/claude.png" alt="Claude Code" width="48"/><br/>
<b>Claude Code</b>
</a><br/>
<sub>⭐ 67.3K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/google-gemini/gemini-cli">
<img src="./public/providers/gemini-cli.png" alt="Gemini CLI" width="48"/><br/>
<b>Gemini CLI</b>
</a><br/>
<sub>⭐ 94.7K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/Kilo-Org/kilocode">
<img src="./public/providers/kilocode.png" alt="Kilo Code" width="48"/><br/>
<b>Kilo Code</b>
</a><br/>
<sub>⭐ 15.5K</sub>
</td>
</tr>
</table>
<sub>📡 Todos los agentes se conectan vía <code>http://localhost:20128/v1</code> o <code>http://cloud.omniroute.online/v1</code> — una configuración, modelos y cuota ilimitados</sub>
---
[![npm version](https://img.shields.io/npm/v/omniroute?color=cb3837&logo=npm)](https://www.npmjs.com/package/omniroute)
[![Docker Hub](https://img.shields.io/docker/v/diegosouzapw/omniroute?label=Docker%20Hub&logo=docker&color=2496ED)](https://hub.docker.com/r/diegosouzapw/omniroute)
[![License](https://img.shields.io/github/license/diegosouzapw/OmniRoute)](https://github.com/diegosouzapw/OmniRoute/blob/main/LICENSE)
[![Website](https://img.shields.io/badge/Website-omniroute.online-blue?logo=google-chrome&logoColor=white)](https://omniroute.online)
[![WhatsApp](https://img.shields.io/badge/WhatsApp-Community-25D366?logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
[🌐 Website](https://omniroute.online) • [🚀 Inicio Rápido](#-inicio-rápido) • [💡 Características](#-características-principales) • [📖 Docs](#-documentación) • [💰 Precios](#-precios-resumidos)
🌐 **Disponible en:** [English](README.md) | [Português](README.pt-BR.md) | [Español](README.es.md) | [Русский](README.ru.md) | [中文](README.zh-CN.md) | [Deutsch](README.de.md) | [Français](README.fr.md) | [Italiano](README.it.md)
</div>
---
## 🤔 ¿Por qué OmniRoute?
**Deja de desperdiciar dinero y chocar con límites:**
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> La cuota de suscripción expira sin usar cada mes
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Los límites de tasa te detienen en medio de la programación
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> APIs caras ($20-50/mes por proveedor)
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Cambiar manualmente entre proveedores
**OmniRoute resuelve esto:**
-**Maximiza suscripciones** - Rastrea cuotas, usa cada bit antes del reset
-**Fallback automático** - Suscripción → API Key → Barato → Gratuito, cero tiempo de inactividad
-**Multi-cuenta** - Round-robin entre cuentas por proveedor
-**Universal** - Funciona con Claude Code, Codex, Gemini CLI, Cursor, Cline, OpenClaw, cualquier herramienta CLI
---
## 🔄 Cómo Funciona
```
┌─────────────┐
│ Tu CLI │ (Claude Code, Codex, Gemini CLI, OpenClaw, Cursor, Cline...)
│ Tool │
└──────┬──────┘
│ http://localhost:20128/v1
┌─────────────────────────────────────────┐
│ OmniRoute (Enrutador Inteligente) │
│ • Traducción de formato (OpenAI ↔ Claude) │
│ • Rastreo de cuota + Embeddings + Imágenes │
│ • Renovación automática de tokens │
└──────┬──────────────────────────────────┘
├─→ [Tier 1: SUSCRIPCIÓN] Claude Code, Codex, Gemini CLI
│ ↓ cuota agotada
├─→ [Tier 2: API KEY] DeepSeek, Groq, xAI, Mistral, NVIDIA NIM, etc.
│ ↓ límite de presupuesto
├─→ [Tier 3: BARATO] GLM ($0.6/1M), MiniMax ($0.2/1M)
│ ↓ límite de presupuesto
└─→ [Tier 4: GRATUITO] iFlow, Qwen, Kiro (ilimitado)
Resultado: Nunca dejes de programar, costo mínimo
```
---
## ⚡ Inicio Rápido
**1. Instala globalmente:**
```bash
npm install -g omniroute
omniroute
```
🎉 El Dashboard se abre en `http://localhost:20128`
| Comando | Descripción |
| ----------------------- | ---------------------------------------------- |
| `omniroute` | Iniciar servidor (puerto predeterminado 20128) |
| `omniroute --port 3000` | Usar puerto personalizado |
| `omniroute --no-open` | No abrir navegador automáticamente |
| `omniroute --help` | Mostrar ayuda |
**2. Conecta un proveedor GRATUITO:**
Dashboard → Proveedores → Conectar **Claude Code** o **Antigravity** → Login OAuth → ¡Listo!
**3. Usa en tu herramienta CLI:**
```
Claude Code/Codex/Gemini CLI/OpenClaw/Cursor/Cline Configuración:
Endpoint: http://localhost:20128/v1
API Key: [copiar del dashboard]
Model: if/kimi-k2-thinking
```
**¡Eso es todo!** Comienza a programar con modelos de IA GRATUITOS.
**Alternativa — ejecutar desde código fuente:**
```bash
cp .env.example .env
npm install
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
---
## 🐳 Docker
OmniRoute está disponible como imagen Docker pública en [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute).
**Ejecución rápida:**
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**Con archivo de entorno:**
```bash
# Copia y edita el .env primero
cp .env.example .env
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file .env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**Usando Docker Compose:**
```bash
# Perfil base (sin herramientas CLI)
docker compose --profile base up -d
# Perfil CLI (Claude Code, Codex, OpenClaw integrados)
docker compose --profile cli up -d
```
| Imagen | Tag | Tamaño | Descripción |
| ------------------------ | -------- | ------ | ---------------------- |
| `diegosouzapw/omniroute` | `latest` | ~250MB | Última versión estable |
| `diegosouzapw/omniroute` | `1.0.4` | ~250MB | Versión actual |
---
## 💰 Precios Resumidos
| Tier | Proveedor | Costo | Reset de Cuota | Mejor Para |
| ------------------ | ----------------- | ---------------------------- | ----------------- | ----------------------- |
| **💳 SUSCRIPCIÓN** | Claude Code (Pro) | $20/mes | 5h + semanal | Ya suscrito |
| | Codex (Plus/Pro) | $20-200/mes | 5h + semanal | Usuarios OpenAI |
| | Gemini CLI | **GRATUITO** | 180K/mes + 1K/día | ¡Todos! |
| | GitHub Copilot | $10-19/mes | Mensual | Usuarios GitHub |
| **🔑 API KEY** | NVIDIA NIM | **GRATUITO** (1000 créditos) | Único | Pruebas gratuitas |
| | DeepSeek | Por uso | Ninguno | Mejor precio/calidad |
| | Groq | Tier gratuito + pago | Limitado | Inferencia ultra-rápida |
| | xAI (Grok) | Por uso | Ninguno | Modelos Grok |
| | Mistral | Tier gratuito + pago | Limitado | IA Europea |
| | OpenRouter | Por uso | Ninguno | 100+ modelos |
| **💰 BARATO** | GLM-4.7 | $0.6/1M | Diario 10h | Respaldo económico |
| | MiniMax M2.1 | $0.2/1M | Rotativo 5h | Opción más barata |
| | Kimi K2 | $9/mes fijo | 10M tokens/mes | Costo predecible |
| **🆓 GRATUITO** | iFlow | $0 | Ilimitado | 8 modelos gratuitos |
| | Qwen | $0 | Ilimitado | 3 modelos gratuitos |
| | Kiro | $0 | Ilimitado | Claude gratuito |
**💡 Consejo Pro:** ¡Comienza con Gemini CLI (180K gratis/mes) + iFlow (ilimitado gratis) = $0 de costo!
---
## 🎯 Casos de Uso
### Caso 1: "Tengo suscripción Claude Pro"
**Problema:** La cuota expira sin usar, límites de tasa durante programación intensa
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (usar suscripción al máximo)
2. glm/glm-4.7 (respaldo barato cuando la cuota se agota)
3. if/kimi-k2-thinking (fallback de emergencia gratuito)
Costo mensual: $20 (suscripción) + ~$5 (respaldo) = $25 total
vs. $20 + chocar con límites = frustración
```
### Caso 2: "Quiero costo cero"
**Problema:** No puede pagar suscripciones, necesita IA confiable para programar
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K gratis/mes)
2. if/kimi-k2-thinking (ilimitado gratis)
3. qw/qwen3-coder-plus (ilimitado gratis)
Costo mensual: $0
Calidad: Modelos listos para producción
```
### Caso 3: "Necesito programar 24/7, sin interrupciones"
**Problema:** Plazos ajustados, no puede permitirse tiempo de inactividad
```
Combo: "always-on"
1. cc/claude-opus-4-6 (mejor calidad)
2. cx/gpt-5.2-codex (segunda suscripción)
3. glm/glm-4.7 (barato, reset diario)
4. minimax/MiniMax-M2.1 (más barato, reset 5h)
5. if/kimi-k2-thinking (gratuito ilimitado)
Resultado: 5 capas de fallback = cero tiempo de inactividad
```
### Caso 4: "Quiero IA GRATUITA en OpenClaw"
**Problema:** Necesita asistente de IA en apps de mensajería, completamente gratuito
```
Combo: "openclaw-free"
1. if/glm-4.7 (ilimitado gratis)
2. if/minimax-m2.1 (ilimitado gratis)
3. if/kimi-k2-thinking (ilimitado gratis)
Costo mensual: $0
Acceso vía: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 💡 Características Principales
### 🧠 Enrutamiento e Inteligencia
| Característica | Qué Hace |
| -------------------------------------- | ------------------------------------------------------------------------------- |
| 🎯 **Fallback Inteligente 4 Tiers** | Auto-enrutamiento: Suscripción → API Key → Barato → Gratuito |
| 📊 **Rastreo de Cuota en Tiempo Real** | Conteo de tokens en vivo + countdown de reset por proveedor |
| 🔄 **Traducción de Formato** | OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro transparente |
| 👥 **Soporte Multi-Cuenta** | Múltiples cuentas por proveedor con selección inteligente |
| 🔄 **Renovación Automática de Token** | Tokens OAuth se renuevan automáticamente con reintentos |
| 🎨 **Combos Personalizados** | 6 estrategias: fill-first, round-robin, p2c, random, least-used, cost-optimized |
| 🧩 **Modelos Personalizados** | Agrega cualquier ID de modelo a cualquier proveedor |
| 🌐 **Enrutador Wildcard** | Enruta patrones `provider/*` a cualquier proveedor dinámicamente |
| 🧠 **Presupuesto de Razonamiento** | Modos passthrough, auto, custom y adaptativo para modelos de razonamiento |
| 💬 **Inyección de System Prompt** | System prompt global aplicado en todas las solicitudes |
| 📄 **API Responses** | Soporte completo de la API Responses de OpenAI (`/v1/responses`) para Codex |
### 🎵 APIs Multi-Modal
| Característica | Qué Hace |
| ----------------------------- | ------------------------------------------------------ |
| 🖼️ **Generación de Imágenes** | `/v1/images/generations` — 4 proveedores, 9+ modelos |
| 📐 **Embeddings** | `/v1/embeddings` — 6 proveedores, 9+ modelos |
| 🎤 **Transcripción de Audio** | `/v1/audio/transcriptions` — Compatible con Whisper |
| 🔊 **Texto a Voz** | `/v1/audio/speech` — Síntesis de audio multi-proveedor |
| 🛡️ **Moderaciones** | `/v1/moderations` — Verificaciones de seguridad |
| 🔀 **Reranking** | `/v1/rerank` — Reranking de relevancia de documentos |
### 🛡️ Resiliencia y Seguridad
| Característica | Qué Hace |
| ---------------------------------- | ---------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Auto-apertura/cierre por proveedor con umbrales configurables |
| 🛡️ **Anti-Thundering Herd** | Mutex + semáforo rate-limit para proveedores con API key |
| 🧠 **Caché Semántico** | Caché de dos niveles (firma + semántico) reduce costo y latencia |
| ⚡ **Idempotencia de Solicitud** | Ventana de dedup de 5s para solicitudes duplicadas |
| 🔒 **Spoofing de Fingerprint TLS** | Bypass de detección de bot vía TLS con wreq-js |
| 🌐 **Filtrado de IP** | Allowlist/blocklist para control de acceso a la API |
| 📊 **Rate Limits Editables** | RPM, gap mínimo y concurrencia máxima configurables |
### 📊 Observabilidad y Analytics
| Característica | Qué Hace |
| ------------------------------ | --------------------------------------------------------------------- |
| 📝 **Logs de Solicitud** | Modo debug con logs completos de request/response |
| 💾 **Logs SQLite** | Logs de proxy persistentes sobreviven a reinicios |
| 📊 **Dashboard de Analytics** | Recharts: cards de estadísticas, gráfico de uso, tabla de proveedores |
| 📈 **Rastreo de Progreso** | Eventos de progreso SSE opt-in para streaming |
| 🧪 **Evaluaciones de LLM** | Pruebas con conjunto golden y 4 estrategias de match |
| 🔍 **Telemetría de Solicitud** | Agregación de latencia p50/p95/p99 + rastreo X-Request-Id |
| 📋 **Logs + Cuotas** | Páginas dedicadas para navegación de logs y rastreo de cuotas |
| 🏥 **Dashboard de Salud** | Uptime, estados de circuit breaker, lockouts, stats de caché |
| 💰 **Rastreo de Costos** | Gestión de presupuesto + configuración de precios por modelo |
### ☁️ Deploy y Sincronización
| Característica | Qué Hace |
| --------------------------------- | ------------------------------------------------------------------------------- |
| 💾 **Cloud Sync** | Sincroniza configuraciones entre dispositivos vía Cloudflare Workers |
| 🌐 **Deploy en Cualquier Lugar** | Localhost, VPS, Docker, Cloudflare Workers |
| 🔑 **Gestión de API Keys** | Genera, rota y define alcance de API keys por proveedor |
| 🧙 **Asistente de Configuración** | Setup guiado en 4 pasos para nuevos usuarios |
| 🔧 **Dashboard CLI Tools** | Configuración en un clic para Claude, Codex, Cline, OpenClaw, Kilo, Antigravity |
| 🔄 **Backups de DB** | Backup y restauración automáticos de todas las configuraciones |
<details>
<summary><b>📖 Detalles de Características</b></summary>
### 🎯 Fallback Inteligente 4 Tiers
Crea combos con fallback automático:
```
Combo: "my-coding-stack"
1. cc/claude-opus-4-6 (tu suscripción)
2. nvidia/llama-3.3-70b (API NVIDIA gratuita)
3. glm/glm-4.7 (respaldo barato, $0.6/1M)
4. if/kimi-k2-thinking (fallback gratuito)
→ Cambia automáticamente cuando la cuota se agota o ocurren errores
```
### 📊 Rastreo de Cuota en Tiempo Real
- Consumo de tokens por proveedor
- Countdown de reset (5 horas, diario, semanal)
- Estimación de costo para tiers pagos
- Reportes de gastos mensuales
### 🔄 Traducción de Formato
Traducción transparente entre formatos:
- **OpenAI** ↔ **Claude****Gemini****OpenAI Responses**
- Tu herramienta CLI envía formato OpenAI → OmniRoute traduce → El proveedor recibe formato nativo
- Funciona con cualquier herramienta que soporte endpoints OpenAI personalizados
### 👥 Soporte Multi-Cuenta
- Agrega múltiples cuentas por proveedor
- Round-robin automático o enrutamiento por prioridad
- Fallback a la siguiente cuenta cuando una alcanza la cuota
### 🔄 Renovación Automática de Token
- Los tokens OAuth se renuevan automáticamente antes de expirar
- Sin necesidad de re-autenticación manual
- Experiencia transparente en todos los proveedores
### 🎨 Combos Personalizados
- Crea combinaciones ilimitadas de modelos
- 6 estrategias: fill-first, round-robin, power-of-two-choices, random, least-used, cost-optimized
- Comparte combos entre dispositivos con Cloud Sync
### 🏥 Dashboard de Salud
- Estado del sistema (uptime, versión, uso de memoria)
- Estados de circuit breaker por proveedor (Closed/Open/Half-Open)
- Estado de rate limit y lockouts activos
- Estadísticas de caché de firma
- Telemetría de latencia (p50/p95/p99) + caché de prompt
- Reset de salud con un clic
### 🔧 Playground del Traductor
- Debug, prueba y visualiza traducciones de formato de API
- Envía solicitudes y ve cómo OmniRoute traduce entre formatos de proveedores
- Invaluable para troubleshooting de problemas de integración
### 💾 Cloud Sync
- Sincroniza proveedores, combos y configuraciones entre dispositivos
- Sincronización automática en segundo plano
- Almacenamiento cifrado seguro
</details>
---
## 📖 Guía de Configuración
<details>
<summary><b>💳 Proveedores por Suscripción</b></summary>
### Claude Code (Pro/Max)
```bash
Dashboard → Proveedores → Conectar Claude Code
→ Login OAuth → Renovación automática de token
→ Rastreo de cuota 5h + semanal
Modelos:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Consejo Pro:** Usa Opus para tareas complejas, Sonnet para velocidad. ¡OmniRoute rastrea cuota por modelo!
### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Proveedores → Conectar Codex
→ Login OAuth (puerto 1455)
→ Reset 5h + semanal
Modelos:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
### Gemini CLI (¡GRATUITO 180K/mes!)
```bash
Dashboard → Proveedores → Conectar Gemini CLI
→ Google OAuth
→ 180K completions/mes + 1K/día
Modelos:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Mejor Valor:** ¡Tier gratuito enorme! Úsalo antes de los tiers pagos.
### GitHub Copilot
```bash
Dashboard → Proveedores → Conectar GitHub
→ OAuth vía GitHub
→ Reset mensual (1ro del mes)
Modelos:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
</details>
<details>
<summary><b>🔑 Proveedores por API Key</b></summary>
### NVIDIA NIM (¡GRATUITO 1000 créditos!)
1. Regístrate: [build.nvidia.com](https://build.nvidia.com)
2. Obtén API key gratuita (1000 créditos de inferencia incluidos)
3. Dashboard → Agregar Proveedor → NVIDIA NIM:
- API Key: `nvapi-your-key`
**Modelos:** `nvidia/llama-3.3-70b-instruct`, `nvidia/mistral-7b-instruct`, y 50+ más
**Consejo Pro:** ¡API compatible con OpenAI — funciona perfectamente con la traducción de formato de OmniRoute!
### DeepSeek
1. Regístrate: [platform.deepseek.com](https://platform.deepseek.com)
2. Obtén API key
3. Dashboard → Agregar Proveedor → DeepSeek
**Modelos:** `deepseek/deepseek-chat`, `deepseek/deepseek-coder`
### Groq (¡Tier Gratuito Disponible!)
1. Regístrate: [console.groq.com](https://console.groq.com)
2. Obtén API key (tier gratuito incluido)
3. Dashboard → Agregar Proveedor → Groq
**Modelos:** `groq/llama-3.3-70b`, `groq/mixtral-8x7b`
**Consejo Pro:** ¡Inferencia ultra-rápida — mejor para programación en tiempo real!
### OpenRouter (100+ Modelos)
1. Regístrate: [openrouter.ai](https://openrouter.ai)
2. Obtén API key
3. Dashboard → Agregar Proveedor → OpenRouter
**Modelos:** Accede a 100+ modelos de todos los principales proveedores a través de una única API key.
</details>
<details>
<summary><b>💰 Proveedores Baratos (Respaldo)</b></summary>
### GLM-4.7 (Reset diario, $0.6/1M)
1. Regístrate: [Zhipu AI](https://open.bigmodel.cn/)
2. Obtén API key del Plan Coding
3. Dashboard → Agregar API Key:
- Proveedor: `glm`
- API Key: `your-key`
**Usa:** `glm/glm-4.7`
**Consejo Pro:** ¡El Plan Coding ofrece 3× cuota a 1/7 del costo! Reset diario 10:00 AM.
### MiniMax M2.1 (Reset 5h, $0.20/1M)
1. Regístrate: [MiniMax](https://www.minimax.io/)
2. Obtén API key
3. Dashboard → Agregar API Key
**Usa:** `minimax/MiniMax-M2.1`
**Consejo Pro:** ¡Opción más barata para contexto largo (1M tokens)!
### Kimi K2 ($9/mes fijo)
1. Suscríbete: [Moonshot AI](https://platform.moonshot.ai/)
2. Obtén API key
3. Dashboard → Agregar API Key
**Usa:** `kimi/kimi-latest`
**Consejo Pro:** ¡$9/mes fijo por 10M tokens = $0.90/1M de costo efectivo!
</details>
<details>
<summary><b>🆓 Proveedores GRATUITOS (Respaldo de Emergencia)</b></summary>
### iFlow (8 modelos GRATUITOS)
```bash
Dashboard → Conectar iFlow
→ Login OAuth iFlow
→ Uso ilimitado
Modelos:
if/kimi-k2-thinking
if/qwen3-coder-plus
if/glm-4.7
if/minimax-m2
if/deepseek-r1
```
### Qwen (3 modelos GRATUITOS)
```bash
Dashboard → Conectar Qwen
→ Autorización por código de dispositivo
→ Uso ilimitado
Modelos:
qw/qwen3-coder-plus
qw/qwen3-coder-flash
```
### Kiro (Claude GRATUITO)
```bash
Dashboard → Conectar Kiro
→ AWS Builder ID o Google/GitHub
→ Uso ilimitado
Modelos:
kr/claude-sonnet-4.5
kr/claude-haiku-4.5
```
</details>
<details>
<summary><b>🎨 Crear Combos</b></summary>
### Ejemplo 1: Maximizar Suscripción → Respaldo Barato
```
Dashboard → Combos → Crear Nuevo
Nombre: premium-coding
Modelos:
1. cc/claude-opus-4-6 (Suscripción primaria)
2. glm/glm-4.7 (Respaldo barato, $0.6/1M)
3. minimax/MiniMax-M2.1 (Fallback más barato, $0.20/1M)
Usa en CLI: premium-coding
```
### Ejemplo 2: Solo Gratuito (Costo Cero)
```
Nombre: free-combo
Modelos:
1. gc/gemini-3-flash-preview (180K gratis/mes)
2. if/kimi-k2-thinking (ilimitado)
3. qw/qwen3-coder-plus (ilimitado)
Costo: ¡$0 para siempre!
```
</details>
<details>
<summary><b>🔧 Integración CLI</b></summary>
### Cursor IDE
```
Configuración → Modelos → Avanzado:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [del dashboard OmniRoute]
Model: cc/claude-opus-4-6
```
### Claude Code
Usa la página **CLI Tools** en el dashboard para configuración en un clic, o edita `~/.claude/settings.json` manualmente.
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
**Opción 1 — Dashboard (recomendado):**
```
Dashboard → CLI Tools → OpenClaw → Seleccionar Modelo → Aplicar
```
**Opción 2 — Manual:** Edita `~/.openclaw/openclaw.json`:
```json
{
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://127.0.0.1:20128/v1",
"apiKey": "sk_omniroute",
"api": "openai-completions"
}
}
}
}
```
> **Nota:** OpenClaw solo funciona con OmniRoute local. Usa `127.0.0.1` en lugar de `localhost` para evitar problemas de resolución IPv6.
### Cline / Continue / RooCode
```
Configuración → Configuración de API:
Proveedor: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [del dashboard OmniRoute]
Model: if/kimi-k2-thinking
```
</details>
---
## 📊 Modelos Disponibles
<details>
<summary><b>Ver todos los modelos disponibles</b></summary>
**Claude Code (`cc/`)** - Pro/Max:
- `cc/claude-opus-4-6`
- `cc/claude-sonnet-4-5-20250929`
- `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** - Plus/Pro:
- `cx/gpt-5.2-codex`
- `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** - GRATUITO:
- `gc/gemini-3-flash-preview`
- `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**:
- `gh/gpt-5`
- `gh/claude-4.5-sonnet`
**NVIDIA NIM (`nvidia/`)** - Créditos GRATUITOS:
- `nvidia/llama-3.3-70b-instruct`
- `nvidia/mistral-7b-instruct`
- 50+ más modelos en [build.nvidia.com](https://build.nvidia.com)
**GLM (`glm/`)** - $0.6/1M:
- `glm/glm-4.7`
**MiniMax (`minimax/`)** - $0.2/1M:
- `minimax/MiniMax-M2.1`
**iFlow (`if/`)** - GRATUITO:
- `if/kimi-k2-thinking`
- `if/qwen3-coder-plus`
- `if/deepseek-r1`
- `if/glm-4.7`
- `if/minimax-m2`
**Qwen (`qw/`)** - GRATUITO:
- `qw/qwen3-coder-plus`
- `qw/qwen3-coder-flash`
**Kiro (`kr/`)** - GRATUITO:
- `kr/claude-sonnet-4.5`
- `kr/claude-haiku-4.5`
**OpenRouter (`or/`)** - 100+ modelos:
- `or/anthropic/claude-4-sonnet`
- `or/google/gemini-2.5-pro`
- Cualquier modelo de [openrouter.ai/models](https://openrouter.ai/models)
</details>
---
## 🧪 Evaluaciones (Evals)
OmniRoute incluye un framework de evaluación integrado para probar la calidad de respuestas de LLM contra un conjunto golden. Accede vía **Analytics → Evals** en el dashboard.
### Conjunto Golden Integrado
El "OmniRoute Golden Set" precargado contiene 10 casos de prueba que cubren:
- Saludos, matemáticas, geografía, generación de código
- Conformidad de formato JSON, traducción, markdown
- Rechazo de seguridad (contenido dañino), conteo, lógica booleana
### Estrategias de Evaluación
| Estrategia | Descripción | Ejemplo |
| ---------- | ---------------------------------------------------- | -------------------------------- |
| `exact` | La salida debe coincidir exactamente | `"4"` |
| `contains` | La salida debe contener subcadena (case-insensitive) | `"Paris"` |
| `regex` | La salida debe coincidir con el patrón regex | `"1.*2.*3"` |
| `custom` | Función JS personalizada retorna true/false | `(output) => output.length > 10` |
---
## 🐛 Solución de Problemas
<details>
<summary><b>Haz clic para expandir la guía de solución de problemas</b></summary>
**"Language model did not provide messages"**
- Cuota del proveedor agotada → Verifica el rastreador de cuota en el dashboard
- Solución: Usa combo con fallback o cambia a tier más barato
**Rate limiting**
- Cuota de suscripción agotada → Fallback a GLM/MiniMax
- Agrega combo: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
**Token OAuth expirado**
- Renovado automáticamente por OmniRoute
- Si persiste: Dashboard → Proveedor → Reconectar
**Costos altos**
- Verifica estadísticas de uso en Dashboard → Costos
- Cambia modelo primario a GLM/MiniMax
- Usa tier gratuito (Gemini CLI, iFlow) para tareas no críticas
**Dashboard se abre en el puerto equivocado**
- Establece `PORT=20128` y `NEXT_PUBLIC_BASE_URL=http://localhost:20128`
**Errores de cloud sync**
- Verifica que `BASE_URL` apunte a tu instancia en ejecución
- Verifica que `CLOUD_URL` apunte a tu endpoint cloud esperado
- Mantén los valores `NEXT_PUBLIC_*` alineados con los valores del servidor
**Primer login no funciona**
- Verifica `INITIAL_PASSWORD` en `.env`
- Si no está definido, la contraseña predeterminada es `123456`
**Sin logs de solicitud**
- Establece `ENABLE_REQUEST_LOGS=true` en `.env`
**Prueba de conexión muestra "Invalid" para proveedores compatibles con OpenAI**
- Muchos proveedores no exponen el endpoint `/models`
- OmniRoute v1.0.4+ incluye validación vía chat completions como fallback
- Asegúrate de que la URL base incluya el sufijo `/v1`
</details>
---
## 🛠️ Stack Tecnológico
- **Runtime**: Node.js 20+
- **Lenguaje**: TypeScript 5.9 — **100% TypeScript** en `src/` y `open-sse/` (v1.0.4)
- **Framework**: Next.js 16 + React 19 + Tailwind CSS 4
- **Base de Datos**: LowDB (JSON) + SQLite (estado del dominio + logs de proxy)
- **Streaming**: Server-Sent Events (SSE)
- **Auth**: OAuth 2.0 (PKCE) + JWT + API Keys
- **Testing**: Node.js test runner (368+ tests unitarios)
- **CI/CD**: GitHub Actions (publicación automática npm + Docker Hub en release)
- **Website**: [omniroute.online](https://omniroute.online)
- **Paquete**: [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute)
- **Docker**: [hub.docker.com/r/diegosouzapw/omniroute](https://hub.docker.com/r/diegosouzapw/omniroute)
- **Resiliencia**: Circuit breaker, backoff exponencial, anti-thundering herd, spoofing TLS
---
## 📖 Documentación
| Documento | Descripción |
| ------------------------------------------------ | -------------------------------------------------- |
| [Guía del Usuario](docs/USER_GUIDE.md) | Proveedores, combos, integración CLI, deploy |
| [Referencia de API](docs/API_REFERENCE.md) | Todos los endpoints con ejemplos |
| [Solución de Problemas](docs/TROUBLESHOOTING.md) | Problemas comunes y soluciones |
| [Arquitectura](docs/ARCHITECTURE.md) | Arquitectura del sistema e internos |
| [Contribuir](CONTRIBUTING.md) | Setup de desarrollo y directrices |
| [Spec OpenAPI](docs/openapi.yaml) | Especificación OpenAPI 3.0 |
| [Política de Seguridad](SECURITY.md) | Reportar vulnerabilidades y prácticas de seguridad |
---
## 📧 Soporte
> 💬 **¡Únete a la comunidad!** [Grupo WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obtén ayuda, comparte consejos y mantente al día.
- **Website**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Grupo de la Comunidad](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Proyecto Original**: [9router por decolua](https://github.com/decolua/9router)
---
## 👥 Contribuidores
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)
### Cómo Contribuir
1. Haz fork del repositorio
2. Crea tu rama de funcionalidad (`git checkout -b feature/amazing-feature`)
3. Haz commit de tus cambios (`git commit -m 'Add amazing feature'`)
4. Haz push a la rama (`git push origin feature/amazing-feature`)
5. Abre un Pull Request
Consulta [CONTRIBUTING.md](CONTRIBUTING.md) para directrices detalladas.
### Lanzar una Nueva Versión
```bash
# Crea un release — la publicación en npm ocurre automáticamente
gh release create v1.0.4 --title "v1.0.4" --generate-notes
```
---
## 📊 Historial de Stars
<a href="https://star-history.com/#diegosouzapw/OmniRoute&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
</picture>
</a>
---
## 🙏 Agradecimientos
Agradecimiento especial a **[9router](https://github.com/decolua/9router)** por **[decolua](https://github.com/decolua)** — el proyecto original que inspiró este fork. OmniRoute se construye sobre esa increíble base con características adicionales, APIs multi-modal y una reescritura completa en TypeScript.
Agradecimiento especial a **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** — la implementación original en Go que inspiró esta adaptación a JavaScript.
---
## 📄 Licencia
Licencia MIT - consulta [LICENSE](LICENSE) para detalles.
---
<div align="center">
<sub>Hecho con ❤️ para desarrolladores que programan 24/7</sub>
<br/>
<sub><a href="https://omniroute.online">omniroute.online</a></sub>
</div>

View File

@@ -1,999 +0,0 @@
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
# 🚀 OmniRoute — La Passerelle IA Gratuite
### N'arrêtez jamais de coder. Routage intelligent vers des **modèles IA GRATUITS et économiques** avec fallback automatique.
_Votre proxy API universel — un endpoint, 36+ fournisseurs, zéro temps d'arrêt._
**Chat Completions • Embeddings • Génération d'images • Audio • Reranking • 100% TypeScript**
---
### 🤖 Fournisseur IA gratuit pour vos agents de programmation préférés
_Connectez n'importe quel IDE ou outil CLI alimenté par l'IA via OmniRoute — passerelle API gratuite pour un codage illimité._
<table>
<tr>
<td align="center" width="110">
<a href="https://github.com/cline/cline">
<img src="./public/providers/openclaw.png" alt="OpenClaw" width="48"/><br/>
<b>OpenClaw</b>
</a><br/>
<sub>⭐ 205K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/HKUDS/nanobot">
<img src="./public/providers/nanobot.png" alt="NanoBot" width="48"/><br/>
<b>NanoBot</b>
</a><br/>
<sub>⭐ 20.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/sipeed/picoclaw">
<img src="./public/providers/picoclaw.jpg" alt="PicoClaw" width="48"/><br/>
<b>PicoClaw</b>
</a><br/>
<sub>⭐ 14.6K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/zeroclaw-labs/zeroclaw">
<img src="./public/providers/zeroclaw.png" alt="ZeroClaw" width="48"/><br/>
<b>ZeroClaw</b>
</a><br/>
<sub>⭐ 9.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/nearai/ironclaw">
<img src="./public/providers/ironclaw.png" alt="IronClaw" width="48"/><br/>
<b>IronClaw</b>
</a><br/>
<sub>⭐ 2.1K</sub>
</td>
</tr>
<tr>
<td align="center" width="110">
<a href="https://github.com/anomalyco/opencode">
<img src="./public/providers/opencode.svg" alt="OpenCode" width="48"/><br/>
<b>OpenCode</b>
</a><br/>
<sub>⭐ 106K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/openai/codex">
<img src="./public/providers/codex.png" alt="Codex CLI" width="48"/><br/>
<b>Codex CLI</b>
</a><br/>
<sub>⭐ 60.8K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/anthropics/claude-code">
<img src="./public/providers/claude.png" alt="Claude Code" width="48"/><br/>
<b>Claude Code</b>
</a><br/>
<sub>⭐ 67.3K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/google-gemini/gemini-cli">
<img src="./public/providers/gemini-cli.png" alt="Gemini CLI" width="48"/><br/>
<b>Gemini CLI</b>
</a><br/>
<sub>⭐ 94.7K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/Kilo-Org/kilocode">
<img src="./public/providers/kilocode.png" alt="Kilo Code" width="48"/><br/>
<b>Kilo Code</b>
</a><br/>
<sub>⭐ 15.5K</sub>
</td>
</tr>
</table>
<sub>📡 Tous les agents se connectent via <code>http://localhost:20128/v1</code> ou <code>http://cloud.omniroute.online/v1</code> — une configuration, modèles et quota illimités</sub>
---
[![npm version](https://img.shields.io/npm/v/omniroute?color=cb3837&logo=npm)](https://www.npmjs.com/package/omniroute)
[![Docker Hub](https://img.shields.io/docker/v/diegosouzapw/omniroute?label=Docker%20Hub&logo=docker&color=2496ED)](https://hub.docker.com/r/diegosouzapw/omniroute)
[![License](https://img.shields.io/github/license/diegosouzapw/OmniRoute)](https://github.com/diegosouzapw/OmniRoute/blob/main/LICENSE)
[![Website](https://img.shields.io/badge/Website-omniroute.online-blue?logo=google-chrome&logoColor=white)](https://omniroute.online)
[![WhatsApp](https://img.shields.io/badge/WhatsApp-Community-25D366?logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
[🌐 Site web](https://omniroute.online) • [🚀 Démarrage rapide](#-démarrage-rapide) • [💡 Fonctionnalités](#-fonctionnalités-principales) • [📖 Docs](#-documentation) • [💰 Tarifs](#-aperçu-des-tarifs)
🌐 **Disponible en :** [English](README.md) | [Português](README.pt-BR.md) | [Español](README.es.md) | [Русский](README.ru.md) | [中文](README.zh-CN.md) | [Deutsch](README.de.md) | [Français](README.fr.md) | [Italiano](README.it.md)
</div>
---
## 🤔 Pourquoi OmniRoute ?
**Arrêtez de gaspiller de l'argent et de vous heurter aux limites :**
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Le quota d'abonnement expire inutilisé chaque mois
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Les limites de débit vous arrêtent en plein codage
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> APIs coûteuses (20-50 $/mois par fournisseur)
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Changement manuel entre fournisseurs
**OmniRoute résout ces problèmes :**
-**Maximisez les abonnements** — Suivez les quotas, utilisez chaque bit avant la réinitialisation
-**Fallback automatique** — Abonnement → Clé API → Économique → Gratuit, zéro temps d'arrêt
-**Multi-comptes** — Round-robin entre les comptes par fournisseur
-**Universel** — Fonctionne avec Claude Code, Codex, Gemini CLI, Cursor, Cline, OpenClaw, tout outil CLI
---
## 🔄 Comment ça fonctionne
```
┌─────────────┐
│ Votre CLI │ (Claude Code, Codex, Gemini CLI, OpenClaw, Cursor, Cline...)
│ Tool │
└──────┬──────┘
│ http://localhost:20128/v1
┌─────────────────────────────────────────┐
│ OmniRoute (Routeur intelligent) │
│ • Traduction de format (OpenAI ↔ Claude) │
│ • Suivi des quotas + Embeddings + Images │
│ • Renouvellement automatique des tokens │
└──────┬──────────────────────────────────┘
├─→ [Tier 1: ABONNEMENT] Claude Code, Codex, Gemini CLI
│ ↓ quota épuisé
├─→ [Tier 2: CLÉ API] DeepSeek, Groq, xAI, Mistral, NVIDIA NIM, etc.
│ ↓ limite de budget
├─→ [Tier 3: ÉCONOMIQUE] GLM ($0.6/1M), MiniMax ($0.2/1M)
│ ↓ limite de budget
└─→ [Tier 4: GRATUIT] iFlow, Qwen, Kiro (illimité)
Résultat : Ne jamais arrêter de coder, coût minimal
```
---
## ⚡ Démarrage rapide
**1. Installer globalement :**
```bash
npm install -g omniroute
omniroute
```
🎉 Le tableau de bord s'ouvre sur `http://localhost:20128`
| Commande | Description |
| ----------------------- | ------------------------------------------- |
| `omniroute` | Démarrer le serveur (port par défaut 20128) |
| `omniroute --port 3000` | Utiliser un port personnalisé |
| `omniroute --no-open` | Ne pas ouvrir le navigateur automatiquement |
| `omniroute --help` | Afficher l'aide |
**2. Connecter un fournisseur GRATUIT :**
Tableau de bord → Fournisseurs → Connecter **Claude Code** ou **Antigravity** → Connexion OAuth → Terminé !
**3. Utiliser dans votre outil CLI :**
```
Claude Code/Codex/Gemini CLI/OpenClaw/Cursor/Cline Paramètres :
Endpoint : http://localhost:20128/v1
API Key : [copier depuis le tableau de bord]
Model : if/kimi-k2-thinking
```
**C'est tout !** Commencez à coder avec des modèles IA GRATUITS.
**Alternative — exécuter depuis le code source :**
```bash
cp .env.example .env
npm install
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
---
## 🐳 Docker
OmniRoute est disponible en tant qu'image Docker publique sur [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute).
**Démarrage rapide :**
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**Avec fichier d'environnement :**
```bash
# Copier et modifier le .env d'abord
cp .env.example .env
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file .env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**Avec Docker Compose :**
```bash
# Profil de base (sans outils CLI)
docker compose --profile base up -d
# Profil CLI (Claude Code, Codex, OpenClaw intégrés)
docker compose --profile cli up -d
```
| Image | Tag | Taille | Description |
| ------------------------ | -------- | ------ | ----------------------- |
| `diegosouzapw/omniroute` | `latest` | ~250MB | Dernière version stable |
| `diegosouzapw/omniroute` | `1.0.4` | ~250MB | Version actuelle |
---
## 💰 Aperçu des tarifs
| Tier | Fournisseur | Coût | Réinitialisation | Idéal pour |
| ----------------- | ----------------- | -------------------------- | ------------------- | ----------------------------- |
| **💳 ABONNEMENT** | Claude Code (Pro) | 20 $/mois | 5h + hebdomadaire | Déjà abonné |
| | Codex (Plus/Pro) | 20-200 $/mois | 5h + hebdomadaire | Utilisateurs OpenAI |
| | Gemini CLI | **GRATUIT** | 180K/mois + 1K/jour | Tout le monde ! |
| | GitHub Copilot | 10-19 $/mois | Mensuel | Utilisateurs GitHub |
| **🔑 CLÉ API** | NVIDIA NIM | **GRATUIT** (1000 crédits) | Unique | Tests gratuits |
| | DeepSeek | À l'usage | Aucune | Meilleur rapport qualité-prix |
| | Groq | Niveau gratuit + payant | Limité | Inférence ultra-rapide |
| | xAI (Grok) | À l'usage | Aucune | Modèles Grok |
| | Mistral | Niveau gratuit + payant | Limité | IA européenne |
| | OpenRouter | À l'usage | Aucune | 100+ modèles |
| **💰 ÉCONOMIQUE** | GLM-4.7 | 0,6 $/1M | Quotidien 10h | Backup économique |
| | MiniMax M2.1 | 0,2 $/1M | Rotatif 5h | Option la moins chère |
| | Kimi K2 | 9 $/mois fixe | 10M tokens/mois | Coût prévisible |
| **🆓 GRATUIT** | iFlow | 0 $ | Illimité | 8 modèles gratuits |
| | Qwen | 0 $ | Illimité | 3 modèles gratuits |
| | Kiro | 0 $ | Illimité | Claude gratuit |
**💡 Conseil Pro :** Commencez avec Gemini CLI (180K gratuits/mois) + iFlow (illimité gratuit) = 0 $ de coût !
---
## 🎯 Cas d'utilisation
### Cas 1 : « J'ai un abonnement Claude Pro »
**Problème :** Le quota expire inutilisé, limites de débit pendant le codage intensif
```
Combo : "maximize-claude"
1. cc/claude-opus-4-6 (utiliser l'abonnement au maximum)
2. glm/glm-4.7 (backup économique quand le quota est épuisé)
3. if/kimi-k2-thinking (fallback d'urgence gratuit)
Coût mensuel : 20 $ (abonnement) + ~5 $ (backup) = 25 $ au total
vs. 20 $ + atteindre les limites = frustration
```
### Cas 2 : « Je veux zéro coût »
**Problème :** Impossible de payer des abonnements, besoin d'IA fiable pour coder
```
Combo : "free-forever"
1. gc/gemini-3-flash (180K gratuits/mois)
2. if/kimi-k2-thinking (illimité gratuit)
3. qw/qwen3-coder-plus (illimité gratuit)
Coût mensuel : 0 $
Qualité : Modèles prêts pour la production
```
### Cas 3 : « Je dois coder 24/7, sans interruption »
**Problème :** Délais serrés, ne peut pas se permettre de temps d'arrêt
```
Combo : "always-on"
1. cc/claude-opus-4-6 (meilleure qualité)
2. cx/gpt-5.2-codex (deuxième abonnement)
3. glm/glm-4.7 (économique, reset quotidien)
4. minimax/MiniMax-M2.1 (le moins cher, reset 5h)
5. if/kimi-k2-thinking (gratuit illimité)
Résultat : 5 niveaux de fallback = zéro temps d'arrêt
```
### Cas 4 : « Je veux l'IA GRATUITE dans OpenClaw »
**Problème :** Besoin d'assistant IA dans les apps de messagerie, entièrement gratuit
```
Combo : "openclaw-free"
1. if/glm-4.7 (illimité gratuit)
2. if/minimax-m2.1 (illimité gratuit)
3. if/kimi-k2-thinking (illimité gratuit)
Coût mensuel : 0 $
Accès via : WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 💡 Fonctionnalités principales
### 🧠 Routage & Intelligence
| Fonctionnalité | Ce qu'elle fait |
| ------------------------------------- | ------------------------------------------------------------------------------- |
| 🎯 **Fallback intelligent 4 niveaux** | Auto-routage : Abonnement → Clé API → Économique → Gratuit |
| 📊 **Suivi des quotas en temps réel** | Comptage de tokens en direct + compte à rebours de réinitialisation |
| 🔄 **Traduction de format** | OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro transparent |
| 👥 **Support multi-comptes** | Plusieurs comptes par fournisseur avec sélection intelligente |
| 🔄 **Renouvellement auto des tokens** | Les tokens OAuth se renouvellent automatiquement avec retry |
| 🎨 **Combos personnalisés** | 6 stratégies : fill-first, round-robin, p2c, random, least-used, cost-optimized |
| 🧩 **Modèles personnalisés** | Ajoutez n'importe quel ID de modèle à n'importe quel fournisseur |
| 🌐 **Routeur wildcard** | Routez les patterns `provider/*` vers n'importe quel fournisseur dynamiquement |
| 🧠 **Budget de raisonnement** | Modes passthrough, auto, custom et adaptive pour les modèles de raisonnement |
| 💬 **Injection System Prompt** | System prompt global appliqué à toutes les requêtes |
| 📄 **API Responses** | Support complet de l'API Responses d'OpenAI (`/v1/responses`) pour Codex |
### 🎵 APIs multi-modales
| Fonctionnalité | Ce qu'elle fait |
| -------------------------- | ------------------------------------------------------- |
| 🖼️ **Génération d'images** | `/v1/images/generations` — 4 fournisseurs, 9+ modèles |
| 📐 **Embeddings** | `/v1/embeddings` — 6 fournisseurs, 9+ modèles |
| 🎤 **Transcription audio** | `/v1/audio/transcriptions` — compatible Whisper |
| 🔊 **Texte vers parole** | `/v1/audio/speech` — synthèse audio multi-fournisseur |
| 🛡️ **Modérations** | `/v1/moderations` — vérifications de sécurité |
| 🔀 **Reranking** | `/v1/rerank` — reclassement de pertinence des documents |
### 🛡️ Résilience & Sécurité
| Fonctionnalité | Ce qu'elle fait |
| ------------------------------- | -------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Ouverture/fermeture auto par fournisseur avec seuils configurables |
| 🛡️ **Anti-Thundering Herd** | Mutex + sémaphore de rate-limit pour les fournisseurs avec clé API |
| 🧠 **Cache sémantique** | Cache à deux niveaux (signature + sémantique) réduit coût et latence |
| ⚡ **Idempotence des requêtes** | Fenêtre de dédup 5s pour les requêtes dupliquées |
| 🔒 **Spoofing TLS Fingerprint** | Contournement de détection de bot via wreq-js |
| 🌐 **Filtrage IP** | Allowlist/blocklist pour le contrôle d'accès API |
| 📊 **Rate limits éditables** | RPM configurable, intervalle minimum, concurrence max |
### 📊 Observabilité & Analytique
| Fonctionnalité | Ce qu'elle fait |
| --------------------------------- | ------------------------------------------------------------------------- |
| 📝 **Logs de requêtes** | Mode debug avec logs complets requête/réponse |
| 💾 **Logs SQLite** | Logs proxy persistants survivant aux redémarrages |
| 📊 **Tableau de bord analytique** | Recharts : cartes de stats, graphique d'utilisation, tableau fournisseurs |
| 📈 **Suivi de progression** | Événements SSE de progression opt-in pour le streaming |
| 🧪 **Évaluations LLM** | Tests avec golden set et 4 stratégies de correspondance |
| 🔍 **Télémétrie des requêtes** | Agrégation de latence p50/p95/p99 + traçage X-Request-Id |
| 📋 **Logs + Quotas** | Pages dédiées pour navigation des logs et suivi des quotas |
| 🏥 **Tableau de bord santé** | Uptime, états circuit breaker, lockouts, stats cache |
| 💰 **Suivi des coûts** | Gestion de budget + configuration des prix par modèle |
### ☁️ Déploiement & Synchronisation
| Fonctionnalité | Ce qu'elle fait |
| --------------------------------- | ------------------------------------------------------------------------------- |
| 💾 **Cloud Sync** | Synchroniser les paramètres entre appareils via Cloudflare Workers |
| 🌐 **Déployer partout** | Localhost, VPS, Docker, Cloudflare Workers |
| 🔑 **Gestion des clés API** | Générer, faire tourner et limiter les clés API par fournisseur |
| 🧙 **Assistant de configuration** | Setup guidé en 4 étapes pour les nouveaux utilisateurs |
| 🔧 **Tableau de bord CLI Tools** | Configuration en un clic pour Claude, Codex, Cline, OpenClaw, Kilo, Antigravity |
| 🔄 **Sauvegardes DB** | Sauvegarde et restauration automatiques de tous les paramètres |
<details>
<summary><b>📖 Détails des fonctionnalités</b></summary>
### 🎯 Fallback intelligent 4 niveaux
Créez des combos avec fallback automatique :
```
Combo : "my-coding-stack"
1. cc/claude-opus-4-6 (votre abonnement)
2. nvidia/llama-3.3-70b (API NVIDIA gratuite)
3. glm/glm-4.7 (backup économique, $0.6/1M)
4. if/kimi-k2-thinking (fallback gratuit)
→ Bascule automatiquement lorsque le quota est épuisé ou en cas d'erreurs
```
### 📊 Suivi des quotas en temps réel
- Consommation de tokens par fournisseur
- Compte à rebours de réinitialisation (5 heures, quotidien, hebdomadaire)
- Estimation des coûts pour les niveaux payants
- Rapports de dépenses mensuels
### 🔄 Traduction de format
Traduction transparente entre les formats :
- **OpenAI** ↔ **Claude****Gemini****OpenAI Responses**
- Votre CLI envoie le format OpenAI → OmniRoute traduit → Le fournisseur reçoit le format natif
- Fonctionne avec tout outil supportant les endpoints OpenAI personnalisés
### 👥 Support multi-comptes
- Ajouter plusieurs comptes par fournisseur
- Round-robin automatique ou routage par priorité
- Basculement vers le compte suivant lorsqu'un quota est atteint
### 🔄 Renouvellement automatique des tokens
- Les tokens OAuth se renouvellent automatiquement avant expiration
- Pas de réauthentification manuelle nécessaire
- Expérience transparente sur tous les fournisseurs
### 🎨 Combos personnalisés
- Créer des combinaisons de modèles illimitées
- 6 stratégies : fill-first, round-robin, power-of-two-choices, random, least-used, cost-optimized
- Partager les combos entre appareils avec Cloud Sync
### 🏥 Tableau de bord santé
- Statut du système (uptime, version, utilisation mémoire)
- États des circuit breakers par fournisseur (Closed/Open/Half-Open)
- Statut des rate limits et lockouts actifs
- Statistiques du cache de signatures
- Télémétrie de latence (p50/p95/p99) + cache de prompt
- Réinitialisation de la santé en un clic
### 🔧 Playground du traducteur
- Déboguer, tester et visualiser les traductions de format d'API
- Envoyer des requêtes et voir comment OmniRoute traduit entre les formats des fournisseurs
- Inestimable pour résoudre les problèmes d'intégration
### 💾 Cloud Sync
- Synchroniser fournisseurs, combos et paramètres entre appareils
- Synchronisation en arrière-plan automatique
- Stockage chiffré sécurisé
</details>
---
## 📖 Guide de configuration
<details>
<summary><b>💳 Fournisseurs par abonnement</b></summary>
### Claude Code (Pro/Max)
```bash
Tableau de bord → Fournisseurs → Connecter Claude Code
→ Connexion OAuth → Renouvellement auto des tokens
→ Suivi de quota 5h + hebdomadaire
Modèles :
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Conseil Pro :** Utilisez Opus pour les tâches complexes, Sonnet pour la vitesse. OmniRoute suit les quotas par modèle !
### OpenAI Codex (Plus/Pro)
```bash
Tableau de bord → Fournisseurs → Connecter Codex
→ Connexion OAuth (port 1455)
→ Reset 5h + hebdomadaire
Modèles :
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
### Gemini CLI (GRATUIT 180K/mois !)
```bash
Tableau de bord → Fournisseurs → Connecter Gemini CLI
→ Google OAuth
→ 180K completions/mois + 1K/jour
Modèles :
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Meilleure valeur :** Niveau gratuit énorme ! Utilisez avant les niveaux payants.
### GitHub Copilot
```bash
Tableau de bord → Fournisseurs → Connecter GitHub
→ OAuth via GitHub
→ Reset mensuel (1er du mois)
Modèles :
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
</details>
<details>
<summary><b>🔑 Fournisseurs par clé API</b></summary>
### NVIDIA NIM (GRATUIT 1000 crédits !)
1. S'inscrire : [build.nvidia.com](https://build.nvidia.com)
2. Obtenir une clé API gratuite (1000 crédits d'inférence inclus)
3. Tableau de bord → Ajouter fournisseur → NVIDIA NIM :
- API Key : `nvapi-your-key`
**Modèles :** `nvidia/llama-3.3-70b-instruct`, `nvidia/mistral-7b-instruct` et 50+ autres
**Conseil Pro :** API compatible OpenAI — fonctionne parfaitement avec la traduction de format d'OmniRoute !
### DeepSeek
1. S'inscrire : [platform.deepseek.com](https://platform.deepseek.com)
2. Obtenir une clé API
3. Tableau de bord → Ajouter fournisseur → DeepSeek
**Modèles :** `deepseek/deepseek-chat`, `deepseek/deepseek-coder`
### Groq (Niveau gratuit disponible !)
1. S'inscrire : [console.groq.com](https://console.groq.com)
2. Obtenir une clé API (niveau gratuit inclus)
3. Tableau de bord → Ajouter fournisseur → Groq
**Modèles :** `groq/llama-3.3-70b`, `groq/mixtral-8x7b`
**Conseil Pro :** Inférence ultra-rapide — idéal pour le codage en temps réel !
### OpenRouter (100+ modèles)
1. S'inscrire : [openrouter.ai](https://openrouter.ai)
2. Obtenir une clé API
3. Tableau de bord → Ajouter fournisseur → OpenRouter
**Modèles :** Accès à 100+ modèles de tous les grands fournisseurs via une seule clé API.
</details>
<details>
<summary><b>💰 Fournisseurs économiques (Backup)</b></summary>
### GLM-4.7 (Reset quotidien, $0.6/1M)
1. S'inscrire : [Zhipu AI](https://open.bigmodel.cn/)
2. Obtenir une clé API du Coding Plan
3. Tableau de bord → Ajouter clé API :
- Fournisseur : `glm`
- API Key : `your-key`
**Utilisez :** `glm/glm-4.7`
**Conseil Pro :** Le Coding Plan offre 3× le quota à 1/7 du coût ! Reset quotidien à 10h.
### MiniMax M2.1 (Reset 5h, $0.20/1M)
1. S'inscrire : [MiniMax](https://www.minimax.io/)
2. Obtenir une clé API
3. Tableau de bord → Ajouter clé API
**Utilisez :** `minimax/MiniMax-M2.1`
**Conseil Pro :** L'option la moins chère pour le contexte long (1M tokens) !
### Kimi K2 (9 $/mois fixe)
1. S'abonner : [Moonshot AI](https://platform.moonshot.ai/)
2. Obtenir une clé API
3. Tableau de bord → Ajouter clé API
**Utilisez :** `kimi/kimi-latest`
**Conseil Pro :** 9 $/mois fixe pour 10M tokens = 0,90 $/1M de coût effectif !
</details>
<details>
<summary><b>🆓 Fournisseurs GRATUITS (Backup d'urgence)</b></summary>
### iFlow (8 modèles GRATUITS)
```bash
Tableau de bord → Connecter iFlow
→ Connexion OAuth iFlow
→ Utilisation illimitée
Modèles :
if/kimi-k2-thinking
if/qwen3-coder-plus
if/glm-4.7
if/minimax-m2
if/deepseek-r1
```
### Qwen (3 modèles GRATUITS)
```bash
Tableau de bord → Connecter Qwen
→ Autorisation par code d'appareil
→ Utilisation illimitée
Modèles :
qw/qwen3-coder-plus
qw/qwen3-coder-flash
```
### Kiro (Claude GRATUIT)
```bash
Tableau de bord → Connecter Kiro
→ AWS Builder ID ou Google/GitHub
→ Utilisation illimitée
Modèles :
kr/claude-sonnet-4.5
kr/claude-haiku-4.5
```
</details>
<details>
<summary><b>🎨 Créer des combos</b></summary>
### Exemple 1 : Maximiser l'abonnement → Backup économique
```
Tableau de bord → Combos → Créer nouveau
Nom : premium-coding
Modèles :
1. cc/claude-opus-4-6 (Abonnement principal)
2. glm/glm-4.7 (Backup économique, $0.6/1M)
3. minimax/MiniMax-M2.1 (Fallback le moins cher, $0.20/1M)
Utilisez en CLI : premium-coding
```
### Exemple 2 : Gratuit uniquement (Zéro coût)
```
Nom : free-combo
Modèles :
1. gc/gemini-3-flash-preview (180K gratuits/mois)
2. if/kimi-k2-thinking (illimité)
3. qw/qwen3-coder-plus (illimité)
Coût : 0 $ pour toujours !
```
</details>
<details>
<summary><b>🔧 Intégration CLI</b></summary>
### Cursor IDE
```
Paramètres → Modèles → Avancé :
OpenAI API Base URL : http://localhost:20128/v1
OpenAI API Key : [du tableau de bord OmniRoute]
Model : cc/claude-opus-4-6
```
### Claude Code
Utilisez la page **CLI Tools** dans le tableau de bord pour la configuration en un clic, ou modifiez `~/.claude/settings.json` manuellement.
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
**Option 1 — Tableau de bord (recommandé) :**
```
Tableau de bord → CLI Tools → OpenClaw → Sélectionner modèle → Appliquer
```
**Option 2 — Manuel :** Modifier `~/.openclaw/openclaw.json` :
```json
{
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://127.0.0.1:20128/v1",
"apiKey": "sk_omniroute",
"api": "openai-completions"
}
}
}
}
```
> **Note :** OpenClaw fonctionne uniquement avec OmniRoute local. Utilisez `127.0.0.1` au lieu de `localhost` pour éviter les problèmes de résolution IPv6.
### Cline / Continue / RooCode
```
Paramètres → Configuration API :
Fournisseur : OpenAI Compatible
Base URL : http://localhost:20128/v1
API Key : [du tableau de bord OmniRoute]
Model : if/kimi-k2-thinking
```
</details>
---
## 📊 Modèles disponibles
<details>
<summary><b>Voir tous les modèles disponibles</b></summary>
**Claude Code (`cc/`)** - Pro/Max :
- `cc/claude-opus-4-6`
- `cc/claude-sonnet-4-5-20250929`
- `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** - Plus/Pro :
- `cx/gpt-5.2-codex`
- `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** - GRATUIT :
- `gc/gemini-3-flash-preview`
- `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)** :
- `gh/gpt-5`
- `gh/claude-4.5-sonnet`
**NVIDIA NIM (`nvidia/`)** - Crédits GRATUITS :
- `nvidia/llama-3.3-70b-instruct`
- `nvidia/mistral-7b-instruct`
- 50+ modèles sur [build.nvidia.com](https://build.nvidia.com)
**GLM (`glm/`)** - $0.6/1M :
- `glm/glm-4.7`
**MiniMax (`minimax/`)** - $0.2/1M :
- `minimax/MiniMax-M2.1`
**iFlow (`if/`)** - GRATUIT :
- `if/kimi-k2-thinking`
- `if/qwen3-coder-plus`
- `if/deepseek-r1`
- `if/glm-4.7`
- `if/minimax-m2`
**Qwen (`qw/`)** - GRATUIT :
- `qw/qwen3-coder-plus`
- `qw/qwen3-coder-flash`
**Kiro (`kr/`)** - GRATUIT :
- `kr/claude-sonnet-4.5`
- `kr/claude-haiku-4.5`
**OpenRouter (`or/`)** - 100+ modèles :
- `or/anthropic/claude-4-sonnet`
- `or/google/gemini-2.5-pro`
- Tout modèle de [openrouter.ai/models](https://openrouter.ai/models)
</details>
---
## 🧪 Évaluations (Evals)
OmniRoute inclut un framework d'évaluation intégré pour tester la qualité des réponses LLM contre un golden set. Accès via **Analytics → Evals** dans le tableau de bord.
### Golden Set intégré
Le « OmniRoute Golden Set » préchargé contient 10 cas de test :
- Salutations, mathématiques, géographie, génération de code
- Conformité format JSON, traduction, markdown
- Rejet de sécurité (contenu nocif), comptage, logique booléenne
### Stratégies d'évaluation
| Stratégie | Description | Exemple |
| ---------- | -------------------------------------------------------------- | -------------------------------- |
| `exact` | La sortie doit correspondre exactement | `"4"` |
| `contains` | La sortie doit contenir la sous-chaîne (insensible à la casse) | `"Paris"` |
| `regex` | La sortie doit correspondre au motif regex | `"1.*2.*3"` |
| `custom` | Fonction JS personnalisée retourne true/false | `(output) => output.length > 10` |
---
## 🐛 Dépannage
<details>
<summary><b>Cliquez pour développer le guide de dépannage</b></summary>
**« Language model did not provide messages »**
- Quota du fournisseur épuisé → Vérifiez le suivi de quota dans le tableau de bord
- Solution : Utilisez un combo avec fallback ou passez à un niveau moins cher
**Rate limiting**
- Quota d'abonnement épuisé → Fallback vers GLM/MiniMax
- Ajoutez un combo : `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
**Token OAuth expiré**
- Renouvelé automatiquement par OmniRoute
- Si le problème persiste : Tableau de bord → Fournisseur → Reconnecter
**Coûts élevés**
- Vérifiez les statistiques d'utilisation dans Tableau de bord → Coûts
- Changez le modèle principal pour GLM/MiniMax
- Utilisez le niveau gratuit (Gemini CLI, iFlow) pour les tâches non critiques
**Le tableau de bord s'ouvre sur le mauvais port**
- Définissez `PORT=20128` et `NEXT_PUBLIC_BASE_URL=http://localhost:20128`
**Erreurs de cloud sync**
- Vérifiez que `BASE_URL` pointe vers votre instance en cours d'exécution
- Vérifiez que `CLOUD_URL` pointe vers le point de terminaison cloud attendu
- Gardez les valeurs `NEXT_PUBLIC_*` alignées avec les valeurs du serveur
**Le premier login ne fonctionne pas**
- Vérifiez `INITIAL_PASSWORD` dans `.env`
- Si non défini, le mot de passe par défaut est `123456`
**Pas de logs de requêtes**
- Définissez `ENABLE_REQUEST_LOGS=true` dans `.env`
**Le test de connexion affiche « Invalid » pour les fournisseurs compatibles OpenAI**
- Beaucoup de fournisseurs n'exposent pas le point de terminaison `/models`
- OmniRoute v1.0.4+ inclut une validation de secours via chat completions
- Assurez-vous que l'URL de base inclut le suffixe `/v1`
</details>
---
## 🛠️ Stack technologique
- **Runtime** : Node.js 20+
- **Langage** : TypeScript 5.9 — **100% TypeScript** dans `src/` et `open-sse/` (v1.0.4)
- **Framework** : Next.js 16 + React 19 + Tailwind CSS 4
- **Base de données** : LowDB (JSON) + SQLite (état du domaine + logs proxy)
- **Streaming** : Server-Sent Events (SSE)
- **Auth** : OAuth 2.0 (PKCE) + JWT + API Keys
- **Tests** : Node.js test runner (368+ tests unitaires)
- **CI/CD** : GitHub Actions (publication automatique npm + Docker Hub lors du release)
- **Site web** : [omniroute.online](https://omniroute.online)
- **Package** : [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute)
- **Docker** : [hub.docker.com/r/diegosouzapw/omniroute](https://hub.docker.com/r/diegosouzapw/omniroute)
- **Résilience** : Circuit breaker, backoff exponentiel, anti-thundering herd, spoofing TLS
---
## 📖 Documentation
| Document | Description |
| ------------------------------------------ | --------------------------------------------------- |
| [Guide utilisateur](docs/USER_GUIDE.md) | Fournisseurs, combos, intégration CLI, déploiement |
| [Référence API](docs/API_REFERENCE.md) | Tous les endpoints avec exemples |
| [Dépannage](docs/TROUBLESHOOTING.md) | Problèmes courants et solutions |
| [Architecture](docs/ARCHITECTURE.md) | Architecture système et détails internes |
| [Contribuer](CONTRIBUTING.md) | Configuration de développement et directives |
| [Spécification OpenAPI](docs/openapi.yaml) | Spécification OpenAPI 3.0 |
| [Politique de sécurité](SECURITY.md) | Signalement de vulnérabilités et pratiques sécurité |
---
## 📧 Support
> 💬 **Rejoignez notre communauté !** [Groupe WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obtenez de l'aide, partagez des astuces et restez informé.
- **Site web** : [omniroute.online](https://omniroute.online)
- **GitHub** : [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Issues** : [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp** : [Groupe communautaire](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projet original** : [9router par decolua](https://github.com/decolua/9router)
---
## 👥 Contributeurs
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)
### Comment contribuer
1. Forkez le dépôt
2. Créez votre branche de fonctionnalité (`git checkout -b feature/amazing-feature`)
3. Committez vos changements (`git commit -m 'Add amazing feature'`)
4. Poussez vers la branche (`git push origin feature/amazing-feature`)
5. Ouvrez une Pull Request
Consultez [CONTRIBUTING.md](CONTRIBUTING.md) pour les directives détaillées.
### Publier une nouvelle version
```bash
# Créer un release — la publication npm est automatique
gh release create v1.0.4 --title "v1.0.4" --generate-notes
```
---
## 📊 Historique des Stars
<a href="https://star-history.com/#diegosouzapw/OmniRoute&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
</picture>
</a>
---
## 🙏 Remerciements
Remerciements spéciaux à **[9router](https://github.com/decolua/9router)** par **[decolua](https://github.com/decolua)** — le projet original qui a inspiré ce fork. OmniRoute construit sur cette base incroyable avec des fonctionnalités supplémentaires, des APIs multi-modales et une réécriture complète en TypeScript.
Remerciements spéciaux à **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** — l'implémentation originale en Go qui a inspiré ce portage en JavaScript.
---
## 📄 Licence
Licence MIT — voir [LICENSE](LICENSE) pour les détails.
---
<div align="center">
<sub>Fait avec ❤️ pour les développeurs qui codent 24/7</sub>
<br/>
<sub><a href="https://omniroute.online">omniroute.online</a></sub>
</div>

File diff suppressed because it is too large Load Diff

1699
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,999 +0,0 @@
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
# 🚀 OmniRoute — Бесплатный AI Gateway
### Никогда не прекращайте программировать. Умная маршрутизация к **БЕСПЛАТНЫМ и дешёвым AI-моделям** с автоматическим fallback.
_Ваш универсальный API-прокси — одна точка доступа, 36+ провайдеров, нулевой простой._
**Chat Completions • Embeddings • Генерация изображений • Аудио • Reranking • 100% TypeScript**
---
### 🤖 Бесплатный AI-провайдер для ваших любимых агентов программирования
_Подключайте любую IDE или CLI-инструмент с AI через OmniRoute — бесплатный API gateway для неограниченного программирования._
<table>
<tr>
<td align="center" width="110">
<a href="https://github.com/cline/cline">
<img src="./public/providers/openclaw.png" alt="OpenClaw" width="48"/><br/>
<b>OpenClaw</b>
</a><br/>
<sub>⭐ 205K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/HKUDS/nanobot">
<img src="./public/providers/nanobot.png" alt="NanoBot" width="48"/><br/>
<b>NanoBot</b>
</a><br/>
<sub>⭐ 20.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/sipeed/picoclaw">
<img src="./public/providers/picoclaw.jpg" alt="PicoClaw" width="48"/><br/>
<b>PicoClaw</b>
</a><br/>
<sub>⭐ 14.6K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/zeroclaw-labs/zeroclaw">
<img src="./public/providers/zeroclaw.png" alt="ZeroClaw" width="48"/><br/>
<b>ZeroClaw</b>
</a><br/>
<sub>⭐ 9.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/nearai/ironclaw">
<img src="./public/providers/ironclaw.png" alt="IronClaw" width="48"/><br/>
<b>IronClaw</b>
</a><br/>
<sub>⭐ 2.1K</sub>
</td>
</tr>
<tr>
<td align="center" width="110">
<a href="https://github.com/anomalyco/opencode">
<img src="./public/providers/opencode.svg" alt="OpenCode" width="48"/><br/>
<b>OpenCode</b>
</a><br/>
<sub>⭐ 106K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/openai/codex">
<img src="./public/providers/codex.png" alt="Codex CLI" width="48"/><br/>
<b>Codex CLI</b>
</a><br/>
<sub>⭐ 60.8K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/anthropics/claude-code">
<img src="./public/providers/claude.png" alt="Claude Code" width="48"/><br/>
<b>Claude Code</b>
</a><br/>
<sub>⭐ 67.3K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/google-gemini/gemini-cli">
<img src="./public/providers/gemini-cli.png" alt="Gemini CLI" width="48"/><br/>
<b>Gemini CLI</b>
</a><br/>
<sub>⭐ 94.7K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/Kilo-Org/kilocode">
<img src="./public/providers/kilocode.png" alt="Kilo Code" width="48"/><br/>
<b>Kilo Code</b>
</a><br/>
<sub>⭐ 15.5K</sub>
</td>
</tr>
</table>
<sub>📡 Все агенты подключаются через <code>http://localhost:20128/v1</code> или <code>http://cloud.omniroute.online/v1</code> — одна конфигурация, неограниченные модели и квота</sub>
---
[![npm version](https://img.shields.io/npm/v/omniroute?color=cb3837&logo=npm)](https://www.npmjs.com/package/omniroute)
[![Docker Hub](https://img.shields.io/docker/v/diegosouzapw/omniroute?label=Docker%20Hub&logo=docker&color=2496ED)](https://hub.docker.com/r/diegosouzapw/omniroute)
[![License](https://img.shields.io/github/license/diegosouzapw/OmniRoute)](https://github.com/diegosouzapw/OmniRoute/blob/main/LICENSE)
[![Website](https://img.shields.io/badge/Website-omniroute.online-blue?logo=google-chrome&logoColor=white)](https://omniroute.online)
[![WhatsApp](https://img.shields.io/badge/WhatsApp-Community-25D366?logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
[🌐 Сайт](https://omniroute.online) • [🚀 Быстрый старт](#-быстрый-старт) • [💡 Функции](#-основные-функции) • [📖 Документация](#-документация) • [💰 Цены](#-обзор-цен)
🌐 **Доступно на:** [English](README.md) | [Português](README.pt-BR.md) | [Español](README.es.md) | [Русский](README.ru.md) | [中文](README.zh-CN.md) | [Deutsch](README.de.md) | [Français](README.fr.md) | [Italiano](README.it.md)
</div>
---
## 🤔 Почему OmniRoute?
**Перестаньте тратить деньги и упираться в лимиты:**
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Квота подписки истекает неиспользованной каждый месяц
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Лимиты скорости останавливают вас посреди программирования
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Дорогие API ($20-50/месяц за провайдера)
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> Ручное переключение между провайдерами
**OmniRoute решает это:**
-**Максимизируйте подписки** — Отслеживайте квоты, используйте всё до сброса
-**Автоматический fallback** — Подписка → API Key → Дешёвый → Бесплатный, нулевой простой
-**Мульти-аккаунт** — Round-robin между аккаунтами каждого провайдера
-**Универсальный** — Работает с Claude Code, Codex, Gemini CLI, Cursor, Cline, OpenClaw, любым CLI-инструментом
---
## 🔄 Как это работает
```
┌─────────────┐
│ Ваш CLI │ (Claude Code, Codex, Gemini CLI, OpenClaw, Cursor, Cline...)
│ Tool │
└──────┬──────┘
│ http://localhost:20128/v1
┌─────────────────────────────────────────┐
│ OmniRoute (Умный маршрутизатор) │
│ • Трансляция формата (OpenAI ↔ Claude) │
│ • Отслеживание квот + Embeddings + Изображения │
│ • Автообновление токенов │
└──────┬──────────────────────────────────┘
├─→ [Tier 1: ПОДПИСКА] Claude Code, Codex, Gemini CLI
│ ↓ квота исчерпана
├─→ [Tier 2: API KEY] DeepSeek, Groq, xAI, Mistral, NVIDIA NIM и др.
│ ↓ лимит бюджета
├─→ [Tier 3: ДЕШЁВЫЙ] GLM ($0.6/1M), MiniMax ($0.2/1M)
│ ↓ лимит бюджета
└─→ [Tier 4: БЕСПЛАТНЫЙ] iFlow, Qwen, Kiro (неограниченно)
Результат: Никогда не прекращайте программировать, минимальные затраты
```
---
## ⚡ Быстрый старт
**1. Установите глобально:**
```bash
npm install -g omniroute
omniroute
```
🎉 Dashboard открывается на `http://localhost:20128`
| Команда | Описание |
| ----------------------- | ------------------------------------------ |
| `omniroute` | Запустить сервер (порт по умолчанию 20128) |
| `omniroute --port 3000` | Использовать другой порт |
| `omniroute --no-open` | Не открывать браузер автоматически |
| `omniroute --help` | Показать справку |
**2. Подключите БЕСПЛАТНОГО провайдера:**
Dashboard → Провайдеры → Подключить **Claude Code** или **Antigravity** → OAuth вход → Готово!
**3. Используйте в CLI-инструменте:**
```
Claude Code/Codex/Gemini CLI/OpenClaw/Cursor/Cline Настройки:
Endpoint: http://localhost:20128/v1
API Key: [скопируйте из dashboard]
Model: if/kimi-k2-thinking
```
**Готово!** Начните программировать с БЕСПЛАТНЫМИ AI-моделями.
**Альтернатива — запуск из исходного кода:**
```bash
cp .env.example .env
npm install
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
---
## 🐳 Docker
OmniRoute доступен как публичный Docker-образ на [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute).
**Быстрый запуск:**
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**С файлом окружения:**
```bash
# Скопируйте и отредактируйте .env
cp .env.example .env
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file .env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**Используя Docker Compose:**
```bash
# Базовый профиль (без CLI-инструментов)
docker compose --profile base up -d
# CLI-профиль (Claude Code, Codex, OpenClaw встроены)
docker compose --profile cli up -d
```
| Образ | Тег | Размер | Описание |
| ------------------------ | -------- | ------ | -------------------------- |
| `diegosouzapw/omniroute` | `latest` | ~250MB | Последний стабильный релиз |
| `diegosouzapw/omniroute` | `1.0.4` | ~250MB | Текущая версия |
---
## 💰 Обзор цен
| Tier | Провайдер | Стоимость | Сброс квоты | Лучше всего для |
| ----------------- | ----------------- | ----------------------------- | ------------------ | -------------------------------- |
| **💳 ПОДПИСКА** | Claude Code (Pro) | $20/мес | 5ч + еженедельно | Уже подписан |
| | Codex (Plus/Pro) | $20-200/мес | 5ч + еженедельно | Пользователи OpenAI |
| | Gemini CLI | **БЕСПЛАТНО** | 180K/мес + 1K/день | Все! |
| | GitHub Copilot | $10-19/мес | Ежемесячно | Пользователи GitHub |
| **🔑 API KEY** | NVIDIA NIM | **БЕСПЛАТНО** (1000 кредитов) | Одноразово | Бесплатное тестирование |
| | DeepSeek | По использованию | Нет | Лучшее соотношение цена/качество |
| | Groq | Беспл. уровень + платный | Ограничено | Сверхбыстрый вывод |
| | xAI (Grok) | По использованию | Нет | Модели Grok |
| | Mistral | Беспл. уровень + платный | Ограничено | Европейский AI |
| | OpenRouter | По использованию | Нет | 100+ моделей |
| **💰 ДЕШЁВЫЙ** | GLM-4.7 | $0.6/1M | Ежедневно 10ч | Бюджетный бэкап |
| | MiniMax M2.1 | $0.2/1M | 5ч ротация | Самый дешёвый вариант |
| | Kimi K2 | $9/мес фикс | 10M токенов/мес | Предсказуемая цена |
| **🆓 БЕСПЛАТНЫЙ** | iFlow | $0 | Неограниченно | 8 бесплатных моделей |
| | Qwen | $0 | Неограниченно | 3 бесплатные модели |
| | Kiro | $0 | Неограниченно | Claude бесплатно |
**💡 Совет:** Начните с Gemini CLI (180K бесплатно/мес) + iFlow (неограниченно бесплатно) = $0!
---
## 🎯 Сценарии использования
### Сценарий 1: «У меня подписка Claude Pro»
**Проблема:** Квота истекает неиспользованной, лимиты скорости во время интенсивного программирования
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (используйте подписку полностью)
2. glm/glm-4.7 (дешёвый бэкап при исчерпании квоты)
3. if/kimi-k2-thinking (бесплатный аварийный fallback)
Месячная стоимость: $20 (подписка) + ~$5 (бэкап) = $25 итого
vs. $20 + упирание в лимиты = разочарование
```
### Сценарий 2: «Хочу нулевую стоимость»
**Проблема:** Не может позволить подписки, нужен надёжный AI для программирования
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K бесплатно/мес)
2. if/kimi-k2-thinking (неограниченно бесплатно)
3. qw/qwen3-coder-plus (неограниченно бесплатно)
Месячная стоимость: $0
Качество: Модели готовые к продакшену
```
### Сценарий 3: «Мне нужно программировать 24/7, без перерывов»
**Проблема:** Дедлайны, не может позволить простой
```
Combo: "always-on"
1. cc/claude-opus-4-6 (лучшее качество)
2. cx/gpt-5.2-codex (вторая подписка)
3. glm/glm-4.7 (дешёвый, ежедневный сброс)
4. minimax/MiniMax-M2.1 (самый дешёвый, сброс 5ч)
5. if/kimi-k2-thinking (бесплатно неограниченно)
Результат: 5 уровней fallback = нулевой простой
```
### Сценарий 4: «Хочу БЕСПЛАТНЫЙ AI в OpenClaw»
**Проблема:** Нужен AI-ассистент в мессенджерах, полностью бесплатно
```
Combo: "openclaw-free"
1. if/glm-4.7 (неограниченно бесплатно)
2. if/minimax-m2.1 (неограниченно бесплатно)
3. if/kimi-k2-thinking (неограниченно бесплатно)
Месячная стоимость: $0
Доступ через: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 💡 Основные функции
### 🧠 Маршрутизация и интеллект
| Функция | Что делает |
| ------------------------------------------- | ----------------------------------------------------------------------------- |
| 🎯 **Умный 4-уровневый Fallback** | Авто-маршрутизация: Подписка → API Key → Дешёвый → Бесплатный |
| 📊 **Отслеживание квот в реальном времени** | Счётчик токенов в реальном времени + обратный отсчёт до сброса |
| 🔄 **Трансляция формата** | OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro бесшовно |
| 👥 **Мульти-аккаунт** | Несколько аккаунтов на провайдера с интеллектуальным выбором |
| 🔄 **Автообновление токенов** | OAuth-токены обновляются автоматически с повторами |
| 🎨 **Пользовательские комбо** | 6 стратегий: fill-first, round-robin, p2c, random, least-used, cost-optimized |
| 🧩 **Пользовательские модели** | Добавьте любой ID модели к любому провайдеру |
| 🌐 **Wildcard-маршрутизатор** | Маршрутизируйте паттерны `provider/*` к любому провайдеру динамически |
| 🧠 **Бюджет рассуждений** | Режимы passthrough, auto, custom и adaptive для моделей рассуждений |
| 💬 **Инъекция System Prompt** | Глобальный system prompt для всех запросов |
| 📄 **API Responses** | Полная поддержка OpenAI Responses API (`/v1/responses`) для Codex |
### 🎵 Мультимодальные API
| Функция | Что делает |
| ---------------------------- | --------------------------------------------------- |
| 🖼️ **Генерация изображений** | `/v1/images/generations` — 4 провайдера, 9+ моделей |
| 📐 **Embeddings** | `/v1/embeddings` — 6 провайдеров, 9+ моделей |
| 🎤 **Транскрипция аудио** | `/v1/audio/transcriptions` — Совместимо с Whisper |
| 🔊 **Текст в речь** | `/v1/audio/speech` — Мульти-провайдерный синтез |
| 🛡️ **Модерация** | `/v1/moderations` — Проверки безопасности контента |
| 🔀 **Reranking** | `/v1/rerank` — Переранжирование релевантности |
### 🛡️ Устойчивость и безопасность
| Функция | Что делает |
| -------------------------------- | -------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Авто-открытие/закрытие по провайдеру с настраиваемыми порогами |
| 🛡️ **Anti-Thundering Herd** | Mutex + семафор для API key провайдеров |
| 🧠 **Семантический кеш** | Двухуровневый кеш (сигнатура + семантика) снижает стоимость |
| ⚡ **Идемпотентность запросов** | 5с окно дедупликации для дублирующихся запросов |
| 🔒 **Спуфинг TLS Fingerprint** | Обход обнаружения ботов через wreq-js |
| 🌐 **Фильтрация IP** | Allowlist/blocklist для контроля доступа к API |
| 📊 **Настраиваемые Rate Limits** | Настраиваемые RPM, минимальный интервал, макс. конкуррентность |
### 📊 Наблюдаемость и аналитика
| Функция | Что делает |
| ----------------------------- | ------------------------------------------------------------------------ |
| 📝 **Логи запросов** | Режим debug с полными логами запросов/ответов |
| 💾 **Логи SQLite** | Постоянные proxy-логи переживают перезапуски |
| 📊 **Dashboard аналитики** | Recharts: карточки статистики, график использования, таблица провайдеров |
| 📈 **Отслеживание прогресса** | Opt-in SSE-события прогресса для стриминга |
| 🧪 **Оценки LLM** | Тестирование с golden set и 4 стратегиями сравнения |
| 🔍 **Телеметрия запросов** | Агрегация латентности p50/p95/p99 + трекинг X-Request-Id |
| 📋 **Логи + Квоты** | Отдельные страницы для просмотра логов и отслеживания квот |
| 🏥 **Dashboard здоровья** | Uptime, состояния circuit breaker, блокировки, статистика кеша |
| 💰 **Отслеживание стоимости** | Управление бюджетом + настройка цен по моделям |
### ☁️ Деплой и синхронизация
| Функция | Что делает |
| -------------------------- | --------------------------------------------------------------------------- |
| 💾 **Cloud Sync** | Синхронизация настроек между устройствами через Cloudflare Workers |
| 🌐 **Деплой куда угодно** | Localhost, VPS, Docker, Cloudflare Workers |
| 🔑 **Управление API Keys** | Генерация, ротация и настройка scope API keys по провайдерам |
| 🧙 **Мастер настройки** | 4-шаговая настройка для новых пользователей |
| 🔧 **Dashboard CLI Tools** | Настройка в один клик для Claude, Codex, Cline, OpenClaw, Kilo, Antigravity |
| 🔄 **Бэкапы БД** | Автоматическое резервное копирование и восстановление всех настроек |
<details>
<summary><b>📖 Подробности функций</b></summary>
### 🎯 Умный 4-уровневый Fallback
Создавайте комбо с автоматическим fallback:
```
Combo: "my-coding-stack"
1. cc/claude-opus-4-6 (ваша подписка)
2. nvidia/llama-3.3-70b (бесплатный NVIDIA API)
3. glm/glm-4.7 (дешёвый бэкап, $0.6/1M)
4. if/kimi-k2-thinking (бесплатный fallback)
→ Автоматически переключается при исчерпании квоты или ошибках
```
### 📊 Отслеживание квот в реальном времени
- Потребление токенов по провайдерам
- Обратный отсчёт до сброса (5 часов, ежедневно, еженедельно)
- Оценка стоимости для платных уровней
- Ежемесячные отчёты о расходах
### 🔄 Трансляция формата
Бесшовная трансляция между форматами:
- **OpenAI** ↔ **Claude****Gemini****OpenAI Responses**
- Ваш CLI отправляет формат OpenAI → OmniRoute транслирует → Провайдер получает нативный формат
- Работает с любым инструментом, поддерживающим пользовательские OpenAI endpoints
### 👥 Мульти-аккаунт
- Добавляйте несколько аккаунтов на провайдера
- Автоматический round-robin или маршрутизация по приоритету
- Fallback на следующий аккаунт при исчерпании квоты
### 🔄 Автообновление токенов
- OAuth-токены обновляются автоматически до истечения
- Без необходимости ручной повторной аутентификации
- Бесшовный опыт по всем провайдерам
### 🎨 Пользовательские комбо
- Создавайте неограниченные комбинации моделей
- 6 стратегий: fill-first, round-robin, power-of-two-choices, random, least-used, cost-optimized
- Делитесь комбо между устройствами с Cloud Sync
### 🏥 Dashboard здоровья
- Статус системы (uptime, версия, использование памяти)
- Состояния circuit breaker по провайдерам (Closed/Open/Half-Open)
- Статус rate limit и активные блокировки
- Статистика кеша сигнатур
- Телеметрия латентности (p50/p95/p99) + кеш промптов
- Сброс состояния здоровья одним кликом
### 🔧 Playground транслятора
- Отладка, тестирование и визуализация трансляции форматов API
- Отправляйте запросы и смотрите, как OmniRoute транслирует между форматами провайдеров
- Бесценно для устранения проблем интеграции
### 💾 Cloud Sync
- Синхронизация провайдеров, комбо и настроек между устройствами
- Автоматическая фоновая синхронизация
- Безопасное шифрованное хранилище
</details>
---
## 📖 Руководство по настройке
<details>
<summary><b>💳 Провайдеры по подписке</b></summary>
### Claude Code (Pro/Max)
```bash
Dashboard → Провайдеры → Подключить Claude Code
→ OAuth вход → Автообновление токенов
→ Отслеживание квоты 5ч + еженедельно
Модели:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Совет:** Используйте Opus для сложных задач, Sonnet для скорости. OmniRoute отслеживает квоту по моделям!
### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Провайдеры → Подключить Codex
→ OAuth вход (порт 1455)
Сброс 5ч + еженедельно
Модели:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
### Gemini CLI (БЕСПЛАТНО 180K/мес!)
```bash
Dashboard → Провайдеры → Подключить Gemini CLI
→ Google OAuth
→ 180K completions/мес + 1K/день
Модели:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Лучшая ценность:** Огромный бесплатный уровень! Используйте перед платными.
### GitHub Copilot
```bash
Dashboard → Провайдеры → Подключить GitHub
→ OAuth через GitHub
→ Ежемесячный сброс (1-е число)
Модели:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
</details>
<details>
<summary><b>🔑 Провайдеры по API Key</b></summary>
### NVIDIA NIM (БЕСПЛАТНО 1000 кредитов!)
1. Регистрация: [build.nvidia.com](https://build.nvidia.com)
2. Получите бесплатный API key (1000 кредитов включены)
3. Dashboard → Добавить провайдера → NVIDIA NIM:
- API Key: `nvapi-your-key`
**Модели:** `nvidia/llama-3.3-70b-instruct`, `nvidia/mistral-7b-instruct` и 50+ других
**Совет:** OpenAI-совместимый API — работает идеально с трансляцией форматов OmniRoute!
### DeepSeek
1. Регистрация: [platform.deepseek.com](https://platform.deepseek.com)
2. Получите API key
3. Dashboard → Добавить провайдера → DeepSeek
**Модели:** `deepseek/deepseek-chat`, `deepseek/deepseek-coder`
### Groq (Бесплатный уровень доступен!)
1. Регистрация: [console.groq.com](https://console.groq.com)
2. Получите API key (бесплатный уровень включён)
3. Dashboard → Добавить провайдера → Groq
**Модели:** `groq/llama-3.3-70b`, `groq/mixtral-8x7b`
**Совет:** Сверхбыстрый вывод — лучший для программирования в реальном времени!
### OpenRouter (100+ моделей)
1. Регистрация: [openrouter.ai](https://openrouter.ai)
2. Получите API key
3. Dashboard → Добавить провайдера → OpenRouter
**Модели:** Доступ к 100+ моделям от всех основных провайдеров через один API key.
</details>
<details>
<summary><b>💰 Дешёвые провайдеры (Бэкап)</b></summary>
### GLM-4.7 (Ежедневный сброс, $0.6/1M)
1. Регистрация: [Zhipu AI](https://open.bigmodel.cn/)
2. Получите API key из Coding Plan
3. Dashboard → Добавить API Key:
- Провайдер: `glm`
- API Key: `your-key`
**Используйте:** `glm/glm-4.7`
**Совет:** Coding Plan предлагает 3× квоту по цене 1/7! Ежедневный сброс в 10:00.
### MiniMax M2.1 (Сброс 5ч, $0.20/1M)
1. Регистрация: [MiniMax](https://www.minimax.io/)
2. Получите API key
3. Dashboard → Добавить API Key
**Используйте:** `minimax/MiniMax-M2.1`
**Совет:** Самый дешёвый вариант для длинного контекста (1M токенов)!
### Kimi K2 ($9/мес фикс)
1. Подпишитесь: [Moonshot AI](https://platform.moonshot.ai/)
2. Получите API key
3. Dashboard → Добавить API Key
**Используйте:** `kimi/kimi-latest`
**Совет:** Фикс $9/мес за 10M токенов = $0.90/1M эффективная стоимость!
</details>
<details>
<summary><b>🆓 БЕСПЛАТНЫЕ провайдеры (Аварийный бэкап)</b></summary>
### iFlow (8 БЕСПЛАТНЫХ моделей)
```bash
Dashboard → Подключить iFlow
→ OAuth вход iFlow
→ Неограниченное использование
Модели:
if/kimi-k2-thinking
if/qwen3-coder-plus
if/glm-4.7
if/minimax-m2
if/deepseek-r1
```
### Qwen (3 БЕСПЛАТНЫЕ модели)
```bash
Dashboard → Подключить Qwen
→ Авторизация по коду устройства
→ Неограниченное использование
Модели:
qw/qwen3-coder-plus
qw/qwen3-coder-flash
```
### Kiro (Claude БЕСПЛАТНО)
```bash
Dashboard → Подключить Kiro
→ AWS Builder ID или Google/GitHub
→ Неограниченное использование
Модели:
kr/claude-sonnet-4.5
kr/claude-haiku-4.5
```
</details>
<details>
<summary><b>🎨 Создание комбо</b></summary>
### Пример 1: Максимизация подписки → Дешёвый бэкап
```
Dashboard → Комбо → Создать новое
Название: premium-coding
Модели:
1. cc/claude-opus-4-6 (Основная подписка)
2. glm/glm-4.7 (Дешёвый бэкап, $0.6/1M)
3. minimax/MiniMax-M2.1 (Самый дешёвый fallback, $0.20/1M)
Используйте в CLI: premium-coding
```
### Пример 2: Только бесплатные (Нулевая стоимость)
```
Название: free-combo
Модели:
1. gc/gemini-3-flash-preview (180K бесплатно/мес)
2. if/kimi-k2-thinking (неограниченно)
3. qw/qwen3-coder-plus (неограниченно)
Стоимость: $0 навсегда!
```
</details>
<details>
<summary><b>🔧 Интеграция с CLI</b></summary>
### Cursor IDE
```
Настройки → Модели → Расширенные:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [из dashboard OmniRoute]
Model: cc/claude-opus-4-6
```
### Claude Code
Используйте страницу **CLI Tools** в dashboard для настройки в один клик, или редактируйте `~/.claude/settings.json` вручную.
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
**Вариант 1 — Dashboard (рекомендуется):**
```
Dashboard → CLI Tools → OpenClaw → Выбрать модель → Применить
```
**Вариант 2 — Вручную:** Редактируйте `~/.openclaw/openclaw.json`:
```json
{
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://127.0.0.1:20128/v1",
"apiKey": "sk_omniroute",
"api": "openai-completions"
}
}
}
}
```
> **Примечание:** OpenClaw работает только с локальным OmniRoute. Используйте `127.0.0.1` вместо `localhost` для избежания проблем с IPv6.
### Cline / Continue / RooCode
```
Настройки → Конфигурация API:
Провайдер: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [из dashboard OmniRoute]
Model: if/kimi-k2-thinking
```
</details>
---
## 📊 Доступные модели
<details>
<summary><b>Посмотреть все доступные модели</b></summary>
**Claude Code (`cc/`)** - Pro/Max:
- `cc/claude-opus-4-6`
- `cc/claude-sonnet-4-5-20250929`
- `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** - Plus/Pro:
- `cx/gpt-5.2-codex`
- `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** - БЕСПЛАТНО:
- `gc/gemini-3-flash-preview`
- `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**:
- `gh/gpt-5`
- `gh/claude-4.5-sonnet`
**NVIDIA NIM (`nvidia/`)** - БЕСПЛАТНЫЕ кредиты:
- `nvidia/llama-3.3-70b-instruct`
- `nvidia/mistral-7b-instruct`
- 50+ моделей на [build.nvidia.com](https://build.nvidia.com)
**GLM (`glm/`)** - $0.6/1M:
- `glm/glm-4.7`
**MiniMax (`minimax/`)** - $0.2/1M:
- `minimax/MiniMax-M2.1`
**iFlow (`if/`)** - БЕСПЛАТНО:
- `if/kimi-k2-thinking`
- `if/qwen3-coder-plus`
- `if/deepseek-r1`
- `if/glm-4.7`
- `if/minimax-m2`
**Qwen (`qw/`)** - БЕСПЛАТНО:
- `qw/qwen3-coder-plus`
- `qw/qwen3-coder-flash`
**Kiro (`kr/`)** - БЕСПЛАТНО:
- `kr/claude-sonnet-4.5`
- `kr/claude-haiku-4.5`
**OpenRouter (`or/`)** - 100+ моделей:
- `or/anthropic/claude-4-sonnet`
- `or/google/gemini-2.5-pro`
- Любая модель с [openrouter.ai/models](https://openrouter.ai/models)
</details>
---
## 🧪 Оценки (Evals)
OmniRoute включает встроенный фреймворк оценки для тестирования качества ответов LLM по golden set. Доступ через **Analytics → Evals** в dashboard.
### Встроенный Golden Set
Предзагруженный «OmniRoute Golden Set» содержит 10 тестов:
- Приветствия, математика, география, генерация кода
- Соответствие формату JSON, перевод, markdown
- Отказ от небезопасного контента, подсчёт, булева логика
### Стратегии оценки
| Стратегия | Описание | Пример |
| ---------- | ----------------------------------------------------- | -------------------------------- |
| `exact` | Вывод должен совпадать точно | `"4"` |
| `contains` | Вывод должен содержать подстроку (без учёта регистра) | `"Paris"` |
| `regex` | Вывод должен соответствовать regex-паттерну | `"1.*2.*3"` |
| `custom` | Пользовательская JS-функция возвращает true/false | `(output) => output.length > 10` |
---
## 🐛 Устранение неполадок
<details>
<summary><b>Нажмите для раскрытия руководства</b></summary>
**«Language model did not provide messages»**
- Квота провайдера исчерпана → Проверьте трекер квот в dashboard
- Решение: Используйте комбо с fallback или переключитесь на более дешёвый уровень
**Rate limiting**
- Квота подписки исчерпана → Fallback на GLM/MiniMax
- Добавьте комбо: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
**OAuth-токен истёк**
- Обновляется автоматически OmniRoute
- Если проблема сохраняется: Dashboard → Провайдер → Переподключить
**Высокие расходы**
- Проверьте статистику в Dashboard → Расходы
- Переключите основную модель на GLM/MiniMax
- Используйте бесплатный уровень (Gemini CLI, iFlow) для некритичных задач
**Dashboard открывается на неправильном порту**
- Установите `PORT=20128` и `NEXT_PUBLIC_BASE_URL=http://localhost:20128`
**Ошибки cloud sync**
- Проверьте что `BASE_URL` указывает на ваш запущенный экземпляр
- Проверьте что `CLOUD_URL` указывает на правильный облачный endpoint
- Держите значения `NEXT_PUBLIC_*` синхронизированными с серверными значениями
**Первый вход не работает**
- Проверьте `INITIAL_PASSWORD` в `.env`
- Если не задан, пароль по умолчанию `123456`
**Нет логов запросов**
- Установите `ENABLE_REQUEST_LOGS=true` в `.env`
**Тест подключения показывает «Invalid» для OpenAI-совместимых провайдеров**
- Многие провайдеры не предоставляют endpoint `/models`
- OmniRoute v1.0.4+ включает fallback-валидацию через chat completions
- Убедитесь что base URL содержит суффикс `/v1`
</details>
---
## 🛠️ Технологический стек
- **Runtime**: Node.js 20+
- **Язык**: TypeScript 5.9 — **100% TypeScript** в `src/` и `open-sse/` (v1.0.4)
- **Framework**: Next.js 16 + React 19 + Tailwind CSS 4
- **База данных**: LowDB (JSON) + SQLite (состояние домена + proxy-логи)
- **Стриминг**: Server-Sent Events (SSE)
- **Аутентификация**: OAuth 2.0 (PKCE) + JWT + API Keys
- **Тестирование**: Node.js test runner (368+ юнит-тестов)
- **CI/CD**: GitHub Actions (авто-публикация npm + Docker Hub при релизе)
- **Сайт**: [omniroute.online](https://omniroute.online)
- **Пакет**: [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute)
- **Docker**: [hub.docker.com/r/diegosouzapw/omniroute](https://hub.docker.com/r/diegosouzapw/omniroute)
- **Устойчивость**: Circuit breaker, экспоненциальный backoff, anti-thundering herd, TLS-спуфинг
---
## 📖 Документация
| Документ | Описание |
| ----------------------------------------------- | ------------------------------------------------ |
| [Руководство пользователя](docs/USER_GUIDE.md) | Провайдеры, комбо, интеграция CLI, деплой |
| [Справка API](docs/API_REFERENCE.md) | Все endpoints с примерами |
| [Устранение неполадок](docs/TROUBLESHOOTING.md) | Частые проблемы и решения |
| [Архитектура](docs/ARCHITECTURE.md) | Архитектура системы и внутреннее устройство |
| [Как внести вклад](CONTRIBUTING.md) | Настройка разработки и руководящие принципы |
| [Спецификация OpenAPI](docs/openapi.yaml) | Спецификация OpenAPI 3.0 |
| [Политика безопасности](SECURITY.md) | Сообщение об уязвимостях и практики безопасности |
---
## 📧 Поддержка
> 💬 **Присоединяйтесь к сообществу!** [Группа WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Получайте помощь, делитесь советами и оставайтесь в курсе.
- **Сайт**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Группа сообщества](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Оригинальный проект**: [9router от decolua](https://github.com/decolua/9router)
---
## 👥 Участники
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)
### Как внести вклад
1. Сделайте fork репозитория
2. Создайте ветку функции (`git checkout -b feature/amazing-feature`)
3. Зафиксируйте изменения (`git commit -m 'Add amazing feature'`)
4. Отправьте в ветку (`git push origin feature/amazing-feature`)
5. Откройте Pull Request
См. [CONTRIBUTING.md](CONTRIBUTING.md) для подробных рекомендаций.
### Выпуск новой версии
```bash
# Создайте релиз — публикация в npm происходит автоматически
gh release create v1.0.4 --title "v1.0.4" --generate-notes
```
---
## 📊 История звёзд
<a href="https://star-history.com/#diegosouzapw/OmniRoute&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
</picture>
</a>
---
## 🙏 Благодарности
Особая благодарность **[9router](https://github.com/decolua/9router)** от **[decolua](https://github.com/decolua)** — оригинальному проекту, вдохновившему этот форк. OmniRoute строится на этом невероятном фундаменте с дополнительными функциями, мультимодальными API и полной переписью на TypeScript.
Особая благодарность **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** — оригинальной реализации на Go, вдохновившей этот порт на JavaScript.
---
## 📄 Лицензия
Лицензия MIT — см. [LICENSE](LICENSE) для подробностей.
---
<div align="center">
<sub>Сделано с ❤️ для разработчиков, которые программируют 24/7</sub>
<br/>
<sub><a href="https://omniroute.online">omniroute.online</a></sub>
</div>

View File

@@ -1,999 +0,0 @@
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
# 🚀 OmniRoute — 免费 AI 网关
### 永不停止编程。智能路由至**免费和低成本 AI 模型**,自动故障转移。
_您的通用 API 代理 — 一个端点36+ 提供商,零停机时间。_
**Chat Completions • Embeddings • 图像生成 • 音频 • Reranking • 100% TypeScript**
---
### 🤖 为您最爱的编程代理提供免费 AI
_通过 OmniRoute 连接任何 AI 驱动的 IDE 或 CLI 工具 — 免费 API 网关,无限编程。_
<table>
<tr>
<td align="center" width="110">
<a href="https://github.com/cline/cline">
<img src="./public/providers/openclaw.png" alt="OpenClaw" width="48"/><br/>
<b>OpenClaw</b>
</a><br/>
<sub>⭐ 205K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/HKUDS/nanobot">
<img src="./public/providers/nanobot.png" alt="NanoBot" width="48"/><br/>
<b>NanoBot</b>
</a><br/>
<sub>⭐ 20.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/sipeed/picoclaw">
<img src="./public/providers/picoclaw.jpg" alt="PicoClaw" width="48"/><br/>
<b>PicoClaw</b>
</a><br/>
<sub>⭐ 14.6K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/zeroclaw-labs/zeroclaw">
<img src="./public/providers/zeroclaw.png" alt="ZeroClaw" width="48"/><br/>
<b>ZeroClaw</b>
</a><br/>
<sub>⭐ 9.9K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/nearai/ironclaw">
<img src="./public/providers/ironclaw.png" alt="IronClaw" width="48"/><br/>
<b>IronClaw</b>
</a><br/>
<sub>⭐ 2.1K</sub>
</td>
</tr>
<tr>
<td align="center" width="110">
<a href="https://github.com/anomalyco/opencode">
<img src="./public/providers/opencode.svg" alt="OpenCode" width="48"/><br/>
<b>OpenCode</b>
</a><br/>
<sub>⭐ 106K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/openai/codex">
<img src="./public/providers/codex.png" alt="Codex CLI" width="48"/><br/>
<b>Codex CLI</b>
</a><br/>
<sub>⭐ 60.8K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/anthropics/claude-code">
<img src="./public/providers/claude.png" alt="Claude Code" width="48"/><br/>
<b>Claude Code</b>
</a><br/>
<sub>⭐ 67.3K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/google-gemini/gemini-cli">
<img src="./public/providers/gemini-cli.png" alt="Gemini CLI" width="48"/><br/>
<b>Gemini CLI</b>
</a><br/>
<sub>⭐ 94.7K</sub>
</td>
<td align="center" width="110">
<a href="https://github.com/Kilo-Org/kilocode">
<img src="./public/providers/kilocode.png" alt="Kilo Code" width="48"/><br/>
<b>Kilo Code</b>
</a><br/>
<sub>⭐ 15.5K</sub>
</td>
</tr>
</table>
<sub>📡 所有代理通过 <code>http://localhost:20128/v1</code> 或 <code>http://cloud.omniroute.online/v1</code> 连接 — 一个配置,无限模型和配额</sub>
---
[![npm version](https://img.shields.io/npm/v/omniroute?color=cb3837&logo=npm)](https://www.npmjs.com/package/omniroute)
[![Docker Hub](https://img.shields.io/docker/v/diegosouzapw/omniroute?label=Docker%20Hub&logo=docker&color=2496ED)](https://hub.docker.com/r/diegosouzapw/omniroute)
[![License](https://img.shields.io/github/license/diegosouzapw/OmniRoute)](https://github.com/diegosouzapw/OmniRoute/blob/main/LICENSE)
[![Website](https://img.shields.io/badge/Website-omniroute.online-blue?logo=google-chrome&logoColor=white)](https://omniroute.online)
[![WhatsApp](https://img.shields.io/badge/WhatsApp-Community-25D366?logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
[🌐 网站](https://omniroute.online) • [🚀 快速开始](#-快速开始) • [💡 功能特性](#-核心功能) • [📖 文档](#-文档) • [💰 定价](#-定价概览)
🌐 **多语言版本:** [English](README.md) | [Português](README.pt-BR.md) | [Español](README.es.md) | [Русский](README.ru.md) | [中文](README.zh-CN.md) | [Deutsch](README.de.md) | [Français](README.fr.md) | [Italiano](README.it.md)
</div>
---
## 🤔 为什么选择 OmniRoute
**停止浪费金钱和遭遇限制:**
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> 订阅配额每月未使用就过期
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> 速率限制在编程中途停止你
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> 昂贵的 API每个提供商 $20-50/月)
- <img src="https://img.shields.io/badge/✗-e74c3c?style=flat-square" height="16"/> 手动在提供商间切换
**OmniRoute 解决这些问题:**
-**最大化订阅** — 追踪配额,在重置前用完每一点
-**自动故障转移** — 订阅 → API Key → 低价 → 免费,零停机
-**多账号** — 每个提供商的账号轮询
-**通用** — 适用于 Claude Code、Codex、Gemini CLI、Cursor、Cline、OpenClaw、任何 CLI 工具
---
## 🔄 工作原理
```
┌─────────────┐
│ 您的 CLI │ (Claude Code, Codex, Gemini CLI, OpenClaw, Cursor, Cline...)
│ 工具 │
└──────┬──────┘
│ http://localhost:20128/v1
┌─────────────────────────────────────────┐
│ OmniRoute智能路由器
│ • 格式转换OpenAI ↔ Claude
│ • 配额追踪 + Embeddings + 图像 │
│ • 自动令牌刷新 │
└──────┬──────────────────────────────────┘
├─→ [第1层: 订阅] Claude Code, Codex, Gemini CLI
│ ↓ 配额用完
├─→ [第2层: API KEY] DeepSeek, Groq, xAI, Mistral, NVIDIA NIM 等
│ ↓ 预算限制
├─→ [第3层: 低价] GLM ($0.6/1M), MiniMax ($0.2/1M)
│ ↓ 预算限制
└─→ [第4层: 免费] iFlow, Qwen, Kiro无限制
结果:永不停止编程,成本最低
```
---
## ⚡ 快速开始
**1. 全局安装:**
```bash
npm install -g omniroute
omniroute
```
🎉 仪表板在 `http://localhost:20128` 打开
| 命令 | 描述 |
| ----------------------- | ---------------------------- |
| `omniroute` | 启动服务器(默认端口 20128 |
| `omniroute --port 3000` | 使用自定义端口 |
| `omniroute --no-open` | 不自动打开浏览器 |
| `omniroute --help` | 显示帮助 |
**2. 连接免费提供商:**
仪表板 → 提供商 → 连接 **Claude Code****Antigravity** → OAuth 登录 → 完成!
**3. 在 CLI 工具中使用:**
```
Claude Code/Codex/Gemini CLI/OpenClaw/Cursor/Cline 设置:
Endpoint: http://localhost:20128/v1
API Key: [从仪表板复制]
Model: if/kimi-k2-thinking
```
**完成!** 开始使用免费 AI 模型编程。
**替代方案 — 从源代码运行:**
```bash
cp .env.example .env
npm install
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
---
## 🐳 Docker
OmniRoute 作为公共 Docker 镜像在 [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute) 上可用。
**快速运行:**
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**使用环境文件:**
```bash
# 先复制并编辑 .env
cp .env.example .env
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file .env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
**使用 Docker Compose**
```bash
# 基础配置(无 CLI 工具)
docker compose --profile base up -d
# CLI 配置(内置 Claude Code、Codex、OpenClaw
docker compose --profile cli up -d
```
| 镜像 | 标签 | 大小 | 描述 |
| ------------------------ | -------- | ------ | ---------- |
| `diegosouzapw/omniroute` | `latest` | ~250MB | 最新稳定版 |
| `diegosouzapw/omniroute` | `1.0.4` | ~250MB | 当前版本 |
---
## 💰 定价概览
| 层级 | 提供商 | 费用 | 配额重置 | 最适合 |
| -------------- | ----------------- | --------------------- | --------------- | ------------ |
| **💳 订阅** | Claude Code (Pro) | $20/月 | 5小时 + 每周 | 已订阅用户 |
| | Codex (Plus/Pro) | $20-200/月 | 5小时 + 每周 | OpenAI 用户 |
| | Gemini CLI | **免费** | 180K/月 + 1K/天 | 所有人! |
| | GitHub Copilot | $10-19/月 | 每月 | GitHub 用户 |
| **🔑 API KEY** | NVIDIA NIM | **免费**1000 积分) | 一次性 | 免费测试 |
| | DeepSeek | 按使用量 | 无 | 最佳性价比 |
| | Groq | 免费层 + 付费 | 限速 | 超快推理 |
| | xAI (Grok) | 按使用量 | 无 | Grok 模型 |
| | Mistral | 免费层 + 付费 | 限速 | 欧洲 AI |
| | OpenRouter | 按使用量 | 无 | 100+ 模型 |
| **💰 低价** | GLM-4.7 | $0.6/1M | 每日 10时 | 经济备用 |
| | MiniMax M2.1 | $0.2/1M | 5小时滚动 | 最便宜选项 |
| | Kimi K2 | $9/月固定 | 每月 10M Token | 可预测成本 |
| **🆓 免费** | iFlow | $0 | 无限制 | 8 个免费模型 |
| | Qwen | $0 | 无限制 | 3 个免费模型 |
| | Kiro | $0 | 无限制 | 免费 Claude |
**💡 专业建议:** 从 Gemini CLI每月 180K 免费)+ iFlow无限免费开始 = $0 成本!
---
## 🎯 使用场景
### 场景 1"我有 Claude Pro 订阅"
**问题:** 配额未使用就过期,编程高峰期遇到速率限制
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (充分使用订阅)
2. glm/glm-4.7 (配额用完时的便宜备用)
3. if/kimi-k2-thinking (免费应急后备)
每月成本:$20订阅+ ~$5备用= $25 总计
对比:$20 + 遇到限制 = 受挫
```
### 场景 2"我想要零成本"
**问题:** 无法承担订阅费用,需要可靠的 AI 编程
```
Combo: "free-forever"
1. gc/gemini-3-flash (每月 180K 免费)
2. if/kimi-k2-thinking (无限免费)
3. qw/qwen3-coder-plus (无限免费)
每月成本:$0
质量:生产级模型
```
### 场景 3"我需要 24/7 编程,不中断"
**问题:** 截止日期紧迫,不能有停机时间
```
Combo: "always-on"
1. cc/claude-opus-4-6 (最佳质量)
2. cx/gpt-5.2-codex (第二个订阅)
3. glm/glm-4.7 (便宜,每日重置)
4. minimax/MiniMax-M2.1 最便宜5小时重置
5. if/kimi-k2-thinking (免费无限制)
结果5 层故障转移 = 零停机
```
### 场景 4"我想在 OpenClaw 中使用免费 AI"
**问题:** 需要在消息应用中使用 AI 助手,完全免费
```
Combo: "openclaw-free"
1. if/glm-4.7 (无限免费)
2. if/minimax-m2.1 (无限免费)
3. if/kimi-k2-thinking (无限免费)
每月成本:$0
访问方式WhatsApp、Telegram、Slack、Discord、iMessage、Signal...
```
---
## 💡 核心功能
### 🧠 路由与智能
| 功能 | 功能描述 |
| ------------------------- | -------------------------------------------------------------------------- |
| 🎯 **智能 4 层故障转移** | 自动路由:订阅 → API Key → 低价 → 免费 |
| 📊 **实时配额追踪** | 实时 Token 计数 + 每个提供商的重置倒计时 |
| 🔄 **格式转换** | OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro 无缝切换 |
| 👥 **多账号支持** | 每个提供商多个账号,智能选择 |
| 🔄 **自动令牌刷新** | OAuth 令牌自动刷新并重试 |
| 🎨 **自定义组合** | 6 种策略fill-first、round-robin、p2c、random、least-used、cost-optimized |
| 🧩 **自定义模型** | 为任何提供商添加任何模型 ID |
| 🌐 **通配符路由** | 动态路由 `provider/*` 模式到任何提供商 |
| 🧠 **推理预算** | passthrough、auto、custom 和 adaptive 模式用于推理模型 |
| 💬 **System Prompt 注入** | 全局 System Prompt 应用于所有请求 |
| 📄 **Responses API** | 完整支持 OpenAI Responses API (`/v1/responses`) 用于 Codex |
### 🎵 多模态 API
| 功能 | 功能描述 |
| ----------------- | ---------------------------------------------- |
| 🖼️ **图像生成** | `/v1/images/generations` — 4 个提供商9+ 模型 |
| 📐 **Embeddings** | `/v1/embeddings` — 6 个提供商9+ 模型 |
| 🎤 **音频转录** | `/v1/audio/transcriptions` — Whisper 兼容 |
| 🔊 **文字转语音** | `/v1/audio/speech` — 多提供商音频合成 |
| 🛡️ **内容审核** | `/v1/moderations` — 内容安全检查 |
| 🔀 **重排序** | `/v1/rerank` — 文档相关性重排序 |
### 🛡️ 弹性与安全
| 功能 | 功能描述 |
| --------------------- | -------------------------------------- |
| 🔌 **断路器** | 每个提供商自动打开/关闭,可配置阈值 |
| 🛡️ **反惊群** | Mutex + 信号量限速用于 API Key 提供商 |
| 🧠 **语义缓存** | 两层缓存(签名 + 语义)降低成本和延迟 |
| ⚡ **请求幂等性** | 5 秒去重窗口防止重复请求 |
| 🔒 **TLS 指纹伪装** | 通过 wreq-js 绕过基于 TLS 的机器人检测 |
| 🌐 **IP 过滤** | 白名单/黑名单用于 API 访问控制 |
| 📊 **可编辑速率限制** | 可配置的 RPM、最小间隔和最大并发 |
### 📊 可观察性与分析
| 功能 | 功能描述 |
| ------------------ | ------------------------------------------ |
| 📝 **请求日志** | 调试模式,完整的请求/响应日志 |
| 💾 **SQLite 日志** | 持久化代理日志,服务器重启后仍然保留 |
| 📊 **分析仪表板** | Recharts统计卡片、使用量图表、提供商表格 |
| 📈 **进度追踪** | 流式传输的 SSE 进度事件(可选) |
| 🧪 **LLM 评估** | 黄金集测试4 种匹配策略 |
| 🔍 **请求遥测** | p50/p95/p99 延迟聚合 + X-Request-Id 追踪 |
| 📋 **日志 + 配额** | 专用页面用于日志浏览和配额追踪 |
| 🏥 **健康仪表板** | 运行时间、断路器状态、锁定、缓存统计 |
| 💰 **成本追踪** | 预算管理 + 每模型定价配置 |
### ☁️ 部署与同步
| 功能 | 功能描述 |
| --------------------- | ---------------------------------------------------------- |
| 💾 **Cloud Sync** | 通过 Cloudflare Workers 在设备间同步配置 |
| 🌐 **随处部署** | Localhost、VPS、Docker、Cloudflare Workers |
| 🔑 **API Key 管理** | 按提供商生成、轮换和设定 API Key 范围 |
| 🧙 **配置向导** | 4 步引导式设置,面向新用户 |
| 🔧 **CLI 工具仪表板** | 一键配置 Claude、Codex、Cline、OpenClaw、Kilo、Antigravity |
| 🔄 **数据库备份** | 自动备份和恢复所有设置 |
<details>
<summary><b>📖 功能详情</b></summary>
### 🎯 智能 4 层故障转移
创建带自动故障转移的组合:
```
Combo: "my-coding-stack"
1. cc/claude-opus-4-6 (您的订阅)
2. nvidia/llama-3.3-70b (免费 NVIDIA API
3. glm/glm-4.7 (便宜备用,$0.6/1M
4. if/kimi-k2-thinking (免费后备)
→ 配额用完或出错时自动切换
```
### 📊 实时配额追踪
- 每个提供商的 Token 消耗
- 重置倒计时5 小时、每日、每周)
- 付费层级的成本估算
- 月度支出报告
### 🔄 格式转换
格式间的无缝转换:
- **OpenAI** ↔ **Claude****Gemini****OpenAI Responses**
- 您的 CLI 发送 OpenAI 格式 → OmniRoute 转换 → 提供商接收原生格式
- 适用于任何支持自定义 OpenAI 端点的工具
### 👥 多账号支持
- 每个提供商添加多个账号
- 自动轮询或基于优先级的路由
- 当一个账号达到配额时自动切换到下一个
### 🔄 自动令牌刷新
- OAuth 令牌在过期前自动刷新
- 无需手动重新认证
- 所有提供商的无缝体验
### 🎨 自定义组合
- 创建无限模型组合
- 6 种策略fill-first、round-robin、power-of-two-choices、random、least-used、cost-optimized
- 通过 Cloud Sync 在设备间共享组合
### 🏥 健康仪表板
- 系统状态(运行时间、版本、内存使用)
- 每个提供商的断路器状态Closed/Open/Half-Open
- 速率限制状态和活动锁定
- 签名缓存统计
- 延迟遥测p50/p95/p99+ 提示缓存
- 一键重置健康状态
### 🔧 翻译器 Playground
- 调试、测试和可视化 API 格式转换
- 发送请求并查看 OmniRoute 如何在提供商格式间转换
- 对排查集成问题非常有价值
### 💾 Cloud Sync
- 在设备间同步提供商、组合和设置
- 自动后台同步
- 安全加密存储
</details>
---
## 📖 设置指南
<details>
<summary><b>💳 订阅提供商</b></summary>
### Claude Code (Pro/Max)
```bash
仪表板 → 提供商 → 连接 Claude Code
→ OAuth 登录 → 自动令牌刷新
5 小时 + 每周配额追踪
模型:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**专业建议:** 复杂任务用 Opus追求速度用 Sonnet。OmniRoute 按模型追踪配额!
### OpenAI Codex (Plus/Pro)
```bash
仪表板 → 提供商 → 连接 Codex
→ OAuth 登录(端口 1455
5 小时 + 每周重置
模型:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
### Gemini CLI免费 180K/月!)
```bash
仪表板 → 提供商 → 连接 Gemini CLI
→ Google OAuth
→ 每月 180K completions + 每天 1K
模型:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**最佳价值:** 巨大的免费额度!在付费层级之前使用。
### GitHub Copilot
```bash
仪表板 → 提供商 → 连接 GitHub
→ 通过 GitHub OAuth
→ 每月重置(每月 1 日)
模型:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
</details>
<details>
<summary><b>🔑 API Key 提供商</b></summary>
### NVIDIA NIM免费 1000 积分!)
1. 注册:[build.nvidia.com](https://build.nvidia.com)
2. 获取免费 API key包含 1000 推理积分)
3. 仪表板 → 添加提供商 → NVIDIA NIM
- API Key`nvapi-your-key`
**模型:** `nvidia/llama-3.3-70b-instruct``nvidia/mistral-7b-instruct` 及 50+ 更多
**专业建议:** OpenAI 兼容的 API — 与 OmniRoute 的格式转换完美配合!
### DeepSeek
1. 注册:[platform.deepseek.com](https://platform.deepseek.com)
2. 获取 API key
3. 仪表板 → 添加提供商 → DeepSeek
**模型:** `deepseek/deepseek-chat``deepseek/deepseek-coder`
### Groq免费层可用
1. 注册:[console.groq.com](https://console.groq.com)
2. 获取 API key包含免费层
3. 仪表板 → 添加提供商 → Groq
**模型:** `groq/llama-3.3-70b``groq/mixtral-8x7b`
**专业建议:** 超快推理 — 最适合实时编程!
### OpenRouter100+ 模型)
1. 注册:[openrouter.ai](https://openrouter.ai)
2. 获取 API key
3. 仪表板 → 添加提供商 → OpenRouter
**模型:** 通过一个 API key 访问所有主要提供商的 100+ 模型。
</details>
<details>
<summary><b>💰 低价提供商(备用)</b></summary>
### GLM-4.7(每日重置,$0.6/1M
1. 注册:[Zhipu AI](https://open.bigmodel.cn/)
2. 从 Coding Plan 获取 API key
3. 仪表板 → 添加 API Key
- 提供商:`glm`
- API Key`your-key`
**使用:** `glm/glm-4.7`
**专业建议:** Coding Plan 以 1/7 的价格提供 3 倍配额!每日 10:00 AM 重置。
### MiniMax M2.15 小时重置,$0.20/1M
1. 注册:[MiniMax](https://www.minimax.io/)
2. 获取 API key
3. 仪表板 → 添加 API Key
**使用:** `minimax/MiniMax-M2.1`
**专业建议:** 长上下文1M Token最便宜的选项
### Kimi K2$9/月固定)
1. 订阅:[Moonshot AI](https://platform.moonshot.ai/)
2. 获取 API key
3. 仪表板 → 添加 API Key
**使用:** `kimi/kimi-latest`
**专业建议:** 固定 $9/月 10M Token = $0.90/1M 有效成本!
</details>
<details>
<summary><b>🆓 免费提供商(应急备用)</b></summary>
### iFlow8 个免费模型)
```bash
仪表板 → 连接 iFlow
→ iFlow OAuth 登录
→ 无限使用
模型:
if/kimi-k2-thinking
if/qwen3-coder-plus
if/glm-4.7
if/minimax-m2
if/deepseek-r1
```
### Qwen3 个免费模型)
```bash
仪表板 → 连接 Qwen
→ 设备码授权
→ 无限使用
模型:
qw/qwen3-coder-plus
qw/qwen3-coder-flash
```
### Kiro免费 Claude
```bash
仪表板 → 连接 Kiro
→ AWS Builder ID 或 Google/GitHub
→ 无限使用
模型:
kr/claude-sonnet-4.5
kr/claude-haiku-4.5
```
</details>
<details>
<summary><b>🎨 创建组合</b></summary>
### 示例 1最大化订阅 → 便宜备用
```
仪表板 → 组合 → 创建新的
名称premium-coding
模型:
1. cc/claude-opus-4-6订阅主力
2. glm/glm-4.7(便宜备用,$0.6/1M
3. minimax/MiniMax-M2.1(最便宜的后备,$0.20/1M
在 CLI 中使用premium-coding
```
### 示例 2仅免费零成本
```
名称free-combo
模型:
1. gc/gemini-3-flash-preview每月 180K 免费)
2. if/kimi-k2-thinking无限制
3. qw/qwen3-coder-plus无限制
成本:永远 $0
```
</details>
<details>
<summary><b>🔧 CLI 集成</b></summary>
### Cursor IDE
```
设置 → 模型 → 高级:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [从 OmniRoute 仪表板获取]
Model: cc/claude-opus-4-6
```
### Claude Code
使用仪表板中的 **CLI Tools** 页面一键配置,或手动编辑 `~/.claude/settings.json`
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
**选项 1 — 仪表板(推荐):**
```
仪表板 → CLI Tools → OpenClaw → 选择模型 → 应用
```
**选项 2 — 手动:** 编辑 `~/.openclaw/openclaw.json`
```json
{
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://127.0.0.1:20128/v1",
"apiKey": "sk_omniroute",
"api": "openai-completions"
}
}
}
}
```
> **注意:** OpenClaw 仅支持本地 OmniRoute。使用 `127.0.0.1` 而非 `localhost` 以避免 IPv6 解析问题。
### Cline / Continue / RooCode
```
设置 → API 配置:
提供商OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [从 OmniRoute 仪表板获取]
Model: if/kimi-k2-thinking
```
</details>
---
## 📊 可用模型
<details>
<summary><b>查看所有可用模型</b></summary>
**Claude Code (`cc/`)** - Pro/Max:
- `cc/claude-opus-4-6`
- `cc/claude-sonnet-4-5-20250929`
- `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** - Plus/Pro:
- `cx/gpt-5.2-codex`
- `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** - 免费:
- `gc/gemini-3-flash-preview`
- `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**:
- `gh/gpt-5`
- `gh/claude-4.5-sonnet`
**NVIDIA NIM (`nvidia/`)** - 免费积分:
- `nvidia/llama-3.3-70b-instruct`
- `nvidia/mistral-7b-instruct`
- 50+ 更多模型在 [build.nvidia.com](https://build.nvidia.com)
**GLM (`glm/`)** - $0.6/1M:
- `glm/glm-4.7`
**MiniMax (`minimax/`)** - $0.2/1M:
- `minimax/MiniMax-M2.1`
**iFlow (`if/`)** - 免费:
- `if/kimi-k2-thinking`
- `if/qwen3-coder-plus`
- `if/deepseek-r1`
- `if/glm-4.7`
- `if/minimax-m2`
**Qwen (`qw/`)** - 免费:
- `qw/qwen3-coder-plus`
- `qw/qwen3-coder-flash`
**Kiro (`kr/`)** - 免费:
- `kr/claude-sonnet-4.5`
- `kr/claude-haiku-4.5`
**OpenRouter (`or/`)** - 100+ 模型:
- `or/anthropic/claude-4-sonnet`
- `or/google/gemini-2.5-pro`
- [openrouter.ai/models](https://openrouter.ai/models) 上的任何模型
</details>
---
## 🧪 评估 (Evals)
OmniRoute 包含内置评估框架,用于针对黄金集测试 LLM 响应质量。通过仪表板中的 **Analytics → Evals** 访问。
### 内置黄金集
预加载的「OmniRoute Golden Set」包含 10 个测试用例:
- 问候、数学、地理、代码生成
- JSON 格式合规性、翻译、markdown
- 安全拒绝(有害内容)、计数、布尔逻辑
### 评估策略
| 策略 | 描述 | 示例 |
| ---------- | -------------------------------- | -------------------------------- |
| `exact` | 输出必须完全匹配 | `"4"` |
| `contains` | 输出必须包含子串(不区分大小写) | `"Paris"` |
| `regex` | 输出必须匹配正则表达式模式 | `"1.*2.*3"` |
| `custom` | 自定义 JS 函数返回 true/false | `(output) => output.length > 10` |
---
## 🐛 故障排除
<details>
<summary><b>点击展开故障排除指南</b></summary>
**"Language model did not provide messages"**
- 提供商配额已耗尽 → 检查仪表板配额追踪器
- 解决方案:使用组合故障转移或切换到更便宜的层级
**速率限制**
- 订阅配额耗尽 → 回退到 GLM/MiniMax
- 添加组合:`cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
**OAuth 令牌过期**
- OmniRoute 自动刷新
- 如果问题持续:仪表板 → 提供商 → 重新连接
**高成本**
- 在仪表板 → 成本中检查使用统计
- 将主要模型切换为 GLM/MiniMax
- 对非关键任务使用免费层Gemini CLI、iFlow
**仪表板在错误端口打开**
- 设置 `PORT=20128``NEXT_PUBLIC_BASE_URL=http://localhost:20128`
**Cloud sync 错误**
- 验证 `BASE_URL` 指向您正在运行的实例
- 验证 `CLOUD_URL` 指向预期的云端点
- 保持 `NEXT_PUBLIC_*` 值与服务器端值一致
**首次登录不工作**
- 检查 `.env` 中的 `INITIAL_PASSWORD`
- 如未设置,默认密码为 `123456`
**没有请求日志**
-`.env` 中设置 `ENABLE_REQUEST_LOGS=true`
**兼容 OpenAI 的提供商连接测试显示 "Invalid"**
- 许多提供商不暴露 `/models` 端点
- OmniRoute v1.0.4+ 包含通过 chat completions 的回退验证
- 确保 base URL 包含 `/v1` 后缀
</details>
---
## 🛠️ 技术栈
- **运行时**: Node.js 20+
- **语言**: TypeScript 5.9 — `src/``open-sse/`**100% TypeScript**v1.0.4
- **框架**: Next.js 16 + React 19 + Tailwind CSS 4
- **数据库**: LowDB (JSON) + SQLite领域状态 + 代理日志)
- **流式传输**: Server-Sent Events (SSE)
- **认证**: OAuth 2.0 (PKCE) + JWT + API Keys
- **测试**: Node.js test runner368+ 单元测试)
- **CI/CD**: GitHub Actions发布时自动 npm 发布 + Docker Hub
- **网站**: [omniroute.online](https://omniroute.online)
- **包**: [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute)
- **Docker**: [hub.docker.com/r/diegosouzapw/omniroute](https://hub.docker.com/r/diegosouzapw/omniroute)
- **弹性**: 断路器、指数退避、反惊群、TLS 伪装
---
## 📖 文档
| 文档 | 描述 |
| ----------------------------------- | ---------------------------- |
| [用户指南](docs/USER_GUIDE.md) | 提供商、组合、CLI 集成、部署 |
| [API 参考](docs/API_REFERENCE.md) | 所有端点及示例 |
| [故障排除](docs/TROUBLESHOOTING.md) | 常见问题和解决方案 |
| [架构](docs/ARCHITECTURE.md) | 系统架构和内部机制 |
| [贡献指南](CONTRIBUTING.md) | 开发设置和指南 |
| [OpenAPI 规范](docs/openapi.yaml) | OpenAPI 3.0 规范 |
| [安全策略](SECURITY.md) | 漏洞报告和安全实践 |
---
## 📧 支持
> 💬 **加入我们的社区!** [WhatsApp 群组](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — 获取帮助、分享技巧、了解最新动态。
- **网站**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [社区群组](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **原始项目**: [decolua 的 9router](https://github.com/decolua/9router)
---
## 👥 贡献者
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)
### 如何贡献
1. Fork 仓库
2. 创建功能分支(`git checkout -b feature/amazing-feature`
3. 提交更改(`git commit -m 'Add amazing feature'`
4. 推送到分支(`git push origin feature/amazing-feature`
5. 打开 Pull Request
详细指南请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
### 发布新版本
```bash
# 创建发布 — npm 发布自动完成
gh release create v1.0.4 --title "v1.0.4" --generate-notes
```
---
## 📊 Star 历史
<a href="https://star-history.com/#diegosouzapw/OmniRoute&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=diegosouzapw/OmniRoute&type=Date" />
</picture>
</a>
---
## 🙏 致谢
特别感谢 **[decolua](https://github.com/decolua)** 的 **[9router](https://github.com/decolua/9router)** — 启发了本 fork 的原始项目。OmniRoute 在这个令人难以置信的基础上添加了额外功能、多模态 API 和完整的 TypeScript 重写。
特别感谢 **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** — 启发了本 JavaScript 移植的原始 Go 实现。
---
## 📄 许可证
MIT 许可证 — 详见 [LICENSE](LICENSE)。
---
<div align="center">
<sub>用 ❤️ 为 24/7 编程的开发者打造</sub>
<br/>
<sub><a href="https://omniroute.online">omniroute.online</a></sub>
</div>

65
bin/mcp-server.mjs Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env node
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ROOT = join(__dirname, "..");
function resolveMcpEntry(rootDir = ROOT) {
const candidates = [
// Preferred distributable JS entry (npm publish artifact)
join(rootDir, "app", "open-sse", "mcp-server", "server.js"),
// Local workspace TypeScript source fallback
join(rootDir, "open-sse", "mcp-server", "server.ts"),
];
for (const entry of candidates) {
if (existsSync(entry)) return entry;
}
return null;
}
function formatSpawnError(exitCode, signal) {
if (signal) return `MCP server exited by signal ${signal}`;
return `MCP server exited with code ${exitCode ?? 1}`;
}
export async function startMcpCli(rootDir = ROOT) {
const mcpEntry = resolveMcpEntry(rootDir);
if (!mcpEntry) {
throw new Error(
"MCP server entrypoint not found. Expected app/open-sse/mcp-server/server.js or open-sse/mcp-server/server.ts."
);
}
// `tsx` loader is only required for local `.ts` fallback; JS entry works without it.
const loaderArgs = mcpEntry.endsWith(".ts") ? ["--import", "tsx/esm"] : [];
await new Promise((resolve, reject) => {
const child = spawn(process.execPath, [...loaderArgs, mcpEntry], {
cwd: rootDir,
env: process.env,
stdio: "inherit",
});
child.once("error", reject);
child.once("exit", (code, signal) => {
if ((code ?? 0) === 0 && !signal) {
resolve(undefined);
return;
}
reject(new Error(formatSpawnError(code, signal)));
});
});
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
startMcpCli().catch((err) => {
console.error("\x1b[31m✖ Failed to start MCP server:\x1b[0m", err?.message || err);
process.exit(1);
});
}

View File

@@ -7,20 +7,76 @@
* omniroute Start the server (default port 20128)
* omniroute --port 3000 Start on custom port
* omniroute --no-open Start without opening browser
* omniroute --mcp Start MCP server (stdio transport for IDEs)
* omniroute --help Show help
* omniroute --version Show version
*/
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { homedir, platform } from "node:os";
import { isNativeBinaryCompatible } from "../scripts/native-binary-compat.mjs";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ROOT = join(__dirname, "..");
const APP_DIR = join(ROOT, "app");
// ── Load .env file (for global npm install) ─────────────────
function loadEnvFile() {
const envPaths = [];
// 1. DATA_DIR/.env if set
if (process.env.DATA_DIR) {
envPaths.push(join(process.env.DATA_DIR, ".env"));
}
// 2. ~/.omniroute/.env (default data dir)
const home = homedir();
if (home) {
if (platform() === "win32") {
const appData = process.env.APPDATA || join(home, "AppData", "Roaming");
envPaths.push(join(appData, "omniroute", ".env"));
} else {
envPaths.push(join(home, ".omniroute", ".env"));
}
}
// 3. ./.env (current working directory)
envPaths.push(join(process.cwd(), ".env"));
for (const envPath of envPaths) {
try {
if (existsSync(envPath)) {
const content = readFileSync(envPath, "utf-8");
for (const line of content.split("\n")) {
const trimmed = line.trim();
// Skip empty lines and comments
if (!trimmed || trimmed.startsWith("#")) continue;
const eqIdx = trimmed.indexOf("=");
if (eqIdx > 0) {
const key = trimmed.slice(0, eqIdx).trim();
const value = trimmed.slice(eqIdx + 1).trim();
// Don't override existing env vars
if (process.env[key] === undefined) {
// Remove surrounding quotes
process.env[key] = value.replace(/^["']|["']$/g, "");
}
}
}
console.log(` \x1b[2m📋 Loaded env from ${envPath}\x1b[0m`);
return;
}
} catch {
// Ignore errors reading env files
}
}
}
loadEnvFile();
// ── Parse args ─────────────────────────────────────────────
const args = process.argv.slice(2);
@@ -30,18 +86,30 @@ if (args.includes("--help") || args.includes("-h")) {
\x1b[1mUsage:\x1b[0m
omniroute Start the server
omniroute --port <port> Use custom port (default: 20128)
omniroute --port <port> Use custom API port (default: 20128)
omniroute --no-open Don't open browser automatically
omniroute --mcp Start MCP server (stdio transport for IDEs)
omniroute --help Show this help
omniroute --version Show version
\x1b[1mMCP Integration:\x1b[0m
The --mcp flag starts an MCP server over stdio, exposing OmniRoute
tools for AI agents in VS Code, Cursor, Claude Desktop, and Copilot.
Available tools: omniroute_get_health, omniroute_list_combos,
omniroute_check_quota, omniroute_route_request, and more.
\x1b[1mConfig:\x1b[0m
Loads .env from: ~/.omniroute/.env or ./.env
Memory limit: OMNIROUTE_MEMORY_MB (default: 512)
\x1b[1mAfter starting:\x1b[0m
Dashboard: http://localhost:<port>
API: http://localhost:<port>/v1
Dashboard: http://localhost:<dashboard-port>
API: http://localhost:<api-port>/v1
\x1b[1mConnect your tools:\x1b[0m
Set your CLI tool (Cursor, Cline, Codex, etc.) to use:
\x1b[33mhttp://localhost:20128/v1\x1b[0m
\x1b[33mhttp://localhost:<api-port>/v1\x1b[0m
`);
process.exit(0);
}
@@ -58,55 +126,117 @@ if (args.includes("--version") || args.includes("-v")) {
process.exit(0);
}
// Parse --port
let port = 20128;
// ── MCP Server Mode ───────────────────────────────────────
if (args.includes("--mcp")) {
try {
const { startMcpCli } = await import(join(ROOT, "bin", "mcp-server.mjs"));
await startMcpCli(ROOT);
} catch (err) {
console.error("\x1b[31m✖ Failed to start MCP server:\x1b[0m", err.message || err);
process.exit(1);
}
process.exit(0);
}
function parsePort(value, fallback) {
const parsed = parseInt(String(value), 10);
return Number.isFinite(parsed) && parsed > 0 && parsed <= 65535 ? parsed : fallback;
}
// Parse --port (canonical/base port)
let port = parsePort(process.env.PORT || "20128", 20128);
const portIdx = args.indexOf("--port");
if (portIdx !== -1 && args[portIdx + 1]) {
port = parseInt(args[portIdx + 1], 10);
if (isNaN(port)) {
const cliPort = parsePort(args[portIdx + 1], null);
if (cliPort === null) {
console.error("\x1b[31m✖ Invalid port number\x1b[0m");
process.exit(1);
}
port = cliPort;
}
const apiPort = parsePort(process.env.API_PORT || String(port), port);
const dashboardPort = parsePort(process.env.DASHBOARD_PORT || String(port), port);
const noOpen = args.includes("--no-open");
// ── Banner ─────────────────────────────────────────────────
console.log(`
\x1b[36m ____ _ ____ _
/ __ \\ (_) __ \\ | |
| | | |_ __ ___ _ __ _| |__) |___ _ _| |_ ___
| | | | '_ \` _ \\| '_ \\ | _ // _ \\| | | | __/ _ \\
| |__| | | | | | | | | | | | \\ \\ (_) | |_| | || __/
\\____/|_| |_| |_|_| |_|_|_| \\_\\___/ \\__,_|\\__\\___|
/ __ \\ (_) __ \\ | |
| | | |_ __ ___ _ __ _| |__) |___ _ _| |_ ___
| | | | '_ \` _ \\| '_ \\ | _ // _ \\| | | | __/ _ \\
| |__| | | | | | | | | | | | \\ \\ (_) | |_| | || __/
\\____/|_| |_| |_|_| |_|_|_| \\_\\___/ \\__,_|\\__\\___|
\x1b[0m`);
// ── Node.js version check ──────────────────────────────────
const nodeMajor = parseInt(process.versions.node.split(".")[0], 10);
if (nodeMajor >= 24) {
console.warn(`\x1b[33m ⚠ Warning: You are running Node.js ${process.versions.node}.
OmniRoute uses better-sqlite3, a native addon that does not yet
have compatible prebuilt binaries for Node.js 24+.
You may experience errors like "is not a valid Win32 application"
or "NODE_MODULE_VERSION mismatch".
Recommended: use Node.js 22 LTS (or 20 LTS).
Workaround: npm rebuild better-sqlite3\x1b[0m
`);
}
// ── Resolve server entry ───────────────────────────────────
const serverJs = join(APP_DIR, "server.js");
if (!existsSync(serverJs)) {
console.error(
"\x1b[31m✖ Server not found at:\x1b[0m",
serverJs,
);
console.error(
" This usually means the package was not built correctly.",
);
console.error("\x1b[31m✖ Server not found at:\x1b[0m", serverJs);
console.error(" This usually means the package was not built correctly.");
console.error(" Try reinstalling: npm install -g omniroute");
process.exit(1);
}
// ── Pre-flight: verify better-sqlite3 native binary ───────
// Verify the binary's actual target platform/arch before trusting dlopen.
// This avoids the macOS false positive where a bundled linux-x64 addon can
// appear to load even though the runtime will fail when better-sqlite3 starts.
const sqliteBinary = join(
APP_DIR,
"node_modules",
"better-sqlite3",
"build",
"Release",
"better_sqlite3.node"
);
if (existsSync(sqliteBinary) && !isNativeBinaryCompatible(sqliteBinary)) {
console.error(
"\x1b[31m✖ better-sqlite3 native module is incompatible with this platform.\x1b[0m"
);
console.error(` Run: cd ${APP_DIR} && npm rebuild better-sqlite3`);
if (platform() === "darwin") {
console.error(" If build tools are missing: xcode-select --install");
}
process.exit(1);
}
// ── Start server ───────────────────────────────────────────
console.log(` \x1b[2m⏳ Starting server...\x1b[0m\n`);
// Sanitize memory limit — parseInt to prevent command injection (#150)
const rawMemory = parseInt(process.env.OMNIROUTE_MEMORY_MB || "512", 10);
const memoryLimit =
Number.isFinite(rawMemory) && rawMemory >= 64 && rawMemory <= 16384 ? rawMemory : 512;
const env = {
...process.env,
PORT: String(port),
OMNIROUTE_PORT: String(port),
PORT: String(dashboardPort),
DASHBOARD_PORT: String(dashboardPort),
API_PORT: String(apiPort),
HOSTNAME: "0.0.0.0",
NODE_ENV: "production",
NODE_OPTIONS: `--max-old-space-size=${memoryLimit}`,
};
const server = spawn("node", [serverJs], {
const server = spawn("node", [`--max-old-space-size=${memoryLimit}`, serverJs], {
cwd: APP_DIR,
env,
stdio: "pipe",
@@ -119,7 +249,10 @@ server.stdout.on("data", (data) => {
process.stdout.write(text);
// Detect server ready
if (!started && (text.includes("Ready") || text.includes("started") || text.includes("listening"))) {
if (
!started &&
(text.includes("Ready") || text.includes("started") || text.includes("listening"))
) {
started = true;
onReady();
}
@@ -156,16 +289,17 @@ process.on("SIGTERM", shutdown);
// ── On ready ───────────────────────────────────────────────
async function onReady() {
const url = `http://localhost:${port}`;
const dashboardUrl = `http://localhost:${dashboardPort}`;
const apiUrl = `http://localhost:${apiPort}`;
console.log(`
\x1b[32m✔ OmniRoute is running!\x1b[0m
\x1b[1m Dashboard:\x1b[0m ${url}
\x1b[1m API Base:\x1b[0m ${url}/v1
\x1b[1m Dashboard:\x1b[0m ${dashboardUrl}
\x1b[1m API Base:\x1b[0m ${apiUrl}/v1
\x1b[2m Point your CLI tool (Cursor, Cline, Codex) to:\x1b[0m
\x1b[33m ${url}/v1\x1b[0m
\x1b[33m ${apiUrl}/v1\x1b[0m
\x1b[2m Press Ctrl+C to stop\x1b[0m
`);
@@ -173,7 +307,7 @@ async function onReady() {
if (!noOpen) {
try {
const open = await import("open");
await open.default(url);
await open.default(dashboardUrl);
} catch {
// open is optional — if not available, just skip
}

Submodule clipr/9router deleted from bc91be7305

Submodule clipr/CLIProxyAPI deleted from 068630dbd0

View File

@@ -22,21 +22,19 @@ services:
env_file: .env
environment:
- NODE_ENV=production
- PORT=20128
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
- HOSTNAME=0.0.0.0
- DATA_DIR=/app/data
ports:
- "20130:20128"
- "${PROD_DASHBOARD_PORT:-20130}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${PROD_API_PORT:-20131}:${API_PORT:-20129}"
volumes:
- omniroute-prod-data:/app/data
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))",
]
test: ["CMD", "node", "healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 3

View File

@@ -18,16 +18,16 @@
x-common: &common
restart: unless-stopped
env_file: .env
environment:
- DATA_DIR=/app/data # Must match the volume mount below
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
volumes:
- omniroute-data:/app/data
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))",
]
test: ["CMD", "node", "healthcheck.mjs"]
interval: 30s
timeout: 5s
retries: 3
@@ -43,7 +43,8 @@ services:
target: runner-base
image: omniroute:base
ports:
- "${PORT:-20128}:20128"
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
profiles:
- base
@@ -56,7 +57,8 @@ services:
target: runner-cli
image: omniroute:cli
ports:
- "${PORT:-20128}:20128"
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
profiles:
- cli
@@ -69,8 +71,14 @@ services:
target: runner-base
image: omniroute:base
ports:
- "${PORT:-20128}:20128"
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
environment:
- DATA_DIR=/app/data
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
- CLI_MODE=host
- CLI_EXTRA_PATHS=/host-local/bin:/host-node/bin
- CLI_CONFIG_HOME=/host-home

196
docs/A2A-SERVER.md Normal file
View File

@@ -0,0 +1,196 @@
# OmniRoute A2A Server Documentation
> Agent-to-Agent Protocol v0.3 — OmniRoute as an intelligent routing agent
## Agent Discovery
```bash
curl http://localhost:20128/.well-known/agent.json
```
Returns the Agent Card describing OmniRoute's capabilities, skills, and authentication requirements.
---
## Authentication
All `/a2a` requests require an API key via the `Authorization` header:
```
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
```
If no API key is configured on the server, authentication is bypassed.
---
## JSON-RPC 2.0 Methods
### `message/send` — Synchronous Execution
Sends a message to a skill and waits for the complete response.
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a hello world in Python"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
}
}'
```
**Response:**
```json
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task": { "id": "uuid", "state": "completed" },
"artifacts": [{ "type": "text", "content": "..." }],
"metadata": {
"routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
"cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" },
"resilience_trace": [
{ "event": "primary_selected", "provider": "anthropic", "timestamp": "..." }
],
"policy_verdict": { "allowed": true, "reason": "within budget and quota limits" }
}
}
}
```
### `message/stream` — SSE Streaming
Same as `message/send` but returns Server-Sent Events for real-time streaming.
```bash
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}
}'
```
**SSE Events:**
```
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
```
### `tasks/get` — Query Task Status
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'
```
### `tasks/cancel` — Cancel a Task
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'
```
---
## Available Skills
| Skill | Description |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------ |
| `smart-routing` | Routes prompts through OmniRoute's intelligent pipeline. Returns response with routing explanation, cost, and resilience trace. |
| `quota-management` | Answers natural-language queries about provider quotas, suggests free combos, and provides quota rankings. |
---
## Task Lifecycle
```
submitted → working → completed
→ failed
→ cancelled
```
- Tasks expire after 5 minutes (configurable)
- Terminal states: `completed`, `failed`, `cancelled`
- Event log tracks every state transition
---
## Error Codes
| Code | Meaning |
| :----- | :----------------------------- |
| -32700 | Parse error (invalid JSON) |
| -32600 | Invalid request / Unauthorized |
| -32601 | Method or skill not found |
| -32602 | Invalid params |
| -32603 | Internal error |
---
## Integration Examples
### Python (requests)
```python
import requests
resp = requests.post("http://localhost:20128/a2a", json={
"jsonrpc": "2.0", "id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Hello"}]
}
}, headers={"Authorization": "Bearer YOUR_KEY"})
result = resp.json()["result"]
print(result["artifacts"][0]["content"])
print(result["metadata"]["routing_explanation"])
```
### TypeScript (fetch)
```typescript
const resp = await fetch("http://localhost:20128/a2a", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_KEY",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "message/send",
params: {
skill: "smart-routing",
messages: [{ role: "user", content: "Hello" }],
},
}),
});
const { result } = await resp.json();
console.log(result.metadata.routing_explanation);
```

View File

@@ -1,5 +1,7 @@
# API Reference
🌐 **Languages:** 🇺🇸 [English](API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](i18n/es/API_REFERENCE.md) | 🇫🇷 [Français](i18n/fr/API_REFERENCE.md) | 🇮🇹 [Italiano](i18n/it/API_REFERENCE.md) | 🇷🇺 [Русский](i18n/ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](i18n/de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](i18n/in/API_REFERENCE.md) | 🇹🇭 [ไทย](i18n/th/API_REFERENCE.md) | 🇺🇦 [Українська](i18n/uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](i18n/ar/API_REFERENCE.md) | 🇯🇵 [日本語](i18n/ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/API_REFERENCE.md) | 🇧🇬 [Български](i18n/bg/API_REFERENCE.md) | 🇩🇰 [Dansk](i18n/da/API_REFERENCE.md) | 🇫🇮 [Suomi](i18n/fi/API_REFERENCE.md) | 🇮🇱 [עברית](i18n/he/API_REFERENCE.md) | 🇭🇺 [Magyar](i18n/hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/API_REFERENCE.md) | 🇰🇷 [한국어](i18n/ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](i18n/nl/API_REFERENCE.md) | 🇳🇴 [Norsk](i18n/no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/API_REFERENCE.md) | 🇷🇴 [Română](i18n/ro/API_REFERENCE.md) | 🇵🇱 [Polski](i18n/pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](i18n/sk/API_REFERENCE.md) | 🇸🇪 [Svenska](i18n/sv/API_REFERENCE.md) | 🇵🇭 [Filipino](i18n/phi/API_REFERENCE.md) | 🇨🇿 [Čeština](i18n/cs/API_REFERENCE.md)
Complete reference for all OmniRoute API endpoints.
---
@@ -258,6 +260,16 @@ Response example:
CLI responses include: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`.
### ACP Agents
| Endpoint | Method | Description |
| ----------------- | ------ | -------------------------------------------------------- |
| `/api/acp/agents` | GET | List all detected agents (built-in + custom) with status |
| `/api/acp/agents` | POST | Add custom agent or refresh detection cache |
| `/api/acp/agents` | DELETE | Remove a custom agent by `id` query param |
GET response includes `agents[]` (id, name, binary, version, installed, protocol, isCustom) and `summary` (total, installed, notFound, builtIn, custom).
### Resilience & Rate Limits
| Endpoint | Method | Description |

View File

@@ -1,6 +1,8 @@
# OmniRoute Architecture
_Last updated: 2026-02-18_
🌐 **Languages:** 🇺🇸 [English](ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](i18n/es/ARCHITECTURE.md) | 🇫🇷 [Français](i18n/fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](i18n/it/ARCHITECTURE.md) | 🇷🇺 [Русский](i18n/ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](i18n/de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](i18n/in/ARCHITECTURE.md) | 🇹🇭 [ไทย](i18n/th/ARCHITECTURE.md) | 🇺🇦 [Українська](i18n/uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](i18n/ar/ARCHITECTURE.md) | 🇯🇵 [日本語](i18n/ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/ARCHITECTURE.md) | 🇧🇬 [Български](i18n/bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](i18n/da/ARCHITECTURE.md) | 🇫🇮 [Suomi](i18n/fi/ARCHITECTURE.md) | 🇮🇱 [עברית](i18n/he/ARCHITECTURE.md) | 🇭🇺 [Magyar](i18n/hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/ARCHITECTURE.md) | 🇰🇷 [한국어](i18n/ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](i18n/nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](i18n/no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/ARCHITECTURE.md) | 🇷🇴 [Română](i18n/ro/ARCHITECTURE.md) | 🇵🇱 [Polski](i18n/pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](i18n/sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](i18n/sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](i18n/phi/ARCHITECTURE.md) | 🇨🇿 [Čeština](i18n/cs/ARCHITECTURE.md)
_Last updated: 2026-03-04_
## Executive Summary
@@ -79,8 +81,8 @@ flowchart LR
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(db.json)]
UDB[(usage.json + log.txt)]
DB[(storage.sqlite)]
UDB[(usage tables + log artifacts)]
end
subgraph Upstreams[Upstream Providers]
@@ -142,7 +144,7 @@ Management domains:
- Providers/connections: `src/app/api/providers*`
- Provider nodes: `src/app/api/provider-nodes*`
- Custom models: `src/app/api/provider-models` (GET/POST/DELETE)
- Model catalog: `src/app/api/models/catalog` (GET)
- Model catalog: `src/app/api/models/route.ts` (GET)
- Proxy config: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- Keys/aliases/combos/pricing: `src/app/api/keys*`, `src/app/api/models/alias`, `src/app/api/combos*`, `src/app/api/pricing`
@@ -223,18 +225,19 @@ OAuth provider modules (12 individual files under `src/lib/oauth/providers/`):
## 3) Persistence Layer
Primary state DB:
Primary state DB (SQLite):
- `src/lib/localDb.ts`
- file: `${DATA_DIR}/db.json` (or `$XDG_CONFIG_HOME/omniroute/db.json` when set, else `~/.omniroute/db.json`)
- entities: providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
Usage DB:
Usage persistence:
- `src/lib/usageDb.ts`
- files: `${DATA_DIR}/usage.json`, `${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`
- follows same base directory policy as `localDb` (`DATA_DIR`, then `XDG_CONFIG_HOME/omniroute` when set)
- decomposed into focused sub-modules: `migrations.ts`, `usageHistory.ts`, `costCalculator.ts`, `usageStats.ts`, `callLogs.ts`
- facade: `src/lib/usageDb.ts` (decomposed modules in `src/lib/usage/*`)
- SQLite tables in `storage.sqlite`: `usage_history`, `call_logs`, `proxy_logs`
- optional file artifacts remain for compatibility/debug (`${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`, `<repo>/logs/...`)
- legacy JSON files are migrated to SQLite by startup migrations when present
Domain State DB (SQLite):
@@ -503,9 +506,9 @@ erDiagram
Physical storage files:
- main state: `${DATA_DIR}/db.json` (or `$XDG_CONFIG_HOME/omniroute/db.json` when set, else `~/.omniroute/db.json`)
- usage stats: `${DATA_DIR}/usage.json`
- request log lines: `${DATA_DIR}/log.txt`
- primary runtime DB: `${DATA_DIR}/storage.sqlite`
- request log lines: `${DATA_DIR}/log.txt` (compat/debug artifact)
- structured call payload archives: `${DATA_DIR}/call_logs/`
- optional translator/request debug sessions: `<repo>/logs/...`
## Deployment Topology
@@ -520,8 +523,8 @@ flowchart LR
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(db.json)]
UsageDB[(usage.json/log.txt)]
MainDB[(storage.sqlite)]
UsageDB[(usage tables + log artifacts)]
end
subgraph External[External Services]
@@ -548,7 +551,7 @@ flowchart LR
- `src/app/api/providers*`: provider CRUD, validation, testing
- `src/app/api/provider-nodes*`: custom compatible node management
- `src/app/api/provider-models`: custom model management (CRUD)
- `src/app/api/models/catalog`: full model catalog API (all types grouped by provider)
- `src/app/api/models/route.ts`: model catalog API (aliases + custom models)
- `src/app/api/oauth/*`: OAuth/device-code flows
- `src/app/api/keys*`: local API key lifecycle
- `src/app/api/models/alias`: alias management
@@ -580,8 +583,9 @@ flowchart LR
### Persistence
- `src/lib/localDb.ts`: persistent config/state
- `src/lib/usageDb.ts`: usage history and rolling request logs
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
- `src/lib/localDb.ts`: compatibility re-export for DB modules
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
## Provider Executor Coverage (Strategy Pattern)
@@ -722,23 +726,23 @@ Files are written to `<repo>/logs/<session>/` for each request session.
## 5) Data Integrity
- DB shape migration/repair for missing keys
- corrupt JSON reset safeguards for localDb and usageDb
- SQLite schema migrations and auto-upgrade hooks at startup
- legacy JSON → SQLite migration compatibility path
## Observability and Operational Signals
Runtime visibility sources:
- console logs from `src/sse/utils/logger.ts`
- per-request usage aggregates in `usage.json`
- textual request status log in `log.txt`
- per-request usage aggregates in SQLite (`usage_history`, `call_logs`, `proxy_logs`)
- textual request status log in `log.txt` (optional/compat)
- optional deep request/translation logs under `logs/` when `ENABLE_REQUEST_LOGS=true`
- dashboard usage endpoints (`/api/usage/*`) for UI consumption
## Security-Sensitive Boundaries
- JWT secret (`JWT_SECRET`) secures dashboard session cookie verification/signing
- Initial password fallback (`INITIAL_PASSWORD`, default `123456`) must be overridden in real deployments
- Initial password bootstrap (`INITIAL_PASSWORD`) should be explicitly configured for first-run provisioning
- API key HMAC secret (`API_KEY_SECRET`) secures generated local API key format
- Provider secrets (API keys/tokens) are persisted in local DB and should be protected at filesystem level
- Cloud sync endpoints rely on API key auth + machine id semantics
@@ -760,13 +764,13 @@ Environment variables actively used by code:
## Known Architectural Notes
1. `usageDb` and `localDb` now share the same base directory policy (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) with legacy file migration.
2. `/api/v1/route.ts` returns a static model list and is not the main models source used by `/v1/models`.
1. `usageDb` and `localDb` share the same base directory policy (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) with legacy file migration.
2. `/api/v1/route.ts` delegates to the same unified catalog builder used by `/api/v1/models` (`src/app/api/v1/models/catalog.ts`) to avoid semantic drift.
3. Request logger writes full headers/body when enabled; treat log directory as sensitive.
4. Cloud behavior depends on correct `NEXT_PUBLIC_BASE_URL` and cloud endpoint reachability.
5. The `open-sse/` directory is published as the `@omniroute/open-sse` **npm workspace package**. Source code imports it via `@omniroute/open-sse/...` (resolved by Next.js `transpilePackages`). File paths in this document still use the directory name `open-sse/` for consistency.
6. Charts in the dashboard use **Recharts** (SVG-based) for accessible, interactive analytics visualizations (model usage bar charts, provider breakdown tables with success rates).
7. E2E tests use **Playwright** (`tests/e2e/`), run via `npm run test:e2e`. Unit tests use **Node.js test runner** (`tests/unit/`), run via `npm run test:plan3`. Source code under `src/` is **TypeScript** (`.ts`/`.tsx`); the `open-sse/` workspace remains JavaScript (`.js`).
7. E2E tests use **Playwright** (`tests/e2e/`), run via `npm run test:e2e`. Unit tests use **Node.js test runner** (`tests/unit/`), run via `npm run test:unit`. Source code under `src/` is **TypeScript** (`.ts`/`.tsx`); the `open-sse/` workspace remains JavaScript (`.js`).
8. Settings page is organized into 5 tabs: Security, Routing (6 global strategies: fill-first, round-robin, p2c, random, least-used, cost-optimized), Resilience (editable rate limits, circuit breaker, policies), AI (thinking budget, system prompt, prompt cache), Advanced (proxy).
## Operational Verification Checklist

63
docs/AUTO-COMBO.md Normal file
View File

@@ -0,0 +1,63 @@
# OmniRoute Auto-Combo Engine
> Self-managing model chains with adaptive scoring
## How It Works
The Auto-Combo Engine dynamically selects the best provider/model for each request using a **6-factor scoring function**:
| Factor | Weight | Description |
| :--------- | :----- | :---------------------------------------------- |
| Quota | 0.20 | Remaining capacity [0..1] |
| Health | 0.25 | Circuit breaker: CLOSED=1.0, HALF=0.5, OPEN=0.0 |
| CostInv | 0.20 | Inverse cost (cheaper = higher score) |
| LatencyInv | 0.15 | Inverse p95 latency (faster = higher) |
| TaskFit | 0.10 | Model × task type fitness score |
| Stability | 0.10 | Low variance in latency/errors |
## Mode Packs
| Pack | Focus | Key Weight |
| :---------------------- | :----------- | :--------------- |
| 🚀 **Ship Fast** | Speed | latencyInv: 0.35 |
| 💰 **Cost Saver** | Economy | costInv: 0.40 |
| 🎯 **Quality First** | Best model | taskFit: 0.40 |
| 📡 **Offline Friendly** | Availability | quota: 0.40 |
## Self-Healing
- **Temporary exclusion**: Score < 0.2 → excluded for 5 min (progressive backoff, max 30 min)
- **Circuit breaker awareness**: OPEN → auto-excluded; HALF_OPEN → probe requests
- **Incident mode**: >50% OPEN → disable exploration, maximize stability
- **Cooldown recovery**: After exclusion, first request is a "probe" with reduced timeout
## Bandit Exploration
5% of requests (configurable) are routed to random providers for exploration. Disabled in incident mode.
## API
```bash
# Create auto-combo
curl -X POST http://localhost:20128/api/combos/auto \
-H "Content-Type: application/json" \
-d '{"id":"my-auto","name":"Auto Coder","candidatePool":["anthropic","google","openai"],"modePack":"ship-fast"}'
# List auto-combos
curl http://localhost:20128/api/combos/auto
```
## Task Fitness
30+ models scored across 6 task types (`coding`, `review`, `planning`, `analysis`, `debugging`, `documentation`). Supports wildcard patterns (e.g., `*-coder` → high coding score).
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------ |
| `open-sse/services/autoCombo/scoring.ts` | Scoring function & pool normalization |
| `open-sse/services/autoCombo/taskFitness.ts` | Model × task fitness lookup |
| `open-sse/services/autoCombo/engine.ts` | Selection logic, bandit, budget cap |
| `open-sse/services/autoCombo/selfHealing.ts` | Exclusion, probes, incident mode |
| `open-sse/services/autoCombo/modePacks.ts` | 4 weight profiles |
| `src/app/api/combos/auto/route.ts` | REST API |

347
docs/CLI-TOOLS.md Normal file
View File

@@ -0,0 +1,347 @@
# CLI Tools Setup Guide — OmniRoute
This guide explains how to install and configure all supported AI coding CLI tools
to use **OmniRoute** as the unified backend, giving you centralized key management,
cost tracking, model switching, and request logging across every tool.
---
## How It Works
```
Claude / Codex / Gemini CLI / OpenCode / Cline / KiloCode / Continue / Kiro CLI
▼ (all point to OmniRoute)
http://YOUR_SERVER:20128/v1
▼ (OmniRoute routes to the right provider)
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
```
**Benefits:**
- One API key to manage all tools
- Cost tracking across all CLIs in the dashboard
- Model switching without reconfiguring every tool
- Works locally and on remote servers (VPS)
---
## Supported Tools
| Tool | Command | Type | Install Method |
| ---------------- | ------------------- | ----------------- | -------------- |
| **Claude Code** | `claude` | CLI | npm |
| **OpenAI Codex** | `codex` | CLI | npm |
| **Gemini CLI** | `gemini` | CLI | npm |
| **OpenCode** | `opencode` | CLI | npm |
| **Cline** | `cline` | CLI + VS Code ext | npm |
| **KiloCode** | `kilocode` / `kilo` | CLI + VS Code ext | npm |
| **Continue** | guide-based | VS Code ext | VS Code |
| **Kiro CLI** | `kiro-cli` | CLI | curl installer |
| **Cursor** | `cursor` | Desktop app | Download |
| **Droid** | web-based | Built-in agent | OmniRoute |
| **OpenClaw** | web-based | Built-in agent | OmniRoute |
---
## Step 1 — Get an OmniRoute API Key
1. Open the OmniRoute dashboard → **API Manager** (`/dashboard/api-manager`)
2. Click **Create API Key**
3. Give it a name (e.g. `cli-tools`) and select all permissions
4. Copy the key — you'll need it for every CLI below
> Your key looks like: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
---
## Step 2 — Install CLI Tools
All npm-based tools require Node.js 18+:
```bash
# Claude Code (Anthropic)
npm install -g @anthropic-ai/claude-code
# OpenAI Codex
npm install -g @openai/codex
# Gemini CLI (Google)
npm install -g @google/gemini-cli
# OpenCode
npm install -g opencode-ai
# Cline
npm install -g cline
# KiloCode
npm install -g kilecode
# Kiro CLI (Amazon — requires curl + unzip)
apt-get install -y unzip # on Debian/Ubuntu
curl -fsSL https://cli.kiro.dev/install | bash
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
```
**Verify:**
```bash
claude --version # 2.x.x
codex --version # 0.x.x
gemini --version # 0.x.x
opencode --version # x.x.x
cline --version # 2.x.x
kilocode --version # x.x.x (or: kilo --version)
kiro-cli --version # 1.x.x
```
---
## Step 3 — Set Global Environment Variables
Add to `~/.bashrc` (or `~/.zshrc`), then run `source ~/.bashrc`:
```bash
# OmniRoute Universal Endpoint
export OPENAI_BASE_URL="http://localhost:20128/v1"
export OPENAI_API_KEY="sk-your-omniroute-key"
export ANTHROPIC_BASE_URL="http://localhost:20128/v1"
export ANTHROPIC_API_KEY="sk-your-omniroute-key"
export GEMINI_BASE_URL="http://localhost:20128/v1"
export GEMINI_API_KEY="sk-your-omniroute-key"
```
> For a **remote server** replace `localhost:20128` with the server IP or domain,
> e.g. `http://192.168.0.15:20128`.
---
## Step 4 — Configure Each Tool
### Claude Code
```bash
# Via CLI:
claude config set --global api-base-url http://localhost:20128/v1
# Or create ~/.claude/settings.json:
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
{
"apiBaseUrl": "http://localhost:20128/v1",
"apiKey": "sk-your-omniroute-key"
}
EOF
```
**Test:** `claude "say hello"`
---
### OpenAI Codex
```bash
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
model: auto
apiKey: sk-your-omniroute-key
apiBaseUrl: http://localhost:20128/v1
EOF
```
**Test:** `codex "what is 2+2?"`
---
### Gemini CLI
```bash
mkdir -p ~/.gemini && cat > ~/.gemini/settings.json << EOF
{
"apiKey": "sk-your-omniroute-key",
"baseUrl": "http://localhost:20128/v1"
}
EOF
```
**Test:** `gemini "hello"`
---
### OpenCode
```bash
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
[provider.openai]
base_url = "http://localhost:20128/v1"
api_key = "sk-your-omniroute-key"
EOF
```
**Test:** `opencode`
---
### Cline (CLI or VS Code)
**CLI mode:**
```bash
mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
{
"apiProvider": "openai",
"openAiBaseUrl": "http://localhost:20128/v1",
"openAiApiKey": "sk-your-omniroute-key"
}
EOF
```
**VS Code mode:**
Cline extension settings → API Provider: `OpenAI Compatible` → Base URL: `http://localhost:20128/v1`
Or use the OmniRoute dashboard → **CLI Tools → Cline → Apply Config**.
---
### KiloCode (CLI or VS Code)
**CLI mode:**
```bash
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
```
**VS Code settings:**
```json
{
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
"kilo-code.apiKey": "sk-your-omniroute-key"
}
```
Or use the OmniRoute dashboard → **CLI Tools → KiloCode → Apply Config**.
---
### Continue (VS Code Extension)
Edit `~/.continue/config.yaml`:
```yaml
models:
- name: OmniRoute
provider: openai
model: auto
apiBase: http://localhost:20128/v1
apiKey: sk-your-omniroute-key
default: true
```
Restart VS Code after editing.
---
### Kiro CLI (Amazon)
```bash
# Login to your AWS/Kiro account:
kiro-cli login
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
# Use kiro-cli alongside OmniRoute for other tools.
kiro-cli status
```
---
### Cursor (Desktop App)
> **Note:** Cursor routes requests through its cloud. For OmniRoute integration,
> enable **Cloud Endpoint** in OmniRoute Settings and use your public domain URL.
Via GUI: **Settings → Models → OpenAI API Key**
- Base URL: `https://your-domain.com/v1`
- API Key: your OmniRoute key
---
## Dashboard Auto-Configuration
The OmniRoute dashboard automates configuration for most tools:
1. Go to `http://localhost:20128/dashboard/cli-tools`
2. Expand any tool card
3. Select your API key from the dropdown
4. Click **Apply Config** (if tool is detected as installed)
5. Or copy the generated config snippet manually
---
## Built-in Agents: Droid & OpenClaw
**Droid** and **OpenClaw** are AI agents built directly into OmniRoute — no installation needed.
They run as internal routes and use OmniRoute's model routing automatically.
- Access: `http://localhost:20128/dashboard/agents`
- Configure: same combos and providers as all other tools
- No API key or CLI install required
---
## Available API Endpoints
| Endpoint | Description | Use For |
| -------------------------- | ----------------------------- | --------------------------- |
| `/v1/chat/completions` | Standard chat (all providers) | All modern tools |
| `/v1/responses` | Responses API (OpenAI format) | Codex, agentic workflows |
| `/v1/completions` | Legacy text completions | Older tools using `prompt:` |
| `/v1/embeddings` | Text embeddings | RAG, search |
| `/v1/images/generations` | Image generation | DALL-E, Flux, etc. |
| `/v1/audio/speech` | Text-to-speech | ElevenLabs, OpenAI TTS |
| `/v1/audio/transcriptions` | Speech-to-text | Deepgram, AssemblyAI |
---
## Troubleshooting
| Error | Cause | Fix |
| ------------------------- | ----------------------- | ------------------------------------------ |
| `Connection refused` | OmniRoute not running | `pm2 start omniroute` |
| `401 Unauthorized` | Wrong API key | Check in `/dashboard/api-manager` |
| `No combo configured` | No active routing combo | Set up in `/dashboard/combos` |
| `invalid model` | Model not in catalog | Use `auto` or check `/dashboard/providers` |
| CLI shows "not installed" | Binary not in PATH | Check `which <command>` |
| `kiro-cli: not found` | Not in PATH | `export PATH="$HOME/.local/bin:$PATH"` |
---
## Quick Setup Script (One Command)
```bash
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
OMNIROUTE_URL="http://localhost:20128/v1"
OMNIROUTE_KEY="sk-your-omniroute-key"
npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli opencode-ai cline kilecode
# Kiro CLI
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
# Write configs
mkdir -p ~/.claude ~/.codex ~/.gemini ~/.config/opencode ~/.continue
cat > ~/.claude/settings.json <<< "{\"apiBaseUrl\":\"$OMNIROUTE_URL\",\"apiKey\":\"$OMNIROUTE_KEY\"}"
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
cat > ~/.gemini/settings.json <<< "{\"apiKey\":\"$OMNIROUTE_KEY\",\"baseUrl\":\"$OMNIROUTE_URL\"}"
cat >> ~/.bashrc << EOF
export OPENAI_BASE_URL="$OMNIROUTE_URL"
export OPENAI_API_KEY="$OMNIROUTE_KEY"
export ANTHROPIC_BASE_URL="$OMNIROUTE_URL"
export ANTHROPIC_API_KEY="$OMNIROUTE_KEY"
EOF
source ~/.bashrc
echo "✅ All CLIs installed and configured for OmniRoute"
```

View File

@@ -1,5 +1,7 @@
# omniroute — Codebase Documentation
🌐 **Languages:** 🇺🇸 [English](CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](i18n/es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](i18n/fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](i18n/it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](i18n/ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](i18n/de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](i18n/in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](i18n/th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](i18n/uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](i18n/ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](i18n/ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](i18n/vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](i18n/bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](i18n/da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](i18n/fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](i18n/he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](i18n/hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](i18n/ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](i18n/nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](i18n/no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](i18n/pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](i18n/ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](i18n/pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](i18n/sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](i18n/sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](i18n/phi/CODEBASE_DOCUMENTATION.md) | 🇨🇿 [Čeština](i18n/cs/CODEBASE_DOCUMENTATION.md)
> A comprehensive, beginner-friendly guide to the **omniroute** multi-provider AI proxy router.
---

View File

@@ -1,12 +1,14 @@
# OmniRoute — Dashboard Features Gallery
🌐 **Languages:** 🇺🇸 [English](FEATURES.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/FEATURES.md) | 🇪🇸 [Español](i18n/es/FEATURES.md) | 🇫🇷 [Français](i18n/fr/FEATURES.md) | 🇮🇹 [Italiano](i18n/it/FEATURES.md) | 🇷🇺 [Русский](i18n/ru/FEATURES.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](i18n/de/FEATURES.md) | 🇮🇳 [हिन्दी](i18n/in/FEATURES.md) | 🇹🇭 [ไทย](i18n/th/FEATURES.md) | 🇺🇦 [Українська](i18n/uk-UA/FEATURES.md) | 🇸🇦 [العربية](i18n/ar/FEATURES.md) | 🇯🇵 [日本語](i18n/ja/FEATURES.md) | 🇻🇳 [Tiếng Việt](i18n/vi/FEATURES.md) | 🇧🇬 [Български](i18n/bg/FEATURES.md) | 🇩🇰 [Dansk](i18n/da/FEATURES.md) | 🇫🇮 [Suomi](i18n/fi/FEATURES.md) | 🇮🇱 [עברית](i18n/he/FEATURES.md) | 🇭🇺 [Magyar](i18n/hu/FEATURES.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/FEATURES.md) | 🇰🇷 [한국어](i18n/ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/FEATURES.md) | 🇳🇱 [Nederlands](i18n/nl/FEATURES.md) | 🇳🇴 [Norsk](i18n/no/FEATURES.md) | 🇵🇹 [Português (Portugal)](i18n/pt/FEATURES.md) | 🇷🇴 [Română](i18n/ro/FEATURES.md) | 🇵🇱 [Polski](i18n/pl/FEATURES.md) | 🇸🇰 [Slovenčina](i18n/sk/FEATURES.md) | 🇸🇪 [Svenska](i18n/sv/FEATURES.md) | 🇵🇭 [Filipino](i18n/phi/FEATURES.md) | 🇨🇿 [Čeština](i18n/cs/FEATURES.md)
Visual guide to every section of the OmniRoute dashboard.
---
## 🔌 Providers
Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI), API key providers (Groq, DeepSeek, OpenRouter), and free providers (iFlow, Qwen, Kiro).
Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI), API key providers (Groq, DeepSeek, OpenRouter), and free providers (iFlow, Qwen, Kiro). Kiro accounts include credit balance tracking — remaining credits, total allowance, and renewal date visible in Dashboard → Usage.
![Providers Dashboard](screenshots/01-providers.png)
@@ -14,7 +16,7 @@ Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI)
## 🎨 Combos
Create model routing combos with 6 strategies: fill-first, round-robin, power-of-two-choices, random, least-used, and cost-optimized. Each combo chains multiple models with automatic fallback.
Create model routing combos with 6 strategies: priority, weighted, round-robin, random, least-used, and cost-optimized. Each combo chains multiple models with automatic fallback and includes quick templates and readiness checks.
![Combos Dashboard](screenshots/02-combos.png)
@@ -44,9 +46,28 @@ Four modes for debugging API translations: **Playground** (format converter), **
---
## 🎮 Model Playground _(v2.0.9+)_
Test any model directly from the dashboard. Select provider, model, and endpoint, write prompts with Monaco Editor, stream responses in real-time, abort mid-stream, and view timing metrics.
---
## 🎨 Themes _(v2.0.5+)_
Customizable color themes for the entire dashboard. Choose from 7 preset colors (Coral, Blue, Red, Green, Violet, Orange, Cyan) or create a custom theme by picking any hex color. Supports light, dark, and system mode.
---
## ⚙️ Settings
General settings, system storage, backup management (export/import database), appearance (dark/light mode), security, routing, resilience, and advanced configuration.
Comprehensive settings panel with tabs:
- **General** — System storage, backup management (export/import database)
- **Appearance** — Theme selector (dark/light/system), color theme presets and custom colors, health log visibility
- **Security** — API endpoint protection, custom provider blocking, IP filtering, session info
- **Routing** — Model aliases, background task degradation
- **Resilience** — Rate limit persistence, circuit breaker tuning
- **Advanced** — Configuration overrides
![Settings Dashboard](screenshots/06-settings.png)
@@ -54,12 +75,29 @@ General settings, system storage, backup management (export/import database), ap
## 🔧 CLI Tools
One-click configuration for AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, and Antigravity.
One-click configuration for AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, Antigravity, Cline, Continue, Cursor, and Factory Droid. Features automated config apply/reset, connection profiles, and model mapping.
![CLI Tools Dashboard](screenshots/07-cli-tools.png)
---
## 🤖 CLI Agents _(v2.0.11+)_
Dashboard for discovering and managing CLI agents. Shows a grid of 14 built-in agents (Codex, Claude, Goose, Gemini CLI, OpenClaw, Aider, OpenCode, Cline, Qwen Code, ForgeCode, Amazon Q, Open Interpreter, Cursor CLI, Warp) with:
- **Installation status** — Installed / Not Found with version detection
- **Protocol badges** — stdio, HTTP, etc.
- **Custom agents** — Register any CLI tool via form (name, binary, version command, spawn args)
- **CLI Fingerprint Matching** — Per-provider toggle to match native CLI request signatures, reducing ban risk while preserving proxy IP
---
## 🖼️ Media _(v2.0.3+)_
Generate images, videos, and music from the dashboard. Supports OpenAI, xAI, Together, Hyperbolic, SD WebUI, ComfyUI, AnimateDiff, Stable Audio Open, and MusicGen.
---
## 📝 Request Logs
Real-time request logging with filtering by provider, model, account, and API key. Shows status codes, token usage, latency, and response details.
@@ -70,6 +108,36 @@ Real-time request logging with filtering by provider, model, account, and API ke
## 🌐 API Endpoint
Your unified API endpoint with capability breakdown: Chat Completions, Embeddings, Image Generation, Reranking, Audio Transcription, and registered API keys.
Your unified API endpoint with capability breakdown: Chat Completions, Responses API, Embeddings, Image Generation, Reranking, Audio Transcription, Text-to-Speech, Moderations, and registered API keys. Cloud proxy support for remote access.
![Endpoint Dashboard](screenshots/09-endpoint.png)
---
## 🔑 API Key Management
Create, scope, and revoke API keys. Each key can be restricted to specific models/providers with full access or read-only permissions. Visual key management with usage tracking.
---
## 📋 Audit Log
Administrative action tracking with filtering by action type, actor, target, IP address, and timestamp. Full security event history.
---
## 🖥️ Desktop Application
Native Electron desktop app for Windows, macOS, and Linux. Run OmniRoute as a standalone application with system tray integration, offline support, auto-update, and one-click install.
Key features:
- Server readiness polling (no blank screen on cold start)
- System tray with port management
- Content Security Policy
- Single-instance lock
- Auto-update on restart
- Platform-conditional UI (macOS traffic lights, Windows/Linux default titlebar)
- Hardened Electron build packaging — symlinked `node_modules` in the standalone bundle is detected and rejected before packaging, preventing runtime dependency on the build machine (v2.5.5+)
📖 See [`electron/README.md`](../electron/README.md) for full documentation.

83
docs/MCP-SERVER.md Normal file
View File

@@ -0,0 +1,83 @@
# OmniRoute MCP Server Documentation
> Model Context Protocol server with 16 intelligent tools
## Installation
OmniRoute MCP is built-in. Start it with:
```bash
omniroute --mcp
```
Or via the open-sse transport:
```bash
# HTTP streamable transport (port 20130)
omniroute --dev # MCP auto-starts on /mcp endpoint
```
## IDE Configuration
See [IDE Configs](integrations/ide-configs.md) for Antigravity, Cursor, Copilot, and Claude Desktop setup.
---
## Essential Tools (8)
| Tool | Description |
| :------------------------------ | :--------------------------------------- |
| `omniroute_get_health` | Gateway health, circuit breakers, uptime |
| `omniroute_list_combos` | All configured combos with models |
| `omniroute_get_combo_metrics` | Performance metrics for a specific combo |
| `omniroute_switch_combo` | Switch active combo by ID/name |
| `omniroute_check_quota` | Quota status per provider or all |
| `omniroute_route_request` | Send a chat completion through OmniRoute |
| `omniroute_cost_report` | Cost analytics for a time period |
| `omniroute_list_models_catalog` | Full model catalog with capabilities |
## Advanced Tools (8)
| Tool | Description |
| :--------------------------------- | :---------------------------------------------- |
| `omniroute_simulate_route` | Dry-run routing simulation with fallback tree |
| `omniroute_set_budget_guard` | Session budget with degrade/block/alert actions |
| `omniroute_set_resilience_profile` | Apply conservative/balanced/aggressive preset |
| `omniroute_test_combo` | Live-test all models in a combo |
| `omniroute_get_provider_metrics` | Detailed metrics for one provider |
| `omniroute_best_combo_for_task` | Task-fitness recommendation with alternatives |
| `omniroute_explain_route` | Explain a past routing decision |
| `omniroute_get_session_snapshot` | Full session state: costs, tokens, errors |
## Authentication
MCP tools are authenticated via API key scopes. Each tool requires specific scopes:
| Scope | Tools |
| :------------- | :----------------------------------------------- |
| `read:health` | get_health, get_provider_metrics |
| `read:combos` | list_combos, get_combo_metrics |
| `write:combos` | switch_combo |
| `read:quota` | check_quota |
| `write:route` | route_request, simulate_route, test_combo |
| `read:usage` | cost_report, get_session_snapshot, explain_route |
| `write:config` | set_budget_guard, set_resilience_profile |
| `read:models` | list_models_catalog, best_combo_for_task |
## Audit Logging
Every tool call is logged to `mcp_tool_audit` with:
- Tool name, arguments, result
- Duration (ms), success/failure
- API key hash, timestamp
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------------ |
| `open-sse/mcp-server/server.ts` | MCP server creation + 16 tool registrations |
| `open-sse/mcp-server/transport.ts` | Stdio + HTTP transport |
| `open-sse/mcp-server/auth.ts` | API key + scope validation |
| `open-sse/mcp-server/audit.ts` | Tool call audit logging |
| `open-sse/mcp-server/tools/advancedTools.ts` | 8 advanced tool handlers |

33
docs/RELEASE_CHECKLIST.md Normal file
View File

@@ -0,0 +1,33 @@
# Release Checklist
Use this checklist before tagging or publishing a new OmniRoute release.
## Version and Changelog
1. Bump `package.json` version (`x.y.z`) in the release branch.
2. Move release notes from `## [Unreleased]` in `CHANGELOG.md` to a dated section:
- `## [x.y.z] — YYYY-MM-DD`
3. Keep `## [Unreleased]` as the first changelog section for upcoming work.
4. Ensure the latest semver section in `CHANGELOG.md` equals `package.json` version.
## API Docs
1. Update `docs/openapi.yaml`:
- `info.version` must equal `package.json` version.
2. Validate endpoint examples if API contracts changed.
## Runtime Docs
1. Review `docs/ARCHITECTURE.md` for storage/runtime drift.
2. Review `docs/TROUBLESHOOTING.md` for env var and operational drift.
3. Update localized docs if source docs changed significantly.
## Automated Check
Run the sync guard locally before opening PR:
```bash
npm run check:docs-sync
```
CI also runs this check in `.github/workflows/ci.yml` (lint job).

View File

@@ -1,113 +0,0 @@
# Rate Limiting & Flow Control Overhaul — Tasks
> Referência: [Relatório de Análise](../walkthrough.md) · Fase docs em `/docs/phases/`
---
## Fase 1 — Error Classification & Provider Profiles
### Backend Core
- [x] `constants.ts` — Substituir `COOLDOWN_MS.transient` por `transientInitial` (5s) + `transientMax` (60s)
- [x] `constants.ts` — Adicionar `PROVIDER_PROFILES` (oauth / apikey) com cooldowns diferenciados
- [x] `constants.ts` — Adicionar `DEFAULT_API_LIMITS` (100 RPM, 200ms minTime)
- [x] `providerRegistry.ts` — Criar helper `getProviderCategory(providerId)``"oauth"` | `"apikey"`
- [x] `accountFallback.ts` — Aceitar `provider` como parâmetro em `checkFallbackError`
- [x] `accountFallback.ts` — Implementar backoff exponencial para 502/503/504 transientes
- [x] `accountFallback.ts` — Calcular cooldown baseado no perfil do provedor
- [x] `accountFallback.ts` — Adicionar helper `getProviderProfile(provider)`
### Callers (propagar `provider`)
- [x] `auth.ts``markAccountUnavailable` — Passar `provider` para `checkFallbackError`
- [x] `combo.ts``handleComboChat` / `handleRoundRobinCombo` — Passar `provider` nos erros
### Testes
- [x] Atualizar `rate-limit-enhanced.test.mjs` — Teste "transient errors don't increase backoff" → `newBackoffLevel = 1`
- [x] Criar `error-classification.test.mjs` — Cooldown exponencial 502, perfis OAuth/API, helper `getProviderCategory`
---
## Fase 2 — Circuit Breaker no Combo Pipeline
### Backend
- [x] `combo.ts` — Importar `getCircuitBreaker` e `CircuitBreakerOpenError`
- [x] `combo.ts``handleComboChat` — Verificar `breaker.canExecute()` antes de cada modelo
- [x] `combo.ts``handleRoundRobinCombo` — Integrar breaker per-model
- [x] `combo.ts` — Marcar `semaphore.markRateLimited` para 502/503/504 (não só 429)
- [x] `combo.ts` — Implementar early exit quando todos os modelos têm breaker OPEN
### Testes
- [x] Criar `combo-circuit-breaker.test.mjs` — Combo skip breaker OPEN, early exit, semáforo 502
---
## Fase 3 — Anti-Thundering Herd & Auto Rate Limit
### Backend
- [x] `rateLimitManager.ts` — Auto-enable para `apikey` providers com limites elevados
- [x] `rateLimitManager.ts` — Criar limiter com defaults (100 RPM) quando não configurado
- [x] `auth.ts` — Adicionar mutex na `markAccountUnavailable` para evitar marcação paralela
### Testes
- [x] Criar `thundering-herd.test.mjs` — Mutex, auto-enable, limites não restritivos
---
## Fase 4 — Frontend Resilience UI
### Settings Page
- [x] `settings/page.tsx` — Adicionar tab "Resilience" (icon: `health_and_safety`) entre Routing e Pricing
### Novos Componentes
- [x] Criar `ResilienceTab.tsx` — Layout com 4 cards (Provider Profiles → Rate Limiting → Circuit Breakers → Policies)
- [x] Criar `ProviderProfilesCard.tsx` — Toggle OAuth/API Key, inputs para cooldowns
- [x] Criar `CircuitBreakerCard.tsx` — Status real-time per-provider, auto-refresh 5s, botão reset
- [x] Criar `RateLimitOverviewCard.tsx` — Tabela providers × accounts × cooldown — **agora editável com RPM, Min Gap, Max Concurrent**
### API Routes
- [x] Criar `api/resilience/route.ts` — GET (estado completo + defaults mesclados) + PATCH (salvar perfis + defaults)
- [x] Criar `api/resilience/reset/route.ts` — POST (resetar breakers + cooldowns)
### Migração
- [x] `PoliciesPanel.tsx` movido de Security para Resilience tab
---
## Fase 5 — Settings Page Restructure (v0.9.0)
### Tab Reorganization
- [x] **Security** — Simplificado para Login/Password + IP Access Control
- [x] **Routing** — Expandido para 6 estratégias globais com descrições
- [x] **Resilience** — Reordenado: Provider Profiles → Rate Limiting (editável) → Circuit Breakers → Policies
- [x] **AI** — Thinking Budget + System Prompt + Prompt Cache (movido do Advanced)
- [x] **Advanced** — Simplificado para apenas Global Proxy
### Backend Routing Strategies
- [x] `auth.ts` — Implementar `random` (Fisher-Yates shuffle)
- [x] `auth.ts` — Implementar `least-used` (sorted by lastUsedAt)
- [x] `auth.ts` — Implementar `cost-optimized` (sorted by priority)
- [x] `auth.ts` — Corrigir `p2c` (power-of-two-choices com health scoring)
- [x] `settings.ts` — Expandir tipo `fallbackStrategy` para 6 valores
---
## Verificação Final
- [x] Rodar todos os testes unitários: `node --test tests/unit/*.test.mjs`
- [x] Build do Next.js: `npm run build`
- [x] Verificar aba Resilience no browser
- [x] Testar persistência dos perfis (salvar → reload)
- [x] Testar Reset All Breakers
- [x] Verificar todas as 5 tabs reestruturadas

View File

@@ -1,5 +1,7 @@
# Troubleshooting
🌐 **Languages:** 🇺🇸 [English](TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](i18n/es/TROUBLESHOOTING.md) | 🇫🇷 [Français](i18n/fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](i18n/it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](i18n/ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](i18n/de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](i18n/in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](i18n/th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](i18n/uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](i18n/ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](i18n/ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](i18n/vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](i18n/bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](i18n/da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](i18n/fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](i18n/he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](i18n/hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](i18n/ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](i18n/nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](i18n/no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](i18n/pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](i18n/ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](i18n/pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](i18n/sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](i18n/sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](i18n/phi/TROUBLESHOOTING.md) | 🇨🇿 [Čeština](i18n/cs/TROUBLESHOOTING.md)
Common problems and solutions for OmniRoute.
---
@@ -8,9 +10,11 @@ Common problems and solutions for OmniRoute.
| Problem | Solution |
| ----------------------------- | ------------------------------------------------------------------ |
| First login not working | Check `INITIAL_PASSWORD` in `.env` (default: `123456`) |
| First login not working | Set `INITIAL_PASSWORD` in `.env` (no hardcoded default) |
| Dashboard opens on wrong port | Set `PORT=20128` and `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
| No request logs under `logs/` | Set `ENABLE_REQUEST_LOGS=true` |
| EACCES: permission denied | Set `DATA_DIR=/path/to/writable/dir` to override `~/.omniroute` |
| Routing strategy not saving | Update to v1.4.11+ (Zod schema fix for settings persistence) |
---
@@ -116,8 +120,8 @@ curl http://localhost:20128/api/monitoring/health
### Runtime Storage
- Main state: `${DATA_DIR}/db.json` (providers, combos, aliases, keys, settings)
- Usage: `${DATA_DIR}/usage.json`, `${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`
- Main state: `${DATA_DIR}/storage.sqlite` (providers, combos, aliases, keys, settings)
- Usage: SQLite tables in `storage.sqlite` (`usage_history`, `call_logs`, `proxy_logs`) + optional `${DATA_DIR}/log.txt` and `${DATA_DIR}/call_logs/`
- Request logs: `<repo>/logs/...` (when `ENABLE_REQUEST_LOGS=true`)
---
@@ -206,6 +210,41 @@ When many concurrent requests hit a rate-limited provider, OmniRoute uses mutex
---
## Optional RAG / LLM failure taxonomy (16 problems)
Some OmniRoute users place the gateway in front of RAG or agent stacks. In those setups it is common to see a strange pattern: OmniRoute looks healthy (providers up, routing profiles ok, no rate limit alerts) but the final answer is still wrong.
In practice these incidents usually come from the downstream RAG pipeline, not from the gateway itself.
If you want a shared vocabulary to describe those failures you can use the WFGY ProblemMap, an external MIT license text resource that defines sixteen recurring RAG / LLM failure patterns. At a high level it covers:
- retrieval drift and broken context boundaries
- empty or stale indexes and vector stores
- embedding versus semantic mismatch
- prompt assembly and context window issues
- logic collapse and overconfident answers
- long chain and agent coordination failures
- multi agent memory and role drift
- deployment and bootstrap ordering problems
The idea is simple:
1. When you investigate a bad response, capture:
- user task and request
- route or provider combo in OmniRoute
- any RAG context used downstream (retrieved documents, tool calls, etc)
2. Map the incident to one or two WFGY ProblemMap numbers (`No.1``No.16`).
3. Store the number in your own dashboard, runbook, or incident tracker next to the OmniRoute logs.
4. Use the corresponding WFGY page to decide whether you need to change your RAG stack, retriever, or routing strategy.
Full text and concrete recipes live here (MIT license, text only):
[WFGY ProblemMap README](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
You can ignore this section if you do not run RAG or agent pipelines behind OmniRoute.
---
## Still Stuck?
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)

View File

@@ -1,5 +1,7 @@
# User Guide
🌐 **Languages:** 🇺🇸 [English](USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](i18n/es/USER_GUIDE.md) | 🇫🇷 [Français](i18n/fr/USER_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/USER_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/USER_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/USER_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/USER_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/USER_GUIDE.md) | 🇧🇬 [Български](i18n/bg/USER_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/USER_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/USER_GUIDE.md) | 🇮🇱 [עברית](i18n/he/USER_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/USER_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/USER_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/USER_GUIDE.md) | 🇷🇴 [Română](i18n/ro/USER_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/USER_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/USER_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/USER_GUIDE.md) | 🇨🇿 [Čeština](i18n/cs/USER_GUIDE.md)
Complete guide for configuring providers, creating combos, integrating CLI tools, and deploying OmniRoute.
---
@@ -316,6 +318,25 @@ Model: cc/claude-opus-4-6
## 🚀 Deployment
### Global npm install (Recommended)
```bash
npm install -g omniroute
# Create config directory
mkdir -p ~/.omniroute
# Create .env file (see .env.example)
cp .env.example ~/.omniroute/.env
# Start server
omniroute
# Or with custom port:
omniroute --port 3000
```
The CLI automatically loads `.env` from `~/.omniroute/.env` or `./.env`.
### VPS Deployment
```bash
@@ -335,6 +356,43 @@ npm run start
# Or: pm2 start npm --name omniroute -- start
```
### PM2 Deployment (Low Memory)
For servers with limited RAM, use the memory limit option:
```bash
# With 512MB limit (default)
pm2 start npm --name omniroute -- start
# Or with custom memory limit
OMNIROUTE_MEMORY_MB=512 pm2 start npm --name omniroute -- start
# Or using ecosystem.config.js
pm2 start ecosystem.config.js
```
Create `ecosystem.config.js`:
```javascript
module.exports = {
apps: [
{
name: "omniroute",
script: "npm",
args: "start",
env: {
NODE_ENV: "production",
OMNIROUTE_MEMORY_MB: "512",
JWT_SECRET: "your-secret",
INITIAL_PASSWORD: "your-password",
},
node_args: "--max-old-space-size=512",
max_memory_restart: "300M",
},
],
};
```
### Docker
```bash
@@ -349,20 +407,23 @@ For host-integrated mode with CLI binaries, see the Docker section in the main d
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------------------------------------ | ------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | JWT signing secret (**change in production**) |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `DATA_DIR` | `~/.omniroute` | Data directory (db, usage, logs) |
| `PORT` | framework default | Service port (`20128` in examples) |
| `HOSTNAME` | framework default | Bind host (Docker defaults to `0.0.0.0`) |
| `NODE_ENV` | runtime default | Set `production` for deploy |
| `BASE_URL` | `http://localhost:20128` | Server-side internal base URL |
| `CLOUD_URL` | `https://omniroute.dev` | Cloud sync endpoint base URL |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | HMAC secret for generated API keys |
| `REQUIRE_API_KEY` | `false` | Enforce Bearer API key on `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | Enables request/response logs |
| `AUTH_COOKIE_SECURE` | `false` | Force `Secure` auth cookie (behind HTTPS reverse proxy) |
| Variable | Default | Description |
| ------------------------- | ------------------------------------ | ------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | JWT signing secret (**change in production**) |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `DATA_DIR` | `~/.omniroute` | Data directory (db, usage, logs) |
| `PORT` | framework default | Service port (`20128` in examples) |
| `HOSTNAME` | framework default | Bind host (Docker defaults to `0.0.0.0`) |
| `NODE_ENV` | runtime default | Set `production` for deploy |
| `BASE_URL` | `http://localhost:20128` | Server-side internal base URL |
| `CLOUD_URL` | `https://omniroute.dev` | Cloud sync endpoint base URL |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | HMAC secret for generated API keys |
| `REQUIRE_API_KEY` | `false` | Enforce Bearer API key on `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | Enables request/response logs |
| `AUTH_COOKIE_SECURE` | `false` | Force `Secure` auth cookie (behind HTTPS reverse proxy) |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit in MB |
| `PROMPT_CACHE_MAX_SIZE` | `50` | Max prompt cache entries |
| `SEMANTIC_CACHE_MAX_SIZE` | `100` | Max semantic cache entries |
For the full environment variable reference, see the [README](../README.md).
@@ -610,7 +671,7 @@ The settings page is organized into 5 tabs for easy navigation:
| Tab | Contents |
| -------------- | ---------------------------------------------------------------------------------------------- |
| **Security** | Login/Password settings and IP Access Control (allowlist/blocklist) |
| **Security** | Login/Password settings, IP Access Control, API auth for `/models`, and Provider Blocking |
| **Routing** | Global routing strategy (6 options), wildcard model aliases, fallback chains, combo defaults |
| **Resilience** | Provider profiles, editable rate limits, circuit breaker status, policies & locked identifiers |
| **AI** | Thinking budget configuration, global system prompt injection, prompt cache stats |
@@ -694,3 +755,55 @@ Access via **Dashboard → Health**. Real-time system health overview with 6 car
| **Latency Telemetry** | p50/p95/p99 latency aggregation per provider |
**Pro Tip:** The Health page auto-refreshes every 10 seconds. Use the circuit breaker card to identify which providers are experiencing issues.
---
## 🖥️ Desktop Application (Electron)
OmniRoute is available as a native desktop application for Windows, macOS, and Linux.
### Installation
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Building Installers
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Output → `electron/dist-electron/`
### Key Features
| Feature | Description |
| --------------------------- | ---------------------------------------------------- |
| **Server Readiness** | Polls server before showing window (no blank screen) |
| **System Tray** | Minimize to tray, change port, quit from tray menu |
| **Port Management** | Change server port from tray (auto-restarts server) |
| **Content Security Policy** | Restrictive CSP via session headers |
| **Single Instance** | Only one app instance can run at a time |
| **Offline Mode** | Bundled Next.js server works without internet |
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------- | -------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
📖 Full documentation: [`electron/README.md`](../electron/README.md)

View File

@@ -1,69 +1,71 @@
# OmniRoute — Guia de Deploy em VM com Cloudflare
# OmniRoute — Deployment Guide on VM with Cloudflare
Guia completo para instalar e configurar o OmniRoute em uma VM (VPS) com domínio gerenciado via Cloudflare.
🌐 **Languages:** 🇺🇸 [English](VM_DEPLOYMENT_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/VM_DEPLOYMENT_GUIDE.md) | 🇪🇸 [Español](i18n/es/VM_DEPLOYMENT_GUIDE.md) | 🇫🇷 [Français](i18n/fr/VM_DEPLOYMENT_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/VM_DEPLOYMENT_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/VM_DEPLOYMENT_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/VM_DEPLOYMENT_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/VM_DEPLOYMENT_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/VM_DEPLOYMENT_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/VM_DEPLOYMENT_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/VM_DEPLOYMENT_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/VM_DEPLOYMENT_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/VM_DEPLOYMENT_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/VM_DEPLOYMENT_GUIDE.md) | 🇧🇬 [Български](i18n/bg/VM_DEPLOYMENT_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/VM_DEPLOYMENT_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/VM_DEPLOYMENT_GUIDE.md) | 🇮🇱 [עברית](i18n/he/VM_DEPLOYMENT_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/VM_DEPLOYMENT_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/VM_DEPLOYMENT_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/VM_DEPLOYMENT_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/VM_DEPLOYMENT_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/VM_DEPLOYMENT_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/VM_DEPLOYMENT_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/VM_DEPLOYMENT_GUIDE.md) | 🇷🇴 [Română](i18n/ro/VM_DEPLOYMENT_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/VM_DEPLOYMENT_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/VM_DEPLOYMENT_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/VM_DEPLOYMENT_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/VM_DEPLOYMENT_GUIDE.md) | 🇨🇿 [Čeština](i18n/cs/VM_DEPLOYMENT_GUIDE.md)
Complete guide to install and configure OmniRoute on a VM (VPS) with domain managed via Cloudflare.
---
## Pré-Requisitos
## Prerequisites
| Item | Mínimo | Recomendado |
| ----------- | ------------------------ | ---------------- |
| **CPU** | 1 vCPU | 2 vCPU |
| **RAM** | 1 GB | 2 GB |
| **Disco** | 10 GB SSD | 25 GB SSD |
| **SO** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| **Domínio** | Registrado no Cloudflare | — |
| **Docker** | Docker Engine 24+ | Docker 27+ |
| Item | Minimum | Recommended |
| ---------- | ------------------------ | ---------------- |
| **CPU** | 1 vCPU | 2 vCPU |
| **RAM** | 1 GB | 2 GB |
| **Disk** | 10 GB SSD | 25 GB SSD |
| **OS** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| **Domain** | Registered on Cloudflare | — |
| **Docker** | Docker Engine 24+ | Docker 27+ |
**Providers testados**: Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
**Tested providers**: Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
---
## 1. Configurar a VM
## 1. Configure the VM
### 1.1 Criar a instância
### 1.1 Create the instance
No seu provider de VPS preferido:
On your preferred VPS provider:
- Escolha Ubuntu 24.04 LTS
- Selecione o plano mínimo (1 vCPU / 1 GB RAM)
- Defina uma senha forte para root ou configure SSH key
- Anote o **IP público** (ex: `203.0.113.10`)
- Choose Ubuntu 24.04 LTS
- Select the minimum plan (1 vCPU / 1 GB RAM)
- Set a strong root password or configure SSH key
- Note the **public IP** (e.g., `203.0.113.10`)
### 1.2 Conectar via SSH
### 1.2 Connect via SSH
```bash
ssh root@203.0.113.10
```
### 1.3 Atualizar o sistema
### 1.3 Update the system
```bash
apt update && apt upgrade -y
```
### 1.4 Instalar Docker
### 1.4 Install Docker
```bash
# Instalar dependências
# Install dependencies
apt install -y ca-certificates curl gnupg
# Adicionar repositório oficial do Docker
# Add official Docker repository
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $ (. /etc/os-release && echo$VERSION_CODENAME”) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
### 1.5 Instalar nginx
### 1.5 Install nginx
```bash
apt install -y nginx
```
### 1.6 Configurar Firewall (UFW)
### 1.6 Configure Firewall (UFW)
```bash
ufw default deny incoming
@@ -74,29 +76,29 @@ ufw allow 443/tcp # HTTPS
ufw enable
```
> **Dica**: Para segurança máxima, restrinja as portas 80 e 443 apenas para IPs da Cloudflare. Veja a seção [Segurança Avançada](#segurança-avançada).
> **Tip**: For maximum security, restrict ports 80 and 443 to Cloudflare IPs only. See the [Advanced Security](#advanced-security) section.
---
## 2. Instalar o OmniRoute
## 2. Install OmniRoute
### 2.1 Criar diretório de configuração
### 2.1 Create configuration directory
```bash
mkdir -p /opt/omniroute
```
### 2.2 Criar arquivo de variáveis de ambiente
### 2.2 Create environment variables file
```bash
cat > /opt/omniroute/.env << 'EOF'
# === Segurança ===
JWT_SECRET=ALTERE-PARA-CHAVE-SECRETA-UNICA-64-CHARS
INITIAL_PASSWORD=SuaSenhaSegura123!
API_KEY_SECRET=ALTERE-PARA-OUTRA-CHAVE-SECRETA
STORAGE_ENCRYPTION_KEY=ALTERE-PARA-TERCEIRA-CHAVE-SECRETA
cat > /opt/omniroute/.env << EOF
# === Security ===
JWT_SECRET=CHANGE-TO-A-UNIQUE-64-CHAR-SECRET-KEY
INITIAL_PASSWORD=YourSecurePassword123!
API_KEY_SECRET=REPLACE-WITH-ANOTHER-SECRET-KEY
STORAGE_ENCRYPTION_KEY=REPLACE-WITH-THIRD-SECRET-KEY
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=ALTERE-PARA-SALT-UNICO
MACHINE_ID_SALT=CHANGE-TO-A-UNIQUE-SALT
# === App ===
PORT=20128
@@ -108,19 +110,19 @@ ENABLE_REQUEST_LOGS=true
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# === Domain (altere para seu domínio) ===
# === Domain (change to your domain) ===
BASE_URL=https://llms.seudominio.com
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
# === Cloud Sync (opcional) ===
# === Cloud Sync (optional) ===
# CLOUD_URL=https://cloud.omniroute.online
# NEXT_PUBLIC_CLOUD_URL=https://cloud.omniroute.online
EOF
```
> ⚠️ **IMPORTANTE**: Gere chaves secretas únicas! Use `openssl rand -hex 32` para cada chave.
> ⚠️ **IMPORTANT**: Generate unique secret keys! Use `openssl rand -hex 32` for each key.
### 2.3 Iniciar o container
### 2.3 Start the container
```bash
docker pull diegosouzapw/omniroute:latest
@@ -134,45 +136,45 @@ docker run -d \
diegosouzapw/omniroute:latest
```
### 2.4 Verificar se está rodando
### 2.4 Verify that it is running
```bash
docker ps | grep omniroute
docker logs omniroute --tail 20
```
Deve exibir: `[DB] SQLite database ready` e `listening on port 20128`.
It should display: `[DB] SQLite database ready` and `listening on port 20128`.
---
## 3. Configurar nginx (Reverse Proxy)
## 3. Configure nginx (Reverse Proxy)
### 3.1 Gerar certificado SSL (Cloudflare Origin)
### 3.1 Generate SSL certificate (Cloudflare Origin)
No painel da Cloudflare:
In the Cloudflare dashboard:
1. Vá em **SSL/TLS → Origin Server**
2. Clique **Create Certificate**
3. Deixe os padrões (15 anos, \*.seudominio.com)
4. Copie o **Origin Certificate** e a **Private Key**
1. Go to **SSL/TLS → Origin Server**
2. Click **Create Certificate**
3. Keep the defaults (15 years, \*.yourdomain.com)
4. Copy the **Origin Certificate** and the **Private Key**
```bash
mkdir -p /etc/nginx/ssl
# Colar o certificado
# Paste the certificate
nano /etc/nginx/ssl/origin.crt
# Colar a chave privada
# Paste the private key
nano /etc/nginx/ssl/origin.key
chmod 600 /etc/nginx/ssl/origin.key
```
### 3.2 Configuração do nginx
### 3.2 Nginx Configuration
```bash
cat > /etc/nginx/sites-available/omniroute << 'NGINX'
# Default server — bloqueia acesso direto por IP
cat > /etc/nginx/sites-available/omniroute << NGINX
# Default server — blocks direct access via IP
server {
listen 80 default_server;
listen [::]:80 default_server;
@@ -188,7 +190,7 @@ server {
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name llms.seudominio.com; # Altere para seu domínio
server_name llms.yourdomain.com; # Change to your domain
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
@@ -206,7 +208,7 @@ server {
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection upgrade;
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
@@ -220,61 +222,61 @@ server {
server {
listen 80;
listen [::]:80;
server_name llms.seudominio.com;
server_name llms.yourdomain.com;
return 301 https://$server_name$request_uri;
}
NGINX
```
### 3.3 Ativar e testar
### 3.3 Enable and Test
```bash
# Remover config padrão
# Remove default configuration
rm -f /etc/nginx/sites-enabled/default
# Ativar OmniRoute
# Enable OmniRoute
ln -sf /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
# Testar e recarregar
# Test and reload
nginx -t && systemctl reload nginx
```
---
## 4. Configurar Cloudflare DNS
## 4. Configure Cloudflare DNS
### 4.1 Adicionar registro DNS
### 4.1 Add DNS record
No painel da Cloudflare → DNS:
In the Cloudflare dashboard → DNS:
| Type | Name | Content | Proxy |
| ---- | ------ | ------------------------- | ---------- |
| A | `llms` | `203.0.113.10` (IP da VM) | ✅ Proxied |
| Type | Name | Content | Proxy |
| ---- | ------ | ---------------------- | ---------- |
| A | `llms` | `203.0.113.10` (VM IP) | ✅ Proxied |
### 4.2 Configurar SSL
### 4.2 Configure SSL
Em **SSL/TLS → Overview**:
Under **SSL/TLS → Overview**:
- Modo: **Full (Strict)**
- Mode: **Full (Strict)**
Em **SSL/TLS → Edge Certificates**:
Under **SSL/TLS → Edge Certificates**:
- Always Use HTTPS: ✅ On
- Minimum TLS Version: TLS 1.2
- Automatic HTTPS Rewrites: ✅ On
### 4.3 Testar
### 4.3 Testing
```bash
curl -sI https://llms.seudominio.com/health
# Deve retornar HTTP/2 200
# Should return HTTP/2 200
```
---
## 5. Operações e Manutenção
## 5. Operations and Maintenance
### Atualizar para nova versão
### Upgrade to a new version
```bash
docker pull diegosouzapw/omniroute:latest
@@ -286,42 +288,42 @@ docker run -d --name omniroute --restart unless-stopped \
diegosouzapw/omniroute:latest
```
### Ver logs
### View logs
```bash
docker logs -f omniroute # Stream em tempo real
docker logs omniroute --tail 50 # Últimas 50 linhas
docker logs -f omniroute # Real-time stream
docker logs omniroute --tail 50 # Last 50 lines
```
### Backup manual do banco
### Manual database backup
```bash
# Copiar dados do volume para o host
# Copy data from the volume to the host
docker cp omniroute:/app/data ./backup-$(date +%F)
# Ou comprimir todo o volume
# Or compress the entire volume
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine tar czf /backup/omniroute-data-$(date +%F).tar.gz /data
```
### Restaurar de backup
### Restore from backup
```bash
docker stop omniroute
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine sh -c "rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /"
alpine sh -c rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /
docker start omniroute
```
---
## 6. Segurança Avançada
## 6. Advanced Security
### Restringir nginx para Cloudflare IPs
### Restrict nginx to Cloudflare IPs
```bash
cat > /etc/nginx/cloudflare-ips.conf << 'CF'
# Cloudflare IPv4 ranges — atualizar periodicamente
cat > /etc/nginx/cloudflare-ips.conf << CF
# Cloudflare IPv4 ranges — update periodically
# https://www.cloudflare.com/ips-v4/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
@@ -342,7 +344,7 @@ real_ip_header CF-Connecting-IP;
CF
```
Adicionar no `nginx.conf` dentro do bloco `http {}`:
Add the following to `nginx.conf` inside the `http {}` block:
```nginx
include /etc/nginx/cloudflare-ips.conf;
@@ -355,45 +357,45 @@ apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
# Verificar status
# Check status
fail2ban-client status sshd
```
### Bloquear acesso direto na porta do Docker
### Block direct access to the Docker port
```bash
# Impedir acesso externo direto à porta 20128
# Prevent direct external access to port 20128
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
# Persistir as regras
# Persist the rules
apt install -y iptables-persistent
netfilter-persistent save
```
---
## 7. Deploy do Cloud Worker (Opcional)
## 7. Deploy to Cloudflare Workers (Optional)
Para acesso remoto via Cloudflare Workers (sem expor a VM diretamente):
For remote access via Cloudflare Workers (without exposing the VM directly):
```bash
# No repositório local
# In the local repository
cd omnirouteCloud
npm install
npx wrangler login
npx wrangler deploy
```
Ver documentação completa em [omnirouteCloud/README.md](../omnirouteCloud/README.md).
See the full documentation at [omnirouteCloud/README.md](../omnirouteCloud/README.md).
---
## Resumo de Portas
## Port Summary
| Porta | Serviço | Acesso |
| ----- | ----------- | ----------------------------- |
| 22 | SSH | Público (com fail2ban) |
| 80 | nginx HTTP | Redirect → HTTPS |
| 443 | nginx HTTPS | Via Cloudflare Proxy |
| 20128 | OmniRoute | Somente localhost (via nginx) |
| Port | Service | Access |
| ----- | ----------- | -------------------------- |
| 22 | SSH | Public (with fail2ban) |
| 80 | nginx HTTP | Redirect → HTTPS |
| 443 | nginx HTTPS | Via Cloudflare Proxy |
| 20128 | OmniRoute | Localhost only (via nginx) |

View File

@@ -0,0 +1,46 @@
# ADR-0001: Proxy Registry + Usage Control Generalization
Date: 2026-03-17
Status: Accepted
## Context
OmniRoute sudah punya:
- Proxy assignment berbasis config-map (`global`, `providers`, `combos`, `keys`).
- Quota-aware selection khusus provider tertentu (notably `codex`).
Gap utama:
- Proxy belum menjadi aset reusable yang bisa di-manage sebagai entitas (metadata, where-used, safe delete).
- Usage policy belum konsisten lintas provider.
- Error contract API belum seragam untuk endpoint manajemen.
## Decision
1. Tambah **Proxy Registry** sebagai domain baru di DB (`proxy_registry`, `proxy_assignments`).
2. Pertahankan kompatibilitas assignment lama (fallback ke `proxyConfig` lama).
3. Resolver runtime pakai prioritas:
- account -> provider -> global (registry)
- fallback ke legacy resolver jika registry belum ada assignment
4. Wajib redaction kredensial di output list registry default.
5. Standarkan error JSON untuk endpoint manajemen proxy agar konsisten dan punya `requestId`.
## Consequences
Positif:
- Proxy reusable dan bisa dilacak pemakaiannya.
- Safe delete bisa ditegakkan (409 saat masih dipakai).
- Migrasi bertahap tanpa breaking change runtime.
Negatif:
- Ada dual-source sementara (registry + legacy config) sampai migrasi selesai.
- Butuh endpoint assignment tambahan dan pemetaan scope yang konsisten.
## Follow-up
- Migrasi UI provider/account dari input raw proxy ke selector registry.
- Tambah health telemetry per proxy dan alerting.
- Generalisasi usage control ke provider lain melalui interface policy yang sama.

View File

@@ -0,0 +1,32 @@
# ADR-0002: Error Contract for Management Endpoints
Date: 2026-03-17
Status: Accepted
## Decision
Management endpoints (proxy config, proxy registry, and proxy assignments) return a uniform error body:
```json
{
"error": {
"message": "Human-readable summary",
"type": "invalid_request | not_found | conflict | server_error",
"details": {}
},
"requestId": "uuid"
}
```
## Status Mapping
- 400: invalid request / validation failure
- 404: resource not found
- 409: resource conflict (for example, proxy still assigned)
- 500: unexpected server error
## Notes
- `requestId` is mandatory for log correlation.
- `details` is optional and only used for safe validation details.
- Sensitive secrets (proxy credentials, tokens) must never appear in `message` or `details`.

View File

@@ -0,0 +1,16 @@
# ADR-0003: Security Checklist for Proxy Registry and Usage Controls
Date: 2026-03-17
Status: Accepted
## Checklist
- Validate all management payloads with Zod.
- Reject malformed scope assignment updates with status 400.
- Reject deleting an in-use proxy with status 409 unless forced.
- Never expose proxy username/password in list responses by default.
- Never log raw credentials or token values.
- Keep error responses free from internal stack traces.
- Protect management endpoints with existing auth middleware policy.
- Audit mutating operations: create/update/delete/assign/migrate.
- Ensure resolver fallback to legacy config while migration is in transition.

View File

@@ -1,37 +0,0 @@
# ADR-001: Next.js as the Foundation for an AI Gateway
## Status: Accepted
## Context
OmniRoute is an AI routing gateway that translates, forwards, and manages requests across 20+ LLM providers. We needed a framework that could serve both the API proxy layer and a management dashboard from a single codebase.
**Alternatives considered:**
- **Express.js only** — Simpler proxy, but requires separate frontend tooling
- **Fastify** — Fast, but no built-in SSR/dashboard support
- **Next.js** — Unified full-stack framework with API routes, SSR, and static pages
## Decision
We chose Next.js because:
1. **Single deployment** — API routes (`/api/*`) and dashboard UI in one process
2. **Middleware layer** — Native request interception for auth guards and request tracing
3. **File-based routing** — Easy to map provider endpoints to handlers
4. **Built-in TypeScript** — Type safety across the entire codebase
## Consequences
**Positive:**
- One `npm run build` produces both API and UI
- Middleware provides centralized auth and request tracing
- Dashboard gets automatic code splitting and optimization
**Negative:**
- Next.js middleware has limitations (no heavy imports, edge runtime constraints)
- Serverless deployment model doesn't align with persistent WebSocket/SSE connections
- Build times are longer than Express-only setups
- The SSE proxy layer (`open-sse/`) operates outside Next.js conventions

View File

@@ -1,37 +0,0 @@
# ADR-002: Hub-and-Spoke Translation with OpenAI as Intermediate Format
## Status: Accepted
## Context
OmniRoute routes requests across 20+ providers, each with its own API format (OpenAI, Anthropic Messages, Google Gemini, AWS Bedrock, etc.). Direct provider-to-provider translation would require O(n²) translators.
**Alternatives considered:**
- **Direct translation** — Each pair needs a dedicated translator (n² complexity)
- **Common intermediate format** — Translate to/from a canonical format (2n complexity)
- **Protocol buffers** — Strong typing but heavy overhead for a proxy
## Decision
We use the **OpenAI Chat Completions format** as the canonical intermediate representation. All incoming requests are normalized to OpenAI format, processed, then translated to the target provider's format.
```
Client → [any format] → OpenAI canonical → [target format] → Provider
Provider → [response] → OpenAI canonical → [original format] → Client
```
## Consequences
**Positive:**
- Only 2 translators per provider (inbound + outbound) instead of n² pairs
- OpenAI format is the de facto standard — most clients already use it
- Adding a new provider requires only implementing one translator pair
- Streaming (SSE) works consistently through the canonical format
**Negative:**
- Some provider-specific features may be lost in translation
- The double translation adds latency (typically < 5ms)
- OpenAI format changes require updating the canonical representation

View File

@@ -1,39 +0,0 @@
# ADR-003: Dual Storage — SQLite Primary with JSON Migration Path
## Status: Accepted
## Context
OmniRoute originally used LowDB (JSON file) for all persistence. As the project grew, JSON-based storage became a bottleneck for concurrent access, querying, and data integrity.
**Alternatives considered:**
- **LowDB only** — Simple but no concurrent access, no ACID, no querying
- **SQLite only** — Fast, ACID-compliant, but breaks existing deployments
- **PostgreSQL** — Production-grade but requires external dependency
- **Dual storage with migration** — SQLite primary + automatic JSON migration
## Decision
We migrated to **SQLite as the primary store** with an automatic one-time migration from `db.json`:
1. On startup, if `db.json` exists and SQLite is empty, auto-migrate all data
2. All new reads/writes go through SQLite
3. The `db.json` file is preserved but no longer written to
Settings remain in a hybrid model where LowDB handles simple key-value configuration for backward compatibility.
## Consequences
**Positive:**
- ACID transactions for provider connections, API keys, and usage data
- Proper SQL queries for analytics and log filtering
- Concurrent read/write safety via WAL mode
- Zero-downtime migration from JSON — users upgrade transparently
**Negative:**
- Two storage engines to maintain (SQLite + LowDB for settings)
- Migration code must handle edge cases and partial data
- SQLite binary dependency needed in deployment environments

13
docs/i18n/README.md Normal file
View File

@@ -0,0 +1,13 @@
# Multilingual Documentation
This directory contains machine-assisted translations based on the English docs.
- **API_REFERENCE.md**: 🇺🇸 [English](../API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](./es/API_REFERENCE.md) | 🇫🇷 [Français](./fr/API_REFERENCE.md) | 🇮🇹 [Italiano](./it/API_REFERENCE.md) | 🇷🇺 [Русский](./ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](./zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](./de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](./in/API_REFERENCE.md) | 🇹🇭 [ไทย](./th/API_REFERENCE.md) | 🇺🇦 [Українська](./uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](./ar/API_REFERENCE.md) | 🇯🇵 [日本語](./ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](./vi/API_REFERENCE.md) | 🇧🇬 [Български](./bg/API_REFERENCE.md) | 🇩🇰 [Dansk](./da/API_REFERENCE.md) | 🇫🇮 [Suomi](./fi/API_REFERENCE.md) | 🇮🇱 [עברית](./he/API_REFERENCE.md) | 🇭🇺 [Magyar](./hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](./id/API_REFERENCE.md) | 🇰🇷 [한국어](./ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](./ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](./nl/API_REFERENCE.md) | 🇳🇴 [Norsk](./no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](./pt/API_REFERENCE.md) | 🇷🇴 [Română](./ro/API_REFERENCE.md) | 🇵🇱 [Polski](./pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](./sk/API_REFERENCE.md) | 🇸🇪 [Svenska](./sv/API_REFERENCE.md) | 🇵🇭 [Filipino](./phi/API_REFERENCE.md) | 🇨🇿 [Čeština](./cs/API_REFERENCE.md)
- **ARCHITECTURE.md**: 🇺🇸 [English](../ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](./es/ARCHITECTURE.md) | 🇫🇷 [Français](./fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](./it/ARCHITECTURE.md) | 🇷🇺 [Русский](./ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](./zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](./de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](./in/ARCHITECTURE.md) | 🇹🇭 [ไทย](./th/ARCHITECTURE.md) | 🇺🇦 [Українська](./uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](./ar/ARCHITECTURE.md) | 🇯🇵 [日本語](./ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](./vi/ARCHITECTURE.md) | 🇧🇬 [Български](./bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](./da/ARCHITECTURE.md) | 🇫🇮 [Suomi](./fi/ARCHITECTURE.md) | 🇮🇱 [עברית](./he/ARCHITECTURE.md) | 🇭🇺 [Magyar](./hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](./id/ARCHITECTURE.md) | 🇰🇷 [한국어](./ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](./ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](./nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](./no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](./pt/ARCHITECTURE.md) | 🇷🇴 [Română](./ro/ARCHITECTURE.md) | 🇵🇱 [Polski](./pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](./sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](./sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](./phi/ARCHITECTURE.md) | 🇨🇿 [Čeština](./cs/ARCHITECTURE.md)
- **CODEBASE_DOCUMENTATION.md**: 🇺🇸 [English](../CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](./pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](./es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](./fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](./it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](./ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](./zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](./de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](./in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](./th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](./uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](./ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](./ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](./vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](./bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](./da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](./fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](./he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](./hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](./id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](./ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](./ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](./nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](./no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](./pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](./ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](./pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](./sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](./sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](./phi/CODEBASE_DOCUMENTATION.md) | 🇨🇿 [Čeština](./cs/CODEBASE_DOCUMENTATION.md)
- **FEATURES.md**: 🇺🇸 [English](../FEATURES.md) | 🇧🇷 [Português (Brasil)](./pt-BR/FEATURES.md) | 🇪🇸 [Español](./es/FEATURES.md) | 🇫🇷 [Français](./fr/FEATURES.md) | 🇮🇹 [Italiano](./it/FEATURES.md) | 🇷🇺 [Русский](./ru/FEATURES.md) | 🇨🇳 [中文 (简体)](./zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](./de/FEATURES.md) | 🇮🇳 [हिन्दी](./in/FEATURES.md) | 🇹🇭 [ไทย](./th/FEATURES.md) | 🇺🇦 [Українська](./uk-UA/FEATURES.md) | 🇸🇦 [العربية](./ar/FEATURES.md) | 🇯🇵 [日本語](./ja/FEATURES.md) | 🇻🇳 [Tiếng Việt](./vi/FEATURES.md) | 🇧🇬 [Български](./bg/FEATURES.md) | 🇩🇰 [Dansk](./da/FEATURES.md) | 🇫🇮 [Suomi](./fi/FEATURES.md) | 🇮🇱 [עברית](./he/FEATURES.md) | 🇭🇺 [Magyar](./hu/FEATURES.md) | 🇮🇩 [Bahasa Indonesia](./id/FEATURES.md) | 🇰🇷 [한국어](./ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](./ms/FEATURES.md) | 🇳🇱 [Nederlands](./nl/FEATURES.md) | 🇳🇴 [Norsk](./no/FEATURES.md) | 🇵🇹 [Português (Portugal)](./pt/FEATURES.md) | 🇷🇴 [Română](./ro/FEATURES.md) | 🇵🇱 [Polski](./pl/FEATURES.md) | 🇸🇰 [Slovenčina](./sk/FEATURES.md) | 🇸🇪 [Svenska](./sv/FEATURES.md) | 🇵🇭 [Filipino](./phi/FEATURES.md) | 🇨🇿 [Čeština](./cs/FEATURES.md)
- **TROUBLESHOOTING.md**: 🇺🇸 [English](../TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](./pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](./es/TROUBLESHOOTING.md) | 🇫🇷 [Français](./fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](./it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](./ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](./zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](./de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](./in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](./th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](./uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](./ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](./ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](./vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](./bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](./da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](./fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](./he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](./hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](./id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](./ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](./ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](./nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](./no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](./pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](./ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](./pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](./sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](./sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](./phi/TROUBLESHOOTING.md) | 🇨🇿 [Čeština](./cs/TROUBLESHOOTING.md)
- **USER_GUIDE.md**: 🇺🇸 [English](../USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](./es/USER_GUIDE.md) | 🇫🇷 [Français](./fr/USER_GUIDE.md) | 🇮🇹 [Italiano](./it/USER_GUIDE.md) | 🇷🇺 [Русский](./ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](./zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](./de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](./in/USER_GUIDE.md) | 🇹🇭 [ไทย](./th/USER_GUIDE.md) | 🇺🇦 [Українська](./uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](./ar/USER_GUIDE.md) | 🇯🇵 [日本語](./ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](./vi/USER_GUIDE.md) | 🇧🇬 [Български](./bg/USER_GUIDE.md) | 🇩🇰 [Dansk](./da/USER_GUIDE.md) | 🇫🇮 [Suomi](./fi/USER_GUIDE.md) | 🇮🇱 [עברית](./he/USER_GUIDE.md) | 🇭🇺 [Magyar](./hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](./id/USER_GUIDE.md) | 🇰🇷 [한국어](./ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](./ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](./nl/USER_GUIDE.md) | 🇳🇴 [Norsk](./no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](./pt/USER_GUIDE.md) | 🇷🇴 [Română](./ro/USER_GUIDE.md) | 🇵🇱 [Polski](./pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](./sk/USER_GUIDE.md) | 🇸🇪 [Svenska](./sv/USER_GUIDE.md) | 🇵🇭 [Filipino](./phi/USER_GUIDE.md) | 🇨🇿 [Čeština](./cs/USER_GUIDE.md)
- **VM_DEPLOYMENT_GUIDE.md**: 🇺🇸 [English](../VM_DEPLOYMENT_GUIDE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/VM_DEPLOYMENT_GUIDE.md) | 🇪🇸 [Español](./es/VM_DEPLOYMENT_GUIDE.md) | 🇫🇷 [Français](./fr/VM_DEPLOYMENT_GUIDE.md) | 🇮🇹 [Italiano](./it/VM_DEPLOYMENT_GUIDE.md) | 🇷🇺 [Русский](./ru/VM_DEPLOYMENT_GUIDE.md) | 🇨🇳 [中文 (简体)](./zh-CN/VM_DEPLOYMENT_GUIDE.md) | 🇩🇪 [Deutsch](./de/VM_DEPLOYMENT_GUIDE.md) | 🇮🇳 [हिन्दी](./in/VM_DEPLOYMENT_GUIDE.md) | 🇹🇭 [ไทย](./th/VM_DEPLOYMENT_GUIDE.md) | 🇺🇦 [Українська](./uk-UA/VM_DEPLOYMENT_GUIDE.md) | 🇸🇦 [العربية](./ar/VM_DEPLOYMENT_GUIDE.md) | 🇯🇵 [日本語](./ja/VM_DEPLOYMENT_GUIDE.md) | 🇻🇳 [Tiếng Việt](./vi/VM_DEPLOYMENT_GUIDE.md) | 🇧🇬 [Български](./bg/VM_DEPLOYMENT_GUIDE.md) | 🇩🇰 [Dansk](./da/VM_DEPLOYMENT_GUIDE.md) | 🇫🇮 [Suomi](./fi/VM_DEPLOYMENT_GUIDE.md) | 🇮🇱 [עברית](./he/VM_DEPLOYMENT_GUIDE.md) | 🇭🇺 [Magyar](./hu/VM_DEPLOYMENT_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](./id/VM_DEPLOYMENT_GUIDE.md) | 🇰🇷 [한국어](./ko/VM_DEPLOYMENT_GUIDE.md) | 🇲🇾 [Bahasa Melayu](./ms/VM_DEPLOYMENT_GUIDE.md) | 🇳🇱 [Nederlands](./nl/VM_DEPLOYMENT_GUIDE.md) | 🇳🇴 [Norsk](./no/VM_DEPLOYMENT_GUIDE.md) | 🇵🇹 [Português (Portugal)](./pt/VM_DEPLOYMENT_GUIDE.md) | 🇷🇴 [Română](./ro/VM_DEPLOYMENT_GUIDE.md) | 🇵🇱 [Polski](./pl/VM_DEPLOYMENT_GUIDE.md) | 🇸🇰 [Slovenčina](./sk/VM_DEPLOYMENT_GUIDE.md) | 🇸🇪 [Svenska](./sv/VM_DEPLOYMENT_GUIDE.md) | 🇵🇭 [Filipino](./phi/VM_DEPLOYMENT_GUIDE.md) | 🇨🇿 [Čeština](./cs/VM_DEPLOYMENT_GUIDE.md)
Generated on 2026-03-19.

200
docs/i18n/ar/A2A-SERVER.md Normal file
View File

@@ -0,0 +1,200 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/A2A-SERVER.md) · 🇪🇸 [es](../es/A2A-SERVER.md) · 🇫🇷 [fr](../fr/A2A-SERVER.md) · 🇩🇪 [de](../de/A2A-SERVER.md) · 🇮🇹 [it](../it/A2A-SERVER.md) · 🇷🇺 [ru](../ru/A2A-SERVER.md) · 🇨🇳 [zh-CN](../zh-CN/A2A-SERVER.md) · 🇯🇵 [ja](../ja/A2A-SERVER.md) · 🇰🇷 [ko](../ko/A2A-SERVER.md) · 🇸🇦 [ar](../ar/A2A-SERVER.md) · 🇮🇳 [in](../in/A2A-SERVER.md) · 🇹🇭 [th](../th/A2A-SERVER.md) · 🇻🇳 [vi](../vi/A2A-SERVER.md) · 🇮🇩 [id](../id/A2A-SERVER.md) · 🇲🇾 [ms](../ms/A2A-SERVER.md) · 🇳🇱 [nl](../nl/A2A-SERVER.md) · 🇵🇱 [pl](../pl/A2A-SERVER.md) · 🇸🇪 [sv](../sv/A2A-SERVER.md) · 🇳🇴 [no](../no/A2A-SERVER.md) · 🇩🇰 [da](../da/A2A-SERVER.md) · 🇫🇮 [fi](../fi/A2A-SERVER.md) · 🇵🇹 [pt](../pt/A2A-SERVER.md) · 🇷🇴 [ro](../ro/A2A-SERVER.md) · 🇭🇺 [hu](../hu/A2A-SERVER.md) · 🇧🇬 [bg](../bg/A2A-SERVER.md) · 🇸🇰 [sk](../sk/A2A-SERVER.md) · 🇺🇦 [uk-UA](../uk-UA/A2A-SERVER.md) · 🇮🇱 [he](../he/A2A-SERVER.md) · 🇵🇭 [phi](../phi/A2A-SERVER.md)
---
# OmniRoute A2A Server Documentation
> Agent-to-Agent Protocol v0.3 — OmniRoute as an intelligent routing agent
## Agent Discovery
```bash
curl http://localhost:20128/.well-known/agent.json
```
Returns the Agent Card describing OmniRoute's capabilities, skills, and authentication requirements.
---
## Authentication
All `/a2a` requests require an API key via the `Authorization` header:
```
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
```
If no API key is configured on the server, authentication is bypassed.
---
## JSON-RPC 2.0 Methods
### `message/send` — Synchronous Execution
Sends a message to a skill and waits for the complete response.
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a hello world in Python"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
}
}'
```
**Response:**
```json
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task": { "id": "uuid", "state": "completed" },
"artifacts": [{ "type": "text", "content": "..." }],
"metadata": {
"routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
"cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" },
"resilience_trace": [
{ "event": "primary_selected", "provider": "anthropic", "timestamp": "..." }
],
"policy_verdict": { "allowed": true, "reason": "within budget and quota limits" }
}
}
}
```
### `message/stream` — SSE Streaming
Same as `message/send` but returns Server-Sent Events for real-time streaming.
```bash
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}
}'
```
**SSE Events:**
```
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
```
### `tasks/get` — Query Task Status
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'
```
### `tasks/cancel` — Cancel a Task
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'
```
---
## Available Skills
| Skill | Description |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------ |
| `smart-routing` | Routes prompts through OmniRoute's intelligent pipeline. Returns response with routing explanation, cost, and resilience trace. |
| `quota-management` | Answers natural-language queries about provider quotas, suggests free combos, and provides quota rankings. |
---
## Task Lifecycle
```
submitted → working → completed
→ failed
→ cancelled
```
- Tasks expire after 5 minutes (configurable)
- Terminal states: `completed`, `failed`, `cancelled`
- Event log tracks every state transition
---
## Error Codes
| Code | Meaning |
| :----- | :----------------------------- |
| -32700 | Parse error (invalid JSON) |
| -32600 | Invalid request / Unauthorized |
| -32601 | Method or skill not found |
| -32602 | Invalid params |
| -32603 | Internal error |
---
## Integration Examples
### Python (requests)
```python
import requests
resp = requests.post("http://localhost:20128/a2a", json={
"jsonrpc": "2.0", "id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Hello"}]
}
}, headers={"Authorization": "Bearer YOUR_KEY"})
result = resp.json()["result"]
print(result["artifacts"][0]["content"])
print(result["metadata"]["routing_explanation"])
```
### TypeScript (fetch)
```typescript
const resp = await fetch("http://localhost:20128/a2a", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_KEY",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "message/send",
params: {
skill: "smart-routing",
messages: [{ role: "user", content: "Hello" }],
},
}),
});
const { result } = await resp.json();
console.log(result.metadata.routing_explanation);
```

View File

@@ -0,0 +1,455 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/API_REFERENCE.md) · 🇪🇸 [es](../es/API_REFERENCE.md) · 🇫🇷 [fr](../fr/API_REFERENCE.md) · 🇩🇪 [de](../de/API_REFERENCE.md) · 🇮🇹 [it](../it/API_REFERENCE.md) · 🇷🇺 [ru](../ru/API_REFERENCE.md) · 🇨🇳 [zh-CN](../zh-CN/API_REFERENCE.md) · 🇯🇵 [ja](../ja/API_REFERENCE.md) · 🇰🇷 [ko](../ko/API_REFERENCE.md) · 🇸🇦 [ar](../ar/API_REFERENCE.md) · 🇮🇳 [in](../in/API_REFERENCE.md) · 🇹🇭 [th](../th/API_REFERENCE.md) · 🇻🇳 [vi](../vi/API_REFERENCE.md) · 🇮🇩 [id](../id/API_REFERENCE.md) · 🇲🇾 [ms](../ms/API_REFERENCE.md) · 🇳🇱 [nl](../nl/API_REFERENCE.md) · 🇵🇱 [pl](../pl/API_REFERENCE.md) · 🇸🇪 [sv](../sv/API_REFERENCE.md) · 🇳🇴 [no](../no/API_REFERENCE.md) · 🇩🇰 [da](../da/API_REFERENCE.md) · 🇫🇮 [fi](../fi/API_REFERENCE.md) · 🇵🇹 [pt](../pt/API_REFERENCE.md) · 🇷🇴 [ro](../ro/API_REFERENCE.md) · 🇭🇺 [hu](../hu/API_REFERENCE.md) · 🇧🇬 [bg](../bg/API_REFERENCE.md) · 🇸🇰 [sk](../sk/API_REFERENCE.md) · 🇺🇦 [uk-UA](../uk-UA/API_REFERENCE.md) · 🇮🇱 [he](../he/API_REFERENCE.md) · 🇵🇭 [phi](../phi/API_REFERENCE.md)
---
# API Reference
🌐 **Languages:** 🇺🇸 [English](API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](i18n/es/API_REFERENCE.md) | 🇫🇷 [Français](i18n/fr/API_REFERENCE.md) | 🇮🇹 [Italiano](i18n/it/API_REFERENCE.md) | 🇷🇺 [Русский](i18n/ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](i18n/de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](i18n/in/API_REFERENCE.md) | 🇹🇭 [ไทย](i18n/th/API_REFERENCE.md) | 🇺🇦 [Українська](i18n/uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](i18n/ar/API_REFERENCE.md) | 🇯🇵 [日本語](i18n/ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/API_REFERENCE.md) | 🇧🇬 [Български](i18n/bg/API_REFERENCE.md) | 🇩🇰 [Dansk](i18n/da/API_REFERENCE.md) | 🇫🇮 [Suomi](i18n/fi/API_REFERENCE.md) | 🇮🇱 [עברית](i18n/he/API_REFERENCE.md) | 🇭🇺 [Magyar](i18n/hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/API_REFERENCE.md) | 🇰🇷 [한국어](i18n/ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](i18n/nl/API_REFERENCE.md) | 🇳🇴 [Norsk](i18n/no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/API_REFERENCE.md) | 🇷🇴 [Română](i18n/ro/API_REFERENCE.md) | 🇵🇱 [Polski](i18n/pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](i18n/sk/API_REFERENCE.md) | 🇸🇪 [Svenska](i18n/sv/API_REFERENCE.md) | 🇵🇭 [Filipino](i18n/phi/API_REFERENCE.md)
Complete reference for all OmniRoute API endpoints.
---
## Table of Contents
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [List Models](#list-models)
- [Compatibility Endpoints](#compatibility-endpoints)
- [Semantic Cache](#semantic-cache)
- [Dashboard & Management](#dashboard--management)
- [Request Processing](#request-processing)
- [Authentication](#authentication)
---
## Chat Completions
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### Custom Headers
| Header | Direction | Description |
| ------------------------ | --------- | --------------------------------- |
| `X-OmniRoute-No-Cache` | Request | Set to `true` to bypass cache |
| `X-OmniRoute-Progress` | Request | Set to `true` for progress events |
| `Idempotency-Key` | Request | Dedup key (5s window) |
| `X-Request-Id` | Request | Alternative dedup key |
| `X-OmniRoute-Cache` | Response | `HIT` or `MISS` (non-streaming) |
| `X-OmniRoute-Idempotent` | Response | `true` if deduplicated |
| `X-OmniRoute-Progress` | Response | `enabled` if progress tracking on |
---
## Embeddings
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
Available providers: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## Image Generation
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
Available providers: OpenAI (DALL-E), xAI (Grok Image), Together AI (FLUX), Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## List Models
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## Compatibility Endpoints
| Method | Path | Format |
| ------ | --------------------------- | ---------------------- |
| POST | `/v1/chat/completions` | OpenAI |
| POST | `/v1/messages` | Anthropic |
| POST | `/v1/responses` | OpenAI Responses |
| POST | `/v1/embeddings` | OpenAI |
| POST | `/v1/images/generations` | OpenAI |
| GET | `/v1/models` | OpenAI |
| POST | `/v1/messages/count_tokens` | Anthropic |
| GET | `/v1beta/models` | Gemini |
| POST | `/v1beta/models/{...path}` | Gemini generateContent |
| POST | `/v1/api/chat` | Ollama |
### Dedicated Provider Routes
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
---
## Semantic Cache
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
Response example:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## Dashboard & Management
### Authentication
| Endpoint | Method | Description |
| ----------------------------- | ------- | --------------------- |
| `/api/auth/login` | POST | Login |
| `/api/auth/logout` | POST | Logout |
| `/api/settings/require-login` | GET/PUT | Toggle login required |
### Provider Management
| Endpoint | Method | Description |
| ---------------------------- | --------------- | ------------------------ |
| `/api/providers` | GET/POST | List / create providers |
| `/api/providers/[id]` | GET/PUT/DELETE | Manage a provider |
| `/api/providers/[id]/test` | POST | Test provider connection |
| `/api/providers/[id]/models` | GET | List provider models |
| `/api/providers/validate` | POST | Validate provider config |
| `/api/provider-nodes*` | Various | Provider node management |
| `/api/provider-models` | GET/POST/DELETE | Custom models |
### OAuth Flows
| Endpoint | Method | Description |
| -------------------------------- | ------- | ----------------------- |
| `/api/oauth/[provider]/[action]` | Various | Provider-specific OAuth |
### Routing & Config
| Endpoint | Method | Description |
| --------------------- | -------- | ----------------------------- |
| `/api/models/alias` | GET/POST | Model aliases |
| `/api/models/catalog` | GET | All models by provider + type |
| `/api/combos*` | Various | Combo management |
| `/api/keys*` | Various | API key management |
| `/api/pricing` | GET | Model pricing |
### Usage & Analytics
| Endpoint | Method | Description |
| --------------------------- | ------ | -------------------- |
| `/api/usage/history` | GET | Usage history |
| `/api/usage/logs` | GET | Usage logs |
| `/api/usage/request-logs` | GET | Request-level logs |
| `/api/usage/[connectionId]` | GET | Per-connection usage |
### Settings
| Endpoint | Method | Description |
| ------------------------------- | ------- | ---------------------- |
| `/api/settings` | GET/PUT | General settings |
| `/api/settings/proxy` | GET/PUT | Network proxy config |
| `/api/settings/proxy/test` | POST | Test proxy connection |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt |
### Monitoring
| Endpoint | Method | Description |
| ------------------------ | ---------- | ----------------------- |
| `/api/sessions` | GET | Active session tracking |
| `/api/rate-limits` | GET | Per-account rate limits |
| `/api/monitoring/health` | GET | Health check |
| `/api/cache` | GET/DELETE | Cache stats / clear |
### Backup & Export/Import
| Endpoint | Method | Description |
| --------------------------- | ------ | --------------------------------------- |
| `/api/db-backups` | GET | List available backups |
| `/api/db-backups` | PUT | Create a manual backup |
| `/api/db-backups` | POST | Restore from a specific backup |
| `/api/db-backups/export` | GET | Download database as .sqlite file |
| `/api/db-backups/import` | POST | Upload .sqlite file to replace database |
| `/api/db-backups/exportAll` | GET | Download full backup as .tar.gz archive |
### Cloud Sync
| Endpoint | Method | Description |
| ---------------------- | ------- | --------------------- |
| `/api/sync/cloud` | Various | Cloud sync operations |
| `/api/sync/initialize` | POST | Initialize sync |
| `/api/cloud/*` | Various | Cloud management |
### CLI Tools
| Endpoint | Method | Description |
| ---------------------------------- | ------ | ------------------- |
| `/api/cli-tools/claude-settings` | GET | Claude CLI status |
| `/api/cli-tools/codex-settings` | GET | Codex CLI status |
| `/api/cli-tools/droid-settings` | GET | Droid CLI status |
| `/api/cli-tools/openclaw-settings` | GET | OpenClaw CLI status |
| `/api/cli-tools/runtime/[toolId]` | GET | Generic CLI runtime |
CLI responses include: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`.
### ACP Agents
| Endpoint | Method | Description |
| ----------------- | ------ | -------------------------------------------------------- |
| `/api/acp/agents` | GET | List all detected agents (built-in + custom) with status |
| `/api/acp/agents` | POST | Add custom agent or refresh detection cache |
| `/api/acp/agents` | DELETE | Remove a custom agent by `id` query param |
GET response includes `agents[]` (id, name, binary, version, installed, protocol, isCustom) and `summary` (total, installed, notFound, builtIn, custom).
### Resilience & Rate Limits
| Endpoint | Method | Description |
| ----------------------- | ------- | ------------------------------- |
| `/api/resilience` | GET/PUT | Get/update resilience profiles |
| `/api/resilience/reset` | POST | Reset circuit breakers |
| `/api/rate-limits` | GET | Per-account rate limit status |
| `/api/rate-limit` | GET | Global rate limit configuration |
### Evals
| Endpoint | Method | Description |
| ------------ | -------- | --------------------------------- |
| `/api/evals` | GET/POST | List eval suites / run evaluation |
### Policies
| Endpoint | Method | Description |
| --------------- | --------------- | ----------------------- |
| `/api/policies` | GET/POST/DELETE | Manage routing policies |
### Compliance
| Endpoint | Method | Description |
| --------------------------- | ------ | ----------------------------- |
| `/api/compliance/audit-log` | GET | Compliance audit log (last N) |
### v1beta (Gemini-Compatible)
| Endpoint | Method | Description |
| -------------------------- | ------ | --------------------------------- |
| `/v1beta/models` | GET | List models in Gemini format |
| `/v1beta/models/{...path}` | POST | Gemini `generateContent` endpoint |
These endpoints mirror Gemini's API format for clients that expect native Gemini SDK compatibility.
### Internal / System APIs
| Endpoint | Method | Description |
| --------------- | ------ | ---------------------------------------------------- |
| `/api/init` | GET | Application initialization check (used on first run) |
| `/api/tags` | GET | Ollama-compatible model tags (for Ollama clients) |
| `/api/restart` | POST | Trigger graceful server restart |
| `/api/shutdown` | POST | Trigger graceful server shutdown |
> **Note:** These endpoints are used internally by the system or for Ollama client compatibility. They are not typically called by end users.
---
## Audio Transcription
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
Transcribe audio files using Deepgram or AssemblyAI.
**Request:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**Response:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**Supported providers:** `deepgram/nova-3`, `assemblyai/best`.
**Supported formats:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
## Ollama Compatibility
For clients that use Ollama's API format:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
Requests are automatically translated between Ollama and internal formats.
---
## Telemetry
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**Response:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## Budget
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## Model Availability
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## Request Processing
1. Client sends request to `/v1/*`
2. Route handler calls `handleChat`, `handleEmbedding`, `handleAudioTranscription`, or `handleImageGeneration`
3. Model is resolved (direct provider/model or alias/combo)
4. Credentials selected from local DB with account availability filtering
5. For chat: `handleChatCore` — format detection, translation, cache check, idempotency check
6. Provider executor sends upstream request
7. Response translated back to client format (chat) or returned as-is (embeddings/images/audio)
8. Usage/logging recorded
9. Fallback applies on errors according to combo rules
Full architecture reference: [`ARCHITECTURE.md`](ARCHITECTURE.md)
---
## Authentication
- Dashboard routes (`/dashboard/*`) use `auth_token` cookie
- Login uses saved password hash; fallback to `INITIAL_PASSWORD`
- `requireLogin` toggleable via `/api/settings/require-login`
- `/v1/*` routes optionally require Bearer API key when `REQUIRE_API_KEY=true`

View File

@@ -0,0 +1,787 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/ARCHITECTURE.md) · 🇪🇸 [es](../es/ARCHITECTURE.md) · 🇫🇷 [fr](../fr/ARCHITECTURE.md) · 🇩🇪 [de](../de/ARCHITECTURE.md) · 🇮🇹 [it](../it/ARCHITECTURE.md) · 🇷🇺 [ru](../ru/ARCHITECTURE.md) · 🇨🇳 [zh-CN](../zh-CN/ARCHITECTURE.md) · 🇯🇵 [ja](../ja/ARCHITECTURE.md) · 🇰🇷 [ko](../ko/ARCHITECTURE.md) · 🇸🇦 [ar](../ar/ARCHITECTURE.md) · 🇮🇳 [in](../in/ARCHITECTURE.md) · 🇹🇭 [th](../th/ARCHITECTURE.md) · 🇻🇳 [vi](../vi/ARCHITECTURE.md) · 🇮🇩 [id](../id/ARCHITECTURE.md) · 🇲🇾 [ms](../ms/ARCHITECTURE.md) · 🇳🇱 [nl](../nl/ARCHITECTURE.md) · 🇵🇱 [pl](../pl/ARCHITECTURE.md) · 🇸🇪 [sv](../sv/ARCHITECTURE.md) · 🇳🇴 [no](../no/ARCHITECTURE.md) · 🇩🇰 [da](../da/ARCHITECTURE.md) · 🇫🇮 [fi](../fi/ARCHITECTURE.md) · 🇵🇹 [pt](../pt/ARCHITECTURE.md) · 🇷🇴 [ro](../ro/ARCHITECTURE.md) · 🇭🇺 [hu](../hu/ARCHITECTURE.md) · 🇧🇬 [bg](../bg/ARCHITECTURE.md) · 🇸🇰 [sk](../sk/ARCHITECTURE.md) · 🇺🇦 [uk-UA](../uk-UA/ARCHITECTURE.md) · 🇮🇱 [he](../he/ARCHITECTURE.md) · 🇵🇭 [phi](../phi/ARCHITECTURE.md)
---
# OmniRoute Architecture
🌐 **Languages:** 🇺🇸 [English](ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](i18n/es/ARCHITECTURE.md) | 🇫🇷 [Français](i18n/fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](i18n/it/ARCHITECTURE.md) | 🇷🇺 [Русский](i18n/ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](i18n/de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](i18n/in/ARCHITECTURE.md) | 🇹🇭 [ไทย](i18n/th/ARCHITECTURE.md) | 🇺🇦 [Українська](i18n/uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](i18n/ar/ARCHITECTURE.md) | 🇯🇵 [日本語](i18n/ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/ARCHITECTURE.md) | 🇧🇬 [Български](i18n/bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](i18n/da/ARCHITECTURE.md) | 🇫🇮 [Suomi](i18n/fi/ARCHITECTURE.md) | 🇮🇱 [עברית](i18n/he/ARCHITECTURE.md) | 🇭🇺 [Magyar](i18n/hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/ARCHITECTURE.md) | 🇰🇷 [한국어](i18n/ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](i18n/nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](i18n/no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/ARCHITECTURE.md) | 🇷🇴 [Română](i18n/ro/ARCHITECTURE.md) | 🇵🇱 [Polski](i18n/pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](i18n/sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](i18n/sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](i18n/phi/ARCHITECTURE.md)
_Last updated: 2026-03-04_
## Executive Summary
OmniRoute is a local AI routing gateway and dashboard built on Next.js.
It provides a single OpenAI-compatible endpoint (`/v1/*`) and routes traffic across multiple upstream providers with translation, fallback, token refresh, and usage tracking.
Core capabilities:
- OpenAI-compatible API surface for CLI/tools (28 providers)
- Request/response translation across provider formats
- Model combo fallback (multi-model sequence)
- Account-level fallback (multi-account per provider)
- OAuth + API-key provider connection management
- Embedding generation via `/v1/embeddings` (6 providers, 9 models)
- Image generation via `/v1/images/generations` (4 providers, 9 models)
- Think tag parsing (`<think>...</think>`) for reasoning models
- Response sanitization for strict OpenAI SDK compatibility
- Role normalization (developer→system, system→user) for cross-provider compatibility
- Structured output conversion (json_schema → Gemini responseSchema)
- Local persistence for providers, keys, aliases, combos, settings, pricing
- Usage/cost tracking and request logging
- Optional cloud sync for multi-device/state sync
- IP allowlist/blocklist for API access control
- Thinking budget management (passthrough/auto/custom/adaptive)
- Global system prompt injection
- Session tracking and fingerprinting
- Per-account enhanced rate limiting with provider-specific profiles
- Circuit breaker pattern for provider resilience
- Anti-thundering herd protection with mutex locking
- Signature-based request deduplication cache
- Domain layer: model availability, cost rules, fallback policy, lockout policy
- Domain state persistence (SQLite write-through cache for fallbacks, budgets, lockouts, circuit breakers)
- Policy engine for centralized request evaluation (lockout → budget → fallback)
- Request telemetry with p50/p95/p99 latency aggregation
- Correlation ID (X-Request-Id) for end-to-end tracing
- Compliance audit logging with opt-out per API key
- Eval framework for LLM quality assurance
- Resilience UI dashboard with real-time circuit breaker status
- Modular OAuth providers (12 individual modules under `src/lib/oauth/providers/`)
Primary runtime model:
- Next.js app routes under `src/app/api/*` implement both dashboard APIs and compatibility APIs
- A shared SSE/routing core in `src/sse/*` + `open-sse/*` handles provider execution, translation, streaming, fallback, and usage
## Scope and Boundaries
### In Scope
- Local gateway runtime
- Dashboard management APIs
- Provider authentication and token refresh
- Request translation and SSE streaming
- Local state + usage persistence
- Optional cloud sync orchestration
### Out of Scope
- Cloud service implementation behind `NEXT_PUBLIC_CLOUD_URL`
- Provider SLA/control plane outside local process
- External CLI binaries themselves (Claude CLI, Codex CLI, etc.)
## High-Level System Context
```mermaid
flowchart LR
subgraph Clients[Developer Clients]
C1[Claude Code]
C2[Codex CLI]
C3[OpenClaw / Droid / Cline / Continue / Roo]
C4[Custom OpenAI-compatible clients]
BROWSER[Browser Dashboard]
end
subgraph Router[OmniRoute Local Process]
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(storage.sqlite)]
UDB[(usage tables + log artifacts)]
end
subgraph Upstreams[Upstream Providers]
P1[OAuth Providers\nClaude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity]
P2[API Key Providers\nOpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax\nDeepSeek/Groq/xAI/Mistral/Perplexity\nTogether/Fireworks/Cerebras/Cohere/NVIDIA]
P3[Compatible Nodes\nOpenAI-compatible / Anthropic-compatible]
end
subgraph Cloud[Optional Cloud Sync]
CLOUD[Cloud Sync Endpoint\nNEXT_PUBLIC_CLOUD_URL]
end
C1 --> API
C2 --> API
C3 --> API
C4 --> API
BROWSER --> DASH
API --> CORE
DASH --> DB
CORE --> DB
CORE --> UDB
CORE --> P1
CORE --> P2
CORE --> P3
DASH --> CLOUD
```
## Core Runtime Components
## 1) API and Routing Layer (Next.js App Routes)
Main directories:
- `src/app/api/v1/*` and `src/app/api/v1beta/*` for compatibility APIs
- `src/app/api/*` for management/configuration APIs
- Next rewrites in `next.config.mjs` map `/v1/*` to `/api/v1/*`
Important compatibility routes:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — includes custom models with `custom: true`
- `src/app/api/v1/embeddings/route.ts` — embedding generation (6 providers)
- `src/app/api/v1/images/generations/route.ts` — image generation (4+ providers incl. Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — dedicated per-provider chat
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — dedicated per-provider embeddings
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — dedicated per-provider images
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
Management domains:
- Auth/settings: `src/app/api/auth/*`, `src/app/api/settings/*`
- Providers/connections: `src/app/api/providers*`
- Provider nodes: `src/app/api/provider-nodes*`
- Custom models: `src/app/api/provider-models` (GET/POST/DELETE)
- Model catalog: `src/app/api/models/route.ts` (GET)
- Proxy config: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- Keys/aliases/combos/pricing: `src/app/api/keys*`, `src/app/api/models/alias`, `src/app/api/combos*`, `src/app/api/pricing`
- Usage: `src/app/api/usage/*`
- Sync/cloud: `src/app/api/sync/*`, `src/app/api/cloud/*`
- CLI tooling helpers: `src/app/api/cli-tools/*`
- IP filter: `src/app/api/settings/ip-filter` (GET/PUT)
- Thinking budget: `src/app/api/settings/thinking-budget` (GET/PUT)
- System prompt: `src/app/api/settings/system-prompt` (GET/PUT)
- Sessions: `src/app/api/sessions` (GET)
- Rate limits: `src/app/api/rate-limits` (GET)
- Resilience: `src/app/api/resilience` (GET/PATCH) — provider profiles, circuit breaker, rate limit state
- Resilience reset: `src/app/api/resilience/reset` (POST) — reset breakers + cooldowns
- Cache stats: `src/app/api/cache/stats` (GET/DELETE)
- Model availability: `src/app/api/models/availability` (GET/POST)
- Telemetry: `src/app/api/telemetry/summary` (GET)
- Budget: `src/app/api/usage/budget` (GET/POST)
- Fallback chains: `src/app/api/fallback/chains` (GET/POST/DELETE)
- Compliance audit: `src/app/api/compliance/audit-log` (GET)
- Evals: `src/app/api/evals` (GET/POST), `src/app/api/evals/[suiteId]` (GET)
- Policies: `src/app/api/policies` (GET/POST)
## 2) SSE + Translation Core
Main flow modules:
- Entry: `src/sse/handlers/chat.ts`
- Core orchestration: `open-sse/handlers/chatCore.ts`
- Provider execution adapters: `open-sse/executors/*`
- Format detection/provider config: `open-sse/services/provider.ts`
- Model parse/resolve: `src/sse/services/model.ts`, `open-sse/services/model.ts`
- Account fallback logic: `open-sse/services/accountFallback.ts`
- Translation registry: `open-sse/translator/index.ts`
- Stream transformations: `open-sse/utils/stream.ts`, `open-sse/utils/streamHandler.ts`
- Usage extraction/normalization: `open-sse/utils/usageTracking.ts`
- Think tag parser: `open-sse/utils/thinkTagParser.ts`
- Embedding handler: `open-sse/handlers/embeddings.ts`
- Embedding provider registry: `open-sse/config/embeddingRegistry.ts`
- Image generation handler: `open-sse/handlers/imageGeneration.ts`
- Image provider registry: `open-sse/config/imageRegistry.ts`
- Response sanitization: `open-sse/handlers/responseSanitizer.ts`
- Role normalization: `open-sse/services/roleNormalizer.ts`
Services (business logic):
- Account selection/scoring: `open-sse/services/accountSelector.ts`
- Context lifecycle management: `open-sse/services/contextManager.ts`
- IP filter enforcement: `open-sse/services/ipFilter.ts`
- Session tracking: `open-sse/services/sessionManager.ts`
- Request deduplication: `open-sse/services/signatureCache.ts`
- System prompt injection: `open-sse/services/systemPrompt.ts`
- Thinking budget management: `open-sse/services/thinkingBudget.ts`
- Wildcard model routing: `open-sse/services/wildcardRouter.ts`
- Rate limit management: `open-sse/services/rateLimitManager.ts`
- Circuit breaker: `open-sse/services/circuitBreaker.ts`
Domain layer modules:
- Model availability: `src/lib/domain/modelAvailability.ts`
- Cost rules/budgets: `src/lib/domain/costRules.ts`
- Fallback policy: `src/lib/domain/fallbackPolicy.ts`
- Combo resolver: `src/lib/domain/comboResolver.ts`
- Lockout policy: `src/lib/domain/lockoutPolicy.ts`
- Policy engine: `src/domain/policyEngine.ts` — centralized lockout → budget → fallback evaluation
- Error codes catalog: `src/lib/domain/errorCodes.ts`
- Request ID: `src/lib/domain/requestId.ts`
- Fetch timeout: `src/lib/domain/fetchTimeout.ts`
- Request telemetry: `src/lib/domain/requestTelemetry.ts`
- Compliance/audit: `src/lib/domain/compliance/index.ts`
- Eval runner: `src/lib/domain/evalRunner.ts`
- Domain state persistence: `src/lib/db/domainState.ts` — SQLite CRUD for fallback chains, budgets, cost history, lockout state, circuit breakers
OAuth provider modules (12 individual files under `src/lib/oauth/providers/`):
- Registry index: `src/lib/oauth/providers/index.ts`
- Individual providers: `claude.ts`, `codex.ts`, `gemini.ts`, `antigravity.ts`, `iflow.ts`, `qwen.ts`, `kimi-coding.ts`, `github.ts`, `kiro.ts`, `cursor.ts`, `kilocode.ts`, `cline.ts`
- Thin wrapper: `src/lib/oauth/providers.ts` — re-exports from individual modules
## 3) Persistence Layer
Primary state DB (SQLite):
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
Usage persistence:
- facade: `src/lib/usageDb.ts` (decomposed modules in `src/lib/usage/*`)
- SQLite tables in `storage.sqlite`: `usage_history`, `call_logs`, `proxy_logs`
- optional file artifacts remain for compatibility/debug (`${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`, `<repo>/logs/...`)
- legacy JSON files are migrated to SQLite by startup migrations when present
Domain State DB (SQLite):
- `src/lib/db/domainState.ts` — CRUD operations for domain state
- Tables (created in `src/lib/db/core.ts`): `domain_fallback_chains`, `domain_budgets`, `domain_cost_history`, `domain_lockout_state`, `domain_circuit_breakers`
- Write-through cache pattern: in-memory Maps are authoritative at runtime; mutations are written synchronously to SQLite; state is restored from DB on cold start
## 4) Auth + Security Surfaces
- Dashboard cookie auth: `src/proxy.ts`, `src/app/api/auth/login/route.ts`
- API key generation/verification: `src/shared/utils/apiKey.ts`
- Provider secrets persisted in `providerConnections` entries
- Outbound proxy support via `open-sse/utils/proxyFetch.ts` (env vars) and `open-sse/utils/networkProxy.ts` (configurable per-provider or global)
## 5) Cloud Sync
- Scheduler init: `src/lib/initCloudSync.ts`, `src/shared/services/initializeCloudSync.ts`
- Periodic task: `src/shared/services/cloudSyncScheduler.ts`
- Control route: `src/app/api/sync/cloud/route.ts`
## Request Lifecycle (`/v1/chat/completions`)
```mermaid
sequenceDiagram
autonumber
participant Client as CLI/SDK Client
participant Route as /api/v1/chat/completions
participant Chat as src/sse/handlers/chat
participant Core as open-sse/handlers/chatCore
participant Model as Model Resolver
participant Auth as Credential Selector
participant Exec as Provider Executor
participant Prov as Upstream Provider
participant Stream as Stream Translator
participant Usage as usageDb
Client->>Route: POST /v1/chat/completions
Route->>Chat: handleChat(request)
Chat->>Model: parse/resolve model or combo
alt Combo model
Chat->>Chat: iterate combo models (handleComboChat)
end
Chat->>Auth: getProviderCredentials(provider)
Auth-->>Chat: active account + tokens/api key
Chat->>Core: handleChatCore(body, modelInfo, credentials)
Core->>Core: detect source format
Core->>Core: translate request to target format
Core->>Exec: execute(provider, transformedBody)
Exec->>Prov: upstream API call
Prov-->>Exec: SSE/JSON response
Exec-->>Core: response + metadata
alt 401/403
Core->>Exec: refreshCredentials()
Exec-->>Core: updated tokens
Core->>Exec: retry request
end
Core->>Stream: translate/normalize stream to client format
Stream-->>Client: SSE chunks / JSON response
Stream->>Usage: extract usage + persist history/log
```
## Combo + Account Fallback Flow
```mermaid
flowchart TD
A[Incoming model string] --> B{Is combo name?}
B -- Yes --> C[Load combo models sequence]
B -- No --> D[Single model path]
C --> E[Try model N]
E --> F[Resolve provider/model]
D --> F
F --> G[Select account credentials]
G --> H{Credentials available?}
H -- No --> I[Return provider unavailable]
H -- Yes --> J[Execute request]
J --> K{Success?}
K -- Yes --> L[Return response]
K -- No --> M{Fallback-eligible error?}
M -- No --> N[Return error]
M -- Yes --> O[Mark account unavailable cooldown]
O --> P{Another account for provider?}
P -- Yes --> G
P -- No --> Q{In combo with next model?}
Q -- Yes --> E
Q -- No --> R[Return all unavailable]
```
Fallback decisions are driven by `open-sse/services/accountFallback.ts` using status codes and error-message heuristics.
## OAuth Onboarding and Token Refresh Lifecycle
```mermaid
sequenceDiagram
autonumber
participant UI as Dashboard UI
participant OAuth as /api/oauth/[provider]/[action]
participant ProvAuth as Provider Auth Server
participant DB as localDb
participant Test as /api/providers/[id]/test
participant Exec as Provider Executor
UI->>OAuth: GET authorize or device-code
OAuth->>ProvAuth: create auth/device flow
ProvAuth-->>OAuth: auth URL or device code payload
OAuth-->>UI: flow data
UI->>OAuth: POST exchange or poll
OAuth->>ProvAuth: token exchange/poll
ProvAuth-->>OAuth: access/refresh tokens
OAuth->>DB: createProviderConnection(oauth data)
OAuth-->>UI: success + connection id
UI->>Test: POST /api/providers/[id]/test
Test->>Exec: validate credentials / optional refresh
Exec-->>Test: valid or refreshed token info
Test->>DB: update status/tokens/errors
Test-->>UI: validation result
```
Refresh during live traffic is executed inside `open-sse/handlers/chatCore.ts` via executor `refreshCredentials()`.
## Cloud Sync Lifecycle (Enable / Sync / Disable)
```mermaid
sequenceDiagram
autonumber
participant UI as Endpoint Page UI
participant Sync as /api/sync/cloud
participant DB as localDb
participant Cloud as External Cloud Sync
participant Claude as ~/.claude/settings.json
UI->>Sync: POST action=enable
Sync->>DB: set cloudEnabled=true
Sync->>DB: ensure API key exists
Sync->>Cloud: POST /sync/{machineId} (providers/aliases/combos/keys)
Cloud-->>Sync: sync result
Sync->>Cloud: GET /{machineId}/v1/verify
Sync-->>UI: enabled + verification status
UI->>Sync: POST action=sync
Sync->>Cloud: POST /sync/{machineId}
Cloud-->>Sync: remote data
Sync->>DB: update newer local tokens/status
Sync-->>UI: synced
UI->>Sync: POST action=disable
Sync->>DB: set cloudEnabled=false
Sync->>Cloud: DELETE /sync/{machineId}
Sync->>Claude: switch ANTHROPIC_BASE_URL back to local (if needed)
Sync-->>UI: disabled
```
Periodic sync is triggered by `CloudSyncScheduler` when cloud is enabled.
## Data Model and Storage Map
```mermaid
erDiagram
SETTINGS ||--o{ PROVIDER_CONNECTION : controls
PROVIDER_NODE ||--o{ PROVIDER_CONNECTION : backs_compatible_provider
PROVIDER_CONNECTION ||--o{ USAGE_ENTRY : emits_usage
SETTINGS {
boolean cloudEnabled
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
string id
string provider
string authType
string name
number priority
boolean isActive
string apiKey
string accessToken
string refreshToken
string expiresAt
string testStatus
string lastError
string rateLimitedUntil
json providerSpecificData
}
PROVIDER_NODE {
string id
string type
string name
string prefix
string apiType
string baseUrl
}
MODEL_ALIAS {
string alias
string targetModel
}
COMBO {
string id
string name
string[] models
}
API_KEY {
string id
string name
string key
string machineId
}
USAGE_ENTRY {
string provider
string model
number prompt_tokens
number completion_tokens
string connectionId
string timestamp
}
CUSTOM_MODEL {
string id
string name
string providerId
}
PROXY_CONFIG {
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
Physical storage files:
- primary runtime DB: `${DATA_DIR}/storage.sqlite`
- request log lines: `${DATA_DIR}/log.txt` (compat/debug artifact)
- structured call payload archives: `${DATA_DIR}/call_logs/`
- optional translator/request debug sessions: `<repo>/logs/...`
## Deployment Topology
```mermaid
flowchart LR
subgraph LocalHost[Developer Host]
CLI[CLI Tools]
Browser[Dashboard Browser]
end
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(storage.sqlite)]
UsageDB[(usage tables + log artifacts)]
end
subgraph External[External Services]
Providers[AI Providers]
SyncCloud[Cloud Sync Service]
end
CLI --> Next
Browser --> Next
Next --> Core
Next --> MainDB
Core --> MainDB
Core --> UsageDB
Core --> Providers
Next --> SyncCloud
```
## Module Mapping (Decision-Critical)
### Route and API Modules
- `src/app/api/v1/*`, `src/app/api/v1beta/*`: compatibility APIs
- `src/app/api/v1/providers/[provider]/*`: dedicated per-provider routes (chat, embeddings, images)
- `src/app/api/providers*`: provider CRUD, validation, testing
- `src/app/api/provider-nodes*`: custom compatible node management
- `src/app/api/provider-models`: custom model management (CRUD)
- `src/app/api/models/route.ts`: model catalog API (aliases + custom models)
- `src/app/api/oauth/*`: OAuth/device-code flows
- `src/app/api/keys*`: local API key lifecycle
- `src/app/api/models/alias`: alias management
- `src/app/api/combos*`: fallback combo management
- `src/app/api/pricing`: pricing overrides for cost calculation
- `src/app/api/settings/proxy`: proxy configuration (GET/PUT/DELETE)
- `src/app/api/settings/proxy/test`: outbound proxy connectivity test (POST)
- `src/app/api/usage/*`: usage and logs APIs
- `src/app/api/sync/*` + `src/app/api/cloud/*`: cloud sync and cloud-facing helpers
- `src/app/api/cli-tools/*`: local CLI config writers/checkers
- `src/app/api/settings/ip-filter`: IP allowlist/blocklist (GET/PUT)
- `src/app/api/settings/thinking-budget`: thinking token budget config (GET/PUT)
- `src/app/api/settings/system-prompt`: global system prompt (GET/PUT)
- `src/app/api/sessions`: active session listing (GET)
- `src/app/api/rate-limits`: per-account rate limit status (GET)
### Routing and Execution Core
- `src/sse/handlers/chat.ts`: request parse, combo handling, account selection loop
- `open-sse/handlers/chatCore.ts`: translation, executor dispatch, retry/refresh handling, stream setup
- `open-sse/executors/*`: provider-specific network and format behavior
### Translation Registry and Format Converters
- `open-sse/translator/index.ts`: translator registry and orchestration
- Request translators: `open-sse/translator/request/*`
- Response translators: `open-sse/translator/response/*`
- Format constants: `open-sse/translator/formats.ts`
### Persistence
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
- `src/lib/localDb.ts`: compatibility re-export for DB modules
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
## Provider Executor Coverage (Strategy Pattern)
Each provider has a specialized executor extending `BaseExecutor` (in `open-sse/executors/base.ts`), which provides URL building, header construction, retry with exponential backoff, credential refresh hooks, and the `execute()` orchestration method.
| Executor | Provider(s) | Special Handling |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `DefaultExecutor` | OpenAI, Claude, Gemini, Qwen, iFlow, OpenRouter, GLM, Kimi, MiniMax, DeepSeek, Groq, xAI, Mistral, Perplexity, Together, Fireworks, Cerebras, Cohere, NVIDIA | Dynamic URL/header config per provider |
| `AntigravityExecutor` | Google Antigravity | Custom project/session IDs, Retry-After parsing |
| `CodexExecutor` | OpenAI Codex | Injects system instructions, forces reasoning effort |
| `CursorExecutor` | Cursor IDE | ConnectRPC protocol, Protobuf encoding, request signing via checksum |
| `GithubExecutor` | GitHub Copilot | Copilot token refresh, VSCode-mimicking headers |
| `KiroExecutor` | AWS CodeWhisperer/Kiro | AWS EventStream binary format → SSE conversion |
| `GeminiCLIExecutor` | Gemini CLI | Google OAuth token refresh cycle |
All other providers (including custom compatible nodes) use the `DefaultExecutor`.
## Provider Compatibility Matrix
| Provider | Format | Auth | Stream | Non-Stream | Token Refresh | Usage API |
| ---------------- | ---------------- | --------------------- | ---------------- | ---------- | ------------- | ------------------ |
| Claude | claude | API Key / OAuth | ✅ | ✅ | ✅ | ⚠️ Admin only |
| Gemini | gemini | API Key / OAuth | ✅ | ✅ | ✅ | ⚠️ Cloud Console |
| Gemini CLI | gemini-cli | OAuth | ✅ | ✅ | ✅ | ⚠️ Cloud Console |
| Antigravity | antigravity | OAuth | ✅ | ✅ | ✅ | ✅ Full quota API |
| OpenAI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Codex | openai-responses | OAuth | ✅ forced | ❌ | ✅ | ✅ Rate limits |
| GitHub Copilot | openai | OAuth + Copilot Token | ✅ | ✅ | ✅ | ✅ Quota snapshots |
| Cursor | cursor | Custom checksum | ✅ | ✅ | ❌ | ❌ |
| Kiro | kiro | AWS SSO OIDC | ✅ (EventStream) | ❌ | ✅ | ✅ Usage limits |
| Qwen | openai | OAuth | ✅ | ✅ | ✅ | ⚠️ Per request |
| iFlow | openai | OAuth (Basic) | ✅ | ✅ | ✅ | ⚠️ Per request |
| OpenRouter | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| GLM/Kimi/MiniMax | claude | API Key | ✅ | ✅ | ❌ | ❌ |
| DeepSeek | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Groq | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| xAI (Grok) | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Mistral | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Perplexity | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Together AI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Fireworks AI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Cerebras | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Cohere | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| NVIDIA NIM | openai | API Key | ✅ | ✅ | ❌ | ❌ |
## Format Translation Coverage
Detected source formats include:
- `openai`
- `openai-responses`
- `claude`
- `gemini`
Target formats include:
- OpenAI chat/Responses
- Claude
- Gemini/Gemini-CLI/Antigravity envelope
- Kiro
- Cursor
Translations use **OpenAI as the hub format** — all conversions go through OpenAI as intermediate:
```
Source Format → OpenAI (hub) → Target Format
```
Translations are selected dynamically based on source payload shape and provider target format.
Additional processing layers in the translation pipeline:
- **Response sanitization** — Strips non-standard fields from OpenAI-format responses (both streaming and non-streaming) to ensure strict SDK compliance
- **Role normalization** — Converts `developer``system` for non-OpenAI targets; merges `system``user` for models that reject the system role (GLM, ERNIE)
- **Think tag extraction** — Parses `<think>...</think>` blocks from content into `reasoning_content` field
- **Structured output** — Converts OpenAI `response_format.json_schema` to Gemini's `responseMimeType` + `responseSchema`
## Supported API Endpoints
| Endpoint | Format | Handler |
| -------------------------------------------------- | ------------------ | ---------------------------------------------------- |
| `POST /v1/chat/completions` | OpenAI Chat | `src/sse/handlers/chat.ts` |
| `POST /v1/messages` | Claude Messages | Same handler (auto-detected) |
| `POST /v1/responses` | OpenAI Responses | `open-sse/handlers/responsesHandler.ts` |
| `POST /v1/embeddings` | OpenAI Embeddings | `open-sse/handlers/embeddings.ts` |
| `GET /v1/embeddings` | Model listing | API route |
| `POST /v1/images/generations` | OpenAI Images | `open-sse/handlers/imageGeneration.ts` |
| `GET /v1/images/generations` | Model listing | API route |
| `POST /v1/providers/{provider}/chat/completions` | OpenAI Chat | Dedicated per-provider with model validation |
| `POST /v1/providers/{provider}/embeddings` | OpenAI Embeddings | Dedicated per-provider with model validation |
| `POST /v1/providers/{provider}/images/generations` | OpenAI Images | Dedicated per-provider with model validation |
| `POST /v1/messages/count_tokens` | Claude Token Count | API route |
| `GET /v1/models` | OpenAI Models list | API route (chat + embedding + image + custom models) |
| `GET /api/models/catalog` | Catalog | All models grouped by provider + type |
| `POST /v1beta/models/*:streamGenerateContent` | Gemini native | API route |
| `GET/PUT/DELETE /api/settings/proxy` | Proxy Config | Network proxy configuration |
| `POST /api/settings/proxy/test` | Proxy Connectivity | Proxy health/connectivity test endpoint |
| `GET/POST/DELETE /api/provider-models` | Custom Models | Custom model management per provider |
## Bypass Handler
The bypass handler (`open-sse/utils/bypassHandler.ts`) intercepts known "throwaway" requests from Claude CLI — warmup pings, title extractions, and token counts — and returns a **fake response** without consuming upstream provider tokens. This is triggered only when `User-Agent` contains `claude-cli`.
## Request Logger Pipeline
The request logger (`open-sse/utils/requestLogger.ts`) provides a 7-stage debug logging pipeline, disabled by default, enabled via `ENABLE_REQUEST_LOGS=true`:
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
→ 5_res_provider.txt → 6_res_openai.txt → 7_res_client.txt
```
Files are written to `<repo>/logs/<session>/` for each request session.
## Failure Modes and Resilience
## 1) Account/Provider Availability
- provider account cooldown on transient/rate/auth errors
- account fallback before failing request
- combo model fallback when current model/provider path is exhausted
## 2) Token Expiry
- pre-check and refresh with retry for refreshable providers
- 401/403 retry after refresh attempt in core path
## 3) Stream Safety
- disconnect-aware stream controller
- translation stream with end-of-stream flush and `[DONE]` handling
- usage estimation fallback when provider usage metadata is missing
## 4) Cloud Sync Degradation
- sync errors are surfaced but local runtime continues
- scheduler has retry-capable logic, but periodic execution currently calls single-attempt sync by default
## 5) Data Integrity
- SQLite schema migrations and auto-upgrade hooks at startup
- legacy JSON → SQLite migration compatibility path
## Observability and Operational Signals
Runtime visibility sources:
- console logs from `src/sse/utils/logger.ts`
- per-request usage aggregates in SQLite (`usage_history`, `call_logs`, `proxy_logs`)
- textual request status log in `log.txt` (optional/compat)
- optional deep request/translation logs under `logs/` when `ENABLE_REQUEST_LOGS=true`
- dashboard usage endpoints (`/api/usage/*`) for UI consumption
## Security-Sensitive Boundaries
- JWT secret (`JWT_SECRET`) secures dashboard session cookie verification/signing
- Initial password bootstrap (`INITIAL_PASSWORD`) should be explicitly configured for first-run provisioning
- API key HMAC secret (`API_KEY_SECRET`) secures generated local API key format
- Provider secrets (API keys/tokens) are persisted in local DB and should be protected at filesystem level
- Cloud sync endpoints rely on API key auth + machine id semantics
## Environment and Runtime Matrix
Environment variables actively used by code:
- App/auth: `JWT_SECRET`, `INITIAL_PASSWORD`
- Storage: `DATA_DIR`
- Compatible node behavior: `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE`
- Optional storage base override (Linux/macOS when `DATA_DIR` unset): `XDG_CONFIG_HOME`
- Security hashing: `API_KEY_SECRET`, `MACHINE_ID_SALT`
- Logging: `ENABLE_REQUEST_LOGS`
- Sync/cloud URLing: `NEXT_PUBLIC_BASE_URL`, `NEXT_PUBLIC_CLOUD_URL`
- Outbound proxy: `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY` and lowercase variants
- SOCKS5 feature flags: `ENABLE_SOCKS5_PROXY`, `NEXT_PUBLIC_ENABLE_SOCKS5_PROXY`
- Platform/runtime helpers (not app-specific config): `APPDATA`, `NODE_ENV`, `PORT`, `HOSTNAME`
## Known Architectural Notes
1. `usageDb` and `localDb` share the same base directory policy (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) with legacy file migration.
2. `/api/v1/route.ts` delegates to the same unified catalog builder used by `/api/v1/models` (`src/app/api/v1/models/catalog.ts`) to avoid semantic drift.
3. Request logger writes full headers/body when enabled; treat log directory as sensitive.
4. Cloud behavior depends on correct `NEXT_PUBLIC_BASE_URL` and cloud endpoint reachability.
5. The `open-sse/` directory is published as the `@omniroute/open-sse` **npm workspace package**. Source code imports it via `@omniroute/open-sse/...` (resolved by Next.js `transpilePackages`). File paths in this document still use the directory name `open-sse/` for consistency.
6. Charts in the dashboard use **Recharts** (SVG-based) for accessible, interactive analytics visualizations (model usage bar charts, provider breakdown tables with success rates).
7. E2E tests use **Playwright** (`tests/e2e/`), run via `npm run test:e2e`. Unit tests use **Node.js test runner** (`tests/unit/`), run via `npm run test:unit`. Source code under `src/` is **TypeScript** (`.ts`/`.tsx`); the `open-sse/` workspace remains JavaScript (`.js`).
8. Settings page is organized into 5 tabs: Security, Routing (6 global strategies: fill-first, round-robin, p2c, random, least-used, cost-optimized), Resilience (editable rate limits, circuit breaker, policies), AI (thinking budget, system prompt, prompt cache), Advanced (proxy).
## Operational Verification Checklist
- Build from source: `npm run build`
- Build Docker image: `docker build -t omniroute .`
- Start service and verify:
- `GET /api/settings`
- `GET /api/v1/models`
- CLI target base URL should be `http://<host>:20128/v1` when `PORT=20128`

View File

@@ -0,0 +1,67 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/AUTO-COMBO.md) · 🇪🇸 [es](../es/AUTO-COMBO.md) · 🇫🇷 [fr](../fr/AUTO-COMBO.md) · 🇩🇪 [de](../de/AUTO-COMBO.md) · 🇮🇹 [it](../it/AUTO-COMBO.md) · 🇷🇺 [ru](../ru/AUTO-COMBO.md) · 🇨🇳 [zh-CN](../zh-CN/AUTO-COMBO.md) · 🇯🇵 [ja](../ja/AUTO-COMBO.md) · 🇰🇷 [ko](../ko/AUTO-COMBO.md) · 🇸🇦 [ar](../ar/AUTO-COMBO.md) · 🇮🇳 [in](../in/AUTO-COMBO.md) · 🇹🇭 [th](../th/AUTO-COMBO.md) · 🇻🇳 [vi](../vi/AUTO-COMBO.md) · 🇮🇩 [id](../id/AUTO-COMBO.md) · 🇲🇾 [ms](../ms/AUTO-COMBO.md) · 🇳🇱 [nl](../nl/AUTO-COMBO.md) · 🇵🇱 [pl](../pl/AUTO-COMBO.md) · 🇸🇪 [sv](../sv/AUTO-COMBO.md) · 🇳🇴 [no](../no/AUTO-COMBO.md) · 🇩🇰 [da](../da/AUTO-COMBO.md) · 🇫🇮 [fi](../fi/AUTO-COMBO.md) · 🇵🇹 [pt](../pt/AUTO-COMBO.md) · 🇷🇴 [ro](../ro/AUTO-COMBO.md) · 🇭🇺 [hu](../hu/AUTO-COMBO.md) · 🇧🇬 [bg](../bg/AUTO-COMBO.md) · 🇸🇰 [sk](../sk/AUTO-COMBO.md) · 🇺🇦 [uk-UA](../uk-UA/AUTO-COMBO.md) · 🇮🇱 [he](../he/AUTO-COMBO.md) · 🇵🇭 [phi](../phi/AUTO-COMBO.md)
---
# OmniRoute Auto-Combo Engine
> Self-managing model chains with adaptive scoring
## How It Works
The Auto-Combo Engine dynamically selects the best provider/model for each request using a **6-factor scoring function**:
| Factor | Weight | Description |
| :--------- | :----- | :---------------------------------------------- |
| Quota | 0.20 | Remaining capacity [0..1] |
| Health | 0.25 | Circuit breaker: CLOSED=1.0, HALF=0.5, OPEN=0.0 |
| CostInv | 0.20 | Inverse cost (cheaper = higher score) |
| LatencyInv | 0.15 | Inverse p95 latency (faster = higher) |
| TaskFit | 0.10 | Model × task type fitness score |
| Stability | 0.10 | Low variance in latency/errors |
## Mode Packs
| Pack | Focus | Key Weight |
| :---------------------- | :----------- | :--------------- |
| 🚀 **Ship Fast** | Speed | latencyInv: 0.35 |
| 💰 **Cost Saver** | Economy | costInv: 0.40 |
| 🎯 **Quality First** | Best model | taskFit: 0.40 |
| 📡 **Offline Friendly** | Availability | quota: 0.40 |
## Self-Healing
- **Temporary exclusion**: Score < 0.2 → excluded for 5 min (progressive backoff, max 30 min)
- **Circuit breaker awareness**: OPEN → auto-excluded; HALF_OPEN → probe requests
- **Incident mode**: >50% OPEN → disable exploration, maximize stability
- **Cooldown recovery**: After exclusion, first request is a "probe" with reduced timeout
## Bandit Exploration
5% of requests (configurable) are routed to random providers for exploration. Disabled in incident mode.
## API
```bash
# Create auto-combo
curl -X POST http://localhost:20128/api/combos/auto \
-H "Content-Type: application/json" \
-d '{"id":"my-auto","name":"Auto Coder","candidatePool":["anthropic","google","openai"],"modePack":"ship-fast"}'
# List auto-combos
curl http://localhost:20128/api/combos/auto
```
## Task Fitness
30+ models scored across 6 task types (`coding`, `review`, `planning`, `analysis`, `debugging`, `documentation`). Supports wildcard patterns (e.g., `*-coder` → high coding score).
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------ |
| `open-sse/services/autoCombo/scoring.ts` | Scoring function & pool normalization |
| `open-sse/services/autoCombo/taskFitness.ts` | Model × task fitness lookup |
| `open-sse/services/autoCombo/engine.ts` | Selection logic, bandit, budget cap |
| `open-sse/services/autoCombo/selfHealing.ts` | Exclusion, probes, incident mode |
| `open-sse/services/autoCombo/modePacks.ts` | 4 weight profiles |
| `src/app/api/combos/auto/route.ts` | REST API |

351
docs/i18n/ar/CLI-TOOLS.md Normal file
View File

@@ -0,0 +1,351 @@
🌐 **Languages:** 🇺🇸 [English](../../CLI-TOOLS.md) · 🇧🇷 [pt-BR](../pt-BR/CLI-TOOLS.md) · 🇪🇸 [es](../es/CLI-TOOLS.md) · 🇫🇷 [fr](../fr/CLI-TOOLS.md) · 🇩🇪 [de](../de/CLI-TOOLS.md) · 🇮🇹 [it](../it/CLI-TOOLS.md) · 🇷🇺 [ru](../ru/CLI-TOOLS.md) · 🇨🇳 [zh-CN](../zh-CN/CLI-TOOLS.md) · 🇯🇵 [ja](../ja/CLI-TOOLS.md) · 🇰🇷 [ko](../ko/CLI-TOOLS.md) · 🇸🇦 [ar](../ar/CLI-TOOLS.md)
# دليل إعداد أدوات CLI — OmniRoute
يشرح هذا الدليل كيفية تثبيت وتهيئة جميع أدوات CLI المدعومة لاستخدام **OmniRoute** كخلفية موحدة.
This guide explains how to install and configure all supported AI coding CLI tools
to use **OmniRoute** as the unified backend, giving you centralized key management,
cost tracking, model switching, and request logging across every tool.
---
## How It Works
```
Claude / Codex / Gemini CLI / OpenCode / Cline / KiloCode / Continue / Kiro CLI
▼ (all point to OmniRoute)
http://YOUR_SERVER:20128/v1
▼ (OmniRoute routes to the right provider)
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
```
**Benefits:**
- One API key to manage all tools
- Cost tracking across all CLIs in the dashboard
- Model switching without reconfiguring every tool
- Works locally and on remote servers (VPS)
---
## Supported Tools
| Tool | Command | Type | Install Method |
| ---------------- | ------------------- | ----------------- | -------------- |
| **Claude Code** | `claude` | CLI | npm |
| **OpenAI Codex** | `codex` | CLI | npm |
| **Gemini CLI** | `gemini` | CLI | npm |
| **OpenCode** | `opencode` | CLI | npm |
| **Cline** | `cline` | CLI + VS Code ext | npm |
| **KiloCode** | `kilocode` / `kilo` | CLI + VS Code ext | npm |
| **Continue** | guide-based | VS Code ext | VS Code |
| **Kiro CLI** | `kiro-cli` | CLI | curl installer |
| **Cursor** | `cursor` | Desktop app | Download |
| **Droid** | web-based | Built-in agent | OmniRoute |
| **OpenClaw** | web-based | Built-in agent | OmniRoute |
---
## Step 1 — Get an OmniRoute API Key
1. Open the OmniRoute dashboard → **API Manager** (`/dashboard/api-manager`)
2. Click **Create API Key**
3. Give it a name (e.g. `cli-tools`) and select all permissions
4. Copy the key — you'll need it for every CLI below
> Your key looks like: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
---
## Step 2 — Install CLI Tools
All npm-based tools require Node.js 18+:
```bash
# Claude Code (Anthropic)
npm install -g @anthropic-ai/claude-code
# OpenAI Codex
npm install -g @openai/codex
# Gemini CLI (Google)
npm install -g @google/gemini-cli
# OpenCode
npm install -g opencode-ai
# Cline
npm install -g cline
# KiloCode
npm install -g kilecode
# Kiro CLI (Amazon — requires curl + unzip)
apt-get install -y unzip # on Debian/Ubuntu
curl -fsSL https://cli.kiro.dev/install | bash
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
```
**Verify:**
```bash
claude --version # 2.x.x
codex --version # 0.x.x
gemini --version # 0.x.x
opencode --version # x.x.x
cline --version # 2.x.x
kilocode --version # x.x.x (or: kilo --version)
kiro-cli --version # 1.x.x
```
---
## Step 3 — Set Global Environment Variables
Add to `~/.bashrc` (or `~/.zshrc`), then run `source ~/.bashrc`:
```bash
# OmniRoute Universal Endpoint
export OPENAI_BASE_URL="http://localhost:20128/v1"
export OPENAI_API_KEY="sk-your-omniroute-key"
export ANTHROPIC_BASE_URL="http://localhost:20128/v1"
export ANTHROPIC_API_KEY="sk-your-omniroute-key"
export GEMINI_BASE_URL="http://localhost:20128/v1"
export GEMINI_API_KEY="sk-your-omniroute-key"
```
> For a **remote server** replace `localhost:20128` with the server IP or domain,
> e.g. `http://192.168.0.15:20128`.
---
## Step 4 — Configure Each Tool
### Claude Code
```bash
# Via CLI:
claude config set --global api-base-url http://localhost:20128/v1
# Or create ~/.claude/settings.json:
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
{
"apiBaseUrl": "http://localhost:20128/v1",
"apiKey": "sk-your-omniroute-key"
}
EOF
```
**Test:** `claude "say hello"`
---
### OpenAI Codex
```bash
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
model: auto
apiKey: sk-your-omniroute-key
apiBaseUrl: http://localhost:20128/v1
EOF
```
**Test:** `codex "what is 2+2?"`
---
### Gemini CLI
```bash
mkdir -p ~/.gemini && cat > ~/.gemini/settings.json << EOF
{
"apiKey": "sk-your-omniroute-key",
"baseUrl": "http://localhost:20128/v1"
}
EOF
```
**Test:** `gemini "hello"`
---
### OpenCode
```bash
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
[provider.openai]
base_url = "http://localhost:20128/v1"
api_key = "sk-your-omniroute-key"
EOF
```
**Test:** `opencode`
---
### Cline (CLI or VS Code)
**CLI mode:**
```bash
mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
{
"apiProvider": "openai",
"openAiBaseUrl": "http://localhost:20128/v1",
"openAiApiKey": "sk-your-omniroute-key"
}
EOF
```
**VS Code mode:**
Cline extension settings → API Provider: `OpenAI Compatible` → Base URL: `http://localhost:20128/v1`
Or use the OmniRoute dashboard → **CLI Tools → Cline → Apply Config**.
---
### KiloCode (CLI or VS Code)
**CLI mode:**
```bash
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
```
**VS Code settings:**
```json
{
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
"kilo-code.apiKey": "sk-your-omniroute-key"
}
```
Or use the OmniRoute dashboard → **CLI Tools → KiloCode → Apply Config**.
---
### Continue (VS Code Extension)
Edit `~/.continue/config.yaml`:
```yaml
models:
- name: OmniRoute
provider: openai
model: auto
apiBase: http://localhost:20128/v1
apiKey: sk-your-omniroute-key
default: true
```
Restart VS Code after editing.
---
### Kiro CLI (Amazon)
```bash
# Login to your AWS/Kiro account:
kiro-cli login
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
# Use kiro-cli alongside OmniRoute for other tools.
kiro-cli status
```
---
### Cursor (Desktop App)
> **Note:** Cursor routes requests through its cloud. For OmniRoute integration,
> enable **Cloud Endpoint** in OmniRoute Settings and use your public domain URL.
Via GUI: **Settings → Models → OpenAI API Key**
- Base URL: `https://your-domain.com/v1`
- API Key: your OmniRoute key
---
## Dashboard Auto-Configuration
The OmniRoute dashboard automates configuration for most tools:
1. Go to `http://localhost:20128/dashboard/cli-tools`
2. Expand any tool card
3. Select your API key from the dropdown
4. Click **Apply Config** (if tool is detected as installed)
5. Or copy the generated config snippet manually
---
## Built-in Agents: Droid & OpenClaw
**Droid** and **OpenClaw** are AI agents built directly into OmniRoute — no installation needed.
They run as internal routes and use OmniRoute's model routing automatically.
- Access: `http://localhost:20128/dashboard/agents`
- Configure: same combos and providers as all other tools
- No API key or CLI install required
---
## Available API Endpoints
| Endpoint | Description | Use For |
| -------------------------- | ----------------------------- | --------------------------- |
| `/v1/chat/completions` | Standard chat (all providers) | All modern tools |
| `/v1/responses` | Responses API (OpenAI format) | Codex, agentic workflows |
| `/v1/completions` | Legacy text completions | Older tools using `prompt:` |
| `/v1/embeddings` | Text embeddings | RAG, search |
| `/v1/images/generations` | Image generation | DALL-E, Flux, etc. |
| `/v1/audio/speech` | Text-to-speech | ElevenLabs, OpenAI TTS |
| `/v1/audio/transcriptions` | Speech-to-text | Deepgram, AssemblyAI |
---
## Troubleshooting
| Error | Cause | Fix |
| ------------------------- | ----------------------- | ------------------------------------------ |
| `Connection refused` | OmniRoute not running | `pm2 start omniroute` |
| `401 Unauthorized` | Wrong API key | Check in `/dashboard/api-manager` |
| `No combo configured` | No active routing combo | Set up in `/dashboard/combos` |
| `invalid model` | Model not in catalog | Use `auto` or check `/dashboard/providers` |
| CLI shows "not installed" | Binary not in PATH | Check `which <command>` |
| `kiro-cli: not found` | Not in PATH | `export PATH="$HOME/.local/bin:$PATH"` |
---
## Quick Setup Script (One Command)
```bash
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
OMNIROUTE_URL="http://localhost:20128/v1"
OMNIROUTE_KEY="sk-your-omniroute-key"
npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli opencode-ai cline kilecode
# Kiro CLI
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
# Write configs
mkdir -p ~/.claude ~/.codex ~/.gemini ~/.config/opencode ~/.continue
cat > ~/.claude/settings.json <<< "{\"apiBaseUrl\":\"$OMNIROUTE_URL\",\"apiKey\":\"$OMNIROUTE_KEY\"}"
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
cat > ~/.gemini/settings.json <<< "{\"apiKey\":\"$OMNIROUTE_KEY\",\"baseUrl\":\"$OMNIROUTE_URL\"}"
cat >> ~/.bashrc << EOF
export OPENAI_BASE_URL="$OMNIROUTE_URL"
export OPENAI_API_KEY="$OMNIROUTE_KEY"
export ANTHROPIC_BASE_URL="$OMNIROUTE_URL"
export ANTHROPIC_API_KEY="$OMNIROUTE_KEY"
EOF
source ~/.bashrc
echo "✅ All CLIs installed and configured for OmniRoute"
```

View File

@@ -0,0 +1,593 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/CODEBASE_DOCUMENTATION.md) · 🇪🇸 [es](../es/CODEBASE_DOCUMENTATION.md) · 🇫🇷 [fr](../fr/CODEBASE_DOCUMENTATION.md) · 🇩🇪 [de](../de/CODEBASE_DOCUMENTATION.md) · 🇮🇹 [it](../it/CODEBASE_DOCUMENTATION.md) · 🇷🇺 [ru](../ru/CODEBASE_DOCUMENTATION.md) · 🇨🇳 [zh-CN](../zh-CN/CODEBASE_DOCUMENTATION.md) · 🇯🇵 [ja](../ja/CODEBASE_DOCUMENTATION.md) · 🇰🇷 [ko](../ko/CODEBASE_DOCUMENTATION.md) · 🇸🇦 [ar](../ar/CODEBASE_DOCUMENTATION.md) · 🇮🇳 [in](../in/CODEBASE_DOCUMENTATION.md) · 🇹🇭 [th](../th/CODEBASE_DOCUMENTATION.md) · 🇻🇳 [vi](../vi/CODEBASE_DOCUMENTATION.md) · 🇮🇩 [id](../id/CODEBASE_DOCUMENTATION.md) · 🇲🇾 [ms](../ms/CODEBASE_DOCUMENTATION.md) · 🇳🇱 [nl](../nl/CODEBASE_DOCUMENTATION.md) · 🇵🇱 [pl](../pl/CODEBASE_DOCUMENTATION.md) · 🇸🇪 [sv](../sv/CODEBASE_DOCUMENTATION.md) · 🇳🇴 [no](../no/CODEBASE_DOCUMENTATION.md) · 🇩🇰 [da](../da/CODEBASE_DOCUMENTATION.md) · 🇫🇮 [fi](../fi/CODEBASE_DOCUMENTATION.md) · 🇵🇹 [pt](../pt/CODEBASE_DOCUMENTATION.md) · 🇷🇴 [ro](../ro/CODEBASE_DOCUMENTATION.md) · 🇭🇺 [hu](../hu/CODEBASE_DOCUMENTATION.md) · 🇧🇬 [bg](../bg/CODEBASE_DOCUMENTATION.md) · 🇸🇰 [sk](../sk/CODEBASE_DOCUMENTATION.md) · 🇺🇦 [uk-UA](../uk-UA/CODEBASE_DOCUMENTATION.md) · 🇮🇱 [he](../he/CODEBASE_DOCUMENTATION.md) · 🇵🇭 [phi](../phi/CODEBASE_DOCUMENTATION.md)
---
# omniroute — Codebase Documentation
🌐 **Languages:** 🇺🇸 [English](CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](i18n/es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](i18n/fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](i18n/it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](i18n/ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](i18n/de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](i18n/in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](i18n/th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](i18n/uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](i18n/ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](i18n/ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](i18n/vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](i18n/bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](i18n/da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](i18n/fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](i18n/he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](i18n/hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](i18n/ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](i18n/nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](i18n/no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](i18n/pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](i18n/ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](i18n/pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](i18n/sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](i18n/sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](i18n/phi/CODEBASE_DOCUMENTATION.md)
> A comprehensive, beginner-friendly guide to the **omniroute** multi-provider AI proxy router.
---
## 1. What Is omniroute?
omniroute is a **proxy router** that sits between AI clients (Claude CLI, Codex, Cursor IDE, etc.) and AI providers (Anthropic, Google, OpenAI, AWS, GitHub, etc.). It solves one big problem:
> **Different AI clients speak different "languages" (API formats), and different AI providers expect different "languages" too.** omniroute translates between them automatically.
Think of it like a universal translator at the United Nations — any delegate can speak any language, and the translator converts it for any other delegate.
---
## 2. Architecture Overview
```mermaid
graph LR
subgraph Clients
A[Claude CLI]
B[Codex]
C[Cursor IDE]
D[OpenAI-compatible]
end
subgraph omniroute
E[Handler Layer]
F[Translator Layer]
G[Executor Layer]
H[Services Layer]
end
subgraph Providers
I[Anthropic Claude]
J[Google Gemini]
K[OpenAI / Codex]
L[GitHub Copilot]
M[AWS Kiro]
N[Antigravity]
O[Cursor API]
end
A --> E
B --> E
C --> E
D --> E
E --> F
F --> G
G --> I
G --> J
G --> K
G --> L
G --> M
G --> N
G --> O
H -.-> E
H -.-> G
```
### Core Principle: Hub-and-Spoke Translation
All format translation passes through **OpenAI format as the hub**:
```
Client Format → [OpenAI Hub] → Provider Format (request)
Provider Format → [OpenAI Hub] → Client Format (response)
```
This means you only need **N translators** (one per format) instead of **N²** (every pair).
---
## 3. Project Structure
```
omniroute/
├── open-sse/ ← Core proxy library (portable, framework-agnostic)
│ ├── index.js ← Main entry point, exports everything
│ ├── config/ ← Configuration & constants
│ ├── executors/ ← Provider-specific request execution
│ ├── handlers/ ← Request handling orchestration
│ ├── services/ ← Business logic (auth, models, fallback, usage)
│ ├── translator/ ← Format translation engine
│ │ ├── request/ ← Request translators (8 files)
│ │ ├── response/ ← Response translators (7 files)
│ │ └── helpers/ ← Shared translation utilities (6 files)
│ └── utils/ ← Utility functions
├── src/ ← Application layer (Express/Worker runtime)
│ ├── app/ ← Web UI, API routes, middleware
│ ├── lib/ ← Database, auth, and shared library code
│ ├── mitm/ ← Man-in-the-middle proxy utilities
│ ├── models/ ← Database models
│ ├── shared/ ← Shared utilities (wrappers around open-sse)
│ ├── sse/ ← SSE endpoint handlers
│ └── store/ ← State management
├── data/ ← Runtime data (credentials, logs)
│ └── provider-credentials.json (external credentials override, gitignored)
└── tester/ ← Test utilities
```
---
## 4. Module-by-Module Breakdown
### 4.1 Config (`open-sse/config/`)
The **single source of truth** for all provider configuration.
| File | Purpose |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constants.ts` | `PROVIDERS` object with base URLs, OAuth credentials (defaults), headers, and default system prompts for every provider. Also defines `HTTP_STATUS`, `ERROR_TYPES`, `COOLDOWN_MS`, `BACKOFF_CONFIG`, and `SKIP_PATTERNS`. |
| `credentialLoader.ts` | Loads external credentials from `data/provider-credentials.json` and merges them over the hardcoded defaults in `PROVIDERS`. Keeps secrets out of source control while maintaining backwards compatibility. |
| `providerModels.ts` | Central model registry: maps provider aliases → model IDs. Functions like `getModels()`, `getProviderByAlias()`. |
| `codexInstructions.ts` | System instructions injected into Codex requests (editing constraints, sandbox rules, approval policies). |
| `defaultThinkingSignature.ts` | Default "thinking" signatures for Claude and Gemini models. |
| `ollamaModels.ts` | Schema definition for local Ollama models (name, size, family, quantization). |
#### Credential Loading Flow
```mermaid
flowchart TD
A["App starts"] --> B["constants.ts defines PROVIDERS\nwith hardcoded defaults"]
B --> C{"data/provider-credentials.json\nexists?"}
C -->|Yes| D["credentialLoader reads JSON"]
C -->|No| E["Use hardcoded defaults"]
D --> F{"For each provider in JSON"}
F --> G{"Provider exists\nin PROVIDERS?"}
G -->|No| H["Log warning, skip"]
G -->|Yes| I{"Value is object?"}
I -->|No| J["Log warning, skip"]
I -->|Yes| K["Merge clientId, clientSecret,\ntokenUrl, authUrl, refreshUrl"]
K --> F
H --> F
J --> F
F -->|Done| L["PROVIDERS ready with\nmerged credentials"]
E --> L
```
---
### 4.2 Executors (`open-sse/executors/`)
Executors encapsulate **provider-specific logic** using the **Strategy Pattern**. Each executor overrides base methods as needed.
```mermaid
classDiagram
class BaseExecutor {
+buildUrl(model, stream, options)
+buildHeaders(credentials, stream, body)
+transformRequest(body, model, stream, credentials)
+execute(url, options)
+shouldRetry(status, error)
+refreshCredentials(credentials, log)
}
class DefaultExecutor {
+refreshCredentials()
}
class AntigravityExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+shouldRetry()
+refreshCredentials()
}
class CursorExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseResponse()
+generateChecksum()
}
class KiroExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseEventStream()
+refreshCredentials()
}
BaseExecutor <|-- DefaultExecutor
BaseExecutor <|-- AntigravityExecutor
BaseExecutor <|-- CursorExecutor
BaseExecutor <|-- KiroExecutor
BaseExecutor <|-- CodexExecutor
BaseExecutor <|-- GeminiCLIExecutor
BaseExecutor <|-- GithubExecutor
```
| Executor | Provider | Key Specializations |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `base.ts` | — | Abstract base: URL building, headers, retry logic, credential refresh |
| `default.ts` | Claude, Gemini, OpenAI, GLM, Kimi, MiniMax | Generic OAuth token refresh for standard providers |
| `antigravity.ts` | Google Cloud Code | Project/session ID generation, multi-URL fallback, custom retry parsing from error messages ("reset after 2h7m23s") |
| `cursor.ts` | Cursor IDE | **Most complex**: SHA-256 checksum auth, Protobuf request encoding, binary EventStream → SSE response parsing |
| `codex.ts` | OpenAI Codex | Injects system instructions, manages thinking levels, removes unsupported parameters |
| `gemini-cli.ts` | Google Gemini CLI | Custom URL building (`streamGenerateContent`), Google OAuth token refresh |
| `github.ts` | GitHub Copilot | Dual token system (GitHub OAuth + Copilot token), VSCode header mimicking |
| `kiro.ts` | AWS CodeWhisperer | AWS EventStream binary parsing, AMZN event frames, token estimation |
| `index.ts` | — | Factory: maps provider name → executor class, with default fallback |
---
### 4.3 Handlers (`open-sse/handlers/`)
The **orchestration layer** — coordinates translation, execution, streaming, and error handling.
| File | Purpose |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chatCore.ts` | **Central orchestrator** (~600 lines). Handles the complete request lifecycle: format detection → translation → executor dispatch → streaming/non-streaming response → token refresh → error handling → usage logging. |
| `responsesHandler.ts` | Adapter for OpenAI's Responses API: converts Responses format → Chat Completions → sends to `chatCore` → converts SSE back to Responses format. |
| `embeddings.ts` | Embedding generation handler: resolves embedding model → provider, dispatches to provider API, returns OpenAI-compatible embedding response. Supports 6+ providers. |
| `imageGeneration.ts` | Image generation handler: resolves image model → provider, supports OpenAI-compatible, Gemini-image (Antigravity), and fallback (Nebius) modes. Returns base64 or URL images. |
#### Request Lifecycle (chatCore.ts)
```mermaid
sequenceDiagram
participant Client
participant chatCore
participant Translator
participant Executor
participant Provider
Client->>chatCore: Request (any format)
chatCore->>chatCore: Detect source format
chatCore->>chatCore: Check bypass patterns
chatCore->>chatCore: Resolve model & provider
chatCore->>Translator: Translate request (source → OpenAI → target)
chatCore->>Executor: Get executor for provider
Executor->>Executor: Build URL, headers, transform request
Executor->>Executor: Refresh credentials if needed
Executor->>Provider: HTTP fetch (streaming or non-streaming)
alt Streaming
Provider-->>chatCore: SSE stream
chatCore->>chatCore: Pipe through SSE transform stream
Note over chatCore: Transform stream translates<br/>each chunk: target → OpenAI → source
chatCore-->>Client: Translated SSE stream
else Non-streaming
Provider-->>chatCore: JSON response
chatCore->>Translator: Translate response
chatCore-->>Client: Translated JSON
end
alt Error (401, 429, 500...)
chatCore->>Executor: Retry with credential refresh
chatCore->>chatCore: Account fallback logic
end
```
---
### 4.4 Services (`open-sse/services/`)
Business logic that supports the handlers and executors.
| File | Purpose |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider.ts` | **Format detection** (`detectFormat`): analyzes request body structure to identify Claude/OpenAI/Gemini/Antigravity/Responses formats (includes `max_tokens` heuristic for Claude). Also: URL building, header building, thinking config normalization. Supports `openai-compatible-*` and `anthropic-compatible-*` dynamic providers. |
| `model.ts` | Model string parsing (`claude/model-name``{provider: "claude", model: "model-name"}`), alias resolution with collision detection, input sanitization (rejects path traversal/control chars), and model info resolution with async alias getter support. |
| `accountFallback.ts` | Rate-limit handling: exponential backoff (1s → 2s → 4s → max 2min), account cooldown management, error classification (which errors trigger fallback vs. not). |
| `tokenRefresh.ts` | OAuth token refresh for **every provider**: Google (Gemini, Antigravity), Claude, Codex, Qwen, iFlow, GitHub (OAuth + Copilot dual-token), Kiro (AWS SSO OIDC + Social Auth). Includes in-flight promise deduplication cache and retry with exponential backoff. |
| `combo.ts` | **Combo models**: chains of fallback models. If model A fails with a fallback-eligible error, try model B, then C, etc. Returns actual upstream status codes. |
| `usage.ts` | Fetches quota/usage data from provider APIs (GitHub Copilot quotas, Antigravity model quotas, Codex rate limits, Kiro usage breakdowns, Claude settings). |
| `accountSelector.ts` | Smart account selection with scoring algorithm: considers priority, health status, round-robin position, and cooldown state to pick the optimal account for each request. |
| `contextManager.ts` | Request context lifecycle management: creates and tracks per-request context objects with metadata (request ID, timestamps, provider info) for debugging and logging. |
| `ipFilter.ts` | IP-based access control: supports allowlist and blocklist modes. Validates client IP against configured rules before processing API requests. |
| `sessionManager.ts` | Session tracking with client fingerprinting: tracks active sessions using hashed client identifiers, monitors request counts, and provides session metrics. |
| `signatureCache.ts` | Request signature-based deduplication cache: prevents duplicate requests by caching recent request signatures and returning cached responses for identical requests within a time window. |
| `systemPrompt.ts` | Global system prompt injection: prepends or appends a configurable system prompt to all requests, with per-provider compatibility handling. |
| `thinkingBudget.ts` | Reasoning token budget management: supports passthrough, auto (strip thinking config), custom (fixed budget), and adaptive (complexity-scaled) modes for controlling thinking/reasoning tokens. |
| `wildcardRouter.ts` | Wildcard model pattern routing: resolves wildcard patterns (e.g., `*/claude-*`) to concrete provider/model pairs based on availability and priority. |
#### Token Refresh Deduplication
```mermaid
sequenceDiagram
participant R1 as Request 1
participant R2 as Request 2
participant Cache as refreshPromiseCache
participant OAuth as OAuth Provider
R1->>Cache: getAccessToken("gemini", token)
Cache->>Cache: No in-flight promise
Cache->>OAuth: Start refresh
R2->>Cache: getAccessToken("gemini", token)
Cache->>Cache: Found in-flight promise
Cache-->>R2: Return existing promise
OAuth-->>Cache: New access token
Cache-->>R1: New access token
Cache-->>R2: Same access token (shared)
Cache->>Cache: Delete cache entry
```
#### Account Fallback State Machine
```mermaid
stateDiagram-v2
[*] --> Active
Active --> Error: Request fails (401/429/500)
Error --> Cooldown: Apply backoff
Cooldown --> Active: Cooldown expires
Active --> Active: Request succeeds (reset backoff)
state Error {
[*] --> ClassifyError
ClassifyError --> ShouldFallback: Rate limit / Auth / Transient
ClassifyError --> NoFallback: 400 Bad Request
}
state Cooldown {
[*] --> ExponentialBackoff
ExponentialBackoff: Level 0 = 1s
ExponentialBackoff: Level 1 = 2s
ExponentialBackoff: Level 2 = 4s
ExponentialBackoff: Max = 2min
}
```
#### Combo Model Chain
```mermaid
flowchart LR
A["Request with\ncombo model"] --> B["Model A"]
B -->|"2xx Success"| C["Return response"]
B -->|"429/401/500"| D{"Fallback\neligible?"}
D -->|Yes| E["Model B"]
D -->|No| F["Return error"]
E -->|"2xx Success"| C
E -->|"429/401/500"| G{"Fallback\neligible?"}
G -->|Yes| H["Model C"]
G -->|No| F
H -->|"2xx Success"| C
H -->|"Fail"| I["All failed →\nReturn last status"]
```
---
### 4.5 Translator (`open-sse/translator/`)
The **format translation engine** using a self-registering plugin system.
#### Architecture
```mermaid
graph TD
subgraph "Request Translation"
A["Claude → OpenAI"]
B["Gemini → OpenAI"]
C["Antigravity → OpenAI"]
D["OpenAI Responses → OpenAI"]
E["OpenAI → Claude"]
F["OpenAI → Gemini"]
G["OpenAI → Kiro"]
H["OpenAI → Cursor"]
end
subgraph "Response Translation"
I["Claude → OpenAI"]
J["Gemini → OpenAI"]
K["Kiro → OpenAI"]
L["Cursor → OpenAI"]
M["OpenAI → Claude"]
N["OpenAI → Antigravity"]
O["OpenAI → Responses"]
end
```
| Directory | Files | Description |
| ------------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `request/` | 8 translators | Convert request bodies between formats. Each file self-registers via `register(from, to, fn)` on import. |
| `response/` | 7 translators | Convert streaming response chunks between formats. Handles SSE event types, thinking blocks, tool calls. |
| `helpers/` | 6 helpers | Shared utilities: `claudeHelper` (system prompt extraction, thinking config), `geminiHelper` (parts/contents mapping), `openaiHelper` (format filtering), `toolCallHelper` (ID generation, missing response injection), `maxTokensHelper`, `responsesApiHelper`. |
| `index.ts` | — | Translation engine: `translateRequest()`, `translateResponse()`, state management, registry. |
| `formats.ts` | — | Format constants: `OPENAI`, `CLAUDE`, `GEMINI`, `ANTIGRAVITY`, `KIRO`, `CURSOR`, `OPENAI_RESPONSES`. |
#### Key Design: Self-Registering Plugins
```javascript
// Each translator file calls register() on import:
import { register } from "../index.js";
register("claude", "openai", translateClaudeToOpenAI);
// The index.js imports all translator files, triggering registration:
import "./request/claude-to-openai.js"; // ← self-registers
```
---
### 4.6 Utils (`open-sse/utils/`)
| File | Purpose |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `error.ts` | Error response building (OpenAI-compatible format), upstream error parsing, Antigravity retry-time extraction from error messages, SSE error streaming. |
| `stream.ts` | **SSE Transform Stream** — the core streaming pipeline. Two modes: `TRANSLATE` (full format translation) and `PASSTHROUGH` (normalize + extract usage). Handles chunk buffering, usage estimation, content length tracking. Per-stream encoder/decoder instances avoid shared state. |
| `streamHelpers.ts` | Low-level SSE utilities: `parseSSELine` (whitespace-tolerant), `hasValuableContent` (filters empty chunks for OpenAI/Claude/Gemini), `fixInvalidId`, `formatSSE` (format-aware SSE serialization with `perf_metrics` cleanup). |
| `usageTracking.ts` | Token usage extraction from any format (Claude/OpenAI/Gemini/Responses), estimation with separate tool/message char-per-token ratios, buffer addition (2000 tokens safety margin), format-specific field filtering, console logging with ANSI colors. |
| `requestLogger.ts` | File-based request logging (opt-in via `ENABLE_REQUEST_LOGS=true`). Creates session folders with numbered files: `1_req_client.json``7_res_client.txt`. All I/O is async (fire-and-forget). Masks sensitive headers. |
| `bypassHandler.ts` | Intercepts specific patterns from Claude CLI (title extraction, warmup, count) and returns fake responses without calling any provider. Supports both streaming and non-streaming. Intentionally limited to Claude CLI scope. |
| `networkProxy.ts` | Resolves outbound proxy URL for a given provider with precedence: provider-specific config → global config → environment variables (`HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY`). Supports `NO_PROXY` exclusions. Caches config for 30s. |
#### SSE Streaming Pipeline
```mermaid
flowchart TD
A["Provider SSE stream"] --> B["TextDecoder\n(per-stream instance)"]
B --> C["Buffer lines\n(split on newline)"]
C --> D["parseSSELine()\n(trim whitespace, parse JSON)"]
D --> E{"Mode?"}
E -->|TRANSLATE| F["translateResponse()\ntarget → OpenAI → source"]
E -->|PASSTHROUGH| G["fixInvalidId()\nnormalize chunk"]
F --> H["hasValuableContent()\nfilter empty chunks"]
G --> H
H -->|"Has content"| I["extractUsage()\ntrack token counts"]
H -->|"Empty"| J["Skip chunk"]
I --> K["formatSSE()\nserialize + clean perf_metrics"]
K --> L["TextEncoder\n(per-stream instance)"]
L --> M["Enqueue to\nclient stream"]
style A fill:#f9f,stroke:#333
style M fill:#9f9,stroke:#333
```
#### Request Logger Session Structure
```
logs/
└── claude_gemini_claude-sonnet_20260208_143045/
├── 1_req_client.json ← Raw client request
├── 2_req_source.json ← After initial conversion
├── 3_req_openai.json ← OpenAI intermediate format
├── 4_req_target.json ← Final target format
├── 5_res_provider.txt ← Provider SSE chunks (streaming)
├── 5_res_provider.json ← Provider response (non-streaming)
├── 6_res_openai.txt ← OpenAI intermediate chunks
├── 7_res_client.txt ← Client-facing SSE chunks
└── 6_error.json ← Error details (if any)
```
---
### 4.7 Application Layer (`src/`)
| Directory | Purpose |
| ------------- | ---------------------------------------------------------------------- |
| `src/app/` | Web UI, API routes, Express middleware, OAuth callback handlers |
| `src/lib/` | Database access (`localDb.ts`, `usageDb.ts`), authentication, shared |
| `src/mitm/` | Man-in-the-middle proxy utilities for intercepting provider traffic |
| `src/models/` | Database model definitions |
| `src/shared/` | Wrappers around open-sse functions (provider, stream, error, etc.) |
| `src/sse/` | SSE endpoint handlers that wire the open-sse library to Express routes |
| `src/store/` | Application state management |
#### Notable API Routes
| Route | Methods | Purpose |
| --------------------------------------------- | --------------- | ------------------------------------------------------------------------------------- |
| `/api/provider-models` | GET/POST/DELETE | CRUD for custom models per provider |
| `/api/models/catalog` | GET | Aggregated catalog of all models (chat, embedding, image, custom) grouped by provider |
| `/api/settings/proxy` | GET/PUT/DELETE | Hierarchical outbound proxy configuration (`global/providers/combos/keys`) |
| `/api/settings/proxy/test` | POST | Validates proxy connectivity and returns public IP/latency |
| `/v1/providers/[provider]/chat/completions` | POST | Dedicated per-provider chat completions with model validation |
| `/v1/providers/[provider]/embeddings` | POST | Dedicated per-provider embeddings with model validation |
| `/v1/providers/[provider]/images/generations` | POST | Dedicated per-provider image generation with model validation |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist management |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget configuration (passthrough/auto/custom/adaptive) |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt injection for all requests |
| `/api/sessions` | GET | Active session tracking and metrics |
| `/api/rate-limits` | GET | Per-account rate limit status |
---
## 5. Key Design Patterns
### 5.1 Hub-and-Spoke Translation
All formats translate through **OpenAI format as the hub**. Adding a new provider only requires writing **one pair** of translators (to/from OpenAI), not N pairs.
### 5.2 Executor Strategy Pattern
Each provider has a dedicated executor class inheriting from `BaseExecutor`. The factory in `executors/index.ts` selects the right one at runtime.
### 5.3 Self-Registering Plugin System
Translator modules register themselves on import via `register()`. Adding a new translator is just creating a file and importing it.
### 5.4 Account Fallback with Exponential Backoff
When a provider returns 429/401/500, the system can switch to the next account, applying exponential cooldowns (1s → 2s → 4s → max 2min).
### 5.5 Combo Model Chains
A "combo" groups multiple `provider/model` strings. If the first fails, fallback to the next automatically.
### 5.6 Stateful Streaming Translation
Response translation maintains state across SSE chunks (thinking block tracking, tool call accumulation, content block indexing) via the `initState()` mechanism.
### 5.7 Usage Safety Buffer
A 2000-token buffer is added to reported usage to prevent clients from hitting context window limits due to overhead from system prompts and format translation.
---
## 6. Supported Formats
| Format | Direction | Identifier |
| ----------------------- | --------------- | ------------------ |
| OpenAI Chat Completions | source + target | `openai` |
| OpenAI Responses API | source + target | `openai-responses` |
| Anthropic Claude | source + target | `claude` |
| Google Gemini | source + target | `gemini` |
| Google Gemini CLI | target only | `gemini-cli` |
| Antigravity | source + target | `antigravity` |
| AWS Kiro | target only | `kiro` |
| Cursor | target only | `cursor` |
---
## 7. Supported Providers
| Provider | Auth Method | Executor | Key Notes |
| ------------------------ | ---------------------- | ----------- | --------------------------------------------- |
| Anthropic Claude | API key or OAuth | Default | Uses `x-api-key` header |
| Google Gemini | API key or OAuth | Default | Uses `x-goog-api-key` header |
| Google Gemini CLI | OAuth | GeminiCLI | Uses `streamGenerateContent` endpoint |
| Antigravity | OAuth | Antigravity | Multi-URL fallback, custom retry parsing |
| OpenAI | API key | Default | Standard Bearer auth |
| Codex | OAuth | Codex | Injects system instructions, manages thinking |
| GitHub Copilot | OAuth + Copilot token | Github | Dual token, VSCode header mimicking |
| Kiro (AWS) | AWS SSO OIDC or Social | Kiro | Binary EventStream parsing |
| Cursor IDE | Checksum auth | Cursor | Protobuf encoding, SHA-256 checksums |
| Qwen | OAuth | Default | Standard auth |
| iFlow | OAuth (Basic + Bearer) | Default | Dual auth header |
| OpenRouter | API key | Default | Standard Bearer auth |
| GLM, Kimi, MiniMax | API key | Default | Claude-compatible, use `x-api-key` |
| `openai-compatible-*` | API key | Default | Dynamic: any OpenAI-compatible endpoint |
| `anthropic-compatible-*` | API key | Default | Dynamic: any Claude-compatible endpoint |
---
## 8. Data Flow Summary
### Streaming Request
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor\nbuildUrl + buildHeaders"]
D --> E["fetch(providerURL)"]
E --> F["createSSEStream()\nTRANSLATE mode"]
F --> G["parseSSELine()"]
G --> H["translateResponse()\ntarget → OpenAI → source"]
H --> I["extractUsage()\n+ addBuffer"]
I --> J["formatSSE()"]
J --> K["Client receives\ntranslated SSE"]
K --> L["logUsage()\nsaveRequestUsage()"]
```
### Non-Streaming Request
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor.execute()"]
D --> E["translateResponse()\ntarget → OpenAI → source"]
E --> F["Return JSON\nresponse"]
```
### Bypass Flow (Claude CLI)
```mermaid
flowchart LR
A["Claude CLI request"] --> B{"Match bypass\npattern?"}
B -->|"Title/Warmup/Count"| C["Generate fake\nOpenAI response"]
B -->|"No match"| D["Normal flow"]
C --> E["Translate to\nsource format"]
E --> F["Return without\ncalling provider"]
```

147
docs/i18n/ar/FEATURES.md Normal file
View File

@@ -0,0 +1,147 @@
# OmniRoute — Dashboard Features Gallery (العربية)
🌐 **Languages:** 🇺🇸 [English](../../../README.md) · 🇧🇷 [pt-BR](../pt-BR/README.md) · 🇪🇸 [es](../es/README.md) · 🇫🇷 [fr](../fr/README.md) · 🇩🇪 [de](../de/README.md) · 🇮🇹 [it](../it/README.md) · 🇷🇺 [ru](../ru/README.md) · 🇨🇳 [zh-CN](../zh-CN/README.md) · 🇯🇵 [ja](../ja/README.md) · 🇰🇷 [ko](../ko/README.md) · 🇸🇦 [ar](../ar/README.md) · 🇮🇳 [in](../in/README.md) · 🇹🇭 [th](../th/README.md) · 🇻🇳 [vi](../vi/README.md) · 🇮🇩 [id](../id/README.md) · 🇲🇾 [ms](../ms/README.md) · 🇳🇱 [nl](../nl/README.md) · 🇵🇱 [pl](../pl/README.md) · 🇸🇪 [sv](../sv/README.md) · 🇳🇴 [no](../no/README.md) · 🇩🇰 [da](../da/README.md) · 🇫🇮 [fi](../fi/README.md) · 🇵🇹 [pt](../pt/README.md) · 🇷🇴 [ro](../ro/README.md) · 🇭🇺 [hu](../hu/README.md) · 🇧🇬 [bg](../bg/README.md) · 🇸🇰 [sk](../sk/README.md) · 🇺🇦 [uk-UA](../uk-UA/README.md) · 🇮🇱 [he](../he/README.md) · 🇵🇭 [phi](../phi/README.md)
> 🇺🇸 [English](../../../docs/FEATURES.md)
---
Visual guide to every section of the OmniRoute dashboard.
---
## 🔌 Providers
Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI), API key providers (Groq, DeepSeek, OpenRouter), and free providers (iFlow, Qwen, Kiro). Kiro accounts include credit balance tracking — remaining credits, total allowance, and renewal date visible in Dashboard → Usage.
![Providers Dashboard](screenshots/01-providers.png)
---
## 🎨 Combos
Create model routing combos with 6 strategies: priority, weighted, round-robin, random, least-used, and cost-optimized. Each combo chains multiple models with automatic fallback and includes quick templates and readiness checks.
![Combos Dashboard](screenshots/02-combos.png)
---
## 📊 Analytics
Comprehensive usage analytics with token consumption, cost estimates, activity heatmaps, weekly distribution charts, and per-provider breakdowns.
![Analytics Dashboard](screenshots/03-analytics.png)
---
## 🏥 System Health
Real-time monitoring: uptime, memory, version, latency percentiles (p50/p95/p99), cache statistics, and provider circuit breaker states.
![Health Dashboard](screenshots/04-health.png)
---
## 🔧 Translator Playground
Four modes for debugging API translations: **Playground** (format converter), **Chat Tester** (live requests), **Test Bench** (batch tests), and **Live Monitor** (real-time stream).
![Translator Playground](screenshots/05-translator.png)
---
## 🎮 Model Playground _(v2.0.9+)_
Test any model directly from the dashboard. Select provider, model, and endpoint, write prompts with Monaco Editor, stream responses in real-time, abort mid-stream, and view timing metrics.
---
## 🎨 Themes _(v2.0.5+)_
Customizable color themes for the entire dashboard. Choose from 7 preset colors (Coral, Blue, Red, Green, Violet, Orange, Cyan) or create a custom theme by picking any hex color. Supports light, dark, and system mode.
---
## ⚙️ Settings
Comprehensive settings panel with tabs:
- **General** — System storage, backup management (export/import database)
- **Appearance** — Theme selector (dark/light/system), color theme presets and custom colors, health log visibility
- **Security** — API endpoint protection, custom provider blocking, IP filtering, session info
- **Routing** — Model aliases, background task degradation
- **Resilience** — Rate limit persistence, circuit breaker tuning
- **Advanced** — Configuration overrides
![Settings Dashboard](screenshots/06-settings.png)
---
## 🔧 CLI Tools
One-click configuration for AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, Antigravity, Cline, Continue, Cursor, and Factory Droid. Features automated config apply/reset, connection profiles, and model mapping.
![CLI Tools Dashboard](screenshots/07-cli-tools.png)
---
## 🤖 CLI Agents _(v2.0.11+)_
Dashboard for discovering and managing CLI agents. Shows a grid of 14 built-in agents (Codex, Claude, Goose, Gemini CLI, OpenClaw, Aider, OpenCode, Cline, Qwen Code, ForgeCode, Amazon Q, Open Interpreter, Cursor CLI, Warp) with:
- **Installation status** — Installed / Not Found with version detection
- **Protocol badges** — stdio, HTTP, etc.
- **Custom agents** — Register any CLI tool via form (name, binary, version command, spawn args)
- **CLI Fingerprint Matching** — Per-provider toggle to match native CLI request signatures, reducing ban risk while preserving proxy IP
---
## 🖼️ Media _(v2.0.3+)_
Generate images, videos, and music from the dashboard. Supports OpenAI, xAI, Together, Hyperbolic, SD WebUI, ComfyUI, AnimateDiff, Stable Audio Open, and MusicGen.
---
## 📝 Request Logs
Real-time request logging with filtering by provider, model, account, and API key. Shows status codes, token usage, latency, and response details.
![Usage Logs](screenshots/08-usage.png)
---
## 🌐 API Endpoint
Your unified API endpoint with capability breakdown: Chat Completions, Responses API, Embeddings, Image Generation, Reranking, Audio Transcription, Text-to-Speech, Moderations, and registered API keys. Cloud proxy support for remote access.
![Endpoint Dashboard](screenshots/09-endpoint.png)
---
## 🔑 API Key Management
Create, scope, and revoke API keys. Each key can be restricted to specific models/providers with full access or read-only permissions. Visual key management with usage tracking.
---
## 📋 Audit Log
Administrative action tracking with filtering by action type, actor, target, IP address, and timestamp. Full security event history.
---
## 🖥️ Desktop Application
Native Electron desktop app for Windows, macOS, and Linux. Run OmniRoute as a standalone application with system tray integration, offline support, auto-update, and one-click install.
Key features:
- Server readiness polling (no blank screen on cold start)
- System tray with port management
- Content Security Policy
- Single-instance lock
- Auto-update on restart
- Platform-conditional UI (macOS traffic lights, Windows/Linux default titlebar)
- Hardened Electron build packaging — symlinked `node_modules` in the standalone bundle is detected and rejected before packaging, preventing runtime dependency on the build machine (v2.5.5+)
📖 See [`electron/README.md`](../electron/README.md) for full documentation.

View File

@@ -0,0 +1,87 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/MCP-SERVER.md) · 🇪🇸 [es](../es/MCP-SERVER.md) · 🇫🇷 [fr](../fr/MCP-SERVER.md) · 🇩🇪 [de](../de/MCP-SERVER.md) · 🇮🇹 [it](../it/MCP-SERVER.md) · 🇷🇺 [ru](../ru/MCP-SERVER.md) · 🇨🇳 [zh-CN](../zh-CN/MCP-SERVER.md) · 🇯🇵 [ja](../ja/MCP-SERVER.md) · 🇰🇷 [ko](../ko/MCP-SERVER.md) · 🇸🇦 [ar](../ar/MCP-SERVER.md) · 🇮🇳 [in](../in/MCP-SERVER.md) · 🇹🇭 [th](../th/MCP-SERVER.md) · 🇻🇳 [vi](../vi/MCP-SERVER.md) · 🇮🇩 [id](../id/MCP-SERVER.md) · 🇲🇾 [ms](../ms/MCP-SERVER.md) · 🇳🇱 [nl](../nl/MCP-SERVER.md) · 🇵🇱 [pl](../pl/MCP-SERVER.md) · 🇸🇪 [sv](../sv/MCP-SERVER.md) · 🇳🇴 [no](../no/MCP-SERVER.md) · 🇩🇰 [da](../da/MCP-SERVER.md) · 🇫🇮 [fi](../fi/MCP-SERVER.md) · 🇵🇹 [pt](../pt/MCP-SERVER.md) · 🇷🇴 [ro](../ro/MCP-SERVER.md) · 🇭🇺 [hu](../hu/MCP-SERVER.md) · 🇧🇬 [bg](../bg/MCP-SERVER.md) · 🇸🇰 [sk](../sk/MCP-SERVER.md) · 🇺🇦 [uk-UA](../uk-UA/MCP-SERVER.md) · 🇮🇱 [he](../he/MCP-SERVER.md) · 🇵🇭 [phi](../phi/MCP-SERVER.md)
---
# OmniRoute MCP Server Documentation
> Model Context Protocol server with 16 intelligent tools
## Installation
OmniRoute MCP is built-in. Start it with:
```bash
omniroute --mcp
```
Or via the open-sse transport:
```bash
# HTTP streamable transport (port 20130)
omniroute --dev # MCP auto-starts on /mcp endpoint
```
## IDE Configuration
See [IDE Configs](integrations/ide-configs.md) for Antigravity, Cursor, Copilot, and Claude Desktop setup.
---
## Essential Tools (8)
| Tool | Description |
| :------------------------------ | :--------------------------------------- |
| `omniroute_get_health` | Gateway health, circuit breakers, uptime |
| `omniroute_list_combos` | All configured combos with models |
| `omniroute_get_combo_metrics` | Performance metrics for a specific combo |
| `omniroute_switch_combo` | Switch active combo by ID/name |
| `omniroute_check_quota` | Quota status per provider or all |
| `omniroute_route_request` | Send a chat completion through OmniRoute |
| `omniroute_cost_report` | Cost analytics for a time period |
| `omniroute_list_models_catalog` | Full model catalog with capabilities |
## Advanced Tools (8)
| Tool | Description |
| :--------------------------------- | :---------------------------------------------- |
| `omniroute_simulate_route` | Dry-run routing simulation with fallback tree |
| `omniroute_set_budget_guard` | Session budget with degrade/block/alert actions |
| `omniroute_set_resilience_profile` | Apply conservative/balanced/aggressive preset |
| `omniroute_test_combo` | Live-test all models in a combo |
| `omniroute_get_provider_metrics` | Detailed metrics for one provider |
| `omniroute_best_combo_for_task` | Task-fitness recommendation with alternatives |
| `omniroute_explain_route` | Explain a past routing decision |
| `omniroute_get_session_snapshot` | Full session state: costs, tokens, errors |
## Authentication
MCP tools are authenticated via API key scopes. Each tool requires specific scopes:
| Scope | Tools |
| :------------- | :----------------------------------------------- |
| `read:health` | get_health, get_provider_metrics |
| `read:combos` | list_combos, get_combo_metrics |
| `write:combos` | switch_combo |
| `read:quota` | check_quota |
| `write:route` | route_request, simulate_route, test_combo |
| `read:usage` | cost_report, get_session_snapshot, explain_route |
| `write:config` | set_budget_guard, set_resilience_profile |
| `read:models` | list_models_catalog, best_combo_for_task |
## Audit Logging
Every tool call is logged to `mcp_tool_audit` with:
- Tool name, arguments, result
- Duration (ms), success/failure
- API key hash, timestamp
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------------ |
| `open-sse/mcp-server/server.ts` | MCP server creation + 16 tool registrations |
| `open-sse/mcp-server/transport.ts` | Stdio + HTTP transport |
| `open-sse/mcp-server/auth.ts` | API key + scope validation |
| `open-sse/mcp-server/audit.ts` | Tool call audit logging |
| `open-sse/mcp-server/tools/advancedTools.ts` | 8 advanced tool handlers |

1687
docs/i18n/ar/README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/RELEASE_CHECKLIST.md) · 🇪🇸 [es](../es/RELEASE_CHECKLIST.md) · 🇫🇷 [fr](../fr/RELEASE_CHECKLIST.md) · 🇩🇪 [de](../de/RELEASE_CHECKLIST.md) · 🇮🇹 [it](../it/RELEASE_CHECKLIST.md) · 🇷🇺 [ru](../ru/RELEASE_CHECKLIST.md) · 🇨🇳 [zh-CN](../zh-CN/RELEASE_CHECKLIST.md) · 🇯🇵 [ja](../ja/RELEASE_CHECKLIST.md) · 🇰🇷 [ko](../ko/RELEASE_CHECKLIST.md) · 🇸🇦 [ar](../ar/RELEASE_CHECKLIST.md) · 🇮🇳 [in](../in/RELEASE_CHECKLIST.md) · 🇹🇭 [th](../th/RELEASE_CHECKLIST.md) · 🇻🇳 [vi](../vi/RELEASE_CHECKLIST.md) · 🇮🇩 [id](../id/RELEASE_CHECKLIST.md) · 🇲🇾 [ms](../ms/RELEASE_CHECKLIST.md) · 🇳🇱 [nl](../nl/RELEASE_CHECKLIST.md) · 🇵🇱 [pl](../pl/RELEASE_CHECKLIST.md) · 🇸🇪 [sv](../sv/RELEASE_CHECKLIST.md) · 🇳🇴 [no](../no/RELEASE_CHECKLIST.md) · 🇩🇰 [da](../da/RELEASE_CHECKLIST.md) · 🇫🇮 [fi](../fi/RELEASE_CHECKLIST.md) · 🇵🇹 [pt](../pt/RELEASE_CHECKLIST.md) · 🇷🇴 [ro](../ro/RELEASE_CHECKLIST.md) · 🇭🇺 [hu](../hu/RELEASE_CHECKLIST.md) · 🇧🇬 [bg](../bg/RELEASE_CHECKLIST.md) · 🇸🇰 [sk](../sk/RELEASE_CHECKLIST.md) · 🇺🇦 [uk-UA](../uk-UA/RELEASE_CHECKLIST.md) · 🇮🇱 [he](../he/RELEASE_CHECKLIST.md) · 🇵🇭 [phi](../phi/RELEASE_CHECKLIST.md)
---
# Release Checklist
Use this checklist before tagging or publishing a new OmniRoute release.
## Version and Changelog
1. Bump `package.json` version (`x.y.z`) in the release branch.
2. Move release notes from `## [Unreleased]` in `CHANGELOG.md` to a dated section:
- `## [x.y.z] — YYYY-MM-DD`
3. Keep `## [Unreleased]` as the first changelog section for upcoming work.
4. Ensure the latest semver section in `CHANGELOG.md` equals `package.json` version.
## API Docs
1. Update `docs/openapi.yaml`:
- `info.version` must equal `package.json` version.
2. Validate endpoint examples if API contracts changed.
## Runtime Docs
1. Review `docs/ARCHITECTURE.md` for storage/runtime drift.
2. Review `docs/TROUBLESHOOTING.md` for env var and operational drift.
3. Update localized docs if source docs changed significantly.
## Automated Check
Run the sync guard locally before opening PR:
```bash
npm run check:docs-sync
```
CI also runs this check in `.github/workflows/ci.yml` (lint job).

View File

@@ -0,0 +1,258 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/TROUBLESHOOTING.md) · 🇪🇸 [es](../es/TROUBLESHOOTING.md) · 🇫🇷 [fr](../fr/TROUBLESHOOTING.md) · 🇩🇪 [de](../de/TROUBLESHOOTING.md) · 🇮🇹 [it](../it/TROUBLESHOOTING.md) · 🇷🇺 [ru](../ru/TROUBLESHOOTING.md) · 🇨🇳 [zh-CN](../zh-CN/TROUBLESHOOTING.md) · 🇯🇵 [ja](../ja/TROUBLESHOOTING.md) · 🇰🇷 [ko](../ko/TROUBLESHOOTING.md) · 🇸🇦 [ar](../ar/TROUBLESHOOTING.md) · 🇮🇳 [in](../in/TROUBLESHOOTING.md) · 🇹🇭 [th](../th/TROUBLESHOOTING.md) · 🇻🇳 [vi](../vi/TROUBLESHOOTING.md) · 🇮🇩 [id](../id/TROUBLESHOOTING.md) · 🇲🇾 [ms](../ms/TROUBLESHOOTING.md) · 🇳🇱 [nl](../nl/TROUBLESHOOTING.md) · 🇵🇱 [pl](../pl/TROUBLESHOOTING.md) · 🇸🇪 [sv](../sv/TROUBLESHOOTING.md) · 🇳🇴 [no](../no/TROUBLESHOOTING.md) · 🇩🇰 [da](../da/TROUBLESHOOTING.md) · 🇫🇮 [fi](../fi/TROUBLESHOOTING.md) · 🇵🇹 [pt](../pt/TROUBLESHOOTING.md) · 🇷🇴 [ro](../ro/TROUBLESHOOTING.md) · 🇭🇺 [hu](../hu/TROUBLESHOOTING.md) · 🇧🇬 [bg](../bg/TROUBLESHOOTING.md) · 🇸🇰 [sk](../sk/TROUBLESHOOTING.md) · 🇺🇦 [uk-UA](../uk-UA/TROUBLESHOOTING.md) · 🇮🇱 [he](../he/TROUBLESHOOTING.md) · 🇵🇭 [phi](../phi/TROUBLESHOOTING.md)
---
# Troubleshooting
🌐 **Languages:** 🇺🇸 [English](TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](i18n/es/TROUBLESHOOTING.md) | 🇫🇷 [Français](i18n/fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](i18n/it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](i18n/ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](i18n/de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](i18n/in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](i18n/th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](i18n/uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](i18n/ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](i18n/ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](i18n/vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](i18n/bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](i18n/da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](i18n/fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](i18n/he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](i18n/hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](i18n/ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](i18n/nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](i18n/no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](i18n/pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](i18n/ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](i18n/pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](i18n/sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](i18n/sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](i18n/phi/TROUBLESHOOTING.md)
Common problems and solutions for OmniRoute.
---
## Quick Fixes
| Problem | Solution |
| ----------------------------- | ------------------------------------------------------------------ |
| First login not working | Set `INITIAL_PASSWORD` in `.env` (no hardcoded default) |
| Dashboard opens on wrong port | Set `PORT=20128` and `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
| No request logs under `logs/` | Set `ENABLE_REQUEST_LOGS=true` |
| EACCES: permission denied | Set `DATA_DIR=/path/to/writable/dir` to override `~/.omniroute` |
| Routing strategy not saving | Update to v1.4.11+ (Zod schema fix for settings persistence) |
---
## Provider Issues
### "Language model did not provide messages"
**Cause:** Provider quota exhausted.
**Fix:**
1. Check dashboard quota tracker
2. Use a combo with fallback tiers
3. Switch to cheaper/free tier
### Rate Limiting
**Cause:** Subscription quota exhausted.
**Fix:**
- Add fallback: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
- Use GLM/MiniMax as cheap backup
### OAuth Token Expired
OmniRoute auto-refreshes tokens. If issues persist:
1. Dashboard → Provider → Reconnect
2. Delete and re-add the provider connection
---
## Cloud Issues
### Cloud Sync Errors
1. Verify `BASE_URL` points to your running instance (e.g., `http://localhost:20128`)
2. Verify `CLOUD_URL` points to your cloud endpoint (e.g., `https://omniroute.dev`)
3. Keep `NEXT_PUBLIC_*` values aligned with server-side values
### Cloud `stream=false` Returns 500
**Symptom:** `Unexpected token 'd'...` on cloud endpoint for non-streaming calls.
**Cause:** Upstream returns SSE payload while client expects JSON.
**Workaround:** Use `stream=true` for cloud direct calls. Local runtime includes SSE→JSON fallback.
### Cloud Says Connected but "Invalid API key"
1. Create a fresh key from local dashboard (`/api/keys`)
2. Run cloud sync: Enable Cloud → Sync Now
3. Old/non-synced keys can still return `401` on cloud
---
## Docker Issues
### CLI Tool Shows Not Installed
1. Check runtime fields: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
2. For portable mode: use image target `runner-cli` (bundled CLIs)
3. For host mount mode: set `CLI_EXTRA_PATHS` and mount host bin directory as read-only
4. If `installed=true` and `runnable=false`: binary was found but failed healthcheck
### Quick Runtime Validation
```bash
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
```
---
## Cost Issues
### High Costs
1. Check usage stats in Dashboard → Usage
2. Switch primary model to GLM/MiniMax
3. Use free tier (Gemini CLI, iFlow) for non-critical tasks
4. Set cost budgets per API key: Dashboard → API Keys → Budget
---
## Debugging
### Enable Request Logs
Set `ENABLE_REQUEST_LOGS=true` in your `.env` file. Logs appear under `logs/` directory.
### Check Provider Health
```bash
# Health dashboard
http://localhost:20128/dashboard/health
# API health check
curl http://localhost:20128/api/monitoring/health
```
### Runtime Storage
- Main state: `${DATA_DIR}/storage.sqlite` (providers, combos, aliases, keys, settings)
- Usage: SQLite tables in `storage.sqlite` (`usage_history`, `call_logs`, `proxy_logs`) + optional `${DATA_DIR}/log.txt` and `${DATA_DIR}/call_logs/`
- Request logs: `<repo>/logs/...` (when `ENABLE_REQUEST_LOGS=true`)
---
## Circuit Breaker Issues
### Provider stuck in OPEN state
When a provider's circuit breaker is OPEN, requests are blocked until the cooldown expires.
**Fix:**
1. Go to **Dashboard → Settings → Resilience**
2. Check the circuit breaker card for the affected provider
3. Click **Reset All** to clear all breakers, or wait for the cooldown to expire
4. Verify the provider is actually available before resetting
### Provider keeps tripping the circuit breaker
If a provider repeatedly enters OPEN state:
1. Check **Dashboard → Health → Provider Health** for the failure pattern
2. Go to **Settings → Resilience → Provider Profiles** and increase the failure threshold
3. Check if the provider has changed API limits or requires re-authentication
4. Review latency telemetry — high latency may cause timeout-based failures
---
## Audio Transcription Issues
### "Unsupported model" error
- Ensure you're using the correct prefix: `deepgram/nova-3` or `assemblyai/best`
- Verify the provider is connected in **Dashboard → Providers**
### Transcription returns empty or fails
- Check supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`
- Verify file size is within provider limits (typically < 25MB)
- Check provider API key validity in the provider card
---
## Translator Debugging
Use **Dashboard → Translator** to debug format translation issues:
| Mode | When to Use |
| ---------------- | -------------------------------------------------------------------------------------------- |
| **Playground** | Compare input/output formats side by side — paste a failing request to see how it translates |
| **Chat Tester** | Send live messages and inspect the full request/response payload including headers |
| **Test Bench** | Run batch tests across format combinations to find which translations are broken |
| **Live Monitor** | Watch real-time request flow to catch intermittent translation issues |
### Common format issues
- **Thinking tags not appearing** — Check if the target provider supports thinking and the thinking budget setting
- **Tool calls dropping** — Some format translations may strip unsupported fields; verify in Playground mode
- **System prompt missing** — Claude and Gemini handle system prompts differently; check translation output
- **SDK returns raw string instead of object** — Fixed in v1.1.0: response sanitizer now strips non-standard fields (`x_groq`, `usage_breakdown`, etc.) that cause OpenAI SDK Pydantic validation failures
- **GLM/ERNIE rejects `system` role** — Fixed in v1.1.0: role normalizer automatically merges system messages into user messages for incompatible models
- **`developer` role not recognized** — Fixed in v1.1.0: automatically converted to `system` for non-OpenAI providers
- **`json_schema` not working with Gemini** — Fixed in v1.1.0: `response_format` is now converted to Gemini's `responseMimeType` + `responseSchema`
---
## Resilience Settings
### Auto rate-limit not triggering
- Auto rate-limit only applies to API key providers (not OAuth/subscription)
- Verify **Settings → Resilience → Provider Profiles** has auto-rate-limit enabled
- Check if the provider returns `429` status codes or `Retry-After` headers
### Tuning exponential backoff
Provider profiles support these settings:
- **Base delay** — Initial wait time after first failure (default: 1s)
- **Max delay** — Maximum wait time cap (default: 30s)
- **Multiplier** — How much to increase delay per consecutive failure (default: 2x)
### Anti-thundering herd
When many concurrent requests hit a rate-limited provider, OmniRoute uses mutex + auto rate-limiting to serialize requests and prevent cascading failures. This is automatic for API key providers.
---
## Optional RAG / LLM failure taxonomy (16 problems)
Some OmniRoute users place the gateway in front of RAG or agent stacks. In those setups it is common to see a strange pattern: OmniRoute looks healthy (providers up, routing profiles ok, no rate limit alerts) but the final answer is still wrong.
In practice these incidents usually come from the downstream RAG pipeline, not from the gateway itself.
If you want a shared vocabulary to describe those failures you can use the WFGY ProblemMap, an external MIT license text resource that defines sixteen recurring RAG / LLM failure patterns. At a high level it covers:
- retrieval drift and broken context boundaries
- empty or stale indexes and vector stores
- embedding versus semantic mismatch
- prompt assembly and context window issues
- logic collapse and overconfident answers
- long chain and agent coordination failures
- multi agent memory and role drift
- deployment and bootstrap ordering problems
The idea is simple:
1. When you investigate a bad response, capture:
- user task and request
- route or provider combo in OmniRoute
- any RAG context used downstream (retrieved documents, tool calls, etc)
2. Map the incident to one or two WFGY ProblemMap numbers (`No.1``No.16`).
3. Store the number in your own dashboard, runbook, or incident tracker next to the OmniRoute logs.
4. Use the corresponding WFGY page to decide whether you need to change your RAG stack, retriever, or routing strategy.
Full text and concrete recipes live here (MIT license, text only):
[WFGY ProblemMap README](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
You can ignore this section if you do not run RAG or agent pipelines behind OmniRoute.
---
## Still Stuck?
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **Architecture**: See [`docs/ARCHITECTURE.md`](ARCHITECTURE.md) for internal details
- **API Reference**: See [`docs/API_REFERENCE.md`](API_REFERENCE.md) for all endpoints
- **Health Dashboard**: Check **Dashboard → Health** for real-time system status
- **Translator**: Use **Dashboard → Translator** to debug format issues

813
docs/i18n/ar/USER_GUIDE.md Normal file
View File

@@ -0,0 +1,813 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/USER_GUIDE.md) · 🇪🇸 [es](../es/USER_GUIDE.md) · 🇫🇷 [fr](../fr/USER_GUIDE.md) · 🇩🇪 [de](../de/USER_GUIDE.md) · 🇮🇹 [it](../it/USER_GUIDE.md) · 🇷🇺 [ru](../ru/USER_GUIDE.md) · 🇨🇳 [zh-CN](../zh-CN/USER_GUIDE.md) · 🇯🇵 [ja](../ja/USER_GUIDE.md) · 🇰🇷 [ko](../ko/USER_GUIDE.md) · 🇸🇦 [ar](../ar/USER_GUIDE.md) · 🇮🇳 [in](../in/USER_GUIDE.md) · 🇹🇭 [th](../th/USER_GUIDE.md) · 🇻🇳 [vi](../vi/USER_GUIDE.md) · 🇮🇩 [id](../id/USER_GUIDE.md) · 🇲🇾 [ms](../ms/USER_GUIDE.md) · 🇳🇱 [nl](../nl/USER_GUIDE.md) · 🇵🇱 [pl](../pl/USER_GUIDE.md) · 🇸🇪 [sv](../sv/USER_GUIDE.md) · 🇳🇴 [no](../no/USER_GUIDE.md) · 🇩🇰 [da](../da/USER_GUIDE.md) · 🇫🇮 [fi](../fi/USER_GUIDE.md) · 🇵🇹 [pt](../pt/USER_GUIDE.md) · 🇷🇴 [ro](../ro/USER_GUIDE.md) · 🇭🇺 [hu](../hu/USER_GUIDE.md) · 🇧🇬 [bg](../bg/USER_GUIDE.md) · 🇸🇰 [sk](../sk/USER_GUIDE.md) · 🇺🇦 [uk-UA](../uk-UA/USER_GUIDE.md) · 🇮🇱 [he](../he/USER_GUIDE.md) · 🇵🇭 [phi](../phi/USER_GUIDE.md)
---
# User Guide
🌐 **Languages:** 🇺🇸 [English](USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](i18n/es/USER_GUIDE.md) | 🇫🇷 [Français](i18n/fr/USER_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/USER_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/USER_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/USER_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/USER_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/USER_GUIDE.md) | 🇧🇬 [Български](i18n/bg/USER_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/USER_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/USER_GUIDE.md) | 🇮🇱 [עברית](i18n/he/USER_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/USER_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/USER_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/USER_GUIDE.md) | 🇷🇴 [Română](i18n/ro/USER_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/USER_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/USER_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/USER_GUIDE.md)
Complete guide for configuring providers, creating combos, integrating CLI tools, and deploying OmniRoute.
---
## Table of Contents
- [Pricing at a Glance](#-pricing-at-a-glance)
- [Use Cases](#-use-cases)
- [Provider Setup](#-provider-setup)
- [CLI Integration](#-cli-integration)
- [Deployment](#-deployment)
- [Available Models](#-available-models)
- [Advanced Features](#-advanced-features)
---
## 💰 Pricing at a Glance
| Tier | Provider | Cost | Quota Reset | Best For |
| ------------------- | ----------------- | ----------- | ---------------- | -------------------- |
| **💳 SUBSCRIPTION** | Claude Code (Pro) | $20/mo | 5h + weekly | Already subscribed |
| | Codex (Plus/Pro) | $20-200/mo | 5h + weekly | OpenAI users |
| | Gemini CLI | **FREE** | 180K/mo + 1K/day | Everyone! |
| | GitHub Copilot | $10-19/mo | Monthly | GitHub users |
| **🔑 API KEY** | DeepSeek | Pay per use | None | Cheap reasoning |
| | Groq | Pay per use | None | Ultra-fast inference |
| | xAI (Grok) | Pay per use | None | Grok 4 reasoning |
| | Mistral | Pay per use | None | EU-hosted models |
| | Perplexity | Pay per use | None | Search-augmented |
| | Together AI | Pay per use | None | Open-source models |
| | Fireworks AI | Pay per use | None | Fast FLUX images |
| | Cerebras | Pay per use | None | Wafer-scale speed |
| | Cohere | Pay per use | None | Command R+ RAG |
| | NVIDIA NIM | Pay per use | None | Enterprise models |
| **💰 CHEAP** | GLM-4.7 | $0.6/1M | Daily 10AM | Budget backup |
| | MiniMax M2.1 | $0.2/1M | 5-hour rolling | Cheapest option |
| | Kimi K2 | $9/mo flat | 10M tokens/mo | Predictable cost |
| **🆓 FREE** | iFlow | $0 | Unlimited | 8 models free |
| | Qwen | $0 | Unlimited | 3 models free |
| | Kiro | $0 | Unlimited | Claude free |
**💡 Pro Tip:** Start with Gemini CLI (180K free/month) + iFlow (unlimited free) combo = $0 cost!
---
## 🎯 Use Cases
### Case 1: "I have Claude Pro subscription"
**Problem:** Quota expires unused, rate limits during heavy coding
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (use subscription fully)
2. glm/glm-4.7 (cheap backup when quota out)
3. if/kimi-k2-thinking (free emergency fallback)
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Case 2: "I want zero cost"
**Problem:** Can't afford subscriptions, need reliable AI coding
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K free/month)
2. if/kimi-k2-thinking (unlimited free)
3. qw/qwen3-coder-plus (unlimited free)
Monthly cost: $0
Quality: Production-ready models
```
### Case 3: "I need 24/7 coding, no interruptions"
**Problem:** Deadlines, can't afford downtime
```
Combo: "always-on"
1. cc/claude-opus-4-6 (best quality)
2. cx/gpt-5.2-codex (second subscription)
3. glm/glm-4.7 (cheap, resets daily)
4. minimax/MiniMax-M2.1 (cheapest, 5h reset)
5. if/kimi-k2-thinking (free unlimited)
Result: 5 layers of fallback = zero downtime
Monthly cost: $20-200 (subscriptions) + $10-20 (backup)
```
### Case 4: "I want FREE AI in OpenClaw"
**Problem:** Need AI assistant in messaging apps, completely free
```
Combo: "openclaw-free"
1. if/glm-4.7 (unlimited free)
2. if/minimax-m2.1 (unlimited free)
3. if/kimi-k2-thinking (unlimited free)
Monthly cost: $0
Access via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 📖 Provider Setup
### 🔐 Subscription Providers
#### Claude Code (Pro/Max)
```bash
Dashboard → Providers → Connect Claude Code
→ OAuth login → Auto token refresh
→ 5-hour + weekly quota tracking
Models:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Pro Tip:** Use Opus for complex tasks, Sonnet for speed. OmniRoute tracks quota per model!
#### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Providers → Connect Codex
→ OAuth login (port 1455)
→ 5-hour + weekly reset
Models:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
#### Gemini CLI (FREE 180K/month!)
```bash
Dashboard → Providers → Connect Gemini CLI
→ Google OAuth
→ 180K completions/month + 1K/day
Models:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Best Value:** Huge free tier! Use this before paid tiers.
#### GitHub Copilot
```bash
Dashboard → Providers → Connect GitHub
→ OAuth via GitHub
→ Monthly reset (1st of month)
Models:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
### 💰 Cheap Providers
#### GLM-4.7 (Daily reset, $0.6/1M)
1. Sign up: [Zhipu AI](https://open.bigmodel.cn/)
2. Get API key from Coding Plan
3. Dashboard → Add API Key: Provider: `glm`, API Key: `your-key`
**Use:** `glm/glm-4.7`**Pro Tip:** Coding Plan offers 3× quota at 1/7 cost! Reset daily 10:00 AM.
#### MiniMax M2.1 (5h reset, $0.20/1M)
1. Sign up: [MiniMax](https://www.minimax.io/)
2. Get API key → Dashboard → Add API Key
**Use:** `minimax/MiniMax-M2.1`**Pro Tip:** Cheapest option for long context (1M tokens)!
#### Kimi K2 ($9/month flat)
1. Subscribe: [Moonshot AI](https://platform.moonshot.ai/)
2. Get API key → Dashboard → Add API Key
**Use:** `kimi/kimi-latest`**Pro Tip:** Fixed $9/month for 10M tokens = $0.90/1M effective cost!
### 🆓 FREE Providers
#### iFlow (8 FREE models)
```bash
Dashboard → Connect iFlow → OAuth login → Unlimited usage
Models: if/kimi-k2-thinking, if/qwen3-coder-plus, if/glm-4.7, if/minimax-m2, if/deepseek-r1
```
#### Qwen (3 FREE models)
```bash
Dashboard → Connect Qwen → Device code auth → Unlimited usage
Models: qw/qwen3-coder-plus, qw/qwen3-coder-flash
```
#### Kiro (Claude FREE)
```bash
Dashboard → Connect Kiro → AWS Builder ID or Google/GitHub → Unlimited
Models: kr/claude-sonnet-4.5, kr/claude-haiku-4.5
```
---
## 🎨 Combos
### Example 1: Maximize Subscription → Cheap Backup
```
Dashboard → Combos → Create New
Name: premium-coding
Models:
1. cc/claude-opus-4-6 (Subscription primary)
2. glm/glm-4.7 (Cheap backup, $0.6/1M)
3. minimax/MiniMax-M2.1 (Cheapest fallback, $0.20/1M)
Use in CLI: premium-coding
```
### Example 2: Free-Only (Zero Cost)
```
Name: free-combo
Models:
1. gc/gemini-3-flash-preview (180K free/month)
2. if/kimi-k2-thinking (unlimited)
3. qw/qwen3-coder-plus (unlimited)
Cost: $0 forever!
```
---
## 🔧 CLI Integration
### Cursor IDE
```
Settings → Models → Advanced:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [from omniroute dashboard]
Model: cc/claude-opus-4-6
```
### Claude Code
Edit `~/.claude/config.json`:
```json
{
"anthropic_api_base": "http://localhost:20128/v1",
"anthropic_api_key": "your-omniroute-api-key"
}
```
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
Edit `~/.openclaw/openclaw.json`:
```json
{
"agents": {
"defaults": {
"model": { "primary": "omniroute/if/glm-4.7" }
}
},
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://localhost:20128/v1",
"apiKey": "your-omniroute-api-key",
"api": "openai-completions",
"models": [{ "id": "if/glm-4.7", "name": "glm-4.7" }]
}
}
}
}
```
**Or use Dashboard:** CLI Tools → OpenClaw → Auto-config
### Cline / Continue / RooCode
```
Provider: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [from dashboard]
Model: cc/claude-opus-4-6
```
---
## 🚀 Deployment
### Global npm install (Recommended)
```bash
npm install -g omniroute
# Create config directory
mkdir -p ~/.omniroute
# Create .env file (see .env.example)
cp .env.example ~/.omniroute/.env
# Start server
omniroute
# Or with custom port:
omniroute --port 3000
```
The CLI automatically loads `.env` from `~/.omniroute/.env` or `./.env`.
### VPS Deployment
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute && npm install && npm run build
export JWT_SECRET="your-secure-secret-change-this"
export INITIAL_PASSWORD="your-password"
export DATA_DIR="/var/lib/omniroute"
export PORT="20128"
export HOSTNAME="0.0.0.0"
export NODE_ENV="production"
export NEXT_PUBLIC_BASE_URL="http://localhost:20128"
export API_KEY_SECRET="endpoint-proxy-api-key-secret"
npm run start
# Or: pm2 start npm --name omniroute -- start
```
### PM2 Deployment (Low Memory)
For servers with limited RAM, use the memory limit option:
```bash
# With 512MB limit (default)
pm2 start npm --name omniroute -- start
# Or with custom memory limit
OMNIROUTE_MEMORY_MB=512 pm2 start npm --name omniroute -- start
# Or using ecosystem.config.js
pm2 start ecosystem.config.js
```
Create `ecosystem.config.js`:
```javascript
module.exports = {
apps: [
{
name: "omniroute",
script: "npm",
args: "start",
env: {
NODE_ENV: "production",
OMNIROUTE_MEMORY_MB: "512",
JWT_SECRET: "your-secret",
INITIAL_PASSWORD: "your-password",
},
node_args: "--max-old-space-size=512",
max_memory_restart: "300M",
},
],
};
```
### Docker
```bash
# Build image (default = runner-cli with codex/claude/droid preinstalled)
docker build -t omniroute:cli .
# Portable mode (recommended)
docker run -d --name omniroute -p 20128:20128 --env-file ./.env -v omniroute-data:/app/data omniroute:cli
```
For host-integrated mode with CLI binaries, see the Docker section in the main docs.
### Environment Variables
| Variable | Default | Description |
| ------------------------- | ------------------------------------ | ------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | JWT signing secret (**change in production**) |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `DATA_DIR` | `~/.omniroute` | Data directory (db, usage, logs) |
| `PORT` | framework default | Service port (`20128` in examples) |
| `HOSTNAME` | framework default | Bind host (Docker defaults to `0.0.0.0`) |
| `NODE_ENV` | runtime default | Set `production` for deploy |
| `BASE_URL` | `http://localhost:20128` | Server-side internal base URL |
| `CLOUD_URL` | `https://omniroute.dev` | Cloud sync endpoint base URL |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | HMAC secret for generated API keys |
| `REQUIRE_API_KEY` | `false` | Enforce Bearer API key on `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | Enables request/response logs |
| `AUTH_COOKIE_SECURE` | `false` | Force `Secure` auth cookie (behind HTTPS reverse proxy) |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit in MB |
| `PROMPT_CACHE_MAX_SIZE` | `50` | Max prompt cache entries |
| `SEMANTIC_CACHE_MAX_SIZE` | `100` | Max semantic cache entries |
For the full environment variable reference, see the [README](../README.md).
---
## 📊 Available Models
<details>
<summary><b>View all available models</b></summary>
**Claude Code (`cc/`)** — Pro/Max: `cc/claude-opus-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** — Plus/Pro: `cx/gpt-5.2-codex`, `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** — FREE: `gc/gemini-3-flash-preview`, `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**: `gh/gpt-5`, `gh/claude-4.5-sonnet`
**GLM (`glm/`)** — $0.6/1M: `glm/glm-4.7`
**MiniMax (`minimax/`)** — $0.2/1M: `minimax/MiniMax-M2.1`
**iFlow (`if/`)** — FREE: `if/kimi-k2-thinking`, `if/qwen3-coder-plus`, `if/deepseek-r1`
**Qwen (`qw/`)** — FREE: `qw/qwen3-coder-plus`, `qw/qwen3-coder-flash`
**Kiro (`kr/`)** — FREE: `kr/claude-sonnet-4.5`, `kr/claude-haiku-4.5`
**DeepSeek (`ds/`)**: `ds/deepseek-chat`, `ds/deepseek-reasoner`
**Groq (`groq/`)**: `groq/llama-3.3-70b-versatile`, `groq/llama-4-maverick-17b-128e-instruct`
**xAI (`xai/`)**: `xai/grok-4`, `xai/grok-4-0709-fast-reasoning`, `xai/grok-code-mini`
**Mistral (`mistral/`)**: `mistral/mistral-large-2501`, `mistral/codestral-2501`
**Perplexity (`pplx/`)**: `pplx/sonar-pro`, `pplx/sonar`
**Together AI (`together/`)**: `together/meta-llama/Llama-3.3-70B-Instruct-Turbo`
**Fireworks AI (`fireworks/`)**: `fireworks/accounts/fireworks/models/deepseek-v3p1`
**Cerebras (`cerebras/`)**: `cerebras/llama-3.3-70b`
**Cohere (`cohere/`)**: `cohere/command-r-plus-08-2024`
**NVIDIA NIM (`nvidia/`)**: `nvidia/nvidia/llama-3.3-70b-instruct`
</details>
---
## 🧩 Advanced Features
### Custom Models
Add any model ID to any provider without waiting for an app update:
```bash
# Via API
curl -X POST http://localhost:20128/api/provider-models \
-H "Content-Type: application/json" \
-d '{"provider": "openai", "modelId": "gpt-4.5-preview", "modelName": "GPT-4.5 Preview"}'
# List: curl http://localhost:20128/api/provider-models?provider=openai
# Remove: curl -X DELETE "http://localhost:20128/api/provider-models?provider=openai&model=gpt-4.5-preview"
```
Or use Dashboard: **Providers → [Provider] → Custom Models**.
### Dedicated Provider Routes
Route requests directly to a specific provider with model validation:
```bash
POST http://localhost:20128/v1/providers/openai/chat/completions
POST http://localhost:20128/v1/providers/openai/embeddings
POST http://localhost:20128/v1/providers/fireworks/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
### Network Proxy Configuration
```bash
# Set global proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"global": {"type":"http","host":"proxy.example.com","port":"8080"}}'
# Per-provider proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"providers": {"openai": {"type":"socks5","host":"proxy.example.com","port":"1080"}}}'
# Test proxy
curl -X POST http://localhost:20128/api/settings/proxy/test \
-d '{"proxy":{"type":"socks5","host":"proxy.example.com","port":"1080"}}'
```
**Precedence:** Key-specific → Combo-specific → Provider-specific → Global → Environment.
### Model Catalog API
```bash
curl http://localhost:20128/api/models/catalog
```
Returns models grouped by provider with types (`chat`, `embedding`, `image`).
### Cloud Sync
- Sync providers, combos, and settings across devices
- Automatic background sync with timeout + fail-fast
- Prefer server-side `BASE_URL`/`CLOUD_URL` in production
### LLM Gateway Intelligence (Phase 9)
- **Semantic Cache** — Auto-caches non-streaming, temperature=0 responses (bypass with `X-OmniRoute-No-Cache: true`)
- **Request Idempotency** — Deduplicates requests within 5s via `Idempotency-Key` or `X-Request-Id` header
- **Progress Tracking** — Opt-in SSE `event: progress` events via `X-OmniRoute-Progress: true` header
---
### Translator Playground
Access via **Dashboard → Translator**. Debug and visualize how OmniRoute translates API requests between providers.
| Mode | Purpose |
| ---------------- | -------------------------------------------------------------------------------------- |
| **Playground** | Select source/target formats, paste a request, and see the translated output instantly |
| **Chat Tester** | Send live chat messages through the proxy and inspect the full request/response cycle |
| **Test Bench** | Run batch tests across multiple format combinations to verify translation correctness |
| **Live Monitor** | Watch real-time translations as requests flow through the proxy |
**Use cases:**
- Debug why a specific client/provider combination fails
- Verify that thinking tags, tool calls, and system prompts translate correctly
- Compare format differences between OpenAI, Claude, Gemini, and Responses API formats
---
### Routing Strategies
Configure via **Dashboard → Settings → Routing**.
| Strategy | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------ |
| **Fill First** | Uses accounts in priority order — primary account handles all requests until unavailable |
| **Round Robin** | Cycles through all accounts with a configurable sticky limit (default: 3 calls per account) |
| **P2C (Power of Two Choices)** | Picks 2 random accounts and routes to the healthier one — balances load with awareness of health |
| **Random** | Randomly selects an account for each request using Fisher-Yates shuffle |
| **Least Used** | Routes to the account with the oldest `lastUsedAt` timestamp, distributing traffic evenly |
| **Cost Optimized** | Routes to the account with the lowest priority value, optimizing for lowest-cost providers |
#### Wildcard Model Aliases
Create wildcard patterns to remap model names:
```
Pattern: claude-sonnet-* → Target: cc/claude-sonnet-4-5-20250929
Pattern: gpt-* → Target: gh/gpt-5.1-codex
```
Wildcards support `*` (any characters) and `?` (single character).
#### Fallback Chains
Define global fallback chains that apply across all requests:
```
Chain: production-fallback
1. cc/claude-opus-4-6
2. gh/gpt-5.1-codex
3. glm/glm-4.7
```
---
### Resilience & Circuit Breakers
Configure via **Dashboard → Settings → Resilience**.
OmniRoute implements provider-level resilience with four components:
1. **Provider Profiles** — Per-provider configuration for:
- Failure threshold (how many failures before opening)
- Cooldown duration
- Rate limit detection sensitivity
- Exponential backoff parameters
2. **Editable Rate Limits** — System-level defaults configurable in the dashboard:
- **Requests Per Minute (RPM)** — Maximum requests per minute per account
- **Min Time Between Requests** — Minimum gap in milliseconds between requests
- **Max Concurrent Requests** — Maximum simultaneous requests per account
- Click **Edit** to modify, then **Save** or **Cancel**. Values persist via the resilience API.
3. **Circuit Breaker** — Tracks failures per provider and automatically opens the circuit when a threshold is reached:
- **CLOSED** (Healthy) — Requests flow normally
- **OPEN** — Provider is temporarily blocked after repeated failures
- **HALF_OPEN** — Testing if provider has recovered
4. **Policies & Locked Identifiers** — Shows circuit breaker status and locked identifiers with force-unlock capability.
5. **Rate Limit Auto-Detection** — Monitors `429` and `Retry-After` headers to proactively avoid hitting provider rate limits.
**Pro Tip:** Use **Reset All** button to clear all circuit breakers and cooldowns when a provider recovers from an outage.
---
### Database Export / Import
Manage database backups in **Dashboard → Settings → System & Storage**.
| Action | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| **Export Database** | Downloads the current SQLite database as a `.sqlite` file |
| **Export All (.tar.gz)** | Downloads a full backup archive including: database, settings, combos, provider connections (no credentials), API key metadata |
| **Import Database** | Upload a `.sqlite` file to replace the current database. A pre-import backup is automatically created |
```bash
# API: Export database
curl -o backup.sqlite http://localhost:20128/api/db-backups/export
# API: Export all (full archive)
curl -o backup.tar.gz http://localhost:20128/api/db-backups/exportAll
# API: Import database
curl -X POST http://localhost:20128/api/db-backups/import \
-F "file=@backup.sqlite"
```
**Import Validation:** The imported file is validated for integrity (SQLite pragma check), required tables (`provider_connections`, `provider_nodes`, `combos`, `api_keys`), and size (max 100MB).
**Use Cases:**
- Migrate OmniRoute between machines
- Create external backups for disaster recovery
- Share configurations between team members (export all → share archive)
---
### Settings Dashboard
The settings page is organized into 5 tabs for easy navigation:
| Tab | Contents |
| -------------- | ---------------------------------------------------------------------------------------------- |
| **Security** | Login/Password settings, IP Access Control, API auth for `/models`, and Provider Blocking |
| **Routing** | Global routing strategy (6 options), wildcard model aliases, fallback chains, combo defaults |
| **Resilience** | Provider profiles, editable rate limits, circuit breaker status, policies & locked identifiers |
| **AI** | Thinking budget configuration, global system prompt injection, prompt cache stats |
| **Advanced** | Global proxy configuration (HTTP/SOCKS5) |
---
### Costs & Budget Management
Access via **Dashboard → Costs**.
| Tab | Purpose |
| ----------- | ---------------------------------------------------------------------------------------- |
| **Budget** | Set spending limits per API key with daily/weekly/monthly budgets and real-time tracking |
| **Pricing** | View and edit model pricing entries — cost per 1K input/output tokens per provider |
```bash
# API: Set a budget
curl -X POST http://localhost:20128/api/usage/budget \
-H "Content-Type: application/json" \
-d '{"keyId": "key-123", "limit": 50.00, "period": "monthly"}'
# API: Get current budget status
curl http://localhost:20128/api/usage/budget
```
**Cost Tracking:** Every request logs token usage and calculates cost using the pricing table. View breakdowns in **Dashboard → Usage** by provider, model, and API key.
---
### Audio Transcription
OmniRoute supports audio transcription via the OpenAI-compatible endpoint:
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
# Example with curl
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@audio.mp3" \
-F "model=deepgram/nova-3"
```
Available providers: **Deepgram** (`deepgram/`), **AssemblyAI** (`assemblyai/`).
Supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
### Combo Balancing Strategies
Configure per-combo balancing in **Dashboard → Combos → Create/Edit → Strategy**.
| Strategy | Description |
| ------------------ | ------------------------------------------------------------------------ |
| **Round-Robin** | Rotates through models sequentially |
| **Priority** | Always tries the first model; falls back only on error |
| **Random** | Picks a random model from the combo for each request |
| **Weighted** | Routes proportionally based on assigned weights per model |
| **Least-Used** | Routes to the model with the fewest recent requests (uses combo metrics) |
| **Cost-Optimized** | Routes to the cheapest available model (uses pricing table) |
Global combo defaults can be set in **Dashboard → Settings → Routing → Combo Defaults**.
---
### Health Dashboard
Access via **Dashboard → Health**. Real-time system health overview with 6 cards:
| Card | What It Shows |
| --------------------- | ----------------------------------------------------------- |
| **System Status** | Uptime, version, memory usage, data directory |
| **Provider Health** | Per-provider circuit breaker state (Closed/Open/Half-Open) |
| **Rate Limits** | Active rate limit cooldowns per account with remaining time |
| **Active Lockouts** | Providers temporarily blocked by the lockout policy |
| **Signature Cache** | Deduplication cache stats (active keys, hit rate) |
| **Latency Telemetry** | p50/p95/p99 latency aggregation per provider |
**Pro Tip:** The Health page auto-refreshes every 10 seconds. Use the circuit breaker card to identify which providers are experiencing issues.
---
## 🖥️ Desktop Application (Electron)
OmniRoute is available as a native desktop application for Windows, macOS, and Linux.
### Installation
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Building Installers
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Output → `electron/dist-electron/`
### Key Features
| Feature | Description |
| --------------------------- | ---------------------------------------------------- |
| **Server Readiness** | Polls server before showing window (no blank screen) |
| **System Tray** | Minimize to tray, change port, quit from tray menu |
| **Port Management** | Change server port from tray (auto-restarts server) |
| **Content Security Policy** | Restrictive CSP via session headers |
| **Single Instance** | Only one app instance can run at a time |
| **Offline Mode** | Bundled Next.js server works without internet |
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------- | -------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
📖 Full documentation: [`electron/README.md`](../electron/README.md)

View File

@@ -0,0 +1,401 @@
# OmniRoute — دليل النشر على VM باستخدام Cloudflare
🌐 **Languages:** 🇺🇸 [English](../../VM_DEPLOYMENT_GUIDE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/VM_DEPLOYMENT_GUIDE.md) | 🇪🇸 [Español](../es/VM_DEPLOYMENT_GUIDE.md) | 🇫🇷 [Français](../fr/VM_DEPLOYMENT_GUIDE.md) | 🇮🇹 [Italiano](../it/VM_DEPLOYMENT_GUIDE.md) | 🇷🇺 [Русский](../ru/VM_DEPLOYMENT_GUIDE.md) | 🇨🇳 [中文 (简体)](../zh-CN/VM_DEPLOYMENT_GUIDE.md) | 🇩🇪 [Deutsch](../de/VM_DEPLOYMENT_GUIDE.md) | 🇮🇳 [हिन्दी](../in/VM_DEPLOYMENT_GUIDE.md) | 🇹🇭 [ไทย](../th/VM_DEPLOYMENT_GUIDE.md) | 🇺🇦 [Українська](../uk-UA/VM_DEPLOYMENT_GUIDE.md) | 🇸🇦 [العربية](../ar/VM_DEPLOYMENT_GUIDE.md) | 🇯🇵 [日本語](../ja/VM_DEPLOYMENT_GUIDE.md) | 🇻🇳 [Tiếng Việt](../vi/VM_DEPLOYMENT_GUIDE.md) | 🇧🇬 [Български](../bg/VM_DEPLOYMENT_GUIDE.md) | 🇩🇰 [Dansk](../da/VM_DEPLOYMENT_GUIDE.md) | 🇫🇮 [Suomi](../fi/VM_DEPLOYMENT_GUIDE.md) | 🇮🇱 [עברית](../he/VM_DEPLOYMENT_GUIDE.md) | 🇭🇺 [Magyar](../hu/VM_DEPLOYMENT_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](../id/VM_DEPLOYMENT_GUIDE.md) | 🇰🇷 [한국어](../ko/VM_DEPLOYMENT_GUIDE.md) | 🇲🇾 [Bahasa Melayu](../ms/VM_DEPLOYMENT_GUIDE.md) | 🇳🇱 [Nederlands](../nl/VM_DEPLOYMENT_GUIDE.md) | 🇳🇴 [Norsk](../no/VM_DEPLOYMENT_GUIDE.md) | 🇵🇹 [Português (Portugal)](../pt/VM_DEPLOYMENT_GUIDE.md) | 🇷🇴 [Română](../ro/VM_DEPLOYMENT_GUIDE.md) | 🇵🇱 [Polski](../pl/VM_DEPLOYMENT_GUIDE.md) | 🇸🇰 [Slovenčina](../sk/VM_DEPLOYMENT_GUIDE.md) | 🇸🇪 [Svenska](../sv/VM_DEPLOYMENT_GUIDE.md) | 🇵🇭 [Filipino](../phi/VM_DEPLOYMENT_GUIDE.md) | 🇨🇿 [Čeština](../cs/VM_DEPLOYMENT_GUIDE.md)
الدليل الكامل لتثبيت OmniRoute وتكوينه على VM (VPS) مع المجال المُدار عبر Cloudflare.
---
## المتطلبات الأساسية
| العنصر | الحد الأدنى | موصى به |
| ---------------------------- | ----------------------------------- | ----------------------------------- |
| ** وحدة المعالجة المركزية ** | 1 وحدة المعالجة المركزية الافتراضية | 2 وحدة المعالجة المركزية الافتراضية |
| **ذاكرة الوصول العشوائي** | 1 جيجا | 2 جيجا |
| **القرص** | 10 جيجا اس اس دي | 25 جيجا اس اس دي |
| **نظام التشغيل** | أوبونتو 22.04 LTS | أوبونتو 24.04 LTS |
| **المجال** | مسجل في Cloudflare | — |
| ** عامل الميناء ** | محرك دوكر 24+ | عامل الميناء 27+ |
**المزودون الذين تم اختبارهم**: Akamai (Linode)، DigitalOcean، Vultr، Hetzner، AWS Lightsail.
---
## 1. قم بتكوين الجهاز الافتراضي
### 1.1 إنشاء المثيل
على موفر VPS المفضل لديك:
- اختر Ubuntu 24.04 LTS
- حدد الحد الأدنى للخطة (1 vCPU / 1 جيجابايت من ذاكرة الوصول العشوائي)
- قم بتعيين كلمة مرور جذر قوية أو قم بتكوين مفتاح SSH
- لاحظ **عنوان IP العام** (على سبيل المثال، `203.0.113.10`)
### 1.2 الاتصال عبر SSH
```bash
ssh root@203.0.113.10
```
### 1.3 تحديث النظام
```bash
apt update && apt upgrade -y
```
### 1.4 تثبيت عامل الميناء
```bash
# Install dependencies
apt install -y ca-certificates curl gnupg
# Add official Docker repository
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $ (. /etc/os-release && echo “$VERSION_CODENAME”) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
### 1.5 تثبيت nginx
```bash
apt install -y nginx
```
### 1.6 تكوين جدار الحماية (UFW)
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP (redirect)
ufw allow 443/tcp # HTTPS
ufw enable
```
> **نصيحة**: للحصول على الحد الأقصى من الأمان، قم بتقييد المنفذين 80 و443 بعناوين Cloudflare IP فقط. راجع قسم [Advanced Security](#advanced-security).
---
## 2. قم بتثبيت OmniRoute
### 2.1 إنشاء دليل التكوين
```bash
mkdir -p /opt/omniroute
```
### 2.2 إنشاء ملف متغيرات البيئة
```bash
cat > /opt/omniroute/.env << EOF
# === Security ===
JWT_SECRET=CHANGE-TO-A-UNIQUE-64-CHAR-SECRET-KEY
INITIAL_PASSWORD=YourSecurePassword123!
API_KEY_SECRET=REPLACE-WITH-ANOTHER-SECRET-KEY
STORAGE_ENCRYPTION_KEY=REPLACE-WITH-THIRD-SECRET-KEY
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=CHANGE-TO-A-UNIQUE-SALT
# === App ===
PORT=20128
NODE_ENV=production
HOSTNAME=0.0.0.0
DATA_DIR=/app/data
STORAGE_DRIVER=sqlite
ENABLE_REQUEST_LOGS=true
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# === Domain (change to your domain) ===
BASE_URL=https://llms.seudominio.com
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
# === Cloud Sync (optional) ===
# CLOUD_URL=https://cloud.omniroute.online
# NEXT_PUBLIC_CLOUD_URL=https://cloud.omniroute.online
EOF
```
> ⚠️ **هام**: أنشئ مفاتيح سرية فريدة! استخدم `openssl rand -hex 32` لكل مفتاح.
### 2.3 ابدأ الحاوية
```bash
docker pull diegosouzapw/omniroute:latest
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### 2.4 التحقق من أنه قيد التشغيل
```bash
docker ps | grep omniroute
docker logs omniroute --tail 20
```
يجب أن يعرض: `[DB] SQLite database ready` و`listening on port 20128`.
---
## 3. تكوين nginx (الوكيل العكسي)
### 3.1 إنشاء شهادة SSL (أصل Cloudflare)
في لوحة معلومات Cloudflare:
1. انتقل إلى **SSL/TLS → خادم الأصل**
2. انقر **إنشاء شهادة**
3. احتفظ بالإعدادات الافتراضية (15 عامًا، \*.yourdomain.com)
4. انسخ **شهادة المنشأ** و**المفتاح الخاص**
```bash
mkdir -p /etc/nginx/ssl
# Paste the certificate
nano /etc/nginx/ssl/origin.crt
# Paste the private key
nano /etc/nginx/ssl/origin.key
chmod 600 /etc/nginx/ssl/origin.key
```
### 3.2 تكوين إنجينكس
```bash
cat > /etc/nginx/sites-available/omniroute << NGINX
# Default server — blocks direct access via IP
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
server_name _;
return 444;
}
# OmniRoute — HTTPS
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name llms.yourdomain.com; # Change to your domain
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name llms.yourdomain.com;
return 301 https://$server_name$request_uri;
}
NGINX
```
### 3.3 تمكين واختبار
```bash
# Remove default configuration
rm -f /etc/nginx/sites-enabled/default
# Enable OmniRoute
ln -sf /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
# Test and reload
nginx -t && systemctl reload nginx
```
---
## 4. تكوين Cloudflare DNS
### 4.1 إضافة سجل DNS
في لوحة معلومات Cloudflare → DNS:
| اكتب | الاسم | المحتوى | الوكيل |
| ---- | ------ | ---------------------- | -------- |
| أ | `llms` | `203.0.113.10` (VM IP) | ✅ توكيل |
### 4.2 تكوين SSL
ضمن **SSL/TLS → نظرة عامة**:
- الوضع: **كامل (صارم)**
ضمن **SSL/TLS → شهادات الحافة**:
- استخدم HTTPS دائمًا: ✅ قيد التشغيل
- الحد الأدنى لإصدار TLS: TLS 1.2
- إعادة كتابة HTTPS تلقائيًا: ✅ تشغيل
### 4.3 الاختبار
```bash
curl -sI https://llms.seudominio.com/health
# Should return HTTP/2 200
```
---
## 5. العمليات والصيانة
### الترقية إلى الإصدار الجديد
```bash
docker pull diegosouzapw/omniroute:latest
docker stop omniroute && docker rm omniroute
docker run -d --name omniroute --restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### عرض السجلات
```bash
docker logs -f omniroute # Real-time stream
docker logs omniroute --tail 50 # Last 50 lines
```
### النسخ الاحتياطي لقاعدة البيانات يدويا
```bash
# Copy data from the volume to the host
docker cp omniroute:/app/data ./backup-$(date +%F)
# Or compress the entire volume
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine tar czf /backup/omniroute-data-$(date +%F).tar.gz /data
```
### الاستعادة من النسخة الاحتياطية
```bash
docker stop omniroute
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine sh -c “rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /”
docker start omniroute
```
---
## 6. الأمان المتقدم
### تقييد nginx على عناوين IP الخاصة بـ Cloudflare
```bash
cat > /etc/nginx/cloudflare-ips.conf << CF
# Cloudflare IPv4 ranges — update periodically
# https://www.cloudflare.com/ips-v4/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
CF
```
أضف ما يلي إلى `nginx.conf` داخل الكتلة `http {}`:
```nginx
include /etc/nginx/cloudflare-ips.conf;
```
### تثبيت Fail2ban
```bash
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
# Check status
fail2ban-client status sshd
```
### منع الوصول المباشر إلى منفذ Docker
```bash
# Prevent direct external access to port 20128
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
# Persist the rules
apt install -y iptables-persistent
netfilter-persistent save
```
---
## 7. النشر إلى عمال Cloudflare (اختياري)
للوصول عن بعد عبر Cloudflare Workers (دون الكشف عن الجهاز الافتراضي مباشرة):
```bash
# In the local repository
cd omnirouteCloud
npm install
npx wrangler login
npx wrangler deploy
```
راجع الوثائق الكاملة على [omnirouteCloud/README.md](../omnirouteCloud/README.md).
---
## ملخص المنفذ
| ميناء | الخدمة | الوصول |
| ----- | ------------- | ----------------------------- |
| 22 | سش | عام (مع Fail2ban) |
| 80 | إنجينكس HTTP | إعادة التوجيه → HTTPS |
| 443 | إنجينكس HTTPS | عبر وكيل Cloudflare |
| 20128 | أومنيروتي | المضيف المحلي فقط (عبر nginx) |

200
docs/i18n/bg/A2A-SERVER.md Normal file
View File

@@ -0,0 +1,200 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/A2A-SERVER.md) · 🇪🇸 [es](../es/A2A-SERVER.md) · 🇫🇷 [fr](../fr/A2A-SERVER.md) · 🇩🇪 [de](../de/A2A-SERVER.md) · 🇮🇹 [it](../it/A2A-SERVER.md) · 🇷🇺 [ru](../ru/A2A-SERVER.md) · 🇨🇳 [zh-CN](../zh-CN/A2A-SERVER.md) · 🇯🇵 [ja](../ja/A2A-SERVER.md) · 🇰🇷 [ko](../ko/A2A-SERVER.md) · 🇸🇦 [ar](../ar/A2A-SERVER.md) · 🇮🇳 [in](../in/A2A-SERVER.md) · 🇹🇭 [th](../th/A2A-SERVER.md) · 🇻🇳 [vi](../vi/A2A-SERVER.md) · 🇮🇩 [id](../id/A2A-SERVER.md) · 🇲🇾 [ms](../ms/A2A-SERVER.md) · 🇳🇱 [nl](../nl/A2A-SERVER.md) · 🇵🇱 [pl](../pl/A2A-SERVER.md) · 🇸🇪 [sv](../sv/A2A-SERVER.md) · 🇳🇴 [no](../no/A2A-SERVER.md) · 🇩🇰 [da](../da/A2A-SERVER.md) · 🇫🇮 [fi](../fi/A2A-SERVER.md) · 🇵🇹 [pt](../pt/A2A-SERVER.md) · 🇷🇴 [ro](../ro/A2A-SERVER.md) · 🇭🇺 [hu](../hu/A2A-SERVER.md) · 🇧🇬 [bg](../bg/A2A-SERVER.md) · 🇸🇰 [sk](../sk/A2A-SERVER.md) · 🇺🇦 [uk-UA](../uk-UA/A2A-SERVER.md) · 🇮🇱 [he](../he/A2A-SERVER.md) · 🇵🇭 [phi](../phi/A2A-SERVER.md)
---
# OmniRoute A2A Server Documentation
> Agent-to-Agent Protocol v0.3 — OmniRoute as an intelligent routing agent
## Agent Discovery
```bash
curl http://localhost:20128/.well-known/agent.json
```
Returns the Agent Card describing OmniRoute's capabilities, skills, and authentication requirements.
---
## Authentication
All `/a2a` requests require an API key via the `Authorization` header:
```
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
```
If no API key is configured on the server, authentication is bypassed.
---
## JSON-RPC 2.0 Methods
### `message/send` — Synchronous Execution
Sends a message to a skill and waits for the complete response.
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a hello world in Python"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
}
}'
```
**Response:**
```json
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task": { "id": "uuid", "state": "completed" },
"artifacts": [{ "type": "text", "content": "..." }],
"metadata": {
"routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
"cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" },
"resilience_trace": [
{ "event": "primary_selected", "provider": "anthropic", "timestamp": "..." }
],
"policy_verdict": { "allowed": true, "reason": "within budget and quota limits" }
}
}
}
```
### `message/stream` — SSE Streaming
Same as `message/send` but returns Server-Sent Events for real-time streaming.
```bash
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}
}'
```
**SSE Events:**
```
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
```
### `tasks/get` — Query Task Status
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'
```
### `tasks/cancel` — Cancel a Task
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'
```
---
## Available Skills
| Skill | Description |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------ |
| `smart-routing` | Routes prompts through OmniRoute's intelligent pipeline. Returns response with routing explanation, cost, and resilience trace. |
| `quota-management` | Answers natural-language queries about provider quotas, suggests free combos, and provides quota rankings. |
---
## Task Lifecycle
```
submitted → working → completed
→ failed
→ cancelled
```
- Tasks expire after 5 minutes (configurable)
- Terminal states: `completed`, `failed`, `cancelled`
- Event log tracks every state transition
---
## Error Codes
| Code | Meaning |
| :----- | :----------------------------- |
| -32700 | Parse error (invalid JSON) |
| -32600 | Invalid request / Unauthorized |
| -32601 | Method or skill not found |
| -32602 | Invalid params |
| -32603 | Internal error |
---
## Integration Examples
### Python (requests)
```python
import requests
resp = requests.post("http://localhost:20128/a2a", json={
"jsonrpc": "2.0", "id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Hello"}]
}
}, headers={"Authorization": "Bearer YOUR_KEY"})
result = resp.json()["result"]
print(result["artifacts"][0]["content"])
print(result["metadata"]["routing_explanation"])
```
### TypeScript (fetch)
```typescript
const resp = await fetch("http://localhost:20128/a2a", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_KEY",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "message/send",
params: {
skill: "smart-routing",
messages: [{ role: "user", content: "Hello" }],
},
}),
});
const { result } = await resp.json();
console.log(result.metadata.routing_explanation);
```

View File

@@ -0,0 +1,455 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/API_REFERENCE.md) · 🇪🇸 [es](../es/API_REFERENCE.md) · 🇫🇷 [fr](../fr/API_REFERENCE.md) · 🇩🇪 [de](../de/API_REFERENCE.md) · 🇮🇹 [it](../it/API_REFERENCE.md) · 🇷🇺 [ru](../ru/API_REFERENCE.md) · 🇨🇳 [zh-CN](../zh-CN/API_REFERENCE.md) · 🇯🇵 [ja](../ja/API_REFERENCE.md) · 🇰🇷 [ko](../ko/API_REFERENCE.md) · 🇸🇦 [ar](../ar/API_REFERENCE.md) · 🇮🇳 [in](../in/API_REFERENCE.md) · 🇹🇭 [th](../th/API_REFERENCE.md) · 🇻🇳 [vi](../vi/API_REFERENCE.md) · 🇮🇩 [id](../id/API_REFERENCE.md) · 🇲🇾 [ms](../ms/API_REFERENCE.md) · 🇳🇱 [nl](../nl/API_REFERENCE.md) · 🇵🇱 [pl](../pl/API_REFERENCE.md) · 🇸🇪 [sv](../sv/API_REFERENCE.md) · 🇳🇴 [no](../no/API_REFERENCE.md) · 🇩🇰 [da](../da/API_REFERENCE.md) · 🇫🇮 [fi](../fi/API_REFERENCE.md) · 🇵🇹 [pt](../pt/API_REFERENCE.md) · 🇷🇴 [ro](../ro/API_REFERENCE.md) · 🇭🇺 [hu](../hu/API_REFERENCE.md) · 🇧🇬 [bg](../bg/API_REFERENCE.md) · 🇸🇰 [sk](../sk/API_REFERENCE.md) · 🇺🇦 [uk-UA](../uk-UA/API_REFERENCE.md) · 🇮🇱 [he](../he/API_REFERENCE.md) · 🇵🇭 [phi](../phi/API_REFERENCE.md)
---
# API Reference
🌐 **Languages:** 🇺🇸 [English](API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](i18n/es/API_REFERENCE.md) | 🇫🇷 [Français](i18n/fr/API_REFERENCE.md) | 🇮🇹 [Italiano](i18n/it/API_REFERENCE.md) | 🇷🇺 [Русский](i18n/ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](i18n/de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](i18n/in/API_REFERENCE.md) | 🇹🇭 [ไทย](i18n/th/API_REFERENCE.md) | 🇺🇦 [Українська](i18n/uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](i18n/ar/API_REFERENCE.md) | 🇯🇵 [日本語](i18n/ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/API_REFERENCE.md) | 🇧🇬 [Български](i18n/bg/API_REFERENCE.md) | 🇩🇰 [Dansk](i18n/da/API_REFERENCE.md) | 🇫🇮 [Suomi](i18n/fi/API_REFERENCE.md) | 🇮🇱 [עברית](i18n/he/API_REFERENCE.md) | 🇭🇺 [Magyar](i18n/hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/API_REFERENCE.md) | 🇰🇷 [한국어](i18n/ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](i18n/nl/API_REFERENCE.md) | 🇳🇴 [Norsk](i18n/no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/API_REFERENCE.md) | 🇷🇴 [Română](i18n/ro/API_REFERENCE.md) | 🇵🇱 [Polski](i18n/pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](i18n/sk/API_REFERENCE.md) | 🇸🇪 [Svenska](i18n/sv/API_REFERENCE.md) | 🇵🇭 [Filipino](i18n/phi/API_REFERENCE.md)
Complete reference for all OmniRoute API endpoints.
---
## Table of Contents
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [List Models](#list-models)
- [Compatibility Endpoints](#compatibility-endpoints)
- [Semantic Cache](#semantic-cache)
- [Dashboard & Management](#dashboard--management)
- [Request Processing](#request-processing)
- [Authentication](#authentication)
---
## Chat Completions
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### Custom Headers
| Header | Direction | Description |
| ------------------------ | --------- | --------------------------------- |
| `X-OmniRoute-No-Cache` | Request | Set to `true` to bypass cache |
| `X-OmniRoute-Progress` | Request | Set to `true` for progress events |
| `Idempotency-Key` | Request | Dedup key (5s window) |
| `X-Request-Id` | Request | Alternative dedup key |
| `X-OmniRoute-Cache` | Response | `HIT` or `MISS` (non-streaming) |
| `X-OmniRoute-Idempotent` | Response | `true` if deduplicated |
| `X-OmniRoute-Progress` | Response | `enabled` if progress tracking on |
---
## Embeddings
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
Available providers: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## Image Generation
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
Available providers: OpenAI (DALL-E), xAI (Grok Image), Together AI (FLUX), Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## List Models
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## Compatibility Endpoints
| Method | Path | Format |
| ------ | --------------------------- | ---------------------- |
| POST | `/v1/chat/completions` | OpenAI |
| POST | `/v1/messages` | Anthropic |
| POST | `/v1/responses` | OpenAI Responses |
| POST | `/v1/embeddings` | OpenAI |
| POST | `/v1/images/generations` | OpenAI |
| GET | `/v1/models` | OpenAI |
| POST | `/v1/messages/count_tokens` | Anthropic |
| GET | `/v1beta/models` | Gemini |
| POST | `/v1beta/models/{...path}` | Gemini generateContent |
| POST | `/v1/api/chat` | Ollama |
### Dedicated Provider Routes
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
---
## Semantic Cache
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
Response example:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## Dashboard & Management
### Authentication
| Endpoint | Method | Description |
| ----------------------------- | ------- | --------------------- |
| `/api/auth/login` | POST | Login |
| `/api/auth/logout` | POST | Logout |
| `/api/settings/require-login` | GET/PUT | Toggle login required |
### Provider Management
| Endpoint | Method | Description |
| ---------------------------- | --------------- | ------------------------ |
| `/api/providers` | GET/POST | List / create providers |
| `/api/providers/[id]` | GET/PUT/DELETE | Manage a provider |
| `/api/providers/[id]/test` | POST | Test provider connection |
| `/api/providers/[id]/models` | GET | List provider models |
| `/api/providers/validate` | POST | Validate provider config |
| `/api/provider-nodes*` | Various | Provider node management |
| `/api/provider-models` | GET/POST/DELETE | Custom models |
### OAuth Flows
| Endpoint | Method | Description |
| -------------------------------- | ------- | ----------------------- |
| `/api/oauth/[provider]/[action]` | Various | Provider-specific OAuth |
### Routing & Config
| Endpoint | Method | Description |
| --------------------- | -------- | ----------------------------- |
| `/api/models/alias` | GET/POST | Model aliases |
| `/api/models/catalog` | GET | All models by provider + type |
| `/api/combos*` | Various | Combo management |
| `/api/keys*` | Various | API key management |
| `/api/pricing` | GET | Model pricing |
### Usage & Analytics
| Endpoint | Method | Description |
| --------------------------- | ------ | -------------------- |
| `/api/usage/history` | GET | Usage history |
| `/api/usage/logs` | GET | Usage logs |
| `/api/usage/request-logs` | GET | Request-level logs |
| `/api/usage/[connectionId]` | GET | Per-connection usage |
### Settings
| Endpoint | Method | Description |
| ------------------------------- | ------- | ---------------------- |
| `/api/settings` | GET/PUT | General settings |
| `/api/settings/proxy` | GET/PUT | Network proxy config |
| `/api/settings/proxy/test` | POST | Test proxy connection |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt |
### Monitoring
| Endpoint | Method | Description |
| ------------------------ | ---------- | ----------------------- |
| `/api/sessions` | GET | Active session tracking |
| `/api/rate-limits` | GET | Per-account rate limits |
| `/api/monitoring/health` | GET | Health check |
| `/api/cache` | GET/DELETE | Cache stats / clear |
### Backup & Export/Import
| Endpoint | Method | Description |
| --------------------------- | ------ | --------------------------------------- |
| `/api/db-backups` | GET | List available backups |
| `/api/db-backups` | PUT | Create a manual backup |
| `/api/db-backups` | POST | Restore from a specific backup |
| `/api/db-backups/export` | GET | Download database as .sqlite file |
| `/api/db-backups/import` | POST | Upload .sqlite file to replace database |
| `/api/db-backups/exportAll` | GET | Download full backup as .tar.gz archive |
### Cloud Sync
| Endpoint | Method | Description |
| ---------------------- | ------- | --------------------- |
| `/api/sync/cloud` | Various | Cloud sync operations |
| `/api/sync/initialize` | POST | Initialize sync |
| `/api/cloud/*` | Various | Cloud management |
### CLI Tools
| Endpoint | Method | Description |
| ---------------------------------- | ------ | ------------------- |
| `/api/cli-tools/claude-settings` | GET | Claude CLI status |
| `/api/cli-tools/codex-settings` | GET | Codex CLI status |
| `/api/cli-tools/droid-settings` | GET | Droid CLI status |
| `/api/cli-tools/openclaw-settings` | GET | OpenClaw CLI status |
| `/api/cli-tools/runtime/[toolId]` | GET | Generic CLI runtime |
CLI responses include: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`.
### ACP Agents
| Endpoint | Method | Description |
| ----------------- | ------ | -------------------------------------------------------- |
| `/api/acp/agents` | GET | List all detected agents (built-in + custom) with status |
| `/api/acp/agents` | POST | Add custom agent or refresh detection cache |
| `/api/acp/agents` | DELETE | Remove a custom agent by `id` query param |
GET response includes `agents[]` (id, name, binary, version, installed, protocol, isCustom) and `summary` (total, installed, notFound, builtIn, custom).
### Resilience & Rate Limits
| Endpoint | Method | Description |
| ----------------------- | ------- | ------------------------------- |
| `/api/resilience` | GET/PUT | Get/update resilience profiles |
| `/api/resilience/reset` | POST | Reset circuit breakers |
| `/api/rate-limits` | GET | Per-account rate limit status |
| `/api/rate-limit` | GET | Global rate limit configuration |
### Evals
| Endpoint | Method | Description |
| ------------ | -------- | --------------------------------- |
| `/api/evals` | GET/POST | List eval suites / run evaluation |
### Policies
| Endpoint | Method | Description |
| --------------- | --------------- | ----------------------- |
| `/api/policies` | GET/POST/DELETE | Manage routing policies |
### Compliance
| Endpoint | Method | Description |
| --------------------------- | ------ | ----------------------------- |
| `/api/compliance/audit-log` | GET | Compliance audit log (last N) |
### v1beta (Gemini-Compatible)
| Endpoint | Method | Description |
| -------------------------- | ------ | --------------------------------- |
| `/v1beta/models` | GET | List models in Gemini format |
| `/v1beta/models/{...path}` | POST | Gemini `generateContent` endpoint |
These endpoints mirror Gemini's API format for clients that expect native Gemini SDK compatibility.
### Internal / System APIs
| Endpoint | Method | Description |
| --------------- | ------ | ---------------------------------------------------- |
| `/api/init` | GET | Application initialization check (used on first run) |
| `/api/tags` | GET | Ollama-compatible model tags (for Ollama clients) |
| `/api/restart` | POST | Trigger graceful server restart |
| `/api/shutdown` | POST | Trigger graceful server shutdown |
> **Note:** These endpoints are used internally by the system or for Ollama client compatibility. They are not typically called by end users.
---
## Audio Transcription
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
Transcribe audio files using Deepgram or AssemblyAI.
**Request:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**Response:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**Supported providers:** `deepgram/nova-3`, `assemblyai/best`.
**Supported formats:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
## Ollama Compatibility
For clients that use Ollama's API format:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
Requests are automatically translated between Ollama and internal formats.
---
## Telemetry
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**Response:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## Budget
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## Model Availability
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## Request Processing
1. Client sends request to `/v1/*`
2. Route handler calls `handleChat`, `handleEmbedding`, `handleAudioTranscription`, or `handleImageGeneration`
3. Model is resolved (direct provider/model or alias/combo)
4. Credentials selected from local DB with account availability filtering
5. For chat: `handleChatCore` — format detection, translation, cache check, idempotency check
6. Provider executor sends upstream request
7. Response translated back to client format (chat) or returned as-is (embeddings/images/audio)
8. Usage/logging recorded
9. Fallback applies on errors according to combo rules
Full architecture reference: [`ARCHITECTURE.md`](ARCHITECTURE.md)
---
## Authentication
- Dashboard routes (`/dashboard/*`) use `auth_token` cookie
- Login uses saved password hash; fallback to `INITIAL_PASSWORD`
- `requireLogin` toggleable via `/api/settings/require-login`
- `/v1/*` routes optionally require Bearer API key when `REQUIRE_API_KEY=true`

View File

@@ -0,0 +1,787 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/ARCHITECTURE.md) · 🇪🇸 [es](../es/ARCHITECTURE.md) · 🇫🇷 [fr](../fr/ARCHITECTURE.md) · 🇩🇪 [de](../de/ARCHITECTURE.md) · 🇮🇹 [it](../it/ARCHITECTURE.md) · 🇷🇺 [ru](../ru/ARCHITECTURE.md) · 🇨🇳 [zh-CN](../zh-CN/ARCHITECTURE.md) · 🇯🇵 [ja](../ja/ARCHITECTURE.md) · 🇰🇷 [ko](../ko/ARCHITECTURE.md) · 🇸🇦 [ar](../ar/ARCHITECTURE.md) · 🇮🇳 [in](../in/ARCHITECTURE.md) · 🇹🇭 [th](../th/ARCHITECTURE.md) · 🇻🇳 [vi](../vi/ARCHITECTURE.md) · 🇮🇩 [id](../id/ARCHITECTURE.md) · 🇲🇾 [ms](../ms/ARCHITECTURE.md) · 🇳🇱 [nl](../nl/ARCHITECTURE.md) · 🇵🇱 [pl](../pl/ARCHITECTURE.md) · 🇸🇪 [sv](../sv/ARCHITECTURE.md) · 🇳🇴 [no](../no/ARCHITECTURE.md) · 🇩🇰 [da](../da/ARCHITECTURE.md) · 🇫🇮 [fi](../fi/ARCHITECTURE.md) · 🇵🇹 [pt](../pt/ARCHITECTURE.md) · 🇷🇴 [ro](../ro/ARCHITECTURE.md) · 🇭🇺 [hu](../hu/ARCHITECTURE.md) · 🇧🇬 [bg](../bg/ARCHITECTURE.md) · 🇸🇰 [sk](../sk/ARCHITECTURE.md) · 🇺🇦 [uk-UA](../uk-UA/ARCHITECTURE.md) · 🇮🇱 [he](../he/ARCHITECTURE.md) · 🇵🇭 [phi](../phi/ARCHITECTURE.md)
---
# OmniRoute Architecture
🌐 **Languages:** 🇺🇸 [English](ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](i18n/es/ARCHITECTURE.md) | 🇫🇷 [Français](i18n/fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](i18n/it/ARCHITECTURE.md) | 🇷🇺 [Русский](i18n/ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](i18n/de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](i18n/in/ARCHITECTURE.md) | 🇹🇭 [ไทย](i18n/th/ARCHITECTURE.md) | 🇺🇦 [Українська](i18n/uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](i18n/ar/ARCHITECTURE.md) | 🇯🇵 [日本語](i18n/ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/ARCHITECTURE.md) | 🇧🇬 [Български](i18n/bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](i18n/da/ARCHITECTURE.md) | 🇫🇮 [Suomi](i18n/fi/ARCHITECTURE.md) | 🇮🇱 [עברית](i18n/he/ARCHITECTURE.md) | 🇭🇺 [Magyar](i18n/hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/ARCHITECTURE.md) | 🇰🇷 [한국어](i18n/ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](i18n/nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](i18n/no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/ARCHITECTURE.md) | 🇷🇴 [Română](i18n/ro/ARCHITECTURE.md) | 🇵🇱 [Polski](i18n/pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](i18n/sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](i18n/sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](i18n/phi/ARCHITECTURE.md)
_Last updated: 2026-03-04_
## Executive Summary
OmniRoute is a local AI routing gateway and dashboard built on Next.js.
It provides a single OpenAI-compatible endpoint (`/v1/*`) and routes traffic across multiple upstream providers with translation, fallback, token refresh, and usage tracking.
Core capabilities:
- OpenAI-compatible API surface for CLI/tools (28 providers)
- Request/response translation across provider formats
- Model combo fallback (multi-model sequence)
- Account-level fallback (multi-account per provider)
- OAuth + API-key provider connection management
- Embedding generation via `/v1/embeddings` (6 providers, 9 models)
- Image generation via `/v1/images/generations` (4 providers, 9 models)
- Think tag parsing (`<think>...</think>`) for reasoning models
- Response sanitization for strict OpenAI SDK compatibility
- Role normalization (developer→system, system→user) for cross-provider compatibility
- Structured output conversion (json_schema → Gemini responseSchema)
- Local persistence for providers, keys, aliases, combos, settings, pricing
- Usage/cost tracking and request logging
- Optional cloud sync for multi-device/state sync
- IP allowlist/blocklist for API access control
- Thinking budget management (passthrough/auto/custom/adaptive)
- Global system prompt injection
- Session tracking and fingerprinting
- Per-account enhanced rate limiting with provider-specific profiles
- Circuit breaker pattern for provider resilience
- Anti-thundering herd protection with mutex locking
- Signature-based request deduplication cache
- Domain layer: model availability, cost rules, fallback policy, lockout policy
- Domain state persistence (SQLite write-through cache for fallbacks, budgets, lockouts, circuit breakers)
- Policy engine for centralized request evaluation (lockout → budget → fallback)
- Request telemetry with p50/p95/p99 latency aggregation
- Correlation ID (X-Request-Id) for end-to-end tracing
- Compliance audit logging with opt-out per API key
- Eval framework for LLM quality assurance
- Resilience UI dashboard with real-time circuit breaker status
- Modular OAuth providers (12 individual modules under `src/lib/oauth/providers/`)
Primary runtime model:
- Next.js app routes under `src/app/api/*` implement both dashboard APIs and compatibility APIs
- A shared SSE/routing core in `src/sse/*` + `open-sse/*` handles provider execution, translation, streaming, fallback, and usage
## Scope and Boundaries
### In Scope
- Local gateway runtime
- Dashboard management APIs
- Provider authentication and token refresh
- Request translation and SSE streaming
- Local state + usage persistence
- Optional cloud sync orchestration
### Out of Scope
- Cloud service implementation behind `NEXT_PUBLIC_CLOUD_URL`
- Provider SLA/control plane outside local process
- External CLI binaries themselves (Claude CLI, Codex CLI, etc.)
## High-Level System Context
```mermaid
flowchart LR
subgraph Clients[Developer Clients]
C1[Claude Code]
C2[Codex CLI]
C3[OpenClaw / Droid / Cline / Continue / Roo]
C4[Custom OpenAI-compatible clients]
BROWSER[Browser Dashboard]
end
subgraph Router[OmniRoute Local Process]
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(storage.sqlite)]
UDB[(usage tables + log artifacts)]
end
subgraph Upstreams[Upstream Providers]
P1[OAuth Providers\nClaude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity]
P2[API Key Providers\nOpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax\nDeepSeek/Groq/xAI/Mistral/Perplexity\nTogether/Fireworks/Cerebras/Cohere/NVIDIA]
P3[Compatible Nodes\nOpenAI-compatible / Anthropic-compatible]
end
subgraph Cloud[Optional Cloud Sync]
CLOUD[Cloud Sync Endpoint\nNEXT_PUBLIC_CLOUD_URL]
end
C1 --> API
C2 --> API
C3 --> API
C4 --> API
BROWSER --> DASH
API --> CORE
DASH --> DB
CORE --> DB
CORE --> UDB
CORE --> P1
CORE --> P2
CORE --> P3
DASH --> CLOUD
```
## Core Runtime Components
## 1) API and Routing Layer (Next.js App Routes)
Main directories:
- `src/app/api/v1/*` and `src/app/api/v1beta/*` for compatibility APIs
- `src/app/api/*` for management/configuration APIs
- Next rewrites in `next.config.mjs` map `/v1/*` to `/api/v1/*`
Important compatibility routes:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — includes custom models with `custom: true`
- `src/app/api/v1/embeddings/route.ts` — embedding generation (6 providers)
- `src/app/api/v1/images/generations/route.ts` — image generation (4+ providers incl. Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — dedicated per-provider chat
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — dedicated per-provider embeddings
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — dedicated per-provider images
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
Management domains:
- Auth/settings: `src/app/api/auth/*`, `src/app/api/settings/*`
- Providers/connections: `src/app/api/providers*`
- Provider nodes: `src/app/api/provider-nodes*`
- Custom models: `src/app/api/provider-models` (GET/POST/DELETE)
- Model catalog: `src/app/api/models/route.ts` (GET)
- Proxy config: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- Keys/aliases/combos/pricing: `src/app/api/keys*`, `src/app/api/models/alias`, `src/app/api/combos*`, `src/app/api/pricing`
- Usage: `src/app/api/usage/*`
- Sync/cloud: `src/app/api/sync/*`, `src/app/api/cloud/*`
- CLI tooling helpers: `src/app/api/cli-tools/*`
- IP filter: `src/app/api/settings/ip-filter` (GET/PUT)
- Thinking budget: `src/app/api/settings/thinking-budget` (GET/PUT)
- System prompt: `src/app/api/settings/system-prompt` (GET/PUT)
- Sessions: `src/app/api/sessions` (GET)
- Rate limits: `src/app/api/rate-limits` (GET)
- Resilience: `src/app/api/resilience` (GET/PATCH) — provider profiles, circuit breaker, rate limit state
- Resilience reset: `src/app/api/resilience/reset` (POST) — reset breakers + cooldowns
- Cache stats: `src/app/api/cache/stats` (GET/DELETE)
- Model availability: `src/app/api/models/availability` (GET/POST)
- Telemetry: `src/app/api/telemetry/summary` (GET)
- Budget: `src/app/api/usage/budget` (GET/POST)
- Fallback chains: `src/app/api/fallback/chains` (GET/POST/DELETE)
- Compliance audit: `src/app/api/compliance/audit-log` (GET)
- Evals: `src/app/api/evals` (GET/POST), `src/app/api/evals/[suiteId]` (GET)
- Policies: `src/app/api/policies` (GET/POST)
## 2) SSE + Translation Core
Main flow modules:
- Entry: `src/sse/handlers/chat.ts`
- Core orchestration: `open-sse/handlers/chatCore.ts`
- Provider execution adapters: `open-sse/executors/*`
- Format detection/provider config: `open-sse/services/provider.ts`
- Model parse/resolve: `src/sse/services/model.ts`, `open-sse/services/model.ts`
- Account fallback logic: `open-sse/services/accountFallback.ts`
- Translation registry: `open-sse/translator/index.ts`
- Stream transformations: `open-sse/utils/stream.ts`, `open-sse/utils/streamHandler.ts`
- Usage extraction/normalization: `open-sse/utils/usageTracking.ts`
- Think tag parser: `open-sse/utils/thinkTagParser.ts`
- Embedding handler: `open-sse/handlers/embeddings.ts`
- Embedding provider registry: `open-sse/config/embeddingRegistry.ts`
- Image generation handler: `open-sse/handlers/imageGeneration.ts`
- Image provider registry: `open-sse/config/imageRegistry.ts`
- Response sanitization: `open-sse/handlers/responseSanitizer.ts`
- Role normalization: `open-sse/services/roleNormalizer.ts`
Services (business logic):
- Account selection/scoring: `open-sse/services/accountSelector.ts`
- Context lifecycle management: `open-sse/services/contextManager.ts`
- IP filter enforcement: `open-sse/services/ipFilter.ts`
- Session tracking: `open-sse/services/sessionManager.ts`
- Request deduplication: `open-sse/services/signatureCache.ts`
- System prompt injection: `open-sse/services/systemPrompt.ts`
- Thinking budget management: `open-sse/services/thinkingBudget.ts`
- Wildcard model routing: `open-sse/services/wildcardRouter.ts`
- Rate limit management: `open-sse/services/rateLimitManager.ts`
- Circuit breaker: `open-sse/services/circuitBreaker.ts`
Domain layer modules:
- Model availability: `src/lib/domain/modelAvailability.ts`
- Cost rules/budgets: `src/lib/domain/costRules.ts`
- Fallback policy: `src/lib/domain/fallbackPolicy.ts`
- Combo resolver: `src/lib/domain/comboResolver.ts`
- Lockout policy: `src/lib/domain/lockoutPolicy.ts`
- Policy engine: `src/domain/policyEngine.ts` — centralized lockout → budget → fallback evaluation
- Error codes catalog: `src/lib/domain/errorCodes.ts`
- Request ID: `src/lib/domain/requestId.ts`
- Fetch timeout: `src/lib/domain/fetchTimeout.ts`
- Request telemetry: `src/lib/domain/requestTelemetry.ts`
- Compliance/audit: `src/lib/domain/compliance/index.ts`
- Eval runner: `src/lib/domain/evalRunner.ts`
- Domain state persistence: `src/lib/db/domainState.ts` — SQLite CRUD for fallback chains, budgets, cost history, lockout state, circuit breakers
OAuth provider modules (12 individual files under `src/lib/oauth/providers/`):
- Registry index: `src/lib/oauth/providers/index.ts`
- Individual providers: `claude.ts`, `codex.ts`, `gemini.ts`, `antigravity.ts`, `iflow.ts`, `qwen.ts`, `kimi-coding.ts`, `github.ts`, `kiro.ts`, `cursor.ts`, `kilocode.ts`, `cline.ts`
- Thin wrapper: `src/lib/oauth/providers.ts` — re-exports from individual modules
## 3) Persistence Layer
Primary state DB (SQLite):
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
Usage persistence:
- facade: `src/lib/usageDb.ts` (decomposed modules in `src/lib/usage/*`)
- SQLite tables in `storage.sqlite`: `usage_history`, `call_logs`, `proxy_logs`
- optional file artifacts remain for compatibility/debug (`${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`, `<repo>/logs/...`)
- legacy JSON files are migrated to SQLite by startup migrations when present
Domain State DB (SQLite):
- `src/lib/db/domainState.ts` — CRUD operations for domain state
- Tables (created in `src/lib/db/core.ts`): `domain_fallback_chains`, `domain_budgets`, `domain_cost_history`, `domain_lockout_state`, `domain_circuit_breakers`
- Write-through cache pattern: in-memory Maps are authoritative at runtime; mutations are written synchronously to SQLite; state is restored from DB on cold start
## 4) Auth + Security Surfaces
- Dashboard cookie auth: `src/proxy.ts`, `src/app/api/auth/login/route.ts`
- API key generation/verification: `src/shared/utils/apiKey.ts`
- Provider secrets persisted in `providerConnections` entries
- Outbound proxy support via `open-sse/utils/proxyFetch.ts` (env vars) and `open-sse/utils/networkProxy.ts` (configurable per-provider or global)
## 5) Cloud Sync
- Scheduler init: `src/lib/initCloudSync.ts`, `src/shared/services/initializeCloudSync.ts`
- Periodic task: `src/shared/services/cloudSyncScheduler.ts`
- Control route: `src/app/api/sync/cloud/route.ts`
## Request Lifecycle (`/v1/chat/completions`)
```mermaid
sequenceDiagram
autonumber
participant Client as CLI/SDK Client
participant Route as /api/v1/chat/completions
participant Chat as src/sse/handlers/chat
participant Core as open-sse/handlers/chatCore
participant Model as Model Resolver
participant Auth as Credential Selector
participant Exec as Provider Executor
participant Prov as Upstream Provider
participant Stream as Stream Translator
participant Usage as usageDb
Client->>Route: POST /v1/chat/completions
Route->>Chat: handleChat(request)
Chat->>Model: parse/resolve model or combo
alt Combo model
Chat->>Chat: iterate combo models (handleComboChat)
end
Chat->>Auth: getProviderCredentials(provider)
Auth-->>Chat: active account + tokens/api key
Chat->>Core: handleChatCore(body, modelInfo, credentials)
Core->>Core: detect source format
Core->>Core: translate request to target format
Core->>Exec: execute(provider, transformedBody)
Exec->>Prov: upstream API call
Prov-->>Exec: SSE/JSON response
Exec-->>Core: response + metadata
alt 401/403
Core->>Exec: refreshCredentials()
Exec-->>Core: updated tokens
Core->>Exec: retry request
end
Core->>Stream: translate/normalize stream to client format
Stream-->>Client: SSE chunks / JSON response
Stream->>Usage: extract usage + persist history/log
```
## Combo + Account Fallback Flow
```mermaid
flowchart TD
A[Incoming model string] --> B{Is combo name?}
B -- Yes --> C[Load combo models sequence]
B -- No --> D[Single model path]
C --> E[Try model N]
E --> F[Resolve provider/model]
D --> F
F --> G[Select account credentials]
G --> H{Credentials available?}
H -- No --> I[Return provider unavailable]
H -- Yes --> J[Execute request]
J --> K{Success?}
K -- Yes --> L[Return response]
K -- No --> M{Fallback-eligible error?}
M -- No --> N[Return error]
M -- Yes --> O[Mark account unavailable cooldown]
O --> P{Another account for provider?}
P -- Yes --> G
P -- No --> Q{In combo with next model?}
Q -- Yes --> E
Q -- No --> R[Return all unavailable]
```
Fallback decisions are driven by `open-sse/services/accountFallback.ts` using status codes and error-message heuristics.
## OAuth Onboarding and Token Refresh Lifecycle
```mermaid
sequenceDiagram
autonumber
participant UI as Dashboard UI
participant OAuth as /api/oauth/[provider]/[action]
participant ProvAuth as Provider Auth Server
participant DB as localDb
participant Test as /api/providers/[id]/test
participant Exec as Provider Executor
UI->>OAuth: GET authorize or device-code
OAuth->>ProvAuth: create auth/device flow
ProvAuth-->>OAuth: auth URL or device code payload
OAuth-->>UI: flow data
UI->>OAuth: POST exchange or poll
OAuth->>ProvAuth: token exchange/poll
ProvAuth-->>OAuth: access/refresh tokens
OAuth->>DB: createProviderConnection(oauth data)
OAuth-->>UI: success + connection id
UI->>Test: POST /api/providers/[id]/test
Test->>Exec: validate credentials / optional refresh
Exec-->>Test: valid or refreshed token info
Test->>DB: update status/tokens/errors
Test-->>UI: validation result
```
Refresh during live traffic is executed inside `open-sse/handlers/chatCore.ts` via executor `refreshCredentials()`.
## Cloud Sync Lifecycle (Enable / Sync / Disable)
```mermaid
sequenceDiagram
autonumber
participant UI as Endpoint Page UI
participant Sync as /api/sync/cloud
participant DB as localDb
participant Cloud as External Cloud Sync
participant Claude as ~/.claude/settings.json
UI->>Sync: POST action=enable
Sync->>DB: set cloudEnabled=true
Sync->>DB: ensure API key exists
Sync->>Cloud: POST /sync/{machineId} (providers/aliases/combos/keys)
Cloud-->>Sync: sync result
Sync->>Cloud: GET /{machineId}/v1/verify
Sync-->>UI: enabled + verification status
UI->>Sync: POST action=sync
Sync->>Cloud: POST /sync/{machineId}
Cloud-->>Sync: remote data
Sync->>DB: update newer local tokens/status
Sync-->>UI: synced
UI->>Sync: POST action=disable
Sync->>DB: set cloudEnabled=false
Sync->>Cloud: DELETE /sync/{machineId}
Sync->>Claude: switch ANTHROPIC_BASE_URL back to local (if needed)
Sync-->>UI: disabled
```
Periodic sync is triggered by `CloudSyncScheduler` when cloud is enabled.
## Data Model and Storage Map
```mermaid
erDiagram
SETTINGS ||--o{ PROVIDER_CONNECTION : controls
PROVIDER_NODE ||--o{ PROVIDER_CONNECTION : backs_compatible_provider
PROVIDER_CONNECTION ||--o{ USAGE_ENTRY : emits_usage
SETTINGS {
boolean cloudEnabled
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
string id
string provider
string authType
string name
number priority
boolean isActive
string apiKey
string accessToken
string refreshToken
string expiresAt
string testStatus
string lastError
string rateLimitedUntil
json providerSpecificData
}
PROVIDER_NODE {
string id
string type
string name
string prefix
string apiType
string baseUrl
}
MODEL_ALIAS {
string alias
string targetModel
}
COMBO {
string id
string name
string[] models
}
API_KEY {
string id
string name
string key
string machineId
}
USAGE_ENTRY {
string provider
string model
number prompt_tokens
number completion_tokens
string connectionId
string timestamp
}
CUSTOM_MODEL {
string id
string name
string providerId
}
PROXY_CONFIG {
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
Physical storage files:
- primary runtime DB: `${DATA_DIR}/storage.sqlite`
- request log lines: `${DATA_DIR}/log.txt` (compat/debug artifact)
- structured call payload archives: `${DATA_DIR}/call_logs/`
- optional translator/request debug sessions: `<repo>/logs/...`
## Deployment Topology
```mermaid
flowchart LR
subgraph LocalHost[Developer Host]
CLI[CLI Tools]
Browser[Dashboard Browser]
end
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(storage.sqlite)]
UsageDB[(usage tables + log artifacts)]
end
subgraph External[External Services]
Providers[AI Providers]
SyncCloud[Cloud Sync Service]
end
CLI --> Next
Browser --> Next
Next --> Core
Next --> MainDB
Core --> MainDB
Core --> UsageDB
Core --> Providers
Next --> SyncCloud
```
## Module Mapping (Decision-Critical)
### Route and API Modules
- `src/app/api/v1/*`, `src/app/api/v1beta/*`: compatibility APIs
- `src/app/api/v1/providers/[provider]/*`: dedicated per-provider routes (chat, embeddings, images)
- `src/app/api/providers*`: provider CRUD, validation, testing
- `src/app/api/provider-nodes*`: custom compatible node management
- `src/app/api/provider-models`: custom model management (CRUD)
- `src/app/api/models/route.ts`: model catalog API (aliases + custom models)
- `src/app/api/oauth/*`: OAuth/device-code flows
- `src/app/api/keys*`: local API key lifecycle
- `src/app/api/models/alias`: alias management
- `src/app/api/combos*`: fallback combo management
- `src/app/api/pricing`: pricing overrides for cost calculation
- `src/app/api/settings/proxy`: proxy configuration (GET/PUT/DELETE)
- `src/app/api/settings/proxy/test`: outbound proxy connectivity test (POST)
- `src/app/api/usage/*`: usage and logs APIs
- `src/app/api/sync/*` + `src/app/api/cloud/*`: cloud sync and cloud-facing helpers
- `src/app/api/cli-tools/*`: local CLI config writers/checkers
- `src/app/api/settings/ip-filter`: IP allowlist/blocklist (GET/PUT)
- `src/app/api/settings/thinking-budget`: thinking token budget config (GET/PUT)
- `src/app/api/settings/system-prompt`: global system prompt (GET/PUT)
- `src/app/api/sessions`: active session listing (GET)
- `src/app/api/rate-limits`: per-account rate limit status (GET)
### Routing and Execution Core
- `src/sse/handlers/chat.ts`: request parse, combo handling, account selection loop
- `open-sse/handlers/chatCore.ts`: translation, executor dispatch, retry/refresh handling, stream setup
- `open-sse/executors/*`: provider-specific network and format behavior
### Translation Registry and Format Converters
- `open-sse/translator/index.ts`: translator registry and orchestration
- Request translators: `open-sse/translator/request/*`
- Response translators: `open-sse/translator/response/*`
- Format constants: `open-sse/translator/formats.ts`
### Persistence
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
- `src/lib/localDb.ts`: compatibility re-export for DB modules
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
## Provider Executor Coverage (Strategy Pattern)
Each provider has a specialized executor extending `BaseExecutor` (in `open-sse/executors/base.ts`), which provides URL building, header construction, retry with exponential backoff, credential refresh hooks, and the `execute()` orchestration method.
| Executor | Provider(s) | Special Handling |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `DefaultExecutor` | OpenAI, Claude, Gemini, Qwen, iFlow, OpenRouter, GLM, Kimi, MiniMax, DeepSeek, Groq, xAI, Mistral, Perplexity, Together, Fireworks, Cerebras, Cohere, NVIDIA | Dynamic URL/header config per provider |
| `AntigravityExecutor` | Google Antigravity | Custom project/session IDs, Retry-After parsing |
| `CodexExecutor` | OpenAI Codex | Injects system instructions, forces reasoning effort |
| `CursorExecutor` | Cursor IDE | ConnectRPC protocol, Protobuf encoding, request signing via checksum |
| `GithubExecutor` | GitHub Copilot | Copilot token refresh, VSCode-mimicking headers |
| `KiroExecutor` | AWS CodeWhisperer/Kiro | AWS EventStream binary format → SSE conversion |
| `GeminiCLIExecutor` | Gemini CLI | Google OAuth token refresh cycle |
All other providers (including custom compatible nodes) use the `DefaultExecutor`.
## Provider Compatibility Matrix
| Provider | Format | Auth | Stream | Non-Stream | Token Refresh | Usage API |
| ---------------- | ---------------- | --------------------- | ---------------- | ---------- | ------------- | ------------------ |
| Claude | claude | API Key / OAuth | ✅ | ✅ | ✅ | ⚠️ Admin only |
| Gemini | gemini | API Key / OAuth | ✅ | ✅ | ✅ | ⚠️ Cloud Console |
| Gemini CLI | gemini-cli | OAuth | ✅ | ✅ | ✅ | ⚠️ Cloud Console |
| Antigravity | antigravity | OAuth | ✅ | ✅ | ✅ | ✅ Full quota API |
| OpenAI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Codex | openai-responses | OAuth | ✅ forced | ❌ | ✅ | ✅ Rate limits |
| GitHub Copilot | openai | OAuth + Copilot Token | ✅ | ✅ | ✅ | ✅ Quota snapshots |
| Cursor | cursor | Custom checksum | ✅ | ✅ | ❌ | ❌ |
| Kiro | kiro | AWS SSO OIDC | ✅ (EventStream) | ❌ | ✅ | ✅ Usage limits |
| Qwen | openai | OAuth | ✅ | ✅ | ✅ | ⚠️ Per request |
| iFlow | openai | OAuth (Basic) | ✅ | ✅ | ✅ | ⚠️ Per request |
| OpenRouter | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| GLM/Kimi/MiniMax | claude | API Key | ✅ | ✅ | ❌ | ❌ |
| DeepSeek | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Groq | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| xAI (Grok) | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Mistral | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Perplexity | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Together AI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Fireworks AI | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Cerebras | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| Cohere | openai | API Key | ✅ | ✅ | ❌ | ❌ |
| NVIDIA NIM | openai | API Key | ✅ | ✅ | ❌ | ❌ |
## Format Translation Coverage
Detected source formats include:
- `openai`
- `openai-responses`
- `claude`
- `gemini`
Target formats include:
- OpenAI chat/Responses
- Claude
- Gemini/Gemini-CLI/Antigravity envelope
- Kiro
- Cursor
Translations use **OpenAI as the hub format** — all conversions go through OpenAI as intermediate:
```
Source Format → OpenAI (hub) → Target Format
```
Translations are selected dynamically based on source payload shape and provider target format.
Additional processing layers in the translation pipeline:
- **Response sanitization** — Strips non-standard fields from OpenAI-format responses (both streaming and non-streaming) to ensure strict SDK compliance
- **Role normalization** — Converts `developer``system` for non-OpenAI targets; merges `system``user` for models that reject the system role (GLM, ERNIE)
- **Think tag extraction** — Parses `<think>...</think>` blocks from content into `reasoning_content` field
- **Structured output** — Converts OpenAI `response_format.json_schema` to Gemini's `responseMimeType` + `responseSchema`
## Supported API Endpoints
| Endpoint | Format | Handler |
| -------------------------------------------------- | ------------------ | ---------------------------------------------------- |
| `POST /v1/chat/completions` | OpenAI Chat | `src/sse/handlers/chat.ts` |
| `POST /v1/messages` | Claude Messages | Same handler (auto-detected) |
| `POST /v1/responses` | OpenAI Responses | `open-sse/handlers/responsesHandler.ts` |
| `POST /v1/embeddings` | OpenAI Embeddings | `open-sse/handlers/embeddings.ts` |
| `GET /v1/embeddings` | Model listing | API route |
| `POST /v1/images/generations` | OpenAI Images | `open-sse/handlers/imageGeneration.ts` |
| `GET /v1/images/generations` | Model listing | API route |
| `POST /v1/providers/{provider}/chat/completions` | OpenAI Chat | Dedicated per-provider with model validation |
| `POST /v1/providers/{provider}/embeddings` | OpenAI Embeddings | Dedicated per-provider with model validation |
| `POST /v1/providers/{provider}/images/generations` | OpenAI Images | Dedicated per-provider with model validation |
| `POST /v1/messages/count_tokens` | Claude Token Count | API route |
| `GET /v1/models` | OpenAI Models list | API route (chat + embedding + image + custom models) |
| `GET /api/models/catalog` | Catalog | All models grouped by provider + type |
| `POST /v1beta/models/*:streamGenerateContent` | Gemini native | API route |
| `GET/PUT/DELETE /api/settings/proxy` | Proxy Config | Network proxy configuration |
| `POST /api/settings/proxy/test` | Proxy Connectivity | Proxy health/connectivity test endpoint |
| `GET/POST/DELETE /api/provider-models` | Custom Models | Custom model management per provider |
## Bypass Handler
The bypass handler (`open-sse/utils/bypassHandler.ts`) intercepts known "throwaway" requests from Claude CLI — warmup pings, title extractions, and token counts — and returns a **fake response** without consuming upstream provider tokens. This is triggered only when `User-Agent` contains `claude-cli`.
## Request Logger Pipeline
The request logger (`open-sse/utils/requestLogger.ts`) provides a 7-stage debug logging pipeline, disabled by default, enabled via `ENABLE_REQUEST_LOGS=true`:
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
→ 5_res_provider.txt → 6_res_openai.txt → 7_res_client.txt
```
Files are written to `<repo>/logs/<session>/` for each request session.
## Failure Modes and Resilience
## 1) Account/Provider Availability
- provider account cooldown on transient/rate/auth errors
- account fallback before failing request
- combo model fallback when current model/provider path is exhausted
## 2) Token Expiry
- pre-check and refresh with retry for refreshable providers
- 401/403 retry after refresh attempt in core path
## 3) Stream Safety
- disconnect-aware stream controller
- translation stream with end-of-stream flush and `[DONE]` handling
- usage estimation fallback when provider usage metadata is missing
## 4) Cloud Sync Degradation
- sync errors are surfaced but local runtime continues
- scheduler has retry-capable logic, but periodic execution currently calls single-attempt sync by default
## 5) Data Integrity
- SQLite schema migrations and auto-upgrade hooks at startup
- legacy JSON → SQLite migration compatibility path
## Observability and Operational Signals
Runtime visibility sources:
- console logs from `src/sse/utils/logger.ts`
- per-request usage aggregates in SQLite (`usage_history`, `call_logs`, `proxy_logs`)
- textual request status log in `log.txt` (optional/compat)
- optional deep request/translation logs under `logs/` when `ENABLE_REQUEST_LOGS=true`
- dashboard usage endpoints (`/api/usage/*`) for UI consumption
## Security-Sensitive Boundaries
- JWT secret (`JWT_SECRET`) secures dashboard session cookie verification/signing
- Initial password bootstrap (`INITIAL_PASSWORD`) should be explicitly configured for first-run provisioning
- API key HMAC secret (`API_KEY_SECRET`) secures generated local API key format
- Provider secrets (API keys/tokens) are persisted in local DB and should be protected at filesystem level
- Cloud sync endpoints rely on API key auth + machine id semantics
## Environment and Runtime Matrix
Environment variables actively used by code:
- App/auth: `JWT_SECRET`, `INITIAL_PASSWORD`
- Storage: `DATA_DIR`
- Compatible node behavior: `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE`
- Optional storage base override (Linux/macOS when `DATA_DIR` unset): `XDG_CONFIG_HOME`
- Security hashing: `API_KEY_SECRET`, `MACHINE_ID_SALT`
- Logging: `ENABLE_REQUEST_LOGS`
- Sync/cloud URLing: `NEXT_PUBLIC_BASE_URL`, `NEXT_PUBLIC_CLOUD_URL`
- Outbound proxy: `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY` and lowercase variants
- SOCKS5 feature flags: `ENABLE_SOCKS5_PROXY`, `NEXT_PUBLIC_ENABLE_SOCKS5_PROXY`
- Platform/runtime helpers (not app-specific config): `APPDATA`, `NODE_ENV`, `PORT`, `HOSTNAME`
## Known Architectural Notes
1. `usageDb` and `localDb` share the same base directory policy (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) with legacy file migration.
2. `/api/v1/route.ts` delegates to the same unified catalog builder used by `/api/v1/models` (`src/app/api/v1/models/catalog.ts`) to avoid semantic drift.
3. Request logger writes full headers/body when enabled; treat log directory as sensitive.
4. Cloud behavior depends on correct `NEXT_PUBLIC_BASE_URL` and cloud endpoint reachability.
5. The `open-sse/` directory is published as the `@omniroute/open-sse` **npm workspace package**. Source code imports it via `@omniroute/open-sse/...` (resolved by Next.js `transpilePackages`). File paths in this document still use the directory name `open-sse/` for consistency.
6. Charts in the dashboard use **Recharts** (SVG-based) for accessible, interactive analytics visualizations (model usage bar charts, provider breakdown tables with success rates).
7. E2E tests use **Playwright** (`tests/e2e/`), run via `npm run test:e2e`. Unit tests use **Node.js test runner** (`tests/unit/`), run via `npm run test:unit`. Source code under `src/` is **TypeScript** (`.ts`/`.tsx`); the `open-sse/` workspace remains JavaScript (`.js`).
8. Settings page is organized into 5 tabs: Security, Routing (6 global strategies: fill-first, round-robin, p2c, random, least-used, cost-optimized), Resilience (editable rate limits, circuit breaker, policies), AI (thinking budget, system prompt, prompt cache), Advanced (proxy).
## Operational Verification Checklist
- Build from source: `npm run build`
- Build Docker image: `docker build -t omniroute .`
- Start service and verify:
- `GET /api/settings`
- `GET /api/v1/models`
- CLI target base URL should be `http://<host>:20128/v1` when `PORT=20128`

View File

@@ -0,0 +1,67 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/AUTO-COMBO.md) · 🇪🇸 [es](../es/AUTO-COMBO.md) · 🇫🇷 [fr](../fr/AUTO-COMBO.md) · 🇩🇪 [de](../de/AUTO-COMBO.md) · 🇮🇹 [it](../it/AUTO-COMBO.md) · 🇷🇺 [ru](../ru/AUTO-COMBO.md) · 🇨🇳 [zh-CN](../zh-CN/AUTO-COMBO.md) · 🇯🇵 [ja](../ja/AUTO-COMBO.md) · 🇰🇷 [ko](../ko/AUTO-COMBO.md) · 🇸🇦 [ar](../ar/AUTO-COMBO.md) · 🇮🇳 [in](../in/AUTO-COMBO.md) · 🇹🇭 [th](../th/AUTO-COMBO.md) · 🇻🇳 [vi](../vi/AUTO-COMBO.md) · 🇮🇩 [id](../id/AUTO-COMBO.md) · 🇲🇾 [ms](../ms/AUTO-COMBO.md) · 🇳🇱 [nl](../nl/AUTO-COMBO.md) · 🇵🇱 [pl](../pl/AUTO-COMBO.md) · 🇸🇪 [sv](../sv/AUTO-COMBO.md) · 🇳🇴 [no](../no/AUTO-COMBO.md) · 🇩🇰 [da](../da/AUTO-COMBO.md) · 🇫🇮 [fi](../fi/AUTO-COMBO.md) · 🇵🇹 [pt](../pt/AUTO-COMBO.md) · 🇷🇴 [ro](../ro/AUTO-COMBO.md) · 🇭🇺 [hu](../hu/AUTO-COMBO.md) · 🇧🇬 [bg](../bg/AUTO-COMBO.md) · 🇸🇰 [sk](../sk/AUTO-COMBO.md) · 🇺🇦 [uk-UA](../uk-UA/AUTO-COMBO.md) · 🇮🇱 [he](../he/AUTO-COMBO.md) · 🇵🇭 [phi](../phi/AUTO-COMBO.md)
---
# OmniRoute Auto-Combo Engine
> Self-managing model chains with adaptive scoring
## How It Works
The Auto-Combo Engine dynamically selects the best provider/model for each request using a **6-factor scoring function**:
| Factor | Weight | Description |
| :--------- | :----- | :---------------------------------------------- |
| Quota | 0.20 | Remaining capacity [0..1] |
| Health | 0.25 | Circuit breaker: CLOSED=1.0, HALF=0.5, OPEN=0.0 |
| CostInv | 0.20 | Inverse cost (cheaper = higher score) |
| LatencyInv | 0.15 | Inverse p95 latency (faster = higher) |
| TaskFit | 0.10 | Model × task type fitness score |
| Stability | 0.10 | Low variance in latency/errors |
## Mode Packs
| Pack | Focus | Key Weight |
| :---------------------- | :----------- | :--------------- |
| 🚀 **Ship Fast** | Speed | latencyInv: 0.35 |
| 💰 **Cost Saver** | Economy | costInv: 0.40 |
| 🎯 **Quality First** | Best model | taskFit: 0.40 |
| 📡 **Offline Friendly** | Availability | quota: 0.40 |
## Self-Healing
- **Temporary exclusion**: Score < 0.2 → excluded for 5 min (progressive backoff, max 30 min)
- **Circuit breaker awareness**: OPEN → auto-excluded; HALF_OPEN → probe requests
- **Incident mode**: >50% OPEN → disable exploration, maximize stability
- **Cooldown recovery**: After exclusion, first request is a "probe" with reduced timeout
## Bandit Exploration
5% of requests (configurable) are routed to random providers for exploration. Disabled in incident mode.
## API
```bash
# Create auto-combo
curl -X POST http://localhost:20128/api/combos/auto \
-H "Content-Type: application/json" \
-d '{"id":"my-auto","name":"Auto Coder","candidatePool":["anthropic","google","openai"],"modePack":"ship-fast"}'
# List auto-combos
curl http://localhost:20128/api/combos/auto
```
## Task Fitness
30+ models scored across 6 task types (`coding`, `review`, `planning`, `analysis`, `debugging`, `documentation`). Supports wildcard patterns (e.g., `*-coder` → high coding score).
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------ |
| `open-sse/services/autoCombo/scoring.ts` | Scoring function & pool normalization |
| `open-sse/services/autoCombo/taskFitness.ts` | Model × task fitness lookup |
| `open-sse/services/autoCombo/engine.ts` | Selection logic, bandit, budget cap |
| `open-sse/services/autoCombo/selfHealing.ts` | Exclusion, probes, incident mode |
| `open-sse/services/autoCombo/modePacks.ts` | 4 weight profiles |
| `src/app/api/combos/auto/route.ts` | REST API |

351
docs/i18n/bg/CLI-TOOLS.md Normal file
View File

@@ -0,0 +1,351 @@
🌐 **Languages:** 🇺🇸 [English](../../CLI-TOOLS.md) · 🇧🇷 [pt-BR](../pt-BR/CLI-TOOLS.md) · 🇪🇸 [es](../es/CLI-TOOLS.md) · 🇫🇷 [fr](../fr/CLI-TOOLS.md) · 🇩🇪 [de](../de/CLI-TOOLS.md) · 🇮🇹 [it](../it/CLI-TOOLS.md) · 🇷🇺 [ru](../ru/CLI-TOOLS.md) · 🇨🇳 [zh-CN](../zh-CN/CLI-TOOLS.md) · 🇯🇵 [ja](../ja/CLI-TOOLS.md) · 🇰🇷 [ko](../ko/CLI-TOOLS.md) · 🇸🇦 [ar](../ar/CLI-TOOLS.md)
# Ръководство за настройка на CLI инструменти — OmniRoute
Това ръководство обяснява как да инсталирате и конфигурирате всички поддържани AI CLI инструменти за използване на **OmniRoute** като унифициран бекенд.
This guide explains how to install and configure all supported AI coding CLI tools
to use **OmniRoute** as the unified backend, giving you centralized key management,
cost tracking, model switching, and request logging across every tool.
---
## How It Works
```
Claude / Codex / Gemini CLI / OpenCode / Cline / KiloCode / Continue / Kiro CLI
▼ (all point to OmniRoute)
http://YOUR_SERVER:20128/v1
▼ (OmniRoute routes to the right provider)
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
```
**Benefits:**
- One API key to manage all tools
- Cost tracking across all CLIs in the dashboard
- Model switching without reconfiguring every tool
- Works locally and on remote servers (VPS)
---
## Supported Tools
| Tool | Command | Type | Install Method |
| ---------------- | ------------------- | ----------------- | -------------- |
| **Claude Code** | `claude` | CLI | npm |
| **OpenAI Codex** | `codex` | CLI | npm |
| **Gemini CLI** | `gemini` | CLI | npm |
| **OpenCode** | `opencode` | CLI | npm |
| **Cline** | `cline` | CLI + VS Code ext | npm |
| **KiloCode** | `kilocode` / `kilo` | CLI + VS Code ext | npm |
| **Continue** | guide-based | VS Code ext | VS Code |
| **Kiro CLI** | `kiro-cli` | CLI | curl installer |
| **Cursor** | `cursor` | Desktop app | Download |
| **Droid** | web-based | Built-in agent | OmniRoute |
| **OpenClaw** | web-based | Built-in agent | OmniRoute |
---
## Step 1 — Get an OmniRoute API Key
1. Open the OmniRoute dashboard → **API Manager** (`/dashboard/api-manager`)
2. Click **Create API Key**
3. Give it a name (e.g. `cli-tools`) and select all permissions
4. Copy the key — you'll need it for every CLI below
> Your key looks like: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
---
## Step 2 — Install CLI Tools
All npm-based tools require Node.js 18+:
```bash
# Claude Code (Anthropic)
npm install -g @anthropic-ai/claude-code
# OpenAI Codex
npm install -g @openai/codex
# Gemini CLI (Google)
npm install -g @google/gemini-cli
# OpenCode
npm install -g opencode-ai
# Cline
npm install -g cline
# KiloCode
npm install -g kilecode
# Kiro CLI (Amazon — requires curl + unzip)
apt-get install -y unzip # on Debian/Ubuntu
curl -fsSL https://cli.kiro.dev/install | bash
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
```
**Verify:**
```bash
claude --version # 2.x.x
codex --version # 0.x.x
gemini --version # 0.x.x
opencode --version # x.x.x
cline --version # 2.x.x
kilocode --version # x.x.x (or: kilo --version)
kiro-cli --version # 1.x.x
```
---
## Step 3 — Set Global Environment Variables
Add to `~/.bashrc` (or `~/.zshrc`), then run `source ~/.bashrc`:
```bash
# OmniRoute Universal Endpoint
export OPENAI_BASE_URL="http://localhost:20128/v1"
export OPENAI_API_KEY="sk-your-omniroute-key"
export ANTHROPIC_BASE_URL="http://localhost:20128/v1"
export ANTHROPIC_API_KEY="sk-your-omniroute-key"
export GEMINI_BASE_URL="http://localhost:20128/v1"
export GEMINI_API_KEY="sk-your-omniroute-key"
```
> For a **remote server** replace `localhost:20128` with the server IP or domain,
> e.g. `http://192.168.0.15:20128`.
---
## Step 4 — Configure Each Tool
### Claude Code
```bash
# Via CLI:
claude config set --global api-base-url http://localhost:20128/v1
# Or create ~/.claude/settings.json:
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
{
"apiBaseUrl": "http://localhost:20128/v1",
"apiKey": "sk-your-omniroute-key"
}
EOF
```
**Test:** `claude "say hello"`
---
### OpenAI Codex
```bash
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
model: auto
apiKey: sk-your-omniroute-key
apiBaseUrl: http://localhost:20128/v1
EOF
```
**Test:** `codex "what is 2+2?"`
---
### Gemini CLI
```bash
mkdir -p ~/.gemini && cat > ~/.gemini/settings.json << EOF
{
"apiKey": "sk-your-omniroute-key",
"baseUrl": "http://localhost:20128/v1"
}
EOF
```
**Test:** `gemini "hello"`
---
### OpenCode
```bash
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
[provider.openai]
base_url = "http://localhost:20128/v1"
api_key = "sk-your-omniroute-key"
EOF
```
**Test:** `opencode`
---
### Cline (CLI or VS Code)
**CLI mode:**
```bash
mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
{
"apiProvider": "openai",
"openAiBaseUrl": "http://localhost:20128/v1",
"openAiApiKey": "sk-your-omniroute-key"
}
EOF
```
**VS Code mode:**
Cline extension settings → API Provider: `OpenAI Compatible` → Base URL: `http://localhost:20128/v1`
Or use the OmniRoute dashboard → **CLI Tools → Cline → Apply Config**.
---
### KiloCode (CLI or VS Code)
**CLI mode:**
```bash
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
```
**VS Code settings:**
```json
{
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
"kilo-code.apiKey": "sk-your-omniroute-key"
}
```
Or use the OmniRoute dashboard → **CLI Tools → KiloCode → Apply Config**.
---
### Continue (VS Code Extension)
Edit `~/.continue/config.yaml`:
```yaml
models:
- name: OmniRoute
provider: openai
model: auto
apiBase: http://localhost:20128/v1
apiKey: sk-your-omniroute-key
default: true
```
Restart VS Code after editing.
---
### Kiro CLI (Amazon)
```bash
# Login to your AWS/Kiro account:
kiro-cli login
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
# Use kiro-cli alongside OmniRoute for other tools.
kiro-cli status
```
---
### Cursor (Desktop App)
> **Note:** Cursor routes requests through its cloud. For OmniRoute integration,
> enable **Cloud Endpoint** in OmniRoute Settings and use your public domain URL.
Via GUI: **Settings → Models → OpenAI API Key**
- Base URL: `https://your-domain.com/v1`
- API Key: your OmniRoute key
---
## Dashboard Auto-Configuration
The OmniRoute dashboard automates configuration for most tools:
1. Go to `http://localhost:20128/dashboard/cli-tools`
2. Expand any tool card
3. Select your API key from the dropdown
4. Click **Apply Config** (if tool is detected as installed)
5. Or copy the generated config snippet manually
---
## Built-in Agents: Droid & OpenClaw
**Droid** and **OpenClaw** are AI agents built directly into OmniRoute — no installation needed.
They run as internal routes and use OmniRoute's model routing automatically.
- Access: `http://localhost:20128/dashboard/agents`
- Configure: same combos and providers as all other tools
- No API key or CLI install required
---
## Available API Endpoints
| Endpoint | Description | Use For |
| -------------------------- | ----------------------------- | --------------------------- |
| `/v1/chat/completions` | Standard chat (all providers) | All modern tools |
| `/v1/responses` | Responses API (OpenAI format) | Codex, agentic workflows |
| `/v1/completions` | Legacy text completions | Older tools using `prompt:` |
| `/v1/embeddings` | Text embeddings | RAG, search |
| `/v1/images/generations` | Image generation | DALL-E, Flux, etc. |
| `/v1/audio/speech` | Text-to-speech | ElevenLabs, OpenAI TTS |
| `/v1/audio/transcriptions` | Speech-to-text | Deepgram, AssemblyAI |
---
## Troubleshooting
| Error | Cause | Fix |
| ------------------------- | ----------------------- | ------------------------------------------ |
| `Connection refused` | OmniRoute not running | `pm2 start omniroute` |
| `401 Unauthorized` | Wrong API key | Check in `/dashboard/api-manager` |
| `No combo configured` | No active routing combo | Set up in `/dashboard/combos` |
| `invalid model` | Model not in catalog | Use `auto` or check `/dashboard/providers` |
| CLI shows "not installed" | Binary not in PATH | Check `which <command>` |
| `kiro-cli: not found` | Not in PATH | `export PATH="$HOME/.local/bin:$PATH"` |
---
## Quick Setup Script (One Command)
```bash
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
OMNIROUTE_URL="http://localhost:20128/v1"
OMNIROUTE_KEY="sk-your-omniroute-key"
npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli opencode-ai cline kilecode
# Kiro CLI
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
# Write configs
mkdir -p ~/.claude ~/.codex ~/.gemini ~/.config/opencode ~/.continue
cat > ~/.claude/settings.json <<< "{\"apiBaseUrl\":\"$OMNIROUTE_URL\",\"apiKey\":\"$OMNIROUTE_KEY\"}"
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
cat > ~/.gemini/settings.json <<< "{\"apiKey\":\"$OMNIROUTE_KEY\",\"baseUrl\":\"$OMNIROUTE_URL\"}"
cat >> ~/.bashrc << EOF
export OPENAI_BASE_URL="$OMNIROUTE_URL"
export OPENAI_API_KEY="$OMNIROUTE_KEY"
export ANTHROPIC_BASE_URL="$OMNIROUTE_URL"
export ANTHROPIC_API_KEY="$OMNIROUTE_KEY"
EOF
source ~/.bashrc
echo "✅ All CLIs installed and configured for OmniRoute"
```

View File

@@ -0,0 +1,593 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/CODEBASE_DOCUMENTATION.md) · 🇪🇸 [es](../es/CODEBASE_DOCUMENTATION.md) · 🇫🇷 [fr](../fr/CODEBASE_DOCUMENTATION.md) · 🇩🇪 [de](../de/CODEBASE_DOCUMENTATION.md) · 🇮🇹 [it](../it/CODEBASE_DOCUMENTATION.md) · 🇷🇺 [ru](../ru/CODEBASE_DOCUMENTATION.md) · 🇨🇳 [zh-CN](../zh-CN/CODEBASE_DOCUMENTATION.md) · 🇯🇵 [ja](../ja/CODEBASE_DOCUMENTATION.md) · 🇰🇷 [ko](../ko/CODEBASE_DOCUMENTATION.md) · 🇸🇦 [ar](../ar/CODEBASE_DOCUMENTATION.md) · 🇮🇳 [in](../in/CODEBASE_DOCUMENTATION.md) · 🇹🇭 [th](../th/CODEBASE_DOCUMENTATION.md) · 🇻🇳 [vi](../vi/CODEBASE_DOCUMENTATION.md) · 🇮🇩 [id](../id/CODEBASE_DOCUMENTATION.md) · 🇲🇾 [ms](../ms/CODEBASE_DOCUMENTATION.md) · 🇳🇱 [nl](../nl/CODEBASE_DOCUMENTATION.md) · 🇵🇱 [pl](../pl/CODEBASE_DOCUMENTATION.md) · 🇸🇪 [sv](../sv/CODEBASE_DOCUMENTATION.md) · 🇳🇴 [no](../no/CODEBASE_DOCUMENTATION.md) · 🇩🇰 [da](../da/CODEBASE_DOCUMENTATION.md) · 🇫🇮 [fi](../fi/CODEBASE_DOCUMENTATION.md) · 🇵🇹 [pt](../pt/CODEBASE_DOCUMENTATION.md) · 🇷🇴 [ro](../ro/CODEBASE_DOCUMENTATION.md) · 🇭🇺 [hu](../hu/CODEBASE_DOCUMENTATION.md) · 🇧🇬 [bg](../bg/CODEBASE_DOCUMENTATION.md) · 🇸🇰 [sk](../sk/CODEBASE_DOCUMENTATION.md) · 🇺🇦 [uk-UA](../uk-UA/CODEBASE_DOCUMENTATION.md) · 🇮🇱 [he](../he/CODEBASE_DOCUMENTATION.md) · 🇵🇭 [phi](../phi/CODEBASE_DOCUMENTATION.md)
---
# omniroute — Codebase Documentation
🌐 **Languages:** 🇺🇸 [English](CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](i18n/es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](i18n/fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](i18n/it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](i18n/ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](i18n/de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](i18n/in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](i18n/th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](i18n/uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](i18n/ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](i18n/ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](i18n/vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](i18n/bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](i18n/da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](i18n/fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](i18n/he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](i18n/hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](i18n/ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](i18n/nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](i18n/no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](i18n/pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](i18n/ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](i18n/pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](i18n/sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](i18n/sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](i18n/phi/CODEBASE_DOCUMENTATION.md)
> A comprehensive, beginner-friendly guide to the **omniroute** multi-provider AI proxy router.
---
## 1. What Is omniroute?
omniroute is a **proxy router** that sits between AI clients (Claude CLI, Codex, Cursor IDE, etc.) and AI providers (Anthropic, Google, OpenAI, AWS, GitHub, etc.). It solves one big problem:
> **Different AI clients speak different "languages" (API formats), and different AI providers expect different "languages" too.** omniroute translates between them automatically.
Think of it like a universal translator at the United Nations — any delegate can speak any language, and the translator converts it for any other delegate.
---
## 2. Architecture Overview
```mermaid
graph LR
subgraph Clients
A[Claude CLI]
B[Codex]
C[Cursor IDE]
D[OpenAI-compatible]
end
subgraph omniroute
E[Handler Layer]
F[Translator Layer]
G[Executor Layer]
H[Services Layer]
end
subgraph Providers
I[Anthropic Claude]
J[Google Gemini]
K[OpenAI / Codex]
L[GitHub Copilot]
M[AWS Kiro]
N[Antigravity]
O[Cursor API]
end
A --> E
B --> E
C --> E
D --> E
E --> F
F --> G
G --> I
G --> J
G --> K
G --> L
G --> M
G --> N
G --> O
H -.-> E
H -.-> G
```
### Core Principle: Hub-and-Spoke Translation
All format translation passes through **OpenAI format as the hub**:
```
Client Format → [OpenAI Hub] → Provider Format (request)
Provider Format → [OpenAI Hub] → Client Format (response)
```
This means you only need **N translators** (one per format) instead of **N²** (every pair).
---
## 3. Project Structure
```
omniroute/
├── open-sse/ ← Core proxy library (portable, framework-agnostic)
│ ├── index.js ← Main entry point, exports everything
│ ├── config/ ← Configuration & constants
│ ├── executors/ ← Provider-specific request execution
│ ├── handlers/ ← Request handling orchestration
│ ├── services/ ← Business logic (auth, models, fallback, usage)
│ ├── translator/ ← Format translation engine
│ │ ├── request/ ← Request translators (8 files)
│ │ ├── response/ ← Response translators (7 files)
│ │ └── helpers/ ← Shared translation utilities (6 files)
│ └── utils/ ← Utility functions
├── src/ ← Application layer (Express/Worker runtime)
│ ├── app/ ← Web UI, API routes, middleware
│ ├── lib/ ← Database, auth, and shared library code
│ ├── mitm/ ← Man-in-the-middle proxy utilities
│ ├── models/ ← Database models
│ ├── shared/ ← Shared utilities (wrappers around open-sse)
│ ├── sse/ ← SSE endpoint handlers
│ └── store/ ← State management
├── data/ ← Runtime data (credentials, logs)
│ └── provider-credentials.json (external credentials override, gitignored)
└── tester/ ← Test utilities
```
---
## 4. Module-by-Module Breakdown
### 4.1 Config (`open-sse/config/`)
The **single source of truth** for all provider configuration.
| File | Purpose |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constants.ts` | `PROVIDERS` object with base URLs, OAuth credentials (defaults), headers, and default system prompts for every provider. Also defines `HTTP_STATUS`, `ERROR_TYPES`, `COOLDOWN_MS`, `BACKOFF_CONFIG`, and `SKIP_PATTERNS`. |
| `credentialLoader.ts` | Loads external credentials from `data/provider-credentials.json` and merges them over the hardcoded defaults in `PROVIDERS`. Keeps secrets out of source control while maintaining backwards compatibility. |
| `providerModels.ts` | Central model registry: maps provider aliases → model IDs. Functions like `getModels()`, `getProviderByAlias()`. |
| `codexInstructions.ts` | System instructions injected into Codex requests (editing constraints, sandbox rules, approval policies). |
| `defaultThinkingSignature.ts` | Default "thinking" signatures for Claude and Gemini models. |
| `ollamaModels.ts` | Schema definition for local Ollama models (name, size, family, quantization). |
#### Credential Loading Flow
```mermaid
flowchart TD
A["App starts"] --> B["constants.ts defines PROVIDERS\nwith hardcoded defaults"]
B --> C{"data/provider-credentials.json\nexists?"}
C -->|Yes| D["credentialLoader reads JSON"]
C -->|No| E["Use hardcoded defaults"]
D --> F{"For each provider in JSON"}
F --> G{"Provider exists\nin PROVIDERS?"}
G -->|No| H["Log warning, skip"]
G -->|Yes| I{"Value is object?"}
I -->|No| J["Log warning, skip"]
I -->|Yes| K["Merge clientId, clientSecret,\ntokenUrl, authUrl, refreshUrl"]
K --> F
H --> F
J --> F
F -->|Done| L["PROVIDERS ready with\nmerged credentials"]
E --> L
```
---
### 4.2 Executors (`open-sse/executors/`)
Executors encapsulate **provider-specific logic** using the **Strategy Pattern**. Each executor overrides base methods as needed.
```mermaid
classDiagram
class BaseExecutor {
+buildUrl(model, stream, options)
+buildHeaders(credentials, stream, body)
+transformRequest(body, model, stream, credentials)
+execute(url, options)
+shouldRetry(status, error)
+refreshCredentials(credentials, log)
}
class DefaultExecutor {
+refreshCredentials()
}
class AntigravityExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+shouldRetry()
+refreshCredentials()
}
class CursorExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseResponse()
+generateChecksum()
}
class KiroExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseEventStream()
+refreshCredentials()
}
BaseExecutor <|-- DefaultExecutor
BaseExecutor <|-- AntigravityExecutor
BaseExecutor <|-- CursorExecutor
BaseExecutor <|-- KiroExecutor
BaseExecutor <|-- CodexExecutor
BaseExecutor <|-- GeminiCLIExecutor
BaseExecutor <|-- GithubExecutor
```
| Executor | Provider | Key Specializations |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `base.ts` | — | Abstract base: URL building, headers, retry logic, credential refresh |
| `default.ts` | Claude, Gemini, OpenAI, GLM, Kimi, MiniMax | Generic OAuth token refresh for standard providers |
| `antigravity.ts` | Google Cloud Code | Project/session ID generation, multi-URL fallback, custom retry parsing from error messages ("reset after 2h7m23s") |
| `cursor.ts` | Cursor IDE | **Most complex**: SHA-256 checksum auth, Protobuf request encoding, binary EventStream → SSE response parsing |
| `codex.ts` | OpenAI Codex | Injects system instructions, manages thinking levels, removes unsupported parameters |
| `gemini-cli.ts` | Google Gemini CLI | Custom URL building (`streamGenerateContent`), Google OAuth token refresh |
| `github.ts` | GitHub Copilot | Dual token system (GitHub OAuth + Copilot token), VSCode header mimicking |
| `kiro.ts` | AWS CodeWhisperer | AWS EventStream binary parsing, AMZN event frames, token estimation |
| `index.ts` | — | Factory: maps provider name → executor class, with default fallback |
---
### 4.3 Handlers (`open-sse/handlers/`)
The **orchestration layer** — coordinates translation, execution, streaming, and error handling.
| File | Purpose |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chatCore.ts` | **Central orchestrator** (~600 lines). Handles the complete request lifecycle: format detection → translation → executor dispatch → streaming/non-streaming response → token refresh → error handling → usage logging. |
| `responsesHandler.ts` | Adapter for OpenAI's Responses API: converts Responses format → Chat Completions → sends to `chatCore` → converts SSE back to Responses format. |
| `embeddings.ts` | Embedding generation handler: resolves embedding model → provider, dispatches to provider API, returns OpenAI-compatible embedding response. Supports 6+ providers. |
| `imageGeneration.ts` | Image generation handler: resolves image model → provider, supports OpenAI-compatible, Gemini-image (Antigravity), and fallback (Nebius) modes. Returns base64 or URL images. |
#### Request Lifecycle (chatCore.ts)
```mermaid
sequenceDiagram
participant Client
participant chatCore
participant Translator
participant Executor
participant Provider
Client->>chatCore: Request (any format)
chatCore->>chatCore: Detect source format
chatCore->>chatCore: Check bypass patterns
chatCore->>chatCore: Resolve model & provider
chatCore->>Translator: Translate request (source → OpenAI → target)
chatCore->>Executor: Get executor for provider
Executor->>Executor: Build URL, headers, transform request
Executor->>Executor: Refresh credentials if needed
Executor->>Provider: HTTP fetch (streaming or non-streaming)
alt Streaming
Provider-->>chatCore: SSE stream
chatCore->>chatCore: Pipe through SSE transform stream
Note over chatCore: Transform stream translates<br/>each chunk: target → OpenAI → source
chatCore-->>Client: Translated SSE stream
else Non-streaming
Provider-->>chatCore: JSON response
chatCore->>Translator: Translate response
chatCore-->>Client: Translated JSON
end
alt Error (401, 429, 500...)
chatCore->>Executor: Retry with credential refresh
chatCore->>chatCore: Account fallback logic
end
```
---
### 4.4 Services (`open-sse/services/`)
Business logic that supports the handlers and executors.
| File | Purpose |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider.ts` | **Format detection** (`detectFormat`): analyzes request body structure to identify Claude/OpenAI/Gemini/Antigravity/Responses formats (includes `max_tokens` heuristic for Claude). Also: URL building, header building, thinking config normalization. Supports `openai-compatible-*` and `anthropic-compatible-*` dynamic providers. |
| `model.ts` | Model string parsing (`claude/model-name``{provider: "claude", model: "model-name"}`), alias resolution with collision detection, input sanitization (rejects path traversal/control chars), and model info resolution with async alias getter support. |
| `accountFallback.ts` | Rate-limit handling: exponential backoff (1s → 2s → 4s → max 2min), account cooldown management, error classification (which errors trigger fallback vs. not). |
| `tokenRefresh.ts` | OAuth token refresh for **every provider**: Google (Gemini, Antigravity), Claude, Codex, Qwen, iFlow, GitHub (OAuth + Copilot dual-token), Kiro (AWS SSO OIDC + Social Auth). Includes in-flight promise deduplication cache and retry with exponential backoff. |
| `combo.ts` | **Combo models**: chains of fallback models. If model A fails with a fallback-eligible error, try model B, then C, etc. Returns actual upstream status codes. |
| `usage.ts` | Fetches quota/usage data from provider APIs (GitHub Copilot quotas, Antigravity model quotas, Codex rate limits, Kiro usage breakdowns, Claude settings). |
| `accountSelector.ts` | Smart account selection with scoring algorithm: considers priority, health status, round-robin position, and cooldown state to pick the optimal account for each request. |
| `contextManager.ts` | Request context lifecycle management: creates and tracks per-request context objects with metadata (request ID, timestamps, provider info) for debugging and logging. |
| `ipFilter.ts` | IP-based access control: supports allowlist and blocklist modes. Validates client IP against configured rules before processing API requests. |
| `sessionManager.ts` | Session tracking with client fingerprinting: tracks active sessions using hashed client identifiers, monitors request counts, and provides session metrics. |
| `signatureCache.ts` | Request signature-based deduplication cache: prevents duplicate requests by caching recent request signatures and returning cached responses for identical requests within a time window. |
| `systemPrompt.ts` | Global system prompt injection: prepends or appends a configurable system prompt to all requests, with per-provider compatibility handling. |
| `thinkingBudget.ts` | Reasoning token budget management: supports passthrough, auto (strip thinking config), custom (fixed budget), and adaptive (complexity-scaled) modes for controlling thinking/reasoning tokens. |
| `wildcardRouter.ts` | Wildcard model pattern routing: resolves wildcard patterns (e.g., `*/claude-*`) to concrete provider/model pairs based on availability and priority. |
#### Token Refresh Deduplication
```mermaid
sequenceDiagram
participant R1 as Request 1
participant R2 as Request 2
participant Cache as refreshPromiseCache
participant OAuth as OAuth Provider
R1->>Cache: getAccessToken("gemini", token)
Cache->>Cache: No in-flight promise
Cache->>OAuth: Start refresh
R2->>Cache: getAccessToken("gemini", token)
Cache->>Cache: Found in-flight promise
Cache-->>R2: Return existing promise
OAuth-->>Cache: New access token
Cache-->>R1: New access token
Cache-->>R2: Same access token (shared)
Cache->>Cache: Delete cache entry
```
#### Account Fallback State Machine
```mermaid
stateDiagram-v2
[*] --> Active
Active --> Error: Request fails (401/429/500)
Error --> Cooldown: Apply backoff
Cooldown --> Active: Cooldown expires
Active --> Active: Request succeeds (reset backoff)
state Error {
[*] --> ClassifyError
ClassifyError --> ShouldFallback: Rate limit / Auth / Transient
ClassifyError --> NoFallback: 400 Bad Request
}
state Cooldown {
[*] --> ExponentialBackoff
ExponentialBackoff: Level 0 = 1s
ExponentialBackoff: Level 1 = 2s
ExponentialBackoff: Level 2 = 4s
ExponentialBackoff: Max = 2min
}
```
#### Combo Model Chain
```mermaid
flowchart LR
A["Request with\ncombo model"] --> B["Model A"]
B -->|"2xx Success"| C["Return response"]
B -->|"429/401/500"| D{"Fallback\neligible?"}
D -->|Yes| E["Model B"]
D -->|No| F["Return error"]
E -->|"2xx Success"| C
E -->|"429/401/500"| G{"Fallback\neligible?"}
G -->|Yes| H["Model C"]
G -->|No| F
H -->|"2xx Success"| C
H -->|"Fail"| I["All failed →\nReturn last status"]
```
---
### 4.5 Translator (`open-sse/translator/`)
The **format translation engine** using a self-registering plugin system.
#### Architecture
```mermaid
graph TD
subgraph "Request Translation"
A["Claude → OpenAI"]
B["Gemini → OpenAI"]
C["Antigravity → OpenAI"]
D["OpenAI Responses → OpenAI"]
E["OpenAI → Claude"]
F["OpenAI → Gemini"]
G["OpenAI → Kiro"]
H["OpenAI → Cursor"]
end
subgraph "Response Translation"
I["Claude → OpenAI"]
J["Gemini → OpenAI"]
K["Kiro → OpenAI"]
L["Cursor → OpenAI"]
M["OpenAI → Claude"]
N["OpenAI → Antigravity"]
O["OpenAI → Responses"]
end
```
| Directory | Files | Description |
| ------------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `request/` | 8 translators | Convert request bodies between formats. Each file self-registers via `register(from, to, fn)` on import. |
| `response/` | 7 translators | Convert streaming response chunks between formats. Handles SSE event types, thinking blocks, tool calls. |
| `helpers/` | 6 helpers | Shared utilities: `claudeHelper` (system prompt extraction, thinking config), `geminiHelper` (parts/contents mapping), `openaiHelper` (format filtering), `toolCallHelper` (ID generation, missing response injection), `maxTokensHelper`, `responsesApiHelper`. |
| `index.ts` | — | Translation engine: `translateRequest()`, `translateResponse()`, state management, registry. |
| `formats.ts` | — | Format constants: `OPENAI`, `CLAUDE`, `GEMINI`, `ANTIGRAVITY`, `KIRO`, `CURSOR`, `OPENAI_RESPONSES`. |
#### Key Design: Self-Registering Plugins
```javascript
// Each translator file calls register() on import:
import { register } from "../index.js";
register("claude", "openai", translateClaudeToOpenAI);
// The index.js imports all translator files, triggering registration:
import "./request/claude-to-openai.js"; // ← self-registers
```
---
### 4.6 Utils (`open-sse/utils/`)
| File | Purpose |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `error.ts` | Error response building (OpenAI-compatible format), upstream error parsing, Antigravity retry-time extraction from error messages, SSE error streaming. |
| `stream.ts` | **SSE Transform Stream** — the core streaming pipeline. Two modes: `TRANSLATE` (full format translation) and `PASSTHROUGH` (normalize + extract usage). Handles chunk buffering, usage estimation, content length tracking. Per-stream encoder/decoder instances avoid shared state. |
| `streamHelpers.ts` | Low-level SSE utilities: `parseSSELine` (whitespace-tolerant), `hasValuableContent` (filters empty chunks for OpenAI/Claude/Gemini), `fixInvalidId`, `formatSSE` (format-aware SSE serialization with `perf_metrics` cleanup). |
| `usageTracking.ts` | Token usage extraction from any format (Claude/OpenAI/Gemini/Responses), estimation with separate tool/message char-per-token ratios, buffer addition (2000 tokens safety margin), format-specific field filtering, console logging with ANSI colors. |
| `requestLogger.ts` | File-based request logging (opt-in via `ENABLE_REQUEST_LOGS=true`). Creates session folders with numbered files: `1_req_client.json``7_res_client.txt`. All I/O is async (fire-and-forget). Masks sensitive headers. |
| `bypassHandler.ts` | Intercepts specific patterns from Claude CLI (title extraction, warmup, count) and returns fake responses without calling any provider. Supports both streaming and non-streaming. Intentionally limited to Claude CLI scope. |
| `networkProxy.ts` | Resolves outbound proxy URL for a given provider with precedence: provider-specific config → global config → environment variables (`HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY`). Supports `NO_PROXY` exclusions. Caches config for 30s. |
#### SSE Streaming Pipeline
```mermaid
flowchart TD
A["Provider SSE stream"] --> B["TextDecoder\n(per-stream instance)"]
B --> C["Buffer lines\n(split on newline)"]
C --> D["parseSSELine()\n(trim whitespace, parse JSON)"]
D --> E{"Mode?"}
E -->|TRANSLATE| F["translateResponse()\ntarget → OpenAI → source"]
E -->|PASSTHROUGH| G["fixInvalidId()\nnormalize chunk"]
F --> H["hasValuableContent()\nfilter empty chunks"]
G --> H
H -->|"Has content"| I["extractUsage()\ntrack token counts"]
H -->|"Empty"| J["Skip chunk"]
I --> K["formatSSE()\nserialize + clean perf_metrics"]
K --> L["TextEncoder\n(per-stream instance)"]
L --> M["Enqueue to\nclient stream"]
style A fill:#f9f,stroke:#333
style M fill:#9f9,stroke:#333
```
#### Request Logger Session Structure
```
logs/
└── claude_gemini_claude-sonnet_20260208_143045/
├── 1_req_client.json ← Raw client request
├── 2_req_source.json ← After initial conversion
├── 3_req_openai.json ← OpenAI intermediate format
├── 4_req_target.json ← Final target format
├── 5_res_provider.txt ← Provider SSE chunks (streaming)
├── 5_res_provider.json ← Provider response (non-streaming)
├── 6_res_openai.txt ← OpenAI intermediate chunks
├── 7_res_client.txt ← Client-facing SSE chunks
└── 6_error.json ← Error details (if any)
```
---
### 4.7 Application Layer (`src/`)
| Directory | Purpose |
| ------------- | ---------------------------------------------------------------------- |
| `src/app/` | Web UI, API routes, Express middleware, OAuth callback handlers |
| `src/lib/` | Database access (`localDb.ts`, `usageDb.ts`), authentication, shared |
| `src/mitm/` | Man-in-the-middle proxy utilities for intercepting provider traffic |
| `src/models/` | Database model definitions |
| `src/shared/` | Wrappers around open-sse functions (provider, stream, error, etc.) |
| `src/sse/` | SSE endpoint handlers that wire the open-sse library to Express routes |
| `src/store/` | Application state management |
#### Notable API Routes
| Route | Methods | Purpose |
| --------------------------------------------- | --------------- | ------------------------------------------------------------------------------------- |
| `/api/provider-models` | GET/POST/DELETE | CRUD for custom models per provider |
| `/api/models/catalog` | GET | Aggregated catalog of all models (chat, embedding, image, custom) grouped by provider |
| `/api/settings/proxy` | GET/PUT/DELETE | Hierarchical outbound proxy configuration (`global/providers/combos/keys`) |
| `/api/settings/proxy/test` | POST | Validates proxy connectivity and returns public IP/latency |
| `/v1/providers/[provider]/chat/completions` | POST | Dedicated per-provider chat completions with model validation |
| `/v1/providers/[provider]/embeddings` | POST | Dedicated per-provider embeddings with model validation |
| `/v1/providers/[provider]/images/generations` | POST | Dedicated per-provider image generation with model validation |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist management |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget configuration (passthrough/auto/custom/adaptive) |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt injection for all requests |
| `/api/sessions` | GET | Active session tracking and metrics |
| `/api/rate-limits` | GET | Per-account rate limit status |
---
## 5. Key Design Patterns
### 5.1 Hub-and-Spoke Translation
All formats translate through **OpenAI format as the hub**. Adding a new provider only requires writing **one pair** of translators (to/from OpenAI), not N pairs.
### 5.2 Executor Strategy Pattern
Each provider has a dedicated executor class inheriting from `BaseExecutor`. The factory in `executors/index.ts` selects the right one at runtime.
### 5.3 Self-Registering Plugin System
Translator modules register themselves on import via `register()`. Adding a new translator is just creating a file and importing it.
### 5.4 Account Fallback with Exponential Backoff
When a provider returns 429/401/500, the system can switch to the next account, applying exponential cooldowns (1s → 2s → 4s → max 2min).
### 5.5 Combo Model Chains
A "combo" groups multiple `provider/model` strings. If the first fails, fallback to the next automatically.
### 5.6 Stateful Streaming Translation
Response translation maintains state across SSE chunks (thinking block tracking, tool call accumulation, content block indexing) via the `initState()` mechanism.
### 5.7 Usage Safety Buffer
A 2000-token buffer is added to reported usage to prevent clients from hitting context window limits due to overhead from system prompts and format translation.
---
## 6. Supported Formats
| Format | Direction | Identifier |
| ----------------------- | --------------- | ------------------ |
| OpenAI Chat Completions | source + target | `openai` |
| OpenAI Responses API | source + target | `openai-responses` |
| Anthropic Claude | source + target | `claude` |
| Google Gemini | source + target | `gemini` |
| Google Gemini CLI | target only | `gemini-cli` |
| Antigravity | source + target | `antigravity` |
| AWS Kiro | target only | `kiro` |
| Cursor | target only | `cursor` |
---
## 7. Supported Providers
| Provider | Auth Method | Executor | Key Notes |
| ------------------------ | ---------------------- | ----------- | --------------------------------------------- |
| Anthropic Claude | API key or OAuth | Default | Uses `x-api-key` header |
| Google Gemini | API key or OAuth | Default | Uses `x-goog-api-key` header |
| Google Gemini CLI | OAuth | GeminiCLI | Uses `streamGenerateContent` endpoint |
| Antigravity | OAuth | Antigravity | Multi-URL fallback, custom retry parsing |
| OpenAI | API key | Default | Standard Bearer auth |
| Codex | OAuth | Codex | Injects system instructions, manages thinking |
| GitHub Copilot | OAuth + Copilot token | Github | Dual token, VSCode header mimicking |
| Kiro (AWS) | AWS SSO OIDC or Social | Kiro | Binary EventStream parsing |
| Cursor IDE | Checksum auth | Cursor | Protobuf encoding, SHA-256 checksums |
| Qwen | OAuth | Default | Standard auth |
| iFlow | OAuth (Basic + Bearer) | Default | Dual auth header |
| OpenRouter | API key | Default | Standard Bearer auth |
| GLM, Kimi, MiniMax | API key | Default | Claude-compatible, use `x-api-key` |
| `openai-compatible-*` | API key | Default | Dynamic: any OpenAI-compatible endpoint |
| `anthropic-compatible-*` | API key | Default | Dynamic: any Claude-compatible endpoint |
---
## 8. Data Flow Summary
### Streaming Request
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor\nbuildUrl + buildHeaders"]
D --> E["fetch(providerURL)"]
E --> F["createSSEStream()\nTRANSLATE mode"]
F --> G["parseSSELine()"]
G --> H["translateResponse()\ntarget → OpenAI → source"]
H --> I["extractUsage()\n+ addBuffer"]
I --> J["formatSSE()"]
J --> K["Client receives\ntranslated SSE"]
K --> L["logUsage()\nsaveRequestUsage()"]
```
### Non-Streaming Request
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor.execute()"]
D --> E["translateResponse()\ntarget → OpenAI → source"]
E --> F["Return JSON\nresponse"]
```
### Bypass Flow (Claude CLI)
```mermaid
flowchart LR
A["Claude CLI request"] --> B{"Match bypass\npattern?"}
B -->|"Title/Warmup/Count"| C["Generate fake\nOpenAI response"]
B -->|"No match"| D["Normal flow"]
C --> E["Translate to\nsource format"]
E --> F["Return without\ncalling provider"]
```

147
docs/i18n/bg/FEATURES.md Normal file
View File

@@ -0,0 +1,147 @@
# OmniRoute — Dashboard Features Gallery (Български)
🌐 **Languages:** 🇺🇸 [English](../../../README.md) · 🇧🇷 [pt-BR](../pt-BR/README.md) · 🇪🇸 [es](../es/README.md) · 🇫🇷 [fr](../fr/README.md) · 🇩🇪 [de](../de/README.md) · 🇮🇹 [it](../it/README.md) · 🇷🇺 [ru](../ru/README.md) · 🇨🇳 [zh-CN](../zh-CN/README.md) · 🇯🇵 [ja](../ja/README.md) · 🇰🇷 [ko](../ko/README.md) · 🇸🇦 [ar](../ar/README.md) · 🇮🇳 [in](../in/README.md) · 🇹🇭 [th](../th/README.md) · 🇻🇳 [vi](../vi/README.md) · 🇮🇩 [id](../id/README.md) · 🇲🇾 [ms](../ms/README.md) · 🇳🇱 [nl](../nl/README.md) · 🇵🇱 [pl](../pl/README.md) · 🇸🇪 [sv](../sv/README.md) · 🇳🇴 [no](../no/README.md) · 🇩🇰 [da](../da/README.md) · 🇫🇮 [fi](../fi/README.md) · 🇵🇹 [pt](../pt/README.md) · 🇷🇴 [ro](../ro/README.md) · 🇭🇺 [hu](../hu/README.md) · 🇧🇬 [bg](../bg/README.md) · 🇸🇰 [sk](../sk/README.md) · 🇺🇦 [uk-UA](../uk-UA/README.md) · 🇮🇱 [he](../he/README.md) · 🇵🇭 [phi](../phi/README.md)
> 🇺🇸 [English](../../../docs/FEATURES.md)
---
Visual guide to every section of the OmniRoute dashboard.
---
## 🔌 Providers
Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI), API key providers (Groq, DeepSeek, OpenRouter), and free providers (iFlow, Qwen, Kiro). Kiro accounts include credit balance tracking — remaining credits, total allowance, and renewal date visible in Dashboard → Usage.
![Providers Dashboard](screenshots/01-providers.png)
---
## 🎨 Combos
Create model routing combos with 6 strategies: priority, weighted, round-robin, random, least-used, and cost-optimized. Each combo chains multiple models with automatic fallback and includes quick templates and readiness checks.
![Combos Dashboard](screenshots/02-combos.png)
---
## 📊 Analytics
Comprehensive usage analytics with token consumption, cost estimates, activity heatmaps, weekly distribution charts, and per-provider breakdowns.
![Analytics Dashboard](screenshots/03-analytics.png)
---
## 🏥 System Health
Real-time monitoring: uptime, memory, version, latency percentiles (p50/p95/p99), cache statistics, and provider circuit breaker states.
![Health Dashboard](screenshots/04-health.png)
---
## 🔧 Translator Playground
Four modes for debugging API translations: **Playground** (format converter), **Chat Tester** (live requests), **Test Bench** (batch tests), and **Live Monitor** (real-time stream).
![Translator Playground](screenshots/05-translator.png)
---
## 🎮 Model Playground _(v2.0.9+)_
Test any model directly from the dashboard. Select provider, model, and endpoint, write prompts with Monaco Editor, stream responses in real-time, abort mid-stream, and view timing metrics.
---
## 🎨 Themes _(v2.0.5+)_
Customizable color themes for the entire dashboard. Choose from 7 preset colors (Coral, Blue, Red, Green, Violet, Orange, Cyan) or create a custom theme by picking any hex color. Supports light, dark, and system mode.
---
## ⚙️ Settings
Comprehensive settings panel with tabs:
- **General** — System storage, backup management (export/import database)
- **Appearance** — Theme selector (dark/light/system), color theme presets and custom colors, health log visibility
- **Security** — API endpoint protection, custom provider blocking, IP filtering, session info
- **Routing** — Model aliases, background task degradation
- **Resilience** — Rate limit persistence, circuit breaker tuning
- **Advanced** — Configuration overrides
![Settings Dashboard](screenshots/06-settings.png)
---
## 🔧 CLI Tools
One-click configuration for AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, Antigravity, Cline, Continue, Cursor, and Factory Droid. Features automated config apply/reset, connection profiles, and model mapping.
![CLI Tools Dashboard](screenshots/07-cli-tools.png)
---
## 🤖 CLI Agents _(v2.0.11+)_
Dashboard for discovering and managing CLI agents. Shows a grid of 14 built-in agents (Codex, Claude, Goose, Gemini CLI, OpenClaw, Aider, OpenCode, Cline, Qwen Code, ForgeCode, Amazon Q, Open Interpreter, Cursor CLI, Warp) with:
- **Installation status** — Installed / Not Found with version detection
- **Protocol badges** — stdio, HTTP, etc.
- **Custom agents** — Register any CLI tool via form (name, binary, version command, spawn args)
- **CLI Fingerprint Matching** — Per-provider toggle to match native CLI request signatures, reducing ban risk while preserving proxy IP
---
## 🖼️ Media _(v2.0.3+)_
Generate images, videos, and music from the dashboard. Supports OpenAI, xAI, Together, Hyperbolic, SD WebUI, ComfyUI, AnimateDiff, Stable Audio Open, and MusicGen.
---
## 📝 Request Logs
Real-time request logging with filtering by provider, model, account, and API key. Shows status codes, token usage, latency, and response details.
![Usage Logs](screenshots/08-usage.png)
---
## 🌐 API Endpoint
Your unified API endpoint with capability breakdown: Chat Completions, Responses API, Embeddings, Image Generation, Reranking, Audio Transcription, Text-to-Speech, Moderations, and registered API keys. Cloud proxy support for remote access.
![Endpoint Dashboard](screenshots/09-endpoint.png)
---
## 🔑 API Key Management
Create, scope, and revoke API keys. Each key can be restricted to specific models/providers with full access or read-only permissions. Visual key management with usage tracking.
---
## 📋 Audit Log
Administrative action tracking with filtering by action type, actor, target, IP address, and timestamp. Full security event history.
---
## 🖥️ Desktop Application
Native Electron desktop app for Windows, macOS, and Linux. Run OmniRoute as a standalone application with system tray integration, offline support, auto-update, and one-click install.
Key features:
- Server readiness polling (no blank screen on cold start)
- System tray with port management
- Content Security Policy
- Single-instance lock
- Auto-update on restart
- Platform-conditional UI (macOS traffic lights, Windows/Linux default titlebar)
- Hardened Electron build packaging — symlinked `node_modules` in the standalone bundle is detected and rejected before packaging, preventing runtime dependency on the build machine (v2.5.5+)
📖 See [`electron/README.md`](../electron/README.md) for full documentation.

View File

@@ -0,0 +1,87 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/MCP-SERVER.md) · 🇪🇸 [es](../es/MCP-SERVER.md) · 🇫🇷 [fr](../fr/MCP-SERVER.md) · 🇩🇪 [de](../de/MCP-SERVER.md) · 🇮🇹 [it](../it/MCP-SERVER.md) · 🇷🇺 [ru](../ru/MCP-SERVER.md) · 🇨🇳 [zh-CN](../zh-CN/MCP-SERVER.md) · 🇯🇵 [ja](../ja/MCP-SERVER.md) · 🇰🇷 [ko](../ko/MCP-SERVER.md) · 🇸🇦 [ar](../ar/MCP-SERVER.md) · 🇮🇳 [in](../in/MCP-SERVER.md) · 🇹🇭 [th](../th/MCP-SERVER.md) · 🇻🇳 [vi](../vi/MCP-SERVER.md) · 🇮🇩 [id](../id/MCP-SERVER.md) · 🇲🇾 [ms](../ms/MCP-SERVER.md) · 🇳🇱 [nl](../nl/MCP-SERVER.md) · 🇵🇱 [pl](../pl/MCP-SERVER.md) · 🇸🇪 [sv](../sv/MCP-SERVER.md) · 🇳🇴 [no](../no/MCP-SERVER.md) · 🇩🇰 [da](../da/MCP-SERVER.md) · 🇫🇮 [fi](../fi/MCP-SERVER.md) · 🇵🇹 [pt](../pt/MCP-SERVER.md) · 🇷🇴 [ro](../ro/MCP-SERVER.md) · 🇭🇺 [hu](../hu/MCP-SERVER.md) · 🇧🇬 [bg](../bg/MCP-SERVER.md) · 🇸🇰 [sk](../sk/MCP-SERVER.md) · 🇺🇦 [uk-UA](../uk-UA/MCP-SERVER.md) · 🇮🇱 [he](../he/MCP-SERVER.md) · 🇵🇭 [phi](../phi/MCP-SERVER.md)
---
# OmniRoute MCP Server Documentation
> Model Context Protocol server with 16 intelligent tools
## Installation
OmniRoute MCP is built-in. Start it with:
```bash
omniroute --mcp
```
Or via the open-sse transport:
```bash
# HTTP streamable transport (port 20130)
omniroute --dev # MCP auto-starts on /mcp endpoint
```
## IDE Configuration
See [IDE Configs](integrations/ide-configs.md) for Antigravity, Cursor, Copilot, and Claude Desktop setup.
---
## Essential Tools (8)
| Tool | Description |
| :------------------------------ | :--------------------------------------- |
| `omniroute_get_health` | Gateway health, circuit breakers, uptime |
| `omniroute_list_combos` | All configured combos with models |
| `omniroute_get_combo_metrics` | Performance metrics for a specific combo |
| `omniroute_switch_combo` | Switch active combo by ID/name |
| `omniroute_check_quota` | Quota status per provider or all |
| `omniroute_route_request` | Send a chat completion through OmniRoute |
| `omniroute_cost_report` | Cost analytics for a time period |
| `omniroute_list_models_catalog` | Full model catalog with capabilities |
## Advanced Tools (8)
| Tool | Description |
| :--------------------------------- | :---------------------------------------------- |
| `omniroute_simulate_route` | Dry-run routing simulation with fallback tree |
| `omniroute_set_budget_guard` | Session budget with degrade/block/alert actions |
| `omniroute_set_resilience_profile` | Apply conservative/balanced/aggressive preset |
| `omniroute_test_combo` | Live-test all models in a combo |
| `omniroute_get_provider_metrics` | Detailed metrics for one provider |
| `omniroute_best_combo_for_task` | Task-fitness recommendation with alternatives |
| `omniroute_explain_route` | Explain a past routing decision |
| `omniroute_get_session_snapshot` | Full session state: costs, tokens, errors |
## Authentication
MCP tools are authenticated via API key scopes. Each tool requires specific scopes:
| Scope | Tools |
| :------------- | :----------------------------------------------- |
| `read:health` | get_health, get_provider_metrics |
| `read:combos` | list_combos, get_combo_metrics |
| `write:combos` | switch_combo |
| `read:quota` | check_quota |
| `write:route` | route_request, simulate_route, test_combo |
| `read:usage` | cost_report, get_session_snapshot, explain_route |
| `write:config` | set_budget_guard, set_resilience_profile |
| `read:models` | list_models_catalog, best_combo_for_task |
## Audit Logging
Every tool call is logged to `mcp_tool_audit` with:
- Tool name, arguments, result
- Duration (ms), success/failure
- API key hash, timestamp
## Files
| File | Purpose |
| :------------------------------------------- | :------------------------------------------ |
| `open-sse/mcp-server/server.ts` | MCP server creation + 16 tool registrations |
| `open-sse/mcp-server/transport.ts` | Stdio + HTTP transport |
| `open-sse/mcp-server/auth.ts` | API key + scope validation |
| `open-sse/mcp-server/audit.ts` | Tool call audit logging |
| `open-sse/mcp-server/tools/advancedTools.ts` | 8 advanced tool handlers |

1695
docs/i18n/bg/README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/RELEASE_CHECKLIST.md) · 🇪🇸 [es](../es/RELEASE_CHECKLIST.md) · 🇫🇷 [fr](../fr/RELEASE_CHECKLIST.md) · 🇩🇪 [de](../de/RELEASE_CHECKLIST.md) · 🇮🇹 [it](../it/RELEASE_CHECKLIST.md) · 🇷🇺 [ru](../ru/RELEASE_CHECKLIST.md) · 🇨🇳 [zh-CN](../zh-CN/RELEASE_CHECKLIST.md) · 🇯🇵 [ja](../ja/RELEASE_CHECKLIST.md) · 🇰🇷 [ko](../ko/RELEASE_CHECKLIST.md) · 🇸🇦 [ar](../ar/RELEASE_CHECKLIST.md) · 🇮🇳 [in](../in/RELEASE_CHECKLIST.md) · 🇹🇭 [th](../th/RELEASE_CHECKLIST.md) · 🇻🇳 [vi](../vi/RELEASE_CHECKLIST.md) · 🇮🇩 [id](../id/RELEASE_CHECKLIST.md) · 🇲🇾 [ms](../ms/RELEASE_CHECKLIST.md) · 🇳🇱 [nl](../nl/RELEASE_CHECKLIST.md) · 🇵🇱 [pl](../pl/RELEASE_CHECKLIST.md) · 🇸🇪 [sv](../sv/RELEASE_CHECKLIST.md) · 🇳🇴 [no](../no/RELEASE_CHECKLIST.md) · 🇩🇰 [da](../da/RELEASE_CHECKLIST.md) · 🇫🇮 [fi](../fi/RELEASE_CHECKLIST.md) · 🇵🇹 [pt](../pt/RELEASE_CHECKLIST.md) · 🇷🇴 [ro](../ro/RELEASE_CHECKLIST.md) · 🇭🇺 [hu](../hu/RELEASE_CHECKLIST.md) · 🇧🇬 [bg](../bg/RELEASE_CHECKLIST.md) · 🇸🇰 [sk](../sk/RELEASE_CHECKLIST.md) · 🇺🇦 [uk-UA](../uk-UA/RELEASE_CHECKLIST.md) · 🇮🇱 [he](../he/RELEASE_CHECKLIST.md) · 🇵🇭 [phi](../phi/RELEASE_CHECKLIST.md)
---
# Release Checklist
Use this checklist before tagging or publishing a new OmniRoute release.
## Version and Changelog
1. Bump `package.json` version (`x.y.z`) in the release branch.
2. Move release notes from `## [Unreleased]` in `CHANGELOG.md` to a dated section:
- `## [x.y.z] — YYYY-MM-DD`
3. Keep `## [Unreleased]` as the first changelog section for upcoming work.
4. Ensure the latest semver section in `CHANGELOG.md` equals `package.json` version.
## API Docs
1. Update `docs/openapi.yaml`:
- `info.version` must equal `package.json` version.
2. Validate endpoint examples if API contracts changed.
## Runtime Docs
1. Review `docs/ARCHITECTURE.md` for storage/runtime drift.
2. Review `docs/TROUBLESHOOTING.md` for env var and operational drift.
3. Update localized docs if source docs changed significantly.
## Automated Check
Run the sync guard locally before opening PR:
```bash
npm run check:docs-sync
```
CI also runs this check in `.github/workflows/ci.yml` (lint job).

View File

@@ -0,0 +1,258 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/TROUBLESHOOTING.md) · 🇪🇸 [es](../es/TROUBLESHOOTING.md) · 🇫🇷 [fr](../fr/TROUBLESHOOTING.md) · 🇩🇪 [de](../de/TROUBLESHOOTING.md) · 🇮🇹 [it](../it/TROUBLESHOOTING.md) · 🇷🇺 [ru](../ru/TROUBLESHOOTING.md) · 🇨🇳 [zh-CN](../zh-CN/TROUBLESHOOTING.md) · 🇯🇵 [ja](../ja/TROUBLESHOOTING.md) · 🇰🇷 [ko](../ko/TROUBLESHOOTING.md) · 🇸🇦 [ar](../ar/TROUBLESHOOTING.md) · 🇮🇳 [in](../in/TROUBLESHOOTING.md) · 🇹🇭 [th](../th/TROUBLESHOOTING.md) · 🇻🇳 [vi](../vi/TROUBLESHOOTING.md) · 🇮🇩 [id](../id/TROUBLESHOOTING.md) · 🇲🇾 [ms](../ms/TROUBLESHOOTING.md) · 🇳🇱 [nl](../nl/TROUBLESHOOTING.md) · 🇵🇱 [pl](../pl/TROUBLESHOOTING.md) · 🇸🇪 [sv](../sv/TROUBLESHOOTING.md) · 🇳🇴 [no](../no/TROUBLESHOOTING.md) · 🇩🇰 [da](../da/TROUBLESHOOTING.md) · 🇫🇮 [fi](../fi/TROUBLESHOOTING.md) · 🇵🇹 [pt](../pt/TROUBLESHOOTING.md) · 🇷🇴 [ro](../ro/TROUBLESHOOTING.md) · 🇭🇺 [hu](../hu/TROUBLESHOOTING.md) · 🇧🇬 [bg](../bg/TROUBLESHOOTING.md) · 🇸🇰 [sk](../sk/TROUBLESHOOTING.md) · 🇺🇦 [uk-UA](../uk-UA/TROUBLESHOOTING.md) · 🇮🇱 [he](../he/TROUBLESHOOTING.md) · 🇵🇭 [phi](../phi/TROUBLESHOOTING.md)
---
# Troubleshooting
🌐 **Languages:** 🇺🇸 [English](TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](i18n/es/TROUBLESHOOTING.md) | 🇫🇷 [Français](i18n/fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](i18n/it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](i18n/ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](i18n/de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](i18n/in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](i18n/th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](i18n/uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](i18n/ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](i18n/ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](i18n/vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](i18n/bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](i18n/da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](i18n/fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](i18n/he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](i18n/hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](i18n/ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](i18n/nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](i18n/no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](i18n/pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](i18n/ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](i18n/pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](i18n/sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](i18n/sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](i18n/phi/TROUBLESHOOTING.md)
Common problems and solutions for OmniRoute.
---
## Quick Fixes
| Problem | Solution |
| ----------------------------- | ------------------------------------------------------------------ |
| First login not working | Set `INITIAL_PASSWORD` in `.env` (no hardcoded default) |
| Dashboard opens on wrong port | Set `PORT=20128` and `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
| No request logs under `logs/` | Set `ENABLE_REQUEST_LOGS=true` |
| EACCES: permission denied | Set `DATA_DIR=/path/to/writable/dir` to override `~/.omniroute` |
| Routing strategy not saving | Update to v1.4.11+ (Zod schema fix for settings persistence) |
---
## Provider Issues
### "Language model did not provide messages"
**Cause:** Provider quota exhausted.
**Fix:**
1. Check dashboard quota tracker
2. Use a combo with fallback tiers
3. Switch to cheaper/free tier
### Rate Limiting
**Cause:** Subscription quota exhausted.
**Fix:**
- Add fallback: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
- Use GLM/MiniMax as cheap backup
### OAuth Token Expired
OmniRoute auto-refreshes tokens. If issues persist:
1. Dashboard → Provider → Reconnect
2. Delete and re-add the provider connection
---
## Cloud Issues
### Cloud Sync Errors
1. Verify `BASE_URL` points to your running instance (e.g., `http://localhost:20128`)
2. Verify `CLOUD_URL` points to your cloud endpoint (e.g., `https://omniroute.dev`)
3. Keep `NEXT_PUBLIC_*` values aligned with server-side values
### Cloud `stream=false` Returns 500
**Symptom:** `Unexpected token 'd'...` on cloud endpoint for non-streaming calls.
**Cause:** Upstream returns SSE payload while client expects JSON.
**Workaround:** Use `stream=true` for cloud direct calls. Local runtime includes SSE→JSON fallback.
### Cloud Says Connected but "Invalid API key"
1. Create a fresh key from local dashboard (`/api/keys`)
2. Run cloud sync: Enable Cloud → Sync Now
3. Old/non-synced keys can still return `401` on cloud
---
## Docker Issues
### CLI Tool Shows Not Installed
1. Check runtime fields: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
2. For portable mode: use image target `runner-cli` (bundled CLIs)
3. For host mount mode: set `CLI_EXTRA_PATHS` and mount host bin directory as read-only
4. If `installed=true` and `runnable=false`: binary was found but failed healthcheck
### Quick Runtime Validation
```bash
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
```
---
## Cost Issues
### High Costs
1. Check usage stats in Dashboard → Usage
2. Switch primary model to GLM/MiniMax
3. Use free tier (Gemini CLI, iFlow) for non-critical tasks
4. Set cost budgets per API key: Dashboard → API Keys → Budget
---
## Debugging
### Enable Request Logs
Set `ENABLE_REQUEST_LOGS=true` in your `.env` file. Logs appear under `logs/` directory.
### Check Provider Health
```bash
# Health dashboard
http://localhost:20128/dashboard/health
# API health check
curl http://localhost:20128/api/monitoring/health
```
### Runtime Storage
- Main state: `${DATA_DIR}/storage.sqlite` (providers, combos, aliases, keys, settings)
- Usage: SQLite tables in `storage.sqlite` (`usage_history`, `call_logs`, `proxy_logs`) + optional `${DATA_DIR}/log.txt` and `${DATA_DIR}/call_logs/`
- Request logs: `<repo>/logs/...` (when `ENABLE_REQUEST_LOGS=true`)
---
## Circuit Breaker Issues
### Provider stuck in OPEN state
When a provider's circuit breaker is OPEN, requests are blocked until the cooldown expires.
**Fix:**
1. Go to **Dashboard → Settings → Resilience**
2. Check the circuit breaker card for the affected provider
3. Click **Reset All** to clear all breakers, or wait for the cooldown to expire
4. Verify the provider is actually available before resetting
### Provider keeps tripping the circuit breaker
If a provider repeatedly enters OPEN state:
1. Check **Dashboard → Health → Provider Health** for the failure pattern
2. Go to **Settings → Resilience → Provider Profiles** and increase the failure threshold
3. Check if the provider has changed API limits or requires re-authentication
4. Review latency telemetry — high latency may cause timeout-based failures
---
## Audio Transcription Issues
### "Unsupported model" error
- Ensure you're using the correct prefix: `deepgram/nova-3` or `assemblyai/best`
- Verify the provider is connected in **Dashboard → Providers**
### Transcription returns empty or fails
- Check supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`
- Verify file size is within provider limits (typically < 25MB)
- Check provider API key validity in the provider card
---
## Translator Debugging
Use **Dashboard → Translator** to debug format translation issues:
| Mode | When to Use |
| ---------------- | -------------------------------------------------------------------------------------------- |
| **Playground** | Compare input/output formats side by side — paste a failing request to see how it translates |
| **Chat Tester** | Send live messages and inspect the full request/response payload including headers |
| **Test Bench** | Run batch tests across format combinations to find which translations are broken |
| **Live Monitor** | Watch real-time request flow to catch intermittent translation issues |
### Common format issues
- **Thinking tags not appearing** — Check if the target provider supports thinking and the thinking budget setting
- **Tool calls dropping** — Some format translations may strip unsupported fields; verify in Playground mode
- **System prompt missing** — Claude and Gemini handle system prompts differently; check translation output
- **SDK returns raw string instead of object** — Fixed in v1.1.0: response sanitizer now strips non-standard fields (`x_groq`, `usage_breakdown`, etc.) that cause OpenAI SDK Pydantic validation failures
- **GLM/ERNIE rejects `system` role** — Fixed in v1.1.0: role normalizer automatically merges system messages into user messages for incompatible models
- **`developer` role not recognized** — Fixed in v1.1.0: automatically converted to `system` for non-OpenAI providers
- **`json_schema` not working with Gemini** — Fixed in v1.1.0: `response_format` is now converted to Gemini's `responseMimeType` + `responseSchema`
---
## Resilience Settings
### Auto rate-limit not triggering
- Auto rate-limit only applies to API key providers (not OAuth/subscription)
- Verify **Settings → Resilience → Provider Profiles** has auto-rate-limit enabled
- Check if the provider returns `429` status codes or `Retry-After` headers
### Tuning exponential backoff
Provider profiles support these settings:
- **Base delay** — Initial wait time after first failure (default: 1s)
- **Max delay** — Maximum wait time cap (default: 30s)
- **Multiplier** — How much to increase delay per consecutive failure (default: 2x)
### Anti-thundering herd
When many concurrent requests hit a rate-limited provider, OmniRoute uses mutex + auto rate-limiting to serialize requests and prevent cascading failures. This is automatic for API key providers.
---
## Optional RAG / LLM failure taxonomy (16 problems)
Some OmniRoute users place the gateway in front of RAG or agent stacks. In those setups it is common to see a strange pattern: OmniRoute looks healthy (providers up, routing profiles ok, no rate limit alerts) but the final answer is still wrong.
In practice these incidents usually come from the downstream RAG pipeline, not from the gateway itself.
If you want a shared vocabulary to describe those failures you can use the WFGY ProblemMap, an external MIT license text resource that defines sixteen recurring RAG / LLM failure patterns. At a high level it covers:
- retrieval drift and broken context boundaries
- empty or stale indexes and vector stores
- embedding versus semantic mismatch
- prompt assembly and context window issues
- logic collapse and overconfident answers
- long chain and agent coordination failures
- multi agent memory and role drift
- deployment and bootstrap ordering problems
The idea is simple:
1. When you investigate a bad response, capture:
- user task and request
- route or provider combo in OmniRoute
- any RAG context used downstream (retrieved documents, tool calls, etc)
2. Map the incident to one or two WFGY ProblemMap numbers (`No.1``No.16`).
3. Store the number in your own dashboard, runbook, or incident tracker next to the OmniRoute logs.
4. Use the corresponding WFGY page to decide whether you need to change your RAG stack, retriever, or routing strategy.
Full text and concrete recipes live here (MIT license, text only):
[WFGY ProblemMap README](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
You can ignore this section if you do not run RAG or agent pipelines behind OmniRoute.
---
## Still Stuck?
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **Architecture**: See [`docs/ARCHITECTURE.md`](ARCHITECTURE.md) for internal details
- **API Reference**: See [`docs/API_REFERENCE.md`](API_REFERENCE.md) for all endpoints
- **Health Dashboard**: Check **Dashboard → Health** for real-time system status
- **Translator**: Use **Dashboard → Translator** to debug format issues

813
docs/i18n/bg/USER_GUIDE.md Normal file
View File

@@ -0,0 +1,813 @@
🌐 **Languages:** 🇺🇸 [English](../../README.md) · 🇧🇷 [pt-BR](../pt-BR/USER_GUIDE.md) · 🇪🇸 [es](../es/USER_GUIDE.md) · 🇫🇷 [fr](../fr/USER_GUIDE.md) · 🇩🇪 [de](../de/USER_GUIDE.md) · 🇮🇹 [it](../it/USER_GUIDE.md) · 🇷🇺 [ru](../ru/USER_GUIDE.md) · 🇨🇳 [zh-CN](../zh-CN/USER_GUIDE.md) · 🇯🇵 [ja](../ja/USER_GUIDE.md) · 🇰🇷 [ko](../ko/USER_GUIDE.md) · 🇸🇦 [ar](../ar/USER_GUIDE.md) · 🇮🇳 [in](../in/USER_GUIDE.md) · 🇹🇭 [th](../th/USER_GUIDE.md) · 🇻🇳 [vi](../vi/USER_GUIDE.md) · 🇮🇩 [id](../id/USER_GUIDE.md) · 🇲🇾 [ms](../ms/USER_GUIDE.md) · 🇳🇱 [nl](../nl/USER_GUIDE.md) · 🇵🇱 [pl](../pl/USER_GUIDE.md) · 🇸🇪 [sv](../sv/USER_GUIDE.md) · 🇳🇴 [no](../no/USER_GUIDE.md) · 🇩🇰 [da](../da/USER_GUIDE.md) · 🇫🇮 [fi](../fi/USER_GUIDE.md) · 🇵🇹 [pt](../pt/USER_GUIDE.md) · 🇷🇴 [ro](../ro/USER_GUIDE.md) · 🇭🇺 [hu](../hu/USER_GUIDE.md) · 🇧🇬 [bg](../bg/USER_GUIDE.md) · 🇸🇰 [sk](../sk/USER_GUIDE.md) · 🇺🇦 [uk-UA](../uk-UA/USER_GUIDE.md) · 🇮🇱 [he](../he/USER_GUIDE.md) · 🇵🇭 [phi](../phi/USER_GUIDE.md)
---
# User Guide
🌐 **Languages:** 🇺🇸 [English](USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](i18n/es/USER_GUIDE.md) | 🇫🇷 [Français](i18n/fr/USER_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/USER_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/USER_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/USER_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/USER_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/USER_GUIDE.md) | 🇧🇬 [Български](i18n/bg/USER_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/USER_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/USER_GUIDE.md) | 🇮🇱 [עברית](i18n/he/USER_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/USER_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/USER_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/USER_GUIDE.md) | 🇷🇴 [Română](i18n/ro/USER_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/USER_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/USER_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/USER_GUIDE.md)
Complete guide for configuring providers, creating combos, integrating CLI tools, and deploying OmniRoute.
---
## Table of Contents
- [Pricing at a Glance](#-pricing-at-a-glance)
- [Use Cases](#-use-cases)
- [Provider Setup](#-provider-setup)
- [CLI Integration](#-cli-integration)
- [Deployment](#-deployment)
- [Available Models](#-available-models)
- [Advanced Features](#-advanced-features)
---
## 💰 Pricing at a Glance
| Tier | Provider | Cost | Quota Reset | Best For |
| ------------------- | ----------------- | ----------- | ---------------- | -------------------- |
| **💳 SUBSCRIPTION** | Claude Code (Pro) | $20/mo | 5h + weekly | Already subscribed |
| | Codex (Plus/Pro) | $20-200/mo | 5h + weekly | OpenAI users |
| | Gemini CLI | **FREE** | 180K/mo + 1K/day | Everyone! |
| | GitHub Copilot | $10-19/mo | Monthly | GitHub users |
| **🔑 API KEY** | DeepSeek | Pay per use | None | Cheap reasoning |
| | Groq | Pay per use | None | Ultra-fast inference |
| | xAI (Grok) | Pay per use | None | Grok 4 reasoning |
| | Mistral | Pay per use | None | EU-hosted models |
| | Perplexity | Pay per use | None | Search-augmented |
| | Together AI | Pay per use | None | Open-source models |
| | Fireworks AI | Pay per use | None | Fast FLUX images |
| | Cerebras | Pay per use | None | Wafer-scale speed |
| | Cohere | Pay per use | None | Command R+ RAG |
| | NVIDIA NIM | Pay per use | None | Enterprise models |
| **💰 CHEAP** | GLM-4.7 | $0.6/1M | Daily 10AM | Budget backup |
| | MiniMax M2.1 | $0.2/1M | 5-hour rolling | Cheapest option |
| | Kimi K2 | $9/mo flat | 10M tokens/mo | Predictable cost |
| **🆓 FREE** | iFlow | $0 | Unlimited | 8 models free |
| | Qwen | $0 | Unlimited | 3 models free |
| | Kiro | $0 | Unlimited | Claude free |
**💡 Pro Tip:** Start with Gemini CLI (180K free/month) + iFlow (unlimited free) combo = $0 cost!
---
## 🎯 Use Cases
### Case 1: "I have Claude Pro subscription"
**Problem:** Quota expires unused, rate limits during heavy coding
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (use subscription fully)
2. glm/glm-4.7 (cheap backup when quota out)
3. if/kimi-k2-thinking (free emergency fallback)
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Case 2: "I want zero cost"
**Problem:** Can't afford subscriptions, need reliable AI coding
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K free/month)
2. if/kimi-k2-thinking (unlimited free)
3. qw/qwen3-coder-plus (unlimited free)
Monthly cost: $0
Quality: Production-ready models
```
### Case 3: "I need 24/7 coding, no interruptions"
**Problem:** Deadlines, can't afford downtime
```
Combo: "always-on"
1. cc/claude-opus-4-6 (best quality)
2. cx/gpt-5.2-codex (second subscription)
3. glm/glm-4.7 (cheap, resets daily)
4. minimax/MiniMax-M2.1 (cheapest, 5h reset)
5. if/kimi-k2-thinking (free unlimited)
Result: 5 layers of fallback = zero downtime
Monthly cost: $20-200 (subscriptions) + $10-20 (backup)
```
### Case 4: "I want FREE AI in OpenClaw"
**Problem:** Need AI assistant in messaging apps, completely free
```
Combo: "openclaw-free"
1. if/glm-4.7 (unlimited free)
2. if/minimax-m2.1 (unlimited free)
3. if/kimi-k2-thinking (unlimited free)
Monthly cost: $0
Access via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 📖 Provider Setup
### 🔐 Subscription Providers
#### Claude Code (Pro/Max)
```bash
Dashboard → Providers → Connect Claude Code
→ OAuth login → Auto token refresh
→ 5-hour + weekly quota tracking
Models:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Pro Tip:** Use Opus for complex tasks, Sonnet for speed. OmniRoute tracks quota per model!
#### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Providers → Connect Codex
→ OAuth login (port 1455)
→ 5-hour + weekly reset
Models:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
#### Gemini CLI (FREE 180K/month!)
```bash
Dashboard → Providers → Connect Gemini CLI
→ Google OAuth
→ 180K completions/month + 1K/day
Models:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Best Value:** Huge free tier! Use this before paid tiers.
#### GitHub Copilot
```bash
Dashboard → Providers → Connect GitHub
→ OAuth via GitHub
→ Monthly reset (1st of month)
Models:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
### 💰 Cheap Providers
#### GLM-4.7 (Daily reset, $0.6/1M)
1. Sign up: [Zhipu AI](https://open.bigmodel.cn/)
2. Get API key from Coding Plan
3. Dashboard → Add API Key: Provider: `glm`, API Key: `your-key`
**Use:** `glm/glm-4.7`**Pro Tip:** Coding Plan offers 3× quota at 1/7 cost! Reset daily 10:00 AM.
#### MiniMax M2.1 (5h reset, $0.20/1M)
1. Sign up: [MiniMax](https://www.minimax.io/)
2. Get API key → Dashboard → Add API Key
**Use:** `minimax/MiniMax-M2.1`**Pro Tip:** Cheapest option for long context (1M tokens)!
#### Kimi K2 ($9/month flat)
1. Subscribe: [Moonshot AI](https://platform.moonshot.ai/)
2. Get API key → Dashboard → Add API Key
**Use:** `kimi/kimi-latest`**Pro Tip:** Fixed $9/month for 10M tokens = $0.90/1M effective cost!
### 🆓 FREE Providers
#### iFlow (8 FREE models)
```bash
Dashboard → Connect iFlow → OAuth login → Unlimited usage
Models: if/kimi-k2-thinking, if/qwen3-coder-plus, if/glm-4.7, if/minimax-m2, if/deepseek-r1
```
#### Qwen (3 FREE models)
```bash
Dashboard → Connect Qwen → Device code auth → Unlimited usage
Models: qw/qwen3-coder-plus, qw/qwen3-coder-flash
```
#### Kiro (Claude FREE)
```bash
Dashboard → Connect Kiro → AWS Builder ID or Google/GitHub → Unlimited
Models: kr/claude-sonnet-4.5, kr/claude-haiku-4.5
```
---
## 🎨 Combos
### Example 1: Maximize Subscription → Cheap Backup
```
Dashboard → Combos → Create New
Name: premium-coding
Models:
1. cc/claude-opus-4-6 (Subscription primary)
2. glm/glm-4.7 (Cheap backup, $0.6/1M)
3. minimax/MiniMax-M2.1 (Cheapest fallback, $0.20/1M)
Use in CLI: premium-coding
```
### Example 2: Free-Only (Zero Cost)
```
Name: free-combo
Models:
1. gc/gemini-3-flash-preview (180K free/month)
2. if/kimi-k2-thinking (unlimited)
3. qw/qwen3-coder-plus (unlimited)
Cost: $0 forever!
```
---
## 🔧 CLI Integration
### Cursor IDE
```
Settings → Models → Advanced:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [from omniroute dashboard]
Model: cc/claude-opus-4-6
```
### Claude Code
Edit `~/.claude/config.json`:
```json
{
"anthropic_api_base": "http://localhost:20128/v1",
"anthropic_api_key": "your-omniroute-api-key"
}
```
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
Edit `~/.openclaw/openclaw.json`:
```json
{
"agents": {
"defaults": {
"model": { "primary": "omniroute/if/glm-4.7" }
}
},
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://localhost:20128/v1",
"apiKey": "your-omniroute-api-key",
"api": "openai-completions",
"models": [{ "id": "if/glm-4.7", "name": "glm-4.7" }]
}
}
}
}
```
**Or use Dashboard:** CLI Tools → OpenClaw → Auto-config
### Cline / Continue / RooCode
```
Provider: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [from dashboard]
Model: cc/claude-opus-4-6
```
---
## 🚀 Deployment
### Global npm install (Recommended)
```bash
npm install -g omniroute
# Create config directory
mkdir -p ~/.omniroute
# Create .env file (see .env.example)
cp .env.example ~/.omniroute/.env
# Start server
omniroute
# Or with custom port:
omniroute --port 3000
```
The CLI automatically loads `.env` from `~/.omniroute/.env` or `./.env`.
### VPS Deployment
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute && npm install && npm run build
export JWT_SECRET="your-secure-secret-change-this"
export INITIAL_PASSWORD="your-password"
export DATA_DIR="/var/lib/omniroute"
export PORT="20128"
export HOSTNAME="0.0.0.0"
export NODE_ENV="production"
export NEXT_PUBLIC_BASE_URL="http://localhost:20128"
export API_KEY_SECRET="endpoint-proxy-api-key-secret"
npm run start
# Or: pm2 start npm --name omniroute -- start
```
### PM2 Deployment (Low Memory)
For servers with limited RAM, use the memory limit option:
```bash
# With 512MB limit (default)
pm2 start npm --name omniroute -- start
# Or with custom memory limit
OMNIROUTE_MEMORY_MB=512 pm2 start npm --name omniroute -- start
# Or using ecosystem.config.js
pm2 start ecosystem.config.js
```
Create `ecosystem.config.js`:
```javascript
module.exports = {
apps: [
{
name: "omniroute",
script: "npm",
args: "start",
env: {
NODE_ENV: "production",
OMNIROUTE_MEMORY_MB: "512",
JWT_SECRET: "your-secret",
INITIAL_PASSWORD: "your-password",
},
node_args: "--max-old-space-size=512",
max_memory_restart: "300M",
},
],
};
```
### Docker
```bash
# Build image (default = runner-cli with codex/claude/droid preinstalled)
docker build -t omniroute:cli .
# Portable mode (recommended)
docker run -d --name omniroute -p 20128:20128 --env-file ./.env -v omniroute-data:/app/data omniroute:cli
```
For host-integrated mode with CLI binaries, see the Docker section in the main docs.
### Environment Variables
| Variable | Default | Description |
| ------------------------- | ------------------------------------ | ------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | JWT signing secret (**change in production**) |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `DATA_DIR` | `~/.omniroute` | Data directory (db, usage, logs) |
| `PORT` | framework default | Service port (`20128` in examples) |
| `HOSTNAME` | framework default | Bind host (Docker defaults to `0.0.0.0`) |
| `NODE_ENV` | runtime default | Set `production` for deploy |
| `BASE_URL` | `http://localhost:20128` | Server-side internal base URL |
| `CLOUD_URL` | `https://omniroute.dev` | Cloud sync endpoint base URL |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | HMAC secret for generated API keys |
| `REQUIRE_API_KEY` | `false` | Enforce Bearer API key on `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | Enables request/response logs |
| `AUTH_COOKIE_SECURE` | `false` | Force `Secure` auth cookie (behind HTTPS reverse proxy) |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit in MB |
| `PROMPT_CACHE_MAX_SIZE` | `50` | Max prompt cache entries |
| `SEMANTIC_CACHE_MAX_SIZE` | `100` | Max semantic cache entries |
For the full environment variable reference, see the [README](../README.md).
---
## 📊 Available Models
<details>
<summary><b>View all available models</b></summary>
**Claude Code (`cc/`)** — Pro/Max: `cc/claude-opus-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** — Plus/Pro: `cx/gpt-5.2-codex`, `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** — FREE: `gc/gemini-3-flash-preview`, `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**: `gh/gpt-5`, `gh/claude-4.5-sonnet`
**GLM (`glm/`)** — $0.6/1M: `glm/glm-4.7`
**MiniMax (`minimax/`)** — $0.2/1M: `minimax/MiniMax-M2.1`
**iFlow (`if/`)** — FREE: `if/kimi-k2-thinking`, `if/qwen3-coder-plus`, `if/deepseek-r1`
**Qwen (`qw/`)** — FREE: `qw/qwen3-coder-plus`, `qw/qwen3-coder-flash`
**Kiro (`kr/`)** — FREE: `kr/claude-sonnet-4.5`, `kr/claude-haiku-4.5`
**DeepSeek (`ds/`)**: `ds/deepseek-chat`, `ds/deepseek-reasoner`
**Groq (`groq/`)**: `groq/llama-3.3-70b-versatile`, `groq/llama-4-maverick-17b-128e-instruct`
**xAI (`xai/`)**: `xai/grok-4`, `xai/grok-4-0709-fast-reasoning`, `xai/grok-code-mini`
**Mistral (`mistral/`)**: `mistral/mistral-large-2501`, `mistral/codestral-2501`
**Perplexity (`pplx/`)**: `pplx/sonar-pro`, `pplx/sonar`
**Together AI (`together/`)**: `together/meta-llama/Llama-3.3-70B-Instruct-Turbo`
**Fireworks AI (`fireworks/`)**: `fireworks/accounts/fireworks/models/deepseek-v3p1`
**Cerebras (`cerebras/`)**: `cerebras/llama-3.3-70b`
**Cohere (`cohere/`)**: `cohere/command-r-plus-08-2024`
**NVIDIA NIM (`nvidia/`)**: `nvidia/nvidia/llama-3.3-70b-instruct`
</details>
---
## 🧩 Advanced Features
### Custom Models
Add any model ID to any provider without waiting for an app update:
```bash
# Via API
curl -X POST http://localhost:20128/api/provider-models \
-H "Content-Type: application/json" \
-d '{"provider": "openai", "modelId": "gpt-4.5-preview", "modelName": "GPT-4.5 Preview"}'
# List: curl http://localhost:20128/api/provider-models?provider=openai
# Remove: curl -X DELETE "http://localhost:20128/api/provider-models?provider=openai&model=gpt-4.5-preview"
```
Or use Dashboard: **Providers → [Provider] → Custom Models**.
### Dedicated Provider Routes
Route requests directly to a specific provider with model validation:
```bash
POST http://localhost:20128/v1/providers/openai/chat/completions
POST http://localhost:20128/v1/providers/openai/embeddings
POST http://localhost:20128/v1/providers/fireworks/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
### Network Proxy Configuration
```bash
# Set global proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"global": {"type":"http","host":"proxy.example.com","port":"8080"}}'
# Per-provider proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"providers": {"openai": {"type":"socks5","host":"proxy.example.com","port":"1080"}}}'
# Test proxy
curl -X POST http://localhost:20128/api/settings/proxy/test \
-d '{"proxy":{"type":"socks5","host":"proxy.example.com","port":"1080"}}'
```
**Precedence:** Key-specific → Combo-specific → Provider-specific → Global → Environment.
### Model Catalog API
```bash
curl http://localhost:20128/api/models/catalog
```
Returns models grouped by provider with types (`chat`, `embedding`, `image`).
### Cloud Sync
- Sync providers, combos, and settings across devices
- Automatic background sync with timeout + fail-fast
- Prefer server-side `BASE_URL`/`CLOUD_URL` in production
### LLM Gateway Intelligence (Phase 9)
- **Semantic Cache** — Auto-caches non-streaming, temperature=0 responses (bypass with `X-OmniRoute-No-Cache: true`)
- **Request Idempotency** — Deduplicates requests within 5s via `Idempotency-Key` or `X-Request-Id` header
- **Progress Tracking** — Opt-in SSE `event: progress` events via `X-OmniRoute-Progress: true` header
---
### Translator Playground
Access via **Dashboard → Translator**. Debug and visualize how OmniRoute translates API requests between providers.
| Mode | Purpose |
| ---------------- | -------------------------------------------------------------------------------------- |
| **Playground** | Select source/target formats, paste a request, and see the translated output instantly |
| **Chat Tester** | Send live chat messages through the proxy and inspect the full request/response cycle |
| **Test Bench** | Run batch tests across multiple format combinations to verify translation correctness |
| **Live Monitor** | Watch real-time translations as requests flow through the proxy |
**Use cases:**
- Debug why a specific client/provider combination fails
- Verify that thinking tags, tool calls, and system prompts translate correctly
- Compare format differences between OpenAI, Claude, Gemini, and Responses API formats
---
### Routing Strategies
Configure via **Dashboard → Settings → Routing**.
| Strategy | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------ |
| **Fill First** | Uses accounts in priority order — primary account handles all requests until unavailable |
| **Round Robin** | Cycles through all accounts with a configurable sticky limit (default: 3 calls per account) |
| **P2C (Power of Two Choices)** | Picks 2 random accounts and routes to the healthier one — balances load with awareness of health |
| **Random** | Randomly selects an account for each request using Fisher-Yates shuffle |
| **Least Used** | Routes to the account with the oldest `lastUsedAt` timestamp, distributing traffic evenly |
| **Cost Optimized** | Routes to the account with the lowest priority value, optimizing for lowest-cost providers |
#### Wildcard Model Aliases
Create wildcard patterns to remap model names:
```
Pattern: claude-sonnet-* → Target: cc/claude-sonnet-4-5-20250929
Pattern: gpt-* → Target: gh/gpt-5.1-codex
```
Wildcards support `*` (any characters) and `?` (single character).
#### Fallback Chains
Define global fallback chains that apply across all requests:
```
Chain: production-fallback
1. cc/claude-opus-4-6
2. gh/gpt-5.1-codex
3. glm/glm-4.7
```
---
### Resilience & Circuit Breakers
Configure via **Dashboard → Settings → Resilience**.
OmniRoute implements provider-level resilience with four components:
1. **Provider Profiles** — Per-provider configuration for:
- Failure threshold (how many failures before opening)
- Cooldown duration
- Rate limit detection sensitivity
- Exponential backoff parameters
2. **Editable Rate Limits** — System-level defaults configurable in the dashboard:
- **Requests Per Minute (RPM)** — Maximum requests per minute per account
- **Min Time Between Requests** — Minimum gap in milliseconds between requests
- **Max Concurrent Requests** — Maximum simultaneous requests per account
- Click **Edit** to modify, then **Save** or **Cancel**. Values persist via the resilience API.
3. **Circuit Breaker** — Tracks failures per provider and automatically opens the circuit when a threshold is reached:
- **CLOSED** (Healthy) — Requests flow normally
- **OPEN** — Provider is temporarily blocked after repeated failures
- **HALF_OPEN** — Testing if provider has recovered
4. **Policies & Locked Identifiers** — Shows circuit breaker status and locked identifiers with force-unlock capability.
5. **Rate Limit Auto-Detection** — Monitors `429` and `Retry-After` headers to proactively avoid hitting provider rate limits.
**Pro Tip:** Use **Reset All** button to clear all circuit breakers and cooldowns when a provider recovers from an outage.
---
### Database Export / Import
Manage database backups in **Dashboard → Settings → System & Storage**.
| Action | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| **Export Database** | Downloads the current SQLite database as a `.sqlite` file |
| **Export All (.tar.gz)** | Downloads a full backup archive including: database, settings, combos, provider connections (no credentials), API key metadata |
| **Import Database** | Upload a `.sqlite` file to replace the current database. A pre-import backup is automatically created |
```bash
# API: Export database
curl -o backup.sqlite http://localhost:20128/api/db-backups/export
# API: Export all (full archive)
curl -o backup.tar.gz http://localhost:20128/api/db-backups/exportAll
# API: Import database
curl -X POST http://localhost:20128/api/db-backups/import \
-F "file=@backup.sqlite"
```
**Import Validation:** The imported file is validated for integrity (SQLite pragma check), required tables (`provider_connections`, `provider_nodes`, `combos`, `api_keys`), and size (max 100MB).
**Use Cases:**
- Migrate OmniRoute between machines
- Create external backups for disaster recovery
- Share configurations between team members (export all → share archive)
---
### Settings Dashboard
The settings page is organized into 5 tabs for easy navigation:
| Tab | Contents |
| -------------- | ---------------------------------------------------------------------------------------------- |
| **Security** | Login/Password settings, IP Access Control, API auth for `/models`, and Provider Blocking |
| **Routing** | Global routing strategy (6 options), wildcard model aliases, fallback chains, combo defaults |
| **Resilience** | Provider profiles, editable rate limits, circuit breaker status, policies & locked identifiers |
| **AI** | Thinking budget configuration, global system prompt injection, prompt cache stats |
| **Advanced** | Global proxy configuration (HTTP/SOCKS5) |
---
### Costs & Budget Management
Access via **Dashboard → Costs**.
| Tab | Purpose |
| ----------- | ---------------------------------------------------------------------------------------- |
| **Budget** | Set spending limits per API key with daily/weekly/monthly budgets and real-time tracking |
| **Pricing** | View and edit model pricing entries — cost per 1K input/output tokens per provider |
```bash
# API: Set a budget
curl -X POST http://localhost:20128/api/usage/budget \
-H "Content-Type: application/json" \
-d '{"keyId": "key-123", "limit": 50.00, "period": "monthly"}'
# API: Get current budget status
curl http://localhost:20128/api/usage/budget
```
**Cost Tracking:** Every request logs token usage and calculates cost using the pricing table. View breakdowns in **Dashboard → Usage** by provider, model, and API key.
---
### Audio Transcription
OmniRoute supports audio transcription via the OpenAI-compatible endpoint:
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
# Example with curl
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@audio.mp3" \
-F "model=deepgram/nova-3"
```
Available providers: **Deepgram** (`deepgram/`), **AssemblyAI** (`assemblyai/`).
Supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
### Combo Balancing Strategies
Configure per-combo balancing in **Dashboard → Combos → Create/Edit → Strategy**.
| Strategy | Description |
| ------------------ | ------------------------------------------------------------------------ |
| **Round-Robin** | Rotates through models sequentially |
| **Priority** | Always tries the first model; falls back only on error |
| **Random** | Picks a random model from the combo for each request |
| **Weighted** | Routes proportionally based on assigned weights per model |
| **Least-Used** | Routes to the model with the fewest recent requests (uses combo metrics) |
| **Cost-Optimized** | Routes to the cheapest available model (uses pricing table) |
Global combo defaults can be set in **Dashboard → Settings → Routing → Combo Defaults**.
---
### Health Dashboard
Access via **Dashboard → Health**. Real-time system health overview with 6 cards:
| Card | What It Shows |
| --------------------- | ----------------------------------------------------------- |
| **System Status** | Uptime, version, memory usage, data directory |
| **Provider Health** | Per-provider circuit breaker state (Closed/Open/Half-Open) |
| **Rate Limits** | Active rate limit cooldowns per account with remaining time |
| **Active Lockouts** | Providers temporarily blocked by the lockout policy |
| **Signature Cache** | Deduplication cache stats (active keys, hit rate) |
| **Latency Telemetry** | p50/p95/p99 latency aggregation per provider |
**Pro Tip:** The Health page auto-refreshes every 10 seconds. Use the circuit breaker card to identify which providers are experiencing issues.
---
## 🖥️ Desktop Application (Electron)
OmniRoute is available as a native desktop application for Windows, macOS, and Linux.
### Installation
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Building Installers
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Output → `electron/dist-electron/`
### Key Features
| Feature | Description |
| --------------------------- | ---------------------------------------------------- |
| **Server Readiness** | Polls server before showing window (no blank screen) |
| **System Tray** | Minimize to tray, change port, quit from tray menu |
| **Port Management** | Change server port from tray (auto-restarts server) |
| **Content Security Policy** | Restrictive CSP via session headers |
| **Single Instance** | Only one app instance can run at a time |
| **Offline Mode** | Bundled Next.js server works without internet |
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------- | -------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
📖 Full documentation: [`electron/README.md`](../electron/README.md)

View File

@@ -0,0 +1,401 @@
# OmniRoute — Ръководство за внедряване на VM с Cloudflare
🌐 **Languages:** 🇺🇸 [English](../../VM_DEPLOYMENT_GUIDE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/VM_DEPLOYMENT_GUIDE.md) | 🇪🇸 [Español](../es/VM_DEPLOYMENT_GUIDE.md) | 🇫🇷 [Français](../fr/VM_DEPLOYMENT_GUIDE.md) | 🇮🇹 [Italiano](../it/VM_DEPLOYMENT_GUIDE.md) | 🇷🇺 [Русский](../ru/VM_DEPLOYMENT_GUIDE.md) | 🇨🇳 [中文 (简体)](../zh-CN/VM_DEPLOYMENT_GUIDE.md) | 🇩🇪 [Deutsch](../de/VM_DEPLOYMENT_GUIDE.md) | 🇮🇳 [हिन्दी](../in/VM_DEPLOYMENT_GUIDE.md) | 🇹🇭 [ไทย](../th/VM_DEPLOYMENT_GUIDE.md) | 🇺🇦 [Українська](../uk-UA/VM_DEPLOYMENT_GUIDE.md) | 🇸🇦 [العربية](../ar/VM_DEPLOYMENT_GUIDE.md) | 🇯🇵 [日本語](../ja/VM_DEPLOYMENT_GUIDE.md) | 🇻🇳 [Tiếng Việt](../vi/VM_DEPLOYMENT_GUIDE.md) | 🇧🇬 [Български](../bg/VM_DEPLOYMENT_GUIDE.md) | 🇩🇰 [Dansk](../da/VM_DEPLOYMENT_GUIDE.md) | 🇫🇮 [Suomi](../fi/VM_DEPLOYMENT_GUIDE.md) | 🇮🇱 [עברית](../he/VM_DEPLOYMENT_GUIDE.md) | 🇭🇺 [Magyar](../hu/VM_DEPLOYMENT_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](../id/VM_DEPLOYMENT_GUIDE.md) | 🇰🇷 [한국어](../ko/VM_DEPLOYMENT_GUIDE.md) | 🇲🇾 [Bahasa Melayu](../ms/VM_DEPLOYMENT_GUIDE.md) | 🇳🇱 [Nederlands](../nl/VM_DEPLOYMENT_GUIDE.md) | 🇳🇴 [Norsk](../no/VM_DEPLOYMENT_GUIDE.md) | 🇵🇹 [Português (Portugal)](../pt/VM_DEPLOYMENT_GUIDE.md) | 🇷🇴 [Română](../ro/VM_DEPLOYMENT_GUIDE.md) | 🇵🇱 [Polski](../pl/VM_DEPLOYMENT_GUIDE.md) | 🇸🇰 [Slovenčina](../sk/VM_DEPLOYMENT_GUIDE.md) | 🇸🇪 [Svenska](../sv/VM_DEPLOYMENT_GUIDE.md) | 🇵🇭 [Filipino](../phi/VM_DEPLOYMENT_GUIDE.md) | 🇨🇿 [Čeština](../cs/VM_DEPLOYMENT_GUIDE.md)
Пълно ръководство за инсталиране и конфигуриране на OmniRoute на VM (VPS) с домейн, управляван чрез Cloudflare.
---
## Предпоставки
| Артикул | Минимум | Препоръчва се |
| ---------- | ------------------------ | ---------------- |
| **CPU** | 1 vCPU | 2 vCPU |
| **RAM** | 1 GB | 2 GB |
| **Диск** | 10 GB SSD | 25 GB SSD |
| **OS** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| **Домейн** | Регистриран в Cloudflare | — |
| **Докер** | Docker Engine 24+ | Докер 27+ |
**Тествани доставчици**: Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
---
## 1. Конфигурирайте VM
### 1.1 Създайте екземпляра
На предпочитания от вас VPS доставчик:
- Изберете Ubuntu 24.04 LTS
- Изберете минималния план (1 vCPU / 1 GB RAM)
- Задайте силна root парола или конфигурирайте SSH ключ
- Обърнете внимание на **публичния IP** (напр. `203.0.113.10`)
### 1.2 Свързване чрез SSH
```bash
ssh root@203.0.113.10
```
### 1.3 Актуализирайте системата
```bash
apt update && apt upgrade -y
```
### 1.4 Инсталирайте Docker
```bash
# Install dependencies
apt install -y ca-certificates curl gnupg
# Add official Docker repository
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $ (. /etc/os-release && echo “$VERSION_CODENAME”) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
### 1.5 Инсталирайте nginx
```bash
apt install -y nginx
```
### 1.6 Конфигуриране на защитна стена (UFW)
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP (redirect)
ufw allow 443/tcp # HTTPS
ufw enable
```
> **Съвет**: За максимална сигурност ограничете портове 80 и 443 само до IP адреси на Cloudflare. Вижте раздела [Advanced Security](#advanced-security).
---
## 2. Инсталирайте OmniRoute
### 2.1 Създайте конфигурационна директория
```bash
mkdir -p /opt/omniroute
```
### 2.2 Създайте файл с променливи на средата
```bash
cat > /opt/omniroute/.env << EOF
# === Security ===
JWT_SECRET=CHANGE-TO-A-UNIQUE-64-CHAR-SECRET-KEY
INITIAL_PASSWORD=YourSecurePassword123!
API_KEY_SECRET=REPLACE-WITH-ANOTHER-SECRET-KEY
STORAGE_ENCRYPTION_KEY=REPLACE-WITH-THIRD-SECRET-KEY
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=CHANGE-TO-A-UNIQUE-SALT
# === App ===
PORT=20128
NODE_ENV=production
HOSTNAME=0.0.0.0
DATA_DIR=/app/data
STORAGE_DRIVER=sqlite
ENABLE_REQUEST_LOGS=true
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# === Domain (change to your domain) ===
BASE_URL=https://llms.seudominio.com
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
# === Cloud Sync (optional) ===
# CLOUD_URL=https://cloud.omniroute.online
# NEXT_PUBLIC_CLOUD_URL=https://cloud.omniroute.online
EOF
```
> ⚠️ **ВАЖНО**: Генерирайте уникални секретни ключове! Използвайте `openssl rand -hex 32` за всеки ключ.
### 2.3 Стартирайте контейнера
```bash
docker pull diegosouzapw/omniroute:latest
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### 2.4 Проверете дали работи
```bash
docker ps | grep omniroute
docker logs omniroute --tail 20
```
Трябва да показва: `[DB] SQLite database ready` и `listening on port 20128`.
---
## 3. Конфигурирайте nginx (обратен прокси)
### 3.1 Генериране на SSL сертификат (Cloudflare Origin)
В таблото за управление на Cloudflare:
1. Отидете на **SSL/TLS → Origin Server**
2. Щракнете върху **Създаване на сертификат**
3. Запазете настройките по подразбиране (15 години, \*.yourdomain.com)
4. Копирайте **Сертификата за произход** и **Личния ключ**
```bash
mkdir -p /etc/nginx/ssl
# Paste the certificate
nano /etc/nginx/ssl/origin.crt
# Paste the private key
nano /etc/nginx/ssl/origin.key
chmod 600 /etc/nginx/ssl/origin.key
```
### 3.2 Конфигурация на Nginx
```bash
cat > /etc/nginx/sites-available/omniroute << NGINX
# Default server — blocks direct access via IP
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
server_name _;
return 444;
}
# OmniRoute — HTTPS
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name llms.yourdomain.com; # Change to your domain
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name llms.yourdomain.com;
return 301 https://$server_name$request_uri;
}
NGINX
```
### 3.3 Активиране и тестване
```bash
# Remove default configuration
rm -f /etc/nginx/sites-enabled/default
# Enable OmniRoute
ln -sf /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
# Test and reload
nginx -t && systemctl reload nginx
```
---
## 4. Конфигурирайте Cloudflare DNS
### 4.1 Добавете DNS запис
В таблото за управление на Cloudflare → DNS:
| Тип | Име | Съдържание | Прокси |
| --- | ------ | ---------------------- | ------------ |
| A | `llms` | `203.0.113.10` (VM IP) | ✅ Проксиран |
### 4.2 Конфигурирайте SSL
Под **SSL/TLS → Общ преглед**:
- Режим: **Пълен (строг)**
Под **SSL/TLS → Edge Certificates**:
- Винаги използвайте HTTPS: ✅ Вкл
- Минимална TLS версия: TLS 1.2
- Автоматично пренаписване на HTTPS: ✅ Включено
### 4.3 Тестване
```bash
curl -sI https://llms.seudominio.com/health
# Should return HTTP/2 200
```
---
## 5. Операции и поддръжка
### Надстройте до нова версия
```bash
docker pull diegosouzapw/omniroute:latest
docker stop omniroute && docker rm omniroute
docker run -d --name omniroute --restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### Преглед на регистрационни файлове
```bash
docker logs -f omniroute # Real-time stream
docker logs omniroute --tail 50 # Last 50 lines
```
### Ръчно архивиране на база данни
```bash
# Copy data from the volume to the host
docker cp omniroute:/app/data ./backup-$(date +%F)
# Or compress the entire volume
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine tar czf /backup/omniroute-data-$(date +%F).tar.gz /data
```
### Възстановяване от резервно копие
```bash
docker stop omniroute
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine sh -c “rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /”
docker start omniroute
```
---
## 6. Разширена сигурност
### Ограничете nginx до IP адреси на Cloudflare
```bash
cat > /etc/nginx/cloudflare-ips.conf << CF
# Cloudflare IPv4 ranges — update periodically
# https://www.cloudflare.com/ips-v4/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
CF
```
Добавете следното към `nginx.conf` в блока `http {}`:
```nginx
include /etc/nginx/cloudflare-ips.conf;
```
### Инсталирайте fail2ban
```bash
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
# Check status
fail2ban-client status sshd
```
### Блокирайте директния достъп до порта на Docker
```bash
# Prevent direct external access to port 20128
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
# Persist the rules
apt install -y iptables-persistent
netfilter-persistent save
```
---
## 7. Разположете в Cloudflare Workers (по избор)
За отдалечен достъп чрез Cloudflare Workers (без директно излагане на VM):
```bash
# In the local repository
cd omnirouteCloud
npm install
npx wrangler login
npx wrangler deploy
```
Вижте пълната документация на [omnirouteCloud/README.md](../omnirouteCloud/README.md).
---
## Резюме на порта
| Пристанище | Обслужване | Достъп |
| ---------- | ----------- | ------------------------------ |
| 22 | SSH | Публичен (с fail2ban) |
| 80 | nginx HTTP | Пренасочване → HTTPS |
| 443 | nginx HTTPS | Чрез прокси Cloudflare |
| 20128 | OmniRoute | Само локален хост (чрез nginx) |

196
docs/i18n/cs/A2A-SERVER.md Normal file
View File

@@ -0,0 +1,196 @@
# Dokumentace k serveru OmniRoute A2A
> Protokol Agent-to-Agent v0.3 — OmniRoute jako inteligentní směrovací agent
## Objevování agentů
```bash
curl http://localhost:20128/.well-known/agent.json
```
Vrátí kartu agenta popisující schopnosti, dovednosti a požadavky na ověřování OmniRoute.
---
## Ověřování
Všechny požadavky `/a2a` vyžadují klíč API zadaný prostřednictvím hlavičky `Authorization` :
```
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
```
Pokud na serveru není nakonfigurován žádný klíč API, ověřování se obejde.
---
## Metody JSON-RPC 2.0
### `message/send` — synchronní spuštění
Odešle zprávu dovednosti a čeká na úplnou odpověď.
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a hello world in Python"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
}
}'
```
**Odpověď:**
```json
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task": { "id": "uuid", "state": "completed" },
"artifacts": [{ "type": "text", "content": "..." }],
"metadata": {
"routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
"cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" },
"resilience_trace": [
{ "event": "primary_selected", "provider": "anthropic", "timestamp": "..." }
],
"policy_verdict": { "allowed": true, "reason": "within budget and quota limits" }
}
}
}
```
### `message/stream` — SSE streamování
Stejné jako `message/send` , ale vrací události odeslané serverem pro streamování v reálném čase.
```bash
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}
}'
```
**Události SSE:**
```
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
```
### `tasks/get` — Dotaz na stav úlohy
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'
```
### `tasks/cancel` — Zrušit úkol
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'
```
---
## Dostupné dovednosti
Dovednost | Popis
:-- | :--
`smart-routing` | Směruje výzvy prostřednictvím inteligentního kanálu OmniRoute. Vrací odpověď s vysvětlením směrování, náklady a trasou odolnosti.
`quota-management` | Odpovídá na dotazy v přirozeném jazyce týkající se kvót poskytovatelů, navrhuje bezplatné kombinace a poskytuje hodnocení kvót.
---
## Životní cyklus úkolu
```
submitted → working → completed
→ failed
→ cancelled
```
- Úkoly vyprší po 5 minutách (konfigurovatelné)
- Stavy terminálu: `completed` , `failed` , `cancelled`
- Záznam událostí sleduje každý přechod stavu
---
## Chybové kódy
Kód | Význam
:-- | :--
-32700 | Chyba při analýze (neplatný JSON)
-32600 | Neplatný požadavek / Neautorizovaný
-32601 | Metoda nebo dovednost nenalezena
-32602 | Neplatné parametry
-32603 | Interní chyba
---
## Příklady integrace
### Python (požadavky)
```python
import requests
resp = requests.post("http://localhost:20128/a2a", json={
"jsonrpc": "2.0", "id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Hello"}]
}
}, headers={"Authorization": "Bearer YOUR_KEY"})
result = resp.json()["result"]
print(result["artifacts"][0]["content"])
print(result["metadata"]["routing_explanation"])
```
### TypeScript (načtení)
```typescript
const resp = await fetch("http://localhost:20128/a2a", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_KEY",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "message/send",
params: {
skill: "smart-routing",
messages: [{ role: "user", content: "Hello" }],
},
}),
});
const { result } = await resp.json();
console.log(result.metadata.routing_explanation);
```

View File

@@ -0,0 +1,451 @@
# Referenční informace k API
🌐 **Jazyky:** 🇺🇸 [angličtina](API_REFERENCE.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](i18n/es/API_REFERENCE.md) | 🇫🇷 [Français](i18n/fr/API_REFERENCE.md) | 🇮🇹 [Italiano](i18n/it/API_REFERENCE.md) | 🇷🇺 [Русский](i18n/ru/API_REFERENCE.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](i18n/de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](i18n/in/API_REFERENCE.md) | 🇹🇭 [ไทย](i18n/th/API_REFERENCE.md) | 🇺🇦 [Українська](i18n/uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](i18n/ar/API_REFERENCE.md) | 🇯🇵[日本語](i18n/ja/API_REFERENCE.md)| 🇻🇳 [Tiếng Việt](i18n/vi/API_REFERENCE.md) | 🇧🇬 [Български](i18n/bg/API_REFERENCE.md) | 🇩🇰 [Dánsko](i18n/da/API_REFERENCE.md) | 🇫🇮 [Suomi](i18n/fi/API_REFERENCE.md) | 🇮🇱 [עברית](i18n/he/API_REFERENCE.md) | 🇭🇺 [maďarština](i18n/hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/API_REFERENCE.md) | 🇰🇷 [한국어](i18n/ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/API_REFERENCE.md) | 🇳🇱 [Nizozemsko](i18n/nl/API_REFERENCE.md) | 🇳🇴 [Norsk](i18n/no/API_REFERENCE.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/API_REFERENCE.md) | 🇷🇴 [Română](i18n/ro/API_REFERENCE.md) | 🇵🇱 [Polski](i18n/pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](i18n/sk/API_REFERENCE.md) | 🇸🇪 [Svenska](i18n/sv/API_REFERENCE.md) | 🇵🇭 [Filipínec](i18n/phi/API_REFERENCE.md) | 🇨🇿 [Čeština](i18n/cs/API_REFERENCE.md)
Kompletní referenční příručka pro všechny koncové body rozhraní OmniRoute API.
---
## Obsah
- [Dokončení chatu](#chat-completions)
- [Vložení](#embeddings)
- [Generování obrázků](#image-generation)
- [Seznam modelů](#list-models)
- [Koncové body kompatibility](#compatibility-endpoints)
- [Sémantická mezipaměť](#semantic-cache)
- [Řídicí panel a správa](#dashboard--management)
- [Zpracování žádosti](#request-processing)
- [Ověřování](#authentication)
---
## Dokončení chatu
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### Vlastní záhlaví
Záhlaví | Směr | Popis
--- | --- | ---
`X-OmniRoute-No-Cache` | Žádost | Nastavením na `true` se vynechá mezipaměť
`X-OmniRoute-Progress` | Žádost | Nastaveno na `true` pro události průběhu
`Idempotency-Key` | Žádost | Klíč pro deduplikaci (okno 5 s)
`X-Request-Id` | Žádost | Alternativní klíč pro odstranění duplicitních dat
`X-OmniRoute-Cache` | Odpověď | `HIT` or `MISS` (nestreamované)
`X-OmniRoute-Idempotent` | Odpověď | `true` , pokud je odstraněna duplikace
`X-OmniRoute-Progress` | Odpověď | `enabled` pokud je zapnuto sledování průběhu
---
## Vložení
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
Dostupní poskytovatelé: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## Generování obrázků
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
Dostupní poskytovatelé: OpenAI (DALL-E), xAI (Grok Image), Together AI (FLUX), Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## Seznam modelů
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## Koncové body kompatibility
Metoda | Cesta | Formát
--- | --- | ---
ZVEŘEJNIT | `/v1/chat/completions` | OpenAI
ZVEŘEJNIT | `/v1/messages` | Antropický
ZVEŘEJNIT | `/v1/responses` | Reakce OpenAI
ZVEŘEJNIT | `/v1/embeddings` | OpenAI
ZVEŘEJNIT | `/v1/images/generations` | OpenAI
ZÍSKAT | `/v1/models` | OpenAI
ZVEŘEJNIT | `/v1/messages/count_tokens` | Antropický
ZÍSKAT | `/v1beta/models` | Blíženci
ZVEŘEJNIT | `/v1beta/models/{...path}` | Gemini generuje obsah
ZVEŘEJNIT | `/v1/api/chat` | Ollama
### Vyhrazené trasy poskytovatelů
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
Pokud chybí prefix poskytovatele, automaticky se přidá. Neshodné modely vrátí chybu `400` .
---
## Sémantická mezipaměť
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
Příklad odpovědi:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## Řídicí panel a správa
### Ověřování
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/auth/login` | ZVEŘEJNIT | Přihlášení
`/api/auth/logout` | ZVEŘEJNIT | Odhlásit se
`/api/settings/require-login` | ZÍSKAT/VLOŽIT | Vyžaduje se přepnutí přihlášení
### Správa poskytovatelů
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/providers` | ZÍSKAT/ODESLAT | Seznam / vytvoření poskytovatelů
`/api/providers/[id]` | ZÍSKAT/VLOŽIT/ODSTRANIT | Správa poskytovatele
`/api/providers/[id]/test` | ZVEŘEJNIT | Testovací připojení poskytovatele
`/api/providers/[id]/models` | ZÍSKAT | Seznam modelů poskytovatelů
`/api/providers/validate` | ZVEŘEJNIT | Ověření konfigurace poskytovatele
`/api/provider-nodes*` | Různé | Správa uzlů poskytovatelů
`/api/provider-models` | ZÍSKAT/ODESLAT/SMAZAT | Vlastní modely
### Toky OAuth
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/oauth/[provider]/[action]` | Různé | OAuth specifický pro poskytovatele
### Směrování a konfigurace
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/models/alias` | ZÍSKAT/ODESLAT | Aliasy modelů
`/api/models/catalog` | ZÍSKAT | Všechny modely podle poskytovatele + typu
`/api/combos*` | Různé | Správa kombinací
`/api/keys*` | Různé | Správa klíčů API
`/api/pricing` | ZÍSKAT | Cena modelu
### Využití a analýzy
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/usage/history` | ZÍSKAT | Historie používání
`/api/usage/logs` | ZÍSKAT | Protokoly používání
`/api/usage/request-logs` | ZÍSKAT | Protokoly na úrovni požadavků
`/api/usage/[connectionId]` | ZÍSKAT | Využití na připojení
### Nastavení
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/settings` | ZÍSKAT/VLOŽIT | Obecná nastavení
`/api/settings/proxy` | ZÍSKAT/VLOŽIT | Konfigurace síťového proxy serveru
`/api/settings/proxy/test` | ZVEŘEJNIT | Testovací připojení k proxy serveru
`/api/settings/ip-filter` | ZÍSKAT/VLOŽIT | Seznam povolených/blokovaných IP adres
`/api/settings/thinking-budget` | ZÍSKAT/VLOŽIT | Zdůvodnění rozpočtu tokenů
`/api/settings/system-prompt` | ZÍSKAT/VLOŽIT | Globální systémový výzva
### Monitorování
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/sessions` | ZÍSKAT | Sledování aktivních relací
`/api/rate-limits` | ZÍSKAT | Limity sazeb na účet
`/api/monitoring/health` | ZÍSKAT | Kontrola stavu
`/api/cache` | ZÍSKAT/SMAZAT | Statistiky mezipaměti / vymazat
### Zálohování a export/import
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/db-backups` | ZÍSKAT | Seznam dostupných záloh
`/api/db-backups` | DÁT | Vytvořte ruční zálohu
`/api/db-backups` | ZVEŘEJNIT | Obnovení z konkrétní zálohy
`/api/db-backups/export` | ZÍSKAT | Stáhnout databázi jako soubor .sqlite
`/api/db-backups/import` | ZVEŘEJNIT | Nahrajte soubor .sqlite pro nahrazení databáze
`/api/db-backups/exportAll` | ZÍSKAT | Stáhnout plnou zálohu jako archiv .tar.gz
### Synchronizace s cloudem
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/sync/cloud` | Různé | Operace synchronizace s cloudem
`/api/sync/initialize` | ZVEŘEJNIT | Inicializovat synchronizaci
`/api/cloud/*` | Různé | Správa cloudu
### Nástroje CLI
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/cli-tools/claude-settings` | ZÍSKAT | Stav Clauda CLI
`/api/cli-tools/codex-settings` | ZÍSKAT | Stav příkazového řádku Codexu
`/api/cli-tools/droid-settings` | ZÍSKAT | Stav příkazového řádku Droidu
`/api/cli-tools/openclaw-settings` | ZÍSKAT | Stav rozhraní příkazového řádku OpenClaw
`/api/cli-tools/runtime/[toolId]` | ZÍSKAT | Generické běhové prostředí CLI
Mezi odpovědi CLI patří: `installed` , `runnable` , `command` , `commandPath` , `runtimeMode` , `reason` .
### Agenti ACP
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/acp/agents` | ZÍSKAT | Zobrazit seznam všech detekovaných agentů (vestavěných + vlastních) se stavem
`/api/acp/agents` | ZVEŘEJNIT | Přidat vlastního agenta nebo obnovit mezipaměť detekce
`/api/acp/agents` | VYMAZAT | Odebrání vlastního agenta podle parametru dotazu `id`
Odpověď GET obsahuje `agents[]` (id, name, binary, version, installed, protocol, isCustom) a `summary` (total, installed, notFound, builtIn, custom).
### Odolnost a limity rychlosti
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/resilience` | ZÍSKAT/VLOŽIT | Získání/aktualizace profilů odolnosti
`/api/resilience/reset` | ZVEŘEJNIT | Resetujte jističe
`/api/rate-limits` | ZÍSKAT | Stav limitu sazby na účet
`/api/rate-limit` | ZÍSKAT | Konfigurace globálního limitu rychlosti
### Evals
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/evals` | ZÍSKAT/ODESLAT | Vypsat eval sady / spustit vyhodnocení
### Zásady
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/policies` | ZÍSKAT/ODESLAT/SMAZAT | Správa směrovacích zásad
### Dodržování
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/compliance/audit-log` | ZÍSKAT | Protokol auditu shody (poslední N)
### v1beta (kompatibilní s Gemini)
Koncový bod | Metoda | Popis
--- | --- | ---
`/v1beta/models` | ZÍSKAT | Seznam modelů ve formátu Gemini
`/v1beta/models/{...path}` | ZVEŘEJNIT | Koncový bod Gemini `generateContent`
Tyto koncové body zrcadlí formát API Gemini pro klienty, kteří očekávají nativní kompatibilitu sady Gemini SDK.
### Interní / systémová API
Koncový bod | Metoda | Popis
--- | --- | ---
`/api/init` | ZÍSKAT | Kontrola inicializace aplikace (používá se při prvním spuštění)
`/api/tags` | ZÍSKAT | Tagy modelů kompatibilní s Ollamou (pro klienty Ollamy)
`/api/restart` | ZVEŘEJNIT | Spustit řádný restart serveru
`/api/shutdown` | ZVEŘEJNIT | Spustit řádné vypnutí serveru
> **Poznámka:** Tyto koncové body používá interně systém nebo pro kompatibilitu s klienty Ollama. Koncoví uživatelé je obvykle nevolají.
---
## Přepis zvuku
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
Přepisujte zvukové soubory pomocí Deepgramu nebo AssemblyAI.
**Žádost:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**Odpověď:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**Podporovaní poskytovatelé:** `deepgram/nova-3` , `assemblyai/best` .
**Podporované formáty:** `mp3` , `wav` , `m4a` , `flac` , `ogg` , `webm` .
---
## Kompatibilita s Ollamou
Pro klienty, kteří používají formát API od Ollamy:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
Požadavky jsou automaticky překládány mezi formátem Ollama a interním formátem.
---
## Telemetrie
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**Odpověď:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## Rozpočet
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## Dostupnost modelu
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## Zpracování žádosti
1. Klient odesílá požadavek na `/v1/*`
2. Obslužná rutina trasy volá `handleChat` , `handleEmbedding` , `handleAudioTranscription` nebo `handleImageGeneration`
3. Model je vyřešen (přímý poskytovatel/model nebo alias/kombinace)
4. Přihlašovací údaje vybrané z lokální databáze s filtrováním dostupnosti účtů
5. Pro chat: `handleChatCore` — detekce formátu, překlad, kontrola mezipaměti, kontrola idempotence
6. Prováděcí program poskytovatele odesílá požadavek nadřazenému serveru
7. Odpověď přeložena zpět do klientského formátu (chat) nebo vrácena tak, jak je (vložené prvky/obrázky/zvuk)
8. Zaznamenáno použití/protokolování
9. Záložní metoda se použije na chyby podle pravidel kombinace.
Úplný referenční popis architektury: [`ARCHITECTURE.md`](ARCHITECTURE.md)
---
## Ověřování
- Trasy dashboardu ( `/dashboard/*` ) používají soubor cookie `auth_token`
- Přihlášení používá uložený hash hesla; záložní nastavení je `INITIAL_PASSWORD`
- `requireLogin` lze přepínat přes `/api/settings/require-login`
- Trasy `/v1/*` volitelně vyžadují klíč API nosiče, pokud `REQUIRE_API_KEY=true`

View File

@@ -0,0 +1,782 @@
# Architektura OmniRoute
🌐 **Jazyky:** 🇺🇸 [angličtina](ARCHITECTURE.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](i18n/es/ARCHITECTURE.md) | 🇫🇷 [Français](i18n/fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](i18n/it/ARCHITECTURE.md) | 🇷🇺 [Русский](i18n/ru/ARCHITECTURE.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](i18n/de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](i18n/in/ARCHITECTURE.md) | 🇹🇭 [ไทย](i18n/th/ARCHITECTURE.md) | 🇺🇦 [Українська](i18n/uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](i18n/ar/ARCHITECTURE.md) | 🇯🇵[日本語](i18n/ja/ARCHITECTURE.md)| 🇻🇳 [Tiếng Việt](i18n/vi/ARCHITECTURE.md) | 🇧🇬 [Български](i18n/bg/ARCHITECTURE.md) | 🇩🇰 [Dánsko](i18n/da/ARCHITECTURE.md) | 🇫🇮 [Suomi](i18n/fi/ARCHITECTURE.md) | 🇮🇱 [עברית](i18n/he/ARCHITECTURE.md) | 🇭🇺 [maďarština](i18n/hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/ARCHITECTURE.md) | 🇰🇷 [한국어](i18n/ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/ARCHITECTURE.md) | 🇳🇱 [Nizozemsko](i18n/nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](i18n/no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/ARCHITECTURE.md) | 🇷🇴 [Română](i18n/ro/ARCHITECTURE.md) | 🇵🇱 [Polski](i18n/pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](i18n/sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](i18n/sv/ARCHITECTURE.md) | 🇵🇭 [Filipínec](i18n/phi/ARCHITECTURE.md) | 🇨🇿 [Čeština](i18n/cs/ARCHITECTURE.md)
*Poslední aktualizace: 2026-03-04*
## Shrnutí pro manažery
OmniRoute je lokální směrovací brána a dashboard s umělou inteligencí postavený na Next.js. Poskytuje jeden koncový bod kompatibilní s OpenAI ( `/v1/*` ) a směruje provoz napříč několika upstreamovými poskytovateli s překladem, záložními funkcemi, obnovou tokenů a sledováním využití.
Základní schopnosti:
- API prostředí kompatibilní s OpenAI pro CLI/nástroje (28 poskytovatelů)
- Překlad požadavků/odpovědí napříč formáty poskytovatelů
- Záložní kombinace modelů (sekvence s více modely)
- Záložní řešení na úrovni účtu (více účtů na poskytovatele)
- Správa připojení poskytovatele OAuth + API klíčů
- Generování embeddingů pomocí `/v1/embeddings` (6 poskytovatelů, 9 modelů)
- Generování obrázků pomocí `/v1/images/generations` (4 poskytovatelé, 9 modelů)
- Pro modely uvažování zvažte analýzu tagů ( `<think>...</think>` ).
- Sanitizace odpovědí pro striktní kompatibilitu s OpenAI SDK
- Normalizace rolí (vývojář→systém, systém→uživatel) pro kompatibilitu mezi poskytovateli
- Konverze strukturovaného výstupu (json_schema → Gemini responseSchema)
- Lokální perzistence pro poskytovatele, klíče, aliasy, kombinace, nastavení, ceny
- Sledování využití/nákladů a protokolování požadavků
- Volitelná cloudová synchronizace pro synchronizaci více zařízení/stavů
- Seznam povolených/blokovaných IP adres pro řízení přístupu k API
- Řízení rozpočtu (průchozí/automatické/vlastní/adaptivní)
- Globální systémová výzva k vložení
- Sledování relací a otisky prstů
- Vylepšené omezení sazeb pro jednotlivé účty s profily specifickými pro poskytovatele
- Vzor jističů pro odolnost poskytovatele
- Ochrana stáda proti hromům s uzamčením mutexů
- Mezipaměť pro deduplikaci požadavků založená na podpisech
- Vrstva domény: dostupnost modelu, pravidla nákladů, záložní politika, politika blokování
- Perzistence stavu domény (mezipaměť SQLite pro zápis pro záložní funkce, rozpočty, uzamčení, jističe)
- Modul zásad pro centralizované vyhodnocování požadavků (uzamčení → rozpočet → záložní)
- Vyžádat telemetrii s agregací latence p50/p95/p99
- Korelační ID (X-Request-Id) pro trasování typu end-to-end
- Protokolování auditu shody s předpisy s možností odhlášení pro každý klíč API
- Evaluační rámec pro zajištění kvality LLM
- Řídicí panel uživatelského rozhraní Resilience se stavem jističe v reálném čase
- Modulární poskytovatelé OAuth (12 jednotlivých modulů v adresáři `src/lib/oauth/providers/` )
Primární běhový model:
- Trasy aplikace Next.js v `src/app/api/*` implementují jak API dashboardů, tak i API kompatibility.
- Sdílené jádro SSE/routing v `src/sse/*` + `open-sse/*` zvládá spouštění poskytovatelů, překlad, streamování, záložní operace a využití.
## Rozsah a hranice
### V rozsahu
- Běhové prostředí lokální brány
- Rozhraní API pro správu řídicích panelů
- Ověřování poskytovatele a aktualizace tokenu
- Žádost o překlad a streamování SSE
- Lokální stav + perzistence využití
- Volitelná orchestrace synchronizace s cloudem
### Mimo rozsah
- Implementace cloudové služby za `NEXT_PUBLIC_CLOUD_URL`
- SLA/řídicí rovina poskytovatele mimo lokální proces
- Samotné externí binární soubory CLI (Claude CLI, Codex CLI atd.)
## Kontext systému na vysoké úrovni
```mermaid
flowchart LR
subgraph Clients[Developer Clients]
C1[Claude Code]
C2[Codex CLI]
C3[OpenClaw / Droid / Cline / Continue / Roo]
C4[Custom OpenAI-compatible clients]
BROWSER[Browser Dashboard]
end
subgraph Router[OmniRoute Local Process]
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(storage.sqlite)]
UDB[(usage tables + log artifacts)]
end
subgraph Upstreams[Upstream Providers]
P1[OAuth Providers\nClaude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity]
P2[API Key Providers\nOpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax\nDeepSeek/Groq/xAI/Mistral/Perplexity\nTogether/Fireworks/Cerebras/Cohere/NVIDIA]
P3[Compatible Nodes\nOpenAI-compatible / Anthropic-compatible]
end
subgraph Cloud[Optional Cloud Sync]
CLOUD[Cloud Sync Endpoint\nNEXT_PUBLIC_CLOUD_URL]
end
C1 --> API
C2 --> API
C3 --> API
C4 --> API
BROWSER --> DASH
API --> CORE
DASH --> DB
CORE --> DB
CORE --> UDB
CORE --> P1
CORE --> P2
CORE --> P3
DASH --> CLOUD
```
## Základní běhové komponenty
## 1) API a směrovací vrstva (trasy aplikací Next.js)
Hlavní adresáře:
- `src/app/api/v1/*` a `src/app/api/v1beta/*` pro rozhraní API pro zajištění kompatibility
- `src/app/api/*` pro API pro správu/konfiguraci
- Další přepisy v `next.config.mjs` mapují `/v1/*` na `/api/v1/*`
Důležité způsoby kompatibility:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — obsahuje vlastní modely s `custom: true`
- `src/app/api/v1/embeddings/route.ts` — generování embeddingů (6 poskytovatelů)
- `src/app/api/v1/images/generations/route.ts` — generování obrázků (4+ poskytovatelů včetně Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — vyhrazený chat pro jednotlivé poskytovatele
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — vyhrazená vkládání pro jednotlivé poskytovatele
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — vyhrazené obrazy pro jednotlivé poskytovatele
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
Domény správy:
- Auth/settings: `src/app/api/auth/*` , `src/app/api/settings/*`
- Poskytovatelé/připojení: `src/app/api/providers*`
- Uzly poskytovatele: `src/app/api/provider-nodes*`
- Vlastní modely: `src/app/api/provider-models` (GET/POST/DELETE)
- Katalog modelů: `src/app/api/models/route.ts` (GET)
- Konfigurace proxy: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- Klíče/aliasy/kombinace/ceny: `src/app/api/keys*` , `src/app/api/models/alias` , `src/app/api/combos*` , `src/app/api/pricing`
- Použití: `src/app/api/usage/*`
- Synchronizace/cloud: `src/app/api/sync/*` , `src/app/api/cloud/*`
- Pomocné nástroje pro CLI: `src/app/api/cli-tools/*`
- IP filtr: `src/app/api/settings/ip-filter` (GET/PUT)
- Rozpočet pro myšlení: `src/app/api/settings/thinking-budget` (GET/PUT)
- Systémový příkaz: `src/app/api/settings/system-prompt` (GET/PUT)
- Relace: `src/app/api/sessions` (GET)
- Limity rychlosti: `src/app/api/rate-limits` (GET)
- Odolnost: `src/app/api/resilience` (GET/PATCH) — profily poskytovatelů, jistič, stav limitu rychlosti
- Reset odolnosti: `src/app/api/resilience/reset` (POST) — reset jističů + doby zchlazení
- Statistiky mezipaměti: `src/app/api/cache/stats` (GET/DELETE)
- Dostupnost modelu: `src/app/api/models/availability` (GET/POST)
- Telemetrie: `src/app/api/telemetry/summary` (GET)
- Rozpočet: `src/app/api/usage/budget` (GET/POST)
- Záložní řetězce: `src/app/api/fallback/chains` (GET/POST/DELETE)
- Audit shody: `src/app/api/compliance/audit-log` (GET)
- Evals: `src/app/api/evals` (GET/POST), `src/app/api/evals/[suiteId]` (GET)
- Zásady: `src/app/api/policies` (GET/POST)
## 2) SSE + Překladatelské jádro
Hlavní moduly toku:
- Záznam: `src/sse/handlers/chat.ts`
- Orchestrace jádra: `open-sse/handlers/chatCore.ts`
- Adaptéry pro spuštění poskytovatelů: `open-sse/executors/*`
- Detekce formátu/konfigurace poskytovatele: `open-sse/services/provider.ts`
- Analýza/řešení modelu: `src/sse/services/model.ts` , `open-sse/services/model.ts`
- Logika záložního účtu: `open-sse/services/accountFallback.ts`
- Registr překladů: `open-sse/translator/index.ts`
- Transformace streamů: `open-sse/utils/stream.ts` , `open-sse/utils/streamHandler.ts`
- Extrakce/normalizace využití: `open-sse/utils/usageTracking.ts`
- Analyzátor tagů Think: `open-sse/utils/thinkTagParser.ts`
- Obslužná rutina pro vkládání: `open-sse/handlers/embeddings.ts`
- Registr poskytovatelů vkládání: `open-sse/config/embeddingRegistry.ts`
- Obslužná rutina generování obrázků: `open-sse/handlers/imageGeneration.ts`
- Registr poskytovatelů obrázků: `open-sse/config/imageRegistry.ts`
- Sanitizace odpovědí: `open-sse/handlers/responseSanitizer.ts`
- Normalizace rolí: `open-sse/services/roleNormalizer.ts`
Služby (obchodní logika):
- Výběr/skórování účtu: `open-sse/services/accountSelector.ts`
- Správa životního cyklu kontextu: `open-sse/services/contextManager.ts`
- Vynucení filtrování IP adres: `open-sse/services/ipFilter.ts`
- Sledování relací: `open-sse/services/sessionManager.ts`
- Požadavek na deduplikaci: `open-sse/services/signatureCache.ts`
- Vložení systémového promptu: `open-sse/services/systemPrompt.ts`
- Řízení rozpočtu v duchu myšlenek: `open-sse/services/thinkingBudget.ts`
- Směrování pomocí modelu zástupných znaků: `open-sse/services/wildcardRouter.ts`
- Správa limitů rychlosti: `open-sse/services/rateLimitManager.ts`
- Jistič: `open-sse/services/circuitBreaker.ts`
Moduly doménové vrstvy:
- Dostupnost modelu: `src/lib/domain/modelAvailability.ts`
- Pravidla/rozpočty nákladů: `src/lib/domain/costRules.ts`
- Záložní zásady: `src/lib/domain/fallbackPolicy.ts`
- Kombinovaný resolver: `src/lib/domain/comboResolver.ts`
- Zásady uzamčení: `src/lib/domain/lockoutPolicy.ts`
- Modul zásad: `src/domain/policyEngine.ts` — centralizované uzamčení → rozpočet → vyhodnocení záložního režimu
- Katalog chybových kódů: `src/lib/domain/errorCodes.ts`
- ID požadavku: `src/lib/domain/requestId.ts`
- Časový limit načtení: `src/lib/domain/fetchTimeout.ts`
- Požadovat telemetrii: `src/lib/domain/requestTelemetry.ts`
- Shoda/audit: `src/lib/domain/compliance/index.ts`
- Zkušební běžec: `src/lib/domain/evalRunner.ts`
- Perzistence stavu domény: `src/lib/db/domainState.ts` — SQLite CRUD pro záložní řetězce, rozpočty, historii nákladů, stav uzamčení, jističe
Moduly poskytovatelů OAuth (12 jednotlivých souborů v adresáři `src/lib/oauth/providers/` ):
- Index registru: `src/lib/oauth/providers/index.ts`
- Jednotliví poskytovatelé: `claude.ts` , `codex.ts` , `gemini.ts` , `antigravity.ts` , `iflow.ts` , `qwen.ts` , `kimi-coding.ts` , `github.ts` , `kiro.ts` , `cursor.ts` , `kilocode.ts` , `cline.ts`
- Thin wrapper: `src/lib/oauth/providers.ts` — reexporty z jednotlivých modulů
## 3) Vrstva perzistence
Primární stavová databáze (SQLite):
- Základní infrastruktura: `src/lib/db/core.ts` (better-sqlite3, migrace, WAL)
- Reexportní fasáda: `src/lib/localDb.ts` (tenká vrstva kompatibility pro volající)
- soubor: `${DATA_DIR}/storage.sqlite` (nebo `$XDG_CONFIG_HOME/omniroute/storage.sqlite` pokud je nastaveno, jinak `~/.omniroute/storage.sqlite` )
- entity (tabulky + jmenné prostory KV): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels** , **proxyConfig** , **ipFilter** , **thinkingBudget** , **systemPrompt**
Trvalost používání:
- fasáda: `src/lib/usageDb.ts` (dekomponované moduly v `src/lib/usage/*` )
- SQLite tabulky v `storage.sqlite` : `usage_history` , `call_logs` , `proxy_logs`
- Volitelné artefakty souborů zůstávají pro účely kompatibility/ladění ( `${DATA_DIR}/log.txt` , `${DATA_DIR}/call_logs/` , `<repo>/logs/...` )
- Starší soubory JSON jsou migrovány do SQLite při migracích při spuštění, pokud jsou k dispozici.
Databáze stavu domény (SQLite):
- `src/lib/db/domainState.ts` — CRUD operace pro stav domény
- Tabulky (vytvořené v `src/lib/db/core.ts` ): `domain_fallback_chains` , `domain_budgets` , `domain_cost_history` , `domain_lockout_state` , `domain_circuit_breakers`
- Vzor mezipaměti pro zápis: mapy v paměti jsou autoritativní za běhu; mutace se zapisují synchronně do SQLite; stav se obnovuje z databáze při studeném startu.
## 4) Ověřovací a bezpečnostní povrchy
- Autorizace souborů cookie v dashboardu: `src/proxy.ts` , `src/app/api/auth/login/route.ts`
- Generování/ověření klíče API: `src/shared/utils/apiKey.ts`
- Tajné kódy poskytovatele přetrvávaly v položkách `providerConnections`
- Podpora odchozí proxy přes `open-sse/utils/proxyFetch.ts` (proměnné prostředí) a `open-sse/utils/networkProxy.ts` (konfigurovatelné pro jednotlivé poskytovatele nebo globálně)
## 5) Synchronizace s cloudem
- Inicializace plánovače: `src/lib/initCloudSync.ts` , `src/shared/services/initializeCloudSync.ts`
- Periodická úloha: `src/shared/services/cloudSyncScheduler.ts`
- Řídicí trasa: `src/app/api/sync/cloud/route.ts`
## Životní cyklus požadavku ( `/v1/chat/completions` )
```mermaid
sequenceDiagram
autonumber
participant Client as CLI/SDK Client
participant Route as /api/v1/chat/completions
participant Chat as src/sse/handlers/chat
participant Core as open-sse/handlers/chatCore
participant Model as Model Resolver
participant Auth as Credential Selector
participant Exec as Provider Executor
participant Prov as Upstream Provider
participant Stream as Stream Translator
participant Usage as usageDb
Client->>Route: POST /v1/chat/completions
Route->>Chat: handleChat(request)
Chat->>Model: parse/resolve model or combo
alt Combo model
Chat->>Chat: iterate combo models (handleComboChat)
end
Chat->>Auth: getProviderCredentials(provider)
Auth-->>Chat: active account + tokens/api key
Chat->>Core: handleChatCore(body, modelInfo, credentials)
Core->>Core: detect source format
Core->>Core: translate request to target format
Core->>Exec: execute(provider, transformedBody)
Exec->>Prov: upstream API call
Prov-->>Exec: SSE/JSON response
Exec-->>Core: response + metadata
alt 401/403
Core->>Exec: refreshCredentials()
Exec-->>Core: updated tokens
Core->>Exec: retry request
end
Core->>Stream: translate/normalize stream to client format
Stream-->>Client: SSE chunks / JSON response
Stream->>Usage: extract usage + persist history/log
```
## Kombinovaný + záložní proces pro účet
```mermaid
flowchart TD
A[Incoming model string] --> B{Is combo name?}
B -- Yes --> C[Load combo models sequence]
B -- No --> D[Single model path]
C --> E[Try model N]
E --> F[Resolve provider/model]
D --> F
F --> G[Select account credentials]
G --> H{Credentials available?}
H -- No --> I[Return provider unavailable]
H -- Yes --> J[Execute request]
J --> K{Success?}
K -- Yes --> L[Return response]
K -- No --> M{Fallback-eligible error?}
M -- No --> N[Return error]
M -- Yes --> O[Mark account unavailable cooldown]
O --> P{Another account for provider?}
P -- Yes --> G
P -- No --> Q{In combo with next model?}
Q -- Yes --> E
Q -- No --> R[Return all unavailable]
```
Rozhodnutí o záložních metodách jsou řízena souborem `open-sse/services/accountFallback.ts` s využitím stavových kódů a heuristik chybových zpráv.
## Životní cyklus aktualizace OAuth a onboardingu tokenu
```mermaid
sequenceDiagram
autonumber
participant UI as Dashboard UI
participant OAuth as /api/oauth/[provider]/[action]
participant ProvAuth as Provider Auth Server
participant DB as localDb
participant Test as /api/providers/[id]/test
participant Exec as Provider Executor
UI->>OAuth: GET authorize or device-code
OAuth->>ProvAuth: create auth/device flow
ProvAuth-->>OAuth: auth URL or device code payload
OAuth-->>UI: flow data
UI->>OAuth: POST exchange or poll
OAuth->>ProvAuth: token exchange/poll
ProvAuth-->>OAuth: access/refresh tokens
OAuth->>DB: createProviderConnection(oauth data)
OAuth-->>UI: success + connection id
UI->>Test: POST /api/providers/[id]/test
Test->>Exec: validate credentials / optional refresh
Exec-->>Test: valid or refreshed token info
Test->>DB: update status/tokens/errors
Test-->>UI: validation result
```
Obnovení během živého provozu se provádí uvnitř `open-sse/handlers/chatCore.ts` pomocí exekutoru `refreshCredentials()` .
## Životní cyklus synchronizace s cloudem (Povolit / Synchronizovat / Zakázat)
```mermaid
sequenceDiagram
autonumber
participant UI as Endpoint Page UI
participant Sync as /api/sync/cloud
participant DB as localDb
participant Cloud as External Cloud Sync
participant Claude as ~/.claude/settings.json
UI->>Sync: POST action=enable
Sync->>DB: set cloudEnabled=true
Sync->>DB: ensure API key exists
Sync->>Cloud: POST /sync/{machineId} (providers/aliases/combos/keys)
Cloud-->>Sync: sync result
Sync->>Cloud: GET /{machineId}/v1/verify
Sync-->>UI: enabled + verification status
UI->>Sync: POST action=sync
Sync->>Cloud: POST /sync/{machineId}
Cloud-->>Sync: remote data
Sync->>DB: update newer local tokens/status
Sync-->>UI: synced
UI->>Sync: POST action=disable
Sync->>DB: set cloudEnabled=false
Sync->>Cloud: DELETE /sync/{machineId}
Sync->>Claude: switch ANTHROPIC_BASE_URL back to local (if needed)
Sync-->>UI: disabled
```
Pravidelnou synchronizaci spouští `CloudSyncScheduler` , když je povolen cloud.
## Datový model a mapa úložiště
```mermaid
erDiagram
SETTINGS ||--o{ PROVIDER_CONNECTION : controls
PROVIDER_NODE ||--o{ PROVIDER_CONNECTION : backs_compatible_provider
PROVIDER_CONNECTION ||--o{ USAGE_ENTRY : emits_usage
SETTINGS {
boolean cloudEnabled
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
string id
string provider
string authType
string name
number priority
boolean isActive
string apiKey
string accessToken
string refreshToken
string expiresAt
string testStatus
string lastError
string rateLimitedUntil
json providerSpecificData
}
PROVIDER_NODE {
string id
string type
string name
string prefix
string apiType
string baseUrl
}
MODEL_ALIAS {
string alias
string targetModel
}
COMBO {
string id
string name
string[] models
}
API_KEY {
string id
string name
string key
string machineId
}
USAGE_ENTRY {
string provider
string model
number prompt_tokens
number completion_tokens
string connectionId
string timestamp
}
CUSTOM_MODEL {
string id
string name
string providerId
}
PROXY_CONFIG {
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
Soubory fyzického úložiště:
- primární běhová databáze: `${DATA_DIR}/storage.sqlite`
- řádky protokolu požadavku: `${DATA_DIR}/log.txt` (artefakt kompatibility/ladění)
- Archivy strukturovaných dat volání: `${DATA_DIR}/call_logs/`
- volitelné relace překladače/vyžádání ladění: `<repo>/logs/...`
## Topologie nasazení
```mermaid
flowchart LR
subgraph LocalHost[Developer Host]
CLI[CLI Tools]
Browser[Dashboard Browser]
end
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(storage.sqlite)]
UsageDB[(usage tables + log artifacts)]
end
subgraph External[External Services]
Providers[AI Providers]
SyncCloud[Cloud Sync Service]
end
CLI --> Next
Browser --> Next
Next --> Core
Next --> MainDB
Core --> MainDB
Core --> UsageDB
Core --> Providers
Next --> SyncCloud
```
## Mapování modulů (kritické pro rozhodnutí)
### Moduly tras a API
- `src/app/api/v1/*` , `src/app/api/v1beta/*` : API pro zajištění kompatibility
- `src/app/api/v1/providers/[provider]/*` : vyhrazené trasy pro jednotlivé poskytovatele (chat, vkládání, obrázky)
- `src/app/api/providers*` : CRUD poskytovatele, validace, testování
- `src/app/api/provider-nodes*` : správa uzlů kompatibilních s vlastními nástroji
- `src/app/api/provider-models` : správa vlastních modelů (CRUD)
- `src/app/api/models/route.ts` : API katalogu modelů (aliasy + vlastní modely)
- `src/app/api/oauth/*` : Toky OAuth/kódu zařízení
- `src/app/api/keys*` : životní cyklus lokálního klíče API
- `src/app/api/models/alias` : správa aliasů
- `src/app/api/combos*` : správa záložních kombinací
- `src/app/api/pricing` : přepsání cen pro výpočet nákladů
- `src/app/api/settings/proxy` : konfigurace proxy (GET/PUT/DELETE)
- `src/app/api/settings/proxy/test` : test připojení odchozí proxy (POST)
- `src/app/api/usage/*` : API pro použití a protokoly
- `src/app/api/sync/*` + `src/app/api/cloud/*` : synchronizace s cloudem a pomocníci pro práci s cloudem
- `src/app/api/cli-tools/*` : lokální programy pro zápis/kontrolu konfigurace CLI
- `src/app/api/settings/ip-filter` : Seznam povolených/blokovaných IP adres (GET/PUT)
- `src/app/api/settings/thinking-budget` : konfigurace rozpočtu tokenu thinking (GET/PUT)
- `src/app/api/settings/system-prompt` : globální systémový příkaz (GET/PUT)
- `src/app/api/sessions` : výpis aktivních relací (GET)
- `src/app/api/rate-limits` : stav limitu rychlosti pro účet (GET)
### Směrovací a spouštěcí jádro
- `src/sse/handlers/chat.ts` : parsování požadavků, zpracování kombinací, smyčka výběru účtu
- `open-sse/handlers/chatCore.ts` : překlad, odeslání exekutoru, zpracování opakování/obnovení, nastavení streamu
- `open-sse/executors/*` : chování sítě a formátu specifické pro poskytovatele
### Registr překladů a převodníky formátů
- `open-sse/translator/index.ts` : registr a orchestrace překladačů
- Žádost o překladatele: `open-sse/translator/request/*`
- Překladače odpovědí: `open-sse/translator/response/*`
- Formátovací konstanty: `open-sse/translator/formats.ts`
### Perzistence
- `src/lib/db/*` : perzistentní ukládání konfigurace/stavu a domény v SQLite
- `src/lib/localDb.ts` : reexport kompatibility pro databázové moduly
- `src/lib/usageDb.ts` : fasáda historie použití/záznamů volání nad tabulkami SQLite
## Pokrytí poskytovatele a vykonavatele (strategický vzorec)
Každý poskytovatel má specializovaný exekutor rozšiřující `BaseExecutor` (v `open-sse/executors/base.ts` ), který zajišťuje vytváření URL adres, konstrukci hlaviček, opakování s exponenciálním odkladem, hooky pro obnovení pověření a orchestrační metodu `execute()` .
Vykonavatel | Poskytovatel(é) | Speciální manipulace
--- | --- | ---
`DefaultExecutor` | OpenAI, Claude, Gemini, Qwen, iFlow, OpenRouter, GLM, Kimi, MiniMax, DeepSeek, Groq, xAI, Mistral, Perplexity, Together, Fireworks, Cerebras, Cohere, NVIDIA | Konfigurace dynamické adresy URL/záhlaví pro každého poskytovatele
`AntigravityExecutor` | Google Antigravitace | Vlastní ID projektů/relací, analýza Opakování po
`CodexExecutor` | Kodex OpenAI | Vkládá systémové instrukce, vynucuje úsilí k uvažování
`CursorExecutor` | IDE kurzoru | Protokol ConnectRPC, kódování Protobuf, podepisování požadavků pomocí kontrolního součtu
`GithubExecutor` | GitHub Copilot | Aktualizace tokenu Copilot, hlavičky napodobující VSCode
`KiroExecutor` | AWS CodeWhisperer/Kiro | Binární formát AWS EventStream → konverze SSE
`GeminiCLIExecutor` | Rozhraní příkazového řádku Gemini | Cyklus obnovy tokenu Google OAuth
Všichni ostatní poskytovatelé (včetně uzlů kompatibilních s vlastními funkcemi) používají `DefaultExecutor` .
## Matice kompatibility poskytovatelů
Poskytovatel | Formát | Autorizace | Proud | Nestreamované | Obnovení tokenu | API pro použití
--- | --- | --- | --- | --- | --- | ---
Claude | Claude | Klíč API / OAuth | ✅ | ✅ | ✅ | ⚠️ Pouze pro administrátory
Blíženci | Blíženci | Klíč API / OAuth | ✅ | ✅ | ✅ | ⚠️ Cloudová konzole
Rozhraní příkazového řádku Gemini | gemini-cli | OAuth | ✅ | ✅ | ✅ | ⚠️ Cloudová konzole
Antigravitace | antigravitace | OAuth | ✅ | ✅ | ✅ | ✅ Plná kvóta API
OpenAI | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Kodex | openai-odpovědi | OAuth | ✅ vynucený | ❌ | ✅ | ✅ Limity sazeb
GitHub Copilot | otevřeno | OAuth + token Copilota | ✅ | ✅ | ✅ | ✅ Snímky kvót
Kurzor | kurzor | Vlastní kontrolní součet | ✅ | ✅ | ❌ | ❌
Kiro | Kiro | OIDC pro jednotné přihlašování AWS | ✅ (Stream událostí) | ❌ | ✅ | ✅ Limity použití
Qwen | otevřeno | OAuth | ✅ | ✅ | ✅ | ⚠️ Na vyžádání
iFlow | otevřeno | OAuth (základní) | ✅ | ✅ | ✅ | ⚠️ Na vyžádání
OpenRouter | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
GLM/Kimi/MiniMax | Claude | Klíč API | ✅ | ✅ | ❌ | ❌
Hluboké vyhledávání | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Groq | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
xAI (Grok) | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Mistral | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Zmatek | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Společně s umělou inteligencí | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Ohňostroj s umělou inteligencí | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Mozky | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
Soudržný | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
NVIDIA NIM | otevřeno | Klíč API | ✅ | ✅ | ❌ | ❌
## Pokrytí překladů formátů
Mezi detekované zdrojové formáty patří:
- `openai`
- `openai-responses`
- `claude`
- `gemini`
Cílové formáty zahrnují:
- Chat/Odpovědi v OpenAI
- Claude
- Obálka Gemini/Gemini-CLI/Antigravitace
- Kiro
- Kurzor
Překlady používají **jako ústřední formát OpenAI** všechny konverze procházejí OpenAI jako zprostředkovatel:
```
Source Format → OpenAI (hub) → Target Format
```
Překlady jsou vybírány dynamicky na základě tvaru zdrojového datového obsahu a formátu cílového poskytovatele.
Další vrstvy zpracování v překladovém kanálu:
- **Sanitizace odpovědí** Odstraňuje nestandardní pole z odpovědí ve formátu OpenAI (streamovaných i nestreamovaných), aby byla zajištěna přísná shoda se SDK.
- **Normalizace rolí** — Převádí `developer``system` pro cíle mimo OpenAI; slučuje `system``user` pro modely, které odmítají systémovou roli (GLM, ERNIE)
- **Extrakce tagu Think** — Analyzuje bloky `<think>...</think>` z obsahu do pole `reasoning_content`
- **Strukturovaný výstup** — Převede OpenAI `response_format.json_schema` na `responseMimeType` + `responseSchema` z Gemini.
## Podporované koncové body API
Koncový bod | Formát | Psovod
--- | --- | ---
`POST /v1/chat/completions` | Chat s OpenAI | `src/sse/handlers/chat.ts`
`POST /v1/messages` | Claude Messages | Stejný obslužný program (automaticky detekováno)
`POST /v1/responses` | Reakce OpenAI | `open-sse/handlers/responsesHandler.ts`
`POST /v1/embeddings` | Vkládání OpenAI | `open-sse/handlers/embeddings.ts`
`GET /v1/embeddings` | Seznam modelů | Trasa API
`POST /v1/images/generations` | Obrázky OpenAI | `open-sse/handlers/imageGeneration.ts`
`GET /v1/images/generations` | Seznam modelů | Trasa API
`POST /v1/providers/{provider}/chat/completions` | Chat s OpenAI | Vyhrazené pro každého poskytovatele s ověřováním modelu
`POST /v1/providers/{provider}/embeddings` | Vkládání OpenAI | Vyhrazené pro každého poskytovatele s ověřováním modelu
`POST /v1/providers/{provider}/images/generations` | Obrázky OpenAI | Vyhrazené pro každého poskytovatele s ověřováním modelu
`POST /v1/messages/count_tokens` | Počet žetonů Claude | Trasa API
`GET /v1/models` | Seznam modelů OpenAI | Trasa API (chat + vkládání + obrázek + vlastní modely)
`GET /api/models/catalog` | Katalog | Všechny modely seskupené podle poskytovatele + typu
`POST /v1beta/models/*:streamGenerateContent` | Rodák z Blíženců | Trasa API
`GET/PUT/DELETE /api/settings/proxy` | Konfigurace proxy serveru | Konfigurace síťového proxy serveru
`POST /api/settings/proxy/test` | Připojení proxy serveru | Koncový bod testu stavu/připojení proxy serveru
`GET/POST/DELETE /api/provider-models` | Vlastní modely | Správa vlastních modelů pro každého poskytovatele
## Obejít obslužnou rutinu
Obslužná rutina bypassu ( `open-sse/utils/bypassHandler.ts` ) zachycuje známé „throwaway“ požadavky z Claude CLI warmup pingy, extrakce titulků a počty tokenů a vrací **falešnou odpověď** bez spotřebování tokenů upstreamového poskytovatele. Toto se spustí pouze tehdy, když `User-Agent` obsahuje `claude-cli` .
## Kanál protokolování požadavků
Záznamník požadavků ( `open-sse/utils/requestLogger.ts` ) poskytuje 7stupňový kanál protokolování ladění, ve výchozím nastavení zakázaný a povolený pomocí `ENABLE_REQUEST_LOGS=true` :
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
→ 5_res_provider.txt → 6_res_openai.txt → 7_res_client.txt
```
Soubory se zapisují do `<repo>/logs/<session>/` pro každou relaci požadavku.
## Způsoby selhání a odolnost
## 1) Dostupnost účtu/poskytovatele
- Doba ochlazování účtu poskytovatele při přechodných chybách/chybách rychlosti/autentizace
- záložní účet před selháním požadavku
- záložní kombinovaný model, když je aktuální cesta modelu/poskytovatele vyčerpána
## 2) Platnost tokenu
- předběžná kontrola a obnovení s opakovaným pokusem o obnovení poskytovatelů
- Opakování 401/403 po pokusu o obnovení v hlavní cestě
## 3) Bezpečnost streamu
- streamovací řadič s vědomím odpojení
- překladový proud s vyprázdněním konce proudu a zpracováním `[DONE]`
- Záložní odhad využití, když chybí metadata využití poskytovatele
## 4) Zhoršení cloudové synchronizace
- Zobrazují se chyby synchronizace, ale lokální běhové prostředí pokračuje.
- Plánovač má logiku umožňující opakování, ale periodické provádění v současné době ve výchozím nastavení volá synchronizaci s jedním pokusem.
## 5) Integrita dat
- Migrace schématu SQLite a automatické aktualizace hooků při spuštění
- Cesta kompatibility migrace starší verze JSON → SQLite
## Pozorovatelnost a provozní signály
Zdroje viditelnosti za běhu:
- protokoly konzole ze `src/sse/utils/logger.ts`
- Agregace využití na požadavek v SQLite ( `usage_history` , `call_logs` , `proxy_logs` )
- textový stav požadavku přihlášení `log.txt` (volitelné/kompatibilní)
- volitelné hluboké protokoly požadavků/překladů v `logs/` pokud `ENABLE_REQUEST_LOGS=true`
- Koncové body použití dashboardu ( `/api/usage/*` ) pro spotřebu v uživatelském rozhraní
## Hranice citlivé z hlediska zabezpečení
- Tajný kód JWT ( `JWT_SECRET` ) zajišťuje ověřování/podepisování souborů cookie relace dashboardu.
- Počáteční bootstrap hesla ( `INITIAL_PASSWORD` ) by měl být explicitně nakonfigurován pro zřizování při prvním spuštění.
- Tajný klíč API HMAC ( `API_KEY_SECRET` ) zabezpečuje formát vygenerovaného lokálního klíče API.
- Tajné klíče/tokeny poskytovatele (klíče/tokeny API) jsou uloženy v lokální databázi a měly by být chráněny na úrovni souborového systému.
- Koncové body synchronizace cloudu se spoléhají na sémantiku ověřování klíče API + ID počítače.
## Matice prostředí a běhového prostředí
Proměnné prostředí aktivně používané kódem:
- Aplikace/autentizace: `JWT_SECRET` , `INITIAL_PASSWORD`
- Úložiště: `DATA_DIR`
- Chování kompatibilního uzlu: `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE`
- Volitelné přepsání úložné základny (Linux/macOS, když `DATA_DIR` není nastaveno): `XDG_CONFIG_HOME`
- Bezpečnostní hashování: `API_KEY_SECRET` , `MACHINE_ID_SALT`
- Protokolování: `ENABLE_REQUEST_LOGS`
- Synchronizace/cloudové URL: `NEXT_PUBLIC_BASE_URL` , `NEXT_PUBLIC_CLOUD_URL`
- Odchozí proxy: `HTTP_PROXY` , `HTTPS_PROXY` , `ALL_PROXY` , `NO_PROXY` a varianty s malými písmeny
- Příznaky funkcí SOCKS5: `ENABLE_SOCKS5_PROXY` , `NEXT_PUBLIC_ENABLE_SOCKS5_PROXY`
- Pomocníci pro platformu/běhové prostředí (ne konfigurace specifická pro aplikaci): `APPDATA` , `NODE_ENV` , `PORT` , `HOSTNAME`
## Známé architektonické poznámky
1. `usageDb` a `localDb` sdílejí stejnou základní adresářovou politiku ( `DATA_DIR` -&gt; `XDG_CONFIG_HOME/omniroute` -&gt; `~/.omniroute` ) se starší migrací souborů.
2. `/api/v1/route.ts` deleguje na stejný jednotný nástroj pro tvorbu katalogů, který používá `/api/v1/models` ( `src/app/api/v1/models/catalog.ts` ), aby se zabránilo sémantickému posunu.
3. Pokud je povoleno, zaznamenávač požadavků zapisuje celé záhlaví/tělo; adresář protokolu je považován za citlivý.
4. Chování cloudu závisí na správné adrese `NEXT_PUBLIC_BASE_URL` a dosažitelnosti cloudového koncového bodu.
5. Adresář `open-sse/` je publikován jako **balíček npm workspace** `@omniroute/open-sse` . Zdrojový kód jej importuje přes `@omniroute/open-sse/...` (vyřešeno pomocí `transpilePackages` v Next.js). Cesty k souborům v tomto dokumentu stále používají název adresáře `open-sse/` pro účely konzistence.
6. Grafy v dashboardu používají **Recharts** (založené na SVG) pro přístupné a interaktivní vizualizace analytiky (sloupcové grafy využití modelu, tabulky s rozpisem poskytovatelů s mírou úspěšnosti).
7. E2E testy používají **Playwright** ( `tests/e2e/` ), spouštěné pomocí `npm run test:e2e` . Unit testy používají **Node.js test runner** ( `tests/unit/` ), spouštěné pomocí `npm run test:unit` . Zdrojový kód pod `src/` je **TypeScript** ( `.ts` / `.tsx` ); pracovní prostor `open-sse/` zůstává JavaScript ( `.js` ).
8. Stránka nastavení je uspořádána do 5 záložek: Zabezpečení, Směrování (6 globálních strategií: fill-first, round robin, p2c, náhodné, nejméně používané, nákladově optimalizované), Odolnost (upravitelné limity rychlosti, jistič, zásady), AI (rozpočet promyšlený, systémový výzva, mezipaměť výzev), Pokročilé (proxy).
## Kontrolní seznam provozního ověření
- Sestavení ze zdroje: `npm run build`
- Sestavení obrazu Dockeru: `docker build -t omniroute .`
- Spusťte službu a ověřte:
- `GET /api/settings`
- `GET /api/v1/models`
- Základní URL cíle CLI by měla být `http://<host>:20128/v1` , pokud `PORT=20128`

View File

@@ -0,0 +1,63 @@
# OmniRoute Auto-Combo Engine
> Samosprávné řetězce modelů s adaptivním bodováním
## Jak to funguje
Systém Auto-Combo dynamicky vybírá nejlepšího poskytovatele/model pro každý požadavek pomocí **6faktorové skórovací funkce** :
Faktor | Hmotnost | Popis
:-- | :-- | :--
Kvóta | 0,20 | Zbývající kapacita [0..1]
Zdraví | 0,25 | Jistič: ZAVŘENO=1,0, POLOVINA=0,5, OTEVŘENO=0,0
Náklady na fakturu | 0,20 | Inverzní náklady (levnější = vyšší skóre)
LatencyInv | 0,15 | Inverzní latence p95 (rychlejší = vyšší)
TaskFit | 0,10 | Skóre zdatnost modelu × typu úlohy
Stabilita | 0,10 | Nízká variabilita latence/chyb
## Balíčky módů
Balíček | Soustředit | Hmotnost klíče
:-- | :-- | :--
🚀 **Rychlé odeslání** | Rychlost | latenceInv: 0,35
💰 **Úspora nákladů** | Ekonomika | Náklady na účet: 0,40
🎯 **Kvalita na prvním místě** | Nejlepší model | taskFit: 0,40
📡 **Vhodné pro offline použití** | Dostupnost | kvóta: 0,40
## Samoléčení
- **Dočasné vyloučení** : Skóre &lt; 0,2 → vyloučeno na 5 minut (postupné oddlužování, max. 30 minut)
- **Upozornění na jistič** : OTEVŘENO → automatické vyloučení; POLOVIČNÍ OTEVŘENO → požadavky sondy
- **Režim incidentu** : &gt;50% OTEVŘENO → deaktivovat průzkum, maximalizovat stabilitu
- **Obnova po zchlazení** : Po vyloučení je první požadavek „sonda“ se zkráceným časovým limitem.
## Průzkum banditů
5 % požadavků (konfigurovatelných) je směrováno k náhodným poskytovatelům k prozkoumání. V režimu incidentu je toto nastavení zakázáno.
## API
```bash
# Create auto-combo
curl -X POST http://localhost:20128/api/combos/auto \
-H "Content-Type: application/json" \
-d '{"id":"my-auto","name":"Auto Coder","candidatePool":["anthropic","google","openai"],"modePack":"ship-fast"}'
# List auto-combos
curl http://localhost:20128/api/combos/auto
```
## Úkol Fitness
Více než 30 modelů hodnocených v 6 typech úkolů ( `coding` , `review` , `planning` , `analysis` , `debugging` , `documentation` ). Podporuje zástupné znaky (např. `*-coder` → vysoké skóre kódování).
## Soubory
Soubor | Účel
:-- | :--
`open-sse/services/autoCombo/scoring.ts` | Skórovací funkce a normalizace poolu
`open-sse/services/autoCombo/taskFitness.ts` | Vyhledávání vhodnosti modelu × úkolu
`open-sse/services/autoCombo/engine.ts` | Logika výběru, bandita, rozpočtový strop
`open-sse/services/autoCombo/selfHealing.ts` | Vyloučení, sondy, režim incidentu
`open-sse/services/autoCombo/modePacks.ts` | 4 hmotnostní profily
`src/app/api/combos/auto/route.ts` | REST API

715
docs/i18n/cs/CHANGELOG.md Normal file
View File

@@ -0,0 +1,715 @@
# Seznam změn
## [Nevydané]
---
## [2.7.8] — 18. 3. 2026
> Sprint: Chyba ukládání rozpočtu + funkce kombinovaného agenta v uživatelském rozhraní + oprava zabezpečení tagu omniModel.
### 🐛 Opravy chyb
- **fix(budget)** : „Uložit limity“ již nevrací chybu 422 — `warningThreshold` se nyní správně odesílá jako zlomek (01) místo procenta (0100) (#451)
- **oprava(kombinace)** : interní tag mezipaměti `<omniModel>` je nyní odstraněn před přeposíláním požadavků poskytovatelům, čímž se zabrání přerušení relace mezipaměti (#454)
### ✨ Funkce
- **feat(combos)** : Do modálního okna pro vytváření/úpravy komb přidána sekce Funkce agenta zpřístupnění přepsání `system_message` , `tool_filter_regex` a `context_cache_protection` přímo z dashboardu (#454)
---
## [2.7.7] — 18. 3. 2026
> Sprint: Pád Dockeru pino, oprava workeru Codex CLI responses, synchronizace zámků balíčků.
### 🐛 Opravy chyb
- **oprava(docker)** : `pino-abstract-transport` a `pino-pretty` jsou nyní explicitně kopírovány ve fázi Docker Runner — Samostatné trasování Next.js tyto závislosti peerů přehlíží, což způsobuje pád `Cannot find module pino-abstract-transport` při spuštění (#449)
- **fix(responses)** : Odstranění `initTranslators()` z trasy `/v1/responses` — worker Next.js `the worker has exited` uncaughtException při požadavcích Codex CLI (#450)
### 🔧 Údržba
- **chore(deps)** : `package-lock.json` je nyní commitován při každém upgradu verze, aby se zajistilo, že Docker `npm ci` použije přesné verze závislostí.
---
## [2.7.5] — 18. 3. 2026
> Sprint: Vylepšení uživatelského rozhraní a oprava kontroly stavu rozhraní Windows CLI.
### 🐛 Opravy chyb
- **fix(ux)** : Zobrazit na přihlašovací stránce nápovědu k výchozímu heslu — noví uživatelé nyní pod polem pro zadání hesla vidí `"Default password: 123456"` (#437)
- **fix(cli)** : Claude CLI a další nástroje nainstalované npm jsou nyní správně detekovány jako spustitelné ve Windows — spawn používá `shell:true` k rozpoznání `.cmd` wrapperů přes PATHEXT (#447)
---
## [2.7.4] — 18. 3. 2026
> Sprint: Panel vyhledávacích nástrojů, opravy i18n, limity Copilota, oprava validace Serperu.
### 🚀 Vlastnosti
- **feat(search)** : Přidáno hřiště pro vyhledávání (10. koncový bod), stránka s nástroji pro vyhledávání s porovnáním poskytovatelů/kanálovým přeřazením/historií vyhledávání, lokální směrování pro přeřazení, ochrana autorizace ve vyhledávacím API (#443 od @Regis-RCR)
- Nová trasa: `/dashboard/search-tools`
- Položka postranního panelu v sekci Ladění
- `GET /api/search/providers` a `GET /api/search/stats` s ochranou autorizace
- Lokální směrování provider_nodes pro `/v1/rerank`
- 30+ klíčů i18n ve vyhledávacím jmenném prostoru
### 🐛 Opravy chyb
- **fix(search)** : Oprava normalizátoru Brave News (vracel 0 výsledků), vynucení zkrácení max_results po normalizaci, oprava URL pro načítání stránek z koncových bodů (#443 od @Regis-RCR)
- **fix(analytics)** : Lokalizace popisků dnů/dat v analytických nástrojích — nahrazení pevně zakódovaných portugalských řetězců pomocí `Intl.DateTimeFormat(locale)` (#444 od @hijak)
- **oprava(copilot)** : Oprava zobrazení typu účtu GitHub Copilot, filtrování zavádějících řádků neomezených kvót z dashboardu limitů (#445 od @hijak)
- **oprava(poskytovatelé)** : Zastavit odmítání platných klíčů Serper API odpovědi jiné než 4xx považovat za platné ověřování (#446 od @hijak)
---
## [2.7.3] — 18. 3. 2026
> Sprint: Oprava záložní kvóty pro přímé API Codexu.
### 🐛 Opravy chyb
- **oprava(codex)** : Blokování týdenních vyčerpávajících účtů v přímém záložním rozhraní API (#440)
- Porovnávání prefixů `resolveQuotaWindow()` : `"weekly"` nyní odpovídá klíčům mezipaměti `"weekly (7d)"`
- `applyCodexWindowPolicy()` správně vynucuje přepínání `useWeekly` / `use5h`
- 4 nové regresní testy (celkem 766)
---
## [2.7.2] — 18. 3. 2026
> Sprint: Opravy kontrastu uživatelského rozhraní v režimu Light.
### 🐛 Opravy chyb
- **fix(logs)** : Oprava kontrastu světelného režimu v protokolech požadavků, tlačítek filtrů a kombinovaného odznaku (#378)
- Tlačítka filtrů Chyba/Úspěch/Kombinace jsou nyní čitelná i ve světlém režimu.
- Odznak kombinované řady používá ve světlém režimu silnější fialovou barvu
---
## [2.7.1] — 17. 3. 2026
> Sprint: Sjednocené směrování webového vyhledávání (POST /v1/search) s 5 poskytovateli + opravy zabezpečení Next.js 16.1.7 (6 CVE).
### ✨ Nové funkce
- **feat(search)** : Sjednocené směrování webového vyhledávání — `POST /v1/search` s 5 poskytovateli (Serper, Brave, Perplexity, Exa, Tavily)
- Automatické přepnutí napříč poskytovateli, více než 6 500 bezplatných vyhledávání/měsíc
- Mezipaměť v paměti se slučováním požadavků (konfigurovatelné TTL)
- Dashboard: Karta Analytika vyhledávání v `/dashboard/analytics` s rozpisem poskytovatelů, mírou zásahů do mezipaměti a sledováním nákladů
- Nové API: `GET /api/v1/search/analytics` pro statistiky vyhledávacích požadavků
- Migrace databáze: sloupec `request_type` v `call_logs` pro sledování požadavků mimo chat
- Ověření Zod ( `v1SearchSchema` ), chráněné autorizací, náklady zaznamenány pomocí `recordCost()`
### 🔒 Bezpečnost
- **deps** : Next.js 16.1.6 → 16.1.7 — opravuje 6 CVE:
- **Kritické** : CVE-2026-29057 (pašování HTTP požadavků přes http-proxy)
- **Vysoká** : CVE-2026-27977, CVE-2026-27978 (WebSocket + akce serveru)
- **Médium** : CVE-2026-27979, CVE-2026-27980, CVE-2026-jcc7
### 📁 Nové soubory
Soubor | Účel
--- | ---
`open-sse/handlers/search.ts` | Vyhledávací obslužná rutina s routováním 5 poskytovatelů
`open-sse/config/searchRegistry.ts` | Registr poskytovatelů (autorizace, náklady, kvóta, TTL)
`open-sse/services/searchCache.ts` | Mezipaměť v paměti se slučováním požadavků
`src/app/api/v1/search/route.ts` | Trasa Next.js (POST + GET)
`src/app/api/v1/search/analytics/route.ts` | API pro statistiky vyhledávání
`src/app/(dashboard)/dashboard/analytics/SearchAnalyticsTab.tsx` | Karta analytického panelu
`src/lib/db/migrations/007_search_request_type.sql` | Migrace databáze
`tests/unit/search-registry.test.mjs` | 277 řádků jednotkových testů
---
## [2.7.0] — 17. 3. 2026
> Sprint: Funkce inspirované ClawRouterem příznak volání toolCalling, vícejazyčná detekce záměru, benchmarkem řízený fallback, deduplikace požadavků, plugin RouterStrategy, ceny Grok-4 Fast + GLM-5 + MiniMax M2.5 + Kimi K2.5.
### ✨ Nové modely a ceny
- **feat. (ceny)** : xAI Grok-4 Fast — `$0.20/$0.50 per 1M tokens` , latence 1143 ms p50, podpora volání nástrojů
- **feat. (ceny)** : xAI Grok-4 (standardní) — `$0.20/$1.50 per 1M tokens` , což je důvodem k odmítnutí.
- **výkon (ceny)** : GLM-5 přes Z.AI — `$0.5/1M` , 128 tisíc výstupních kontextů
- **výkon (ceny)** : MiniMax M2.5 — `$0.30/1M input` , uvažování + agentní úkoly
- **feat.(ceny)** : DeepSeek V3.2 — aktualizované ceny `$0.27/$1.10 per 1M`
- **výkon (cena)** : Kimi K2.5 přes Moonshot API — přímý přístup k Moonshot API
- **feat(providers)** : Přidán poskytovatel Z.AI (alias `zai` ) — rodina GLM-5 s výstupem 128K
### 🧠 Směrovací inteligence
- **feat(registry)** : příznak `toolCalling` pro každý model v registru poskytovatelů kombinace nyní mohou preferovat/vyžadovat modely s možností volání nástrojů
- **feat(scoring)** : Detekce vícejazyčného záměru pro skórování AutoCombo — skriptové/jazykové vzory PT/ZH/ES/AR ovlivňují výběr modelu podle kontextu požadavku
- **feat(fallback)** : Řetězce záložních metod řízené benchmarky — skutečná data o latenci (p50 z `comboMetrics` ) používaná k dynamickému přeskupení priorit záložních metod
- **feat(dedup)** : Vyžádání deduplikace pomocí content-hash — 5sekundové okno idempotence zabraňuje duplicitním voláním poskytovatele v opakovaném pokusu o odeslání klientům
- **feat(router)** : Připojitelné rozhraní `RouterStrategy` v `autoCombo/routerStrategy.ts` — lze vložit vlastní logiku směrování bez úpravy jádra
### 🔧 Vylepšení serveru MCP
- **feat(mcp)** : 2 nová pokročilá schémata nástrojů: `omniroute_get_provider_metrics` (p50/p95/p99 na poskytovatele) a `omniroute_explain_route` (vysvětlení rozhodnutí o směrování)
- **feat(mcp)** : Aktualizovány rozsahy autorizace nástroje MCP přidán rozsah `metrics:read` pro nástroje pro metriky poskytovatelů
- **feat(mcp)** : `omniroute_best_combo_for_task` nyní akceptuje parametr `languageHint` pro vícejazyčné směrování
### 📊 Pozorovatelnost
- **feat(metrics)** : Soubor `comboMetrics.ts` rozšířen o sledování percentilů latence v reálném čase pro každého poskytovatele/účet.
- **feat(health)** : Rozhraní Health API ( `/api/monitoring/health` ) nyní vrací pole `p50Latency` a `errorRate` pro každého poskytovatele.
- **feat(usage)** : Migrace historie použití pro sledování latence pro jednotlivé modely
### 🗄️ Migrace databází
- **feat(migrations)** : Nový sloupec `latency_p50` v tabulce `combo_metrics` — nulový, bezpečný pro stávající uživatele
### 🐛 Opravy chyb / Uzavření
- **close(#411)** : rozlišení hašovaných modulů better-sqlite3 ve Windows — opraveno ve verzi 2.6.10 (f02c5b5)
- **close(#409)** : Dokončení chatu GitHub Copilot selhává u modelů Claude při připojení souborů opraveno ve verzi 2.6.9 (838f1d6)
- **close(#405)** : Duplikát #411 vyřešeno
## [2.6.10] — 17. 3. 2026
> Oprava pro Windows: stažení předkompilovaného better-sqlite3 bez node-gyp/Pythonu/MSVC (#426).
### 🐛 Opravy chyb
- **fix(install/#426)** : Ve Windows dříve selhával příkaz `npm install -g omniroute` s `better_sqlite3.node is not a valid Win32 application` , protože přiložený nativní binární soubor byl zkompilován pro Linux. Přidává **strategii 1.5** do `scripts/postinstall.mjs` : používá `@mapbox/node-pre-gyp install --fallback-to-build=false` (přiloženo v rámci `better-sqlite3` ) ke stažení správného předkompilovaného binárního souboru pro aktuální OS/arch bez nutnosti použití jakýchkoli nástrojů pro sestavení (žádný node-gyp, žádný Python, žádný MSVC). Vrací se k `npm rebuild` pouze v případě, že stahování selže. Přidává chybové zprávy specifické pro platformu s jasnými pokyny k ruční opravě.
---
## [2.6.9] — 17. 3. 2026
> Opravy CI (t11 s libovolným rozpočtem), oprava chyby č. 409 (souborové přílohy přes Copilot+Claude), korekce pracovního postupu vydání.
### 🐛 Opravy chyb
- **fix(ci)** : Odstranění slova „any“ z komentářů v `openai-responses.ts` a `chatCore.ts` , které neprošly kontrolou rozpočtu t11 `\bany\b` (falešně pozitivní výsledek z počítání regexů v komentářích).
- **oprava(chatCore)** : Normalizovat nepodporované typy částí obsahu před přeposláním poskytovatelům (#409 — Kurzor odesílá `{type:"file"}` když jsou připojeny soubory `.md` ; Copilot a další poskytovatelé kompatibilní s OpenAI odmítají s "type musí být buď 'image_url', nebo 'text'"; oprava převádí bloky `file` / `document` na `text` a odstraňuje neznámé typy)
### 🔧 Pracovní postup
- **chore(generate-release)** : Přidat pravidlo pro atomický commit — navýšení verze ( `npm version patch` ) MUSÍ proběhnout před commitem souborů funkcí, aby se zajistilo, že tag vždy ukazuje na commit obsahující všechny změny verzí dohromady.
---
## [2.6.8] — 17. 3. 2026
> Sprint: Kombinace jako agent (systémový příkaz + filtr nástrojů), ochrana kontextového ukládání do mezipaměti, automatická aktualizace, podrobné protokoly, MITM Kiro IDE.
### 🗄️ Migrace databází (bez nutnosti aktualizace bezpečné pro stávající uživatele)
- **005_combo_agent_fields.sql** : `ALTER TABLE combos ADD COLUMN system_message TEXT DEFAULT NULL` , `tool_filter_regex TEXT DEFAULT NULL` , `context_cache_protection INTEGER DEFAULT 0`
- **006_detailed_request_logs.sql** : Nová tabulka `request_detail_logs` s triggerem kruhového bufferu s 500 záznamy, možnost přihlášení přes přepínač nastavení
### ✨ Funkce
- **feat(combo)** : Přepsání systémových zpráv pro Combo (#399 — pole `system_message` nahrazuje nebo vkládá systémový výzvu před přesměrováním poskytovateli)
- **feat(combo)** : Regulární výraz filtru nástrojů pro každou kombinaci (#399`tool_filter_regex` uchovává pouze nástroje odpovídající vzoru; podporuje formáty OpenAI + Anthropic)
- **feat(combo)** : Ochrana před ukládáním do mezipaměti kontextu (#401`context_cache_protection` označuje odpovědi s `<omniModel>provider/model</omniModel>` a modelem pins pro zajištění kontinuity relace)
- **feat(settings)** : Automatická aktualizace přes Nastavení (#320`GET /api/system/version` + `POST /api/system/update` — kontroluje registr npm a aktualizuje na pozadí s restartem pm2)
- **feat(logs)** : Podrobné protokoly požadavků (#378 — zachycuje kompletní těla procesů ve 4 fázích: požadavek klienta, přeložený požadavek, odpověď poskytovatele, odpověď klienta — přepínání přihlášení, ořezávání na 64 kB, kruhová vyrovnávací paměť s 500 záznamy)
- **feat(mitm)** : Profil MITM Kiro IDE (#336`src/mitm/targets/kiro.ts` cílí na api.anthropic.com, znovu využívá stávající infrastrukturu MITM)
---
## [2.6.7] — 17. 3. 2026
> Sprint: Vylepšení SSE, rozšíření lokálních provider_nodes, registr proxy, opravy Claude passthrough.
### ✨ Funkce
- **feat(health)** : Kontrola stavu lokálních `provider_nodes` na pozadí s exponenciálním zpožděním (30s→300s) a `Promise.allSettled` pro zamezení blokování (#423, @Regis-RCR)
- **feat(embeddings)** : Směrování `/v1/embeddings` do lokálních uzlů `provider_nodes``buildDynamicEmbeddingProvider()` s ověřením názvu hostitele (#422, @Regis-RCR)
- **feat(audio)** : Směrování TTS/STT do lokálních `provider_nodes``buildDynamicAudioProvider()` s ochranou SSRF (#416, @Regis-RCR)
- **feat(proxy)** : Registr proxy, API pro správu a zobecnění limitů kvót (#429, @Regis-RCR)
### 🐛 Opravy chyb
- **fix(sse)** : Odstranění polí specifických pro Claude ( `metadata` , `anthropic_version` ), pokud je cíl kompatibilní s OpenAI (#421, @prakersh)
- **fix(sse)** : Extrahuje využití Claude SSE ( `input_tokens` , `output_tokens` , cache tokeny) v režimu průchozího streamu (#420, @prakersh)
- **fix(sse)** : Generování záložního `call_id` pro volání nástrojů s chybějícími/prázdnými ID (#419, @prakersh)
- **oprava(sse)** : Průchod mezi Claudey a Claudey — přední tělo zcela nedotčeno, bez opětovného překladu (#418, @prakersh)
- **fix(sse)** : Filtrovat osiřelé položky `tool_result` po zhuštění kontextu Claude Code, aby se zabránilo chybám 400 (#417, @prakersh)
- **fix(sse)** : Přeskočit volání nástrojů s prázdnými názvy v překladači Responses API, aby se zabránilo nekonečným smyčkám `placeholder_tool` (#415, @prakersh)
- **fix(sse)** : Odstranění prázdných bloků textového obsahu před překladem (#427, @prakersh)
- **fix(api)** : Přidáno `refreshable: true` do testovací konfigurace Claude OAuth (#428, @prakersh)
### 📦 Závislosti
- Zvýšení `vitest` , `@vitest/*` a související devDependencies (#414, @dependabot)
---
## [2.6.6] — 17. 3. 2026
> Oprava: Kompatibilita s Turbopackem/Dockerem — odebrání protokolu `node:` ze všech importů `src/` .
### 🐛 Opravy chyb
- **fix(build)** : Z příkazů `import` v 17 souborech v `src/` byl odstraněn prefix `node:` protocol. Importy `node:fs` , `node:path` , `node:url` , `node:os` atd. způsobovaly, že `Ecmascript file had an error` v sestaveních Turbopack (Next.js 15 Docker) a při upgradech ze starších globálních instalací npm. Dotčené soubory: `migrationRunner.ts` , `core.ts` , `backup.ts` , `prompts.ts` , `dataPaths.ts` a 12 dalších v `src/app/api/` a `src/lib/` .
- **chore(workflow)** : Aktualizován `generate-release.md` , aby synchronizace Docker Hubu a nasazení duálního VPS zahrnovaly **povinné** kroky v každé verzi.
---
## [2.6.5] — 17. 3. 2026
> Sprint: filtrování parametrů modelu uvažování, oprava chyby 404 lokálního poskytovatele, poskytovatel Kilo Gateway, vylepšení závislostí.
### ✨ Nové funkce
- **feat(api)** : Přidán **Kilo Gateway** ( `api.kilo.ai` ) jako nový poskytovatel API klíčů (alias `kg` ) — více než 335 modelů, 6 bezplatných modelů, 3 modely automatického směrování ( `kilo-auto/frontier` , `kilo-auto/balanced` , `kilo-auto/free` ). Průchozí modely podporovány přes endpoint `/api/gateway/models` . (PR #408 od @Regis-RCR)
### 🐛 Opravy chyb
- **fix(sse)** : Odstranění nepodporovaných parametrů pro modely uvažování (o1, o1-mini, o1-pro, o3, o3-mini). Modely v rodině `o1` / `o3` odmítají `temperature` , `top_p` , `frequency_penalty` , `presence_penalty` , `logprobs` , `top_logprobs` a `n` s HTTP 400. Parametry jsou nyní odstraňovány na vrstvě `chatCore` před přeposíláním. Používá deklarativní pole `unsupportedParams` pro každý model a předpočítanou mapu O(1) pro vyhledávání. (PR #412 od @Regis-RCR)
- **fix(sse)** : Kód 404 lokálního poskytovatele nyní vede k **uzamčení pouze modelu (5 sekund)** namísto uzamčení na úrovni připojení (2 minuty). Když lokální inferenční backend (Ollama, LM Studio, oMLX) vrátí kód 404 pro neznámý model, připojení zůstane aktivní a ostatní modely okamžitě pokračují v práci. Také opravuje již existující chybu, kdy `model` nebyl předán funkci `markAccountUnavailable()` . Lokální poskytovatelé detekováni pomocí názvu hostitele ( `localhost` , `127.0.0.1` , `::1` , rozšiřitelné pomocí proměnné prostředí `LOCAL_HOSTNAMES` ). (PR #410 od @Regis-RCR)
### 📦 Závislosti
- `better-sqlite3` 12.6.2 → 12.8.0
- `undici` 7.24.2 → 7.24.4
- `https-proxy-agent` 7 → 8
- `agent-base` 7 → 8
---
## [2.6.4] — 17. 3. 2026
### 🐛 Opravy chyb
- **fix(providers)** : Odstraněny neexistující názvy modelů u 5 poskytovatelů:
- **gemini / gemini-cli** : odstraněny `gemini-3.1-pro/flash` a `gemini-3-*-preview` (neexistují v Google API v1beta); nahrazeny `gemini-2.5-pro` , `gemini-2.5-flash` , `gemini-2.0-flash` , `gemini-1.5-pro/flash`
- **antigravity** : odstraněny `gemini-3.1-pro-high/low` a `gemini-3-flash` (neplatné interní aliasy); nahrazeny skutečnými modely z verze 2.x
- **github (Copilot)** : odstraněny `gemini-3-flash-preview` a `gemini-3-pro-preview` ; nahrazeny `gemini-2.5-flash`
- **nvidia** : opraveno `nvidia/llama-3.3-70b-instruct``meta/llama-3.3-70b-instruct` (NVIDIA NIM používá pro modely Meta jmenný prostor `meta/` /); přidány `nvidia/llama-3.1-70b-instruct` a `nvidia/llama-3.1-405b-instruct`
- **fix(db/combo)** : Aktualizováno `free-stack` combo na vzdálené databázi: odstraněno `qw/qwen3-coder-plus` (prošlý obnovovací token), opraveno `nvidia/llama-3.3-70b-instruct``nvidia/meta/llama-3.3-70b-instruct` , opraveno `gemini/gemini-3.1-flash``gemini/gemini-2.5-flash` , přidáno `if/deepseek-v3.2`
---
## [2.6.3] — 16. 3. 2026
> Sprint: hash-strip zod/pino zapečený do build pipeline, přidán syntetický poskytovatel, opravena cesta VPS PM2.
### 🐛 Opravy chyb
- **fix(build)** : Turbopack hash-strip se nyní spouští při **kompilaci** pro VŠECHNY balíčky — nejen `better-sqlite3` . Krok 5.6 v `prepublish.mjs` prochází každý `.js` v `app/.next/server/` a odstraňuje 16znakovou hexadecimální příponu z jakékoli hashované `require()` . Opravuje `zod-dcb22c...` , `pino-...` atd. MODULE_NOT_FOUND u globálních instalací npm. Zavírá #398.
- **Oprava (nasazení)** : PM2 na obou VPS ukazoval na zastaralé adresáře git-clone. V globálním balíčku npm překonfigurováno na `app/server.js` . Aktualizován pracovní postup `/deploy-vps` pro použití `npm pack + scp` (registr npm odmítá balíčky o velikosti 299 MB).
### ✨ Funkce
- **feat(provider)** : Synthetic ( [synthetic.new](https://synthetic.new) ) — inference kompatibilní s OpenAI zaměřená na soukromí. `passthroughModels: true` pro dynamický katalog modelů HuggingFace. Počáteční modely: Kimi K2.5, MiniMax M2.5, GLM 4.7, DeepSeek V3.2. (PR #404 od @Regis-RCR)
### 📋 Problémy uzavřeny
- **zavřít #398** : regrese hashování npm — opraveno hashováním při kompilaci v prepublish
- **triáž č. 324** : Snímek obrazovky s chybou bez kroků požadovány podrobnosti o reprodukci
---
## [2.6.2] — 16. 3. 2026
> Sprint: hashování modulů kompletně opraveno, sloučeny 2 PR (filtr Anthropic tools + vlastní cesty k endpointům), přidán poskytovatel Alibaba Cloud DashScope, uzavřeny 3 zastaralé problémy.
### 🐛 Opravy chyb
- **fix(build)** : Rozšířeno hashování `externals` webpacku tak, aby zahrnovalo VŠECHNY `serverExternalPackages` , nejen `better-sqlite3` . Next.js 16 Turbopack hashuje `zod` , `pino` a všechny ostatní externí balíčky serveru do názvů jako `zod-dcb22c6336e0bc69` , které za běhu v `node_modules` neexistují. HASH_PATTERN regex catch-all nyní odstraňuje 16znakovou příponu a vrací se k základnímu názvu balíčku. Také přidána `NEXT_PRIVATE_BUILD_WORKER=0` v `prepublish.mjs` pro posílení režimu webpacku a následné skenování po sestavení, které hlásí všechny zbývající hashované reference. (#396, #398, PR #403)
- **fix(chat)** : Názvy nástrojů v anthropic formátu ( `tool.name` bez wrapperu `.function` ) byly tiše vynechány filtrem prázdných názvů zavedeným v bodě #346. LiteLLM proxyuje požadavky s prefixem `anthropic/` ve formátu Anthropic Messages API, což způsobuje filtrování všech nástrojů a Anthropic vrací chybu `400: tool_choice.any may only be specified while providing tools` . Opraveno návratem k `tool.name` , když chybí `tool.function.name` . Přidáno 8 regresních jednotkových testů. (PR #397)
### ✨ Funkce
- **feat(api)** : Vlastní cesty koncových bodů pro uzly poskytovatelů kompatibilní s OpenAI — konfigurace `chatPath` a `modelsPath` pro každý uzel (např. `/v4/chat/completions` ) v uživatelském rozhraní pro připojení poskytovatele. Zahrnuje migraci databáze ( `003_provider_node_custom_paths.sql` ) a sanitizaci cesty URL (bez `..` traversal, musí začínat znakem `/` ). (PR #400)
- **feat(provider)** : Alibaba Cloud DashScope přidán jako poskytovatel kompatibilní s OpenAI. Mezinárodní endpoint: `dashscope-intl.aliyuncs.com/compatible-mode/v1` . 12 modelů: `qwen-max` , `qwen-plus` , `qwen-turbo` , `qwen3-coder-plus/flash` , `qwq-plus` , `qwq-32b` , `qwen3-32b` , `qwen3-235b-a22b` . Autorizace: Nosný API klíč.
### 📋 Problémy uzavřeny
- **zavřít #323** : Chyba připojení Cline `[object Object]` opraveno ve verzi 2.3.7; uživateli bylo doručeno pokyny k upgradu z verze 2.2.9
- **zavřít #337** : Sledování úvěru Kiro — implementováno ve verzi 2.5.5 (#381); odkázalo uživatele na Dashboard → Použití
- **triage #402** : Poškozený soubor ARM64 macOS DMG požadovaná verze macOS, přesná chyba a doporučené alternativní řešení `xattr -d com.apple.quarantine`
---
## [2.6.1] — 15. 3. 2026
> Kritická oprava při spuštění: Globální instalace npm v2.6.0 havarovaly s chybou 500 kvůli chybě hashování názvů modulů Turbopack/webpack v instrumentačním hooku Next.js 16.
### 🐛 Opravy chyb
- **fix(build)** : Vynutit, aby byl `better-sqlite3` vždy vyžadován přesným názvem balíčku v balíčku webpack server. Next.js 16 zkompiloval instrumentační hook do samostatného chunku a vygeneroval `require('better-sqlite3-<hash>')` — hashovaný název modulu, který neexistuje v `node_modules` — přestože byl balíček uveden v `serverExternalPackages` . Do konfigurace webpacku serveru byla přidána explicitní funkce `externals` , takže bundler vždy vygeneruje `require('better-sqlite3')` , čímž se vyřeší `500 Internal Server Error` při spuštění čistých globálních instalací. (#394, PR #395)
### 🔧 CI
- **ci** : Do `npm-publish.yml` přidána `workflow_dispatch` se zabezpečením synchronizace verzí pro manuální spouštěče (#392).
- **ci** : Přidán `workflow_dispatch` do `docker-publish.yml` , aktualizovány akce GitHubu na nejnovější verze (#392)
---
## [2.6.0] - 15. 3. 2026
> Sprint řešení problémů: Opraveny 4 chyby, vylepšeno uživatelské rozhraní protokolů, přidáno sledování kreditů Kiro.
### 🐛 Opravy chyb
- **oprava(média)** : ComfyUI a SD WebUI se již nezobrazují v seznamu poskytovatelů na stránce Média, pokud nejsou nakonfigurovány — při připojení načtou `/api/providers` a skryjí lokální poskytovatele bez připojení (#390)
- **oprava(auth)** : Round-robin již po zpoždění znovu nevybírá účty s omezenou rychlostí ihned `backoffLevel` se nyní používá jako primární třídicí klíč v rotaci LRU (#340)
- **oprava(oauth)** : iFlow (a další poskytovatelé, kteří přesměrovávají na své vlastní uživatelské rozhraní) již nenechávají modální okno OAuth zaseknuté na „Čekání na autorizaci“ detektor zavřených vyskakovacích oken automaticky přechází do režimu ručního zadávání URL (#344)
- **oprava(logy)** : Tabulka protokolů požadavků je nyní čitelná ve světlém režimu stavové odznaky, počty tokenů a kombinované tagy používají adaptivní `dark:` barevné třídy (#378)
### ✨ Funkce
- **feat(kiro)** : Do fetcheru využití přidáno sledování kreditů Kiro — dotazy `getUserCredits` z endpointu AWS CodeWhisperer (#337)
### 🛠 Domácí práce
- **chore(tests)** : Zarovnání `test:plan3` , `test:fixes` , `test:security` pro použití stejného zavaděče `tsx/esm` jako u `npm test` eliminuje falešně negativní výsledky rozlišení modulů v cílených bězích (PR #386)
---
## [2.5.9] - 15. 3. 2026
> Oprava nativní passthrough Codexu + posílení validace těla trasy.
### 🐛 Opravy chyb
- **fix(codex)** : Zachovává nativní průchod Responses API pro klienty Codexu zabraňuje zbytečným mutacím překladu (PR #387)
- **fix(api)** : Ověřování těl požadavků na trasách pro stanovení cen/synchronizaci a směrování úloh zabraňuje pádům způsobeným chybně formátovanými vstupy (PR #388)
- **fix(auth)** : Tajné hodnoty JWT přetrvávají i po restartech pomocí `src/lib/db/secrets.ts` — eliminuje chyby 401 po restartu PM2 (PR #388)
---
## [2.5.8] - 15. 3. 2026
> Oprava sestavení: obnovení připojení VPS přerušeného nedokončeným publikováním v2.5.7.
### 🐛 Opravy chyb
- **oprava(build)** : `scripts/prepublish.mjs` se stále používají, zastaralý příznak `--webpack` způsobuje tiché selhání samostatného sestavení Next.js — publikování npm dokončeno bez `app/server.js` , což narušuje nasazení VPS
---
## [2.5.7] - 15. 3. 2026
> Opravy chyb při zpracování v Media Playground.
### 🐛 Opravy chyb
- **oprava(média)** : Přepis „Vyžadován klíč API“ falešně pozitivní, pokud zvuk neobsahuje žádnou řeč (hudba, ticho) nyní se místo toho zobrazuje „Není detekována žádná řeč“
- **oprava(media)** : `upstreamErrorResponse` v `audioTranscription.ts` a `audioSpeech.ts` nyní vrací správný JSON ( `{error:{message}}` ), což umožňuje správnou detekci chyb přihlašovacích údajů 401/403 v MediaPageClient
- **oprava(média)** : `parseApiError` nyní zpracovává pole `err_msg` v Deepgramu a detekuje `"api key"` v chybových zprávách pro přesnou klasifikaci chyb přihlašovacích údajů.
---
## [2.5.6] - 15. 3. 2026
> Kritické opravy zabezpečení/autentizace: OAuth v Antigravity nefunkční + relace JWT ztraceny po restartu.
### 🐛 Opravy chyb
- **fix(oauth) #384** : Antigravity Google OAuth nyní správně odesílá `client_secret` do koncového bodu tokenu. Záložní volbou pro `ANTIGRAVITY_OAUTH_CLIENT_SECRET` byl prázdný řetězec, což je chyba `client_secret` tedy nebyl v požadavku nikdy zahrnut, což způsobovalo chyby `"client_secret is missing"` u všech uživatelů bez vlastní proměnné prostředí. Zavírá #383.
- **fix(auth) #385** : `JWT_SECRET` je nyní ukládán do SQLite ( `namespace='secrets'` ) při první generaci a znovu načten při následných spuštěních. Dříve byl při každém spuštění procesu generován nový náhodný tajný klíč, který po jakémkoli restartu nebo upgradu zneplatňoval všechny existující soubory cookie/relace. Ovlivňuje `JWT_SECRET` i `API_KEY_SECRET` . Zavírá #382.
---
## [2.5.5] - 15. 3. 2026
> Oprava odstranění duplicitních dat v seznamu modelů, posílení samostatného sestavení Electronu a sledování kreditů Kiro.
### 🐛 Opravy chyb
- **fix(models) #380** : `GET /api/models` nyní zahrnuje aliasy poskytovatelů při sestavování filtru aktivního poskytovatele — modely pro `claude` (alias `cc` ) a `github` (alias `gh` ) se vždy zobrazovaly bez ohledu na to, zda bylo nakonfigurováno připojení, protože klíče `PROVIDER_MODELS` jsou aliasy, ale připojení k databázi jsou uložena pod ID poskytovatelů. Opraveno rozšířením každého aktivního ID poskytovatele o jeho alias pomocí `PROVIDER_ID_TO_ALIAS` . Zavírá #353.
- **fix(electron) #379** : Nové `scripts/prepare-electron-standalone.mjs` připraví vyhrazený balíček `/.next/electron-standalone` před zabalením Electronu. Pokud je `node_modules` symbolický odkaz, dojde k ukončení s chybou (electron-builder by na sestavovací stroj odeslal běhovou závislost). Multiplatformní sanitizace cest pomocí `path.basename` . Od @kfiramar.
### ✨ Nové funkce
- **feat(kiro) #381** : Sledování zůstatku kreditů Kiro — koncový bod využití nyní vrací data o kreditech pro Kiro účty voláním `codewhisperer.us-east-1.amazonaws.com/getUserCredits` (stejný koncový bod, který Kiro IDE používá interně). Vrací zbývající kredity, celkový limit, datum obnovení a úroveň předplatného. Uzavírá #337.
## [2.5.4] - 15. 3. 2026
> Oprava spouštění loggeru, oprava zabezpečení přihlašovacího bootstrapu a vylepšení spolehlivosti vývojářského HMR. Zlepšení infrastruktury CI.
### 🐛 Opravy chyb (PR #374, #375, #376 od @kfiramar)
- **oprava(logger) #376** : Obnovit cestu k protokolovacímu modulu pino transport — `formatters.level` v kombinaci s `transport.targets` je odmítnut modulem pino. Konfigurace založené na transportu nyní odstraňují formátovač úrovní pomocí funkce `getTransportCompatibleConfig()` . Také opravuje numerické mapování úrovní v `/api/logs/console` : `30→info, 40→warn, 50→error` (bylo posunuto o jednu).
- **oprava(login) #375** : Přihlašovací stránka se nyní bootuje z veřejného endpointu `/api/settings/require-login` namísto chráněného `/api/settings` . V nastaveních chráněných heslem dostávala stránka předběžného ověřování chybu 401 a zbytečně se vracela k bezpečným výchozím hodnotám. Veřejná trasa nyní vrací všechna bootstrapová metadata ( `requireLogin` , `hasPassword` , `setupComplete` ) s konzervativní fallback chybou 200.
- **oprava(dev) #374** : Přidání `localhost` a `127.0.0.1` do `allowedDevOrigins` v `next.config.mjs` — HMR websocket byl blokován při přístupu k aplikaci přes loopback adresu, což opakovaně produkovalo varování cross-origin.
### 🔧 CI a infrastruktura
- **Oprava chyb ESLint OOM** : `eslint.config.mjs` nyní ignoruje `vscode-extension/**` , `electron/**` , `docs/**` , `app/.next/**` a `clipr/**` — ESLint havaroval s chybou JS haldy OOM skenováním binárních blobů a kompilovaných chunků VS Code.
- **Oprava jednotkového testu** : Z 2 testovacích souborů byl odstraněn zastaralý `ALTER TABLE provider_connections ADD COLUMN "group"` sloupec je nyní součástí základního schématu (přidáno v #373), což způsobovalo `SQLITE_ERROR: duplicate column name` při každém spuštění CI.
- **Pre-commit hook** : Do `.husky/pre-commit` přidán `npm run test:unit` — unit testy nyní blokují poškozené commity dříve, než se dostanou do CI.
## [2.5.3] - 14. 3. 2026
> Opravy kritických chyb: migrace schématu databáze, načítání spouštěcího prostředí, mazání chyb poskytovatele a oprava popisků i18n. Vylepšení kvality kódu nad každým PR.
### 🐛 Opravy chyb (PR #369, #371, #372, #373 od @kfiramar)
- **oprava(db) #373** : Přidání sloupce `provider_connections.group` do základního schématu + migrace zpětného doplnění pro existující databáze — sloupec byl použit ve všech dotazech, ale chyběl v definici schématu
- **fix(i18n) #371** : Nahrazení neexistujícího klíče `t("deleteConnection")` existujícím `providers.delete` — oprava `MISSING_MESSAGE: providers.deleteConnection` na stránce s podrobnostmi o poskytovateli
- **oprava(auth) #372** : Vymazat zastaralá chybová metadata ( `errorCode` , `lastErrorType` , `lastErrorSource` ) z účtů poskytovatelů po skutečném zotavení dříve se obnovené účty zobrazovaly jako selhané
- **oprava(startup) #369** : Sjednocení načítání env napříč `npm run start` , `run-standalone.mjs` a Electron s ohledem na prioritu `DATA_DIR/.env → ~/.omniroute/.env → ./.env` — zabránění generování nového `STORAGE_ENCRYPTION_KEY` přes existující šifrovanou databázi
### 🔧 Kvalita kódu
- Zdokumentované vzory `result.success` vs. `response?.ok` v `auth.ts` (oba úmyslné, nyní vysvětlené)
- Normalizované `overridePath?.trim()` v `electron/main.js` pro shodu s `bootstrap-env.mjs`
- Přidán komentář k objednávce sloučení `preferredEnv` při spuštění Electronu
> Oprava kvót pro účty Codex s automatickou rotací, rychlým přepínáním úrovní, modelem gpt-5.4 a označením analytických nástrojů.
### ✨ Nové funkce (PR #366, #367, #368)
- **Zásady kvót Codexu (PR #366)** : Okno kvóty 5 hodin/týden pro účet se přepíná v dashboardu poskytovatele. Účty jsou automaticky přeskočeny, když povolená okna dosáhnou prahové hodnoty 90 %, a znovu povoleny po `resetAt` . Zahrnuje `quotaCache.ts` s vedlejším efektem pro získávání statusu zdarma.
- **Přepínání rychlé úrovně Codexu (PR #367)** : Dashboard → Nastavení → Úroveň služeb Codexu. Přepínání ve výchozím nastavení vkládá `service_tier: "flex"` pouze pro požadavky Codexu, což snižuje náklady o ~80 %. Celý stack: karta UI + koncový bod API + exekutor + překladač + obnovení po spuštění.
- **Model gpt-5.4 (PR #368)** : Přidává `cx/gpt-5.4` a `codex/gpt-5.4` do registru modelů Codex. Regresní test je součástí.
### 🐛 Opravy chyb
- **oprava č. 356** : Analytické grafy (Nejlepší poskytovatel, Podle účtu, Rozdělení poskytovatelů) nyní zobrazují lidsky čitelné názvy/štítky poskytovatelů namísto nezpracovaných interních ID u poskytovatelů kompatibilních s OpenAI.
> Hlavní vydání: strategie striktně náhodného směrování, řízení přístupu k klíčům API, skupiny připojení, synchronizace externích cen a opravy kritických chyb pro modely myšlení, kombinované testování a validaci názvů nástrojů.
### ✨ Nové funkce (PR #363 a #365)
- **Strategie striktně náhodného směrování** : Fisher-Yatesův náhodný balíček s garancí neopakování a serializací mutexů pro souběžné požadavky. Nezávislé balíčky pro každé kombo a providera.
- **Řízení přístupu ke klíčům API** : `allowedConnections` (omezení připojení, která může klíč používat), `is_active` (povolení/zakázání klíče s kódem 403), `accessSchedule` (řízení přístupu na základě času), přepínání `autoResolve` , přejmenování klíčů pomocí PATCH.
- **Skupiny připojení** : Seskupování připojení poskytovatelů podle prostředí. Harmonické zobrazení na stránce Limity s perzistencí localStorage a inteligentním automatickým přepínáním.
- **Synchronizace externích cen (LiteLLM)** : 3stupňové rozlišení cen (uživatelské přepsání → synchronizace → výchozí hodnoty). Možnost přihlášení přes `PRICING_SYNC_ENABLED=true` . Nástroj MCP `omniroute_sync_pricing` . 23 nových testů.
- **i18n** : 30 jazyků aktualizováno strategií striktní náhodnosti, řetězce pro správu klíčů API. pt-BR plně přeloženo.
### 🐛 Opravy chyb
- **Oprava č. 355** : Časový limit nečinnosti streamu zvýšen z 60 s na 300 s zabraňuje přerušení modelů s rozšířeným myšlením (claude-opus-4-6, o3 atd.) během dlouhých fází uvažování. Konfigurovatelné pomocí `STREAM_IDLE_TIMEOUT_MS` .
- **Oprava č. 350** : Kombinovaný test nyní obchází `REQUIRE_API_KEY=true` pomocí interní hlavičky a univerzálně používá formát kompatibilní s OpenAI. Časový limit prodloužen z 15 s na 20 s.
- **oprava #346** : Nástroje s prázdným `function.name` (přeposláno Claudem Code) jsou nyní filtrovány předtím, než je obdrží upstreamoví poskytovatelé, čímž se zabrání chybám „Neplatný vstup[N].name: prázdný řetězec“.
### 🗑️ Uzavřené problémy
- **#341** : Sekce ladění odstraněna nahrazena je `/dashboard/logs` a `/dashboard/health` .
> Podpora API Key Round-Robin pro nastavení poskytovatelů s více klíči a potvrzení již zavedeného směrování zástupných znaků a rolování oken kvót.
### ✨ Nové funkce
- **Round-Robin klíčů API (T07)** : Připojení poskytovatelů nyní mohou obsahovat více klíčů API (Upravit připojení → Další klíče API). Požadavky rotují round-robin mezi primárními a dalšími klíči pomocí `providerSpecificData.extraApiKeys[]` . Klíče jsou uchovávány v paměti indexované pro každé připojení nejsou nutné žádné změny schématu databáze.
### 📝 Již implementováno (potvrzeno auditem)
- **Směrování modelu s wildcard znaky (T13)** : soubor `wildcardRouter.ts` s porovnáváním zástupných znaků ve stylu glob ( `gpt*` , `claude-?-sonnet` atd.) je již integrován do `model.ts` s hodnocením specificity.
- **Posunování okna kvót (T08)** : `accountFallback.ts:isModelLocked()` již automaticky posouvá okno vpřed pokud `Date.now() > entry.until` , zámek se okamžitě smaže (žádné blokování zastaralých funkcí).
> Vylepšení uživatelského rozhraní, doplnění strategií směrování a elegantní zpracování chyb pro omezení využití.
### ✨ Nové funkce
- **Strategie směrování Fill-First a P2C** : Do výběru kombinované strategie přidány strategie `fill-first` (vyčerpání kvóty před přesunem) a `p2c` (výběr Power-of-Two-Choices s nízkou latencí) s kompletními panely s pokyny a barevně odlišenými odznaky.
- **Přednastavené modely Free Stack** : Vytvoření kombinace pomocí šablony Free Stack nyní automaticky vyplní 7 nejlepších modelů bezplatných poskytovatelů ve své třídě (Gemini CLI, Kiro, iFlow×2, Qwen, NVIDIA NIM, Groq). Uživatelé stačí aktivovat poskytovatele a ihned získají kombinaci 0 $/měsíc.
- **Širší kombo modální okno** : Modální okno pro vytvoření/úpravu komba nyní používá `max-w-4xl` pro pohodlnou úpravu velkých komb.
### 🐛 Opravy chyb
- **Stránka s limity HTTP 500 pro Codex a GitHub** : `getCodexUsage()` a `getGitHubUsage()` nyní vracejí uživatelsky přívětivou zprávu, když poskytovatel vrátí 401/403 (vypršelý token), místo aby vyvolaly chybu 500 na stránce s limity.
- **Falešně pozitivní MaintenanceBanner** : Banner již při načítání stránky falešně nezobrazuje „Server je nedostupný“. Opraveno okamžitým voláním `checkHealth()` při připojení a odstraněním zastaralého uzavření `show` -state.
- **Popisky ikon poskytovatele** : Tlačítka s ikonami pro úpravu (tužka) a odstranění v řádku připojení poskytovatele nyní obsahují nativní HTML popisky všech 6 ikon akcí je nyní samodokumentovaných.
> Několik vylepšení z analýzy problémů komunity, podpora nových poskytovatelů, opravy chyb pro sledování tokenů, směrování modelů a spolehlivost streamování.
### ✨ Nové funkce
- **Inteligentní směrování s ohledem na úlohy (T05)** : Automatický výběr modelu na základě typu obsahu požadavku — kódování → deepseek-chat, analýza → gemini-2.5-pro, vision → gpt-4o, sumarizace → gemini-2.5-flash. Konfigurovatelné v Nastavení. Nové API `GET/PUT/POST /api/settings/task-routing` .
- **Poskytovatel HuggingFace** : Přidán HuggingFace Router jako poskytovatel kompatibilní s OpenAI s Llama 3.1 70B/8B, Qwen 2.5 72B, Mistral 7B, Phi-3.5 Mini.
- **Poskytovatel Vertex AI** : Přidán poskytovatel Vertex AI (Google Cloud) s Gemini 2.5 Pro/Flash, Gemma 2 27B, Claude přes Vertex.
- **Nahrávání souborů do Playgroundu** : Nahrávání zvuku pro přepis, nahrávání obrázků pro modely vidění (automatická detekce podle názvu modelu), inline vykreslování obrázků pro výsledky generování obrázků.
- **Vizuální zpětná vazba při výběru modelu** : Již přidané modely v kombinovaném výběru nyní zobrazují zelený odznak ✓ zabraňuje záměně duplicitních modelů.
- **Kompatibilita s Qwen (PR #352)** : Aktualizováno nastavení otisků uživatelského agenta a rozhraní CLI pro kompatibilitu s poskytovateli Qwen.
- **Správa stavu round-robin (PR #349)** : Vylepšená logika round-robin pro zpracování vyloučených účtů a správné udržování stavu rotace.
- **Uživatelská zkušenost se schránkou (PR #360)** : Vylepšené operace se schránkou s možností zálohování pro nezabezpečené kontexty; vylepšení normalizace nástroje Claude.
### 🐛 Opravy chyb
- **Oprava č. 302 OpenAI SDK stream=False zanechává tool_calls** : T01 Accept header negotiation již nevynucuje streamování, pokud je `body.stream` explicitně `false` . Způsobovalo to tiché zanechávání tool_calls při použití OpenAI Python SDK v režimu bez streamování.
- **Oprava č. 73 — Claude Haiku směrován do OpenAI bez prefixu poskytovatele** : modely `claude-*` odeslané bez prefixu poskytovatele nyní správně směrují k poskytovateli `antigravity` (antropickému). Přidána také heuristika `gemini-*` / `gemma-*``gemini` .
- **Oprava č. 74 Počet tokenů je pro streamování Antigravity/Claude vždy 0** : Událost SSE `message_start` , která obsahuje `input_tokens` nebyla analyzována funkcí `extractUsage()` , což způsobovalo pokles všech počtů vstupních tokenů. Sledování vstupních/výstupních tokenů nyní funguje správně pro streamované odpovědi.
- **Oprava č. 180 Duplikáty importovaných modelů bez zpětné vazby** : `ModelSelectModal` nyní zobrazuje ✓ zelené zvýraznění u modelů, které jsou již v kombinaci, takže je zřejmé, že jsou již přidány.
- **Chyby generování mediálních stránek** : Výsledky obrázků se nyní vykreslují jako tagy `<img>` místo nezpracovaného JSON. Výsledky přepisu se zobrazují jako čitelný text. Chyby přihlašovacích údajů zobrazují oranžový banner místo tiché chyby.
- **Tlačítko pro obnovení tokenu na stránce poskytovatele** : Pro poskytovatele OAuth bylo přidáno uživatelské rozhraní pro ruční obnovení tokenu.
### 🔧 Vylepšení
- **Registr poskytovatelů** : Do `providerRegistry.ts` a `providers.ts` (frontend) přidány prvky HuggingFace a Vertex AI.
- **Čtení mezipaměti** : Nový `src/lib/db/readCache.ts` pro efektivní ukládání do mezipaměti čtení databáze.
- **Mezipaměť kvót** : Vylepšená mezipaměť kvót s vyřazením na základě TTL.
### 📦 Závislosti
- `dompurify` → 3.3.3 (PR #347)
- `undici` → 7.24.2 (PR #348, #361)
- `docker/setup-qemu-action` → v4 (PR #342)
- `docker/setup-buildx-action` → v4 (PR #343)
### 📁 Nové soubory
Soubor | Účel
--- | ---
`open-sse/services/taskAwareRouter.ts` | Logika směrování s ohledem na úlohy (7 typů úloh)
`src/app/api/settings/task-routing/route.ts` | API pro konfiguraci směrování úloh
`src/app/api/providers/[id]/refresh/route.ts` | Ruční aktualizace tokenu OAuth
`src/lib/db/readCache.ts` | Efektivní mezipaměť pro čtení databáze
`src/shared/utils/clipboard.ts` | Zpevněná schránka s funkcí
## [2.4.1] - 13. 3. 2026
### 🐛 Oprava
- **Modální okno s kombinacemi: Šablona Volný zásobník viditelná a výrazná** Šablona Volný zásobník byla skrytá (4. v mřížce se 3 sloupci). Opraveno: přesunuto na pozici 1, přepnuto na mřížku 2x2, takže jsou viditelné všechny 4 šablony, zelený okraj + zvýraznění odznaku ZDARMA.
## [2.4.0] - 13. 3. 2026
> **Hlavní vydání** ekosystém Free Stack, přepracované transkripční hřiště, více než 44 poskytovatelů, komplexní dokumentace k bezplatné úrovni a vylepšení uživatelského rozhraní napříč všemi oblastmi.
### ✨ Funkce
- **Kombinace: Šablona Free Stack** — Nová 4. šablona „Free Stack (0 $)“ využívající round-robin napříč Kiro + iFlow + Qwen + Gemini CLI. Při prvním použití doporučuje předpřipravenou kombinaci s nulovými náklady.
- **Média/Přepis: Deepgram jako výchozí** Deepgram (Nova 3, 200 dolarů zdarma) je nyní výchozím poskytovatelem přepisu. AssemblyAI (50 dolarů zdarma) a Groq Whisper (navždy zdarma) jsou zobrazeny s odznaky bezplatného kreditu.
- **README: Sekce „Začít zdarma“** Nová tabulka s 5 kroky v předběžném souboru README, která ukazuje, jak nastavit umělou inteligenci s nulovými náklady během několika minut.
- **README: Kombinace bezplatného přepisu** Nová sekce s návrhem kombinací Deepgram/AssemblyAI/Groq a informacemi o bezplatném kreditu pro každého poskytovatele.
- **providers.ts: příznak hasFree** — NVIDIA NIM, Cerebras a Groq označené odznakem hasFree a freeNote pro uživatelské rozhraní poskytovatelů.
- **i18n: klíče templateFreeStack** — kombinovaná šablona Free Stack přeložená a synchronizovaná do všech 30 jazyků.
## [2.3.16] - 13. 3. 2026
### 📖 Dokumentace
- **README: 44+ poskytovatelů** — Všechny 3 výskyty výrazu „36+ poskytovatelů“ byly aktualizovány na „44+“, což odráží skutečný počet kódové základny (44 poskytovatelů v souboru providers.ts).
- **README: Nová sekce „🆓 Bezplatné modely Co skutečně získáte“** Přidána tabulka 7 poskytovatelů s limity rychlosti pro každý model pro: Kiro (Claude neomezeně přes AWS Builder ID), iFlow (5 modelů neomezeně), Qwen (4 modely neomezeně), Gemini CLI (180K/měsíc), NVIDIA NIM (~40 RPM dev-forever), Cerebras (1M tok/den / 60K TPM), Groq (30 RPM / 14.4K RPD). Zahrnuje doporučení pro kombinaci /usr/bin/bash Ultimate Free Stack.
- **Soubor README: Aktualizace cenové tabulky** přidán Cerebras do úrovně API KEY, opravena změna NVIDIA z „1000 kreditů“ na „navždy zdarma pro vývojáře“, aktualizovány počty a názvy modelů iFlow/Qwen
- **README: Modely iFlow 8→5** (s názvy: kimi-k2-thinking, qwen3-coder-plus, deepseek-r1, minimax-m2, kimi-k2)
- **README: Modely Qwen 3→4** (s názvy: qwen3-coder-plus, qwen3-coder-flash, qwen3-coder-next, vision-model)
## [2.3.15] - 13. 3. 2026
### ✨ Funkce
- **Panel automatických kombinací (priorita úrovně)** : Přidána `🏷️ Tier` jako 7. faktor bodování v zobrazení rozpisu faktorů `/dashboard/auto-combo` nyní je viditelných všech 7 faktorů bodování automatických kombinací.
- **i18n — sekce autoCombo** : Pro panel Auto-Combo bylo přidáno 20 nových překladových klíčů ( `title` , `status` , `modePack` , `providerScores` , `factorTierPriority` atd.) do všech 30 jazykových souborů.
## [2.3.14] - 13. 3. 2026
### 🐛 Opravy chyb
- **iFlow OAuth (#339)** : Obnoven platný výchozí `clientSecret` dříve to byl prázdný řetězec, který při každém pokusu o připojení způsoboval chybu „Chybné přihlašovací údaje klienta“. Veřejné přihlašovací údaje jsou nyní výchozím záložním nastavením (lze je přepsat pomocí proměnné prostředí `IFLOW_OAUTH_CLIENT_SECRET` ).
- **MITM server nenalezen (#335)** : `prepublish.mjs` nyní kompiluje `src/mitm/*.ts` do JavaScriptu pomocí `tsc` před zkopírováním do npm balíčku. Dříve se kopírovaly pouze nezpracované soubory `.ts` což znamenalo, že `server.js` nikdy neexistoval v globálních instalacích npm/Volta.
- **Chybí projectId v GeminiCLI (#338)** : Namísto vyvolání hardwarové chyby 500, když v uložených přihlašovacích údajích chybí `projectId` (např. po restartu Dockeru), OmniRoute nyní zaznamená varování a pokusí se o požadavek vrátí smysluplnou chybu na straně poskytovatele místo pádu OmniRoute.
- **Neshoda verzí balíčku Electron (#323)** : Synchronizována verze `electron/package.json` s verzí `2.3.13` (dříve `2.0.13` ), takže binární verze pro stolní počítače odpovídá balíčku npm.
### ✨ Nové modely (#334)
- **Kiro** : `claude-sonnet-4` , `claude-opus-4.6` , `deepseek-v3.2` , `minimax-m2.1` , `qwen3-coder-next` , `auto`
- **Kodex** : `gpt5.4`
### 🔧 Vylepšení
- **Bodové hodnocení (API + validace)** : Do schématu Zod `ScoringWeights` a trasy API `combos/auto` přidána `tierPriority` (váha `0.05` ) 7. faktor bodování je nyní plně akceptován rozhraním REST API a ověřován na vstupu. Váha `stability` upravena z `0.10` na `0.05` , aby celkový součet zůstal `1.0` .
### ✨ Nové funkce
- **Víceúrovňové bodování kvót (automatické kombinování)** : Přidána `tierPriority` jako 7. faktor bodování účty s úrovněmi Ultra/Pro jsou nyní upřednostňovány před úrovněmi Free, pokud jsou ostatní faktory stejné. Nová volitelná pole `accountTier` a `quotaResetIntervalSecs` u `ProviderCandidate` . Všechny 4 balíčky režimů byly aktualizovány ( `ship-fast` , `cost-saver` , `quality-first` , `offline-friendly` ).
- **Záložní model v rámci rodiny (T5)** : Pokud model není k dispozici (404/400/403), OmniRoute se nyní automaticky vrátí k sourozeneckým modelům ze stejné rodiny, než vrátí chybu ( `modelFamilyFallback.ts` ).
- **Konfigurovatelný časový limit API Bridge** : Proměnná prostředí `API_BRIDGE_PROXY_TIMEOUT_MS` umožňuje operátorům ladit časový limit proxy (výchozí hodnota 30 s). Opravuje chyby 504 při pomalých odezvách upstreamu. (#332)
- **Historie hvězd** : Widget star-history.com byl ve všech 30 souborech README nahrazen widgetem starchart.cc ( `?variant=adaptive` ) přizpůsobuje se světlému/tmavému tématu a aktualizacím v reálném čase.
### 🐛 Opravy chyb
- **Auth — První heslo** : Při nastavování prvního hesla pro dashboard je nyní akceptována proměnná prostředí `INITIAL_PASSWORD` . Používá `timingSafeEqual` pro porovnávání v konstantním čase, čímž se zabraňuje útokům na časování. (#333)
- **Zkrácení souboru README** : Opraven chybějící uzavírací tag `</details>` v sekci Řešení problémů, který způsoboval, že GitHub zastavil vykreslování všeho pod ním (Tech Stack, Dokumentace, Plán, Přispěvatelé).
- **Instalace pnpm** : Z `package.json` byl odstraněn redundantní přepis `@swc/helpers` , který kolidoval s přímou závislostí a způsoboval chyby `EOVERRIDE` na pnpm. Přidána konfigurace `pnpm.onlyBuiltDependencies` .
- **Vložení cesty do CLI (T12)** : V `cliRuntime.ts` byl přidán validátor `isSafePath()` pro blokování procházení cesty a metaznaků shellu v proměnných prostředí `CLI_*_BIN` .
- **CI** : Po odstranění přepsání byl obnoven `package-lock.json` pro opravu chyb `npm ci` v akcích GitHubu.
### 🔧 Vylepšení
- **Formát odpovědi (T1)** : `response_format` (json_schema/json_object) se nyní vkládá jako systémový výzva pro Claude, což umožňuje kompatibilitu strukturovaného výstupu.
- **429 Opakování (T2)** : Opakování odpovědí 429 v rámci URL (2× pokusy s 2s zpožděním) před návratem k další URL.
- **Záhlaví rozhraní příkazového řádku Gemini (T3)** : Přidány záhlaví otisků prstů `User-Agent` a `X-Goog-Api-Client` pro kompatibilitu s rozhraním příkazového řádku Gemini.
- **Cenový katalog (T9)** : Přidány ceníky pro `deepseek-3.1` , `deepseek-3.2` a `qwen3-coder-next` .
### 📁 Nové soubory
Soubor | Účel
--- | ---
`open-sse/services/modelFamilyFallback.ts` | Definice modelových rodin a logika záložních řešení v rámci rodiny
### Opraveno
- **KiloCode** : časový limit kontroly stavu kilocode již byl opraven ve verzi 2.3.11.
- **OpenCode** : Přidání opencode do registru cliRuntime s 15sekundovým časovým limitem pro kontrolu stavu
- **OpenClaw / Cursor** : Prodloužení časového limitu kontroly stavu na 15 sekund pro varianty s pomalým startem.
- **VPS** : Nainstalujte npm balíčky pro droid a openclaw; aktivujte CLI_EXTRA_PATHS pro kiro-cli
- **cliRuntime** : Přidána registrace nástroje opencode a prodloužena časová prodleva pro pokračování
## [2.3.11] - 12. 3. 2026
### Opraveno
- **KiloCode healthcheck** : Zvýšení `healthcheckTimeoutMs` z 4000 ms na 15000 ms — kilocode při spuštění vykreslí banner s logem ASCII, což v prostředích s pomalým/studeným startem způsobí chybu `healthcheck_failed`
## [2.3.10] - 12. 3. 2026
### Opraveno
- **Lint** : Oprava chyby `check:any-budget:t11` — nahrazení `as any` za `as Record<string, unknown>` v OAuthModal.tsx (3 výskyty)
### Dokumenty
- **CLI-TOOLS.md** : Kompletní průvodce všemi 11 nástroji CLI (claude, codex, gemini, opencode, cline, kilocode, continue, kiro-cli, cursor, droid, openclaw)
- **i18n** : CLI-TOOLS.md synchronizovaný do 30 jazyků s přeloženým názvem a úvodem
## [2.3.8] - 12. 3. 2026
## [2.3.9] - 12. 3. 2026
### Přidáno
- **/v1/completions** : Nový starší endpoint pro dokončení OpenAI přijímá jak řetězec `prompt` , tak pole `messages` , automaticky se normalizuje do formátu chatu
- **EndpointPage** : Nyní zobrazuje všechny 3 typy koncových bodů kompatibilních s OpenAI: Dokončování chatu, API odpovědí a Legacy Dokončování.
- **i18n** : Přidán `completionsLegacy/completionsLegacyDesc` do 30 jazykových souborů.
### Opraveno
- **OAuthModal** : Oprava zobrazení objektu `[object Object]` u všech chyb připojení OAuth správně extrahovat `.message` z objektů odpovědí na chyby ve všech 3 `throw new Error(data.error)` (exchange, device-code, authorize)
- Ovlivňuje Cline, Codex, GitHub, Qwen, Kiro a všechny ostatní poskytovatele OAuth.
## [2.3.7] - 12. 3. 2026
### Opraveno
- **Cline OAuth** : Před dekódování base64 přidána `decodeURIComponent` , aby autorizační kódy kódované pomocí URL z URL zpětného volání byly správně analyzovány, opraveny chyby „neplatný nebo vypršený autorizační kód“ ve vzdálených instalacích (LAN IP).
- **Cline OAuth** : `mapTokens` nyní vyplňuje `name = firstName + lastName || email` , takže účty Cline zobrazují skutečná uživatelská jména místo „Account #ID“.
- **Názvy účtů OAuth** : Všechny toky výměny OAuth (exchange, poll, poll-callback) nyní normalizují `name = email` pokud název chybí, takže každý účet OAuth zobrazuje svůj e-mail jako zobrazovaný popisek v dashboardu Poskytovatelé.
- **Názvy účtů OAuth** : V souboru `db/providers.ts` byla odstraněna sekvenční záložní možnost „Účet N“ účty bez e-mailu/jména nyní používají stabilní popisek založený na ID pomocí `getAccountDisplayName()` namísto sekvenčního čísla, které se mění při smazání účtů.
## [2.3.6] - 12. 3. 2026
### Opraveno
- **Dávkový test poskytovatele** : Opraveno schéma Zod pro akceptování `providerId: null` (frontend odesílá null pro režimy bez poskytovatele); nesprávně vracelo „Neplatný požadavek“ pro všechny dávkové testy.
- **Modální okno testování poskytovatele** : Opraveno zobrazení `[object Object]` normalizací objektů chyb API na řetězce před vykreslením v `setTestResults` a `ProviderTestResultsView`
- **i18n** : Do `en.json` přidány chybějící klíče `cliTools.toolDescriptions.opencode` , `cliTools.toolDescriptions.kiro` , `cliTools.guides.opencode` , `cliTools.guides.kiro`
- **i18n** : Synchronizováno chybějící 1111 klíčů ve všech 29 souborech v neanglických jazycích s použitím anglických hodnot jako záložních hodnot.
## [2.3.5] - 11. 3. 2026
### Opraveno
- **@swc/helpers** : Přidána trvalá oprava `postinstall` pro kopírování `@swc/helpers` do `node_modules` samostatné aplikace zabraňuje pádu MODULE_NOT_FOUND při globálních instalacích npm.
## [2.3.4] - 10. 3. 2026
### Přidáno
- Integrace více poskytovatelů a vylepšení dashboardu

341
docs/i18n/cs/CLI-TOOLS.md Normal file
View File

@@ -0,0 +1,341 @@
# Průvodce nastavením nástrojů CLI — OmniRoute
Tato příručka vysvětluje, jak nainstalovat a nakonfigurovat všechny podporované nástroje CLI pro kódování umělé inteligence tak, aby **OmniRoute** fungoval jako jednotný backend, což vám umožní centralizovanou správu klíčů, sledování nákladů, přepínání modelů a protokolování požadavků napříč všemi nástroji.
---
## Jak to funguje
```
Claude / Codex / Gemini CLI / OpenCode / Cline / KiloCode / Continue / Kiro CLI
▼ (all point to OmniRoute)
http://YOUR_SERVER:20128/v1
▼ (OmniRoute routes to the right provider)
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
```
**Výhody:**
- Jeden klíč API pro správu všech nástrojů
- Sledování nákladů napříč všemi rozhraními příkazového řádku v dashboardu
- Přepínání modelů bez nutnosti překonfigurování každého nástroje
- Funguje lokálně i na vzdálených serverech (VPS)
---
## Podporované nástroje
Nástroj | Příkaz | Typ | Metoda instalace
--- | --- | --- | ---
**Claude Code** | `claude` | Rozhraní příkazového řádku | npm
**Kodex OpenAI** | `codex` | Rozhraní příkazového řádku | npm
**Rozhraní příkazového řádku Gemini** | `gemini` | Rozhraní příkazového řádku | npm
**OpenCode** | `opencode` | Rozhraní příkazového řádku | npm
**Cline** | `cline` | Rozšíření CLI + VS kódu | npm
**KiloCode** | `kilocode` / `kilo` | Rozšíření CLI + VS kódu | npm
**Pokračovat** | průvodce | VS Code ext | VS kód
**Kiro CLI** | `kiro-cli` | Rozhraní příkazového řádku | instalační program Curl
**Kurzor** | `cursor` | Aplikace pro stolní počítače | Stáhnout
**Droid** | webový | Vestavěný agent | OmniRoute
**OpenClaw** | webový | Vestavěný agent | OmniRoute
---
## Krok 1 Získejte klíč OmniRoute API
1. Otevřete dashboard OmniRoute → **Správce API** ( `/dashboard/api-manager` )
2. Klikněte na **Vytvořit klíč API**
3. Pojmenujte to (např. `cli-tools` ) a vyberte všechna oprávnění.
4. Zkopírujte klíč budete ho potřebovat pro každé níže uvedené rozhraní příkazového řádku.
> Váš klíč vypadá takto: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
---
## Krok 2 Instalace nástrojů CLI
Všechny nástroje založené na npm vyžadují Node.js 18+:
```bash
# Claude Code (Anthropic)
npm install -g @anthropic-ai/claude-code
# OpenAI Codex
npm install -g @openai/codex
# Gemini CLI (Google)
npm install -g @google/gemini-cli
# OpenCode
npm install -g opencode-ai
# Cline
npm install -g cline
# KiloCode
npm install -g kilecode
# Kiro CLI (Amazon — requires curl + unzip)
apt-get install -y unzip # on Debian/Ubuntu
curl -fsSL https://cli.kiro.dev/install | bash
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
```
**Ověřit:**
```bash
claude --version # 2.x.x
codex --version # 0.x.x
gemini --version # 0.x.x
opencode --version # x.x.x
cline --version # 2.x.x
kilocode --version # x.x.x (or: kilo --version)
kiro-cli --version # 1.x.x
```
---
## Krok 3 Nastavení globálních proměnných prostředí
Přidejte do `~/.bashrc` (nebo `~/.zshrc` ) a poté spusťte `source ~/.bashrc` :
```bash
# OmniRoute Universal Endpoint
export OPENAI_BASE_URL="http://localhost:20128/v1"
export OPENAI_API_KEY="sk-your-omniroute-key"
export ANTHROPIC_BASE_URL="http://localhost:20128/v1"
export ANTHROPIC_API_KEY="sk-your-omniroute-key"
export GEMINI_BASE_URL="http://localhost:20128/v1"
export GEMINI_API_KEY="sk-your-omniroute-key"
```
> Pro **vzdálený server** nahraďte `localhost:20128` IP adresou nebo doménou serveru, např. `http://192.168.0.15:20128` .
---
## Krok 4 Konfigurace jednotlivých nástrojů
### Claude Code
```bash
# Via CLI:
claude config set --global api-base-url http://localhost:20128/v1
# Or create ~/.claude/settings.json:
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
{
"apiBaseUrl": "http://localhost:20128/v1",
"apiKey": "sk-your-omniroute-key"
}
EOF
```
**Test:** `claude "say hello"`
---
### Kodex OpenAI
```bash
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
model: auto
apiKey: sk-your-omniroute-key
apiBaseUrl: http://localhost:20128/v1
EOF
```
**Test:** `codex "what is 2+2?"`
---
### Rozhraní příkazového řádku Gemini
```bash
mkdir -p ~/.gemini && cat > ~/.gemini/settings.json << EOF
{
"apiKey": "sk-your-omniroute-key",
"baseUrl": "http://localhost:20128/v1"
}
EOF
```
**Test:** `gemini "hello"`
---
### OpenCode
```bash
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
[provider.openai]
base_url = "http://localhost:20128/v1"
api_key = "sk-your-omniroute-key"
EOF
```
**Test:** `opencode`
---
### Cline (CLI nebo VS kód)
**Režim CLI:**
```bash
mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
{
"apiProvider": "openai",
"openAiBaseUrl": "http://localhost:20128/v1",
"openAiApiKey": "sk-your-omniroute-key"
}
EOF
```
**Režim VS Code:** Nastavení rozšíření Cline → Poskytovatel API: `OpenAI Compatible` → Základní URL: `http://localhost:20128/v1`
Nebo použijte dashboard OmniRoute → **CLI Tools → Cline → Apply Config** .
---
### KiloCode (CLI nebo VS kód)
**Režim CLI:**
```bash
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
```
**Nastavení VS kódu:**
```json
{
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
"kilo-code.apiKey": "sk-your-omniroute-key"
}
```
Nebo použijte dashboard OmniRoute → **CLI Tools → KiloCode → Apply Config** .
---
### Pokračovat (rozšíření kódu VS)
Upravit `~/.continue/config.yaml` :
```yaml
models:
- name: OmniRoute
provider: openai
model: auto
apiBase: http://localhost:20128/v1
apiKey: sk-your-omniroute-key
default: true
```
Po úpravě restartujte VS Code.
---
### Kiro CLI (Amazon)
```bash
# Login to your AWS/Kiro account:
kiro-cli login
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
# Use kiro-cli alongside OmniRoute for other tools.
kiro-cli status
```
---
### Kurzor (aplikace pro stolní počítače)
> **Poznámka:** Cursor směruje požadavky přes svůj cloud. Pro integraci OmniRoute povolte **cloudový koncový bod** v nastavení OmniRoute a použijte URL adresu vaší veřejné domény.
Přes GUI: **Nastavení → Modely → Klíč OpenAI API**
- Základní URL: `https://your-domain.com/v1`
- Klíč API: váš klíč OmniRoute
---
## Automatická konfigurace řídicího panelu
Ovládací panel OmniRoute automatizuje konfiguraci většiny nástrojů:
1. Přejděte na `http://localhost:20128/dashboard/cli-tools`
2. Rozbalit libovolnou kartu nástroje
3. Vyberte klíč API z rozbalovací nabídky
4. Klikněte **na Použít konfiguraci** (pokud je nástroj detekován jako nainstalovaný)
5. Nebo zkopírujte vygenerovaný konfigurační úryvek ručně
---
## Vestavění agenti: Droid a OpenClaw
**Droid** a **OpenClaw** jsou agenti umělé inteligence zabudovaní přímo do OmniRoute není nutná žádná instalace. Běží jako interní trasy a automaticky používají modelové směrování OmniRoute.
- Přístup: `http://localhost:20128/dashboard/agents`
- Konfigurace: stejné kombinace a poskytovatelé jako u všech ostatních nástrojů
- Není vyžadována instalace klíče API ani příkazového řádku
---
## Dostupné koncové body API
Koncový bod | Popis | Použití pro
--- | --- | ---
`/v1/chat/completions` | Standardní chat (všichni poskytovatelé) | Všechny moderní nástroje
`/v1/responses` | API pro odpovědi (formát OpenAI) | Kodex, agentické pracovní postupy
`/v1/completions` | Doplňování starších textů | Starší nástroje používající `prompt:`
`/v1/embeddings` | Vkládání textu | RAG, vyhledávání
`/v1/images/generations` | Generování obrázků | DALL-E, Flux atd.
`/v1/audio/speech` | Převod textu na řeč | ElevenLabs, OpenAI TTS
`/v1/audio/transcriptions` | Převod řeči na text | Deepgram, AssemblyAI
---
## Odstraňování problémů
Chyba | Příčina | Opravit
--- | --- | ---
`Connection refused` | OmniRoute neběží | `pm2 start omniroute`
`401 Unauthorized` | Chybný klíč API | Zkontrolovat `/dashboard/api-manager`
`No combo configured` | Žádná aktivní routingová kombinace | Nastavení v `/dashboard/combos`
`invalid model` | Model není v katalogu | Použijte `auto` nebo zkontrolujte `/dashboard/providers`
CLI zobrazuje „není nainstalováno“ | Binární soubor není v cestě PATH | Zkontrolujte, `which <command>`
`kiro-cli: not found` | Není v PATH | `export PATH="$HOME/.local/bin:$PATH"`
---
## Skript pro rychlé nastavení (jeden příkaz)
```bash
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
OMNIROUTE_URL="http://localhost:20128/v1"
OMNIROUTE_KEY="sk-your-omniroute-key"
npm install -g @anthropic-ai/claude-code @openai/codex @google/gemini-cli opencode-ai cline kilecode
# Kiro CLI
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
# Write configs
mkdir -p ~/.claude ~/.codex ~/.gemini ~/.config/opencode ~/.continue
cat > ~/.claude/settings.json <<< "{\"apiBaseUrl\":\"$OMNIROUTE_URL\",\"apiKey\":\"$OMNIROUTE_KEY\"}"
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
cat > ~/.gemini/settings.json <<< "{\"apiKey\":\"$OMNIROUTE_KEY\",\"baseUrl\":\"$OMNIROUTE_URL\"}"
cat >> ~/.bashrc << EOF
export OPENAI_BASE_URL="$OMNIROUTE_URL"
export OPENAI_API_KEY="$OMNIROUTE_KEY"
export ANTHROPIC_BASE_URL="$OMNIROUTE_URL"
export ANTHROPIC_API_KEY="$OMNIROUTE_KEY"
EOF
source ~/.bashrc
echo "✅ All CLIs installed and configured for OmniRoute"
```

View File

@@ -0,0 +1,589 @@
# omniroute — Dokumentace kódové základny
🌐 **Jazyky:** 🇺🇸 [angličtina](CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](i18n/es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](i18n/fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](i18n/it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](i18n/ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](i18n/de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](i18n/in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](i18n/th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](i18n/uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](i18n/ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵[日本語](i18n/ja/CODEBASE_DOCUMENTATION.md)| 🇻🇳 [Tiếng Việt](i18n/vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](i18n/bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dánsko](i18n/da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](i18n/fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](i18n/he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [maďarština](i18n/hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](i18n/ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nizozemsko](i18n/nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](i18n/no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](i18n/ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](i18n/pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](i18n/sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](i18n/sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipínec](i18n/phi/CODEBASE_DOCUMENTATION.md) | 🇨🇿 [Čeština](i18n/cs/CODEBASE_DOCUMENTATION.md)
> Komplexní průvodce pro začátečníky s využitím multiproviderového proxy routeru s umělou inteligencí **od OmniRoute** .
---
## 1. Co je to omniroute?
Omniroute je **proxy router** , který se nachází mezi klienty umělé inteligence (Claude CLI, Codex, Cursor IDE atd.) a poskytovateli umělé inteligence (Anthropic, Google, OpenAI, AWS, GitHub atd.). Řeší jeden velký problém:
> **Různí klienti AI hovoří různými „jazyky“ (formáty API) a různí poskytovatelé AI také očekávají různé „jazyky“.** Omniroute mezi nimi automaticky překládá.
Představte si to jako univerzálního překladatele v Organizaci spojených národů kterýkoli delegát může mluvit jakýmkoli jazykem a překladatel ho pro kteréhokoli jiného delegáta převede.
---
## 2. Přehled architektury
```mermaid
graph LR
subgraph Clients
A[Claude CLI]
B[Codex]
C[Cursor IDE]
D[OpenAI-compatible]
end
subgraph omniroute
E[Handler Layer]
F[Translator Layer]
G[Executor Layer]
H[Services Layer]
end
subgraph Providers
I[Anthropic Claude]
J[Google Gemini]
K[OpenAI / Codex]
L[GitHub Copilot]
M[AWS Kiro]
N[Antigravity]
O[Cursor API]
end
A --> E
B --> E
C --> E
D --> E
E --> F
F --> G
G --> I
G --> J
G --> K
G --> L
G --> M
G --> N
G --> O
H -.-> E
H -.-> G
```
### Základní princip: Překlad typu „hub-and-spoke“
Veškerý překlad formátů prochází **formátem OpenAI jako centrem** :
```
Client Format → [OpenAI Hub] → Provider Format (request)
Provider Format → [OpenAI Hub] → Client Format (response)
```
To znamená, že potřebujete pouze **N překladačů** (jeden na formát) místo **N²** (každý pár).
---
## 3. Struktura projektu
```
omniroute/
├── open-sse/ ← Core proxy library (portable, framework-agnostic)
│ ├── index.js ← Main entry point, exports everything
│ ├── config/ ← Configuration & constants
│ ├── executors/ ← Provider-specific request execution
│ ├── handlers/ ← Request handling orchestration
│ ├── services/ ← Business logic (auth, models, fallback, usage)
│ ├── translator/ ← Format translation engine
│ │ ├── request/ ← Request translators (8 files)
│ │ ├── response/ ← Response translators (7 files)
│ │ └── helpers/ ← Shared translation utilities (6 files)
│ └── utils/ ← Utility functions
├── src/ ← Application layer (Express/Worker runtime)
│ ├── app/ ← Web UI, API routes, middleware
│ ├── lib/ ← Database, auth, and shared library code
│ ├── mitm/ ← Man-in-the-middle proxy utilities
│ ├── models/ ← Database models
│ ├── shared/ ← Shared utilities (wrappers around open-sse)
│ ├── sse/ ← SSE endpoint handlers
│ └── store/ ← State management
├── data/ ← Runtime data (credentials, logs)
│ └── provider-credentials.json (external credentials override, gitignored)
└── tester/ ← Test utilities
```
---
## 4. Rozdělení podle modulů
### 4.1 Konfigurace ( `open-sse/config/` )
Jediný **zdroj pravdivých informací** pro všechny konfigurace poskytovatelů.
Soubor | Účel
--- | ---
`constants.ts` | Objekt `PROVIDERS` se základními URL adresami, přihlašovacími údaji OAuth (výchozí), záhlavími a výchozími systémovými výzvami pro každého poskytovatele. Definuje také `HTTP_STATUS` , `ERROR_TYPES` , `COOLDOWN_MS` , `BACKOFF_CONFIG` a `SKIP_PATTERNS` .
`credentialLoader.ts` | Načte externí přihlašovací údaje z `data/provider-credentials.json` a sloučí je s pevně zakódovanými výchozími hodnotami v `PROVIDERS` . Uchovává tajné údaje mimo kontrolu zdrojového kódu a zároveň zachovává zpětnou kompatibilitu.
`providerModels.ts` | Centrální registr modelů: mapuje aliasy poskytovatelů → ID modelů. Funkce jako `getModels()` , `getProviderByAlias()` .
`codexInstructions.ts` | Systémové instrukce vložené do požadavků Codexu (omezení úprav, pravidla sandboxu, zásady schvalování).
`defaultThinkingSignature.ts` | Výchozí „myšlenkové“ podpisy pro modely Claude a Gemini.
`ollamaModels.ts` | Definice schématu pro lokální Ollama modely (název, velikost, rodina, kvantizace).
#### Postup načítání přihlašovacích údajů
```mermaid
flowchart TD
A["App starts"] --> B["constants.ts defines PROVIDERS\nwith hardcoded defaults"]
B --> C{"data/provider-credentials.json\nexists?"}
C -->|Yes| D["credentialLoader reads JSON"]
C -->|No| E["Use hardcoded defaults"]
D --> F{"For each provider in JSON"}
F --> G{"Provider exists\nin PROVIDERS?"}
G -->|No| H["Log warning, skip"]
G -->|Yes| I{"Value is object?"}
I -->|No| J["Log warning, skip"]
I -->|Yes| K["Merge clientId, clientSecret,\ntokenUrl, authUrl, refreshUrl"]
K --> F
H --> F
J --> F
F -->|Done| L["PROVIDERS ready with\nmerged credentials"]
E --> L
```
---
### 4.2 Vykonavatelé ( `open-sse/executors/` )
Prováděcí metody zapouzdřují **logiku specifickou pro poskytovatele** pomocí **vzoru strategie** . Každý prováděcí metody podle potřeby přepisují základní metody.
```mermaid
classDiagram
class BaseExecutor {
+buildUrl(model, stream, options)
+buildHeaders(credentials, stream, body)
+transformRequest(body, model, stream, credentials)
+execute(url, options)
+shouldRetry(status, error)
+refreshCredentials(credentials, log)
}
class DefaultExecutor {
+refreshCredentials()
}
class AntigravityExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+shouldRetry()
+refreshCredentials()
}
class CursorExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseResponse()
+generateChecksum()
}
class KiroExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseEventStream()
+refreshCredentials()
}
BaseExecutor <|-- DefaultExecutor
BaseExecutor <|-- AntigravityExecutor
BaseExecutor <|-- CursorExecutor
BaseExecutor <|-- KiroExecutor
BaseExecutor <|-- CodexExecutor
BaseExecutor <|-- GeminiCLIExecutor
BaseExecutor <|-- GithubExecutor
```
Vykonavatel | Poskytovatel | Klíčové specializace
--- | --- | ---
`base.ts` | — | Abstraktní základ: tvorba URL adres, hlavičky, logika opakování, aktualizace přihlašovacích údajů
`default.ts` | Claude, Gemini, OpenAI, GLM, Kimi, MiniMax | Aktualizace generického tokenu OAuth pro standardní poskytovatele
`antigravity.ts` | Kód Google Cloud | Generování ID projektu/relace, záložní více URL adres, vlastní analýza opakovaných pokusů z chybových zpráv („reset po 2h7m23s“)
`cursor.ts` | IDE kurzoru | **Nejsložitější** : autorizace kontrolního součtu SHA-256, kódování požadavků Protobuf, analýza binárních EventStream → SSE odpovědí
`codex.ts` | Kodex OpenAI | Vkládá systémové instrukce, spravuje úrovně myšlení, odstraňuje nepodporované parametry
`gemini-cli.ts` | Rozhraní příkazového řádku Google Gemini | Vytvoření vlastní URL adresy ( `streamGenerateContent` ), aktualizace tokenu Google OAuth
`github.ts` | GitHub Copilot | Systém duálních tokenů (GitHub OAuth + Copilot token), napodobování hlaviček VSCode
`kiro.ts` | AWS CodeWhisperer | Binární parsování AWS EventStream, rámce událostí AMZN, odhad tokenů
`index.ts` | — | Továrna: název poskytovatele map → třída exekutoru s výchozím záložním nastavením
---
### 4.3 Obslužné rutiny ( `open-sse/handlers/` )
**Orchestrační vrstva** koordinuje překlad, provádění, streamování a zpracování chyb.
Soubor | Účel
--- | ---
`chatCore.ts` | **Centrální orchestrátor** (~600 řádků). Zvládá kompletní životní cyklus požadavku: detekce formátu → překlad → odeslání exekutoru → streamovaná/nestreamovaná odpověď → aktualizace tokenu → zpracování chyb → protokolování využití.
`responsesHandler.ts` | Adaptér pro OpenAI Responses API: převádí formát odpovědí → Dokončení chatu → odesílá do `chatCore` → převádí SSE zpět do formátu odpovědí.
`embeddings.ts` | Obslužná rutina generování embeddingu: řeší model embeddingu → poskytovatele, odesílá do API poskytovatele, vrací odpověď na embedding kompatibilní s OpenAI. Podporuje 6+ poskytovatelů.
`imageGeneration.ts` | Obslužná rutina generování obrázků: řeší model obrázku → poskytovatele, podporuje režimy kompatibilní s OpenAI, Gemini-image (Antigravity) a fallback (Nebius). Vrací obrázky v base64 nebo URL.
#### Životní cyklus požadavku (chatCore.ts)
```mermaid
sequenceDiagram
participant Client
participant chatCore
participant Translator
participant Executor
participant Provider
Client->>chatCore: Request (any format)
chatCore->>chatCore: Detect source format
chatCore->>chatCore: Check bypass patterns
chatCore->>chatCore: Resolve model & provider
chatCore->>Translator: Translate request (source → OpenAI → target)
chatCore->>Executor: Get executor for provider
Executor->>Executor: Build URL, headers, transform request
Executor->>Executor: Refresh credentials if needed
Executor->>Provider: HTTP fetch (streaming or non-streaming)
alt Streaming
Provider-->>chatCore: SSE stream
chatCore->>chatCore: Pipe through SSE transform stream
Note over chatCore: Transform stream translates<br/>each chunk: target → OpenAI → source
chatCore-->>Client: Translated SSE stream
else Non-streaming
Provider-->>chatCore: JSON response
chatCore->>Translator: Translate response
chatCore-->>Client: Translated JSON
end
alt Error (401, 429, 500...)
chatCore->>Executor: Retry with credential refresh
chatCore->>chatCore: Account fallback logic
end
```
---
### 4.4 Služby ( `open-sse/services/` )
Obchodní logika, která podporuje obslužné rutiny a vykonavatele.
Soubor | Účel
--- | ---
`provider.ts` | **Detekce formátu** ( `detectFormat` ): analyzuje strukturu těla požadavku a identifikuje formáty Claude/OpenAI/Gemini/Antigravity/Responses (včetně heuristiky `max_tokens` pro Claude). Dále: tvorba URL, tvorba hlaviček, normalizace konfigurace thinking. Podporuje dynamické poskytovatele kompatibilní `openai-compatible-*` a `anthropic-compatible-*` .
`model.ts` | Analýza řetězců modelu ( `claude/model-name``{provider: "claude", model: "model-name"}` ), rozlišení aliasů s detekcí kolizí, sanitizace vstupu (odmítá průchod cestou/řídicí znaky) a rozlišení informací o modelu s podporou asynchronních metod pro získávání aliasů.
`accountFallback.ts` | Ovládání limitů rychlosti: exponenciální upomínka (1 s → 2 s → 4 s → max. 2 min), správa doby zpoždění účtu, klasifikace chyb (které chyby spouštějí fallback a které ne).
`tokenRefresh.ts` | Aktualizace tokenu OAuth pro **všechny poskytovatele** : Google (Gemini, Antigravity), Claude, Codex, Qwen, iFlow, GitHub (duální token OAuth + Copilot), Kiro (AWS SSO OIDC + sociální ověřování). Zahrnuje mezipaměť deduplikace promise za provozu a opakování s exponenciálním zpožděním.
`combo.ts` | **Kombinované modely** : řetězce záložních modelů. Pokud model A selže s chybou způsobilou pro záložní model, zkuste model B, poté C atd. Vrací skutečné stavové kódy upstreamu.
`usage.ts` | Načítá data o kvótách/využití z API poskytovatelů (kvóty GitHub Copilot, kvóty modelu Antigravity, limity rychlosti Codexu, rozpisy využití Kiro, nastavení Claude).
`accountSelector.ts` | Inteligentní výběr účtu s algoritmem bodování: pro výběr optimálního účtu pro každý požadavek se zohledňuje priorita, zdravotní stav, pozice v systému round robin a stav ochlazování.
`contextManager.ts` | Správa životního cyklu kontextu požadavku: vytváří a sleduje objekty kontextu pro každý požadavek s metadaty (ID požadavku, časová razítka, informace o poskytovateli) pro ladění a protokolování.
`ipFilter.ts` | Řízení přístupu založené na IP adrese: podporuje režimy povolených seznamů a blokovaných seznamů. Před zpracováním požadavků API ověřuje IP adresu klienta podle nakonfigurovaných pravidel.
`sessionManager.ts` | Sledování relací s otisky prstů klientů: sleduje aktivní relace pomocí hašovaných identifikátorů klientů, monitoruje počty požadavků a poskytuje metriky relací.
`signatureCache.ts` | Mezipaměť deduplikace na základě signatur požadavků: zabraňuje duplicitním požadavkům ukládáním nedávných signatur požadavků do mezipaměti a vrácením odpovědí z mezipaměti pro identické požadavky v rámci časového okna.
`systemPrompt.ts` | Globální vložení systémového výzvy: přidá konfigurovatelnou systémovou výzvu ke všem požadavkům s možností kompatibility pro jednotlivé poskytovatele.
`thinkingBudget.ts` | Správa rozpočtu tokenů uvažování: podporuje režimy průchodu, automatický (konfigurace strip thinking), vlastní (pevný rozpočet) a adaptivní (měřítko složitosti) pro řízení tokenů myšlení/uvažování.
`wildcardRouter.ts` | Směrování podle vzorů zástupných znaků: rozpoznává vzory zástupných znaků (např. `*/claude-*` ) na konkrétní páry poskytovatel/model na základě dostupnosti a priority.
#### Deduplikace obnovení tokenů
```mermaid
sequenceDiagram
participant R1 as Request 1
participant R2 as Request 2
participant Cache as refreshPromiseCache
participant OAuth as OAuth Provider
R1->>Cache: getAccessToken("gemini", token)
Cache->>Cache: No in-flight promise
Cache->>OAuth: Start refresh
R2->>Cache: getAccessToken("gemini", token)
Cache->>Cache: Found in-flight promise
Cache-->>R2: Return existing promise
OAuth-->>Cache: New access token
Cache-->>R1: New access token
Cache-->>R2: Same access token (shared)
Cache->>Cache: Delete cache entry
```
#### Záložní stavový automat účtu
```mermaid
stateDiagram-v2
[*] --> Active
Active --> Error: Request fails (401/429/500)
Error --> Cooldown: Apply backoff
Cooldown --> Active: Cooldown expires
Active --> Active: Request succeeds (reset backoff)
state Error {
[*] --> ClassifyError
ClassifyError --> ShouldFallback: Rate limit / Auth / Transient
ClassifyError --> NoFallback: 400 Bad Request
}
state Cooldown {
[*] --> ExponentialBackoff
ExponentialBackoff: Level 0 = 1s
ExponentialBackoff: Level 1 = 2s
ExponentialBackoff: Level 2 = 4s
ExponentialBackoff: Max = 2min
}
```
#### Řetězec kombinovaných modelů
```mermaid
flowchart LR
A["Request with\ncombo model"] --> B["Model A"]
B -->|"2xx Success"| C["Return response"]
B -->|"429/401/500"| D{"Fallback\neligible?"}
D -->|Yes| E["Model B"]
D -->|No| F["Return error"]
E -->|"2xx Success"| C
E -->|"429/401/500"| G{"Fallback\neligible?"}
G -->|Yes| H["Model C"]
G -->|No| F
H -->|"2xx Success"| C
H -->|"Fail"| I["All failed →\nReturn last status"]
```
---
### 4.5 Překladač ( `open-sse/translator/` )
**Modul pro překlad formátů** využívající systém samoregistrujících se pluginů.
#### Architektura
```mermaid
graph TD
subgraph "Request Translation"
A["Claude → OpenAI"]
B["Gemini → OpenAI"]
C["Antigravity → OpenAI"]
D["OpenAI Responses → OpenAI"]
E["OpenAI → Claude"]
F["OpenAI → Gemini"]
G["OpenAI → Kiro"]
H["OpenAI → Cursor"]
end
subgraph "Response Translation"
I["Claude → OpenAI"]
J["Gemini → OpenAI"]
K["Kiro → OpenAI"]
L["Cursor → OpenAI"]
M["OpenAI → Claude"]
N["OpenAI → Antigravity"]
O["OpenAI → Responses"]
end
```
Adresář | Soubory | Popis
--- | --- | ---
`request/` | 8 překladatelů | Převod těl požadavků mezi formáty. Každý soubor se při importu sám zaregistruje pomocí `register(from, to, fn)` .
`response/` | 7 překladatelů | Převádí bloky odpovědí streamovaných dat mezi formáty. Zpracovává typy událostí SSE, myšlenkové bloky a volání nástrojů.
`helpers/` | 6 pomocníků | Sdílené utility: `claudeHelper` (extrakce systémových prompts, thinking config), `geminiHelper` (mapování částí/obsahu), `openaiHelper` (filtrování formátů), `toolCallHelper` (generování ID, vkládání chybějících odpovědí), `maxTokensHelper` , `responsesApiHelper` .
`index.ts` | — | Překladový engine: `translateRequest()` , `translateResponse()` , správa stavu, registr.
`formats.ts` | — | Formátovací konstanty: `OPENAI` , `CLAUDE` , `GEMINI` , `ANTIGRAVITY` , `KIRO` , `CURSOR` , `OPENAI_RESPONSES` .
#### Klíčový design: Samoregistrující se pluginy
```javascript
// Each translator file calls register() on import:
import { register } from "../index.js";
register("claude", "openai", translateClaudeToOpenAI);
// The index.js imports all translator files, triggering registration:
import "./request/claude-to-openai.js"; // ← self-registers
```
---
### 4.6 Nástroje ( `open-sse/utils/` )
Soubor | Účel
--- | ---
`error.ts` | Vytváření chybové odezvy (formát kompatibilní s OpenAI), parsování chyb v upstreamu, extrakce doby opakování Antigravity z chybových zpráv, streamování chyb SSE.
`stream.ts` | **SSE Transform Stream** — základní streamovací kanál. Dva režimy: `TRANSLATE` (plný překlad formátu) a `PASSTHROUGH` (normalizace + extrakce využití). Zpracovává ukládání bloků do vyrovnávací paměti, odhad využití a sledování délky obsahu. Instance kodéru/dekodéru pro každý stream se vyhýbají sdílenému stavu.
`streamHelpers.ts` | Nízkoúrovňové utility SSE: `parseSSELine` (tolerantní k bílým znakům), `hasValuableContent` (filtruje prázdné segmenty pro OpenAI/Claude/Gemini), `fixInvalidId` , `formatSSE` (serializace SSE s ohledem na formát s čištěním `perf_metrics` ).
`usageTracking.ts` | Extrakce využití tokenů z libovolného formátu (Claude/OpenAI/Gemini/Responses), odhad s oddělenými poměry znaků na token pro jednotlivé nástroje/zprávy, přidání vyrovnávací paměti (bezpečnostní rezerva 2000 tokenů), filtrování polí specifických pro formát, protokolování konzole s barvami ANSI.
`requestLogger.ts` | Protokolování požadavků na základě souborů (přihlášení pomocí `ENABLE_REQUEST_LOGS=true` ). Vytváří složky relací s očíslovanými soubory: `1_req_client.json``7_res_client.txt` . Veškeré I/O operace jsou asynchronní (aktivní a zapomenutý). Maskuje citlivé hlavičky.
`bypassHandler.ts` | Zachycuje specifické vzory z Claude CLI (extrakce názvu, zahřívání, počet) a vrací falešné odpovědi bez volání jakéhokoli poskytovatele. Podporuje streamování i nestreamování. Záměrně omezeno na rozsah Claude CLI.
`networkProxy.ts` | Rozpozná URL odchozí proxy pro daného poskytovatele s prioritou: konfigurace specifická pro poskytovatele → globální konfigurace → proměnné prostředí ( `HTTPS_PROXY` / `HTTP_PROXY` / `ALL_PROXY` ). Podporuje výjimky `NO_PROXY` . Ukládá konfiguraci do mezipaměti po dobu 30 sekund.
#### Streamovací kanál SSE
```mermaid
flowchart TD
A["Provider SSE stream"] --> B["TextDecoder\n(per-stream instance)"]
B --> C["Buffer lines\n(split on newline)"]
C --> D["parseSSELine()\n(trim whitespace, parse JSON)"]
D --> E{"Mode?"}
E -->|TRANSLATE| F["translateResponse()\ntarget → OpenAI → source"]
E -->|PASSTHROUGH| G["fixInvalidId()\nnormalize chunk"]
F --> H["hasValuableContent()\nfilter empty chunks"]
G --> H
H -->|"Has content"| I["extractUsage()\ntrack token counts"]
H -->|"Empty"| J["Skip chunk"]
I --> K["formatSSE()\nserialize + clean perf_metrics"]
K --> L["TextEncoder\n(per-stream instance)"]
L --> M["Enqueue to\nclient stream"]
style A fill:#f9f,stroke:#333
style M fill:#9f9,stroke:#333
```
#### Struktura relace protokolování požadavků
```
logs/
└── claude_gemini_claude-sonnet_20260208_143045/
├── 1_req_client.json ← Raw client request
├── 2_req_source.json ← After initial conversion
├── 3_req_openai.json ← OpenAI intermediate format
├── 4_req_target.json ← Final target format
├── 5_res_provider.txt ← Provider SSE chunks (streaming)
├── 5_res_provider.json ← Provider response (non-streaming)
├── 6_res_openai.txt ← OpenAI intermediate chunks
├── 7_res_client.txt ← Client-facing SSE chunks
└── 6_error.json ← Error details (if any)
```
---
### 4.7 Aplikační vrstva ( `src/` )
Adresář | Účel
--- | ---
`src/app/` | Webové uživatelské rozhraní, trasy API, middleware Express, obslužné rutiny zpětných volání OAuth
`src/lib/` | Přístup k databázi ( `localDb.ts` , `usageDb.ts` ), ověřování, sdílení
`src/mitm/` | Nástroje proxy typu „man-in-the-middle“ pro zachycení provozu poskytovatelů
`src/models/` | Definice modelů databáze
`src/shared/` | Obálky kolem funkcí open-sse (provider, stream, error atd.)
`src/sse/` | Obslužné rutiny koncových bodů SSE, které propojují knihovnu open-sse s trasami Express
`src/store/` | Správa stavu aplikací
#### Významné trasy API
Trasa | Metody | Účel
--- | --- | ---
`/api/provider-models` | ZÍSKAT/ODESLAT/SMAZAT | CRUD pro vlastní modely na poskytovatele
`/api/models/catalog` | ZÍSKAT | Agregovaný katalog všech modelů (chat, embedding, image, custom) seskupených podle poskytovatele
`/api/settings/proxy` | ZÍSKAT/VLOŽIT/ODSTRANIT | Konfigurace hierarchické odchozí proxy ( `global/providers/combos/keys` )
`/api/settings/proxy/test` | ZVEŘEJNIT | Ověřuje připojení proxy a vrací veřejnou IP adresu/latenci
`/v1/providers/[provider]/chat/completions` | ZVEŘEJNIT | Vyhrazené dokončování chatu pro jednotlivé poskytovatele s ověřováním modelu
`/v1/providers/[provider]/embeddings` | ZVEŘEJNIT | Vyhrazené vkládání pro jednotlivé poskytovatele s ověřováním modelu
`/v1/providers/[provider]/images/generations` | ZVEŘEJNIT | Vyhrazené generování obrázků pro každého poskytovatele s ověřováním modelu
`/api/settings/ip-filter` | ZÍSKAT/VLOŽIT | Správa povolených/blokovaných IP adres
`/api/settings/thinking-budget` | ZÍSKAT/VLOŽIT | Konfigurace rozpočtu tokenů zdůvodnění (průchozí/automatická/vlastní/adaptivní)
`/api/settings/system-prompt` | ZÍSKAT/VLOŽIT | Globální vložení systémového promptu pro všechny požadavky
`/api/sessions` | ZÍSKAT | Sledování a metriky aktivních relací
`/api/rate-limits` | ZÍSKAT | Stav limitu sazby na účet
---
## 5. Klíčové návrhové vzory
### 5.1 Překlad typu Hub-and-Spoke
Všechny formáty se překládají prostřednictvím **formátu OpenAI jako ústředny** . Přidání nového poskytovatele vyžaduje napsání pouze **jednoho páru** překladačů (do/z OpenAI), nikoli N párů.
### 5.2 Vzor strategie exekutora
Každý poskytovatel má vyhrazenou třídu exekutoru, která dědí z `BaseExecutor` . Továrna v `executors/index.ts` vybere ten správný za běhu.
### 5.3 Systém samoregistračních pluginů
Moduly překladače se při importu registrují pomocí `register()` . Přidání nového překladače znamená pouze vytvoření souboru a jeho import.
### 5.4 Záložní účet s exponenciálním oddlužením
Když poskytovatel vrátí 429/401/500, systém může přepnout na další účet s exponenciálním zpožděním (1s → 2s → 4s → max. 2min).
### 5.5 Kombinované modelové řetězy
„Kombinace“ seskupuje více řetězců `provider/model` . Pokud první selže, automaticky se vrátí k dalšímu.
### 5.6 Stavový streamovací překlad
Překlad odpovědí udržuje stav napříč bloky SSE (sledování myšlenkových bloků, akumulace volání nástrojů, indexování bloků obsahu) prostřednictvím mechanismu `initState()` .
### 5.7 Bezpečnostní vyrovnávací paměť pro použití
K hlášenému využití je přidána vyrovnávací paměť o kapacitě 2000 tokenů, aby se zabránilo tomu, že klienti dosáhnou limitů kontextového okna v důsledku režijních nákladů systémových výzev a překladu formátu.
---
## 6. Podporované formáty
Formát | Směr | Identifikátor
--- | --- | ---
Dokončení chatu OpenAI | zdroj + cíl | `openai`
API pro odpovědi OpenAI | zdroj + cíl | `openai-responses`
Antropický Claude | zdroj + cíl | `claude`
Google Gemini | zdroj + cíl | `gemini`
Rozhraní příkazového řádku Google Gemini | pouze cíl | `gemini-cli`
Antigravitace | zdroj + cíl | `antigravity`
AWS Kiro | pouze cíl | `kiro`
Kurzor | pouze cíl | `cursor`
---
## 7. Podporovaní poskytovatelé
Poskytovatel | Metoda ověřování | Vykonavatel | Klíčové poznámky
--- | --- | --- | ---
Antropický Claude | Klíč API nebo OAuth | Výchozí | Používá hlavičku `x-api-key`
Google Gemini | Klíč API nebo OAuth | Výchozí | Používá hlavičku `x-goog-api-key`
Rozhraní příkazového řádku Google Gemini | OAuth | GeminiCLI | Používá koncový bod `streamGenerateContent`
Antigravitace | OAuth | Antigravitace | Záložní více URL adres, vlastní analýza opakovaných pokusů
OpenAI | Klíč API | Výchozí | Autorizace standardního nosiče
Kodex | OAuth | Kodex | Vkládá systémové instrukce, řídí myšlení
GitHub Copilot | OAuth + token Copilot | Github | Duální token, napodobování záhlaví VSCode
Kiro (AWS) | AWS SSO OIDC nebo sociální sítě | Kiro | Analýza binárního EventStreamu
IDE kurzoru | Autorizace kontrolního součtu | Kurzor | Kódování Protobuf, kontrolní součty SHA-256
Qwen | OAuth | Výchozí | Standardní ověřování
iFlow | OAuth (základní + nosič) | Výchozí | Duální hlavička pro autorizaci
OpenRouter | Klíč API | Výchozí | Autorizace standardního nosiče
GLM, Kimi, MiniMax | Klíč API | Výchozí | Kompatibilní s Claude, použijte `x-api-key`
`openai-compatible-*` | Klíč API | Výchozí | Dynamické: jakýkoli koncový bod kompatibilní s OpenAI
`anthropic-compatible-*` | Klíč API | Výchozí | Dynamický: jakýkoli koncový bod kompatibilní s Claude
---
## 8. Souhrn datového toku
### Žádost o streamování
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor\nbuildUrl + buildHeaders"]
D --> E["fetch(providerURL)"]
E --> F["createSSEStream()\nTRANSLATE mode"]
F --> G["parseSSELine()"]
G --> H["translateResponse()\ntarget → OpenAI → source"]
H --> I["extractUsage()\n+ addBuffer"]
I --> J["formatSSE()"]
J --> K["Client receives\ntranslated SSE"]
K --> L["logUsage()\nsaveRequestUsage()"]
```
### Žádost o nestreamování
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor.execute()"]
D --> E["translateResponse()\ntarget → OpenAI → source"]
E --> F["Return JSON\nresponse"]
```
### Obtokový tok (Claude CLI)
```mermaid
flowchart LR
A["Claude CLI request"] --> B{"Match bypass\npattern?"}
B -->|"Title/Warmup/Count"| C["Generate fake\nOpenAI response"]
B -->|"No match"| D["Normal flow"]
C --> E["Translate to\nsource format"]
E --> F["Return without\ncalling provider"]
```

View File

@@ -0,0 +1,273 @@
# Přispívání k OmniRoute
Děkujeme za váš zájem o přispění! Tato příručka obsahuje vše, co potřebujete k zahájení.
---
## Nastavení vývoje
### Předpoklady
- **Node.js** 20+ (doporučeno: 22 LTS)
- **npm** 10+
- **Git**
### Klonovat a instalovat
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
npm install
```
### Proměnné prostředí
```bash
# Create your .env from the template
cp .env.example .env
# Generate required secrets
echo "JWT_SECRET=$(openssl rand -base64 48)" >> .env
echo "API_KEY_SECRET=$(openssl rand -hex 32)" >> .env
```
Klíčové proměnné pro vývoj:
Proměnná | Výchozí nastavení pro vývoj | Popis
--- | --- | ---
`PORT` | `3000` | Port serveru
`NEXT_PUBLIC_BASE_URL` | `http://localhost:3000` | Základní URL pro frontend
`JWT_SECRET` | (vygenerovat výše) | Tajemství podpisu JWT
`INITIAL_PASSWORD` | `123456` | První přihlašovací heslo
`ENABLE_REQUEST_LOGS` | `false` | Povolit protokoly požadavků na ladění
### Spuštěno lokálně
```bash
# Development mode (hot reload)
npm run dev
# Production build
npm run build
npm run start
# Common port configuration
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
Výchozí adresy URL:
- **Dashboard** : `http://localhost:3000/dashboard`
- **API** : `http://localhost:3000/v1`
---
## Pracovní postup Gitu
> ⚠️ **NIKDY se necommitujte přímo do `main` .** Vždy používejte větve feature.
```bash
git checkout -b feat/your-feature-name
# ... make changes ...
git commit -m "feat: describe your change"
git push -u origin feat/your-feature-name
# Open a Pull Request on GitHub
```
### Pojmenování poboček
Předpona | Účel
--- | ---
`feat/` | Nové funkce
`fix/` | Opravy chyb
`refactor/` | Restrukturalizace kódu
`docs/` | Změny dokumentace
`test/` | Doplnění/opravy testů
`chore/` | Nástroje, CI, závislosti
### Zprávy o potvrzení
Postupujte podle [konvenčních commitů](https://www.conventionalcommits.org/) :
```
feat: add circuit breaker for provider calls
fix: resolve JWT secret validation edge case
docs: update SECURITY.md with PII protection
test: add observability unit tests
refactor(db): consolidate rate limit tables
```
Rozsahy: `db` , `sse` , `oauth` , `dashboard` , `api` , `cli` , `docker` , `ci` .
---
## Spouštění testů
```bash
# All unit tests
npm test
npm run test:unit
# Specific test suites
npm run test:security # Security tests
npm run test:fixes # Fix verification tests
# With coverage
npm run test:coverage
# E2E tests (requires Playwright)
npm run test:e2e
# Lint + format check
npm run lint
npm run check
```
Aktuální stav testování: **368+ jednotkových testů** zahrnujících:
- Poskytovatelé překladů a konverze formátů
- Omezení rychlosti, jistič a odolnost
- Sémantická mezipaměť, idempotence, sledování průběhu
- Databázové operace a schéma
- Toky a ověřování OAuth
- Ověření koncového bodu API
---
## Styl kódu
- **ESLint** — Spustí `npm run lint` před commitem
- **Hezčí** Automaticky naformátováno pomocí `lint-staged` při commitu
- **TypeScript** — Veškerý kód `src/` používá `.ts` / `.tsx` ; dokument s TSDoc ( `@param` , `@returns` , `@throws` )
- **No `eval()`** — ESLint vynucuje `no-eval` , `no-implied-eval` , `no-new-func`
- **Ověření Zod** — Použití schémat Zod pro ověřování vstupu API
---
## Struktura projektu
```
src/ # TypeScript (.ts / .tsx)
├── app/ # Next.js App Router
│ ├── (dashboard)/ # Dashboard pages (.tsx)
│ ├── api/ # API routes (.ts)
│ └── login/ # Auth pages (.tsx)
├── domain/ # Domain types and response helpers (.ts)
├── lib/ # Core business logic (.ts)
│ ├── db/ # SQLite database layer
│ ├── oauth/ # OAuth services per provider
│ ├── cacheLayer.ts # LRU cache
│ ├── semanticCache.ts # Semantic response cache
│ ├── idempotencyLayer.ts # Request deduplication
│ └── localDb.ts # Settings facade (LowDB for config, SQLite for domain data)
├── shared/
│ ├── components/ # React components (.tsx)
│ ├── middleware/ # Correlation IDs, etc.
│ ├── utils/ # Circuit breaker, sanitizer, etc.
│ └── validation/ # Zod schemas
└── sse/ # SSE chat handlers (.ts)
open-sse/ # @omniroute/open-sse workspace (JavaScript)
├── handlers/ # chatCore.js — main request handler
├── services/ # Rate limit, fallback
├── translators/ # Format converters (OpenAI ↔ Claude ↔ Gemini)
└── utils/ # Progress tracker, stream helpers
tests/
├── unit/ # Node.js test runner (.test.mjs)
└── e2e/ # Playwright tests
docs/ # Documentation
├── USER_GUIDE.md # Provider setup, CLI integration
├── API_REFERENCE.md # All endpoints
├── TROUBLESHOOTING.md # Common issues
├── ARCHITECTURE.md # System architecture
└── adr/ # Architecture Decision Records
```
---
## Přidání nového poskytovatele
### Krok 1: Služba OAuth (pokud používáte OAuth)
Vytvořte `src/lib/oauth/services/your-provider.ts` rozšiřující `OAuthService` :
```typescript
import { OAuthService } from "../OAuthService";
export class YourProviderService extends OAuthService {
constructor() {
super({
name: "your-provider",
authUrl: "https://provider.com/oauth/authorize",
tokenUrl: "https://provider.com/oauth/token",
clientId: "...",
scopes: ["..."],
});
}
}
```
### Krok 2: Registrace poskytovatele
Přidat do `src/lib/oauth/providers.ts` :
```typescript
import { YourProviderService } from "./services/your-provider";
// Add to the providers map
```
### Krok 3: Přidání konstant
Přidejte konstanty poskytovatele do `src/lib/providerConstants.ts` :
- Předpona poskytovatele (např. `yp/` )
- Výchozí modely
- Informace o cenách
### Krok 4: Přidání překladače (pokud se nejedná o formát OpenAI)
Pokud poskytovatel používá vlastní formát API, vytvořte překladač v `open-sse/translators/` .
### Krok 5: Přidání časového limitu
Přidejte konfiguraci časového limitu požadavku do `src/shared/utils/requestTimeout.ts` .
### Krok 6: Přidání testů
Pište jednotkové testy v `tests/unit/` které pokrývají minimálně:
- Registrace poskytovatele
- Překlad žádostí/odpovědí
- Ošetření chyb
---
## Kontrolní seznam žádostí o natažení
- [ ] Testy prošly ( `npm test` )
- [ ] Průchody pro linting ( `npm run lint` )
- [ ] Sestavení proběhlo úspěšně ( `npm run build` )
- [ ] Pro nové veřejné funkce a rozhraní přidány typy TypeScript
- [ ] Žádné pevně zakódované tajné kódy ani záložní hodnoty
- [ ] Aktualizován CHANGELOG (pokud se změna týká uživatele)
- [ ] Aktualizovaná dokumentace (pokud je to relevantní)
---
## Uvolnění
Když je vytvořena nová verze GitHubu (např. `v0.4.0` ), balíček je **automaticky publikován do npm** prostřednictvím akcí GitHubu:
```bash
gh release create v0.4.0 --title "v0.4.0" --generate-notes
```
---
## Získání pomoci
- **Architektura** : Viz [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
- **Problémy** : [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **ADR** : Viz `docs/adr/`

143
docs/i18n/cs/FEATURES.md Normal file
View File

@@ -0,0 +1,143 @@
# OmniRoute — Galerie funkcí řídicího panelu
🌐 **Jazyky:** 🇺🇸 [angličtina](FEATURES.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/FEATURES.md) | 🇪🇸 [Español](i18n/es/FEATURES.md) | 🇫🇷 [Français](i18n/fr/FEATURES.md) | 🇮🇹 [Italiano](i18n/it/FEATURES.md) | 🇷🇺 [Русский](i18n/ru/FEATURES.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](i18n/de/FEATURES.md) | 🇮🇳 [हिन्दी](i18n/in/FEATURES.md) | 🇹🇭 [ไทย](i18n/th/FEATURES.md) | 🇺🇦 [Українська](i18n/uk-UA/FEATURES.md) | 🇸🇦 [العربية](i18n/ar/FEATURES.md) | 🇯🇵[日本語](i18n/ja/FEATURES.md)| 🇻🇳 [Tiếng Việt](i18n/vi/FEATURES.md) | 🇧🇬 [Български](i18n/bg/FEATURES.md) | 🇩🇰 [Dánsko](i18n/da/FEATURES.md) | 🇫🇮 [Suomi](i18n/fi/FEATURES.md) | 🇮🇱 [עברית](i18n/he/FEATURES.md) | 🇭🇺 [maďarština](i18n/hu/FEATURES.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/FEATURES.md) | 🇰🇷 [한국어](i18n/ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/FEATURES.md) | 🇳🇱 [Nizozemsko](i18n/nl/FEATURES.md) | 🇳🇴 [Norsk](i18n/no/FEATURES.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/FEATURES.md) | 🇷🇴 [Română](i18n/ro/FEATURES.md) | 🇵🇱 [Polski](i18n/pl/FEATURES.md) | 🇸🇰 [Slovenčina](i18n/sk/FEATURES.md) | 🇸🇪 [Svenska](i18n/sv/FEATURES.md) | 🇵🇭 [Filipínec](i18n/phi/FEATURES.md) | 🇨🇿 [Čeština](i18n/cs/FEATURES.md)
Vizuální průvodce všemi částmi ovládacího panelu OmniRoute.
---
## 🔌 Poskytovatelé
Spravujte připojení poskytovatelů AI: poskytovatelé OAuth (Claude Code, Codex, Gemini CLI), poskytovatelé klíčů API (Groq, DeepSeek, OpenRouter) a bezplatní poskytovatelé (iFlow, Qwen, Kiro). Účty Kiro zahrnují sledování zůstatku kreditů zbývající kredity, celkový limit a datum obnovení jsou viditelné v Dashboard → Usage.
![Dashboard poskytovatelů](screenshots/01-providers.png)
---
## 🎨 Kombinace
Vytvářejte kombinace směrování modelů pomocí 6 strategií: prioritní, vážená, kruhová, náhodná, nejméně používaná a nákladově optimalizovaná. Každá kombinace řetězí více modelů s automatickým přepínáním mezi nimi a zahrnuje rychlé šablony a kontroly připravenosti.
![Dashboard kombinací](screenshots/02-combos.png)
---
## 📊 Analytika
Komplexní analýzy využití se spotřebou tokenů, odhady nákladů, mapami aktivit, týdenními distribučními grafy a rozpisy podle jednotlivých poskytovatelů.
![Analytický řídicí panel](screenshots/03-analytics.png)
---
## 🏥 Stav systému
Monitorování v reálném čase: dostupnost, paměť, verze, percentily latence (p50/p95/p99), statistiky mezipaměti a stavy jističů poskytovatelů.
![Dashboard zdraví](screenshots/04-health.png)
---
## 🔧 Překladatelské hřiště
Čtyři režimy pro ladění překladů API: **Playground** (převodník formátů), **Chat Tester** (živé požadavky), **Test Bench** (dávkové testy) a **Live Monitor** (stream v reálném čase).
![Hřiště překladatelů](screenshots/05-translator.png)
---
## 🎮 Modelové hřiště *(v2.0.9+)*
Otestujte libovolný model přímo z řídicího panelu. Vyberte poskytovatele, model a koncový bod, pište výzvy pomocí editoru Monaco, streamujte odpovědi v reálném čase, přerušte stream a zobrazte metriky časování.
---
## 🎨 Témata *(v2.0.5+)*
Přizpůsobitelná barevná témata pro celý dashboard. Vyberte si ze 7 přednastavených barev (korálová, modrá, červená, zelená, fialová, oranžová, azurová) nebo si vytvořte vlastní téma výběrem libovolné hexadecimální barvy. Podporuje světlý, tmavý a systémový režim.
---
## ⚙️ Nastavení
Komplexní panel nastavení s kartami:
- **Obecné** Systémové úložiště, správa záloh (export/import databáze)
- **Vzhled** Výběr motivu (tmavý/světlý/systémový), přednastavené barevné motivy a vlastní barvy, viditelnost protokolu stavu
- **Zabezpečení** — ochrana koncových bodů API, blokování vlastních poskytovatelů, filtrování IP adres, informace o relaci
- **Směrování** — Aliasy modelů, degradace úloh na pozadí
- **Odolnost** — Perzistence omezení rychlosti, ladění jističe
- **Pokročilé** Přepsání konfigurace
![Ovládací panel nastavení](screenshots/06-settings.png)
---
## 🔧 Nástroje CLI
Konfigurace nástrojů pro kódování s umělou inteligencí jedním kliknutím: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, Antigravity, Cline, Continue, Cursor a Factory Droid. Nabízí automatické použití/resetování konfigurace, profily připojení a mapování modelů.
![Řídicí panel nástrojů CLI](screenshots/07-cli-tools.png)
---
## 🤖 Agenti CLI *(v2.0.11+)*
Ovládací panel pro vyhledávání a správu agentů CLI. Zobrazuje mřížku 14 vestavěných agentů (Codex, Claude, Goose, Gemini CLI, OpenClaw, Aider, OpenCode, Cline, Qwen Code, ForgeCode, Amazon Q, Open Interpreter, Cursor CLI, Warp) s:
- **Stav instalace** — Nainstalováno / Nenalezeno s detekcí verze
- **Odznaky protokolů** stdio, HTTP atd.
- **Vlastní agenti** — Registrace libovolného nástroje CLI pomocí formuláře (název, binární soubor, verze příkazu, argumenty spawn)
- **Porovnávání otisků prstů v příkazovém řádku** Přepínání pro jednotlivé poskytovatele pro porovnávání nativních podpisů požadavků v příkazovém řádku, čímž se snižuje riziko zablokování a zároveň se zachovává IP adresa proxy.
---
## 🖼️ Média *(v2.0.3+)*
Generujte obrázky, videa a hudbu z řídicího panelu. Podporuje OpenAI, xAI, Together, Hyperbolic, SD WebUI, ComfyUI, AnimateDiff, Stable Audio Open a MusicGen.
---
## 📝 Vyžádat si protokoly
Protokolování požadavků v reálném čase s filtrováním podle poskytovatele, modelu, účtu a klíče API. Zobrazuje stavové kódy, využití tokenů, latenci a podrobnosti o odpovědi.
![Protokoly používání](screenshots/08-usage.png)
---
## 🌐 Koncový bod API
Váš jednotný koncový bod API s rozpisem funkcí: Dokončování chatu, API odpovědí, vkládání, generování obrázků, změna pořadí, přepis zvuku, převod textu na řeč, moderování a registrované klíče API. Podpora cloudového proxy pro vzdálený přístup.
![Dashboard koncového bodu](screenshots/09-endpoint.png)
---
## 🔑 Správa klíčů API
Vytvářejte, upravujte rozsah a rušte klíče API. Každý klíč lze omezit na konkrétní modely/poskytovatele s plným přístupem nebo oprávněním pouze pro čtení. Vizuální správa klíčů se sledováním využití.
---
## 📋 Záznam auditu
Sledování administrativních akcí s filtrováním podle typu akce, aktéra, cíle, IP adresy a časového razítka. Úplná historie bezpečnostních událostí.
---
## 🖥️ Desktopová aplikace
Desktopová aplikace Native Electron pro Windows, macOS a Linux. Spouštějte OmniRoute jako samostatnou aplikaci s integrací do systémové lišty, podporou offline, automatickými aktualizacemi a instalací jedním kliknutím.
Klíčové vlastnosti:
- Dotazování připravenosti serveru (žádná prázdná obrazovka při studeném startu)
- Systémový panel se správou portů
- Zásady zabezpečení obsahu
- Jednoinstanční zámek
- Automatická aktualizace při restartu
- Podmíněné uživatelské rozhraní pro platformu (semafory pro macOS, výchozí záhlaví okna pro Windows/Linux)
- Zpevněné balení buildů Electron — symbolicky odkazované `node_modules` v samostatném balíčku jsou detekovány a odmítnuty před balením, čímž se zabrání závislosti na buildovacím stroji za běhu (v2.5.5+)
📖 Úplnou dokumentaci naleznete v [`electron/README.md`](../electron/README.md) .

View File

@@ -0,0 +1,83 @@
# Dokumentace k serveru OmniRoute MCP
> Server protokolu kontextu modelu s 16 inteligentními nástroji
## Instalace
OmniRoute MCP je integrovaný. Spusťte ho pomocí:
```bash
omniroute --mcp
```
Nebo prostřednictvím open-sse transportu:
```bash
# HTTP streamable transport (port 20130)
omniroute --dev # MCP auto-starts on /mcp endpoint
```
## Konfigurace IDE
Viz [konfigurace IDE](integrations/ide-configs.md) pro nastavení Antigravity, Cursoru, Copilota a Claude Desktopu.
---
## Základní nástroje (8)
Nástroj | Popis
:-- | :--
`omniroute_get_health` | Stav brány, jističe, provozuschopnost
`omniroute_list_combos` | Všechny nakonfigurované kombinace s modely
`omniroute_get_combo_metrics` | Metriky výkonu pro konkrétní kombinaci
`omniroute_switch_combo` | Přepnout aktivní kombinaci podle ID/jména
`omniroute_check_quota` | Stav kvóty pro jednotlivé poskytovatele nebo všechny
`omniroute_route_request` | Odeslání dokončení chatu přes OmniRoute
`omniroute_cost_report` | Analýza nákladů za určité časové období
`omniroute_list_models_catalog` | Kompletní katalog modelů s funkcemi
## Pokročilé nástroje (8)
Nástroj | Popis
:-- | :--
`omniroute_simulate_route` | Simulace trasování na dryru s fallback stromem
`omniroute_set_budget_guard` | Rozpočet relace s akcemi degradace/blokování/upozornění
`omniroute_set_resilience_profile` | Použít konzervativní/vyvážený/agresivní předvolbu
`omniroute_test_combo` | Živé testování všech modelů v kombinaci
`omniroute_get_provider_metrics` | Podrobné metriky pro jednoho poskytovatele
`omniroute_best_combo_for_task` | Doporučení pro splnění úkolu a jeho vhodnosti s alternativami
`omniroute_explain_route` | Vysvětlete minulé rozhodnutí o trase
`omniroute_get_session_snapshot` | Stav celé relace: náklady, tokeny, chyby
## Ověřování
Nástroje MCP jsou ověřovány pomocí rozsahů klíčů API. Každý nástroj vyžaduje specifické rozsahy:
Rozsah | Nástroje
:-- | :--
`read:health` | get_health, get_provider_metrics
`read:combos` | seznam_kombinací, získání_kombinovaných_metrik
`write:combos` | přepínač_kombinace
`read:quota` | check_quote
`write:route` | požadavek_trasy, simulace_trasy, testovací_kombinace
`read:usage` | zpráva_o_nákladech, získání_snímku_relace, vysvětlení_trasy
`write:config` | set_budget_guard, set_resilience_profile
`read:models` | seznam_modelů_katalog, nejlepší_kombinace_pro_úkol
## Protokolování auditu
Každé volání nástroje je zaznamenáno do `mcp_tool_audit` s touto funkcí:
- Název nástroje, argumenty, výsledek
- Trvání (ms), úspěch/neúspěch
- Haš klíče API, časové razítko
## Soubory
Soubor | Účel
:-- | :--
`open-sse/mcp-server/server.ts` | Vytvoření MCP serveru + 16 registrací nástrojů
`open-sse/mcp-server/transport.ts` | Stdio + HTTP transport
`open-sse/mcp-server/auth.ts` | Ověření klíče API + rozsahu
`open-sse/mcp-server/audit.ts` | Protokolování auditu volání nástrojů
`open-sse/mcp-server/tools/advancedTools.ts` | 8 pokročilých manipulátorů s nástroji

2010
docs/i18n/cs/README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
# Kontrolní seznam vydání
Tento kontrolní seznam použijte před označením nebo publikováním nové verze OmniRoute.
## Verze a seznam změn
1. Navýšit verzi `package.json` ( `xyz` ) ve větvi release.
2. Přesunout poznámky k vydání z `## [Unreleased]` v `CHANGELOG.md` do sekce s datem vydání:
- `## [x.y.z] — YYYY-MM-DD`
3. Ponechte `## [Unreleased]` jako první sekci changelogu pro nadcházející práci.
4. Ujistěte se, že nejnovější sekce semver v `CHANGELOG.md` je rovna verzi `package.json` .
## Dokumentace API
1. Aktualizace `docs/openapi.yaml` :
- Soubor `info.version` se musí rovnat verzi `package.json` .
2. Ověřte příklady koncových bodů, pokud se změnily smlouvy API.
## Dokumentace k běhovému prostředí
1. Projděte si `docs/ARCHITECTURE.md` , zda nedochází k posunu v úložišti/běhovém prostředí.
2. Projděte si soubor `docs/TROUBLESHOOTING.md` , kde naleznete informace o proměnné prostředí a provozním posunu.
3. Aktualizujte lokalizovanou dokumentaci, pokud se zdrojová dokumentace výrazně změnila.
## Automatická kontrola
Před otevřením PR spusťte lokálně ochranu synchronizace:
```bash
npm run check:docs-sync
```
CI také spouští tuto kontrolu v `.github/workflows/ci.yml` (úloha lint).

169
docs/i18n/cs/SECURITY.md Normal file
View File

@@ -0,0 +1,169 @@
# Bezpečnostní zásady
## Hlášení zranitelností
Pokud v OmniRoute objevíte bezpečnostní zranitelnost, nahlaste ji prosím zodpovědně:
1. **NEOTVÍREJTE** veřejný problém na GitHubu
2. Používejte [bezpečnostní doporučení GitHubu](https://github.com/diegosouzapw/OmniRoute/security/advisories/new)
3. Zahrňte: popis, kroky reprodukce a potenciální dopad
## Časová osa odezvy
Fáze | Cíl
--- | ---
Potvrzení | 48 hodin
Triáž a posouzení | 5 pracovních dnů
Vydání záplaty | 14 pracovních dnů (kritické)
## Podporované verze
Verze | Stav podpory
--- | ---
1.0.x | ✅ Aktivní
0.8.x | ✅ Bezpečnost
&lt; 0,8,0 | ❌ Nepodporováno
---
## Bezpečnostní architektura
OmniRoute implementuje vícevrstvý bezpečnostní model:
```
Request → CORS → API Key Auth → Prompt Injection Guard → Input Sanitizer → Rate Limiter → Circuit Breaker → Provider
```
### 🔐 Ověřování a autorizace
Funkce | Implementace
--- | ---
**Přihlášení do ovládacího panelu** | Ověřování na základě hesla s tokeny JWT (soubory cookie HttpOnly)
**Autorizace klíče API** | Klíče podepsané HMAC s ověřením CRC
**OAuth 2.0 + PKCE** | Bezpečné ověřování poskytovatelů (Claude, Codex, Gemini, Cursor atd.)
**Obnovení tokenu** | Automatická aktualizace tokenu OAuth před vypršením platnosti
**Bezpečné soubory cookie** | `AUTH_COOKIE_SECURE=true` pro prostředí HTTPS
### 🛡️ Šifrování v klidovém stavu
Všechna citlivá data uložená v SQLite jsou šifrována pomocí **AES-256-GCM** s odvozením klíče scrypt:
- Klíče API, přístupové tokeny, obnovovací tokeny a ID tokeny
- Verzovaný formát: `enc:v1:<iv>:<ciphertext>:<authTag>`
- Režim průchodu (prostý text), pokud není nastaven `STORAGE_ENCRYPTION_KEY`
```bash
# Generate encryption key:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
```
### 🧠 Ochrana před okamžitou injekcí
Middleware, který detekuje a blokuje útoky prompt injection v požadavcích LLM:
Typ vzoru | Závažnost | Příklad
--- | --- | ---
Přepsání systému | Vysoký | "ignorovat všechny předchozí pokyny"
Únos role | Vysoký | "Teď jsi DAN, dokážeš cokoli."
Vložení oddělovače | Střední | Kódované oddělovače pro přerušení hranic kontextu
DAN/Útěk z vězení | Vysoký | Známé vzory výzev k jailbreaku
Únik instrukcí | Střední | „Ukaž mi systémový výzvu“
Konfigurace přes ovládací panel (Nastavení → Zabezpečení) nebo `.env` :
```env
INPUT_SANITIZER_ENABLED=true
INPUT_SANITIZER_MODE=block # warn | block | redact
```
### 🔒 Redakční úprava osobních údajů
Automatická detekce a volitelná redakce osobních údajů:
Typ osobních údajů | Vzor | Nahrazení
--- | --- | ---
E-mail | `user@domain.com` | `[EMAIL_REDACTED]`
CPF (Brazílie) | `123.456.789-00` | `[CPF_REDACTED]`
CNPJ (Brazílie) | `12.345.678/0001-00` | `[CNPJ_REDACTED]`
Kreditní karta | `4111-1111-1111-1111` | `[CC_REDACTED]`
Telefon | `+55 11 99999-9999` | `[PHONE_REDACTED]`
Číslo sociálního zabezpečení (USA) | `123-45-6789` | `[SSN_REDACTED]`
```env
PII_REDACTION_ENABLED=true
```
### 🌐 Zabezpečení sítě
Funkce | Popis
--- | ---
**CORS** | Konfigurovatelná kontrola původu (proměnná prostředí `CORS_ORIGIN` , výchozí nastavení `*` )
**Filtrování IP adres** | Rozsahy IP adres na bílou/černou listinu v dashboardu
**Omezení rychlosti** | Limity sazeb na poskytovatele s automatickým ukončením
**Protihromové stádo** | Mutex + uzamčení pro každé připojení zabraňuje kaskádování 502.
### 🔌 Odolnost a dostupnost
Funkce | Popis
--- | ---
**Jistič** | 3 stavy (Zavřeno → Otevřeno → Polootevřeno) na poskytovatele, trvalé uložení v SQLite
**Žádost o idempotenci** | 5sekundové okno pro odstranění duplicitních požadavků
**Exponenciální odklon** | Automatické opakování s rostoucím zpožděním
**Dashboard zdraví** | Monitorování stavu poskytovatele v reálném čase
### 📋 Dodržování předpisů
Funkce | Popis
--- | ---
**Uchovávání protokolů** | Automatické čištění po `LOG_RETENTION_DAYS`
**Odhlášení bez ukládání protokolů** | Příznak `noLog` pro každý klíč API zakazuje protokolování požadavků.
**Protokol auditu** | Administrativní akce sledované v tabulce `audit_log`
---
## Požadované proměnné prostředí
Všechny tajné kódy musí být nastaveny před spuštěním serveru. Server **rychle selže** , pokud chybí nebo jsou slabé.
```bash
# REQUIRED — server will not start without these:
JWT_SECRET=$(openssl rand -base64 48) # min 32 chars
API_KEY_SECRET=$(openssl rand -hex 32) # min 16 chars
# RECOMMENDED — enables encryption at rest:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
```
Server aktivně odmítá známé slabé hodnoty, jako například `changeme` , `secret` nebo `password` .
---
## Zabezpečení Dockeru
- Použití uživatele bez oprávnění root v produkčním prostředí
- Připojte tajné kódy jako svazky jen pro čtení
- Nikdy nekopírujte soubory `.env` do imagí Dockeru
- Použití `.dockerignore` k vyloučení citlivých souborů
- Nastavit `AUTH_COOKIE_SECURE=true` při připojení za HTTPS
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
--read-only \
-p 20128:20128 \
-v omniroute-data:/app/data \
-e JWT_SECRET="$(openssl rand -base64 48)" \
-e API_KEY_SECRET="$(openssl rand -hex 32)" \
-e STORAGE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
diegosouzapw/omniroute:latest
```
---
## Závislosti
- Pravidelně spouštějte `npm audit`
- Udržujte závislosti aktualizované
- Projekt používá pro kontroly před commitem `husky` + `lint-staged`
- CI pipeline spouští bezpečnostní pravidla ESLint při každém odeslání.

View File

@@ -0,0 +1,254 @@
# Odstraňování problémů
🌐 **Jazyky:** 🇺🇸 [angličtina](TROUBLESHOOTING.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](i18n/es/TROUBLESHOOTING.md) | 🇫🇷 [Français](i18n/fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](i18n/it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](i18n/ru/TROUBLESHOOTING.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](i18n/de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](i18n/in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](i18n/th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](i18n/uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](i18n/ar/TROUBLESHOOTING.md) | 🇯🇵[日本語](i18n/ja/TROUBLESHOOTING.md)| 🇻🇳 [Tiếng Việt](i18n/vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](i18n/bg/TROUBLESHOOTING.md) | 🇩🇰 [Dánsko](i18n/da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](i18n/fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](i18n/he/TROUBLESHOOTING.md) | 🇭🇺 [maďarština](i18n/hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](i18n/ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/TROUBLESHOOTING.md) | 🇳🇱 [Nizozemsko](i18n/nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](i18n/no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](i18n/ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](i18n/pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](i18n/sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](i18n/sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipínec](i18n/phi/TROUBLESHOOTING.md) | 🇨🇿 [Čeština](i18n/cs/TROUBLESHOOTING.md)
Běžné problémy a řešení pro OmniRoute.
---
## Rychlé opravy
Problém | Řešení
--- | ---
První přihlášení nefunguje | Nastavit `INITIAL_PASSWORD` v `.env` (bez pevně zakódovaného výchozího nastavení)
Dashboard se otevírá na nesprávném portu | Nastavte `PORT=20128` a `NEXT_PUBLIC_BASE_URL=http://localhost:20128`
Žádné protokoly požadavků v sekci `logs/` | Nastavte `ENABLE_REQUEST_LOGS=true`
PŘÍSTUP: povolení zamítnuto | Nastavením `DATA_DIR=/path/to/writable/dir` přepíšete `~/.omniroute`
Strategie směrování se neukládá | Aktualizace na v1.4.11+ (oprava schématu Zod pro perzistenci nastavení)
---
## Problémy s poskytovateli
### "Jazykový model neposkytoval zprávy"
**Příčina:** Vyčerpání kvóty poskytovatele.
**Opravit:**
1. Zkontrolujte sledovač kvót na řídicím panelu
2. Použijte kombinaci se záložními úrovněmi
3. Přepnout na levnější/bezplatnou úroveň
### Omezení rychlosti
**Příčina:** Vyčerpání kvóty předplatného.
**Opravit:**
- Přidat záložní variantu: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
- Použijte GLM/MiniMax jako levnou zálohu
### Platnost tokenu OAuth vypršela
OmniRoute automaticky obnovuje tokeny. Pokud problémy přetrvávají:
1. Ovládací panel → Poskytovatel → Znovu připojit
2. Odstranění a opětovné přidání připojení poskytovatele
---
## Problémy s cloudem
### Chyby synchronizace s cloudem
1. Ověřte, zda `BASE_URL` odkazuje na vaši spuštěnou instanci (např. `http://localhost:20128` )
2. Ověřte, zda `CLOUD_URL` odkazuje na váš cloudový koncový bod (např. `https://omniroute.dev` ).
3. Udržujte hodnoty `NEXT_PUBLIC_*` zarovnané s hodnotami na straně serveru.
### Cloud `stream=false` Vrací 500
**Příznak:** `Unexpected token 'd'...` na cloudovém koncovém bodu pro nestreamovaná volání.
**Příčina:** Upstream vrací datovou část SSE, zatímco klient očekává JSON.
**Řešení:** Pro přímá volání z cloudu použijte `stream=true` . Lokální běhové prostředí zahrnuje záložní SSE→JSON.
### Cloud hlásí připojení, ale „neplatný klíč API“.
1. Vytvořte nový klíč z lokálního dashboardu ( `/api/keys` )
2. Spuštění synchronizace s cloudem: Povolit cloud → Synchronizovat nyní
3. Staré/nesynchronizované klíče mohou v cloudu stále vracet `401`
---
## Problémy s Dockerem
### Nástroj CLI se zobrazuje jako nenainstalovaný
1. Zkontrolujte běhová pole: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
2. Pro přenosný režim: použijte cílový soubor image `runner-cli` (dodávané CLI)
3. Pro režim připojení hostitele: nastavte `CLI_EXTRA_PATHS` a připojte adresář hostitele bin jako pouze pro čtení.
4. Pokud `installed=true` a `runnable=false` : binární soubor byl nalezen, ale kontrola stavu selhala.
### Rychlé ověření za běhu
```bash
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
```
---
## Problémy s náklady
### Vysoké náklady
1. Zkontrolujte statistiky využití v sekci Nástěnka → Využití
2. Přepnout primární model na GLM/MiniMax
3. Pro nekritické úlohy použijte bezplatnou úroveň (Gemini CLI, iFlow).
4. Nastavení rozpočtů nákladů pro každý klíč API: Dashboard → API klíče → Rozpočet
---
## Ladění
### Povolit protokoly požadavků
V souboru `.env` nastavte `ENABLE_REQUEST_LOGS=true` . Protokoly se zobrazují v adresáři `logs/` .
### Zkontrolujte stav poskytovatele
```bash
# Health dashboard
http://localhost:20128/dashboard/health
# API health check
curl http://localhost:20128/api/monitoring/health
```
### Runtimové úložiště
- Hlavní stav: `${DATA_DIR}/storage.sqlite` (poskytovatelé, kombinace, aliasy, klíče, nastavení)
- Použití: SQLite tabulky v `storage.sqlite` ( `usage_history` , `call_logs` , `proxy_logs` ) + volitelné `${DATA_DIR}/log.txt` a `${DATA_DIR}/call_logs/`
- Záznamy požadavků: `<repo>/logs/...` (pokud `ENABLE_REQUEST_LOGS=true` )
---
## Problémy s jističi
### Poskytovatel uvízl ve stavu OPEN (OTEVŘENO)
Pokud je jistič poskytovatele VYPNUTÝ, požadavky jsou blokovány, dokud neuplyne doba ochlazování.
**Opravit:**
1. Přejděte do **nabídky Ovládací panel → Nastavení → Odolnost**
2. Zkontrolujte kartu jističe u dotčeného poskytovatele
3. Kliknutím na **Obnovit vše** vynulujete všechny jističe nebo počkejte, až vyprší doba zpoždění.
4. Před resetováním ověřte, zda je poskytovatel skutečně dostupný.
### Poskytovatel neustále vypíná jistič
Pokud poskytovatel opakovaně přechází do stavu OTEVŘENO:
1. Zkontrolujte **v části Dashboard → Stav → Stav poskytovatele** vzorec selhání.
2. Přejděte do **Nastavení → Odolnost → Profily poskytovatelů** a zvyšte prahovou hodnotu selhání.
3. Zkontrolujte, zda poskytovatel změnil limity API nebo vyžaduje opětovné ověření.
4. Zkontrolujte telemetrii latence vysoká latence může způsobit selhání z důvodu časového limitu.
---
## Problémy s přepisem zvuku
### Chyba „Nepodporovaný model“
- Ujistěte se, že používáte správný prefix: `deepgram/nova-3` nebo `assemblyai/best`
- Ověřte, zda je poskytovatel připojen v **nabídce Dashboard → Poskytovatelé.**
### Přepis vrací prázdný výsledek nebo selže
- Zkontrolujte podporované zvukové formáty: `mp3` , `wav` , `m4a` , `flac` , `ogg` , `webm`
- Ověřte, zda je velikost souboru v rámci limitů poskytovatele (obvykle &lt; 25 MB)
- Zkontrolujte platnost klíče API poskytovatele v kartě poskytovatele
---
## Ladění překladače
Pro ladění problémů s překladem formátu použijte **Dashboard → Translator** :
Režim | Kdy použít
--- | ---
**Dětské hřiště** | Porovnejte vstupní/výstupní formáty vedle sebe vložte neúspěšný požadavek a podívejte se, jak se přeloží
**Tester chatu** | Odesílejte živé zprávy a kontrolujte kompletní datovou část požadavků/odpovědí včetně záhlaví
**Zkušební stolice** | Spusťte dávkové testy napříč kombinacemi formátů a zjistěte, které překlady jsou poškozené.
**Živý monitor** | Sledujte tok požadavků v reálném čase a zachyťte občasné problémy s překladem
### Běžné problémy s formátováním
- **Štítky myšlení se nezobrazují** Zkontrolujte, zda cílový poskytovatel podporuje myšlení a nastavení rozpočtu myšlení.
- **Volání nástrojů se vynechávají** Některé překlady formátů mohou odstranit nepodporovaná pole; ověřte v režimu Playground.
- **Chybí systémová výzva** Claude a Gemini zpracovávají systémové výzvy odlišně; zkontrolujte překlad výstupu
- **SDK vrací nezpracovaný řetězec místo objektu** Opraveno ve verzi 1.1.0: sanitizér odpovědí nyní odstraňuje nestandardní pole ( `x_groq` , `usage_breakdown` atd.), která způsobují selhání validace OpenAI SDK v Pydantic.
- **GLM/ERNIE odmítá `system` roli** — Opraveno ve verzi 1.1.0: normalizátor rolí automaticky slučoval systémové zprávy s uživatelskými zprávami pro nekompatibilní modely.
- **role `developer` nebyla rozpoznána** Opraveno ve verzi 1.1.0: automaticky převedeno na `system` pro poskytovatele, kteří nepoužívají OpenAI
- **`json_schema` nefunguje s Gemini** — Opraveno ve verzi 1.1.0: `response_format` se nyní převádí na `responseMimeType` + `responseSchema` z Gemini.
---
## Nastavení odolnosti
### Automatické omezení rychlosti se nespouští
- Automatické omezení rychlosti se vztahuje pouze na poskytovatele klíčů API (ne na OAuth/předplatné)
- Ověřte **Nastavení → Odolnost → Profily poskytovatelů** mají povoleno automatické omezení rychlosti
- Zkontrolujte, zda poskytovatel vrací stavové kódy `429` nebo hlavičky `Retry-After`
### Ladění exponenciálního poklesu
Profily poskytovatelů podporují tato nastavení:
- **Základní zpoždění** — Počáteční doba čekání po prvním selhání (výchozí: 1 s)
- **Max. zpoždění** — Maximální doba čekání (výchozí: 30 s)
- **Násobitel** — O kolik se má zvýšit zpoždění za každou po sobě jdoucí chybu (výchozí: 2x)
### Stádo proti hromům
Když se na poskytovatele s omezenou rychlostí odesílá mnoho souběžných požadavků, OmniRoute použije mutex + automatické omezení rychlosti k serializaci požadavků a zabránění kaskádovým selháním. Toto je automatické pro poskytovatele klíčů API.
---
## Volitelná taxonomie selhání RAG / LLM (16 problémů)
Někteří uživatelé OmniRoute umisťují bránu před RAG nebo agent stacky. V těchto nastaveních je běžné vidět zvláštní vzorec: OmniRoute vypadá v pořádku (poskytovatelé aktivní, profily směrování v pořádku, žádná upozornění na limity rychlosti), ale konečná odpověď je stále nesprávná.
V praxi tyto incidenty obvykle pocházejí z následného RAG kanálu, nikoli ze samotné brány.
Pokud chcete sdílenou slovní zásobu pro popis těchto selhání, můžete použít WFGY ProblemMap, externí textový zdroj s licencí MIT, který definuje šestnáct opakujících se vzorců selhání RAG / LLM. Na obecné úrovni zahrnuje:
- drift vyhledávání a narušené hranice kontextu
- prázdné nebo zastaralé indexy a vektorové úložiště
- vkládání versus sémantický nesoulad
- problémy s assembly promptu a kontextovým oknem
- logický kolaps a přehnaně sebevědomé odpovědi
- selhání dlouhého řetězce a koordinace agentů
- paměť více agentů a posun rolí
- problémy s nasazením a objednáváním bootstrapů
Myšlenka je jednoduchá:
1. Při vyšetřování špatné odpovědi zaznamenejte:
- úkol a požadavek uživatele
- Kombinace trasy nebo poskytovatele v OmniRoute
- jakýkoli kontext RAG použitý v následných fázích (načtené dokumenty, volání nástrojů atd.)
2. Namapujte incident na jedno nebo dvě čísla z WFGY ProblemMap ( `No.1``No.16` ).
3. Uložte číslo do vlastního řídicího panelu, runbooku nebo sledovače incidentů vedle protokolů OmniRoute.
4. Pro rozhodnutí, zda je potřeba změnit RAG stack, retriever nebo směrovací strategii, použijte odpovídající stránku WFGY.
Plný text a konkrétní recepty naleznete zde (licence MIT, pouze text):
[Soubor README pro mapu problémů WFGY](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
Tuto část můžete ignorovat, pokud za OmniRoute nespouštěte RAG ani agenty.
---
## Stále v koncích?
- **Problémy s GitHubem** : [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **Architektura** : Viz [`docs/ARCHITECTURE.md`](ARCHITECTURE.md) pro interní podrobnosti
- **Referenční informace k API** : Všechny koncové body naleznete v [`docs/API_REFERENCE.md`](API_REFERENCE.md)
- **Panel stavu** : Zkontrolujte **Panel stavu, kde** najdete stav systému v reálném čase.
- **Překladač** : Použijte **Dashboard → Překladač** k ladění problémů s formátem

814
docs/i18n/cs/USER_GUIDE.md Normal file
View File

@@ -0,0 +1,814 @@
# Uživatelská příručka
🌐 **Jazyky:** 🇺🇸 [angličtina](USER_GUIDE.md) | 🇧🇷 [Português (Brazílie)](i18n/pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](i18n/es/USER_GUIDE.md) | 🇫🇷 [Français](i18n/fr/USER_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/USER_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/USER_GUIDE.md) | 🇨🇳[中文 (简体)](i18n/zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/USER_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/USER_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/USER_GUIDE.md) | 🇯🇵[日本語](i18n/ja/USER_GUIDE.md)| 🇻🇳 [Tiếng Việt](i18n/vi/USER_GUIDE.md) | 🇧🇬 [Български](i18n/bg/USER_GUIDE.md) | 🇩🇰 [Dánsko](i18n/da/USER_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/USER_GUIDE.md) | 🇮🇱 [עברית](i18n/he/USER_GUIDE.md) | 🇭🇺 [maďarština](i18n/hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonésie](i18n/id/USER_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/USER_GUIDE.md) | 🇳🇱 [Nizozemsko](i18n/nl/USER_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/USER_GUIDE.md) | 🇵🇹 [Português (Portugalsko)](i18n/pt/USER_GUIDE.md) | 🇷🇴 [Română](i18n/ro/USER_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/USER_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/USER_GUIDE.md) | 🇵🇭 [Filipínec](i18n/phi/USER_GUIDE.md) | 🇨🇿 [Čeština](i18n/cs/USER_GUIDE.md)
Kompletní průvodce konfigurací poskytovatelů, vytvářením kombinací, integrací nástrojů CLI a nasazením OmniRoute.
---
## Obsah
- [Ceny v kostce](#-pricing-at-a-glance)
- [Případy použití](#-use-cases)
- [Nastavení poskytovatele](#-provider-setup)
- [Integrace s rozhraním CLI](#-cli-integration)
- [Nasazení](#-deployment)
- [Dostupné modely](#-available-models)
- [Pokročilé funkce](#-advanced-features)
---
## 💰 Přehled cen
Úroveň | Poskytovatel | Náklady | Obnovení kvóty | Nejlepší pro
--- | --- | --- | --- | ---
**💳 PŘEDPLATNÉ** | Claude Code (profesionál) | 20 dolarů měsíčně | 5 hodin + týdně | Již přihlášen/a k odběru
| Kodex (Plus/Pro) | 20200 USD/měsíc | 5 hodin + týdně | Uživatelé OpenAI
| Rozhraní příkazového řádku Gemini | **UVOLNIT** | 180 tisíc měsíčně + 1 tisíc denně | Každý!
| GitHub Copilot | 1019 USD/měsíc | Měsíční | Uživatelé GitHubu
**🔑 KLÍČ API** | Hluboké vyhledávání | Platba za použití | Žádný | Laciné uvažování
| Groq | Platba za použití | Žádný | Ultrarychlá inference
| xAI (Grok) | Platba za použití | Žádný | Grok 4 uvažování
| Mistral | Platba za použití | Žádný | Modely hostované v EU
| Zmatek | Platba za použití | Žádný | Rozšířené vyhledávání
| Společně s umělou inteligencí | Platba za použití | Žádný | Modely s otevřeným zdrojovým kódem
| Ohňostroj s umělou inteligencí | Platba za použití | Žádný | Rychlé snímky FLUX
| Mozky | Platba za použití | Žádný | Rychlost v měřítku destičky
| Soudržný | Platba za použití | Žádný | Příkaz R+ RAG
| NVIDIA NIM | Platba za použití | Žádný | Podnikové modely
**💰 LEVNÉ** | GLM-4.7 | 0,6 USD/1 milion | Denně v 10:00 | Záloha rozpočtu
| MiniMax M2.1 | 0,2 USD/1 milion | 5hodinové válcování | Nejlevnější varianta
| Kimi K2 | 9 dolarů měsíčně bez závazků | 10 milionů tokenů/měsíc | Předvídatelné náklady
**🆓 ZDARMA** | iFlow | 0 dolarů | Neomezený | 8 modelů zdarma
| Qwen | 0 dolarů | Neomezený | 3 modely zdarma
| Kiro | 0 dolarů | Neomezený | Claude zdarma
**💡 Tip pro profesionály:** Začněte s kombinací Gemini CLI (180 tisíc zdarma/měsíc) + iFlow (neomezeně zdarma) = 0 dolarů!
---
## 🎯 Případy použití
### Případ 1: „Mám předplatné Claude Pro“
**Problém:** Kvóta vyprší, nevyužitá, limity rychlosti během náročného kódování
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (use subscription fully)
2. glm/glm-4.7 (cheap backup when quota out)
3. if/kimi-k2-thinking (free emergency fallback)
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Případ 2: „Chci nulové náklady“
**Problém:** Nemůžu si dovolit předplatné, potřebuji spolehlivé kódování s využitím umělé inteligence
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K free/month)
2. if/kimi-k2-thinking (unlimited free)
3. qw/qwen3-coder-plus (unlimited free)
Monthly cost: $0
Quality: Production-ready models
```
### Případ 3: „Potřebuji kódování 24 hodin denně, 7 dní v týdnu, bez přerušení“
**Problém:** Termíny, nemůžeme si dovolit prostoje
```
Combo: "always-on"
1. cc/claude-opus-4-6 (best quality)
2. cx/gpt-5.2-codex (second subscription)
3. glm/glm-4.7 (cheap, resets daily)
4. minimax/MiniMax-M2.1 (cheapest, 5h reset)
5. if/kimi-k2-thinking (free unlimited)
Result: 5 layers of fallback = zero downtime
Monthly cost: $20-200 (subscriptions) + $10-20 (backup)
```
### Případ 4: „Chci BEZPLATNOU AI v OpenClaw“
**Problém:** Potřebujete asistenta s umělou inteligencí v aplikacích pro zasílání zpráv, zcela zdarma
```
Combo: "openclaw-free"
1. if/glm-4.7 (unlimited free)
2. if/minimax-m2.1 (unlimited free)
3. if/kimi-k2-thinking (unlimited free)
Monthly cost: $0
Access via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 📖 Nastavení poskytovatele
### 🔐 Poskytovatelé předplatného
#### Claude Code (Pro/Max)
```bash
Dashboard → Providers → Connect Claude Code
→ OAuth login → Auto token refresh
→ 5-hour + weekly quota tracking
Models:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Tip pro profesionály:** Pro složité úkoly používejte Opus, pro rychlost Sonnet. OmniRoute sleduje kvótu pro každý model!
#### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Providers → Connect Codex
→ OAuth login (port 1455)
→ 5-hour + weekly reset
Models:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
#### Gemini CLI (ZDARMA 180 000/měsíc!)
```bash
Dashboard → Providers → Connect Gemini CLI
→ Google OAuth
→ 180K completions/month + 1K/day
Models:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Nejlepší hodnota:** Obrovská bezplatná úroveň! Použijte ji před placenými úrovněmi.
#### GitHub Copilot
```bash
Dashboard → Providers → Connect GitHub
→ OAuth via GitHub
→ Monthly reset (1st of month)
Models:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
### 💰 Levní poskytovatelé
#### GLM-4.7 (Denní reset, 0,6 USD/1 milion)
1. Registrace: [Zhipu AI](https://open.bigmodel.cn/)
2. Získejte klíč API z kódovacího plánu
3. Nástěnka → Přidat klíč API: Poskytovatel: `glm` , klíč API: `your-key`
**Použití:** `glm/glm-4.7`**Tip pro profesionály:** Coding Plan nabízí 3× kvótu za cenu 1/7! Resetovat denně v 10:00.
#### MiniMax M2.1 (5h reset, 0,20 $/1 milion)
1. Registrace: [MiniMax](https://www.minimax.io/)
2. Získat API klíč → Dashboard → Přidat API klíč
**Použití:** `minimax/MiniMax-M2.1`**Tip pro profesionály:** Nejlevnější varianta pro dlouhý kontext (1 milion tokenů)!
#### Kimi K2 (paušální poplatek 9 dolarů měsíčně)
1. Odebírat: [Moonshot AI](https://platform.moonshot.ai/)
2. Získat API klíč → Dashboard → Přidat API klíč
**Použití:** `kimi/kimi-latest`**Tip pro profesionály:** Fixní cena 9 $/měsíc za 10 milionů tokenů = efektivní náklady 0,90 $/1 milion!
### 🆓 Poskytovatelé ZDARMA
#### iFlow (8 modelů ZDARMA)
```bash
Dashboard → Connect iFlow → OAuth login → Unlimited usage
Models: if/kimi-k2-thinking, if/qwen3-coder-plus, if/glm-4.7, if/minimax-m2, if/deepseek-r1
```
#### Qwen (3 modely ZDARMA)
```bash
Dashboard → Connect Qwen → Device code auth → Unlimited usage
Models: qw/qwen3-coder-plus, qw/qwen3-coder-flash
```
#### Kiro (Claude ZDARMA)
```bash
Dashboard → Connect Kiro → AWS Builder ID or Google/GitHub → Unlimited
Models: kr/claude-sonnet-4.5, kr/claude-haiku-4.5
```
---
## 🎨 Kombinace
### Příklad 1: Maximalizace předplatného → Levné zálohování
```
Dashboard → Combos → Create New
Name: premium-coding
Models:
1. cc/claude-opus-4-6 (Subscription primary)
2. glm/glm-4.7 (Cheap backup, $0.6/1M)
3. minimax/MiniMax-M2.1 (Cheapest fallback, $0.20/1M)
Use in CLI: premium-coding
```
### Příklad 2: Pouze zdarma (nulové náklady)
```
Name: free-combo
Models:
1. gc/gemini-3-flash-preview (180K free/month)
2. if/kimi-k2-thinking (unlimited)
3. qw/qwen3-coder-plus (unlimited)
Cost: $0 forever!
```
---
## 🔧 Integrace s rozhraním příkazového řádku
### IDE kurzoru
```
Settings → Models → Advanced:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [from omniroute dashboard]
Model: cc/claude-opus-4-6
```
### Claude Code
Upravit `~/.claude/config.json` :
```json
{
"anthropic_api_base": "http://localhost:20128/v1",
"anthropic_api_key": "your-omniroute-api-key"
}
```
### CLI Codexu
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
Upravit `~/.openclaw/openclaw.json` :
```json
{
"agents": {
"defaults": {
"model": { "primary": "omniroute/if/glm-4.7" }
}
},
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://localhost:20128/v1",
"apiKey": "your-omniroute-api-key",
"api": "openai-completions",
"models": [{ "id": "if/glm-4.7", "name": "glm-4.7" }]
}
}
}
}
```
**Nebo použijte Dashboard:** CLI Tools → OpenClaw → Auto-config
### Cline / Pokračovat / RooCode
```
Provider: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [from dashboard]
Model: cc/claude-opus-4-6
```
---
## 🚀 Nasazení
### Globální instalace npm (doporučeno)
```bash
npm install -g omniroute
# Create config directory
mkdir -p ~/.omniroute
# Create .env file (see .env.example)
cp .env.example ~/.omniroute/.env
# Start server
omniroute
# Or with custom port:
omniroute --port 3000
```
Rozhraní příkazového řádku automaticky načte `.env` z adresáře `~/.omniroute/.env` nebo `./.env` .
### Nasazení VPS
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute && npm install && npm run build
export JWT_SECRET="your-secure-secret-change-this"
export INITIAL_PASSWORD="your-password"
export DATA_DIR="/var/lib/omniroute"
export PORT="20128"
export HOSTNAME="0.0.0.0"
export NODE_ENV="production"
export NEXT_PUBLIC_BASE_URL="http://localhost:20128"
export API_KEY_SECRET="endpoint-proxy-api-key-secret"
npm run start
# Or: pm2 start npm --name omniroute -- start
```
### Nasazení PM2 (málo paměti)
Pro servery s omezenou pamětí RAM použijte možnost omezení paměti:
```bash
# With 512MB limit (default)
pm2 start npm --name omniroute -- start
# Or with custom memory limit
OMNIROUTE_MEMORY_MB=512 pm2 start npm --name omniroute -- start
# Or using ecosystem.config.js
pm2 start ecosystem.config.js
```
Vytvořte soubor `ecosystem.config.js` :
```javascript
module.exports = {
apps: [
{
name: "omniroute",
script: "npm",
args: "start",
env: {
NODE_ENV: "production",
OMNIROUTE_MEMORY_MB: "512",
JWT_SECRET: "your-secret",
INITIAL_PASSWORD: "your-password",
},
node_args: "--max-old-space-size=512",
max_memory_restart: "300M",
},
],
};
```
### Přístavní dělník
```bash
# Build image (default = runner-cli with codex/claude/droid preinstalled)
docker build -t omniroute:cli .
# Portable mode (recommended)
docker run -d --name omniroute -p 20128:20128 --env-file ./.env -v omniroute-data:/app/data omniroute:cli
```
Informace o režimu integrovaném s hostitelem s binárními soubory CLI naleznete v části Docker v hlavní dokumentaci.
### Proměnné prostředí
Proměnná | Výchozí | Popis
--- | --- | ---
`JWT_SECRET` | `omniroute-default-secret-change-me` | Tajný klíč podpisu JWT ( **změna v produkčním prostředí** )
`INITIAL_PASSWORD` | `123456` | První přihlašovací heslo
`DATA_DIR` | `~/.omniroute` | Datový adresář (db, využití, protokoly)
`PORT` | výchozí nastavení rámce | Servisní port ( `20128` v příkladech)
`HOSTNAME` | výchozí nastavení rámce | Vázat hostitele (Docker má výchozí hodnotu `0.0.0.0` )
`NODE_ENV` | výchozí nastavení za běhu | Nastavení `production` pro nasazení
`BASE_URL` | `http://localhost:20128` | Interní základní URL na straně serveru
`CLOUD_URL` | `https://omniroute.dev` | Základní adresa URL koncového bodu synchronizace s cloudem
`API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | Tajný klíč HMAC pro generované klíče API
`REQUIRE_API_KEY` | `false` | Vynutit klíč rozhraní Bearer API na `/v1/*`
`ENABLE_REQUEST_LOGS` | `false` | Povoluje protokolování požadavků/odpovědí
`AUTH_COOKIE_SECURE` | `false` | Vynutit soubor cookie `Secure` ověřování (za reverzní proxy HTTPS)
`OMNIROUTE_MEMORY_MB` | `512` | Limit haldy Node.js v MB
`PROMPT_CACHE_MAX_SIZE` | `50` | Maximální počet položek mezipaměti výzev
`SEMANTIC_CACHE_MAX_SIZE` | `100` | Maximální počet položek sémantické mezipaměti
Úplný přehled proměnných prostředí naleznete v souboru [README](../README.md) .
---
## 📊 Dostupné modely
<details>
<summary><b>Zobrazit všechny dostupné modely</b></summary>
</details>
**Claude Code ( `cc/` )** — Pro/Max: `cc/claude-opus-4-6` , `cc/claude-sonnet-4-5-20250929` , `cc/claude-haiku-4-5-20251001`
**Codex ( `cx/` )** — Plus/Pro: `cx/gpt-5.2-codex` , `cx/gpt-5.1-codex-max`
**Rozhraní příkazového řádku Gemini ( `gc/` )** — ZDARMA: `gc/gemini-3-flash-preview` , `gc/gemini-2.5-pro`
**GitHub Copilot ( `gh/` )** : `gh/gpt-5` , `gh/claude-4.5-sonnet`
**GLM ( `glm/` )** — 0,6 USD/1 milion: `glm/glm-4.7`
**MiniMax ( `minimax/` )** — 0,2 USD/1 milion: `minimax/MiniMax-M2.1`
**iFlow ( `if/` )** — ZDARMA: `if/kimi-k2-thinking` , `if/qwen3-coder-plus` , `if/deepseek-r1`
**Qwen ( `qw/` )** — ZDARMA: `qw/qwen3-coder-plus` , `qw/qwen3-coder-flash`
**Kiro ( `kr/` )** — ZDARMA: `kr/claude-sonnet-4.5` , `kr/claude-haiku-4.5`
**DeepSeek ( `ds/` )** : `ds/deepseek-chat` , `ds/deepseek-reasoner`
**Groq ( `groq/` )** : `groq/llama-3.3-70b-versatile` , `groq/llama-4-maverick-17b-128e-instruct`
**xAI ( `xai/` )** : `xai/grok-4` , `xai/grok-4-0709-fast-reasoning` , `xai/grok-code-mini`
**Mistral ( `mistral/` )** : `mistral/mistral-large-2501` , `mistral/codestral-2501`
**Zmatek ( `pplx/` )** : `pplx/sonar-pro` , `pplx/sonar`
**Společně AI ( `together/` )** : `together/meta-llama/Llama-3.3-70B-Instruct-Turbo`
**Umělá inteligence pro ohňostroje ( `fireworks/` )** : `fireworks/accounts/fireworks/models/deepseek-v3p1`
**Cerebras ( `cerebras/` )** : `cerebras/llama-3.3-70b`
**Soudržnost ( `cohere/` )** : `cohere/command-r-plus-08-2024`
**NVIDIA NIM ( `nvidia/` )** : `nvidia/nvidia/llama-3.3-70b-instruct`
---
## 🧩 Pokročilé funkce
### Vlastní modely
Přidejte libovolné ID modelu k libovolnému poskytovateli bez čekání na aktualizaci aplikace:
```bash
# Via API
curl -X POST http://localhost:20128/api/provider-models \
-H "Content-Type: application/json" \
-d '{"provider": "openai", "modelId": "gpt-4.5-preview", "modelName": "GPT-4.5 Preview"}'
# List: curl http://localhost:20128/api/provider-models?provider=openai
# Remove: curl -X DELETE "http://localhost:20128/api/provider-models?provider=openai&model=gpt-4.5-preview"
```
Nebo použijte Dashboard: **Poskytovatelé → [Poskytovatel] → Vlastní modely** .
### Vyhrazené trasy poskytovatelů
Směrování požadavků přímo ke konkrétnímu poskytovateli s validací modelu:
```bash
POST http://localhost:20128/v1/providers/openai/chat/completions
POST http://localhost:20128/v1/providers/openai/embeddings
POST http://localhost:20128/v1/providers/fireworks/images/generations
```
Pokud chybí prefix poskytovatele, automaticky se přidá. Neshodné modely vrátí chybu `400` .
### Konfigurace síťového proxy serveru
```bash
# Set global proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"global": {"type":"http","host":"proxy.example.com","port":"8080"}}'
# Per-provider proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"providers": {"openai": {"type":"socks5","host":"proxy.example.com","port":"1080"}}}'
# Test proxy
curl -X POST http://localhost:20128/api/settings/proxy/test \
-d '{"proxy":{"type":"socks5","host":"proxy.example.com","port":"1080"}}'
```
**Priorita:** Specifická pro klíč → Specifická pro kombinaci → Specifická pro poskytovatele → Globální → Prostředí.
### API katalogu modelů
```bash
curl http://localhost:20128/api/models/catalog
```
Vrátí modely seskupené podle poskytovatele s typy ( `chat` , `embedding` , `image` ).
### Synchronizace s cloudem
- Synchronizace poskytovatelů, kombinací a nastavení napříč zařízeními
- Automatická synchronizace na pozadí s časovým limitem + rychlá ochrana proti selhání
- V produkčním prostředí preferovat `BASE_URL` / `CLOUD_URL` na straně serveru
### LLM Gateway Intelligence (fáze 9)
- **Sémantická mezipaměť** — Automaticky ukládá do mezipaměti nestreamované odpovědi s teplotou 0 (obejde se pomocí `X-OmniRoute-No-Cache: true` )
- **Request Idempotency** — Deduplikuje požadavky do 5 sekund pomocí hlavičky `Idempotency-Key` nebo `X-Request-Id`
- **Sledování průběhu** — `event: progress` prostřednictvím záhlaví `X-OmniRoute-Progress: true`
---
### Hřiště překladatelů
Přístup přes **Dashboard → Translator** . Ladění a vizualizace toho, jak OmniRoute překládá požadavky API mezi poskytovateli.
Režim | Účel
--- | ---
**Dětské hřiště** | Vyberte zdrojový/cílový formát, vložte požadavek a okamžitě si prohlédněte přeložený výstup
**Tester chatu** | Odesílejte zprávy živého chatu přes proxy a kontrolujte celý cyklus požadavku/odpovědi
**Zkušební stolice** | Spusťte dávkové testy napříč různými kombinacemi formátů pro ověření správnosti překladu
**Živý monitor** | Sledujte překlady v reálném čase, jak požadavky procházejí proxy serverem
**Případy použití:**
- Ladění, proč selhává určitá kombinace klienta/poskytovatele
- Ověřte, zda se tagy myšlení, volání nástrojů a systémové výzvy správně překládají.
- Porovnejte rozdíly ve formátech OpenAI, Claude, Gemini a Responses API
---
### Strategie směrování
Konfigurace přes **Dashboard → Nastavení → Routing** .
Strategie | Popis
--- | ---
**Nejprve vyplňte** | Používá účty podle priority primární účet zpracovává všechny požadavky, dokud není k dispozici.
**Round Robin** | Cykluje mezi všemi účty s nastavitelným trvalým limitem (výchozí: 3 volání na účet)
**P2C (Síla dvou možností)** | Vybere 2 náhodné účty a nasměruje je k tomu zdravějšímu vyvažuje zátěž s povědomím o zdraví
**Náhodný** | Náhodně vybere účet pro každý požadavek pomocí Fisher-Yatesova náhodného výběru.
**Nejméně používané** | Směruje k účtu s nejstarším časovým razítkem `lastUsedAt` a rovnoměrně rozděluje provoz.
**Optimalizované náklady** | Směruje k účtu s nejnižší prioritou a optimalizuje pro poskytovatele s nejnižšími náklady.
#### Aliasy zástupných znaků modelů
Vytvořte zástupné znaky pro přemapování názvů modelů:
```
Pattern: claude-sonnet-* → Target: cc/claude-sonnet-4-5-20250929
Pattern: gpt-* → Target: gh/gpt-5.1-codex
```
Zástupné znaky podporují `*` (libovolný znak) a `?` (jeden znak).
#### Záložní řetězce
Definujte globální záložní řetězce, které platí pro všechny požadavky:
```
Chain: production-fallback
1. cc/claude-opus-4-6
2. gh/gpt-5.1-codex
3. glm/glm-4.7
```
---
### Odolnost a jističe
Konfigurace přes **Dashboard → Settings → Resilience** .
OmniRoute implementuje odolnost na úrovni poskytovatele se čtyřmi komponentami:
1. **Profily poskytovatelů** Konfigurace pro jednotlivé poskytovatele pro:
- Práh selhání (počet selhání před otevřením)
- Doba zchlazení
- Citlivost detekce limitu frekvence
- Exponenciální backoff parametry
2. **Upravitelné limity rychlosti** Výchozí nastavení na úrovni systému konfigurovatelná na řídicím panelu:
- **Požadavky za minutu (RPM)** — Maximální počet požadavků za minutu na účet
- **Minimální doba mezi požadavky** — Minimální mezera v milisekundách mezi požadavky
- **Max. počet souběžných požadavků** — Maximální počet souběžných požadavků na účet
- Klikněte na **Upravit** pro úpravu a poté **na Uložit** nebo **Zrušit** . Hodnoty se ukládají prostřednictvím rozhraní API pro odolnost.
3. **Jistič** Sleduje poruchy u jednotlivých poskytovatelů a automaticky rozpojuje obvod, když je dosaženo prahové hodnoty:
- **ZAVŘENO** (v pořádku) Požadavky probíhají normálně.
- **OTEVŘENO** — Poskytovatel je dočasně zablokován po opakovaných selháních
- **HALF_OPEN** — Testování, zda se poskytovatel zotavil
4. **Zásady a uzamčené identifikátory** Zobrazuje stav jističe a uzamčené identifikátory s možností vynuceného odemčení.
5. **Automatická detekce limitu rychlosti** Monitoruje záhlaví `429` a `Retry-After` , aby se proaktivně zabránilo dosažení limitů rychlosti poskytovatele.
**Tip pro profesionály:** Pomocí tlačítka **Obnovit vše** vymažete všechny jističe a doby ochlazování, když se poskytovatel zotaví z výpadku.
---
### Export / import databáze
Správa záloh databáze se provádí v **nabídce Ovládací panel → Nastavení → Systém a úložiště** .
Akce | Popis
--- | ---
**Exportovat databázi** | Stáhne aktuální databázi SQLite jako soubor `.sqlite`
**Exportovat vše (.tar.gz)** | Stáhne kompletní zálohu včetně: databáze, nastavení, kombinací, připojení k poskytovatelům (bez přihlašovacích údajů) a metadat klíče API.
**Importovat databázi** | Nahrajte soubor `.sqlite` , který nahradí aktuální databázi. Záloha před importem se vytvoří automaticky.
```bash
# API: Export database
curl -o backup.sqlite http://localhost:20128/api/db-backups/export
# API: Export all (full archive)
curl -o backup.tar.gz http://localhost:20128/api/db-backups/exportAll
# API: Import database
curl -X POST http://localhost:20128/api/db-backups/import \
-F "file=@backup.sqlite"
```
**Ověření importu:** Importovaný soubor je ověřen z hlediska integrity (kontrola pragma SQLite), požadovaných tabulek ( `provider_connections` , `provider_nodes` , `combos` , `api_keys` ) a velikosti (max. 100 MB).
**Případy použití:**
- Migrace OmniRoute mezi počítači
- Vytvořte externí zálohy pro zotavení po havárii
- Sdílení konfigurací mezi členy týmu (exportovat vše → sdílet archiv)
---
### Ovládací panel nastavení
Stránka nastavení je pro snadnou navigaci uspořádána do 5 záložek:
Záložka | Obsah
--- | ---
**Zabezpečení** | Nastavení přihlášení/hesla, řízení přístupu k IP adrese, autorizace API pro `/models` a blokování poskytovatelů
**Směrování** | Globální strategie směrování (6 možností), aliasy zástupných znaků, záložní řetězce, kombinované výchozí hodnoty
**Odolnost** | Profily poskytovatelů, upravitelné limity sazeb, stav jističů, zásady a uzamčené identifikátory
**Umělá inteligence** | Konfigurace rozpočtu promyšleného projektu, globální vkládání promptu do systému, statistiky mezipaměti promptu
**Moderní** | Globální konfigurace proxy (HTTP/SOCKS5)
---
### Správa nákladů a rozpočtu
Přístup přes **Dashboard → Náklady** .
Záložka | Účel
--- | ---
**Rozpočet** | Nastavte limity útrat pro každý klíč API s denními/týdenními/měsíčními rozpočty a sledováním v reálném čase
**Ceny** | Zobrazení a úprava cenových položek modelu cena za 1000 vstupních/výstupních tokenů na poskytovatele
```bash
# API: Set a budget
curl -X POST http://localhost:20128/api/usage/budget \
-H "Content-Type: application/json" \
-d '{"keyId": "key-123", "limit": 50.00, "period": "monthly"}'
# API: Get current budget status
curl http://localhost:20128/api/usage/budget
```
**Sledování nákladů:** Každý požadavek zaznamenává využití tokenů a vypočítává náklady pomocí ceníkové tabulky. Rozdělení si můžete prohlédnout v **sekci Dashboard → Využití** podle poskytovatele, modelu a klíče API.
---
### Přepis zvuku
OmniRoute podporuje přepis zvuku prostřednictvím koncového bodu kompatibilního s OpenAI:
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
# Example with curl
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@audio.mp3" \
-F "model=deepgram/nova-3"
```
Dostupní poskytovatelé: **Deepgram** ( `deepgram/` ), **AssemblyAI** ( `assemblyai/` ).
Podporované zvukové formáty: `mp3` , `wav` , `m4a` , `flac` , `ogg` , `webm` .
---
### Strategie kombinovaného vyvažování
Nastavte vyvažování jednotlivých kombinací v **nabídce Dashboard → Kombinace → Vytvořit/Upravit → Strategie** .
Strategie | Popis
--- | ---
**Round-Robin** | Postupně prochází modely
**Přednost** | Vždy se pokusí o první model; vrací se pouze v případě chyby.
**Náhodný** | Pro každý požadavek vybere náhodný model z komba
**Vážené** | Trasy proporcionálně na základě přiřazených vah pro každý model
**Nejméně používané** | Směruje k modelu s nejmenším počtem nedávných požadavků (používá kombinované metriky)
**Optimalizované z hlediska nákladů** | Trasy k nejlevnějšímu dostupnému modelu (používá ceník)
Globální výchozí hodnoty kombinací lze nastavit v **nabídce Dashboard → Settings → Routing → Combo Defaults** .
---
### Dashboard zdraví
Přístup přes **Dashboard → Stav** . Přehled stavu systému v reálném čase se 6 kartami:
Karta | Co to ukazuje
--- | ---
**Stav systému** | Doba provozuschopnosti, verze, využití paměti, datový adresář
**Zdraví poskytovatelů** | Stav jističe podle dodavatele (Zapnuto/Vypnuto/Napůl vypnuto)
**Limity sazeb** | Aktivní limit rychlosti cooldownů na účet se zbývajícím časem
**Aktivní výluky** | Poskytovatelé dočasně blokovaní politikou uzamčení
**Mezipaměť podpisů** | Statistiky mezipaměti pro deduplikaci (aktivní klíče, míra zásahů)
**Telemetrie latence** | Agregace latence p50/p95/p99 na poskytovatele
**Tip pro profesionály:** Stránka Zdraví se automaticky obnovuje každých 10 sekund. Pomocí karty jističe můžete zjistit, kteří poskytovatelé mají problémy.
---
## 🖥️ Desktopová aplikace (Electron)
OmniRoute je k dispozici jako nativní desktopová aplikace pro Windows, macOS a Linux.
### Instalace
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Instalatéři budov
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Výstup → `electron/dist-electron/`
### Klíčové vlastnosti
Funkce | Popis
--- | ---
**Připravenost serveru** | Před zobrazením okna se dotazuje server (žádná prázdná obrazovka)
**Systémový zásobník** | Minimalizovat do zásobníku, změnit port, ukončit menu v zásobníku
**Správa přístavů** | Změna portu serveru z panelu úloh (automatické restartování serveru)
**Zásady zabezpečení obsahu** | Omezující CSP prostřednictvím záhlaví relace
**Jedna instance** | V daném okamžiku může běžet pouze jedna instance aplikace
**Offline režim** | Dodávaný server Next.js funguje bez internetu
### Proměnné prostředí
Proměnná | Výchozí | Popis
--- | --- | ---
`OMNIROUTE_PORT` | `20128` | Port serveru
`OMNIROUTE_MEMORY_MB` | `512` | Limit haldy Node.js (6416384 MB)
📖 Úplná dokumentace: [`electron/README.md`](../electron/README.md)

View File

@@ -0,0 +1,399 @@
# OmniRoute — Guia de Deploy em VM com Cloudflare
Kompletní instalace a konfigurace OmniRoute u VM (VPS) s gerenciou přes Cloudflare.
---
## Předpoklady
Položka | Mínimo | Doporučeno
--- | --- | ---
**Procesor** | 1 virtuální procesor | 2 vCPU
**BERAN** | 1 GB | 2 GB
**Disko** | 10GB SSD | 25GB SSD
**TAK** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS
**Domínio** | Registrován v Cloudflare | —
**Přístavní dělník** | Docker Engine 24+ | Docker 27+
**Testados poskytovatelů** : Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
---
## 1. Konfigurace virtuálního počítače
### 1.1 Vytvořit ihned
Žádný preferovaný poskytovatel seu VPS:
- Vyberte si Ubuntu 24.04 LTS
- Výběr nebo plano minimo (1 vCPU / 1 GB RAM)
- Definujte sílu pro root nebo konfiguraci klíče SSH
- Anote o **IP público** (např.: `203.0.113.10` )
### 1.2 Připojení přes SSH
```bash
ssh root@203.0.113.10
```
### 1.3 Aktualizace systému
```bash
apt update && apt upgrade -y
```
### 1.4 Instalace Dockeru
```bash
# Instalar dependências
apt install -y ca-certificates curl gnupg
# Adicionar repositório oficial do Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
### 1.5 Instalace nginxu
```bash
apt install -y nginx
```
### 1.6 Konfigurace firewallu (UFW)
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP (redirect)
ufw allow 443/tcp # HTTPS
ufw enable
```
> **Dica** : Maximální zabezpečení, omezení jako porty 80 a 443 přístupů pro IP Cloudflare. Veja a seção [Segurança Avançada](#seguran%C3%A7a-avan%C3%A7ada) .
---
## 2. Instalace OmniRoute
### 2.1 Criar diretório de configuração
```bash
mkdir -p /opt/omniroute
```
### 2.2 Criar arquivo de variáveis de ambiente
```bash
cat > /opt/omniroute/.env << 'EOF'
# === Segurança ===
JWT_SECRET=ALTERE-PARA-CHAVE-SECRETA-UNICA-64-CHARS
INITIAL_PASSWORD=SuaSenhaSegura123!
API_KEY_SECRET=ALTERE-PARA-OUTRA-CHAVE-SECRETA
STORAGE_ENCRYPTION_KEY=ALTERE-PARA-TERCEIRA-CHAVE-SECRETA
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=ALTERE-PARA-SALT-UNICO
# === App ===
PORT=20128
NODE_ENV=production
HOSTNAME=0.0.0.0
DATA_DIR=/app/data
STORAGE_DRIVER=sqlite
ENABLE_REQUEST_LOGS=true
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# === Domain (altere para seu domínio) ===
BASE_URL=https://llms.seudominio.com
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
# === Cloud Sync (opcional) ===
# CLOUD_URL=https://cloud.omniroute.online
# NEXT_PUBLIC_CLOUD_URL=https://cloud.omniroute.online
EOF
```
> ⚠️ **DŮLEŽITÉ** : Gere chaves secretas únicas! Použijte `openssl rand -hex 32` para cada chave.
### 2.3 Spuštění kontejneru
```bash
docker pull diegosouzapw/omniroute:latest
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### 2.4 Verificar se está rodando
```bash
docker ps | grep omniroute
docker logs omniroute --tail 20
```
Vývojový příklad: `[DB] SQLite database ready` a `listening on port 20128` .
---
## 3. Konfigurace nginx (reverzní proxy)
### 3.1 Gerar Certificado SSL (Cloudflare Origin)
Cloudflare nic neřeší:
1. Používá **SSL/TLS → Origin Server**
2. **Certifikát Clique Create**
3. Deixe os padrões (15 ano, *.seudominio.com)
4. Zkopírujte nebo zkopírujte **certifikát původu** a **soukromý klíč**
```bash
mkdir -p /etc/nginx/ssl
# Colar o certificado
nano /etc/nginx/ssl/origin.crt
# Colar a chave privada
nano /etc/nginx/ssl/origin.key
chmod 600 /etc/nginx/ssl/origin.key
```
### 3.2 Konfigurace nginxu
```bash
cat > /etc/nginx/sites-available/omniroute << 'NGINX'
# Default server — bloqueia acesso direto por IP
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
server_name _;
return 444;
}
# OmniRoute — HTTPS
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name llms.seudominio.com; # Altere para seu domínio
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name llms.seudominio.com;
return 301 https://$server_name$request_uri;
}
NGINX
```
### 3.3 Ativar a testování
```bash
# Remover config padrão
rm -f /etc/nginx/sites-enabled/default
# Ativar OmniRoute
ln -sf /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
# Testar e recarregar
nginx -t && systemctl reload nginx
```
---
## 4. Konfigurace DNS v Cloudflare
### 4.1 Další DNS registr
No painel da Cloudflare → DNS:
Typ | Jméno | Obsah | Proxy
--- | --- | --- | ---
A | `llms` | `203.0.113.10` (IP adresa virtuálního počítače) | ✅ Proxy
### 4.2 Konfigurace SSL
Em **SSL/TLS → Přehled** :
- Režim: **Plný (Přísný)**
Em **SSL/TLS → Edge certifikáty** :
- Vždy používat HTTPS: ✅ Zapnuto
- Minimální verze TLS: TLS 1.2
- Automatické přepisování HTTPS: ✅ Zapnuto
### 4.3 Testar
```bash
curl -sI https://llms.seudominio.com/health
# Deve retornar HTTP/2 200
```
---
## 5. Operace a údržba
### Aktualizovat na novou verzi
```bash
docker pull diegosouzapw/omniroute:latest
docker stop omniroute && docker rm omniroute
docker run -d --name omniroute --restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### Verzovní protokoly
```bash
docker logs -f omniroute # Stream em tempo real
docker logs omniroute --tail 50 # Últimas 50 linhas
```
### Ruční zálohování banky
```bash
# Copiar dados do volume para o host
docker cp omniroute:/app/data ./backup-$(date +%F)
# Ou comprimir todo o volume
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine tar czf /backup/omniroute-data-$(date +%F).tar.gz /data
```
### Obnovení zálohy
```bash
docker stop omniroute
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine sh -c "rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /"
docker start omniroute
```
---
## 6. Pokročilá bezpečnost
### Omezte přístup k IP Cloudflare
```bash
cat > /etc/nginx/cloudflare-ips.conf << 'CF'
# Cloudflare IPv4 ranges — atualizar periodicamente
# https://www.cloudflare.com/ips-v4/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
CF
```
Přidat `nginx.conf` dentro do bloco `http {}` :
```nginx
include /etc/nginx/cloudflare-ips.conf;
```
### Nainstalujte fail2ban
```bash
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
# Verificar status
fail2ban-client status sshd
```
### Bloquear accesso direto na port do Docker
```bash
# Impedir acesso externo direto à porta 20128
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
# Persistir as regras
apt install -y iptables-persistent
netfilter-persistent save
```
---
## 7. Nasazení cloudového pracovníka (volitelné)
Vzdálený přístup přes Cloudflare Workers (zde exponovat diretament VM):
```bash
# No repositório local
cd omnirouteCloud
npm install
npx wrangler login
npx wrangler deploy
```
Dokumenty jsou kompletní pro [omnirouteCloud/README.md](../omnirouteCloud/README.md) .
---
## Resumo de Portas
Porta | Služba | Přístup
--- | --- | ---
22 | SSH | Veřejné (s fail2ban)
80 | nginx HTTP | Přesměrování → HTTPS
443 | nginx HTTPS | Prostřednictvím proxy serveru Cloudflare
20128 | OmniRoute | Někdy na localhostu (přes nginx)

View File

@@ -0,0 +1,45 @@
# ADR-0001: Zobecnění registru proxy serverů + kontroly využití
Datum: 17. 3. 2026 Stav: Přijato
## Kontext
OmniRoute je užitečný:
- Přiřazení proxy na základě konfigurační mapy ( `global` , `providers` , `combos` , `keys` ).
- Výběr s ohledem na kvóty poskytovatele khusus tertentu (zejména `codex` ).
Mezera utama:
- Proxy belum menjadi asset opakovaně použitelný jang bisa di-manage sebagai entitas (metadata, kde se používají, bezpečné smazání).
- Zásady použití belum konsisten lintas provider.
- Chybová smlouva API belum seragam untuk manajemen endpoint manajemen.
## Rozhodnutí
1. Tambah **Proxy Registry** sebegai domény baru di DB ( `proxy_registry` , `proxy_assignments` ).
2. Stálá kompatibilita přiřazení lama (záložní lama `proxyConfig` ).
3. Priority pakai runtime modulu Resolver:
- účet -&gt; poskytovatel -&gt; globální (registr)
- záložní ke legacy resolver jika registry belum ada přiřazení
4. Výchozí registr výstupního seznamu Wajib redaction kredensial di.
5. Standarkan error JSON unuk endpoint manajemen proxy agar konsisten dan punya `requestId` .
## Důsledky
Pozitivní:
- Opakovaně použitelný proxy server.
- Bezpečné odstranění bisa ditegakkan (409 saat masih dipakai).
- Migrasi bertahap tanpa prolomení runtime změn.
Negativní:
- Ada dual-source sementara (registr + starší konfigurace) sampai migrasi selesai.
- Ale přiřazení koncových bodů tambahan a pemetaan rozsah a rozsah.
## Následná opatření
- Poskytovatel uživatelského rozhraní Migrasi/účet umožňuje zadat nezpracovaný registr selektoru proxy serveru.
- Telemetrie zdraví Tambah na proxy a upozornění.
- Všeobecná kontrola používání ke poskytovateli lain melalui interface policy yang sama.

View File

@@ -0,0 +1,31 @@
# ADR-0002: Chybová smlouva pro koncové body správy
Datum: 17. 3. 2026 Stav: Přijato
## Rozhodnutí
Koncové body správy (konfigurace proxy, registr proxy a přiřazení proxy) vracejí jednotné tělo chyby:
```json
{
"error": {
"message": "Human-readable summary",
"type": "invalid_request | not_found | conflict | server_error",
"details": {}
},
"requestId": "uuid"
}
```
## Mapování stavu
- 400: neplatný požadavek / selhání ověření
- 404: zdroj nenalezen
- 409: konflikt zdrojů (například proxy stále přiřazen)
- 500: neočekávaná chyba serveru
## Poznámky
- `requestId` je povinný pro korelaci protokolů.
- `details` je volitelné a používá se pouze pro bezpečné ověření detailů.
- Citlivé tajné informace (přihlašovací údaje proxy, tokeny) se nikdy nesmí objevit ve `message` ani v `details` .

View File

@@ -0,0 +1,15 @@
# ADR-0003: Kontrolní seznam zabezpečení pro registr proxy a kontroly používání
Datum: 17. 3. 2026 Stav: Přijato
## Kontrolní seznam
- Ověřte všechny datové části správy pomocí Zodu.
- Odmítnout aktualizace chybně formátovaného přiřazení rozsahu se stavem 400.
- Odmítnout smazání používané proxy se stavem 409, pokud to není vynuceno.
- Ve výchozím nastavení nikdy nezobrazovat uživatelské jméno/heslo proxy v odpovědích seznamu.
- Nikdy nezaznamenávejte nezpracované přihlašovací údaje ani hodnoty tokenů.
- Udržujte chybové odpovědi bez interních trasování zásobníku.
- Chraňte koncové body správy pomocí stávajících zásad middlewaru pro ověřování.
- Auditovat mutující operace: vytvořit/aktualizovat/smazat/přiřadit/migraci.
- Zajistěte, aby se resolver během přechodu vrátil k původní konfiguraci.

View File

@@ -0,0 +1,254 @@
# Aplikace OmniRoute Electron pro stolní počítače
Tento adresář obsahuje obalovou aplikaci Electron pro desktopovou aplikaci OmniRoute.
## Architektura (v1.6.4)
```
electron/
├── main.js # Main process — window, tray, server lifecycle, CSP, IPC
├── preload.js # Preload script — secure IPC bridge with disposer pattern
├── package.json # Electron-specific dependencies & electron-builder config
├── types.d.ts # TypeScript definitions (AppInfo, ServerStatus, ElectronAPI)
└── assets/ # Application icons and resources
src/shared/hooks/
└── useElectron.ts # React hooks — useSyncExternalStore, zero re-renders
```
## Klíčová rozhodnutí o designu
Rozhodnutí | Odůvodnění
--- | ---
dotazování `waitForServer()` | Zabraňuje zobrazení prázdné obrazovky při studeném startu — před načtením se ozve `http://localhost:PORT`
`stdio: 'pipe'` | Zachycuje stdout/stderr serveru pro logování + detekci připravenosti ( `inherit` )
Vzor drtiče odpadu | `onServerStatus()` vrací `() => void` pro přesné vyčištění listeneru (ne `removeAllListeners` )
`useSyncExternalStore` | Nulové renderování pro `useIsElectron()` — žádný cyklus `useState` + `useEffect`
CSP prostřednictvím záhlaví relace | `Content-Security-Policy` omezuje `script-src` , `connect-src` atd. dle osvědčených postupů Electron.
Podmíněný titulek pro platformu | `titleBarStyle: 'hiddenInset'` pouze v systému macOS; `default` ve Windows/Linuxu
## Rozvoj
### Předpoklady
1. Nejprve sestavte aplikaci Next.js:
```bash
npm run build
```
1. Instalace závislostí Electronu:
```bash
cd electron
npm install
```
### Spuštěno ve vývoji
1. Spusťte vývojový server Next.js:
```bash
npm run dev
```
1. V jiném terminálu spusťte Electron:
```bash
cd electron
npm run dev
```
### Spuštění v produkčním režimu
1. Sestavení Next.js v samostatném režimu:
```bash
npm run build
```
1. Spuštění elektronu:
```bash
cd electron
npm start
```
## Budova
### Sestavení pro aktuální platformu
```bash
cd electron
npm run build
```
### Vytvořte pro specifické platformy
```bash
# Windows
npm run build:win
# macOS (x64 + arm64)
npm run build:mac
# Linux
npm run build:linux
```
## Výstup
Vytvořené aplikace jsou umístěny v `dist-electron/` :
- Windows: `.exe` instalační program (NSIS) + přenosný `.exe`
- macOS: instalační soubor `.dmg` (Intel + Apple Silicon)
- Linux: `.AppImage`
## Instalace
### macOS
1. Stáhněte si nejnovější soubor `.dmg` ze stránky [Verze](https://github.com/diegosouzapw/OmniRoute/releases) .
2. Otevřete soubor `.dmg` .
3. Přetáhněte `OmniRoute.app` do složky Aplikace.
4. Spustit z Aplikací.
> ⚠️ **Poznámka:** Aplikace zatím není podepsána certifikátem Apple Developer. Pokud macOS aplikaci blokuje, spusťte:
>
> ```bash
> xattr -cr /Applications/OmniRoute.app
> ```
>
> Nebo klikněte pravým tlačítkem myši na aplikaci → Otevřít → Otevřít (pro obejití Gatekeeperu při prvním spuštění).
### Windows
**Instalační program (doporučeno):**
1. Stáhněte si `OmniRoute.Setup.*.exe` z [Releases](https://github.com/diegosouzapw/OmniRoute/releases) .
2. Spusťte instalační program.
3. Spuštění z nabídky Start nebo zástupce na ploše.
**Přenosné (bez instalace):**
1. Stáhněte si soubor `OmniRoute.exe` ze [sekce Vydání](https://github.com/diegosouzapw/OmniRoute/releases) .
2. Spouštět přímo z libovolné složky.
### Linux
1. Stáhněte si soubor `.AppImage` ze [sekce Releases](https://github.com/diegosouzapw/OmniRoute/releases) .
2. Udělejte z něj spustitelný soubor:
```bash
chmod +x OmniRoute-*.AppImage
```
3. Běh:
```bash
./OmniRoute-*.AppImage
```
## Funkce
- **Připravenost serveru** Před zobrazením okna čeká na kontrolu stavu
- **Systémový zásobník** — Minimalizace do systémového zásobníku s rychlými akcemi (otevřít, změnit port, ukončit)
- **Správa portů** — Změna portu z nabídky v systémové liště (server se automaticky restartuje)
- **Ovládací prvky oken** — Vlastní minimalizace, maximalizace, zavření přes IPC
- **Zásady zabezpečení obsahu** Omezující CSP prostřednictvím záhlaví relací
- **Offline podpora** — Samostatný server Next.js v balíčku
- **Jedna instance** V daném okamžiku může běžet pouze jedna instance aplikace.
## Konfigurace
### Proměnné prostředí
Proměnná | Výchozí | Popis
--- | --- | ---
`OMNIROUTE_PORT` | `20128` | Port serveru
`OMNIROUTE_MEMORY_MB` | `512` | Limit haldy Node.js (6416384 MB)
`NODE_ENV` | `production` | Nastavit na `development` pro vývojářský režim
### Vlastní ikona
Umístěte ikony do `assets/` :
- `icon.ico` — ikona Windows (256×256)
- `icon.icns` — balíček ikon pro macOS
- `icon.png` — Linux/obecné použití (512×512)
- `tray-icon.png` — Ikona na systémové liště (16×16 nebo 32×32)
## Kanály IPC
### Vyvolání (Renderer → Hlavní, asynchronní)
Kanál | Vrácení zboží | Popis
--- | --- | ---
`get-app-info` | `AppInfo` | Název aplikace, verze, platforma, isDev, port
`open-external` | `void` | Otevřít URL ve výchozím prohlížeči (pouze http/https)
`get-data-dir` | `string` | Získat cestu k adresáři userData
`restart-server` | `{ success }` | Zastavení + restart serveru (časový limit 5 s + SIGKILL)
### Odeslat (Renderer → Hlavní, spustit a zapomenout)
Kanál | Popis
--- | ---
`window-minimize` | Minimalizovat okno
`window-maximize` | Přepnout maximalizaci/obnovení
`window-close` | Zavřít okno (minimalizovat do zásobníku)
### Příjem (Hlavní → Renderer, události)
Kanál | Užitečné zatížení | Vydáno, když
--- | --- | ---
`server-status` | `ServerStatus` | Server se spouští, zastavuje, dochází k chybám nebo se restartuje
`port-changed` | `number` | Změna portu přes menu zásobníku
> **Poznámka** : Posluchače vracejí funkce pro přesné čištění. Viz hooky `useServerStatus` a `usePortChanged` .
## Zabezpečení
Funkce | Implementace
--- | ---
Izolace kontextu | `contextIsolation: true` — renderer nemůže přistupovat k Node.js
Integrace uzlů | `nodeIntegration: false` — v rendereru není `require()`
Bílý seznam IPC | Názvy kanálů ověřené při předběžném načítání pomocí `safeInvoke` / `safeSend` / `safeOn`
Ověření URL adresy | `shell.openExternal()` povoluje pouze protokoly `http:` / `https:`
CSP | Záhlaví `Content-Security-Policy` nastavené pomocí `session.webRequest.onHeadersReceived`
Zabezpečení webu | `webSecurity: true` vynucena politika stejného původu
## React Hooky
Háček | Vrácení zboží | Popis
--- | --- | ---
`useIsElectron()` | `boolean` | Detekce nulového renderování pomocí `useSyncExternalStore`
`useElectronAppInfo()` | `{ appInfo, loading, error }` | Informace o aplikaci z hlavního procesu
`useDataDir()` | `{ dataDir, loading, error }` | Adresář uživatelských dat
`useWindowControls()` | `{ minimize, maximize, close }` | Akce ovládání oken
`useOpenExternal()` | `{ openExternal }` | Otevřít URL adresy v prohlížeči
`useServerControls()` | `{ restart, restarting }` | Řízení restartu serveru
`useServerStatus(cb)` | Drtič odpadu | Poslouchejte události stavu serveru
`usePortChanged(cb)` | Drtič odpadu | Poslouchejte události změny portu
## Odstraňování problémů
### Aplikace se nespustí
1. Zkontrolujte, zda je port 20128 dostupný: `lsof -i :20128`
2. Zkontrolujte protokoly konzole pro prefix `[Electron]`
3. Ověřte, zda výstup sestavení existuje v souboru `.next/standalone`
### Bílá obrazovka
1. Ověření existence buildu Next.js čekání na připravenost serveru maximálně 30 sekund
2. Zkontrolujte výstup protokolů `[Server]` a `[Server:err]`
3. Hledání porušení CSP v konzoli pro vývojáře
### Selhání sestavení
Ujistěte se, že máte nainstalované nástroje pro sestavení:
- Windows: Nástroje pro sestavení ve Visual Studiu
- macOS: Nástroje příkazového řádku Xcode
- Linux: `build-essential` , `libsecret-1-dev`
## Licence
MIT

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