Compare commits

...

82 Commits

Author SHA1 Message Date
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
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
396 changed files with 51891 additions and 12948 deletions

View File

@@ -6,7 +6,7 @@ description: Fetch all open GitHub issues, analyze bugs, resolve what's possible
## 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 commit or release automatically** — it presents a report and waits for user validation before proceeding.
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
@@ -60,11 +60,12 @@ Call the `/issue-triage` workflow (located at `~/.gemini/antigravity/global_work
Proceed with resolution:
1. **Research** — Search the codebase for files related to the issue
2. **Root Cause** — Identify the root cause by reading the relevant source files
3. **Implement Fix** — Apply the fix following existing code patterns and conventions
4. **Test** — Build the project and run tests to verify the fix
5. **DO NOT commit yet** — Leave changes staged but uncommitted
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
@@ -83,25 +84,37 @@ Present a summary report to the user via `notify_user` with `BlockedOnUser: true
- 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 All Fixes (only after user approval)
### 6. Commit & Push Fix Branch (only after user approval)
After the user validates:
- Commit each fix individually with message format: `fix: <description> (#<issue_number>)`
- Each fix should be its own commit for clean git history
- 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. Close Resolved Issues
### 7. 🛑 WAIT — Notify User & Await PR Verification
For each successfully fixed issue:
// turbo
**This is a mandatory stop point.** Use `notify_user` with `BlockedOnUser: true`:
- Close with a comment: `gh issue close <NUMBER> --repo <owner>/<repo> --comment "Fixed in <commit_hash>. The fix will be included in the next release."`
- 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**
### 8. Update Docs & Release
Wait for the user to respond:
If any fixes were committed:
- **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
1. Run the `/update-docs` workflow (at `~/.gemini/antigravity/global_workflows/update-docs.md`) to update CHANGELOG and README
2. Run the `/generate-release` workflow (at `.agents/workflows/generate-release.md`) to bump version, tag, and publish
### 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

@@ -6,7 +6,7 @@ description: Analyze open Pull Requests from the project's GitHub repository, ge
## 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.
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
@@ -94,28 +94,52 @@ Perform a **global impact assessment** to verify whether the PR changes are comp
### 6. Implementation (if approved)
- Checkout the PR branch or apply changes locally
- 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 in this step
- 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
- If all checks pass, prepare the merge
- Push the updated branch: `git push origin <branch-name>`
### 7. Thank the Contributor
### 7. 🛑 WAIT — Notify User & Await PR Verification
- After the PR is approved (and before or after merging), post a **thank-you comment** on the PR via the GitHub UI or API
**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
- 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!"_
### 8. Post-Merge (if applicable)
### 9. Merge & Release (only after user confirms PR)
- Update CHANGELOG.md with the new feature
- Consider version bump if warranted
- Follow the `/generate-release` workflow if a release is needed
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

@@ -22,6 +22,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 +133,6 @@ jobs:
cache: npm
- run: npm ci
- run: npm run test:integration
continue-on-error: true
test-security:
name: Security Tests
@@ -144,4 +149,3 @@ jobs:
cache: npm
- run: npm ci
- run: npm run test:security
continue-on-error: true

View File

@@ -89,6 +89,8 @@ jobs:
run: npm ci
- name: Build Next.js standalone
env:
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
run: npm run build
- name: Install Electron dependencies
@@ -108,9 +110,13 @@ jobs:
for file in *${{ matrix.ext }}; do
[ -f "$file" ] && cp "$file" ../../release-assets/
done
# Windows: also copy portable standalone exe
# Windows: also copy portable standalone exe as OmniRoute.exe
if [ "${{ matrix.platform }}" = "windows" ]; then
[ -f "OmniRoute.exe" ] && cp OmniRoute.exe ../../release-assets/
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

6
.gitignore vendored
View File

@@ -63,6 +63,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
@@ -106,10 +107,13 @@ 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/
/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/

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

View File

@@ -7,6 +7,300 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
---
## [2.0.2] — 2026-03-05
> ### 🐛 Bug Fixes & ✨ Endpoint-Aware Model Management
### 🐛 Bug Fixes
- **#212 — API Key creation crash** — Auto-generate `API_KEY_SECRET` at startup (like `JWT_SECRET`) to prevent HMAC crashes
- **#213 — Circuit breaker scope** — Changed circuit breaker key from provider-level to model-level; a 429 on one account no longer blocks all accounts for the same provider
- **#200 — Custom provider connection check** — Added connectivity fallback for OpenAI-compatible providers (Ollama, LM Studio); if `/models` and `/chat/completions` fail, a simple HTTP ping to the base URL marks the provider as connected
### ✨ New Features
- **#204 — API Format selector** — Custom models can now specify `apiFormat`: `chat-completions` (default) or `responses` (for the Responses API)
- **#205 — Combo endpoint support** — Combos now accept an `endpoint` field in the schema (`chat` | `embeddings` | `images`), enabling fallback/rotation combos for non-chat endpoints
- **#206 — Supported Endpoints mapping** — When adding custom models, users can check which endpoints the model supports (💬 Chat, 📐 Embeddings, 🖼️ Images, 🔊 Audio). Models tagged for embeddings appear in `/v1/embeddings` and models tagged for images appear in `/v1/images/generations`
- **Visual badges** — Model rows now display colored badges for non-default API formats and endpoint types
- **Model catalog metadata** — `/v1/models` response includes `api_format`, `type`, and `supported_endpoints` for custom models
### 📁 Files Changed
| File | Change |
| ------------------------------------------------------- | ------------------------------------------------ |
| `src/instrumentation.ts` | Auto-generate `API_KEY_SECRET` |
| `open-sse/services/combo.ts` | Circuit breaker keyed per-model |
| `src/lib/providers/validation.ts` | Connectivity fallback ping |
| `src/lib/db/models.ts` | `apiFormat` + `supportedEndpoints` fields |
| `src/shared/schemas/validation.ts` | `endpoint` in `comboSchema` |
| `src/shared/validation/schemas.ts` | Extended `providerModelMutationSchema` |
| `src/app/api/provider-models/route.ts` | Pass new fields through API |
| `src/app/(dashboard)/dashboard/providers/[id]/page.tsx` | API format dropdown, endpoint checkboxes, badges |
| `src/app/api/v1/models/catalog.ts` | Custom model metadata enrichment |
| `src/app/api/v1/embeddings/route.ts` | Include custom embedding models |
| `src/app/api/v1/images/generations/route.ts` | Include custom image models |
---
## [2.0.0] — 2026-03-05
> ### 🚀 Major Release — MCP Multi-Transport, A2A Protocol, Auto-Combo Engine & Full Type Safety Overhaul
>
> **OmniRoute 2.0** transforms the AI gateway into a fully **agent-controllable platform**. AI agents can now discover, orchestrate, and optimize routing through 16 MCP tools (via 3 transports: stdio, SSE, Streamable HTTP) or the A2A v0.3 protocol. Accompanied by a self-healing Auto-Combo engine, VS Code extension, consolidated Endpoints dashboard with service toggles, and a comprehensive type safety overhaul across the entire codebase.
### 🔌 MCP Multi-Transport (3 Modes)
- **stdio** — Local transport for IDE integration (Claude Desktop, Cursor, VS Code Copilot). Launched via `omniroute --mcp`
- **SSE (Server-Sent Events)** — Remote HTTP transport at `/api/mcp/sse` (GET+POST). Runs in-process inside Next.js
- **Streamable HTTP** — Modern bidirectional HTTP transport at `/api/mcp/stream` (GET+POST+DELETE). Uses `WebStandardStreamableHTTPServerTransport` singleton
- **Transport Selector UI** — When MCP is enabled, a transport picker shows all 3 modes with connection URLs and a Copy button
- **Settings Persistence** — `mcpTransport` field in settings API (enum: `stdio` | `sse` | `streamable-http`)
### 🆕 MCP Server (16 Tools)
- **8 Essential Tools** — `get_health`, `list_combos`, `get_combo_metrics`, `switch_combo`, `check_quota`, `route_request`, `cost_report`, `list_models_catalog`
- **8 Advanced Tools** — `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 permission scopes (`read:health`, `read:combos`, `read:quota`, `read:usage`, `read:models`, `execute:completions`, `write:combos`, `write:budget`, `write:resilience`) with wildcard support
- **Audit Logging** — Every tool call logged to SQLite with SHA-256 input hashing, output summarization, and duration tracking
- **IDE Configs** — MCP configuration templates for Claude Desktop, Cursor, VS Code Copilot, and stdio transport
- **Type-Safe Schemas** — All 16 tools defined with Zod input/output schemas, descriptions, and scope declarations
- 📖 **Documentation** — [`open-sse/mcp-server/README.md`](open-sse/mcp-server/README.md) with architecture, tool reference, and client examples in Python, TypeScript, and Go
### 🤖 A2A Server (Agent-to-Agent v0.3)
- **JSON-RPC 2.0** — Full router with `message/send`, `message/stream`, `tasks/get`, `tasks/cancel`
- **Agent Card** — Dynamic `/.well-known/agent.json` with 2 skills and bearer auth
- **Skills** — `smart-routing` (routing explanation, cost envelope, resilience trace, policy verdict) and `quota-management` (natural language quota queries with ranking, free combo suggestions, and full summaries)
- **SSE Streaming** — Real-time task streaming with 15s heartbeat, chunk events, and completion metadata
- **Task Manager** — State machine (`submitted``working``completed`/`failed`/`cancelled`), TTL (5min default), auto-cleanup (2× TTL)
- **Routing Logger** — Decision audit trail with 7-day retention and routing statistics
- **Task Execution** — Generic executor with proper state transitions on success/failure
- 📖 **Documentation** — [`src/lib/a2a/README.md`](src/lib/a2a/README.md) with JSON-RPC methods, skill reference, client examples, and MCP vs A2A comparison
### ⚡ Auto-Combo Engine
- **6-Factor Scoring** — Quota, health, costInv, latencyInv, taskFit, stability (normalized 0-1)
- **Task Fitness Table** — 30+ models × 6 task types with wildcard boosts
- **4 Mode Packs** — Ship Fast, Cost Saver, Quality First, Offline Friendly
- **Self-Healing** — Progressive cooldown exclusion, probe-based re-admission, incident mode (>50% OPEN)
- **Bandit Exploration** — 5% exploratory routing for discovering better providers
- **Adaptation Persistence** — EMA scoring with disk persistence every 10 decisions
- **REST API** — `POST/GET /api/combos/auto` for CRUD operations
### 🎛️ Consolidated Endpoints Dashboard
- **Tabbed Navigation** — Merged standalone Endpoint, MCP, and A2A sidebar entries into a single **"Endpoints"** page using `SegmentedControl`. Four tabs: **Endpoint Proxy**, **MCP**, **A2A**, **API Endpoints**
- **Service Enable/Disable Toggles** — MCP and A2A tabs have clickable ON/OFF toggle switches with settings persistence (default: OFF)
- **Service Status Indicators** — Inline status badges (green "Online" / red "Offline") with 30s auto-refresh
- **API Endpoints Tab** — Placeholder page with "Coming Soon" badge, listing planned features: REST API catalog, webhooks, OpenAPI/Swagger spec, and per-endpoint auth management
- **Sidebar Cleanup** — Removed standalone MCP and A2A entries; renamed "Endpoint" to "Endpoints"
### 🧩 VS Code Extension — Advanced Features
- **MCP Client** — 16 tool wrappers with REST API fallback
- **A2A Client** — Agent discovery, message send/stream, task management
- **Smart Dispatch** — Task type detection, combo recommendation, risk scoring
- **Preflight Dialog** — Risk-based display (auto-skip low, info medium, modal high)
- **Budget Guard** — Session cost tracking with status bar indicator and threshold actions
- **Mode Pack Selector** — Quick-pick UI for switching optimization profiles
- **Health Monitor** — Circuit breaker state change notifications
- **Human Checkpoint** — Multi-factor confidence evaluation with handoff dialog
### 📊 Dashboard Pages
- **MCP Dashboard** — Tool listing, usage stats, audit log with 30s auto-refresh
- **A2A Dashboard** — Agent Card display, skill listing, task history with routing metadata
- **Auto-Combo Dashboard** — Provider score bars, factor breakdown, mode pack selector, incident indicator, exclusion list
- **Error Pages** — Custom error and not-found pages for the dashboard
### 🔗 Integrations
- **OpenClaw** — Dynamic `provider.order` endpoint at `/api/cli-tools/openclaw/auto-order`
- **Configurable Tool Name Prefix** — `TOOL_NAME_PREFIX` env var for custom MCP tool naming (#199)
- **Custom RPM/TPM Rate Limits** — Per-provider rate limit overrides (#198)
- **CORS Fix** — CORS headers on early-return error responses (#208)
- **Auto-Combo Validation** — Proper validation for auto-combo CRUD operations (#209)
### 🌐 i18n (30 Languages)
- **Endpoints Namespace** — Added `endpoints` i18n namespace with tab labels, toggle labels, and API Endpoints page translations across all 30 locales
- **Sidebar & Header Updates** — Updated sidebar key from `endpoint` to `endpoints` and header breadcrumb descriptions across all 30 locales
- **Media & Themes i18n** — Added media section and combo strategy guide translations across all 30 locales
### 🔧 Code Quality & Type Safety
- **Eliminated `any` types** — Replaced `any` casts across `open-sse/` services, translators, and handlers with proper generics and explicit types
- **Zod Validation Schemas** — Added Zod-based validation for all MCP tool inputs/outputs and API validation layer
- **Shared Contracts** — Normalized quota and combos API responses with shared contracts (`src/shared/contracts/quota.ts`) for consistent data shapes across MCP, A2A, and REST APIs
- **TypeScript Translator Types** — Added strict types and modularized the translator registry with proper interfaces
- **DB Layer Hardening** — Improved database layer with proper error handling and type safety in the compliance module
- **A2A Lifecycle Safety** — Enhanced A2A task lifecycle with type-safe state transitions, preventing invalid state changes on completed tasks
- **Stream Handling** — Improved ComfyUI and stream handling with proper type safety
- **Webpack Barrel-File Fix** — Extracted `updateSettingsSchema` into dedicated `settingsSchemas.ts` to bypass webpack tree-shaking bug
- **Security Fix** — Insecure randomness fix for code scanning alert #54
### 🧪 Tests
- **E2E Test Suite** — 6 scenarios covering MCP, A2A, Auto-Combo, OpenClaw, Stress (100+50 parallel), Security
- **Unit Tests** — Essential tools (139 tests), advanced tools (141 tests), Auto-Combo engine (162 tests), A2A lifecycle regression tests
- **Schema Hardening Tests** — `t06-schema-hardening.test.mjs` (132 tests) for input validation
- **Security Tests** — `t07-no-log-key-config.test.mjs` (138 tests), `t08-mcp-scope-enforcement.test.mjs` (72 tests)
- **Integration Tests** — `v1-contracts-behavior.test.mjs` (171 tests), `security-hardening.test.mjs` (103 tests)
- **Migrated Tests to TypeScript** — E2E ecosystem tests migrated from `.mjs` to `.ts` with proper typing
- **Combo E2E Tests** — Strategy guides, advanced settings, readiness checks
### 📝 Documentation
- **AGENTS.md** — Updated to v2.0.0 with MCP multi-transport, A2A Protocol, Auto-Combo Engine, consolidated Endpoints dashboard, and Zod validation references
- **README.md** — Updated Agent & Protocol feature table with 3 transport modes, consolidated endpoints, and service toggles
- **30 Translated READMEs** — Synced feature tables across all language versions
- **CHANGELOG.md** — Comprehensive release notes covering all v1.8.1 → v2.0.0 changes
### 📁 New Files (60+)
| Directory | Files |
| :------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `open-sse/mcp-server/` | `server.ts`, `index.ts`, `audit.ts`, `scopeEnforcement.ts`, `httpTransport.ts`, `tools/advancedTools.ts`, `README.md` |
| `open-sse/mcp-server/schemas/` | `tools.ts`, `a2a.ts`, `audit.ts`, `index.ts` |
| `src/lib/a2a/` | `taskManager.ts`, `taskExecution.ts`, `streaming.ts`, `routingLogger.ts`, `README.md` |
| `src/lib/a2a/skills/` | `smartRouting.ts`, `quotaManagement.ts` |
| `src/app/a2a/` | `route.ts` (JSON-RPC 2.0 dispatch handler) |
| `src/app/api/mcp/sse/` | `route.ts` (SSE transport endpoint) |
| `src/app/api/mcp/stream/` | `route.ts` (Streamable HTTP transport endpoint) |
| `open-sse/services/autoCombo/` | `scoring.ts`, `taskFitness.ts`, `engine.ts`, `selfHealing.ts`, `modePacks.ts`, `persistence.ts`, `index.ts` |
| `src/shared/contracts/` | `quota.ts` (shared API contracts) |
| `src/shared/constants/` | `mcpScopes.ts` |
| `src/shared/validation/` | `settingsSchemas.ts` (extracted settings Zod schema) |
| `src/lib/db/migrations/` | `002_mcp_a2a_tables.sql` |
| `src/app/(dashboard)/` | `dashboard/mcp/page.tsx`, `dashboard/a2a/page.tsx`, `dashboard/auto-combo/page.tsx`, `dashboard/endpoint/ApiEndpointsTab.tsx` |
| `vscode-extension/src/services/` | `mcpClient.ts`, `a2aClient.ts`, `policyEngine.ts`, `preflightDialog.ts`, `budgetGuard.ts`, `healthMonitor.ts`, `modePackSelector.ts`, `humanCheckpoint.ts` |
| `scripts/` | `check-cycles.mjs`, `check-docs-sync.mjs`, `check-route-validation.mjs`, `check-t11-any-budget.mjs`, `run-playwright-tests.mjs`, `runtime-env.mjs` |
| `tests/` | `t06-schema-hardening.test.mjs`, `t07-no-log-key-config.test.mjs`, `t08-mcp-scope-enforcement.test.mjs`, `ecosystem.test.ts` |
| `docs/` | `mcp-server.md`, `a2a-server.md`, `auto-combo.md`, `vscode-extension.md`, `integrations/ide-configs.md`, `RELEASE_CHECKLIST.md` |
### 📝 Commit History (`features-agente-mcp-a2a` branch)
| Commit | Date | Description |
| :-------- | :--------- | :--------------------------------------------------------------------------------------- |
| `e0ddb22` | 2026-03-03 | feat: add MCP server mode with `--mcp` flag for IDE integration |
| `09a1748` | 2026-03-03 | feat: add Phase 3 advanced MCP tools and A2A smart routing skill |
| `1e1a9c9` | 2026-03-04 | feat: migrate tests to TypeScript and add MCP advanced tools test suite |
| `ab77452` | 2026-03-04 | feat: normalize quota and combos API responses with shared contracts |
| `88ad4cc` | 2026-03-04 | feat: add MCP server, A2A protocol, auto-combo engine & VS Code extension |
| `cc429d4` | 2026-03-04 | feat: add TypeScript types and modularize translator registry |
| `adc8fdf` | 2026-03-04 | feat: add A2A protocol support and refactor API validation layer |
| `500cae3` | 2026-03-04 | refactor: replace `any` types with generics and add Zod validation schemas |
| `889e2ba` | 2026-03-04 | feat: add error pages, harden DB layer and compliance module |
| `cbd0b1c` | 2026-03-04 | refactor: harden open-sse services, eliminate any casts, add dashboard pages |
| `b33a853` | 2026-03-04 | feat: Introduce A2A lifecycle management, add type safety to ComfyUI and stream handling |
| `a1a2610` | 2026-03-04 | feat: v2.0.0 - MCP server, A2A agent, proxy improvements and docs update |
| `d615ca5` | 2026-03-05 | feat: configurable tool name prefix (#199) and custom rpm/tpm rate limits (#198) |
| `6d8868b` | 2026-03-05 | fix: extract validation helpers to fix webpack barrel-file resolution bug |
| `bc2e60c` | 2026-03-05 | feat: Introduce new A2A and MCP API routes, enhance dashboard UI, E2E tests |
| `79c23df` | 2026-03-05 | feat: Add i18n for media/themes, enhance combos with strategy guides, E2E tests |
| `2490ba5` | 2026-03-05 | feat: Introduce combo readiness checks and strategy recommendations |
| `48dda26` | 2026-03-05 | fix: CORS headers on early-return error responses + auto-combo validation (#208, #209) |
| `078a42b` | 2026-03-05 | feat: consolidate Endpoint, MCP, A2A into tabbed Endpoints page |
| `6f1e6a0` | 2026-03-05 | feat: add MCP/A2A enable/disable toggle switches on Endpoints page |
| `bb9d85b` | 2026-03-05 | fix: extract updateSettingsSchema to bypass webpack barrel-file bug |
| `cc7e1a0` | 2026-03-05 | feat: add MCP multi-transport (stdio + SSE + Streamable HTTP) |
---
## [1.8.1] — 2026-03-03
### 🐛 Bug Fixes
- **Usage API Proxy Support** — Quota/usage fetch calls (`/api/usage/[connectionId]`) now route through the dashboard-configured proxy (Global → Provider → Key level). Previously, usage fetchers used bare `fetch()` which bypassed the Global Proxy setting, causing "fetch failed" errors in Docker deployments behind a proxy. Fixes #194
## [1.8.0] — 2026-03-03
### 🐛 Bug Fixes
- **Empty `tool_use.name` Validation** — Fixed intermittent HTTP 400 errors when using Claude Code through OmniRoute. Assistant messages with empty `tool_use.name` fields (from interrupted tool calls or malformed history) are now validated and filtered at two layers: the `openai-to-claude` request translator and the `prepareClaudeRequest` sanitizer. Fixes #191
- **Windows Electron Release** — Fixed the "Collect installers" step failing in every Windows build since v1.7.5+. `electron-builder` produces versioned portable exe filenames (e.g., `OmniRoute 1.6.9.exe`), not the hardcoded `OmniRoute.exe` the workflow expected. Now finds the portable exe dynamically by pattern. PR #190 by @benzntech
## [1.7.14] — 2026-03-02
### 🐛 Bug Fixes
- **Responses SSE Passthrough** — Passthrough mode is now format-aware: Responses SSE payloads (`response.*` type) skip Chat Completions-specific sanitization (`sanitizeStreamingChunk`, `fixInvalidId`, `hasValuableContent`), preventing potential stream corruption for Responses-native clients. Usage extraction still works for both formats. Fixes #186
### ✨ Features
- **Blackbox AI Dashboard** — Added blackbox.ai provider to the dashboard frontend (providers page, pricing, models endpoint). Completes #175
## [1.7.11] — 2026-03-02
### ✨ Features
- **Blackbox AI Provider** — Added blackbox.ai as a new OpenAI-compatible provider with 6 default models (GPT-4o, Gemini 2.5 Flash, Claude Sonnet 4, DeepSeek V3, Blackbox AI, Blackbox AI Pro) and provider logo. Fixes #175
### 🐛 Bug Fixes
- **Antigravity 404 Error** — Added warning logs when `generateProjectId()` generates a fallback project ID because `credentials.projectId` is null. The executor now prefers the translator-set `body.project` before generating a new fallback, eliminating duplicate warnings and ID mismatch. Fixes #176. Includes improvements from PRs #184 and #185
## [1.7.10] — 2026-03-02
### 🐛 Bug Fixes
- **Streaming Tool Calls (Responses→ChatCompletions)** — Fixed two issues in the `openaiResponsesToOpenAIResponse` translator that broke tool call execution in agentic clients (OpenCode, Claude Code, Cursor, etc.): (1) Argument delta chunks now include `tool_calls[].id` and `type: "function"` so clients can associate argument fragments correctly. (2) `finish_reason` is now `"tool_calls"` instead of hardcoded `"stop"` when tool calls occurred. Fixes #180
## [1.7.9] — 2026-03-02
### 🐛 Bug Fixes
- **Electron CI Build** — Added `JWT_SECRET` environment variable to the Electron release workflow `Build Next.js standalone` step, fixing build failures in GitHub Actions. PR #178 by @benzntech
### 📝 Documentation
- **README** — Updated OpenClaw link from `cline/cline` to `openclaw/openclaw` to reflect the project rename. PR #179 by @MAINER4IK
## [1.7.8] — 2026-03-02
### ✨ New Features
- **Theme Color Customization** — Users can now select from 7 preset accent colors (Coral, Blue, Red, Green, Violet, Orange, Cyan) or define a custom color via color picker/hex input. The chosen color dynamically updates `--color-primary` and `--color-primary-hover` CSS variables across the entire UI. PR #174 by @mainer4ik
### 🌐 Multi-Language Sync
- **Theme & Media i18n** — Added `themeCoral`, `themeBlue`, `themeRed`, `themeGreen`, `themeViolet`, `themeOrange`, `themeCyan`, `themeAccent`, `themeAccentDesc`, `themeCustom`, `themeCreate`, and media section translations across all **30 language locales**
### 🔧 Code Quality (Review Improvements)
- Exported `COLOR_THEMES` constant from `themeStore.ts` for DRY reuse
- Added hex color validation with visual feedback (red border + disabled apply button)
- Synced local state via Zustand `subscribe` pattern for cross-tab consistency
- Removed dead `/themes` route from Header.tsx
- Added CSS `color-mix()` fallback for older browsers
## [1.7.7] — 2026-03-02
### 🐛 Bug Fixes
- **Gemini Tool Schema Sanitization** — The standard Gemini provider now sanitizes OpenAI tool schemas before forwarding to Gemini API, removing unsupported JSON Schema keywords (`additionalProperties`, `$schema`, `const`, `default`, `not`, etc.). Previously, sanitization only ran in the CLI executor path, causing Gemini to reject tool calls when schemas contained unsupported constraints. Also applied sanitization to `response_format.json_schema`. Fixes #173
## [1.7.6] — 2026-03-02
### 🐛 Bug Fixes
- **Cloud Proxy `undefined/v1` Fix** — When the `NEXT_PUBLIC_CLOUD_URL` environment variable is not set (common in Docker deployments), the endpoint page now correctly falls back instead of showing `undefined/v1`. The cloud sync API now returns `cloudUrl` in its response so the frontend can use it dynamically. Fixes #171
### ✨ New Features
- **Cloud Worker `/v1/models` Endpoint** — The Cloud Worker now supports the `/v1/models` endpoint for both URL formats (`/v1/models` and `/{machineId}/v1/models`), returning all available models synced from the local OmniRoute instance
### 🔧 Infrastructure
- **Cloudflare Workers Compatibility** — Fixed `setInterval` in global scope issue in `accountFallback.ts` that blocked Cloud Worker deployment. Lazy initialization pattern ensures compatibility with Cloudflare Workers runtime restrictions
## [1.7.5] — 2026-03-02
### 🐛 Bug Fixes
- **OAuth Re-Auth Duplicate Fix** — Re-authenticating an expired OAuth connection now updates the existing connection instead of creating a duplicate entry. When re-auth is triggered, the system matches by `provider` + `email` + `authType` and refreshes tokens in-place. Fixes #170
## [1.7.4] — 2026-03-01
### ✨ New Features

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -110,6 +110,35 @@ _Conecta cualquier IDE o herramienta CLI con IA a través de OmniRoute — gatew
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 ¿Por qué OmniRoute?
**Deja de desperdiciar dinero y chocar con límites:**
@@ -128,6 +157,18 @@ _Conecta cualquier IDE o herramienta CLI con IA a través de OmniRoute — gatew
---
## 📧 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)
---
## 🔄 Cómo Funciona
```
@@ -157,263 +198,497 @@ Resultado: Nunca dejes de programar, costo mínimo
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Lo que resuelve OmniRoute: 30 puntos débiles reales y casos de uso
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Todos los desarrolladores que utilizan herramientas de IA se enfrentan a estos problemas a diario.** OmniRoute se creó para resolverlos todos: desde sobrecostos hasta bloqueos regionales, desde flujos rotos de OAuth hasta operaciones de protocolo y observabilidad empresarial.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Pago una suscripción costosa pero aún así me interrumpen los límites"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Los desarrolladores pagan entre 20 y 200 dólares al mes por Claude Pro, Codex Pro o GitHub Copilot. Incluso pagando, la cuota tiene un límite: 5 horas de uso, límites semanales o límites de tarifa por minuto. A mitad de la sesión de codificación, el proveedor deja de responder y el desarrollador pierde flujo y productividad.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Reserva inteligente de 4 niveles**: si se agota la cuota de suscripción, se redirige automáticamente a la clave API → Barato → Gratis sin intervención manual
- **Seguimiento de cuotas en tiempo real**: muestra el consumo de tokens en tiempo real con cuenta regresiva de reinicio (5 h, diario, semanal)
- **Soporte multicuenta**: varias cuentas por proveedor con rotación automática: cuando una se agota, cambia a la siguiente
- **Combinaciones personalizadas**: cadenas de respaldo personalizables con 6 estrategias de equilibrio (completar primero, por turnos, P2C, aleatoria, menos utilizada, de costo optimizado)
- **Cuotas comerciales de Codex**: monitoreo de cuotas del espacio de trabajo empresarial/de equipo directamente en el panel
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Necesito usar varios proveedores pero cada uno tiene una API diferente"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI usa un formato, Claude (Anthropic) usa otro, Gemini otro más. Si un desarrollador quiere probar modelos de diferentes proveedores o recurrir a ellos, debe reconfigurar los SDK, cambiar los puntos finales y lidiar con formatos incompatibles. Los proveedores personalizados (FriendLI, NIM) tienen puntos finales de modelo no estándar.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Punto final unificado**: un único `http://localhost:20128/v1` sirve como proxy para los más de 36 proveedores
- **Traducción de formato**: automática y transparente: OpenAI ↔ Claude ↔ Gemini ↔ API de respuestas
- **Desinfección de respuesta**: elimina los campos no estándar (`x_groq`, `usage_breakdown`, `service_tier`) que interrumpen OpenAI SDK v1.83+
- **Normalización de roles**: convierte `developer``system` para proveedores que no son OpenAI; `system``user` para GLM/ERNIE
- **Think Tag Extraction**: extrae bloques `<think>` de modelos como DeepSeek R1 en `reasoning_content` estandarizado.
- **Salida estructurada para Gemini** — `json_schema``responseMimeType`/`responseSchema` conversión automática
- **`stream` por defecto es `false`**: se alinea con las especificaciones de OpenAI, evitando SSE inesperado en los SDK de Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Mi proveedor de IA bloquea mi región/país"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Proveedores como OpenAI/Codex bloquean el acceso desde ciertas regiones geográficas. Los usuarios obtienen errores como `unsupported_country_region_territory` durante las conexiones OAuth y API. Esto resulta especialmente frustrante para los desarrolladores de los países en desarrollo.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Configuración de proxy de 3 niveles**: Proxy configurable en 3 niveles: global (todo el tráfico), por proveedor (un solo proveedor) y por conexión/clave.
- **Insignias de proxy codificadas por colores** — Indicadores visuales: 🟢 proxy global, 🟡 proxy de proveedor, 🔵 proxy de conexión, que siempre muestra la IP
- **Intercambio de tokens de OAuth a través de proxy**: el flujo de OAuth también pasa a través del proxy, lo que resuelve `unsupported_country_region_territory`
- **Pruebas de conexión a través de proxy**: las pruebas de conexión utilizan el proxy configurado (no más derivación directa)
- **Soporte SOCKS5**: soporte completo de proxy SOCKS5 para enrutamiento saliente
- **Suplantación de huellas dactilares TLS**: huella digital TLS similar a la de un navegador a través de `wreq-js` para evitar la detección de bots.
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Quiero usar IA para codificar pero no tengo dinero"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
No todo el mundo puede pagar entre 20 y 200 dólares al mes por suscripciones a IA. Los estudiantes, desarrolladores de países emergentes, aficionados y autónomos necesitan acceso a modelos de calidad sin costo alguno.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Proveedores de nivel gratuito integrados**: soporte nativo para proveedores 100% gratuitos: iFlow (8 modelos ilimitados), Qwen (3 modelos ilimitados), Kiro (Claude gratis), Gemini CLI (180K/mes gratis)
- **Combos solo gratuitos**: cadena `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/mes sin tiempo de inactividad
- **Créditos gratuitos NVIDIA NIM**: 1000 créditos gratuitos integrados
- **Estrategia de optimización de costos**: estrategia de enrutamiento que elige automáticamente el proveedor más barato disponible
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Necesito proteger mi puerta de enlace AI del acceso no autorizado"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Al exponer una puerta de enlace de IA a la red (LAN, VPS, Docker), cualquiera con la dirección puede consumir los tokens/cuota del desarrollador. Sin protección, las API son vulnerables al mal uso, la inyección rápida y el abuso.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Administración de claves API**: generación, rotación y alcance por proveedor con una página `/dashboard/api-manager` dedicada
- **Permisos a nivel de modelo**: restrinja las claves API a modelos específicos (`openai/*`, patrones comodín), con la opción Permitir todo/Restringir
- **API Endpoint Protection**: requiere una clave para `/v1/models` y bloquea proveedores específicos del listado
- **Auth Guard + Protección CSRF**: todas las rutas del panel protegidas con middleware `withAuth` + tokens CSRF
- **Limitador de velocidad**: limitación de velocidad por IP con ventanas configurables
- **Filtrado de IP**: lista permitida/lista bloqueada para control de acceso
- **Prompt injection guard**: desinfección contra patrones de avisos maliciosos
- **Cifrado AES-256-GCM**: credenciales cifradas en reposo
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Mi proveedor dejó de funcionar y perdí mi flujo de codificación"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Los proveedores de IA pueden volverse inestables, devolver errores 5xx o alcanzar límites de velocidad temporales. Si un desarrollador depende de un solo proveedor, se le interrumpe. Sin disyuntores, los reintentos repetidos pueden bloquear la aplicación.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Disyuntor por proveedor**: apertura/cierre automático con umbrales configurables y enfriamiento (cerrado/abierto/medio abierto)
- **Retroceso exponencial**: retrasos progresivos en los reintentos
- **Anti-Thundering Herd** — Mutex + protección de semáforo contra tormentas de reintentos simultáneos
- **Cadenas alternativas combinadas**: si el proveedor principal falla, automáticamente pasa por la cadena sin intervención.
- **Disyuntor combinado**: desactiva automáticamente los proveedores defectuosos dentro de una cadena combinada
- **Panel de estado**: monitoreo del tiempo de actividad, estados de disyuntores, bloqueos, estadísticas de caché, latencia p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Configurar cada herramienta de IA es tedioso y repetitivo"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Los desarrolladores utilizan Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Cada herramienta necesita una configuración diferente (punto final API, clave, modelo). Reconfigurar al cambiar de proveedor o modelo es una pérdida de tiempo.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Panel de herramientas CLI**: página dedicada con configuración con un solo clic para Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **Generador de configuración de GitHub Copilot**: genera `chatLanguageModels.json` para código VS con selección de modelo masivo
- **Asistente de incorporación**: configuración guiada de 4 pasos para usuarios nuevos
- **Un punto final, todos los modelos**: configure `http://localhost:20128/v1` una vez, acceda a más de 36 proveedores
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Administrar tokens OAuth de múltiples proveedores es un infierno"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot: todos usan OAuth 2.0 con tokens que caducan. Los desarrolladores necesitan volver a autenticarse constantemente, lidiar con `client_secret is missing`, `redirect_uri_mismatch` y fallas en servidores remotos. OAuth en LAN/VPS es particularmente problemático.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Actualización automática de tokens**: los tokens de OAuth se actualizan en segundo plano antes de que caduquen
- **OAuth 2.0 (PKCE) integrado**: flujo automático para Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth multicuenta**: varias cuentas por proveedor mediante extracción de token JWT/ID
- **OAuth LAN/Remote Fix** — Detección de IP privada para `redirect_uri` + modo URL manual para servidores remotos
- **OAuth detrás de Nginx**: utiliza `window.location.origin` para compatibilidad con proxy inverso
- **Guía remota de OAuth**: guía paso a paso para las credenciales de Google Cloud en VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "No sé cuánto estoy gastando ni dónde"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Los desarrolladores utilizan múltiples proveedores pagos pero no tienen una visión unificada del gasto. Cada proveedor tiene su propio panel de facturación, pero no hay una vista consolidada. Los costos inesperados pueden acumularse.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Panel de análisis de costos**: seguimiento de costos por token y gestión de presupuesto por proveedor
- **Límites de presupuesto por nivel**: límite de gasto por nivel que activa el respaldo automático
- **Configuración de precios por modelo**: precios configurables por modelo
- **Estadísticas de uso por clave API**: recuento de solicitudes y marca de tiempo utilizada por última vez por clave
- **Panel de análisis**: tarjetas de estadísticas, tabla de uso de modelos, tabla de proveedores con tasas de éxito y latencia.
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "No puedo diagnosticar errores y problemas en llamadas AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Cuando falla una llamada, el desarrollador no sabe si se trata de un límite de velocidad, un token caducado, un formato incorrecto o un error del proveedor. Registros fragmentados en diferentes terminales. Sin observabilidad, la depuración es de prueba y error.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Panel de registros unificados**: 4 pestañas: registros de solicitudes, registros de proxy, registros de auditoría y consola
- **Visor de registros de consola**: visor estilo terminal en tiempo real con niveles codificados por colores, desplazamiento automático, búsqueda y filtro
- **Registros de proxy SQLite**: registros persistentes que sobreviven a los reinicios del servidor
- **Translator Playground**: 4 modos de depuración: Playground (traducción de formato), Chat Tester (ida y vuelta), Test Bench (por lotes), Live Monitor (en tiempo real)
- **Solicitud de telemetría**: latencia p50/p95/p99 + seguimiento de X-Request-Id
- **Registro basado en archivos con rotación**: el interceptor de consola captura todo en el registro JSON con rotación basada en el tamaño.
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Implementar y mantener la puerta de enlace es complejo"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Instalar, configurar y mantener un proxy de IA en diferentes entornos (local, VPS, Docker, nube) requiere mucha mano de obra. Problemas como rutas codificadas, `EACCES` en directorios, conflictos de puertos y compilaciones multiplataforma añaden fricción.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **instalación global de npm** — `npm install -g omniroute && omniroute`hecho
- **Docker multiplataforma**: AMD64 + ARM64 nativo (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Perfiles de Docker Compose**: `base` (sin herramientas CLI) y `cli` (con Claude Code, Codex, OpenClaw)
- **Aplicación de escritorio Electron**: aplicación nativa para Windows/macOS/Linux con bandeja del sistema, inicio automático y modo sin conexión
- **Modo de puerto dividido**: API y panel en puertos separados para escenarios avanzados (proxy inverso, redes de contenedores)
- **Cloud Sync**: sincronización de configuración entre dispositivos a través de Cloudflare Workers
- **Copias de seguridad de base de datos**: copia de seguridad, restauración, exportación e importación automáticas de todas las configuraciones
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "La interfaz es solo en inglés y mi equipo no habla inglés"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Los equipos en países que no hablan inglés, especialmente en América Latina, Asia y Europa, tienen dificultades con las interfaces solo en inglés. Las barreras del idioma reducen la adopción y aumentan los errores de configuración.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Panel i18n — 30 idiomas** — Las más de 500 teclas traducidas, incluidas árabe, búlgaro, danés, alemán, español, finlandés, francés, hebreo, hindi, ngaro, indonesio, italiano, japonés, coreano, malayo, holandés, noruego, polaco, portugués (PT/BR), rumano, ruso, eslovaco, sueco, tailandés, ucraniano, vietnamita, chino, filipino, inglés.
- **Soporte RTL**: soporte de derecha a izquierda para árabe y hebreo
- **README multilingüe**: 30 traducciones de documentación completa
- **Selector de idioma**: ícono de globo en el encabezado para cambiar en tiempo real
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Necesito más que chat: necesito incrustaciones, imágenes y audio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
La IA no es solo completar un chat. Los desarrolladores necesitan generar imágenes, transcribir audio, crear incrustaciones para RAG, reclasificar documentos y moderar contenido. Cada API tiene un punto final y un formato diferentes.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Integraciones** — `/v1/embeddings` con 6 proveedores y más de 9 modelos
- **Generación de imágenes** — `/v1/images/generations` con 10 proveedores y más de 20 modelos (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Texto a vídeo** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) y SD WebUI
- **Texto a música** — `/v1/music/generations` — ComfyUI (audio estable abierto, MusicGen)
- **Transcripción de audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Texto a voz** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 y proveedores existentes
- **Moderaciones** — `/v1/moderations` — Comprobaciones de seguridad del contenido
- **Reclasificación** — `/v1/rerank` — Reclasificación de relevancia del documento
- **API de respuestas**: compatibilidad total con `/v1/responses` para Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "No tengo forma de probar y comparar la calidad entre modelos"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Los desarrolladores quieren saber qué modelo es mejor para su caso de uso (código, traducción, razonamiento), pero comparar manualmente es lento. No existen herramientas de evaluación integradas.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Evaluaciones LLM**: pruebas de conjunto dorado con 10 casos precargados que cubren saludos, matemáticas, geografía, generación de código, cumplimiento de JSON, traducción, rebajas y rechazo de seguridad.
- **4 estrategias de coincidencia**: `exact`, `contains`, `regex`, `custom` (función JS)
- **Translator Playground Test Bench**: pruebas por lotes con múltiples entradas y resultados esperados, comparación entre proveedores
- **Chat Tester**: recorrido completo de ida y vuelta con representación de respuesta visual
- **Live Monitor**: flujo en tiempo real de todas las solicitudes que fluyen a través del proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Necesito escalar sin perder rendimiento"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
A medida que crece el volumen de solicitudes, sin almacenar en caché las mismas preguntas generan costos duplicados. Sin idempotencia, las solicitudes duplicadas desperdician el procesamiento. Se deben respetar los límites de tarifas por proveedor.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Caché semántica**: la caché de dos niveles (firma + semántica) reduce el costo y la latencia
- **Solicitud de idempotencia**: ventana de deduplicación de 5 segundos para solicitudes idénticas
- **Detección de límite de velocidad**: RPM por proveedor, intervalo mínimo y seguimiento simultáneo máximo
- **Límites de velocidad editables**: valores predeterminados configurables en Configuración → Resiliencia con persistencia
- **Caché de validación de clave API**: caché de 3 niveles para rendimiento de producción
- **Panel de estado con telemetría**: latencia p50/p95/p99, estadísticas de caché, tiempo de actividad
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Quiero controlar el comportamiento del modelo globalmente"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Desarrolladores que quieran todas las respuestas en un idioma específico, con un tono específico o quieran limitar los tokens de razonamiento. Configurar esto en cada herramienta/solicitud no es práctico.
**How OmniRoute solves it:**
**Cómo lo resuelve OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Inyección de aviso del sistema**: aviso global aplicado a todas las solicitudes
- **Thinking Budget Validation**: control de asignación de tokens de razonamiento por solicitud (transferencia, automática, personalizada, adaptativa)
- **6 estrategias de enrutamiento**: estrategias globales que determinan cómo se distribuyen las solicitudes
- **Enrutador comodín**: los patrones `provider/*` se enrutan dinámicamente a cualquier proveedor
- **Activar/desactivar combinación de alternar**: alterna combinaciones directamente desde el panel
- **Alternar proveedor**: activa/desactiva todas las conexiones de un proveedor con un solo clic
- **Proveedores bloqueados**: excluye proveedores específicos del listado `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Necesito herramientas MCP como capacidades de producto de primera clase"</b></summary>
Muchas puertas de enlace de IA exponen MCP solo como un detalle de implementación oculto. Los equipos necesitan una capa operativa visible y manejable.
**Cómo lo resuelve OmniRoute:**
- MCP aparece en la pestaña de navegación del panel y protocolo de punto final
- Página de gestión de MCP dedicada con procesos, herramientas, alcances y auditoría
- Inicio rápido integrado para `omniroute --mcp` e incorporación de clientes
</details>
<details>
<summary><b>🧠 18. "Necesito orquestación A2A con rutas de tareas de sincronización + transmisión"</b></summary>
Los flujos de trabajo de los agentes necesitan respuestas directas y una ejecución continua de larga duración con control del ciclo de vida.
**Cómo lo resuelve OmniRoute:**
- Punto final A2A JSON-RPC (`POST /a2a`) con `message/send` y `message/stream`
- Transmisión SSE con propagación del estado terminal
- API de ciclo de vida de tareas para `tasks/get` y `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Necesito un estado real del proceso MCP, no un estado adivinado"</b></summary>
Los equipos operativos necesitan saber si MCP está realmente activo, no solo si se puede acceder a una API.
**Cómo lo resuelve OmniRoute:**
- Archivo de latidos en tiempo de ejecución con PID, marcas de tiempo, transporte, recuento de herramientas y modo de alcance
- API de estado de MCP que combina latidos + actividad reciente
- Tarjetas de estado de la interfaz de usuario para el proceso/tiempo de actividad/actualización de latidos
</details>
<details>
<summary><b>📋 20. "Necesito ejecución de herramienta MCP auditable"</b></summary>
Cuando las herramientas modifican la configuración o desencadenan acciones de operaciones, los equipos necesitan trazabilidad forense.
**Cómo lo resuelve OmniRoute:**
- Registro de auditoría respaldado por SQLite para llamadas a herramientas MCP
- Filtros por herramienta, éxito/fracaso, clave API y paginación
- Tabla de auditoría del panel + puntos finales de estadísticas para automatización
</details>
<details>
<summary><b>🔐 21. "Necesito permisos MCP con alcance por integración"</b></summary>
Los diferentes clientes deberían tener acceso con privilegios mínimos a las categorías de herramientas.
**Cómo lo resuelve OmniRoute:**
- 9 alcances MCP granulares para acceso controlado a herramientas
- Aplicación del alcance y visibilidad en la interfaz de usuario de gestión de MCP
- Postura predeterminada segura para herramientas operativas
</details>
<details>
<summary><b>⚙️ 22. "Necesito controles operativos sin redistribuir"</b></summary>
Los equipos necesitan cambios rápidos en el tiempo de ejecución durante incidentes o eventos de costos.
**Cómo lo resuelve OmniRoute:**
- Cambie la activación combinada directamente desde el panel de MCP
- Aplicar perfiles de resiliencia de paquetes de políticas predefinidos
- Restablecer el estado del disyuntor desde el mismo panel de operaciones.
</details>
<details>
<summary><b>🔄 23. "Necesito visibilidad y cancelación del ciclo de vida de la tarea A2A en vivo"</b></summary>
Sin visibilidad del ciclo de vida, los incidentes de tareas se vuelven difíciles de clasificar.
**Cómo lo resuelve OmniRoute:**
- Listado de tareas/filtrado por estado/habilidad con paginación
- Profundización en metadatos, eventos y artefactos de tareas
- Punto final de cancelación de tarea y acción de UI con confirmación
</details>
<details>
<summary><b>🌊 24. "Necesito métricas de transmisión activas para la carga A2A"</b></summary>
Los flujos de trabajo de streaming requieren información operativa sobre la simultaneidad y las conexiones en vivo.
**Cómo lo resuelve OmniRoute:**
- Contadores de flujo activos integrados en el estado A2A
- Marca de tiempo de la última tarea y recuentos por estado
- Tarjetas de tablero A2A para monitoreo de operaciones en tiempo real
</details>
<details>
<summary><b>🪪 25. "Necesito descubrimiento de agente estándar para clientes"</b></summary>
Los clientes y orquestadores externos necesitan metadatos legibles por máquina para la incorporación.
**Cómo lo resuelve OmniRoute:**
- Tarjeta de agente expuesta en `/.well-known/agent.json`
- Capacidades y habilidades mostradas en la interfaz de usuario de gestión.
- La API de estado A2A incluye metadatos de descubrimiento para la automatización
</details>
<details>
<summary><b>🧭 26. "Necesito capacidad de descubrimiento de protocolo en la UX del producto"</b></summary>
Si los usuarios no pueden descubrir las superficies de protocolo, la calidad de la adopción y el soporte disminuye.
**Cómo lo resuelve OmniRoute:**
- Entradas de la barra lateral para MCP y A2A
- Pestaña Protocolos de la página del endpoint con inicio rápido y estado
- Enlaces desde la descripción general a paneles de gestión dedicados
</details>
<details>
<summary><b>🧪 27. "Necesito validación de protocolo de extremo a extremo con clientes reales"</b></summary>
Las pruebas simuladas no son suficientes para validar la compatibilidad del protocolo antes del lanzamiento.
**Cómo lo resuelve OmniRoute:**
- Suite E2E que inicia la aplicación y utiliza transporte de cliente MCP SDK real
- Pruebas de cliente A2A para descubrimiento, envío, transmisión, obtención y cancelación de flujos
- Verificar las afirmaciones con las API de auditoría MCP y tareas A2A.
</details>
<details>
<summary><b>📡 28. "Necesito observabilidad unificada en todas las interfaces"</b></summary>
Dividir la observabilidad por protocolo crea puntos ciegos y MTTR más largos.
**Cómo lo resuelve OmniRoute:**
- Paneles/registros/análisis unificados en un solo producto
- Salud + auditoría + solicitud de telemetría en capas OpenAI, MCP y A2A
- API operativas para estado y automatización.
</details>
<details>
<summary><b>💼 29. "Necesito un tiempo de ejecución para proxy + herramientas + orquestación de agentes"</b></summary>
La ejecución de muchos servicios separados aumenta los costos operativos y los modos de falla.
**Cómo lo resuelve OmniRoute:**
- Proxy compatible con OpenAI, servidor MCP y servidor A2A en una sola pila
- Autenticación compartida, resiliencia, almacenamiento de datos y observabilidad.
- Modelo de política consistente en todas las superficies de interacción.
</details>
<details>
<summary><b>🚀 30. "Necesito enviar flujos de trabajo agentes sin expansión de código adhesivo"</b></summary>
Los equipos pierden velocidad al unir múltiples scripts y servicios ad hoc.
**Cómo lo resuelve OmniRoute:**
- Estrategia de endpoint unificada para clientes y agentes
- UI de gestión de protocolos integradas y rutas de validación de humo
- Fundamentos listos para producción (seguridad, registro, resiliencia, respaldo)
</details>
### Guías de ejemplo (casos de uso integrados)
**Libro de estrategias A: maximizar la suscripción paga + copia de seguridad económica**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Libro de estrategias B: pila de codificación de costo cero**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Libro de estrategias C: cadena alternativa siempre disponible las 24 horas del día, los 7 días de la semana**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Libro de jugadas D: Operaciones del agente con MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Inicio Rápido
**1. Instala globalmente:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Aplicación de Escritorio — Sin Conexión y Siempre Activo
## 🖥️
> 🆕 **¡NUEVO!** OmniRoute ahora está disponible como **aplicación de escritorio nativa** para Windows, macOS y Linux.
@@ -593,6 +868,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Característica | Qué Hace |
| ---------------------------------- | ---------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Auto-apertura/cierre por proveedor con umbrales configurables |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **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 |
@@ -700,66 +976,26 @@ Traducción transparente entre formatos:
</details>
---
## 🧪 Evaluaciones (Evals)
## 🎯 Casos de Uso
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.
### Caso 1: "Tengo suscripción Claude Pro"
### Conjunto Golden Integrado
**Problema:** La cuota expira sin usar, límites de tasa durante programación intensa
El "OmniRoute Golden Set" precargado contiene 10 casos de prueba que cubren:
```
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)
- 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
Costo mensual: $20 (suscripción) + ~$5 (respaldo) = $25 total
vs. $20 + chocar con límites = frustración
```
### Estrategias de Evaluació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...
```
| 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` |
---
@@ -1043,29 +1279,6 @@ Configuración → Configuración de API:
---
## 🧪 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>
@@ -1121,7 +1334,7 @@ El "OmniRoute Golden Set" precargado contiene 10 casos de prueba que cubren:
---
## 🛠️ Stack Tecnológico
## 🛠️
- **Runtime**: Node.js 20+
- **Lenguaje**: TypeScript 5.9 — **100% TypeScript** en `src/` y `open-sse/` (v1.0.6)
@@ -1152,17 +1365,7 @@ El "OmniRoute Golden Set" precargado contiene 10 casos de prueba que cubren:
---
## 📧 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

View File

@@ -110,6 +110,35 @@ _Yhdistä mikä tahansa tekoälyllä toimiva IDE- tai CLI-työkalu OmniRouten ka
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Miksi OmniRoute?
**Lopeta rahan tuhlaaminen ja rajojen ylittäminen:**
@@ -128,6 +157,18 @@ _Yhdistä mikä tahansa tekoälyllä toimiva IDE- tai CLI-työkalu OmniRouten ka
---
## 📧 Tuki
> 💬 **Liity yhteisöömme!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Hanki apua, jaa vinkkejä ja pysy ajan tasalla.
- **Verkkosivusto**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Ongelmia**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Alkuperäinen projekti**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Näin se toimii
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Mitä OmniRoute ratkaisee 30 todellista kipukohtaa ja käyttötapausta
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Jokainen tekoälytyökaluja käyttävä kehittäjä kohtaa nämä ongelmat päivittäin.** OmniRoute luotiin ratkaisemaan ne kaikki kustannusten ylityksistä alueellisiin lohkoihin, rikkinäisistä OAuth-virroista protokollatoimintoihin ja yrityksen havainnointikykyyn.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Maksan kalliista tilauksesta, mutta silti rajoitukset häiritsevät minua"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Kehittäjät maksavat 20200 dollaria kuukaudessa Claude Prosta, Codex Prosta tai GitHub Copilotista. Maksamallakin kiintiöllä on katto 5 tuntia käyttöä, viikkorajat tai minuuttirajoitukset. Koodausistunnon puolivälissä palveluntarjoaja lakkaa vastaamasta ja kehittäjä menettää virtauksen ja tuottavuuden.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Jos tilauskiintiö loppuu, ohjataan automaattisesti kohtaan API-avain → Halpa → Ilmainen ilman manuaalista toimenpiteitä
- **Reaaliaikainen kiintiöseuranta** - Näyttää tunnuksen kulutuksen reaaliajassa ja nollaa lähtölaskenta (5 tuntia, päivittäin, viikoittain)
- **Useiden tilien tuki** — Useita tilejä palveluntarjoajaa kohden automaattisella kierrätyksellä — kun yksi loppuu, vaihtuu seuraavaan
- **Muokatut yhdistelmät** — Muokattavat varaketjut, joissa on 6 tasapainotusstrategiaa (täytä ensin, round-robin, P2C, satunnainen, vähiten käytetty, kustannusoptimoitu)
- **Codex Business Quotat** — Yritysten/Tiimien työtilan kiintiöiden valvonta suoraan kojelaudassa
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Minun täytyy käyttää useita palveluntarjoajia, mutta jokaisella on erilainen API"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI käyttää yhtä muotoa, Claude (Anthropic) käyttää toista, Gemini vielä toista. Jos kehittäjä haluaa testata eri palveluntarjoajien malleja tai vaihtoehtoja niiden välillä, hänen on määritettävä SDK:t uudelleen, muutettava päätepisteitä ja käsiteltävä yhteensopimattomia muotoja. Mukautetuilla palveluntarjoajilla (FriendLI, NIM) on mallista poikkeavat päätepisteet.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Yhdistetty päätepiste** — Yksi `http://localhost:20128/v1` toimii välityspalvelimena kaikille yli 36 palveluntarjoajalle
- **Format Translation** - Automaattinen ja läpinäkyvä: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** Poistaa standardista poikkeavat kentät (`x_groq`, `usage_breakdown`, `service_tier`), jotka rikkovat OpenAI SDK v1.83+:n
- **Roolin normalisointi** — Muuntaa `developer``system` muille kuin OpenAI-palveluntarjoajille; `system``user` GLM/ERNIE:lle
- **Think Tag Extraction** - Purkaa `<think>`-lohkot malleista, kuten DeepSeek R1, standardoituun `reasoning_content`:hen
- **Strukturoitu lähtö Geminille** — `json_schema``responseMimeType`/`responseSchema` automaattinen muunnos
- **`stream`:n oletusarvo on `false`** — yhdenmukaistuu OpenAI-spesifikaation kanssa välttäen odottamattoman SSE:n Python/Rust/Go SDK:issa
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Tekoälypalveluntarjoajani estää alueeni/maani"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Palveluntarjoajat, kuten OpenAI/Codex, estävät pääsyn tietyiltä maantieteellisiltä alueilta. Käyttäjät saavat virheitä, kuten `unsupported_country_region_territory`, OAuth- ja API-yhteyksien aikana. Tämä on erityisen turhauttavaa kehitysmaiden kehittäjille.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-tason välityspalvelimen määritys** Muokattava välityspalvelin kolmella tasolla: yleinen (kaikki liikenne), palveluntarjoajakohtainen (vain yksi palveluntarjoaja) ja yhteys/avain
- **Värikoodatut välityspalvelinmerkit** — Visuaaliset ilmaisimet: 🟢 maailmanlaajuinen välityspalvelin, 🟡 tarjoajan välityspalvelin, 🔵 yhteysvälityspalvelin, joka näyttää aina IP-osoitteen
- **OAuth-tunnusten vaihto välityspalvelimen kautta** — OAuth-kulku kulkee myös välityspalvelimen kautta, mikä ratkaisee `unsupported_country_region_territory`
- **Yhteystestit välityspalvelimen kautta** - Yhteystestit käyttävät määritettyä välityspalvelinta (ei enää suoraa ohitusta)
- **SOCKS5-tuki** — Täysi SOCKS5-välityspalvelintuki lähtevään reititykseen
- **TLS-sormenjälkien huijaus** — Selaimen kaltainen TLS-sormenjälki `wreq-js`:n kautta ohittaakseen bot-tunnistuksen
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Haluan käyttää tekoälyä koodaukseen, mutta minulla ei ole rahaa"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Kaikki eivät voi maksaa 20200 dollaria kuukaudessa tekoälytilauksista. Opiskelijat, kehittäjät nousevista maista, harrastajat ja freelancerit tarvitsevat pääsyn laadukkaisiin malleihin ilman kustannuksia.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Free Tier Providers Built-in** Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Free Tier Providers -sisäänrakennettu** - Natiivituki 100 % ilmaisille palveluntarjoajille: iFlow (8 rajatonta mallia), Qwen (3 rajoittamatonta mallia), Kiro (Claude ilmaiseksi), Gemini CLI (180 000/kk ilmaiseksi)
- **Vain ilmaiset yhdistelmät** — Ketju `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 $/kk ilman seisonta-aikaa
- **NVIDIA NIM Free Credits** - 1000 ilmaista saldoa integroituna
- **Kustannusoptimoitu strategia** — Reititysstrategia, joka valitsee automaattisesti halvimman saatavilla olevan palveluntarjoajan
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Minun täytyy suojata tekoälyyhdyskäytävääni luvattomalta käytöltä"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Kun paljastat tekoälyyhdyskäytävän verkkoon (LAN, VPS, Docker), kuka tahansa osoitteen tietävä voi kuluttaa kehittäjän tunnukset/kiintiöt. Ilman suojaa API:t ovat alttiita väärinkäytölle, nopealle injektiolle ja väärinkäytöksille.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API-avainten hallinta** — Luominen, kierto ja laajuus palveluntarjoajakohtaisesti erillisellä `/dashboard/api-manager`-sivulla
- **Mallitason käyttöoikeudet** - Rajoita API-avaimet tiettyihin malleihin (`openai/*`, jokerimerkkimallit) Salli kaikki/Rajoita-kytkimellä
- **API Endpoint Protection** — Vaadi avainta `/v1/models`:lle ja estä tietyt palveluntarjoajat luettelosta
- **Auth Guard + CSRF-suojaus** — Kaikki kojelaudan reitit on suojattu `withAuth`-väliohjelmistolla + CSRF-tunnuksilla
- **Rate Limiter** — IP-nopeuden rajoitus konfiguroitavilla ikkunoilla
- **IP-suodatus** — Pääsynhallinnan sallittu-/estolista
- **Prompt Injection Guard** — Desinfiointi haitallisia kehotusmalleja vastaan
- **AES-256-GCM Encryption** — Tunnistetiedot on salattu lepotilassa
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "palveluntarjoajani kaatui ja menetin koodauskulkuni"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Tekoälypalveluntarjoajat voivat muuttua epävakaiksi, palauttaa 5xx-virheitä tai saavuttaa väliaikaiset nopeusrajoitukset. Jos kehittäjä on riippuvainen yhdestä palveluntarjoajasta, se keskeytyy. Ilman katkaisijoita toistuvat uudelleenyritykset voivat kaataa sovelluksen.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Circuit Breaker per-provider** Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Katkaisija palveluntarjoajakohtaisesti** - Automaattinen avautuminen/sulkeminen konfiguroitavilla kynnyksillä ja jäähdytys (suljettu/auki/puoliauki)
- **Eksponentiaalinen peruutus** — Progressiiviset uudelleenyritysviiveet
- **Anti-Thundering Herd** — Mutex + semaforisuoja samanaikaisia myrskyjä vastaan
- **Yhdistelmävaraketjut** Jos ensisijainen toimittaja epäonnistuu, putoaa automaattisesti ketjun läpi ilman väliintuloa
- **Combo Circuit Breaker** — Poistaa automaattisesti käytöstä vialliset palveluntarjoajat yhdistelmäketjussa
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Health Dashboard** — käytettävyyden valvonta, katkaisijoiden tilat, lukitukset, välimuistitilastot, p50/p95/p99-viive
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Jokaisen tekoälytyökalun määrittäminen on työlästä ja toistuvaa"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Kehittäjät käyttävät kursoria, Claude Codea, Codex CLI:tä, OpenClaw:ta, Gemini CLI:tä, Kilo Codea... Jokainen työkalu tarvitsee eri konfiguraation (API-päätepiste, avain, malli). Uudelleenmääritys toimittajaa tai mallia vaihdettaessa on ajanhukkaa.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** - Erillinen sivu yhdellä napsautuksella Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Luo `chatLanguageModels.json` VS-koodille joukkomallin valinnalla
- **Ohjattu käyttöönottotoiminto** — Ohjattu 4-vaiheinen asennus ensikertalaisille
- **Yksi päätepiste, kaikki mallit** — Määritä `http://localhost:20128/v1` kerran, käytä 36+ palveluntarjoajaa
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Useiden palveluntarjoajien OAuth-tunnusten hallinta on helvettiä"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot kaikki käyttävät OAuth 2.0:aa vanhentuvilla tunnuksilla. Kehittäjien on todennettava jatkuvasti uudelleen, käsiteltävä `client_secret is missing`-, `redirect_uri_mismatch`- ja etäpalvelimien vikoja. OAuth LAN/VPS:ssä on erityisen ongelmallinen.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Auto Token Refresh** OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automaattinen tunnuksen päivitys** - OAuth-tunnukset päivittyvät taustalla ennen vanhenemista
- **Sisäänrakennettu OAuth 2.0 (PKCE)** - Automaattinen kulku Claude Codelle, Codexille, Gemini CLI:lle, Copilotille, Kirolle, Qwenille, iFlowille
- **Multi-Account OAuth** - Useita tilejä palveluntarjoajaa kohden JWT/ID-tunnuksen purkamisen kautta
- **OAuth LAN/Remote Fix** — Yksityinen IP-tunnistus `redirect_uri`:lle + manuaalinen URL-tila etäpalvelimille
- **OAuth Nginxin takana** - Käyttää `window.location.origin`-protokollaa käänteisen välityspalvelimen yhteensopivuuteen
- **OAuth-etäopas** — Vaiheittainen opas Google Cloud -kirjautumistiedoille VPS/Dockerissa
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "En tiedä kuinka paljon kulutan tai minne"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Kehittäjät käyttävät useita maksullisia palveluntarjoajia, mutta heillä ei ole yhtenäistä näkemystä kuluttamisesta. Jokaisella palveluntarjoajalla on oma laskutuksen hallintapaneeli, mutta yhdistettyä näkymää ei ole. Odottamattomat kustannukset voivat kasaantua.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Cost Analytics Dashboard** Token-kohtainen kustannusseuranta ja budjetin hallinta palveluntarjoajakohtaisesti
- **Tasokohtaiset budjettirajat** Tasokohtainen kulutuskatto, joka laukaisee automaattisen varauksen
- **Malleittainen hinnoittelu** — Muokattavat hinnat mallikohtaisesti
- **Käyttötilastot API-avainta kohti** — Pyyntömäärä ja viimeksi käytetty aikaleima avainta kohti
- **Analytics Dashboard** - Tilastokortit, mallin käyttökaavio, toimittajataulukko onnistumisprosenteilla ja viiveellä
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "En pysty diagnosoimaan tekoälypuhelujen virheitä ja ongelmia"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Kun puhelu epäonnistuu, kehittäjä ei tiedä, oliko kyseessä nopeusrajoitus, vanhentunut tunnus, väärä muoto vai palveluntarjoajan virhe. Sirpaloituneet lokit eri terminaaleissa. Ilman havaittavuutta virheenkorjaus on yrityksen ja erehdysten menetelmää.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Unified Logs Dashboard** 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Yhdistettyjen lokien hallintapaneeli** - 4 välilehteä: pyyntölokit, välityspalvelimen lokit, tarkastuslokit, konsoli
- **Console Log Viewer** - Reaaliaikainen päätetyylinen katseluohjelma värikoodatuilla tasoilla, automaattinen vieritys, haku, suodatin
- **SQLite-välityspalvelimen lokit** — Pysyvät lokit, jotka kestävät palvelimen uudelleenkäynnistyksen
- **Kääntäjän leikkikenttä** — 4 virheenkorjaustilaa: Playground (muodon käännös), Chat Tester (meno-paluu), testipenkki (erä), Live Monitor (reaaliaikainen)
- **Pyyntötelemetria** — p50/p95/p99-latenssi + X-Request-Id-seuranta
- **Tiedostopohjainen kirjaaminen rotaatiolla** Konsolin sieppaaja tallentaa kaiken JSON-lokiin kokoperusteisella kierrolla
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Yhdyskäytävän käyttöönotto ja ylläpito on monimutkaista"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
AI-välityspalvelimen asentaminen, määrittäminen ja ylläpito eri ympäristöissä (paikallinen, VPS, Docker, pilvi) on työvoimavaltaista. Ongelmat, kuten kovakoodatut polut, `EACCES` hakemistoissa, porttiristiriidat ja monikäyttöjärjestelmät lisäävät kitkaa.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm yleinen asennus** — `npm install -g omniroute && omniroute`valmis
- **Docker Multi-Platform** - AMD64 + ARM64 natiivi (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose -profiilit** — `base` (ei CLI-työkaluja) ja `cli` (Claude Code, Codex, OpenClaw)
- **Electron Desktop App** - Natiivisovellus Windowsille/macOS:lle/Linuxille, jossa ilmaisinalue, automaattinen käynnistys, offline-tila
- **Split-Port Mode** — API ja Dashboard erillisissä porteissa edistyneille skenaarioille (käänteinen välityspalvelin, konttiverkko)
- **Cloud Sync** - Määritä synkronointi laitteiden välillä Cloudflare Workersin kautta
- **DB-varmuuskopiot** — Kaikkien asetusten automaattinen varmuuskopiointi, palautus, vienti ja tuonti
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Käyttöliittymä on vain englanninkielinen ja tiimini ei puhu englantia"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Ryhmät muissa kuin englanninkielisissä maissa, erityisesti Latinalaisessa Amerikassa, Aasiassa ja Euroopassa, kamppailevat vain englanninkielisten käyttöliittymien kanssa. Kielimuurit vähentävät käyttöönottoa ja lisäävät konfigurointivirheitä.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 kieltä** — Kaikki yli 500 näppäintä käännetty mukaan lukien arabia, bulgaria, tanska, saksa, espanja, suomi, ranska, heprea, hindi, unkari, indonesia, italia, japani, korea, malaiji, hollanti, norja, puola, portugali (PT/BR), romania, thai, venäjä, ukraina, slovakki, ruotsi, englanti
- **RTL-tuki** — Tuki oikealta vasemmalle arabian ja heprean kielelle
- **Multi-Language READMEs** - 30 täydellistä dokumentaation käännöstä
- **Kielen valitsin** — Maapallokuvake otsikossa reaaliaikaista vaihtoa varten
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Tarvitsen muutakin kuin chatin tarvitsen upotuksia, kuvia, ääntä"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
Tekoäly ei ole vain chatin loppuun saattamista. Kehittäjien on luotava kuvia, litteroitava ääni, luotava upotuksia RAG:lle, järjestettävä asiakirjat uudelleen ja valvottava sisältöä. Jokaisella API:lla on eri päätepiste ja muoto.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Upotukset** — `/v1/embeddings`, 6 toimittajaa ja 9+ mallia
- **Image Generation** — `/v1/images/generations` 10 palveluntarjoajan ja 20+ mallin kanssa (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Tekstistä videoksi** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) ja SD WebUI
- **Tekstistä musiikiksi** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Äänitranskriptio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Tekstistä puheeksi** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 ja olemassa olevat palveluntarjoajat
- **Moderaatiot** — `/v1/moderations` — Sisällön turvallisuustarkastukset
- **Uudelleensijoitus** — `/v1/rerank` — Asiakirjan relevanssin uudelleensijoitus
- **Responses API** — Täysi `/v1/responses`-tuki Codexille
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Minulla ei ole mahdollisuutta testata ja vertailla laatua eri mallien välillä"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Kehittäjät haluavat tietää, mikä malli sopii parhaiten heidän käyttötapaukseensa koodi, käännös, päättely mutta manuaalinen vertailu on hidasta. Integroituja arviointityökaluja ei ole olemassa.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM-arvioinnit** — Golden set -testaus 10 esiladatulla kotelolla, jotka kattavat tervehdyksen, matematiikan, maantieteen, koodin luomisen, JSON-yhteensopivuuden, käännöksen, merkinnän, turvallisuuden kieltämisen
- **4 sovitusstrategiaa** — `exact`, `contains`, `regex`, `custom` (JS-toiminto)
- **Translator Playground Test Bench** - Erätestaus useilla tuloilla ja odotetulla lähdöllä, tarjoajien välinen vertailu
- **Chat Tester** - Täysi edestakainen matka visuaalisen vasteen renderöinnillä
- **Live Monitor** — Reaaliaikainen tietovirta kaikista välityspalvelimen kautta kulkevista pyynnöistä
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Minun täytyy skaalata suorituskykyä menettämättä"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Pyynnön määrän kasvaessa samat kysymykset aiheuttavat päällekkäisiä kustannuksia välimuistiin tallentamatta. Ilman idempotenssia kaksoiskappaleet pyytävät jätteenkäsittelyä. Palveluntarjoajakohtaisia hintarajoja on noudatettava.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** 3-tier cache for production performance
- **Health Dashboard with Telemetry** p50/p95/p99 latency, cache stats, uptime
- **Semanttinen välimuisti** Kaksitasoinen välimuisti (allekirjoitus + semanttinen) vähentää kustannuksia ja viivettä
- **Request Idempotency** — 5 sekunnin deduplikaatioikkuna identtisille pyynnöille
- **nopeusrajoituksen tunnistus** palveluntarjoajakohtainen RPM, pienin väli ja suurin samanaikainen seuranta
- **Muokattavat nopeusrajoitukset** - Määritettävissä olevat oletusasetukset kohdassa Asetukset → Resilience with persistence
- **API Key Validation Cache** 3-tasoinen välimuisti tuotannon suorituskykyä varten
- **Health Dashboard telemetrialla** - p50/p95/p99 latenssi, välimuistitilastot, käyttöaika
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Haluan hallita mallin käyttäytymistä maailmanlaajuisesti"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Kehittäjät, jotka haluavat kaikki vastaukset tietyllä kielellä, tietyllä sävyllä tai haluavat rajoittaa perusteluita. Tämän määrittäminen jokaiseen työkaluun/pyyntöön on epäkäytännöllistä.
**How OmniRoute solves it:**
**Kuinka OmniRoute ratkaisee sen:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Järjestelmäkehotteen lisäys** — Yleinen kehote koskee kaikkia pyyntöjä
- **Thinking Budget Validation** perustelutunnisteen allokoinnin ohjaus pyyntöä kohti (läpivienti, automaattinen, mukautettu, mukautuva)
- **6 reititysstrategiaa** — Globaalit strategiat, jotka määrittävät pyyntöjen jakautumisen
- **Wildcard Router** — `provider/*`-mallit reitittävät dynaamisesti mille tahansa palveluntarjoajalle
- **Yhdistelmä käyttöön/pois käytöstä** - Vaihda yhdistelmät suoraan kojelaudalta
- **Provider Toggle** — Ota käyttöön tai poista käytöstä kaikki palveluntarjoajan yhteydet yhdellä napsautuksella
- **Estetyt palveluntarjoajat** - Sulje tietyt palveluntarjoajat pois `/v1/models`-luettelosta
</details>
<details>
<summary><b>🧰 17. "Tarvitsen MCP-työkaluja ensiluokkaisina tuoteominaisuuksina"</b></summary>
Monet tekoälyyhdyskäytävät paljastavat MCP:n vain piilotettuna toteutustietona. Tiimit tarvitsevat näkyvän, hallittavan toimintakerroksen.
**Kuinka OmniRoute ratkaisee sen:**
- MCP näkyy kojelaudan navigointi- ja päätepisteprotokolla-välilehdessä
- Erillinen MCP-hallintasivu, jossa on prosessit, työkalut, laajuudet ja tarkastus
- Sisäänrakennettu pikakäynnistys `omniroute --mcp`:lle ja asiakkaan käyttöönottoon
</details>
<details>
<summary><b>🧠 18. "Tarvitsen A2A-orkesterin synkronointia ja suoratoiston tehtäväpolkuja"</b></summary>
Agenttityönkulut tarvitsevat sekä suoria vastauksia että pitkäkestoista suoratoistoa elinkaariohjauksella.
**Kuinka OmniRoute ratkaisee sen:**
- A2A JSON-RPC -päätepiste (`POST /a2a`) `message/send`:n ja `message/stream`:n kanssa
- SSE-suoratoisto päätetilan etenemisellä
- Tehtävän elinkaaren sovellusliittymät `tasks/get`:lle ja `tasks/cancel`:lle
</details>
<details>
<summary><b>🛰️ 19. "Tarvitsen todellisen MCP-prosessin kunnon, en arvatun tilan"</b></summary>
Operatiivisten tiimien on tiedettävä, onko MCP todella elossa, ei vain sitä, onko API tavoitettavissa.
**Kuinka OmniRoute ratkaisee sen:**
- Ajonaikainen syketiedosto, jossa on PID, aikaleimat, kuljetus, työkalujen määrä ja laajuustila
- MCP-tilan API, joka yhdistää sykkeen + viimeaikaisen toiminnan
- Käyttöliittymän tilakortit prosessin / käytettävyyden / sydämenlyöntien tuoreudelle
</details>
<details>
<summary><b>📋 20. "Tarvitsen tarkastettavan MCP-työkalun suorituksen"</b></summary>
Kun työkalut muuttavat määrityksiä tai käynnistävät operaatioita, tiimit tarvitsevat rikosteknistä jäljitettävyyttä.
**Kuinka OmniRoute ratkaisee sen:**
- SQLite-tuettu tarkastusloki MCP-työkalukutsuille
- Suodattimet työkalun, onnistumisen/epäonnistumisen, API-avaimen ja sivutuksen mukaan
- Kojelaudan tarkastustaulukko + tilastopäätepisteet automatisointia varten
</details>
<details>
<summary><b>🔐 21. "Tarvitsen laajennettuja MCP-oikeuksia integraatiota kohti"</b></summary>
Eri asiakkailla tulisi olla vähiten käyttöoikeus työkaluluokkiin.
**Kuinka OmniRoute ratkaisee sen:**
- 9 rakeista MCP-skooppia ohjattua työkalujen käyttöä varten
- Laajuuden valvonta ja näkyvyys MCP-hallintaliittymässä
- Turvallinen oletusasento käyttötyökaluille
</details>
<details>
<summary><b>⚙️ 22. "Tarvitsen toiminnan ohjaimia ilman uudelleenjärjestelyä"</b></summary>
Tiimit tarvitsevat nopeita ajonaikaisia muutoksia tapausten tai kustannustapahtumien aikana.
**Kuinka OmniRoute ratkaisee sen:**
- Vaihda yhdistelmäaktivointia suoraan MCP-kojelaudalta
- Käytä joustavuusprofiileja ennalta määritetyistä käytäntöpaketeista
- Nollaa katkaisijan tila samasta käyttöpaneelista
</details>
<details>
<summary><b>🔄 23. "Tarvitsen live-A2A-tehtävän elinkaaren näkyvyyden ja peruutuksen"</b></summary>
Ilman elinkaaren näkyvyyttä tehtäväkohtauksista tulee vaikeasti luokiteltuja.
**Kuinka OmniRoute ratkaisee sen:**
- Tehtäväluettelo / suodatus tilan / taitojen mukaan ja sivutus
- Tehtävän metatietojen, tapahtumien ja artefaktien yksityiskohdat
- Tehtävän peruutuksen päätepiste ja käyttöliittymätoiminto vahvistuksen kanssa
</details>
<details>
<summary><b>🌊 24. "Tarvitsen aktiivisia suoratoistotietoja A2A-kuormalle"</b></summary>
Streaming-työnkulut edellyttävät toiminnallista tietoa samanaikaisuudesta ja reaaliaikaisista yhteyksistä.
**Kuinka OmniRoute ratkaisee sen:**
- Aktiiviset virtalaskurit integroitu A2A-tilaan
- Viimeisen tehtävän aikaleima ja tilakohtaiset määrät
- A2A kojelautakortit reaaliaikaiseen toimintojen seurantaan
</details>
<details>
<summary><b>🪪 25. "Tarvitsen asiakkaille vakioagentin haun"</b></summary>
Ulkoiset asiakkaat ja orkesterit tarvitsevat koneellisesti luettavaa metadataa käyttöönottoa varten.
**Kuinka OmniRoute ratkaisee sen:**
- Agenttikortti esillä osoitteessa `/.well-known/agent.json`
- Johdon käyttöliittymässä näkyvät valmiudet ja taidot
- A2A status API sisältää etsintämetatiedot automatisointia varten
</details>
<details>
<summary><b>🧭 26. "Tarvitsen protokollan löydettävyyden tuotteessa UX"</b></summary>
Jos käyttäjät eivät löydä protokollapintoja, käyttöönoton ja tuen laatu heikkenee.
**Kuinka OmniRoute ratkaisee sen:**
- Sivupalkkimerkinnät MCP:lle ja A2A:lle
- Päätepistesivu Protokollat-välilehti, jossa on pika-aloitus ja tila
- Linkit yleiskatsauksesta erityisiin hallintapaneeliin
</details>
<details>
<summary><b>🧪 27. "Tarvitsen päästä päähän -protokollan validoinnin oikeiden asiakkaiden kanssa"</b></summary>
Valetestit eivät riitä vahvistamaan protokollan yhteensopivuutta ennen julkaisua.
**Kuinka OmniRoute ratkaisee sen:**
- E2E-paketti, joka käynnistää sovelluksen ja käyttää todellista MCP SDK -asiakassiirtoa
- A2A-asiakas testaa virtojen löytämistä, lähettämistä, suoratoistoa, vastaanottamista ja peruuttamista
- Tarkista väitteet MCP-tarkastuksen ja A2A-tehtävien sovellusliittymien kanssa
</details>
<details>
<summary><b>📡 28. "Tarvitsen yhtenäisen havainnoinnin kaikissa liitännöissä"</b></summary>
Havainnon jakaminen protokollan mukaan luo kuolleita kulmia ja pidemmän MTTR:n.
**Kuinka OmniRoute ratkaisee sen:**
- Yhdistetyt kojelaudat/lokit/analytiikka yhdessä tuotteessa
- Terveys + auditointi + pyyntö telemetria OpenAI-, MCP- ja A2A-tasoilla
- Toiminnalliset sovellusliittymät tilaa ja automaatiota varten
</details>
<details>
<summary><b>💼 29. "Tarvitsen yhden suoritusajan välityspalvelimelle + työkaluille + agentin orkestraatiolle"</b></summary>
Useiden erillisten palvelujen suorittaminen lisää käyttökustannuksia ja vikatiloja.
**Kuinka OmniRoute ratkaisee sen:**
- OpenAI-yhteensopiva välityspalvelin, MCP-palvelin ja A2A-palvelin yhdessä pinossa
- Jaettu todennus, joustavuus, tietovarasto ja havaittavuus
- Yhdenmukainen toimintamalli kaikilla vuorovaikutuspinnoilla
</details>
<details>
<summary><b>🚀 30. "Minun on lähetettävä agenttityönkulkuja ilman liimakoodin leviämistä"</b></summary>
Tiimit menettävät nopeutta yhdistäessään useita ad-hoc-palveluita ja skriptejä.
**Kuinka OmniRoute ratkaisee sen:**
- Yhtenäinen päätepistestrategia asiakkaille ja edustajille
- Sisäänrakennetut protokollien hallinnan käyttöliittymät ja savun vahvistuspolut
- Tuotantovalmis perusta (turvallisuus, puunkorjuu, joustavuus, varmuuskopiointi)
</details>
### Esimerkkiohjekirjat (integroidut käyttötapaukset)
**Ohjekirja A: maksimoi maksullinen tilaus + halpa varmuuskopio**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Ohjekirja B: Nollahintainen koodauspino**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 aina päällä oleva varaketju**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Pelikirja D: Agentti toimii MCP:llä + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Pika-aloitus
**1. Asenna maailmanlaajuisesti:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +991,26 @@ OmniRoute sisältää tehokkaan sisäänrakennetun Translator Playgroundin, joss
</details>
---
## 🧪 Arvioinnit (Evals)
## 🎯 Käyttökotelot
OmniRoute sisältää sisäänrakennetun arviointikehyksen, jolla testataan LLM-vastauksen laatua kultaiseen joukkoon verrattuna. Käytä sitä kojelaudan **Analytics → Evals** kautta.
### Tapaus 1: "Minulla on Claude Pro -tilaus"
### Sisäänrakennettu kultainen setti
**Ongelma:** Kiintiö vanhenee käyttämättä, nopeusrajoitukset raskaan koodauksen aikana
Esiladattu "OmniRoute Golden Set" sisältää 10 testitapausta, jotka kattavat:
```
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)
- Tervehdys, matematiikka, maantiede, koodin luominen
- JSON-muodon noudattaminen, käännös, merkintä
- Turvallisuuskielto (haitallinen sisältö), laskenta, boolen logiikka
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Arviointistrategiat
### Tapaus 2: "Haluan ilman kustannuksia"
**Ongelma:** Ei ole varaa tilauksiin, tarvitaan luotettavaa tekoälykoodausta
```
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
```
### Tapaus 3: "Tarvitsen 24/7-koodausta, ei keskeytyksiä"
**Ongelma:** Määräajat, seisokkeihin ei ole varaa
```
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
```
### Tapaus 4: "Haluan ILMAISTA tekoälyä OpenClawissa"
**Ongelma:** Tarvitset AI-avustajan viestisovelluksissa, täysin ilmainen
```
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...
```
| Strategia | Kuvaus | Esimerkki |
| ---------- | ------------------------------------------------------------------------ | -------------------------------- |
| `exact` | Tulosten on vastattava tarkasti | `"4"` |
| `contains` | Tulosteen tulee sisältää alimerkkijono (kirjainkoolla ei ole merkitystä) | `"Paris"` |
| `regex` | Tulostuksen on vastattava regex-mallia | `"1.*2.*3"` |
| `custom` | Mukautettu JS-funktio palauttaa true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Arvioinnit (Evals)
OmniRoute sisältää sisäänrakennetun arviointikehyksen, jolla testataan LLM-vastauksen laatua kultaiseen joukkoon verrattuna. Käytä sitä kojelaudan **Analytics → Evals** kautta.
### Sisäänrakennettu kultainen setti
Esiladattu "OmniRoute Golden Set" sisältää 10 testitapausta, jotka kattavat:
- Tervehdys, matematiikka, maantiede, koodin luominen
- JSON-muodon noudattaminen, käännös, merkintä
- Turvallisuuskielto (haitallinen sisältö), laskenta, boolen logiikka
### Arviointistrategiat
| Strategia | Kuvaus | Esimerkki |
| ---------- | ------------------------------------------------------------------------ | -------------------------------- |
| `exact` | Tulosten on vastattava tarkasti | `"4"` |
| `contains` | Tulosteen tulee sisältää alimerkkijono (kirjainkoolla ei ole merkitystä) | `"Paris"` |
| `regex` | Tulostuksen on vastattava regex-mallia | `"1.*2.*3"` |
| `custom` | Mukautettu JS-funktio palauttaa true/false | `(output) => output.length > 10` |
---
## 🐛 Vianetsintä
<details>
@@ -1132,13 +1345,13 @@ Esiladattu "OmniRoute Golden Set" sisältää 10 testitapausta, jotka kattavat:
- OmniRoute v1.0.6+ sisältää varatarkistuksen chatin loppuunsaattamisen kautta
- Varmista, että perus-URL sisältää `/v1`-liitteen
### 🔐 OAuth em Servidor Remoto (OAuth-etäasetus)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ TÄRKEÄÄ käyttäjille com OmniRoute em VPS/Docker/servidor Remoto**
### Onko OAuth do Antigravity / Gemini CLI falha em servidores Remotos?
### OAuth
Os provedores **Antigravity** ja **Gemini CLI** usam **Google OAuth 2.0** para autenticação. O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pre-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **Suoritusaika**: Node.js 1822 LTS (⚠️ Node.js 24+ -versiota **ei tueta**`better-sqlite3` alkuperäiset binaarit eivät ole yhteensopivia)
- **Kieli**: TypeScript 5.9 — **100 % TypeScript** `src/` ja `open-sse/` (v1.0.6) välillä
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Etenemissuunnitelma
## 🗺️
OmniRoutella on **210+ suunniteltua ominaisuutta** useissa kehitysvaiheissa. Tässä ovat tärkeimmät alueet:
@@ -1304,18 +1517,6 @@ OmniRoutella on **210+ suunniteltua ominaisuutta** useissa kehitysvaiheissa. Tä
---
## 📧 Tuki
> 💬 **Liity yhteisöömme!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Hanki apua, jaa vinkkejä ja pysy ajan tasalla.
- **Verkkosivusto**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Ongelmia**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Alkuperäinen projekti**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Avustajat
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Connectez n'importe quel IDE ou outil CLI alimenté par l'IA via OmniRoute —
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Pourquoi OmniRoute ?
**Arrêtez de gaspiller de l'argent et de vous heurter aux limites :**
@@ -128,6 +157,18 @@ _Connectez n'importe quel IDE ou outil CLI alimenté par l'IA via OmniRoute —
---
## 📧 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)
---
## 🔄 Comment ça fonctionne
```
@@ -157,263 +198,497 @@ Résultat : Ne jamais arrêter de coder, coût minimal
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Ce qu'OmniRoute résout : 30 problèmes réels et cas d'utilisation
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Tous les développeurs utilisant des outils d'IA sont confrontés quotidiennement à ces problèmes.** OmniRoute a été conçu pour tous les résoudre : des dépassements de coûts aux blocages régionaux, des flux OAuth interrompus aux opérations de protocole et à l'observabilité de l'entreprise.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Je paie un abonnement coûteux mais je suis quand même interrompu par des limites" </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Les développeurs paient entre 20 et 200 $/mois pour Claude Pro, Codex Pro ou GitHub Copilot. Même payant, le quota est plafonné : 5 heures d'utilisation, limites hebdomadaires ou limites de tarif à la minute. En cours de session de codage, le fournisseur ne répond plus et le développeur perd en fluidité et en productivité.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Si le quota d'abonnement est épuisé, redirige automatiquement vers la clé API → Pas cher → Gratuit sans intervention manuelle
- **Suivi des quotas en temps réel** — Affiche la consommation de jetons en temps réel avec un compte à rebours réinitialisé (5 h, quotidiennement, hebdomadairement)
- **Support multi-comptes** — Plusieurs comptes par fournisseur avec tourniquet automatique — lorsqu'un compte est épuisé, passe au suivant
- **Combos personnalisés** — Chaînes de secours personnalisables avec 6 stratégies d'équilibrage (remplir en premier, round-robin, P2C, aléatoire, les moins utilisées, optimisées en termes de coûts)
- **Codex Business Quotas** — Surveillance des quotas d'espace de travail Business/Équipe directement dans le tableau de bord
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Je dois utiliser plusieurs fournisseurs mais chacun a une API différente" </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI utilise un format, Claude (Anthropic) en utilise un autre, Gemini encore un autre. Si un développeur souhaite tester des modèles de différents fournisseurs ou utiliser un modèle de secours entre eux, il doit reconfigurer les SDK, modifier les points de terminaison et gérer les formats incompatibles. Les fournisseurs personnalisés (FriendLI, NIM) ont des points de terminaison de modèle non standard.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Point de terminaison unifié** : un seul `http://localhost:20128/v1` sert de proxy pour les plus de 36 fournisseurs.
- **Traduction de format** — Automatique et transparente : OpenAI ↔ Claude ↔ Gemini ↔ API Responses
- **Response Sanitization** — Supprime les champs non standard (`x_groq`, `usage_breakdown`, `service_tier`) qui cassent OpenAI SDK v1.83+
- **Role Normalization** — Convertit `developer``system` pour les fournisseurs non OpenAI ; `system``user` pour GLM/ERNIE
- **Think Tag Extraction** — Extrait les blocs `<think>` de modèles comme DeepSeek R1 dans un `reasoning_content` standardisé.
- **Sortie structurée pour Gemini** — Conversion automatique `json_schema``responseMimeType`/`responseSchema`
- **`stream` est par défaut `false`** — S'aligne sur les spécifications OpenAI, évitant ainsi le SSE inattendu dans les SDK Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Mon fournisseur d'IA bloque ma région/pays" </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Des fournisseurs comme OpenAI/Codex bloquent laccès depuis certaines régions géographiques. Les utilisateurs obtiennent des erreurs telles que `unsupported_country_region_territory` lors des connexions OAuth et API. Ceci est particulièrement frustrant pour les développeurs des pays en développement.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Configuration proxy à 3 niveaux** — Proxy configurable à 3 niveaux : global (tout le trafic), par fournisseur (un seul fournisseur) et par connexion/clé
- **Badges proxy à code couleur** — Indicateurs visuels : 🟢 proxy global, 🟡 proxy fournisseur, 🔵 proxy de connexion, affichant toujours l'adresse IP
- **Échange de jetons OAuth via proxy** — Le flux OAuth passe également par le proxy, solvant `unsupported_country_region_territory`
- **Tests de connexion via proxy** — Les tests de connexion utilisent le proxy configuré (plus de contournement direct)
- **Support SOCKS5** — Prise en charge complète du proxy SOCKS5 pour le routage sortant
- **TLS Fingerprint Spoofing** — Empreinte digitale TLS de type navigateur via `wreq-js` pour contourner la détection des robots
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Je veux utiliser l'IA pour coder mais je n'ai pas d'argent"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Tout le monde ne peut pas payer entre 20 et 200 $/mois pour des abonnements à lIA. Les étudiants, les développeurs des pays émergents, les amateurs et les indépendants doivent avoir accès à des modèles de qualité à un coût nul.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Fournisseurs gratuits intégrés** — Prise en charge native des fournisseurs 100 % gratuits : iFlow (8 modèles illimités), Qwen (3 modèles illimités), Kiro (Claude gratuit), Gemini CLI (180 000 /mois gratuits)
- **Combos gratuits uniquement** — Chaîne `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 $/mois sans temps d'arrêt
- **Crédits gratuits NVIDIA NIM** — 1 000 crédits gratuits intégrés
- **Stratégie d'optimisation des coûts** — Stratégie de routage qui choisit automatiquement le fournisseur disponible le moins cher
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Je dois protéger ma passerelle IA contre les accès non autorisés" </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Lors de l'exposition d'une passerelle IA au réseau (LAN, VPS, Docker), toute personne possédant l'adresse peut consommer les jetons/quota du développeur. Sans protection, les API sont vulnérables aux utilisations abusives, aux injections rapides et aux abus.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Gestion des clés API** — Génération, rotation et portée par fournisseur avec une page `/dashboard/api-manager` dédiée
- **Autorisations au niveau du modèle** : restreindre les clés API à des modèles spécifiques (`openai/*`, modèles génériques), avec la bascule Autoriser tout/Restreindre
- **API Endpoint Protection**  exige une clé pour `/v1/models` et bloque des fournisseurs spécifiques de la liste
- **Auth Guard + Protection CSRF** — Toutes les routes du tableau de bord protégées avec le middleware `withAuth` + les jetons CSRF
- **Rate Limiter** — Limitation du débit par IP avec fenêtres configurables
- **Filtrage IP**  Liste autorisée/liste de blocage pour le contrôle d'accès
- **Prompt Injection Guard** — Nettoyage contre les modèles d'invite malveillants
- **Chiffrement AES-256-GCM** — Informations d'identification chiffrées au repos
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Mon fournisseur est tombé en panne et j'ai perdu mon flux de codage"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Les fournisseurs dIA peuvent devenir instables, renvoyer des erreurs 5xx ou atteindre des limites de débit temporaires. Si un développeur dépend d'un seul fournisseur, il est interrompu. Sans disjoncteurs, des tentatives répétées peuvent faire planter lapplication.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Disjoncteur par fournisseur** — Ouverture/fermeture automatique avec seuils et temps de recharge configurables (Fermé/Ouvert/Semi-ouvert)
- **Exponential Backoff** — Délais progressifs entre les tentatives
- **Anti-Thundering Herd** — Protection mutex + sémaphore contre les tempêtes de nouvelles tentatives simultanées
- **Chaînes de secours combinées** — Si le fournisseur principal échoue, passe automatiquement à travers la chaîne sans intervention
- **Combo Circuit Breaker**  Désactive automatiquement les fournisseurs défaillants au sein d'une chaîne combo
- **Tableau de bord de santé** — Surveillance de la disponibilité, états des disjoncteurs, verrouillages, statistiques du cache, latence p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "La configuration de chaque outil d'IA est fastidieuse et répétitive"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Les développeurs utilisent Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Chaque outil nécessite une configuration différente (point de terminaison API, clé, modèle). La reconfiguration lors du changement de fournisseur ou de modèle est une perte de temps.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Page dédiée avec configuration en un clic pour Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Génère `chatLanguageModels.json` pour VS Code avec sélection groupée de modèles
- **Assistant d'intégration** — Configuration guidée en 4 étapes pour les nouveaux utilisateurs
- **Un point de terminaison, tous les modèles**  Configurez `http://localhost:20128/v1` une fois, accédez à plus de 36 fournisseurs
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Gérer les jetons OAuth de plusieurs fournisseurs est un enfer"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — tous utilisent OAuth 2.0 avec des jetons expirant. Les développeurs doivent se réauthentifier constamment, gérer `client_secret is missing`, `redirect_uri_mismatch` et les pannes sur les serveurs distants. OAuth sur LAN/VPS est particulièrement problématique.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Actualisation automatique des jetons** : les jetons OAuth sont actualisés en arrière-plan avant leur expiration.
- **OAuth 2.0 (PKCE) intégré** — Flux automatique pour Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Plusieurs comptes par fournisseur via l'extraction de jetons JWT/ID
- **OAuth LAN/Remote Fix** — Détection IP privée pour `redirect_uri` + mode URL manuel pour les serveurs distants
- **OAuth derrière Nginx** — Utilise `window.location.origin` pour la compatibilité du proxy inverse
- **Guide OAuth à distance** — Guide étape par étape pour les informations d'identification Google Cloud sur VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Je ne sais pas combien je dépense ni où" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Les développeurs utilisent plusieurs fournisseurs payants mais n'ont pas de vue unifiée des dépenses. Chaque fournisseur dispose de son propre tableau de bord de facturation, mais il n'existe pas de vue consolidée. Les coûts inattendus peuvent saccumuler.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Cost Analytics Dashboard** — Suivi des coûts par jeton et gestion du budget par fournisseur
- **Limites budgétaires par niveau** — Plafond de dépenses par niveau qui déclenche un repli automatique
- **Configuration de tarification par modèle** — Prix configurables par modèle
- **Statistiques d'utilisation par clé API** — Nombre de demandes et horodatage de la dernière utilisation par clé
- **Tableau de bord Analytics** — Cartes statistiques, tableau d'utilisation du modèle, tableau des fournisseurs avec taux de réussite et latence
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Je ne peux pas diagnostiquer les erreurs et les problèmes dans les appels IA" </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Lorsqu'un appel échoue, le développeur ne sait pas s'il s'agit d'une limite de débit, d'un jeton expiré, d'un format incorrect ou d'une erreur du fournisseur. Journaux fragmentés sur différents terminaux. Sans observabilité, le débogage est un essai et une erreur.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Tableau de bord des journaux unifiés** — 4 onglets : journaux de requêtes, journaux proxy, journaux d'audit, console
- **Console Log Viewer** — Visualiseur de style terminal en temps réel avec niveaux de code couleur, défilement automatique, recherche, filtre
- **Journaux du proxy SQLite** — Journaux persistants qui survivent aux redémarrages du serveur
- **Translator Playground** — 4 modes de débogage : Playground (traduction de format), Chat Tester (aller-retour), Test Bench (batch), Live Monitor (temps réel)
- **Demande de télémétrie** — latence p50/p95/p99 + traçage X-Request-Id
- **Journalisation basée sur des fichiers avec rotation** — L'intercepteur de console capture tout dans le journal JSON avec une rotation basée sur la taille
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Le déploiement et la maintenance de la passerelle sont complexes"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
L'installation, la configuration et la maintenance d'un proxy IA dans différents environnements (local, VPS, Docker, cloud) demandent beaucoup de main-d'œuvre. Des problèmes tels que les chemins codés en dur, `EACCES` sur les répertoires, les conflits de ports et les versions multiplateformes ajoutent des frictions.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync**Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Installation globale npm** — `npm install -g omniroute && omniroute`terminée
- **Docker Multi-Platform** — AMD64 + ARM64 natif (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Profils Docker Compose** — `base` (pas d'outils CLI) et `cli` (avec Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Application native pour Windows/macOS/Linux avec barre d'état système, démarrage automatique et mode hors ligne
- **Mode Split-Port** — API et tableau de bord sur des ports séparés pour des scénarios avancés (proxy inverse, réseau de conteneurs)
- **Cloud Sync**  Configurez la synchronisation entre les appareils via Cloudflare Workers
- **Sauvegardes DB** — Sauvegarde, restauration, exportation et importation automatiques de tous les paramètres
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "L'interface est uniquement en anglais et mon équipe ne parle pas anglais" </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Les équipes des pays non anglophones, notamment en Amérique latine, en Asie et en Europe, ont du mal à utiliser des interfaces uniquement en anglais. Les barrières linguistiques réduisent ladoption et augmentent les erreurs de configuration.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Tableau de bord i18n — 30 langues** — Plus de 500 touches traduites, dont arabe, bulgare, danois, allemand, espagnol, finnois, français, hébreu, hindi, hongrois, indonésien, italien, japonais, coréen, malais, néerlandais, norgien, polonais, portugais (PT/BR), roumain, russe, slovaque, suédois, thaï, ukrainien, vietnamien, chinois, philippin, anglais.
- **Support RTL** — Prise en charge de droite à gauche pour l'arabe et l'hébreu
- ** README multilingues ** — 30 traductions complètes de la documentation
- **Sélecteur de langue** — Icône de globe dans l'en-tête pour une commutation en temps réel
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "J'ai besoin de plus que du chat : j'ai besoin d'intégrations, d'images, d'audio" </b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
L'IA ne se limite pas à la réalisation de discussions. Les développeurs doivent générer des images, transcrire l'audio, créer des intégrations pour RAG, reclasser les documents et modérer le contenu. Chaque API a un point de terminaison et un format différents.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Embeddings** — `/v1/embeddings` avec 6 fournisseurs et plus de 9 modèles
- **Génération d'images** — `/v1/images/generations` avec 10 fournisseurs et plus de 20 modèles (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Texte vers vidéo** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) et SD WebUI
- **Texte en musique** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Transcription audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + fournisseurs existants
- **Modérations** — `/v1/moderations` — Contrôles de sécurité du contenu
- **Reclassement** — `/v1/rerank` — Reclassement de la pertinence du document
- **API Réponses** — Prise en charge complète de `/v1/responses` pour le Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Je n'ai aucun moyen de tester et de comparer la qualité des modèles" </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Les développeurs veulent savoir quel modèle convient le mieux à leur cas d'utilisation (code, traduction, raisonnement) mais la comparaison manuelle est lente. Il nexiste aucun outil dévaluation intégré.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Évaluations LLM** — Tests Golden Set avec 10 cas préchargés couvrant les salutations, les mathématiques, la géographie, la génération de code, la conformité JSON, la traduction, la démarque, le refus de sécurité
- **4 stratégies de correspondance** — `exact`, `contains`, `regex`, `custom` (fonction JS)
- **Banc de test Translator Playground** — Tests par lots avec plusieurs entrées et sorties attendues, comparaison entre fournisseurs
- **Chat Tester** — Aller-retour complet avec rendu de réponse visuelle
- **Live Monitor** — Flux en temps réel de toutes les requêtes transitant par le proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "J'ai besoin d'évoluer sans perdre en performances"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
À mesure que le volume de demandes augmente, sans mettre en cache les mêmes questions, cela génère des coûts en double. Sans idempotence, les demandes en double gaspillent le traitement. Les limites tarifaires par fournisseur doivent être respectées.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache sémantique** — Le cache à deux niveaux (signature + sémantique) réduit les coûts et la latence
- **Request Idempotency** — Fenêtre de déduplication de 5 s pour des requêtes identiques
- **Détection de limite de débit** — RPM par fournisseur, écart minimum et suivi simultané maximum
- **Limites de débit modifiables** — Valeurs par défaut configurables dans Paramètres → Résilience avec persistance
- **Cache de validation de clé API** — Cache à 3 niveaux pour les performances de production
- **Tableau de bord de santé avec télémétrie** — latence p50/p95/p99, statistiques de cache, disponibilité
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Je souhaite contrôler le comportement du modèle à l'échelle mondiale" </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Les développeurs qui souhaitent que toutes les réponses soient dans une langue spécifique, avec un ton spécifique, ou qui souhaitent limiter les jetons de raisonnement. Configurer cela dans chaque outil/demande nest pas pratique.
**How OmniRoute solves it:**
**Comment OmniRoute le résout :**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Injection d'invite système** — Invite globale appliquée à toutes les requêtes
- **Thinking Budget Validation** — Contrôle d'allocation de jetons de raisonnement par requête (passthrough, automatique, personnalisé, adaptatif)
- **6 Stratégies de routage**  Stratégies globales qui déterminent la façon dont les demandes sont distribuées
- **Wildcard Router** — Les modèles `provider/*` sont acheminés dynamiquement vers n'importe quel fournisseur.
- **Combo Enable/Disable Toggle** — Basculez les combos directement depuis le tableau de bord
- **Provider Toggle** — Activer/désactiver toutes les connexions pour un fournisseur en un seul clic
- **Fournisseurs bloqués** — Exclure des fournisseurs spécifiques de la liste `/v1/models`
</details>
<details>
<summary><b>🧰 17. "J'ai besoin d'outils MCP en tant que fonctionnalités de produit de première classe" </b></summary>
De nombreuses passerelles IA exposent MCP uniquement en tant que détail d'implémentation caché. Les équipes ont besoin dune couche opérationnelle visible et gérable.
**Comment OmniRoute le résout :**
- MCP apparaît dans l'onglet de navigation du tableau de bord et de protocole de point de terminaison
- Page de gestion MCP dédiée avec processus, outils, portées et audit
- Démarrage rapide intégré pour `omniroute --mcp` et intégration du client
</details>
<details>
<summary><b>🧠 18. "J'ai besoin d'une orchestration A2A avec des chemins de tâches de synchronisation + flux" </b></summary>
Les flux de travail des agents nécessitent à la fois des réponses directes et une exécution en continu de longue durée avec contrôle du cycle de vie.
**Comment OmniRoute le résout :**
- Point de terminaison A2A JSON-RPC (`POST /a2a`) avec `message/send` et `message/stream`
- Streaming SSE avec propagation de l'état terminal
- API de cycle de vie des tâches pour `tasks/get` et `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "J'ai besoin d'un véritable état de santé du processus MCP, et non d'un état deviné" </b></summary>
Les équipes opérationnelles doivent savoir si MCP est réellement actif, et pas seulement si une API est accessible.
**Comment OmniRoute le résout :**
- Fichier de battement de cœur d'exécution avec PID, horodatages, transport, nombre d'outils et mode de portée
- API de statut MCP combinant battement de coeur + activité récente
- Cartes d'état de l'interface utilisateur pour la fraîcheur des processus/disponibilité/battement de cœur
</details>
<details>
<summary><b>📋 20. "J'ai besoin d'une exécution vérifiable de l'outil MCP" </b></summary>
Lorsque les outils modifient la configuration ou déclenchent des actions opérationnelles, les équipes ont besoin d'une traçabilité médico-légale.
**Comment OmniRoute le résout :**
- Journalisation d'audit basée sur SQLite pour les appels d'outils MCP
- Filtres par outil, succès/échec, clé API et pagination
- Tableau d'audit du tableau de bord + points de terminaison de statistiques pour l'automatisation
</details>
<details>
<summary><b>🔐 21. "J'ai besoin d'autorisations MCP limitées par intégration" </b></summary>
Différents clients doivent avoir le moindre privilège daccès aux catégories doutils.
**Comment OmniRoute le résout :**
- 9 étendues MCP granulaires pour un accès contrôlé aux outils
- Application de la portée et visibilité dans l'interface utilisateur de gestion MCP
- Posture par défaut sûre pour les outils opérationnels
</details>
<details>
<summary><b>⚙️ 22. "J'ai besoin de contrôles opérationnels sans redéploiement"</b></summary>
Les équipes ont besoin de changements d'exécution rapides lors d'incidents ou d'événements de coûts.
**Comment OmniRoute le résout :**
- Activer le combo de commutation directement depuis le tableau de bord MCP
- Appliquer des profils de résilience à partir de packs de politiques prédéfinis
- Réinitialiser l'état du disjoncteur à partir du même panneau de commande
</details>
<details>
<summary><b>🔄 23. "J'ai besoin d'une visibilité et d'une annulation en direct du cycle de vie des tâches A2A" </b></summary>
Sans visibilité sur le cycle de vie, les incidents de tâches deviennent difficiles à trier.
**Comment OmniRoute le résout :**
- Liste des tâches/filtrage par état/compétence avec pagination
- Analyse approfondie des métadonnées, des événements et des artefacts des tâches
- Point de terminaison d'annulation de tâche et action de l'interface utilisateur avec confirmation
</details>
<details>
<summary><b>🌊 24. "J'ai besoin de métriques de flux actif pour la charge A2A" </b></summary>
Les flux de travail de streaming nécessitent une vision opérationnelle de la concurrence et des connexions en direct.
**Comment OmniRoute le résout :**
- Compteurs de flux actifs intégrés au statut A2A
- Horodatage de la dernière tâche et nombre par état
- Cartes de tableau de bord A2A pour la surveillance des opérations en temps réel
</details>
<details>
<summary><b>🪪 25. "J'ai besoin d'une découverte d'agent standard pour les clients" </b></summary>
Les clients et orchestrateurs externes ont besoin de métadonnées lisibles par machine pour l'intégration.
**Comment OmniRoute le résout :**
- Carte d'agent exposée à `/.well-known/agent.json`
- Capacités et compétences affichées dans l'interface utilisateur de gestion
- L'API de statut A2A inclut des métadonnées de découverte pour l'automatisation
</details>
<details>
<summary><b>🧭 26. "J'ai besoin de la possibilité de découvrir le protocole dans le produit UX"</b></summary>
Si les utilisateurs ne peuvent pas découvrir les surfaces de protocole, ladoption et la qualité du support chutent.
**Comment OmniRoute le résout :**
- Entrées de la barre latérale pour MCP et A2A
- Onglet Protocoles de la page du point de terminaison avec démarrage rapide et état
- Liens depuis l'aperçu vers les tableaux de bord de gestion dédiés
</details>
<details>
<summary><b>🧪 27. "J'ai besoin d'une validation de protocole de bout en bout avec de vrais clients"</b></summary>
Les tests simulés ne suffisent pas pour valider la compatibilité des protocoles avant la publication.
**Comment OmniRoute le résout :**
- Suite E2E qui démarre l'application et utilise un véritable transport client MCP SDK
- Tests client A2A pour les flux de découverte, d'envoi, de streaming, d'obtention et d'annulation
- Vérifier les assertions par rapport aux API d'audit MCP et de tâches A2A
</details>
<details>
<summary><b>📡 28. "J'ai besoin d'une observabilité unifiée sur toutes les interfaces"</b></summary>
Le fractionnement de l'observabilité par protocole crée des angles morts et un MTTR plus long.
**Comment OmniRoute le résout :**
- Tableaux de bord/journaux/analyses unifiés dans un seul produit
- Santé + audit + télémétrie des demandes sur les couches OpenAI, MCP et A2A
- API opérationnelles pour le statut et l'automatisation
</details>
<details>
<summary><b>💼 29. "J'ai besoin d'un environnement d'exécution pour l'orchestration proxy + outils + agent" </b></summary>
Lexécution de nombreux services distincts augmente les coûts opérationnels et les modes de défaillance.
**Comment OmniRoute le résout :**
- Proxy compatible OpenAI, serveur MCP et serveur A2A dans une seule pile
- Authentification partagée, résilience, stockage de données et observabilité
- Modèle de politique cohérent sur toutes les surfaces d'interaction
</details>
<details>
<summary><b>🚀 30. "Je dois expédier des flux de travail agentiques sans prolifération de codes adhésifs" </b></summary>
Les équipes perdent de la vitesse lors de lassemblage de plusieurs services et scripts ad hoc.
**Comment OmniRoute le résout :**
- Stratégie de point de terminaison unifiée pour les clients et les agents
- Interfaces utilisateur de gestion de protocole intégrées et chemins de validation de fumée
- Bases prêtes pour la production (sécurité, journalisation, résilience, sauvegarde)
</details>
### Exemples de playbooks (cas d'utilisation intégrés)
**Playbook A : Maximisez l'abonnement payant + sauvegarde bon marché**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B : pile de codage à coût nul**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C : chaîne de secours toujours active 24h/24 et 7j/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D : Opérations d'agent avec MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Démarrage rapide
**1. Installer globalement :**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Application Bureau — Hors Ligne et Toujours Actif
## 🖥️
> 🆕 **NOUVEAU !** OmniRoute est maintenant disponible en tant qu'**application de bureau native** pour Windows, macOS et Linux.
@@ -591,6 +866,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Fonctionnalité | Ce qu'elle fait |
| ------------------------------- | ---------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Ouverture/fermeture auto par fournisseur avec seuils configurables |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **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 |
@@ -698,66 +974,26 @@ Traduction transparente entre les formats :
</details>
---
## 🧪 Évaluations (Evals)
## 🎯 Cas d'utilisation
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.
### Cas 1 : « J'ai un abonnement Claude Pro »
### Set intégré
**Problème :** Le quota expire inutilisé, limites de débit pendant le codage intensif
Le « OmniRoute Golden Set » préchargé contient 10 cas de test :
```
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)
- 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
Coût mensuel : 20 $ (abonnement) + ~5 $ (backup) = 25 $ au total
vs. 20 $ + atteindre les limites = frustration
```
### Stratégies d'évaluation
### 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...
```
| 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` |
---
@@ -1041,29 +1277,6 @@ Paramètres → Configuration API :
---
## 🧪 É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>
@@ -1119,7 +1332,7 @@ Le « OmniRoute Golden Set » préchargé contient 10 cas de test :
---
## 🛠️ Stack technologique
## 🛠️
- **Runtime** : Node.js 20+
- **Langage** : TypeScript 5.9 — **100% TypeScript** dans `src/` et `open-sse/` (v1.0.6)
@@ -1150,17 +1363,7 @@ Le « OmniRoute Golden Set » préchargé contient 10 cas de test :
---
## 📧 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

View File

@@ -110,6 +110,35 @@ _חבר כל כלי IDE או CLI המופעל על ידי AI דרך OmniRoute -
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 למה OmniRoute?
**הפסיקו לבזבז כסף ולהגיע לגבולות:**
@@ -128,6 +157,18 @@ _חבר כל כלי IDE או CLI המופעל על ידי AI דרך OmniRoute -
---
## 📧 תמיכה
> 💬 **הצטרפו לקהילה שלנו!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — קבל עזרה, שתף טיפים והישאר מעודכן.
- **אתר**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **בעיות**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **וואטסאפ**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **פרויקט מקורי**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 איך זה עובד
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 מה OmniRoute פותר - 30 נקודות כאב אמיתיות ומקרי שימוש
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **כל מפתח המשתמש בכלי בינה מלאכותית מתמודד עם הבעיות הללו מדי יום.** OmniRoute נבנתה כדי לפתור את כולן - החל מחריפות עלויות ועד לחסימות אזוריות, מזרימות OAuth שבורות ועד פעולות פרוטוקול וצפייה ארגונית.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "אני משלם עבור מנוי יקר אבל עדיין מופרע על ידי גבולות" </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
מפתחים משלמים $20-200 לחודש עבור Claude Pro, Codex Pro או GitHub Copilot. אפילו בתשלום, למכסה יש תקרה - 5 שעות שימוש, מגבלות שבועיות או מגבלות תעריף לדקה. סשן קידוד באמצע, הספק מפסיק להגיב והמפתח מאבד זרימה ופרודוקטיביות.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** - אם מכסת המנויים נגמרת, מפנה אוטומטית למפתח API → זול → חינם עם אפס התערבות ידנית
- **מעקב מכסות בזמן אמת** - מציג צריכת אסימונים בזמן אמת עם ספירה לאחור מאפס (5 שעות, יומי, שבועי)
- **תמיכה בריבוי חשבונות** - מספר חשבונות לכל ספק עם סבב אוטומטי - כאשר אחד אוזל, עובר לאחר
- **שילובים מותאמים אישית** - שרשראות ניתנות להתאמה אישית עם 6 אסטרטגיות איזון (מילוי ראשון, סיבוב סיבובי, P2C, אקראי, הכי פחות בשימוש, אופטימיזציה לעלות)
- **Codex Business Quotas** - ניטור מכסות סביבת עבודה עסקית/צוותית ישירות בלוח המחוונים
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "אני צריך להשתמש במספר ספקים אבל לכל אחד יש API אחר" </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI משתמש בפורמט אחד, קלוד (אנתרופיק) משתמש בפורמט אחר, תאומים בנוסח אחר. אם מפתח רוצה לבחון דגמים מספקים שונים או לחלוף ביניהם, הוא צריך להגדיר מחדש SDK, לשנות נקודות קצה, להתמודד עם פורמטים לא תואמים. לספקים מותאמים אישית (FriendLI, NIM) יש נקודות קצה לא סטנדרטיות במודל.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **נקודת קצה מאוחדת** - `http://localhost:20128/v1` יחיד משמש כ-proxy עבור כל 36+ הספקים
- **תרגום פורמט** — אוטומטי ושקוף: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **חיטוי תגובה** - מסיר שדות לא סטנדרטיים (`x_groq`, `usage_breakdown`, `service_tier`) שמפרקים את OpenAI SDK v1.83+
- **נורמליזציה של תפקידים** — ממירה `developer``system` עבור ספקים שאינם OpenAI; `system``user` עבור GLM/ERNIE
- **Think Tag Extraction** — מחלץ בלוקים `<think>` מדגמים כמו DeepSeek R1 לתוך `reasoning_content` הסטנדרטי
- **פלט מובנה עבור מזל תאומים** — `json_schema``responseMimeType`/`responseSchema` המרה אוטומטית
- **`stream` ברירת המחדל היא `false`** - מתיישר עם מפרט OpenAI, הימנעות SSE בלתי צפוי ב- Python/Rust/Go SDK
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "ספק הבינה המלאכותית שלי חוסם את האזור/המדינה שלי" </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
ספקים כמו OpenAI/Codex חוסמים גישה מאזורים גיאוגרפיים מסוימים. משתמשים מקבלים שגיאות כמו `unsupported_country_region_territory` במהלך חיבורי OAuth ו-API. זה מתסכל במיוחד עבור מפתחים ממדינות מתפתחות.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **תצורת פרוקסי בשלוש רמות** - פרוקסי ניתן להגדרה ב-3 רמות: גלובלית (כל התעבורה), לכל ספק (ספק אחד בלבד), ולכל חיבור/מפתח
- **תגי פרוקסי מקודדים בצבע** - אינדיקטורים חזותיים: 🟢 פרוקסי גלובלי, 🟡 פרוקסי ספק, 🔵 פרוקסי חיבור, תמיד מציג את ה-IP
- **החלפת אסימונים של OAuth באמצעות פרוקסי** - זרימת OAuth עוברת גם דרך ה-proxy, ופותרת את `unsupported_country_region_territory`
- **בדיקות חיבור באמצעות פרוקסי** - בדיקות חיבור משתמשות בפרוקסי המוגדר (לא עוד מעקף ישיר)
- **תמיכה SOCKS5** — תמיכה מלאה ב-Proxy SOCKS5 לניתוב יוצא
- **זיוף טביעות אצבע TLS** - טביעת אצבע TLS דמוית דפדפן באמצעות `wreq-js` כדי לעקוף את זיהוי הבוטים
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "אני רוצה להשתמש ב-AI לקידוד אבל אין לי כסף"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
לא כולם יכולים לשלם 20-200 $ לחודש עבור מנויי AI. סטודנטים, מפתחים ממדינות מתפתחות, חובבים ופרילנסרים צריכים גישה לדגמים איכותיים בעלות אפסית.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **ספקי שכבת חינם מובנית** - תמיכה מקורית עבור 100% ספקים בחינם: iFlow (8 דגמים ללא הגבלה), Qwen (3 דגמים ללא הגבלה), Kiro (קלוד בחינם), Gemini CLI (180K/חודש חינם)
- **שילובים בחינם בלבד** — שרשרת `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0 לחודש עם אפס זמן השבתה
- **קרדיטים חינם של NVIDIA NIM** - 1000 זיכויים חינם משולבים
- **אסטרטגיית אופטימיזציה לעלות** — אסטרטגיית ניתוב שבוחרת אוטומטית את הספק הזמין הזול ביותר
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "אני צריך להגן על שער הבינה המלאכותית שלי מגישה לא מורשית" </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
בעת חשיפת שער AI לרשת (LAN, VPS, Docker), כל מי שיש לו את הכתובת יכול לצרוך את האסימונים/מכסה של המפתח. ללא הגנה, ממשקי API חשופים לשימוש לרעה, הזרקה מהירה וניצול לרעה.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **ניהול מפתחות API** - יצירה, סיבוב והיקף לכל ספק עם דף `/dashboard/api-manager` ייעודי
- **הרשאות ברמת הדגם** - הגבל מפתחות API לדגמים ספציפיים (`openai/*`, דפוסי תווים כלליים), עם החלפת מצב אפשר הכל/הגבל
- **הגנה על נקודות קצה של API** - דרוש מפתח עבור `/v1/models` וחסום ספקים ספציפיים מהרישום
- **Auth Guard + CSRF Protection** — כל מסלולי לוח המחוונים מוגנים באמצעות תוכנת ביניים `withAuth` + אסימוני CSRF
- ** מגביל קצב** - הגבלת קצב לפי IP עם חלונות הניתנים להגדרה
- **סינון IP** — רשימת הרשאות/רשימת חסימות לבקרת גישה
- **משמר הזרקה מהירה** - חיטוי נגד דפוסי הנחיה זדוניים
- **הצפנת AES-256-GCM** - אישורים מוצפנים בזמן מנוחה
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "הספק שלי נפל ואיבדתי את זרימת הקידוד" </b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
ספקי בינה מלאכותית עלולים להפוך לבלתי יציבים, להחזיר שגיאות 5xx או לפגוע במגבלות קצב זמניות. אם מפתח תלוי בספק יחיד, הם מופרעים. ללא מפסקים, נסיונות חוזרים ונשנים עלולים לקרוס את האפליקציה.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **מפסק מעגלים לכל ספק** - פתיחה/סגירה אוטומטית עם ספים ניתנים להגדרה והתקררות (סגור/פתוח/חצי פתוח)
- **גיבוי אקספוננציאלי** - עיכובים מתקדמים בניסיון חוזר
- **עדר נגד רעמים** - הגנה על מוטקס + סמפור מפני סופות ניסיונות חוזרות במקביל
- **שרשראות משולבות Fallback** - אם הספק הראשי נכשל, נופל אוטומטית בשרשרת ללא התערבות
- **מפסק משולב** - משבית אוטומטית ספקים כושלים בשרשרת משולבת
- **לוח מחוונים לבריאות** - ניטור זמן פעולה, מצבי מפסק זרם, נעילות, סטטיסטיקות מטמון, זמן אחזור p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "הגדרת כל כלי בינה מלאכותית היא מייגעת וחוזרת על עצמה" </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
מפתחים משתמשים ב-Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... כל כלי צריך תצורה שונה (נקודת קצה, מפתח, מודל API). הגדרה מחדש בעת החלפת ספקים או דגמים היא בזבוז זמן.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **לוח המחוונים של CLI Tools** - דף ייעודי עם הגדרה בלחיצה אחת עבור Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — מייצר `chatLanguageModels.json` עבור קוד VS עם בחירת דגמים בכמות גדולה
- **אשף ההטמעה** — הגדרה מודרכת בת 4 שלבים למשתמשים ראשונים
- **נקודת קצה אחת, כל הדגמים** - הגדר את `http://localhost:20128/v1` פעם אחת, גש ל-36+ ספקים
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "ניהול אסימוני OAuth ממספר ספקים זה גיהנום" </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot - כולם משתמשים ב-OAuth 2.0 עם אסימונים שפג תוקפם. מפתחים צריכים לבצע אימות מחדש כל הזמן, להתמודד עם `client_secret is missing`, `redirect_uri_mismatch` וכשלים בשרתים מרוחקים. OAuth ב-LAN/VPS בעייתי במיוחד.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **רענון אסימון אוטומטי** - אסימוני OAuth מתרעננים ברקע לפני פקיעת תוקף
- **OAuth 2.0 (PKCE) מובנה** - זרימה אוטומטית עבור Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- ** OAuth מרובה חשבונות** - מספר חשבונות לכל ספק באמצעות חילוץ אסימון JWT/ID
- **OAuth LAN/תיקון מרחוק** - זיהוי IP פרטי עבור `redirect_uri` + מצב כתובת URL ידני עבור שרתים מרוחקים
- **OAuth Behind Nginx** - משתמש ב-`window.location.origin` עבור תאימות פרוקסי הפוכה
- **מדריך OAuth מרחוק** - מדריך שלב אחר שלב לאישורי Google Cloud ב-VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "אני לא יודע כמה אני מוציא או איפה" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
מפתחים משתמשים במספר ספקים בתשלום אך אין להם ראייה אחידה של הוצאות. לכל ספק יש לוח מחוונים משלו לחיוב, אבל אין תצוגה מאוחדת. עלויות בלתי צפויות עלולות להיערם.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **לוח מחוונים של ניתוח עלויות** - מעקב אחר עלויות לפי אסימון וניהול תקציב לכל ספק
- **מגבלות תקציב לכל שכבה** - תקרת הוצאה לכל שכבה שמפעילה נפילה אוטומטית
- **תצורת תמחור לפי דגם** — מחירים הניתנים להגדרה לכל דגם
- **סטטיסטיקת שימוש לכל מפתח API** - ספירת בקשות וחותמת זמן אחרונה בשימוש לכל מפתח
- **לוח המחוונים של אנליטיקס** - כרטיסי סטטיסטיקה, טבלת שימוש במודל, טבלת ספקים עם אחוזי הצלחה והשהייה
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "אני לא יכול לאבחן שגיאות ובעיות בשיחות AI" </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
כאשר שיחה נכשלת, ה-dev לא יודע אם זו הייתה מגבלת תעריף, אסימון שפג תוקפו, פורמט שגוי או שגיאת ספק. יומנים מפוצלים על פני מסופים שונים. ללא צפייה, איתור באגים הוא ניסוי וטעייה.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Unified Logs Dashboard** 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **לוח מחוונים של יומנים מאוחדים** - 4 כרטיסיות: יומני בקשות, יומני פרוקסי, יומני ביקורת, מסוף
- **מציג יומן מסוף** - מציג בזמן אמת בסגנון טרמינל עם רמות מקודדות צבע, גלילה אוטומטית, חיפוש, סינון
- **SQLite Proxy Logs** - יומנים מתמשכים ששורדים אתחול מחדש של השרת
- **מגרש משחקים לתרגום** - 4 מצבי ניפוי באגים: מגרש משחקים (תרגום פורמט), בודק צ'אט (הלוך ושוב), ספסל בדיקה (אצווה), צג חי (בזמן אמת)
- **Request Telemetry** — חביון p50/p95/p99 + X-Request-Id מעקב
- **רישום מבוסס קבצים עם סיבוב** - מיירט המסוף לוכד הכל ליומן JSON עם סיבוב מבוסס גודל
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "פריסה ותחזוקה של השער מורכבת" </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
התקנה, הגדרה ותחזוקה של פרוקסי בינה מלאכותית בסביבות שונות (מקומי, VPS, Docker, ענן) היא עתירת עבודה. בעיות כמו נתיבים מקודדים קשיחים, `EACCES` על ספריות, התנגשויות יציאות ובנייה בין פלטפורמות מוסיפות חיכוך.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **התקנה גלובלית npm** — `npm install -g omniroute && omniroute`בוצעה
- **Docker Multi-Platform** - מקורי AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (ללא כלי CLI) ו-`cli` (עם קוד קלוד, Codex, OpenClaw)
- **אפליקציית Electron Desktop** — אפליקציה מקורית עבור Windows/macOS/Linux עם מגש מערכת, הפעלה אוטומטית, מצב לא מקוון
- **מצב יציאות מפוצלות** - API ולוח מחוונים ביציאות נפרדות עבור תרחישים מתקדמים (פרוקסי הפוך, רשת קונטיינר)
- **Cloud Sync** - הגדרת סנכרון בין מכשירים באמצעות Cloudflare Workers
- **גיבויי DB** - גיבוי, שחזור, ייצוא וייבוא אוטומטי של כל ההגדרות
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "הממשק הוא באנגלית בלבד והצוות שלי לא מדבר אנגלית"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
צוותים במדינות שאינן דוברות אנגלית, במיוחד באמריקה הלטינית, אסיה ואירופה, נאבקים עם ממשקים באנגלית בלבד. מחסומי שפה מפחיתים את האימוץ ומגדילים את שגיאות התצורה.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **לוח המחוונים i18n — 30 שפות** — כל 500+ המקשים מתורגמים כולל ערבית, בולגרית, דנית, גרמנית, ספרדית, פינית, צרפתית, עברית, הינדית, הונגרית, אינדונזית, איטלקית, יפנית, קוריאנית, מלאית, הולנדית, נורווגית, פולנית, פורטוגזית (PT/BR), רומנית, רוסית, סלובקית, שוודית, תאילנדית, סלובקית, שוודית, סינית, סלובקית, וייטנאם
- **תמיכה ב-RTL** — תמיכה מימין לשמאל לערבית ולעברית
- ** README מרובים שפות** - 30 תרגומי תיעוד מלאים
- **בורר שפה** - סמל גלובוס בכותרת למעבר בזמן אמת
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "אני צריך יותר מצ'אט - אני צריך הטמעות, תמונות, אודיו"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI זה לא רק השלמת צ'אט. מפתחים צריכים ליצור תמונות, לתמלל אודיו, ליצור הטמעות עבור RAG, לדרג מחדש מסמכים ולתת תוכן. לכל API יש נקודת קצה ופורמט שונים.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **הטמעות** — `/v1/embeddings` עם 6 ספקים ו-9+ דגמים
- **יצירת תמונות** — `/v1/images/generations` עם 10 ספקים ו-20+ דגמים (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **טקסט לווידאו** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) ו-SD WebUI
- **טקסט למוזיקה** — `/v1/music/generations` — ComfyUI (פתוח אודיו יציב, MusicGen)
- **תמלול אודיו** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **טקסט לדיבור** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + ספקים קיימים
- **מודציות** — `/v1/moderations` — בדיקות בטיחות תוכן
- **דירוג מחדש** — `/v1/rerank` — דירוג מחדש של רלוונטיות המסמך
- **Responses API** — תמיכה מלאה ב-`/v1/responses` עבור Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "אין לי דרך לבדוק ולהשוות איכות בין דגמים" </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
מפתחים רוצים לדעת איזה דגם הוא הטוב ביותר עבור מקרה השימוש שלהם - קוד, תרגום, הנמקה - אבל ההשוואה ידנית היא איטית. לא קיימים כלי eval משולבים.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **הערכות LLM** - בדיקת סט זהב עם 10 מקרים טעונים מראש המכסים ברכות, מתמטיקה, גיאוגרפיה, יצירת קוד, תאימות ל-JSON, תרגום, סימון, סירוב בטיחות
- **4 אסטרטגיות התאמה** — `exact`, `contains`, `regex`, `custom` (פונקציית JS)
- **ספסל בדיקה במגרש משחקים של מתרגם** - בדיקות אצווה עם מספר כניסות ויציאות צפויות, השוואה בין ספקים
- ** בודק צ'אט** - הלוך ושוב מלא עם עיבוד תגובה ויזואלית
- **מעקב חי** - זרם בזמן אמת של כל הבקשות הזורמות דרך ה-proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "אני צריך לשנות קנה מידה מבלי לאבד ביצועים" </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
ככל שנפח הבקשות גדל, ללא שמירה במטמון, אותן שאלות מייצרות עלויות כפולות. ללא אימפוטנציה, עיבוד פסולת בקשות כפולות. יש לכבד את מגבלות התעריפים לכל ספק.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **מטמון סמנטי** - מטמון דו-שכבתי (חתימה + סמנטי) מפחית את העלות והשהייה
- **Request Idempotency** — חלון מניעת כפילויות של 5 שניות לבקשות זהות
- **זיהוי מגבלת תעריף** - RPM לכל ספק, פער מינימלי ומעקב מרבי בו-זמנית
- **מגבלות קצב הניתנות לעריכה** - ברירות מחדל הניתנות להגדרה בהגדרות ← חוסן עם התמדה
- **מטמון מפתח API** - מטמון בן 3 שכבות לביצועי ייצור
- **לוח מחוונים לבריאות עם טלמטריה** - זמן אחזור p50/p95/p99, סטטיסטיקות מטמון, זמן פעולה
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "אני רוצה לשלוט בהתנהגות המודל באופן גלובלי" </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
מפתחים שרוצים את כל התגובות בשפה ספציפית, עם טון ספציפי, או רוצים להגביל את אסימוני הנמקה. הגדרה זו בכל כלי/בקשה אינה מעשית.
**How OmniRoute solves it:**
**איך OmniRoute פותר את זה:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **הזרקת הנחיית מערכת** - הנחיה גלובלית חלה על כל הבקשות
- **אימות תקציב חשיבה** - בקרת הקצאת אסימונים בהיגיון לכל בקשה (מעבר, אוטומטי, מותאם אישית, אדפטיבי)
- **6 אסטרטגיות ניתוב** - אסטרטגיות גלובליות הקובעות את אופן הפצת הבקשות
- **נתב תווים כלליים** — תבניות `provider/*` מנותבות באופן דינמי לכל ספק
- **הפעל/השבת שילוב של החלפה** — החלף שילובים ישירות מלוח המחוונים
- **החלפת ספק** — הפעל/השבת את כל החיבורים עבור ספק בלחיצה אחת
- **ספקים חסומים** — אל תכלול ספקים ספציפיים מרשימת `/v1/models`
</details>
<details>
<summary><b>🧰 17. "אני צריך כלי MCP כיכולות מוצר מהשורה הראשונה" </b></summary>
שערי AI רבים חושפים את MCP רק כפרט יישום נסתר. צוותים צריכים שכבת פעולה גלויה וניתנת לניהול.
**איך OmniRoute פותר את זה:**
- MCP מופיע בכרטיסיית הניווט של לוח המחוונים ופרוטוקול נקודת הקצה
- דף ניהול MCP ייעודי עם תהליך, כלים, היקפים וביקורת
- התחלה מהירה מובנית עבור `omniroute --mcp` וכניסה ללקוח
</details>
<details>
<summary><b>🧠 18. "אני צריך תזמור A2A עם נתיבי משימות סינכרון + זרם" </b></summary>
זרימות עבודה של סוכן זקוקות הן לתשובות ישירות והן לביצוע זרימה ארוך טווח עם בקרת מחזור חיים.
**איך OmniRoute פותר את זה:**
- נקודת קצה A2A JSON-RPC (`POST /a2a`) עם `message/send` ו-`message/stream`
- הזרמת SSE עם הפצת מצב מסוף
- ממשקי API של מחזור חיים של משימות עבור `tasks/get` ו-`tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "אני צריך בריאות של תהליך MCP אמיתי, מצב לא מנחש" </b></summary>
צוותים תפעוליים צריכים לדעת אם MCP באמת חי, לא רק אם ניתן להגיע ל-API.
**איך OmniRoute פותר את זה:**
- קובץ פעימות לב בזמן ריצה עם PID, חותמות זמן, תחבורה, ספירת כלים ומצב היקף
- MCP status API המשלב פעימות לב + פעילות אחרונה
- כרטיסי סטטוס ממשק משתמש עבור תהליך/זמן פעולה/רעננות פעימות לב
</details>
<details>
<summary><b>📋 20. "אני צריך ביצוע כלי MCP שניתן לביקורת" </b></summary>
כאשר כלים משתנים בתצורה או מפעילים פעולות מבצעיות, הצוותים זקוקים למעקב פורנזי.
**איך OmniRoute פותר את זה:**
- רישום ביקורת מגובה SQLite עבור קריאות לכלי MCP
- מסננים לפי כלי, הצלחה/כישלון, מפתח API ועימוד
- טבלת ביקורת לוח המחוונים + נקודות קצה סטטיסטיקות לאוטומציה
</details>
<details>
<summary><b>🔐 21. "אני צריך הרשאות MCP בטווחים לכל אינטגרציה" </b></summary>
ללקוחות שונים צריכה להיות גישה בעלת הרשאות מינימליות לקטגוריות כלים.
**איך OmniRoute פותר את זה:**
- 9 היקפי MCP גרגירים לגישה מבוקרת לכלי
- אכיפה של היקף ונראות בממשק המשתמש של ניהול MCP
- תנוחת ברירת מחדל בטוחה עבור כלי עבודה תפעוליים
</details>
<details>
<summary><b>⚙️ 22. "אני צריך בקרות תפעוליות בלי לפרוס מחדש" </b></summary>
צוותים זקוקים לשינויים מהירים בזמן ריצה במהלך אירועים או אירועי עלות.
**איך OmniRoute פותר את זה:**
- החלף הפעלה משולבת ישירות מלוח המחוונים של MCP
- החל פרופילי חוסן מחבילות מדיניות מוגדרות מראש
- אפס את מצב מפסק החשמל מאותו לוח פעולות
</details>
<details>
<summary><b>🔄 23. "אני צריך נראות וביטול של מחזור החיים של משימות A2A בשידור חי" </b></summary>
ללא נראות של מחזור חיים, אירועי משימות הופכים קשים לבדיקה.
**איך OmniRoute פותר את זה:**
- רישום משימות/סינון לפי מצב/מיומנות עם עימוד
- פירוט על מטא נתונים של משימות, אירועים וחפצים
- נקודת קצה לביטול משימות ופעולת ממשק משתמש עם אישור
</details>
<details>
<summary><b>🌊 24. "אני צריך מדדי סטרימינג פעילים עבור טעינת A2A" </b></summary>
זרימות עבודה בסטרימינג דורשות תובנה תפעולית לגבי חיבורים במקביל וחיבורים חיים.
**איך OmniRoute פותר את זה:**
- מוני זרמים פעילים משולבים בסטטוס A2A
- חותמת הזמן האחרונה של המשימה וספירות לכל מדינה
- כרטיסי לוח מחוונים A2A לניטור פעולות בזמן אמת
</details>
<details>
<summary><b>🪪 25. "אני צריך גילוי סוכן סטנדרטי עבור לקוחות" </b></summary>
לקוחות חיצוניים ומתזמרים זקוקים למטא-נתונים הניתנים לקריאת מכונה לצורך הצטרפות.
**איך OmniRoute פותר את זה:**
- כרטיס סוכן חשוף ב-`/.well-known/agent.json`
- יכולות ומיומנויות המוצגות בממשק המשתמש לניהול
- API לסטטוס A2A כולל מטא נתונים של גילוי לאוטומציה
</details>
<details>
<summary><b>🧭 26. "אני צריך גילוי פרוטוקול ב-UX של המוצר"</b></summary>
אם משתמשים לא יכולים לגלות משטחי פרוטוקול, האימוץ והתמיכה יורדים.
**איך OmniRoute פותר את זה:**
- ערכים בסרגל הצד עבור MCP ו-A2A
- כרטיסיית פרוטוקולים של דף נקודות קצה עם התחלה מהירה ומצב
- קישורים מסקירה כללית ללוחות ניהול ייעודיים
</details>
<details>
<summary><b>🧪 27. "אני צריך אימות פרוטוקול מקצה לקצה עם לקוחות אמיתיים" </b></summary>
בדיקות מדומה אינן מספיקות כדי לאמת תאימות פרוטוקול לפני השחרור.
**איך OmniRoute פותר את זה:**
- חבילת E2E המאתחלת אפליקציה ומשתמשת בהעברת לקוח MCP SDK אמיתית
- בדיקות לקוח A2A לאיתור, לשלוח, להזרים, לקבל ולבטל זרימות
- צלב הצהרות מול ביקורת MCP ומשימות A2A APIs
</details>
<details>
<summary><b>📡 28. "אני צריך צפייה מאוחדת בכל הממשקים" </b></summary>
פיצול צפיות לפי פרוטוקול יוצר כתמים עיוורים ו-MTTR ארוך יותר.
**איך OmniRoute פותר את זה:**
- לוחות מחוונים/יומנים/ניתוח מאוחדים במוצר אחד
- בריאות + ביקורת + טלמטריית בקשה על פני שכבות OpenAI, MCP ו-A2A
- APIs תפעוליים לסטטוס ואוטומציה
</details>
<details>
<summary><b>💼 29. "אני צריך זמן ריצה אחד עבור פרוקסי + כלים + תזמור סוכן"</b></summary>
הפעלת שירותים נפרדים רבים מגדילה את העלות התפעולית ואת מצבי הכשל.
**איך OmniRoute פותר את זה:**
- פרוקסי תואם OpenAI, שרת MCP ושרת A2A בערימה אחת
- אימות משותף, חוסן, מאגר נתונים וצפייה
- מודל מדיניות עקבי בכל משטחי האינטראקציה
</details>
<details>
<summary><b>🚀 30. "אני צריך לשלוח זרימות עבודה סוכניות ללא התפשטות קוד דבק" </b></summary>
צוותים מאבדים מהירות בעת תפירת שירותים ותסריטים אד-הוק מרובים.
**איך OmniRoute פותר את זה:**
- אסטרטגיית נקודות קצה אחידה עבור לקוחות וסוכנים
- ממשקי משתמש מובנים לניהול פרוטוקול ונתיבי אימות עשן
- יסודות מוכנים לייצור (אבטחה, רישום, חוסן, גיבוי)
</details>
### ספרי הפעלה לדוגמה (מקרי שימוש משולבים)
**Playbook A: מקסום מנוי בתשלום + גיבוי זול**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: ערימת קידוד בעלות אפסית**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: שרשרת ניצול תמיד 24/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: סוכן מבצע עם MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ התחלה מהירה
**1. התקן ברחבי העולם:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +990,26 @@ OmniRoute כולל מגרש משחקי מתרגמים מובנה רב עוצמה
</details>
---
## 🧪 הערכות (הערכות)
## 🎯 מקרי שימוש
OmniRoute כולל מסגרת הערכה מובנית לבדיקת איכות תגובת LLM מול סט מוזהב. גש אליו דרך **Analytics → Evals** בלוח המחוונים.
### מקרה 1: "יש לי מנוי לקלוד פרו"
### סט מוזהב מובנה
**בעיה:** תוקף המכסה פג ללא שימוש, מגבלות תעריף במהלך קידוד כבד
ה-"OmniRoute Golden Set" הנטען מראש מכיל 10 מקרי בדיקה המכסים:
```
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)
- ברכות, מתמטיקה, גיאוגרפיה, יצירת קוד
- תאימות לפורמט JSON, תרגום, סימון
- סירוב בטיחותי (תוכן מזיק), ספירה, היגיון בוליאני
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### אסטרטגיות הערכה
### מקרה 2: "אני רוצה עלות אפס"
**בעיה:** לא יכול להרשות לעצמו מנויים, צריך קידוד AI אמין
```
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
```
### מקרה 3: "אני צריך קידוד 24/7, ללא הפרעות"
**בעיה:** מועדים, לא יכול להרשות לעצמו זמן השבתה
```
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
```
### מקרה 4: "אני רוצה AI בחינם ב-OpenClaw"
**בעיה:** צריך עוזר בינה מלאכותית באפליקציות הודעות, בחינם לחלוטין
```
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...
```
| אסטרטגיה | תיאור | דוגמה |
| ---------- | ------------------------------------------ | -------------------------------- |
| `exact` | הפלט חייב להתאים בדיוק | `"4"` |
| `contains` | הפלט חייב להכיל תת מחרוזת (לא תלוי רישיות) | `"Paris"` |
| `regex` | הפלט חייב להתאים לדפוס הרקס | `"1.*2.*3"` |
| `custom` | פונקציית JS מותאמת מחזירה true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1293,6 @@ Settings → API Configuration:
---
## 🧪 הערכות (הערכות)
OmniRoute כולל מסגרת הערכה מובנית לבדיקת איכות תגובת LLM מול סט מוזהב. גש אליו דרך **Analytics → Evals** בלוח המחוונים.
### סט מוזהב מובנה
ה-"OmniRoute Golden Set" הנטען מראש מכיל 10 מקרי בדיקה המכסים:
- ברכות, מתמטיקה, גיאוגרפיה, יצירת קוד
- תאימות לפורמט JSON, תרגום, סימון
- סירוב בטיחותי (תוכן מזיק), ספירה, היגיון בוליאני
### אסטרטגיות הערכה
| אסטרטגיה | תיאור | דוגמה |
| ---------- | ------------------------------------------ | -------------------------------- |
| `exact` | הפלט חייב להתאים בדיוק | `"4"` |
| `contains` | הפלט חייב להכיל תת מחרוזת (לא תלוי רישיות) | `"Paris"` |
| `regex` | הפלט חייב להתאים לדפוס הרקס | `"1.*2.*3"` |
| `custom` | פונקציית JS מותאמת מחזירה true/false | `(output) => output.length > 10` |
---
## 🐛 פתרון בעיות
<details>
@@ -1132,7 +1344,7 @@ OmniRoute כולל מסגרת הערכה מובנית לבדיקת איכות ת
- OmniRoute v1.0.6+ כולל אימות חוזר באמצעות השלמת צ'אט
- ודא שכתובת האתר הבסיסית כוללת את הסיומת `/v1`
### 🔐 OAuth em Servidor Remoto (הגדרת OAuth מרחוק)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
@@ -1227,7 +1439,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **זמן ריצה**: Node.js 1822 LTS (⚠️ Node.js 24+ **לא נתמך** - `better-sqlite3` קבצים בינאריים מקוריים אינם תואמים)
- **שפה**: TypeScript 5.9 — **100% TypeScript** על פני `src/` ו`open-sse/` (v1.0.6)
@@ -1279,18 +1491,19 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ מפת דרכים
## 🗺️
ל-OmniRoute יש **210+ תכונות מתוכננות** לאורך שלבי פיתוח מרובים. להלן תחומי המפתח:
| קטגוריה | תכונות מתוכננות | הבהרה |
| --------------------- | --------------- | ---------------------------------------------------------------------------------------- |
| 🧠 **ניתוב ומודיעין** | 25+ | ניתוב עם זמן האחזור הנמוך ביותר, ניתוב מבוסס תגים, בדיקה מוקדמת של מכסה, בחירת חשבון P2C |
| 🔒 **אבטחה ותאימות** | 20+ | הקשחת SSRF, הסוואה של אישורים, הגבלת קצב לכל נקודת קצה, היקף מפתח ניהול |
| 📊 **צפיות** | 15+ | אינטגרציה של OpenTelemetry, ניטור מכסות בזמן אמת, מעקב עלויות לכל דגם |
| 🔄 **שילובי ספקים** | 20+ | רישום מודלים דינמיים, צינון ספקים, Codex מרובה חשבונות, ניתוח מכסת Copilot |
| **ביצועים** | 15+ | שכבת מטמון כפולה, מטמון הנחיה, מטמון תגובה, סטרימינג Keepalive, API אצווה |
| 🌐 **מערכת אקולוגית** | 10+ | WebSocket API, טעינה חוזרת של תצורה, חנות תצורה מבוזרת, מצב מסחרי |
| קטגוריה | תכונות מתוכננות | הבהרה |
| ---------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🧠 **ניתוב ומודיעין** | 25+ | ניתוב עם זמן האחזור הנמוך ביותר, ניתוב מבוסס תגים, בדיקה מוקדמת של מכסה, בחירת חשבון P2C |
| 🔒 **אבטחה ותאימות** | 20+ | הקשחת SSRF, הסוואה של אישורים, הגבלת קצב לכל נקודת קצה, היקף מפתח ניהול |
| 📊 **צפיות** | 15+ | אינטגרציה של OpenTelemetry, ניטור מכסות בזמן אמת, מעקב עלויות לכל דגם |
| 🔄 **שילובי ספקים** | 20+ | רישום מודלים דינמיים, צינון ספקים, Codex מרובה חשבונות, ניתוח מכסת Copilot |
| **ביצועים** | 15+ | שכבת מטמון כפולה, מטמון הנחיה, מטמון תגובה, סטרימינג Keepalive, API אצווה |
| 🌐 **מערכת אקולוגית** | 10+ | WebSocket API, טעינה חוזרת של תצורה, חנות תצורה מבוזרת, מצב מסחרי |
### 🔜 בקרוב
@@ -1304,18 +1517,6 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 📧 תמיכה
> 💬 **הצטרפו לקהילה שלנו!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — קבל עזרה, שתף טיפים והישאר מעודכן.
- **אתר**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **בעיות**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **וואטסאפ**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **פרויקט מקורי**: [9router by 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)

View File

@@ -110,6 +110,35 @@ _Csatlakoztasson bármilyen mesterséges intelligencia-alapú IDE-t vagy CLI-esz
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Miért az OmniRoute?
**Ne pazarolja a pénzt, és ne lépje túl a limiteket:**
@@ -128,6 +157,18 @@ _Csatlakoztasson bármilyen mesterséges intelligencia-alapú IDE-t vagy CLI-esz
---
## 📧 Támogatás
> 💬 **Csatlakozzon közösségünkhöz!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Kérjen segítséget, ossza meg tippjeit, és naprakész legyen.
- **Webhely**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problémák**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Eredeti projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Hogyan működik
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Mit old meg az OmniRoute 30 valódi fájdalompont és használati eset
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Minden mesterséges intelligencia-eszközöket használó fejlesztő naponta szembesül ezekkel a problémákkal.** Az OmniRoute úgy készült, hogy ezeket mind megoldja a költségtúllépésektől a regionális blokkokig, a megszakadt OAuth-folyamatoktól a protokollműveletekig és a vállalati megfigyelhetőségig.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Drága előfizetésért fizetek, de még mindig megszakítanak a korlátozások" </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
A fejlesztők havi 20200 dollárt fizetnek a Claude Pro, Codex Pro vagy GitHub Copilotért. A kvótának még fizetés esetén is van felső határa 5 óra használat, heti limitek vagy percdíjkorlátok. A kódolási munkamenet közepén a szolgáltató leáll, és a fejlesztő elveszíti a folyamatot és a termelékenységet.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** Ha az előfizetési kvóta kimerül, automatikusan átirányítja az API-kulcs → Olcsó → Ingyenes, manuális beavatkozás nélkül
- **Valós idejű kvótakövetés** Valós időben mutatja a token felhasználást, visszaszámlálással (5 óra, napi, heti)
- **Több fiók támogatása** - Több fiók szolgáltatónként automatikus körváltással - ha az egyik elfogy, átvált a következőre
- **Egyéni kombók** — Testreszabható tartalék láncok 6 kiegyensúlyozási stratégiával (fill-first, round-robin, P2C, véletlenszerű, legkevésbé használt, költségoptimalizált)
- **Codex üzleti kvóták** — Üzleti/csapat munkaterület-kvóta figyelése közvetlenül az irányítópulton
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Több szolgáltatót kell használnom, de mindegyiknek más API" </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
Az OpenAI egy formátumot használ, a Claude (Anthropic) egy másikat, a Gemini pedig egy másikat. Ha egy fejlesztő különböző szolgáltatók modelljeit szeretné tesztelni, vagy tartalékot szeretne közöttük, akkor újra kell konfigurálnia az SDK-kat, módosítania kell a végpontokat, és kezelnie kell az inkompatibilis formátumokat. Az egyéni szolgáltatók (FriendLI, NIM) nem szabványos modellvégpontokkal rendelkeznek.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Egységes végpont** - Egy `http://localhost:20128/v1` proxyként szolgál mind a 36+ szolgáltató számára
- **Formátumfordítás** - Automatikus és átlátható: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** Eltávolítja azokat a nem szabványos mezőket (`x_groq`, `usage_breakdown`, `service_tier`), amelyek megszakítják az OpenAI SDK v1.83+ verzióját
- **Szerepek normalizálása** — `developer``system` konvertálása nem OpenAI szolgáltatók számára; `system``user` a GLM/ERNIE számára
- **Think Tag Extraction** `<think>` blokkokat bont ki olyan modellekből, mint a DeepSeek R1 szabványos `reasoning_content`-be
- **Strukturált kimenet a Gemini számára** — `json_schema``responseMimeType`/`responseSchema` automatikus átalakítás
- **`stream` az alapértelmezett `false`** - Az OpenAI specifikációhoz igazodik, elkerülve a váratlan SSE-t a Python/Rust/Go SDK-kban
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. „Az AI-szolgáltatóm blokkolja a régiómat/országomat”</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Az olyan szolgáltatók, mint az OpenAI/Codex, blokkolják a hozzáférést bizonyos földrajzi régiókból. A felhasználók OAuth- és API-kapcsolatok során olyan hibákat kapnak, mint az `unsupported_country_region_territory`. Ez különösen frusztráló a fejlődő országok fejlesztői számára.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-szintű proxykonfiguráció** 3 szinten konfigurálható proxy: globális (teljes forgalom), szolgáltatónként (csak egy szolgáltató) és kapcsolatonként/kulcsonként
- **Színes proxy jelvények** - Vizuális jelzők: 🟢 globális proxy, 🟡 szolgáltató proxy, 🔵 kapcsolat proxy, mindig az IP-t mutatja
- **OAuth-tokencsere proxyn keresztül** — Az OAuth-folyamat a proxyn keresztül is megy, megoldva az `unsupported_country_region_territory` problémát
- **Kapcsolódási tesztek proxyn keresztül** - A csatlakozási tesztek a konfigurált proxyt használják (nincs többé közvetlen kiiktatás)
- **SOCKS5 támogatás** — Teljes SOCKS5 proxy támogatás a kimenő útválasztáshoz
- **TLS-ujjlenyomat-hamisítás** — Böngészőszerű TLS-ujjlenyomat az `wreq-js`-n keresztül a botészlelés megkerüléséhez
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "MI-t akarok használni kódoláshoz, de nincs pénzem" </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nem mindenki fizethet havi 20200 dollárt az AI-előfizetésekért. A feltörekvő országok diákjainak, fejlesztőinek, amatőröknek és szabadúszóknak nulla költséggel kell hozzáférniük a minőségi modellekhez.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Free Tier Providers Built-in** Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Beépített ingyenes szolgáltatók** - Natív támogatás 100%-ban ingyenes szolgáltatókhoz: iFlow (8 korlátlan modell), Qwen (3 korlátlan modell), Kiro (Claude ingyenes), Gemini CLI (180 000/hónap ingyenes)
- **Csak ingyenes kombók** — `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` lánc = 0 USD/hó nulla állásidővel
- **NVIDIA NIM ingyenes kreditek** 1000 ingyenes kredit integrálva
- **Költségoptimalizált stratégia** — Útválasztási stratégia, amely automatikusan a legolcsóbb elérhető szolgáltatót választja
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Meg kell védenem a mesterséges intelligencia átjárómat a jogosulatlan hozzáféréstől"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Ha AI átjárót teszünk ki a hálózatnak (LAN, VPS, Docker), a cím birtokában bárki felhasználhatja a fejlesztő tokenjeit/kvótáját. Védelem nélkül az API-k sebezhetőek a visszaélésekkel, azonnali befecskendezéssel és visszaélésekkel szemben.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API-kulcskezelés** — Generálás, rotáció és hatókör szolgáltatónként egy dedikált `/dashboard/api-manager`-oldallal
- **Modellszintű engedélyek** - API-kulcsok korlátozása adott modellekre (`openai/*`, helyettesítő karakteres minták), az Összes engedélyezése/Korlátozása kapcsolóval
- **API Endpoint Protection** — Kulcs szükséges az `/v1/models` számára, és bizonyos szolgáltatók letiltása a listáról
- **Auth Guard + CSRF védelem** - Minden irányítópult-útvonal `withAuth` köztes szoftverrel + CSRF tokenekkel védett
- **Rate Limiter** — IP-nkénti sebességkorlátozás konfigurálható ablakokkal
- **IP-szűrés** — Engedélyezési lista/blokkolólista a hozzáférés-vezérléshez
- **Prompt Injection Guard** fertőtlenítés a rosszindulatú felszólítási minták ellen
- **AES-256-GCM titkosítás** - A hitelesítő adatok nyugalmi állapotban titkosítva
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "A szolgáltatóm leállt, és elvesztettem a kódolási folyamatomat"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Az AI-szolgáltatók instabillá válhatnak, 5xx-es hibákat adnak vissza, vagy elérhetik az ideiglenes sebességkorlátokat. Ha egy fejlesztő egyetlen szolgáltatótól függ, akkor megszakad. Megszakítók nélkül az ismételt újrapróbálkozások összeomolhatják az alkalmazást.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Circuit Breaker per-provider** Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Megszakító szolgáltatónként** - Automatikus nyitás/zárás konfigurálható küszöbértékekkel és lehűtéssel (zárt/nyitott/félig nyitott)
- **Exponenciális visszalépés** — Progresszív újrapróbálkozási késések
- **Mennydörgés elleni csorda** - Mutex + szemafor védelem az egyidejű újrapróbálkozási viharok ellen
- **Kombinált tartalék láncok** Ha az elsődleges szolgáltató meghibásodik, automatikusan, beavatkozás nélkül átesik a láncon
- **Combo Circuit Breaker** Automatikusan letiltja a hibás szolgáltatókat a kombinált láncon belül
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Egészségügyi irányítópult** — Üzemidő-figyelés, áramkör-megszakító állapotok, zárolások, gyorsítótár-statisztika, p50/p95/p99 késleltetés
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Az egyes AI-eszközök konfigurálása fárasztó és ismétlődő"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
A fejlesztők Cursort, Claude Code-ot, Codex CLI-t, OpenClaw-ot, Gemini CLI-t, Kilo Code-ot használnak... Minden eszköznek más konfigurációra van szüksége (API végpont, kulcs, modell). Az újrakonfigurálás szolgáltató- vagy modellváltáskor időpocsékolás.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **CLI Tools Dashboard** Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** - Dedikált oldal egykattintásos beállítással a Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline számára
- **GitHub másodpilóta konfigurációs generátor** — `chatLanguageModels.json` kódot generál VS kódhoz tömeges modellválasztással
- **Bevezető varázsló** Irányított 4 lépéses beállítás első felhasználók számára
- **Egy végpont, minden modell** — Az `http://localhost:20128/v1` egyszeri konfigurálása, 36+ szolgáltató elérése
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "A több szolgáltatótól származó OAuth-tokenek kezelése pokol"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot mindegyik az OAuth 2.0-t használja lejáró tokenekkel. A fejlesztőknek folyamatosan újra kell hitelesíteniük, kezelniük kell az `client_secret is missing`, `redirect_uri_mismatch` és a távoli szerverek hibáit. Az OAuth a LAN/VPS-en különösen problémás.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatikus tokenfrissítés** - Az OAuth-tokenek a háttérben frissülnek a lejárat előtt
- **OAuth 2.0 (PKCE) beépített** - Automatikus áramlás Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow számára
- **Multi-Account OAuth** - Több fiók szolgáltatónként a JWT/ID token kivonattal
- **OAuth LAN/Távoli javítás** - Privát IP-észlelés `redirect_uri`-hez + kézi URL mód távoli szerverekhez
- **OAuth az Nginx mögött** - `window.location.origin`-t használ a fordított proxy kompatibilitás érdekében
- **Távoli OAuth útmutató** Lépésről lépésre útmutató a Google Cloud hitelesítő adataihoz VPS/Docker rendszeren
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Nem tudom, mennyit költök vagy hova"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
A fejlesztők több fizetős szolgáltatót használnak, de nincs egységes nézetük a kiadásokról. Minden szolgáltató saját számlázási irányítópulttal rendelkezik, de nincs összevont nézet. A váratlan költségek felhalmozódhatnak.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Költségelemzési irányítópult** Tokenenkénti költségkövetés és költségkeret-kezelés szolgáltatónként
- **Költségkeret-korlátok rétegenként** - Költési felső határ szintenként, amely automatikus visszalépést vált ki
- **Modellenkénti árképzés** - Konfigurálható árak modellenként
- **Használati statisztika API-kulcsonként** — A kérések száma és az utoljára használt időbélyeg kulcsonként
- **Analytics Dashboard** — Statisztikai kártyák, modellhasználati diagram, szolgáltatói táblázat sikerarányokkal és késleltetéssel
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Nem tudom diagnosztizálni a hibákat és problémákat az AI-hívásoknál"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Ha egy hívás meghiúsul, a fejlesztő nem tudja, hogy sebességkorlátozás, lejárt token, rossz formátum vagy szolgáltatói hiba volt-e. Töredezett naplók különböző terminálokon. Megfigyelhetőség nélkül a hibakeresés próba és hiba.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Unified Logs Dashboard** 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Egységes naplók irányítópultja** - 4 lap: Kérelemnaplók, Proxynaplók, Auditnaplók, Konzol
- **Konzolnapló-nézegető** — Valós idejű terminál stílusú megjelenítő színkódolt szintekkel, automatikus görgetés, keresés, szűrés
- **SQLite proxynaplók** Állandó naplók, amelyek túlélik a szerver újraindítását
- **Translator Playground** 4 hibakeresési mód: Playground (formátum fordítás), Chat Tester (oda-vissza út), Tesztpad (kötegelt), Élő monitor (valós idejű)
- **Request Telemetria** p50/p95/p99 késleltetés + X-Request-Id nyomkövetés
- **Fájlalapú naplózás elforgatással** - A konzolelfogó mindent JSON-naplóba rögzít méretalapú elforgatással
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Az átjáró telepítése és karbantartása összetett" </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Az AI-proxy telepítése, konfigurálása és karbantartása különböző környezetekben (helyi, VPS, Docker, felhő) munkaigényes. Az olyan problémák, mint a keménykódolt elérési utak, az `EACCES` a könyvtárakon, a portütközések és a többplatformos buildek súrlódást okoznak.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm globális telepítés** — `npm install -g omniroute && omniroute`kész
- **Docker Multi-Platform** AMD64 + ARM64 natív (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (nincs CLI-eszközök) és `cli` (Claude Code-al, Codex-szel, OpenClaw-val)
- **Electron Desktop App** Natív alkalmazás Windows/macOS/Linux rendszerhez rendszertálcával, automatikus indítással, offline móddal
- **Split-Port Mode** API és irányítópult külön portokon haladó forgatókönyvekhez (fordított proxy, konténerhálózat)
- **Cloud Sync** Szinkronizálás konfigurálása az eszközök között a Cloudflare Workers segítségével
- **DB biztonsági mentések** — Az összes beállítás automatikus biztonsági mentése, visszaállítása, exportálása és importálása
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "A felület csak angol nyelvű, és a csapatom nem beszél angolul"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
A nem angol nyelvű országokban, különösen Latin-Amerikában, Ázsiában és Európában működő csapatok csak angol nyelvű felületekkel küszködnek. A nyelvi akadályok csökkentik az átvételt és növelik a konfigurációs hibákat.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Dashboard i18n 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- ** Irányítópult i18n 30 nyelv** Mind az 500+ billentyű lefordítva, beleértve arab, bolgár, dán, német, spanyol, finn, francia, héber, hindi, magyar, indonéz, olasz, japán, koreai, maláj, holland, norvég, lengyel, portugál (PT/BR), román, thai, orosz, szlovák, svéd, filippínó, angol, thai, orosz, kínai, filippínó
- **RTL támogatás** Jobbról balra haladó arab és héber nyelv támogatása
- **Többnyelvű README-k** — 30 teljes dokumentáció fordítás
- **Nyelvválasztó** — Globe ikon a fejlécben a valós idejű váltáshoz
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Többre van szükségem, mint csevegésre beágyazásra, képekre, hangra van szükségem"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
Az AI nem csak a csevegés befejezése. A fejlesztőknek képeket kell generálniuk, hangot kell átírniuk, beágyazást kell létrehozniuk a RAG számára, át kell sorolniuk a dokumentumokat, és moderálniuk kell a tartalmat. Minden API más végponttal és formátummal rendelkezik.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Beágyazások** — `/v1/embeddings` 6 szolgáltatóval és 9+ modellel
- **Képgenerálás** — `/v1/images/generations` 10 szolgáltatóval és 20+ modellel (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) és SD WebUI
- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Audio átírás** - `/v1/audio/transcriptions` - Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Szövegfelolvasó** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + meglévő szolgáltatók
- **Moderálás** — `/v1/moderations` — Tartalombiztonsági ellenőrzések
- **Átsorolás** — `/v1/rerank` — Dokumentumreleváns átsorolás
- **Responses API** - Teljes `/v1/responses` támogatás a Codexhez
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Nincs módom tesztelni és összehasonlítani a minőséget a különböző modellek között"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
A fejlesztők szeretnék tudni, hogy melyik modell a legjobb az ő használati esetükben kód, fordítás, érvelés , de a manuális összehasonlítás lassú. Nincsenek integrált eval eszközök.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM-értékelések** — Arany készlet tesztelése 10 előre betöltött esettel, beleértve az üdvözlést, a matematikát, a földrajzot, a kódgenerálást, a JSON-megfelelőséget, a fordítást, a leértékelést, a biztonsági megtagadást
- **4 egyezési stratégia** — `exact`, `contains`, `regex`, `custom` (JS funkció)
- **Translator Playground Test Bench** - Kötegelt tesztelés több bemenettel és várható kimenettel, szolgáltatók közötti összehasonlítás
- **Csevegés teszte** - Teljes körút vizuális válaszmegjelenítéssel
- **Élő monitor** Valós idejű adatfolyam a proxyn keresztül folyó összes kérésről
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "A teljesítmény elvesztése nélkül kell méreteznem" </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
A kérelmek mennyiségének növekedésével ugyanazok a kérdések a gyorsítótárazás nélkül duplikált költségeket generálnak. Idempotencia nélkül a duplikált hulladékfeldolgozási kérelmek. A szolgáltatónkénti díjkorlátokat be kell tartani.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Szemantikus gyorsítótár** A kétszintű gyorsítótár (aláírás + szemantikai) csökkenti a költségeket és a késleltetést
- **Idempotency kérése** 5 másodperces deduplikációs ablak azonos kérések esetén
- **Drátakorlát észlelése** Szolgáltatónkénti RPM, minimális rés és maximális egyidejű követés
- **Szerkeszthető sebességkorlátok** - Konfigurálható alapértékek a Beállítások → Kitartással ellenálló képesség menüpontban
- **API Key Validation Cache** 3-szintű gyorsítótár az éles teljesítményhez
- **Egészségügyi irányítópult telemetriával** — p50/p95/p99 késleltetés, gyorsítótár statisztika, üzemidő
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Globálisan szeretném szabályozni a modell viselkedését" </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Azok a fejlesztők, akik minden választ egy adott nyelven, egy adott hangnemben szeretnének, vagy korlátozni szeretnék az érvelési tokeneket. Ennek konfigurálása minden eszközben/kérelemben nem praktikus.
**How OmniRoute solves it:**
**Hogyan oldja meg az OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Rendszerprompt Injection** — Globális prompt minden kérelemre vonatkozik
- **A költségkeret átgondolásának ellenőrzése** Indoklási token-kiosztás ellenőrzése kérésenként (áthaladó, automatikus, egyéni, adaptív)
- **6 Útválasztási stratégia** Globális stratégiák, amelyek meghatározzák a kérések elosztását
- **Wildcard Router** — `provider/*` minták dinamikusan továbbítanak bármely szolgáltatóhoz
- **Kombinációs engedélyezés/letiltás váltás** - A kombók váltása közvetlenül az irányítópultról
- **Provider Toggle** — Egy szolgáltató összes kapcsolatának engedélyezése/letiltása egyetlen kattintással
- **Letiltott szolgáltatók** - Adott szolgáltatók kizárása az `/v1/models` listáról
</details>
<details>
<summary><b>🧰 17. "MCP eszközökre van szükségem, mint első osztályú termékképességekre" </b></summary>
Sok mesterséges intelligencia-átjáró csak rejtett megvalósítási részletként teszi közzé az MCP-t. A csapatoknak látható, kezelhető műveleti rétegre van szükségük.
**Hogyan oldja meg az OmniRoute:**
- Az MCP megjelenik az irányítópult navigációs és végponti protokoll lapján
- Dedikált MCP-kezelési oldal folyamatokkal, eszközökkel, hatókörökkel és audittal
- Beépített gyorsindítás az `omniroute --mcp` és a kliens beépítéséhez
</details>
<details>
<summary><b>🧠 18. "A2A hangszerelésre van szükségem szinkronizálással + adatfolyam feladatútvonalak" </b></summary>
Az ügynöki munkafolyamatokhoz közvetlen válaszokra és hosszú távú, streamelt végrehajtásra van szükség életciklus-vezérléssel.
**Hogyan oldja meg az OmniRoute:**
- A2A JSON-RPC végpont (`POST /a2a`) `message/send` és `message/stream`
- SSE streaming terminál állapot terjesztéssel
- Feladat életciklus API-k `tasks/get` és `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Valódi MCP folyamatállapotra van szükségem, nem kitalált állapotra" </b></summary>
Az operatív csapatoknak tudniuk kell, hogy az MCP valóban életben van-e, nem csak azt, hogy egy API elérhető-e.
**Hogyan oldja meg az OmniRoute:**
- Futásidejű szívverés fájl PID-vel, időbélyegekkel, szállítással, szerszámszámmal és hatókör móddal
- MCP állapot API, amely kombinálja a szívverést + a legutóbbi tevékenységet
- UI állapotkártyák a folyamat/üzemidő/szívverés frissességéhez
</details>
<details>
<summary><b>📋 20. "Kivizsgálható MCP-eszköz végrehajtásra van szükségem" </b></summary>
Amikor az eszközök módosítják a konfigurációt vagy működési műveleteket indítanak el, a csapatoknak kriminalisztikai nyomon követhetőségre van szükségük.
**Hogyan oldja meg az OmniRoute:**
- SQLite-alapú audit naplózás MCP-eszközhívásokhoz
- Szűrések eszköz, siker/kudarc, API-kulcs és oldalszámozás szerint
- Irányítópult audit táblázat + statisztikai végpontok az automatizáláshoz
</details>
<details>
<summary><b>🔐 21. "Hatókörű MCP-engedélyekre van szükségem integrációnként"</b></summary>
A különböző ügyfeleknek a legkevesebb jogosultsággal kell rendelkezniük az eszközkategóriákhoz.
**Hogyan oldja meg az OmniRoute:**
- 9 szemcsés MCP hatókör az ellenőrzött szerszámhozzáféréshez
- Hatályérvényesítés és láthatóság az MCP-kezelő felületen
- Biztonságos alaphelyzet az üzemi szerszámokhoz
</details>
<details>
<summary><b>⚙️ 22. "Üzemeltetési vezérlőkre van szükségem átcsoportosítás nélkül" </b></summary>
A csapatoknak gyors futásidejű változtatásokra van szükségük incidensek vagy költségesemények során.
**Hogyan oldja meg az OmniRoute:**
- A kombinált aktiválás váltása közvetlenül az MCP műszerfaláról
- Rugalmassági profilok alkalmazása előre meghatározott házirend-csomagokból
- Állítsa vissza a megszakító állapotát ugyanarról a kezelőpanelről
</details>
<details>
<summary><b>🔄 23. "Szükségem van élő A2A feladatok életciklusának láthatóságára és törlésére"</b></summary>
Az életciklus láthatósága nélkül a feladat-incidensek nehezen osztályozhatók.
**Hogyan oldja meg az OmniRoute:**
- Feladatok listázása/szűrés állapot/készség szerint oldalszámozással
- A feladatok metaadatainak, eseményeinek és műtermékeinek részletezése
- Feladat törlési végpont és felhasználói felület művelet megerősítéssel
</details>
<details>
<summary><b>🌊 24. "Aktív adatfolyam-metrikákra van szükségem A2A terheléshez"</b></summary>
A streamelési munkafolyamatok működési betekintést igényelnek a párhuzamosság és az élő kapcsolatok terén.
**Hogyan oldja meg az OmniRoute:**
- Az A2A állapotba integrált aktív folyamszámlálók
- Utolsó feladat időbélyegzője és állapotonkénti száma
- A2A műszerfalkártyák a valós idejű műveletek figyeléséhez
</details>
<details>
<summary><b>🪪 25. "Szabványos ügynökfelderítésre van szükségem az ügyfelek számára" </b></summary>
A külső klienseknek és hangszerelőknek géppel olvasható metaadatokra van szükségük a bevezetéshez.
**Hogyan oldja meg az OmniRoute:**
- Az ügynökkártya az `/.well-known/agent.json` címen látható
- A menedzsment felületen látható képességek és készségek
- Az A2A állapot API felfedezési metaadatokat tartalmaz az automatizáláshoz
</details>
<details>
<summary><b>🧭 26. "Protokoll felfedezhetőségre van szükségem az UX termékben"</b></summary>
Ha a felhasználók nem fedezik fel a protokollfelületeket, az elfogadás és a támogatás minősége csökken.
**Hogyan oldja meg az OmniRoute:**
- Oldalsáv bejegyzések MCP és A2A számára
- Végpont oldal Protokollok lap gyorsindítással és állapottal
- Linkek az áttekintésből a dedikált felügyeleti irányítópultokhoz
</details>
<details>
<summary><b>🧪 27. "Végponttól végpontig terjedő protokoll-érvényesítésre van szükségem valós kliensekkel"</b></summary>
A próbatesztek nem elegendőek a protokoll-kompatibilitás ellenőrzéséhez a kiadás előtt.
**Hogyan oldja meg az OmniRoute:**
- E2E csomag, amely elindítja az alkalmazást, és valódi MCP SDK kliens szállítást használ
- Az A2A kliens teszteli az áramlások felfedezését, küldését, streamingjét, lekérését és megszakítását
- Az állítások keresztellenőrzése az MCP audit és az A2A feladatok API-jával szemben
</details>
<details>
<summary><b>📡 28. "Egységes megfigyelhetőségre van szükségem minden interfészen"</b></summary>
A megfigyelhetőség protokoll szerinti felosztása vakfoltokat és hosszabb MTTR-t hoz létre.
**Hogyan oldja meg az OmniRoute:**
- Egységes irányítópultok/naplók/analytics egy termékben
- Egészség + audit + kérés telemetria OpenAI, MCP és A2A rétegeken keresztül
- Működési API-k az állapothoz és az automatizáláshoz
</details>
<details>
<summary><b>💼 29. "Egy futási időre van szükségem a proxyhoz + eszközökhöz + ügynök hangszereléshez" </b></summary>
Számos külön szolgáltatás futtatása növeli a működési költségeket és a hibamódokat.
**Hogyan oldja meg az OmniRoute:**
- OpenAI-kompatibilis proxy, MCP szerver és A2A szerver egy veremben
- Megosztott hitelesítés, rugalmasság, adattárolás és megfigyelhetőség
- Konzisztens politikai modell az összes interakciós felületen
</details>
<details>
<summary><b>🚀 30. "Az ügynöki munkafolyamatokat ragasztókód szétszórása nélkül kell szállítanom" </b></summary>
A csapatok veszítenek sebességükből, amikor több ad-hoc szolgáltatást és szkriptet illesztenek össze.
**Hogyan oldja meg az OmniRoute:**
- Egységes végpont stratégia az ügyfelek és ügynökök számára
- Beépített protokollkezelő felhasználói felületek és füstellenőrzési útvonalak
- Gyártásra kész alapok (biztonság, naplózás, rugalmasság, biztonsági mentés)
</details>
### Példa forgatókönyvekre (integrált használati esetek)
**A játékkönyv: Maximalizálja a fizetett előfizetést + olcsó biztonsági mentés**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Zéró költségű kódolási verem**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 mindig bekapcsolt tartalék lánc**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**D játékkönyv: Az ügynök MCP + A2A-val működik**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Gyors kezdés
**1. Globális telepítés:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +991,26 @@ Az OmniRoute egy erőteljes beépített fordítói játszóteret tartalmaz **4 m
</details>
---
## 🧪 Értékelések (Evals)
## 🎯 Használati esetek
Az OmniRoute egy beépített értékelési keretrendszert tartalmaz az LLM-válasz minőségének tesztelésére egy aranykészlettel összehasonlítva. Az irányítópult **Analytics → Evals** menüpontjában érheti el.
### 1. eset: "Claude Pro előfizetésem van"
### Beépített arany készlet
**Probléma:** A kvóta lejár, kihasználatlanul, sebességkorlátozások erős kódolás közben
Az előre feltöltött "OmniRoute Golden Set" 10 tesztesetet tartalmaz, amelyek lefedik:
```
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)
- Üdvözlet, matematika, földrajz, kódgenerálás
- JSON formátum megfelelés, fordítás, leértékelés
- Biztonsági elutasítás (káros tartalom), számlálás, logikai logika
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Értékelési stratégiák
### 2. eset: "Nulla költséget akarok"
**Probléma:** Nem engedheti meg magának az előfizetést, megbízható mesterséges intelligencia kódolásra van szüksége
```
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
```
### 3. eset: "24 órás kódolásra van szükségem, megszakítás nélkül"
**Probléma:** Határidők, nem engedheti meg magának az állásidőt
```
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
```
### 4. eset: "INGYENES AI-t akarok az OpenClawban"
**Probléma:** AI-asszisztens szükséges az üzenetküldő alkalmazásokhoz, teljesen ingyenes
```
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...
```
| Stratégia | Leírás | Példa |
| ---------- | ------------------------------------------------------------------------------------------------- | -------------------------------- |
| `exact` | A kimenetnek pontosan meg kell egyeznie | `"4"` |
| `contains` | A kimenetnek tartalmaznia kell részkarakterláncot (a kis- és nagybetűk nem különböznek egymástól) | `"Paris"` |
| `regex` | A kimenetnek meg kell egyeznie a regex mintával | `"1.*2.*3"` |
| `custom` | Az egyéni JS függvény igaz/hamis | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Értékelések (Evals)
Az OmniRoute egy beépített értékelési keretrendszert tartalmaz az LLM-válasz minőségének tesztelésére egy aranykészlettel összehasonlítva. Az irányítópult **Analytics → Evals** menüpontjában érheti el.
### Beépített arany készlet
Az előre feltöltött "OmniRoute Golden Set" 10 tesztesetet tartalmaz, amelyek lefedik:
- Üdvözlet, matematika, földrajz, kódgenerálás
- JSON formátum megfelelés, fordítás, leértékelés
- Biztonsági elutasítás (káros tartalom), számlálás, logikai logika
### Értékelési stratégiák
| Stratégia | Leírás | Példa |
| ---------- | ------------------------------------------------------------------------------------------------- | -------------------------------- |
| `exact` | A kimenetnek pontosan meg kell egyeznie | `"4"` |
| `contains` | A kimenetnek tartalmaznia kell részkarakterláncot (a kis- és nagybetűk nem különböznek egymástól) | `"Paris"` |
| `regex` | A kimenetnek meg kell egyeznie a regex mintával | `"1.*2.*3"` |
| `custom` | Az egyéni JS függvény igaz/hamis | `(output) => output.length > 10` |
---
## 🐛 Hibaelhárítás
<details>
@@ -1132,13 +1345,13 @@ Az előre feltöltött "OmniRoute Golden Set" 10 tesztesetet tartalmaz, amelyek
- Az OmniRoute v1.0.6+ tartalmazza a tartalék érvényesítést a csevegés befejezésén keresztül
- Győződjön meg arról, hogy az alap URL tartalmazza a `/v1` utótagot
### 🔐 OAuth em Servidor Remoto (távoli OAuth beállítás)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ FONTOS az OmniRoute em VPS/Docker/servidor Remoto használatához**
### Az OAuth do Antigravity / Gemini CLI falha em servidores remotos?
### OAuth
Az **Antigravitáció** és a **Gemini CLI** usam **Google OAuth 2.0** hitelesítése. A Google exige que a `redirect_uri` nincs fluxo OAuth seja **exatamente** uma das URI-k pre-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **Futtatási idejű**: Node.js 1822 LTS (⚠️ A Node.js 24+ **nem támogatott** - A `better-sqlite3` natív binárisok nem kompatibilisek)
- **Nyelv**: TypeScript 5.9 **100% TypeScript** `src/` és `open-sse/` (v1.0.6) között
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Útiterv
## 🗺️
Az OmniRoute **210+ funkciót tervez** több fejlesztési fázisban. Íme a legfontosabb területek:
@@ -1304,18 +1517,6 @@ Az OmniRoute **210+ funkciót tervez** több fejlesztési fázisban. Íme a legf
---
## 📧 Támogatás
> 💬 **Csatlakozzon közösségünkhöz!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Kérjen segítséget, ossza meg tippjeit, és naprakész legyen.
- **Webhely**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problémák**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Eredeti projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Közreműködők
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Hubungkan alat IDE atau CLI apa pun yang didukung AI melalui OmniRoute — gerb
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Mengapa OmniRoute?
**Berhenti membuang-buang uang dan mencapai batas:**
@@ -128,6 +157,18 @@ _Hubungkan alat IDE atau CLI apa pun yang didukung AI melalui OmniRoute — gerb
---
## 📧 Dukungan
> 💬 **Bergabunglah dengan komunitas kami!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Dapatkan bantuan, berbagi kiat, dan dapatkan informasi terbaru.
- **Situs Web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Masalah**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Proyek Asli**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Cara Kerjanya
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Apa yang Dipecahkan OmniRoute — 30 Masalah Nyata & Kasus Penggunaan
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Setiap pengembang yang menggunakan alat AI menghadapi masalah ini setiap hari.** OmniRoute dibuat untuk menyelesaikan semuanya — mulai dari pembengkakan biaya hingga pemblokiran regional, mulai dari aliran OAuth yang rusak hingga operasi protokol dan kemampuan observasi perusahaan.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Saya membayar langganan yang mahal tetapi masih terganggu oleh batasan"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Pengembang membayar $20200/bulan untuk Claude Pro, Codex Pro, atau GitHub Copilot. Bahkan saat membayar, kuota memiliki batas tertinggipenggunaan 5 jam, batas mingguan, atau batas tarif per menit. Di tengah sesi pengkodean, penyedia berhenti merespons dan pengembang kehilangan aliran dan produktivitas.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Jika kuota berlangganan habis, otomatis dialihkan ke Kunci API → Murah → Gratis tanpa intervensi manual
- **Pelacakan Kuota Real-Time** — Menampilkan konsumsi token secara real-time dengan hitungan mundur reset (5 jam, harian, mingguan)
- **Dukungan Multi-Akun** — Beberapa akun per penyedia dengan sistem round-robin otomatis — jika satu akun habis, beralih ke akun berikutnya
- **Kombo Khusus** — Rantai cadangan yang dapat disesuaikan dengan 6 strategi penyeimbangan (isi terlebih dahulu, round-robin, P2C, acak, paling jarang digunakan, hemat biaya)
- **Codex Business Quotas** — Pemantauan kuota ruang kerja Bisnis/Tim langsung di dasbor
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Saya perlu menggunakan beberapa penyedia tetapi masing-masing memiliki API yang berbeda"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI menggunakan satu format, Claude (Anthropic) menggunakan format lain, Gemini menggunakan format lain. Jika pengembang ingin menguji model dari penyedia yang berbeda atau melakukan fallback di antara penyedia tersebut, mereka perlu mengonfigurasi ulang SDK, mengubah titik akhir, menangani format yang tidak kompatibel. Penyedia khusus (FriendLI, NIM) memiliki titik akhir model non-standar.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Titik Akhir Terpadu** — Satu `http://localhost:20128/v1` berfungsi sebagai proxy untuk 36+ penyedia
- **Terjemahan Format** — Otomatis dan transparan: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Sanitasi Respons** — Menghapus kolom non-standar (`x_groq`, `usage_breakdown`, `service_tier`) yang merusak OpenAI SDK v1.83+
- **Normalisasi Peran** — Mengonversi `developer``system` untuk penyedia non-OpenAI; `system``user` untuk GLM/ERNIE
- **Think Tag Extraction** — Mengekstrak blok `<think>` dari model seperti DeepSeek R1 ke dalam `reasoning_content` standar
- **Output Terstruktur untuk Gemini** — `json_schema``responseMimeType`/`responseSchema` konversi otomatis
- **`stream` defaultnya adalah `false`** — Sesuai dengan spesifikasi OpenAI, menghindari SSE yang tidak terduga di SDK Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Penyedia AI saya memblokir wilayah/negara saya"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Penyedia seperti OpenAI/Codex memblokir akses dari wilayah geografis tertentu. Pengguna mendapatkan kesalahan seperti `unsupported_country_region_territory` selama koneksi OAuth dan API. Hal ini sangat membuat frustasi bagi pengembang dari negara-negara berkembang.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Konfigurasi Proksi 3 Tingkat** — Proksi yang dapat dikonfigurasi pada 3 tingkat: global (semua lalu lintas), per penyedia (hanya satu penyedia), dan per koneksi/kunci
- **Lencana Proksi Berkode Warna** — Indikator visual: 🟢 proksi global, 🟡 proksi penyedia, 🔵 proksi koneksi, selalu menampilkan IP
- **OAuth Token Exchange Through Proxy** — Aliran OAuth juga melewati proxy, menyelesaikan `unsupported_country_region_territory`
- **Tes Koneksi melalui Proxy** — Tes koneksi menggunakan proxy yang dikonfigurasi (tidak ada lagi bypass langsung)
- **Dukungan SOCKS5** — Dukungan proksi SOCKS5 penuh untuk perutean keluar
- **TLS Fingerprint Spoofing** — Sidik jari TLS mirip browser melalui `wreq-js` untuk melewati deteksi bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Saya ingin menggunakan AI untuk coding tetapi saya tidak punya uang" </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Tidak semua orang mampu membayar $20200/bulan untuk berlangganan AI. Pelajar, pengembang dari negara-negara berkembang, penghobi, dan pekerja lepas memerlukan akses ke model berkualitas tanpa biaya.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Terintegrasi Penyedia Tingkat Gratis** — Dukungan asli untuk 100% penyedia gratis: iFlow (8 model tak terbatas), Qwen (3 model tak terbatas), Kiro (Claude gratis), Gemini CLI (gratis 180K/bulan)
- **Kombo Khusus Gratis** — Rantai `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/bulan tanpa downtime
- **Kredit Gratis NVIDIA NIM** — 1000 kredit gratis terintegrasi
- **Strategi Pengoptimalan Biaya** — Strategi perutean yang secara otomatis memilih penyedia termurah yang tersedia
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Saya perlu melindungi gateway AI saya dari akses tidak sah" </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Saat mengekspos gateway AI ke jaringan (LAN, VPS, Docker), siapa pun yang memiliki alamat tersebut dapat menggunakan token/kuota pengembang. Tanpa perlindungan, API rentan terhadap penyalahgunaan, injeksi cepat, dan penyalahgunaan.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Manajemen Kunci API** — Pembuatan, rotasi, dan pelingkupan per penyedia dengan halaman `/dashboard/api-manager` khusus
- **Izin Tingkat Model** — Membatasi kunci API untuk model tertentu (`openai/*`, pola karakter pengganti), dengan tombol Izinkan Semua/Batasi
- **API Endpoint Protection** — Memerlukan kunci untuk `/v1/models` dan memblokir penyedia tertentu dari daftar
- **Auth Guard + Perlindungan CSRF** — Semua rute dasbor dilindungi dengan middleware `withAuth` + token CSRF
- **Pembatas Kecepatan** — Pembatasan kecepatan per-IP dengan jendela yang dapat dikonfigurasi
- **Pemfilteran IP** — Daftar yang diizinkan/daftar blokir untuk kontrol akses
- **Prompt Injection Guard** — Sanitasi terhadap pola prompt berbahaya
- **Enkripsi AES-256-GCM** — Kredensial dienkripsi saat disimpan
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Penyedia saya down dan saya kehilangan alur pengkodean"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Penyedia AI bisa menjadi tidak stabil, menampilkan kesalahan 5xx, atau mencapai batas kecepatan sementara. Jika pengembang bergantung pada satu penyedia, mereka akan terganggu. Tanpa pemutus sirkuit, percobaan ulang yang berulang-ulang dapat membuat aplikasi crash.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Pemutus Sirkuit per penyedia** — Buka/tutup otomatis dengan ambang batas dan cooldown yang dapat dikonfigurasi (Tertutup/Terbuka/Setengah Terbuka)
- **Kemunduran Eksponensial** — Penundaan percobaan ulang yang progresif
- **Kawanan Anti-Guntur** — Perlindungan mutex + semaphore terhadap badai percobaan ulang secara bersamaan
- **Combo Fallback Chains** — Jika penyedia utama gagal, otomatis gagal dalam rantai tanpa intervensi
- **Combo Circuit Breaker** — Menonaktifkan secara otomatis penyedia yang gagal dalam rantai kombo
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Dasbor Kesehatan** — Pemantauan waktu aktif, status pemutus sirkuit, penguncian, statistik cache, latensi p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Mengonfigurasi setiap alat AI membosankan dan berulang-ulang"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Pengembang menggunakan Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Setiap alat memerlukan konfigurasi yang berbeda (titik akhir API, kunci, model). Mengonfigurasi ulang saat berpindah penyedia atau model hanya membuang-buang waktu.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Dasbor Alat CLI** — Halaman khusus dengan pengaturan sekali klik untuk Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Menghasilkan `chatLanguageModels.json` untuk VS Code dengan pemilihan model massal
- **Onboarding Wizard** — Panduan penyiapan 4 langkah untuk pengguna pertama kali
- **Satu titik akhir, semua model** — Konfigurasikan `http://localhost:20128/v1` satu kali, akses 36+ penyedia
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Mengelola token OAuth dari banyak penyedia adalah neraka"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — semuanya menggunakan OAuth 2.0 dengan token yang kedaluwarsa. Pengembang perlu melakukan autentikasi ulang terus-menerus, menangani `client_secret is missing`, `redirect_uri_mismatch`, dan kegagalan pada server jarak jauh. OAuth pada LAN/VPS sangat bermasalah.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Penyegaran Token Otomatis** — Penyegaran token OAuth di latar belakang sebelum masa berlakunya habis
- **OAuth 2.0 (PKCE) Bawaan** — Aliran otomatis untuk Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth Multi-Akun** — Beberapa akun per penyedia melalui ekstraksi token JWT/ID
- **OAuth LAN/Remote Fix** — Deteksi IP pribadi untuk `redirect_uri` + mode URL manual untuk server jarak jauh
- **OAuth Dibalik Nginx** — Menggunakan `window.location.origin` untuk kompatibilitas proxy terbalik
- **Panduan OAuth Jarak Jauh** — Panduan langkah demi langkah untuk kredensial Google Cloud di VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Saya tidak tahu berapa banyak yang saya belanjakan atau di mana" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Pengembang menggunakan beberapa penyedia berbayar tetapi tidak memiliki pandangan terpadu mengenai pembelanjaan. Setiap penyedia memiliki dasbor penagihannya sendiri, namun tidak ada tampilan gabungan. Biaya tak terduga bisa menumpuk.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Dasbor Analisis Biaya** — Pelacakan biaya per token dan pengelolaan anggaran per penyedia
- **Batas Anggaran per Tingkat** — Batas pembelanjaan per tingkat yang memicu penggantian otomatis
- **Konfigurasi Harga Per Model** — Harga per model yang dapat dikonfigurasi
- **Statistik Penggunaan Per Kunci API** — Jumlah permintaan dan stempel waktu terakhir digunakan per kunci
- **Dasbor Analytics** — Kartu statistik, diagram penggunaan model, tabel penyedia dengan tingkat keberhasilan dan latensi
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Saya tidak dapat mendiagnosis kesalahan dan masalah dalam panggilan AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Saat panggilan gagal, pengembang tidak mengetahui apakah itu batas kecepatan, token kedaluwarsa, format salah, atau kesalahan penyedia. Log terfragmentasi di terminal yang berbeda. Tanpa observabilitas, debugging adalah trial-and-error.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Dasbor Log Terpadu** — 4 tab: Log Permintaan, Log Proksi, Log Audit, Konsol
- **Penampil Log Konsol** — Penampil gaya terminal real-time dengan level kode warna, gulir otomatis, pencarian, filter
- **Log Proxy SQLite** — Log persisten yang bertahan saat server dimulai ulang
- **Translator Playground** — 4 mode debugging: Playground (terjemahan format), Chat Tester (pulang pergi), Test Bench (batch), Live Monitor (real-time)
- **Telemetri Permintaan** — latensi p50/p95/p99 + penelusuran X-Request-Id
- **Logging Berbasis File dengan Rotasi** — Pencegat konsol menangkap semuanya ke log JSON dengan rotasi berbasis ukuran
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Menyebarkan dan memelihara gateway itu rumit"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Menginstal, mengonfigurasi, dan memelihara proksi AI di berbagai lingkungan (lokal, VPS, Docker, cloud) membutuhkan banyak tenaga. Masalah seperti jalur hardcode, `EACCES` pada direktori, konflik port, dan pembangunan lintas platform menambah gesekan.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **instal global npm** — `npm install -g omniroute && omniroute`selesai
- **Docker Multi-Platform** — asli AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (tanpa alat CLI) dan `cli` (dengan Claude Code, Codex, OpenClaw)
- **Aplikasi Desktop Electron** — Aplikasi asli untuk Windows/macOS/Linux dengan baki sistem, mulai otomatis, mode offline
- **Mode Port Terpisah** — API dan Dasbor pada port terpisah untuk skenario tingkat lanjut (proksi terbalik, jaringan kontainer)
- **Cloud Sync** — Konfigurasi sinkronisasi antar perangkat melalui Cloudflare Workers
- **DB Backups** — Pencadangan otomatis, pemulihan, ekspor dan impor semua pengaturan
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Antarmuka hanya berbahasa Inggris dan tim saya tidak bisa berbahasa Inggris"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Tim di negara-negara yang tidak berbahasa Inggris, khususnya di Amerika Latin, Asia, dan Eropa, kesulitan dengan antarmuka yang hanya berbahasa Inggris. Hambatan bahasa mengurangi adopsi dan meningkatkan kesalahan konfigurasi.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dasbor i18n — 30 Bahasa** — 500+ tombol diterjemahkan termasuk Arab, Bulgaria, Denmark, Jerman, Spanyol, Finlandia, Prancis, Ibrani, Hindi, Hungaria, Indonesia, Italia, Jepang, Korea, Melayu, Belanda, Norwegia, Polandia, Portugis (PT/BR), Rumania, Rusia, Slovakia, Swedia, Thailand, Ukraina, Vietnam, China, Filipina, Inggris
- **Dukungan RTL** — Dukungan kanan ke kiri untuk bahasa Arab dan Ibrani
- **README Multi-Bahasa** — 30 terjemahan dokumentasi lengkap
- **Pemilih Bahasa** — Ikon bola dunia di header untuk peralihan waktu nyata
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Saya memerlukan lebih dari sekadar obrolan — saya memerlukan penyematan, gambar, audio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI bukan hanya penyelesaian obrolan. Pengembang perlu membuat gambar, mentranskripsikan audio, membuat penyematan untuk RAG, mengubah peringkat dokumen, dan memoderasi konten. Setiap API memiliki titik akhir dan format yang berbeda.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Sematan** — `/v1/embeddings` dengan 6 penyedia dan 9+ model
- **Image Generation** — `/v1/images/generations` dengan 10 penyedia dan 20+ model (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Teks-ke-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) dan SD WebUI
- **Teks-ke-Musik** — `/v1/music/generations` — ComfyUI (Audio Terbuka Stabil, MusicGen)
- **Transkripsi Audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + penyedia yang ada
- **Moderasi** — `/v1/moderations` — Pemeriksaan keamanan konten
- **Pemeringkatan ulang** — `/v1/rerank` — Pemeringkatan ulang relevansi dokumen
- **Respon API** — Dukungan penuh `/v1/responses` untuk Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Saya tidak punya cara untuk menguji dan membandingkan kualitas antar model"</b></summary>
Developers want to know which model is best for their use casecode, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Pengembang ingin mengetahui model mana yang terbaik untuk kasus penggunaan merekakode, terjemahan, penalaran — tetapi membandingkan secara manual itu lambat. Tidak ada alat evaluasi terintegrasi.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Evaluasi LLM** — Pengujian set emas dengan 10 kasus yang dimuat sebelumnya yang mencakup salam, matematika, geografi, pembuatan kode, kepatuhan JSON, terjemahan, penurunan harga, penolakan keamanan
- **4 Strategi Pertandingan** — `exact`, `contains`, `regex`, `custom` (fungsi JS)
- **Bangku Tes Taman Bermain Penerjemah** — Pengujian batch dengan banyak masukan dan keluaran yang diharapkan, perbandingan lintas penyedia
- **Penguji Obrolan** — Perjalanan bolak-balik penuh dengan rendering respons visual
- **Monitor Langsung** — Aliran real-time dari semua permintaan yang mengalir melalui proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Saya perlu melakukan penskalaan tanpa kehilangan performa"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Seiring bertambahnya volume permintaan, tanpa menyimpan pertanyaan yang sama akan menghasilkan biaya duplikat. Tanpa idempotensi, permintaan duplikat akan membuang-buang pemrosesan. Batasan tarif per penyedia harus dipatuhi.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache Semantik** — Cache dua tingkat (tanda tangan + semantik) mengurangi biaya dan latensi
- **Request Idempoency** — Jendela deduplikasi 5 detik untuk permintaan yang identik
- **Deteksi Batas Tarif** — RPM per penyedia, selisih minimum, dan pelacakan serentak maks
- **Batas Nilai yang Dapat Diedit** — Default yang dapat dikonfigurasi di Pengaturan → Ketahanan dengan persistensi
- **Cache Validasi Kunci API** — cache 3 tingkat untuk kinerja produksi
- **Dasbor Kesehatan dengan Telemetri** — latensi p50/p95/p99, statistik cache, waktu aktif
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Saya ingin mengontrol perilaku model secara global"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Pengembang yang menginginkan semua respons dalam bahasa tertentu, dengan nada tertentu, atau ingin membatasi token penalaran. Mengonfigurasi ini di setiap alat/permintaan tidak praktis.
**How OmniRoute solves it:**
**Bagaimana OmniRoute menyelesaikannya:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Injeksi Perintah Sistem** — Perintah global diterapkan ke semua permintaan
- **Validasi Anggaran Berpikir** — Kontrol alokasi token penalaran per permintaan (passthrough, otomatis, kustom, adaptif)
- **6 Strategi Perutean** — Strategi global yang menentukan cara permintaan didistribusikan
- **Wildcard Router** — Pola `provider/*` dirutekan secara dinamis ke penyedia mana pun
- **Combo Aktifkan/Nonaktifkan Toggle** — Beralih kombo langsung dari dasbor
- **Toggle Penyedia** — Mengaktifkan/menonaktifkan semua koneksi untuk penyedia dengan satu klik
- **Penyedia yang Diblokir** — Kecualikan penyedia tertentu dari daftar `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Saya membutuhkan alat MCP sebagai kemampuan produk kelas satu" </b></summary>
Banyak gateway AI yang mengekspos MCP hanya sebagai detail implementasi yang tersembunyi. Tim memerlukan lapisan operasi yang terlihat dan dapat dikelola.
**Bagaimana OmniRoute menyelesaikannya:**
- MCP muncul di navigasi dasbor dan tab protokol titik akhir
- Halaman manajemen MCP khusus dengan proses, alat, cakupan, dan audit
- Mulai cepat bawaan untuk `omniroute --mcp` dan orientasi klien
</details>
<details>
<summary><b>🧠 18. "Saya memerlukan orkestrasi A2A dengan jalur tugas sinkronisasi + streaming"</b></summary>
Alur kerja agen memerlukan balasan langsung dan eksekusi streaming jangka panjang dengan kontrol siklus hidup.
**Bagaimana OmniRoute menyelesaikannya:**
- Titik akhir A2A JSON-RPC (`POST /a2a`) dengan `message/send` dan `message/stream`
- Streaming SSE dengan propagasi status terminal
- API siklus hidup tugas untuk `tasks/get` dan `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Saya membutuhkan kesehatan proses MCP yang nyata, bukan status yang dapat ditebak" </b></summary>
Tim operasional perlu mengetahui apakah MCP benar-benar aktif, bukan hanya apakah API dapat dijangkau.
**Bagaimana OmniRoute menyelesaikannya:**
- File detak jantung runtime dengan PID, stempel waktu, transportasi, jumlah alat, dan mode cakupan
- API status MCP menggabungkan detak jantung + aktivitas terkini
- Kartu status UI untuk kesegaran proses/waktu aktif/detak jantung
</details>
<details>
<summary><b>📋 20. "Saya memerlukan eksekusi alat MCP yang dapat diaudit"</b></summary>
Saat alat mengubah konfigurasi atau memicu tindakan operasi, tim memerlukan kemampuan penelusuran forensik.
**Bagaimana OmniRoute menyelesaikannya:**
- Pencatatan audit yang didukung SQLite untuk panggilan alat MCP
- Filter berdasarkan alat, keberhasilan/kegagalan, kunci API, dan penomoran halaman
- Tabel audit dasbor + titik akhir statistik untuk otomatisasi
</details>
<details>
<summary><b>🔐 21. "Saya memerlukan izin MCP terbatas per integrasi"</b></summary>
Klien yang berbeda harus memiliki akses dengan hak istimewa paling rendah ke kategori alat.
**Bagaimana OmniRoute menyelesaikannya:**
- 9 cakupan MCP granular untuk akses alat terkontrol
- Penegakan cakupan dan visibilitas di UI manajemen MCP
- Postur default yang aman untuk perkakas operasional
</details>
<details>
<summary><b>⚙️ 22. "Saya memerlukan kontrol operasional tanpa memindahkan" </b></summary>
Tim memerlukan perubahan runtime yang cepat selama insiden atau peristiwa biaya.
**Bagaimana OmniRoute menyelesaikannya:**
- Beralih aktivasi kombo langsung dari dasbor MCP
- Menerapkan profil ketahanan dari paket kebijakan yang telah ditentukan sebelumnya
- Reset status pemutus sirkuit dari panel operasi yang sama
</details>
<details>
<summary><b>🔄 23. "Saya memerlukan visibilitas dan pembatalan siklus hidup tugas A2A langsung" </b></summary>
Tanpa visibilitas siklus hidup, insiden tugas menjadi sulit untuk diprioritaskan.
**Bagaimana OmniRoute menyelesaikannya:**
- Daftar tugas/pemfilteran berdasarkan status/keterampilan dengan penomoran halaman
- Telusuri metadata tugas, peristiwa, dan artefak
- Titik akhir pembatalan tugas dan tindakan UI dengan konfirmasi
</details>
<details>
<summary><b>🌊 24. "Saya memerlukan metrik streaming aktif untuk memuat A2A"</b></summary>
Alur kerja streaming memerlukan wawasan operasional tentang konkurensi dan koneksi langsung.
**Bagaimana OmniRoute menyelesaikannya:**
- Penghitung aliran aktif terintegrasi ke dalam status A2A
- Stempel waktu tugas terakhir dan jumlah per negara bagian
- Kartu dasbor A2A untuk pemantauan operasi waktu nyata
</details>
<details>
<summary><b>🪪 25. "Saya memerlukan penemuan agen standar untuk klien"</b></summary>
Klien dan orkestra eksternal memerlukan metadata yang dapat dibaca mesin untuk orientasi.
**Bagaimana OmniRoute menyelesaikannya:**
- Kartu Agen terekspos di `/.well-known/agent.json`
- Kemampuan dan keterampilan yang ditunjukkan dalam manajemen UI
- API status A2A mencakup metadata penemuan untuk otomatisasi
</details>
<details>
<summary><b>🧭 26. "Saya memerlukan kemampuan protokol untuk ditemukan di UX produk" </b></summary>
Jika pengguna tidak dapat menemukan permukaan protokol, kualitas adopsi dan dukungan akan menurun.
**Bagaimana OmniRoute menyelesaikannya:**
- Entri sidebar untuk MCP dan A2A
- Tab Protokol halaman titik akhir dengan mulai cepat dan status
- Tautan dari ikhtisar ke dasbor manajemen khusus
</details>
<details>
<summary><b>🧪 27. "Saya memerlukan validasi protokol end-to-end dengan klien nyata"</b></summary>
Tes tiruan tidak cukup untuk memvalidasi kompatibilitas protokol sebelum rilis.
**Bagaimana OmniRoute menyelesaikannya:**
- Suite E2E yang mem-boot aplikasi dan menggunakan transportasi klien MCP SDK yang sebenarnya
- Klien A2A menguji penemuan, pengiriman, streaming, dapatkan, dan pembatalan aliran
- Periksa silang pernyataan terhadap audit MCP dan API tugas A2A
</details>
<details>
<summary><b>📡 28. "Saya memerlukan kemampuan pengamatan terpadu di semua antarmuka"</b></summary>
Memisahkan observabilitas berdasarkan protokol menciptakan titik buta dan MTTR yang lebih panjang.
**Bagaimana OmniRoute menyelesaikannya:**
- Dasbor/log/analitik terpadu dalam satu produk
- Kesehatan + audit + permintaan telemetri di seluruh lapisan OpenAI, MCP, dan A2A
- API Operasional untuk status dan otomatisasi
</details>
<details>
<summary><b>💼 29. "Saya memerlukan satu runtime untuk proxy + alat + orkestrasi agen" </b></summary>
Menjalankan banyak layanan terpisah akan meningkatkan biaya operasional dan mode kegagalan.
**Bagaimana OmniRoute menyelesaikannya:**
- Proksi yang kompatibel dengan OpenAI, server MCP, dan server A2A dalam satu tumpukan
- Otentikasi bersama, ketahanan, penyimpanan data, dan kemampuan observasi
- Model kebijakan yang konsisten di seluruh platform interaksi
</details>
<details>
<summary><b>🚀 30. "Saya perlu mengirimkan alur kerja agen tanpa gepeng kode lem"</b></summary>
Tim kehilangan kecepatan saat menggabungkan beberapa layanan dan skrip ad-hoc.
**Bagaimana OmniRoute menyelesaikannya:**
- Strategi titik akhir terpadu untuk klien dan agen
- UI manajemen protokol bawaan dan jalur validasi asap
- Fondasi siap produksi (keamanan, logging, ketahanan, cadangan)
</details>
### Contoh Playbook (Kasus Penggunaan Terintegrasi)
**Playbook A: Maksimalkan langganan berbayar + cadangan murah**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Tumpukan coding tanpa biaya**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: Rantai fallback yang selalu aktif 24/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Operasi agen dengan MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Mulai Cepat
**1. Instal secara global:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +991,26 @@ OmniRoute menyertakan Taman Bermain Penerjemah bawaan yang canggih dengan **4 mo
</details>
---
## 🧪 Evaluasi (Eval)
## 🎯 Kasus Penggunaan
OmniRoute menyertakan kerangka evaluasi bawaan untuk menguji kualitas respons LLM terhadap rangkaian emas. Akses melalui **Analytics → Evals** di dasbor.
### Kasus 1: "Saya berlangganan Claude Pro"
### Set Emas Bawaan
**Masalah:** Kuota habis tanpa terpakai, batas kecepatan selama coding berat
"OmniRoute Golden Set" yang dimuat sebelumnya berisi 10 kasus uji yang meliputi:
```
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)
- Salam, matematika, geografi, pembuatan kode
- Kepatuhan format JSON, terjemahan, penurunan harga
- Penolakan keamanan (konten berbahaya), penghitungan, logika boolean
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Strategi Evaluasi
### Kasus 2: "Saya ingin tanpa biaya"
**Masalah:** Tidak mampu berlangganan, memerlukan pengkodean AI yang andal
```
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
```
### Kasus 3: "Saya memerlukan pengkodean 24/7, tanpa gangguan"
**Masalah:** Tenggat waktu, tidak mampu membayar 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
```
### Kasus 4: "Saya ingin AI GRATIS di OpenClaw"
**Masalah:** Membutuhkan asisten AI dalam aplikasi perpesanan, sepenuhnya gratis
```
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...
```
| Strategi | Deskripsi | Contoh |
| ---------- | ------------------------------------------------------------ | -------------------------------- |
| `exact` | Output harus sama persis | `"4"` |
| `contains` | Output harus berisi substring (tidak peka huruf besar-kecil) | `"Paris"` |
| `regex` | Output harus sesuai dengan pola regex | `"1.*2.*3"` |
| `custom` | Fungsi JS khusus mengembalikan benar/salah | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Evaluasi (Eval)
OmniRoute menyertakan kerangka evaluasi bawaan untuk menguji kualitas respons LLM terhadap rangkaian emas. Akses melalui **Analytics → Evals** di dasbor.
### Set Emas Bawaan
"OmniRoute Golden Set" yang dimuat sebelumnya berisi 10 kasus uji yang meliputi:
- Salam, matematika, geografi, pembuatan kode
- Kepatuhan format JSON, terjemahan, penurunan harga
- Penolakan keamanan (konten berbahaya), penghitungan, logika boolean
### Strategi Evaluasi
| Strategi | Deskripsi | Contoh |
| ---------- | ------------------------------------------------------------ | -------------------------------- |
| `exact` | Output harus sama persis | `"4"` |
| `contains` | Output harus berisi substring (tidak peka huruf besar-kecil) | `"Paris"` |
| `regex` | Output harus sesuai dengan pola regex | `"1.*2.*3"` |
| `custom` | Fungsi JS khusus mengembalikan benar/salah | `(output) => output.length > 10` |
---
## 🐛 Pemecahan masalah
<details>
@@ -1132,13 +1345,13 @@ OmniRoute menyertakan kerangka evaluasi bawaan untuk menguji kualitas respons LL
- OmniRoute v1.0.6+ menyertakan validasi fallback melalui penyelesaian obrolan
- Pastikan URL dasar menyertakan akhiran `/v1`
### 🔐 OAuth em Servidor Remoto (Pengaturan OAuth Jarak Jauh)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ PENTING bagi pengguna dengan OmniRoute pada VPS/Docker/server jarak jauh**
### Mengapa OAuth melakukan Antigravity / Gemini CLI gagal dalam layanan jarak jauh?
### OAuth
Pembuktiannya **Antigravitasi** dan **Gemini CLI** digunakan **Google OAuth 2.0** untuk autentikasi. Google meminta agar `redirect_uri` menggunakan OAuth yang terus berubah, jadi **exatamente** adalah URI yang sudah ada sebelumnya di Google Cloud Console yang dapat diterapkan.
@@ -1227,7 +1440,7 @@ Jika Anda tidak ingin membuat kredensial pribadi sekarang, Anda mungkin dapat me
---
## 🛠️ Tumpukan Teknologi
## 🛠️
- **Runtime**: Node.js 1822 LTS (⚠️ Node.js 24+ **tidak didukung**`better-sqlite3` biner asli tidak kompatibel)
- **Bahasa**: TypeScript 5.9 — **100% TypeScript** di `src/` dan `open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Jika Anda tidak ingin membuat kredensial pribadi sekarang, Anda mungkin dapat me
---
## 🗺️ Peta Jalan
## 🗺️
OmniRoute memiliki **210+ fitur yang direncanakan** di berbagai fase pengembangan. Berikut adalah bidang-bidang utamanya:
@@ -1304,18 +1517,6 @@ OmniRoute memiliki **210+ fitur yang direncanakan** di berbagai fase pengembanga
---
## 📧 Dukungan
> 💬 **Bergabunglah dengan komunitas kami!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Dapatkan bantuan, berbagi kiat, dan dapatkan informasi terbaru.
- **Situs Web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Masalah**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Proyek Asli**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Kontributor
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

File diff suppressed because it is too large Load Diff

View File

@@ -110,6 +110,35 @@ _Connetti qualsiasi IDE o strumento CLI con IA tramite OmniRoute — gateway API
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Perché OmniRoute?
**Smetti di sprecare soldi e di sbattere contro i limiti:**
@@ -128,6 +157,19 @@ _Connetti qualsiasi IDE o strumento CLI con IA tramite OmniRoute — gateway API
---
## 📧 Supporto
> 💬 **Unisciti alla nostra community!** [Gruppo WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Ottieni aiuto, condividi consigli e rimani aggiornato.
- **Sito 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**: [Gruppo della comunità](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **WhatsApp**: [Gruppo della comunità](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Progetto Originale**: [9router di decolua](https://github.com/decolua/9router)
---
## 🔄 Come Funziona
```
@@ -157,263 +199,497 @@ Risultato: Non smettere mai di programmare, costo minimo
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Cosa risolve OmniRoute: 30 punti critici reali e casi d'uso
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Ogni sviluppatore che utilizza strumenti di intelligenza artificiale affronta questi problemi quotidianamente.** OmniRoute è stato creato per risolverli tutti: dai superamenti dei costi ai blocchi regionali, dai flussi OAuth interrotti alle operazioni di protocollo e all'osservabilità aziendale.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Pago un abbonamento costoso ma vengo comunque interrotto dai limiti"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Gli sviluppatori pagano $ 20-200 al mese per Claude Pro, Codex Pro o GitHub Copilot. Anche pagando, la quota ha un tetto: 5 ore di utilizzo, limiti settimanali o limiti di tariffa al minuto. A metà sessione di codifica, il provider smette di rispondere e lo sviluppatore perde flusso e produttività.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Fallback intelligente a 4 livelli**: se la quota dell'abbonamento si esaurisce, reindirizza automaticamente alla chiave API → Economico → Gratuito senza alcun intervento manuale
- **Monitoraggio delle quote in tempo reale**: mostra il consumo di token in tempo reale con il conto alla rovescia ripristinato (5 ore, giornaliero, settimanale)
- **Supporto multi-account**: più account per fornitore con round robin automatico: quando uno si esaurisce, passa a quello successivo
- **Combo personalizzate** — Catene di fallback personalizzabili con 6 strategie di bilanciamento (fill-first, round-robin, P2C, casuale, meno utilizzato, ottimizzato in termini di costi)
- **Quote aziendali Codex**: monitoraggio delle quote dello spazio di lavoro aziendale/team direttamente nella dashboard
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Devo utilizzare più provider ma ognuno ha un'API diversa"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI utilizza un formato, Claude (Anthropic) ne utilizza un altro, Gemini ancora un altro. Se uno sviluppatore desidera testare modelli di fornitori diversi o eseguire il fallback tra di loro, deve riconfigurare gli SDK, modificare gli endpoint e gestire formati incompatibili. I provider personalizzati (FriendLI, NIM) hanno endpoint del modello non standard.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Endpoint unificato**: un singolo `http://localhost:20128/v1` funge da proxy per tutti gli oltre 36 provider
- **Traduzione del formato** — Automatica e trasparente: OpenAI ↔ Claude ↔ Gemini ↔ API di risposta
- **Sanitizzazione della risposta**: rimuove i campi non standard (`x_groq`, `usage_breakdown`, `service_tier`) che interrompono OpenAI SDK v1.83+
- **Normalizzazione del ruolo**: converte `developer``system` per provider non OpenAI; `system``user` per GLM/ERNIE
- **Think Tag Extraction** — Estrae i blocchi `<think>` da modelli come DeepSeek R1 in `reasoning_content` standardizzati
- **Uscita strutturata per Gemini** — `json_schema``responseMimeType`/`responseSchema` conversione automatica
- **`stream` per impostazione predefinita è `false`** — Si allinea con le specifiche OpenAI, evitando SSE imprevisti negli SDK Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Il mio fornitore di intelligenza artificiale blocca la mia regione/paese"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Provider come OpenAI/Codex bloccano l'accesso da determinate regioni geografiche. Gli utenti ricevono errori come `unsupported_country_region_territory` durante le connessioni OAuth e API. Ciò è particolarmente frustrante per gli sviluppatori dei paesi in via di sviluppo.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Configurazione proxy a 3 livelli**: proxy configurabile a 3 livelli: globale (tutto il traffico), per provider (un solo provider) e per connessione/chiave
- **Badge proxy con codice colore** — Indicatori visivi: 🟢 proxy globale, 🟡 proxy provider, 🔵 proxy di connessione, che mostra sempre l'IP
- **Scambio di token OAuth tramite proxy**: anche il flusso OAuth passa attraverso il proxy, risolvendo `unsupported_country_region_territory`
- **Test di connessione tramite proxy**: i test di connessione utilizzano il proxy configurato (non più bypass diretto)
- **Supporto SOCKS5**: supporto completo del proxy SOCKS5 per il routing in uscita
- **Spoofing dell'impronta digitale TLS**: impronta digitale TLS simile a un browser tramite `wreq-js` per bypassare il rilevamento dei bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Voglio usare l'intelligenza artificiale per programmare ma non ho soldi"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Non tutti possono pagare $ 20-200 al mese per gli abbonamenti AI. Studenti, sviluppatori provenienti da paesi emergenti, hobbisti e liberi professionisti hanno bisogno di accedere a modelli di qualità a costo zero.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Fornitori del livello gratuito integrati**: supporto nativo per fornitori gratuiti al 100%: iFlow (8 modelli illimitati), Qwen (3 modelli illimitati), Kiro (Claude gratis), Gemini CLI (180.000/mese gratuiti)
- **Combo solo gratuiti** — Catena `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $ 0/mese senza tempi di inattività
- **Crediti gratuiti NVIDIA NIM**: 1000 crediti gratuiti integrati
- **Strategia di ottimizzazione dei costi**: strategia di routing che sceglie automaticamente il fornitore più economico disponibile
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Devo proteggere il mio gateway AI da accessi non autorizzati"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Quando si espone un gateway AI alla rete (LAN, VPS, Docker), chiunque abbia l'indirizzo può consumare i token/la quota dello sviluppatore. Senza protezione, le API sono vulnerabili ad usi impropri, tempestive iniezioni e abusi.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Gestione delle chiavi API**: generazione, rotazione e ambito per provider con una pagina `/dashboard/api-manager` dedicata
- **Autorizzazioni a livello di modello**: limita le chiavi API a modelli specifici (`openai/*`, modelli con caratteri jolly), con l'interruttore Consenti tutto/Limita
- **API Endpoint Protection**: richiede una chiave per `/v1/models` e blocca provider specifici dall'elenco
- **Auth Guard + Protezione CSRF**: tutti i percorsi del dashboard protetti con middleware `withAuth` + token CSRF
- **Rate Limiter**: limitazione della velocità per IP con finestre configurabili
- **Filtro IP**: lista consentita/lista bloccata per il controllo degli accessi
- **Prompt Injection Guard**: sanificazione contro modelli di prompt dannosi
- **Crittografia AES-256-GCM**: credenziali crittografate a riposo
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Il mio provider è andato in tilt e ho perso il flusso di codifica"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
I fornitori di intelligenza artificiale possono diventare instabili, restituire errori 5xx o raggiungere limiti di velocità temporanei. Se uno sviluppatore dipende da un singolo fornitore, viene interrotto. Senza interruttori automatici, tentativi ripetuti possono bloccare l'applicazione.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Interruttore automatico per provider**: apertura/chiusura automatica con soglie e raffreddamento configurabili (chiuso/aperto/semiaperto)
- **Backoff esponenziale**: ritardi progressivi tra i tentativi
- **Anti-Thundering Herd** — Mutex + protezione semaforo contro tempeste di tentativi simultanei
- **Catene di fallback combinate**: se il fornitore primario fallisce, cade automaticamente nella catena senza alcun intervento
- **Combo Circuit Breaker**: disabilita automaticamente i provider in errore all'interno di una catena combinata
- **Dashboard integrità**: monitoraggio del tempo di attività, stati degli interruttori automatici, blocchi, statistiche della cache, latenza p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Configurare ogni strumento AI è noioso e ripetitivo"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Gli sviluppatori utilizzano Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Ogni strumento necessita di una configurazione diversa (endpoint API, chiave, modello). La riconfigurazione quando si cambia fornitore o modello è una perdita di tempo.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Dashboard degli strumenti CLI**: pagina dedicata con configurazione con un clic per Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator**: genera `chatLanguageModels.json` per VS Code con selezione di modelli in blocco
- **Procedura guidata di onboarding**: configurazione guidata in 4 passaggi per gli utenti alle prime armi
- **Un endpoint, tutti i modelli**: configura `http://localhost:20128/v1` una volta, accedi a oltre 36 provider
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Gestire token OAuth da più provider è un inferno"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot: utilizzano tutti OAuth 2.0 con token in scadenza. Gli sviluppatori devono autenticarsi nuovamente costantemente, gestire `client_secret is missing`, `redirect_uri_mismatch` e errori sui server remoti. OAuth su LAN/VPS è particolarmente problematico.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Aggiornamento automatico dei token**: i token OAuth si aggiornano in background prima della scadenza
- **OAuth 2.0 (PKCE) integrato**: flusso automatico per Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth multi-account**: account multipli per provider tramite estrazione di token JWT/ID
- **OAuth LAN/Correzione remota**: rilevamento IP privato per `redirect_uri` + modalità URL manuale per server remoti
- **OAuth Behind Nginx**: utilizza `window.location.origin` per la compatibilità con proxy inverso
- **Guida OAuth remota**: guida passo passo per le credenziali Google Cloud su VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Non so quanto sto spendendo né dove"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Gli sviluppatori utilizzano più fornitori a pagamento ma non hanno una visione unificata della spesa. Ogni fornitore ha il proprio dashboard di fatturazione, ma non esiste una visualizzazione consolidata. I costi imprevisti possono accumularsi.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Dashboard di analisi dei costi**: monitoraggio dei costi per token e gestione del budget per fornitore
- **Limiti di budget per livello**: massimale di spesa per livello che attiva il fallback automatico
- **Configurazione dei prezzi per modello**: prezzi configurabili per modello
- **Statistiche di utilizzo per chiave API**: conteggio delle richieste e timestamp dell'ultimo utilizzo per chiave
- **Dashboard di analisi**: schede statistiche, grafico di utilizzo del modello, tabella dei fornitori con percentuali di successo e latenza
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Non riesco a diagnosticare errori e problemi nelle chiamate AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Quando una chiamata fallisce, lo sviluppatore non sa se si trattava di un limite di velocità, di un token scaduto, di un formato errato o di un errore del provider. Registri frammentati su diversi terminali. Senza osservabilità, il debug è un processo per tentativi ed errori.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Dashboard dei registri unificati**: 4 schede: registri delle richieste, registri del proxy, registri di controllo, console
- **Visualizzatore log della console**: visualizzatore in stile terminale in tempo reale con livelli codificati a colori, scorrimento automatico, ricerca, filtro
- **Registri proxy SQLite**: registri persistenti che sopravvivono ai riavvii del server
- **Translator Playground** — 4 modalità di debug: Playground (traduzione del formato), Chat Tester (andata e ritorno), Test Bench (batch), Live Monitor (in tempo reale)
- **Telemetria richiesta**: latenza p50/p95/p99 + traccia X-Request-Id
- **Registrazione basata su file con rotazione**: l'interceptor della console acquisisce tutto nel registro JSON con rotazione basata sulle dimensioni
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "L'implementazione e la manutenzione del gateway sono complesse"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
L'installazione, la configurazione e la manutenzione di un proxy AI in diversi ambienti (locale, VPS, Docker, cloud) richiedono molto lavoro. Problemi come percorsi codificati, `EACCES` nelle directory, conflitti di porte e build multipiattaforma aggiungono attrito.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Installazione globale npm** — `npm install -g omniroute && omniroute`completata
- **Docker multipiattaforma** — AMD64 + ARM64 nativo (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (senza strumenti CLI) e `cli` (con Claude Code, Codex, OpenClaw)
- **App desktop Electron**: app nativa per Windows/macOS/Linux con barra delle applicazioni, avvio automatico, modalità offline
- **Modalità porta divisa**: API e dashboard su porte separate per scenari avanzati (proxy inverso, rete di contenitori)
- **Cloud Sync**: configura la sincronizzazione tra dispositivi tramite Cloudflare Workers
- **Backup DB**: backup, ripristino, esportazione e importazione automatici di tutte le impostazioni
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "L'interfaccia è solo inglese e il mio team non parla inglese"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
I team nei paesi non anglofoni, soprattutto in America Latina, Asia ed Europa, hanno difficoltà con le interfacce solo in inglese. Le barriere linguistiche riducono l'adozione e aumentano gli errori di configurazione.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 lingue** — Tutti gli oltre 500 tasti tradotti tra cui arabo, bulgaro, danese, tedesco, spagnolo, finlandese, francese, ebraico, hindi, ungherese, indonesiano, italiano, giapponese, coreano, malese, olandese, norvegese, polacco, portoghese (PT/BR), rumeno, russo, slovacco, svedese, tailandese, ucraino, vietnamita, cinese, filippino, inglese
- **Supporto RTL**: supporto da destra a sinistra per arabo ed ebraico
- **README multilingue**: 30 traduzioni complete di documentazione
- **Selettore lingua**: icona del globo nell'intestazione per la commutazione in tempo reale
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Ho bisogno di qualcosa di più della semplice chat: ho bisogno di incorporamenti, immagini, audio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
L'intelligenza artificiale non è solo il completamento della chat. Gli sviluppatori devono generare immagini, trascrivere audio, creare incorporamenti per RAG, riclassificare i documenti e moderare i contenuti. Ogni API ha un endpoint e un formato diversi.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Incorporamenti** — `/v1/embeddings` con 6 fornitori e oltre 9 modelli
- **Generazione di immagini** — `/v1/images/generations` con 10 provider e oltre 20 modelli (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Da testo a video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) e SD WebUI
- **Trasformazione testo in musica** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Trascrizione audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Sintesi vocale** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + fornitori esistenti
- **Moderazioni** — `/v1/moderations` — Controlli di sicurezza dei contenuti
- **Riclassificazione** — `/v1/rerank`: riclassificazione della pertinenza del documento
- **API di risposta**: supporto `/v1/responses` completo per Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Non ho modo di testare e confrontare la qualità tra i modelli"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Gli sviluppatori vogliono sapere quale modello è il migliore per il loro caso d'uso (codice, traduzione, ragionamento), ma il confronto manuale è lento. Non esistono strumenti di valutazione integrati.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Valutazioni LLM**: test Golden Set con 10 casi precaricati che coprono saluti, matematica, geografia, generazione di codice, conformità JSON, traduzione, ribasso, rifiuto di sicurezza
- **4 strategie di corrispondenza** — `exact`, `contains`, `regex`, `custom` (funzione JS)
- **Translator Playground Test Bench**: test in batch con input multipli e output previsti, confronto tra provider
- **Chat Tester**: andata e ritorno completo con rendering della risposta visiva
- **Live Monitor**: flusso in tempo reale di tutte le richieste che passano attraverso il proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Ho bisogno di scalare senza perdere prestazioni"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Man mano che il volume delle richieste cresce, senza la memorizzazione nella cache le stesse domande generano costi duplicati. Senza idempotenza, le richieste duplicate sprecano elaborazione. I limiti tariffari per fornitore devono essere rispettati.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache semantica**: la cache a due livelli (firma + semantica) riduce costi e latenza
- **Idempotenza richiesta**: finestra di deduplicazione di 5 secondi per richieste identiche
- **Rilevamento del limite di velocità**: RPM per provider, gap minimo e monitoraggio simultaneo massimo
- **Limiti di velocità modificabili**: impostazioni predefinite configurabili in Impostazioni → Resilienza con persistenza
- **Cache di convalida della chiave API**: cache a 3 livelli per prestazioni di produzione
- **Dashboard integrità con telemetria**: latenza p50/p95/p99, statistiche cache, tempo di attività
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Voglio controllare il comportamento del modello a livello globale"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Sviluppatori che desiderano tutte le risposte in una lingua specifica, con un tono specifico o che desiderano limitare i token di ragionamento. Configurarlo in ogni strumento/richiesta non è pratico.
**How OmniRoute solves it:**
**Come OmniRoute risolve il problema:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Inserimento prompt di sistema**: prompt globale applicato a tutte le richieste
- **Thinking Budget Validation**: controllo dell'allocazione dei token tramite ragionamento per richiesta (passthrough, automatico, personalizzato, adattivo)
- **6 Strategie di routing**: strategie globali che determinano la modalità di distribuzione delle richieste
- **Wildcard Router**: i modelli `provider/*` instradano dinamicamente a qualsiasi provider
- **Abilita/Disabilita combo**: attiva/disattiva le combo direttamente dalla dashboard
- **Attiva/disattiva provider**: attiva/disattiva tutte le connessioni per un provider con un clic
- **Fornitori bloccati**: esclude fornitori specifici dall'elenco `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Ho bisogno degli strumenti MCP come funzionalità di prodotto di prima classe"</b></summary>
Molti gateway AI espongono MCP solo come dettaglio di implementazione nascosto. I team hanno bisogno di un livello operativo visibile e gestibile.
**Come OmniRoute risolve il problema:**
- MCP viene visualizzato nella navigazione del dashboard e nella scheda del protocollo dell'endpoint
- Pagina di gestione MCP dedicata con processo, strumenti, ambiti e audit
- Avvio rapido integrato per `omniroute --mcp` e onboarding del client
</details>
<details>
<summary><b>🧠 18. "Ho bisogno dell'orchestrazione A2A con percorsi di attività di sincronizzazione + streaming"</b></summary>
I flussi di lavoro degli agenti necessitano sia di risposte dirette che di esecuzione in streaming di lunga durata con controllo del ciclo di vita.
**Come OmniRoute risolve il problema:**
- Endpoint A2A JSON-RPC (`POST /a2a`) con `message/send` e `message/stream`
- Streaming SSE con propagazione dello stato terminale
- API del ciclo di vita delle attività per `tasks/get` e `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Ho bisogno dello stato reale del processo MCP, non di uno stato indovinato"</b></summary>
I team operativi devono sapere se MCP è effettivamente attivo, non solo se un'API è raggiungibile.
**Come OmniRoute risolve il problema:**
- File heartbeat di runtime con PID, timestamp, trasporto, conteggio strumenti e modalità ambito
- API di stato MCP che combina battito cardiaco + attività recente
- Schede di stato dell'interfaccia utente per l'aggiornamento di processo/tempo di attività/battito cardiaco
</details>
<details>
<summary><b>📋 20. "Ho bisogno dell'esecuzione verificabile dello strumento MCP"</b></summary>
Quando gli strumenti modificano la configurazione o attivano azioni operative, i team necessitano di tracciabilità forense.
**Come OmniRoute risolve il problema:**
- Registrazione di controllo supportata da SQLite per le chiamate allo strumento MCP
- Filtri per strumento, successo/fallimento, chiave API e impaginazione
- Tabella di controllo della dashboard + endpoint statistici per l'automazione
</details>
<details>
<summary><b>🔐 21. "Ho bisogno di autorizzazioni MCP con ambito per integrazione"</b></summary>
Client diversi dovrebbero avere accesso con privilegi minimi alle categorie di strumenti.
**Come OmniRoute risolve il problema:**
- 9 ambiti MCP granulari per l'accesso controllato agli strumenti
- Applicazione dell'ambito e visibilità nell'interfaccia utente di gestione MCP
- Postura predefinita sicura per gli strumenti operativi
</details>
<details>
<summary><b>⚙️ 22. "Ho bisogno di controlli operativi senza ridistribuirmi"</b></summary>
I team necessitano di rapidi cambiamenti di runtime durante incidenti o eventi di costo.
**Come OmniRoute risolve il problema:**
- Cambia l'attivazione combinata direttamente dalla dashboard MCP
- Applicare profili di resilienza da pacchetti di policy predefiniti
- Ripristinare lo stato dell'interruttore dallo stesso pannello operativo
</details>
<details>
<summary><b>🔄 23. "Ho bisogno di visibilità e cancellazione del ciclo di vita delle attività A2A in tempo reale"</b></summary>
Senza visibilità del ciclo di vita, gli incidenti relativi alle attività diventano difficili da valutare.
**Come OmniRoute risolve il problema:**
- Elenco/filtro delle attività per stato/competenza con impaginazione
- Esamina i metadati, gli eventi e gli artefatti delle attività
- Endpoint di annullamento dell'attività e azione dell'interfaccia utente con conferma
</details>
<details>
<summary><b>🌊 24. "Ho bisogno di metriche di flusso attive per il carico A2A"</b></summary>
I flussi di lavoro in streaming richiedono informazioni operative sulla concorrenza e sulle connessioni live.
**Come OmniRoute risolve il problema:**
- Contatori di flussi attivi integrati nello stato A2A
- Timestamp dell'ultima attività e conteggi per stato
- Schede dashboard A2A per il monitoraggio delle operazioni in tempo reale
</details>
<details>
<summary><b>🪪 25. "Ho bisogno del rilevamento degli agenti standard per i clienti"</b></summary>
I client e gli agenti di orchestrazione esterni necessitano di metadati leggibili dal computer per l'onboarding.
**Come OmniRoute risolve il problema:**
- Carta Agente esposta a `/.well-known/agent.json`
- Capacità e competenze mostrate nell'interfaccia utente di gestione
- L'API di stato A2A include metadati di rilevamento per l'automazione
</details>
<details>
<summary><b>🧭 26. "Ho bisogno della rilevabilità del protocollo nella UX del prodotto"</b></summary>
Se gli utenti non riescono a scoprire le superfici del protocollo, l'adozione e la qualità del supporto diminuiscono.
**Come OmniRoute risolve il problema:**
- Voci della barra laterale per MCP e A2A
- Scheda Protocolli della pagina Endpoint con avvio rapido e stato
- Collegamenti dalla panoramica alle dashboard di gestione dedicate
</details>
<details>
<summary><b>🧪 27. "Ho bisogno della convalida del protocollo end-to-end con clienti reali"</b></summary>
I test simulati non sono sufficienti per verificare la compatibilità del protocollo prima del rilascio.
**Come OmniRoute risolve il problema:**
- Suite E2E che avvia l'app e utilizza il trasporto client SDK MCP reale
- Test client A2A per i flussi di rilevamento, invio, streaming, acquisizione e annullamento
- Effettuare un controllo incrociato delle asserzioni con l'audit MCP e le API delle attività A2A
</details>
<details>
<summary><b>📡 28. "Ho bisogno di osservabilità unificata su tutte le interfacce"</b></summary>
Suddividere l'osservabilità per protocollo crea punti ciechi e un MTTR più lungo.
**Come OmniRoute risolve il problema:**
- Dashboard/registri/analisi unificati in un unico prodotto
- Salute + audit + richiesta di telemetria su livelli OpenAI, MCP e A2A
- API operative per stato e automazione
</details>
<details>
<summary><b>💼 29. "Ho bisogno di un runtime per proxy + strumenti + orchestrazione agente"</b></summary>
L'esecuzione di numerosi servizi separati aumenta i costi operativi e le modalità di guasto.
**Come OmniRoute risolve il problema:**
- Proxy compatibile con OpenAI, server MCP e server A2A in uno stack
- Autenticazione condivisa, resilienza, archivio dati e osservabilità
- Modello politico coerente su tutte le superfici di interazione
</details>
<details>
<summary><b>🚀 30. "Ho bisogno di spedire flussi di lavoro di agenti senza la proliferazione del codice adesivo"</b></summary>
I team perdono velocità quando uniscono più servizi e script ad hoc.
**Come OmniRoute risolve il problema:**
- Strategia endpoint unificata per clienti e agenti
- Interfacce utente di gestione del protocollo integrate e percorsi di convalida del fumo
- Fondamenti pronti per la produzione (sicurezza, registrazione, resilienza, backup)
</details>
### Playbook di esempio (casi d'uso integrati)
**Playbook A: massimizza l'abbonamento a pagamento + backup economico**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: stack di codifica a costo zero**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: catena di fallback sempre attiva 24 ore su 24, 7 giorni su 7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: operazioni dell'agente con MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Avvio Rapido
**1. Installa globalmente:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -589,6 +865,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Funzionalità | Cosa Fa |
| ------------------------------- | ---------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Apertura/chiusura auto per provider con soglie configurabili |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-Thundering Herd** | Mutex + semaforo rate-limit per provider con API key |
| 🧠 **Cache semantica** | Cache a due livelli (firma + semantica) riduce costi e latenza |
| ⚡ **Idempotenza richieste** | Finestra dedup 5s per richieste duplicate |
@@ -696,66 +973,26 @@ Traduzione trasparente tra formati:
</details>
---
## 🧪 Valutazioni (Evals)
## 🎯 Casi d'Uso
OmniRoute include un framework di valutazione integrato per testare la qualità delle risposte LLM contro un golden set. Accesso via **Analytics → Evals** nella dashboard.
### Caso 1: "Ho un abbonamento Claude Pro"
### Set integrato
**Problema:** La quota scade inutilizzata, limiti di rate durante la programmazione intensa
Il "OmniRoute Golden Set" precaricato contiene 10 casi di test:
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (usa l'abbonamento al massimo)
2. glm/glm-4.7 (backup economico quando la quota è esaurita)
3. if/kimi-k2-thinking (fallback d'emergenza gratuito)
- Saluti, matematica, geografia, generazione codice
- Conformità formato JSON, traduzione, markdown
- Rifiuto sicurezza (contenuto nocivo), conteggio, logica booleana
Costo mensile: $20 (abbonamento) + ~$5 (backup) = $25 totale
vs. $20 + sbattere contro i limiti = frustrazione
```
### Strategie di valutazione
### Caso 2: "Voglio costo zero"
**Problema:** Non può permettersi abbonamenti, ha bisogno di IA affidabile per programmare
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K gratis/mese)
2. if/kimi-k2-thinking (illimitato gratis)
3. qw/qwen3-coder-plus (illimitato gratis)
Costo mensile: $0
Qualità: Modelli pronti per la produzione
```
### Caso 3: "Devo programmare 24/7, senza interruzioni"
**Problema:** Scadenze strette, non può permettersi downtime
```
Combo: "always-on"
1. cc/claude-opus-4-6 (migliore qualità)
2. cx/gpt-5.2-codex (secondo abbonamento)
3. glm/glm-4.7 (economico, reset giornaliero)
4. minimax/MiniMax-M2.1 (più economico, reset 5h)
5. if/kimi-k2-thinking (gratuito illimitato)
Risultato: 5 livelli di fallback = zero downtime
```
### Caso 4: "Voglio IA GRATUITA in OpenClaw"
**Problema:** Ha bisogno di assistente IA nelle app di messaggistica, completamente gratuito
```
Combo: "openclaw-free"
1. if/glm-4.7 (illimitato gratis)
2. if/minimax-m2.1 (illimitato gratis)
3. if/kimi-k2-thinking (illimitato gratis)
Costo mensile: $0
Accesso via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
| Strategia | Descrizione | Esempio |
| ---------- | ---------------------------------------------------------- | -------------------------------- |
| `exact` | L'output deve corrispondere esattamente | `"4"` |
| `contains` | L'output deve contenere la sottostringa (case-insensitive) | `"Paris"` |
| `regex` | L'output deve corrispondere al pattern regex | `"1.*2.*3"` |
| `custom` | Funzione JS personalizzata restituisce true/false | `(output) => output.length > 10` |
---
@@ -1039,29 +1276,6 @@ Impostazioni → Configurazione API:
---
## 🧪 Valutazioni (Evals)
OmniRoute include un framework di valutazione integrato per testare la qualità delle risposte LLM contro un golden set. Accesso via **Analytics → Evals** nella dashboard.
### Golden Set integrato
Il "OmniRoute Golden Set" precaricato contiene 10 casi di test:
- Saluti, matematica, geografia, generazione codice
- Conformità formato JSON, traduzione, markdown
- Rifiuto sicurezza (contenuto nocivo), conteggio, logica booleana
### Strategie di valutazione
| Strategia | Descrizione | Esempio |
| ---------- | ---------------------------------------------------------- | -------------------------------- |
| `exact` | L'output deve corrispondere esattamente | `"4"` |
| `contains` | L'output deve contenere la sottostringa (case-insensitive) | `"Paris"` |
| `regex` | L'output deve corrispondere al pattern regex | `"1.*2.*3"` |
| `custom` | Funzione JS personalizzata restituisce true/false | `(output) => output.length > 10` |
---
## 🐛 Risoluzione Problemi
<details>
@@ -1117,7 +1331,7 @@ Il "OmniRoute Golden Set" precaricato contiene 10 casi di test:
---
## 🛠️ Stack Tecnologico
## 🛠️
- **Runtime**: Node.js 20+
- **Linguaggio**: TypeScript 5.9 — **100% TypeScript** in `src/` e `open-sse/` (v1.0.6)
@@ -1148,18 +1362,7 @@ Il "OmniRoute Golden Set" precaricato contiene 10 casi di test:
---
## 📧 Supporto
> 💬 **Unisciti alla nostra community!** [Gruppo WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Ottieni aiuto, condividi consigli e rimani aggiornato.
- **Sito 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**: [Gruppo della comunità](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **WhatsApp**: [Gruppo della comunità](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Progetto Originale**: [9router di decolua](https://github.com/decolua/9router)
---
## 🗺️
## 👥 Contributori

View File

@@ -110,6 +110,35 @@ _AI を活用した IDE または CLI ツールを、無制限のコーディン
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 なぜオムニルートなのか?
**お金の無駄遣いや限界に達するのはやめましょう:**
@@ -128,6 +157,18 @@ _AI を活用した IDE または CLI ツールを、無制限のコーディン
---
## 📧 サポート
> 💬 **コミュニティに参加してください!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — ヘルプを取得し、ヒントを共有し、最新情報を入手してください。
- **ウェブサイト**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **問題**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **オリジナル プロジェクト**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 仕組み
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 OmniRoute が解決するもの — 30 の実際の問題点とユースケース
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **AI ツールを使用するすべての開発者は、これらの問題に日々直面しています。** OmniRoute は、コスト超過から地域ブロック、壊れた OAuth フローからプロトコル操作、企業の可観測性まで、それらすべてを解決するために構築されました。
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. 「高価なサブスクリプションの料金を支払っているのに、制限によって中断されます」</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
開発者は、Claude ProCodex Pro、または GitHub Copilot に月額 20 200 ドルを支払います。有料であっても、割り当てには上限があり、5 時間の使用量、週ごとの制限、または分ごとのレート制限があります。コーディング セッションの途中でプロバイダーが応答を停止し、開発者はフローと生産性を失います。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **スマート 4 層フォールバック** — サブスクリプション クォータが不足すると、手動介入なしで自動的に API キー→格安→無料にリダイレクトされます。
- **リアルタイム クォータ トラッキング** — リセット カウントダウン (5 時間、毎日、毎週) でトークンの消費量をリアルタイムで表示します。
- **マルチアカウントのサポート** — 自動ラウンドロビンによるプロバイダーごとの複数のアカウント — 1 つのアカウントがなくなると、次のアカウントに切り替わります
- **カスタム コンボ** — 6 つのバランシング戦略 (フィルファースト、ラウンドロビン、P2C、ランダム、最小使用、コスト最適化) を備えたカスタマイズ可能なフォールバック チェーン
- **Codex Business クォータ** — ビジネス/チームのワークスペース クォータをダッシュボードで直接監視
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. 「複数のプロバイダーを使用する必要がありますが、それぞれに異なる API があります」</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI は 1 つの形式を使用し、Claude (Anthropic) は別の形式を使用し、Gemini はさらに別の形式を使用します。開発者が異なるプロバイダーのモデルをテストしたり、プロバイダー間でフォールバックしたりする場合は、SDK を再構成し、エンドポイントを変更し、互換性のない形式に対処する必要があります。カスタム プロバイダー (FriendLINIM) には、非標準モデルのエンドポイントがあります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **統合エンドポイント** - 単一の `http://localhost:20128/v1` が 36 を超えるすべてのプロバイダーのプロキシとして機能します
- **フォーマット変換** — 自動かつ透過的: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **レスポンスのサニタイズ** — OpenAI SDK v1.83 以降を破壊する非標準フィールド (`x_groq``usage_breakdown``service_tier`) を除去します。
- **ロールの正規化** — 非 OpenAI プロバイダーに対して `developer``system` を変換します。 GLM/ERNIE 用 `system``user`
- **Think Tag Extraction** — DeepSeek R1 などのモデルから `<think>` ブロックを標準化された `reasoning_content` に抽出します。
- **Gemini の構造化出力** — `json_schema``responseMimeType`/`responseSchema` 自動変換
- **`stream` のデフォルトは `false`** — OpenAI 仕様に準拠し、Python/Rust/Go SDK での予期しない SSE を回避します
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. 「AI プロバイダーが私の地域/国をブロックしています」</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
OpenAI/Codex などのプロバイダーは、特定の地理的地域からのアクセスをブロックします。 OAuth および API 接続中に、ユーザーは `unsupported_country_region_territory` のようなエラーを受け取ります。これは、発展途上国の開発者にとって特にイライラさせられます。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3 レベルのプロキシ構成** — 3 つのレベルで構成可能なプロキシ: グローバル (すべてのトラフィック)、プロバイダーごと (1 つのプロバイダーのみ)、および接続/キーごと
- **色分けされたプロキシ バッジ** — 視覚的なインジケーター: 🟢 グローバル プロキシ、🟡 プロバイダー プロキシ、🔵 接続プロキシ、常に IP を表示
- **プロキシを介した OAuth トークン交換** — OAuth フローもプロキシを通過し、`unsupported_country_region_territory` を解決します
- **プロキシ経由の接続テスト** — 接続テストは構成されたプロキシを使用します (直接バイパスはありません)。
- **SOCKS5 サポート** — アウトバウンド ルーティングに対する SOCKS5 プロキシの完全なサポート
- **TLS フィンガープリント スプーフィング** — `wreq-js` を介したブラウザーのような TLS フィンガープリントによりボット検出をバイパスします
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. 「AIを使ってコーディングしたいけどお金がない」</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
誰もが AI サブスクリプションに月額 20 200 ドルを支払えるわけではありません。学生、新興国の開発者、愛好家、フリーランサーは、高品質のモデルに無料でアクセスできる必要があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **無料利用枠プロバイダーの組み込み** — 100% 無料プロバイダーのネイティブ サポート: iFlow (8 つの無制限のモデル)、Qwen (3 つの無制限のモデル)、Kiro (無料の Claude)、Gemini CLI (180K/月無料)
- **無料のみのコンボ** — チェーン `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 月額 0 ドル、ダウンタイムなし
- **NVIDIA NIM 無料クレジット** — 1000 の無料クレジットが統合されています
- **コスト最適化戦略** — 利用可能な最も安価なプロバイダーを自動的に選択するルーティング戦略
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. 「AI ゲートウェイを不正アクセスから保護する必要があります」</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
AI ゲートウェイをネットワーク (LANVPSDocker) に公開すると、アドレスを持っている人は誰でも開発者のトークン/クォータを消費できます。保護がなければ、API は誤用、即時挿入、悪用に対して脆弱になります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API キー管理** — 専用の `/dashboard/api-manager` ページを使用したプロバイダーごとの生成、ローテーション、およびスコープ設定
- **モデルレベルの権限** — すべて許可/制限の切り替えにより、API キーを特定のモデル (`openai/*`、ワイルドカード パターン) に制限します
- **API エンドポイント保護** - `/v1/models` のキーを要求し、リストから特定のプロバイダーをブロックします
- **認証ガード + CSRF 保護** — すべてのダッシュボード ルートは `withAuth` ミドルウェア + CSRF トークンで保護されています
- **レート リミッター** — 構成可能なウィンドウによる IP ごとのレート制限
- **IP フィルタリング** — アクセス制御の許可リスト/ブロックリスト
- **プロンプト インジェクション ガード** — 悪意のあるプロンプト パターンに対するサニタイズ
- **AES-256-GCM 暗号化** — 認証情報は保存時に暗号化されます
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. 「プロバイダーがダウンしてコーディング フローが失われました」</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI プロバイダーが不安定になったり、5xx エラーを返したり、一時的なレート制限に達したりする可能性があります。開発者が単一のプロバイダーに依存している場合、それらは中断されます。サーキット ブレーカーがないと、再試行を繰り返すとアプリケーションがクラッシュする可能性があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **プロバイダーごとのサーキット ブレーカー** — 設定可能なしきい値とクールダウンによる自動開閉 (クローズ/オープン/ハーフオープン)
- **指数バックオフ** — 漸進的な再試行遅延
- **Anti-Thundering Herd** — 同時再試行の嵐に対するミューテックス + セマフォ保護
- **コンボ フォールバック チェーン** - プライマリ プロバイダーに障害が発生した場合、介入なしで自動的にチェーンを通過します。
- **コンボ サーキット ブレーカー** — コンボ チェーン内の障害が発生したプロバイダーを自動的に無効にします
- **ヘルス ダッシュボード** — 稼働時間モニタリング、サーキット ブレーカーの状態、ロックアウト、キャッシュ統計、p50/p95/p99 レイテンシ
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. 「各 AI ツールの設定は面倒で繰り返しが多い」</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
開発者は、CursorClaude CodeCodex CLIOpenClawGemini CLIKilo Code を使用します。各ツールには異なる構成 (API エンドポイント、キー、モデル) が必要です。プロバイダーや機種変更時に再設定するのは時間の無駄です。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI ツール ダッシュボード** — Claude CodeCodex CLIOpenClawKilo CodeAntigravityCline をワンクリックでセットアップできる専用ページ
- **GitHub Copilot Config Generator** — モデルを一括選択して VS Code の `chatLanguageModels.json` を生成します
- **オンボーディング ウィザード** - 初めてユーザー向けのガイド付き 4 ステップ セットアップ
- **1 つのエンドポイント、すべてのモデル** — `http://localhost:20128/v1` を 1 回構成すると、36 を超えるプロバイダーにアクセスできます
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. 「複数のプロバイダーからの OAuth トークンを管理するのは地獄です」</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude CodeCodexGemini CLICopilot — すべては有効期限切れのトークンを持つ OAuth 2.0 を使用します。開発者は定期的に再認証し、`client_secret is missing``redirect_uri_mismatch`、およびリモート サーバーの障害に対処する必要があります。 LAN/VPS 上の OAuth は特に問題があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **自動トークン更新** — OAuth トークンは有効期限が切れる前にバックグラウンドで更新されます。
- **OAuth 2.0 (PKCE) ビルトイン** — Claude CodeCodexGemini CLICopilotKiroQweniFlow の自動フロー
- **マルチアカウント OAuth** — JWT/ID トークン抽出によるプロバイダーごとの複数のアカウント
- **OAuth LAN/リモート修正** — `redirect_uri` のプライベート IP 検出 + リモート サーバーの手動 URL モード
- **Nginx の背後にある OAuth** — リバース プロキシの互換性のために `window.location.origin` を使用します
- **リモート OAuth ガイド** — VPS/Docker での Google Cloud 認証情報のステップバイステップ ガイド
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. 「どこにいくら使っているのか分かりません」</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
開発者は複数の有料プロバイダーを使用していますが、支出について統一した見解がありません。各プロバイダーには独自の請求ダッシュボードがありますが、統合されたビューはありません。予期せぬ出費がかさむ可能性があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **コスト分析ダッシュボード** — トークンごとのコスト追跡とプロバイダーごとの予算管理
- **階層ごとの予算制限** — 自動フォールバックをトリガーする階層ごとの支出上限
- **モデルごとの価格構成** — モデルごとに構成可能な価格
- **API キーごとの使用統計** — キーごとのリクエスト数と最後に使用されたタイムスタンプ
- **分析ダッシュボード** — 統計カード、モデル使用状況グラフ、成功率と遅延を含むプロバイダー表
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. 「AI 呼び出しのエラーや問題を診断できません」</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
呼び出しが失敗すると、開発者はそれがレート制限なのか、トークンの期限切れなのか、間違った形式なのか、プロバイダーのエラーなのかわかりません。さまざまな端末にわたる断片化されたログ。可観測性がなければ、デバッグは試行錯誤になります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **統合ログ ダッシュボード** — 4 つのタブ: リクエスト ログ、プロキシ ログ、監査ログ、コンソール
- **コンソール ログ ビューア** — 色分けされたレベル、自動スクロール、検索、フィルターを備えたリアルタイムのターミナル スタイルのビューア
- **SQLite プロキシ ログ** — サーバーの再起動後も存続する永続的なログ
- **Translator Playground** — 4 つのデバッグ モード: プレイグラウンド (形式変換)、チャット テスター (往復)、テストベンチ (バッチ)、ライブ モニター (リアルタイム)
- **リクエスト テレメトリ** — p50/p95/p99 レイテンシ + X-Request-Id トレース
- **ローテーションを使用したファイルベースのログ** — コンソール インターセプターは、サイズベースのローテーションを使用してすべてを JSON ログにキャプチャします。
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. 「ゲートウェイの導入と保守は複雑です」</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
さまざまな環境 (ローカル、VPSDocker、クラウド) 間で AI プロキシをインストール、構成、維持するには、多大な労力がかかります。ハードコーディングされたパス、ディレクトリ上の `EACCES`、ポートの競合、クロスプラットフォーム ビルドなどの問題により、摩擦が増大します。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm グローバル インストール** — `npm install -g omniroute && omniroute`完了
- **Docker マルチプラットフォーム** — AMD64 + ARM64 ネイティブ (Apple SiliconAWS GravitonRaspberry Pi)
- **Docker Compose プロファイル** — `base` (CLI ツールなし) および `cli` (Claude CodeCodexOpenClaw あり)
- **Electron デスクトップ アプリ** — システム トレイ、自動起動、オフライン モードを備えた Windows/macOS/Linux 用ネイティブ アプリ
- **分割ポート モード** - 高度なシナリオ (リバース プロキシ、コンテナ ネットワーキング) 向けに個別のポート上の API とダッシュボード
- **Cloud Sync** — Cloudflare Workers を介したデバイス間での設定の同期
- **DB バックアップ** — すべての設定の自動バックアップ、復元、エクスポート、インポート
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. 「インターフェースは英語のみで、私のチームは英語を話せません」</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
非英語圏の国、特にラテンアメリカ、アジア、ヨーロッパのチームは、英語のみのインターフェースに苦労しています。言語の壁があると採用が減り、構成エラーが増加します。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **ダッシュボード i18n — 30 言語** — アラビア語、ブルガリア語、デンマーク語、ドイツ語、スペイン語、フィンランド語、フランス語、ヘブライ語、ヒンディー語、ハンガリー語、インドネシア語、イタリア語、日本語、韓国語、マレー語、オランダ語、ノルウェー語、ポーランド語、ポルトガル語 (PT/BR)、ルーマニア語、ロシア語、スロバキア語、スウェーデン語、タイ語、ウクライナ語、ベトナム語、中国語、フィリピン語、英語
- **RTL サポート** — アラビア語とヘブライ語の右から左へのサポート
- **多言語 README** — 30 件の完全なドキュメント翻訳
- **言語セレクター** — リアルタイム切り替えのためのヘッダーの地球儀アイコン
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. 「チャット以上のものが必要です — 埋め込み、画像、音声が必要です」</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AIは単なるチャット補完ではありません。開発者は、画像の生成、音声の文字起こし、RAG の埋め込みの作成、ドキュメントの再ランク付け、およびコンテンツの管理を行う必要があります。各 API には異なるエンドポイントと形式があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **エンベディング** — 6 つのプロバイダーと 9 つ以上のモデルを備えた `/v1/embeddings`
- **画像生成** — 10 プロバイダーと 20 以上のモデルを備えた `/v1/images/generations` (OpenAI、xAI、Togetter、Fireworks、Nebius、Hyperbolic、NanoBanana、Antigravity、SD WebUI、ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff、SVD) および SD WebUI
- **テキストから音楽へ** — `/v1/music/generations` — ComfyUI (安定したオーディオ オープン、MusicGen)
- **音声転写** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM、HuggingFace、Qwen3
- **テキスト読み上げ** — `/v1/audio/speech` — イレブンラボ、Nvidia NIM、HuggingFace、Coqui、Tortoise、Qwen3、+ 既存のプロバイダー
- **モデレーション** — `/v1/moderations` — コンテンツの安全性チェック
- **再ランキング** — `/v1/rerank` — ドキュメントの関連性の再ランキング
- **応答 API** — Codex の `/v1/responses` の完全サポート
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. 「モデル間で品質をテストして比較する方法がありません」</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
開発者は、コード、翻訳、推論などのユースケースにどのモデルが最適であるかを知りたいと考えていますが、手動で比較するのは時間がかかります。統合された評価ツールは存在しません。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM 評価** — 挨拶、数学、地理、コード生成、JSON 準拠、翻訳、マークダウン、安全性の拒否をカバーする 10 個の事前ロードされたケースによるゴールデン セット テスト
- **4 つのマッチ戦略** — `exact``contains``regex``custom` (JS 関数)
- **Translator Playground Test Bench** — 複数の入力と予想される出力を使用したバッチ テスト、クロスプロバイダー比較
- **チャット テスター** — 視覚的な応答レンダリングによる完全な往復
- **ライブ モニター** — プロキシを通過するすべてのリクエストのリアルタイム ストリーム
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. 「パフォーマンスを落とさずにスケールする必要がある」</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
リクエストの量が増えると、同じ質問をキャッシュしないと重複したコストが発生します。冪等性がないと、重複したリクエストにより処理が無駄になります。プロバイダーごとのレート制限を遵守する必要があります。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **セマンティック キャッシュ** — 2 層キャッシュ (署名 + セマンティック) によりコストと遅延が削減されます。
- **リクエストの冪等性** — 同一のリクエストに対する重複排除ウィンドウは 5 秒です
- **レート制限検出** — プロバイダーごとの RPM、最小ギャップ、最大同時トラッキング
- **編集可能なレート制限** — [設定] → [永続性を伴う回復力] で構成可能なデフォルト
- **API キー検証キャッシュ** — 運用パフォーマンスのための 3 層キャッシュ
- **テレメトリ付きヘルス ダッシュボード** — p50/p95/p99 レイテンシ、キャッシュ統計、稼働時間
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. 「モデルの動作をグローバルに制御したい」</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
すべての応答を特定の言語、特定の口調で行いたい、または推論トークンを制限したい開発者。すべてのツール/リクエストでこれを設定するのは現実的ではありません。
**How OmniRoute solves it:**
**OmniRoute がそれを解決する方法:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **システム プロンプト インジェクション** — すべてのリクエストに適用されるグローバル プロンプト
- **思考予算検証** — リクエストごとの推論トークン割り当て制御 (パススルー、自動、カスタム、適応)
- **6 ルーティング戦略** — リクエストの分散方法を決定するグローバル戦略
- **ワイルドカード ルーター** - `provider/*` パターンは任意のプロバイダーに動的にルーティングします
- **コンボ有効/無効切り替え** — ダッシュボードから直接コンボを切り替えます
- **プロバイダー切り替え** — ワンクリックでプロバイダーのすべての接続を有効/無効にします。
- **ブロックされたプロバイダー** — `/v1/models` リストから特定のプロバイダーを除外します
</details>
<details>
<summary><b>🧰 17. 「一流の製品機能として MCP ツールが必要です」</b></summary>
多くの AI ゲートウェイは、MCP を非表示の実装詳細としてのみ公開します。チームには、目に見えて管理しやすいオペレーション レイヤーが必要です。
**OmniRoute がそれを解決する方法:**
- MCP はダッシュボードのナビゲーションとエンドポイント プロトコル タブに表示されます
- プロセス、ツール、スコープ、監査を備えた専用の MCP 管理ページ
- `omniroute --mcp` およびクライアントのオンボーディング用の組み込みクイックスタート
</details>
<details>
<summary><b>🧠 18. 「同期 + ストリーム タスク パスを備えた A2A オーケストレーションが必要です」</b></summary>
エージェント ワークフローには、直接応答と、ライフサイクル制御による長時間実行のストリーミング実行の両方が必要です。
**OmniRoute がそれを解決する方法:**
- A2A JSON-RPC エンドポイント (`POST /a2a`) (`message/send` および `message/stream`)
- 端末状態の伝播を伴う SSE ストリーミング
- `tasks/get` および `tasks/cancel` のタスク ライフサイクル API
</details>
<details>
<summary><b>🛰️ 19. 「推測されたステータスではなく、実際の MCP プロセスの健全性が必要です」</b></summary>
運用チームは、API が到達可能かどうかだけでなく、MCP が実際に生きているかどうかを知る必要があります。
**OmniRoute がそれを解決する方法:**
- PID、タイムスタンプ、トランスポート、ツール数、およびスコープモードを含むランタイムハートビートファイル
- ハートビートと最近のアクティビティを組み合わせた MCP ステータス API
- プロセス/稼働時間/ハートビートの鮮度を示す UI ステータス カード
</details>
<details>
<summary><b>📋 20. 「監査可能な MCP ツールの実行が必要です」</b></summary>
ツールが構成を変更したり、運用アクションをトリガーしたりする場合、チームはフォレンジックなトレーサビリティを必要とします。
**OmniRoute がそれを解決する方法:**
- MCP ツール呼び出しの SQLite ベースの監査ログ
- ツール、成功/失敗、API キー、ページネーションによるフィルター
- ダッシュボード監査テーブル + 自動化のための統計エンドポイント
</details>
<details>
<summary><b>🔐 21. 「統合ごとにスコープ指定された MCP 権限が必要です」</b></summary>
異なるクライアントには、ツール カテゴリへの最小限の特権アクセスが必要です。
**OmniRoute がそれを解決する方法:**
- 制御されたツールアクセスのための 9 つの詳細な MCP スコープ
- MCP 管理 UI でのスコープの適用と可視性
- 運用ツールの安全なデフォルト姿勢
</details>
<details>
<summary><b>⚙️ 22. 「再デプロイせずに運用制御が必要です」</b></summary>
チームは、インシデントやコスト イベントが発生した際に、実行時の変更を迅速に行う必要があります。
**OmniRoute がそれを解決する方法:**
- MCP ダッシュボードからコンボのアクティブ化を直接切り替えます
- 事前定義されたポリシーパックから復元プロファイルを適用
- 同じ操作パネルからサーキットブレーカーの状態をリセット
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
</details>
<details>
<summary><b>🔄 23. 「ライブ A2A タスクのライフサイクルの可視化とキャンセルが必要です」</b></summary>
ライフサイクルの可視性がなければ、タスク インシデントの優先順位付けが困難になります。
**OmniRoute がそれを解決する方法:**
- ページネーションを使用した状態/スキルによるタスクのリスト/フィルタリング
- タスクのメタデータ、イベント、アーティファクトのドリルダウン
- タスクキャンセルエンドポイントと確認付きの UI アクション
</details>
<details>
<summary><b>🌊 24. 「A2A ロード用のアクティブ ストリーム メトリクスが必要です」</b></summary>
ストリーミング ワークフローには、同時実行性とライブ接続に関する運用上の洞察が必要です。
**OmniRoute がそれを解決する方法:**
- アクティブ ストリーム カウンターが A2A ステータスに統合されました
- 最後のタスクのタイムスタンプと状態ごとのカウント
- リアルタイム運用監視用の A2A ダッシュボード カード
</details>
<details>
<summary><b>🪪 25. 「クライアントの標準エージェント検出が必要です」</b></summary>
外部クライアントとオーケストレーターには、オンボーディング用の機械可読メタデータが必要です。
**OmniRoute がそれを解決する方法:**
- エージェント カードが `/.well-known/agent.json` で公開される
- 管理UIに表示される能力とスキル
- A2A ステータス API には自動化のための検出メタデータが含まれています
</details>
<details>
<summary><b>🧭 26. 「製品 UX にプロトコルの検出機能が必要です」</b></summary>
ユーザーがプロトコルの表面を発見できない場合、導入とサポートの品質が低下します。
**OmniRoute がそれを解決する方法:**
- MCP および A2A のサイドバー エントリ
- クイックスタートとステータスを含むエンドポイント ページの [プロトコル] タブ
- 概要から専用の管理ダッシュボードへのリンク
</details>
<details>
<summary><b>🧪 27. 「実際のクライアントを使用したエンドツーエンドのプロトコル検証が必要です」</b></summary>
模擬テストは、リリース前にプロトコルの互換性を検証するには十分ではありません。
**OmniRoute がそれを解決する方法:**
- アプリを起動し、実際の MCP SDK クライアント トランスポートを使用する E2E スイート
- A2A クライアントは、フローの検出、送信、ストリーミング、取得、キャンセルをテストします。
- MCP 監査および A2A タスク API に対するアサーションのクロスチェック
</details>
<details>
<summary><b>📡 28. 「すべてのインターフェースにわたって統合された可観測性が必要です」</b></summary>
プロトコルごとに可観測性を分割すると、盲点が生じ、MTTR が長くなります。
**OmniRoute がそれを解決する方法:**
- ダッシュボード/ログ/分析を 1 つの製品に統合
- OpenAI、MCP、A2A レイヤーにわたるヘルス + 監査 + リクエスト テレメトリ
- ステータスと自動化のための運用 API
</details>
<details>
<summary><b>💼 29. 「プロキシ + ツール + エージェント オーケストレーション用のランタイムが 1 つ必要です」</b></summary>
多くの個別のサービスを実行すると、運用コストが増加し、障害モードが増加します。
**OmniRoute がそれを解決する方法:**
- OpenAI互換プロキシ、MCPサーバー、A2Aサーバーを1つのスタックに搭載
- 共有認証、復元力、データストア、可観測性
- すべての対話面にわたる一貫したポリシー モデル
</details>
<details>
<summary><b>🚀 30. 「グルーコードのスプロールなしでエージェント ワークフローを出荷する必要がある」</b></summary>
複数のアドホック サービスとスクリプトをつなぎ合わせると、チームの速度が低下します。
**OmniRoute がそれを解決する方法:**
- クライアントとエージェント向けの統合エンドポイント戦略
- 組み込みのプロトコル管理 UI とスモーク検証パス
- 本番環境に対応した基盤 (セキュリティ、ロギング、復元力、バックアップ)
</details>
### プレイブックの例 (統合されたユースケース)
**戦略 A: 有料サブスクリプション + 安価なバックアップを最大限に活用する**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**プレイブック B: ゼロコストのコーディング スタック**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**プレイブック C: 24 時間年中無休の常時オンのフォールバック チェーン**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**プレイブック D: MCP + A2A を使用したエージェントの運用**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ クイックスタート
**1.グローバルにインストール:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ デスクトップアプリ — オフライン&常時稼働
## 🖥️
> 🆕 **新機能!** OmniRouteが**ネイティブデスクトップアプリケーション**としてWindows、macOS、Linuxで利用可能になりました。
@@ -589,6 +865,7 @@ npm run electron:build:linux # Linux (.AppImage)
| 特集 | 何をするのか |
| -------------------------------- | ---------------------------------------------------------------------------- |
| 🔌 **サーキットブレーカー** | 設定可能なしきい値によるプロバイダーごとの自動開閉 |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **対雷鳴の群れ** | API キープロバイダーのミューテックス + セマフォのレート制限 |
| 🧠 **セマンティック キャッシュ** | 2 層キャッシュ (シグネチャ + セマンティック) によりコストと遅延が削減 |
| ⚡ **冪等性のリクエスト** | 重複リクエストに対する 5 秒の重複除去ウィンドウ |
@@ -689,6 +966,7 @@ Combo: "my-coding-stack"
- システムステータス (稼働時間、バージョン、メモリ使用量)
- プロバイダーごとのサーキットブレーカーの状態 (クローズ/オープン/ハーフオープン)
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- レート制限ステータスとアクティブなロックアウト
- 署名キャッシュ統計
- レイテンシ テレメトリ (p50/p95/p99) + プロンプト キャッシュ
@@ -715,66 +993,26 @@ OmniRoute には、API 翻訳のデバッグ、テスト、監視のための **
</details>
---
## 🧪 評価 (Evals)
## 🎯 使用例
OmniRoute には、ゴールデン セットに対して LLM 応答品質をテストするための評価フレームワークが組み込まれています。ダッシュボードの **Analytics → Evals** からアクセスします。
### ケース 1: 「Claude Pro サブスクリプションを持っています」
### 内蔵ゴールデンセット
**問題:** 大量のコーディング中にクォータが使用されずに期限切れになり、レート制限が発生する
プリロードされた「OmniRoute Golden Set」には、以下をカバーする 10 のテスト ケースが含まれています。
```
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)
- 挨拶、数学、地理、コード生成
- JSON形式への準拠、翻訳、マークダウン
- 安全拒否(有害なコンテンツ)、カウント、ブール論理
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### 評価戦略
### ケース 2: 「コストをゼロにしたい」
**問題:** サブスクリプションを購入する余裕がないため、信頼性の高い AI コーディングが必要です
```
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
```
### ケース 3: 「24 時間年中無休でコーディングが必要で、中断はありません」
**問題:** 締め切りが迫っており、ダウンタイムを許すことができません
```
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
```
### ケース 4: 「OpenClaw に無料の AI が欲しい」
**問題:** メッセージング アプリには AI アシスタントが必要ですが、完全に無料です
```
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...
```
| 戦略 | 説明 | 例 |
| ---------- | ------------------------------------------------------------------------------------------- | ----------- |
| `exact` | 出力は正確に一致する必要があります | `"4"` |
| `contains` | 出力には部分文字列が含まれている必要があります (大文字と小文字は区別されません)。 `"Paris"` |
| `regex` | 出力は正規表現パターンと一致する必要があります | `"1.*2.*3"` |
| `custom` | カスタム JS 関数は true/false を返します。 `(output) => output.length > 10` |
---
@@ -1057,29 +1295,6 @@ Settings → API Configuration:
---
## 🧪 評価 (Evals)
OmniRoute には、ゴールデン セットに対して LLM 応答品質をテストするための評価フレームワークが組み込まれています。ダッシュボードの **Analytics → Evals** からアクセスします。
### 内蔵ゴールデンセット
プリロードされた「OmniRoute Golden Set」には、以下をカバーする 10 のテスト ケースが含まれています。
- 挨拶、数学、地理、コード生成
- JSON形式への準拠、翻訳、マークダウン
- 安全拒否(有害なコンテンツ)、カウント、ブール論理
### 評価戦略
| 戦略 | 説明 | 例 |
| ---------- | ------------------------------------------------------------------------------------------- | ----------- |
| `exact` | 出力は正確に一致する必要があります | `"4"` |
| `contains` | 出力には部分文字列が含まれている必要があります (大文字と小文字は区別されません)。 `"Paris"` |
| `regex` | 出力は正規表現パターンと一致する必要があります | `"1.*2.*3"` |
| `custom` | カスタム JS 関数は true/false を返します。 `(output) => output.length > 10` |
---
## 🐛 トラブルシューティング
<details>
@@ -1137,7 +1352,7 @@ OmniRoute には、ゴールデン セットに対して LLM 応答品質をテ
> **⚠️ VPS/Docker/サーバーリモートの OmniRoute に関する重要事項**
### Antigravity / Gemini CLI で OAuth を実行すると、リモートのサービスが提供されますか?
### OAuth
**反重力****Gemini CLI** を使用して **Google OAuth 2.0** を認証します。 O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pré-cadastradas Google Cloud Console でアプリケーションを実行できません。
@@ -1226,7 +1441,7 @@ docker restart omniroute
---
## 🛠️ 技術スタック
## 🛠️
- **ランタイム**: Node.js 1822 LTS (⚠️ Node.js 24+ は **サポートされていません**`better-sqlite3` ネイティブ バイナリは互換性がありません)
- **言語**: TypeScript 5.9 — `src/` および `open-sse/`**100% TypeScript** (v1.0.6)
@@ -1278,7 +1493,7 @@ docker restart omniroute
---
## 🗺️ ロードマップ
## 🗺️
OmniRoute には、複数の開発フェーズにわたって **210 以上の機能が計画されています**。主要な領域は次のとおりです。
@@ -1303,18 +1518,6 @@ OmniRoute には、複数の開発フェーズにわたって **210 以上の機
---
## 📧 サポート
> 💬 **コミュニティに参加してください!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — ヘルプを取得し、ヒントを共有し、最新情報を入手してください。
- **ウェブサイト**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **問題**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **オリジナル プロジェクト**: [9router by 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)

View File

@@ -110,6 +110,35 @@ _무제한 코딩을 위한 무료 API 게이트웨이인 OmniRoute를 통해 AI
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 왜 OmniRoute인가요?
**돈을 낭비하지 말고 한도에 도달하지 마세요.**
@@ -128,6 +157,18 @@ _무제한 코딩을 위한 무료 API 게이트웨이인 OmniRoute를 통해 AI
---
## 📧 지원
> 💬 **커뮤니티에 가입하세요!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — 도움을 받고, 팁을 공유하고, 최신 소식을 받아보세요.
- **웹사이트**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **문제**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **원래 프로젝트**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 작동 방식
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 OmniRoute가 해결하는 것 — 30가지 실제 문제점 및 사용 사례
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **AI 도구를 사용하는 모든 개발자는 매일 이러한 문제에 직면합니다.** OmniRoute는 비용 초과부터 지역적 차단, 손상된 OAuth 흐름부터 프로토콜 운영 및 기업 관찰 가능성까지 모든 문제를 해결하기 위해 구축되었습니다.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "비싼 구독료를 지불했지만 여전히 한도 때문에 방해를 받습니다."</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
개발자는 Claude Pro, Codex Pro 또는 GitHub Copilot에 대해 월 20~200달러를 지불합니다. 비용을 지불하더라도 할당량에는 5시간 사용량, 주간 한도 또는 분당 비율 한도 등 상한선이 있습니다. 코딩 세션이 진행되는 동안 공급자는 응답을 중단하고 개발자는 흐름과 생산성을 잃게 됩니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **스마트 4계층 폴백** — 구독 할당량이 소진되면 수동 개입 없이 자동으로 API 키 → 저렴함 → 무료로 리디렉션됩니다.
- **실시간 할당량 추적** — 재설정 카운트다운(5시간, 매일, 매주)을 통해 실시간으로 토큰 소비를 표시합니다.
- **다중 계정 지원** — 자동 라운드 로빈 기능을 갖춘 공급자당 여러 계정 — 하나가 소진되면 다음 계정으로 전환
- **사용자 정의 콤보** — 6가지 균형 전략(채우기 우선, 라운드 로빈, P2C, 무작위, 최소 사용, 비용 최적화)을 갖춘 사용자 정의 가능한 폴백 체인
- **Codex 비즈니스 할당량** — 대시보드에서 직접 비즈니스/팀 작업 공간 할당량 모니터링
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "여러 공급자를 사용해야 하는데 각각 API가 다릅니다"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI는 하나의 형식을 사용하고 Claude(Anthropic)는 또 다른 형식을 사용하고 Gemini는 또 다른 형식을 사용합니다. 개발자가 다른 제공업체의 모델을 테스트하거나 이들 사이에서 대체하려는 경우 SDK를 재구성하고, 엔드포인트를 변경하고, 호환되지 않는 형식을 처리해야 합니다. 사용자 지정 공급자(FriendLI, NIM)에는 비표준 모델 끝점이 있습니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI Claude Gemini Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **통합 엔드포인트** — 단일 `http://localhost:20128/v1`가 36개 이상의 모든 공급자에 대한 프록시 역할을 합니다.
- **형식 번역** — 자동 및 투명함: OpenAI Claude Gemini Responses API
- **응답 삭제** — OpenAI SDK v1.83+를 손상시키는 비표준 필드(`x_groq`, `usage_breakdown`, `service_tier`)를 제거합니다.
- **역할 정규화** — OpenAI가 아닌 제공업체에 대해 `developer``system`로 변환합니다. GLM/ERNIE의 경우 `system``user`
- **Think Tag Extraction** — DeepSeek R1과 같은 모델에서 `<think>` 블록을 표준화된 `reasoning_content`로 추출합니다.
- **Gemini용 구조화된 출력** — `json_schema``responseMimeType`/`responseSchema` 자동 변환
- **`stream`의 기본값은 `false`** — OpenAI 사양에 맞춰 Python/Rust/Go SDK에서 예기치 않은 SSE를 방지합니다.
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. " AI 공급자가 내 지역/국가를 차단합니다."</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
OpenAI/Codex와 같은 공급자는 특정 지역의 액세스를 차단합니다. OAuth 및 API 연결 중에 사용자에게 `unsupported_country_region_territory`와 같은 오류가 발생합니다. 이는 특히 개발도상국의 개발자에게 실망스러운 일입니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3레벨 프록시 구성** — 3가지 레벨로 구성 가능한 프록시: 글로벌(모든 트래픽), 공급자별(하나의 공급자만), 연결/키별
- **색상으로 구분된 프록시 배지** — 시각적 표시기: 🟢 글로벌 프록시, 🟡 공급자 프록시, 🔵 연결 프록시, 항상 IP 표시
- **프록시를 통한 OAuth 토큰 교환** — OAuth 흐름도 프록시를 통과하여 `unsupported_country_region_territory`를 해결합니다.
- **프록시를 통한 연결 테스트** - 연결 테스트에서는 구성된 프록시를 사용합니다(더 이상 직접 우회 없음).
- **SOCKS5 지원** — 아웃바운드 라우팅을 위한 전체 SOCKS5 프록시 지원
- **TLS 지문 스푸핑** — `wreq-js`를 통한 브라우저와 유사한 TLS 지문으로 봇 감지 우회
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "AI로 코딩하고 싶은데 돈이 없어요"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
모든 사람이 AI 구독 비용으로 월 20~200달러를 지불할 수 있는 것은 아닙니다. 학생, 신흥 국가의 개발자, 취미생활자, 프리랜서는 무료로 고품질 모델에 액세스해야 합니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **무료 계층 제공자 내장** — 100% 무료 제공자에 대한 기본 지원: iFlow(8개 무제한 모델), Qwen(3개 무제한 모델), Kiro(Claude 무료), Gemini CLI(180K/월 무료)
- **무료 전용 콤보** — 체인 `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/월, 가동 중지 시간 없음
- **NVIDIA NIM 무료 크레딧** — 1000개의 무료 크레딧 통합
- **비용 최적화 전략** — 가장 저렴한 공급자를 자동으로 선택하는 라우팅 전략
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "AI 게이트웨이를 무단 액세스로부터 보호해야 합니다"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
AI 게이트웨이를 네트워크(LAN, VPS, Docker)에 노출하면 주소가 있는 사람은 누구나 개발자의 토큰/할당량을 사용할 수 있습니다. 보호하지 않으면 API는 오용, 즉각적인 주입, 남용에 취약해집니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API 키 관리** — 전용 `/dashboard/api-manager` 페이지를 사용하여 공급자별 생성, 순환 및 범위 지정
- **모델 수준 권한** — 모두 허용/제한 토글을 사용하여 API 키를 특정 모델(`openai/*`, 와일드카드 패턴)로 제한합니다.
- **API 엔드포인트 보호** — `/v1/models`에 대한 키가 필요하며 목록에서 특정 공급자를 차단합니다.
- **Auth Guard + CSRF 보호** — `withAuth` 미들웨어 + CSRF 토큰으로 보호되는 모든 대시보드 경로
- **속도 제한기** — 구성 가능한 창으로 IP당 속도 제한
- **IP 필터링** — 액세스 제어를 위한 허용 목록/차단 목록
- **프롬프트 주입 가드** — 악성 프롬프트 패턴 제거
- **AES-256-GCM 암호화** — 저장된 자격 증명은 암호화됩니다.
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "공급업체가 다운되어 코딩 흐름이 손실되었습니다."</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI 제공자는 불안정해지거나, 5xx 오류를 반환하거나, 임시 속도 제한에 도달할 수 있습니다. 개발자가 단일 공급자에 의존하는 경우 중단됩니다. 회로 차단기가 없으면 반복적으로 재시도하면 애플리케이션이 중단될 수 있습니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **공급업체별 회로 차단기** — 구성 가능한 임계값 및 쿨다운을 통한 자동 열기/닫기(닫힘/열림/반열림)
- **지수 백오프** — 점진적인 재시도 지연
- **Anti-Thundering Herd** — 동시 재시도 폭풍에 대한 뮤텍스 + 세마포어 보호
- **콤보 폴백 체인** — 기본 공급자가 실패하면 개입 없이 자동으로 체인을 통과합니다.
- **콤보 회로 차단기** — 콤보 체인 내에서 실패한 공급자를 자동으로 비활성화합니다.
- **상태 대시보드** — 가동 시간 모니터링, 회로 차단기 상태, 잠금, 캐시 통계, p50/p95/p99 대기 시간
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "각 AI 도구를 구성하는 것은 지루하고 반복적입니다."</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
개발자는 Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code 등을 사용합니다. 각 도구에는 서로 다른 구성(API 엔드포인트, 키, 모델)이 필요합니다. 공급자나 모델을 전환할 때 재구성하는 것은 시간 낭비입니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI 도구 대시보드** — Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline을 원클릭으로 설정할 수 있는 전용 페이지
- **GitHub Copilot Config Generator** — 대량 모델 선택을 통해 VS Code용 `chatLanguageModels.json`를 생성합니다.
- **온보딩 마법사** — 처음 사용자를 위한 4단계 설정 안내
- **하나의 엔드포인트, 모든 모델** — `http://localhost:20128/v1`를 한 번 구성하면 36개 이상의 공급자에 액세스할 수 있습니다.
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "여러 공급자의 OAuth 토큰 관리는 지옥입니다"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — 모두 만료되는 토큰과 함께 OAuth 2.0을 사용합니다. 개발자는 지속적으로 재인증을 수행하고 `client_secret is missing`, `redirect_uri_mismatch` 및 원격 서버의 오류를 처리해야 합니다. LAN/VPS의 OAuth는 특히 문제가 됩니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **자동 토큰 새로 고침** — OAuth 토큰이 만료되기 전에 백그라운드에서 새로 고쳐집니다.
- **OAuth 2.0(PKCE) 내장** — Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow에 대한 자동 흐름
- **다중 계정 OAuth** — JWT/ID 토큰 추출을 통해 공급자당 여러 계정
- **OAuth LAN/원격 수정** — `redirect_uri`에 대한 개인 IP 감지 + 원격 서버에 대한 수동 URL 모드
- **Nginx 뒤의 OAuth** — 역방향 프록시 호환성을 위해 `window.location.origin`를 사용합니다.
- **원격 OAuth 가이드** — VPS/Docker의 Google Cloud 자격 증명에 대한 단계별 가이드
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "얼마나 쓰고 있는지, 어디에 쓰는지 모르겠어요"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
개발자는 여러 유료 제공업체를 이용하지만 지출에 대한 통합된 보기가 없습니다. 각 제공업체에는 자체 청구 대시보드가 ​​있지만 통합된 보기는 없습니다. 예상치 못한 비용이 쌓일 수 있습니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **비용 분석 대시보드** — 토큰별 비용 추적 및 공급자별 예산 관리
- **계층당 예산 한도** — 자동 폴백을 트리거하는 계층당 지출 한도
- **모델별 가격 구성** — 모델당 가격 구성 가능
- **API 키당 사용 통계** — 키당 요청 수 및 마지막으로 사용된 타임스탬프
- **분석 대시보드** — 통계 카드, 모델 사용 차트, 성공률 및 대기 시간이 포함된 공급자 테이블
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "AI 호출 오류 및 문제 진단이 안 돼요"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
호출이 실패하면 개발자는 속도 제한, 만료된 토큰, 잘못된 형식 또는 공급자 오류인지 알 수 없습니다. 여러 터미널에 걸쳐 조각화된 로그. 관찰 가능성이 없으면 디버깅은 시행착오를 겪게 됩니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **통합 로그 대시보드** — 탭 4개: 요청 로그, 프록시 로그, 감사 로그, 콘솔
- **콘솔 로그 뷰어** — 색상으로 구분된 레벨, 자동 스크롤, 검색, 필터 기능을 갖춘 실시간 터미널 스타일 뷰어
- **SQLite 프록시 로그** — 서버를 다시 시작해도 지속되는 영구 로그
- **번역기 플레이그라운드** — 4가지 디버깅 모드: 플레이그라운드(형식 번역), 채팅 테스터(왕복), 테스트 벤치(일괄), 라이브 모니터(실시간)
- **원격 측정 요청** — p50/p95/p99 대기 시간 + X-요청-ID 추적
- **회전을 통한 파일 기반 로깅** — 콘솔 인터셉터는 크기 기반 회전을 통해 모든 것을 JSON 로그에 캡처합니다.
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "게이트웨이 배포 및 유지 관리가 복잡합니다."</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
다양한 환경(로컬, VPS, Docker, 클라우드)에서 AI 프록시를 설치, 구성 및 유지 관리하는 것은 노동 집약적입니다. 하드코딩된 경로, 디렉터리의 `EACCES`, 포트 충돌, 크로스 플랫폼 빌드와 같은 문제로 인해 마찰이 가중됩니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm 전역 설치** — `npm install -g omniroute && omniroute`완료
- **Docker 다중 플랫폼** — AMD64 + ARM64 기본(Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose 프로필** — `base`(CLI 도구 없음) 및 `cli`(Claude Code, Codex, OpenClaw 포함)
- **Electron 데스크탑 앱** — 시스템 트레이, 자동 시작, 오프라인 모드를 갖춘 Windows/macOS/Linux용 기본 앱
- **분할 포트 모드** — 고급 시나리오(역방향 프록시, 컨테이너 네트워킹)를 위한 별도의 포트에 있는 API 및 대시보드
- **클라우드 동기화** — Cloudflare Workers를 통해 장치 간 구성 동기화
- **DB 백업** — 모든 설정의 자동 백업, 복원, 내보내기 및 가져오기
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "인터페이스는 영어로만 제공되며 우리 팀은 영어를 구사하지 않습니다."</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
영어를 사용하지 않는 국가, 특히 라틴 아메리카, 아시아, 유럽의 팀은 영어 전용 인터페이스로 인해 어려움을 겪고 있습니다. 언어 장벽으로 인해 채택이 줄어들고 구성 오류가 증가합니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **대시보드 i18n — 30개 언어** — 한국어, 아랍어, 불가리아어, 덴마크어, 독일어, 스페인어, 핀란드어, 프랑스어, 히브리어, 힌디어, 헝가리어, 인도네시아어, 이탈리아어, 일본어, 말레이어, 네덜란드어, 노르웨이어, 폴란드어, 포르투갈어(PT/BR), 루마니아어, 러시아어, 슬로바키아어, 스웨덴어, 태국어, 우크라이나어, 베트남어, 중국어, 필리핀어, 영어를 포함한 500개 이상의 키 번역됨
- **RTL 지원** — 아랍어 및 히브리어에 대해 오른쪽에서 왼쪽으로 지원
- **다국어 README** — 30개의 완전한 문서 번역
- **언어 선택기** — 실시간 전환을 위한 헤더의 지구본 아이콘
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "채팅 이상의 것이 필요합니다. 임베딩, 이미지, 오디오가 필요합니다."</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI는 단순한 채팅 완성이 아닙니다. 개발자는 이미지를 생성하고, 오디오를 기록하고, RAG용 임베딩을 만들고, 문서 순위를 다시 지정하고, 콘텐츠를 조정해야 합니다. 각 API에는 서로 다른 엔드포인트와 형식이 있습니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **임베딩** — 6개 공급자와 9개 이상의 모델이 포함된 `/v1/embeddings`
- **이미지 생성** — 10개 공급자와 20개 이상의 모델(OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)을 갖춘 `/v1/images/generations`
- **텍스트-비디오** — `/v1/videos/generations` — ComfyUI(AnimateDiff, SVD) 및 SD WebUI
- **텍스트-음악** — `/v1/music/generations` — ComfyUI(안정적인 오디오 개방형, MusicGen)
- **오디오 녹음** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **텍스트 음성 변환** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + 기존 제공업체
- **조정** — `/v1/moderations` — 콘텐츠 안전 확인
- **재순위** — `/v1/rerank` — 문서 관련성 재지정
- **응답 API** — Codex에 대한 전체 `/v1/responses` 지원
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "모델별 품질을 테스트하고 비교할 방법이 없어요"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
개발자는 자신의 사용 사례(코드, 번역, 추론)에 가장 적합한 모델을 알고 싶어하지만 수동으로 비교하는 것은 느립니다. 통합 평가 도구가 없습니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM 평가** — 인사말, 수학, 지리, 코드 생성, JSON 준수, 번역, 마크다운, 안전 거부를 다루는 사전 로드된 10가지 사례를 사용한 골든 세트 테스트
- **4가지 일치 전략** — `exact`, `contains`, `regex`, `custom`(JS 함수)
- **번역기 플레이그라운드 테스트 벤치** — 여러 입력 및 예상 출력을 사용한 일괄 테스트, 공급업체 간 비교
- **채팅 테스터** — 시각적 응답 렌더링을 포함한 전체 왕복
- **라이브 모니터** — 프록시를 통해 흐르는 모든 요청의 실시간 스트림
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "성능 저하 없이 확장해야 합니다"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
요청량이 증가함에 따라 동일한 질문을 캐싱하지 않으면 중복 비용이 발생합니다. 멱등성이 없으면 중복 요청으로 인해 처리가 낭비됩니다. 공급자별 요금 제한을 준수해야 합니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **의미 체계 캐시** — 2계층 캐시(서명 + 의미 체계)로 비용과 대기 시간 감소
- **멱등성 요청** — 동일한 요청에 대한 중복 제거 기간은 5초입니다.
- **속도 제한 감지** — 제공업체별 RPM, 최소 간격 및 최대 동시 추적
- **편집 가능한 속도 제한** — 설정 → 지속성을 통한 복원력에서 구성 가능한 기본값
- **API 키 검증 캐시** — 프로덕션 성능을 위한 3계층 캐시
- **원격 측정 기능을 갖춘 상태 대시보드** — p50/p95/p99 대기 시간, 캐시 통계, 가동 시간
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "모델 동작을 전체적으로 제어하고 싶습니다"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
특정 언어, 특정 어조로 모든 응답을 원하거나 추론 토큰을 제한하려는 개발자. 모든 도구/요청에서 이를 구성하는 것은 비현실적입니다.
**How OmniRoute solves it:**
**OmniRoute가 이를 해결하는 방법:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **시스템 프롬프트 삽입** — 모든 요청에 전역 프롬프트 적용
- **생각 예산 검증** — 요청별 토큰 할당 제어 추론(패스스루, 자동, 사용자 정의, 적응형)
- **6가지 라우팅 전략** — 요청 배포 방법을 결정하는 글로벌 전략
- **와일드카드 라우터** — `provider/*` 패턴은 모든 공급자에게 동적으로 라우팅됩니다.
- **콤보 활성화/비활성화 토글** — 대시보드에서 직접 콤보를 토글합니다.
- **공급자 토글** — 한 번의 클릭으로 공급자에 대한 모든 연결을 활성화/비활성화합니다.
- **차단된 제공자** — `/v1/models` 목록에서 특정 제공자를 제외합니다.
</details>
<details>
<summary><b>🧰 17. "일류 제품 기능으로 MCP 도구가 필요합니다"</b></summary>
많은 AI 게이트웨이는 MCP를 숨겨진 구현 세부 사항으로만 노출합니다. 팀에는 가시적이고 관리 가능한 운영 레이어가 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- 대시보드 탐색 및 엔드포인트 프로토콜 탭에 MCP가 나타납니다.
- 프로세스, 도구, 범위 및 감사가 포함된 전용 MCP 관리 페이지
- `omniroute --mcp` 및 클라이언트 온보딩을 위한 빠른 시작 내장
</details>
<details>
<summary><b>🧠 18. "동기화 + 스트림 작업 경로를 갖춘 A2A 오케스트레이션이 필요합니다"</b></summary>
에이전트 워크플로에는 수명 주기 제어를 통해 직접 응답과 장기 실행 스트리밍 실행이 모두 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- `message/send``message/stream`가 포함된 A2A JSON-RPC 엔드포인트(`POST /a2a`)
- 터미널 상태 전파를 통한 SSE 스트리밍
- `tasks/get``tasks/cancel`용 작업 수명 주기 API
</details>
<details>
<summary><b>🛰️ 19. "추측된 상태가 아닌 실제 MCP 프로세스 상태가 필요합니다"</b></summary>
운영팀은 API에 접근할 수 있는지 여부뿐만 아니라 MCP가 실제로 활성화되어 있는지 알아야 합니다.
**OmniRoute가 이를 해결하는 방법:**
- PID, 타임스탬프, 전송, 도구 개수 및 범위 모드가 포함된 런타임 하트비트 파일
- 하트비트 + 최근 활동을 결합한 MCP 상태 API
- 프로세스/가동 시간/하트비트 최신성을 위한 UI 상태 카드
</details>
<details>
<summary><b>📋 20. "감사 가능한 MCP 도구 실행이 필요합니다"</b></summary>
도구가 구성을 변경하거나 운영 작업을 트리거하는 경우 팀에는 법의학적 추적성이 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- MCP 도구 호출에 대한 SQLite 지원 감사 로깅
- 도구, 성공/실패, API 키, 페이지 매김 기준으로 필터링
- 자동화를 위한 대시보드 감사 테이블 + 통계 엔드포인트
</details>
<details>
<summary><b>🔐 21. "통합당 범위가 지정된 MCP 권한이 필요합니다."</b></summary>
다양한 클라이언트에는 도구 범주에 대한 최소 권한 액세스 권한이 있어야 합니다.
**OmniRoute가 이를 해결하는 방법:**
- 제어된 도구 액세스를 위한 9개의 세분화된 MCP 범위
- MCP 관리 UI의 범위 적용 및 가시성
- 운영 툴링을 위한 안전한 기본 자세
</details>
<details>
<summary><b>⚙️ 22. "재배치 없이 작전 통제가 필요해요"</b></summary>
팀은 사고 또는 비용 이벤트 중에 빠른 런타임 변경이 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- MCP 대시보드에서 직접 콤보 활성화 전환
- 사전 정의된 정책 팩의 복원력 프로필 적용
- 동일한 운영 패널에서 회로 차단기 상태 재설정
</details>
<details>
<summary><b>🔄 23. "실시간 A2A 작업 수명주기 가시성 및 취소가 필요합니다"</b></summary>
수명주기 가시성이 없으면 작업 사고를 분류하기가 어려워집니다.
**OmniRoute가 이를 해결하는 방법:**
- 페이지 매김을 통한 상태/기술별 작업 목록/필터링
- 작업 메타데이터, 이벤트 및 아티팩트에 대한 드릴다운
- 작업 취소 끝점 및 확인이 포함된 UI 작업
</details>
<details>
<summary><b>🌊 24. "A2A 로드를 위한 활성 스트림 메트릭이 필요합니다"</b></summary>
스트리밍 워크플로에는 동시성 및 라이브 연결에 대한 운영 통찰력이 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- A2A 상태에 통합된 활성 스트림 카운터
- 마지막 작업 타임스탬프 및 상태별 개수
- 실시간 운영 모니터링을 위한 A2A 대시보드 카드
</details>
<details>
<summary><b>🪪 25. "클라이언트를 위한 표준 에이전트 검색이 필요합니다"</b></summary>
외부 클라이언트 및 오케스트레이터에는 온보딩을 위해 컴퓨터에서 읽을 수 있는 메타데이터가 필요합니다.
**OmniRoute가 이를 해결하는 방법:**
- `/.well-known/agent.json`에 노출된 에이전트 카드
- 관리 UI에 표시되는 능력과 기술
- A2A 상태 API에는 자동화를 위한 검색 메타데이터가 포함되어 있습니다.
</details>
<details>
<summary><b>🧭 26. "제품 UX에서 프로토콜 검색 기능이 필요합니다"</b></summary>
사용자가 프로토콜 표면을 발견할 수 없는 경우 채택 및 지원 품질이 저하됩니다.
**OmniRoute가 이를 해결하는 방법:**
- MCP 및 A2A용 사이드바 항목
- 빠른 시작 및 상태가 포함된 엔드포인트 페이지 프로토콜 탭
- 개요에서 전용 관리 대시보드로의 링크
</details>
<details>
<summary><b>🧪 27. "실제 클라이언트와의 엔드투엔드 프로토콜 검증이 필요합니다"</b></summary>
모의 테스트는 출시 전에 프로토콜 호환성을 검증하기에 충분하지 않습니다.
**OmniRoute가 이를 해결하는 방법:**
- 앱을 부팅하고 실제 MCP SDK 클라이언트 전송을 사용하는 E2E 제품군
- 흐름 검색, 전송, 스트리밍, 가져오기 및 취소에 대한 A2A 클라이언트 테스트
- MCP 감사 및 A2A 작업 API에 대한 교차 확인 주장
</details>
<details>
<summary><b>📡 28. "모든 인터페이스에 걸쳐 통합된 관찰 가능성이 필요합니다"</b></summary>
프로토콜별로 관찰 가능성을 분할하면 사각지대가 발생하고 MTTR이 길어집니다.
**OmniRoute가 이를 해결하는 방법:**
- 대시보드/로그/분석을 하나의 제품으로 통합
- OpenAI, MCP 및 A2A 계층 전반에 걸쳐 상태 + 감사 + 원격 측정 요청
- 상태 및 자동화를 위한 운영 API
</details>
<details>
<summary><b>💼 29. "프록시 + 도구 + 에이전트 오케스트레이션을 위해 하나의 런타임이 필요합니다."</b></summary>
여러 개별 서비스를 실행하면 운영 비용과 오류 모드가 증가합니다.
**OmniRoute가 이를 해결하는 방법:**
- OpenAI 호환 프록시, MCP 서버, A2A 서버가 하나의 스택에 있음
- 공유 인증, 복원력, 데이터 저장소 및 관찰 가능성
- 모든 상호 작용 표면에 걸쳐 일관된 정책 모델
</details>
<details>
<summary><b>🚀 30. "글루 코드 확장 없이 에이전트 워크플로를 제공해야 합니다."</b></summary>
여러 임시 서비스와 스크립트를 결합할 때 팀의 속도가 느려집니다.
**OmniRoute가 이를 해결하는 방법:**
- 클라이언트와 에이전트를 위한 통합 엔드포인트 전략
- 내장된 프로토콜 관리 UI 및 연기 검증 경로
- 프로덕션 준비 기반(보안, 로깅, 탄력성, 백업)
</details>
### 플레이북 예시(통합 사용 사례)
**플레이북 A: 유료 구독 극대화 + 저렴한 백업**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**플레이북 B: 비용이 전혀 들지 않는 코딩 스택**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**플레이북 C: 연중무휴 상시 가동 폴백 체인**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**플레이북 D: MCP + A2A를 사용한 에이전트 작업**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ 빠른 시작
**1. 전역적으로 설치:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ 데스크톱 앱 — 오프라인 & 상시 가동
## 🖥️
> 🆕 **새 기능!** OmniRoute가 Windows, macOS, Linux용 **네이티브 데스크톱 앱**으로 출시되었습니다.
@@ -715,66 +990,26 @@ OmniRoute에는 API 번역 디버깅, 테스트 및 모니터링을 위한 **4
</details>
---
## 🧪 평가(Evals)
## 🎯 사용 사례
OmniRoute에는 골든 세트에 대해 LLM 응답 품질을 테스트하기 위한 내장 평가 프레임워크가 포함되어 있습니다. 대시보드의 **분석 → 평가**를 통해 액세스하세요.
### 사례 1: "Claude Pro를 구독하고 있습니다."
### 내장 골든 세트
**문제:** 할당량은 사용되지 않은 상태로 만료되며, 코딩 작업이 많은 동안 속도 제한이 발생합니다.
사전 로드된 "OmniRoute Golden Set"에는 다음을 다루는 10개의 테스트 사례가 포함되어 있습니다.
```
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)
- 인사말, 수학, 지리, 코드 생성
- JSON 형식 준수, 번역, 마크다운
- 안전 거부(유해 콘텐츠), 카운팅, 부울 논리
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### 평가 전략
### 사례 2: "비용이 0이길 원합니다"
**문제:** 구독료를 감당할 수 없고 안정적인 AI 코딩이 필요함
```
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
```
### 사례 3: "중단 없이 연중무휴 코딩이 필요합니다."
**문제:** 마감일, 가동 중지 시간을 감당할 수 없음
```
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
```
### 사례 4: "OpenClaw에서 무료 AI를 원합니다"
**문제:** 메시징 앱에 AI 도우미가 필요하며 완전 무료입니다.
```
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...
```
| 전략 | 설명 | 예 |
| ---------- | -------------------------------------------------------------- | -------------------------------- |
| `exact` | 출력은 정확히 일치해야 합니다 | `"4"` |
| `contains` | 출력에는 하위 문자열(대소문자 구분 안 함)이 포함되어야 합니다. | `"Paris"` |
| `regex` | 출력은 정규식 패턴과 일치해야 합니다 | `"1.*2.*3"` |
| `custom` | 사용자 정의 JS 함수가 true/false를 반환합니다. | `(output) => output.length > 10` |
---
@@ -1058,29 +1293,6 @@ Settings → API Configuration:
---
## 🧪 평가(Evals)
OmniRoute에는 골든 세트에 대해 LLM 응답 품질을 테스트하기 위한 내장 평가 프레임워크가 포함되어 있습니다. 대시보드의 **분석 → 평가**를 통해 액세스하세요.
### 내장 골든 세트
사전 로드된 "OmniRoute Golden Set"에는 다음을 다루는 10개의 테스트 사례가 포함되어 있습니다.
- 인사말, 수학, 지리, 코드 생성
- JSON 형식 준수, 번역, 마크다운
- 안전 거부(유해 콘텐츠), 카운팅, 부울 논리
### 평가 전략
| 전략 | 설명 | 예 |
| ---------- | -------------------------------------------------------------- | -------------------------------- |
| `exact` | 출력은 정확히 일치해야 합니다 | `"4"` |
| `contains` | 출력에는 하위 문자열(대소문자 구분 안 함)이 포함되어야 합니다. | `"Paris"` |
| `regex` | 출력은 정규식 패턴과 일치해야 합니다 | `"1.*2.*3"` |
| `custom` | 사용자 정의 JS 함수가 true/false를 반환합니다. | `(output) => output.length > 10` |
---
## 🐛 문제 해결
<details>
@@ -1132,13 +1344,13 @@ OmniRoute에는 골든 세트에 대해 LLM 응답 품질을 테스트하기 위
- OmniRoute v1.0.6+에는 채팅 완료를 통한 대체 검증이 포함되어 있습니다.
- 기본 URL에 `/v1` 접미사가 포함되어 있는지 확인하세요.
### 🔐 OAuth em Servidor Remoto(원격 OAuth 설정)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ VPS/Docker/remotor의 OmniRoute를 사용하는 경우 중요**
### OAuth에서 Antigravity/Gemini CLI를 원격 서비스로 사용하려면 어떻게 해야 합니까?
### OAuth
Os는 **반중력****Gemini CLI**를 인증하기 위해 **Google OAuth 2.0**을 입증했습니다. O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pre-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1439,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ 기술 스택
## 🛠️
- **런타임**: Node.js 1822 LTS(⚠️ Node.js 24+는 **지원되지 않습니다**`better-sqlite3` 네이티브 바이너리는 호환되지 않습니다)
- **언어**: TypeScript 5.9 — `src/``open-sse/`에서 **100% TypeScript**(v1.0.6)
@@ -1279,18 +1491,19 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ 로드맵
## 🗺️
OmniRoute에는 여러 개발 단계에 걸쳐 **210개 이상의 기능이 계획되어 있습니다**. 주요 영역은 다음과 같습니다.
| 카테고리 | 계획된 기능 | 하이라이트 |
| --------------------------- | ----------- | ------------------------------------------------------------------------------ |
| 🧠 **라우팅 및 인텔리전스** | 25세 이상 | 최저 대기 시간 라우팅, 태그 기반 라우팅, 실행 전 할당량, P2C 계정 선택 |
| 🔒 **보안 및 규정 준수** | 20세 이상 | SSRF 강화, 자격 증명 클로킹, 엔드포인트당 속도 제한, 관리 키 범위 지정 |
| 📊 **관측성** | 15세 이상 | OpenTelemetry 통합, 실시간 할당량 모니터링, 모델별 비용 추적 |
| 🔄 **공급자 통합** | 20세 이상 | 동적 모델 레지스트리, 공급자 쿨다운, 다중 계정 Codex, Copilot 할당량 구문 분석 |
| **성능** | 15세 이상 | 듀얼 캐시 레이어, 프롬프트 캐시, 응답 캐시, 스트리밍 Keepalive, 배치 API |
| 🌐 **생태계** | 10세 이상 | WebSocket API, 구성 핫 리로드, 분산 구성 저장소, 상용 모드 |
| 카테고리 | 계획된 기능 | 하이라이트 |
| ---------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------ |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🧠 **라우팅 및 인텔리전스** | 25세 이상 | 최저 대기 시간 라우팅, 태그 기반 라우팅, 실행 전 할당량, P2C 계정 선택 |
| 🔒 **보안 및 규정 준수** | 20세 이상 | SSRF 강화, 자격 증명 클로킹, 엔드포인트당 속도 제한, 관리 키 범위 지정 |
| 📊 **관측성** | 15세 이상 | OpenTelemetry 통합, 실시간 할당량 모니터링, 모델별 비용 추적 |
| 🔄 **공급자 통합** | 20세 이상 | 동적 모델 레지스트리, 공급자 쿨다운, 다중 계정 Codex, Copilot 할당량 구문 분석 |
| **성능** | 15세 이상 | 듀얼 캐시 레이어, 프롬프트 캐시, 응답 캐시, 스트리밍 Keepalive, 배치 API |
| 🌐 **생태계** | 10세 이상 | WebSocket API, 구성 핫 리로드, 분산 구성 저장소, 상용 모드 |
### 🔜 출시 예정
@@ -1304,18 +1517,6 @@ OmniRoute에는 여러 개발 단계에 걸쳐 **210개 이상의 기능이 계
---
## 📧 지원
> 💬 **커뮤니티에 가입하세요!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — 도움을 받고, 팁을 공유하고, 최신 소식을 받아보세요.
- **웹사이트**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **문제**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **원래 프로젝트**: [9router by 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)

827
README.md
View File

@@ -1,16 +1,15 @@
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
# 🚀 OmniRoute — The Free AI Gateway
# 🚀 OmniRoute — The Free AI Gateway
### Never stop coding. Smart routing to **FREE & low-cost AI models** with automatic fallback.
_Your universal API proxy — one endpoint, 36+ providers, zero downtime._
_Your universal API proxy — one endpoint, 36+ providers, zero downtime. Now with **MCP & A2A** agent orchestration._
**Chat Completions • Embeddings • Image Generation • Video • Music • Audio • Reranking • 100% TypeScript**
**Chat Completions • Embeddings • Image Generation • Video • Music • Audio • Reranking • MCP Server • A2A Protocol • 100% TypeScript**
---
<div align="center">
[![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)
@@ -19,12 +18,41 @@ _Your universal API proxy — one endpoint, 36+ providers, zero downtime._
[🌐 Website](https://omniroute.online) • [🚀 Quick Start](#-quick-start) • [💡 Features](#-key-features) • [📖 Docs](#-documentation) • [💰 Pricing](#-pricing-at-a-glance) • [💬 WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
</div>
🌐 **Available in:** 🇺🇸 [English](README.md) | 🇧🇷 [Português (Brasil)](README.pt-BR.md) | 🇪🇸 [Español](README.es.md) | 🇫🇷 [Français](README.fr.md) | 🇮🇹 [Italiano](README.it.md) | 🇷🇺 [Русский](README.ru.md) | 🇨🇳 [中文 (简体)](README.zh-CN.md) | 🇩🇪 [Deutsch](README.de.md) | 🇮🇳 [हिन्दी](README.in.md) | 🇹🇭 [ไทย](README.th.md) | 🇺🇦 [Українська](README.uk-UA.md) | 🇸🇦 [العربية](README.ar.md) | 🇯🇵 [日本語](README.ja.md) | 🇻🇳 [Tiếng Việt](README.vi.md) | 🇧🇬 [Български](README.bg.md) | 🇩🇰 [Dansk](README.da.md) | 🇫🇮 [Suomi](README.fi.md) | 🇮🇱 [עברית](README.he.md) | 🇭🇺 [Magyar](README.hu.md) | 🇮🇩 [Bahasa Indonesia](README.id.md) | 🇰🇷 [한국어](README.ko.md) | 🇲🇾 [Bahasa Melayu](README.ms.md) | 🇳🇱 [Nederlands](README.nl.md) | 🇳🇴 [Norsk](README.no.md) | 🇵🇹 [Português (Portugal)](README.pt.md) | 🇷🇴 [Română](README.ro.md) | 🇵🇱 [Polski](README.pl.md) | 🇸🇰 [Slovenčina](README.sk.md) | 🇸🇪 [Svenska](README.sv.md) | 🇵🇭 [Filipino](README.phi.md)
---
## 🖼️ Main Dashboard
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute Dashboard" width="800"/>
</div>
---
## 📸 Dashboard Preview
<details>
<summary><b>Click to see dashboard screenshots</b></summary>
| Page | Screenshot |
| -------------- | ------------------------------------------------- |
| **Providers** | ![Providers](docs/screenshots/01-providers.png) |
| **Combos** | ![Combos](docs/screenshots/02-combos.png) |
| **Analytics** | ![Analytics](docs/screenshots/03-analytics.png) |
| **Health** | ![Health](docs/screenshots/04-health.png) |
| **Translator** | ![Translator](docs/screenshots/05-translator.png) |
| **Settings** | ![Settings](docs/screenshots/06-settings.png) |
| **CLI Tools** | ![CLI Tools](docs/screenshots/07-cli-tools.png) |
| **Usage Logs** | ![Usage](docs/screenshots/08-usage.png) |
| **Endpoints** | ![Endpoints](docs/screenshots/09-endpoint.png) |
</details>
---
### 🤖 Free AI Provider for your favorite coding agents
_Connect any AI-powered IDE or CLI tool through OmniRoute — free API gateway for unlimited coding._
@@ -32,7 +60,7 @@ _Connect any AI-powered IDE or CLI tool through OmniRoute — free API gateway f
<table>
<tr>
<td align="center" width="110">
<a href="https://github.com/cline/cline">
<a href="https://github.com/openclaw/openclaw">
<img src="./public/providers/openclaw.png" alt="OpenClaw" width="48"/><br/>
<b>OpenClaw</b>
</a><br/>
@@ -110,18 +138,6 @@ _Connect any AI-powered IDE or CLI tool through OmniRoute — free API gateway f
---
## 📧 Support
> 💬 **Join our community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Get help, share tips, and stay updated.
- **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**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Original Project**: [9router by decolua](https://github.com/decolua/9router)
---
## 🤔 Why OmniRoute?
**Stop wasting money and hitting limits:**
@@ -140,6 +156,19 @@ _Connect any AI-powered IDE or CLI tool through OmniRoute — free API gateway f
---
## 📧 Support
> 💬 **Join our community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Get help, share tips, and stay updated.
- **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**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Contributing**: See [CONTRIBUTING.md](CONTRIBUTING.md), open a PR, or pick a `good first issue`
- **Original Project**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 How It Works
```
@@ -169,9 +198,9 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 What OmniRoute Solves — 30 Real Pain Points & Use Cases
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to protocol operations and enterprise observability.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
@@ -260,7 +289,7 @@ AI providers can become unstable, return 5xx errors, or hit temporary rate limit
**How OmniRoute solves it:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Circuit Breaker per-model** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open), scoped per-model to avoid cascading blocks
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
@@ -428,23 +457,254 @@ Developers who want all responses in a specific language, with a specific tone,
</details>
<details>
<summary><b>🧰 17. "I need MCP tools as first-class product capabilities"</b></summary>
Many AI gateways expose MCP only as a hidden implementation detail. Teams need a visible, manageable operation layer.
**How OmniRoute solves it:**
- MCP appears in the dashboard navigation and endpoint protocol tab
- Dedicated MCP management page with process, tools, scopes, and audit
- Built-in quick-start for `omniroute --mcp` and client onboarding
</details>
<details>
<summary><b>🧠 18. "I need A2A orchestration with sync + stream task paths"</b></summary>
Agent workflows need both direct replies and long-running streamed execution with lifecycle control.
**How OmniRoute solves it:**
- A2A JSON-RPC endpoint (`POST /a2a`) with `message/send` and `message/stream`
- SSE streaming with terminal state propagation
- Task lifecycle APIs for `tasks/get` and `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "I need real MCP process health, not guessed status"</b></summary>
Operational teams need to know if MCP is actually alive, not just whether an API is reachable.
**How OmniRoute solves it:**
- Runtime heartbeat file with PID, timestamps, transport, tool count, and scope mode
- MCP status API combining heartbeat + recent activity
- UI status cards for process/uptime/heartbeat freshness
</details>
<details>
<summary><b>📋 20. "I need auditable MCP tool execution"</b></summary>
When tools mutate config or trigger ops actions, teams need forensic traceability.
**How OmniRoute solves it:**
- SQLite-backed audit logging for MCP tool calls
- Filters by tool, success/failure, API key, and pagination
- Dashboard audit table + stats endpoints for automation
</details>
<details>
<summary><b>🔐 21. "I need scoped MCP permissions per integration"</b></summary>
Different clients should have least-privilege access to tool categories.
**How OmniRoute solves it:**
- 9 granular MCP scopes for controlled tool access
- Scope enforcement and visibility in MCP management UI
- Safe default posture for operational tooling
</details>
<details>
<summary><b>⚙️ 22. "I need operational controls without redeploying"</b></summary>
Teams need quick runtime changes during incidents or cost events.
**How OmniRoute solves it:**
- Switch combo activation directly from MCP dashboard
- Apply resilience profiles from pre-defined policy packs
- Reset circuit breaker state from the same operations panel
</details>
<details>
<summary><b>🔄 23. "I need live A2A task lifecycle visibility and cancellation"</b></summary>
Without lifecycle visibility, task incidents become hard to triage.
**How OmniRoute solves it:**
- Task listing/filtering by state/skill with pagination
- Drill-down on task metadata, events, and artifacts
- Task cancellation endpoint and UI action with confirmation
</details>
<details>
<summary><b>🌊 24. "I need active stream metrics for A2A load"</b></summary>
Streaming workflows require operational insight into concurrency and live connections.
**How OmniRoute solves it:**
- Active stream counters integrated into A2A status
- Last task timestamp and per-state counts
- A2A dashboard cards for real-time ops monitoring
</details>
<details>
<summary><b>🪪 25. "I need standard agent discovery for clients"</b></summary>
External clients and orchestrators need machine-readable metadata for onboarding.
**How OmniRoute solves it:**
- Agent Card exposed at `/.well-known/agent.json`
- Capabilities and skills shown in management UI
- A2A status API includes discovery metadata for automation
</details>
<details>
<summary><b>🧭 26. "I need protocol discoverability in the product UX"</b></summary>
If users cannot discover protocol surfaces, adoption and support quality drop.
**How OmniRoute solves it:**
- Consolidated **Endpoints** page with tabs for Proxy, MCP, A2A, and API Endpoints
- Inline service status toggles (Online/Offline) for MCP and A2A
- Links from overview to dedicated management tabs
</details>
<details>
<summary><b>🧪 27. "I need end-to-end protocol validation with real clients"</b></summary>
Mock tests are not enough to validate protocol compatibility before release.
**How OmniRoute solves it:**
- E2E suite that boots app and uses real MCP SDK client transport
- A2A client tests for discovery, send, stream, get, and cancel flows
- Cross-check assertions against MCP audit and A2A tasks APIs
</details>
<details>
<summary><b>📡 28. "I need unified observability across all interfaces"</b></summary>
Splitting observability by protocol creates blind spots and longer MTTR.
**How OmniRoute solves it:**
- Unified dashboards/logs/analytics in one product
- Health + audit + request telemetry across OpenAI, MCP, and A2A layers
- Operational APIs for status and automation
</details>
<details>
<summary><b>💼 29. "I need one runtime for proxy + tools + agent orchestration"</b></summary>
Running many separate services increases operational cost and failure modes.
**How OmniRoute solves it:**
- OpenAI-compatible proxy, MCP server, and A2A server in one stack
- Shared auth, resilience, data store, and observability
- Consistent policy model across all interaction surfaces
</details>
<details>
<summary><b>🚀 30. "I need to ship agentic workflows without glue-code sprawl"</b></summary>
Teams lose velocity when stitching multiple ad-hoc services and scripts.
**How OmniRoute solves it:**
- Unified endpoint strategy for clients and agents
- Built-in protocol management UIs and smoke validation paths
- Production-ready foundations (security, logging, resilience, backup)
</details>
### Example Playbooks (Integrated Use Cases)
**Playbook A: Maximize paid subscription + cheap backup**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Zero-cost coding stack**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 always-on fallback chain**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Agent ops with MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/endpoint (MCP and A2A tabs)
4) Toggle services via inline status controls
```
---
## ⚡ Quick Start
**1. Install globally:**
### 1) Install and run
```bash
npm install -g omniroute
omniroute
```
🎉 Dashboard opens at `http://localhost:20128`
Dashboard opens at `http://localhost:20128` and API base URL is `http://localhost:20128/v1`.
| Command | Description |
| ----------------------- | ----------------------------------------------------------- |
| `omniroute` | Start server (`PORT=20128`, API and dashboard on same port) |
| `omniroute --port 3000` | Set canonical/API port to 3000 |
| `omniroute --mcp` | Start MCP server (stdio transport) |
| `omniroute --no-open` | Don't auto-open browser |
| `omniroute --help` | Show help |
@@ -456,24 +716,56 @@ PORT=20128 DASHBOARD_PORT=20129 omniroute
# Dashboard: http://localhost:20129
```
When ports are split, the API port serves only OpenAI-compatible routes (`/v1`, `/chat/completions`, `/responses`, `/models`, `/codex/*`).
### 2) Connect providers and create your API key
**2. Connect a FREE provider:**
1. Open Dashboard → `Providers` and connect at least one provider (OAuth or API key).
2. Open Dashboard → `Endpoints` and create an API key.
3. (Optional) Open Dashboard → `Combos` and set your fallback chain.
Dashboard → Providers → Connect **Claude Code** or **Antigravity** → OAuth login → Done!
### 3) Point your coding tool to OmniRoute
**3. Use in your CLI tool:**
```
Claude Code/Codex/Gemini CLI/OpenClaw/Cursor/Cline Settings:
Endpoint: http://localhost:20128/v1
API Key: [copy from dashboard]
Model: if/kimi-k2-thinking
```txt
Base URL: http://localhost:20128/v1
API Key: [copy from Endpoint page]
Model: if/kimi-k2-thinking (or any provider/model prefix)
```
**That's it!** Start coding with FREE AI models.
Works with Claude Code, Codex CLI, Gemini CLI, Cursor, Cline, OpenClaw, OpenCode, and OpenAI-compatible SDKs.
**Alternative — run from source:**
### 4) Enable and validate protocols (v2.0)
**MCP (for tool-driven operations):**
```bash
omniroute --mcp
```
Then connect your MCP client over `stdio` and test tools like:
- `omniroute_get_health`
- `omniroute_list_combos`
**A2A (for agent-to-agent workflows):**
```bash
curl http://localhost:20128/.well-known/agent.json
```
```bash
curl -X POST http://localhost:20128/a2a \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":"quickstart","method":"message/send","params":{"skill":"quota-management","messages":[{"role":"user","content":"Give me a short quota summary."}]}}'
```
### 5) Validate everything end-to-end (recommended)
```bash
npm run test:protocols:e2e
```
This suite validates real MCP and A2A client flows against a running app.
### Alternative: run from source
```bash
cp .env.example .env
@@ -594,233 +886,227 @@ When minimized, OmniRoute lives in your system tray with quick actions:
## 💡 Key Features
### 🧠 Core Routing & Intelligence
OmniRoute v2.0 is built as an operational platform, not just a relay proxy.
| Feature | What It Does |
| ------------------------------- | ------------------------------------------------------------------------------ |
| 🎯 **Smart 4-Tier Fallback** | Auto-route: Subscription → API Key → Cheap → Free |
| 📊 **Real-Time Quota Tracking** | Live token count + reset countdown per provider |
| 🔄 **Format Translation** | OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro seamless + response sanitization |
| 👥 **Multi-Account Support** | Multiple accounts per provider with intelligent selection |
| 🔄 **Auto Token Refresh** | OAuth tokens refresh automatically with retry |
| 🎨 **Custom Combos** | 6 strategies: fill-first, round-robin, p2c, random, least-used, cost-optimized |
| 🧩 **Custom Models** | Add any model ID to any provider |
| 🌐 **Wildcard Router** | Route `provider/*` patterns to any provider dynamically |
| 🧠 **Thinking Budget** | Passthrough, auto, custom, and adaptive modes for reasoning models |
| 🔀 **Model Aliases** | Auto-forward deprecated model IDs to current replacements (built-in + custom) |
| **Background Degradation** | Auto-route background tasks (titles, summaries) to cheaper models |
| 💬 **System Prompt Injection** | Global system prompt applied across all requests |
| 📄 **Responses API** | Full OpenAI Responses API (`/v1/responses`) support for Codex |
### 🤖 Agent & Protocol Operations (v2.0)
| Feature | What It Does |
| ------------------------------------- | -------------------------------------------------------------------------------------------------- |
| 🔧 **MCP Server (16 tools)** | IDE/agent tools via 3 transports: stdio, SSE (`/api/mcp/sse`), Streamable HTTP (`/api/mcp/stream`) |
| 🤝 **A2A Server (JSON-RPC + SSE)** | Agent-to-agent task execution with sync and streaming flows |
| 🧭 **Consolidated Endpoints Page** | Tabbed management page with Endpoint Proxy, MCP, A2A, and API Endpoints tabs |
| 🎚️ **Service Enable/Disable Toggles** | ON/OFF switches for MCP and A2A with settings persistence (default: OFF) |
| 🛰️ **MCP Runtime Heartbeat** | Real process status (pid, uptime, heartbeat age, transport, scope mode) |
| 📋 **MCP Audit Trail** | Filterable audit logs with success/failure and key attribution |
| 🔐 **MCP Scope Enforcement** | 9 granular scope permissions for controlled tool access |
| 📡 **A2A Task Lifecycle Management** | List/filter tasks, inspect events/artifacts, cancel running tasks |
| 📋 **Agent Card Discovery** | `/.well-known/agent.json` for client auto-discovery |
| 🧪 **Protocol E2E Test Harness** | Real MCP SDK + A2A client flows in `test:protocols:e2e` |
| ⚙️ **Operational Controls** | Switch combo, apply resilience profiles, reset breakers from one control surface |
### 🧠 Routing & Intelligence
| Feature | What It Does |
| ---------------------------------- | --------------------------------------------------------------------- |
| 🎯 **Smart 4-Tier Fallback** | Auto-route: Subscription → API Key → Cheap → Free |
| 📊 **Real-Time Quota Tracking** | Live token count + reset countdown per provider |
| 🔄 **Format Translation** | OpenAI ↔ Claude ↔ Gemini ↔ Responses with schema-safe conversions |
| 👥 **Multi-Account Support** | Multiple accounts per provider with intelligent selection |
| 🔄 **Auto Token Refresh** | OAuth tokens refresh automatically with retry |
| 🎨 **Custom Combos** | 6 balancing strategies + fallback chain control |
| 🌐 **Wildcard Router** | `provider/*` dynamic routing |
| 🧠 **Thinking Budget Controls** | Passthrough, auto, custom, and adaptive reasoning limits |
| 🔀 **Model Aliases** | Built-in + custom model aliasing and migration safety |
| ⚡ **Background Degradation** | Route low-priority background tasks to cheaper models |
| 💬 **System Prompt Injection** | Global behavior controls applied consistently |
| 📄 **Responses API Compatibility** | Full `/v1/responses` support for Codex and advanced agentic workflows |
### 🎵 Multi-Modal APIs
| Feature | What It Does |
| -------------------------- | -------------------------------------------------------------------------------- |
| 🖼️ **Image Generation** | `/v1/images/generations` — 10 providers, 20+ models (cloud + local) |
| 📐 **Embeddings** | `/v1/embeddings` — 6 providers, 9+ models |
| 🎤 **Audio Transcription** | `/v1/audio/transcriptions` Whisper + Nvidia NIM, HuggingFace, Qwen3 |
| 🔊 **Text-to-Speech** | `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 |
| 🎬 **Video Generation** | `/v1/videos/generations` ComfyUI (AnimateDiff, SVD), SD WebUI |
| 🎵 **Music Generation** | `/v1/music/generations` ComfyUI (Stable Audio Open, MusicGen) |
| 🛡️ **Moderations** | `/v1/moderations` — Content safety checks |
| 🔀 **Reranking** | `/v1/rerank` — Document relevance reranking |
| Feature | What It Does |
| -------------------------- | ------------------------------------------------------------- |
| 🖼️ **Image Generation** | `/v1/images/generations` with cloud and local backends |
| 📐 **Embeddings** | `/v1/embeddings` for search and RAG pipelines |
| 🎤 **Audio Transcription** | `/v1/audio/transcriptions` (Whisper and additional providers) |
| 🔊 **Text-to-Speech** | `/v1/audio/speech` (multiple engines/providers) |
| 🎬 **Video Generation** | `/v1/videos/generations` (ComfyUI + SD WebUI workflows) |
| 🎵 **Music Generation** | `/v1/music/generations` (ComfyUI workflows) |
| 🛡️ **Moderations** | `/v1/moderations` safety checks |
| 🔀 **Reranking** | `/v1/rerank` for relevance scoring |
### 🛡️ Resilience & Security
### 🛡️ Resilience, Security & Governance
| Feature | What It Does |
| ------------------------------- | ----------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Auto-open/close per-provider with configurable thresholds |
| 🛡️ **Anti-Thundering Herd** | Mutex + semaphore rate-limit for API key providers |
| 🧠 **Semantic Cache** | Two-tier cache (signature + semantic) reduces cost & latency |
| **Request Idempotency** | 5s dedup window for duplicate requests |
| 🔒 **TLS Fingerprint Spoofing** | Bypass TLS-based bot detection via wreq-js |
| 🌐 **IP Filtering** | Allowlist/blocklist for API access control |
| 📊 **Editable Rate Limits** | Configurable RPM, min gap, and max concurrent at system level |
| 💾 **Rate Limit Persistence** | Learned limits survive restarts via SQLite with 60s debounce + 24h staleness |
| 🔄 **Token Refresh Resilience** | Per-provider circuit breaker (5 fails→30min) + 30s timeout per attempt |
| 🛡 **API Endpoint Protection** | Auth gating + provider blocking for the `/models` endpoint |
| 🔒 **Proxy Visibility** | Color-coded badges: 🟢 global, 🟡 provider, 🔵 per-connection with IP display |
| 🌐 **3-Level Proxy Config** | Configure proxies at global, per-provider, or per-connection level |
| Feature | What It Does |
| ----------------------------------- | ---------------------------------------------------------- |
| 🔌 **Circuit Breakers** | Per-model trip/recover with threshold controls |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-Thundering Herd** | Mutex + semaphore protections on retry/rate events |
| 🧠 **Semantic + Signature Cache** | Cost/latency reduction with two cache layers |
| **Request Idempotency** | Duplicate protection window |
| 🔒 **TLS Fingerprint Spoofing** | Better compatibility with anti-bot filtered providers |
| 🌐 **IP Filtering** | Allowlist/blocklist control for exposed deployments |
| 📊 **Editable Rate Limits** | Configurable global/provider-level limits with persistence |
| 🔑 **API Key Management + Scoping** | Secure key issuance/rotation and model/provider controls |
| 🛡 **Protected `/models`** | Optional auth gating and provider hiding for model catalog |
### 📊 Observability & Analytics
| Feature | What It Does |
| -------------------------- | ---------------------------------------------------------------------- |
| 📝 **Request Logging** | Debug mode with full request/response logs |
| 💾 **SQLite Proxy Logs** | Persistent proxy logs survive server restarts |
| 📊 **Analytics Dashboard** | Recharts-powered: stat cards, model usage chart, provider table |
| 📈 **Progress Tracking** | Opt-in SSE progress events for streaming |
| 🧪 **LLM Evaluations** | Golden set testing with 4 match strategies |
| 🔍 **Request Telemetry** | p50/p95/p99 latency aggregation + X-Request-Id tracing |
| 📋 **Logs Dashboard** | Unified 4-tab page: Request Logs, Proxy Logs, Audit Logs, Console |
| 🖥️ **Console Log Viewer** | Real-time terminal-style viewer with level filter, search, auto-scroll |
| 📑 **File-Based Logging** | Console interceptor captures all output to JSON log file with rotation |
| 🏥 **Health Dashboard** | System uptime, circuit breaker states, lockouts, cache stats |
| 💰 **Cost Tracking** | Budget management + per-model pricing configuration |
| Feature | What It Does |
| ------------------------------- | ----------------------------------------------------- |
| 📝 **Request + Proxy Logging** | Full request/response and proxy logging |
| 📋 **Unified Logs Dashboard** | Request, proxy, audit, and console views in one page |
| 🔍 **Request Telemetry** | p50/p95/p99 latency and request tracing |
| 🏥 **Health Dashboard** | Uptime, breaker states, lockouts, cache stats |
| 💰 **Cost Tracking** | Budget controls and per-model pricing visibility |
| 📈 **Analytics Visualizations** | Model/provider usage insights and trend views |
| 🧪 **Evaluation Framework** | Golden set testing with configurable match strategies |
### ☁️ Deployment & Sync
### ☁️ Deployment & Platform
| Feature | What It Does |
| ---------------------------- | --------------------------------------------------------------------- |
| 💾 **Cloud Sync** | Sync config across devices via Cloudflare Workers |
| 🌐 **Deploy Anywhere** | Localhost, VPS, Docker, Cloudflare Workers |
| 🔑 **API Key Management** | Generate, rotate, and scope API keys per provider |
| 🧙 **Onboarding Wizard** | 4-step guided setup for first-time users |
| 🔧 **CLI Tools Dashboard** | One-click configure Claude, Codex, Cline, OpenClaw, Kilo, Antigravity |
| 🔄 **DB Backups** | Automatic backup, restore, export & import for all settings |
| 🌐 **Internationalization** | Full i18n with next-intl — 30 languages including RTL support |
| 🌍 **Language Selector** | Globe icon in header for real-time switching between 30 languages |
| 📂 **Custom Data Directory** | `DATA_DIR` env var to override default `~/.omniroute` storage path |
| Feature | What It Does |
| ---------------------------- | -------------------------------------------------------- |
| 🌐 **Deploy Anywhere** | Localhost, VPS, Docker, Cloud environments |
| 💾 **Cloud Sync** | Configuration sync via cloud worker |
| 🔄 **Backup/Restore** | Export/import and disaster recovery flows |
| 🧙 **Onboarding Wizard** | First-run guided setup |
| 🔧 **CLI Tools Dashboard** | One-click setup for popular coding tools |
| 🌐 **i18n (30 languages)** | Full dashboard + docs language support with RTL coverage |
| 📂 **Custom Data Directory** | `DATA_DIR` override for storage location |
<details>
<summary><b>📖 Feature Details</b></summary>
### Feature Deep Dive
### 🎯 Smart 4-Tier Fallback
#### Smart fallback with practical cost control
Create combos with automatic fallback:
```
```txt
Combo: "my-coding-stack"
1. cc/claude-opus-4-6 (your subscription)
2. nvidia/llama-3.3-70b (free NVIDIA API)
3. glm/glm-4.7 (cheap backup, $0.6/1M)
4. if/kimi-k2-thinking (free fallback)
→ Auto switches when quota runs out or errors occur
1. cc/claude-opus-4-6
2. nvidia/llama-3.3-70b
3. glm/glm-4.7
4. if/kimi-k2-thinking
```
### 📊 Real-Time Quota Tracking
When quota, rate, or health fails, OmniRoute automatically moves to the next candidate without manual switching.
- Token consumption per provider
- Reset countdown (5-hour, daily, weekly)
- Cost estimation for paid tiers
- Monthly spending reports
#### Protocol management that is visible and operable
### 🔄 Format Translation
- MCP + A2A are discoverable in UI and docs (not hidden)
- Protocol status APIs expose live operational data (`/api/mcp/*`, `/api/a2a/*`)
- Dashboards include actions for day-2 ops (combo toggles, breaker resets, task cancellation)
Seamless translation between formats:
#### Translator + validation workflow
- **OpenAI** ↔ **Claude****Gemini****OpenAI Responses**
- Your CLI tool sends OpenAI format → OmniRoute translates → Provider receives native format
- Works with any tool that supports custom OpenAI endpoints
- **Response sanitization** — Strips non-standard fields for strict OpenAI SDK compatibility
- **Role normalization** — `developer``system` for non-OpenAI; `system``user` for GLM/ERNIE models
- **Think tag extraction** — `<think>` blocks → `reasoning_content` for thinking models
- **Structured output** — `json_schema` → Gemini's `responseMimeType`/`responseSchema`
The Translator area includes:
### 👥 Multi-Account Support
- **Playground**: request transformation checks
- **Chat Tester**: full request/response round-trip
- **Test Bench**: multiple cases in one run
- **Live Monitor**: real-time traffic view
- Add multiple accounts per provider
- Auto round-robin or priority-based routing
- Fallback to next account when one hits quota
Plus protocol validation with real clients via `npm run test:protocols:e2e`.
### 🔄 Auto Token Refresh
> 📖 **[MCP Server README](open-sse/mcp-server/README.md)** — Tool reference, IDE configs, and client examples
>
> 📖 **[A2A Server README](src/lib/a2a/README.md)** — Skills, JSON-RPC methods, streaming, and task lifecycle
- OAuth tokens automatically refresh before expiration
- No manual re-authentication needed
- Seamless experience across all providers
## 🧪 Evaluations (Evals)
### 🎨 Custom Combos
OmniRoute includes a built-in evaluation framework to test LLM response quality against a golden set. Access it via **Analytics → Evals** in the dashboard.
- Create unlimited model combinations
- 6 strategies: fill-first, round-robin, power-of-two-choices, random, least-used, cost-optimized
- Share combos across devices with Cloud Sync
### Built-in Golden Set
### 🏥 Health Dashboard
The pre-loaded "OmniRoute Golden Set" contains test cases for:
- System status (uptime, version, memory usage)
- Circuit breaker states per provider (Closed/Open/Half-Open)
- Rate limit status and active lockouts
- Signature cache statistics
- Latency telemetry (p50/p95/p99) + prompt cache
- Reset health status with one click
- Greetings, math, geography, code generation
- JSON format compliance, translation, markdown generation
- Safety refusal (harmful content), counting, boolean logic
### 🔧 Translator Playground
### Evaluation Strategies
OmniRoute includes a powerful built-in Translator Playground with **4 modes** for debugging, testing, and monitoring API translations:
| Mode | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **💻 Playground** | Direct format translation — paste any API request body and instantly see how OmniRoute translates it between provider formats (OpenAI ↔ Claude ↔ Gemini ↔ Responses API). Includes example templates and format auto-detection. |
| **💬 Chat Tester** | Send real chat requests through OmniRoute and see the full round-trip: your input, the translated request, the provider response, and the translated response back. Invaluable for validating combo routing. |
| **🧪 Test Bench** | Batch testing mode — define multiple test cases with different inputs and expected outputs, run them all at once, and compare results across providers and models. |
| **📱 Live Monitor** | Real-time request monitoring — watch incoming requests as they flow through OmniRoute, see format translations happening live, and identify issues instantly. |
**Access:** Dashboard → Translator (sidebar)
### 💾 Cloud Sync
- Sync providers, combos, and settings across devices
- Automatic background sync
- Secure encrypted storage
</details>
---
## 🎯 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
```
### 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...
```
| Strategy | Description | Example |
| ---------- | ------------------------------------------------ | -------------------------------- |
| `exact` | Output must match exactly | `"4"` |
| `contains` | Output must contain substring (case-insensitive) | `"Paris"` |
| `regex` | Output must match regex pattern | `"1.*2.*3"` |
| `custom` | Custom JS function returns true/false | `(output) => output.length > 10` |
---
## 📖 Setup Guide
### Protocol Setup (MCP + A2A)
<details>
<summary><b>🧩 MCP Setup (Model Context Protocol)</b></summary>
Start MCP transport in stdio mode:
```bash
omniroute --mcp
```
Recommended validation flow:
1. Connect your MCP client over stdio.
2. Run `omniroute_get_health`.
3. Run `omniroute_list_combos`.
4. Open `/dashboard/mcp` to confirm heartbeat, activity, and audit.
Useful APIs for automation:
- `GET /api/mcp/status`
- `GET /api/mcp/tools`
- `GET /api/mcp/audit`
- `GET /api/mcp/audit/stats`
</details>
<details>
<summary><b>🤝 A2A Setup (Agent2Agent)</b></summary>
Discover the agent:
```bash
curl http://localhost:20128/.well-known/agent.json
```
Send a task:
```bash
curl -X POST http://localhost:20128/a2a \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":"setup-a2a","method":"message/send","params":{"skill":"quota-management","messages":[{"role":"user","content":"Summarize quota status."}]}}'
```
Manage lifecycle:
- `GET /api/a2a/status`
- `GET /api/a2a/tasks`
- `GET /api/a2a/tasks/:id`
- `POST /api/a2a/tasks/:id/cancel`
Operational UI:
- `/dashboard/a2a` for task/state/stream observability and smoke actions
</details>
<details>
<summary><b>🧪 End-to-end protocol validation</b></summary>
Validate both protocols with real clients:
```bash
npm run test:protocols:e2e
```
This verifies:
- MCP SDK client connect/list/call
- A2A discovery/send/stream/get/cancel
- Cross-check data in MCP audit and A2A task management APIs
</details>
<details>
<summary><b>💳 Subscription Providers</b></summary>
@@ -1140,29 +1426,6 @@ opencode
---
## 🧪 Evaluations (Evals)
OmniRoute includes a built-in evaluation framework to test LLM response quality against a golden set. Access it via **Analytics → Evals** in the dashboard.
### Built-in Golden Set
The pre-loaded "OmniRoute Golden Set" contains 10 test cases covering:
- Greetings, math, geography, code generation
- JSON format compliance, translation, markdown
- Safety refusal (harmful content), counting, boolean logic
### Evaluation Strategies
| Strategy | Description | Example |
| ---------- | ------------------------------------------------ | -------------------------------- |
| `exact` | Output must match exactly | `"4"` |
| `contains` | Output must contain substring (case-insensitive) | `"Paris"` |
| `regex` | Output must match regex pattern | `"1.*2.*3"` |
| `custom` | Custom JS function returns true/false | `(output) => output.length > 10` |
---
## 🐛 Troubleshooting
<details>
@@ -1314,53 +1577,45 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
## 🛠️ Tech Stack
<details>
<summary><b>Click to expand tech stack details</b></summary>
- **Runtime**: Node.js 1822 LTS (⚠️ Node.js 24+ is **not supported**`better-sqlite3` native binaries are incompatible)
- **Language**: TypeScript 5.9 — **100% TypeScript** across `src/` and `open-sse/` (v1.0.6)
- **Language**: TypeScript 5.9 — **100% TypeScript** across `src/` and `open-sse/` (zero `any` in core modules since v2.0)
- **Framework**: Next.js 16 + React 19 + Tailwind CSS 4
- **Database**: LowDB (JSON) + SQLite (domain state + proxy logs)
- **Database**: LowDB (JSON) + SQLite (domain state + proxy logs + MCP audit + routing decisions)
- **Schemas**: Zod (MCP tool I/O validation, API contracts)
- **Protocols**: MCP (stdio/HTTP) + A2A v0.3 (JSON-RPC 2.0 + SSE)
- **Streaming**: Server-Sent Events (SSE)
- **Auth**: OAuth 2.0 (PKCE) + JWT + API Keys
- **Testing**: Node.js test runner (368+ unit tests)
- **Auth**: OAuth 2.0 (PKCE) + JWT + API Keys + MCP Scoped Authorization
- **Testing**: Node.js test runner + Vitest (900+ tests including unit, integration, E2E)
- **CI/CD**: GitHub Actions (auto npm publish + Docker Hub on release)
- **Website**: [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)
- **Resilience**: Circuit breaker, exponential backoff, anti-thundering herd, TLS spoofing
- **Resilience**: Circuit breaker, exponential backoff, anti-thundering herd, TLS spoofing, auto-combo self-healing
</details>
---
## 📖 Documentation
| Document | Description |
| -------------------------------------------- | ---------------------------------------------- |
| [User Guide](docs/USER_GUIDE.md) | Providers, combos, CLI integration, deployment |
| [API Reference](docs/API_REFERENCE.md) | All endpoints with examples |
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Common problems and solutions |
| [Architecture](docs/ARCHITECTURE.md) | System architecture and internals |
| [Contributing](CONTRIBUTING.md) | Development setup and guidelines |
| [OpenAPI Spec](docs/openapi.yaml) | OpenAPI 3.0 specification |
| [Security Policy](SECURITY.md) | Vulnerability reporting and security practices |
| [VM Deployment](docs/VM_DEPLOYMENT_GUIDE.md) | Complete guide: VM + nginx + Cloudflare setup |
| [Features Gallery](docs/FEATURES.md) | Visual dashboard tour with screenshots |
### 📸 Dashboard Preview
<details>
<summary><b>Click to see dashboard screenshots</b></summary>
| Page | Screenshot |
| -------------- | ------------------------------------------------- |
| **Providers** | ![Providers](docs/screenshots/01-providers.png) |
| **Combos** | ![Combos](docs/screenshots/02-combos.png) |
| **Analytics** | ![Analytics](docs/screenshots/03-analytics.png) |
| **Health** | ![Health](docs/screenshots/04-health.png) |
| **Translator** | ![Translator](docs/screenshots/05-translator.png) |
| **Settings** | ![Settings](docs/screenshots/06-settings.png) |
| **CLI Tools** | ![CLI Tools](docs/screenshots/07-cli-tools.png) |
| **Usage Logs** | ![Usage](docs/screenshots/08-usage.png) |
| **Endpoint** | ![Endpoint](docs/screenshots/09-endpoint.png) |
</details>
| Document | Description |
| ---------------------------------------------- | --------------------------------------------------- |
| [User Guide](docs/USER_GUIDE.md) | Providers, combos, CLI integration, deployment |
| [API Reference](docs/API_REFERENCE.md) | All endpoints with examples |
| [MCP Server](open-sse/mcp-server/README.md) | 16 MCP tools, IDE configs, Python/TS/Go clients |
| [A2A Server](src/lib/a2a/README.md) | JSON-RPC 2.0 protocol, skills, streaming, task mgmt |
| [Auto-Combo Engine](docs/auto-combo.md) | 6-factor scoring, mode packs, self-healing |
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Common problems and solutions |
| [Architecture](docs/ARCHITECTURE.md) | System architecture and internals |
| [Contributing](CONTRIBUTING.md) | Development setup and guidelines |
| [OpenAPI Spec](docs/openapi.yaml) | OpenAPI 3.0 specification |
| [Security Policy](SECURITY.md) | Vulnerability reporting and security practices |
| [VM Deployment](docs/VM_DEPLOYMENT_GUIDE.md) | Complete guide: VM + nginx + Cloudflare setup |
| [Features Gallery](docs/FEATURES.md) | Visual dashboard tour with screenshots |
| [Release Checklist](docs/RELEASE_CHECKLIST.md) | Pre-release validation steps |
---
@@ -1407,7 +1662,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
```bash
# Create a release — npm publish happens automatically
gh release create v1.0.6 --title "v1.0.6" --generate-notes
gh release create v2.0.0 --title "v2.0.0" --generate-notes
```
---

View File

@@ -110,6 +110,35 @@ _Sambungkan mana-mana alat IDE atau CLI berkuasa AI melalui OmniRoute — get la
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Mengapa OmniRoute?
**Berhenti membazir wang dan mencapai had:**
@@ -128,6 +157,18 @@ _Sambungkan mana-mana alat IDE atau CLI berkuasa AI melalui OmniRoute — get la
---
## 📧 Sokongan
> 💬 **Sertai komuniti kami!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Dapatkan bantuan, kongsi petua dan kekal kemas kini.
- **Laman web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Isu**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projek Asal**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Cara Ia Berfungsi
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Perkara yang Selesaikan OmniRoute — 30 Titik Sakit Nyata & Kes Penggunaan
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Setiap pembangun yang menggunakan alatan AI menghadapi masalah ini setiap hari.** OmniRoute dibina untuk menyelesaikan kesemuanya — daripada lebihan kos kepada blok serantau, daripada aliran OAuth yang rosak kepada operasi protokol dan kebolehmerhatian perusahaan.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Saya membayar untuk langganan yang mahal tetapi masih terganggu oleh had"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Pembangun membayar $20200/bulan untuk Claude Pro, Codex Pro atau GitHub Copilot. Walaupun membayar, kuota mempunyai siling — 5j penggunaan, had mingguan atau had kadar seminit. Sesi pertengahan pengekodan, pembekal berhenti bertindak balas dan pembangun kehilangan aliran dan produktiviti.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Jika kuota langganan habis, diubah hala secara automatik ke API Key → Murah → Percuma tanpa campur tangan manual
- **Penjejakan Kuota Masa Nyata** — Menunjukkan penggunaan token dalam masa nyata dengan kira detik tetapan semula (5j, harian, mingguan)
- **Sokongan Berbilang Akaun** — Berbilang akaun bagi setiap pembekal dengan auto round-robin — apabila satu kehabisan, beralih kepada yang seterusnya
- **Kombo Tersuai** — Rantaian sandaran yang boleh disesuaikan dengan 6 strategi pengimbangan (isi dahulu, round-robin, P2C, rawak, paling kurang digunakan, dioptimumkan kos)
- **Kuota Perniagaan Codex** — Pemantauan kuota ruang kerja Perniagaan/Pasukan terus dalam papan pemuka
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Saya perlu menggunakan berbilang penyedia tetapi setiap satu mempunyai API yang berbeza"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI menggunakan satu format, Claude (Anthropic) menggunakan satu lagi, Gemini satu lagi. Jika pembangun ingin menguji model daripada pembekal yang berbeza atau sandaran antara mereka, mereka perlu mengkonfigurasi semula SDK, menukar titik akhir, menangani format yang tidak serasi. Pembekal tersuai (FriendLI, NIM) mempunyai titik akhir model bukan standard.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Titik Akhir Disatukan** — Satu `http://localhost:20128/v1` berfungsi sebagai proksi untuk kesemua 36+ pembekal
- **Format Terjemahan** — Automatik dan telus: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Pembersihan Tindak Balas** — Mengosongkan medan bukan standard (`x_groq`, `usage_breakdown`, `service_tier`) yang memecahkan OpenAI SDK v1.83+
- **Penormalan Peranan** — Menukar `developer``system` untuk penyedia bukan OpenAI; `system``user` untuk GLM/ERNIE
- **Think Tag Extraction** — Mengekstrak blok `<think>` daripada model seperti DeepSeek R1 ke dalam `reasoning_content` standard
- **Output Berstruktur untuk Gemini** — `json_schema``responseMimeType`/`responseSchema` penukaran automatik
- **`stream` lalai kepada `false`** — Menjajarkan dengan spesifikasi OpenAI, mengelakkan SSE yang tidak dijangka dalam Python/Rust/Go SDK
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Pembekal AI saya menyekat wilayah/negara saya"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Penyedia seperti OpenAI/Codex menyekat akses daripada kawasan geografi tertentu. Pengguna mendapat ralat seperti `unsupported_country_region_territory` semasa sambungan OAuth dan API. Ini amat mengecewakan bagi pemaju dari negara membangun.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Konfigurasi Proksi 3 Tahap** — Proksi boleh dikonfigurasikan pada 3 peringkat: global (semua trafik), setiap pembekal (satu pembekal sahaja) dan setiap sambungan/kunci
- **Lencana Proksi Berkod Warna** — Penunjuk visual: 🟢 proksi global, 🟡 proksi pembekal, 🔵 proksi sambungan, sentiasa menunjukkan IP
- **Pertukaran Token OAuth Melalui Proksi** — Aliran OAuth juga melalui proksi, menyelesaikan `unsupported_country_region_territory`
- **Ujian Sambungan melalui Proksi** — Ujian sambungan menggunakan proksi yang dikonfigurasikan (tiada lagi pintasan langsung)
- **Sokongan SOCKS5** — Sokongan proksi SOCKS5 penuh untuk penghalaan keluar
- **TLS Fingerprint Spoofing** — Cap jari TLS seperti pelayar melalui `wreq-js` untuk memintas pengesanan bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Saya mahu menggunakan AI untuk pengekodan tetapi saya tidak mempunyai wang"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Tidak semua orang boleh membayar $20200/bulan untuk langganan AI. Pelajar, pembangun dari negara baru muncul, penggemar dan pekerja bebas memerlukan akses kepada model berkualiti pada kos sifar.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Pembekal Peringkat Percuma Terbina dalam** — Sokongan asli untuk 100% pembekal percuma: iFlow (8 model tanpa had), Qwen (3 model tanpa had), Kiro (Claude secara percuma), Gemini CLI (180K/bulan percuma)
- **Kombo Percuma Sahaja** — Rantaian `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/bulan dengan masa henti sifar
- **Kredit Percuma NVIDIA NIM** — 1000 kredit percuma disepadukan
- **Strategi Dioptimumkan Kos** — Strategi penghalaan yang secara automatik memilih pembekal yang tersedia paling murah
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Saya perlu melindungi gerbang AI saya daripada akses tanpa kebenaran"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Apabila mendedahkan get laluan AI kepada rangkaian (LAN, VPS, Docker), sesiapa sahaja yang mempunyai alamat boleh menggunakan token/kuota pembangun. Tanpa perlindungan, API terdedah kepada penyalahgunaan, suntikan segera dan penyalahgunaan.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Pengurusan Kunci API** — Penjanaan, penggiliran dan skop setiap pembekal dengan halaman `/dashboard/api-manager` khusus
- **Kebenaran Tahap Model** — Hadkan kunci API kepada model tertentu (`openai/*`, corak kad bebas), dengan Togol Benarkan Semua/Sekat
- **Perlindungan Titik Akhir API** — Memerlukan kunci untuk `/v1/models` dan menyekat penyedia tertentu daripada penyenaraian
- **Auth Guard + CSRF Protection** — Semua laluan papan pemuka dilindungi dengan `withAuth` middleware + token CSRF
- **Penghad Kadar** — Pengehadan kadar Per-IP dengan tetingkap boleh dikonfigurasikan
- **Penapisan IP** — Senarai Benar/senarai sekat untuk kawalan akses
- **Pengawal Suntikan Segera** — Pensanitasi terhadap corak segera yang berniat jahat
- **Penyulitan AES-256-GCM** — Bukti kelayakan disulitkan semasa rehat
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Pembekal saya gagal dan saya kehilangan aliran pengekodan saya"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Pembekal AI boleh menjadi tidak stabil, mengembalikan ralat 5xx atau mencapai had kadar sementara. Jika pembangun bergantung pada penyedia tunggal, mereka akan terganggu. Tanpa pemutus litar, percubaan semula berulang boleh ranap aplikasi.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Pemutus Litar bagi setiap pembekal** — Auto buka/tutup dengan ambang boleh dikonfigurasikan dan cooldown (Ditutup/Buka/Separuh Terbuka)
- **Penyingkiran Eksponen** — Kelewatan percubaan semula progresif
- **Kawanan Anti Gemuruh** — Mutex + perlindungan semafor terhadap ribut percubaan semula serentak
- **Kombo Rantai Sandar** — Jika pembekal utama gagal, secara automatik jatuh melalui rantaian tanpa campur tangan
- **Pemutus Litar Kombo** — Lumpuhkan automatik pembekal yang gagal dalam rantaian kombo
- **Papan Pemuka Kesihatan** — Pemantauan masa aktif, keadaan pemutus litar, penguncian, statistik cache, kependaman p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Mengkonfigurasi setiap alat AI adalah membosankan dan berulang"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Pembangun menggunakan Kursor, Kod Claude, Codex CLI, OpenClaw, Gemini CLI, Kod Kilo... Setiap alat memerlukan konfigurasi yang berbeza (titik akhir API, kunci, model). Mengkonfigurasi semula apabila menukar pembekal atau model adalah membuang masa.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Papan Pemuka Alat CLI** — Halaman khusus dengan persediaan satu klik untuk Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Menghasilkan `chatLanguageModels.json` untuk Kod VS dengan pemilihan model pukal
- **Onboarding Wizard** — Persediaan 4 langkah berpandu untuk pengguna kali pertama
- **Satu titik akhir, semua model** — Konfigurasikan `http://localhost:20128/v1` sekali, akses 36+ pembekal
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Menguruskan token OAuth daripada berbilang penyedia adalah neraka"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Kod Claude, Codex, Gemini CLI, Copilot — semuanya menggunakan OAuth 2.0 dengan token tamat tempoh. Pembangun perlu sentiasa mengesahkan semula, menangani `client_secret is missing`, `redirect_uri_mismatch` dan kegagalan pada pelayan jauh. OAuth pada LAN/VPS amat bermasalah.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Muat Semula Token Auto** — Token OAuth dimuat semula di latar belakang sebelum tamat tempoh
- **OAuth 2.0 (PKCE) Terbina dalam** — Aliran automatik untuk Kod Claude, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth Berbilang Akaun** — Berbilang akaun bagi setiap pembekal melalui pengekstrakan token JWT/ID
- **OAuth LAN/Remote Fix** — Pengesanan IP peribadi untuk `redirect_uri` + mod URL manual untuk pelayan jauh
- **OAuth Behind Nginx** — Menggunakan `window.location.origin` untuk keserasian proksi terbalik
- **Panduan OAuth Jauh** — Panduan langkah demi langkah untuk kelayakan Google Cloud pada VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Saya tidak tahu berapa banyak yang saya belanjakan atau di mana"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Pembangun menggunakan berbilang penyedia berbayar tetapi tidak mempunyai pandangan bersatu tentang perbelanjaan. Setiap pembekal mempunyai papan pemuka pengebilan sendiri, tetapi tiada paparan disatukan. Kos yang tidak dijangka boleh bertimbun.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Papan Pemuka Analitis Kos** — Penjejakan kos per-token dan pengurusan belanjawan bagi setiap pembekal
- **Had Belanjawan setiap Peringkat** — Siling perbelanjaan setiap peringkat yang mencetuskan sandaran automatik
- **Konfigurasi Harga Per-Model** — Harga boleh dikonfigurasikan bagi setiap model
- **Statistik Penggunaan Setiap Kunci API** — Kiraan permintaan dan cap masa yang terakhir digunakan setiap kunci
- **Papan Pemuka Analitik** — Kad statistik, carta penggunaan model, jadual pembekal dengan kadar kejayaan dan kependaman
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Saya tidak dapat mendiagnosis ralat dan masalah dalam panggilan AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Apabila panggilan gagal, pembangun tidak tahu sama ada ia adalah had kadar, token tamat tempoh, format yang salah atau ralat pembekal. Log berpecah-belah merentasi terminal yang berbeza. Tanpa pemerhatian, penyahpepijatan adalah percubaan-dan-ralat.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Papan Pemuka Log Bersatu** — 4 tab: Log Permintaan, Log Proksi, Log Audit, Konsol
- **Pemapar Log Konsol** — Pemapar gaya terminal masa nyata dengan tahap berkod warna, tatal automatik, carian, penapis
- **Log Proksi SQLite** — Log berterusan yang bertahan dimulakan semula
- **Taman Permainan Penterjemah** — 4 mod nyahpepijat: Taman Permainan (terjemahan format), Penguji Sembang (perjalanan pergi balik), Bangku Ujian (batch), Monitor Langsung (masa nyata)
- **Permintaan Telemetri** — kependaman p50/p95/p99 + pengesanan X-Request-Id
- **Pengelogan Berasaskan Fail dengan Putaran** — Pemintas konsol menangkap segala-galanya ke log JSON dengan putaran berasaskan saiz
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Menyedia dan menyelenggara gerbang adalah rumit"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Memasang, mengkonfigurasi dan menyelenggara proksi AI merentas persekitaran yang berbeza (tempatan, VPS, Docker, awan) adalah intensif buruh. Masalah seperti laluan berkod keras, `EACCES` pada direktori, konflik port dan binaan merentas platform menambah geseran.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **pemasangan global npm** — `npm install -g omniroute && omniroute`selesai
- **Docker Multi-Platform** — AMD64 + ARM64 asli (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Profil Karang Docker** — `base` (tiada alat CLI) dan `cli` (dengan Kod Claude, Codex, OpenClaw)
- **Apl Desktop Elektron** — Apl asli untuk Windows/macOS/Linux dengan dulang sistem, auto mula, mod luar talian
- **Mod Split-Port** — API dan Papan Pemuka pada port berasingan untuk senario lanjutan (proksi terbalik, rangkaian kontena)
- **Cloud Sync** — Konfigurasikan penyegerakan merentas peranti melalui Cloudflare Workers
- **Sandaran DB** — Sandaran automatik, pulihkan, eksport dan import semua tetapan
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Antara muka adalah bahasa Inggeris sahaja dan pasukan saya tidak berbahasa Inggeris"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Pasukan di negara bukan berbahasa Inggeris, terutamanya di Amerika Latin, Asia dan Eropah, bergelut dengan antara muka bahasa Inggeris sahaja. Halangan bahasa mengurangkan penggunaan dan meningkatkan ralat konfigurasi.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Papan pemuka i18n — 30 Bahasa** — Semua 500+ kunci diterjemahkan termasuk bahasa Arab, Bulgaria, Denmark, Jerman, Sepanyol, Finland, Perancis, Ibrani, Hindi, Hungary, Indonesia, Itali, Jepun, Korea, Melayu, Belanda, Norway, Poland, Portugis (PT/BR), Romania, Rusia, Slovak, Sweden, Thai, Ukraine, Vietnam, Cina
- **Sokongan RTL** — Sokongan kanan ke kiri untuk bahasa Arab dan Ibrani
- **README Berbilang Bahasa** — 30 terjemahan dokumentasi lengkap
- **Pemilih Bahasa** — Ikon Glob dalam pengepala untuk penukaran masa nyata
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Saya perlukan lebih daripada sembang — saya perlukan benam, imej, audio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI bukan sekadar penyelesaian sembang. Pembangun perlu menjana imej, menyalin audio, membuat pembenaman untuk RAG, menyusun semula dokumen dan kandungan sederhana. Setiap API mempunyai titik akhir dan format yang berbeza.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Pembenaman** — `/v1/embeddings` dengan 6 pembekal dan 9+ model
- **Penjanaan Imej** — `/v1/images/generations` dengan 10 pembekal dan 20+ model (OpenAI, xAI, Together, Bunga Api, Nebius, Hiperbolik, NanoBanana, Antigraviti, SD WebUI, ComfyUI)
- **Teks-ke-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) dan SD WebUI
- **Teks-ke-Muzik** — `/v1/music/generations` — ComfyUI (Audio Terbuka, MusicGen)
- **Transkripsi Audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Teks-ke-Ucapan** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + pembekal sedia ada
- **Moderasi** — `/v1/moderations` — Pemeriksaan keselamatan kandungan
- **Penyusunan semula** — `/v1/rerank` — Penyusunan semula perkaitan dokumen
- **Respons API** — Sokongan penuh `/v1/responses` untuk Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Saya tiada cara untuk menguji dan membandingkan kualiti merentas model"</b></summary>
Developers want to know which model is best for their use casecode, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Pembangun ingin mengetahui model mana yang terbaik untuk kes penggunaan merekakod, terjemahan, penaakulan — tetapi membandingkan secara manual adalah perlahan. Tiada alat eval bersepadu wujud.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM Evaluations** — Ujian set emas dengan 10 kes pra-muat meliputi salam, matematik, geografi, penjanaan kod, pematuhan JSON, terjemahan, penurunan harga, penolakan keselamatan
- **4 Strategi Padanan** — `exact`, `contains`, `regex`, `custom` (fungsi JS)
- **Bangku Ujian Taman Permainan Penterjemah** — Ujian kelompok dengan berbilang input dan output yang dijangka, perbandingan merentas pembekal
- **Penguji Sembang** — Perjalanan pergi balik penuh dengan pemaparan respons visual
- **Pantau Langsung** — Strim masa nyata semua permintaan yang mengalir melalui proksi
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Saya perlu skala tanpa kehilangan prestasi"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Apabila volum permintaan bertambah, tanpa menyimpan cache soalan yang sama menjana kos pendua. Tanpa idempotensi, pendua meminta pemprosesan sisa. Had kadar setiap pembekal mesti dipatuhi.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache Semantik** — Cache dua peringkat (tandatangan + semantik) mengurangkan kos dan kependaman
- **Request Idempotency** — tetingkap penyahduplikasi 5s untuk permintaan yang sama
- **Pengesanan Had Kadar** — RPM setiap pembekal, jurang min dan penjejakan serentak maks
- **Had Kadar Boleh Diedit** — Lalai boleh dikonfigurasikan dalam Tetapan → Ketahanan dengan kegigihan
- **Cache Pengesahan Kunci API** — Cache 3 peringkat untuk prestasi pengeluaran
- **Papan Pemuka Kesihatan dengan Telemetri** — kependaman p50/p95/p99, statistik cache, masa beroperasi
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Saya mahu mengawal tingkah laku model secara global"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Pembangun yang mahukan semua respons dalam bahasa tertentu, dengan nada tertentu atau ingin mengehadkan token penaakulan. Mengkonfigurasi ini dalam setiap alat/permintaan adalah tidak praktikal.
**How OmniRoute solves it:**
**Cara OmniRoute menyelesaikannya:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **System Prompt Injection** — Gesaan global digunakan untuk semua permintaan
- **Pengesahan Belanjawan Berfikir** — Kawalan peruntukan token penaakulan setiap permintaan (laluan, auto, tersuai, adaptif)
- **6 Strategi Penghalaan** — Strategi global yang menentukan cara permintaan diedarkan
- **Penghala Wildcard** — Corak `provider/*` halakan secara dinamik kepada mana-mana pembekal
- **Kombo Dayakan/Lumpuhkan Togol** — Togol kombo terus dari papan pemuka
- **Togol Pembekal** — Dayakan/lumpuhkan semua sambungan untuk pembekal dengan satu klik
- **Pembekal Disekat** — Kecualikan pembekal khusus daripada penyenaraian `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Saya memerlukan alatan MCP sebagai keupayaan produk kelas pertama"</b></summary>
Banyak get laluan AI mendedahkan MCP hanya sebagai butiran pelaksanaan tersembunyi. Pasukan memerlukan lapisan operasi yang boleh dilihat dan boleh diurus.
**Cara OmniRoute menyelesaikannya:**
- MCP muncul dalam navigasi papan pemuka dan tab protokol titik akhir
- Halaman pengurusan MCP khusus dengan proses, alatan, skop dan audit
- Permulaan pantas terbina dalam untuk `omniroute --mcp` dan onboarding pelanggan
</details>
<details>
<summary><b>🧠 18. "Saya memerlukan orkestrasi A2A dengan laluan tugas penyegerakan + aliran"</b></summary>
Aliran kerja ejen memerlukan balasan langsung dan pelaksanaan strim jangka panjang dengan kawalan kitaran hayat.
**Cara OmniRoute menyelesaikannya:**
- Titik akhir A2A JSON-RPC (`POST /a2a`) dengan `message/send` dan `message/stream`
- Penstriman SSE dengan penyebaran keadaan terminal
- API kitaran hayat tugas untuk `tasks/get` dan `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Saya memerlukan kesihatan proses MCP sebenar, bukan status yang diduga"</b></summary>
Pasukan operasi perlu mengetahui sama ada MCP sebenarnya masih hidup, bukan hanya sama ada API boleh dicapai.
**Cara OmniRoute menyelesaikannya:**
- Fail degupan jantung masa jalan dengan PID, cap masa, pengangkutan, kiraan alat dan mod skop
- API status MCP yang menggabungkan degupan jantung + aktiviti terkini
- Kad status UI untuk kesegaran proses/masa hidup/degupan jantung
</details>
<details>
<summary><b>📋 20. "Saya memerlukan pelaksanaan alat MCP yang boleh diaudit"</b></summary>
Apabila alat mengubah konfigurasi atau mencetuskan tindakan ops, pasukan memerlukan kebolehkesanan forensik.
**Cara OmniRoute menyelesaikannya:**
- Pengelogan audit yang disokong SQLite untuk panggilan alat MCP
- Tapis mengikut alat, kejayaan/kegagalan, kunci API dan penomboran
- Jadual audit papan pemuka + titik akhir statistik untuk automasi
</details>
<details>
<summary><b>🔐 21. "Saya memerlukan keizinan MCP berskop bagi setiap penyepaduan"</b></summary>
Pelanggan yang berbeza harus mempunyai akses paling tidak istimewa kepada kategori alat.
**Cara OmniRoute menyelesaikannya:**
- 9 skop MCP berbutir untuk akses alat terkawal
- Penguatkuasaan skop dan keterlihatan dalam UI pengurusan MCP
- Postur lalai yang selamat untuk perkakas operasi
</details>
<details>
<summary><b>⚙️ 22. "Saya memerlukan kawalan operasi tanpa mengatur semula"</b></summary>
Pasukan memerlukan perubahan masa jalan yang cepat semasa insiden atau peristiwa kos.
**Cara OmniRoute menyelesaikannya:**
- Tukar pengaktifan kombo terus dari papan pemuka MCP
- Gunakan profil daya tahan daripada pek dasar yang telah ditetapkan
- Tetapkan semula keadaan pemutus litar daripada panel operasi yang sama
</details>
<details>
<summary><b>🔄 23. "Saya memerlukan keterlihatan dan pembatalan kitaran hayat tugas A2A secara langsung"</b></summary>
Tanpa keterlihatan kitaran hayat, insiden tugasan menjadi sukar untuk dicuba.
**Cara OmniRoute menyelesaikannya:**
- Penyenaraian tugas/penapisan mengikut keadaan/kemahiran dengan penomboran
- Latih tubi tentang metadata tugas, peristiwa dan artifak
- Titik akhir pembatalan tugas dan tindakan UI dengan pengesahan
</details>
<details>
<summary><b>🌊 24. "Saya memerlukan metrik strim aktif untuk beban A2A"</b></summary>
Aliran kerja penstriman memerlukan cerapan operasi tentang konkurensi dan sambungan langsung.
**Cara OmniRoute menyelesaikannya:**
- Kaunter aliran aktif disepadukan ke dalam status A2A
- Cap masa tugas terakhir dan kiraan setiap negeri
- Kad papan pemuka A2A untuk pemantauan operasi masa nyata
</details>
<details>
<summary><b>🪪 25. "Saya memerlukan penemuan ejen standard untuk pelanggan"</b></summary>
Pelanggan dan orkestra luar memerlukan metadata yang boleh dibaca mesin untuk onboarding.
**Cara OmniRoute menyelesaikannya:**
- Kad Agen terdedah pada `/.well-known/agent.json`
- Keupayaan dan kemahiran ditunjukkan dalam UI pengurusan
- API status A2A termasuk metadata penemuan untuk automasi
</details>
<details>
<summary><b>🧭 26. "Saya memerlukan kebolehtemuan protokol dalam produk UX"</b></summary>
Jika pengguna tidak dapat menemui permukaan protokol, penggunaan dan kualiti sokongan akan menurun.
**Cara OmniRoute menyelesaikannya:**
- Entri bar sisi untuk MCP dan A2A
- Tab Protokol halaman titik akhir dengan permulaan pantas dan status
- Pautan dari gambaran keseluruhan ke papan pemuka pengurusan khusus
</details>
<details>
<summary><b>🧪 27. "Saya memerlukan pengesahan protokol hujung ke hujung dengan pelanggan sebenar"</b></summary>
Ujian olok-olok tidak mencukupi untuk mengesahkan keserasian protokol sebelum dikeluarkan.
**Cara OmniRoute menyelesaikannya:**
- Suite E2E yang but apl dan menggunakan pengangkutan pelanggan MCP SDK sebenar
- Ujian pelanggan A2A untuk penemuan, menghantar, menstrim, mendapatkan dan membatalkan aliran
- Periksa silang dakwaan terhadap audit MCP dan API tugasan A2A
</details>
<details>
<summary><b>📡 28. "Saya memerlukan pemerhatian bersatu merentas semua antara muka"</b></summary>
Memisahkan kebolehmerhatian mengikut protokol mewujudkan titik buta dan MTTR yang lebih panjang.
**Cara OmniRoute menyelesaikannya:**
- Papan pemuka/log/analisis bersatu dalam satu produk
- Kesihatan + audit + telemetri permintaan merentas lapisan OpenAI, MCP dan A2A
- API Operasi untuk status dan automasi
</details>
<details>
<summary><b>💼 29. "Saya memerlukan satu masa jalan untuk proksi + alatan + orkestrasi ejen"</b></summary>
Menjalankan banyak perkhidmatan berasingan meningkatkan kos operasi dan mod kegagalan.
**Cara OmniRoute menyelesaikannya:**
- Proksi serasi OpenAI, pelayan MCP dan pelayan A2A dalam satu tindanan
- Kebenaran dikongsi, daya tahan, stor data dan kebolehmerhatian
- Model dasar yang konsisten merentas semua permukaan interaksi
</details>
<details>
<summary><b>🚀 30. "Saya perlu menghantar aliran kerja ejentik tanpa sebaran kod gam"</b></summary>
Pasukan kehilangan halaju apabila mencantumkan berbilang perkhidmatan dan skrip ad-hoc.
**Cara OmniRoute menyelesaikannya:**
- Strategi titik akhir bersatu untuk pelanggan dan ejen
- UI pengurusan protokol terbina dalam dan laluan pengesahan asap
- Asas sedia pengeluaran (keselamatan, pembalakan, daya tahan, sandaran)
</details>
### Contoh Buku Main (Kes Penggunaan Bersepadu)
**Playbook A: Maksimumkan langganan berbayar + sandaran murah**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Timbunan pengekodan kos sifar**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 rantai sandaran sentiasa hidup**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Operasi ejen dengan MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Mula Pantas
**1. Pasang secara global:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +990,26 @@ OmniRoute termasuk Taman Permainan Penterjemah terbina dalam yang berkuasa denga
</details>
---
## 🧪 Penilaian (Evals)
## 🎯 Kes Penggunaan
OmniRoute termasuk rangka kerja penilaian terbina dalam untuk menguji kualiti tindak balas LLM terhadap set emas. Aksesnya melalui **Analytics → Evals** dalam papan pemuka.
### Kes 1: "Saya mempunyai langganan Claude Pro"
### Set Emas Terbina dalam
**Masalah:** Kuota tamat tempoh tidak digunakan, had kadar semasa pengekodan berat
"Set Emas OmniRoute" pra-muat mengandungi 10 kes ujian yang meliputi:
```
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)
- Salam, matematik, geografi, penjanaan kod
- Pematuhan format JSON, terjemahan, penurunan harga
- Penolakan keselamatan (kandungan berbahaya), pengiraan, logik boolean
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Strategi Penilaian
### Kes 2: "Saya mahu kos sifar"
**Masalah:** Tidak mampu membayar langganan, memerlukan pengekodan AI yang boleh dipercayai
```
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
```
### Kes 3: "Saya memerlukan pengekodan 24/7, tiada gangguan"
**Masalah:** Tarikh akhir, tidak mampu membayar masa henti
```
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
```
### Kes 4: "Saya mahukan AI PERCUMA dalam OpenClaw"
**Masalah:** Memerlukan pembantu AI dalam apl pemesejan, percuma sepenuhnya
```
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...
```
| Strategi | Penerangan | Contoh |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | Output mesti sepadan dengan tepat | `"4"` |
| `contains` | Output mesti mengandungi subrentetan (tidak peka huruf besar-besaran) | `"Paris"` |
| `regex` | Output mesti sepadan dengan corak regex | `"1.*2.*3"` |
| `custom` | Fungsi JS tersuai mengembalikan benar/salah | `(output) => output.length > 10` |
---
@@ -1058,29 +1293,6 @@ Settings → API Configuration:
---
## 🧪 Penilaian (Evals)
OmniRoute termasuk rangka kerja penilaian terbina dalam untuk menguji kualiti tindak balas LLM terhadap set emas. Aksesnya melalui **Analytics → Evals** dalam papan pemuka.
### Set Emas Terbina dalam
"Set Emas OmniRoute" pra-muat mengandungi 10 kes ujian yang meliputi:
- Salam, matematik, geografi, penjanaan kod
- Pematuhan format JSON, terjemahan, penurunan harga
- Penolakan keselamatan (kandungan berbahaya), pengiraan, logik boolean
### Strategi Penilaian
| Strategi | Penerangan | Contoh |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | Output mesti sepadan dengan tepat | `"4"` |
| `contains` | Output mesti mengandungi subrentetan (tidak peka huruf besar-besaran) | `"Paris"` |
| `regex` | Output mesti sepadan dengan corak regex | `"1.*2.*3"` |
| `custom` | Fungsi JS tersuai mengembalikan benar/salah | `(output) => output.length > 10` |
---
## 🐛 Menyelesaikan masalah
<details>
@@ -1132,7 +1344,7 @@ OmniRoute termasuk rangka kerja penilaian terbina dalam untuk menguji kualiti ti
- OmniRoute v1.0.6+ termasuk pengesahan sandaran melalui pelengkapan sembang
- Pastikan URL asas mengandungi akhiran `/v1`
### 🔐 OAuth em Servidor Remoto (Persediaan OAuth Jauh)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
@@ -1227,7 +1439,7 @@ Jika anda ingin mendapatkan credenciais próprias agora, ada kemungkinan penggun
---
## 🛠️ Timbunan Teknologi
## 🛠️
- **Waktu Jalan**: Node.js 1822 LTS (⚠️ Node.js 24+ **tidak disokong**`better-sqlite3` binari asli tidak serasi)
- **Bahasa**: TypeScript 5.9 — **100% TypeScript** merentas `src/` dan `open-sse/` (v1.0.6)
@@ -1279,18 +1491,19 @@ Jika anda ingin mendapatkan credenciais próprias agora, ada kemungkinan penggun
---
## 🗺️ Pelan Hala Tuju
## 🗺️
OmniRoute mempunyai **210+ ciri yang dirancang** merentas berbilang fasa pembangunan. Berikut adalah bidang utama:
| Kategori | Ciri Terancang | Sorotan |
| ------------------------------ | -------------- | ---------------------------------------------------------------------------------------------------- |
| 🧠 **Penghalaan & Perisikan** | 25+ | Penghalaan kependaman terendah, penghalaan berasaskan teg, kuota prapenerbangan, pemilihan akaun P2C |
| 🔒 **Keselamatan & Pematuhan** | 20+ | Pengerasan SSRF, penyelubungan kelayakan, had kadar setiap titik akhir, skop kunci pengurusan |
| 📊 **Kebolehlihatan** | 15+ | Penyepaduan OpenTelemetry, pemantauan kuota masa nyata, penjejakan kos setiap model |
| 🔄 **Integrasi Pembekal** | 20+ | Pendaftaran model dinamik, penyejukan pembekal, Codex berbilang akaun, penghuraian kuota Copilot |
| **Prestasi** | 15+ | Lapisan cache dwi, cache gesaan, cache respons, penstriman keepalive, API kelompok |
| 🌐 **Ekosistem** | 10+ | API WebSocket, konfigurasi hot-reload, kedai konfigurasi teragih, mod komersial |
| Kategori | Ciri Terancang | Sorotan |
| ------------------------------ | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🧠 **Penghalaan & Perisikan** | 25+ | Penghalaan kependaman terendah, penghalaan berasaskan teg, kuota prapenerbangan, pemilihan akaun P2C |
| 🔒 **Keselamatan & Pematuhan** | 20+ | Pengerasan SSRF, penyelubungan kelayakan, had kadar setiap titik akhir, skop kunci pengurusan |
| 📊 **Kebolehlihatan** | 15+ | Penyepaduan OpenTelemetry, pemantauan kuota masa nyata, penjejakan kos setiap model |
| 🔄 **Integrasi Pembekal** | 20+ | Pendaftaran model dinamik, penyejukan pembekal, Codex berbilang akaun, penghuraian kuota Copilot |
| **Prestasi** | 15+ | Lapisan cache dwi, cache gesaan, cache respons, penstriman keepalive, API kelompok |
| 🌐 **Ekosistem** | 10+ | API WebSocket, konfigurasi hot-reload, kedai konfigurasi teragih, mod komersial |
### 🔜 Akan Datang
@@ -1304,18 +1517,6 @@ OmniRoute mempunyai **210+ ciri yang dirancang** merentas berbilang fasa pembang
---
## 📧 Sokongan
> 💬 **Sertai komuniti kami!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Dapatkan bantuan, kongsi petua dan kekal kemas kini.
- **Laman web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Isu**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projek Asal**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Penyumbang
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Verbind elke AI-aangedreven IDE- of CLI-tool via OmniRoute: gratis API-gateway
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Waarom OmniRoute?
**Stop met het verspillen van geld en het bereiken van grenzen:**
@@ -128,6 +157,18 @@ _Verbind elke AI-aangedreven IDE- of CLI-tool via OmniRoute: gratis API-gateway
---
## 📧 Ondersteuning
> 💬 **Word lid van onze community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Krijg hulp, deel tips en blijf op de hoogte.
- **Website**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemen**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Origineel project**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Hoe het werkt
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Wat OmniRoute oplost — 30 echte pijnpunten en gebruiksscenario's
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Elke ontwikkelaar die AI-tools gebruikt, wordt dagelijks met deze problemen geconfronteerd.** OmniRoute is gebouwd om ze allemaal op te lossen: van kostenoverschrijdingen tot regionale blokkades, van kapotte OAuth-stromen tot protocolbewerkingen en bedrijfsobservatie.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Ik betaal voor een duur abonnement, maar word nog steeds onderbroken door limieten"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Ontwikkelaars betalen $20-200/maand voor Claude Pro, Codex Pro of GitHub Copilot. Zelfs als je betaalt, heeft het quotum een plafond: 5 uur gebruik, wekelijkse limieten of tarieflimieten per minuut. Halverwege de codeersessie reageert de provider niet meer en verliest de ontwikkelaar flow en productiviteit.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Als het abonnementsquotum opraakt, wordt automatisch doorgestuurd naar API Key → Goedkoop → Gratis zonder handmatige tussenkomst
- **Realtime bijhouden van quota** — Toont het tokenverbruik in realtime met aftellen van de reset (5 uur, dagelijks, wekelijks)
- **Ondersteuning voor meerdere accounts** — Meerdere accounts per provider met automatische round-robin — als de ene op is, wordt er overgeschakeld naar de volgende
- **Aangepaste combo's** — Aanpasbare fallback-ketens met 6 balanceringsstrategieën (fill-first, round-robin, P2C, willekeurig, minst gebruikt, kostengeoptimaliseerd)
- **Codex Business Quota** — Quotabewaking van zakelijke/teamwerkruimte rechtstreeks in het dashboard
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Ik moet meerdere providers gebruiken, maar elk heeft een andere API"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI gebruikt het ene formaat, Claude (Anthropic) gebruikt een ander, Gemini nog een ander. Als een ontwikkelaar modellen van verschillende providers wil testen of terug wil vallen tussen deze providers, moet hij SDK's opnieuw configureren, eindpunten wijzigen en omgaan met incompatibele formaten. Aangepaste providers (FriendLI, NIM) hebben niet-standaard modeleindpunten.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** — Eén enkele `http://localhost:20128/v1` dient als proxy voor alle 36+ providers
- **Formatvertaling** — Automatisch en transparant: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Verwijdert niet-standaardvelden (`x_groq`, `usage_breakdown`, `service_tier`) die OpenAI SDK v1.83+ breken
- **Rolnormalisatie** — Converteert `developer``system` voor niet-OpenAI-providers; `system``user` voor GLM/ERNIE
- **Think Tag Extraction** — Extraheert `<think>`-blokken uit modellen zoals DeepSeek R1 naar gestandaardiseerde `reasoning_content`
- **Gestructureerde uitvoer voor Gemini** — `json_schema``responseMimeType`/`responseSchema` automatische conversie
- **`stream` is standaard ingesteld op `false`** — Sluit aan bij de OpenAI-specificaties en vermijdt onverwachte SSE in Python/Rust/Go SDK's
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Mijn AI-provider blokkeert mijn regio/land"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Providers zoals OpenAI/Codex blokkeren de toegang vanuit bepaalde geografische regio's. Gebruikers krijgen fouten zoals `unsupported_country_region_territory` tijdens OAuth- en API-verbindingen. Dit is vooral frustrerend voor ontwikkelaars uit ontwikkelingslanden.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Proxyconfiguratie op 3 niveaus** — Configureerbare proxy op 3 niveaus: globaal (al het verkeer), per provider (slechts één provider) en per verbinding/sleutel
- **Kleurgecodeerde proxybadges** — Visuele indicatoren: 🟢 globale proxy, 🟡 providerproxy, 🔵verbindingsproxy, waarbij altijd het IP-adres wordt weergegeven
- **OAuth-tokenuitwisseling via proxy**: de OAuth-stroom verloopt ook via de proxy, waardoor `unsupported_country_region_territory` wordt opgelost
- **Verbindingstests via proxy** — Verbindingstests gebruiken de geconfigureerde proxy (geen directe bypass meer)
- **SOCKS5-ondersteuning** — Volledige SOCKS5-proxyondersteuning voor uitgaande routering
- **TLS Fingerprint Spoofing** — Browserachtige TLS-vingerafdruk via `wreq-js` om botdetectie te omzeilen
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Ik wil AI gebruiken voor codering, maar ik heb geen geld"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Niet iedereen kan $ 20-200 per maand betalen voor AI-abonnementen. Studenten, ontwikkelaars uit opkomende landen, hobbyisten en freelancers hebben kosteloos toegang nodig tot kwaliteitsmodellen.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Free Tier Providers ingebouwd** — Native ondersteuning voor 100% gratis providers: iFlow (8 onbeperkte modellen), Qwen (3 onbeperkte modellen), Kiro (Claude gratis), Gemini CLI (180K/maand gratis)
- **Alleen gratis combo's** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $ 0/maand zonder downtime
- **NVIDIA NIM Free Credits** — 1000 gratis credits geïntegreerd
- **Kostengeoptimaliseerde strategie** — Routingstrategie die automatisch de goedkoopste beschikbare provider kiest
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Ik moet mijn AI-gateway beschermen tegen ongeoorloofde toegang"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Bij het blootstellen van een AI-gateway aan het netwerk (LAN, VPS, Docker) kan iedereen met het adres de tokens/quota van de ontwikkelaar gebruiken. Zonder bescherming zijn API's kwetsbaar voor misbruik, snelle injectie en misbruik.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API Key Management** — Generatie, rotatie en bereik per provider met een speciale `/dashboard/api-manager`-pagina
- **Machtigingen op modelniveau** — Beperk API-sleutels tot specifieke modellen (`openai/*`, jokertekenpatronen), met de schakelaar Alles toestaan/Beperken
- **API Endpoint Protection** — Vereist een sleutel voor `/v1/models` en blokkeer specifieke providers uit de lijst
- **Auth Guard + CSRF-bescherming** — Alle dashboardroutes beschermd met `withAuth` middleware + CSRF-tokens
- **Rate Limiter** — Per-IP-snelheidslimiet met configureerbare vensters
- **IP-filtering** — Toelatingslijst/blokkeerlijst voor toegangscontrole
- **Prompt Injection Guard** — Sanering tegen kwaadaardige promptpatronen
- **AES-256-GCM-codering** — Inloggegevens gecodeerd in rust
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Mijn provider is uitgevallen en ik ben mijn codeerstroom kwijt"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI-aanbieders kunnen instabiel worden, 5xx-fouten retourneren of tijdelijke tarieflimieten bereiken. Als een ontwikkelaar afhankelijk is van één enkele provider, worden deze onderbroken. Zonder stroomonderbrekers kunnen herhaalde pogingen de toepassing laten crashen.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Stroomonderbreker per provider** — Automatisch openen/sluiten met configureerbare drempels en cooldown (gesloten/open/halfopen)
- **Exponentiële uitstel** — Progressieve vertragingen bij nieuwe pogingen
- **Anti-Thundering Herd** — Mutex + semafoorbescherming tegen gelijktijdige nieuwe stormen
- **Combo Fallback Chains** — Als de primaire provider faalt, valt deze automatisch zonder tussenkomst door de keten
- **Combo-stroomonderbreker** — Schakelt falende providers binnen een combo-keten automatisch uit
- **Gezondheidsdashboard** — Uptime-monitoring, status van stroomonderbrekers, uitsluitingen, cachestatistieken, p50/p95/p99-latentie
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Het configureren van elke AI-tool is vervelend en repetitief"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Ontwikkelaars gebruiken Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Elke tool heeft een andere configuratie nodig (API-eindpunt, sleutel, model). Opnieuw configureren bij het wisselen van provider of model is tijdverspilling.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Speciale pagina met installatie met één klik voor Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Genereert `chatLanguageModels.json` voor VS-code met bulkmodelselectie
- **Onboarding Wizard** — Begeleide installatie in 4 stappen voor nieuwe gebruikers
- **Eén eindpunt, alle modellen** — Configureer `http://localhost:20128/v1` één keer, krijg toegang tot meer dan 36 providers
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Het beheren van OAuth-tokens van meerdere providers is een hel"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot: ze gebruiken allemaal OAuth 2.0 met aflopende tokens. Ontwikkelaars moeten zich voortdurend opnieuw authenticeren en omgaan met `client_secret is missing`, `redirect_uri_mismatch` en storingen op externe servers. OAuth op LAN/VPS is bijzonder problematisch.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatische tokenvernieuwing**: OAuth-tokens worden op de achtergrond vernieuwd voordat ze verlopen
- **OAuth 2.0 (PKCE) ingebouwd** — Automatische stroom voor Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Meerdere accounts per provider via JWT/ID-tokenextractie
- **OAuth LAN/Remote Fix** — Privé-IP-detectie voor `redirect_uri` + handmatige URL-modus voor externe servers
- **OAuth achter Nginx** — gebruikt `window.location.origin` voor reverse proxy-compatibiliteit
- **Remote OAuth-handleiding** — Stapsgewijze handleiding voor Google Cloud-inloggegevens op VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Ik weet niet hoeveel ik uitgeef of waar"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Ontwikkelaars gebruiken meerdere betaalde providers, maar hebben geen uniform beeld van de uitgaven. Elke provider heeft zijn eigen factureringsdashboard, maar er is geen geconsolideerd overzicht. Onverwachte kosten kunnen zich opstapelen.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Cost Analytics Dashboard** — Kostenregistratie per token en budgetbeheer per provider
- **Budgetlimieten per niveau** — Uitgavenplafond per niveau dat automatische terugval activeert
- **Prijsconfiguratie per model** — Configureerbare prijzen per model
- **Gebruiksstatistieken per API-sleutel** — Verzoekaantal en laatst gebruikte tijdstempel per sleutel
- **Analytics Dashboard** — Statistiekkaarten, modelgebruiksgrafiek, providertabel met succespercentages en latentie
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Ik kan geen fouten en problemen in AI-oproepen diagnosticeren"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Wanneer een oproep mislukt, weet de ontwikkelaar niet of het een snelheidslimiet, een verlopen token, een verkeerd formaat of een providerfout is. Gefragmenteerde logboeken over verschillende terminals. Zonder waarneembaarheid is debuggen een kwestie van vallen en opstaan.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Unified Logs Dashboard** — 4 tabbladen: aanvraaglogboeken, proxylogboeken, auditlogboeken, console
- **Consolelogviewer** — Realtime viewer in terminalstijl met kleurgecodeerde niveaus, automatisch scrollen, zoeken, filteren
- **SQLite Proxy Logs** — Persistente logs die het opnieuw opstarten van de server overleven
- **Translator Playground** — 4 foutopsporingsmodi: Playground (formaatvertaling), Chat Tester (retour), Testbank (batch), Live Monitor (realtime)
- **Request Telemetry** — p50/p95/p99 latentie + X-Request-Id-tracering
- **Op bestanden gebaseerde logboekregistratie met rotatie** — Console-interceptor legt alles vast in JSON-logboek met op grootte gebaseerde rotatie
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Het implementeren en onderhouden van de gateway is complex"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Het installeren, configureren en onderhouden van een AI-proxy in verschillende omgevingen (lokaal, VPS, Docker, cloud) is arbeidsintensief. Problemen zoals hardgecodeerde paden, `EACCES` in mappen, poortconflicten en platformonafhankelijke builds zorgen voor wrijving.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **npm globale installatie** — `npm install -g omniroute && omniroute`klaar
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Docker Compose Profiles** — `base` (geen CLI-tools) en `cli` (met Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app voor Windows/macOS/Linux met systeemvak, automatisch starten, offlinemodus
- **Split-Port-modus** — API en Dashboard op afzonderlijke poorten voor geavanceerde scenario's (reverse proxy, containernetwerken)
- **Cloud Sync** — Configureer synchronisatie tussen apparaten via Cloudflare Workers
- **DB-back-ups** — Automatische back-up, herstel, export en import van alle instellingen
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "De interface is alleen in het Engels en mijn team spreekt geen Engels"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Teams in niet-Engelssprekende landen, vooral in Latijns-Amerika, Azië en Europa, worstelen met interfaces die alleen in het Engels beschikbaar zijn. Taalbarrières verminderen de adoptie en vergroten de configuratiefouten.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 talen** — Alle 500+ toetsen vertaald, waaronder Arabisch, Bulgaars, Deens, Duits, Spaans, Fins, Frans, Hebreeuws, Hindi, Hongaars, Indonesisch, Italiaans, Japans, Koreaans, Maleis, Nederlands, Noors, Pools, Portugees (PT/BR), Roemeens, Russisch, Slowaaks, Zweeds, Thais, Oekraïens, Vietnamees, Chinees, Filipijns, Engels
- **RTL-ondersteuning** — Ondersteuning van rechts naar links voor Arabisch en Hebreeuws
- **Meertalige README's** — 30 volledige documentatievertalingen
- **Taalkiezer** — Wereldbolpictogram in de koptekst voor realtime schakelen
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Ik heb meer nodig dan chatten - ik heb insluitingen, afbeeldingen en audio nodig"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI is niet alleen het voltooien van chats. Ontwikkelaars moeten afbeeldingen genereren, audio transcriberen, insluitingen voor RAG maken, documenten opnieuw rangschikken en inhoud modereren. Elke API heeft een ander eindpunt en formaat.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Inbedding** — `/v1/embeddings` met 6 providers en 9+ modellen
- **Beeldgeneratie** — `/v1/images/generations` met 10 providers en 20+ modellen (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Tekst-naar-video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) en SD WebUI
- **Tekst-naar-muziek** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Audiotranscriptie** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Tekst-naar-spraak** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + bestaande providers
- **Moderaties** — `/v1/moderations` — Veiligheidscontroles van inhoud
- **Herschikking** — `/v1/rerank` — Herschikking van de relevantie van documenten
- **Responses API** — Volledige `/v1/responses`-ondersteuning voor Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Ik heb geen manier om de kwaliteit van verschillende modellen te testen en te vergelijken"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Ontwikkelaars willen weten welk model het beste is voor hun gebruiksscenario (code, vertaling, redenering), maar handmatig vergelijken gaat traag. Er bestaan geen geïntegreerde evaluatietools.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM-evaluaties** — Golden set-tests met 10 vooraf geladen cases over begroetingen, wiskunde, aardrijkskunde, codegeneratie, JSON-compliance, vertaling, prijsverlaging, veiligheidsweigering
- **4 Matchstrategieën** — `exact`, `contains`, `regex`, `custom` (JS-functie)
- **Translator Playground Test Bench** — Batchtests met meerdere inputs en verwachte outputs, vergelijking tussen providers
- **Chat Tester** — Volledige rondreis met visuele responsweergave
- **Live Monitor** — Realtime stream van alle verzoeken die door de proxy stromen
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Ik moet schalen zonder prestatieverlies"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Naarmate het verzoekvolume groeit, genereren dezelfde vragen dubbele kosten als dezelfde vragen niet in de cache worden opgeslagen. Zonder idempotentie verspillen dubbele aanvragen de verwerking. Tarieflimieten per aanbieder moeten worden gerespecteerd.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in SettingsResilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Semantische cache** — Cache met twee lagen (handtekening + semantisch) verlaagt de kosten en de latentie
- **Request Idempotency** — 5s deduplicatievenster voor identieke verzoeken
- **Detectie van tarieflimiet** — RPM per provider, minimale tussenruimte en maximale gelijktijdige tracking
- **Bewerkbare snelheidslimieten** — Configureerbare standaardinstellingen in InstellingenVeerkracht met doorzettingsvermogen
- **API Key Validation Cache** — 3-tier cache voor productieprestaties
- **Gezondheidsdashboard met telemetrie** — p50/p95/p99-latentie, cachestatistieken, uptime
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Ik wil het modelgedrag wereldwijd controleren"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Ontwikkelaars die alle antwoorden in een specifieke taal willen, met een specifieke toon, of redeneringstokens willen beperken. Het is onpraktisch om dit in elke tool/verzoek te configureren.
**How OmniRoute solves it:**
**Hoe OmniRoute het oplost:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Systeempromptinjectie**: algemene prompt toegepast op alle verzoeken
- **Thinking Budget Validation** — Redenering van tokentoewijzingscontrole per verzoek (passthrough, automatisch, aangepast, adaptief)
- **6 Routingstrategieën** — Globale strategieën die bepalen hoe verzoeken worden gedistribueerd
- **Wildcard Router** — `provider/*`-patronen routeren dynamisch naar elke provider
- **Combo in-/uitschakelen schakelen** — Schakel combo's rechtstreeks vanuit het dashboard in
- **Provider wisselen** — Schakel alle verbindingen voor een provider met één klik in/uit
- **Geblokkeerde providers**: sluit specifieke providers uit van de `/v1/models`-lijst
</details>
<details>
<summary><b>🧰 17. "Ik heb MCP-tools nodig als eersteklas productmogelijkheden"</b></summary>
Veel AI-gateways stellen MCP alleen bloot als een verborgen implementatiedetail. Teams hebben een zichtbare, beheersbare operationele laag nodig.
**Hoe OmniRoute het oplost:**
- MCP verschijnt op het dashboardnavigatie- en eindpuntprotocoltabblad
- Speciale MCP-beheerpagina met proces, tools, scopes en audit
- Ingebouwde snelstart voor `omniroute --mcp` en onboarding van klanten
</details>
<details>
<summary><b>🧠 18. "Ik heb A2A-orkestratie nodig met synchronisatie- en streamtaakpaden"</b></summary>
Agentworkflows hebben zowel directe antwoorden nodig als langdurige gestreamde uitvoering met levenscycluscontrole.
**Hoe OmniRoute het oplost:**
- A2A JSON-RPC-eindpunt (`POST /a2a`) met `message/send` en `message/stream`
- SSE-streaming met voortplanting van de terminalstatus
- Taaklevenscyclus-API's voor `tasks/get` en `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Ik heb echte MCP-processtatus nodig, geen geraden status"</b></summary>
Operationele teams moeten weten of MCP daadwerkelijk leeft, en niet alleen of een API bereikbaar is.
**Hoe OmniRoute het oplost:**
- Runtime-hartslagbestand met PID, tijdstempels, transport, aantal gereedschappen en scope-modus
- MCP-status-API die hartslag + recente activiteit combineert
- UI-statuskaarten voor proces/uptime/hartslagversheid
</details>
<details>
<summary><b>📋 20. "Ik heb controleerbare MCP-tooluitvoering nodig"</b></summary>
Wanneer tools de configuratie muteren of operationele acties activeren, hebben teams forensische traceerbaarheid nodig.
**Hoe OmniRoute het oplost:**
- SQLite-ondersteunde auditregistratie voor MCP-toolaanroepen
- Filters op tool, succes/mislukking, API-sleutel en paginering
- Dashboard-audittabel + statistiekeneindpunten voor automatisering
</details>
<details>
<summary><b>🔐 21. "Ik heb MCP-rechten per integratie nodig"</b></summary>
Verschillende clients moeten toegang tot de toolcategorieën met de minste bevoegdheden hebben.
**Hoe OmniRoute het oplost:**
- 9 gedetailleerde MCP-scopes voor gecontroleerde toegang tot tools
- Scopehandhaving en zichtbaarheid in de MCP-beheerinterface
- Veilige standaardhouding voor operationeel gereedschap
</details>
<details>
<summary><b>⚙️ 22. "Ik heb operationele controles nodig zonder opnieuw te implementeren"</b></summary>
Teams hebben snelle runtimewijzigingen nodig tijdens incidenten of kostengebeurtenissen.
**Hoe OmniRoute het oplost:**
- Schakel combo-activering rechtstreeks vanuit het MCP-dashboard
- Pas veerkrachtprofielen toe uit vooraf gedefinieerde beleidspakketten
- Reset de status van de stroomonderbreker vanaf hetzelfde bedieningspaneel
</details>
<details>
<summary><b>🔄 23. "Ik heb live zichtbaarheid en annulering van de levenscyclus van A2A-taken nodig"</b></summary>
Zonder inzicht in de levenscyclus worden taakincidenten moeilijk te beoordelen.
**Hoe OmniRoute het oplost:**
- Takenlijst/filteren op staat/vaardigheid met paginering
- Inzoomen op taakmetagegevens, gebeurtenissen en artefacten
- Eindpunt voor het annuleren van taken en UI-actie met bevestiging
</details>
<details>
<summary><b>🌊 24. "Ik heb actieve streamstatistieken nodig voor A2A-belasting"</b></summary>
Streamingworkflows vereisen operationeel inzicht in gelijktijdigheid en liveverbindingen.
**Hoe OmniRoute het oplost:**
- Actieve streamtellers geïntegreerd in de A2A-status
- Tijdstempel van de laatste taak en tellingen per staat
- A2A-dashboardkaarten voor real-time operationele monitoring
</details>
<details>
<summary><b>🪪 25. "Ik heb standaard agentdetectie nodig voor klanten"</b></summary>
Externe klanten en orkestrators hebben machinaal leesbare metagegevens nodig voor onboarding.
**Hoe OmniRoute het oplost:**
- Agentkaart zichtbaar op `/.well-known/agent.json`
- Mogelijkheden en vaardigheden weergegeven in de management-UI
- A2A-status-API bevat ontdekkingsmetagegevens voor automatisering
</details>
<details>
<summary><b>🧭 26. "Ik heb protocolvindbaarheid nodig in de product-UX"</b></summary>
Als gebruikers protocoloppervlakken niet kunnen ontdekken, neemt de acceptatie- en ondersteuningskwaliteit af.
**Hoe OmniRoute het oplost:**
- Zijbalkinvoer voor MCP en A2A
- Eindpuntpagina Tabblad Protocollen met snelstart en status
- Koppelingen van overzicht naar speciale managementdashboards
</details>
<details>
<summary><b>🧪 27. "Ik heb end-to-end protocolvalidatie nodig met echte clients"</b></summary>
Mock-tests zijn niet voldoende om de protocolcompatibiliteit vóór de release te valideren.
**Hoe OmniRoute het oplost:**
- E2E-suite die de app opstart en echt MCP SDK-clienttransport gebruikt
- A2A-clienttests voor het ontdekken, verzenden, streamen, ophalen en annuleren van stromen
- Controleer beweringen aan de hand van MCP-audit- en A2A-taken-API's
</details>
<details>
<summary><b>📡 28. "Ik heb uniforme observatie nodig over alle interfaces heen"</b></summary>
Het opsplitsen van de waarneembaarheid per protocol creëert blinde vlekken en een langere MTTR.
**Hoe OmniRoute het oplost:**
- Uniforme dashboards/logboeken/analyses in één product
- Gezondheid + audit + verzoektelemetrie over OpenAI-, MCP- en A2A-lagen
- Operationele API's voor status en automatisering
</details>
<details>
<summary><b>💼 29. "Ik heb één runtime nodig voor proxy + tools + agentorkestratie"</b></summary>
Het uitvoeren van veel afzonderlijke services verhoogt de operationele kosten en faalwijzen.
**Hoe OmniRoute het oplost:**
- OpenAI-compatibele proxy, MCP-server en A2A-server in één stapel
- Gedeelde authenticatie, veerkracht, gegevensopslag en waarneembaarheid
- Consistent beleidsmodel op alle interactieoppervlakken
</details>
<details>
<summary><b>🚀 30. "Ik moet agentische workflows verzenden zonder wildgroei van lijmcodes"</b></summary>
Teams verliezen snelheid bij het samenvoegen van meerdere ad-hocservices en scripts.
**Hoe OmniRoute het oplost:**
- Uniforme eindpuntstrategie voor klanten en agenten
- Ingebouwde gebruikersinterfaces voor protocolbeheer en rookvalidatiepaden
- Productieklare fundamenten (beveiliging, loggen, veerkracht, back-up)
</details>
### Voorbeeld-playbooks (geïntegreerde gebruiksscenario's)
**Playbook A: Maximaliseer betaald abonnement + goedkope back-up**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Codeerstapel zonder kosten**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7, altijd actieve fallback-keten**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Agentoperaties met MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Snelle start
**1. Wereldwijd installeren:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +990,26 @@ OmniRoute bevat een krachtige ingebouwde Translator Playground met **4 modi** vo
</details>
---
## 🧪 Evaluaties (Evals)
## 🎯 Gebruiksscenario's
OmniRoute bevat een ingebouwd evaluatieframework om de LLM-responskwaliteit te testen aan de hand van een gouden set. U kunt deze openen via **Analytics → Evaluaties** in het dashboard.
### Geval 1: "Ik heb een Claude Pro-abonnement"
### Ingebouwde gouden set
**Probleem:** Quotum verloopt ongebruikt, snelheidslimieten tijdens intensief coderen
De vooraf geladen "OmniRoute Golden Set" bevat 10 testcases die betrekking hebben op:
```
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)
- Groeten, wiskunde, aardrijkskunde, codegeneratie
- Naleving van JSON-formaat, vertaling, prijsverlaging
- Veiligheidsweigering (schadelijke inhoud), tellen, booleaanse logica
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Evaluatiestrategieën
### Geval 2: "Ik wil geen kosten"
**Probleem:** Ik kan geen abonnementen betalen, heb betrouwbare AI-codering nodig
```
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
```
### Geval 3: "Ik heb 24/7 codering nodig, geen onderbrekingen"
**Probleem:** Deadlines, downtime is niet mogelijk
```
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
```
### Case 4: "Ik wil GRATIS AI in OpenClaw"
**Probleem:** AI-assistent nodig in berichtenapps, geheel gratis
```
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...
```
| Strategie | Beschrijving | Voorbeeld |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | De uitvoer moet exact overeenkomen met | `"4"` |
| `contains` | De uitvoer moet een subtekenreeks bevatten (niet hoofdlettergevoelig) | `"Paris"` |
| `regex` | Uitvoer moet overeenkomen met regex-patroon | `"1.*2.*3"` |
| `custom` | Aangepaste JS-functie retourneert waar/onwaar | `(output) => output.length > 10` |
---
@@ -1058,29 +1293,6 @@ Settings → API Configuration:
---
## 🧪 Evaluaties (Evals)
OmniRoute bevat een ingebouwd evaluatieframework om de LLM-responskwaliteit te testen aan de hand van een gouden set. U kunt deze openen via **Analytics → Evaluaties** in het dashboard.
### Ingebouwde gouden set
De vooraf geladen "OmniRoute Golden Set" bevat 10 testcases die betrekking hebben op:
- Groeten, wiskunde, aardrijkskunde, codegeneratie
- Naleving van JSON-formaat, vertaling, prijsverlaging
- Veiligheidsweigering (schadelijke inhoud), tellen, booleaanse logica
### Evaluatiestrategieën
| Strategie | Beschrijving | Voorbeeld |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | De uitvoer moet exact overeenkomen met | `"4"` |
| `contains` | De uitvoer moet een subtekenreeks bevatten (niet hoofdlettergevoelig) | `"Paris"` |
| `regex` | Uitvoer moet overeenkomen met regex-patroon | `"1.*2.*3"` |
| `custom` | Aangepaste JS-functie retourneert waar/onwaar | `(output) => output.length > 10` |
---
## 🐛 Problemen oplossen
<details>
@@ -1132,13 +1344,13 @@ De vooraf geladen "OmniRoute Golden Set" bevat 10 testcases die betrekking hebbe
- OmniRoute v1.0.6+ omvat fallback-validatie via chat-voltooiingen
- Zorg ervoor dat de basis-URL het achtervoegsel `/v1` bevat
### 🔐 OAuth em Servidor Remoto (OAuth-installatie op afstand)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ BELANGRIJK voor gebruik met OmniRoute op VPS/Docker/server op afstand**
### Waarom werkt OAuth met Antigravity / Gemini CLI op externe servers?
### OAuth
Deze bewijzen **Antigravity** en **Gemini CLI** gebruiken **Google OAuth 2.0** voor authenticatie. O Google vraagt dat `redirect_uri` geen OAuth-stroom gebruikt **exatamente** een van de URI's vóór de kadaster zonder toepassing van Google Cloud Console.
@@ -1279,18 +1491,19 @@ Als u geen geloofwaardige geloofwaardigheid meer heeft, is het mogelijk om de st
---
## 🗺️ Routekaart
## 🗺️
OmniRoute heeft **210+ functies gepland** over meerdere ontwikkelingsfasen. Dit zijn de belangrijkste gebieden:
| Categorie | Geplande functies | Hoogtepunten |
| ------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------- |
| 🧠 **Routing en intelligentie** | 25+ | Routering met de laagste latentie, op tags gebaseerde routering, quota-preflight, P2C-accountselectie |
| 🔒 **Beveiliging en naleving** | 20+ | SSRF-verharding, cloaking van inloggegevens, snelheidslimiet per eindpunt, scoping van beheersleutels |
| 📊 **Waarneembaarheid** | 15+ | OpenTelemetry-integratie, realtime quotabewaking, kostenregistratie per model |
| 🔄 **Provider-integraties** | 20+ | Dynamisch modelregister, cooldowns van providers, Codex met meerdere accounts, parseren van Copilot-quota |
| **Prestaties** | 15+ | Dubbele cachelaag, promptcache, responscache, streaming keepalive, batch-API |
| 🌐 **Ecosysteem** | 10+ | WebSocket API, configuratie hot-reload, gedistribueerde configuratieopslag, commerciële modus |
| Categorie | Geplande functies | Hoogtepunten |
| ------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🧠 **Routing en intelligentie** | 25+ | Routering met de laagste latentie, op tags gebaseerde routering, quota-preflight, P2C-accountselectie |
| 🔒 **Beveiliging en naleving** | 20+ | SSRF-verharding, cloaking van inloggegevens, snelheidslimiet per eindpunt, scoping van beheersleutels |
| 📊 **Waarneembaarheid** | 15+ | OpenTelemetry-integratie, realtime quotabewaking, kostenregistratie per model |
| 🔄 **Provider-integraties** | 20+ | Dynamisch modelregister, cooldowns van providers, Codex met meerdere accounts, parseren van Copilot-quota |
| **Prestaties** | 15+ | Dubbele cachelaag, promptcache, responscache, streaming keepalive, batch-API |
| 🌐 **Ecosysteem** | 10+ | WebSocket API, configuratie hot-reload, gedistribueerde configuratieopslag, commerciële modus |
### 🔜 Binnenkort beschikbaar
@@ -1304,18 +1517,6 @@ OmniRoute heeft **210+ functies gepland** over meerdere ontwikkelingsfasen. Dit
---
## 📧 Ondersteuning
> 💬 **Word lid van onze community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Krijg hulp, deel tips en blijf op de hoogte.
- **Website**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemen**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Origineel project**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Bijdragers
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Koble til ethvert AI-drevet IDE- eller CLI-verktøy gjennom OmniRoute grati
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Hvorfor OmniRoute?
**Slutt å kaste bort penger og nå grensene:**
@@ -128,6 +157,18 @@ _Koble til ethvert AI-drevet IDE- eller CLI-verktøy gjennom OmniRoute grati
---
## 📧 Støtte
> 💬 **Bli med i fellesskapet vårt!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Få hjelp, del tips og hold deg oppdatert.
- **Nettsted**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemer**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Originalt prosjekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Hvordan det fungerer
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Hva OmniRoute løser — 30 ekte smertepoeng og brukstilfeller
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Hver utviklere som bruker AI-verktøy møter disse problemene daglig.** OmniRoute ble bygget for å løse dem alle fra kostnadsoverskridelser til regionale blokker, fra ødelagte OAuth-flyter til protokolloperasjoner og observerbarhet i bedrifter.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Jeg betaler for et dyrt abonnement, men blir fortsatt avbrutt av grenser" </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Utviklere betaler $20200/måned for Claude Pro, Codex Pro eller GitHub Copilot. Selv om du betaler, har kvoten et tak 5 timers bruk, ukentlige grenser eller rategrenser per minutt. Midtkodingsøkt, leverandøren slutter å svare og utvikleren mister flyt og produktivitet.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-lags fallback** — Hvis abonnementskvoten går tom, omdirigeres automatisk til API-nøkkel → Billig → Gratis med null manuell intervensjon
- **Sanntidskvotesporing** — Viser tokenforbruk i sanntid med tilbakestilt nedtelling (5 timer, daglig, ukentlig)
- **Støtte for flere kontoer** - Flere kontoer per leverandør med automatisk round-robin - når en går tom, bytter du til den neste
- **Egendefinerte kombinasjoner** — Tilpassbare reservekjeder med 6 balansestrategier (fyllrst, round-robin, P2C, tilfeldig, minst brukt, kostnadsoptimalisert)
- **Codex Business Quotas** — Overvåking av bedrifts-/teamarbeidsområdekvoter direkte i dashbordet
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Jeg trenger å bruke flere leverandører, men hver av dem har en annen API" </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI bruker ett format, Claude (Anthropic) bruker et annet, Gemini enda et annet. Hvis en utvikler ønsker å teste modeller fra forskjellige leverandører eller fallback mellom dem, må de rekonfigurere SDK-er, endre endepunkter, håndtere inkompatible formater. Tilpassede leverandører (FriendLI, NIM) har ikke-standardmodellende endepunkter.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** - En enkelt `http://localhost:20128/v1` fungerer som proxy for alle 36+ leverandører
- **Formatoversettelse** — Automatisk og gjennomsiktig: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Responsrensing** — Fjerner ikke-standardfelter (`x_groq`, `usage_breakdown`, `service_tier`) som bryter OpenAI SDK v1.83+
- **Rollenormalisering** — Konverterer `developer``system` for ikke-OpenAI-leverandører; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Trekker ut `<think>`-blokker fra modeller som DeepSeek R1 til standardiserte `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatisk konvertering
- **`stream` er standard til `false`** — Justerer med OpenAI-spesifikasjoner, og unngår uventet SSE i Python/Rust/Go SDK-er
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Min AI-leverandør blokkerer min region/land" </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Leverandører som OpenAI/Codex blokkerer tilgang fra visse geografiske områder. Brukere får feil som `unsupported_country_region_territory` under OAuth- og API-tilkoblinger. Dette er spesielt frustrerende for utviklere fra utviklingsland.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-Level Proxy Config** — Konfigurerbar proxy 3 nivåer: global (all trafikk), per leverandør (kun én leverandør) og per tilkobling/nøkkel
- **Fargekodede proxy-merker** — Visuelle indikatorer: 🟢 global proxy, 🟡 leverandørproxy, 🔵 tilkoblings proxy, viser alltid IP
- **OAuth-tokenutveksling gjennom proxy** - OAuth-flyt går også gjennom proxyen, og løser `unsupported_country_region_territory`
- **Test av tilkobling via proxy** — Tilkoblingstester bruker den konfigurerte proxyen (ikke mer direkte forbikobling)
- **SOCKS5-støtte** — Full SOCKS5-proxystøtte for utgående ruting
- **TLS-fingeravtrykkspoofing** — Nettleserlignende TLS-fingeravtrykk via `wreq-js` for å omgå botdeteksjon
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Jeg vil bruke AI for koding, men jeg har ingen penger" </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Ikke alle kan betale $20200 per måned for AI-abonnementer. Studenter, utviklere fra fremvoksende land, hobbyfolk og frilansere trenger tilgang til kvalitetsmodeller uten kostnad.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Gratis-tilbydere innebygd** — Innebygd støtte for 100 % gratisleverandører: iFlow (8 ubegrensede modeller), Qwen (3 ubegrensede modeller), Kiro (Claude gratis), Gemini CLI (180K/mnd gratis)
- **Kun gratis kombinasjoner** — Kjede `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/måned med null nedetid
- **NVIDIA NIM gratis kreditter** — 1000 gratis kreditter integrert
- **Kostnadsoptimalisert strategi** — Rutingstrategi som automatisk velger den billigste tilgjengelige leverandøren
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Jeg trenger å beskytte AI-gatewayen min mot uautorisert tilgang" </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Når du eksponerer en AI-gateway til nettverket (LAN, VPS, Docker), kan alle med adressen konsumere utviklerens tokens/kvote. Uten beskyttelse er API-er sårbare for misbruk, umiddelbar injeksjon og misbruk.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API Key Management** — Generering, rotasjon og scoping per leverandør med en dedikert `/dashboard/api-manager`-side
- **Tillatelser på modellnivå** — Begrens API-nøkler til spesifikke modeller (`openai/*`, jokertegnmønstre), med Tillat alt/begrens
- **API Endpoint Protection** — Krev en nøkkel for `/v1/models` og blokker spesifikke leverandører fra oppføringen
- **Auth Guard + CSRF Protection** — Alle dashbordruter beskyttet med `withAuth` mellomvare + CSRF-tokens
- **Rate Limiter** — Per-IP ratebegrensning med konfigurerbare vinduer
- **IP-filtrering** — Tillatelsesliste/blokkeringsliste for tilgangskontroll
- **Prompt Injection Guard** — Sanitisering mot ondsinnede spørsmålsmønstre
- **AES-256-GCM-kryptering** — Legitimasjon kryptert i hvile
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. «Tilbyderen min gikk ned og jeg mistet kodeflyten min» </b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI-leverandører kan bli ustabile, returnere 5xx-feil eller nå midlertidige hastighetsgrenser. Hvis en utvikler er avhengig av en enkelt leverandør, blir de avbrutt. Uten strømbrytere kan gjentatte forsøk krasje applikasjonen.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Circuit Breaker per leverandør** — Automatisk åpning/lukking med konfigurerbare terskler og nedkjøling (Lukket/Åpen/Halpen)
- **Eksponentiell backoff** — Progressive forsinkelser på nytt forsøk
- **Anti-tordenflokk** — Mutex + semaforbeskyttelse mot samtidige stormer på nytt forsøk
- **Combo Fallback Chains** — Hvis primærleverandøren mislykkes, faller den automatisk gjennom kjeden uten inngrep
- **Combo Circuit Breaker** - Deaktiverer sviktende leverandører automatisk i en kombinasjonskjede
- **Helsedashbord** — Oppetidsovervåking, strømbrytertilstander, sperringer, cachestatistikk, p50/p95/p99 latency
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Å konfigurere hvert AI-verktøy er kjedelig og repeterende" </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Utviklere bruker Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Hvert verktøy trenger en annen konfigurasjon (API-endepunkt, nøkkel, modell). Å konfigurere på nytt når du bytter leverandør eller modell er bortkastet tid.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Dedikert side med ett-klikksoppsett for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Genererer `chatLanguageModels.json` for VS-kode med bulkmodellvalg
- **Onboarding Wizard** — Veiledet 4-trinns oppsett for førstegangsbrukere
- **Ett endepunkt, alle modeller** — Konfigurer `http://localhost:20128/v1` én gang, få tilgang til 36+ leverandører
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Å administrere OAuth-tokens fra flere leverandører er et helvete" </b></summary>
Claude Code, Codex, Gemini CLI, Copilot all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot alle bruker OAuth 2.0 med tokens som utløper. Utviklere må re-autentisere hele tiden, håndtere `client_secret is missing`, `redirect_uri_mismatch` og feil på eksterne servere. OAuth LAN/VPS er spesielt problematisk.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatisk oppdatering av token** — OAuth-tokener oppdateres i bakgrunnen før utløp
- **OAuth 2.0 (PKCE) innebygd** — Automatisk flyt for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** - Flere kontoer per leverandør via JWT/ID-tokenutvinning
- **OAuth LAN/Remote Fix** — Privat IP-deteksjon for `redirect_uri` + manuell URL-modus for eksterne servere
- **OAuth Behind Nginx** — Bruker `window.location.origin` for omvendt proxy-kompatibilitet
- **Remote OAuth Guide** — Trinn-for-trinn-veiledning for Google Cloud-legitimasjon på VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Jeg vet ikke hvor mye jeg bruker eller hvor" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Utviklere bruker flere betalte leverandører, men har ikke noe enhetlig syn på utgifter. Hver leverandør har sitt eget faktureringsdashbord, men det er ingen konsolidert visning. Uventede kostnader kan hope seg opp.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Dashboard for kostnadsanalyse** — Kostnadssporing per token og budsjettadministrasjon per leverandør
**Budsjettgrenser per nivå** Utgiftstak per nivå som utløser automatisk fallback
- **Priskonfigurasjon per modell** — Konfigurerbare priser per modell
- **Bruksstatistikk per API-nøkkel** — Antall forespørsler og sist brukte tidsstempel per nøkkel
- **Analytics Dashboard** — Statistiske kort, modellbruksdiagram, leverandørtabell med suksessrater og latens
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Jeg kan ikke diagnostisere feil og problemer i AI-anrop" </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Når et anrop mislykkes, vet ikke utvikleren om det var en takstgrense, utløpt token, feil format eller leverandørfeil. Fragmenterte logger på tvers av forskjellige terminaler. Uten observerbarhet er feilsøking prøving og feiling.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Unified Logs Dashboard** — 4 faner: Forespørselslogger, proxy-logger, revisjonslogger, konsoll
- **Console Log Viewer** — Viser i sanntid i terminalstil med fargekodede nivåer, automatisk rulling, søk, filter
- **SQLite Proxy Logger** — Vedvarende logger som overlever serverstarter
- **Translator Playground** — 4 feilsøkingsmoduser: Playground (formatoversettelse), Chat Tester (tur-retur), Test Bench (batch), Live Monitor (sanntid)
- **Request Telemetri** — p50/p95/p99 latens + X-Request-Id-sporing
- **Filbasert logging med rotasjon** — Konsollinterceptor fanger opp alt til JSON-logg med størrelsesbasert rotasjon
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Deployering og vedlikehold av gatewayen er kompleks" </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Installering, konfigurering og vedlikehold av en AI-proxy på tvers av forskjellige miljøer (lokalt, VPS, Docker, sky) er arbeidskrevende. Problemer som hardkodede baner, `EACCES` på kataloger, portkonflikter og kryssplattformbygg gir friksjon.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **npm global installasjon** — `npm install -g omniroute && omniroute`ferdig
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Docker Compose-profiler** — `base` (ingen CLI-verktøy) og `cli` (med Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Innebygd app for Windows/macOS/Linux med systemstatusfelt, automatisk start, offline-modus
- **Split-Port Mode** — API og Dashboard separate porter for avanserte scenarier (omvendt proxy, containernettverk)
- **Cloud Sync** — Konfigurer synkronisering på tvers av enheter via Cloudflare Workers
- **DB-sikkerhetskopier** — Automatisk sikkerhetskopiering, gjenoppretting, eksport og import av alle innstillinger
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Grensesnittet er kun engelsk, og teamet mitt snakker ikke engelsk" </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Lag i ikke-engelsktalende land, spesielt i Latin-Amerika, Asia og Europa, sliter med grensesnitt som kun er på engelsk. Språkbarrierer reduserer bruken og øker konfigurasjonsfeil.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 språk** — Alle 500+ nøkler oversatt, inkludert arabisk, bulgarsk, dansk, tysk, spansk, finsk, fransk, hebraisk, hindi, ungarsk, indonesisk, italiensk, japansk, koreansk, malaysisk, nederlandsk, norsk, polsk, portugisisk (PT/BR), rumensk, russisk, ukrainsk, ukrainsk, kinesisk, engelsk, kinesisk, ukrainsk, kinesisk, ukrainsk, kinesisk, ukrainsk, kinesisk, ukrainsk, kinesisk
- **RTL-støtte** — Høyre-til-venstre-støtte for arabisk og hebraisk
- **Multi-Language READMEs** - 30 komplette dokumentasjonsoversettelser
- **Språkvelger** — Globusikon i overskriften for sanntidsbytte
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Jeg trenger mer enn chat — jeg trenger innebygginger, bilder, lyd" </b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI er ikke bare fullføring av chat. Utviklere må generere bilder, transkribere lyd, lage innbygginger for RAG, omrangere dokumenter og moderere innhold. Hver API har et annet endepunkt og format.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Innbygging** — `/v1/embeddings` med 6 leverandører og 9+ modeller
- **Bildegenerering** — `/v1/images/generations` med 10 leverandører og 20+ modeller (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Tekst-til-video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) og SD WebUI
- **Tekst-til-musikk** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Lydtranskripsjon** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Tekst-til-tale** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + eksisterende leverandører
- **Moderasjoner** — `/v1/moderations` — Innholdssikkerhetssjekker
- **Rerangering** — `/v1/rerank` — Rerangering av dokumentrelevans
- **Responses API** — Full `/v1/responses`-støtte for Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Jeg har ingen måte å teste og sammenligne kvalitet på tvers av modeller" </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Utviklere ønsker å vite hvilken modell som er best for deres brukssituasjon kode, oversettelse, resonnement men det går tregt å sammenligne manuelt. Det finnes ingen integrerte evalueringsverktøy.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM-evalueringer** — Gyldent sett-testing med 10 forhåndslastede tilfeller som dekker hilsener, matematikk, geografi, kodegenerering, JSON-overholdelse, oversettelse, nedskrivning, sikkerhetsavslag
- **4 matchstrategier** — `exact`, `contains`, `regex`, `custom` (JS-funksjon)
- **Translator Playground Test Bench** — Batchtesting med flere innganger og forventede utganger, sammenligning på tvers av leverandører
- **Chattetester** — Full rundtur med visuell responsgjengivelse
- **Live Monitor** — Sanntidsstrøm av alle forespørsler som strømmer gjennom proxyen
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Jeg trenger å skalere uten å miste ytelse" </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Når forespørselsvolumet vokser, genererer de samme spørsmålene dupliserte kostnader uten å bufre. Uten idempotens, dupliserte forespørsler om avfallsbehandling. Satsgrenser per leverandør må respekteres.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Semantisk hurtigbuffer** — To-lags cache (signatur + semantisk) reduserer kostnader og ventetid
- **Request Idempotency** — 5s dedupliseringsvindu for identiske forespørsler
- **Deteksjon av hastighetsgrense** - RPM per leverandør, minimum gap og maksimal samtidig sporing
- **Redigerbare frekvensgrenser** — Konfigurerbare standardinnstillinger i Innstillinger → Motstandsdyktighet med utholdenhet
- **API Key Validation Cache** — 3-lags cache for produksjonsytelse
- **Helsedashbord med telemetri** — p50/p95/p99-forsinkelse, hurtigbufferstatistikk, oppetid
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Jeg vil kontrollere modellatferd globalt" </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Utviklere som vil ha alle svar på et spesifikt språk, med en bestemt tone, eller som ønsker å begrense resonnement-tokens. Å konfigurere dette i hvert verktøy/hver forespørsel er upraktisk.
**How OmniRoute solves it:**
**Hvordan OmniRoute løser det:**
- **System Prompt Injection** — Global prompt applied to all requests
- **System Prompt Injection** — Global forespørsel brukt på alle forespørsler
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **6 rutingstrategier** — Globale strategier som bestemmer hvordan forespørsler distribueres
- **Wildcard-ruter** — `provider/*`-mønstre ruter dynamisk til enhver leverandør
- **Kombo aktiver/deaktiver veksle** — Veksle kombinasjoner direkte fra dashbordet
- **Tilkobling av leverandør** — Aktiver/deaktiver alle tilkoblinger for en leverandør med ett klikk
- **Blokkerte leverandører** — Ekskluder spesifikke leverandører fra `/v1/models`-oppføringen
</details>
<details>
<summary><b>🧰 17. "Jeg trenger MCP-verktøy som førsteklasses produktegenskaper" </b></summary>
Mange AI-gatewayer avslører MCP bare som en skjult implementeringsdetalj. Team trenger et synlig, håndterbart driftslag.
**Hvordan OmniRoute løser det:**
- MCP vises i dashbordnavigasjons- og endepunktprotokollfanen
- Dedikert MCP-administrasjonsside med prosess, verktøy, omfang og revisjon
- Innebygd hurtigstart for `omniroute --mcp` og klient onboarding
</details>
<details>
<summary><b>🧠 18. "Jeg trenger A2A-orkestrering med synkronisering + strømoppgavestier" </b></summary>
Agentarbeidsflyter trenger både direkte svar og langvarig strømmet utførelse med livssykluskontroll.
**Hvordan OmniRoute løser det:**
- A2A JSON-RPC-endepunkt (`POST /a2a`) med `message/send` og `message/stream`
- SSE-streaming med forplantning av terminaltilstand
- Oppgavelivssyklus-APIer for `tasks/get` og `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Jeg trenger ekte MCP-prosesshelse, ikke gjettet status" </b></summary>
Operasjonelle team må vite om MCP faktisk er i live, ikke bare om en API er tilgjengelig.
**Hvordan OmniRoute løser det:**
- Runtime hjerteslag-fil med PID, tidsstempler, transport, verktøytelling og omfangsmodus
- MCP status API som kombinerer hjerteslag + nylig aktivitet
- UI-statuskort for prosess/oppetid/hjerteslag
</details>
<details>
<summary><b>📋 20. "Jeg trenger reviderbar MCP-verktøykjøring" </b></summary>
Når verktøy muterer konfigurasjon eller utløser operasjonshandlinger, trenger teamene rettsmedisinsk sporbarhet.
**Hvordan OmniRoute løser det:**
- SQLite-støttet revisjonslogging for MCP-verktøykall
- Filtrerer etter verktøy, suksess/fiasko, API-nøkkel og paginering
- Dashboard revisjonstabell + statistikkendepunkter for automatisering
</details>
<details>
<summary><b>🔐 21. "Jeg trenger scoped MCP-tillatelser per integrasjon" </b></summary>
Ulike klienter bør ha minst privilegert tilgang til verktøykategorier.
**Hvordan OmniRoute løser det:**
- 9 granulære MCP-skoper for kontrollert verktøytilgang
- Håndhevelse av omfang og synlighet i MCP-administrasjonsgrensesnittet
- Sikker standardstilling for operativt verktøy
</details>
<details>
<summary><b>⚙️ 22. "Jeg trenger operasjonelle kontroller uten å omdistribuere" </b></summary>
Lag trenger raske endringer i kjøretiden under hendelser eller kostnadshendelser.
**Hvordan OmniRoute løser det:**
- Bytt kombinasjonsaktivering direkte fra MCP-dashbordet
- Bruk robusthetsprofiler fra forhåndsdefinerte policypakker
- Tilbakestill strømbryterens tilstand fra samme driftspanel
</details>
<details>
<summary><b>🔄 23. «I need live A2A task lifecycle synibility and cancellation»</b></summary>
Uten livssyklussynlighet blir oppgavehendelser vanskelig å triage.
**Hvordan OmniRoute løser det:**
- Oppgaveliste/filtrering etter tilstand/ferdighet med paginering
- Drill-down på oppgavemetadata, hendelser og artefakter
- Sluttpunkt for kansellering av oppgave og UI-handling med bekreftelse
</details>
<details>
<summary><b>🌊 24. «Jeg trenger aktive strømmålinger for A2A-last» </b></summary>
Strømmearbeidsflyter krever operasjonell innsikt i samtidighet og direkteforbindelser.
**Hvordan OmniRoute løser det:**
- Aktive strømtellere integrert i A2A-status
- Tidsstempel for siste oppgave og antall per stat
- A2A dashbordkort for operasjonsovervåking i sanntid
</details>
<details>
<summary><b>🪪 25. "Jeg trenger standard agentoppdagelse for klienter" </b></summary>
Eksterne klienter og orkestratorer trenger maskinlesbare metadata for onboarding.
**Hvordan OmniRoute løser det:**
- Agentkort eksponert på `/.well-known/agent.json`
- Evner og ferdigheter vist i ledelsens brukergrensesnitt
- A2A status API inkluderer oppdagelsesmetadata for automatisering
</details>
<details>
<summary><b>🧭 26. "Jeg trenger protokolloppdagbarhet i produktets UX" </b></summary>
Hvis brukere ikke kan oppdage protokolloverflater, faller kvaliteten på adopsjon og støtte.
**Hvordan OmniRoute løser det:**
- Sidefeltoppføringer for MCP og A2A
- Endpoint-side Protokoller-fane med hurtigstart og status
- Lenker fra oversikt til dedikerte styringsdashboards
</details>
<details>
<summary><b>🧪 27. "Jeg trenger ende-til-ende protokollvalidering med ekte klienter" </b></summary>
Mock-tester er ikke nok til å validere protokollkompatibilitet før utgivelse.
**Hvordan OmniRoute løser det:**
- E2E-suite som starter opp app og bruker ekte MCP SDK-klienttransport
- A2A-klient tester for å oppdage, sende, streame, hente og kansellere flyter
- Krysssjekk påstander mot MCP-revisjon og A2A-oppgave-APIer
</details>
<details>
<summary><b>📡 28. «Jeg trenger enhetlig observerbarhet på tvers av alle grensesnitt» </b></summary>
Å dele observerbarhet etter protokoll skaper blinde flekker og lengre MTTR.
**Hvordan OmniRoute løser det:**
- Samlede dashboards/logger/analyse i ett produkt
- Helse + revisjon + forespørsel om telemetri på tvers av OpenAI-, MCP- og A2A-lag
- Operasjonelle APIer for status og automatisering
</details>
<details>
<summary><b>💼 29. "Jeg trenger én kjøretid for proxy + verktøy + agentorkestrering" </b></summary>
Å kjøre mange separate tjenester øker driftskostnadene og feilmodusene.
**Hvordan OmniRoute løser det:**
- OpenAI-kompatibel proxy, MCP-server og A2A-server i én stabel
- Delt autentisering, robusthet, datalagring og observerbarhet
- Konsekvent policymodell på tvers av alle interaksjonsflater
</details>
<details>
<summary><b>🚀 30. "Jeg trenger å sende agentiske arbeidsflyter uten limkodespredning" </b></summary>
Lag mister hastighet når de setter sammen flere ad-hoc-tjenester og skript.
**Hvordan OmniRoute løser det:**
- Enhetlig endepunktstrategi for kunder og agenter
- Innebygde brukergrensesnitt for protokolladministrasjon og røykvalideringsveier
- Produksjonsklare fundamenter (sikkerhet, logging, robusthet, backup)
</details>
### Eksempel på Playbooks (integrerte brukstilfeller)
**Playbook A: Maksimer betalt abonnement + billig backup**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Nullkostnadskodestabel**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 alltid aktiv reservekjede**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Agentoperasjoner med MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Hurtigstart
**1. Installer globalt:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -589,6 +864,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Funksjon | Hva det gjør |
| --------------------------------- | ----------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Automatisk åpning/lukking per leverandør med konfigurerbare terskler |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-tordenflokk** | Mutex + semaforhastighetsgrense for API-nøkkelleverandører |
| 🧠 **Semantisk cache** | To-lags cache (signatur + semantisk) reduserer kostnader og ventetid |
| ⚡ **Be om idempotens** | 5s dedup-vindu for dupliserte forespørsler |
@@ -715,66 +991,26 @@ OmniRoute inkluderer en kraftig innebygd oversetterlekeplass med **4 moduser** f
</details>
---
## 🧪 Evalueringer (evalueringer)
## 🎯 Brukssaker
OmniRoute inkluderer et innebygd evalueringsrammeverk for å teste LLM-responskvaliteten mot et gyldent sett. Få tilgang til den via **Analytics → Evals** i dashbordet.
### Sak 1: "Jeg har Claude Pro-abonnement"
### Innebygd gyldent sett
**Problem:** Kvoten utløper ubrukt, satsgrenser under tung koding
Det forhåndsinstallerte "OmniRoute Golden Set" inneholder 10 testcases som dekker:
```
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)
- Hilsen, matematikk, geografi, kodegenerering
- JSON-formatoverholdelse, oversettelse, markdown
- Sikkerhetsavslag (skadelig innhold), telling, boolsk logikk
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Evalueringsstrategier
### Tilfelle 2: "Jeg vil ha null kostnad"
**Problem:** Har ikke råd til abonnementer, trenger pålitelig AI-koding
```
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
```
### Tilfelle 3: "Jeg trenger 24/7 koding, ingen avbrudd"
**Problem:** Tidsfrister, har ikke råd til nedetid
```
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
```
### Tilfelle 4: "Jeg vil ha GRATIS AI i OpenClaw"
**Problem:** Trenger AI-assistent i meldingsapper, helt gratis
```
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...
```
| Strategi | Beskrivelse | Eksempel |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | Utdata må samsvare nøyaktig med | `"4"` |
| `contains` | Utdata må inneholde understreng (uavhengig av store og små bokstaver) | `"Paris"` |
| `regex` | Utdata må samsvare med regulært uttrykksmønster | `"1.*2.*3"` |
| `custom` | Egendefinert JS-funksjon returnerer true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Evalueringer (evalueringer)
OmniRoute inkluderer et innebygd evalueringsrammeverk for å teste LLM-responskvaliteten mot et gyldent sett. Få tilgang til den via **Analytics → Evals** i dashbordet.
### Innebygd gyldent sett
Det forhåndsinstallerte "OmniRoute Golden Set" inneholder 10 testcases som dekker:
- Hilsen, matematikk, geografi, kodegenerering
- JSON-formatoverholdelse, oversettelse, markdown
- Sikkerhetsavslag (skadelig innhold), telling, boolsk logikk
### Evalueringsstrategier
| Strategi | Beskrivelse | Eksempel |
| ---------- | --------------------------------------------------------------------- | -------------------------------- |
| `exact` | Utdata må samsvare nøyaktig med | `"4"` |
| `contains` | Utdata må inneholde understreng (uavhengig av store og små bokstaver) | `"Paris"` |
| `regex` | Utdata må samsvare med regulært uttrykksmønster | `"1.*2.*3"` |
| `custom` | Egendefinert JS-funksjon returnerer true/false | `(output) => output.length > 10` |
---
## 🐛 Feilsøking
<details>
@@ -1132,13 +1345,13 @@ Det forhåndsinstallerte "OmniRoute Golden Set" inneholder 10 testcases som dekk
- OmniRoute v1.0.6+ inkluderer reservevalidering via chatfullføringer
- Sørg for at basis-URL inkluderer suffikset `/v1`
### 🔐 OAuth em Servidor Remoto (Ekstern OAuth-oppsett)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ VIKTIG for bruk av OmniRoute med VPS/Docker/server-fjernkontroll**
### Hva med OAuth gjør Antigravity / Gemini CLI falha em servidores remotos?
### OAuth
Os testedores **Antigravity** og **Gemini CLI** usam **Google OAuth 2.0** for autenticação. O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pre-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **Kjøretid**: Node.js 1822 LTS (⚠️ Node.js 24+ støttes **ikke**`better-sqlite3` native binærfiler er inkompatible)
- **Språk**: TypeScript 5.9 — **100 % TypeScript** på tvers av `src/` og `open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Veikart
## 🗺️
OmniRoute har **210+ funksjoner planlagt** på tvers av flere utviklingsfaser. Her er nøkkelområdene:
@@ -1304,18 +1517,6 @@ OmniRoute har **210+ funksjoner planlagt** på tvers av flere utviklingsfaser. H
---
## 📧 Støtte
> 💬 **Bli med i fellesskapet vårt!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Få hjelp, del tips og hold deg oppdatert.
- **Nettsted**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemer**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Originalt prosjekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Bidragsytere
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Ikonekta ang anumang AI-powered IDE o CLI tool sa pamamagitan ng OmniRoute —
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Bakit OmniRoute?
**Ihinto ang pag-aaksaya ng pera at pag-abot sa mga limitasyon:**
@@ -128,6 +157,18 @@ _Ikonekta ang anumang AI-powered IDE o CLI tool sa pamamagitan ng OmniRoute —
---
## 📧 Suporta
> 💬 **Sumali sa aming komunidad!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Humingi ng tulong, magbahagi ng mga tip, at manatiling updated.
- **Website**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Mga Isyu**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Orihinal na Proyekto**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Paano Ito Gumagana
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Ano ang Lutasin ng OmniRoute — 30 Tunay na Pain Points at Mga Kaso ng Paggamit
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Ang bawat developer na gumagamit ng mga tool ng AI ay nahaharap sa mga problemang ito araw-araw.** Binuo ang OmniRoute para lutasin ang lahat ng ito — mula sa mga pag-overrun sa gastos hanggang sa mga panrehiyong bloke, mula sa mga sirang daloy ng OAuth hanggang sa mga pagpapatakbo ng protocol at pagmamasid sa enterprise.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Nagbabayad ako para sa isang mamahaling subscription ngunit naaantala pa rin ng mga limitasyon"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Nagbabayad ang mga developer ng $20200/buwan para sa Claude Pro, Codex Pro, o GitHub Copilot. Kahit na nagbabayad, may kisame ang quota — 5h ng paggamit, lingguhang limitasyon, o bawat minutong limitasyon sa rate. Sesyon sa kalagitnaan ng coding, hihinto sa pagtugon ang provider at nawawalan ng daloy at pagiging produktibo ang developer.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Kung maubusan ang quota ng subscription, awtomatikong magre-redirect sa API Key → Murang → Libre nang walang manu-manong interbensyon
- **Real-Time Quota Tracking** — Ipinapakita ang pagkonsumo ng token sa real-time na may reset countdown (5h, araw-araw, lingguhan)
- **Multi-Account Support** — Maramihang account sa bawat provider na may auto round-robin — kapag naubos ang isa, lilipat sa susunod
- **Custom Combos** — Nako-customize na fallback chain na may 6 na diskarte sa pagbabalanse (fill-first, round-robin, P2C, random, hindi gaanong ginagamit, cost-optimized)
- **Codex Business Quotas** — Direktang pagsubaybay sa quota ng workspace ng Negosyo/Team sa dashboard
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Kailangan kong gumamit ng maraming provider ngunit bawat isa ay may iba't ibang API"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
Gumagamit ang OpenAI ng isang format, gumagamit si Claude (Anthropic) ng isa pa, isa pa ang Gemini. Kung gusto ng isang dev na subukan ang mga modelo mula sa iba't ibang provider o fallback sa pagitan nila, kailangan nilang i-configure muli ang mga SDK, baguhin ang mga endpoint, harapin ang mga hindi tugmang format. Ang mga custom na provider (FriendLI, NIM) ay may hindi karaniwang mga endpoint ng modelo.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Pinag-isang Endpoint** — Isang `http://localhost:20128/v1` ang nagsisilbing proxy para sa lahat ng 36+ provider
- **Format Translation** — Awtomatiko at transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Tinatanggal ang mga hindi karaniwang field (`x_groq`, `usage_breakdown`, `service_tier`) na sumisira sa OpenAI SDK v1.83+
- **Role Normalization** — Kino-convert ang `developer``system` para sa mga provider na hindi OpenAI; `system``user` para sa GLM/ERNIE
- **Think Tag Extraction** — Kinukuha ang `<think>` block mula sa mga modelo tulad ng DeepSeek R1 sa standardized `reasoning_content`
- **Structured Output para sa Gemini** — `json_schema``responseMimeType`/`responseSchema` awtomatikong conversion
- **`stream` ang mga default sa `false`** — Naka-align sa OpenAI spec, iniiwasan ang hindi inaasahang SSE sa Python/Rust/Go SDK
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Bina-block ng aking AI provider ang aking rehiyon/bansa"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Hinaharang ng mga provider tulad ng OpenAI/Codex ang pag-access mula sa ilang partikular na heyograpikong rehiyon. Nakakakuha ang mga user ng mga error tulad ng `unsupported_country_region_territory` sa panahon ng mga koneksyon sa OAuth at API. Ito ay lalo na nakakabigo para sa mga developer mula sa pagbuo ng mga bansa.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-Level Proxy Config** — Nako-configure na proxy sa 3 antas: global (lahat ng trapiko), bawat provider (isang provider lang), at bawat koneksyon/key
- **Color-Coded Proxy Badges** — Visual indicator: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, palaging ipinapakita ang IP
- **OAuth Token Exchange Through Proxy** — Ang daloy ng OAuth ay dumadaan din sa proxy, na nilulutas ang `unsupported_country_region_territory`
- **Mga Pagsusuri sa Koneksyon sa pamamagitan ng Proxy** — Ginagamit ng mga pagsubok sa koneksyon ang naka-configure na proxy (wala nang direktang bypass)
- **SOCKS5 Support** — Buong SOCKS5 proxy support para sa papalabas na pagruruta
- **TLS Fingerprint Spoofing** — tulad ng browser na TLS fingerprint sa pamamagitan ng `wreq-js` para i-bypass ang pag-detect ng bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Gusto kong gumamit ng AI para sa coding ngunit wala akong pera"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Hindi lahat ay maaaring magbayad ng $20200/buwan para sa mga subscription sa AI. Ang mga mag-aaral, mga dev mula sa mga umuusbong na bansa, mga hobbyist, at mga freelancer ay nangangailangan ng access sa mga de-kalidad na modelo sa zero cost.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Libreng Tier Provider Built-in** — Native na suporta para sa 100% libreng provider: iFlow (8 unlimited na modelo), Qwen (3 unlimited na modelo), Kiro (Claude nang libre), Gemini CLI (180K/buwan libre)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/buwan na walang downtime
- **NVIDIA NIM Free Credits** — 1000 libreng credits na isinama
- **Cost Optimized Strategy** — Istratehiya sa pagruruta na awtomatikong pinipili ang pinakamurang available na provider
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Kailangan kong protektahan ang aking AI gateway mula sa hindi awtorisadong pag-access"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Kapag inilantad ang isang gateway ng AI sa network (LAN, VPS, Docker), maaaring kumonsumo ng mga token/quota ng developer ang sinumang may address. Kung walang proteksyon, ang mga API ay mahina sa maling paggamit, agarang pag-iniksyon, at pang-aabuso.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API Key Management** — Pagbuo, pag-ikot, at saklaw ng bawat provider na may nakalaang `/dashboard/api-manager` na pahina
- **Mga Pahintulot sa Antas ng Modelo** — Limitahan ang mga API key sa mga partikular na modelo (`openai/*`, mga wildcard pattern), na may Allow All/Restrict toggle
- **API Endpoint Protection** — Mangangailangan ng key para sa `/v1/models` at i-block ang mga partikular na provider mula sa listahan
- **Auth Guard + CSRF Protection** — Lahat ng mga ruta ng dashboard ay protektado ng `withAuth` middleware + CSRF token
- **Rate Limiter** — Per-IP rate na naglilimita sa mga na-configure na window
- **IP Filtering** — Allowlist/blocklist para sa access control
- **Prompt Injection Guard** — Sanitization laban sa malisyosong prompt pattern
- **AES-256-GCM Encryption** — Ang mga kredensyal ay naka-encrypt sa pahinga
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Bumaba ang provider ko at nawala ang coding flow ko"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Ang mga tagapagbigay ng AI ay maaaring maging hindi matatag, magbalik ng 5xx na mga error, o maabot ang mga pansamantalang limitasyon sa rate. Kung ang isang dev ay nakadepende sa isang provider, maaantala sila. Kung walang mga circuit breaker, ang mga paulit-ulit na pagsubok ay maaaring mag-crash sa application.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Circuit Breaker per-model** — Awtomatikong buksan/sarado na may mga na-configure na threshold at cooldown (Sarado/Bukas/Kalahating Bukas)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Anti-Thundering Herd** — Mutex + semaphore na proteksyon laban sa kasabay na muling pagsubok na mga bagyo
- **Combo Fallback Chains** — Kung nabigo ang pangunahing provider, awtomatikong mahuhulog sa chain nang walang interbensyon
- **Combo Circuit Breaker** — Awtomatikong idi-disable ang mga nabigong provider sa loob ng combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Ang pag-configure ng bawat AI tool ay nakakapagod at paulit-ulit"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Gumagamit ang mga developer ng Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Ang bawat tool ay nangangailangan ng ibang config (API endpoint, key, model). Ang muling pag-configure kapag lumipat ng mga provider o modelo ay isang pag-aaksaya ng oras.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Nakatuon na page na may isang-click na setup para sa Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Bumubuo ng `chatLanguageModels.json` para sa VS Code na may maramihang pagpili ng modelo
- **Onboarding Wizard** — May gabay na 4-step na pag-setup para sa mga unang beses na user
- **Isang endpoint, lahat ng modelo** — I-configure ang `http://localhost:20128/v1` nang isang beses, i-access ang 36+ provider
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Impiyerno ang pamamahala sa mga token ng OAuth mula sa maraming provider"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — lahat ay gumagamit ng OAuth 2.0 na may mga mag-e-expire na token. Kailangang muling mag-authenticate ang mga developer, harapin ang `client_secret is missing`, `redirect_uri_mismatch`, at mga pagkabigo sa mga malalayong server. Ang OAuth sa LAN/VPS ay partikular na may problema.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Auto Token Refresh** — Ang mga token ng OAuth ay nagre-refresh sa background bago mag-expire
- **OAuth 2.0 (PKCE) Built-in** — Awtomatikong daloy para sa Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Maramihang account bawat provider sa pamamagitan ng pagkuha ng token ng JWT/ID
- **OAuth LAN/Remote Fix** — Pribadong IP detection para sa `redirect_uri` + manual URL mode para sa mga malalayong server
- **OAuth Behind Nginx** — Gumagamit ng `window.location.origin` para sa reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step na gabay para sa mga kredensyal ng Google Cloud sa VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Hindi ko alam kung magkano ang ginagastos ko o kung saan"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Gumagamit ang mga developer ng maraming bayad na provider ngunit walang pinag-isang pagtingin sa paggastos. Ang bawat provider ay may sariling dashboard ng pagsingil, ngunit walang pinagsama-samang view. Maaaring tumambak ang mga hindi inaasahang gastos.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Cost Analytics Dashboard** — Per-token cost tracking at pamamahala ng badyet bawat provider
- **Mga Limitasyon sa Badyet bawat Tier** — Paggastos ng kisame sa bawat tier na nagti-trigger ng awtomatikong fallback
- **Per-Model Pricing Configuration** — Nako-configure na mga presyo bawat modelo
- **Mga Istatistika ng Paggamit Bawat API Key** — Bilang ng kahilingan at timestamp na huling ginamit bawat key
- **Analytics Dashboard** — Mga stat card, chart ng paggamit ng modelo, talahanayan ng provider na may mga rate ng tagumpay at latency
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Hindi ko matukoy ang mga error at problema sa mga tawag sa AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Kapag nabigo ang isang tawag, hindi alam ng dev kung ito ay isang limitasyon sa rate, nag-expire na token, maling format, o error sa provider. Mga fragment na log sa iba't ibang terminal. Kung walang pagmamasid, ang pag-debug ay trial-and-error.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Unified Logs Dashboard** — 4 na tab: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time na terminal-style viewer na may color-coded level, auto-scroll, paghahanap, filter
- **SQLite Proxy Logs** — Mga paulit-ulit na log na nakaligtas sa pag-restart ng server
- **Translator Playground** — 4 na mode ng pag-debug: Playground (pagsasalin ng format), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Pag-log na Nakabatay sa File na may Pag-ikot** — Kinukuha ng Console interceptor ang lahat sa log ng JSON na may pag-ikot batay sa laki
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Ang pag-deploy at pagpapanatili ng gateway ay kumplikado"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Ang pag-install, pag-configure, at pagpapanatili ng AI proxy sa iba't ibang kapaligiran (lokal, VPS, Docker, cloud) ay labor-intensive. Ang mga problema tulad ng mga hardcoded na path, `EACCES` sa mga direktoryo, port conflict, at cross-platform build ay nagdaragdag ng friction.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **npm global install** — `npm install -g omniroute && omniroute`tapos na
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Docker Compose Profiles** — `base` (walang CLI tool) at `cli` (na may Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app para sa Windows/macOS/Linux na may system tray, auto-start, offline mode
- **Split-Port Mode** — API at Dashboard sa magkahiwalay na port para sa mga advanced na sitwasyon (reverse proxy, container networking)
- **Cloud Sync** — I-configure ang pag-synchronize sa mga device sa pamamagitan ng Cloudflare Workers
- **DB Backup** — Awtomatikong pag-backup, pagpapanumbalik, pag-export at pag-import ng lahat ng mga setting
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Ang interface ay English-only at ang aking team ay hindi nagsasalita ng English"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Ang mga koponan sa mga bansang hindi nagsasalita ng Ingles, lalo na sa Latin America, Asia, at Europe, ay nakikipagpunyagi sa mga interface na Ingles lamang. Binabawasan ng mga hadlang sa wika ang pag-aampon at pinapataas ang mga error sa pagsasaayos.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 Wika** — Lahat ng 500+ key na isinalin kasama ang Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Vietnamese
- **RTL Support** — Kanan-pakaliwa na suporta para sa Arabic at Hebrew
- **Multi-Language READMEs** — 30 kumpletong pagsasalin ng dokumentasyon
- **Language Selector** — Globe icon sa header para sa real-time na paglipat
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Kailangan ko ng higit pa sa chat — kailangan ko ng mga embed, larawan, audio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
Ang AI ay hindi lamang pagkumpleto ng chat. Kailangan ng mga dev na bumuo ng mga larawan, mag-transcribe ng audio, gumawa ng mga pag-embed para sa RAG, mag-rerank ng mga dokumento, at katamtamang nilalaman. Ang bawat API ay may iba't ibang endpoint at format.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Mga Pag-embed** — `/v1/embeddings` na may 6 na provider at 9+ na modelo
- **Pagbuo ng Larawan** — `/v1/images/generations` na may 10 provider at 20+ modelo (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) at SD WebUI
- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + mga kasalukuyang provider
- **Moderations** — `/v1/moderations` — Mga pagsusuri sa kaligtasan ng content
- **Muling pagraranggo** — `/v1/rerank` — Muling pagraranggo ng kaugnayan ng dokumento
- **Responses API** — Buong `/v1/responses` na suporta para sa Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Wala akong paraan para subukan at paghambingin ang kalidad sa mga modelo"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Gustong malaman ng mga developer kung aling modelo ang pinakamainam para sa kanilang kaso ng paggamit — code, pagsasalin, pangangatwiran — ngunit mabagal ang paghahambing nang manu-mano. Walang pinagsamang mga tool sa eval ang umiiral.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM Evaluations** — Golden set testing na may 10 pre-loaded na case na sumasaklaw sa mga pagbati, matematika, heograpiya, pagbuo ng code, pagsunod sa JSON, pagsasalin, markdown, pagtanggi sa kaligtasan
- **4 na Istratehiya sa Pagtutugma** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing na may maraming input at inaasahang output, cross-provider na paghahambing
- **Chat Tester** — Buong round-trip na may visual response rendering
- **Live Monitor** — Real-time na stream ng lahat ng kahilingang dumadaloy sa proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Kailangan kong mag-scale nang hindi nawawala ang performance"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Habang lumalaki ang dami ng kahilingan, nang walang pag-cache sa parehong mga tanong ay bumubuo ng mga dobleng gastos. Nang walang idempotency, humihiling ang duplicate sa pagpoproseso ng basura. Dapat igalang ang mga limitasyon sa rate ng bawat provider.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Semantic Cache** — Ang two-tier na cache (pirma + semantiko) ay binabawasan ang gastos at latency
- **Request Idempotency** — 5s deduplication window para sa magkaparehong mga kahilingan
- **Pagtukoy sa Limitasyon ng Rate** — RPM ng bawat provider, min na gap, at max na kasabay na pagsubaybay
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **API Key Validation Cache** — 3-tier na cache para sa performance ng produksyon
- **Health Dashboard na may Telemetry** — p50/p95/p99 latency, cache stats, uptime
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Gusto kong kontrolin ang gawi ng modelo sa buong mundo"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Mga developer na gusto ang lahat ng tugon sa isang partikular na wika, na may partikular na tono, o gustong limitahan ang mga token ng pangangatwiran. Ang pag-configure nito sa bawat tool/kahilingan ay hindi praktikal.
**How OmniRoute solves it:**
**Paano ito niresolba ng OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **System Prompt Injection** — Inilapat ang pandaigdigang prompt sa lahat ng kahilingan
- **Thinking Budget Validation** — Reasoning token allocation control bawat kahilingan (passthrough, auto, custom, adaptive)
- **6 Mga Istratehiya sa Pagruruta** — Mga pandaigdigang diskarte na tumutukoy kung paano ipinamamahagi ang mga kahilingan
- **Wildcard Router** — Ang mga pattern ng `provider/*` ay dynamic na ruta sa anumang provider
- **Combo Enable/Disable Toggle** — I-toggle ang mga combo nang direkta mula sa dashboard
- **Toggle ng Provider** — I-enable/i-disable ang lahat ng koneksyon para sa isang provider sa isang click
- **Mga Naka-block na Provider** — Ibukod ang mga partikular na provider mula sa listahan ng `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Kailangan ko ng mga tool sa MCP bilang mga first-class na kakayahan ng produkto"</b></summary>
Maraming AI gateway ang naglalantad sa MCP bilang isang nakatagong detalye ng pagpapatupad. Ang mga koponan ay nangangailangan ng isang nakikita, napapamahalaang layer ng operasyon.
**Paano ito niresolba ng OmniRoute:**
- Lumilitaw ang MCP sa dashboard navigation at tab ng endpoint protocol
- Nakatuon na pahina ng pamamahala ng MCP na may proseso, mga tool, saklaw, at pag-audit
- Built-in na quick-start para sa `omniroute --mcp` at onboarding ng kliyente
</details>
<details>
<summary><b>🧠 18. "Kailangan ko ng A2A orchestration na may sync + stream task path"</b></summary>
Ang mga daloy ng trabaho ng ahente ay nangangailangan ng parehong direktang tugon at matagal na naka-stream na pagpapatupad na may kontrol sa lifecycle.
**Paano ito niresolba ng OmniRoute:**
- A2A JSON-RPC endpoint (`POST /a2a`) na may `message/send` at `message/stream`
- SSE streaming na may terminal state propagation
- Mga task lifecycle API para sa `tasks/get` at `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Kailangan ko ng totoong kalusugan ng proseso ng MCP, hindi nahulaan ang status"</b></summary>
Kailangang malaman ng mga operational team kung talagang buhay ang MCP, hindi lang kung maaabot ang isang API.
**Paano ito niresolba ng OmniRoute:**
- Runtime heartbeat file na may PID, timestamp, transport, bilang ng tool, at mode ng saklaw
- MCP status API na pinagsasama ang tibok ng puso + kamakailang aktibidad
- Mga UI status card para sa pagiging bago ng proseso/uptime/heartbeat
</details>
<details>
<summary><b>📋 20. "Kailangan ko ng auditable MCP tool execution"</b></summary>
Kapag ang mga tool ay nag-mutate ng config o nag-trigger ng mga pagkilos ng ops, ang mga team ay nangangailangan ng forensic traceability.
**Paano ito niresolba ng OmniRoute:**
- SQLite-backed audit logging para sa mga tawag sa tool ng MCP
- Mga filter ayon sa tool, tagumpay/kabiguan, API key, at pagination
- Dashboard audit table + stats endpoints para sa automation
</details>
<details>
<summary><b>🔐 21. "Kailangan ko ng mga saklaw na pahintulot ng MCP sa bawat pagsasama"</b></summary>
Ang iba't ibang mga kliyente ay dapat magkaroon ng hindi gaanong pribilehiyong pag-access sa mga kategorya ng tool.
**Paano ito niresolba ng OmniRoute:**
- 9 na butil na saklaw ng MCP para sa kontroladong pag-access ng tool
- Pagpapatupad ng saklaw at kakayahang makita sa UI ng pamamahala ng MCP
- Ligtas na default na postura para sa operational tooling
</details>
<details>
<summary><b>⚙️ 22. "Kailangan ko ng mga kontrol sa pagpapatakbo nang hindi nagre-redeploy"</b></summary>
Ang mga koponan ay nangangailangan ng mabilis na mga pagbabago sa runtime sa panahon ng mga insidente o mga kaganapan sa gastos.
**Paano ito niresolba ng OmniRoute:**
- Lumipat ng combo activation nang direkta mula sa MCP dashboard
- Ilapat ang mga profile ng katatagan mula sa paunang natukoy na mga pack ng patakaran
- I-reset ang estado ng circuit breaker mula sa parehong panel ng mga operasyon
</details>
<details>
<summary><b>🔄 23. "Kailangan ko ng live A2A task lifecycle visibility at pagkansela"</b></summary>
Kung walang lifecycle visibility, ang mga insidente ng gawain ay nagiging mahirap subukan.
**Paano ito niresolba ng OmniRoute:**
- Listahan ng gawain/pag-filter ayon sa estado/kasanayan sa pagination
- Mag-drill-down sa metadata ng gawain, mga kaganapan, at mga artifact
- Endpoint ng pagkansela ng gawain at pagkilos ng UI na may kumpirmasyon
</details>
<details>
<summary><b>🌊 24. "Kailangan ko ng mga aktibong sukatan ng stream para sa A2A load"</b></summary>
Ang mga stream ng workflow ay nangangailangan ng operational insight sa concurrency at live na koneksyon.
**Paano ito niresolba ng OmniRoute:**
- Mga aktibong stream counter na isinama sa A2A status
- Mga bilang ng huling timestamp ng gawain at bawat estado
- A2A dashboard card para sa real-time na pagsubaybay sa ops
</details>
<details>
<summary><b>🪪 25. "Kailangan ko ng karaniwang pagtuklas ng ahente para sa mga kliyente"</b></summary>
Ang mga panlabas na kliyente at orkestra ay nangangailangan ng metadata na nababasa ng makina para sa onboarding.
**Paano ito niresolba ng OmniRoute:**
- Nalantad ang Agent Card sa `/.well-known/agent.json`
- Mga kakayahan at kasanayan na ipinapakita sa management UI
- Kasama sa A2A status API ang metadata ng pagtuklas para sa automation
</details>
<details>
<summary><b>🧭 26. "Kailangan ko ang pagtuklas ng protocol sa UX ng produkto"</b></summary>
Kung hindi matuklasan ng mga user ang mga surface ng protocol, bumababa ang kalidad ng pag-aampon at suporta.
**Paano ito niresolba ng OmniRoute:**
- Mga entry sa sidebar para sa MCP at A2A
- Tab na Mga Protokol ng pahina ng Endpoint na may mabilis na pagsisimula at katayuan
- Mga link mula sa pangkalahatang-ideya hanggang sa nakalaang mga dashboard ng pamamahala
</details>
<details>
<summary><b>🧪 27. "Kailangan ko ng end-to-end protocol validation sa mga totoong kliyente"</b></summary>
Ang mga kunwaring pagsubok ay hindi sapat upang patunayan ang pagiging tugma ng protocol bago ilabas.
**Paano ito niresolba ng OmniRoute:**
- E2E suite na nagbo-boot ng app at gumagamit ng totoong MCP SDK client transport
- Mga pagsubok sa A2A client para sa pagtuklas, pagpapadala, pag-stream, pagkuha, at pagkansela ng mga daloy
- Cross-check assertion laban sa MCP audit at A2A tasks API
</details>
<details>
<summary><b>📡 28. "Kailangan ko ng pinag-isang observability sa lahat ng interface"</b></summary>
Ang paghahati ng observability sa pamamagitan ng protocol ay lumilikha ng mga blind spot at mas mahabang MTTR.
**Paano ito niresolba ng OmniRoute:**
- Pinag-isang mga dashboard/log/analytics sa isang produkto
- Health + audit + humiling ng telemetry sa mga layer ng OpenAI, MCP, at A2A
- Mga Operational API para sa status at automation
</details>
<details>
<summary><b>💼 29. "Kailangan ko ng isang runtime para sa proxy + tool + orkestrasyon ng ahente"</b></summary>
Ang pagpapatakbo ng maraming magkakahiwalay na serbisyo ay nagpapataas ng gastos sa pagpapatakbo at mga mode ng pagkabigo.
**Paano ito niresolba ng OmniRoute:**
- OpenAI-compatible na proxy, MCP server, at A2A server sa isang stack
- Nakabahaging auth, resilience, data store, at observability
- Pare-parehong modelo ng patakaran sa lahat ng surface ng pakikipag-ugnayan
</details>
<details>
<summary><b>🚀 30. "Kailangan kong magpadala ng mga ahenteng daloy ng trabaho nang walang glue-code sprawl"</b></summary>
Nawawalan ng bilis ang mga koponan kapag nagtatahi ng maraming ad-hoc na serbisyo at script.
**Paano ito niresolba ng OmniRoute:**
- Pinag-isang endpoint na diskarte para sa mga kliyente at ahente
- Mga built-in na UI sa pamamahala ng protocol at mga daanan sa pagpapatunay ng usok
- Mga pundasyong handa sa produksyon (seguridad, pag-log, katatagan, backup)
</details>
### Mga Halimbawang Playbook
**Playbook A: I-maximize ang bayad na subscription + murang backup**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Zero-cost coding stack**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 always-on fallback chain**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Ahente ops sa MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Mabilis na Pagsisimula
**1. I-install sa buong mundo:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -589,6 +864,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Tampok | Ano ang Ginagawa Nito |
| ----------------------------------------- | ------------------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Awtomatikong buksan/isara ang bawat provider na may mga na-configure na threshold |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-Thundering Herd** | Mutex + semaphore rate-limit para sa mga API key provider |
| 🧠 **Semantic Cache** | Binabawasan ng two-tier na cache (pirma + semantiko) ang gastos at latency |
| ⚡ **Humiling ng Idempotency** | 5s dedup window para sa mga duplicate na kahilingan |
@@ -715,66 +991,26 @@ Kasama sa OmniRoute ang isang malakas na built-in na Playground ng Translator na
</details>
---
## 🧪 Mga Pagsusuri (Evals)
## 🎯 Use Cases
Ang OmniRoute ay may kasamang built-in na balangkas ng pagsusuri upang subukan ang kalidad ng pagtugon ng LLM laban sa isang ginintuang hanay. I-access ito sa pamamagitan ng **Analytics → Evals** sa dashboard.
### Case 1: "May subscription ako sa Claude Pro"
### na Set
**Problema:** Nag-e-expire ang quota nang hindi nagamit, mga limitasyon sa rate sa panahon ng mabigat na coding
Ang pre-loaded na "OmniRoute Golden Set" ay naglalaman ng 10 test case na sumasaklaw sa:
```
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)
- Pagbati, matematika, heograpiya, pagbuo ng code
- Pagsunod sa format ng JSON, pagsasalin, markdown
- Pagtanggi sa kaligtasan (nakapipinsalang nilalaman), pagbibilang, lohika ng boolean
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Estratehiya sa Pagsusuri
### Case 2: "Gusto ko ng zero cost"
**Problema:** Hindi kayang bayaran ang mga subscription, kailangan ng maaasahang 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: "Kailangan ko ng 24/7 coding, walang mga pagkaantala"
**Problema:** Mga deadline, hindi kayang bayaran ang 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
```
### Kaso 4: "Gusto ko ng LIBRENG AI sa OpenClaw"
**Problema:** Kailangan ng AI assistant sa mga app sa pagmemensahe, ganap na libre
```
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...
```
| Diskarte | Paglalarawan | Halimbawa |
| ---------- | ------------------------------------------------------------ | -------------------------------- |
| `exact` | Dapat na eksaktong tumugma ang output | `"4"` |
| `contains` | Ang output ay dapat maglaman ng substring (case-insensitive) | `"Paris"` |
| `regex` | Ang output ay dapat tumugma sa regex pattern | `"1.*2.*3"` |
| `custom` | Ang custom na JS function ay nagbabalik ng true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Mga Pagsusuri (Evals)
Ang OmniRoute ay may kasamang built-in na balangkas ng pagsusuri upang subukan ang kalidad ng pagtugon ng LLM laban sa isang ginintuang hanay. I-access ito sa pamamagitan ng **Analytics → Evals** sa dashboard.
### Built-in na Golden Set
Ang pre-loaded na "OmniRoute Golden Set" ay naglalaman ng 10 test case na sumasaklaw sa:
- Pagbati, matematika, heograpiya, pagbuo ng code
- Pagsunod sa format ng JSON, pagsasalin, markdown
- Pagtanggi sa kaligtasan (nakapipinsalang nilalaman), pagbibilang, lohika ng boolean
### Estratehiya sa Pagsusuri
| Diskarte | Paglalarawan | Halimbawa |
| ---------- | ------------------------------------------------------------ | -------------------------------- |
| `exact` | Dapat na eksaktong tumugma ang output | `"4"` |
| `contains` | Ang output ay dapat maglaman ng substring (case-insensitive) | `"Paris"` |
| `regex` | Ang output ay dapat tumugma sa regex pattern | `"1.*2.*3"` |
| `custom` | Ang custom na JS function ay nagbabalik ng true/false | `(output) => output.length > 10` |
---
## 🐛 Pag-troubleshoot
<details>
@@ -1132,13 +1345,13 @@ Ang pre-loaded na "OmniRoute Golden Set" ay naglalaman ng 10 test case na sumasa
- Kasama sa OmniRoute v1.0.6+ ang fallback validation sa pamamagitan ng mga pagkumpleto ng chat
- Tiyaking may kasamang `/v1` suffix ang base URL
### 🔐 OAuth em Servidor Remoto (Remote OAuth Setup)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ MAHALAGA para sa usuários com OmniRoute sa VPS/Docker/servidor remoto**
### Para sa que o OAuth do Antigravity / Gemini CLI falha em servidores remotos?
### OAuth
Os provedores **Antigravity** at **Gemini CLI** gamit ang **Google OAuth 2.0** para sa autenticação. O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pré-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, may posibilidad na magamit o f
---
## 🛠️ Tech Stack
## 🛠️
- **Runtime**: Node.js 1822 LTS (⚠️ Node.js 24+ ay **hindi suportado**`better-sqlite3` native binary ay hindi tugma)
- **Wika**: TypeScript 5.9 — **100% TypeScript** sa `src/` at `open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, may posibilidad na magamit o f
---
## 🗺️ Roadmap
## 🗺️
Ang OmniRoute ay may **210+ feature na binalak** sa maraming yugto ng pag-unlad. Narito ang mga pangunahing lugar:
@@ -1304,18 +1517,6 @@ Ang OmniRoute ay may **210+ feature na binalak** sa maraming yugto ng pag-unlad.
---
## 📧 Suporta
> 💬 **Sumali sa aming komunidad!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Humingi ng tulong, magbahagi ng mga tip, at manatiling updated.
- **Website**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Mga Isyu**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Orihinal na Proyekto**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Mga nag-aambag
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Połącz dowolne narzędzie IDE lub CLI oparte na sztucznej inteligencji poprze
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Dlaczego OmniRoute?
**Przestań marnować pieniądze i przekraczać limity:**
@@ -128,6 +157,18 @@ _Połącz dowolne narzędzie IDE lub CLI oparte na sztucznej inteligencji poprze
---
## 📧 Wsparcie
> 💬 **Dołącz do naszej społeczności!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Uzyskaj pomoc, dziel się wskazówkami i bądź na bieżąco.
- **Strona internetowa**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemy**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Oryginalny projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Jak to działa
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Co rozwiązuje OmniRoute — 30 rzeczywistych problemów i przypadków użycia
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Każdy programista korzystający z narzędzi AI codziennie spotyka się z tymi problemami.** OmniRoute został stworzony, aby rozwiązać je wszystkie — od przekroczeń kosztów po blokady regionalne, od zepsutych przepływów OAuth po operacje protokołów i obserwowalność przedsiębiorstwa.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. „Płacę za kosztowną subskrypcję, ale nadal przeszkadzają mi limity”</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Programiści płacą 20200 USD miesięcznie za Claude Pro, Codex Pro lub GitHub Copilot. Nawet płacąc, limit ma pułap 5 godzin użytkowania, limity tygodniowe lub limity stawek za minutę. W połowie sesji kodowania dostawca przestaje odpowiadać, a programista traci płynność i produktywność.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Inteligentny 4-poziomowy powrót** — Jeśli limit subskrypcji się wyczerpie, automatycznie przekierowuje do klucza API → Tani → Bezpłatny bez ręcznej interwencji
- **Śledzenie limitów w czasie rzeczywistym** — Pokazuje zużycie tokenów w czasie rzeczywistym z resetowanym odliczaniem (5 godzin, codziennie, co tydzień)
- **Obsługa wielu kont** — Wiele kont na dostawcę z funkcją automatycznego przełączania między kontami — gdy skończy się jedno, następuje przejście do następnego
- **Niestandardowe kombinacje** — Konfigurowalne łańcuchy rezerwowe z 6 strategiami równoważenia (pierwsze wypełnienie, działanie okrężne, P2C, losowe, najrzadziej używane, zoptymalizowane pod względem kosztów)
- **Przydziały biznesowe Kodeksu** — monitorowanie przydziałów przestrzeni roboczej firmy/zespołu bezpośrednio na pulpicie nawigacyjnym
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. „Muszę korzystać z wielu dostawców, ale każdy ma inny interfejs API</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI używa jednego formatu, Claude (Anthropic) używa innego, Gemini jeszcze innego. Jeśli programista chce przetestować modele od różnych dostawców lub korzystać z nich w trybie awaryjnym, musi ponownie skonfigurować pakiety SDK, zmienić punkty końcowe i poradzić sobie z niekompatybilnymi formatami. Dostawcy niestandardowi (FriendLI, NIM) mają niestandardowe punkty końcowe modelu.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Ujednolicony punkt końcowy** — pojedynczy `http://localhost:20128/v1` służy jako serwer proxy dla wszystkich ponad 36 dostawców
- **Tłumaczenie formatu** — Automatyczne i przejrzyste: OpenAI ↔ Claude ↔ Gemini ↔ API odpowiedzi
- **Odkażanie odpowiedzi** — usuwa niestandardowe pola (`x_groq`, `usage_breakdown`, `service_tier`), które psują OpenAI SDK v1.83+
- **Normalizacja ról** — Konwertuje `developer``system` dla dostawców innych niż OpenAI; `system``user` dla GLM/ERNIE
- **Pomyśl o ekstrakcji tagów** — wyodrębnia bloki `<think>` z modeli takich jak DeepSeek R1 do standardowego `reasoning_content`
- **Wyjście strukturalne dla Gemini** — `json_schema``responseMimeType`/`responseSchema` automatyczna konwersja
- **`stream` domyślnie to `false`** — Zgodność ze specyfikacją OpenAI, unikanie nieoczekiwanego SSE w pakietach SDK Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. „Mój dostawca AI blokuje mój region/kraj”</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Dostawcy tacy jak OpenAI/Codex blokują dostęp z określonych regionów geograficznych. Podczas połączeń OAuth i API użytkownicy otrzymują błędy takie jak `unsupported_country_region_territory`. Jest to szczególnie frustrujące dla programistów z krajów rozwijających się.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-poziomowa konfiguracja serwera proxy** — Konfigurowalny serwer proxy na 3 poziomach: globalny (cały ruch), na dostawcę (tylko jeden dostawca) i na połączenie/klucz
- **Oznaczone kolorami identyfikatory proxy** — Wskaźniki wizualne: 🟢 globalny serwer proxy, 🟡 serwer proxy dostawcy, 🔵 serwer proxy połączenia, zawsze pokazujący adres IP
- **Wymiana tokenów OAuth przez serwer proxy** — Przepływ OAuth przechodzi również przez serwer proxy, co rozwiązuje problem `unsupported_country_region_territory`
- **Test połączenia przez serwer proxy** — Testy połączenia wykorzystują skonfigurowany serwer proxy (koniec z bezpośrednim obejściem)
- **Obsługa SOCKS5** — Pełna obsługa proxy SOCKS5 dla routingu wychodzącego
- **Podrabianie odcisków palców TLS** — Odcisk palca TLS podobny do przeglądarki za pośrednictwem `wreq-js` w celu ominięcia wykrywania botów
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. „Chcę używać AI do kodowania, ale nie mam pieniędzy”</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nie każdy może zapłacić 20200 USD miesięcznie za subskrypcje AI. Studenci, programiści z krajów wschodzących, hobbyści i freelancerzy potrzebują dostępu do wysokiej jakości modeli po zerowych kosztach.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Wbudowani dostawcy bezpłatnych poziomów** — Natywne wsparcie dla w 100% darmowych dostawców: iFlow (8 nielimitowanych modeli), Qwen (3 nieograniczone modele), Kiro (Claude za darmo), Gemini CLI (180 tys./miesiąc za darmo)
- **Kombinacje dostępne wyłącznie bezpłatnie** — Łańcuch `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 USD/miesiąc z zerowymi przestojami
- **Darmowe kredyty NVIDIA NIM** — zintegrowane 1000 darmowych kredytów
- **Strategia zoptymalizowana pod względem kosztów** — Strategia routingu, która automatycznie wybiera najtańszego dostępnego dostawcę
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. „Muszę chronić moją bramę AI przed nieautoryzowanym dostępem”</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Podczas udostępniania bramy AI w sieci (LAN, VPS, Docker) każda osoba posiadająca adres może wykorzystać tokeny/przydział programisty. Bez ochrony interfejsy API są podatne na niewłaściwe użycie, natychmiastowe wstrzyknięcie i nadużycia.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Zarządzanie kluczami API** — generowanie, rotacja i ustalanie zakresu dla każdego dostawcy za pomocą dedykowanej strony `/dashboard/api-manager`
- **Uprawnienia na poziomie modelu** — Ogranicz klucze API do określonych modeli (`openai/*`, wzorce symboli wieloznacznych), za pomocą przełącznika Zezwalaj na wszystko/Ogranicz
- **API Endpoint Protection** — Wymagaj klucza dla `/v1/models` i blokuj określonych dostawców na liście
- **Auth Guard + ochrona CSRF** — Wszystkie trasy panelu kontrolnego chronione oprogramowaniem pośredniczącym `withAuth` + tokenami CSRF
- **Rate Limiter** — Ograniczanie szybkości na IP z konfigurowalnymi oknami
- **Filtrowanie IP** — Lista dozwolonych/blokowanych do kontroli dostępu
- **Szybka ochrona przed wstrzyknięciem** — Oczyszczanie przed złośliwymi wzorcami podpowiedzi
- **Szyfrowanie AES-256-GCM** — Poświadczenia szyfrowane w stanie spoczynku
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. „Mój dostawca przestał działać i straciłem płynność kodowania”</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Dostawcy sztucznej inteligencji mogą stać się niestabilni, zwracać błędy 5xx lub przekraczać tymczasowe limity szybkości. Jeśli programista jest zależny od jednego dostawcy, jego praca jest przerywana. Bez wyłączników automatycznych wielokrotne próby mogą spowodować awarię aplikacji.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Wyłącznik automatyczny na dostawcę** — Automatyczne otwieranie/zamykanie z konfigurowalnymi progami i czasem schładzania (zamknięty/otwarty/półotwarty)
- **Wykładniczy wycofywanie** — Stopniowe opóźnienia ponownych prób
- **Anti-Thundering Herd** — Mutex + ochrona semaforów przed równoczesnymi burzami ponownych prób
- **Łańcuchy awaryjne typu Combo** — jeśli główny dostawca zawiedzie, automatycznie przejdzie przez łańcuch bez interwencji
- **Wyłącznik automatyczny** — automatycznie wyłącza niesprawnych dostawców w łańcuchu combo
- **Panel stanu** — Monitorowanie czasu pracy, stany wyłączników, blokady, statystyki pamięci podręcznej, opóźnienia p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. „Konfigurowanie każdego narzędzia AI jest żmudne i powtarzalne”</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Programiści używają Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Każde narzędzie wymaga innej konfiguracji (punkt końcowy API, klucz, model). Ponowna konfiguracja w przypadku zmiany dostawcy lub modelu jest stratą czasu.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- ** Panel narzędzi CLI** — Dedykowana strona z konfiguracją jednym kliknięciem dla Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **Generator konfiguracji GitHub Copilot** — Generuje `chatLanguageModels.json` dla kodu VS z zbiorczym wyborem modelu
- **Kreator wprowadzenia** — konfiguracja w 4 krokach dla początkujących użytkowników
- **Jeden punkt końcowy, wszystkie modele** — Skonfiguruj `http://localhost:20128/v1` raz, uzyskaj dostęp do ponad 36 dostawców
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. „Zarządzanie tokenami OAuth od wielu dostawców to piekło”</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — wszystkie korzystają z OAuth 2.0 z wygasającymi tokenami. Programiści muszą stale przeprowadzać ponowne uwierzytelnianie, radzić sobie z `client_secret is missing`, `redirect_uri_mismatch` i awariami na zdalnych serwerach. Szczególnie problematyczny jest protokół OAuth w sieci LAN/VPS.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatyczne odświeżanie tokenu** — tokeny OAuth odświeżają się w tle przed wygaśnięciem
- **Wbudowany OAuth 2.0 (PKCE)** — Automatyczny przepływ dla Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Wielokontowy OAuth** — wiele kont na dostawcę poprzez ekstrakcję tokenów JWT/ID
- **OAuth LAN/remote fix** — wykrywanie prywatnego adresu IP dla `redirect_uri` + ręczny tryb adresu URL dla serwerów zdalnych
- **OAuth Behind Nginx** — wykorzystuje `window.location.origin` w celu zapewnienia zgodności z odwrotnym proxy
- **Przewodnik po zdalnym OAuth** — szczegółowy przewodnik dotyczący danych uwierzytelniających Google Cloud na platformie VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. „Nie wiem, ile i gdzie wydaję”</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Programiści korzystają z wielu płatnych dostawców, ale nie mają jednolitego widoku wydatków. Każdy dostawca ma własny pulpit rozliczeniowy, ale nie ma widoku skonsolidowanego. Nieoczekiwane koszty mogą się kumulować.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Panel analizy kosztów** — śledzenie kosztów według tokenu i zarządzanie budżetem dla każdego dostawcy
- **Limity budżetowe na poziom** — Pułap wydatków na poziom, który uruchamia automatyczne wycofanie
- **Konfiguracja cen dla poszczególnych modeli** — Ceny dla poszczególnych modeli można konfigurować
- **Statystyki użytkowania na klucz API** — Liczba żądań i znacznik czasu ostatniego użycia na klucz
- **Panel analityczny** — karty statystyk, wykres wykorzystania modelu, tabela dostawców ze wskaźnikami powodzenia i opóźnieniami
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. „Nie mogę diagnozować błędów i problemów w wywołaniach AI”</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Gdy połączenie nie powiedzie się, programista nie wie, czy był to limit szybkości, wygasły token, nieprawidłowy format czy błąd dostawcy. Fragmentowane dzienniki na różnych terminalach. Bez obserwowalności debugowanie odbywa się metodą prób i błędów.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Ujednolicony pulpit nawigacyjny** — 4 karty: Dzienniki żądań, Dzienniki proxy, Dzienniki audytu, Konsola
- **Przeglądarka logów w konsoli** — Przeglądarka działająca w stylu terminala w czasie rzeczywistym z poziomami oznaczonymi kolorami, automatycznym przewijaniem, wyszukiwaniem i filtrowaniem
- **Dzienniki proxy SQLite** — trwałe dzienniki, które przetrwają ponowne uruchomienie serwera
- **Plac zabaw dla tłumaczy** — 4 tryby debugowania: Plac zabaw (tłumaczenie formatu), Tester czatu (w obie strony), Stanowisko testowe (wsadowe), Monitor na żywo (w czasie rzeczywistym)
- **Żądanie telemetrii** — opóźnienie p50/p95/p99 + śledzenie identyfikatora X-Request-Id
- **Logowanie oparte na plikach z rotacją** — Przechwytywacz konsoli przechwytuje wszystko do dziennika JSON z rotacją na podstawie rozmiaru
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. „Wdrażanie i konserwacja bramy jest skomplikowane”</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Instalacja, konfiguracja i utrzymanie serwera proxy AI w różnych środowiskach (lokalnym, VPS, Docker, chmura) jest pracochłonne. Problemy takie jak zakodowane na stałe ścieżki, `EACCES` w katalogach, konflikty portów i kompilacje międzyplatformowe zwiększają tarcia.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm globalna instalacja** — `npm install -g omniroute && omniroute`gotowe
- **Docker Multi-platform** — natywny AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Profile Docker Compose** — `base` (bez narzędzi CLI) i `cli` (z Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Natywna aplikacja dla systemów Windows/macOS/Linux z zasobnikiem systemowym, automatycznym uruchamianiem i trybem offline
- **Tryb Split-Port** — API i pulpit nawigacyjny na oddzielnych portach dla zaawansowanych scenariuszy (odwrotne proxy, sieć kontenerowa)
- **Cloud Sync** — skonfiguruj synchronizację między urządzeniami za pośrednictwem Cloudflare Workers
- **Kopie zapasowe DB** — Automatyczne tworzenie kopii zapasowych, przywracanie, eksportowanie i importowanie wszystkich ustawień
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. „Interfejs jest wyłącznie w języku angielskim, a mój zespół nie mówi po angielsku”</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Zespoły w krajach nieanglojęzycznych, szczególnie w Ameryce Łacińskiej, Azji i Europie, mają trudności z interfejsami dostępnymi wyłącznie w języku angielskim. Bariery językowe ograniczają wdrażanie i zwiększają liczbę błędów konfiguracyjnych.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- ** Panel i18n — 30 języków** — Przetłumaczono ponad 500 klawiszy, w tym arabski, bułgarski, duński, niemiecki, hiszpański, fiński, francuski, hebrajski, hindi, węgierski, indonezyjski, włoski, japoński, koreański, malajski, holenderski, norweski, polski, portugalski (PT/BR), rumuński, rosyjski, słowacki, szwedzki, tajski, ukraiński, wietnamski, chiński, filipiński, angielski
- **Obsługa RTL** — obsługa tekstu od prawej do lewej w języku arabskim i hebrajskim
- **Wielojęzyczne pliki README** — 30 kompletnych tłumaczeń dokumentacji
- **Wybór języka** — Ikona kuli ziemskiej w nagłówku umożliwiająca przełączanie w czasie rzeczywistym
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. „Potrzebuję czegoś więcej niż czatupotrzebuję osadzania, obrazów i dźwięku”</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
Sztuczna inteligencja to nie tylko ukończenie czatu. Twórcy muszą generować obrazy, transkrybować dźwięk, tworzyć osadzania dla RAG, zmieniać ran dokumentów i moderować treści. Każdy interfejs API ma inny punkt końcowy i format.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Osadzania** — `/v1/embeddings` z 6 dostawcami i ponad 9 modelami
- **Generowanie obrazu** — `/v1/images/generations` z 10 dostawcami i ponad 20 modelami (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Tekst na wideo** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) i SD WebUI
- **Tekst na muzykę** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Transkrypcja audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Zamiana tekstu na mowę** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + obecni dostawcy
- **Moderacje** — `/v1/moderations` — Sprawdzanie bezpieczeństwa treści
- **Reranking** — `/v1/rerank` — Zmiana rankingu trafności dokumentu
- **Responses API** — Pełna obsługa `/v1/responses` dla Codexu
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. „Nie mam możliwości przetestowania i porównania jakości pomiędzy modelami”</b></summary>
Developers want to know which model is best for their use casecode, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Programiści chcą wiedzieć, który model jest najlepszy dla ich przypadku użyciakodu, tłumaczenia, rozumowania — ale ręczne porównywanie jest powolne. Nie istnieją żadne zintegrowane narzędzia eval.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Oceny LLM** — Testowanie złotego zestawu z 10 fabrycznie załadowanymi skrzynkami obejmującymi pozdrowienia, matematykę, geografię, generowanie kodu, zgodność z JSON, tłumaczenie, przeceny, odmowy ze względów bezpieczeństwa
- **4 strategie dopasowania** — `exact`, `contains`, `regex`, `custom` (funkcja JS)
- **Stolik testowy dla tłumaczy** — Testowanie wsadowe z wieloma danymi wejściowymi i oczekiwanymi wynikami, porównanie różnych dostawców
- **Tester czatu** — Pełna podróż w obie strony z renderowaniem odpowiedzi wizualnych
- **Live Monitor** — Strumień w czasie rzeczywistym wszystkich żądań przepływających przez serwer proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. „Muszę skalować bez utraty wydajności”</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
W miarę wzrostu liczby żądań bez buforowania tych samych pytań generowane są podwójne koszty. Bez idempotencji zduplikowane żądania przetwarzania odpadów. Należy przestrzegać limitów stawek dla poszczególnych dostawców.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Semantyczna pamięć podręczna** — Dwuwarstwowa pamięć podręczna (podpis + semantyka) zmniejsza koszty i opóźnienia
- **Request Idempotency** — okno deduplikacji 5 s dla identycznych żądań
- **Wykrywanie limitów szybkości** — RPM na dostawcę, minimalna przerwa i maksymalne jednoczesne śledzenie
- **Edytowalne limity szybkości** — Konfigurowalne ustawienia domyślne w Ustawieniach → Odporność z trwałością
- **API Key Validation Cache** — 3-warstwowa pamięć podręczna zapewniająca wydajność produkcyjną
- **Panel kontrolny stanu z telemetr** — opóźnienia p50/p95/p99, statystyki pamięci podręcznej, czas pracy
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. „Chcę kontrolować zachowanie modelu globalnie”</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Deweloperzy, którzy chcą wszystkich odpowiedzi w określonym języku, w określonym tonie lub chcą ograniczyć tokeny rozumowania. Konfigurowanie tego w każdym narzędziu/żądaniu jest niepraktyczne.
**How OmniRoute solves it:**
**Jak rozwiązuje to OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Wstrzykiwanie monitu systemowego** — monit globalny stosowany do wszystkich żądań
- **Przemyślana walidacja budżetu** — Kontrola alokacji tokenów rozumowania na każde żądanie (przejściowe, automatyczne, niestandardowe, adaptacyjne)
- **6 Strategii routingu** — Globalne strategie określające sposób dystrybucji żądań
- **Wildcard Router** — wzorce `provider/*` są przesyłane dynamicznie do dowolnego dostawcy
- **Przełączanie kombinacji włącz/wyłącz** — przełączaj kombinacje bezpośrednio z pulpitu nawigacyjnego
- **Przełączanie dostawcy** — Włącz/wyłącz wszystkie połączenia dla dostawcy jednym kliknięciem
- **Zablokowani dostawcy** — Wyklucz określonych dostawców z listy `/v1/models`
</details>
<details>
<summary><b>🧰 17. „Potrzebuję narzędzi MCP jako produktów najwyższej klasy”</b></summary>
Wiele bram AI ujawnia MCP jedynie jako ukryty szczegół implementacji. Zespoły potrzebują widocznej, zarządzalnej warstwy operacyjnej.
**Jak rozwiązuje to OmniRoute:**
- MCP pojawia się w panelu nawigacji na desce rozdzielczej i w zakładce protokołu punktu końcowego
- Dedykowana strona zarządzania MCP z procesem, narzędziami, zakresami i audytem
- Wbudowany szybki start dla `omniroute --mcp` i dołączania klientów
</details>
<details>
<summary><b>🧠 18. „Potrzebuję orkiestracji A2A ze ścieżkami zadań synchronizacji i strumieniowania”</b></summary>
Przepływy pracy agentów wymagają zarówno bezpośrednich odpowiedzi, jak i długotrwałego wykonywania strumieniowego z kontrolą cyklu życia.
**Jak rozwiązuje to OmniRoute:**
- Punkt końcowy A2A JSON-RPC (`POST /a2a`) z `message/send` i `message/stream`
- Przesyłanie strumieniowe SSE z propagacją stanu terminala
— Interfejsy API cyklu życia zadań dla `tasks/get` i `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. „Potrzebuję prawdziwego stanu procesu MCP, a nie zgadniętego statusu”</b></summary>
Zespoły operacyjne muszą wiedzieć, czy MCP rzeczywiście żyje, a nie tylko, czy można uzyskać dostęp do interfejsu API.
**Jak rozwiązuje to OmniRoute:**
- Plik pulsu środowiska wykonawczego z PID, znacznikami czasu, transportem, liczbą narzędzi i trybem zakresu
- API statusu MCP łączące puls + ostatnią aktywność
- Karty stanu interfejsu użytkownika dotyczące świeżości procesów/czasu pracy/bicia serca
</details>
<details>
<summary><b>📋 20. „Potrzebuję wykonania narzędzia MCP z możliwością audytu”</b></summary>
Gdy narzędzia modyfikują konfigurację lub uruchamiają działania operacyjne, zespoły potrzebują identyfikowalności kryminalistycznej.
**Jak rozwiązuje to OmniRoute:**
- Wspierane przez SQLite rejestrowanie audytu dla wywołań narzędzi MCP
- Filtruje według narzędzia, sukcesu/porażki, klucza API i paginacji
- Tabela audytu pulpitu nawigacyjnego + punkty końcowe statystyk dla automatyzacji
</details>
<details>
<summary><b>🔐 21. „Potrzebuję uprawnień MCP o określonym zakresie na integrację”</b></summary>
Różni klienci powinni mieć najniższy dostęp do kategorii narzędzi.
**Jak rozwiązuje to OmniRoute:**
- 9 szczegółowych zakresów MCP zapewniających kontrolowany dostęp do narzędzi
- Egzekwowanie zakresu i widoczność w interfejsie zarządzania MCP
- Bezpieczna domyślna pozycja dla narzędzi operacyjnych
</details>
<details>
<summary><b>⚙️ 22. „Potrzebuję kontroli operacyjnej bez ponownego wdrażania”</b></summary>
Zespoły potrzebują szybkich zmian w czasie działania podczas incydentów lub zdarzeń kosztowych.
**Jak rozwiązuje to OmniRoute:**
- Aktywacja kombinacji przełączników bezpośrednio z pulpitu nawigacyjnego MCP
- Zastosuj profile odporności ze wstępnie zdefiniowanych pakietów zasad
- Zresetuj stan wyłącznika automatycznego z tego samego panelu operacyjnego
</details>
<details>
<summary><b>🔄 23. „Potrzebuję widoczności i anulowania cyklu życia zadania A2A na żywo”</b></summary>
Bez widoczności cyklu życia zdarzenia związane z zadaniami stają się trudne do segregacji.
**Jak rozwiązuje to OmniRoute:**
- Lista zadań/filtrowanie według stanu/umiejętności z paginacją
- Szczegółowa analiza metadanych zadań, zdarzeń i artefaktów
- Punkt końcowy anulowania zadania i akcja interfejsu użytkownika z potwierdzeniem
</details>
<details>
<summary><b>🌊 24. „Potrzebuję metryk aktywnego strumienia dla obciążenia A2A”</b></summary>
Przepływy pracy związane z przesyłaniem strumieniowym wymagają operacyjnego wglądu w współbieżność i połączenia na żywo.
**Jak rozwiązuje to OmniRoute:**
- Aktywne liczniki strumieni zintegrowane ze statusem A2A
- Znacznik czasu ostatniego zadania i liczba stanów
- Karty pulpitu A2A do monitorowania operacji w czasie rzeczywistym
</details>
<details>
<summary><b>🪪 25. „Potrzebuję standardowego wyszukiwania agentów dla klientów”</b></summary>
Zewnętrzni klienci i koordynatorzy potrzebują metadanych do odczytu maszynowego na potrzeby wdrożenia.
**Jak rozwiązuje to OmniRoute:**
- Karta agenta ujawniona pod adresem `/.well-known/agent.json`
- Możliwości i umiejętności pokazane w interfejsie zarządzania
- Interfejs API stanu A2A zawiera metadane wykrywania do automatyzacji
</details>
<details>
<summary><b>🧭 26. „Potrzebuję możliwości wykrycia protokołu w UX produktu”</b></summary>
Jeśli użytkownicy nie mogą odkryć powierzchni protokołu, spada jakość przyjęcia i wsparcia.
**Jak rozwiązuje to OmniRoute:**
- Wpisy na pasku bocznym dla MCP i A2A
- Strona punktu końcowego, zakładka Protokoły z szybkim startem i statusem
- Linki z przeglądu do dedykowanych pulpitów zarządzania
</details>
<details>
<summary><b>🧪 27. „Potrzebuję kompleksowej weryfikacji protokołu z prawdziwymi klientami”</b></summary>
Testy próbne nie wystarczą do sprawdzenia zgodności protokołu przed wydaniem.
**Jak rozwiązuje to OmniRoute:**
- Pakiet E2E, który uruchamia aplikację i wykorzystuje prawdziwy transport klienta MCP SDK
- Testy klienta A2A pod kątem wykrywania, wysyłania, przesyłania strumieniowego, pobierania i anulowania przepływów
- Sprawdzaj twierdzenia względem interfejsów API audytu MCP i zadań A2A
</details>
<details>
<summary><b>📡 28. „Potrzebuję ujednoliconej obserwowalności na wszystkich interfejsach”</b></summary>
Podział obserwowalności według protokołu tworzy martwe punkty i wydłuża MTTR.
**Jak rozwiązuje to OmniRoute:**
- Ujednolicone dashboardy/dzienniki/analizy w jednym produkcie
- Stan + audyt + telemetria żądań w warstwach OpenAI, MCP i A2A
- Operacyjne interfejsy API dla statusu i automatyzacji
</details>
<details>
<summary><b>💼 29. „Potrzebuję jednego środowiska wykonawczego dla serwera proxy + narzędzi + orkiestracji agenta”</b></summary>
Uruchamianie wielu oddzielnych usług zwiększa koszty operacyjne i tryby awarii.
**Jak rozwiązuje to OmniRoute:**
- Serwer proxy zgodny z OpenAI, serwer MCP i serwer A2A w jednym stosie
- Wspólne uwierzytelnianie, odporność, magazyn danych i obserwowalność
- Spójny model polityki na wszystkich płaszczyznach interakcji
</details>
<details>
<summary><b>🚀 30. „Muszę dostarczać agentowe przepływy pracy bez konieczności rozrzucania kodu kleju”</b></summary>
Zespoły tracą prędkość podczas łączenia wielu usług i skryptów ad hoc.
**Jak rozwiązuje to OmniRoute:**
- Ujednolicona strategia dotycząca punktów końcowych dla klientów i agentów
- Wbudowane interfejsy zarządzania protokołami i ścieżki sprawdzania dymu
- Podstawy gotowe do produkcji (bezpieczeństwo, logowanie, odporność, kopie zapasowe)
</details>
### Przykładowe podręczniki (zintegrowane przypadki użycia)
**Poradnik A: maksymalizuj płatną subskrypcję + tanią kopię zapasową**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Poradnik B: stos kodowania o zerowym koszcie**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Poradnik C: łańcuch awaryjny działający 24 godziny na dobę, 7 dni w tygodniu**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Poradnik D: Operacje agenta z MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Szybki start
**1. Zainstaluj globalnie:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +990,26 @@ OmniRoute zawiera potężny, wbudowany plac zabaw dla tłumaczy z **4 trybami**
</details>
---
## 🧪 Oceny (Ewaluacje)
## 🎯 Przypadki użycia
OmniRoute zawiera wbudowaną platformę ewaluacyjną do testowania jakości odpowiedzi LLM na podstawie złotego zestawu. Uzyskaj do niego dostęp poprzez **Analytics → Evals** na pulpicie nawigacyjnym.
### Przypadek 1: „Mam subskrypcję Claude Pro”
### Wbudowany złoty zestaw
**Problem:** Limit wygasa niewykorzystany, limity szybkości podczas intensywnego kodowania
Fabrycznie załadowany „Złoty zestaw OmniRoute” zawiera 10 przypadków testowych obejmujących:
```
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)
- Pozdrowienia, matematyka, geografia, generowanie kodu
- Zgodność z formatem JSON, tłumaczenie, przecena
- Odmowa bezpieczeństwa (szkodliwa treść), liczenie, logika boolowska
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Strategie oceny
### Przypadek 2: „Chcę zerowych kosztów”
**Problem:** Nie stać Cię na subskrypcje, potrzebujesz niezawodnego kodowania AI
```
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
```
### Przypadek 3: „Potrzebuję kodowania 24 godziny na dobę, 7 dni w tygodniu, bez przerw”
**Problem:** Terminy, nie mogę sobie pozwolić na przestoje
```
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
```
### Przypadek 4: „Chcę DARMOWEJ sztucznej inteligencji w OpenClaw”
**Problem:** Potrzebujesz asystenta AI w aplikacjach do przesyłania wiadomości, całkowicie za darmo
```
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...
```
| Strategia | Opis | Przykład |
| ---------- | ----------------------------------------------------------------------- | -------------------------------- |
| `exact` | Dane wyjściowe muszą dokładnie odpowiadać | `"4"` |
| `contains` | Dane wyjściowe muszą zawierać podciąg (wielkość liter nie ma znaczenia) | `"Paris"` |
| `regex` | Dane wyjściowe muszą pasować do wzorca wyrażenia regularnego | `"1.*2.*3"` |
| `custom` | Niestandardowa funkcja JS zwraca wartość prawda/fałsz | `(output) => output.length > 10` |
---
@@ -1058,29 +1293,6 @@ Settings → API Configuration:
---
## 🧪 Oceny (Ewaluacje)
OmniRoute zawiera wbudowaną platformę ewaluacyjną do testowania jakości odpowiedzi LLM na podstawie złotego zestawu. Uzyskaj do niego dostęp poprzez **Analytics → Evals** na pulpicie nawigacyjnym.
### Wbudowany złoty zestaw
Fabrycznie załadowany „Złoty zestaw OmniRoute” zawiera 10 przypadków testowych obejmujących:
- Pozdrowienia, matematyka, geografia, generowanie kodu
- Zgodność z formatem JSON, tłumaczenie, przecena
- Odmowa bezpieczeństwa (szkodliwa treść), liczenie, logika boolowska
### Strategie oceny
| Strategia | Opis | Przykład |
| ---------- | ----------------------------------------------------------------------- | -------------------------------- |
| `exact` | Dane wyjściowe muszą dokładnie odpowiadać | `"4"` |
| `contains` | Dane wyjściowe muszą zawierać podciąg (wielkość liter nie ma znaczenia) | `"Paris"` |
| `regex` | Dane wyjściowe muszą pasować do wzorca wyrażenia regularnego | `"1.*2.*3"` |
| `custom` | Niestandardowa funkcja JS zwraca wartość prawda/fałsz | `(output) => output.length > 10` |
---
## 🐛 Rozwiązywanie problemów
<details>
@@ -1138,7 +1350,7 @@ Fabrycznie załadowany „Złoty zestaw OmniRoute” zawiera 10 przypadków test
> **⚠️ WAŻNE dla zwykłych usług OmniRoute w VPS/Docker/serwidor zdalny**
#### Por que o OAuth do Antigravity / Gemini CLI falha na zdalnych serwerach?
#### OAuth
Sprawdzone **Antigravity** i **Gemini CLI** używane **Google OAuth 2.0** dla autentyczności. O Google, jeśli potrzebujesz `redirect_uri`, aby nie zmieniać protokołu OAuth seja **exatamente** uma das URI pre-cadastradas no Google Cloud Console to aplicativo.
@@ -1227,7 +1439,7 @@ Jeśli chcesz uzyskać dostęp do **podręcznika URL**:
---
## 🛠️ Stos technologii
## 🛠️
- **Środowisko wykonawcze**: Node.js 1822 LTS (⚠️ Node.js 24+ jest **nieobsługiwany**`better-sqlite3` natywne pliki binarne są niekompatybilne)
- **Język**: TypeScript 5.9 — **100% TypeScript** w `src/` i `open-sse/` (v1.0.6)
@@ -1279,18 +1491,19 @@ Jeśli chcesz uzyskać dostęp do **podręcznika URL**:
---
## 🗺️ Plan działania
## 🗺️
OmniRoute ma **ponad 210 funkcji zaplanowanych** w wielu fazach rozwoju. Oto kluczowe obszary:
| Kategoria | Planowane funkcje | Najważniejsze |
| -------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🧠 **Routing i inteligencja** | 25+ | Routing z najmniejszym opóźnieniem, routing oparty na tagach, wstępna inspekcja przydziału, wybór konta P2C |
| 🔒 **Bezpieczeństwo i zgodność** | 20+ | Wzmocnienie SSRF, maskowanie poświadczeń, limit szybkości na punkt końcowy, zakres kluczy zarządzania |
| 📊 **Obserwowalność** | 15+ | Integracja OpenTelemetry, monitorowanie kwot w czasie rzeczywistym, śledzenie kosztów według modelu |
| 🔄 **Integracja dostawców** | 20+ | Rejestr modeli dynamicznych, czasy odnowienia dostawcy, Kodeks dla wielu kont, analiza przydziału Copilot |
| **Wydajność** | 15+ | Podwójna warstwa pamięci podręcznej, pamięć podręczna podpowiedzi, pamięć podręczna odpowiedzi, utrzymywanie transmisji strumieniowej, wsadowe API |
| 🌐 **Ekosystem** | 10+ | WebSocket API, ładowanie konfiguracji na gorąco, rozproszony magazyn konfiguracji, tryb komercyjny |
| Kategoria | Planowane funkcje | Najważniejsze |
| -------------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🧠 **Routing i inteligencja** | 25+ | Routing z najmniejszym opóźnieniem, routing oparty na tagach, wstępna inspekcja przydziału, wybór konta P2C |
| 🔒 **Bezpieczeństwo i zgodność** | 20+ | Wzmocnienie SSRF, maskowanie poświadczeń, limit szybkości na punkt końcowy, zakres kluczy zarządzania |
| 📊 **Obserwowalność** | 15+ | Integracja OpenTelemetry, monitorowanie kwot w czasie rzeczywistym, śledzenie kosztów według modelu |
| 🔄 **Integracja dostawców** | 20+ | Rejestr modeli dynamicznych, czasy odnowienia dostawcy, Kodeks dla wielu kont, analiza przydziału Copilot |
| **Wydajność** | 15+ | Podwójna warstwa pamięci podręcznej, pamięć podręczna podpowiedzi, pamięć podręczna odpowiedzi, utrzymywanie transmisji strumieniowej, wsadowe API |
| 🌐 **Ekosystem** | 10+ | WebSocket API, ładowanie konfiguracji na gorąco, rozproszony magazyn konfiguracji, tryb komercyjny |
### 🔜 Już wkrótce
@@ -1304,18 +1517,6 @@ OmniRoute ma **ponad 210 funkcji zaplanowanych** w wielu fazach rozwoju. Oto klu
---
## 📧 Wsparcie
> 💬 **Dołącz do naszej społeczności!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Uzyskaj pomoc, dziel się wskazówkami i bądź na bieżąco.
- **Strona internetowa**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemy**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Oryginalny projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Współtwórcy
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Conecte qualquer IDE ou ferramenta CLI com IA através do OmniRoute — gateway
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Por que OmniRoute?
**Pare de desperdiçar dinheiro e bater em limites:**
@@ -128,6 +157,18 @@ _Conecte qualquer IDE ou ferramenta CLI com IA através do OmniRoute — gateway
---
## 📧 Suporte
> 💬 **Participe da comunidade!** [Grupo WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Tire dúvidas, compartilhe dicas e fique atualizado.
- **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 da Comunidade](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projeto Original**: [9router por decolua](https://github.com/decolua/9router)
---
## 🔄 Como Funciona
```
@@ -157,265 +198,473 @@ Resultado: Nunca pare de programar, custo mínimo
---
## 🎯 What OmniRoute Solves16 Real Pain Points
## 🎯 O que o OmniRoute resolve — 30 dores reais e casos de uso
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Todo desenvolvedor que usa ferramentas de IA enfrenta esses problemas diariamente.** O OmniRoute foi criado para resolver todos eles, desde estouro de custos e bloqueios regionais até operações de protocolo e observabilidade de nível produção.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Pago uma assinatura cara e ainda sou interrompido por limites"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Desenvolvedores pagam de $20 a $200/mês por Claude Pro, Codex Pro ou GitHub Copilot. Mesmo pagando, há teto de cota, limite de 5h, limites semanais ou por minuto. No meio da sessão de coding, o provedor para de responder e o desenvolvedor perde fluxo e produtividade.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Fallback Inteligente em 4 Tiers** — Se a cota de assinatura acabar, redireciona automaticamente para API Key → Barato → Gratuito sem intervenção manual
- **Rastreamento de Cota em Tempo Real** — Exibe consumo de tokens ao vivo com contagem regressiva de reset (5h, diário, semanal)
- **Suporte Multi-Conta** — Várias contas por provedor com round-robin automático; quando uma esgota, passa para a próxima
- **Combos Personalizados** — Cadeias de fallback customizáveis com 6 estratégias (fill-first, round-robin, P2C, aleatório, least-used, cost-optimized)
- **Cotas Business do Codex** — Monitoramento de cota de workspace Business/Team direto no dashboard
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Preciso usar múltiplos provedores, mas cada um tem uma API diferente"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI usa um formato, Claude (Anthropic) usa outro, Gemini usa outro. Se o dev quer testar modelos de provedores diferentes ou fazer fallback entre eles, precisa reconfigurar SDKs, trocar endpoints e lidar com formatos incompatíveis. Provedores customizados (FriendLI, NIM) também têm endpoints não padronizados.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Endpoint Unificado** — Um único `http://localhost:20128/v1` serve como proxy para 36+ provedores
- **Tradução de Formato** — Conversão automática e transparente: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Sanitização de Resposta** — Remove campos fora do padrão (`x_groq`, `usage_breakdown`, `service_tier`) que quebram OpenAI SDK v1.83+
- **Normalização de Roles** — Converte `developer``system` para provedores não-OpenAI; `system``user` para GLM/ERNIE
- **Extração de Tags Think** — Extrai blocos `<think>` de modelos como DeepSeek R1 para `reasoning_content` padronizado
- **Saída Estruturada no Gemini** — Conversão automática de `json_schema``responseMimeType`/`responseSchema`
- **`stream` padrão `false`** — Alinha com a especificação OpenAI e evita SSE inesperado em SDKs Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Meu provedor de IA bloqueia minha região/país"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Provedores como OpenAI/Codex bloqueiam acesso em determinadas regiões. Usuários recebem erros como `unsupported_country_region_territory` durante OAuth e conexões de API. Isso é especialmente frustrante para desenvolvedores de países emergentes.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Config de Proxy em 3 Níveis** — Proxy configurável em nível global (todo tráfego), por provedor e por conexão/chave
- **Badges de Proxy por Cor** — Indicadores visuais: 🟢 proxy global, 🟡 proxy do provedor, 🔵 proxy da conexão, sempre mostrando o IP
- **Troca de Token OAuth via Proxy** — O fluxo OAuth também passa pelo proxy, resolvendo `unsupported_country_region_territory`
- **Teste de Conexão via Proxy** — Testes usam o proxy configurado (sem bypass direto)
- **Suporte SOCKS5** — Suporte completo a proxy SOCKS5 para roteamento de saída
- **Spoofing de Impressão TLS** — Fingerprint TLS estilo navegador via `wreq-js` para contornar detecção de bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Quero usar IA para programar, mas não tenho dinheiro"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nem todo mundo pode pagar $20200/mês em assinaturas de IA. Estudantes, devs de países emergentes, hobistas e freelancers precisam de acesso a modelos de qualidade com custo zero.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Provedores Gratuitos nativos** — Suporte nativo a provedores 100% free: iFlow (8 modelos ilimitados), Qwen (3 ilimitados), Kiro (Claude grátis), Gemini CLI (180K/mês grátis)
- **Combos Apenas Gratuitos** — Cadeia `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/mês com zero downtime
- **Créditos Gratuitos NVIDIA NIM** — 1000 créditos free integrados
- **Estratégia Cost Optimized** — Estratégia que escolhe automaticamente o provedor mais barato disponível
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Preciso proteger meu gateway de IA contra acesso não autorizado"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Ao expor um gateway de IA na rede (LAN, VPS, Docker), qualquer pessoa com o endereço pode consumir tokens/cota do desenvolvedor. Sem proteção, as APIs ficam vulneráveis a uso indevido, prompt injection e abuso.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Gestão de API Keys** — Geração, rotação e escopo por provedor com página dedicada em `/dashboard/api-manager`
- **Permissões por Modelo** — Restringe chaves a modelos específicos (`openai/*`, padrões wildcard), com toggle Allow All/Restrict
- **Proteção de Endpoint de API** — Exige chave para `/v1/models` e bloqueia provedores específicos da listagem
- **Auth Guard + CSRF Protection** — Todas as rotas do dashboard protegidas com middleware `withAuth` + tokens CSRF
- **Rate Limiter** — Limite por IP com janelas configuráveis
- **Filtragem por IP** — Allowlist/blocklist para controle de acesso
- **Proteção contra Prompt Injection** — Sanitização contra padrões maliciosos
- **Criptografia AES-256-GCM** — Credenciais criptografadas em repouso
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Meu provedor caiu e eu perdi meu fluxo de programação"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Provedores de IA podem ficar instáveis, retornar erro 5xx ou atingir limites temporários de taxa. Se o dev depende de um único provedor, ele é interrompido. Sem circuit breaker, retries repetidos podem derrubar a aplicação.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Circuit Breaker por modelo** — Abre/fecha automaticamente com limiares e cooldown configuráveis (Closed/Open/Half-Open)
- **Exponential Backoff** — Atrasos progressivos de retry
- **Anti-Thundering Herd** — Proteção com mutex + semáforo contra tempestade de retries concorrentes
- **Cadeias de Fallback em Combo** — Se o primário falhar, avança automaticamente na cadeia sem intervenção
- **Circuit Breaker de Combo** — Desativa automaticamente provedores com falha dentro da cadeia
- **Health Dashboard** — Monitoramento de uptime, estados de breaker, lockouts, estatísticas de cache e latência p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Configurar cada ferramenta de IA é tedioso e repetitivo"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Desenvolvedores usam Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Cada ferramenta pede configuração diferente (endpoint, chave, modelo). Reconfigurar ao trocar de provedor ou modelo é perda de tempo.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Dashboard de Ferramentas CLI** — Página dedicada com setup em 1 clique para Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity e Cline
- **Gerador de Config do GitHub Copilot** — Gera `chatLanguageModels.json` para VS Code com seleção em lote de modelos
- **Onboarding Wizard** — Fluxo guiado de 4 etapas para novos usuários
- **Um endpoint para todos os modelos** — Configure `http://localhost:20128/v1` uma vez e acesse 36+ provedores
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Gerenciar tokens OAuth de múltiplos provedores é um caos"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI e Copilot usam OAuth 2.0 com tokens que expiram. Devs precisam reautenticar o tempo todo e lidar com erros como `client_secret is missing`, `redirect_uri_mismatch` e falhas em servidores remotos. OAuth em LAN/VPS é especialmente problemático.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Auto Token Refresh** — Tokens OAuth renovados em background antes da expiração
- **OAuth 2.0 (PKCE) nativo** — Fluxo automático para Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen e iFlow
- **OAuth Multi-Conta** — Múltiplas contas por provedor via extração de JWT/ID token
- **Correções OAuth LAN/Remoto** — Detecção de IP privado para `redirect_uri` + modo manual de URL para servidores remotos
- **OAuth atrás de Nginx** — Usa `window.location.origin` para compatibilidade com reverse proxy
- **Guia de OAuth Remoto** — Passo a passo para credenciais Google Cloud em VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Não sei quanto estou gastando nem onde"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Desenvolvedores usam vários provedores pagos, mas não têm visão unificada de gastos. Cada provedor tem seu dashboard de billing, sem consolidação. Custos inesperados podem se acumular.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Dashboard de Analytics de Custo** — Rastreamento de custo por token e gestão de orçamento por provedor
- **Limites de Orçamento por Tier** — Teto de gasto por tier que aciona fallback automático
- **Configuração de Preço por Modelo** — Preços configuráveis por modelo
- **Estatísticas de Uso por API Key** — Contagem de requests e timestamp de último uso por chave
- **Analytics Dashboard** — Cards, gráfico de uso por modelo e tabela de provedores com taxa de sucesso e latência
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Não consigo diagnosticar erros e problemas nas chamadas de IA"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Quando uma chamada falha, o dev não sabe se foi rate limit, token expirado, formato incorreto ou erro do provedor. Logs ficam fragmentados em terminais diferentes. Sem observabilidade, debug vira tentativa e erro.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Dashboard de Logs Unificado** — 4 abas: Request Logs, Proxy Logs, Audit Logs e Console
- **Visualizador de Console** — Viewer em tempo real estilo terminal com níveis por cor, auto-scroll, busca e filtros
- **Proxy Logs em SQLite** — Logs persistentes que sobrevivem a reinícios do servidor
- **Playground do Tradutor** — 4 modos de debug: Playground (tradução), Chat Tester (round-trip), Test Bench (lote), Live Monitor (tempo real)
- **Telemetria de Request** — Latência p50/p95/p99 + rastreamento por X-Request-Id
- **Logging em Arquivo com Rotação** — Interceptador de console grava tudo em JSON com rotação por tamanho
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Implantar e manter o gateway é complexo"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Instalar, configurar e manter um proxy de IA em ambientes diferentes (local, VPS, Docker, cloud) exige muito trabalho. Problemas como caminhos hardcoded, `EACCES` em direrios, conflito de portas e build cross-platform aumentam a fricção.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **npm global install** — `npm install -g omniroute && omniroute` — done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Instalação global via npm** — `npm install -g omniroute && omniroute` e pronto
- **Docker Multi-Platform** — AMD64 + ARM64 nativo (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Perfis Docker Compose** — `base` (sem ferramentas CLI) e `cli` (com Claude Code, Codex, OpenClaw)
- **App Desktop Electron** — App nativo para Windows/macOS/Linux com bandeja, auto-start e modo offline
- **Modo de Porta Separada** — API e Dashboard em portas distintas para cenários avançados (reverse proxy, rede de containers)
- **Cloud Sync** — Sincronização de configuração entre dispositivos via Cloudflare Workers
- **Backups de DB** — Backup automático, restauração, export e import de todas as configurações
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "A interface é só em inglês e meu time não fala inglês"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Times em países não anglófonos, especialmente na América Latina, Ásia e Europa, sofrem com interfaces só em inglês. A barreira de idioma reduz adoção e aumenta erros de configuração.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **i18n do Dashboard — 30 idiomas** — Mais de 500 chaves traduzidas, incluindo árabe, búlgaro, dinamarquês, alemão, espanhol, finlandês, francês, hebraico, hindi, ngaro, indonésio, italiano, japonês, coreano, malaio, holandês, norueguês, polonês, português (PT/BR), romeno, russo, eslovaco, sueco, tailandês, ucraniano, vietnamita, chinês, filipino e inglês
- **Suporte RTL** — Suporte right-to-left para árabe e hebraico
- **READMEs multilíngues** — 30 traduções completas de documentação
- **Seletor de Idioma** — Ícone de globo no header para troca em tempo real
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Preciso de mais do que chat: embeddings, imagens, áudio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
IA não é só chat completion. Devs precisam gerar imagens, transcrever áudio, criar embeddings para RAG, reranquear documentos e moderar conteúdo. Cada API tem endpoint e formato diferentes.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 10 providers and 20+ models (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` ComfyUI (AnimateDiff, SVD) and SD WebUI
- **Text-to-Music** — `/v1/music/generations` ComfyUI (Stable Audio Open, MusicGen)
- **Audio Transcription** — `/v1/audio/transcriptions` Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Embeddings** — `/v1/embeddings` com 6 provedores e 9+ modelos
- **Geração de Imagem** — `/v1/images/generations` com 10 provedores e 20+ modelos (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Texto para Vídeo** — `/v1/videos/generations` com ComfyUI (AnimateDiff, SVD) e SD WebUI
- **Texto para Música** — `/v1/music/generations` com ComfyUI (Stable Audio Open, MusicGen)
- **Transcrição de Áudio** — `/v1/audio/transcriptions` com Whisper + Nvidia NIM, HuggingFace e Qwen3
- **Texto para Fala (TTS)** — `/v1/audio/speech` com ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise e Qwen3
- **Moderações** — `/v1/moderations` para checagens de segurança de conteúdo
- **Reranking** — `/v1/rerank` para relevância de documentos
- **Responses API** — Suporte completo a `/v1/responses` para Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Não tenho como testar e comparar qualidade entre modelos"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Desenvolvedores querem saber qual modelo é melhor para cada caso de uso (código, tradução, raciocínio), mas comparar manualmente é lento. Não existem ferramentas integradas de avaliação na maioria das stacks.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Avaliações de LLM** — Golden set com 10 casos pré-carregados cobrindo saudação, matemática, geografia, geração de código, conformidade JSON, tradução, markdown e recusa de conteúdo inseguro
- **4 Estratégias de Match** — `exact`, `contains`, `regex`, `custom` (função JS)
- **Test Bench do Playground do Tradutor** — Testes em lote com múltiplas entradas/saídas esperadas e comparação entre provedores
- **Chat Tester** — Round-trip completo com renderização visual da resposta
- **Live Monitor** — Stream em tempo real de todas as requisições que passam pelo proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Preciso escalar sem perder performance"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
À medida que o volume cresce, sem cache as mesmas perguntas geram custos duplicados. Sem idempotência, requisições duplicadas desperdiçam processamento. Também é necessário respeitar rate limits por provedor.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache Semântico** — Cache em duas camadas (assinatura + semântico) para reduzir custo e latência
- **Idempotência de Request** — Janela de deduplicação de 5s para requisições idênticas
- **Detecção de Rate Limit** — Rastreamento por provedor de RPM, intervalo mínimo e concorrência máxima
- **Rate Limits Editáveis** — Padrões configuráveis em Settings → Resilience com persistência
- **Cache de Validação de API Key** — Cache em 3 camadas para performance em produção
- **Health Dashboard com Telemetria** — Latência p50/p95/p99, estatísticas de cache e uptime
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Quero controlar o comportamento dos modelos globalmente"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Desenvolvedores podem querer todas as respostas em um idioma específico, com tom específico ou com limite de tokens de raciocínio. Configurar isso em cada ferramenta/requisição é impraticável.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Injeção de System Prompt** — Prompt global aplicado a todas as requisições
- **Validação de Thinking Budget** — Controle de alocação de tokens de raciocínio por requisição (passthrough, auto, custom, adaptive)
- **6 Estratégias de Roteamento** — Estratégias globais que definem como as requisições são distribuídas
- **Wildcard Router** — Padrões `provider/*` roteiam dinamicamente para qualquer provedor
- **Toggle de Combo** — Ativa/desativa combos diretamente no dashboard
- **Toggle de Provedor** — Ativa/desativa todas as conexões de um provedor com um clique
- **Provedores Bloqueados** — Exclui provedores específicos da listagem de `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Preciso de ferramentas MCP como capacidades de primeira classe do produto"</b></summary>
Muitos gateways de IA expõem MCP apenas como detalhe de implementação oculto. Times precisam de uma camada operacional visível e gerenciável.
**Como o OmniRoute resolve isso:**
- MCP aparece no menu do dashboard e na aba de protocolos em Endpoint
- Página dedicada de gestão MCP com processo, ferramentas, escopos e auditoria
- Quick-start embutido para `omniroute --mcp` e onboarding de clientes
</details>
<details>
<summary><b>🧠 18. "Preciso de orquestração A2A com caminhos síncronos + streaming"</b></summary>
Fluxos de agentes precisam de respostas diretas e também de execuções longas com streaming e controle de ciclo de vida.
**Como o OmniRoute resolve isso:**
- Endpoint A2A JSON-RPC (`POST /a2a`) com `message/send` e `message/stream`
- Streaming SSE com propagação de estado terminal
- APIs de ciclo de vida de tarefas para `tasks/get` e `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Preciso de saúde real do processo MCP, não status estimado"</b></summary>
Times operacionais precisam saber se o MCP está realmente ativo, não apenas se uma API está respondendo.
**Como o OmniRoute resolve isso:**
- Arquivo de heartbeat em runtime com PID, timestamps, transporte, quantidade de ferramentas e modo de escopo
- API de status MCP combinando heartbeat + atividade recente
- Cards de status na UI para processo/uptime/frescor do heartbeat
</details>
<details>
<summary><b>📋 20. "Preciso de execução auditável das ferramentas MCP"</b></summary>
Quando ferramentas alteram configuração ou disparam ações operacionais, os times precisam de rastreabilidade forense.
**Como o OmniRoute resolve isso:**
- Auditoria de chamadas MCP baseada em SQLite
- Filtros por ferramenta, sucesso/falha, chave de API e paginação
- Tabela de auditoria no dashboard + endpoints de métricas para automação
</details>
<details>
<summary><b>🔐 21. "Preciso de permissões MCP por escopo para cada integração"</b></summary>
Clientes diferentes devem operar com privilégio mínimo por categoria de ferramenta.
**Como o OmniRoute resolve isso:**
- 9 escopos MCP granulares para controle de acesso às ferramentas
- Aplicação de escopo e visibilidade na UI de gestão MCP
- Postura segura por padrão para operações sensíveis
</details>
<details>
<summary><b>⚙️ 22. "Preciso de controles operacionais sem redeploy"</b></summary>
Times precisam de mudanças rápidas em runtime durante incidentes e picos de custo.
**Como o OmniRoute resolve isso:**
- Troca de ativação de combo direto no dashboard de MCP
- Aplicação de perfis de resiliência via pacotes de política prontos
- Reset de circuit breaker no mesmo painel operacional
</details>
<details>
<summary><b>🔄 23. "Preciso de visibilidade ao vivo do ciclo de vida A2A e cancelamento"</b></summary>
Sem visibilidade de lifecycle, incidentes de tarefas ficam difíceis de investigar e corrigir.
**Como o OmniRoute resolve isso:**
- Listagem/filtragem de tarefas por estado/skill com paginação
- Drill-down de metadados, eventos e artefatos da tarefa
- Endpoint de cancelamento + ação de UI com confirmação
</details>
<details>
<summary><b>🌊 24. "Preciso de métricas de streams ativos para carga A2A"</b></summary>
Fluxos em streaming exigem visão operacional de concorrência e conexões ativas.
**Como o OmniRoute resolve isso:**
- Contadores de streams ativos integrados ao status A2A
- Timestamp da última tarefa e contagens por estado
- Cards no dashboard A2A para monitoramento operacional em tempo real
</details>
<details>
<summary><b>🪪 25. "Preciso de descoberta padrão de agente para clientes"</b></summary>
Clientes externos e orquestradores precisam de metadados legíveis por máquina para onboarding automático.
**Como o OmniRoute resolve isso:**
- Agent Card exposto em `/.well-known/agent.json`
- Capacidades e skills exibidas na UI de gestão
- API de status A2A inclui metadados de descoberta para automação
</details>
<details>
<summary><b>🧭 26. "Preciso de descobribilidade de protocolos na experiência do produto"</b></summary>
Se os usuários não encontram superfícies de protocolo, adoção e qualidade de suporte caem.
**Como o OmniRoute resolve isso:**
- Entradas MCP e A2A na sidebar
- Aba Protocolos em Endpoint com quick-start e status
- Links do overview para dashboards dedicados de gestão
</details>
<details>
<summary><b>🧪 27. "Preciso de validação end-to-end de protocolo com clientes reais"</b></summary>
Testes mockados não bastam para validar compatibilidade de protocolo antes do release.
**Como o OmniRoute resolve isso:**
- Suíte E2E que sobe a aplicação e usa transporte real do SDK MCP
- Testes de cliente A2A para discovery, send, stream, get e cancel
- Cross-check das validações com APIs de auditoria MCP e tarefas A2A
</details>
<details>
<summary><b>📡 28. "Preciso de observabilidade unificada em todas as interfaces"</b></summary>
Separar observabilidade por protocolo cria pontos cegos e aumenta o MTTR.
**Como o OmniRoute resolve isso:**
- Dashboards/logs/analytics unificados no mesmo produto
- Saúde + auditoria + telemetria de requisição em OpenAI, MCP e A2A
- APIs operacionais de status para automação
</details>
<details>
<summary><b>💼 29. "Preciso de um runtime único para proxy + tools + orquestração de agentes"</b></summary>
Manter vários serviços separados aumenta custo operacional e modos de falha.
**Como o OmniRoute resolve isso:**
- Proxy OpenAI-compatible, servidor MCP e servidor A2A na mesma stack
- Autenticação, resiliência, armazenamento e observabilidade compartilhados
- Modelo de políticas consistente em todas as superfícies de interação
</details>
<details>
<summary><b>🚀 30. "Preciso entregar workflows agênticos sem sprawl de glue code"</b></summary>
Times perdem velocidade quando precisam costurar múltiplos serviços e scripts ad hoc.
**Como o OmniRoute resolve isso:**
- Estratégia de endpoint unificada para clientes e agentes
- UIs de gestão de protocolo e fluxos de validação/smoke embutidos
- Base pronta para produção (segurança, logging, resiliência e backup)
</details>
### Exemplos de Playbooks (Casos de Uso Integrados)
**Playbook A: Maximizar assinatura paga + backup barato**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Custo mensal: $20 + pequeno gasto de backup
Resultado: qualidade maior, interrupção quase zero
```
**Playbook B: Stack de programação com custo zero**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Custo mensal: $0
Resultado: fluxo de coding gratuito e estável
```
## ⚡ Início Rápido
**1. Instale globalmente:**
@@ -508,7 +757,7 @@ docker compose --profile cli up -d
---
## 🖥️ Aplicativo Desktop — Offline e Sempre Ativo
## 🖥️
> 🆕 **NOVO!** O OmniRoute agora está disponível como **aplicativo desktop nativo** para Windows, macOS e Linux.
@@ -572,6 +821,21 @@ Quando minimizado, o OmniRoute fica na bandeja do sistema com ações rápidas:
## 💡 Funcionalidades Principais
### 🧭 Gestão MCP + A2A (Camada Operacional)
A maioria dos gateways de IA expõe MCP/A2A apenas como endpoints “escondidos”. O OmniRoute traz operação de primeira classe para os dois protocolos:
- **Descoberta na interface** — Entradas `MCP` e `A2A` na sidebar e aba `Protocolos` na página de Endpoint com quick-start e cartões de status.
- **Painel operacional MCP** (`/dashboard/mcp`) — Status real do processo por heartbeat, inventário de ferramentas/scopes, auditoria com filtros e controles operacionais (trocar combo, aplicar perfil de resiliência, resetar breakers).
- **Painel operacional A2A** (`/dashboard/a2a`) — Visão do agent card, ciclo de vida de tarefas por estado, contagem de streams ativos, drill-down/cancelamento de tasks e smoke tests de `message/send` e `message/stream`.
- **APIs de monitoramento** — Endpoints `/api/mcp/*` e `/api/a2a/*` para status, tasks, auditoria e automações externas.
Por que isso é relevante:
- **Um runtime, três papéis**: router/proxy OpenAI-compatible + servidor de ferramentas MCP + servidor agente A2A.
- **Governança unificada**: autenticação, auditoria e controles de resiliência compartilhados.
- **Operação confiável**: times conseguem validar, monitorar e depurar comportamento dos protocolos sem sair do produto.
### 🧠 Roteamento e Inteligência
| Funcionalidade | O que Faz |
@@ -607,7 +871,8 @@ Quando minimizado, o OmniRoute fica na bandeja do sistema com ações rápidas:
| Funcionalidade | O que Faz |
| ----------------------------------- | ----------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Auto-abertura/fechamento por provedor com limites configuráveis |
| 🔌 **Circuit Breaker** | Trip/recover por modelo com limites configuráveis |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-Thundering Herd** | Mutex + semáforo rate-limit para provedores com API key |
| 🧠 **Cache Semântico** | Cache de duas camadas (assinatura + semântico) reduz custo e latência |
| ⚡ **Idempotência de Requisição** | Janela de dedup de 5s para requisições duplicadas |
@@ -730,64 +995,26 @@ O OmniRoute inclui um poderoso Playground de Tradução integrado com **4 modos*
---
## 🎯 Casos de Uso
## 🧪 Avaliações (Evals)
### Caso 1: "Tenho assinatura Claude Pro"
OmniRoute inclui um framework de avaliação integrado para testar a qualidade de respostas de LLM contra um conjunto golden. Acesse via **Analytics → Evals** no dashboard.
**Problema:** Cota expira sem uso, limites de taxa durante programação intensa
### Conjunto Golden Integrado
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (usar assinatura ao máximo)
2. glm/glm-4.7 (backup barato quando a cota acabar)
3. if/kimi-k2-thinking (fallback de emergência gratuito)
O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
Custo mensal: $20 (assinatura) + ~$5 (backup) = $25 total
vs. $20 + bater em limites = frustração
```
- Saudações, matemática, geografia, geração de código
- Conformidade de formato JSON, tradução, markdown
- Recusa de segurança (conteúdo prejudicial), contagem, lógica booleana
### Caso 2: "Quero custo zero"
### Estratégias de Avaliação
**Problema:** Não pode pagar assinaturas, precisa de IA confiável para programar
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K grátis/mês)
2. if/kimi-k2-thinking (ilimitado grátis)
3. qw/qwen3-coder-plus (ilimitado grátis)
Custo mensal: $0
Qualidade: Modelos prontos para produção
```
### Caso 3: "Preciso programar 24/7, sem interrupções"
**Problema:** Prazos apertados, não pode ter tempo de inatividade
```
Combo: "always-on"
1. cc/claude-opus-4-6 (melhor qualidade)
2. cx/gpt-5.2-codex (segunda assinatura)
3. glm/glm-4.7 (barato, reset diário)
4. minimax/MiniMax-M2.1 (mais barato, reset 5h)
5. if/kimi-k2-thinking (gratuito ilimitado)
Resultado: 5 camadas de fallback = zero tempo de inatividade
```
### Caso 4: "Quero IA GRATUITA no OpenClaw"
**Problema:** Precisa de assistente de IA em aplicativos de mensagens, completamente gratuito
```
Combo: "openclaw-free"
1. if/glm-4.7 (ilimitado grátis)
2. if/minimax-m2.1 (ilimitado grátis)
3. if/kimi-k2-thinking (ilimitado grátis)
Custo mensal: $0
Acesso via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
| Estratégia | Descrição | Exemplo |
| ---------- | ---------------------------------------------- | -------------------------------- |
| `exact` | Saída deve corresponder exatamente | `"4"` |
| `contains` | Saída deve conter substring (case-insensitive) | `"Paris"` |
| `regex` | Saída deve corresponder ao padrão regex | `"1.*2.*3"` |
| `custom` | Função JS customizada retorna true/false | `(output) => output.length > 10` |
---
@@ -1071,29 +1298,6 @@ Configurações → Configuração de API:
---
## 🧪 Avaliações (Evals)
OmniRoute inclui um framework de avaliação integrado para testar a qualidade de respostas de LLM contra um conjunto golden. Acesse via **Analytics → Evals** no dashboard.
### Conjunto Golden Integrado
O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
- Saudações, matemática, geografia, geração de código
- Conformidade de formato JSON, tradução, markdown
- Recusa de segurança (conteúdo prejudicial), contagem, lógica booleana
### Estratégias de Avaliação
| Estratégia | Descrição | Exemplo |
| ---------- | ---------------------------------------------- | -------------------------------- |
| `exact` | Saída deve corresponder exatamente | `"4"` |
| `contains` | Saída deve conter substring (case-insensitive) | `"Paris"` |
| `regex` | Saída deve corresponder ao padrão regex | `"1.*2.*3"` |
| `custom` | Função JS customizada retorna true/false | `(output) => output.length > 10` |
---
## 🐛 Solução de Problemas
<details>
@@ -1149,7 +1353,7 @@ O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
---
## 🛠️ Stack Tecnológico
## 🛠️
- **Runtime**: Node.js 20+
- **Linguagem**: TypeScript 5.9 — **100% TypeScript** em `src/` e `open-sse/` (v1.0.6)
@@ -1201,7 +1405,7 @@ O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
---
## 🗺️ Roadmap
## 🗺️
O OmniRoute tem **210+ funcionalidades planejadas** em múltiplas fases de desenvolvimento. Áreas principais:
@@ -1226,18 +1430,6 @@ O OmniRoute tem **210+ funcionalidades planejadas** em múltiplas fases de desen
---
## 📧 Suporte
> 💬 **Participe da comunidade!** [Grupo WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Tire dúvidas, compartilhe dicas e fique atualizado.
- **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 da Comunidade](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projeto 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)

View File

@@ -110,6 +110,35 @@ _Conecte qualquer ferramenta IDE ou CLI com tecnologia de IA por meio do OmniRou
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Por que OmniRoute?
**Pare de desperdiçar dinheiro e atingir limites:**
@@ -128,6 +157,18 @@ _Conecte qualquer ferramenta IDE ou CLI com tecnologia de IA por meio do OmniRou
---
## 📧 Suporte
> 💬 **Junte-se à nossa comunidade!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obtenha ajuda, compartilhe dicas e fique atualizado.
- **Site**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemas**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projeto Original**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Como funciona
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves16 Real Pain Points
## 🎯 O que o OmniRoute resolve — 30 pontos reais de dor e casos de uso
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Todo desenvolvedor que usa ferramentas de IA enfrenta esses problemas diariamente.** O OmniRoute foi criado para resolver todos eles, desde custos excessivos até bloqueios regionais, desde fluxos quebrados de OAuth até operações de protocolo e observabilidade empresarial.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Eu pago por uma assinatura cara, mas ainda sou interrompido pelos limites"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Os desenvolvedores pagam US$ 20200/mês pelo Claude Pro, Codex Pro ou GitHub Copilot. Mesmo pagando, a cota tem um limite máximo 5h de uso, limites semanais ou limites de taxa por minuto. No meio da sessão de codificação, o provedor para de responder e o desenvolvedor perde fluxo e produtividade.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Se a cota de assinatura acabar, redireciona automaticamente para API Key → Barato → Gratuito sem intervenção manual
- **Rastreamento de cota em tempo real** — Mostra o consumo de tokens em tempo real com contagem regressiva redefinida (5h, diariamente, semanalmente)
- **Suporte para múltiplas contas** — Várias contas por provedor com round-robin automático — quando uma acabar, muda para a próxima
- **Combos personalizados** — Cadeias alternativas personalizáveis com 6 estratégias de balanceamento (preencher primeiro, round-robin, P2C, aleatório, menos usado, com custo otimizado)
- **Codex Business Quotas** — Monitoramento de cotas de espaço de trabalho de negócios/equipe diretamente no painel
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Preciso usar vários provedores, mas cada um tem uma API diferente"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI usa um formato, Claude (Anthropic) usa outro, Gemini ainda outro. Se um desenvolvedor quiser testar modelos de diferentes provedores ou fazer fallback entre eles, ele precisará reconfigurar SDKs, alterar endpoints e lidar com formatos incompatíveis. Provedores personalizados (FriendLI, NIM) possuem endpoints de modelo não padrão.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Endpoint unificado** — Um único `http://localhost:20128/v1` serve como proxy para todos os mais de 36 provedores
- **Tradução de formato** — Automática e transparente: OpenAI ↔ Claude ↔ Gemini ↔ API de respostas
- **Response Sanitization** — Remove campos não padrão (`x_groq`, `usage_breakdown`, `service_tier`) que quebram o OpenAI SDK v1.83+
- **Normalização de função** — Converte `developer``system` para provedores não-OpenAI; `system``user` para GLM/ERNIE
- **Think Tag Extraction** — Extrai blocos `<think>` de modelos como DeepSeek R1 em `reasoning_content` padronizado
- **Saída estruturada para Gemini** — `json_schema` conversão automática `responseMimeType`/`responseSchema`
- **`stream` é padronizado como `false`** — Alinha-se com as especificações OpenAI, evitando SSE inesperado em SDKs Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Meu provedor de IA bloqueia minha região/país"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Provedores como OpenAI/Codex bloqueiam o acesso de determinadas regiões geográficas. Os usuários recebem erros como `unsupported_country_region_territory` durante conexões OAuth e API. Isto é especialmente frustrante para desenvolvedores de países em desenvolvimento.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Configuração de proxy de 3 níveis** — Proxy configurável em 3 veis: global (todo o tráfego), por provedor (apenas um provedor) e por conexão/chave
- **Selos de proxy codificados por cores** — Indicadores visuais: 🟢 proxy global, 🟡 proxy do provedor, 🔵 proxy de conexão, sempre mostrando o IP
- **Troca de token OAuth por meio de proxy** — O fluxo OAuth também passa pelo proxy, resolvendo `unsupported_country_region_territory`
- **Testes de conexão via proxy** — Os testes de conexão usam o proxy configurado (não há mais bypass direto)
- **Suporte SOCKS5** — Suporte completo ao proxy SOCKS5 para roteamento de saída
- **TLS Fingerprint Spoofing** — Impressão digital TLS semelhante a um navegador via `wreq-js` para ignorar a detecção de bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Quero usar IA para codificação, mas não tenho dinheiro"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nem todos podem pagar US$ 20200/mês por assinaturas de IA. Estudantes, desenvolvedores de países emergentes, amadores e freelancers precisam de acesso a modelos de qualidade a custo zero.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Provedores de nível gratuito integrados** — Suporte nativo para provedores 100% gratuitos: iFlow (8 modelos ilimitados), Qwen (3 modelos ilimitados), Kiro (Claude grátis), Gemini CLI (180 mil/mês grátis)
- **Combos somente gratuitos** — Cadeia `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = US$ 0/mês com tempo de inatividade zero
- **Créditos gratuitos NVIDIA NIM** — 1.000 créditos gratuitos integrados
- **Estratégia de Custo Otimizado** — Estratégia de roteamento que escolhe automaticamente o provedor mais barato disponível
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Preciso proteger meu gateway de IA contra acesso não autorizado"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Ao expor um gateway de IA à rede (LAN, VPS, Docker), qualquer pessoa com o endereço pode consumir os tokens/cota do desenvolvedor. Sem proteção, as APIs ficam vulneráveis ao uso indevido, injeção imediata e abuso.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Gerenciamento de chaves de API** — Geração, rotação e escopo por provedor com uma página `/dashboard/api-manager` dedicada
- **Permissões em nível de modelo** — Restringir chaves de API a modelos específicos (`openai/*`, padrões curinga), com alternância Permitir tudo/Restringir
- **API Endpoint Protection** — Exija uma chave para `/v1/models` e bloqueie provedores específicos da listagem
- **Auth Guard + Proteção CSRF** — Todas as rotas do painel protegidas com middleware `withAuth` + tokens CSRF
- **Rate Limiter** — Limitação de taxa por IP com janelas configuráveis
- **Filtragem de IP** — Lista de permissões/lista de bloqueio para controle de acesso
- **Prompt Injection Guard** — Sanitização contra padrões de prompt maliciosos
- **Criptografia AES-256-GCM** — Credenciais criptografadas em repouso
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Meu provedor caiu e perdi meu fluxo de codificação"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Os provedores de IA podem ficar instáveis, retornar erros 5xx ou atingir limites de taxa temporários. Se um desenvolvedor depender de um único provedor, ele será interrompido. Sem disjuntores, tentativas repetidas podem travar o aplicativo.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Disjuntor por provedor** — Abertura/fechamento automático com limites e resfriamento configuráveis (Fechado/Aberto/Meio-aberto)
- **Retirada exponencial** — Atrasos progressivos em novas tentativas
- **Rebanho Anti-Trovão** — Proteção Mutex + semáforo contra tempestades de novas tentativas simultâneas
- **Combo Fallback Chains** — Se o provedor primário falhar, ele cairá automaticamente na cadeia sem intervenção
- **Combo Circuit Breaker** — Desativa automaticamente provedores com falha em uma cadeia de combinação
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Health Dashboard** — Monitoramento de tempo de atividade, estados de disjuntores, bloqueios, estatísticas de cache, latência p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Configurar cada ferramenta de IA é tedioso e repetitivo"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Os desenvolvedores usam Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Cada ferramenta precisa de uma configuração diferente (endpoint da API, chave, modelo). Reconfigurar ao trocar de provedor ou modelo é uma perda de tempo.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Página dedicada com configuração de um clique para Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Gera `chatLanguageModels.json` para VS Code com seleção de modelo em massa
- **Assistente de integração** — Configuração guiada em 4 etapas para usuários iniciantes
- **Um endpoint, todos os modelos** — Configure `http://localhost:20128/v1` uma vez, acesse mais de 36 provedores
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Gerenciar tokens OAuth de vários provedores é um inferno"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — todos usam OAuth 2.0 com tokens expirados. Os desenvolvedores precisam se autenticar novamente constantemente, lidar com `client_secret is missing`, `redirect_uri_mismatch` e falhas em servidores remotos. OAuth em LAN/VPS é particularmente problemático.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Atualização automática de token** — Os tokens OAuth são atualizados em segundo plano antes da expiração
- **OAuth 2.0 (PKCE) integrado ** — Fluxo automático para Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth de várias contas** — Várias contas por provedor por meio de extração de token JWT/ID
- **OAuth LAN/Remote Fix** — Detecção de IP privado para `redirect_uri` + modo URL manual para servidores remotos
- **OAuth Behind Nginx** — Usa `window.location.origin` para compatibilidade de proxy reverso
- **Guia OAuth remoto** — Guia passo a passo para credenciais do Google Cloud em VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Não sei quanto estou gastando ou onde"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Os desenvolvedores usam vários provedores pagos, mas não têm uma visão unificada dos gastos. Cada provedor possui seu próprio painel de faturamento, mas não há visão consolidada. Custos inesperados podem se acumular.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Painel de análise de custos** — Acompanhamento de custos por token e gerenciamento de orçamento por provedor
- **Limites de orçamento por nível** — Teto de gastos por nível que aciona substituto automático
- **Configuração de preços por modelo** — Preços configuráveis por modelo
- **Estatísticas de uso por chave de API** — Contagem de solicitações e carimbo de data/hora do último uso por chave
- **Painel de análise** — Cartões de estatísticas, gráfico de uso do modelo, tabela de provedores com taxas de sucesso e latência
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Não consigo diagnosticar erros e problemas em chamadas de IA"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Quando uma chamada falha, o desenvolvedor não sabe se foi um limite de taxa, um token expirado, um formato errado ou um erro do provedor. Logs fragmentados em diferentes terminais. Sem observabilidade, a depuração é uma tentativa e erro.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Painel de registros unificados** — 4 guias: registros de solicitação, registros de proxy, registros de auditoria, console
- **Console Log Viewer** — Visualizador em estilo terminal em tempo real com níveis codificados por cores, rolagem automática, pesquisa, filtro
- **SQLite Proxy Logs** — Logs persistentes que sobrevivem às reinicializações do servidor
- **Translator Playground** — 4 modos de depuração: Playground (tradução de formato), Chat Tester (ida e volta), Test Bench (lote), Live Monitor (tempo real)
- **Solicitar telemetria** — latência p50/p95/p99 + rastreamento X-Request-Id
- **Registro baseado em arquivo com rotação** — O interceptador do console captura tudo no log JSON com rotação baseada em tamanho
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Implantar e manter o gateway é complexo"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Instalar, configurar e manter um proxy de IA em diferentes ambientes (local, VPS, Docker, nuvem) exige muito trabalho. Problemas como caminhos codificados, `EACCES` em direrios, conflitos de porta e compilações entre plataformas aumentam o atrito.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **npm global install** — `npm install -g omniroute && omniroute` — done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **instalação global npm** — `npm install -g omniroute && omniroute`concluído
- **Docker Multiplataforma** — AMD64 + ARM64 nativo (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Perfis Docker Compose** — `base` (sem ferramentas CLI) e `cli` (com Claude Code, Codex, OpenClaw)
- **Aplicativo Electron Desktop** — Aplicativo nativo para Windows/macOS/Linux com bandeja do sistema, inicialização automática e modo offline
- **Modo Split-Port** — API e Dashboard em portas separadas para cenários avançados (proxy reverso, rede de contêineres)
- **Cloud Sync** — Sincronização de configuração entre dispositivos via Cloudflare Workers
- **Backups de banco de dados** — Backup, restauração, exportação e importação automática de todas as configurações
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "A interface é somente em inglês e minha equipe não fala inglês"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Equipes em países que não falam inglês, especialmente na América Latina, Ásia e Europa, enfrentam dificuldades com interfaces somente em inglês. As barreiras linguísticas reduzem a adoção e aumentam os erros de configuração.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Painel i18n — 30 idiomas** — Todas as mais de 500 teclas traduzidas, incluindo árabe, búlgaro, dinamarquês, alemão, espanhol, finlandês, francês, hebraico, hindi, ngaro, indonésio, italiano, japonês, coreano, malaio, holandês, norueguês, polonês, português (PT/BR), romeno, russo, eslovaco, sueco, tailandês, ucraniano, vietnamita, chinês, filipino, inglês
- **Suporte RTL** — Suporte da direita para a esquerda para árabe e hebraico
- **READMEs multilíngues** — 30 traduções completas de documentação
- **Seletor de idioma** — Ícone de globo no cabeçalho para troca em tempo real
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Preciso de mais do que bate-papo - preciso de incorporações, imagens, áudio"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
IA não é apenas conclusão de bate-papo. Os desenvolvedores precisam gerar imagens, transcrever áudio, criar embeddings para RAG, reclassificar documentos e moderar conteúdo. Cada API possui um endpoint e formato diferente.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Embeddings** — `/v1/embeddings` com 6 provedores e mais de 9 modelos
- **Geração de imagem** — `/v1/images/generations` com 10 provedores e mais de 20 modelos (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Texto para vídeo** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) e SD WebUI
- **Texto para música** — `/v1/music/generations` — ComfyUI (áudio estável aberto, MusicGen)
- **Transcrição de áudio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Conversão de texto em fala** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + provedores existentes
- **Moderações** — `/v1/moderations` — Verificações de segurança de conteúdo
- **Reclassificação** — `/v1/rerank` — Reclassificação da relevância do documento
- **API de respostas ** — Suporte completo a `/v1/responses` para Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Não tenho como testar e comparar a qualidade entre modelos"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Os desenvolvedores querem saber qual modelo é melhor para seu caso de uso código, tradução, raciocínio mas comparar manualmente é lento. Não existem ferramentas de avaliação integradas.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Avaliações LLM** — Teste Golden Set com 10 casos pré-carregados cobrindo saudações, matemática, geografia, geração de código, conformidade com JSON, tradução, remarcação, recusa de segurança
- **4 estratégias de correspondência** — `exact`, `contains`, `regex`, `custom` (função JS)
- **Translator Playground Test Bench** — Teste em lote com múltiplas entradas e saídas esperadas, comparação entre fornecedores
- **Testador de bate-papo** — Ida e volta completa com renderização de resposta visual
- **Monitoramento ao vivo** — Transmissão em tempo real de todas as solicitações que passam pelo proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Preciso escalar sem perder desempenho"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
À medida que o volume de solicitações aumenta, sem armazenar em cache as mesmas perguntas geram custos duplicados. Sem idempotência, solicitações duplicadas desperdiçam processamento. Os limites de tarifas por provedor devem ser respeitados.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache Semântico** — Cache de duas camadas (assinatura + semântica) reduz custo e latência
- **Idempotência de solicitação** — janela de desduplicação de 5s para solicitações idênticas
- **Detecção de limite de taxa** — RPM por provedor, intervalo mínimo e rastreamento simultâneo máximo
- **Limites de taxa editáveis** — Padrões configuráveis em Configurações → Resiliência com persistência
- **Cache de validação de chave de API** — cache de três camadas para desempenho de produção
- **Health Dashboard com telemetria** — latência p50/p95/p99, estatísticas de cache, tempo de atividade
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Quero controlar o comportamento do modelo globalmente"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Desenvolvedores que desejam todas as respostas em um idioma específico, com um tom específico ou que desejam limitar os tokens de raciocínio. Configurar isso em cada ferramenta/solicitação é impraticável.
**How OmniRoute solves it:**
**Como o OmniRoute resolve isso:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Injeção de Prompt do Sistema** — Prompt global aplicado a todas as solicitações
- **Thinking Budget Validation** — Controle de alocação de token de raciocínio por solicitação (passthrough, automático, personalizado, adaptativo)
- **6 Estratégias de Roteamento** — Estratégias globais que determinam como as solicitações são distribuídas
- **Wildcard Router** — Os padrões `provider/*` roteiam dinamicamente para qualquer provedor
- **Combo Habilitar/Desabilitar Alternar** — Alternar combos diretamente do painel
- **Alternância de provedor** — Habilite/desabilite todas as conexões de um provedor com um clique
- **Provedores bloqueados** — Excluir provedores específicos da listagem `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Preciso de ferramentas MCP como recursos de produto de primeira classe"</b></summary>
Muitos gateways de IA expõem o MCP apenas como um detalhe de implementação oculto. As equipes precisam de uma camada operacional visível e gerenciável.
**Como o OmniRoute resolve isso:**
- MCP aparece na navegação do painel e na guia protocolo de endpoint
- Página dedicada de gerenciamento de MCP com processos, ferramentas, escopos e auditoria
- Início rápido integrado para `omniroute --mcp` e integração de cliente
</details>
<details>
<summary><b>🧠 18. "Preciso de orquestração A2A com caminhos de tarefa de sincronização + fluxo"</b></summary>
Os fluxos de trabalho do agente precisam de respostas diretas e execução em streaming de longa duração com controle do ciclo de vida.
**Como o OmniRoute resolve isso:**
- Endpoint A2A JSON-RPC (`POST /a2a`) com `message/send` e `message/stream`
- Streaming SSE com propagação de estado terminal
- APIs de ciclo de vida de tarefas para `tasks/get` e `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Preciso de integridade real do processo MCP, não de status adivinhado"</b></summary>
As equipes operacionais precisam saber se o MCP está realmente ativo, e não apenas se uma API está acessível.
**Como o OmniRoute resolve isso:**
- Arquivo de pulsação em tempo de execução com PID, carimbos de data/hora, transporte, contagem de ferramentas e modo de escopo
- API de status MCP combinando pulsação + atividade recente
- Cartões de status da interface do usuário para atualização de processo/tempo de atividade/pulsação
</details>
<details>
<summary><b>📋 20. "Preciso de execução auditável da ferramenta MCP"</b></summary>
Quando as ferramentas alteram a configuração ou acionam ações operacionais, as equipes precisam de rastreabilidade forense.
**Como o OmniRoute resolve isso:**
- Registro de auditoria apoiado por SQLite para chamadas de ferramentas MCP
- Filtros por ferramenta, sucesso/falha, chave de API e paginação
- Tabela de auditoria do painel + endpoints de estatísticas para automação
</details>
<details>
<summary><b>🔐 21. "Preciso de permissões MCP com escopo definido por integração"</b></summary>
Clientes diferentes devem ter acesso com privilégios mínimos às categorias de ferramentas.
**Como o OmniRoute resolve isso:**
- 9 escopos MCP granulares para acesso controlado à ferramenta
- Aplicação do escopo e visibilidade na UI de gerenciamento do MCP
- Postura padrão segura para ferramentas operacionais
</details>
<details>
<summary><b>⚙️ 22. "Preciso de controles operacionais sem reimplantar"</b></summary>
As equipes precisam de mudanças rápidas no tempo de execução durante incidentes ou eventos de custo.
**Como o OmniRoute resolve isso:**
- Alternar ativação combinada diretamente do painel MCP
- Aplicar perfis de resiliência de pacotes de políticas predefinidos
- Redefinir o estado do disjuntor no mesmo painel de operações
</details>
<details>
<summary><b>🔄 23. "Preciso de visibilidade e cancelamento do ciclo de vida da tarefa A2A ao vivo"</b></summary>
Sem visibilidade do ciclo de vida, os incidentes de tarefas tornam-se difíceis de triagem.
**Como o OmniRoute resolve isso:**
- Listagem/filtragem de tarefas por estado/habilidade com paginação
- Detalhamento de metadados de tarefas, eventos e artefatos
- Terminal de cancelamento de tarefa e ação de UI com confirmação
</details>
<details>
<summary><b>🌊 24. "Preciso de métricas de fluxo ativo para carga A2A"</b></summary>
Os fluxos de trabalho de streaming exigem insights operacionais sobre simultaneidade e conexões em tempo real.
**Como o OmniRoute resolve isso:**
- Contadores de fluxo ativos integrados ao status A2A
- Carimbo de data/hora da última tarefa e contagens por estado
- Cartões de painel A2A para monitoramento de operações em tempo real
</details>
<details>
<summary><b>🪪 25. "Preciso de descoberta de agente padrão para clientes"</b></summary>
Clientes e orquestradores externos precisam de metadados legíveis por máquina para integração.
**Como o OmniRoute resolve isso:**
- Cartão de agente exposto em `/.well-known/agent.json`
- Capacidades e habilidades mostradas na UI de gerenciamento
- A API de status A2A inclui metadados de descoberta para automação
</details>
<details>
<summary><b>🧭 26. "Preciso de descoberta de protocolo na UX do produto"</b></summary>
Se os usuários não conseguirem descobrir superfícies de protocolo, a adoção e a qualidade do suporte cairão.
**Como o OmniRoute resolve isso:**
- Entradas da barra lateral para MCP e A2A
- Guia Protocolos da página Endpoint com início rápido e status
- Links da visão geral para painéis de gerenciamento dedicados
</details>
<details>
<summary><b>🧪 27. "Preciso de validação de protocolo ponta a ponta com clientes reais"</b></summary>
Os testes simulados não são suficientes para validar a compatibilidade do protocolo antes do lançamento.
**Como o OmniRoute resolve isso:**
- Suíte E2E que inicializa o aplicativo e usa transporte de cliente SDK MCP real
- Testes de cliente A2A para fluxos de descoberta, envio, streaming, obtenção e cancelamento
- Verificação cruzada de afirmações com APIs de auditoria MCP e tarefas A2A
</details>
<details>
<summary><b>📡 28. "Preciso de observabilidade unificada em todas as interfaces"</b></summary>
A divisão da observabilidade por protocolo cria pontos cegos e MTTR mais longo.
**Como o OmniRoute resolve isso:**
- Painéis/logs/análises unificados em um produto
- Saúde + auditoria + solicitação de telemetria nas camadas OpenAI, MCP e A2A
- APIs operacionais para status e automação
</details>
<details>
<summary><b>💼 29. "Preciso de um tempo de execução para proxy + ferramentas + orquestração de agente"</b></summary>
A execução de muitos serviços separados aumenta o custo operacional e os modos de falha.
**Como o OmniRoute resolve isso:**
- Proxy compatível com OpenAI, servidor MCP e servidor A2A em uma pilha
- Autenticação compartilhada, resiliência, armazenamento de dados e observabilidade
- Modelo de política consistente em todas as superfícies de interação
</details>
<details>
<summary><b>🚀 30. "Preciso enviar fluxos de trabalho de agente sem expansão de códigos colados"</b></summary>
As equipes perdem velocidade ao unir vários serviços e scripts ad hoc.
**Como o OmniRoute resolve isso:**
- Estratégia unificada de endpoint para clientes e agentes
- UIs de gerenciamento de protocolo integradas e caminhos de validação de fumaça
- Fundações prontas para produção (segurança, registro, resiliência, backup)
</details>
### Exemplos de manuais (casos de uso integrados)
**Manual A: Maximize a assinatura paga + backup barato**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Manual B: Pilha de codificação de custo zero**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Manual C: cadeia de fallback sempre ativa 24 horas por dia, 7 dias por semana**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Manual D: Operações de agente com MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Início rápido
**1. Instale globalmente:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +991,26 @@ OmniRoute inclui um poderoso Translator Playground integrado com **4 modos** par
</details>
---
## 🧪 Avaliações (Evals)
## 🎯 Casos de uso
OmniRoute inclui uma estrutura de avaliação integrada para testar a qualidade da resposta do LLM em relação a um conjunto dourado. Acesse-o em **Analytics → Evals** no painel.
### Caso 1: "Tenho assinatura do Claude Pro"
### Conjunto Dourado Integrado
**Problema:** A cota expira sem ser utilizada, limites de taxa durante codificação pesada
O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
```
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)
- Saudações, matemática, geografia, geração de código
- Conformidade com o formato JSON, tradução, remarcação
- Recusa de segurança (conteúdo prejudicial), contagem, lógica booleana
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Estratégias de Avaliação
### Caso 2: "Quero custo zero"
**Problema:** Não posso pagar assinaturas, preciso de codificação de IA confiável
```
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
```
### Caso 3: "Preciso de codificação 24 horas por dia, 7 dias por semana, sem interrupções"
**Problema:** Prazos, não podemos arcar com o tempo de inatividade
```
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
```
### Caso 4: "Quero IA GRATUITA no OpenClaw"
**Problema:** Precisa de assistente de IA em aplicativos de mensagens, totalmente gratuito
```
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...
```
| Estratégia | Descrição | Exemplo |
| ---------- | --------------------------------------------------------------------------- | -------------------------------- |
| `exact` | A saída deve corresponder exatamente | `"4"` |
| `contains` | A saída deve conter substring (sem distinção entre maiúsculas e minúsculas) | `"Paris"` |
| `regex` | A saída deve corresponder ao padrão regex | `"1.*2.*3"` |
| `custom` | Função JS personalizada retorna verdadeiro/falso | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Avaliações (Evals)
OmniRoute inclui uma estrutura de avaliação integrada para testar a qualidade da resposta do LLM em relação a um conjunto dourado. Acesse-o em **Analytics → Evals** no painel.
### Conjunto Dourado Integrado
O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
- Saudações, matemática, geografia, geração de código
- Conformidade com o formato JSON, tradução, remarcação
- Recusa de segurança (conteúdo prejudicial), contagem, lógica booleana
### Estratégias de Avaliação
| Estratégia | Descrição | Exemplo |
| ---------- | --------------------------------------------------------------------------- | -------------------------------- |
| `exact` | A saída deve corresponder exatamente | `"4"` |
| `contains` | A saída deve conter substring (sem distinção entre maiúsculas e minúsculas) | `"Paris"` |
| `regex` | A saída deve corresponder ao padrão regex | `"1.*2.*3"` |
| `custom` | Função JS personalizada retorna verdadeiro/falso | `(output) => output.length > 10` |
---
## 🐛 Solução de problemas
<details>
@@ -1132,13 +1345,13 @@ O "OmniRoute Golden Set" pré-carregado contém 10 casos de teste cobrindo:
- OmniRoute v1.0.6+ inclui validação de fallback por meio de conclusões de chat
- Certifique-se de que o URL base inclua o sufixo `/v1`
### 🔐 OAuth em Servidor Remoto (Remote OAuth Setup)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ IMPORTANTE para usuários com OmniRoute em VPS/Docker/servidor remoto**
#### Por que o OAuth do Antigravity / Gemini CLI falha em servidores remotos?
#### OAuth
Os provedores **Antigravity** e **Gemini CLI** usam **Google OAuth 2.0** para autenticação. O Google exige que um `redirect_uri` usado no fluxo OAuth seja **exatamente** uma das URIs pré-cadastradas no Google Cloud Console do aplicativo.
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Pilha de tecnologia
## 🛠️
- **Tempo de execução**: Node.js 1822 LTS (⚠️ Node.js 24+ **não é compatível**`better-sqlite3` binários nativos são incompatíveis)
- **Idioma**: TypeScript 5.9 — **100% TypeScript** em `src/` e `open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Roteiro
## 🗺️
OmniRoute tem **210+ recursos planejados** em diversas fases de desenvolvimento. Aqui estão as principais áreas:
@@ -1304,18 +1517,6 @@ OmniRoute tem **210+ recursos planejados** em diversas fases de desenvolvimento.
---
## 📧 Suporte
> 💬 **Junte-se à nossa comunidade!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obtenha ajuda, compartilhe dicas e fique atualizado.
- **Site**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problemas**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Projeto Original**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Colaboradores
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Conectați orice instrument IDE sau CLI alimentat de AI prin OmniRoute — gate
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 De ce OmniRoute?
**Nu mai risipi banii și nu mai atingeți limitele:**
@@ -128,6 +157,18 @@ _Conectați orice instrument IDE sau CLI alimentat de AI prin OmniRoute — gate
---
## 📧 Suport
> 💬 **Alăturați-vă comunității noastre!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obțineți ajutor, împărtășiți sfaturi și fiți la curent.
- **Site web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Probleme**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Proiect original**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Cum funcționează
```
@@ -157,263 +198,499 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Ce rezolvă OmniRoute — 30 de puncte reale de durere și cazuri de utilizare
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Fiecare dezvoltator care folosește instrumente AI se confruntă zilnic cu aceste probleme.** OmniRoute a fost creat pentru a le rezolva pe toate - de la depășiri de costuri la blocaje regionale, de la fluxuri OAuth întrerupte la operațiuni de protocol și observabilitate a întreprinderii.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. „Plătesc pentru un abonament scump, dar tot sunt întrerupt de limite”</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Dezvoltatorii plătesc 20200 USD/lună pentru Claude Pro, Codex Pro sau GitHub Copilot. Chiar și plătind, cota are un plafon - 5 ore de utilizare, limite săptămânale sau limite de tarif pe minut. La mijlocul sesiunii de codare, furnizorul nu mai răspunde și dezvoltatorul își pierde fluxul și productivitatea.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — Dacă cota de abonament se epuizează, redirecționează automat la cheia API → Ieftin → Gratuit fără intervenție manuală
- **Urmărirea cotelor în timp real** — Afișează consumul de simboluri în timp real cu numărătoarea inversă de resetare (5 ore, zilnic, săptămânal)
- **Asistență pentru mai multe conturi** — Conturi multiple per furnizor cu turneu automat automat — când unul se epuizează, trece la următorul
- **Combinații personalizate** — Lanțuri de rezervă personalizabile cu 6 strategii de echilibrare (fill-first, round-robin, P2C, aleatoriu, cel mai puțin utilizat, optimizat din punct de vedere al costurilor)
- **Cote de afaceri Codex** — Monitorizarea cotelor de spațiu de lucru pentru afaceri/echipe direct în tabloul de bord
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. „Trebuie să folosesc mai mulți furnizori, dar fiecare are un API diferit”</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI folosește un format, Claude (Anthropic) folosește altul, Gemini încă altul. Dacă un dezvoltator dorește să testeze modele de la diferiți furnizori sau să se retragă între aceștia, trebuie să reconfigureze SDK-urile, să schimbe punctele finale, să se ocupe de formate incompatibile. Furnizorii personalizați (FriendLI, NIM) au puncte finale de model non-standard.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** — Un singur `http://localhost:20128/v1` servește drept proxy pentru toți cei 36 de furnizori și mai sus
- **Traducerea formatului** — Automată și transparentă: OpenAI ↔ Claude ↔ Gemeni ↔ Responses API
- **Response Sanitization** — Elimina câmpurile nestandard (`x_groq`, `usage_breakdown`, `service_tier`) care încalcă OpenAI SDK v1.83+
- **Normalizarea rolurilor** — Convertește `developer``system` pentru furnizorii non-OpenAI; `system``user` pentru GLM/ERNIE
- **Think Tag Extraction** — Extrage blocurile `<think>` de la modele precum DeepSeek R1 în `reasoning_content` standardizat
- **Ieșire structurată pentru Gemeni** — `json_schema``responseMimeType`/`responseSchema` conversie automată
- **`stream` este implicit `false`** — Se aliniază cu specificațiile OpenAI, evitând SSE neașteptat în SDK-urile Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. „Furnizorul meu AI îmi blochează regiunea/țara”</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Furnizori precum OpenAI/Codex blochează accesul din anumite regiuni geografice. Utilizatorii primesc erori precum `unsupported_country_region_territory` în timpul conexiunilor OAuth și API. Acest lucru este frustrant în special pentru dezvoltatorii din țările în curs de dezvoltare.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-Level Proxy Config** — Proxy configurabil la 3 niveluri: global (tot traficul), per furnizor (doar un singur furnizor) și per conexiune/cheie
- **Insigne de proxy cu coduri de culoare** — Indicatori vizuali: 🟢 proxy global, 🟡 proxy furnizor, 🔵 proxy de conexiune, indicând întotdeauna IP-ul
- **Schimb de jetoane OAuth prin proxy** — fluxul OAuth trece și prin proxy, rezolvând `unsupported_country_region_territory`
- **Teste de conexiune prin proxy** — Testele de conexiune folosesc proxy-ul configurat (nu mai este ocolire directă)
- **Support SOCKS5** — Suport complet SOCKS5 proxy pentru rutarea de ieșire
- **TLS Fingerprint Spoofing** — Amprenta TLS asemănătoare unui browser prin `wreq-js` pentru a ocoli detectarea botului
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. „Vreau să folosesc AI pentru codare, dar nu am bani”</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nu toată lumea poate plăti 20200 USD/lună pentru abonamentele AI. Studenții, dezvoltatorii din țările emergente, pasionații și freelancerii au nevoie de acces la modele de calitate la cost zero.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Free Tier Providers Built-in** — Suport nativ pentru furnizori 100% gratuiti: iFlow (8 modele nelimitate), Qwen (3 modele nelimitate), Kiro (Claude gratuit), Gemini CLI (180K/lună gratuit)
- **Combinații numai gratuite** — Lanțul `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 USD/lună fără timp de nefuncționare
- **Credite gratuite NVIDIA NIM** — 1000 de credite gratuite integrate
- **Cost Optimized Strategy** — Strategie de rutare care alege automat cel mai ieftin furnizor disponibil
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. „Trebuie să-mi protejez poarta AI de accesul neautorizat”</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Când expuneți un gateway AI în rețea (LAN, VPS, Docker), oricine are adresa poate consuma jetoanele/cota dezvoltatorului. Fără protecție, API-urile sunt vulnerabile la utilizare greșită, injectare promptă și abuz.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Gestionarea cheilor API** — Generare, rotație și definire pentru fiecare furnizor cu o pagină dedicată `/dashboard/api-manager`
- **Permisiuni la nivel de model** — Restricționați cheile API la anumite modele (`openai/*`, modele cu caractere metalice), cu comutatorul Permite toate/Restricționați
- **API Endpoint Protection** — Solicitați o cheie pentru `/v1/models` și blocați anumiți furnizori din listă
- **Auth Guard + CSRF Protection** — Toate rutele tabloului de bord sunt protejate cu middleware `withAuth` + jetoane CSRF
- **Rate Limiter** — Limitarea ratei per-IP cu ferestre configurabile
- **Filtrare IP** — Lista permisă/lista blocată pentru controlul accesului
- **Prompt Injection Guard** — Igienizare împotriva tiparelor de prompte rău intenționate
- **Criptare AES-256-GCM** — Acreditări criptate în repaus
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. „Furnizorul meu a căzut și mi-am pierdut fluxul de codare”</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Furnizorii de AI pot deveni instabili, pot returna erori 5xx sau pot atinge limitele temporare ale ratei. Dacă un dezvoltator depinde de un singur furnizor, acesta este întrerupt. Fără întreruptoare, reîncercări repetate pot bloca aplicația.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Circuit Breaker per furnizor** - Deschidere/închidere automată cu praguri configurabile și răcire (Închis/Deschis/Pe jumătate deschis)
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Backoff exponențial** — Întârzieri progresive ale reîncercării
- **Anti-Thundering Herd** — Mutex + protecție semafor împotriva furtunilor concurente de reîncercare
- **Combo Fallback Chains** — Dacă furnizorul principal eșuează, trece automat prin lanț fără nicio intervenție
- **Combo Circuit Breaker** — Dezactivează automat furnizorii care eșuează dintr-un lanț combinat
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Tabloul de bord pentru sănătate** — Monitorizare timp de funcționare, stări întrerupătoare de circuit, blocări, statistici cache, latență p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. Configurarea fiecărui instrument AI este plictisitoare și repetitivă”</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Dezvoltatorii folosesc Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Fiecare instrument are nevoie de o configurație diferită (punct final API, cheie, model). Reconfigurarea la schimbarea de furnizor sau de model este o pierdere de timp.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — pagină dedicată cu setare cu un singur clic pentru Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — generează `chatLanguageModels.json` pentru VS Code cu selecția în bloc a modelului
- **Onboarding Wizard** — Configurare ghidată în 4 pași pentru utilizatorii debutanți
- **Un punct final, toate modelele** — Configurați `http://localhost:20128/v1` o dată, accesați peste 36 de furnizori
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. „Gestionarea jetoanelor OAuth de la mai mulți furnizori este un iad” </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot - toate folosesc OAuth 2.0 cu token-uri care expiră. Dezvoltatorii trebuie să se reautentifice în mod constant, să se ocupe de `client_secret is missing`, `redirect_uri_mismatch` și defecțiunile de pe serverele de la distanță. OAuth pe LAN/VPS este deosebit de problematică.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Reîmprospătare automată a simbolurilor** — jetoanele OAuth se reîmprospătează în fundal înainte de expirare
- **OAuth 2.0 (PKCE) încorporat** — Flux automat pentru Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth cu mai multe conturi** — Conturi multiple per furnizor prin extragerea jetonului JWT/ID
- **OAuth LAN/Remediere la distanță** — Detectare IP privată pentru `redirect_uri` + modul URL manual pentru servere la distanță
- **OAuth în spatele Nginx** — Utilizează `window.location.origin` pentru compatibilitatea cu proxy invers
- **Ghid OAuth la distanță** — Ghid pas cu pas pentru acreditările Google Cloud pe VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. „Nu știu cât cheltuiesc sau unde”</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Dezvoltatorii folosesc mai mulți furnizori plătiți, dar nu au o viziune unificată asupra cheltuielilor. Fiecare furnizor are propriul tablou de bord de facturare, dar nu există o vizualizare consolidată. Costurile neașteptate se pot acumula.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Tabloul de bord pentru analiza costurilor** — Urmărirea costurilor pe token și gestionarea bugetului per furnizor
- **Limite bugetare pe nivel** — Plafonul de cheltuieli pe nivel care declanșează o rezervă automată
- **Configurație de preț pe model** — Prețuri configurabile pe model
- **Statistici de utilizare per cheie API** — Numărul de solicitări și marcajul temporal al ultimei utilizări per cheie
- **Tabloul de bord de analiză** — Carduri cu statistici, diagramă de utilizare a modelului, tabel cu furnizori cu rate de succes și latență
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. „Nu pot diagnostica erorile și problemele în apelurile AI”</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Când un apel eșuează, dezvoltatorul nu știe dacă a fost o limită de rată, un simbol expirat, un format greșit sau o eroare a furnizorului. Jurnalele fragmentate pe diferite terminale. Fără observabilitate, depanarea este o încercare și eroare.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Tabloul de bord pentru jurnalele unificate** — 4 file: jurnalele de solicitare, jurnalele proxy, jurnalele de audit, consolă
- **Console Log Viewer** — Vizualizator în timp real în stil terminal cu niveluri codificate în culori, defilare automată, căutare, filtru
- **SQLite Proxy Logs** — Jurnale persistente care supraviețuiesc repornirilor serverului
- **Translator Playground** — 4 moduri de depanare: Playground (traducere format), Chat Tester (dus-întors), Test Bench (lot), Live Monitor (în timp real)
- **Solicitare telemetrie** — latență p50/p95/p99 + urmărire X-Request-Id
- **Înregistrare bazată pe fișiere cu rotație** — Interceptor de consolă captează totul în jurnalul JSON cu rotație bazată pe dimensiune
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. „Implementarea și întreținerea gateway-ului este complexă”</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Instalarea, configurarea și menținerea unui proxy AI în diferite medii (local, VPS, Docker, cloud) necesită multă muncă. Probleme precum căile codificate hard, `EACCES` pe directoare, conflictele de porturi și versiunile pe mai multe platforme adaugă fricțiuni.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm global install** — `npm install -g omniroute && omniroute`finalizat
- **Docker Multi-Platform** - AMD64 + ARM64 nativ (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (fără instrumente CLI) și `cli` (cu Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — aplicație nativă pentru Windows/macOS/Linux cu bară de sistem, pornire automată, mod offline
- **Split-Port Mode** — API și tablou de bord pe porturi separate pentru scenarii avansate (reverse proxy, rețea container)
- **Cloud Sync** — Configurați sincronizarea între dispozitive prin Cloudflare Workers
- **Backups DB** — Backup automat, restaurare, export și import al tuturor setărilor
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. „Interfața este doar în limba engleză și echipa mea nu vorbește engleză” </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Echipele din țările care nu vorbesc engleza, în special din America Latină, Asia și Europa, se luptă cu interfețele doar în limba engleză. Barierele lingvistice reduc adoptarea și cresc erorile de configurare.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Tabloul de bord i18n — 30 de limbi** — Toate cele peste 500 de taste traduse, inclusiv arabă, bulgară, daneză, germană, spaniolă, finlandeză, franceză, ebraică, hindi, maghiară, indoneziană, italiană, japone, coreeană, malay, olandeză, norvegiană, poloneză, portugheză (PT/BR), română, rusă, slovacă, suedeză, thailandeză, ucraineană, filipineză, engleză, chineză, vietnameză,
- ** Suport RTL** — Suport de la dreapta la stânga pentru arabă și ebraică
- **ReadME-uri în mai multe limbi** — 30 de traduceri complete de documentație
- **Selector de limbă** — Pictograma glob în antet pentru comutare în timp real
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. „Am nevoie de mai mult decât de chat — am nevoie de încorporare, imagini, audio</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI nu este doar finalizarea chatului. Dezvoltatorii trebuie să genereze imagini, să transcrie sunetul, să creeze înglobări pentru RAG, să reclasifice documentele și să modereze conținutul. Fiecare API are un punct final și un format diferit.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Embeddings** — `/v1/embeddings` cu 6 furnizori și peste 9 modele
- **Generarea imaginii** — `/v1/images/generations` cu 10 furnizori și peste 20 de modele (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) și SD WebUI
- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Transcriere audio** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + furnizori existenți
- **Moderări** — `/v1/moderations` — Verificări de siguranță a conținutului
- **Reclasificare** — `/v1/rerank` — Reclasificarea relevanței documentului
- **Responses API** — Suport complet `/v1/responses` pentru Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. „Nu am cum să testez și să compar calitatea între modele” </b></summary>
Developers want to know which model is best for their use case code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Dezvoltatorii vor să știe care model este cel mai bun pentru cazul lor de utilizare - cod, traducere, raționament - dar compararea manuală este lentă. Nu există instrumente de evaluare integrate.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Evaluări LLM** — Testarea setului de aur cu 10 cazuri preîncărcate care acoperă salutări, matematică, geografie, generare de cod, conformitate cu JSON, traducere, reducere, refuz de siguranță
- **4 strategii de potrivire** — `exact`, `contains`, `regex`, `custom` (funcția JS)
- **Translator Playground Test Bench** — Testare în loturi cu mai multe intrări și rezultate așteptate, comparație între furnizori
- **Tester de chat** — Tur complet dus-întors cu randare vizuală a răspunsului
- **Live Monitor** — Flux în timp real al tuturor solicitărilor care circulă prin proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. „Trebuie să mă scalez fără a pierde performanța”</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Pe măsură ce volumul cererilor crește, fără memorarea în cache aceleași întrebări generează costuri duplicate. Fara idempotenta, cererile duplicate procesarea deseurilor. Limitele de tarife pentru fiecare furnizor trebuie respectate.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Cache semantic** — Cache-ul pe două niveluri (semnătură + semantică) reduce costurile și latența
- **Request Idempotency** — fereastră de deduplicare 5s pentru cereri identice
- **Rate Limit Detection** — RPM per furnizor, interval minim și urmărire simultană maximă
- **Limite de rată editabile** — Valori implicite configurabile în Setări → Reziliență cu persistență
- **API Key Validation Cache** — cache pe 3 niveluri pentru performanța producției
- **Tabloul de bord pentru sănătate cu telemetrie** — latență p50/p95/p99, statistici cache, timp de funcționare
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. „Vreau să controlez comportamentul modelului la nivel global</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Dezvoltatori care doresc toate răspunsurile într-o anumită limbă, cu un anumit ton sau care doresc să limiteze simbolurile de raționament. Configurarea acestui lucru în fiecare instrument/cerere nu este practică.
**How OmniRoute solves it:**
**Cum o rezolvă OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **System Prompt Injection** — Prompt global aplicat tuturor solicitărilor
- **Thinking Budget Validation** — Controlul raționării alocării token-ului per cerere (transmis, automat, personalizat, adaptiv)
- **6 Strategii de rutare** — Strategii globale care determină modul în care sunt distribuite cererile
- **Wildcard Router** — modelele `provider/*` sunt direcționate dinamic către orice furnizor
- **Combo Activare/Dezactivare Comutare** — Comută combo direct din tabloul de bord
- **Comutare furnizor** — Activați/dezactivați toate conexiunile pentru un furnizor cu un singur clic
- **Furnizori blocați** — Excludeți anumiți furnizori din lista `/v1/models`
</details>
<details>
<summary><b>🧰 17. „Am nevoie de instrumente MCP ca capabilități de produs de primă clasă”</b></summary>
Multe gateway-uri AI expun MCP doar ca un detaliu ascuns de implementare. Echipele au nevoie de un nivel de operare vizibil și ușor de gestionat.
**Cum o rezolvă OmniRoute:**
- MCP apare în panoul de bord de navigare și fila de protocol final
- Pagina de management MCP dedicată cu proces, instrumente, domenii și audit
- Pornire rapidă încorporată pentru `omniroute --mcp` și integrarea clientului
</details>
<details>
<summary><b>🧠 18. „Am nevoie de orchestrare A2A cu sincronizare + căi de activități de flux” </b></summary>
Fluxurile de lucru ale agenților necesită atât răspunsuri directe, cât și execuție în flux de lungă durată, cu control ciclului de viață.
**Cum o rezolvă OmniRoute:**
- Punct final A2A JSON-RPC (`POST /a2a`) cu `message/send` și `message/stream`
- Streaming SSE cu propagare a stării terminale
- API-uri pentru ciclul de viață al sarcinilor pentru `tasks/get` și `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. „Am nevoie de sănătate reală a procesului MCP, nu de stare ghicită” </b></summary>
Echipele operaționale trebuie să știe dacă MCP este de fapt în viață, nu doar dacă un API este accesibil.
**Cum o rezolvă OmniRoute:**
- Fișier runtime heartbeat cu PID, marcaje de timp, transport, număr de instrumente și modul de aplicare
- API de stare MCP care combină bătăile inimii + activitatea recentă
- Carduri de stare a interfeței de utilizare pentru prospețimea procesului/uptime/inima
</details>
<details>
<summary><b>📋 20. „Am nevoie de o execuție auditabilă a instrumentului MCP” </b></summary>
Când instrumentele modifică configurația sau declanșează acțiuni operaționale, echipele au nevoie de trasabilitate criminalistică.
**Cum o rezolvă OmniRoute:**
- Înregistrare de audit susținută de SQLite pentru apelurile instrumentelor MCP
- Filtrează după instrument, succes/eșec, cheie API și paginare
- Tabelul de audit al tabloului de bord + punctele finale de statistici pentru automatizare
</details>
<details>
<summary><b>🔐 21. „Am nevoie de permisiuni MCP pentru fiecare integrare” </b></summary>
Clienții diferiți ar trebui să aibă cel mai mic privilegiu de acces la categoriile de instrumente.
**Cum o rezolvă OmniRoute:**
- 9 lunete MCP granulare pentru acces controlat la instrumente
- Aplicarea domeniului de aplicare și vizibilitatea în interfața de utilizare a managementului MCP
- Poziție implicită sigură pentru instrumentele operaționale
</details>
<details>
<summary><b>⚙️ 22. „Am nevoie de controale operaționale fără redistribuire”</b></summary>
Echipele au nevoie de modificări rapide ale timpului de rulare în timpul incidentelor sau evenimentelor de cost.
**Cum o rezolvă OmniRoute:**
- Comutați activarea comboi direct din tabloul de bord MCP
- Aplicați profiluri de rezistență din pachetele de politici predefinite
- Resetați starea întreruptorului de la același panou de operare
</details>
<details>
<summary><b>🔄 23. „Am nevoie de vizibilitate și anulare a ciclului de viață a sarcinii A2A live”</b></summary>
Fără vizibilitatea ciclului de viață, incidentele sarcinilor devin greu de triat.
**Cum o rezolvă OmniRoute:**
- Listarea sarcinilor/filtrarea după stare/abilitate cu paginare
- Detaliați metadatele sarcinii, evenimentele și artefactele
- Punct final de anulare a sarcinii și acțiune UI cu confirmare
</details>
<details>
<summary><b>🌊 24. „Am nevoie de valori de flux active pentru încărcarea A2A”</b></summary>
Fluxurile de lucru în flux necesită o perspectivă operațională privind concurența și conexiunile live.
**Cum o rezolvă OmniRoute:**
- Contoare active de flux integrate în starea A2A
- Marcaj de timp pentru ultima sarcină și numărătoare pentru fiecare stat
- Carduri de bord A2A pentru monitorizarea operațiunilor în timp real
</details>
<details>
<summary><b>🪪 25. „Am nevoie de descoperire de agenți standard pentru clienți”</b></summary>
Clienții externi și orchestratorii au nevoie de metadate care pot fi citite de mașină pentru integrare.
**Cum o rezolvă OmniRoute:**
- Card de agent expus la `/.well-known/agent.json`
- Capacități și abilități afișate în UI de management
- API-ul de stare A2A include metadate de descoperire pentru automatizare
</details>
<details>
<summary><b>🧭 26. „Am nevoie de descoperirea protocolului în produsul UX”</b></summary>
Dacă utilizatorii nu pot descoperi suprafețele de protocol, calitatea adoptării și a suportului scade.
**Cum o rezolvă OmniRoute:**
- Intrări din bara laterală pentru MCP și A2A
- Pagina Endpoint Fila Protocoale cu pornire rapidă și stare
- Link-uri de la prezentare generală la tablouri de bord dedicate de management
</details>
<details>
<summary><b>🧪 27. „Am nevoie de validarea protocolului end-to-end cu clienți reali”</b></summary>
Testele simulate nu sunt suficiente pentru a valida compatibilitatea protocolului înainte de lansare.
**Cum o rezolvă OmniRoute:**
- Suita E2E care pornește aplicația și utilizează transportul clientului MCP SDK real
- Testele client A2A pentru descoperirea, trimiterea, transmiterea în flux, obținerea și anularea fluxurilor
- Verificați încrucișați afirmațiile cu auditul MCP și API-urile pentru sarcini A2A
</details>
<details>
<summary><b>📡 28. „Am nevoie de observabilitate unificată pe toate interfețele”</b></summary>
Împărțirea observabilității în funcție de protocol creează puncte oarbe și MTTR mai lung.
**Cum o rezolvă OmniRoute:**
- Tablouri de bord/jurnale/analitice unificate într-un singur produs
- Sănătate + audit + solicitare de telemetrie în straturi OpenAI, MCP și A2A
- API-uri operaționale pentru stare și automatizare
</details>
<details>
<summary><b>💼 29. „Am nevoie de un timp de rulare pentru proxy + instrumente + orchestrare agent”</b></summary>
Rularea multor servicii separate crește costurile operaționale și modurile de eșec.
**Cum o rezolvă OmniRoute:**
- Proxy compatibil OpenAI, server MCP și server A2A într-o singură stivă
- Autentificare partajată, rezistență, stocare de date și observabilitate
- Model de politică consistent pe toate suprafețele de interacțiune
</details>
<details>
<summary><b>🚀 30. „Trebuie să trimit fluxuri de lucru agentice fără extinderea codului lipici”</b></summary>
Echipele își pierd din viteza atunci când realizează mai multe servicii și scripturi ad-hoc.
**Cum o rezolvă OmniRoute:**
- Strategie unificată pentru clienți și agenți
- Interfețe de utilizare a protocolului încorporate și căi de validare a fumului
- Baze pregătite pentru producție (securitate, logare, rezistență, backup)
</details>
### Exemple de manuale (cazuri de utilizare integrate)
**Playbook A: Maximizați abonamentul plătit + backup ieftin**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: teanc de codare cu costuri zero**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: lanț alternativ permanent activ 24/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Agentul operează cu MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Pornire rapidă
**1. Instalați la nivel global:**
@@ -506,7 +783,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +992,26 @@ OmniRoute include un puternic Translator Playground încorporat cu **4 moduri**
</details>
---
## 🧪 Evaluări (Evaluări)
## 🎯 Cazuri de utilizare
OmniRoute include un cadru de evaluare încorporat pentru a testa calitatea răspunsului LLM față de un set de aur. Accesați-l prin **Analitice → Evaluări** în tabloul de bord.
### Cazul 1: „Am abonament Claude Pro”
### Set de aur încorporat
**Problemă:** Cota expiră neutilizată, limitele ratei în timpul codării grele
„Setul de Aur OmniRoute” preîncărcat conține 10 cazuri de testare care acoperă:
```
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)
- Salutări, matematică, geografie, generare de cod
- Conformitatea formatului JSON, traducere, reducere
- Refuz de siguranță (conținut dăunător), numărare, logică booleană
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Strategii de evaluare
### Cazul 2: „Vreau cost zero”
**Problemă:** Nu-mi permit abonamente, au nevoie de codare AI de încredere
```
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
```
### Cazul 3: „Am nevoie de codare 24/7, fără întreruperi”
**Problemă:** Termenele limită, nu-mi permit timpi de nefuncționare
```
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
```
### Cazul 4: „Vreau AI GRATUIT în OpenClaw”
**Problemă:** Aveți nevoie de asistent AI în aplicațiile de mesagerie, complet gratuit
```
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...
```
| Strategie | Descriere | Exemplu |
| ---------- | ------------------------------------------------------------------------- | -------------------------------- |
| `exact` | Ieșirea trebuie să se potrivească exact cu | `"4"` |
| `contains` | Ieșirea trebuie să conțină subșir (indiferență de majuscule și minuscule) | `"Paris"` |
| `regex` | Ieșirea trebuie să se potrivească cu modelul regex | `"1.*2.*3"` |
| `custom` | Funcția JS personalizată returnează adevărat/fals | `(output) => output.length > 10` |
---
@@ -1058,29 +1295,6 @@ Settings → API Configuration:
---
## 🧪 Evaluări (Evaluări)
OmniRoute include un cadru de evaluare încorporat pentru a testa calitatea răspunsului LLM față de un set de aur. Accesați-l prin **Analitice → Evaluări** în tabloul de bord.
### Set de aur încorporat
„Setul de Aur OmniRoute” preîncărcat conține 10 cazuri de testare care acoperă:
- Salutări, matematică, geografie, generare de cod
- Conformitatea formatului JSON, traducere, reducere
- Refuz de siguranță (conținut dăunător), numărare, logică booleană
### Strategii de evaluare
| Strategie | Descriere | Exemplu |
| ---------- | ------------------------------------------------------------------------- | -------------------------------- |
| `exact` | Ieșirea trebuie să se potrivească exact cu | `"4"` |
| `contains` | Ieșirea trebuie să conțină subșir (indiferență de majuscule și minuscule) | `"Paris"` |
| `regex` | Ieșirea trebuie să se potrivească cu modelul regex | `"1.*2.*3"` |
| `custom` | Funcția JS personalizată returnează adevărat/fals | `(output) => output.length > 10` |
---
## 🐛 Depanare
<details>
@@ -1132,13 +1346,13 @@ OmniRoute include un cadru de evaluare încorporat pentru a testa calitatea răs
- OmniRoute v1.0.6+ include validarea de rezervă prin finalizarea chatului
- Asigurați-vă că adresa URL de bază include sufixul `/v1`
### 🔐 OAuth em Servidor Remoto (Configurare OAuth la distanță)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ IMPORTANT pentru utilizatorii cu OmniRoute în VPS/Docker/servidor remoto**
#### Por que o OAuth do Antigravity / Gemini CLI falha em serveres remotes?
#### OAuth
Pentru autentificare, **Antigravity** și **Gemini CLI** folosesc **Google OAuth 2.0**. O Google exige que a `redirect_uri` utilizat nu fluxo OAuth seja **exatamente** uma das URIs pre-cadastradas no Google Cloud Console do aplicative.
@@ -1227,7 +1441,7 @@ Nu vă rugăm să vă convingeți acum, dar este posibil să utilizați sau să
---
## 🛠️ Tech Stack
## 🛠️
- **Runtime**: Node.js 1822 LTS (⚠️ Node.js 24+ este **nu este acceptat** - `better-sqlite3` binarele native sunt incompatibile)
- **Limba**: TypeScript 5.9 — **100% TypeScript** în `src/` și `open-sse/` (v1.0.6)
@@ -1279,7 +1493,7 @@ Nu vă rugăm să vă convingeți acum, dar este posibil să utilizați sau să
---
## 🗺️ Foaia de parcurs
## 🗺️
OmniRoute are **210+ funcții planificate** în mai multe faze de dezvoltare. Iată domeniile cheie:
@@ -1304,18 +1518,6 @@ OmniRoute are **210+ funcții planificate** în mai multe faze de dezvoltare. Ia
---
## 📧 Suport
> 💬 **Alăturați-vă comunității noastre!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Obțineți ajutor, împărtășiți sfaturi și fiți la curent.
- **Site web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Probleme**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Proiect original**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Colaboratori
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Подключайте любую IDE или CLI-инструмент с AI ч
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Почему OmniRoute?
**Перестаньте тратить деньги и упираться в лимиты:**
@@ -128,6 +157,18 @@ _Подключайте любую IDE или CLI-инструмент с AI ч
---
## 📧 Поддержка
> 💬 **Присоединяйтесь к сообществу!** [Группа 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)
---
## 🔄 Как это работает
```
@@ -157,263 +198,497 @@ _Подключайте любую IDE или CLI-инструмент с AI ч
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Что решает OmniRoute — 30 реальных проблем и вариантов использования
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Каждый разработчик, использующий инструменты искусственного интеллекта, ежедневно сталкивается с этими проблемами.** OmniRoute был создан для решения всех этих проблем — от перерасхода средств до региональных блоков, от нарушенных потоков OAuth до операций протокола и наблюдения за предприятием.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. «Я плачу за дорогую подписку, но меня все равно прерывают лимиты» </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Разработчики платят 20200 долларов в месяц за Claude Pro, Codex Pro или GitHub Copilot. Даже при оплате квота имеет потолок — 5 часов использования, еженедельные лимиты или поминутные ограничения. В середине сеанса кодирования провайдер перестает отвечать, и разработчик теряет поток и производительность.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Умный 4-уровневый резерв** — если квота подписки исчерпана, происходит автоматическое перенаправление на API-ключ → Дешево → Бесплатно без вмешательства вручную.
- **Отслеживание квот в реальном времени** — показывает потребление токенов в режиме реального времени с обратным отсчетом сброса (5 часов, ежедневно, еженедельно).
- **Поддержка нескольких учетных записей** — Несколько учетных записей у каждого провайдера с автоматическим циклическим перебором — когда один из них заканчивается, переключается на следующий
- **Пользовательские комбинации** Настраиваемые резервные цепочки с 6 стратегиями балансировки (сначала заполняемые, циклический, P2C, случайные, наименее используемые, с оптимизацией затрат)
- **Бизнес-квоты Кодекса** — мониторинг квот рабочего пространства для бизнеса/команды непосредственно на панели управления.
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. «Мне нужно использовать несколько поставщиков, но у каждого свой API» </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI использует один формат, Claude (Anthropic) — другой, Gemini — третий. Если разработчик хочет протестировать модели от разных поставщиков или использовать резервный вариант между ними, ему необходимо перенастроить SDK, изменить конечные точки, разобраться с несовместимыми форматами. Пользовательские поставщики (FriendLI, NIM) имеют нестандартные конечные точки модели.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer` `system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Единая конечная точка** — один `http://localhost:20128/v1` служит прокси для всех 36+ провайдеров.
- **Перевод формата** — Автоматический и прозрачный: OpenAI ↔ Claude ↔ Gemini ↔ API ответов
- **Очистка ответов** — удаляются нестандартные поля (`x_groq`, `usage_breakdown`, `service_tier`), которые нарушают OpenAI SDK v1.83+.
- **Нормализация ролей** — преобразует `developer` в `system` для поставщиков, не поддерживающих OpenAI; `system``user` для GLM/ERNIE
- **Think Tag Extraction** — извлекает блоки `<think>` из таких моделей, как DeepSeek R1, в стандартизированный `reasoning_content`.
- **Структурированный вывод для Gemini** — автоматическое преобразование `json_schema``responseMimeType`/`responseSchema`.
- **`stream` по умолчанию — `false`** — соответствует спецификации OpenAI, что позволяет избежать неожиданного SSE в SDK Python/Rust/Go.
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. «Мой провайдер ИИ блокирует мой регион/страну» </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Такие провайдеры, как OpenAI/Codex, блокируют доступ из определенных географических регионов. Пользователи получают ошибки типа `unsupported_country_region_territory` во время подключений OAuth и API. Особенно это расстраивает разработчиков из развивающихся стран.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-уровневая конфигурация прокси** — настраиваемый прокси-сервер на трех уровнях: глобальный (весь трафик), для каждого провайдера (только один провайдер) и для каждого соединения/ключа.
- **Значки прокси с цветной кодировкой** — Визуальные индикаторы: 🟢 глобальный прокси, 🟡 прокси-сервер провайдера, 🔵 прокси-сервер подключения, всегда показывающий IP-адрес.
- **Обмен токенов OAuth через прокси** — поток OAuth также проходит через прокси, решая проблему `unsupported_country_region_territory`.
- **Тесты подключения через прокси** — тесты подключения используют настроенный прокси-сервер (прямого обхода больше нет)
- **Поддержка SOCKS5** — Полная поддержка прокси-сервера SOCKS5 для исходящей маршрутизации.
- **Подмена отпечатка пальца TLS** — отпечаток TLS, подобный браузеру, через `wreq-js` для обхода обнаружения ботов.
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. «Я хочу использовать ИИ для кодирования, но у меня нет денег» </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Не каждый может платить 20200 долларов в месяц за подписку на ИИ. Студентам, разработчикам из развивающихся стран, любителям и фрилансерам нужен доступ к качественным моделям по нулевой цене.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Встроенные провайдеры уровня бесплатного пользования** — Встроенная поддержка 100% бесплатных провайдеров: iFlow (8 моделей с неограниченным количеством пользователей), Qwen (3 модели с неограниченным количеством пользователей), Kiro (Claude бесплатно), Gemini CLI (180 тысяч в месяц бесплатно).
- **Комбинации только бесплатно** — цепочка `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 долларов США в месяц без простоев.
- **Бесплатные кредиты NVIDIA NIM** — интегрировано 1000 бесплатных кредитов.
- **Стратегия оптимизации затрат** — стратегия маршрутизации, которая автоматически выбирает самого дешевого доступного провайдера.
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. «Мне нужно защитить мой AI-шлюз от несанкционированного доступа» </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
При предоставлении доступа к сети AI-шлюза (LAN, VPS, Docker) любой, у кого есть адрес, может использовать токены/квоту разработчика. Без защиты API уязвимы для неправильного использования, быстрого внедрения и злоупотреблений.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Управление ключами API** — генерация, ротация и определение области действия для каждого поставщика с помощью специальной страницы `/dashboard/api-manager`.
- **Разрешения на уровне модели** — Ограничьте использование ключей API определенными моделями (`openai/*`, шаблоны подстановочных знаков) с помощью переключателя Разрешить все/Ограничить.
- **API Endpoint Protection** — требует ключ для `/v1/models` и блокирует определенных поставщиков из списка.
- **Auth Guard + защита CSRF** — все маршруты информационной панели защищены промежуточным программным обеспечением `withAuth` + токенами CSRF.
- **Ограничитель скорости** — ограничение скорости для каждого IP с помощью настраиваемых окон.
- **IP-фильтрация** — список разрешенных/блокированных для контроля доступа.
- **Prompt Injection Guard** — очистка от вредоносных шаблонов подсказок.
- **Шифрование AES-256-GCM** — неактивные учетные данные зашифрованы.
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. «Мой провайдер вышел из строя, и я потерял процесс кодирования» </b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Поставщики ИИ могут работать нестабильно, возвращать ошибки 5xx или достигать временных ограничений скорости. Если разработчик зависит от одного провайдера, его работу прерывают. Без автоматических выключателей повторные попытки могут привести к сбою приложения.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Выключатель для каждого поставщика** — автоматическое открытие/закрытие с настраиваемыми пороговыми значениями и временем восстановления (закрыто/открыто/полуоткрыто).
- **Экспоненциальная задержка**  прогрессивная задержка повторных попыток.
- **Anti-Thundering Herd** — Мьютекс + защита семафора от одновременных штормов повторных попыток.
- **Комбо-резервные цепочки** — в случае сбоя основного поставщика автоматически проходит через цепочку без вмешательства.
- **Комбо-выключатель** — автоматически отключает неисправных поставщиков в комбинированной цепочке.
- **Панель работоспособности** — мониторинг работоспособности, состояния автоматических выключателей, блокировки, статистика кэша, задержка p50/p95/p99.
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. «Настройка каждого инструмента искусственного интеллекта утомительна и повторяется» </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Разработчики используют Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Для каждого инструмента требуется своя конфигурация (конечная точка API, ключ, модель). Перенастройка при смене провайдера или модели — пустая трата времени.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Панель инструментов CLI** — выделенная страница с настройкой в один клик Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline.
- **Генератор конфигураций GitHub Copilot** — генерирует `chatLanguageModels.json` для кода VS с массовым выбором модели.
- **Мастер адаптации** пошаговая пошаговая настройка для начинающих пользователей.
- **Одна конечная точка, все модели** — настройте `http://localhost:20128/v1` один раз и получите доступ к более чем 36 поставщикам услуг.
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. «Управление токенами OAuth от нескольких провайдеров — это ад» </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — все используют OAuth 2.0 с токенами с истекающим сроком действия. Разработчикам необходимо постоянно проходить повторную аутентификацию, иметь дело с `client_secret is missing`, `redirect_uri_mismatch` и сбоями на удаленных серверах. OAuth в LAN/VPS особенно проблематичен.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Автоматическое обновление токенов** — токены OAuth обновляются в фоновом режиме до истечения срока их действия.
- **Встроенный OAuth 2.0 (PKCE)** — автоматический поток для Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow.
- **OAuth с несколькими учетными записями**  несколько учетных записей для каждого провайдера посредством извлечения токена JWT/ID.
- **OAuth LAN/Remote Fix** — обнаружение частного IP-адреса для `redirect_uri` + ручной режим URL-адреса для удаленных серверов.
- **OAuth за Nginx** — использует `window.location.origin` для совместимости с обратным прокси-сервером.
- **Руководство по удаленному OAuth** — пошаговое руководство по учетным данным Google Cloud на VPS/Docker.
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. «Я не знаю, сколько и куда я трачу» </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Разработчики используют нескольких платных поставщиков, но не имеют единого представления о расходах. У каждого провайдера есть своя панель выставления счетов, но единого представления нет. Неожиданные расходы могут накопиться.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Панель анализа затрат** — отслеживание затрат на каждый токен и управление бюджетом для каждого поставщика.
- **Ограничения бюджета на уровень** потолок расходов на уровень, который запускает автоматический возврат к резервному варианту.
- **Конфигурация цен на модель** — настраиваемые цены на модель.
- **Статистика использования каждого ключа API** — количество запросов и временная метка последнего использования для каждого ключа.
- **Панель аналитики** — карточки статистики, диаграмма использования модели, таблица поставщиков с показателями успеха и задержкой.
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. «Я не могу диагностировать ошибки и проблемы в вызовах ИИ» </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Когда вызов завершается неудачей, разработчик не знает, было ли это ограничением скорости, сроком действия токена, неправильным форматом или ошибкой провайдера. Фрагментированные журналы на разных терминалах. Без наблюдаемости отладка осуществляется методом проб и ошибок.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Панель управления унифицированными журналами** — 4 вкладки: журналы запросов, журналы прокси, журналы аудита, консоль.
- **Консольный просмотр журнала** — просмотрщик в режиме терминала в режиме реального времени с уровнями с цветовой кодировкой, автоматической прокруткой, поиском и фильтрацией.
- **Журналы прокси-сервера SQLite** — постоянные журналы, сохраняющиеся после перезапуска сервера.
- **Площадка переводчика** — 4 режима отладки: Площадка (перевод формата), Тестер чата (туда и обратно), Тестовый стенд (пакетный), Мониторинг в реальном времени (в режиме реального времени).
- **Запрос телеметрии** — задержка p50/p95/p99 + отслеживание X-Request-Id
- **Журналирование на основе файлов с ротацией** — перехватчик консоли записывает все в журнал JSON с ротацией на основе размера.
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. «Развертывание и обслуживание шлюза сложны» </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Установка, настройка и обслуживание прокси-сервера AI в различных средах (локальных, VPS, Docker, облаке) — трудоемкий процесс. Такие проблемы, как жестко запрограммированные пути, `EACCES` в каталогах, конфликты портов и кроссплатформенные сборки, добавляют проблем.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **глобальная установка npm** — `npm install -g omniroute && omniroute`выполнено
- **Мультиплатформенность Docker** — встроенная версия AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Профили Docker Compose** — `base` (без инструментов CLI) и `cli` (с Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — собственное приложение для Windows/macOS/Linux с панелью задач, автозапуском и автономным режимом.
- **Режим разделения портов** — API и панель мониторинга на отдельных портах для расширенных сценариев (обратный прокси-сервер, сеть контейнеров).
- **Cloud Sync** — синхронизация конфигурации между устройствами через Cloudflare Workers.
- **Резервные копии БД** — автоматическое резервное копирование, восстановление, экспорт и импорт всех настроек.
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. «Интерфейс только на английском языке, и моя команда не говорит по-английски» </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Команды в неанглоязычных странах, особенно в Латинской Америке, Азии и Европе, испытывают трудности с интерфейсами только на английском языке. Языковые барьеры сокращают внедрение и увеличивают количество ошибок в конфигурации.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Панель управления i18n — 30 языков** — Все более 500 клавиш переведены, включая арабский, болгарский, датский, немецкий, испанский, финский, французский, иврит, хинди, венгерский, индонезийский, итальянский, японский, корейский, малайский, голландский, норвежский, польский, португальский (PT/BR), румынский, русский, словацкий, шведский, тайский, украинский, вьетнамский, китайский, филиппинский, английский
- **Поддержка RTL** — поддержка написания справа налево для арабского языка и иврита.
- **Многоязычные файлы README** — 30 полных переводов документации.
- **Выбор языка** — значок глобуса в заголовке для переключения в реальном времени.
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. «Мне нужно больше, чем просто чат — мне нужны вложения, изображения, аудио»</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
ИИ — это не просто завершение чата. Разработчикам необходимо генерировать изображения, расшифровывать аудио, создавать вложения для RAG, изменять ранжирование документов и модерировать контент. Каждый API имеет свою конечную точку и формат.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Встраивания** — `/v1/embeddings` с 6 поставщиками и более чем 9 моделями.
- **Генерация изображений** — `/v1/images/generations` с 10 поставщиками и более чем 20 моделями (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigradity, SD WebUI, ComfyUI)
- **Преобразование текста в видео** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) и SD WebUI.
- **Преобразование текста в музыку** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Аудиотранскрипция** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Преобразование текста в речь** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 и + существующие поставщики
- **Модерация** — `/v1/moderations` — Проверка безопасности контента.
- **Реранжирование** — `/v1/rerank` — Изменение ранжирования релевантности документа.
- **API ответов** — полная поддержка `/v1/responses` для Кодекса.
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. «У меня нет возможности тестировать и сравнивать качество разных моделей» </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Разработчики хотят знать, какая модель лучше всего подходит для их варианта использования (код, перевод, рассуждения), но сравнивать вручную — это медленно. Интегрированных инструментов оценки не существует.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **LLM Evaluations** Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Оценки LLM** тестирование золотого набора с 10 предварительно загруженными вариантами, охватывающими приветствия, математику, географию, генерацию кода, соответствие JSON, перевод, уценку, отказ от безопасности.
- **4 стратегии сопоставления** — `exact`, `contains`, `regex`, `custom` (функция JS)
- **Тестовый стенд Translator Playground** — пакетное тестирование с несколькими входными данными и ожидаемыми результатами, сравнение между поставщиками.
- **Тестер чата** полный цикл с визуальным отображением ответов.
- **Живой монитор** — поток всех запросов, проходящих через прокси, в реальном времени.
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. «Мне нужно масштабироваться без потери производительности» </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
По мере роста объема запросов без кэширования одних и тех же вопросов возникают дублирующие затраты. Без идемпотентности дублирование запросов приводит к отходам обработки. Необходимо соблюдать ограничения по тарифам для каждого поставщика.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Семантический кеш** — двухуровневый кеш (сигнатура + семантика) снижает стоимость и задержку.
- **Request Idempotency** — окно дедупликации 5 с для идентичных запросов.
- **Обнаружение ограничения скорости** — число оборотов в минуту для каждого провайдера, минимальный разрыв и максимальное одновременное отслеживание.
- **Редактируемые ограничения скорости** — настраиваемые значения по умолчанию в меню «Настройки» → «Устойчивость с постоянством».
- **Кэш проверки ключей API** — трехуровневый кеш для повышения производительности.
- **Панель состояния с телеметрией** — задержка p50/p95/p99, статистика кэша, время безотказной работы.
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. «Я хочу глобально контролировать поведение модели» </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Разработчики, которым нужны все ответы на определенном языке, с определенным тоном или которые хотят ограничить количество токенов рассуждения. Настраивать это в каждом инструменте/запросе непрактично.
**How OmniRoute solves it:**
**Как OmniRoute решает эту проблему:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** Exclude specific providers from `/v1/models` listing
- **Внедрение системных подсказок** — глобальное приглашение применяется ко всем запросам.
- **Продуманная проверка бюджета** — контроль распределения токенов для каждого запроса (сквозной, автоматический, пользовательский, адаптивный)
- **6 стратегий маршрутизации** — глобальные стратегии, определяющие распределение запросов.
- **Маршрутизатор с подстановочными знаками** — шаблоны `provider/*` динамически маршрутизируются к любому поставщику.
- **Переключение/включение комбо** — переключение комбо непосредственно с панели управления.
- **Переключение поставщика** — включение/отключение всех подключений к провайдеру одним щелчком мыши.
- **Заблокированные поставщики** исключить определенных поставщиков из списка `/v1/models`.
</details>
<details>
<summary><b>🧰 17. «Мне нужны инструменты MCP как первоклассные возможности продукта» </b></summary>
Многие шлюзы AI предоставляют MCP только как скрытую деталь реализации. Командам нужен видимый и управляемый операционный уровень.
**Как OmniRoute решает эту проблему:**
- MCP отображается на панели навигации панели управления и на вкладке протокола конечной точки.
- Отдельная страница управления MCP с процессами, инструментами, объемами работ и аудитом.
- Встроенное краткое руководство по `omniroute --mcp` и адаптации клиентов.
</details>
<details>
<summary><b>🧠 18. «Мне нужна оркестровка A2A с путями задач синхронизации и потоковой передачи» </b></summary>
Рабочие процессы агента требуют как прямых ответов, так и длительного потокового выполнения с контролем жизненного цикла.
**Как OmniRoute решает эту проблему:**
- Конечная точка A2A JSON-RPC (`POST /a2a`) с `message/send` и `message/stream`.
- Потоковая передача SSE с распространением состояния терминала
- API жизненного цикла задач для `tasks/get` и `tasks/cancel`.
</details>
<details>
<summary><b>🛰️ 19. «Мне нужно реальное состояние процесса MCP, а не угаданный статус» </b></summary>
Оперативным группам необходимо знать, действительно ли MCP работает, а не только доступен ли API.
**Как OmniRoute решает эту проблему:**
- Файл контрольного сигнала времени выполнения с PID, временными метками, транспортом, количеством инструментов и режимом области действия.
- API статуса MCP, объединяющий пульс + недавнюю активность
- Карты состояния пользовательского интерфейса для актуальности процессов, времени безотказной работы и пульса.
</details>
<details>
<summary><b>📋 20. «Мне нужно проверяемое выполнение инструмента MCP» </b></summary>
Когда инструменты изменяют конфигурацию или запускают действия операционной системы, командам необходима судебно-медицинская отслеживаемость.
**Как OmniRoute решает эту проблему:**
- Ведение журнала аудита на основе SQLite для вызовов инструментов MCP.
- Фильтры по инструменту, успеху/неуспеху, ключу API и нумерации страниц.
- Таблица аудита панели мониторинга + конечные точки статистики для автоматизации
</details>
<details>
<summary><b>🔐 21. «Мне нужны ограниченные разрешения MCP для каждой интеграции» </b></summary>
Разные клиенты должны иметь минимальный доступ к категориям инструментов.
**Как OmniRoute решает эту проблему:**
- 9 детальных областей MCP для контролируемого доступа к инструментам
- Обеспечение соблюдения границ и видимость в пользовательском интерфейсе управления MCP.
- Безопасное положение по умолчанию для рабочих инструментов.
</details>
<details>
<summary><b>⚙️ 22. «Мне нужен оперативный контроль без передислокации» </b></summary>
Командам необходимы быстрые изменения во время выполнения во время инцидентов или событий, связанных с затратами.
**Как OmniRoute решает эту проблему:**
- Переключение комбо-активации прямо с панели управления MCP.
- Применение профилей устойчивости из предварительно определенных пакетов политик.
- Сброс состояния автоматического выключателя с той же панели управления.
</details>
<details>
<summary><b>🔄 23. «Мне нужна оперативная видимость и отмена жизненного цикла задачи A2A» </b></summary>
Без прозрачности жизненного цикла инциденты с задачами становится трудно сортировать.
**Как OmniRoute решает эту проблему:**
- Список задач/фильтрация по состоянию/навыку с нумерацией страниц
- Детализация метаданных задачи, событий и артефактов.
- Конечная точка отмены задачи и действие пользовательского интерфейса с подтверждением.
</details>
<details>
<summary><b>🌊 24. «Мне нужны метрики активного потока для загрузки A2A» </b></summary>
Рабочие процессы потоковой передачи требуют оперативного понимания параллелизма и живых соединений.
**Как OmniRoute решает эту проблему:**
- Счетчики активных потоков интегрированы в статус A2A
- Временная метка последней задачи и количество состояний
- Карты информационной панели A2A для мониторинга операций в реальном времени.
</details>
<details>
<summary><b>🪪 25. «Мне нужно стандартное обнаружение агента для клиентов» </b></summary>
Внешним клиентам и оркестраторам для адаптации необходимы машиночитаемые метаданные.
**Как OmniRoute решает эту проблему:**
- Карта агента открыта по адресу `/.well-known/agent.json`.
- Возможности и навыки, отображаемые в пользовательском интерфейсе управления.
- API статуса A2A включает метаданные обнаружения для автоматизации.
</details>
<details>
<summary><b>🧭 26. «Мне нужна возможность обнаружения протокола в UX продукта» </b></summary>
Если пользователи не могут обнаружить поверхности протокола, качество внедрения и поддержки снижается.
**Как OmniRoute решает эту проблему:**
- Записи на боковой панели для MCP и A2A.
- Вкладка «Протоколы» на странице конечной точки с быстрым запуском и статусом.
- Ссылки из обзора на специальные панели управления.
</details>
<details>
<summary><b>🧪 27. «Мне нужна сквозная проверка протокола с реальными клиентами» </b></summary>
Пробных тестов недостаточно для проверки совместимости протокола перед выпуском.
**Как OmniRoute решает эту проблему:**
- Пакет E2E, который загружает приложение и использует настоящий клиентский транспорт MCP SDK.
- Клиент A2A тестирует потоки обнаружения, отправки, потоковой передачи, получения и отмены.
- Перекрестная проверка утверждений с помощью API-интерфейсов аудита MCP и задач A2A.
</details>
<details>
<summary><b>📡 28. «Мне нужна унифицированная наблюдаемость на всех интерфейсах» </b></summary>
Разделение наблюдаемости по протоколам создает «слепые зоны» и увеличивает MTTR.
**Как OmniRoute решает эту проблему:**
- Унифицированные дашборды/логи/аналитика в одном продукте
- Здоровье + аудит + телеметрия запросов на уровнях OpenAI, MCP и A2A.
- Операционные API для статуса и автоматизации
</details>
<details>
<summary><b>💼 29. «Мне нужна одна среда выполнения для прокси + инструментов + оркестровки агентов» </b></summary>
Запуск множества отдельных служб увеличивает эксплуатационные расходы и количество видов сбоев.
**Как OmniRoute решает эту проблему:**
- OpenAI-совместимый прокси, сервер MCP и сервер A2A в одном стеке
- Общая аутентификация, устойчивость, хранилище данных и наблюдаемость.
- Согласованная модель политики на всех поверхностях взаимодействия.
</details>
<details>
<summary><b>🚀 30. «Мне нужно реализовать агентские рабочие процессы без разрастания связующего кода» </b></summary>
Команды теряют скорость при объединении нескольких специальных сервисов и сценариев.
**Как OmniRoute решает эту проблему:**
- Единая стратегия конечных точек для клиентов и агентов
- Встроенные пользовательские интерфейсы управления протоколами и пути проверки дыма.
- Готовые к работе основы (безопасность, ведение журналов, отказоустойчивость, резервное копирование)
</details>
### Примеры сборников сценариев (интегрированные варианты использования)
**Пособие А: максимальное использование платной подписки + дешевое резервное копирование**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Пособие Б: стек кодирования с нулевой стоимостью**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Пособие C: Всегда работающая резервная цепочка 24 часа в сутки, 7 дней в неделю**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Сборник D: Операции агента с помощью MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Быстрый старт
**1. Установите глобально:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Настольное Приложение — Оффлайн и Всегда Активно
## 🖥️
> 🆕 **НОВИНКА!** OmniRoute теперь доступен как **нативное настольное приложение** для Windows, macOS и Linux.
@@ -589,6 +864,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Функция | Что делает |
| -------------------------------- | ---------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Авто-открытие/закрытие по провайдеру с настраиваемыми порогами |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-Thundering Herd** | Mutex + семафор для API key провайдеров |
| 🧠 **Семантический кеш** | Двухуровневый кеш (сигнатура + семантика) снижает стоимость |
| ⚡ **Идемпотентность запросов** | 5с окно дедупликации для дублирующихся запросов |
@@ -696,66 +972,26 @@ Combo: "my-coding-stack"
</details>
---
## 🧪 Оценки (Evals)
## 🎯 Сценарии использования
OmniRoute включает встроенный фреймворк оценки для тестирования качества ответов LLM по golden set. Доступ через **Analytics → Evals** в dashboard.
### Сценарий 1: «У меня подписка Claude Pro»
### Встроенный Set
**Проблема:** Квота истекает неиспользованной, лимиты скорости во время интенсивного программирования
Предзагруженный «OmniRoute Golden Set» содержит 10 тестов:
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (используйте подписку полностью)
2. glm/glm-4.7 (дешёвый бэкап при исчерпании квоты)
3. if/kimi-k2-thinking (бесплатный аварийный fallback)
- Приветствия, математика, география, генерация кода
- Соответствие формату JSON, перевод, markdown
- Отказ от небезопасного контента, подсчёт, булева логика
Месячная стоимость: $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...
```
| Стратегия | Описание | Пример |
| ---------- | ----------------------------------------------------- | -------------------------------- |
| `exact` | Вывод должен совпадать точно | `"4"` |
| `contains` | Вывод должен содержать подстроку (без учёта регистра) | `"Paris"` |
| `regex` | Вывод должен соответствовать regex-паттерну | `"1.*2.*3"` |
| `custom` | Пользовательская JS-функция возвращает true/false | `(output) => output.length > 10` |
---
@@ -1039,29 +1275,6 @@ Dashboard → CLI Tools → OpenClaw → Выбрать модель → При
---
## 🧪 Оценки (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>
@@ -1117,7 +1330,7 @@ OmniRoute включает встроенный фреймворк оценки
---
## 🛠️ Технологический стек
## 🛠️
- **Runtime**: Node.js 20+
- **Язык**: TypeScript 5.9 — **100% TypeScript** в `src/` и `open-sse/` (v1.0.6)
@@ -1148,17 +1361,7 @@ OmniRoute включает встроенный фреймворк оценки
---
## 📧 Поддержка
> 💬 **Присоединяйтесь к сообществу!** [Группа 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)
---
## 🗺️
## 👥 Участники

View File

@@ -110,6 +110,35 @@ _Pripojte akýkoľvek nástroj IDE alebo CLI poháňaný AI cez OmniRoute be
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Prečo OmniRoute?
**Prestaňte plytvať peniazmi a dosahovať limity:**
@@ -128,6 +157,18 @@ _Pripojte akýkoľvek nástroj IDE alebo CLI poháňaný AI cez OmniRoute be
---
## 📧 Podpora
> 💬 **Pripojte sa k našej komunite!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Získajte pomoc, zdieľajte tipy a buďte informovaní.
- **Web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problémy**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Pôvodný projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Ako to funguje
```
@@ -157,263 +198,501 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Čo OmniRoute rieši — 30 bodov skutočnej bolesti a prípadov použitia
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Každý vývojár, ktorý používa nástroje AI, čelí týmto problémom denne.** OmniRoute bol vytvorený tak, aby ich všetky vyriešil od prekročenia nákladov po regionálne bloky, od prerušených tokov OAuth po operácie protokolov a pozorovateľnosť podniku.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. „Platím za drahé predplatné, ale stále ma prerušujú limity“ </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Vývojári platia za Claude Pro, Codex Pro alebo GitHub Copilot 20 200 dolárov mesačne. Aj pri platení má kvóta strop 5 hodín používania, týždenné limity alebo limity za minútu. Počas relácie kódovania poskytovateľ prestane reagovať a vývojár stráca tok a produktivitu.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Inteligentný 4-úrovňový záložný systém** Ak sa vyčerpá kvóta predplatného, automaticky sa presmeruje na kľúč API → Lacné → Zadarmo s nulovým manuálnym zásahom
- **Sledovanie kvóty v reálnom čase** Zobrazuje spotrebu tokenov v reálnom čase s resetovaným odpočítavaním (5 hodín, denne, týždenne)
**Podpora viacerých účtov** Viacero účtov na poskytovateľa s automatickým opakovaním keď sa jeden minie, prepne sa na ďalší
**Vlastné kombá** Prispôsobiteľné záložné reťazce so 6 stratégiami vyvažovania (najskôr vyplniť, opakovane, P2C, náhodné, najmenej používané, nákladovo optimalizované)
- **Codex Business Quotas** — Monitorovanie kvót pracovného priestoru pre firmy/tím priamo na paneli
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. „Potrebujem použiť viacerých poskytovateľov, ale každý má iné API</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI používa jeden formát, Claude (Anthropic) iný a Gemini ďalší. Ak chce vývojár testovať modely od rôznych poskytovateľov alebo medzi nimi záložné riešenie, musí prekonfigurovať súpravy SDK, zmeniť koncové body, vysporiadať sa s nekompatibilnými formátmi. Vlastní poskytovatelia (FriendLI, NIM) majú neštandard modelové koncové body.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** Jediný `http://localhost:20128/v1` slúži ako proxy pre všetkých 36+ poskytovateľov
- **Formátový preklad** — Automatic a transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
**Dezinfekcia odozvy** Odstráni neštandardné polia (`x_groq`, `usage_breakdown`, `service_tier`), ktoré porušujú OpenAI SDK v1.83+
- **Normalizácia rolí** Konvertuje `developer``system` pre poskytovateľov, ktorí nie sú OpenAI; `system``user` pre GLM/ERNIE
**Think Tag Extraction** Extrahuje bloky `<think>` z modelov ako DeepSeek R1 do štandardizovaných `reasoning_content`
- **Štruktúrovaný výstup pre Gemini** — `json_schema` automatická konverzia `responseMimeType`/`responseSchema`
- **`stream` predvolene je `false`** — Zosúladí sa so špecifikáciou OpenAI, čím sa zabráni neočakávanému SSE v súpravách Python/Rust/Go SDK
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. „Môj poskytovateľ AI blokuje môj región/krajinu“</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Poskytovatelia ako OpenAI/Codex blokujú prístup z určitých geografických oblastí. Používatelia dostanú chyby ako `unsupported_country_region_territory` počas pripojení OAuth a API. To je frustrujúce najmä pre vývojárov z rozvojových krajín.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Konfigurácia proxy servera na troch úrovniach** Konfigurovateľný server proxy na 3 úrovniach: globálny (celá prevádzka), podľa jednotlivých poskytovateľov (iba jeden poskytovateľ) a podľa pripojenia/kľúča
- **Farebné odznaky proxy** — Vizuálne inditory: 🢢 globálny proxy, 🟡 proxy poskytovateľa, 🔵 proxy pripojenia, vždy zobrazuje IP
**Výmena tokenov OAuth cez proxy** tok OAuth prechádza aj cez proxy, čím sa rieši `unsupported_country_region_territory`
- **Testy pripojenia cez proxy** Testy pripojenia používajú nakonfigurovaný proxy (už žiadne priame obchádzanie)
- **Podpora SOCKS5** — Úplná podpora proxy SOCKS5 pre odchádzajúce smerovanie
- **TLS Fingerprint Spoofing** Odtlačok prsta TLS podobný prehliadaču cez `wreq-js` na obídenie detekcie robotov
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. „Chcem použiť AI na kódovanie, ale nemám peniaze“</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Nie každý môže platiť 20 200 $ mesačne za predplatné AI. Študenti, vývojári z rozvíjajúcich sa krajín, fanúšikovia a nezávislí pracovníci potrebujú prístup ku kvalitným modelom za nulové náklady.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Zabudovaní poskytovatelia bezplatnej úrovne** — Natívna podpora pre 100 % bezplatných poskytovateľov: iFlow (8 neobmedzených modelov), Qwen (3 neobmedzené modely), Kiro (Claude zdarma), Gemini CLI (180 000/mesiac zdarma)
- **Len bezplatné kombá** — Reťaz `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 USD/mesiac s nulovými prestojmi
- **Bezplatné kredity NVIDIA NIM** integrovaných 1 000 bezplatných kreditov
- **Cost Optimized Strategy** Stratégia smerovania, ktorá automaticky vyberie najlacnejšieho dostupného poskytovateľa
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. „Potrebujem chrániť svoju bránu AI pred neoprávneným prístupom“</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Pri vystavení brány AI do siete (LAN, VPS, Docker) môže ktokoľvek s adresou spotrebovať tokeny/kvótu vývojára. Bez ochrany sú rozhrania API náchylné na nesprávne použitie, rýchle vloženie a zneužitie.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
**Správa kľúčov API** Generovanie, rotácia a rozsah podľa poskytovateľa s vyhradenou stránkou `/dashboard/api-manager`
**Povolenia na úrovni modelu** Obmedzenie kľúčov API na konkrétne modely (`openai/*`, vzory zástupných znakov) s prepínačom Povoliť všetko/Obmedziť
**API Endpoint Protection** Vyžadovať kľúč pre `/v1/models` a blokovať konkrétnych poskytovateľov zo zoznamu
- **Auth Guard + ochrana CSRF** - Všetky trasy na dashboarde sú chránené middlevérom `withAuth` + tokenmi CSRF
- **Rate Limiter** — Obmedzenie rýchlosti na IP pomocou konfigurovateľných okien
- **IP Filtering** — Zoznam povolených/blokovaných pre riadenie prístupu
- **Prompt Injection Guard** Dezinfekcia proti škodlivým vzorom výzvy
- **Šifrovanie AES-256-GCM** — Prihlasovacie údaje sú v pokoji zašifrované
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. „Môj poskytovateľ zlyhal a stratil som tok kódovania“</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Poskytovatelia AI sa môžu stať nestabilnými, vrátiť chyby 5xx alebo dosiahnuť dočasné limity sadzieb. Ak vývojár závisí od jedného poskytovateľa, bude prerušený. Bez ističov môžu opakované pokusy zlyhať aplikáciu.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Istič pre každého poskytovateľa** — Automatické otváranie/zatváranie s konfigurovateľnými prahmi a chladením (zatvorené/otvorené/polootvorené)
- **Exponenciálne stiahnutie** — Postupné oneskorenie opakovania
- **Anti-Thundering Herd** - ochrana Mutex + semafor proti súbežným opakovaným búrkam
- **Combo Fallback Chains** Ak primárny poskytovateľ zlyhá, automaticky prepadne reťazcom bez akéhokoľvek zásahu
- **Combo Circuit Breaker** Automaticky deaktivuje zlyhávajúcich poskytovateľov v rámci kombinovaného reťazca
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
**Health Dashboard** Monitorovanie dostupnosti, stavy ističov, blokovania, štatistiky vyrovnávacej pamäte, latencia p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. „Konfigurácia každého nástroja AI je únavná a opakovaná“ </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Vývojári používajú Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Každý nástroj potrebuje inú konfiguráciu (API endpoint, kľúč, model). Prekonfigurovanie pri zmene poskytovateľa alebo modelu je strata času.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** Vyhradená stránka s nastavením jedným kliknutím pre Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
**GitHub Copilot Config Generator** Generuje `chatLanguageModels.json` pre kód VS s hromadným výberom modelu
- **Sprievodca registráciou** Sprievodca nastavením v 4 krokoch pre začínajúcich používateľov
**Jeden koncový bod, všetky modely** Nakonfigurujte `http://localhost:20128/v1` raz a získajte prístup k viac ako 36 poskytovateľom
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. „Správa tokenov OAuth od viacerých poskytovateľov je peklo“ </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot všetky používajú OAuth 2.0 s tokenmi, ktorých platnosť sa končí. Vývojári sa musia neustále znovu overovať, riešiť `client_secret is missing`, `redirect_uri_mismatch` a zlyhania na vzdialených serveroch. Obzvlášť problematické je OAuth na LAN/VPS.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatická obnova tokenov** Tokeny OAuth sa pred vypršaním platnosti obnovujú na pozadí
- **Vstavaný OAuth 2.0 (PKCE)** Automatický tok pre Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
**Multi-Auth OAuth** Viaceré účty na poskytovateľa prostredníctvom extrakcie tokenov JWT/ID
- **Oprava OAuth LAN/Remote** — Detekcia súkromnej adresy IP pre `redirect_uri` + manuálny režim adresy URL pre vzdialené servery
- **OAuth Behind Nginx** - Používa `window.location.origin` na reverznú kompatibilitu proxy
**Príručka vzdialeného OAuth** Podrobný sprievodca povereniami Google Cloud na VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Neviem, koľko míňam alebo kde" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Vývojári využívajú viacerých platených poskytovateľov, ale nemajú jednotný pohľad na výdavky. Každý poskytovateľ má svoj vlastný informačný panel fakturácie, ale neexistuje žiadne konsolidované zobrazenie. Neočakávané náklady sa môžu nahromadiť.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
**Informačný panel analýzy nákladov** sledovanie nákladov na token a správa rozpočtu podľa poskytovateľa
- **Obmedzenia rozpočtu na úroveň** Strop výdavkov na úroveň, ktorý spúšťa automatické záložné právo
- **Konfigurácia cien za model** Konfigurovateľné ceny za model
- **Štatistiky používania na kľúč API** Počet žiadostí a časová pečiatka posledného použitia na kľúč
**Panel Analytics** štatistické karty, graf používania modelu, tabuľka poskytovateľov s mierami úspešnosti a latenciou
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. „Nedokážem diagnostikovať chyby a problémy vo volaniach AI“ </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Keď hovor zlyhá, vývojár nevie, či to bol limit sadzby, vypršaný token, nesprávny formát alebo chyba poskytovateľa. Fragmentované protokoly cez rôzne terminály. Bez pozorovateľnosti je ladenie metódou pokus-omyl.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
**Panel jednotných protokolov** 4 karty: Protokoly žiadostí, Protokoly proxy, Protokoly auditu, Konzola
- **Console Log Viewer** — Prehliadač v štýle terminálu v reálnom čase s farebne odlíšenými úrovňami, automatickým posúvaním, vyhľadávaním a filtrovaním
- **Proxy protokoly SQLite** — Trvalé protokoly, ktoré prežijú reštart servera
- **Translator Playground** 4 režimy ladenia: Playground (preklad formátu), Chat Tester (spiatočný), Test Bench (dávka), Live Monitor (v reálnom čase)
**Požiadať o telemetriu** latencia p50/p95/p99 + sledovanie X-request-Id
**Protokolovanie založené na súboroch s rotáciou** Konzolový zachytávač zachytáva všetko do protokolu JSON s rotáciou na základe veľkosti
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. „Nasadenie a údržba brány je zložitá“ </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Inštalácia, konfigurácia a údržba AI proxy v rôznych prostrediach (lokálne, VPS, Docker, cloud) je náročná na prácu. Problémy ako pevne zakódované cesty, `EACCES` v adresároch, konflikty portov a zostavy naprieč platformami zvyšujú trenie.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **Globálna inštalácia npm** — `npm install -g omniroute && omniroute`hotovo
- **Docker Multi-Platform** natívne AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Profily Docker Compose** — `base` (bez nástrojov CLI) a `cli` (s Claude Code, Codex, OpenClaw)
- **Electron Desktop App** natívna aplikácia pre Windows/macOS/Linux so systémovou lištou, automatickým spustením, offline režimom
- **Split-Port Mode** API a Dashboard na samostatných portoch pre pokročilé scenáre (reverzný proxy, kontajnerová sieť)
- **Cloud Sync** — Synchronizácia konfigurácie medzi zariadeniami cez Cloudflare Workers
- **DB Backups** — Automatické zálohovanie, obnovenie, export a import všetkých nastavení
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. „Rozhranie je len v angličtine a môj tím nehovorí po anglicky“ </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Tímy v neanglicky hovoriacich krajinách, najmä v Latinskej Amerike, Ázii a Európe, zápasia s rozhraním iba v angličtine. Jazykové bariéry znižujú prijatie a zvyšujú chyby v konfigurácii.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 jazykov** — Všetkých 500+ kláves preložených vrátane arabčiny, bulharčiny, dánčiny, nemčiny, španielčiny, fínčiny, francúzštiny, hebrejčiny, hindčiny, maďarčiny, indonézštiny, taliančiny, japončiny, kórejčiny, malajčiny, holandčiny, nórčiny, poľštiny, portugalčiny (PT/BR), rumunčiny, ruštiny, slovenčiny, švédčiny, thajčiny, ukrajinčiny, vietnamčiny, angličtiny
- **Podpora RTL** — Podpora sprava doľava pre arabčinu a hebrejčinu
- **Viacjazyčné README** — 30 kompletných prekladov dokumentácie
- **Language Selector** ikona zemegule v hlavičke pre prepínanie v reálnom čase
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. „Potrebujem viac ako chat potrebujem vloženie, obrázky, zvuk“</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI nie je len dokončenie chatu. Vývojári potrebujú generovať obrázky, prepisovať zvuk, vytvárať vloženia pre RAG, meniť hodnotenie dokumentov a moderovať obsah. Každé API má iný koncový bod a formát.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Vloženie** — `/v1/embeddings` so 6 poskytovateľmi a 9+ modelmi
- **Generácia obrazu** — `/v1/images/generations` s 10 poskytovateľmi a 20+ modelmi (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) a SD WebUI
- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Prepis zvuku** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 a + existujúci poskytovatelia
- **Moderácie** — `/v1/moderations` — Kontroly bezpečnosti obsahu
- **Zmena poradia** — `/v1/rerank` — Zmena poradia relevantnosti dokumentu
- **Responses API** plná podpora `/v1/responses` pre kódex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. „Nemám možnosť testovať a porovnávať kvalitu medzi modelmi“ </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Vývojári chcú vedieť, ktorý model je pre ich prípad použitia najlepší kód, preklad, zdôvodnenie ale manuálne porovnávanie je pomalé. Neexistujú žiadne integrované nástroje hodnotenia.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Hodnotenia LLM** testovanie zlatej sady s 10 predinštalovanými prípadmi zahŕňajúcimi pozdravy, matematiku, geografiu, generovanie kódu, súlad s JSON, preklad, označenie, odmietnutie bezpečnosti
- **4 stratégie zhody** — `exact`, `contains`, `regex`, `custom` (funkcia JS)
- **Testovacia lavica pre prekladateľské ihrisko** dávkové testovanie s viacerými vstupmi a očakávanými výstupmi, porovnanie medzi poskytovateľmi
- **Chat Tester** celý spiatočný výlet s vykresľovaním vizuálnej odozvy
- **Live Monitor** tok všetkých požiadaviek prechádzajúcich cez server proxy v reálnom čase
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. „Potrebujem škálovať bez straty výkonu“</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Keďže objem žiadostí rastie, bez ukladania rovnakých otázok do vyrovnávacej pamäte vznikajú duplicitné náklady. Bez idempotencie duplikát požaduje spracovanie odpadu. Musia sa dodržiavať limity sadzieb na poskytovateľa.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Sémantická vyrovnávacia pamäť** Dvojvrstvová vyrovnávacia pamäť (podpis + sémantická) znižuje náklady a latenciu
- **Idempotencia požiadavky** 5-sekundové deduplikačné okno pre identické požiadavky
**Detekcia limitu rýchlosti** RPM, minimálna medzera a maximálne súbežné sledovanie jednotlivých poskytovateľov
- **Upraviteľné limity frekvencie** Konfigurovateľné predvolené hodnoty v Nastaveniach → Odolnosť s perzistenciou
- **Cache na overenie kľúča API** — 3-vrstvová vyrovnávacia pamäť pre produkčný výkon
**Panel zdravia s telemetriou** latencia p50/p95/p99, štatistiky vyrovnávacej pamäte, doba prevádzky
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. „Chcem globálne ovládať správanie modelu“</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Vývojári, ktorí chcú všetky odpovede v konkrétnom jazyku, so špecifickým tónom alebo chcú obmedziť tokeny uvažovania. Konfigurovať to v každom nástroji/požiadavke je nepraktic.
**How OmniRoute solves it:**
**Ako to rieši OmniRoute:**
- **System Prompt Injection** Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **System Prompt Injection** Globálna výzva aplikovaná na všetky požiadavky
**Thinking Budget Validation** Zdôvodnenie riadenia prideľovania tokenov na žiadosť (priechodné, automatické, vlastné, adaptívne)
- **6 stratégií smerovania** — Globálne stratégie, ktoré určujú spôsob distribúcie požiadaviek
- **Wildcard Router** — Vzory `provider/*` smerujú dynamicky k akémukoľvek poskytovateľovi
- **Prepínač povoliť/zakázať kombo** — Prepínajte kombinácie priamo z ovládacieho panela
- **Provider Toggle** — Povolenie/zakázanie všetkých pripojení pre poskytovateľa jedným kliknutím
**Blokovaní poskytovatelia** vylúčte konkrétnych poskytovateľov zo zoznamu `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Potrebujem nástroje MCP ako prvotriedne možnosti produktu"</b></summary>
Mnohé brány AI odhaľujú MCP iba ako skrytý detail implementácie. Tímy potrebujú viditeľnú a spravovateľnú operačnú vrstvu.
**Ako to rieši OmniRoute:**
- MCP sa zobrazí na navigačnom paneli a na karte protokolu koncového bodu
- Vyhradená stránka správy MCP s procesmi, nástrojmi, rozsahmi a auditom
- Vstavaný rýchly štart pre `omniroute --mcp` a registráciu klienta
</details>
<details>
<summary><b>🧠 18. "Potrebujem orchestráciu A2A s cestami synchronizácie + streamovania"</b></summary>
Pracovné postupy agentov vyžadujú priame odpovede a dlhotrvajúce streamované vykonávanie s kontrolou životného cyklu.
**Ako to rieši OmniRoute:**
- Koncový bod A2A JSON-RPC (`POST /a2a`) s `message/send` a `message/stream`
- SSE streaming so šírením koncového stavu
- Rozhrania API životného cyklu úloh pre `tasks/get` a `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. „Potrebujem skutočné zdravie procesu MCP, nie uhádnutý stav“</b></summary>
Operačné tímy potrebujú vedieť, či je MCP skutočne nažive, nielen to, či je dostupné API.
**Ako to rieši OmniRoute:**
- Súbor srdcového tepu za behu s PID, časovými pečiatkami, transportom, počtom nástrojov a režimom rozsahu
- Stavové rozhranie MCP API, ktoré kombinuje srdcový tep + nedávnu aktivitu
- Stavové karty používateľského rozhrania pre sviežosť procesu / dostupnosti / tepu
</details>
<details>
<summary><b>📋 20. "Potrebujem auditovateľné spustenie nástroja MCP" </b></summary>
Keď nástroje mutujú konfiguráciu alebo spúšťajú akcie operácií, tímy potrebujú forenznú sledovateľnosť.
**Ako to rieši OmniRoute:**
- Záznamy auditu podporované SQLite pre volania nástrojov MCP
- Filtre podľa nástroja, úspechu/neúspechu, kľúča API a stránkovania
- Tabuľka auditu palubnej dosky + štatistické koncové body pre automatizáciu
</details>
<details>
<summary><b>🔐 21. "Potrebujem povolenia MCP v rozsahu na jednu integráciu"</b></summary>
Rôzni klienti by mali mať najmenej privilegovaný prístup ku kategóriám nástrojov.
**Ako to rieši OmniRoute:**
- 9 zrnitých rozsahov MCP pre kontrolovaný prístup k nástrojom
- Presadzovanie rozsahu a viditeľnosť v používateľskom rozhraní správy MCP
- Bezpečná východisková poloha pre prevádzkové nástroje
</details>
<details>
<summary><b>⚙️ 22. „Potrebujem prevádzkové ovládacie prvky bez premiestňovania“ </b></summary>
Tímy potrebujú rýchle zmeny runtime počas incidentov alebo nákladových udalostí.
**Ako to rieši OmniRoute:**
- Aktivácia komba prepínača priamo z ovládacieho panela MCP
- Použite profily odolnosti z preddefinovaných balíkov politík
- Resetujte stav ističa z rovnakého ovládacieho panela
</details>
<details>
<summary><b>🔄 23. „Potrebujem viditeľnosť a zrušenie životného cyklu úlohy A2A“ </b></summary>
Bez viditeľnosti životného cyklu sa incidenty úloh ťažko triedia.
**Ako to rieši OmniRoute:**
- Zoznam úloh / filtrovanie podľa stavu / zručnosti so stránkovaním
- Rozbalenie metadát úloh, udalostí a artefaktov
- Koncový bod zrušenia úlohy a akcia používateľského rozhrania s potvrdením
</details>
<details>
<summary><b>🌊 24. „Potrebujem aktívne metriky streamu pre načítanie A2A“</b></summary>
Streamovanie pracovných tokov vyžaduje operačný prehľad o súbežnosti a živých pripojeniach.
**Ako to rieši OmniRoute:**
- Aktívne počítadlá toku integrované do stavu A2A
- Časová pečiatka poslednej úlohy a počet jednotlivých štátov
- Karty palubnej dosky A2A na monitorovanie operácií v reálnom čase
</details>
<details>
<summary><b>🪪 25. "Potrebujem štandardné vyhľadávanie agentov pre klientov"</b></summary>
Externí klienti a orchestrátori potrebujú strojovo čitateľné metadáta na integráciu.
**Ako to rieši OmniRoute:**
- Karta agenta vystavená na `/.well-known/agent.json`
- Schopnosti a zručnosti zobrazené v používateľskom rozhraní správy
- API stavu A2A obsahuje metaúdaje zisťovania pre automatizáciu
</details>
<details>
<summary><b>🧭 26. "Potrebujem zistiteľnosť protokolu v UX produktu"</b></summary>
Ak používatelia nemôžu objaviť povrchy protokolov, kvalita prijatia a podpory klesá.
**Ako to rieši OmniRoute:**
- Položky na bočnom paneli pre MCP a A2A
- Koncový bod Karta Protokoly s rýchlym spustením a stavom
- Odkazy z prehľadu na špecializované riadiace panely
</details>
<details>
<summary><b>🧪 27. "Potrebujem komplexné overenie protokolu so skutočnými klientmi" </b></summary>
Falošné testy nestačia na overenie kompatibility protokolu pred vydaním.
**Ako to rieši OmniRoute:**
- E2E balík, ktorý spúšťa aplikáciu a využíva skutočný prenos klienta MCP SDK
- Klient A2A testuje toky zisťovania, odosielania, streamovania, získavania a rušenia
- Krížová kontrola tvrdení proti auditu MCP a API úloh A2A
</details>
<details>
<summary><b>📡 28. „Potrebujem jednotnú pozorovateľnosť naprieč všetkými rozhraniami“ </b></summary>
Rozdelenie pozorovateľnosti podľa protokolu vytvára slepé miesta a dlhšie MTTR.
**Ako to rieši OmniRoute:**
- Zjednotené informačné panely / protokoly / analýzy v jednom produkte
- Zdravie + audit + telemetria požiadaviek cez vrstvy OpenAI, MCP a A2A
- Operačné API pre stav a automatizáciu
</details>
<details>
<summary><b>💼 29. "Potrebujem jeden runtime pre proxy + nástroje + orchestráciu agentov" </b></summary>
Prevádzka mnohých samostatných služieb zvyšuje prevádzkové náklady a spôsoby zlyhania.
**Ako to rieši OmniRoute:**
- Proxy, server MCP a server A2A kompatibilný s OpenAI v jednom zásobníku
- Zdieľaná autentifikácia, odolnosť, ukladanie údajov a pozorovateľnosť
- Konzistentný model politiky na všetkých interakčných plochách
</details>
<details>
<summary><b>🚀 30. „Potrebujem odoslať agentské pracovné postupy bez roztiahnutia kódu lepidla“ </b></summary>
Tímy strácajú rýchlosť pri spájaní viacerých ad-hoc služieb a skriptov.
**Ako to rieši OmniRoute:**
- Jednotná stratégia koncových bodov pre klientov a agentov
- Vstavané používateľské rozhrania na správu protokolov a cesty overovania dymu
- Základy pripravené na výrobu (zabezpečenie, protokolovanie, odolnosť, zálohovanie)
</details>
### Príklady príručiek (integrované prípady použitia)
**Príručka A: Maximalizujte platené predplatné + lacné zálohovanie**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Príručka B: Balík kódovania s nulovými nákladmi**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Príručka C: 24/7 vždy zapnutý záložný reťazec**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Príručka D: Operačný program agenta s MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Rýchly štart
**1. Inštalovať globálne:**
@@ -506,7 +785,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -716,66 +995,26 @@ OmniRoute obsahuje výkonné vstavané ihrisko pre prekladateľov so **4 režima
</details>
---
## 🧪 Hodnotenia (Evals)
## 🎯 Prípady použitia
OmniRoute obsahuje vstavaný hodnotiaci rámec na testovanie kvality odozvy LLM oproti zlatému súboru. Prístup k nej získate cez **Analytics → Evals** na hlavnom paneli.
### Prípad 1: „Mám predplatné Claude Pro“
### Vstavaná zlatá súprava
**Problém:** Platnosť kvóty vyprší nevyužitá, obmedzenia sadzieb počas náročného kódovania
Predinštalovaná sada „OmniRoute Golden Set“ obsahuje 10 testovacích prípadov, ktoré zahŕňajú:
```
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)
- Pozdravy, matematika, geografia, generovanie kódu
- Súlad s formátom JSON, preklad, zníženie
- Bezpečnostné odmietnutie (škodlivý obsah), počítanie, booleovská logika
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Stratégie hodnotenia
### Prípad 2: „Chcem nulové náklady“
**Problém:** Nemôžem si dovoliť predplatné, potrebujem spoľahlivé kódovanie AI
```
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
```
### Prípad 3: „Potrebujem kódovanie 24/7, žiadne prerušenia“
**Problém:** Termíny, nemôžem si dovoliť prestoje
```
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
```
### Prípad 4: „Chcem AI ZDARMA v OpenClaw“
**Problém:** Potrebujete asistenta AI v aplikáciách na odosielanie správ, úplne zadarmo
```
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...
```
| Stratégia | Popis | Príklad |
| ---------- | ---------------------------------------------------------------------- | -------------------------------- |
| `exact` | Výstup sa musí presne zhodovať | `"4"` |
| `contains` | Výstup musí obsahovať podreťazec (nerozlišujú sa malé a veľké písmená) | `"Paris"` |
| `regex` | Výstup musí zodpovedať vzoru regulárneho výrazu | `"1.*2.*3"` |
| `custom` | Vlastná funkcia JS vracia true/false | `(output) => output.length > 10` |
---
@@ -1059,29 +1298,6 @@ Settings → API Configuration:
---
## 🧪 Hodnotenia (Evals)
OmniRoute obsahuje vstavaný hodnotiaci rámec na testovanie kvality odozvy LLM oproti zlatému súboru. Prístup k nej získate cez **Analytics → Evals** na hlavnom paneli.
### Vstavaná zlatá súprava
Predinštalovaná sada „OmniRoute Golden Set“ obsahuje 10 testovacích prípadov, ktoré zahŕňajú:
- Pozdravy, matematika, geografia, generovanie kódu
- Súlad s formátom JSON, preklad, zníženie
- Bezpečnostné odmietnutie (škodlivý obsah), počítanie, booleovská logika
### Stratégie hodnotenia
| Stratégia | Popis | Príklad |
| ---------- | ---------------------------------------------------------------------- | -------------------------------- |
| `exact` | Výstup sa musí presne zhodovať | `"4"` |
| `contains` | Výstup musí obsahovať podreťazec (nerozlišujú sa malé a veľké písmená) | `"Paris"` |
| `regex` | Výstup musí zodpovedať vzoru regulárneho výrazu | `"1.*2.*3"` |
| `custom` | Vlastná funkcia JS vracia true/false | `(output) => output.length > 10` |
---
## 🐛 Riešenie problémov
<details>
@@ -1133,13 +1349,13 @@ Predinštalovaná sada „OmniRoute Golden Set“ obsahuje 10 testovacích príp
- OmniRoute v1.0.6+ zahŕňa záložné overenie prostredníctvom dokončenia chatu
- Uistite sa, že základná adresa URL obsahuje príponu `/v1`
### 🔐 OAuth em Servidor Remoto (Vzdialené nastavenie OAuth)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ DÔLEŽITÉ pre používateľov s OmniRoute a diaľkovým ovládaním VPS/Docker/servidor**
### Od OAuth do Antigravity / Gemini CLI falha em servidores remotos?
### OAuth
Osvedčuje **Antigravity** a **Gemini CLI** používame **Google OAuth 2.0** ako autentifikáciu. O Google exige que a `redirect_uri` usada no fluxo OAuth saja **exatamente** uma das URI pre-kadastradas no Google Cloud Console to use.
@@ -1228,7 +1444,7 @@ Ak chcete získať prístup k dôvere, môžete použiť **príručku URL**:
---
## 🛠️ Tech Stack
## 🛠️
- **Runtime**: Node.js 1822 LTS (⚠️ Node.js 24+ nie je **podporovaný**`better-sqlite3` natívne binárne súbory sú nekompatibilné)
**Jazyk**: TypeScript 5.9 — **100 % TypeScript** v `src/` a `open-sse/` (v1.0.6)
@@ -1280,7 +1496,7 @@ Ak chcete získať prístup k dôvere, môžete použiť **príručku URL**:
---
## 🗺️ Cestovná mapa
## 🗺️
OmniRoute má naplánovaných **210+ funkcií** vo viacerých fázach vývoja. Tu sú kľúčové oblasti:
@@ -1305,18 +1521,6 @@ OmniRoute má naplánovaných **210+ funkcií** vo viacerých fázach vývoja. T
---
## 📧 Podpora
> 💬 **Pripojte sa k našej komunite!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Získajte pomoc, zdieľajte tipy a buďte informovaní.
- **Web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Problémy**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Pôvodný projekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Prispievatelia
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _Anslut alla AI-drivna IDE- eller CLI-verktyg via OmniRoute — gratis API-gatew
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Varför OmniRoute?
**Sluta slösa pengar och nå gränser:**
@@ -128,6 +157,18 @@ _Anslut alla AI-drivna IDE- eller CLI-verktyg via OmniRoute — gratis API-gatew
---
## 📧 Support
> 💬 **Gå med i vår community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Få hjälp, dela tips och håll dig uppdaterad.
- **Webbplats**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Frågor**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Originalprojekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Hur det fungerar
```
@@ -157,263 +198,497 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Vad OmniRoute löser — 30 verkliga smärtpunkter och användningsfall
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Varje utvecklare som använder AI-verktyg möter dessa problem dagligen.** OmniRoute byggdes för att lösa dem alla — från kostnadsöverskridanden till regionala block, från trasiga OAuth-flöden till protokolloperationer och observerbarhet i företag.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Jag betalar för ett dyrt abonnemang men blir ändå avbruten av limits" </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Utvecklare betalar $20200/månad för Claude Pro, Codex Pro eller GitHub Copilot. Även om du betalar har kvoten ett tak - 5 timmars användning, veckogränser eller gränser per minut. Mid-coding session, leverantören slutar svara och utvecklaren tappar flöde och produktivitet.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-lagers fallback** — Om prenumerationskvoten tar slut, omdirigeras automatiskt till API-nyckel → Billigt → Gratis med noll manuellt ingrepp
- **Kvotspårning i realtid** — Visar tokenförbrukning i realtid med återställningsnedräkning (5 timmar, dagligen, veckovis)
- **Multi-Account Support** — Flera konton per leverantör med automatisk round-robin — när ett tar slut, byter du till nästa
- **Anpassade kombinationer** — Anpassningsbara reservkedjor med 6 balanseringsstrategier (fill-first, round-robin, P2C, slumpmässig, minst använda, kostnadsoptimerad)
- **Codex Business Quotas** — Övervakning av företags-/teamarbetsutrymmeskvoter direkt i instrumentpanelen
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Jag måste använda flera leverantörer men alla har olika API" </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI använder ett format, Claude (Anthropic) använder ett annat, Gemini ännu ett annat. Om en utvecklare vill testa modeller från olika leverantörer eller fallback mellan dem måste de konfigurera om SDK:er, ändra slutpunkter, hantera inkompatibla format. Anpassade leverantörer (FriendLI, NIM) har icke-standardiserade modellslutpunkter.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** — En enda `http://localhost:20128/v1` fungerar som proxy för alla 36+ leverantörer
- **Formatöversättning** — Automatisk och transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Responssanering** — Tar bort icke-standardiserade fält (`x_groq`, `usage_breakdown`, `service_tier`) som bryter OpenAI SDK v1.83+
- **Rollnormalisering** — Konverterar `developer``system` för icke-OpenAI-leverantörer; `system``user` för GLM/ERNIE
- **Think Tag Extraction** — Extraherar `<think>`-block från modeller som DeepSeek R1 till standardiserade `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatisk konvertering
- **`stream` är standard till `false`** — Justerar med OpenAI-specifikationen, undviker oväntad SSE i Python/Rust/Go SDK:er
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Min AI-leverantör blockerar min region/land" </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Leverantörer som OpenAI/Codex blockerar åtkomst från vissa geografiska regioner. Användare får fel som `unsupported_country_region_territory` under OAuth- och API-anslutningar. Detta är särskilt frustrerande för utvecklare från utvecklingsländer.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-Level Proxy Config** — Konfigurerbar proxy 3 nivåer: global (all trafik), per leverantör (endast en leverantör) och per anslutning/nyckel
- **Färgkodade proxymärken** — Visuella indikatorer: 🟢 global proxy, 🟡 leverantörsproxy, 🔵 anslutningsproxy, visar alltid IP:n
- **OAuth Token Exchange Through Proxy** — OAuth-flödet går också genom proxyn, vilket löser `unsupported_country_region_territory`
- **Anslutningstester via proxy** — Anslutningstester använder den konfigurerade proxyn (ingen mer direkt förbikoppling)
- **SOCKS5-stöd** — Fullständigt SOCKS5-proxystöd för utgående routing
- **TLS Fingerprint Spoofing** — Webbläsarliknande TLS-fingeravtryck via `wreq-js` för att kringgå botdetektering
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Jag vill använda AI för kodning men jag har inga pengar" </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Alla kan inte betala $20200/månad för AI-prenumerationer. Studenter, utvecklare från tillväxtländer, hobbyister och frilansare behöver tillgång till kvalitetsmodeller utan kostnad.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Gratis leverantörer inbyggda** — Inbyggt stöd för 100 % gratis leverantörer: iFlow (8 obegränsade modeller), Qwen (3 obegränsade modeller), Kiro (Claude gratis), Gemini CLI (180K/månad gratis)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/månad utan stilleståndstid
- **NVIDIA NIM gratis krediter** — 1000 gratis krediter integrerade
- **Kostnadsoptimerad strategi** — Routingstrategi som automatiskt väljer den billigaste tillgängliga leverantören
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Jag behöver skydda min AI-gateway från obehörig åtkomst" </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
När du exponerar en AI-gateway för nätverket (LAN, VPS, Docker) kan vem som helst med adressen konsumera utvecklarens tokens/kvot. Utan skydd är API:er sårbara för missbruk, snabb injektion och missbruk.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API Key Management** — Generering, rotation och omfattning per leverantör med en dedikerad `/dashboard/api-manager`-sida
- **Behörigheter på modellnivå** — Begränsa API-nycklar till specifika modeller (`openai/*`, jokerteckenmönster), med växlaren Tillåt allt/Begränsa
- **API Endpoint Protection** — Kräv en nyckel för `/v1/models` och blockera specifika leverantörer från listan
- **Auth Guard + CSRF Protection** — Alla instrumentpanelsrutter skyddade med `withAuth` middleware + CSRF-tokens
- **Rate Limiter** — Per-IP-hastighetsbegränsning med konfigurerbara fönster
- **IP-filtrering** — Tillåtelselista/blockeringslista för åtkomstkontroll
- **Prompt Injection Guard** — Sanering mot skadliga promptmönster
- **AES-256-GCM-kryptering** — Autentiseringsuppgifter krypterade i vila
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Min leverantör gick ner och jag tappade mitt kodningsflöde" </b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI-leverantörer kan bli instabila, returnera 5xx-fel eller nå tillfälliga hastighetsgränser. Om en utvecklare är beroende av en enskild leverantör avbryts de. Utan strömbrytare kan upprepade försök krascha programmet.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Circuit Breaker per leverantör** — Autoöppning/stängning med konfigurerbara trösklar och nedkylning (stängd/öppen/halvöppen)
- **Exponentiell backoff** — Progressiva fördröjningar igen
- **Anti-Thundering Herd** — Mutex + semaforskydd mot samtidiga stormar igen
- **Combo reservkedjor** — Om den primära leverantören misslyckas, faller den automatiskt genom kedjan utan ingrepp
- **Combo Circuit Breaker** - Inaktiverar automatiskt felande leverantörer inom en kombinationskedja
- **Health Dashboard** — Drifttidsövervakning, strömbrytartillstånd, låsningar, cachestatistik, p50/p95/p99 latens
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Att konfigurera varje AI-verktyg är tråkigt och repetitivt" </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Utvecklare använder Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Varje verktyg behöver en annan konfiguration (API-slutpunkt, nyckel, modell). Att konfigurera om när man byter leverantör eller modell är ett slöseri med tid.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI Tools Dashboard** — Dedikerad sida med ett-klicksinställningar för Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Genererar `chatLanguageModels.json` för VS-kod med bulkmodellval
- **Onboarding Wizard** — Guidad 4-stegs installation för förstagångsanvändare
- **En slutpunkt, alla modeller** — Konfigurera `http://localhost:20128/v1` en gång, få tillgång till 36+ leverantörer
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Hantera OAuth-tokens från flera leverantörer är ett helvete" </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — alla använder OAuth 2.0 med utgående tokens. Utvecklare måste autentisera på nytt hela tiden, hantera `client_secret is missing`, `redirect_uri_mismatch` och fel på fjärrservrar. OAuth LAN/VPS är särskilt problematiskt.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Automatisk uppdatering av token** — OAuth-tokens uppdateras i bakgrunden innan de löper ut
- **OAuth 2.0 (PKCE) Inbyggd** — Automatiskt flöde för Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Flera konton per leverantör via JWT/ID-tokenextraktion
- **OAuth LAN/Remote Fix** — Privat IP-detektering för `redirect_uri` + manuellt URL-läge för fjärrservrar
- **OAuth Behind Nginx** — Använder `window.location.origin` för omvänd proxykompatibilitet
- **Remote OAuth Guide** — Steg-för-steg-guide för Google Cloud-uppgifter på VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Jag vet inte hur mycket jag spenderar eller var" </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Utvecklare använder flera betalleverantörer men har ingen enhetlig syn på utgifter. Varje leverantör har sin egen faktureringspanel, men det finns ingen konsoliderad vy. Oväntade kostnader kan hopa sig.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Kostnadsanalysinstrumentpanel** — Kostnadsspårning per token och budgethantering per leverantör
- **Budgetgränser per nivå** — Utgiftstak per nivå som utlöser automatisk reserv
- **Priskonfiguration per modell** — Konfigurerbara priser per modell
- **Användningsstatistik per API-nyckel** — Antal förfrågningar och senast använda tidsstämpel per nyckel
- **Analytics Dashboard** — Statistikkort, modellanvändningsdiagram, leverantörstabell med framgångsfrekvens och latens
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Jag kan inte diagnostisera fel och problem i AI-samtal" </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
När ett samtal misslyckas vet inte utvecklaren om det var en hastighetsgräns, utgången token, fel format eller leverantörsfel. Fragmenterade loggar över olika terminaler. Utan observerbarhet är felsökning att trial-and-error.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Unified Logs Dashboard** — 4 flikar: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Viewer i realtid i terminalstil med färgkodade nivåer, automatisk rullning, sökning, filtrering
- **SQLite Proxy-loggar** — Beständiga loggar som överlever serverstarter
- **Translator Playground** — 4 felsökningslägen: Playground (formatöversättning), Chat Tester (tur och retur), Testbänk (batch), Live Monitor (realtid)
- **Request Telemetri** — p50/p95/p99 latens + X-Request-Id-spårning
- **Filbaserad loggning med rotation** — Konsolinterceptor fångar allt till JSON-logg med storleksbaserad rotation
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Det är komplext att distribuera och underhålla gatewayen" </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Att installera, konfigurera och underhålla en AI-proxy i olika miljöer (lokalt, VPS, Docker, moln) är arbetskrävande. Problem som hårdkodade sökvägar, `EACCES` på kataloger, portkonflikter och plattformsoberoende konstruktioner ger friktion.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm global installation** — `npm install -g omniroute && omniroute`klar
- **Docker Multi-Platform** — AMD64 + ARM64 inbyggt (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (inga CLI-verktyg) och `cli` (med Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Inbyggd app för Windows/macOS/Linux med systemfältet, autostart, offlineläge
- **Split-Port Mode** — API och Dashboard separata portar för avancerade scenarier (omvänd proxy, containernätverk)
- **Cloud Sync** — Konfigurera synkronisering mellan enheter via Cloudflare Workers
- **DB-säkerhetskopior** — Automatisk säkerhetskopiering, återställning, export och import av alla inställningar
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Gränssnittet är endast engelska och mitt team talar inte engelska" </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Lag i icke-engelsktalande länder, särskilt i Latinamerika, Asien och Europa, kämpar med enbart engelska gränssnitt. Språkbarriärer minskar användningen och ökar konfigurationsfelen.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Dashboard i18n — 30 språk** — Alla 500+ nycklar översatta, inklusive arabiska, bulgariska, danska, tyska, spanska, finska, franska, hebreiska, hindi, ungerska, indonesiska, italienska, japanska, koreanska, malaysiska, holländska, norska, polska, portugisiska (PT/BR), rumänska, ryska, thailändska, ukrainska, ukrainska, kinesiska, engelska, ukrainska, vietnamesiska, ukrainska, svenska, ukrainska
- **RTL-stöd** — Höger-till-vänster-stöd för arabiska och hebreiska
- **Multi-Language READMEs** — 30 fullständiga dokumentationsöversättningar
- **Språkväljare** — Globikon i rubriken för växling i realtid
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Jag behöver mer än chattjag behöver inbäddningar, bilder, ljud"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI är inte bara att slutföra chatt. Utvecklare måste generera bilder, transkribera ljud, skapa inbäddningar för RAG, ranka om dokument och moderera innehåll. Varje API har olika slutpunkt och format.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Inbäddningar** — `/v1/embeddings` med 6 leverantörer och 9+ modeller
- **Bildgenerering** — `/v1/images/generations` med 10 leverantörer och 20+ modeller (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Text-till-video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) och SD WebUI
- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Ljudtranskription** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Text-till-tal** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + befintliga leverantörer
- **Moderationer** — `/v1/moderations` — Innehållssäkerhetskontroller
- **Omrankning** — `/v1/rerank` — Omrankning av dokumentrelevans
- **Responses API** — Fullständigt `/v1/responses`-stöd för Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Jag har inget sätt att testa och jämföra kvalitet mellan olika modeller" </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Utvecklare vill veta vilken modell som är bäst för deras användningsfall - kod, översättning, resonemang - men det går långsamt att jämföra manuellt. Det finns inga integrerade utvärderingsverktyg.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM-utvärderingar** — Golden set-testning med 10 förinstallerade fall som täcker hälsningar, matematik, geografi, kodgenerering, JSON-efterlevnad, översättning, markdown, säkerhetsvägran
- **4 matchningsstrategier** — `exact`, `contains`, `regex`, `custom` (JS-funktion)
- **Translator Playground Test Bench** — Batchtestning med flera ingångar och förväntade utgångar, jämförelse mellan olika leverantörer
- **Chatttestare** — Fullständig tur och retur med visuell responsåtergivning
- **Live Monitor** — Realtidsström av alla förfrågningar som flödar genom proxyn
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Jag behöver skala utan att förlora prestanda" </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
När förfrågningsvolymen ökar, utan att cachelagra genererar samma frågor dubbla kostnader. Utan idempotens, dubbletter begär avfallshantering. Prisgränser per leverantör måste respekteras.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in SettingsResilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Semantisk cache** — Tvåskiktscache (signatur + semantisk) minskar kostnaden och fördröjningen
- **Request Idempotency** — 5s dedupliceringsfönster för identiska förfrågningar
- **Rate Limit Detection** — RPM per leverantör, min gap och max samtidig spårning
- **Redigerbara hastighetsgränser** — Konfigurerbara standardinställningar i InställningarMotståndskraft med uthållighet
- **API Key Validation Cache** — 3-lagers cache för produktionsprestanda
- **Hälsoinstrumentpanel med telemetri** — p50/p95/p99 latens, cachestatistik, drifttid
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Jag vill kontrollera modellens beteende globalt" </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Utvecklare som vill ha alla svar på ett specifikt språk, med en specifik ton, eller som vill begränsa resonemangstokens. Att konfigurera detta i varje verktyg/förfrågan är opraktiskt.
**How OmniRoute solves it:**
**Hur OmniRoute löser det:**
- **System Prompt Injection** — Global prompt applied to all requests
- **System Prompt Injection** — Global prompt tillämpas på alla förfrågningar
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **6 routingstrategier** — Globala strategier som avgör hur förfrågningar distribueras
- **Wildcard Router** — `provider/*`-mönster dirigerar dynamiskt till vilken leverantör som helst
- **Kombo Aktivera/Inaktivera Växla** — Växla kombinationer direkt från instrumentpanelen
- **Visa leverantör** — Aktivera/inaktivera alla anslutningar för en leverantör med ett klick
- **Blockerade leverantörer** — Uteslut specifika leverantörer från `/v1/models`-listan
</details>
<details>
<summary><b>🧰 17. "Jag behöver MCP-verktyg som förstklassiga produktegenskaper" </b></summary>
Många AI-gateways exponerar MCP endast som en dold implementeringsdetalj. Team behöver ett synligt, hanterbart driftlager.
**Hur OmniRoute löser det:**
- MCP visas på navigeringspanelen och fliken för slutpunktsprotokoll
- Dedikerad MCP-hanteringssida med process, verktyg, omfattningar och revision
- Inbyggd snabbstart för `omniroute --mcp` och klientintroduktion
</details>
<details>
<summary><b>🧠 18. "Jag behöver A2A-orkestrering med synkronisering + strömningsuppgiftsvägar" </b></summary>
Agentarbetsflöden kräver både direkta svar och långvarig streamad exekvering med livscykelkontroll.
**Hur OmniRoute löser det:**
- A2A JSON-RPC-ändpunkt (`POST /a2a`) med `message/send` och `message/stream`
- SSE-strömning med terminaltillståndspridning
- Task lifecycle API:er för `tasks/get` och `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Jag behöver riktig MCP-processhälsa, inte gissad status" </b></summary>
Operativa team måste veta om MCP faktiskt lever, inte bara om ett API är tillgängligt.
**Hur OmniRoute löser det:**
- Runtime heartbeat-fil med PID, tidsstämplar, transport, verktygsräkning och scope-läge
- MCP status API som kombinerar hjärtslag + senaste aktivitet
- UI-statuskort för process/upptid/hjärtslagsnyhet
</details>
<details>
<summary><b>📋 20. "Jag behöver revisionsbart MCP-verktygsexekvering" </b></summary>
När verktyg muterar konfiguration eller utlöser operationsåtgärder behöver team rättsmedicinsk spårbarhet.
**Hur OmniRoute löser det:**
- SQLite-stödd revisionsloggning för MCP-verktygsanrop
- Filtrerar efter verktyg, framgång/misslyckande, API-nyckel och paginering
- Dashboard revisionstabell + statistikslutpunkter för automatisering
</details>
<details>
<summary><b>🔐 21. "Jag behöver scoped MCP-behörigheter per integration" </b></summary>
Olika klienter bör ha minst privilegierad åtkomst till verktygskategorier.
**Hur OmniRoute löser det:**
- 9 granulära MCP-scopes för kontrollerad verktygsåtkomst
- Tillämpning av omfattning och synlighet i MCP-hanteringsgränssnitt
- Säker standardställning för operativa verktyg
</details>
<details>
<summary><b>⚙️ 22. "Jag behöver driftskontroller utan att omdistribuera" </b></summary>
Team behöver snabba körtidsförändringar under incidenter eller kostnadshändelser.
**Hur OmniRoute löser det:**
- Växla kombinationsaktivering direkt från MCP-instrumentpanelen
- Tillämpa motståndskraftsprofiler från fördefinierade policypaket
- Återställ strömbrytarens tillstånd från samma manöverpanel
</details>
<details>
<summary><b>🔄 23. "I need live A2A task lifecycle synibility and cancellation"</b></summary>
Utan livscykelsynlighet blir uppgiftsincidenter svåra att triage.
**Hur OmniRoute löser det:**
- Uppgiftslista/filtrering efter stat/färdighet med sidnumrering
- Drill down på uppgiftens metadata, händelser och artefakter
- Slutpunkt för annullering av uppgifter och gränssnittsåtgärd med bekräftelse
</details>
<details>
<summary><b>🌊 24. "Jag behöver mätvärden för aktiv strömning för A2A-laddning" </b></summary>
Strömmande arbetsflöden kräver operativ insikt i samtidighet och direktanslutningar.
**Hur OmniRoute löser det:**
- Aktiva strömräknare integrerade i A2A-status
- Tidsstämpel för senaste uppgift och antal per stat
- A2A instrumentpanelskort för operationsövervakning i realtid
</details>
<details>
<summary><b>🪪 25. "Jag behöver standardagentupptäckt för klienter" </b></summary>
Externa klienter och orkestratorer behöver maskinläsbar metadata för onboarding.
**Hur OmniRoute löser det:**
- Agentkort exponerat på `/.well-known/agent.json`
- Förmåga och färdigheter som visas i ledningsgränssnittet
- A2A status API inkluderar upptäcktsmetadata för automatisering
</details>
<details>
<summary><b>🧭 26. "Jag behöver protokollupptäckbarhet i produktens UX" </b></summary>
Om användare inte kan upptäcka protokollytor, sjunker kvaliteten på adoption och support.
**Hur OmniRoute löser det:**
- Sidofältsposter för MCP och A2A
- Slutpunktssida Protokoll-fliken med snabbstart och status
- Länkar från översikt till dedikerade hanteringspaneler
</details>
<details>
<summary><b>🧪 27. "Jag behöver end-to-end protokollvalidering med riktiga klienter" </b></summary>
Mock-tester räcker inte för att validera protokollkompatibilitet före release.
**Hur OmniRoute löser det:**
- E2E-svit som startar appen och använder riktig MCP SDK-klienttransport
- A2A-klient testar för upptäckt, skicka, streama, hämta och avbryta flöden
- Korskontrollera påståenden mot MCP-revision och A2A-uppgifter API:er
</details>
<details>
<summary><b>📡 28. "Jag behöver enhetlig observerbarhet över alla gränssnitt" </b></summary>
Att dela upp observerbarheten enligt protokoll skapar blinda fläckar och längre MTTR.
**Hur OmniRoute löser det:**
- Enhetliga instrumentpaneler/loggar/analyser i en produkt
- Hälsa + revision + begäran om telemetri över OpenAI-, MCP- och A2A-lager
- Operativa API:er för status och automatisering
</details>
<details>
<summary><b>💼 29. "Jag behöver en körtid för proxy + verktyg + agentorkestrering" </b></summary>
Att köra många separata tjänster ökar driftskostnaderna och fellägen.
**Hur OmniRoute löser det:**
- OpenAI-kompatibel proxy, MCP-server och A2A-server i en stack
- Delad autentisering, resiliens, datalagring och observerbarhet
- Konsekvent policymodell över alla interaktionsytor
</details>
<details>
<summary><b>🚀 30. "Jag behöver skicka agentiska arbetsflöden utan limkodsprawl" </b></summary>
Lag tappar hastighet när de sammanfogar flera ad-hoc-tjänster och skript.
**Hur OmniRoute löser det:**
- Enhetlig slutpunktsstrategi för kunder och agenter
- Inbyggda gränssnitt för protokollhantering och rökvalideringsvägar
- Produktionsfärdiga grunder (säkerhet, loggning, resiliens, backup)
</details>
### Exempel på Playbooks (integrerade användningsfall)
**Playbook A: Maximera betald prenumeration + billig backup**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Noll-kostnad kodningsstack**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: 24/7 alltid-på reservkedja**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Agent ops med MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Snabbstart
**1. Installera globalt:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -589,6 +864,7 @@ npm run electron:build:linux # Linux (.AppImage)
| Funktion | Vad det gör |
| -------------------------------------- | --------------------------------------------------------------------------------- |
| 🔌 **Circuit Breaker** | Autoöppna/stäng per leverantör med konfigurerbara trösklar |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| 🛡️ **Anti-ånflock** | Mutex + semaforhastighetsgräns för API-nyckelleverantörer |
| 🧠 **Semantisk cache** | Tvåskiktscache (signatur + semantisk) minskar kostnaden och fördröjningen |
| ⚡ **Begär idempotens** | 5s dedup-fönster för dubblettförfrågningar |
@@ -715,66 +991,26 @@ OmniRoute inkluderar en kraftfull inbyggd översättarlekplats med **4 lägen**
</details>
---
## 🧪 Utvärderingar (Evals)
## 🎯 Användningsfall
OmniRoute inkluderar ett inbyggt utvärderingsramverk för att testa LLM-svarskvalitet mot en gyllene uppsättning. Få åtkomst till det via **Analytics → Evals** i instrumentpanelen.
### Fall 1: "Jag har Claude Pro-abonnemang"
### Inbyggt gyllene set
**Problem:** Kvoten går ut oanvänd, hastighetsgränser under tung kodning
Det förinstallerade "OmniRoute Golden Set" innehåller 10 testfall som täcker:
```
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)
- Hälsningar, matematik, geografi, kodgenerering
- JSON-formatöverensstämmelse, översättning, markdown
- Säkerhetsvägran (skadligt innehåll), räkning, boolesk logik
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Utvärderingsstrategier
### Fall 2: "Jag vill ha noll kostnad"
**Problem:** Har inte råd med prenumerationer, behöver pålitlig AI-kodning
```
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
```
### Fall 3: "Jag behöver kodning dygnet runt, inga avbrott"
**Problem:** Deadlines, har inte råd med driftstopp
```
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
```
### Fall 4: "Jag vill ha GRATIS AI i OpenClaw"
**Problem:** Behöver AI-assistent i meddelandeappar, helt gratis
```
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...
```
| Strategi | Beskrivning | Exempel |
| ---------- | ---------------------------------------------------- | -------------------------------- |
| `exact` | Utdata måste matcha exakt | `"4"` |
| `contains` | Utdata måste innehålla delsträng (skiftlägeskänslig) | `"Paris"` |
| `regex` | Utdata måste matcha regexmönster | `"1.*2.*3"` |
| `custom` | Anpassad JS-funktion returnerar true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Utvärderingar (Evals)
OmniRoute inkluderar ett inbyggt utvärderingsramverk för att testa LLM-svarskvalitet mot en gyllene uppsättning. Få åtkomst till det via **Analytics → Evals** i instrumentpanelen.
### Inbyggt gyllene set
Det förinstallerade "OmniRoute Golden Set" innehåller 10 testfall som täcker:
- Hälsningar, matematik, geografi, kodgenerering
- JSON-formatöverensstämmelse, översättning, markdown
- Säkerhetsvägran (skadligt innehåll), räkning, boolesk logik
### Utvärderingsstrategier
| Strategi | Beskrivning | Exempel |
| ---------- | ---------------------------------------------------- | -------------------------------- |
| `exact` | Utdata måste matcha exakt | `"4"` |
| `contains` | Utdata måste innehålla delsträng (skiftlägeskänslig) | `"Paris"` |
| `regex` | Utdata måste matcha regexmönster | `"1.*2.*3"` |
| `custom` | Anpassad JS-funktion returnerar true/false | `(output) => output.length > 10` |
---
## 🐛 Felsökning
<details>
@@ -1132,7 +1345,7 @@ Det förinstallerade "OmniRoute Golden Set" innehåller 10 testfall som täcker:
- OmniRoute v1.0.6+ inkluderar reservvalidering via chattslutföranden
- Se till att baswebbadressen innehåller suffixet `/v1`
### 🔐 OAuth em Servidor Remoto (Remote OAuth Setup)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
@@ -1227,7 +1440,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **Körtid**: Node.js 1822 LTS (⚠️ Node.js 24+ stöds **inte**`better-sqlite3` inbyggda binärer är inkompatibla)
- **Språk**: TypeScript 5.9 — **100 % TypeScript** över `src/` och `open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Färdkarta
## 🗺️
OmniRoute har **210+ funktioner planerade** över flera utvecklingsfaser. Här är nyckelområdena:
@@ -1304,18 +1517,6 @@ OmniRoute har **210+ funktioner planerade** över flera utvecklingsfaser. Här
---
## 📧 Support
> 💬 **Gå med i vår community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Få hjälp, dela tips och håll dig uppdaterad.
- **Webbplats**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Frågor**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Originalprojekt**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Bidragsgivare
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _เชื่อมต่อเครื่องมือ IDE หรือ CLI
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 ทำไมต้อง OmniRoute?
**หยุดเสียเงินและจำกัดขีดจำกัด:**
@@ -128,6 +157,18 @@ _เชื่อมต่อเครื่องมือ IDE หรือ CLI
---
## 📧 สนับสนุน
> 💌 **เข้าร่วมชุมชนของเรา!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — รับความช่วยเหลือ แบ่งปันเคล็ดลับ และติดตามข่าวสารล่าสุด
- **เว็บไซต์**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **ปัญหา**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **โปรเจ็กต์ดั้งเดิม**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 มันทำงานอย่างไร
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 สิ่งที่ OmniRoute แก้ปัญหาได้ — 30 คะแนนปัญหาและกรณีการใช้งานจริง
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **นักพัฒนาทุกคนที่ใช้เครื่องมือ AI ต้องเผชิญกับปัญหาเหล่านี้ทุกวัน** OmniRoute ถูกสร้างขึ้นเพื่อแก้ไขปัญหาทั้งหมด ตั้งแต่ค่าใช้จ่ายที่มากเกินไปไปจนถึงการบล็อกระดับภูมิภาค จากโฟลว์ OAuth ที่เสียหาย ไปจนถึงการทำงานของโปรโตคอลและความสามารถในการสังเกตระดับองค์กร
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "ฉันจ่ายค่าสมัครสมาชิกราคาแพงแต่ยังคงถูกขัดจังหวะด้วยขีดจำกัด"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
นักพัฒนาจ่ายเงิน $20200/เดือนสำหรับ Claude Pro, Codex Pro หรือ GitHub Copilot แม้จะจ่ายเงิน โควต้าก็มีเพดาน — การใช้งาน 5 ชม. ขีดจำกัดรายสัปดาห์ หรือขีดจำกัดอัตราต่อนาที เซสชันการเข้ารหัสกลาง ผู้ให้บริการหยุดการตอบสนอง และนักพัฒนาสูญเสียความลื่นไหลและประสิทธิภาพการทำงาน
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **ทางเลือกสำรองอัจฉริยะ 4 ระดับ** — หากโควต้าการสมัครสมาชิกหมด จะเปลี่ยนเส้นทางไปยังคีย์ API → ราคาถูก → ฟรีโดยไม่มีการแทรกแซงด้วยตนเอง
- **การติดตามโควต้าแบบเรียลไทม์** — แสดงการใช้โทเค็นแบบเรียลไทม์พร้อมการนับถอยหลังการรีเซ็ต (5 ชม. รายวัน รายสัปดาห์)
- **การสนับสนุนหลายบัญชี** — หลายบัญชีต่อผู้ให้บริการพร้อมการหมุนเวียนอัตโนมัติ — เมื่อบัญชีหนึ่งหมด ให้สลับไปยังบัญชีถัดไป
- **คอมโบแบบกำหนดเอง** — ห่วงโซ่ทางเลือกที่ปรับแต่งได้พร้อมกลยุทธ์การปรับสมดุล 6 แบบ (เติมก่อน, ปัดเศษ, P2C, สุ่ม, ใช้น้อยที่สุด, ปรับต้นทุนให้เหมาะสม)
- **โควต้าธุรกิจ Codex** — การตรวจสอบโควต้าพื้นที่ทำงานของธุรกิจ/ทีมโดยตรงในแดชบอร์ด
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "ฉันจำเป็นต้องใช้ผู้ให้บริการหลายราย แต่แต่ละรายมี API ที่แตกต่างกัน"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI ใช้รูปแบบหนึ่ง Claude (Anthropic) ใช้อีกรูปแบบหนึ่ง Gemini ยังใช้อีกรูปแบบหนึ่ง หากผู้พัฒนาต้องการทดสอบโมเดลจากผู้ให้บริการหลายรายหรือทางเลือกระหว่างผู้ให้บริการ พวกเขาจำเป็นต้องกำหนดค่า SDK ใหม่ เปลี่ยนตำแหน่งข้อมูล และจัดการกับรูปแบบที่เข้ากันไม่ได้ ผู้ให้บริการแบบกำหนดเอง (FriendLI, NIM) มีจุดสิ้นสุดโมเดลที่ไม่ได้มาตรฐาน
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Unified Endpoint** — `http://localhost:20128/v1` เดียวทำหน้าที่เป็นพร็อกซีสำหรับผู้ให้บริการมากกว่า 36 ราย
- **การแปลรูปแบบ** — อัตโนมัติและโปร่งใส: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **การฆ่าเชื้อการตอบสนอง** — ตัดช่องที่ไม่ได้มาตรฐาน (`x_groq`, `usage_breakdown`, `service_tier`) ที่ทำลาย OpenAI SDK v1.83+
- **การปรับบทบาทให้เป็นมาตรฐาน** — แปลง `developer``system` สำหรับผู้ให้บริการที่ไม่ใช่ OpenAI `system``user` สำหรับ GLM/ERNIE
- **คิดการแยกแท็ก** — แยกบล็อก `<think>` จากรุ่นอย่าง DeepSeek R1 ให้เป็น `reasoning_content` ที่ได้มาตรฐาน
- **เอาต์พุตที่มีโครงสร้างสำหรับราศีเมถุน** — `json_schema``responseMimeType`/`responseSchema` การแปลงอัตโนมัติ
- **`stream` มีค่าเริ่มต้นเป็น `false`** — สอดคล้องกับข้อกำหนด OpenAI หลีกเลี่ยง SSE ที่ไม่คาดคิดใน Python/Rust/Go SDK
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "ผู้ให้บริการ AI ของฉันบล็อกภูมิภาค/ประเทศของฉัน"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
ผู้ให้บริการเช่น OpenAI/Codex บล็อกการเข้าถึงจากภูมิภาคทางภูมิศาสตร์บางแห่ง ผู้ใช้ได้รับข้อผิดพลาดเช่น `unsupported_country_region_territory` ในระหว่างการเชื่อมต่อ OAuth และ API สิ่งนี้น่าหงุดหงิดเป็นพิเศษสำหรับนักพัฒนาจากประเทศกำลังพัฒนา
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **การกำหนดค่าพร็อกซี 3 ระดับ** — พร็อกซีที่กำหนดค่าได้ 3 ระดับ: ทั่วโลก (การรับส่งข้อมูลทั้งหมด) ต่อผู้ให้บริการ (ผู้ให้บริการรายเดียวเท่านั้น) และต่อการเชื่อมต่อ/คีย์
- **ป้ายพร็อกซีที่ใช้รหัสสี** — ตัวบ่งชี้ภาพ: 🟢 พร็อกซีส่วนกลาง, 🟡 พร็อกซีผู้ให้บริการ, 🔵 พร็อกซีการเชื่อมต่อ แสดง IP เสมอ
- **การแลกเปลี่ยนโทเค็น OAuth ผ่านพร็อกซี** — โฟลว์ OAuth ยังต้องผ่านพร็อกซีด้วย การแก้ปัญหา `unsupported_country_region_territory`
- **การทดสอบการเชื่อมต่อผ่านพร็อกซี** — การทดสอบการเชื่อมต่อใช้พร็อกซีที่กำหนดค่าไว้ (ไม่มีการบายพาสโดยตรงอีกต่อไป)
- **รองรับ SOCKS5** — รองรับพร็อกซี SOCKS5 เต็มรูปแบบสำหรับการกำหนดเส้นทางขาออก
- **การปลอมแปลงลายนิ้วมือ TLS** — ลายนิ้วมือ TLS เหมือนเบราว์เซอร์ผ่าน `wreq-js` เพื่อเลี่ยงการตรวจจับบอท
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "ฉันต้องการใช้ AI ในการเขียนโค้ด แต่ไม่มีเงิน"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
ไม่ใช่ทุกคนที่สามารถจ่าย $20200/เดือน สำหรับการสมัครสมาชิก AI นักศึกษา นักพัฒนาจากประเทศเกิดใหม่ ผู้ที่สมัครเล่น และฟรีแลนซ์ต้องการเข้าถึงโมเดลคุณภาพโดยไม่มีค่าใช้จ่าย
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **ผู้ให้บริการ Tier ฟรีในตัว** — รองรับเนทิฟสำหรับผู้ให้บริการฟรี 100%: iFlow (8 รุ่นไม่จำกัด), Qwen (3 รุ่นไม่จำกัด), Kiro (Claude ฟรี), Gemini CLI (ฟรี 180K/เดือน)
- **คอมโบฟรีเท่านั้น** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/เดือน โดยไม่มีการหยุดทำงาน
- **เครดิตฟรี NVIDIA NIM** — รวมเครดิตฟรี 1,000 รายการ
- **กลยุทธ์การปรับต้นทุนให้เหมาะสม** — กลยุทธ์การกำหนดเส้นทางที่จะเลือกผู้ให้บริการที่ถูกที่สุดที่มีอยู่โดยอัตโนมัติ
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "ฉันต้องปกป้องเกตเวย์ AI ของฉันจากการเข้าถึงที่ไม่ได้รับอนุญาต"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
เมื่อเปิดเผยเกตเวย์ AI ไปยังเครือข่าย (LAN, VPS, Docker) ใครก็ตามที่มีที่อยู่จะสามารถใช้โทเค็น/โควต้าของนักพัฒนาได้ หากไม่มีการป้องกัน API ก็เสี่ยงต่อการถูกนำไปใช้ในทางที่ผิด การแทรกทันที และการละเมิด
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **การจัดการคีย์ API** — การสร้าง การหมุนเวียน และการกำหนดขอบเขตต่อผู้ให้บริการด้วยเพจ `/dashboard/api-manager` เฉพาะ
- **การอนุญาตระดับโมเดล** — จำกัดคีย์ API ให้กับโมเดลเฉพาะ (`openai/*` รูปแบบไวด์การ์ด) พร้อมสลับอนุญาตทั้งหมด/จำกัด
- **การป้องกันปลายทาง API** — ต้องใช้รหัสสำหรับ `/v1/models` และบล็อกผู้ให้บริการบางรายจากรายการ
- **Auth Guard + การป้องกัน CSRF** — เส้นทางแดชบอร์ดทั้งหมดที่ได้รับการป้องกันด้วยมิดเดิลแวร์ `withAuth` + โทเค็น CSRF
- **ตัวจำกัดอัตรา** — การจำกัดอัตราต่อ IP ด้วยหน้าต่างที่กำหนดค่าได้
- **การกรอง IP** — รายการที่อนุญาต/รายการบล็อกสำหรับการควบคุมการเข้าถึง
- **Prompt Injection Guard** — การฆ่าเชื้อจากรูปแบบการแจ้งเตือนที่เป็นอันตราย
- **การเข้ารหัส AES-256-GCM** — ข้อมูลประจำตัวได้รับการเข้ารหัสเมื่อไม่ได้ใช้งาน
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "ผู้ให้บริการของฉันหยุดทำงานและฉันสูญเสียขั้นตอนการเขียนโค้ด"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
ผู้ให้บริการ AI อาจไม่เสถียร ส่งกลับข้อผิดพลาด 5xx หรือถึงขีดจำกัดอัตราชั่วคราว หากผู้พัฒนาขึ้นอยู่กับผู้ให้บริการรายเดียว ผู้ให้บริการเหล่านั้นจะถูกขัดจังหวะ หากไม่มีเซอร์กิตเบรกเกอร์ การลองซ้ำหลายครั้งอาจทำให้แอปพลิเคชันเสียหายได้
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **เซอร์กิตเบรกเกอร์ต่อผู้ให้บริการ** — เปิด/ปิดอัตโนมัติด้วยเกณฑ์และคูลดาวน์ที่กำหนดค่าได้ (ปิด/เปิด/เปิดครึ่งหนึ่ง)
- **Exponential Backoff** — ความล่าช้าในการลองใหม่อย่างต่อเนื่อง
- **Anti-Thundering Herd** — Mutex + การป้องกันเซมาฟอร์จากพายุที่ลองใหม่พร้อมกัน
- **Combo Fallback Chains** — หากผู้ให้บริการหลักล้มเหลว จะตกผ่านห่วงโซ่โดยอัตโนมัติโดยไม่มีการแทรกแซง
- **Combo Circuit Breaker** — ปิดการใช้งานผู้ให้บริการที่ล้มเหลวภายในคอมโบเชนโดยอัตโนมัติ
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **แดชบอร์ดสุขภาพ** — การตรวจสอบสถานะการออนไลน์ สถานะของเซอร์กิตเบรกเกอร์ การล็อก สถิติแคช เวลาแฝง p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🏽 7. "การกำหนดค่าเครื่องมือ AI แต่ละรายการนั้นน่าเบื่อและซ้ำซาก"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
นักพัฒนาใช้ Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... เครื่องมือแต่ละอันจำเป็นต้องมีการกำหนดค่าที่แตกต่างกัน (จุดสิ้นสุด API, คีย์, โมเดล) การกำหนดค่าใหม่เมื่อเปลี่ยนผู้ให้บริการหรือรุ่นเป็นการเสียเวลา
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **แดชบอร์ดเครื่องมือ CLI** — หน้าเฉพาะพร้อมการตั้งค่าเพียงคลิกเดียวสำหรับ Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — สร้าง `chatLanguageModels.json` สำหรับโค้ด VS พร้อมการเลือกรุ่นจำนวนมาก
- **ตัวช่วยสร้างการเริ่มต้นใช้งาน** — คำแนะนำการตั้งค่า 4 ขั้นตอนสำหรับผู้ใช้ครั้งแรก
- **จุดสิ้นสุดเดียว ทุกรุ่น** — กำหนดค่า `http://localhost:20128/v1` ครั้งเดียว เข้าถึงผู้ให้บริการมากกว่า 36 ราย
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "การจัดการโทเค็น OAuth จากผู้ให้บริการหลายรายนั้นช่างเลวร้าย" </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — ทั้งหมดใช้ OAuth 2.0 โดยมีโทเค็นที่กำลังจะหมดอายุ นักพัฒนาจำเป็นต้องตรวจสอบความถูกต้องอีกครั้งอย่างต่อเนื่อง จัดการกับ `client_secret is missing`, `redirect_uri_mismatch` และความล้มเหลวบนเซิร์ฟเวอร์ระยะไกล OAuth บน LAN/VPS เป็นปัญหาอย่างยิ่ง
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **รีเฟรชโทเค็นอัตโนมัติ** — โทเค็น OAuth รีเฟรชในพื้นหลังก่อนหมดอายุ
- **OAuth 2.0 (PKCE) ในตัว** — โฟลว์อัตโนมัติสำหรับ Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth หลายบัญชี** — หลายบัญชีต่อผู้ให้บริการผ่านการดึงโทเค็น JWT/ID
- **OAuth LAN/Remote Fix** — การตรวจจับ IP ส่วนตัวสำหรับ `redirect_uri` + โหมด URL แบบแมนนวลสำหรับเซิร์ฟเวอร์ระยะไกล
- **OAuth ที่อยู่เบื้องหลัง Nginx** — ใช้ `window.location.origin` สำหรับความเข้ากันได้ของ Reverse Proxy
- **คู่มือ OAuth ระยะไกล** — คำแนะนำทีละขั้นตอนสำหรับข้อมูลรับรอง Google Cloud บน VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "ฉันไม่รู้ว่าใช้เงินไปเท่าไหร่หรือที่ไหน"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
นักพัฒนาซอฟต์แวร์ใช้ผู้ให้บริการแบบชำระเงินหลายราย แต่ไม่มีมุมมองการใช้จ่ายแบบรวมศูนย์ ผู้ให้บริการแต่ละรายมีแดชบอร์ดการเรียกเก็บเงินของตัวเอง แต่ไม่มีข้อมูลรวม ค่าใช้จ่ายที่ไม่คาดคิดอาจกองพะเนิน
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **แดชบอร์ดการวิเคราะห์ต้นทุน** — การติดตามต้นทุนต่อโทเค็นและการจัดการงบประมาณต่อผู้ให้บริการ
- **ขีดจำกัดงบประมาณต่อระดับ** — เพดานการใช้จ่ายต่อระดับที่ทำให้เกิดทางเลือกสำรองอัตโนมัติ
- **การกำหนดค่าราคาต่อรุ่น** — ราคาที่กำหนดค่าได้ต่อรุ่น
- **สถิติการใช้งานต่อคีย์ API** — จำนวนคำขอและการประทับเวลาที่ใช้ล่าสุดต่อคีย์
- **แดชบอร์ดการวิเคราะห์** — การ์ดสถิติ แผนภูมิการใช้งานโมเดล ตารางผู้ให้บริการพร้อมอัตราความสำเร็จและเวลาแฝง
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "ฉันไม่สามารถวินิจฉัยข้อผิดพลาดและปัญหาในการเรียก AI ได้"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
เมื่อการโทรล้มเหลว ผู้พัฒนาจะไม่ทราบว่าเป็นการจำกัดอัตรา โทเค็นหมดอายุ รูปแบบไม่ถูกต้อง หรือข้อผิดพลาดของผู้ให้บริการ บันทึกที่แยกส่วนในเทอร์มินัลต่างๆ หากไม่สามารถสังเกตได้ การดีบักถือเป็นการลองผิดลองถูก
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Unified Logs Dashboard** — 4 แท็บ: บันทึกคำขอ, บันทึกพร็อกซี, บันทึกการตรวจสอบ, คอนโซล
- **โปรแกรมดูบันทึกคอนโซล** — โปรแกรมดูสไตล์เทอร์มินัลแบบเรียลไทม์พร้อมระดับรหัสสี เลื่อนอัตโนมัติ ค้นหา ตัวกรอง
- **SQLite Proxy Logs** — บันทึกถาวรที่รอดจากการรีสตาร์ทเซิร์ฟเวอร์
- **Translator Playground** — โหมดแก้ไขข้อบกพร่อง 4 โหมด: Playground (การแปลรูปแบบ), Chat Tester (ไป-กลับ), ม้านั่งทดสอบ (เป็นกลุ่ม), Live Monitor (เรียลไทม์)
- **ร้องขอการตรวจวัดทางไกล** — p50/p95/p99 latency + การติดตาม X-Request-Id
- **การบันทึกตามไฟล์พร้อมการหมุน** — ตัวสกัดกั้นคอนโซลจะบันทึกทุกอย่างไปยังบันทึก JSON ด้วยการหมุนตามขนาด
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "การปรับใช้และการบำรุงรักษาเกตเวย์นั้นซับซ้อน"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
การติดตั้ง การกำหนดค่า และการบำรุงรักษาพร็อกซี AI ในสภาพแวดล้อมที่แตกต่างกัน (ภายในเครื่อง, VPS, Docker, คลาวด์) ต้องใช้แรงงานมาก ปัญหาเช่นเส้นทางฮาร์ดโค้ด `EACCES` บนไดเร็กทอรี ข้อขัดแย้งของพอร์ต และการสร้างข้ามแพลตฟอร์มจะเพิ่มแรงเสียดทาน
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **การติดตั้งทั่วโลก npm** — `npm install -g omniroute && omniroute`เสร็จแล้ว
- **นักเทียบท่าหลายแพลตฟอร์ม** — AMD64 + ARM64 ดั้งเดิม (Apple Silicon, AWS Graviton, Raspberry Pi)
- **โปรไฟล์นักเทียบท่าเขียน** — `base` (ไม่มีเครื่องมือ CLI) และ `cli` (พร้อม Claude Code, Codex, OpenClaw)
- **แอป Electron Desktop** — แอปเนทีฟสำหรับ Windows/macOS/Linux พร้อมถาดระบบ เริ่มอัตโนมัติ โหมดออฟไลน์
- **โหมดแยกพอร์ต** — API และแดชบอร์ดบนพอร์ตแยกกันสำหรับสถานการณ์ขั้นสูง (พร็อกซีย้อนกลับ เครือข่ายคอนเทนเนอร์)
- **Cloud Sync** — กำหนดค่าการซิงโครไนซ์ระหว่างอุปกรณ์ผ่าน Cloudflare Workers
- **การสำรองข้อมูล DB** — การสำรองข้อมูล กู้คืน ส่งออก และนำเข้าการตั้งค่าทั้งหมดโดยอัตโนมัติ
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "อินเทอร์เฟซเป็นภาษาอังกฤษเท่านั้น และทีมของฉันไม่พูดภาษาอังกฤษ"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
ทีมในประเทศที่ไม่ได้ใช้ภาษาอังกฤษ โดยเฉพาะในละตินอเมริกา เอเชีย และยุโรป ประสบปัญหากับอินเทอร์เฟซที่ใช้ภาษาอังกฤษเท่านั้น อุปสรรคทางภาษาลดการนำไปใช้และเพิ่มข้อผิดพลาดในการกำหนดค่า
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **แดชบอร์ด i18n — 30 ภาษา** — ทั้งหมด 500+ คีย์ที่แปล รวมถึงอารบิก บัลแกเรีย เดนมาร์ก เยอรมัน สเปน ฟินแลนด์ ฝรั่งเศส ฮิบรู ฮินดี ฮังการี อินโดนีเซีย อิตาลี ญี่ปุ่น เกาหลี มาเลย์ ดัตช์ นอร์เวย์ โปแลนด์ โปรตุเกส (PT/BR) โรมาเนีย รัสเซีย สโลวาเกีย สวีเดน ไทย ยูเครน เวียดนาม จีน ฟิลิปปินส์ อังกฤษ
- **รองรับ RTL** — รองรับภาษาอาหรับและฮีบรูจากขวาไปซ้าย
- **README หลายภาษา** — การแปลเอกสารฉบับสมบูรณ์ 30 รายการ
- **ตัวเลือกภาษา** — ไอคอนลูกโลกในส่วนหัวสำหรับการสลับแบบเรียลไทม์
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "ฉันต้องการมากกว่าการแชท — ฉันต้องการการฝัง รูปภาพ เสียง"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI ไม่ใช่แค่การแชทให้เสร็จสิ้นเท่านั้น นักพัฒนาจำเป็นต้องสร้างภาพ ถอดเสียง สร้างการฝังสำหรับ RAG จัดอันดับเอกสารใหม่ และกลั่นกรองเนื้อหา API แต่ละรายการมีจุดสิ้นสุดและรูปแบบที่แตกต่างกัน
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **การฝัง** — `/v1/embeddings` พร้อมผู้ให้บริการ 6 รายและรุ่น 9+
- **การสร้างภาพ** — `/v1/images/generations` พร้อมผู้ให้บริการ 10 รายและโมเดลมากกว่า 20 รุ่น (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **ข้อความเป็นวิดีโอ** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) และ SD WebUI
- **ข้อความเป็นเพลง** — `/v1/music/generations` — ComfyUI (เปิดเสียงที่เสถียร, MusicGen)
- **การถอดเสียง** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **การอ่านออกเสียงข้อความ** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 และผู้ให้บริการที่มีอยู่
- **การกลั่นกรอง** — `/v1/moderations` — การตรวจสอบความปลอดภัยของเนื้อหา
- **การจัดอันดับใหม่** — `/v1/rerank` — การจัดอันดับความเกี่ยวข้องของเอกสารใหม่
- **Responses API** — รองรับ `/v1/responses` เต็มรูปแบบสำหรับ Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "ฉันไม่มีวิธีทดสอบและเปรียบเทียบคุณภาพระหว่างรุ่นต่างๆ"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
นักพัฒนาต้องการทราบว่าโมเดลใดดีที่สุดสำหรับกรณีการใช้งานของพวกเขา เช่น โค้ด การแปล การใช้เหตุผล แต่การเปรียบเทียบด้วยตนเองนั้นช้า ไม่มีเครื่องมือประเมินแบบรวมอยู่
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **การประเมิน LLM** — การทดสอบชุดทองพร้อมเคสที่โหลดไว้ล่วงหน้า 10 เคส ซึ่งครอบคลุมการทักทาย คณิตศาสตร์ ภูมิศาสตร์ การสร้างโค้ด การปฏิบัติตาม JSON การแปล การมาร์กดาวน์ การปฏิเสธด้านความปลอดภัย
- **4 กลยุทธ์การจับคู่** — `exact`, `contains`, `regex`, `custom` (ฟังก์ชัน JS)
- **ม้านั่งทดสอบสนามเด็กเล่นสำหรับนักแปล** — การทดสอบเป็นกลุ่มที่มีอินพุตหลายอินพุตและเอาต์พุตที่คาดหวัง การเปรียบเทียบข้ามผู้ให้บริการ
- **เครื่องมือทดสอบการแชท** — ไป-กลับเต็มรูปแบบพร้อมการเรนเดอร์การตอบสนองด้วยภาพ
- **Live Monitor** — สตรีมคำขอทั้งหมดที่ไหลผ่านพร็อกซีแบบเรียลไทม์
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "ฉันต้องปรับขนาดโดยไม่สูญเสียประสิทธิภาพ"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
เมื่อปริมาณคำขอเพิ่มขึ้น หากไม่มีการแคช คำถามเดียวกันจะทำให้เกิดต้นทุนซ้ำซ้อน หากไม่มีการระบุตัวตน คำขอซ้ำจะสูญเปล่าในการประมวลผล ต้องเคารพขีดจำกัดอัตราต่อผู้ให้บริการ
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Semantic Cache** — แคชสองชั้น (ลายเซ็น + ความหมาย) ช่วยลดต้นทุนและเวลาแฝง
- **คำขอ Idempotency** — หน้าต่างการขจัดข้อมูลซ้ำซ้อน 5 วินาทีสำหรับคำขอที่เหมือนกัน
- **การตรวจจับขีดจำกัดอัตรา** — RPM ต่อผู้ให้บริการ ช่องว่างขั้นต่ำ และการติดตามพร้อมกันสูงสุด
- **ขีดจำกัดอัตราที่แก้ไขได้** — ค่าเริ่มต้นที่กำหนดค่าได้ในการตั้งค่า → ความยืดหยุ่นด้วยความคงอยู่
- **แคชการตรวจสอบคีย์ API** — แคช 3 ระดับสำหรับประสิทธิภาพการผลิต
- **แดชบอร์ดสุขภาพพร้อมการวัดและส่งข้อมูลทางไกล** — เวลาแฝง p50/p95/p99 สถิติแคช เวลาทำงาน
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "ฉันต้องการควบคุมพฤติกรรมของโมเดลทั่วโลก"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
นักพัฒนาที่ต้องการคำตอบทั้งหมดในภาษาใดภาษาหนึ่ง มีน้ำเสียงเฉพาะ หรือต้องการจำกัดโทเค็นการให้เหตุผล การกำหนดค่านี้ในทุกเครื่องมือ/คำขอไม่สามารถทำได้
**How OmniRoute solves it:**
**OmniRoute แก้ปัญหาอย่างไร:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **การแจ้งพร้อมท์ของระบบ** — พร้อมท์ทั่วโลกนำไปใช้กับคำขอทั้งหมด
- **การตรวจสอบงบประมาณการคิด** — การควบคุมการจัดสรรโทเค็นการให้เหตุผลต่อคำขอ (การส่งผ่าน, อัตโนมัติ, กำหนดเอง, การปรับตัว)
- **6 กลยุทธ์การกำหนดเส้นทาง** — กลยุทธ์ระดับโลกที่กำหนดวิธีกระจายคำขอ
- **Wildcard Router** — รูปแบบ `provider/*` จะกำหนดเส้นทางแบบไดนามิกไปยังผู้ให้บริการใดๆ
- **Combo Enable/Disable Toggle** — สลับคอมโบได้โดยตรงจากแดชบอร์ด
- **สลับผู้ให้บริการ** — เปิด/ปิดการเชื่อมต่อทั้งหมดสำหรับผู้ให้บริการได้ด้วยคลิกเดียว
- **ผู้ให้บริการที่ถูกบล็อก** — ยกเว้นผู้ให้บริการบางรายจากรายการ `/v1/models`
</details>
<details>
<summary><b>🧰 17. "ฉันต้องการเครื่องมือ MCP เนื่องจากความสามารถด้านผลิตภัณฑ์ระดับเฟิร์สคลาส"</b></summary>
เกตเวย์ AI จำนวนมากเปิดเผย MCP เป็นเพียงรายละเอียดการใช้งานที่ซ่อนอยู่เท่านั้น ทีมจำเป็นต้องมีชั้นการปฏิบัติงานที่มองเห็นได้และจัดการได้
**OmniRoute แก้ปัญหาอย่างไร:**
- MCP ปรากฏในการนำทางแดชบอร์ดและแท็บโปรโตคอลปลายทาง
- หน้าการจัดการ MCP เฉพาะพร้อมกระบวนการ เครื่องมือ ขอบเขต และการตรวจสอบ
- การเริ่มต้นอย่างรวดเร็วในตัวสำหรับ `omniroute --mcp` และการเริ่มต้นใช้งานไคลเอ็นต์
</details>
<details>
<summary><b>🧠 18. "ฉันต้องการการประสาน A2A พร้อมเส้นทางงานการซิงค์ + สตรีม"</b></summary>
เวิร์กโฟลว์ของตัวแทนต้องการทั้งการตอบกลับโดยตรงและการดำเนินการสตรีมที่ใช้เวลานานพร้อมการควบคุมวงจรชีวิต
**OmniRoute แก้ปัญหาอย่างไร:**
- จุดสิ้นสุด A2A JSON-RPC (`POST /a2a`) พร้อม `message/send` และ `message/stream`
- การสตรีม SSE พร้อมการเผยแพร่สถานะเทอร์มินัล
- API วงจรชีวิตของงานสำหรับ `tasks/get` และ `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "ฉันต้องการความสมบูรณ์ของกระบวนการ MCP ที่แท้จริง ไม่ใช่สถานะที่เดาได้"</b></summary>
ทีมปฏิบัติการจำเป็นต้องทราบว่า MCP ยังคงอยู่จริงหรือไม่ ไม่ใช่แค่ว่า API สามารถเข้าถึงได้หรือไม่
**OmniRoute แก้ปัญหาอย่างไร:**
- ไฟล์ฮาร์ทบีทรันไทม์พร้อม PID, การประทับเวลา, การขนส่ง, จำนวนเครื่องมือ และโหมดขอบเขต
- API สถานะ MCP รวมการเต้นของหัวใจ + กิจกรรมล่าสุด
- การ์ดสถานะ UI สำหรับความสดใหม่ของกระบวนการ/สถานะการออนไลน์/การเต้นของหัวใจ
</details>
<details>
<summary><b>📋 20. "ฉันต้องการการทำงานของเครื่องมือ MCP ที่ตรวจสอบได้"</b></summary>
เมื่อเครื่องมือเปลี่ยนแปลงการกำหนดค่าหรือทริกเกอร์การดำเนินการ ทีมจำเป็นต้องมีการตรวจสอบย้อนกลับทางนิติเวช
**OmniRoute แก้ปัญหาอย่างไร:**
- การบันทึกการตรวจสอบที่ได้รับการสนับสนุนจาก SQLite สำหรับการเรียกใช้เครื่องมือ MCP
- กรองตามเครื่องมือ ความสำเร็จ/ความล้มเหลว คีย์ API และการแบ่งหน้า
- ตารางการตรวจสอบแดชบอร์ด + จุดสิ้นสุดสถิติสำหรับระบบอัตโนมัติ
</details>
<details>
<summary><b>🔐 21. "ฉันต้องการสิทธิ์ MCP ที่กำหนดขอบเขตต่อการบูรณาการ"</b></summary>
ไคลเอนต์ที่แตกต่างกันควรมีสิทธิ์เข้าถึงหมวดหมู่เครื่องมือน้อยที่สุด
**OmniRoute แก้ปัญหาอย่างไร:**
- ขอบเขต MCP แบบละเอียด 9 แบบสำหรับการเข้าถึงเครื่องมือที่ควบคุม
- การบังคับใช้ขอบเขตและการมองเห็นใน UI การจัดการ MCP
- ท่าทางเริ่มต้นที่ปลอดภัยสำหรับเครื่องมือในการปฏิบัติงาน
</details>
<details>
<summary><b>⚙️ 22. "ฉันต้องการการควบคุมการปฏิบัติงานโดยไม่ต้องปรับใช้ใหม่"</b></summary>
ทีมต้องการการเปลี่ยนแปลงรันไทม์อย่างรวดเร็วระหว่างเหตุการณ์หรือเหตุการณ์ต้นทุน
**OmniRoute แก้ปัญหาอย่างไร:**
- สลับการเปิดใช้งานคอมโบโดยตรงจากแดชบอร์ด MCP
- ใช้โปรไฟล์ความยืดหยุ่นจากชุดนโยบายที่กำหนดไว้ล่วงหน้า
- รีเซ็ตสถานะเซอร์กิตเบรกเกอร์จากแผงการทำงานเดียวกัน
</details>
<details>
<summary><b>🔄 23. "ฉันต้องการการมองเห็นและการยกเลิกวงจรการใช้งาน A2A แบบสด"</b></summary>
หากไม่มีการมองเห็นวงจรการใช้งาน เหตุการณ์ของงานจะยากต่อการคัดแยก
**OmniRoute แก้ปัญหาอย่างไร:**
- รายการงาน/การกรองตามสถานะ/ทักษะพร้อมการแบ่งหน้า
- เจาะลึกข้อมูลเมตาของงาน เหตุการณ์ และสิ่งประดิษฐ์
- จุดสิ้นสุดการยกเลิกงานและการดำเนินการ UI พร้อมการยืนยัน
</details>
<details>
<summary><b>🌊 24. "ฉันต้องการตัววัดสตรีมที่ใช้งานอยู่สำหรับโหลด A2A"</b></summary>
เวิร์กโฟลว์การสตรีมจำเป็นต้องมีข้อมูลเชิงลึกในการดำเนินงานเกี่ยวกับการทำงานพร้อมกันและการเชื่อมต่อแบบสด
**OmniRoute แก้ปัญหาอย่างไร:**
- ตัวนับสตรีมที่ใช้งานรวมอยู่ในสถานะ A2A
- การประทับเวลางานล่าสุดและการนับต่อรัฐ
- การ์ดแดชบอร์ด A2A สำหรับการตรวจสอบการปฏิบัติงานแบบเรียลไทม์
</details>
<details>
<summary><b>🪪 25. "ฉันต้องการการค้นพบเอเจนต์มาตรฐานสำหรับลูกค้า"</b></summary>
ไคลเอนต์และผู้ควบคุมภายนอกต้องการเมตาดาต้าที่เครื่องอ่านได้เพื่อการเริ่มต้นใช้งาน
**OmniRoute แก้ปัญหาอย่างไร:**
- บัตรตัวแทนเปิดเผยที่ `/.well-known/agent.json`
- ความสามารถและทักษะที่แสดงใน UI การจัดการ
- API สถานะ A2A รวมถึงข้อมูลเมตาการค้นพบสำหรับระบบอัตโนมัติ
</details>
<details>
<summary><b>🧭 26. "ฉันต้องการการค้นพบโปรโตคอลในผลิตภัณฑ์ UX"</b></summary>
หากผู้ใช้ไม่พบพื้นผิวของโปรโตคอล การนำไปใช้และคุณภาพการสนับสนุนจะลดลง
**OmniRoute แก้ปัญหาอย่างไร:**
- รายการแถบด้านข้างสำหรับ MCP และ A2A
- แท็บโปรโตคอลหน้าปลายทางพร้อมการเริ่มต้นและสถานะอย่างรวดเร็ว
- ลิงก์จากภาพรวมไปยังแดชบอร์ดการจัดการเฉพาะ
</details>
<details>
<summary><b>🧪 27. "ฉันต้องการการตรวจสอบโปรโตคอลแบบ end-to-end กับไคลเอนต์จริง"</b></summary>
การทดสอบจำลองไม่เพียงพอที่จะตรวจสอบความเข้ากันได้ของโปรโตคอลก่อนเผยแพร่
**OmniRoute แก้ปัญหาอย่างไร:**
- ชุด E2E ที่บูทแอปและใช้การขนส่งไคลเอนต์ MCP SDK จริง
- ไคลเอนต์ A2A ทดสอบการค้นหา ส่ง สตรีม รับ และยกเลิกโฟลว์
- ยืนยันการตรวจสอบข้ามกับการตรวจสอบ MCP และ API งาน A2A
</details>
<details>
<summary><b>📡 28. "ฉันต้องการความสามารถในการสังเกตแบบรวมศูนย์ในทุกอินเทอร์เฟซ"</b></summary>
การแยกความสามารถในการสังเกตตามโปรโตคอลทำให้เกิดจุดบอดและ MTTR ที่ยาวขึ้น
**OmniRoute แก้ปัญหาอย่างไร:**
- แดชบอร์ด/บันทึก/การวิเคราะห์แบบรวมในผลิตภัณฑ์เดียว
- สุขภาพ + การตรวจสอบ + ขอการตรวจวัดทางไกลผ่านเลเยอร์ OpenAI, MCP และ A2A
- API การดำเนินงานสำหรับสถานะและระบบอัตโนมัติ
</details>
<details>
<summary><b>💼 29. "ฉันต้องการหนึ่งรันไทม์สำหรับพร็อกซี + เครื่องมือ + การจัดการเอเจนต์"</b></summary>
การใช้บริการแยกกันจำนวนมากจะเพิ่มต้นทุนการดำเนินงานและโหมดความล้มเหลว
**OmniRoute แก้ปัญหาอย่างไร:**
- พร็อกซีที่เข้ากันได้กับ OpenAI, เซิร์ฟเวอร์ MCP และเซิร์ฟเวอร์ A2A ในสแต็กเดียว
- การรับรองความถูกต้องที่ใช้ร่วมกัน ความยืดหยุ่น การจัดเก็บข้อมูล และความสามารถในการสังเกต
- รูปแบบนโยบายที่สอดคล้องกันในทุกรูปแบบการโต้ตอบ
</details>
<details>
<summary><b>🚀 30. "ฉันต้องจัดส่งเวิร์กโฟลว์เอเจนต์โดยไม่มีการแผ่ขยายโค้ดกาว"</b></summary>
ทีมจะสูญเสียความเร็วเมื่อรวมบริการและสคริปต์เฉพาะกิจหลายรายการเข้าด้วยกัน
**OmniRoute แก้ปัญหาอย่างไร:**
- กลยุทธ์อุปกรณ์ปลายทางแบบครบวงจรสำหรับลูกค้าและตัวแทน
- UIs การจัดการโปรโตคอลในตัวและเส้นทางการตรวจสอบควัน
- รากฐานที่พร้อมสำหรับการผลิต (ความปลอดภัย การบันทึก ความยืดหยุ่น การสำรองข้อมูล)
</details>
### Playbook ตัวอย่าง (กรณีการใช้งานแบบรวม)
**Playbook A: เพิ่มการสมัครสมาชิกแบบชำระเงินให้สูงสุด + การสำรองข้อมูลราคาถูก**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: สแต็คการเขียนโค้ดแบบไม่มีค่าใช้จ่าย**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: ห่วงโซ่ทางเลือกที่เปิดตลอด 24 ชั่วโมงทุกวัน**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: ตัวแทนดำเนินการด้วย MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ เริ่มต้นอย่างรวดเร็ว
**1. ติดตั้งทั่วโลก:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -714,66 +990,26 @@ OmniRoute มี Translator Playground ในตัวอันทรงพล
</details>
---
## 🧪 การประเมินผล (Evals)
## 🎯 กรณีการใช้งาน
OmniRoute มีกรอบการประเมินในตัวเพื่อทดสอบคุณภาพการตอบสนองของ LLM เทียบกับชุดทอง เข้าถึงได้ผ่านทาง **Analytics → Evals** ในแดชบอร์ด
### กรณีที่ 1: "ฉันสมัครสมาชิก Claude Pro"
### ชุดทองในตัว
**ปัญหา:** โควต้าหมดอายุโดยไม่ได้ใช้ อัตราจำกัดระหว่างการเขียนโค้ดจำนวนมาก
"OmniRoute Golden Set" ที่โหลดไว้ล่วงหน้าประกอบด้วยกรณีทดสอบ 10 กรณีที่ครอบคลุม:
```
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)
- คำทักทาย คณิตศาสตร์ ภูมิศาสตร์ การสร้างโค้ด
- การปฏิบัติตามรูปแบบ JSON, การแปล, มาร์กดาวน์
- การปฏิเสธอย่างปลอดภัย (เนื้อหาที่เป็นอันตราย) การนับ ตรรกะบูลีน
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### กลยุทธ์การประเมินผล
### กรณีที่ 2: "ฉันต้องการต้นทุนเป็นศูนย์"
**ปัญหา:** ไม่สามารถสมัครสมาชิกได้ ต้องการการเข้ารหัส AI ที่เชื่อถือได้
```
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
```
### กรณีที่ 3: "ฉันต้องการการเข้ารหัสตลอด 24 ชั่วโมงทุกวัน ไม่มีการหยุดชะงัก"
**ปัญหา:** กำหนดเวลา ไม่สามารถหยุดการทำงานได้
```
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
```
### กรณีที่ 4: "ฉันต้องการ AI ฟรีใน OpenClaw"
**ปัญหา:** ต้องการผู้ช่วย AI ในแอปส่งข้อความ ไม่มีค่าใช้จ่ายใดๆ ทั้งสิ้น
```
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...
```
| กลยุทธ์ | คำอธิบาย | ตัวอย่าง |
| ---------- | ------------------------------------------------------------------ | -------------------------------- |
| `exact` | ผลลัพธ์จะต้องตรงกันทุกประการ | `"4"` |
| `contains` | เอาต์พุตจะต้องมีสตริงย่อย (ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) | `"Paris"` |
| `regex` | เอาต์พุตต้องตรงกับรูปแบบ regex | `"1.*2.*3"` |
| `custom` | ฟังก์ชัน JS แบบกำหนดเองส่งคืนค่า true/false | `(output) => output.length > 10` |
---
@@ -1051,29 +1287,6 @@ Settings → API Configuration:
---
## 🧪 การประเมินผล (Evals)
OmniRoute มีกรอบการประเมินในตัวเพื่อทดสอบคุณภาพการตอบสนองของ LLM เทียบกับชุดทอง เข้าถึงได้ผ่านทาง **Analytics → Evals** ในแดชบอร์ด
### ชุดทองในตัว
"OmniRoute Golden Set" ที่โหลดไว้ล่วงหน้าประกอบด้วยกรณีทดสอบ 10 กรณีที่ครอบคลุม:
- คำทักทาย คณิตศาสตร์ ภูมิศาสตร์ การสร้างโค้ด
- การปฏิบัติตามรูปแบบ JSON, การแปล, มาร์กดาวน์
- การปฏิเสธอย่างปลอดภัย (เนื้อหาที่เป็นอันตราย) การนับ ตรรกะบูลีน
### กลยุทธ์การประเมินผล
| กลยุทธ์ | คำอธิบาย | ตัวอย่าง |
| ---------- | ------------------------------------------------------------------ | -------------------------------- |
| `exact` | ผลลัพธ์จะต้องตรงกันทุกประการ | `"4"` |
| `contains` | เอาต์พุตจะต้องมีสตริงย่อย (ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) | `"Paris"` |
| `regex` | เอาต์พุตต้องตรงกับรูปแบบ regex | `"1.*2.*3"` |
| `custom` | ฟังก์ชัน JS แบบกำหนดเองส่งคืนค่า true/false | `(output) => output.length > 10` |
---
## 🐛 การแก้ไขปัญหา
<details>
@@ -1130,7 +1343,7 @@ OmniRoute มีกรอบการประเมินในตัวเพ
> **⚠️ สิ่งสำคัญสำหรับการใช้ OmniRoute กับ VPS/Docker/servidor remoto**
### ใช่ OAuth ของ Antigravity / Gemini CLI หรือไม่?
### OAuth
ระบบปฏิบัติการ **Antigravity** และ **Gemini CLI** ใช้ **Google OAuth 2.0** สำหรับการรับรองความถูกต้อง O Google ต้องการ `redirect_uri` usada no fluxo OAuth seja **exatamente** uma das URIs pré-cadastradas no Google Cloud Console do aplicativo.
@@ -1219,7 +1432,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ เทคสแต็ค
## 🛠️
- **รันไทม์**: Node.js 1822 LTS (⚠️ Node.js 24+ ไม่ได้รับการสนับสนุน\*\* — `better-sqlite3` ไบนารีดั้งเดิมเข้ากันไม่ได้)
- **ภาษา**: TypeScript 5.9 — **100% TypeScript** ทั่วทั้ง `src/` และ `open-sse/` (v1.0.6)
@@ -1270,7 +1483,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ โรดแมป
## 🗺️
OmniRoute มี **ฟีเจอร์มากกว่า 210 รายการที่วางแผน** ไว้ในขั้นตอนการพัฒนาหลายขั้นตอน นี่คือประเด็นสำคัญ:
@@ -1295,18 +1508,6 @@ OmniRoute มี **ฟีเจอร์มากกว่า 210 รายก
---
## 📧 สนับสนุน
> 💌 **เข้าร่วมชุมชนของเรา!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — รับความช่วยเหลือ แบ่งปันเคล็ดลับ และติดตามข่าวสารล่าสุด
- **เว็บไซต์**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **ปัญหา**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **โปรเจ็กต์ดั้งเดิม**: [9router by 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)

View File

@@ -110,6 +110,35 @@ _Підключіть будь-який інструмент IDE або CLI на
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Чому OmniRoute?
**Припиніть витрачати гроші та досягати лімітів:**
@@ -128,6 +157,18 @@ _Підключіть будь-який інструмент IDE або CLI на
---
## 📧 Підтримка
> 💬 **Приєднуйтесь до нашої спільноти!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — отримуйте допомогу, діліться порадами та будьте в курсі подій.
- **Веб-сайт**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Проблеми**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Оригінальний проект**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Як це працює
```
@@ -157,263 +198,502 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 Що вирішує OmniRoute — 30 реальних проблем і варіантів використання
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Кожен розробник, який використовує інструменти штучного інтелекту, щодня стикається з цими проблемами.** OmniRoute було створено, щоб вирішити їх усі — від перевитрати коштів до регіональних блокувань, від порушених потоків OAuth до операцій протоколу та спостережуваності підприємства.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. «Я плачу за дорогу підписку, але мене все одно переривають через обмеження» </b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Розробники платять 20200 доларів на місяць за Claude Pro, Codex Pro або GitHub Copilot. Навіть якщо платити, квота має максимальну межу — 5 годин використання, тижневі ліміти або ліміти за хвилину. У середині сеансу кодування постачальник перестає відповідати, а розробник втрачає швидкість і продуктивність.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Smart 4-Tier Fallback** — якщо квота підписки закінчується, автоматично перенаправляється до API Key → Дешево → Безкоштовно без ручного втручання
- **Відстеження квот у реальному часі** — показує споживання токенів у реальному часі зі зворотним відліком скидання (5 годин, щодня, щотижня)
- **Підтримка кількох облікових записів** — кілька облікових записів у кожного постачальника з автоматичним циклічним перебором — коли один закінчується, перемикається на наступний
- **Користувацькі комбінації** — резервні ланцюжки, які можна налаштувати, із 6 стратегіями балансування (спочатку заповнення, циклічний, P2C, випадковий, найменш використовуваний, економічно оптимізований)
- **Бізнес-квоти Codex** — Моніторинг квот робочого простору бізнесу/команди безпосередньо на інформаційній панелі
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. «Мені потрібно використовувати кілька постачальників, але кожен має різний API» </b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI використовує один формат, Claude (Anthropic) використовує інший, Gemini ще інший. Якщо розробник хоче перевірити моделі від різних постачальників або повернутися до них, йому потрібно переналаштувати SDK, змінити кінцеві точки, мати справу з несумісними форматами. Спеціальні постачальники (FriendLI, NIM) мають нестандартні кінцеві точки моделі.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Уніфікована кінцева точка** — один `http://localhost:20128/v1` служить проксі для всіх 36+ постачальників
- **Переклад форматів** — автоматичний і прозорий: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — видаляє нестандартні поля (`x_groq`, `usage_breakdown`, `service_tier`), які порушують роботу OpenAI SDK v1.83+
- **Нормалізація ролі** — перетворює `developer``system` для постачальників, які не є OpenAI; `system``user` для GLM/ERNIE
- **Think Tag Extraction** — витягує блоки `<think>` із таких моделей, як DeepSeek R1, у стандартизований `reasoning_content`
- **Структурований вихід для Gemini** — `json_schema``responseMimeType`/`responseSchema` автоматичне перетворення
- **`stream` за замовчуванням — `false`** — відповідає специфікації OpenAI, уникаючи неочікуваних SSE у Python/Rust/Go SDK.
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. «Мій постачальник штучного інтелекту блокує мій регіон/країну» </b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Такі постачальники, як OpenAI/Codex, блокують доступ із певних географічних регіонів. Користувачі отримують помилки на зразок `unsupported_country_region_territory` під час з’єднань OAuth і API. Це особливо засмучує розробників із країн, що розвиваються.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3-рівнева конфігурація проксі-сервера** — налаштовується проксі-сервер на 3 рівнях: глобальний (увесь трафік), для кожного постачальника (лише один постачальник) і для кожного підключення/ключа
- **Значки проксі-сервера з кольоровим кодуванням** — Візуальні індикатори: 🟢 глобальний проксі, 🟡 проксі-сервер постачальника, 🔵 проксі-сервер підключення, завжди показує IP-адресу
- **Обмін маркерами OAuth через проксі** — потік OAuth також проходить через проксі, вирішуючи `unsupported_country_region_territory`
- **Тестування з’єднання через проксі** — тестування з’єднання використовує налаштований проксі (без прямого обходу)
- **Підтримка SOCKS5** — повна підтримка проксі SOCKS5 для вихідної маршрутизації
- **TLS Fingerprint Spoofing** — TLS-відбиток, як у браузері, через `wreq-js` для обходу виявлення ботів
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. «Я хочу використовувати ШІ для кодування, але в мене немає грошей» </b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Не кожен може платити 20200 доларів на місяць за підписку на AI. Студентам, розробникам із країн, що розвиваються, любителям і фрілансерам потрібен доступ до якісних моделей за нульовою ціною.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Вбудовані безкоштовні постачальники рівня** — Вбудована підтримка 100% безкоштовних постачальників: iFlow (8 необмежених моделей), Qwen (3 необмежені моделі), Kiro (Claude безкоштовно), Gemini CLI (180K/місяць безкоштовно)
- **Безкоштовні комбінації** — ланцюжок `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 доларів США/місяць без простоїв
- **Безкоштовні кредити NVIDIA NIM** — інтегровано 1000 безкоштовних кредитів
- **Стратегія оптимізації витрат** — стратегія маршрутизації, яка автоматично вибирає найдешевшого доступного постачальника
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. «Мені потрібно захистити свій ШІ-шлюз від несанкціонованого доступу» </b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Коли шлюз штучного інтелекту надається мережі (LAN, VPS, Docker), будь-хто, хто має адресу, може використовувати токени/квоту розробника. Без захисту API вразливі до неправильного використання, швидкого впровадження та зловживання.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Керування ключами API** — генерація, ротація та визначення обсягу для кожного постачальника за допомогою спеціальної сторінки `/dashboard/api-manager`
- **Дозволи на рівні моделі** — обмежте ключі API певними моделями (`openai/*`, шаблони узагальнення) із перемикачем «Дозволити все»/«Обмежити»
- **API Endpoint Protection** — вимагати ключ для `/v1/models` і блокувати певних постачальників зі списку
- **Auth Guard + CSRF Protection** — усі маршрути інформаційної панелі захищені проміжним програмним забезпеченням `withAuth` + маркерами CSRF
- **Обмежувач швидкості** — обмеження швидкості за IP-адресою з настроюваними вікнами
- **IP Filtering** — список дозволених/чорних адрес для контролю доступу
- **Prompt Injection Guard** — очищення від шкідливих шаблонів підказок
- **Шифрування AES-256-GCM** — облікові дані зашифровані в стані спокою
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. «Мій постачальник не працює, і я втратив потік кодування» </b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Постачальники AI можуть стати нестабільними, повертати помилки 5xx або досягати тимчасових обмежень швидкості. Якщо розробник залежить від одного постачальника, вони перериваються. Без автоматичних вимикачів повторні спроби можуть призвести до збою програми.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Автоматичний вимикач для кожного постачальника** — автоматичне розмикання/замикання з настроюваними пороговими значеннями та часом відновлення (закрито/розімкнуто/напіврозімкнуто)
- **Exponential Backoff** — прогресивні затримки повторних спроб
- **Anti-Thundering Herd** — Mutex + захист семафора від одночасних повторних штормів
- **Комбіновані запасні ланцюги** — якщо основний постачальник виходить з ладу, автоматично проходить через ланцюжок без втручання.
- **Combo Circuit Breaker** — автоматично вимикає несправні постачальники в комбінованому ланцюжку
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Health Dashboard** — Моніторинг безвідмовної роботи, стани автоматичного вимикача, блокування, статистика кешу, затримка p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. «Налаштування кожного інструменту штучного інтелекту є виснажливим і повторюваним процесом» </b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Розробники використовують Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Кожному інструменту потрібна інша конфігурація (кінцева точка API, ключ, модель). Перенастроювання при зміні постачальника чи моделі марна трата часу.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Панель інструментів CLI** — спеціальна сторінка з налаштуванням одним клацанням для Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — генерує `chatLanguageModels.json` для коду VS із масовим вибором моделі
- **Майстер адаптації** — 4-етапне налаштування для тих, хто вперше користується
- **Одна кінцева точка, усі моделі** — налаштуйте `http://localhost:20128/v1` один раз, отримайте доступ до 36+ постачальників
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. «Керування токенами OAuth від кількох постачальників — це пекло» </b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — усі використовують OAuth 2.0 із терміном дії маркерів. Розробникам необхідно постійно проходити повторну автентифікацію, мати справу з `client_secret is missing`, `redirect_uri_mismatch` і збоями на віддалених серверах. OAuth у LAN/VPS є особливо проблематичним.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Auto Token Refresh** — маркери OAuth оновлюються у фоновому режимі до завершення терміну дії
- **Вбудований OAuth 2.0 (PKCE)** — автоматичний потік для Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — кілька облікових записів на постачальника за допомогою вилучення токенів JWT/ID
- **OAuth LAN/Remote Fix** — виявлення приватної IP-адреси для `redirect_uri` + ручний режим URL-адреси для віддалених серверів
- **OAuth за Nginx** — використовує `window.location.origin` для зворотної сумісності проксі
- **Remote OAuth Guide** — покроковий посібник для облікових даних Google Cloud на VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. «Я не знаю, скільки я витрачаю і куди» </b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Розробники використовують кілька платних постачальників, але не мають єдиного уявлення про витрати. Кожен постачальник має власну платіжну панель, але немає консолідованого перегляду. Несподівані витрати можуть накопичитися.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Інформаційна панель аналізу витрат** — відстеження вартості кожного токена та керування бюджетом для кожного постачальника
- **Бюджетні обмеження на рівень** — максимальна сума витрат на рівень, що запускає автоматичний відкат
- **Конфігурація ціни за модель** — налаштовувані ціни за модель
- **Статистика використання за ключ API** — кількість запитів і позначка часу останнього використання для кожного ключа
- **Інформаційна панель аналітики** — картки зі статистичними даними, діаграма використання моделі, таблиця постачальників із показниками успіху та затримкою
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. «Я не можу діагностувати помилки та проблеми під час викликів ШІ» </b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Коли виклик не вдається, розробник не знає, чи це було обмеження швидкості, прострочений маркер, неправильний формат чи помилка постачальника. Фрагментовані журнали на різних терміналах. Без спостережливості налагодження відбувається методом проб і помилок.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Інформаційна панель уніфікованих журналів** — 4 вкладки: журнали запитів, журнали проксі, журнали аудиту, консоль
- **Console Log Viewer** — засіб перегляду терміналу в режимі реального часу з кольоровими рівнями, автопрокручуванням, пошуком, фільтром
- **Проксі-журнали SQLite** — постійні журнали, які залишаються після перезапуску сервера
- **Translator Playground** — 4 режими налагодження: Playground (переклад формату), Chat Tester (туди й назад), Test Bench (пакет), Live Monitor (у реальному часі)
- **Запит телеметрії** — затримка p50/p95/p99 + трасування X-Request-Id
- **Логування на основі файлів із ротацією** — консольний перехоплювач записує все в журнал JSON із ротацією на основі розміру
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. «Розгортання та підтримка шлюзу є складною справою» </b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Встановлення, налаштування та обслуговування проксі ШІ в різних середовищах (локальне, VPS, Docker, хмара) є трудомістким. Такі проблеми, як жорстко закодовані шляхи, `EACCES` у каталогах, конфлікти портів і кросплатформні збірки, додають тертя.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm global install** — `npm install -g omniroute && omniroute`готово
- **Мультиплатформенний Docker** — нативний AMD64 + ARM64 (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Профілі створення Docker** — `base` (без інструментів CLI) і `cli` (з Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — рідна програма для Windows/macOS/Linux із системним треєм, автозапуском, офлайн-режимом
- **Режим розділеного порту** — API та інформаційна панель на окремих портах для розширених сценаріїв (зворотний проксі, мережа контейнерів)
- **Cloud Sync** — синхронізація налаштувань між пристроями через Cloudflare Workers
- **Резервне копіювання БД** — автоматичне резервне копіювання, відновлення, експорт та імпорт усіх налаштувань
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. «Інтерфейс лише англійською мовою, і моя команда не розмовляє англійською» </b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Команди в неангломовних країнах, особливо в Латинській Америці, Азії та Європі, стикаються з інтерфейсами лише англійською мовою. Мовні бар’єри зменшують адаптацію та збільшують кількість помилок конфігурації.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Інформаційна панель i18n — 30 мов** — перекладено всі 500+ клавіш, включаючи арабську, болгарську, датську, німецьку, іспанську, фінську, французьку, іврит, гінді, угорську, індонезійську, італійську, японську, корейську, малайську, голландську, норвезьку, польську, португальську (PT/BR), румунську, російську, словацьку, шведську, тайську, українську, в’єтнамську, китайська, філіппінська, англійська
- **Підтримка RTL** — підтримка арабської та івриту справа наліво
- **Багатомовні файли README** — 30 повних перекладів документації
- **Вибір мови** — значок глобуса в заголовку для перемикання в реальному часі
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. «Мені потрібно більше, ніж чат — мені потрібні вставки, зображення, аудіо» </b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
ШІ — це не просто завершення чату. Розробникам потрібно генерувати зображення, транскрибувати аудіо, створювати вбудовування для RAG, змінювати рейтинг документів і модерувати вміст. Кожен API має різну кінцеву точку та формат.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Вбудовування** — `/v1/embeddings` із 6 постачальниками та 9+ моделями
- **Генерація зображень** — `/v1/images/generations` із 10 постачальниками та понад 20 моделями (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI)
- **Текст у відео** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) і SD WebUI
- **Текст у музику** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen)
- **Транскрипція аудіо** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Перетворення тексту в мовлення** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3 + існуючі постачальники
- **Модерації** — `/v1/moderations` — Перевірки безпеки вмісту
- **Переранжування** — `/v1/rerank` — Переранжування релевантності документа
- **Responses API** — повна підтримка `/v1/responses` для Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. «У мене немає можливості перевірити та порівняти якість різних моделей» </b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Розробники хочуть знати, яка модель найкраще підходить для їхнього випадку використання — код, переклад, міркування — але порівнювати вручну повільно. Інтегрованих інструментів оцінювання не існує.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Оцінки LLM** — Золотий набір тестів із 10 попередньо завантаженими випадками, що охоплюють привітання, математику, географію, генерацію коду, відповідність JSON, переклад, уцінку, відмову безпеки
- **4 стратегії збігу** — `exact`, `contains`, `regex`, `custom` (функція JS)
- **Translator Playground Test Bench** — Пакетне тестування з кількома входами та очікуваними результатами, порівняння між постачальниками
- **Chat Tester** — повний цикл із візуальним відтворенням відповідей
- **Live Monitor** — потік усіх запитів, що проходять через проксі, у реальному часі
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. «Мені потрібно масштабувати без втрати продуктивності» </b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Оскільки кількість запитів зростає, без кешування ті самі запитання створюють дублюючі витрати. Без ідемпотентності, дублікат запитів обробки відходів. Необхідно дотримуватися обмежень тарифів для кожного постачальника.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Семантичний кеш** — дворівневий кеш (підпис + семантичний) зменшує вартість і затримку
- **Request Idempotency** — вікно дедуплікації 5 с для ідентичних запитів
- **Виявлення ліміту швидкості** — RPM для кожного постачальника, мінімальний розрив і максимальне одночасне відстеження
- **Обмеження швидкості, які можна редагувати** — налаштування за замовчуванням у Параметрах → Стійкість із наполегливістю
- **API Key Validation Cache** — 3-рівневий кеш для продуктивності
- **Інформаційна панель справності з телеметрією** — затримка p50/p95/p99, статистика кешу, час роботи
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. «Я хочу глобально контролювати поведінку моделі» </b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Розробники, які хочуть, щоб усі відповіді відповідали певною мовою, з певним тоном або хочуть обмежити маркери міркування. Налаштовувати це в кожному інструменті/запиті є недоцільним.
**How OmniRoute solves it:**
**Як це вирішує OmniRoute:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Впровадження системної підказки** — глобальна підказка застосовується до всіх запитів
- **Thinking Budget Validation** — Контроль розподілу токенів міркувань за запитом (прохідний, автоматичний, спеціальний, адаптивний)
- **6 стратегій маршрутизації** — глобальні стратегії, які визначають спосіб розподілу запитів
- **Wildcard Router** — шаблони `provider/*` динамічно маршрутизують до будь-якого постачальника
- **Увімкнути/вимкнути комбо** — перемикайте комбо безпосередньо з інформаційної панелі
- **Перемикнути постачальника** — увімкнути/вимкнути всі з’єднання для постачальника одним клацанням миші
- **Заблоковані постачальники** — виключити певних постачальників зі списку `/v1/models`
</details>
<details>
<summary><b>🧰 17. «Мені потрібні інструменти MCP як першокласні можливості продукту» </b></summary>
Багато шлюзів ШІ розкривають MCP лише як приховану деталь реалізації. Командам потрібен видимий, керований рівень операцій.
**Як це вирішує OmniRoute:**
- MCP з’являється на панелі навігації та на вкладці протоколу кінцевої точки
- Спеціальна сторінка керування MCP із процесом, інструментами, обсягами й аудитом
- Вбудований швидкий запуск для `omniroute --mcp` і адаптація клієнта
</details>
<details>
<summary><b>🧠 18. «Мені потрібна оркестровка A2A із синхронізацією + шляхи завдань потоку» </b></summary>
Робочі процеси агента потребують як прямих відповідей, так і тривалого потокового виконання з контролем життєвого циклу.
**Як це вирішує OmniRoute:**
- Кінцева точка A2A JSON-RPC (`POST /a2a`) з `message/send` і `message/stream`
- Потокова передача SSE з розповсюдженням стану терміналу
- API життєвого циклу завдань для `tasks/get` і `tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. «Мені потрібна реальна справність процесу MCP, а не вгаданий статус» </b></summary>
Операційним групам потрібно знати, чи справді MCP активний, а не лише те, чи доступний API.
**Як це вирішує OmniRoute:**
- Файл серцевого ритму виконання з PID, часовими мітками, транспортом, кількістю інструментів і режимом області
- API статусу MCP, що поєднує серцебиття + останню активність
- Картки стану інтерфейсу користувача для процесу/часу безперебійної роботи/свіжості пульсу
</details>
<details>
<summary><b>📋 20. «Мені потрібне виконання інструменту MCP з можливістю перевірки» </b></summary>
Коли інструменти змінюють конфігурацію або запускають операційні дії, командам потрібна криміналістична відстежуваність.
**Як це вирішує OmniRoute:**
— Журнал аудиту з підтримкою SQLite для викликів інструментів MCP
- Фільтри за інструментом, успіхом/невдачею, ключем API та розбивкою на сторінки
- Таблиця аудиту інформаційної панелі + кінцеві точки статистики для автоматизації
</details>
<details>
<summary><b>🔐 21. «Мені потрібні обмежені дозволи MCP для інтеграції» </b></summary>
Різні клієнти повинні мати мінімальний доступ до категорій інструментів.
**Як це вирішує OmniRoute:**
- 9 детальних областей MCP для контрольованого доступу до інструменту
- Застосування обсягу та видимість в інтерфейсі користувача керування MCP
- Безпечна поза за замовчуванням для робочих інструментів
</details>
<details>
<summary><b>⚙️ 22. «Мені потрібен оперативний контроль без перерозподілу» </b></summary>
Командам потрібні швидкі зміни часу виконання під час інцидентів або витрат.
**Як це вирішує OmniRoute:**
- Перемикання комбо-активації безпосередньо з інформаційної панелі MCP
- Застосовуйте профілі стійкості з попередньо визначених пакетів політик
- Скинути стан автоматичного вимикача з тієї ж панелі керування
</details>
<details>
<summary><b>🔄 23. «Мені потрібна видимість і скасування життєвого циклу завдання A2A» </b></summary>
Без видимості життєвого циклу інциденти завдань стає важко сортувати.
**Як це вирішує OmniRoute:**
— Список завдань/фільтрування за станом/навиками з розбивкою на сторінки
- Деталізація метаданих завдань, подій і артефактів
- Кінцева точка скасування завдання та дія інтерфейсу користувача з підтвердженням
</details>
<details>
<summary><b>🌊 24. «Мені потрібні активні показники потоку для завантаження A2A» </b></summary>
Робочі процеси потокової передачі вимагають оперативного розуміння паралельності та живих з’єднань.
**Як це вирішує OmniRoute:**
— Лічильники активних потоків інтегровані в статус A2A
- Мітка часу останнього завдання та підрахунок стану
- Картки інформаційної панелі A2A для моніторингу операцій у реальному часі
</details>
<details>
<summary><b>🪪 25. «Мені потрібне стандартне виявлення агентів для клієнтів» </b></summary>
Зовнішнім клієнтам і оркестрантам потрібні машинозчитувані метадані для адаптації.
**Як це вирішує OmniRoute:**
- Картка агента розкрита на `/.well-known/agent.json`
- Можливості та навички, показані в інтерфейсі користувача користувача
- API стану A2A включає метадані виявлення для автоматизації
</details>
<details>
<summary><b>🧭 26. «Мені потрібна можливість виявлення протоколу в UX продукту» </b></summary>
Якщо користувачі не можуть виявити поверхні протоколу, якість впровадження та підтримки падає.
**Як це вирішує OmniRoute:**
— Записи бічної панелі для MCP і A2A
- Сторінка кінцевої точки Вкладка протоколів із швидким запуском і статусом
- Посилання з огляду на спеціальні інформаційні панелі керування
</details>
<details>
<summary><b>🧪 27. «Мені потрібна наскрізна перевірка протоколу з реальними клієнтами» </b></summary>
Пробних тестів недостатньо для перевірки сумісності протоколу перед випуском.
**Як це вирішує OmniRoute:**
- Комплект E2E, який завантажує програму та використовує реальний клієнтський транспорт MCP SDK
- Клієнт A2A перевіряє потоки виявлення, надсилання, потокової передачі, отримання та скасування
- Перехресна перевірка тверджень щодо аудиту MCP та API завдань A2A
</details>
<details>
<summary><b>📡 28. «Мені потрібна уніфікована можливість спостереження через усі інтерфейси» </b></summary>
Поділ спостережуваності за протоколом створює сліпі зони та довший MTTR.
**Як це вирішує OmniRoute:**
- Уніфіковані інформаційні панелі/журнали/аналітика в одному продукті
- Справність + аудит + телеметрія запитів на рівнях OpenAI, MCP і A2A
- Операційні API для статусу та автоматизації
</details>
<details>
<summary><b>💼 29. «Мені потрібне одне середовище виконання для проксі + інструментів + оркестровки агента» </b></summary>
Запуск багатьох окремих служб збільшує експлуатаційні витрати та частоту збоїв.
**Як це вирішує OmniRoute:**
- OpenAI-сумісний проксі, сервер MCP і сервер A2A в одному стеку
- Спільна автентифікація, стійкість, зберігання даних і можливість спостереження
- Послідовна модель політики на всіх поверхнях взаємодії
</details>
<details>
<summary><b>🚀 30. «Мені потрібно надсилати агентські робочі процеси без розповсюдження клею-коду» </b></summary>
Команди втрачають швидкість під час з’єднання кількох спеціальних служб і сценаріїв.
**Як це вирішує OmniRoute:**
- Уніфікована стратегія кінцевих точок для клієнтів і агентів
— Вбудовані інтерфейси керування протоколами та шляхи перевірки диму
- Основи, готові до виробництва (безпека, журналювання, стійкість, резервне копіювання)
</details>
### Приклади Playbooks
**Playbook A: Максимальна кількість платної підписки + дешеве резервне копіювання**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: стек кодування без витрат**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: резервний ланцюжок 24/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Операції агента з MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Швидкий старт
**1. Встановити глобально:**
@@ -506,7 +786,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +995,26 @@ OmniRoute містить потужний вбудований Translator Playgr
</details>
---
## 🧪 Оцінки (Evals)
## 🎯 Випадки використання
OmniRoute містить вбудовану систему оцінювання для перевірки якості відповіді LLM на відповідність золотому набору. Доступ до нього через **Аналітика → Оцінки** на інформаційній панелі.
### Випадок 1: «У мене є підписка на Claude Pro»
### Вбудований Золотий набір
**Проблема:** Квота закінчується невикористаною, обмеження швидкості під час інтенсивного кодування
Попередньо завантажений "Золотий набір OmniRoute" містить 10 тестів, які охоплюють:
```
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)
- Привітання, математика, географія, генерація коду
- Відповідність формату JSON, переклад, розмітка
- Відмова безпеки (шкідливий контент), підрахунок, булева логіка
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Стратегії оцінювання
### Випадок 2: "Я хочу нульову вартість"
**Проблема:** не можу дозволити собі підписку, потрібне надійне кодування ШІ
```
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
```
### Випадок 3: «Мені потрібне кодування 24/7, без перерв»
**Проблема:** Дедлайни, не можу дозволити собі простою
```
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
```
### Випадок 4: «Я хочу БЕЗКОШТОВНОГО ШІ в OpenClaw»
**Проблема:** потрібен помічник штучного інтелекту в програмах для обміну повідомленнями, повністю безкоштовний
```
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...
```
| Стратегія | Опис | Приклад |
| ---------- | -------------------------------------------------------------- | -------------------------------- |
| `exact` | Вихідні дані повинні точно відповідати | `"4"` |
| `contains` | Вихідні дані повинні містити підрядок (незалежно від регістру) | `"Paris"` |
| `regex` | Вихідні дані мають відповідати шаблону регулярного виразу | `"1.*2.*3"` |
| `custom` | Спеціальна функція JS повертає true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1298,6 @@ Settings → API Configuration:
---
## 🧪 Оцінки (Evals)
OmniRoute містить вбудовану систему оцінювання для перевірки якості відповіді LLM на відповідність золотому набору. Доступ до нього через **Аналітика → Оцінки** на інформаційній панелі.
### Вбудований Золотий набір
Попередньо завантажений "Золотий набір OmniRoute" містить 10 тестів, які охоплюють:
- Привітання, математика, географія, генерація коду
- Відповідність формату JSON, переклад, розмітка
- Відмова безпеки (шкідливий контент), підрахунок, булева логіка
### Стратегії оцінювання
| Стратегія | Опис | Приклад |
| ---------- | -------------------------------------------------------------- | -------------------------------- |
| `exact` | Вихідні дані повинні точно відповідати | `"4"` |
| `contains` | Вихідні дані повинні містити підрядок (незалежно від регістру) | `"Paris"` |
| `regex` | Вихідні дані мають відповідати шаблону регулярного виразу | `"1.*2.*3"` |
| `custom` | Спеціальна функція JS повертає true/false | `(output) => output.length > 10` |
---
## 🐛 Усунення несправностей
<details>
@@ -1134,13 +1351,13 @@ OmniRoute містить вбудовану систему оцінювання
- OmniRoute v1.0.6+ включає резервну перевірку через завершення чату
- Переконайтеся, що базова URL-адреса містить суфікс `/v1`
### 🔐 OAuth em Servidor Remoto (віддалене налаштування OAuth)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ ВАЖЛИВО для використання OmniRoute у віддаленому VPS/Docker/сервері**
### Чи OAuth для Antigravity / Gemini CLI не підтримує віддалені сервери?
### OAuth
Провідники **Antigravity** і **Gemini CLI** використовують **Google OAuth 2.0** для автентифікації. Google вимагає, щоб `redirect_uri` не використовував fluxo OAuth, який **exatamente** має URI перед кадастрадами без додатка Google Cloud Console.
@@ -1229,7 +1446,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🛠️ Tech Stack
## 🛠️
- **Серед виконання**: Node.js 1822 LTS (⚠️ Node.js 24+ **не підтримується** — рідні двійкові файли `better-sqlite3` несумісні)
- **Мова**: TypeScript 5.9 — **100% TypeScript** для `src/` та `open-sse/` (версія 1.0.6)
@@ -1281,7 +1498,7 @@ Se não quiser criar credenciais próprias agora, ainda é possível usar o flux
---
## 🗺️ Дорожня карта
## 🗺️
OmniRoute має **заплановано понад 210 функцій** на кількох етапах розробки. Ось ключові області:
@@ -1306,18 +1523,6 @@ OmniRoute має **заплановано понад 210 функцій** на
---
## 📧 Підтримка
> 💬 **Приєднуйтесь до нашої спільноти!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — отримуйте допомогу, діліться порадами та будьте в курсі подій.
- **Веб-сайт**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Проблеми**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Оригінальний проект**: [9router by 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)

View File

@@ -110,6 +110,35 @@ _Kết nối mọi công cụ IDE hoặc CLI được hỗ trợ bởi AI thông
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 Tại sao lại là OmniRoute?
**Ngưng lãng phí tiền và đạt đến giới hạn:**
@@ -128,6 +157,18 @@ _Kết nối mọi công cụ IDE hoặc CLI được hỗ trợ bởi AI thông
---
## 📧 Hỗ trợ
> 💬 **Tham gia cộng đồng của chúng tôi!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Nhận trợ giúp, chia sẻ mẹo và luôn cập nhật.
- **Trang web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Vấn đề**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Dự án gốc**: [9router by decolua](https://github.com/decolua/9router)
---
## 🔄 Nó hoạt động như thế nào
```
@@ -157,263 +198,498 @@ Result: Never stop coding, minimal cost
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 OmniRoute giải quyết được gì — 30 điểm khó thực sự và trường hợp sử dụng
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **Mọi nhà phát triển sử dụng công cụ AI đều phải đối mặt với những vấn đề này hàng ngày.** OmniRoute được xây dựng để giải quyết tất cả — từ chi phí vượt mức cho đến chặn khu vực, từ luồng OAuth bị hỏng đến hoạt động giao thức và khả năng quan sát của doanh nghiệp.
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1. "Tôi trả tiền cho một thuê bao đắt tiền nhưng vẫn bị gián đoạn bởi các giới hạn"</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
Các nhà phát triển trả 20200 USD/tháng cho Claude Pro, Codex Pro hoặc GitHub Copilot. Ngay cả khi trả tiền, hạn ngạch vẫn có mức trần - 5 giờ sử dụng, giới hạn hàng tuần hoặc giới hạn tốc độ mỗi phút. Giữa phiên mã hóa, nhà cung cấp ngừng phản hồi và nhà phát triển mất đi dòng chảy và năng suất.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **Dự phòng 4 tầng thông minh** — Nếu hết hạn ngạch đăng ký, tự động chuyển hướng đến Khóa API → Giá rẻ → Miễn phí mà không cần can thiệp thủ công
- **Theo dõi hạn ngạch theo thời gian thực** — Hiển thị mức tiêu thụ mã thông báo trong thời gian thực với tính năng đếm ngược đặt lại (5 giờ, hàng ngày, hàng tuần)
- **Hỗ trợ nhiều tài khoản** — Nhiều tài khoản cho mỗi nhà cung cấp với tính năng tự động quay vòng — khi hết một tài khoản, hãy chuyển sang tài khoản tiếp theo
- **Combo tùy chỉnh** — Chuỗi dự phòng có thể tùy chỉnh với 6 chiến lược cân bằng (điền trước, quay vòng, P2C, ngẫu nhiên, ít sử dụng nhất, tối ưu hóa chi phí)
- **Hạn ngạch kinh doanh Codex** — Giám sát hạn ngạch không gian làm việc của Doanh nghiệp/Nhóm trực tiếp trong bảng điều khiển
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2. "Tôi cần sử dụng nhiều nhà cung cấp nhưng mỗi nhà cung cấp có một API khác nhau"</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI sử dụng một định dạng, Claude (Anthropic) sử dụng một định dạng khác, Gemini lại sử dụng một định dạng khác. Nếu nhà phát triển muốn thử nghiệm các mô hình từ các nhà cung cấp khác nhau hoặc dự phòng giữa các nhà cung cấp đó, họ cần phải định cấu hình lại SDK, thay đổi điểm cuối, xử lý các định dạng không tương thích. Các nhà cung cấp tùy chỉnh (FriendLI, NIM) có các điểm cuối mô hình không chuẩn.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **Điểm cuối hợp nhất** — Một `http://localhost:20128/v1` duy nhất đóng vai trò là proxy cho tất cả hơn 36 nhà cung cấp
- **Dịch định dạng** — Tự động và minh bạch: OpenAI ↔ Claude ↔ Gemini ↔ API phản hồi
- **Sạch hóa phản hồi** — Loại bỏ các trường không chuẩn (`x_groq`, `usage_breakdown`, `service_tier`) phá vỡ OpenAI SDK v1.83+
- **Chuẩn hóa vai trò** — Chuyển đổi `developer``system` cho các nhà cung cấp không thuộc OpenAI; `system``user` cho GLM/ERNIE
- **Think Tag Extraction** — Trích xuất các khối `<think>` từ các mô hình như DeepSeek R1 thành `reasoning_content` được tiêu chuẩn hóa
- **Đầu ra có cấu trúc cho Gemini** — `json_schema``responseMimeType`/`responseSchema` chuyển đổi tự động
- **`stream` mặc định là `false`** — Phù hợp với thông số OpenAI, tránh SSE không mong muốn trong SDK Python/Rust/Go
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3. "Nhà cung cấp AI của tôi chặn khu vực/quốc gia của tôi"</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
Các nhà cung cấp như OpenAI/Codex chặn quyền truy cập từ các khu vực địa lý nhất định. Người dùng gặp phải các lỗi như `unsupported_country_region_territory` trong quá trình kết nối OAuth API. Điều này đặc biệt gây khó chịu cho các nhà phát triển từ các nước đang phát triển.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **Cấu hình proxy 3 cấp** — Proxy có thể định cấu hình ở 3 cấp độ: toàn cầu (tất cả lưu lượng truy cập), mỗi nhà cung cấp (chỉ một nhà cung cấp) và mỗi kết nối/khóa
- **Huy hiệu proxy được mã hóa màu** — Chỉ báo trực quan: 🟢 proxy toàn cầu, 🟡 proxy nhà cung cấp, 🔵 proxy kết nối, luôn hiển th IP
- **Trao đổi mã thông báo OAuth thông qua proxy** — Luồng OAuth cũng đi qua proxy, giải quyết `unsupported_country_region_territory`
- **Kiểm tra kết nối qua Proxy** — Kiểm tra kết nối sử dụng proxy đã định cấu hình (không cần bỏ qua trực tiếp nữa)
- **Hỗ trợ SOCKS5** — Hỗ trợ proxy SOCKS5 đầy đủ cho định tuyến đi
- **Giả mạo dấu vân tay TLS** — Dấu vân tay TLS giống trình duyệt thông qua `wreq-js` để vượt qua khả năng phát hiện bot
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4. "Tôi muốn sử dụng AI để viết mã nhưng tôi không có tiền"</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
Không phải ai cũng có thể trả 20200 USD/tháng để đăng ký AI. Sinh viên, nhà phát triển từ các quốc gia mới nổi, những người có sở thích và người làm nghề tự do cần được tiếp cận với các mô hình chất lượng với chi phí bằng 0.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **Tích hợp sẵn nhà cung cấp cấp miễn phí** — Hỗ trợ riêng cho các nhà cung cấp miễn phí 100%: iFlow (8 mẫu không giới hạn), Qwen (3 mẫu không giới hạn), Kiro (Claude miễn phí), Gemini CLI (miễn phí 180K/tháng)
- **Combo chỉ miễn phí** — Chuỗi `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/tháng mà không có thời gian ngừng hoạt động
- **Tín dụng miễn phí NVIDIA NIM** — Tích hợp 1000 tín dụng miễn phí
- **Chiến lược tối ưu hóa chi phí** — Chiến lược định tuyến tự động chọn nhà cung cấp sẵn có rẻ nhất
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5. "Tôi cần bảo vệ cổng AI của mình khỏi bị truy cập trái phép"</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
Khi đưa cổng AI vào mạng (LAN, VPS, Docker), bất kỳ ai có địa chỉ đều có thể sử dụng mã thông báo/hạn ngạch của nhà phát triển. Nếu không có biện pháp bảo vệ, các API dễ bị lạm dụng, chèn ép và lạm dụng.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **Quản lý khóa API** — Tạo, xoay vòng và xác định phạm vi cho mỗi nhà cung cấp bằng trang `/dashboard/api-manager` chuyên dụng
- **Quyền cấp mô hình** — Hạn chế khóa API đối với các mô hình cụ thể (`openai/*`, mẫu ký tự đại diện), với nút chuyển đổi Cho phép tất cả/Hạn chế
- **Bảo vệ điểm cuối API** — Yêu cầu khóa cho `/v1/models` và chặn các nhà cung cấp cụ thể khỏi danh sách
- **Auth Guard + CSRF Protection** — Tất cả các tuyến bảng điều khiển được bảo vệ bằng phần mềm trung gian `withAuth` + mã thông báo CSRF
- **Giới hạn tốc độ** — Giới hạn tốc độ trên mỗi IP với các cửa sổ có thể định cấu hình
- **Lọc IP** — Danh sách cho phép/danh sách chặn để kiểm soát truy cập
- **Prompt Tiêm Guard** — Khử trùng các mẫu nhắc nhở độc hại
- **Mã hóa AES-256-GCM** — Thông tin xác thực được mã hóa ở trạng thái lưu trữ
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6. "Nhà cung cấp của tôi ngừng hoạt động và tôi mất luồng mã hóa"</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
Các nhà cung cấp AI có thể trở nên không ổn định, trả về lỗi 5xx hoặc đạt giới hạn tốc độ tạm thời. Nếu một nhà phát triển phụ thuộc vào một nhà cung cấp duy nhất thì họ sẽ bị gián đoạn. Nếu không có bộ ngắt mạch, việc thử lại nhiều lần có thể làm hỏng ứng dụng.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **Bộ ngắt mạch cho mỗi nhà cung cấp** — Tự động mở/đóng với ngưỡng có thể định cấu hình và thời gian hồi chiêu (Đóng/Mở/Nửa mở)
- **Thời gian chờ theo cấp số nhân** — Độ trễ thử lại lũy tiến
- **Bầy chống sấm sét** — Mutex + bảo vệ semaphore chống lại các cơn bão thử lại đồng thời
- **Chuỗi dự phòng kết hợp** — Nếu nhà cung cấp chính không thành công, nó sẽ tự động rơi qua chuỗi mà không cần can thiệp
- **Combo Circuit Breaker** — Tự động vô hiệu hóa các nhà cung cấp bị lỗi trong chuỗi kết hợp
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
- **Bảng thông tin sức khỏe** — Giám sát thời gian hoạt động, trạng thái ngắt mạch, khóa, số liệu thống kê bộ nhớ đệm, độ trễ p50/p95/p99
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. "Cấu hình từng công cụ AI thật tẻ nhạt và lặp đi lặp lại"</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
Nhà phát triển sử dụng Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Mỗi công cụ cần một cấu hình khác nhau (điểm cuối API, khóa, mô hình). Việc cấu hình lại khi chuyển đổi nhà cung cấp hoặc mô hình là một sự lãng phí thời gian.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **Bảng điều khiển công cụ CLI** — Trang chuyên dụng với thiết lập bằng một cú nhấp chuột cho Claude Code, Codex CLI, OpenClaw, Kilo Code, AntiGravity, Cline
- **Trình tạo cấu hình GitHub Copilot** — Tạo `chatLanguageModels.json` cho Mã VS với lựa chọn mô hình hàng loạt
- **Trình hướng dẫn tích hợp** — Thiết lập 4 bước có hướng dẫn cho người dùng lần đầu
- **Một điểm cuối, tất cả các kiểu máy** — Định cấu hình `http://localhost:20128/v1` một lần, truy cập hơn 36 nhà cung cấp
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8. "Quản lý mã thông báo OAuth từ nhiều nhà cung cấp là địa ngục"</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude Code, Codex, Gemini CLI, Copilot — tất cả đều sử dụng OAuth 2.0 với các mã thông báo sắp hết hạn. Các nhà phát triển cần liên tục xác thực lại, xử lý `client_secret is missing`, `redirect_uri_mismatch` và các lỗi trên máy chủ từ xa. OAuth trên LAN/VPS đặc biệt có vấn đề.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **Tự động làm mới mã thông báo** — Làm mới mã thông báo OAuth ở chế độ nền trước khi hết hạn
- **Tích hợp OAuth 2.0 (PKCE)** — Luồng tự động cho Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **OAuth nhiều tài khoản** — Nhiều tài khoản cho mỗi nhà cung cấp thông qua trích xuất mã thông báo JWT/ID
- **OAuth LAN/Remote Fix** — Phát hiện IP riêng cho `redirect_uri` + chế độ URL thủ công cho máy chủ từ xa
- **OAuth đằng sau Nginx** — Sử dụng `window.location.origin` để tương thích với proxy ngược
- **Hướng dẫn OAuth từ xa** — Hướng dẫn từng bước về thông tin đăng nhập Google Cloud trên VPS/Docker
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9. "Tôi không biết mình đang chi bao nhiêu hay ở đâu"</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
Các nhà phát triển sử dụng nhiều nhà cung cấp trả phí nhưng không có quan điểm thống nhất về chi tiêu. Mỗi nhà cung cấp có trang tổng quan thanh toán riêng nhưng không có chế độ xem tổng hợp. Chi phí bất ngờ có thể chồng chất.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **Bảng thông tin phân tích chi phí** — Theo dõi chi phí mỗi mã thông báo và quản lý ngân sách cho mỗi nhà cung cấp
- **Giới hạn ngân sách cho mỗi cấp** — Mức chi tiêu trần cho mỗi cấp kích hoạt dự phòng tự động
- **Cấu hình định giá theo mẫu** — Giá có thể định cấu hình cho mỗi mẫu
- **Thống kê sử dụng trên mỗi khóa API** — Số lượng yêu cầu và dấu thời gian được sử dụng lần cuối trên mỗi khóa
- **Bảng thông tin phân tích** — Thẻ thống kê, biểu đồ sử dụng mô hình, bảng nhà cung cấp với tỷ lệ thành công và độ trễ
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10. "Tôi không thể chẩn đoán lỗi và sự cố trong cuộc gọi AI"</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
Khi cuộc gọi không thành công, nhà phát triển không biết liệu đó có phải là giới hạn tốc độ, mã thông báo đã hết hạn, sai định dạng hay lỗi nhà cung cấp hay không. Nhật ký bị phân mảnh trên các thiết bị đầu cuối khác nhau. Nếu không có khả năng quan sát được thì việc gỡ lỗi chỉ là thử và sai.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **Bảng điều khiển nhật ký hợp nhất** — 4 tab: Nhật ký yêu cầu, Nhật ký proxy, Nhật ký kiểm tra, Bảng điều khiển
- **Trình xem nhật ký bảng điều khiển** — Trình xem kiểu thiết bị đầu cuối thời gian thực với các cấp độ được mã hóa màu, tự động cuộn, tìm kiếm, lọc
- **Nhật ký proxy SQLite** — Nhật ký liên tục vẫn tồn tại khi máy chủ khởi động lại
- **Sân chơi dịch thuật** — 4 chế độ gỡ lỗi: Sân chơi (dịch định dạng), Trình kiểm tra trò chuyện (khứ hồi), Bàn thử nghiệm (hàng loạt), Giám sát trực tiếp (thời gian thực)
- **Yêu cầu đo từ xa** — độ trễ p50/p95/p99 + truy tìm X-Request-Id
- **Ghi nhật ký dựa trên tệp bằng xoay vòng** — Trình chặn chặn bảng điều khiển ghi lại mọi thứ vào nhật ký JSON bằng cách xoay vòng dựa trên kích thước
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11. "Việc triển khai và bảo trì cổng rất phức tạp"</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
Việc cài đặt, định cấu hình và duy trì proxy AI trên các môi trường khác nhau (cục bộ, VPS, Docker, đám mây) tốn nhiều công sức. Các vấn đề như đường dẫn được mã hóa cứng, `EACCES` trên thư mục, xung đột cổng và các bản dựng đa nền tảng sẽ gây thêm rắc rối.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm cài đặt toàn cầu** — `npm install -g omniroute && omniroute`đã xong
- **Docker Đa nền tảng** — AMD64 + ARM64 gốc (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Hồ sơ soạn thảo Docker** — `base` (không có công cụ CLI) và `cli` (với Claude Code, Codex, OpenClaw)
- **Ứng dụng máy tính để bàn điện tử** — Ứng dụng gốc dành cho Windows/macOS/Linux với khay hệ thống, tự động khởi động, chế độ ngoại tuyến
- **Chế độ chia cổng** — API và Bảng điều khiển trên các cổng riêng biệt cho các tình huống nâng cao (proxy ngược, mạng vùng chứa)
- **Cloud Sync** — Đồng bộ hóa cấu hình giữa các thiết bị thông qua Cloudflare Workers
- **Sao lưu DB** — Tự động sao lưu, khôi phục, xuất và nhập tất cả cài đặt
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12. "Giao diện chỉ có tiếng Anh và nhóm của tôi không nói được tiếng Anh"</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
Các đội ở các quốc gia không nói tiếng Anh, đặc biệt là ở Châu Mỹ Latinh, Châu Á và Châu Âu, gặp khó khăn với giao diện chỉ có tiếng Anh. Rào cản ngôn ngữ làm giảm khả năng tiếp nhận và tăng lỗi cấu hình.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **Bảng điều khiển i18n — 30 ngôn ngữ** — Tất cả hơn 500 phím được dịch bao gồm tiếng Ả Rập, tiếng Bungari, tiếng Đan Mạch, tiếng Đức, tiếng Tây Ban Nha, tiếng Phần Lan, tiếng Pháp, tiếng Do Thái, tiếng Hindi, tiếng Hungary, tiếng Indonesia, tiếng Ý, tiếng Nhật, tiếng Hàn, tiếng Mã Lai, tiếng Hà Lan, tiếng Na Uy, tiếng Ba Lan, tiếng Bồ Đào Nha (PT/BR), tiếng Rumani, tiếng Nga, tiếng Slovak, tiếng Thụy Điển, tiếng Thái, tiếng Ukraina, tiếng Việt, tiếng Trung, tiếng Philipin, tiếng Anh
- **Hỗ trợ RTL** — Hỗ trợ từ phải sang trái cho tiếng Ả Rập và tiếng Do Thái
- **README đa ngôn ngữ** — 30 bản dịch tài liệu hoàn chỉnh
- **Bộ chọn ngôn ngữ** — Biểu tượng quả cầu trong tiêu đề để chuyển đổi theo thời gian thực
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13. "Tôi cần nhiều hơn là trò chuyện - tôi cần nội dung nhúng, hình ảnh, âm thanh"</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
AI không chỉ hoàn thành cuộc trò chuyện. Nhà phát triển cần to hình ảnh, phiên âm âm thanh, tạo phần nhúng cho RAG, sắp xếp lại tài liệu và kiểm duyệt nội dung. Mỗi API có điểm cuối và định dạng khác nhau.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **Nhúng** — `/v1/embeddings` với 6 nhà cung cấp và hơn 9 mẫu máy
- **Tạo hình ảnh** — `/v1/images/generations` với 10 nhà cung cấp và hơn 20 mô hình (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, AntiGravity, SD WebUI, ComfyUI)
- **Chuyển văn bản thành video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) và SD WebUI
- **Chuyển văn bản thành nhạc** — `/v1/music/generations` — ComfyUI (Mở âm thanh ổn định, MusicGen)
- **Phiên âm âm thanh** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3
- **Chuyển văn bản thành giọng nói** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, + các nhà cung cấp hiện có
- **Kiểm duyệt** — `/v1/moderations` — Kiểm tra an toàn nội dung
- **Sắp xếp lại** — `/v1/rerank` — Sắp xếp lại mức độ liên quan của tài liệu
- **API phản hồi** — Hỗ trợ đầy đủ `/v1/responses` cho Codex
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14. "Tôi không có cách nào để kiểm tra và so sánh chất lượng giữa các mẫu"</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
Các nhà phát triển muốn biết mô hình nào là tốt nhất cho trường hợp sử dụng của họ — mã, dịch thuật, lý luận — nhưng việc so sánh thủ công rất chậm. Không có công cụ đánh giá tích hợp nào tồn tại.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **Đánh giá LLM** — Bộ thử nghiệm vàng với 10 trường hợp tải sẵn bao gồm lời chào, toán, địa lý, tạo mã, tuân thủ JSON, dịch thuật, đánh dấu, từ chối an toàn
- **4 Chiến lược kết hợp** — `exact`, `contains`, `regex`, `custom` (chức năng JS)
- **Băng thử nghiệm sân chơi dịch giả** — Thử nghiệm hàng loạt với nhiều đầu vào và đầu ra dự kiến, so sánh giữa các nhà cung cấp
- **Trình kiểm tra trò chuyện** — Toàn bộ chuyến đi với kết xuất phản hồi trực quan
- **Live Monitor** — Luồng thời gian thực của tất cả các yêu cầu truyền qua proxy
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15. "Tôi cần mở rộng quy mô mà không làm giảm hiệu suất"</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
Khi khối lượng yêu cầu tăng lên mà không lưu vào bộ nhớ đệm thì các câu hỏi tương tự sẽ tạo ra chi phí trùng lặp. Nếu không có tính tạm thời, các yêu cầu trùng lặp sẽ bị lãng phí. Giới hạn tỷ lệ cho mỗi nhà cung cấp phải được tôn trọng.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **Bộ nhớ đệm ngữ nghĩa** — Bộ nhớ đệm hai tầng (chữ ký + ngữ nghĩa) giúp giảm chi phí và độ trễ
- **Yêu cầu Idempotency** — Khoảng thời gian loại bỏ trùng lặp 5 giây cho các yêu cầu giống hệt nhau
- **Phát hiện giới hạn tỷ lệ** — RPM của mỗi nhà cung cấp, khoảng cách tối thiểu và theo dõi đồng thời tối đa
- **Giới hạn tỷ lệ có thể chỉnh sửa** — Giá trị mặc định có thể định cấu hình trong Cài đặt → Khả năng phục hồi với tính bền bỉ
- **Bộ đệm xác thực khóa API** — Bộ đệm 3 tầng cho hiệu suất sản xuất
- **Bảng thông tin sức khỏe với phép đo từ xa** — độ trễ p50/p95/p99, số liệu thống kê bộ nhớ đệm, thời gian hoạt động
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16. "Tôi muốn kiểm soát hành vi của mô hình trên toàn cầu"</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
Các nhà phát triển muốn tất cả phản hồi bằng một ngôn ngữ cụ thể, với giọng điệu cụ thể hoặc muốn giới hạn các mã thông báo lý luận. Việc định cấu hình điều này trong mọi công cụ/yêu cầu là không thực tế.
**How OmniRoute solves it:**
**Cách OmniRoute giải quyết vấn đề này:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **Tiêm nhắc nhở hệ thống** — Lời nhắc chung được áp dụng cho tất cả các yêu cầu
- **Xác thực ngân sách tư duy** — Kiểm soát phân bổ mã thông báo hợp lý cho mỗi yêu cầu (chuyển qua, tự động, tùy chỉnh, thích ứng)
- **6 Chiến lược định tuyến** — Chiến lược toàn cầu xác định cách phân phối yêu cầu
- **Bộ định tuyến ký tự đại diện** — Các mẫu `provider/*` tự động định tuyến tới bất kỳ nhà cung cấp nào
- **Bật/Tắt kết hợp chuyển đổi** — Chuyển đổi kết hợp trực tiếp từ bảng điều khiển
- **Chuyển đổi nhà cung cấp** — Bật/tắt tất cả kết nối cho nhà cung cấp chỉ bằng một cú nhấp chuột
- **Nhà cung cấp bị chặn** — Loại trừ các nhà cung cấp cụ thể khỏi danh sách `/v1/models`
</details>
<details>
<summary><b>🧰 17. "Tôi cần các công cụ MCP làm khả năng của sản phẩm hạng nhất"</b></summary>
Nhiều cổng AI chỉ hiển thị MCP dưới dạng chi tiết triển khai ẩn. Các nhóm cần một lớp hoạt động rõ ràng và dễ quản lý.
**Cách OmniRoute giải quyết vấn đề này:**
- MCP xuất hiện trong tab điều hướng bảng điều khiển và giao thức điểm cuối
- Trang quản lý MCP chuyên dụng với quy trình, công cụ, phạm vi và kiểm tra
- Tích hợp tính năng khởi động nhanh cho `omniroute --mcp` và quá trình cài đặt ứng dụng khách
</details>
<details>
<summary><b>🧠 18. "Tôi cần phối hợp A2A với đường dẫn tác vụ đồng bộ hóa + truyền phát"</b></summary>
Quy trình làm việc của tổng đài viên cần cả phản hồi trực tiếp và thực thi theo luồng trong thời gian dài với khả năng kiểm soát vòng đời.
**Cách OmniRoute giải quyết vấn đề này:**
- Điểm cuối JSON-RPC A2A (`POST /a2a`) với `message/send``message/stream`
- Truyền phát SSE với sự lan truyền trạng thái đầu cuối
- API vòng đời tác vụ cho `tasks/get``tasks/cancel`
</details>
<details>
<summary><b>🛰️ 19. "Tôi cần tình trạng quy trình MCP thực sự, trạng thái không đoán được"</b></summary>
Các nhóm vận hành cần biết liệu MCP có thực sự tồn tại hay không, chứ không chỉ là liệu API có thể truy cập được hay không.
**Cách OmniRoute giải quyết vấn đề này:**
- Tệp nhịp tim thời gian chạy với PID, dấu thời gian, vận chuyển, số lượng công cụ và chế độ phạm vi
- API trạng thái MCP kết hợp nhịp tim + hoạt động gần đây
- Thẻ trạng thái giao diện người dùng về độ mới của quy trình/thời gian hoạt động/nhịp tim
</details>
<details>
<summary><b>📋 20. "Tôi cần thực thi công cụ MCP có thể kiểm tra được"</b></summary>
Khi các công cụ thay đổi cấu hình hoặc kích hoạt các hành động vận hành, các nhóm cần truy xuất nguồn gốc pháp lý.
**Cách OmniRoute giải quyết vấn đề này:**
- Ghi nhật ký kiểm tra được hỗ trợ bởi SQLite cho các lệnh gọi công cụ MCP
- Bộ lọc theo công cụ, thành công/thất bại, khóa API và phân trang
- Bảng kiểm tra bảng điều khiển + điểm cuối thống kê để tự động hóa
</details>
<details>
<summary><b>🔐 21. "Tôi cần quyền MCP trong phạm vi cho mỗi lần tích hợp"</b></summary>
Các khách hàng khác nhau phải có quyền truy cập ít đặc quyền nhất vào các danh mục công cụ.
**Cách OmniRoute giải quyết vấn đề này:**
- 9 phạm vi MCP chi tiết để truy cập công cụ được kiểm soát
- Thực thi phạm vi và khả năng hiển thị trong giao diện người dùng quản lý MCP
- Tư thế mặc định an toàn cho dụng cụ vận hành
</details>
<details>
<summary><b>⚙️ 22. "Tôi cần kiểm soát hoạt động mà không cần triển khai lại"</b></summary>
Các nhóm cần thay đổi thời gian chạy nhanh trong các sự cố hoặc sự kiện tốn kém.
**Cách OmniRoute giải quyết vấn đề này:**
- Chuyển đổi kích hoạt kết hợp trực tiếp từ bảng điều khiển MCP
- Áp dụng hồ sơ khả năng phục hồi từ các gói chính sách được xác định trước
- Đặt lại trạng thái ngắt mạch từ cùng bảng vận hành
</details>
<details>
<summary><b>🔄 23. "Tôi cần khả năng hiển thị và hủy trực tiếp trong vòng đời nhiệm vụ A2A"</b></summary>
Nếu không có khả năng hiển thị vòng đời, các sự cố trong nhiệm vụ sẽ khó phân loại.
**Cách OmniRoute giải quyết vấn đề này:**
- Liệt kê/lọc nhiệm vụ theo trạng thái/kỹ năng với phân trang
- Xem chi tiết về siêu dữ liệu, sự kiện và hiện vật của nhiệm vụ
- Điểm cuối hủy tác vụ và hành động UI có xác nhận
</details>
<details>
<summary><b>🌊 24. "Tôi cần số liệu luồng hoạt động cho tải A2A"</b></summary>
Luồng công việc phát trực tuyến yêu cầu hiểu biết sâu sắc về hoạt động đồng thời và kết nối trực tiếp.
**Cách OmniRoute giải quyết vấn đề này:**
- Bộ đếm luồng hoạt động được tích hợp vào trạng thái A2A
- Dấu thời gian nhiệm vụ cuối cùng và số lượng trên mỗi trạng thái
- Thẻ bảng điều khiển A2A để theo dõi hoạt động theo thời gian thực
</details>
<details>
<summary><b>🪪 25. "Tôi cần phát hiện đại lý tiêu chuẩn cho khách hàng"</b></summary>
Máy khách và người điều phối bên ngoài cần siêu dữ liệu có thể đọc được bằng máy để triển khai.
**Cách OmniRoute giải quyết vấn đề này:**
- Thẻ đại lý bị lộ tại `/.well-known/agent.json`
- Khả năng và kỹ năng thể hiện trong UI quản lý
- API trạng thái A2A bao gồm siêu dữ liệu khám phá để tự động hóa
</details>
<details>
<summary><b>🧭 26. "Tôi cần khả năng khám phá giao thức trong UX sản phẩm"</b></summary>
Nếu người dùng không thể khám phá các bề mặt giao thức, chất lượng chấp nhận và hỗ trợ sẽ giảm.
**Cách OmniRoute giải quyết vấn đề này:**
- Các mục thanh bên cho MCP và A2A
- Tab Giao thức của trang điểm cuối với trạng thái và khởi động nhanh
- Liên kết từ tổng quan đến bảng điều khiển quản lý chuyên dụng
</details>
<details>
<summary><b>🧪 27. "Tôi cần xác thực giao thức end-to-end với khách hàng thực"</b></summary>
Các thử nghiệm mô phỏng không đủ để xác thực tính tương thích của giao thức trước khi phát hành.
**Cách OmniRoute giải quyết vấn đề này:**
- Bộ E2E khởi động ứng dụng và sử dụng vận chuyển máy khách MCP SDK thực
- Máy khách A2A kiểm tra các luồng khám phá, gửi, truyền phát, nhận và hủy
- Kiểm tra chéo các xác nhận đối với kiểm tra MCP và API nhiệm vụ A2A
</details>
<details>
<summary><b>📡 28. "Tôi cần khả năng quan sát thống nhất trên tất cả các giao diện"</b></summary>
Việc phân chia khả năng quan sát theo giao thức sẽ tạo ra các điểm mù và MTTR dài hơn.
**Cách OmniRoute giải quyết vấn đề này:**
- Bảng điều khiển/nhật ký/phân tích thống nhất trong một sản phẩm
- Sức khỏe + kiểm toán + yêu cầu đo từ xa trên các lớp OpenAI, MCP và A2A
- API hoạt động cho trạng thái và tự động hóa
</details>
<details>
<summary><b>💼 29. "Tôi cần một thời gian chạy cho proxy + công cụ + điều phối tác nhân"</b></summary>
Việc chạy nhiều dịch vụ riêng biệt làm tăng chi phí vận hành và các chế độ lỗi.
**Cách OmniRoute giải quyết vấn đề này:**
- Proxy tương thích với OpenAI, máy chủ MCP và máy chủ A2A trong một ngăn xếp
- Chia sẻ xác thực, khả năng phục hồi, lưu trữ dữ liệu và khả năng quan sát
- Mô hình chính sách nhất quán trên tất cả các bề mặt tương tác
</details>
<details>
<summary><b>🚀 30. "Tôi cần gửi quy trình công việc tổng thể mà không cần sử dụng quá nhiều mã keo"</b></summary>
Các nhóm bị mất tốc độ khi kết hợp nhiều dịch vụ và tập lệnh đặc biệt.
**Cách OmniRoute giải quyết vấn đề này:**
- Chiến lược điểm cuối thống nhất cho khách hàng và đại lý
- Giao diện người dùng quản lý giao thức tích hợp và đường dẫn xác thực khói
- Nền tảng sẵn sàng sản xuất (bảo mật, ghi nhật ký, khả năng phục hồi, sao lưu)
</details>
### Sách hướng dẫn ví dụ (Trường hợp sử dụng tích hợp)
**Playbook A: Tối đa hóa đăng ký trả phí + dự phòng giá rẻ**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**Playbook B: Ngăn xếp mã hóa không tốn phí**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**Playbook C: chuỗi dự phòng luôn hoạt động 24/7**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**Playbook D: Tác nhân hoạt động với MCP + A2A**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ Bắt đầu nhanh
**1. Cài đặt trên toàn cầu:**
@@ -506,7 +782,7 @@ docker compose --profile cli up -d
---
## 🖥️ Desktop App — Offline & Always-On
## 🖥️
> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux.
@@ -715,66 +991,26 @@ OmniRoute bao gồm Sân chơi dịch thuật tích hợp mạnh mẽ với **4
</details>
---
## 🧪 Đánh giá (Evals)
## 🎯 Trường hợp sử dụng
OmniRoute bao gồm khung đánh giá tích hợp để kiểm tra chất lượng phản hồi LLM dựa trên bộ vàng. Truy cập thông qua **Analytics → Đánh giá** trong bảng điều khiển.
### Trường hợp 1: "Tôi có đăng ký Claude Pro"
### Bộ vàng tích hợp
**Vấn đề:** Hạn ngạch hết hạn không được sử dụng, giới hạn tốc độ trong quá trình mã hóa nặng
"Bộ vàng OmniRoute" được tải sẵn chứa 10 trường hợp thử nghiệm bao gồm:
```
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)
- Lời chào, toán, địa lý, tạo mã
- Tuân thủ định dạng JSON, dịch thuật, đánh dấu
- Từ chối an toàn (nội dung có hại), đếm, logic boolean
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Chiến lược đánh giá
### Trường hợp 2: "Tôi muốn chi phí bằng 0"
**Vấn đề:** Không đủ khả năng đăng ký, cần mã hóa AI đáng tin cậy
```
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
```
### Trường hợp 3: "Tôi cần code 24/7, không bị gián đoạn"
**Vấn đề:** Thời hạn, không đủ khả năng cho thời gian ngừng hoạt động
```
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
```
### Trường hợp 4: "Tôi muốn AI MIỄN PHÍ trong OpenClaw"
**Vấn đề:** Cần trợ lý AI trong ứng dụng nhắn tin, hoàn toàn miễn phí
```
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...
```
| Chiến lược | Mô tả | Ví dụ |
| ---------- | --------------------------------------------------------------- | -------------------------------- |
| `exact` | Đầu ra phải khớp chính xác | `"4"` |
| `contains` | Đầu ra phải chứa chuỗi con (không phân biệt chữ hoa chữ thường) | `"Paris"` |
| `regex` | Đầu ra phải khớp với mẫu biểu thức chính quy | `"1.*2.*3"` |
| `custom` | Hàm JS tùy chỉnh trả về true/false | `(output) => output.length > 10` |
---
@@ -1058,29 +1294,6 @@ Settings → API Configuration:
---
## 🧪 Đánh giá (Evals)
OmniRoute bao gồm khung đánh giá tích hợp để kiểm tra chất lượng phản hồi LLM dựa trên bộ vàng. Truy cập thông qua **Analytics → Đánh giá** trong bảng điều khiển.
### Bộ vàng tích hợp
"Bộ vàng OmniRoute" được tải sẵn chứa 10 trường hợp thử nghiệm bao gồm:
- Lời chào, toán, địa lý, tạo mã
- Tuân thủ định dạng JSON, dịch thuật, đánh dấu
- Từ chối an toàn (nội dung có hại), đếm, logic boolean
### Chiến lược đánh giá
| Chiến lược | Mô tả | Ví dụ |
| ---------- | --------------------------------------------------------------- | -------------------------------- |
| `exact` | Đầu ra phải khớp chính xác | `"4"` |
| `contains` | Đầu ra phải chứa chuỗi con (không phân biệt chữ hoa chữ thường) | `"Paris"` |
| `regex` | Đầu ra phải khớp với mẫu biểu thức chính quy | `"1.*2.*3"` |
| `custom` | Hàm JS tùy chỉnh trả về true/false | `(output) => output.length > 10` |
---
## 🐛 Khắc phục sự cố
<details>
@@ -1132,13 +1345,13 @@ OmniRoute bao gồm khung đánh giá tích hợp để kiểm tra chất lượ
- OmniRoute v1.0.6+ bao gồm xác thực dự phòng thông qua hoàn thành trò chuyện
- Đảm bảo URL cơ sở bao gồm hậu tố `/v1`
### 🔐 OAuth trên Servidor Remoto (Thiết lập OAuth từ xa)
### 🔐 OAuth
<a name="oauth-em-servidor-remoto"></a>
> **⚠️ QUAN TRỌNG đối với người sử dụng OmniRoute trên VPS/Docker/servidor remoto**
### Bởi vì OAuth làm cho AntiGravity / Gemini CLI có bị ảnh hưởng bởi các dịch vụ điều khiển từ xa không?
### OAuth
Os đã được chứng minh **AntiGravity** e **Gemini CLI** sử dụng **Google OAuth 2.0** để xác thực. O Google exige que a `redirect_uri` usada no fluxo OAuth seja **exatamente** một trong các URI trước khi lập danh sách trên Google Cloud Console để ứng dụng.
@@ -1227,7 +1440,7 @@ Nếu không có câu hỏi nào về thông tin xác thực trước đây, b
---
## 🛠️ Ngăn xếp công nghệ
## 🛠️
- **Thời gian chạy**: Node.js 1822 LTS (⚠️ Node.js 24+ **không được hỗ trợ**`better-sqlite3` các tệp nhị phân gốc không tương thích)
- **Ngôn ngữ**: TypeScript 5.9 — **100% TypeScript** trên `src/``open-sse/` (v1.0.6)
@@ -1279,7 +1492,7 @@ Nếu không có câu hỏi nào về thông tin xác thực trước đây, b
---
## 🗺️ Lộ trình
## 🗺️
OmniRoute có **210+ tính năng được lên kế hoạch** qua nhiều giai đoạn phát triển. Dưới đây là các lĩnh vực chính:
@@ -1304,18 +1517,6 @@ OmniRoute có **210+ tính năng được lên kế hoạch** qua nhiều giai
---
## 📧 Hỗ trợ
> 💬 **Tham gia cộng đồng của chúng tôi!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Nhận trợ giúp, chia sẻ mẹo và luôn cập nhật.
- **Trang web**: [omniroute.online](https://omniroute.online)
- **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- **Vấn đề**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
- **Dự án gốc**: [9router by decolua](https://github.com/decolua/9router)
---
## 👥 Người đóng góp
[![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors)

View File

@@ -110,6 +110,35 @@ _通过 OmniRoute 连接任何 AI 驱动的 IDE 或 CLI 工具 — 免费 API
---
## 🖼️
<div align="center">
<img src="./docs/screenshots/MainOmniRoute.png" alt="OmniRoute" width="800"/>
</div>
---
## 📸
<details>
<summary><b>...</b></summary>
| # | # |
| ----- | ---------------------------------------- |
| **1** | ![1](docs/screenshots/01-providers.png) |
| **2** | ![2](docs/screenshots/02-combos.png) |
| **3** | ![3](docs/screenshots/03-analytics.png) |
| **4** | ![4](docs/screenshots/04-health.png) |
| **5** | ![5](docs/screenshots/05-translator.png) |
| **6** | ![6](docs/screenshots/06-settings.png) |
| **7** | ![7](docs/screenshots/07-cli-tools.png) |
| **8** | ![8](docs/screenshots/08-usage.png) |
| **9** | ![9](docs/screenshots/09-endpoint.png) |
</details>
---
## 🤔 为什么选择 OmniRoute
**停止浪费金钱和遭遇限制:**
@@ -128,6 +157,18 @@ _通过 OmniRoute 连接任何 AI 驱动的 IDE 或 CLI 工具 — 免费 API
---
## 📧 支持
> 💬 **加入我们的社区!** [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)
---
## 🔄 工作原理
```
@@ -157,263 +198,497 @@ _通过 OmniRoute 连接任何 AI 驱动的 IDE 或 CLI 工具 — 免费 API
---
## 🎯 What OmniRoute Solves — 16 Real Pain Points
## 🎯 OmniRoute 解决了什么 — 30 个真正的痛点和用例
> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to zero observability.
> **每个使用 AI 工具的开发人员每天都会面临这些问题。** OmniRoute 的构建是为了解决所有这些问题 - 从成本超支到区域封锁,从损坏的 OAuth 流程到协议操作和企业可观察性。
<details>
<summary><b>💸 1. "I pay for an expensive subscription but still get interrupted by limits"</b></summary>
<summary><b>💸 1.“我支付了昂贵的订阅费用,但仍然受到限制的干扰”</b></summary>
Developers pay $20200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity.
开发人员每月为 Claude ProCodex Pro GitHub Copilot 支付 20-200 美元。即使付费配额也有上限——5 小时的使用时间、每周限制或每分钟的费率限制。在编码会话中,提供商停止响应,开发人员失去流量和生产力。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention
- **Real-Time Quota Tracking** — Shows token consumption in real-time with reset countdown (5h, daily, weekly)
- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next
- **Custom Combos** — Customizable fallback chains with 6 balancing strategies (fill-first, round-robin, P2C, random, least-used, cost-optimized)
- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard
- **智能 4 层回退** — 如果订阅配额用完,自动重定向到 API 密钥 → 便宜 → 免费,零手动干预
- **实时配额跟踪** — 实时显示代币消耗情况并重置倒计时5 小时、每日、每周)
- **多帐户支持** — 每个提供商有多个帐户,具有自动循环 — 当一个帐户用完时,切换到下一个帐户
- **自定义组合** — 可定制的后备链,具有 6 种平衡策略先填充、循环、P2C、随机、最少使用、成本优化
- **Codex Business Quotas** — 直接在仪表板中监控业务/团队工作空间配额
</details>
<details>
<summary><b>🔌 2. "I need to use multiple providers but each has a different API"</b></summary>
<summary><b>🔌 2.“我需要使用多个提供程序,但每个提供程序都有不同的 API</b></summary>
OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints.
OpenAI 使用一种格式,ClaudeAnthropic使用另一种格式Gemini 使用另一种格式。如果开发人员想要测试来自不同提供商的模型或在它们之间进行回退,他们需要重新配置 SDK、更改端点、处理不兼容的格式。自定义提供程序FriendLINIM)具有非标准模型端点。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 36+ providers
- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+
- **Role Normalization** — Converts `developer``system` for non-OpenAI providers; `system``user` for GLM/ERNIE
- **Think Tag Extraction** — Extracts `<think>` blocks from models like DeepSeek R1 into standardized `reasoning_content`
- **Structured Output for Gemini** — `json_schema``responseMimeType`/`responseSchema` automatic conversion
- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs
- **统一端点** — 单个 `http://localhost:20128/v1` 充当所有 36 个以上提供商的代理
- **格式翻译** — 自动且透明:OpenAI ↔ Claude ↔ Gemini ↔ Responses API
- **响应清理** — 删除破坏 OpenAI SDK v1.83+ 的非标准字段(`x_groq``usage_breakdown``service_tier`
- **角色标准化** — 对于非 OpenAI 提供商,将 `developer``system` 转换; `system``user` 适用于 GLM/ERNIE
- **Think Tag Extraction** — 将 DeepSeek R1 等模型中的 `<think>` 块提取为标准化 `reasoning_content`
- **Gemini 的结构化输出** — `json_schema``responseMimeType`/`responseSchema` 自动转换
- **`stream` 默认为 `false`** — 与 OpenAI 规范保持一致,避免 Python/Rust/Go SDK 中出现意外的 SSE
</details>
<details>
<summary><b>🌐 3. "My AI provider blocks my region/country"</b></summary>
<summary><b>🌐 3.“我的人工智能提供商封锁了我的地区/国家”</b></summary>
Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries.
OpenAI/Codex 等提供商会阻止来自某些地理区域的访问。用户在 OAuth 和 API 连接期间收到类似 `unsupported_country_region_territory` 的错误。这对于发展中国家的开发商来说尤其令人沮丧。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key
- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP
- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory`
- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass)
- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing
- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection
- **3 级代理配置** — 3 级可配置代理:全局(所有流量)、每个提供商(仅一个提供商)和每个连接/密钥
- **颜色编码的代理徽章** — 视觉指示器:🟢 全局代理、🟡 提供商代理、🔵 连接代理,始终显示 IP
- **通过代理进行 OAuth 令牌交换** — OAuth 流程也通过代理,解决了 `unsupported_country_region_territory`
- **通过代理进行连接测试** — 连接测试使用配置的代理(不再直接绕过)
- **SOCKS5 支持** — 对出站路由的完整 SOCKS5 代理支持
- **TLS 指纹欺骗** — 通过 `wreq-js` 的类似浏览器的 TLS 指纹来绕过机器人检测
</details>
<details>
<summary><b>🆓 4. "I want to use AI for coding but I have no money"</b></summary>
<summary><b>🆓 4.“我想用AI编码但我没有钱”</b></summary>
Not everyone can pay $20200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost.
并不是每个人都能每月支付 20-200 美元来订阅 AI。来自新兴国家的学生、开发人员、业余爱好者和自由职业者需要以零成本获得优质模型。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Free Tier Providers Built-in** — Native support for 100% free providers: iFlow (8 unlimited models), Qwen (3 unlimited models), Kiro (Claude for free), Gemini CLI (180K/month free)
- **Free-Only Combos** — Chain `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = $0/month with zero downtime
- **NVIDIA NIM Free Credits** — 1000 free credits integrated
- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider
- **内置免费层级提供商** — 对 100% 免费提供商的本机支持iFlow8 个无限型号、Qwen3 个无限型号)、KiroClaude 免费)、Gemini CLI180K/月免费)
- **仅限免费组合** — 链 `gc/gemini-3-flash → if/kimi-k2-thinking → qw/qwen3-coder-plus` = 0 美元/月,零停机时间
- **NVIDIA NIM 免费积分** — 集成 1000 个免费积分
- **成本优化策略** — 自动选择最便宜的可用提供商的路由策略
</details>
<details>
<summary><b>🔒 5. "I need to protect my AI gateway from unauthorized access"</b></summary>
<summary><b>🔒 5.“我需要保护我的AI网关免遭未经授权的访问”</b></summary>
When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse.
当将人工智能网关暴露到网络(LANVPSDocker)时,任何拥有该地址的人都可以消耗开发者的代币/配额。如果没有保护API 很容易被误用、提示注入和滥用。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page
- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle
- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing
- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens
- **Rate Limiter** — Per-IP rate limiting with configurable windows
- **IP Filtering** — Allowlist/blocklist for access control
- **Prompt Injection Guard** — Sanitization against malicious prompt patterns
- **AES-256-GCM Encryption** — Credentials encrypted at rest
- **API 密钥管理** — 使用专用的 `/dashboard/api-manager` 页面为每个提供商生成、轮换和范围界定
- **模型级权限** — 将 API 密钥限制为特定模型(`openai/*`、通配符模式),并具有“允许全部”/“限制”切换功能
- **API 端点保护** — 需要 `/v1/models` 的密钥并阻止列表中的特定提供商
- **Auth Guard + CSRF 保护** — 所有仪表板路由均受 `withAuth` 中间件 + CSRF 令牌保护
- **速率限制器** — 通过可配置窗口限制每个 IP 的速率
- **IP 过滤** — 用于访问控制的允许列表/阻止列表
- **Prompt Injection Guard** — 针对恶意提示模式的清理
- **AES-256-GCM 加密** — 静态加密的凭证
</details>
<details>
<summary><b>🛑 6. "My provider went down and I lost my coding flow"</b></summary>
<summary><b>🛑 6.“我的提供商宕机了,我失去了编码流程”</b></summary>
AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application.
AI 提供商可能会变得不稳定、返回 5xx 错误或达到临时速率限制。如果开发人员依赖于单一提供商,他们就会受到干扰。如果没有断路器,重复重试可能会使应用程序崩溃。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Circuit Breaker per-provider** — Auto-open/close with configurable thresholds and cooldown (Closed/Open/Half-Open)
- **Exponential Backoff** — Progressive retry delays
- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms
- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention
- **Combo Circuit Breaker** — Auto-disables failing providers within a combo chain
- **Health Dashboard** — Uptime monitoring, circuit breaker states, lockouts, cache stats, p50/p95/p99 latency
- **每个提供商的断路器** — 自动打开/关闭,具有可配置的阈值和冷却时间(关闭/打开/半打开)
- **指数退避** — 渐进式重试延迟
- **Anti-Thundering Herd** — 互斥锁 + 信号量保护,防止并发重试风暴
- **组合后备链** — 如果主要提供商发生故障,则自动从该链中掉下来,无需干预
- **组合断路器** — 自动禁用组合链中出现故障的提供商
- **运行状况仪表板** — 正常运行时间监控、断路器状态、锁定、缓存统计、p50/p95/p99 延迟
</details>
<details>
<summary><b>🔧 7. "Configuring each AI tool is tedious and repetitive"</b></summary>
<summary><b>🔧 7. “配置每个AI工具都是繁琐且重复的”</b></summary>
Developers use Cursor, Claude Code, Codex CLI, OpenClaw, Gemini CLI, Kilo Code... Each tool needs a different config (API endpoint, key, model). Reconfiguring when switching providers or models is a waste of time.
开发人员使用 CursorClaude CodeCodex CLIOpenClawGemini CLIKilo Code...每个工具都需要不同的配置API 端点、密钥、模型)。切换提供商或模型时重新配置是浪费时间。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline
- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection
- **Onboarding Wizard** — Guided 4-step setup for first-time users
- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 36+ providers
- **CLI 工具仪表板** — 专用页面,可一键设置 Claude CodeCodex CLIOpenClawKilo CodeAntigravityCline
- **GitHub Copilot 配置生成器** — 通过批量模型选择为 VS Code 生成 `chatLanguageModels.json`
- **入门向导** — 为首次使用的用户提供 4 步设置指导
- **一个端点,所有型号** — 配置 `http://localhost:20128/v1` 一次,访问 36 个以上提供商
</details>
<details>
<summary><b>🔑 8. "Managing OAuth tokens from multiple providers is hell"</b></summary>
<summary><b>🔑 8.“管理来自多个提供商的 OAuth 令牌简直就是地狱”</b></summary>
Claude Code, Codex, Gemini CLI, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic.
Claude CodeCodexGemini CLICopilot — 全部使用带有过期令牌的 OAuth 2.0。开发人员需要不断地重新进行身份验证,处理`client_secret is missing``redirect_uri_mismatch`以及远程服务器上的故障。 LAN/VPS 上的 OAuth 问题尤其严重。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Auto Token Refresh** — OAuth tokens refresh in background before expiration
- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Gemini CLI, Copilot, Kiro, Qwen, iFlow
- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction
- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers
- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility
- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker
- **自动令牌刷新** — OAuth 令牌在过期前在后台刷新
- **OAuth 2.0 (PKCE) 内置** — Claude CodeCodexGemini CLICopilotKiroQweniFlow 的自动流程
- **多帐户 OAuth** — 每个提供商通过 JWT/ID 令牌提取多个帐户
- **OAuth LAN/远程修复** — `redirect_uri` 的私有 IP 检测 + 远程服务器的手动 URL 模式
- **Nginx 背后的 OAuth** — 使用 `window.location.origin` 实现反向代理兼容性
- **远程 OAuth 指南** — VPS/Docker 上的 Google Cloud 凭据分步指南
</details>
<details>
<summary><b>📊 9. "I don't know how much I'm spending or where"</b></summary>
<summary><b>📊 9.“我不知道我花了多少钱或在哪里”</b></summary>
Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up.
开发商使用多个付费提供商,但对支出没有统一的看法。每个提供商都有自己的计费仪表板,但没有统一的视图。意外的成本可能会不断增加。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider
- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback
- **Per-Model Pricing Configuration** — Configurable prices per model
- **Usage Statistics Per API Key** — Request count and last-used timestamp per key
- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency
- **成本分析仪表板** — 每个提供商的每个代币成本跟踪和预算管理
- **每层预算限制** — 触发自动回退的每层支出上限
- **按型号定价配置** — 每个型号的可配置价格
- **每个 API 密钥的使用统计信息** — 每个密钥的请求计数和上次使用的时间戳
- **分析仪表板** — 统计卡、模型使用图表、包含成功率和延迟的提供商表
</details>
<details>
<summary><b>🐛 10. "I can't diagnose errors and problems in AI calls"</b></summary>
<summary><b>🐛 10.“我无法诊断人工智能调用中的错误和问题”</b></summary>
When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error.
当调用失败时,开发人员不知道这是否是速率限制、令牌过期、格式错误或提供商错误。跨不同终端的碎片日志。如果没有可观察性,调试就是反复试验。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console
- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter
- **SQLite Proxy Logs** — Persistent logs that survive server restarts
- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time)
- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing
- **File-Based Logging with Rotation** — Console interceptor captures everything to JSON log with size-based rotation
- **统一日志仪表板** — 4 个选项卡:请求日志、代理日志、审核日志、控制台
- **控制台日志查看器** — 实时终端式查看器,具有颜色编码级别、自动滚动、搜索、过滤功能
- **SQLite 代理日志** — 服务器重新启动后仍保留的持久日志
- **Translator Playground** — 4 种调试模式Playground格式翻译、Chat Tester往返、Test Bench批量、Live Monitor实时
- **请求遥测** — p50/p95/p99 延迟 + X-Request-Id 跟踪
- **基于文件的日志记录与旋转** — 控制台拦截器通过基于大小的旋转将所有内容捕获到 JSON 日志
</details>
<details>
<summary><b>🏗️ 11. "Deploying and maintaining the gateway is complex"</b></summary>
<summary><b>🏗️ 11.“部署和维护网关很复杂”</b></summary>
Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction.
跨不同环境(本地、VPSDocker、云)安装、配置和维护 AI 代理是一项劳动密集型工作。硬编码路径、目录上的 `EACCES`、端口冲突和跨平台构建等问题会增加摩擦。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **npm global install** — `npm install -g omniroute && omniroute`done
- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi)
- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw)
- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode
- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking)
- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers
- **DB Backups** — Automatic backup, restore, export and import of all settings
- **npm 全局安装** — `npm install -g omniroute && omniroute`完成
- **Docker 多平台** — AMD64 + ARM64 本机(Apple SiliconAWS GravitonRaspberry Pi
- **Docker Compose Profiles** — `base`(无 CLI 工具)和 `cli`(带有 Claude CodeCodexOpenClaw
- **Electron 桌面应用程序** — 适用于 Windows/macOS/Linux 的本机应用程序,带系统托盘、自动启动、离线模式
- **分割端口模式** — API 和仪表板位于单独的端口上,适用于高级场景(反向代理、容器网络)
- **云同步** — 通过 Cloudflare Workers 跨设备配置同步
- **数据库备份** — 自动备份、恢复、导出和导入所有设置
</details>
<details>
<summary><b>🌍 12. "The interface is English-only and my team doesn't speak English"</b></summary>
<summary><b>🌍 12.“界面只有英文,我的团队不会说英语”</b></summary>
Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors.
非英语国家的团队,尤其是拉丁美洲、亚洲和欧洲的团队,在纯英文界面上遇到了困难。语言障碍会降低采用率并增加配置错误。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English
- **RTL Support** — Right-to-left support for Arabic and Hebrew
- **Multi-Language READMEs** — 30 complete documentation translations
- **Language Selector** — Globe icon in header for real-time switching
- **仪表板 i18n — 30 种语言** — 所有 500 多个按键已翻译包括阿拉伯语、保加利亚语、丹麦语、德语、西班牙语、芬兰语、法语、希伯来语、印地语、匈牙利语、印度尼西亚语、意大利语、日语、韩语、马来语、荷兰语、挪威语、波兰语、葡萄牙语PT/BR、罗马尼亚语、俄语、斯洛伐克语、瑞典语、泰语、乌克兰语、越南语、中文、菲律宾语、英语
- **RTL 支持** — 从右到左支持阿拉伯语和希伯来语
- **多语言自述文件** — 30 个完整的文档翻译
- **语言选择器** — 标题中的地球图标用于实时切换
</details>
<details>
<summary><b>🔄 13. "I need more than chat — I need embeddings, images, audio"</b></summary>
<summary><b>🔄 13.“我需要的不仅仅是聊天 - 我需要嵌入、图像、音频”</b></summary>
AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format.
人工智能不仅仅是完成聊天。开发人员需要生成图像、转录音频、为 RAG 创建嵌入、重新排列文档以及审核内容。每个 API 都有不同的端点和格式。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models
- **Image Generation** — `/v1/images/generations` with 4 providers and 9+ models
- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper-compatible
- **Text-to-Speech** — `/v1/audio/speech` — Multi-provider audio synthesis
- **Moderations** — `/v1/moderations` — Content safety checks
- **Reranking** — `/v1/rerank` — Document relevance reranking
- **Responses API** — Full `/v1/responses` support for Codex
- **嵌入** — `/v1/embeddings` 具有 6 个提供商和 9 个以上模型
- **图像生成** — `/v1/images/generations` 具有 10 个提供商和 20 多个模型OpenAI、xAI、Together、Fireworks、Nebius、Hyperbolic、NanoBanana、Antigravity、SD WebUI、ComfyUI
- **文本到视频** — `/v1/videos/generations` — ComfyUIAnimateDiff、SVD和 SD WebUI
- **文本转音乐** — `/v1/music/generations` — ComfyUI稳定音频打开MusicGen
- **音频转录** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM、HuggingFace、Qwen3
- **文本转语音** — `/v1/audio/speech` — ElevenLabs、Nvidia NIM、HuggingFace、Coqui、Tortoise、Qwen3 以及现有提供商
- **审核** — `/v1/moderations` — 内容安全检查
- **重新排名** — `/v1/rerank` — 文档相关性重新排名
- **响应 API** — 对 Codex 的完整 `/v1/responses` 支持
</details>
<details>
<summary><b>🧪 14. "I have no way to test and compare quality across models"</b></summary>
<summary><b>🧪 14.“我无法测试和比较不同型号的质量”</b></summary>
Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist.
开发人员想知道哪种模型最适合他们的用例(代码、翻译、推理),但手动比较速度很慢。不存在集成的评估工具。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal
- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function)
- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison
- **Chat Tester** — Full round-trip with visual response rendering
- **Live Monitor** — Real-time stream of all requests flowing through the proxy
- **LLM 评估** — 黄金套装测试,包含 10 个预加载案例涵盖问候语、数学、地理、代码生成、JSON 合规性、翻译、降价、安全拒绝
- **4种匹配策略** — `exact``contains``regex``custom`JS函数
- **Translator Playground 测试台** — 使用多个输入和预期输出进行批量测试、跨提供商比较
- **聊天测试器** — 带有视觉响应渲染的完整往返
- **实时监控** — 流经代理的所有请求的实时流
</details>
<details>
<summary><b>📈 15. "I need to scale without losing performance"</b></summary>
<summary><b>📈 15.“我需要在不损失性能的情况下进行扩展”</b></summary>
As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected.
随着请求量的增长,如果不缓存相同的问题,就会产生重复的成本。如果没有幂等性,重复的请求就会浪费处理。必须遵守每个提供商的速率限制。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency
- **Request Idempotency** — 5s deduplication window for identical requests
- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking
- **Editable Rate Limits** — Configurable defaults in Settings → Resilience with persistence
- **API Key Validation Cache** — 3-tier cache for production performance
- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime
- **语义缓存** - 两层缓存(签名+语义)降低成本和延迟
- **请求幂等性** — 相同请求的 5 秒重复数据删除窗口
- **速率限制检测** — 每个提供商的 RPM、最小间隙和最大并发跟踪
- **可编辑的速率限制** — 可在“设置”→“持久弹性”中配置默认值
- **API 密钥验证缓存** — 用于提高生产性能的 3 层缓存
- **带有遥测功能的运行状况仪表板** — p50/p95/p99 延迟、缓存统计数据、正常运行时间
</details>
<details>
<summary><b>🤖 16. "I want to control model behavior globally"</b></summary>
<summary><b>🤖 16.“我想全局控制模型行为”</b></summary>
Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical.
希望所有响应都以特定语言、特定语气或想要限制推理标记的开发人员。在每个工具/请求中配置此功能是不切实际的。
**How OmniRoute solves it:**
**OmniRoute 如何解决:**
- **System Prompt Injection** — Global prompt applied to all requests
- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive)
- **6 Routing Strategies** — Global strategies that determine how requests are distributed
- **Wildcard Router** — `provider/*` patterns route dynamically to any provider
- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard
- **Provider Toggle** — Enable/disable all connections for a provider with one click
- **Blocked Providers** — Exclude specific providers from `/v1/models` listing
- **系统提示注入** — 全局提示应用于所有请求
- **思考预算验证** - 每个请求的推理令牌分配控制(直通、自动、自定义、自适应)
- **6 种路由策略** — 确定如何分发请求的全局策略
- **通配符路由器** — `provider/*` 模式动态路由到任何提供商
- **组合启用/禁用切换** — 直接从仪表板切换组合
- **提供商切换** — 一键启用/禁用提供商的所有连接
- **阻止的提供商** — 从 `/v1/models` 列表中排除特定提供商
</details>
<details>
<summary><b>🧰 17.“我需要MCP工具作为一流的产品能力”</b></summary>
许多 AI 网关仅将 MCP 作为隐藏的实现细节公开。团队需要一个可见的、可管理的操作层。
**OmniRoute 如何解决:**
- MCP 显示在仪表板导航和端点协议选项卡中
- 专用 MCP 管理页面,包含流程、工具、范围和审计
- `omniroute --mcp` 和客户入门的内置快速启动
</details>
<details>
<summary><b>🧠 18.“我需要具有同步+流任务路径的 A2A 编排”</b></summary>
代理工作流程需要直接回复和具有生命周期控制的长时间运行的流式执行。
**OmniRoute 如何解决:**
- A2A JSON-RPC 端点 (`POST /a2a`) 与 `message/send``message/stream`
- 具有终端状态传播的 SSE 流式传输
- `tasks/get``tasks/cancel` 的任务生命周期 API
</details>
<details>
<summary><b>🛰️ 19.“我需要真实的 MCP 进程运行状况,而不是猜测的状态”</b></summary>
运营团队需要知道 MCP 是否确实存在,而不仅仅是 API 是否可访问。
**OmniRoute 如何解决:**
- 带有 PID、时间戳、传输、工具计数和范围模式的运行时心跳文件
- MCP状态API结合心跳+最近的活动
- 用于流程/正常运行时间/心跳新鲜度的 UI 状态卡
</details>
<details>
<summary><b>📋 20.“我需要可审核的 MCP 工具执行”</b></summary>
当工具改变配置或触发操作操作时,团队需要取证可追溯性。
**OmniRoute 如何解决:**
- SQLite 支持的 MCP 工具调用审核日志记录
- 按工具、成功/失败、API 密钥和分页过滤
- 仪表板审核表+自动化统计端点
</details>
<details>
<summary><b>🔐 21.“每次集成我都需要范围内的 MCP 权限”</b></summary>
不同的客户端应该具有对工具类别的最低权限访问权限。
**OmniRoute 如何解决:**
- 9 个粒度 MCP 范围,用于受控工具访问
- MCP 管理 UI 中的范围执行和可见性
- 操作工具的安全默认姿势
</details>
<details>
<summary><b>⚙️ 22.“我需要操作控制而不重新部署”</b></summary>
团队需要在事件或成本事件期间快速更改运行时。
**OmniRoute 如何解决:**
- 直接从 MCP 仪表板切换组合激活
- 应用预定义策略包中的弹性配置文件
- 从同一操作面板重置断路器状态
</details>
<details>
<summary><b>🔄 23.“我需要实时 A2A 任务生命周期可见性和取消”</b></summary>
如果没有生命周期可见性,任务事件就很难分类。
**OmniRoute 如何解决:**
- 任务列表/按状态/技能过滤并分页
- 深入了解任务元数据、事件和工件
- 任务取消端点和带有确认的 UI 操作
</details>
<details>
<summary><b>🌊 24.“我需要 A2A 负载的活动流指标”</b></summary>
流媒体工作流程需要对并发和实时连接的操作洞察。
**OmniRoute 如何解决:**
- 活动流计数器集成到 A2A 状态中
- 最后任务时间戳和每个状态计数
- 用于实时操作监控的 A2A 仪表板卡
</details>
<details>
<summary><b>🪪 25.“我需要为客户发现标准代理”</b></summary>
外部客户端和协调器需要机器可读的元数据来进行引导。
**OmniRoute 如何解决:**
- 特工卡暴露在`/.well-known/agent.json`
- 管理 UI 中显示的能力和技能
- A2A 状态 API 包括用于自动化的发现元数据
</details>
<details>
<summary><b>🧭 26.“我需要产品 UX 中的协议可发现性”</b></summary>
如果用户无法发现协议表面,采用和支持质量就会下降。
**OmniRoute 如何解决:**
- MCP 和 A2A 的侧边栏条目
- 端点页面“协议”选项卡包含快速启动和状态
- 从概述到专用管理仪表板的链接
</details>
<details>
<summary><b>🧪 27.“我需要与真实客户端进行端到端协议验证”</b></summary>
模拟测试不足以在发布前验证协议兼容性。
**OmniRoute 如何解决:**
- E2E 套件,可启动应用程序并使用真正的 MCP SDK 客户端传输
- A2A 客户端测试发现、发送、流式传输、获取和取消流程
- 针对 MCP 审计和 A2A 任务 API 交叉检查断言
</details>
<details>
<summary><b>📡 28.“我需要跨所有接口的统一可观察性”</b></summary>
按协议分割可观察性会产生盲点和更长的 MTTR。
**OmniRoute 如何解决:**
- 一个产品中的统一仪表板/日志/分析
- 跨 OpenAI、MCP 和 A2A 层的运行状况 + 审计 + 请求遥测
- 用于状态和自动化的操作 API
</details>
<details>
<summary><b>💼 29.“我需要一个用于代理+工具+代理编排的运行时”</b></summary>
运行许多单独的服务会增加运营成本和故障模式。
**OmniRoute 如何解决:**
- 兼容 OpenAI 的代理、MCP 服务器和 A2A 服务器位于一个堆栈中
- 共享身份验证、弹性、数据存储和可观察性
- 所有交互界面上一致的策略模型
</details>
<details>
<summary><b>🚀 30.“我需要在没有胶水代码蔓延的情况下交付代理工作流程”</b></summary>
拼接多个临时服务和脚本时,团队会失去速度。
**OmniRoute 如何解决:**
- 客户端和代理的统一端点策略
- 内置协议管理 UI 和烟雾验证路径
- 生产就绪的基础(安全性、日志记录、弹性、备份)
</details>
### 示例手册(集成用例)
**剧本 A最大化付费订阅 + 廉价备份**
```txt
Combo: "maximize-claude"
1. cc/claude-opus-4-6
2. glm/glm-4.7
3. if/kimi-k2-thinking
Monthly cost: $20 + small backup spend
Outcome: higher quality, near-zero interruption
```
**剧本 B零成本编码堆栈**
```txt
Combo: "free-forever"
1. gc/gemini-3-flash
2. if/kimi-k2-thinking
3. qw/qwen3-coder-plus
Monthly cost: $0
Outcome: stable free coding workflow
```
**剧本 C24/7 始终在线的后备链**
```txt
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. if/kimi-k2-thinking
Outcome: deep fallback depth for deadline-critical workloads
```
**剧本 D使用 MCP + A2A 的特工操作**
```txt
1) Start MCP transport (`omniroute --mcp`) for tool-driven operations
2) Run A2A tasks via `message/send` and `message/stream`
3) Observe via /dashboard/mcp and /dashboard/a2a
4) Control incidents with resilience profile + task cancellation
```
---
## ⚡ 快速开始
**1. 全局安装:**
@@ -506,7 +781,7 @@ docker compose --profile cli up -d
---
## 🖥️ 桌面应用 — 离线 & 始终在线
## 🖥️
> 🆕 **全新!** OmniRoute 现已提供适用于 Windows、macOS 和 Linux 的**原生桌面应用程序**。
@@ -696,66 +971,26 @@ Combo: "my-coding-stack"
</details>
---
## 🧪 评估 (Evals)
## 🎯 使用场景
OmniRoute 包含内置评估框架,用于针对黄金集测试 LLM 响应质量。通过仪表板中的 **Analytics → Evals** 访问。
### 场景 1"我有 Claude Pro 订阅"
### 内置黄金集
**问题:** 配额未使用就过期,编程高峰期遇到速率限制
预加载的「OmniRoute Golden Set」包含 10 个测试用例:
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (充分使用订阅)
2. glm/glm-4.7 (配额用完时的便宜备用)
3. if/kimi-k2-thinking (免费应急后备)
- 问候、数学、地理、代码生成
- JSON 格式合规性、翻译、markdown
- 安全拒绝(有害内容)、计数、布尔逻辑
每月成本:$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...
```
| 策略 | 描述 | 示例 |
| ---------- | -------------------------------- | -------------------------------- |
| `exact` | 输出必须完全匹配 | `"4"` |
| `contains` | 输出必须包含子串(不区分大小写) | `"Paris"` |
| `regex` | 输出必须匹配正则表达式模式 | `"1.*2.*3"` |
| `custom` | 自定义 JS 函数返回 true/false | `(output) => output.length > 10` |
---
@@ -1039,29 +1274,6 @@ codex "your prompt"
---
## 🧪 评估 (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>
@@ -1117,7 +1329,7 @@ OmniRoute 包含内置评估框架,用于针对黄金集测试 LLM 响应质
---
## 🛠️ 技术栈
## 🛠️
- **运行时**: Node.js 20+
- **语言**: TypeScript 5.9 — `src/``open-sse/`**100% TypeScript**v1.0.6
@@ -1136,29 +1348,20 @@ OmniRoute 包含内置评估框架,用于针对黄金集测试 LLM 响应质
## 📖 文档
| 文档 | 描述 |
| ----------------------------------- | ---------------------------- |
| [用户指南](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) | 漏洞报告和安全实践 |
| 文档 | 描述 |
| ----------------------------------- | ------------------------------------------------------ |
| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format |
| [用户指南](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)
---
## 🗺️
## 👥 贡献者

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,6 +7,7 @@
* 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
*/
@@ -86,9 +87,17 @@ if (args.includes("--help") || args.includes("-h")) {
omniroute Start the server
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)
@@ -116,6 +125,18 @@ if (args.includes("--version") || args.includes("-v")) {
process.exit(0);
}
// ── 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;

View File

@@ -2,7 +2,7 @@
🌐 **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-02-18_
_Last updated: 2026-03-04_
## Executive Summary
@@ -81,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]
@@ -144,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`
@@ -225,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):
@@ -505,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
@@ -522,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]
@@ -550,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
@@ -582,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)
@@ -724,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
@@ -762,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

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

@@ -10,7 +10,7 @@ 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` |
@@ -120,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`)
---

View File

@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: OmniRoute API
version: 0.5.0
version: 2.0.0
description: |
OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible
endpoint that routes requests to multiple AI providers with load balancing,

View File

@@ -55,7 +55,7 @@ When you are running with \`approval_policy == on-request\`, and sandboxing enab
- You are about to take a potentially destructive action such as an \`rm\` or \`git reset\` that the user did not explicitly ask for
- (for all of these, you should weigh alternative paths that do not require approval)
When \`sandbox_mode\` is set to read-only, you'll need to request approval for any command that isn't a read.
When \`sandbox_mode\` is set to read-only, you'll need to request approval for each command that isn't a read.
You will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing enabled, and approval on-failure.
@@ -68,7 +68,7 @@ When requesting approval to execute a command that will require escalated privil
## Special user requests
- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as \`date\`), you should do so.
- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps.
- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention residual risks or testing gaps.
## Frontend tasks
When doing frontend design tasks, avoid collapsing into "AI slop" or safe, average-looking layouts.

View File

@@ -157,7 +157,7 @@ export function parseImageModel(modelStr) {
}
}
// No provider prefix — try to find the model in any provider
// No provider prefix — try to find the model in every provider
for (const [providerId, config] of Object.entries(IMAGE_PROVIDERS)) {
if (config.models.some((m) => m.id === modelStr)) {
return { provider: providerId, model: modelStr };

View File

@@ -1,4 +1,4 @@
import { generateModels, generateAliasMap } from "./providerRegistry.ts";
import { generateModels, generateAliasMap, type RegistryModel } from "./providerRegistry.ts";
// Provider models - Generated from providerRegistry.js (single source of truth)
export const PROVIDER_MODELS = generateModels();
@@ -7,37 +7,41 @@ export const PROVIDER_MODELS = generateModels();
export const PROVIDER_ID_TO_ALIAS = generateAliasMap();
// Helper functions
export function getProviderModels(aliasOrId) {
export function getProviderModels(aliasOrId: string): RegistryModel[] {
return PROVIDER_MODELS[aliasOrId] || [];
}
export function getDefaultModel(aliasOrId) {
export function getDefaultModel(aliasOrId: string): string | null {
const models = PROVIDER_MODELS[aliasOrId];
return models?.[0]?.id || null;
}
export function isValidModel(aliasOrId, modelId, passthroughProviders = new Set()) {
export function isValidModel(
aliasOrId: string,
modelId: string,
passthroughProviders = new Set<string>()
): boolean {
if (passthroughProviders.has(aliasOrId)) return true;
const models = PROVIDER_MODELS[aliasOrId];
if (!models) return false;
return models.some((m) => m.id === modelId);
}
export function findModelName(aliasOrId, modelId) {
export function findModelName(aliasOrId: string, modelId: string): string {
const models = PROVIDER_MODELS[aliasOrId];
if (!models) return modelId;
const found = models.find((m) => m.id === modelId);
return found?.name || modelId;
}
export function getModelTargetFormat(aliasOrId, modelId) {
export function getModelTargetFormat(aliasOrId: string, modelId: string): string | null {
const models = PROVIDER_MODELS[aliasOrId];
if (!models) return null;
const found = models.find((m) => m.id === modelId);
return found?.targetFormat || null;
}
export function getModelsByProviderId(providerId) {
export function getModelsByProviderId(providerId: string): RegistryModel[] {
const alias = PROVIDER_ID_TO_ALIAS[providerId] || providerId;
return PROVIDER_MODELS[alias] || [];
}

View File

@@ -49,6 +49,21 @@ export interface RegistryEntry {
passthroughModels?: boolean;
}
interface LegacyProvider {
format: string;
baseUrl?: string;
baseUrls?: string[];
responsesBaseUrl?: string;
headers?: Record<string, string>;
clientId?: string;
clientSecret?: string;
tokenUrl?: string;
refreshUrl?: string;
authUrl?: string;
chatPath?: string;
clientVersion?: string;
}
// ── Registry ──────────────────────────────────────────────────────────────
export const REGISTRY: Record<string, RegistryEntry> = {
@@ -108,7 +123,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
clientIdEnv: "GEMINI_OAUTH_CLIENT_ID",
clientIdDefault: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
clientSecretEnv: "GEMINI_OAUTH_CLIENT_SECRET",
clientSecretDefault: "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",
clientSecretDefault: "",
},
models: [
{ id: "gemini-3.1-pro", name: "Gemini 3.1 Pro" },
@@ -137,7 +152,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
clientIdEnv: "GEMINI_CLI_OAUTH_CLIENT_ID",
clientIdDefault: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
clientSecretEnv: "GEMINI_CLI_OAUTH_CLIENT_SECRET",
clientSecretDefault: "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",
clientSecretDefault: "",
},
models: [
{ id: "gemini-3.1-pro", name: "Gemini 3.1 Pro" },
@@ -228,7 +243,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
clientIdEnv: "IFLOW_OAUTH_CLIENT_ID",
clientIdDefault: "10009311001",
clientSecretEnv: "IFLOW_OAUTH_CLIENT_SECRET",
clientSecretDefault: "4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW",
clientSecretDefault: "",
tokenUrl: "https://iflow.cn/oauth/token",
authUrl: "https://iflow.cn/oauth",
},
@@ -266,7 +281,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
clientIdEnv: "ANTIGRAVITY_OAUTH_CLIENT_ID",
clientIdDefault: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com",
clientSecretEnv: "ANTIGRAVITY_OAUTH_CLIENT_SECRET",
clientSecretDefault: "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",
clientSecretDefault: "",
},
models: [
{ id: "claude-opus-4-6-thinking", name: "Claude Opus 4.6 Thinking" },
@@ -641,6 +656,25 @@ export const REGISTRY: Record<string, RegistryEntry> = {
],
},
blackbox: {
id: "blackbox",
alias: "bb",
format: "openai",
executor: "default",
baseUrl: "https://api.blackbox.ai/v1/chat/completions",
modelsUrl: "https://api.blackbox.ai/v1/models",
authType: "apikey",
authHeader: "bearer",
models: [
{ id: "gpt-4o", name: "GPT-4o" },
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash" },
{ id: "claude-sonnet-4", name: "Claude Sonnet 4" },
{ id: "deepseek-v3", name: "DeepSeek V3" },
{ id: "blackboxai", name: "Blackbox AI" },
{ id: "blackboxai-pro", name: "Blackbox AI Pro" },
],
},
xai: {
id: "xai",
alias: "xai",
@@ -825,10 +859,10 @@ export const REGISTRY: Record<string, RegistryEntry> = {
// ── Generator Functions ───────────────────────────────────────────────────
/** Generate legacy PROVIDERS object shape for constants.js backward compatibility */
export function generateLegacyProviders(): Record<string, any> {
const providers: Record<string, any> = {};
export function generateLegacyProviders(): Record<string, LegacyProvider> {
const providers: Record<string, LegacyProvider> = {};
for (const [id, entry] of Object.entries(REGISTRY)) {
const p: Record<string, any> = { format: entry.format };
const p: LegacyProvider = { format: entry.format };
// URL(s)
if (entry.baseUrls) {
@@ -898,7 +932,7 @@ export function generateAliasMap(): Record<string, string> {
// ── Registry Lookup Helpers ───────────────────────────────────────────────
const _byAlias = new Map();
const _byAlias = new Map<string, RegistryEntry>();
for (const entry of Object.values(REGISTRY)) {
if (entry.alias && entry.alias !== entry.id) {
_byAlias.set(entry.alias, entry);

View File

@@ -37,7 +37,7 @@ export function parseModelFromRegistry<P extends BaseProvider>(
}
}
// No provider prefix — try to find the model in any provider
// No provider prefix — try to find the model in every provider
for (const [providerId, config] of Object.entries(registry)) {
if (config.models.some((m) => m.id === modelStr)) {
return { provider: providerId, model: modelStr };

View File

@@ -5,7 +5,7 @@ import { PROVIDERS, OAUTH_ENDPOINTS, HTTP_STATUS } from "../config/constants.ts"
const MAX_RETRY_AFTER_MS = 10000;
/**
* Strip any provider prefix (e.g. "antigravity/model" → "model").
* Strip provider prefixes (e.g. "antigravity/model" → "model").
* Ensures the model name sent to the upstream API never contains a routing prefix.
*/
function cleanModelName(model: string): string {
@@ -36,7 +36,18 @@ export class AntigravityExecutor extends BaseExecutor {
}
transformRequest(model, body, stream, credentials) {
const projectId = credentials?.projectId || this.generateProjectId();
const bodyProjectId = body?.project;
const credentialsProjectId = credentials?.projectId;
const hasExplicitProject = !!(bodyProjectId || credentialsProjectId);
const projectId = bodyProjectId || credentialsProjectId || this.generateProjectId();
if (!hasExplicitProject) {
console.warn(
`[Antigravity] ⚠️ No projectId provided via body or credentials — using generated fallback "${projectId}". ` +
`This may cause 404 errors if the account has no active GCP project. ` +
`Ensure the OAuth token includes a valid project or the request includes a project field.`
);
}
// Fix contents for Claude models via Antigravity
const normalizedContents =

View File

@@ -1,15 +1,75 @@
import { HTTP_STATUS, FETCH_TIMEOUT_MS } from "../config/constants.ts";
type JsonRecord = Record<string, unknown>;
export type ProviderConfig = {
id?: string;
baseUrl?: string;
baseUrls?: string[];
responsesBaseUrl?: string;
chatPath?: string;
clientVersion?: string;
clientId?: string;
clientSecret?: string;
tokenUrl?: string;
refreshUrl?: string;
authUrl?: string;
headers?: Record<string, string>;
};
export type ProviderCredentials = {
accessToken?: string;
refreshToken?: string;
apiKey?: string;
expiresAt?: string;
providerSpecificData?: JsonRecord;
};
export type ExecutorLog = {
debug?: (tag: string, message: string) => void;
info?: (tag: string, message: string) => void;
warn?: (tag: string, message: string) => void;
error?: (tag: string, message: string) => void;
};
export type ExecuteInput = {
model: string;
body: unknown;
stream: boolean;
credentials: ProviderCredentials;
signal?: AbortSignal | null;
log?: ExecutorLog | null;
};
function mergeAbortSignals(primary: AbortSignal, secondary: AbortSignal): AbortSignal {
const controller = new AbortController();
const abortBoth = () => {
if (!controller.signal.aborted) {
controller.abort();
}
};
if (primary.aborted || secondary.aborted) {
abortBoth();
return controller.signal;
}
primary.addEventListener("abort", abortBoth, { once: true });
secondary.addEventListener("abort", abortBoth, { once: true });
return controller.signal;
}
/**
* BaseExecutor - Base class for provider executors.
* Implements the Strategy pattern: subclasses override specific methods
* (buildUrl, buildHeaders, transformRequest, etc.) for each provider.
*/
export class BaseExecutor {
provider: any;
config: any;
provider: string;
config: ProviderConfig;
constructor(provider: any, config: any) {
constructor(provider: string, config: ProviderConfig) {
this.provider = provider;
this.config = config;
}
@@ -26,9 +86,19 @@ export class BaseExecutor {
return this.getBaseUrls().length || 1;
}
buildUrl(model, stream, urlIndex = 0, credentials = null) {
buildUrl(
model: string,
stream: boolean,
urlIndex = 0,
credentials: ProviderCredentials | null = null
) {
void model;
void stream;
if (this.provider?.startsWith?.("openai-compatible-")) {
const baseUrl = credentials?.providerSpecificData?.baseUrl || "https://api.openai.com/v1";
const baseUrl =
typeof credentials?.providerSpecificData?.baseUrl === "string"
? credentials.providerSpecificData.baseUrl
: "https://api.openai.com/v1";
const normalized = baseUrl.replace(/\/$/, "");
const path = this.provider.includes("responses") ? "/responses" : "/chat/completions";
return `${normalized}${path}`;
@@ -37,8 +107,8 @@ export class BaseExecutor {
return baseUrls[urlIndex] || baseUrls[0] || this.config.baseUrl;
}
buildHeaders(credentials, stream = true) {
const headers = {
buildHeaders(credentials: ProviderCredentials, stream = true): Record<string, string> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
...this.config.headers,
};
@@ -70,32 +140,42 @@ export class BaseExecutor {
}
// Override in subclass for provider-specific transformations
transformRequest(model, body, stream, credentials) {
transformRequest(
model: string,
body: unknown,
stream: boolean,
credentials: ProviderCredentials
): unknown {
void model;
void stream;
void credentials;
return body;
}
shouldRetry(status, urlIndex) {
shouldRetry(status: number, urlIndex: number) {
return status === HTTP_STATUS.RATE_LIMITED && urlIndex + 1 < this.getFallbackCount();
}
// Override in subclass for provider-specific refresh
async refreshCredentials(credentials, log) {
async refreshCredentials(credentials: ProviderCredentials, log: ExecutorLog | null) {
void credentials;
void log;
return null;
}
needsRefresh(credentials) {
needsRefresh(credentials: ProviderCredentials) {
if (!credentials.expiresAt) return false;
const expiresAtMs = new Date(credentials.expiresAt).getTime();
return expiresAtMs - Date.now() < 5 * 60 * 1000;
}
parseError(response, bodyText) {
parseError(response: Response, bodyText: string) {
return { status: response.status, message: bodyText || `HTTP ${response.status}` };
}
async execute({ model, body, stream, credentials, signal, log }) {
async execute({ model, body, stream, credentials, signal, log }: ExecuteInput) {
const fallbackCount = this.getFallbackCount();
let lastError = null;
let lastError: unknown = null;
let lastStatus = 0;
for (let urlIndex = 0; urlIndex < fallbackCount; urlIndex++) {
@@ -109,10 +189,10 @@ export class BaseExecutor {
const timeoutSignal = !stream ? AbortSignal.timeout(FETCH_TIMEOUT_MS) : null;
const combinedSignal =
signal && timeoutSignal
? AbortSignal.any([signal, timeoutSignal])
? mergeAbortSignals(signal, timeoutSignal)
: signal || timeoutSignal;
const fetchOptions: Record<string, any> = {
const fetchOptions: RequestInit = {
method: "POST",
headers,
body: JSON.stringify(transformedBody),
@@ -130,15 +210,16 @@ export class BaseExecutor {
return { response, url, headers, transformedBody };
} catch (error) {
// Distinguish timeout errors from other abort errors
if (error.name === "TimeoutError") {
const err = error instanceof Error ? error : new Error(String(error));
if (err.name === "TimeoutError") {
log?.warn?.("TIMEOUT", `Fetch timeout after ${FETCH_TIMEOUT_MS}ms on ${url}`);
}
lastError = error;
lastError = err;
if (urlIndex + 1 < fallbackCount) {
log?.debug?.("RETRY", `Error on ${url}, trying fallback ${urlIndex + 1}`);
continue;
}
throw error;
throw err;
}
}

View File

@@ -1,4 +1,4 @@
declare var EdgeRuntime: any;
declare const EdgeRuntime: string | undefined;
/**
* CursorExecutor — Handles communication with the Cursor IDE API.
*
@@ -121,13 +121,19 @@ function createErrorResponse(jsonError) {
);
}
type CursorHttpResponse = {
status: number;
headers: Record<string, unknown>;
body: Buffer;
};
export class CursorExecutor extends BaseExecutor {
constructor() {
super("cursor", PROVIDERS.cursor);
}
buildUrl() {
return `${this.config.baseUrl}${this.config.chatPath}`;
return `${this.config.baseUrl}${this.config.chatPath || ""}`;
}
// Jyh cipher checksum for Cursor API authentication
@@ -217,27 +223,37 @@ export class CursorExecutor extends BaseExecutor {
return generateCursorBody(messages, model, tools, reasoningEffort);
}
async makeFetchRequest(url, headers, body, signal) {
async makeFetchRequest(
url: string,
headers: Record<string, string>,
body: Uint8Array,
signal?: AbortSignal
): Promise<CursorHttpResponse> {
const response = await fetch(url, {
method: "POST",
headers,
body,
body: body as unknown as BodyInit,
signal,
});
return {
status: response.status,
headers: Object.fromEntries((response.headers as any).entries()),
headers: Object.fromEntries(response.headers.entries()),
body: Buffer.from(await response.arrayBuffer()),
};
}
makeHttp2Request(url, headers, body, signal) {
makeHttp2Request(
url: string,
headers: Record<string, string>,
body: Uint8Array,
signal?: AbortSignal
): Promise<CursorHttpResponse> {
if (!http2) {
throw new Error("http2 module not available");
}
return new Promise((resolve, reject) => {
return new Promise<CursorHttpResponse>((resolve, reject) => {
const urlObj = new URL(url);
const client = http2.connect(`https://${urlObj.host}`);
const chunks = [];
@@ -262,7 +278,10 @@ export class CursorExecutor extends BaseExecutor {
req.on("end", () => {
client.close();
resolve({
status: responseHeaders[":status"],
status:
typeof responseHeaders[":status"] === "number"
? responseHeaders[":status"]
: Number(responseHeaders[":status"] || HTTP_STATUS.SERVER_ERROR),
headers: responseHeaders,
body: Buffer.concat(chunks),
});
@@ -291,7 +310,7 @@ export class CursorExecutor extends BaseExecutor {
const transformedBody = this.transformRequest(model, body, stream, credentials);
try {
const response: any = http2
const response: CursorHttpResponse = http2
? await this.makeHttp2Request(url, headers, transformedBody, signal)
: await this.makeFetchRequest(url, headers, transformedBody, signal);
@@ -459,7 +478,8 @@ export class CursorExecutor extends BaseExecutor {
console.log(`[CURSOR BUFFER] Final toolCalls count: ${toolCalls.length}`);
const message: Record<string, any> = { role: "assistant",
const message: Record<string, unknown> = {
role: "assistant",
content: totalContent || null,
};

View File

@@ -74,7 +74,7 @@ export class DefaultExecutor extends BaseExecutor {
/**
* For compatible providers, ensure the model name sent upstream
* is the clean model name without any internal routing prefix.
* is the clean model name without internal routing prefixes.
* e.g. "openapi-chat-anti/claude-opus-4-6-thinking" → "claude-opus-4-6-thinking"
*/
transformRequest(model, body, stream, credentials) {

View File

@@ -2,6 +2,11 @@ import crypto from "crypto";
import { BaseExecutor } from "./base.ts";
import { PROVIDERS } from "../config/constants.ts";
type IFlowCredentials = {
apiKey?: string;
accessToken?: string;
};
/**
* IFlowExecutor - Executor for iFlow API with HMAC-SHA256 signature.
*
@@ -41,7 +46,7 @@ export class IFlowExecutor extends BaseExecutor {
* Build headers with iFlow-specific HMAC-SHA256 signature.
* Includes session-id, x-iflow-timestamp, and x-iflow-signature.
*/
buildHeaders(credentials: any, stream = true) {
buildHeaders(credentials: IFlowCredentials, stream = true) {
// Generate session ID and timestamp
const sessionID = `session-${crypto.randomUUID()}`;
const timestamp = Date.now();
@@ -82,14 +87,26 @@ export class IFlowExecutor extends BaseExecutor {
/**
* Build URL for iFlow API — uses baseUrl directly.
*/
buildUrl(model: string, stream: boolean, urlIndex = 0, credentials: any = null) {
buildUrl(
model: string,
stream: boolean,
urlIndex = 0,
credentials: IFlowCredentials | null = null
) {
void model;
void stream;
void urlIndex;
void credentials;
return this.config.baseUrl;
}
/**
* Transform request body (passthrough for iFlow).
*/
transformRequest(model: string, body: any, stream: boolean, credentials: any) {
transformRequest(model: string, body: unknown, stream: boolean, credentials: IFlowCredentials) {
void model;
void stream;
void credentials;
return body;
}
}

View File

@@ -1,8 +1,39 @@
import { BaseExecutor } from "./base.ts";
import {
BaseExecutor,
type ExecuteInput,
type ExecutorLog,
type ProviderCredentials,
} from "./base.ts";
import { PROVIDERS } from "../config/constants.ts";
import { v4 as uuidv4 } from "uuid";
import { refreshKiroToken } from "../services/tokenRefresh.ts";
type JsonRecord = Record<string, unknown>;
type UsageSummary = {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
type KiroStreamState = {
endDetected: boolean;
finishEmitted: boolean;
hasToolCalls: boolean;
toolCallIndex: number;
seenToolIds: Map<string, number>;
totalContentLength?: number;
contextUsagePercentage?: number;
hasContextUsage?: boolean;
hasMeteringEvent?: boolean;
usage?: UsageSummary;
};
type EventFrame = {
headers: Record<string, string>;
payload: JsonRecord | null;
};
// ── CRC32 lookup table (IEEE polynomial, no dependency) ──
const CRC32_TABLE = new Uint32Array(256);
for (let i = 0; i < 256; i++) {
@@ -13,7 +44,7 @@ for (let i = 0; i < 256; i++) {
CRC32_TABLE[i] = c >>> 0;
}
function crc32(buf) {
function crc32(buf: Uint8Array) {
let crc = 0xffffffff;
for (let i = 0; i < buf.length; i++) {
crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
@@ -30,7 +61,8 @@ export class KiroExecutor extends BaseExecutor {
super("kiro", PROVIDERS.kiro);
}
buildHeaders(credentials, stream = true) {
buildHeaders(credentials: ProviderCredentials, stream = true) {
void stream;
const headers = {
...this.config.headers,
"Amz-Sdk-Request": "attempt=1; max=3",
@@ -44,14 +76,17 @@ export class KiroExecutor extends BaseExecutor {
return headers;
}
transformRequest(model, body, stream, credentials) {
transformRequest(model: string, body: unknown, stream: boolean, credentials: unknown): unknown {
void model;
void stream;
void credentials;
return body;
}
/**
* Custom execute for Kiro - handles AWS EventStream binary response
*/
async execute({ model, body, stream, credentials, signal, log }) {
async execute({ model, body, stream, credentials, signal, log }: ExecuteInput) {
const url = this.buildUrl(model, stream, 0);
const headers = this.buildHeaders(credentials, stream);
const transformedBody = this.transformRequest(model, body, stream, credentials);
@@ -78,12 +113,13 @@ export class KiroExecutor extends BaseExecutor {
* Transform AWS EventStream binary response to SSE text stream
* Using TransformStream instead of ReadableStream.pull() to avoid Workers timeout
*/
transformEventStreamToSSE(response, model) {
transformEventStreamToSSE(response: Response, model: string) {
let buffer = new Uint8Array(0);
let chunkIndex = 0;
const responseId = `chatcmpl-${Date.now()}`;
const created = Math.floor(Date.now() / 1000);
const state: Record<string, any> = { endDetected: false,
const state: KiroStreamState = {
endDetected: false,
finishEmitted: false,
hasToolCalls: false,
toolCallIndex: 0,
@@ -121,11 +157,14 @@ export class KiroExecutor extends BaseExecutor {
if (!state.contextUsagePercentage) state.contextUsagePercentage = 0;
// Handle assistantResponseEvent
if (eventType === "assistantResponseEvent" && event.payload?.content) {
const content = event.payload.content;
if (eventType === "assistantResponseEvent") {
const content = typeof event.payload?.content === "string" ? event.payload.content : "";
if (!content) {
continue;
}
state.totalContentLength += content.length;
const chunk: Record<string, any> = {
const chunk: JsonRecord = {
id: responseId,
object: "chat.completion.chunk",
created,
@@ -144,7 +183,7 @@ export class KiroExecutor extends BaseExecutor {
// Handle codeEvent
if (eventType === "codeEvent" && event.payload?.content) {
const chunk: Record<string, any> = {
const chunk: JsonRecord = {
id: responseId,
object: "chat.completion.chunk",
created,
@@ -256,7 +295,7 @@ export class KiroExecutor extends BaseExecutor {
// Handle messageStopEvent
if (eventType === "messageStopEvent") {
const chunk: Record<string, any> = {
const chunk: JsonRecord = {
id: responseId,
object: "chat.completion.chunk",
created,
@@ -274,8 +313,15 @@ export class KiroExecutor extends BaseExecutor {
}
// Handle contextUsageEvent to extract contextUsagePercentage
if (eventType === "contextUsageEvent" && event.payload?.contextUsagePercentage) {
state.contextUsagePercentage = event.payload.contextUsagePercentage;
if (eventType === "contextUsageEvent") {
const contextUsage =
typeof event.payload?.contextUsagePercentage === "number"
? event.payload.contextUsagePercentage
: 0;
if (contextUsage <= 0) {
continue;
}
state.contextUsagePercentage = contextUsage;
// Mark that we received context usage event
state.hasContextUsage = true;
}
@@ -290,8 +336,14 @@ export class KiroExecutor extends BaseExecutor {
// Extract usage data from metricsEvent payload
const metrics = event.payload?.metricsEvent || event.payload;
if (metrics && typeof metrics === "object") {
const inputTokens = metrics.inputTokens || 0;
const outputTokens = metrics.outputTokens || 0;
const inputTokens =
typeof (metrics as JsonRecord).inputTokens === "number"
? ((metrics as JsonRecord).inputTokens as number)
: 0;
const outputTokens =
typeof (metrics as JsonRecord).outputTokens === "number"
? ((metrics as JsonRecord).outputTokens as number)
: 0;
if (inputTokens > 0 || outputTokens > 0) {
state.usage = {
@@ -329,7 +381,7 @@ export class KiroExecutor extends BaseExecutor {
};
}
const finishChunk: Record<string, any> = {
const finishChunk: JsonRecord = {
id: responseId,
object: "chat.completion.chunk",
created,
@@ -398,7 +450,7 @@ export class KiroExecutor extends BaseExecutor {
});
}
async refreshCredentials(credentials, log) {
async refreshCredentials(credentials: ProviderCredentials, log?: ExecutorLog | null) {
if (!credentials.refreshToken) return null;
try {
@@ -411,7 +463,8 @@ export class KiroExecutor extends BaseExecutor {
return result;
} catch (error) {
log?.error?.("TOKEN", `Kiro refresh error: ${error.message}`);
const err = error instanceof Error ? error : new Error(String(error));
log?.error?.("TOKEN", `Kiro refresh error: ${err.message}`);
return null;
}
}
@@ -420,7 +473,7 @@ export class KiroExecutor extends BaseExecutor {
/**
* Parse AWS EventStream frame
*/
function parseEventFrame(data) {
function parseEventFrame(data: Uint8Array): EventFrame | null {
try {
const view = new DataView(data.buffer, data.byteOffset);
const totalLength = view.getUint32(0, false);
@@ -447,7 +500,7 @@ function parseEventFrame(data) {
return null;
}
// Parse headers
const headers = {};
const headers: Record<string, string> = {};
let offset = 12; // After prelude
const headerEnd = 12 + headersLength;
@@ -480,7 +533,7 @@ function parseEventFrame(data) {
const payloadStart = 12 + headersLength;
const payloadEnd = data.length - 4; // Exclude message CRC
let payload = null;
let payload: JsonRecord | null = null;
if (payloadEnd > payloadStart) {
const payloadStr = new TextDecoder().decode(data.slice(payloadStart, payloadEnd));
@@ -492,9 +545,10 @@ function parseEventFrame(data) {
try {
payload = JSON.parse(payloadStr);
} catch (parseError) {
const err = parseError instanceof Error ? parseError : new Error(String(parseError));
// Log parse error for debugging
console.warn(
`[Kiro] Failed to parse payload: ${parseError.message} | payload: ${payloadStr.substring(0, 100)}`
`[Kiro] Failed to parse payload: ${err.message} | payload: ${payloadStr.substring(0, 100)}`
);
payload = { raw: payloadStr };
}
@@ -502,7 +556,8 @@ function parseEventFrame(data) {
return { headers, payload };
} catch (err) {
console.warn(`[Kiro] Frame parse error: ${err.message}`);
const error = err instanceof Error ? err : new Error(String(err));
console.warn(`[Kiro] Frame parse error: ${error.message}`);
return null;
}
}

View File

@@ -256,7 +256,7 @@ async function handleTortoiseSpeech(providerConfig, body) {
* @param {Object} options.credentials - Provider credentials { apiKey }
* @returns {Response}
*/
/** @returns {Promise<any>} */
/** @returns {Promise<unknown>} */
export async function handleAudioSpeech({ body, credentials }) {
if (!body.model) {
return errorResponse(400, "model is required");
@@ -276,7 +276,8 @@ export async function handleAudioSpeech({ body, credentials }) {
}
// Skip credential check for local providers (authType: "none")
const token = providerConfig.authType === "none" ? null : (credentials?.apiKey || credentials?.accessToken);
const token =
providerConfig.authType === "none" ? null : credentials?.apiKey || credentials?.accessToken;
if (providerConfig.authType !== "none" && !token) {
return errorResponse(401, `No credentials for speech provider: ${providerId}`);
}
@@ -335,4 +336,4 @@ export async function handleAudioSpeech({ body, credentials }) {
} catch (err) {
return errorResponse(500, `Speech request failed: ${err.message}`);
}
}
}

View File

@@ -17,6 +17,11 @@ import { getTranscriptionProvider, parseTranscriptionModel } from "../config/aud
import { buildAuthHeaders } from "../config/registryUtils.ts";
import { errorResponse } from "../utils/error.ts";
type TranscriptionCredentials = {
apiKey?: string;
accessToken?: string;
};
/**
* Return a CORS error response from an upstream fetch failure
*/
@@ -37,6 +42,10 @@ function isValidPathSegment(segment: string): boolean {
return !segment.includes("..") && !segment.includes("//");
}
function getUploadedFileName(file: Blob & { name?: unknown }): string {
return typeof file.name === "string" && file.name.length > 0 ? file.name : "audio.wav";
}
/**
* Handle Deepgram transcription (raw binary audio, model via query param)
*/
@@ -144,7 +153,7 @@ async function handleAssemblyAITranscription(providerConfig, file, modelId, toke
*/
async function handleNvidiaTranscription(providerConfig, file, modelId, token) {
const upstreamForm = new FormData();
upstreamForm.append("file", /** @type {Blob} */ file, /** @type {any} */ file.name || "audio.wav");
upstreamForm.append("file", file, getUploadedFileName(file));
upstreamForm.append("model", modelId);
const res = await fetch(providerConfig.baseUrl, {
@@ -203,17 +212,23 @@ async function handleHuggingFaceTranscription(providerConfig, file, modelId, tok
* @param {Object} options.credentials - Provider credentials { apiKey }
* @returns {Response}
*/
/** @returns {Promise<any>} */
export async function handleAudioTranscription({ formData, credentials }) {
export async function handleAudioTranscription({
formData,
credentials,
}: {
formData: FormData;
credentials?: TranscriptionCredentials | null;
}): Promise<Response> {
const model = formData.get("model");
if (!model) {
if (typeof model !== "string" || !model) {
return errorResponse(400, "model is required");
}
const file = formData.get("file");
if (!file) {
const fileEntry = formData.get("file");
if (!(fileEntry instanceof Blob)) {
return errorResponse(400, "file is required");
}
const file = fileEntry as Blob & { name?: unknown };
const { provider: providerId, model: modelId } = parseTranscriptionModel(model);
const providerConfig = providerId ? getTranscriptionProvider(providerId) : null;
@@ -226,7 +241,8 @@ export async function handleAudioTranscription({ formData, credentials }) {
}
// Skip credential check for local providers (authType: "none")
const token = providerConfig.authType === "none" ? null : (credentials?.apiKey || credentials?.accessToken);
const token =
providerConfig.authType === "none" ? null : credentials?.apiKey || credentials?.accessToken;
if (providerConfig.authType !== "none" && !token) {
return errorResponse(401, `No credentials for transcription provider: ${providerId}`);
}
@@ -250,11 +266,7 @@ export async function handleAudioTranscription({ formData, credentials }) {
// Default: OpenAI/Groq/Qwen3-compatible multipart proxy
const upstreamForm = new FormData();
upstreamForm.append(
"file",
/** @type {Blob} */ file,
/** @type {any} */ file.name || "audio.wav"
);
upstreamForm.append("file", file, getUploadedFileName(file));
upstreamForm.append("model", modelId);
// Forward optional parameters
@@ -290,6 +302,7 @@ export async function handleAudioTranscription({ formData, credentials }) {
headers: { "Content-Type": contentType, "Access-Control-Allow-Origin": getCorsOrigin() },
});
} catch (err) {
return errorResponse(500, `Transcription request failed: ${err.message}`);
const error = err instanceof Error ? err : new Error(String(err));
return errorResponse(500, `Transcription request failed: ${error.message}`);
}
}
}

View File

@@ -54,7 +54,6 @@ import { createProgressTransform, wantsProgress } from "../utils/progressTracker
* @param {string} options.connectionId - Connection ID for usage tracking
* @param {object} options.apiKeyInfo - API key metadata for usage attribution
*/
/** @param {any} options */
export async function handleChatCore({
body,
modelInfo,
@@ -135,7 +134,7 @@ export async function handleChatCore({
// Create request logger for this session: sourceFormat_targetFormat_model
const reqLogger = await createRequestLogger(sourceFormat, targetFormat, model);
// 0. Log client raw request (before any conversion)
// 0. Log client raw request (before format conversion)
if (clientRawRequest) {
reqLogger.logClientRawRequest(
clientRawRequest.endpoint,
@@ -152,11 +151,18 @@ export async function handleChatCore({
// Translate request (pass reqLogger for intermediate logging)
let translatedBody = body;
try {
// Issue #199: Disable tool name prefix when routing Claude-format requests
// to non-Claude backends (prefix causes tool name mismatches)
const claudeProviders = ["claude", "anthropic"];
if (targetFormat === FORMATS.CLAUDE && !claudeProviders.includes(provider?.toLowerCase?.())) {
translatedBody = { ...translatedBody, _disableToolPrefix: true };
}
translatedBody = translateRequest(
sourceFormat,
targetFormat,
model,
body,
translatedBody,
stream,
credentials,
provider,
@@ -203,6 +209,7 @@ export async function handleChatCore({
// Extract toolNameMap for response translation (Claude OAuth)
const toolNameMap = translatedBody._toolNameMap;
delete translatedBody._toolNameMap;
delete translatedBody._disableToolPrefix;
// Update model in body
translatedBody.model = model;
@@ -283,6 +290,7 @@ export async function handleChatCore({
comboName,
apiKeyId: apiKeyInfo?.id || null,
apiKeyName: apiKeyInfo?.name || null,
noLog: apiKeyInfo?.noLog === true,
}).catch(() => {});
if (error.name === "AbortError") {
streamController.handleError(error);
@@ -298,11 +306,14 @@ export async function handleChatCore({
providerResponse.status === HTTP_STATUS.UNAUTHORIZED ||
providerResponse.status === HTTP_STATUS.FORBIDDEN
) {
const newCredentials = await refreshWithRetry(
const newCredentials = (await refreshWithRetry(
() => executor.refreshCredentials(credentials, log),
3,
log
);
)) as null | {
accessToken?: string;
copilotToken?: string;
};
if (newCredentials?.accessToken || newCredentials?.copilotToken) {
log?.info?.("TOKEN", `${provider.toUpperCase()} | refreshed`);
@@ -363,6 +374,7 @@ export async function handleChatCore({
comboName,
apiKeyId: apiKeyInfo?.id || null,
apiKeyName: apiKeyInfo?.name || null,
noLog: apiKeyInfo?.noLog === true,
}).catch(() => {});
const errMsg = formatProviderError(new Error(message), provider, model, statusCode);
console.log(`${COLORS.red}[ERROR] ${errMsg}${COLORS.reset}`);
@@ -454,6 +466,7 @@ export async function handleChatCore({
comboName,
apiKeyId: apiKeyInfo?.id || null,
apiKeyName: apiKeyInfo?.name || null,
noLog: apiKeyInfo?.noLog === true,
}).catch(() => {});
if (usage && typeof usage === "object") {
const msg = `[${new Date().toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit" })}] 📊 [USAGE] ${provider.toUpperCase()} | in=${usage?.prompt_tokens || 0} | out=${usage?.completion_tokens || 0}${connectionId ? ` | account=${connectionId.slice(0, 8)}...` : ""}`;
@@ -489,7 +502,7 @@ export async function handleChatCore({
const buffered = addBufferToUsage(translatedResponse.usage);
translatedResponse.usage = filterUsageForFormat(buffered, sourceFormat);
} else {
// Fallback: estimate usage when provider didn't return any
// Fallback: estimate usage when provider returned no usage block
const contentLength = JSON.stringify(
translatedResponse?.choices?.[0]?.message?.content || ""
).length;
@@ -556,6 +569,7 @@ export async function handleChatCore({
comboName,
apiKeyId: apiKeyInfo?.id || null,
apiKeyName: apiKeyInfo?.name || null,
noLog: apiKeyInfo?.noLog === true,
}).catch(() => {});
};

View File

@@ -52,7 +52,7 @@ export async function handleEmbedding({ body, credentials, log }) {
}
// Build upstream request
const upstreamBody: Record<string, any> = {
const upstreamBody: Record<string, unknown> = {
model: model,
input: body.input,
};

View File

@@ -246,7 +246,7 @@ async function handleOpenAIImageGeneration({
};
// Build upstream request (OpenAI-compatible format)
const upstreamBody: Record<string, any> = {
const upstreamBody: Record<string, unknown> = {
model: model,
prompt: body.prompt,
};
@@ -612,7 +612,8 @@ async function handleSDWebUIImageGeneration({ model, provider, providerConfig, b
if (!response.ok) {
const errorText = await response.text();
if (log) log.error("IMAGE", `${provider} error ${response.status}: ${errorText.slice(0, 200)}`);
if (log)
log.error("IMAGE", `${provider} error ${response.status}: ${errorText.slice(0, 200)}`);
saveCallLog({
method: "POST",

View File

@@ -16,7 +16,7 @@ import { errorResponse } from "../utils/error.ts";
* @param {Object} options.credentials - Provider credentials { apiKey }
* @returns {Response}
*/
/** @returns {Promise<any>} */
/** @returns {Promise<unknown>} */
export async function handleModeration({ body, credentials }) {
if (!body.input) {
return errorResponse(400, "input is required");

View File

@@ -70,7 +70,7 @@ function transformResponseFromProvider(providerConfig, data) {
* @param {Object} options.credentials - Provider credentials { apiKey, accessToken }
* @returns {Response}
*/
/** @returns {Promise<any>} */
/** @returns {Promise<unknown>} */
export async function handleRerank({
model,
query,

View File

@@ -9,17 +9,6 @@
* 4. Converts developer role → system for non-OpenAI providers
*/
// ── Standard OpenAI ChatCompletion fields ──────────────────────────────────
const ALLOWED_TOP_LEVEL_FIELDS = new Set([
"id",
"object",
"created",
"model",
"choices",
"usage",
"system_fingerprint",
]);
const ALLOWED_USAGE_FIELDS = new Set([
"prompt_tokens",
"completion_tokens",
@@ -28,16 +17,20 @@ const ALLOWED_USAGE_FIELDS = new Set([
"completion_tokens_details",
]);
const ALLOWED_MESSAGE_FIELDS = new Set([
"role",
"content",
"tool_calls",
"function_call",
"refusal",
"reasoning_content",
]);
type JsonRecord = Record<string, unknown>;
const ALLOWED_CHOICE_FIELDS = new Set(["index", "message", "delta", "finish_reason", "logprobs"]);
function toRecord(value: unknown): JsonRecord | null {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
return value as JsonRecord;
}
function toString(value: unknown): string | undefined {
return typeof value === "string" ? value : undefined;
}
function toNumber(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
}
// ── Think tag regex ────────────────────────────────────────────────────────
// Matches <think>...</think> blocks (greedy, dotAll)
@@ -81,33 +74,34 @@ export function extractThinkingFromContent(text: string): {
* Sanitize a non-streaming OpenAI ChatCompletion response.
* Strips non-standard fields and normalizes required fields.
*/
export function sanitizeOpenAIResponse(body: any): any {
if (!body || typeof body !== "object") return body;
export function sanitizeOpenAIResponse(body: unknown): unknown {
const bodyRecord = toRecord(body);
if (!bodyRecord) return body;
// Build sanitized response with only allowed top-level fields
const sanitized: Record<string, any> = {};
const sanitized: JsonRecord = {};
// Ensure required fields exist
sanitized.id = normalizeResponseId(body.id);
sanitized.object = body.object || "chat.completion";
sanitized.created = body.created || Math.floor(Date.now() / 1000);
sanitized.model = body.model || "unknown";
sanitized.id = normalizeResponseId(bodyRecord.id);
sanitized.object = toString(bodyRecord.object) || "chat.completion";
sanitized.created = toNumber(bodyRecord.created) ?? Math.floor(Date.now() / 1000);
sanitized.model = toString(bodyRecord.model) || "unknown";
// Sanitize choices
if (Array.isArray(body.choices)) {
sanitized.choices = body.choices.map((choice: any, idx: number) => sanitizeChoice(choice, idx));
if (Array.isArray(bodyRecord.choices)) {
sanitized.choices = bodyRecord.choices.map((choice, idx) => sanitizeChoice(choice, idx));
} else {
sanitized.choices = [];
}
// Sanitize usage
if (body.usage && typeof body.usage === "object") {
sanitized.usage = sanitizeUsage(body.usage);
if (bodyRecord.usage !== undefined) {
sanitized.usage = sanitizeUsage(bodyRecord.usage);
}
// Keep system_fingerprint if present (it's a valid OpenAI field)
if (body.system_fingerprint) {
sanitized.system_fingerprint = body.system_fingerprint;
if (bodyRecord.system_fingerprint) {
sanitized.system_fingerprint = bodyRecord.system_fingerprint;
}
return sanitized;
@@ -116,23 +110,32 @@ export function sanitizeOpenAIResponse(body: any): any {
/**
* Sanitize a single choice object.
*/
function sanitizeChoice(choice: any, defaultIndex: number): any {
const sanitized: Record<string, any> = {
index: choice.index ?? defaultIndex,
finish_reason: choice.finish_reason || null,
function sanitizeChoice(choice: unknown, defaultIndex: number): JsonRecord {
const choiceRecord = toRecord(choice);
const sanitized: JsonRecord = {
index: defaultIndex,
finish_reason: null,
};
// Sanitize message (non-streaming) or delta (streaming)
if (choice.message) {
sanitized.message = sanitizeMessage(choice.message);
if (choiceRecord?.index !== undefined) {
sanitized.index = choiceRecord.index;
}
if (choice.delta) {
sanitized.delta = sanitizeMessage(choice.delta);
if (choiceRecord?.finish_reason !== undefined) {
sanitized.finish_reason = choiceRecord.finish_reason;
}
// Sanitize message (non-streaming) or delta (streaming)
if (choiceRecord?.message !== undefined) {
sanitized.message = sanitizeMessage(choiceRecord.message);
}
if (choiceRecord?.delta !== undefined) {
sanitized.delta = sanitizeMessage(choiceRecord.delta);
}
// Keep logprobs if present
if (choice.logprobs !== undefined) {
sanitized.logprobs = choice.logprobs;
if (choiceRecord?.logprobs !== undefined) {
sanitized.logprobs = choiceRecord.logprobs;
}
return sanitized;
@@ -141,41 +144,42 @@ function sanitizeChoice(choice: any, defaultIndex: number): any {
/**
* Sanitize a message object, extracting <think> tags if present.
*/
function sanitizeMessage(msg: any): any {
if (!msg || typeof msg !== "object") return msg;
function sanitizeMessage(msg: unknown): unknown {
const msgRecord = toRecord(msg);
if (!msgRecord) return msg;
const sanitized: Record<string, any> = {};
const sanitized: JsonRecord = {};
// Copy only allowed fields
if (msg.role) sanitized.role = msg.role;
if (msg.refusal !== undefined) sanitized.refusal = msg.refusal;
if (msgRecord.role) sanitized.role = msgRecord.role;
if (msgRecord.refusal !== undefined) sanitized.refusal = msgRecord.refusal;
// Handle content — extract <think> tags
if (typeof msg.content === "string") {
const { content, thinking } = extractThinkingFromContent(msg.content);
if (typeof msgRecord.content === "string") {
const { content, thinking } = extractThinkingFromContent(msgRecord.content);
sanitized.content = content;
// Set reasoning_content from <think> tags (if not already set)
if (thinking && !msg.reasoning_content) {
if (thinking && !msgRecord.reasoning_content) {
sanitized.reasoning_content = thinking;
}
} else if (msg.content !== undefined) {
sanitized.content = msg.content;
} else if (msgRecord.content !== undefined) {
sanitized.content = msgRecord.content;
}
// Preserve existing reasoning_content (from providers that natively support it)
if (msg.reasoning_content && !sanitized.reasoning_content) {
sanitized.reasoning_content = msg.reasoning_content;
if (msgRecord.reasoning_content && !sanitized.reasoning_content) {
sanitized.reasoning_content = msgRecord.reasoning_content;
}
// Preserve tool_calls
if (msg.tool_calls) {
sanitized.tool_calls = msg.tool_calls;
if (msgRecord.tool_calls) {
sanitized.tool_calls = msgRecord.tool_calls;
}
// Preserve function_call (legacy)
if (msg.function_call) {
sanitized.function_call = msg.function_call;
if (msgRecord.function_call) {
sanitized.function_call = msgRecord.function_call;
}
return sanitized;
@@ -184,22 +188,25 @@ function sanitizeMessage(msg: any): any {
/**
* Sanitize usage object — keep only standard fields.
*/
function sanitizeUsage(usage: any): any {
if (!usage || typeof usage !== "object") return usage;
function sanitizeUsage(usage: unknown): unknown {
const usageRecord = toRecord(usage);
if (!usageRecord) return usage;
const sanitized: Record<string, any> = {};
const sanitized: JsonRecord = {};
for (const key of ALLOWED_USAGE_FIELDS) {
if (usage[key] !== undefined) {
sanitized[key] = usage[key];
if (usageRecord[key] !== undefined) {
sanitized[key] = usageRecord[key];
}
}
// Ensure required fields
if (sanitized.prompt_tokens === undefined) sanitized.prompt_tokens = 0;
if (sanitized.completion_tokens === undefined) sanitized.completion_tokens = 0;
if (sanitized.total_tokens === undefined) {
sanitized.total_tokens = sanitized.prompt_tokens + sanitized.completion_tokens;
}
const promptTokens = toNumber(sanitized.prompt_tokens) ?? 0;
const completionTokens = toNumber(sanitized.completion_tokens) ?? 0;
const totalTokens = toNumber(sanitized.total_tokens) ?? promptTokens + completionTokens;
sanitized.prompt_tokens = promptTokens;
sanitized.completion_tokens = completionTokens;
sanitized.total_tokens = totalTokens;
return sanitized;
}
@@ -207,7 +214,7 @@ function sanitizeUsage(usage: any): any {
/**
* Normalize response ID to use chatcmpl- prefix.
*/
function normalizeResponseId(id: any): string {
function normalizeResponseId(id: unknown): string {
if (!id || typeof id !== "string") {
return `chatcmpl-${crypto.randomUUID().replace(/-/g, "").slice(0, 29)}`;
}
@@ -221,48 +228,60 @@ function normalizeResponseId(id: any): string {
* Sanitize a streaming SSE chunk for passthrough mode.
* Lighter than full sanitization — only strips problematic extra fields.
*/
export function sanitizeStreamingChunk(parsed: any): any {
if (!parsed || typeof parsed !== "object") return parsed;
export function sanitizeStreamingChunk(parsed: unknown): unknown {
const parsedRecord = toRecord(parsed);
if (!parsedRecord) return parsed;
// Build sanitized chunk
const sanitized: Record<string, any> = {};
const sanitized: JsonRecord = {};
// Keep only standard fields
if (parsed.id !== undefined) sanitized.id = parsed.id;
sanitized.object = parsed.object || "chat.completion.chunk";
if (parsed.created !== undefined) sanitized.created = parsed.created;
if (parsed.model !== undefined) sanitized.model = parsed.model;
if (parsedRecord.id !== undefined) sanitized.id = parsedRecord.id;
sanitized.object = toString(parsedRecord.object) || "chat.completion.chunk";
if (parsedRecord.created !== undefined) sanitized.created = parsedRecord.created;
if (parsedRecord.model !== undefined) sanitized.model = parsedRecord.model;
// Sanitize choices with delta
if (Array.isArray(parsed.choices)) {
sanitized.choices = parsed.choices.map((choice: any) => {
const c: Record<string, any> = {
index: choice.index ?? 0,
};
if (choice.delta !== undefined) {
c.delta = {};
const delta = choice.delta;
if (delta.role !== undefined) c.delta.role = delta.role;
if (delta.content !== undefined) c.delta.content = delta.content;
if (delta.reasoning_content !== undefined)
c.delta.reasoning_content = delta.reasoning_content;
if (delta.tool_calls !== undefined) c.delta.tool_calls = delta.tool_calls;
if (delta.function_call !== undefined) c.delta.function_call = delta.function_call;
if (Array.isArray(parsedRecord.choices)) {
sanitized.choices = parsedRecord.choices.map((choice) => {
const c: JsonRecord = { index: 0 };
const choiceRecord = toRecord(choice);
if (!choiceRecord) return c;
c.index = toNumber(choiceRecord.index) ?? 0;
if (choiceRecord.delta !== undefined) {
const deltaRecord = toRecord(choiceRecord.delta);
if (deltaRecord) {
const delta: JsonRecord = {};
if (deltaRecord.role !== undefined) delta.role = deltaRecord.role;
if (deltaRecord.content !== undefined) delta.content = deltaRecord.content;
if (deltaRecord.reasoning_content !== undefined) {
delta.reasoning_content = deltaRecord.reasoning_content;
}
if (deltaRecord.tool_calls !== undefined) delta.tool_calls = deltaRecord.tool_calls;
if (deltaRecord.function_call !== undefined)
delta.function_call = deltaRecord.function_call;
c.delta = delta;
} else {
c.delta = choiceRecord.delta;
}
}
if (choice.finish_reason !== undefined) c.finish_reason = choice.finish_reason;
if (choice.logprobs !== undefined) c.logprobs = choice.logprobs;
if (choiceRecord.finish_reason !== undefined) c.finish_reason = choiceRecord.finish_reason;
if (choiceRecord.logprobs !== undefined) c.logprobs = choiceRecord.logprobs;
return c;
});
}
// Sanitize usage if present
if (parsed.usage && typeof parsed.usage === "object") {
sanitized.usage = sanitizeUsage(parsed.usage);
if (parsedRecord.usage !== undefined) {
sanitized.usage = sanitizeUsage(parsedRecord.usage);
}
// Keep system_fingerprint if present
if (parsed.system_fingerprint) {
sanitized.system_fingerprint = parsed.system_fingerprint;
if (parsedRecord.system_fingerprint) {
sanitized.system_fingerprint = parsedRecord.system_fingerprint;
}
return sanitized;

View File

@@ -1,10 +1,34 @@
import { FORMATS } from "../translator/formats.ts";
type JsonRecord = Record<string, unknown>;
function toRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
}
function toString(value: unknown, fallback = ""): string {
return typeof value === "string" ? value : fallback;
}
function toNumber(value: unknown, fallback = 0): number {
const parsed =
typeof value === "number"
? value
: typeof value === "string" && value.trim().length > 0
? Number(value)
: Number.NaN;
return Number.isFinite(parsed) ? parsed : fallback;
}
/**
* Translate non-streaming response to OpenAI format
* Handles different provider response formats (Gemini, Claude, etc.)
*/
export function translateNonStreamingResponse(responseBody, targetFormat, sourceFormat) {
export function translateNonStreamingResponse(
responseBody: unknown,
targetFormat: string,
sourceFormat: string
): unknown {
// If already in source format (usually OpenAI), return as-is
if (targetFormat === sourceFormat || targetFormat === FORMATS.OPENAI) {
return responseBody;
@@ -12,51 +36,60 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
// Handle OpenAI Responses API format
if (targetFormat === FORMATS.OPENAI_RESPONSES) {
const responseRoot = toRecord(responseBody);
const response =
responseBody?.object === "response" ? responseBody : responseBody?.response || responseBody;
const output = Array.isArray(response?.output) ? response.output : [];
const usage = response?.usage || responseBody?.usage;
responseRoot.object === "response"
? responseRoot
: toRecord(responseRoot.response ?? responseRoot);
const output = Array.isArray(response.output) ? response.output : [];
const usage = toRecord(response.usage ?? responseRoot.usage);
let textContent = "";
let reasoningContent = "";
const toolCalls = [];
const toolCalls: JsonRecord[] = [];
for (const item of output) {
if (!item || typeof item !== "object") continue;
const itemObj = toRecord(item);
if (item.type === "message" && Array.isArray(item.content)) {
for (const part of item.content) {
if (itemObj.type === "message" && Array.isArray(itemObj.content)) {
for (const part of itemObj.content) {
if (!part || typeof part !== "object") continue;
if (part.type === "output_text" && typeof part.text === "string") {
textContent += part.text;
} else if (part.type === "summary_text" && typeof part.text === "string") {
reasoningContent += part.text;
const partObj = toRecord(part);
if (partObj.type === "output_text" && typeof partObj.text === "string") {
textContent += partObj.text;
} else if (partObj.type === "summary_text" && typeof partObj.text === "string") {
reasoningContent += partObj.text;
}
}
} else if (item.type === "reasoning" && Array.isArray(item.summary)) {
for (const part of item.summary) {
if (part?.type === "summary_text" && typeof part.text === "string") {
reasoningContent += part.text;
} else if (itemObj.type === "reasoning" && Array.isArray(itemObj.summary)) {
for (const part of itemObj.summary) {
const partObj = toRecord(part);
if (partObj.type === "summary_text" && typeof partObj.text === "string") {
reasoningContent += partObj.text;
}
}
} else if (item.type === "function_call") {
const callId = item.call_id || item.id || `call_${Date.now()}_${toolCalls.length}`;
} else if (itemObj.type === "function_call") {
const callId =
toString(itemObj.call_id) ||
toString(itemObj.id) ||
`call_${Date.now()}_${toolCalls.length}`;
const fnArgs =
typeof item.arguments === "string"
? item.arguments
: JSON.stringify(item.arguments || {});
typeof itemObj.arguments === "string"
? itemObj.arguments
: JSON.stringify(itemObj.arguments || {});
toolCalls.push({
id: callId,
type: "function",
function: {
name: item.name || "",
name: toString(itemObj.name),
arguments: fnArgs,
},
});
}
}
const message: Record<string, any> = { role: "assistant" };
const message: JsonRecord = { role: "assistant" };
if (textContent) {
message.content = textContent;
}
@@ -70,12 +103,12 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
message.content = "";
}
const createdAt = Number(response?.created_at) || Math.floor(Date.now() / 1000);
const model = response?.model || responseBody?.model || "openai-responses";
const createdAt = toNumber(response.created_at, Math.floor(Date.now() / 1000));
const model = toString(response.model || responseRoot.model, "openai-responses");
const finishReason = toolCalls.length > 0 ? "tool_calls" : "stop";
const result: Record<string, any> = {
id: `chatcmpl-${response?.id || Date.now()}`,
const result: JsonRecord = {
id: `chatcmpl-${toString(response.id, String(Date.now()))}`,
object: "chat.completion",
created: createdAt,
model,
@@ -88,28 +121,31 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
],
};
if (usage && typeof usage === "object") {
const inputTokens = usage.input_tokens || 0;
const outputTokens = usage.output_tokens || 0;
if (Object.keys(usage).length > 0) {
const inputTokens = toNumber(usage.input_tokens, 0);
const outputTokens = toNumber(usage.output_tokens, 0);
result.usage = {
prompt_tokens: inputTokens,
completion_tokens: outputTokens,
total_tokens: inputTokens + outputTokens,
};
if (usage.reasoning_tokens > 0) {
result.usage.completion_tokens_details = {
reasoning_tokens: usage.reasoning_tokens,
if (toNumber(usage.reasoning_tokens, 0) > 0) {
(result.usage as JsonRecord).completion_tokens_details = {
reasoning_tokens: toNumber(usage.reasoning_tokens, 0),
};
}
if (usage.cache_read_input_tokens > 0 || usage.cache_creation_input_tokens > 0) {
result.usage.prompt_tokens_details = {};
if (usage.cache_read_input_tokens > 0) {
result.usage.prompt_tokens_details.cached_tokens = usage.cache_read_input_tokens;
if (
toNumber(usage.cache_read_input_tokens, 0) > 0 ||
toNumber(usage.cache_creation_input_tokens, 0) > 0
) {
(result.usage as JsonRecord).prompt_tokens_details = {};
const promptDetails = (result.usage as JsonRecord).prompt_tokens_details as JsonRecord;
if (toNumber(usage.cache_read_input_tokens, 0) > 0) {
promptDetails.cached_tokens = toNumber(usage.cache_read_input_tokens, 0);
}
if (usage.cache_creation_input_tokens > 0) {
result.usage.prompt_tokens_details.cache_creation_tokens =
usage.cache_creation_input_tokens;
if (toNumber(usage.cache_creation_input_tokens, 0) > 0) {
promptDetails.cache_creation_tokens = toNumber(usage.cache_creation_input_tokens, 0);
}
}
}
@@ -123,38 +159,42 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
targetFormat === FORMATS.ANTIGRAVITY ||
targetFormat === FORMATS.GEMINI_CLI
) {
const response = responseBody.response || responseBody;
if (!response?.candidates?.[0]) {
const root = toRecord(responseBody);
const response = toRecord(root.response ?? root);
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
if (!candidates[0]) {
return responseBody; // Can't translate, return raw
}
const candidate = response.candidates[0];
const content = candidate.content;
const usage = response.usageMetadata || responseBody.usageMetadata;
const candidate = toRecord(candidates[0]);
const content = toRecord(candidate.content);
const usage = toRecord(response.usageMetadata ?? root.usageMetadata);
// Build message content
let textContent = "";
const toolCalls = [];
const toolCalls: JsonRecord[] = [];
let reasoningContent = "";
if (content?.parts) {
if (Array.isArray(content.parts)) {
for (const part of content.parts) {
const partObj = toRecord(part);
// Handle thinking/reasoning
if (part.thought === true && part.text) {
reasoningContent += part.text;
if (partObj.thought === true && typeof partObj.text === "string") {
reasoningContent += partObj.text;
}
// Regular text
else if (part.text !== undefined) {
textContent += part.text;
else if (typeof partObj.text === "string") {
textContent += partObj.text;
}
// Function calls
if (part.functionCall) {
if (partObj.functionCall) {
const fn = toRecord(partObj.functionCall);
toolCalls.push({
id: `call_${part.functionCall.name}_${Date.now()}_${toolCalls.length}`,
id: `call_${toString(fn.name, "unknown")}_${Date.now()}_${toolCalls.length}`,
type: "function",
function: {
name: part.functionCall.name,
arguments: JSON.stringify(part.functionCall.args || {}),
name: toString(fn.name),
arguments: JSON.stringify(fn.args || {}),
},
});
}
@@ -162,7 +202,7 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
}
// Build OpenAI format message
const message: Record<string, any> = { role: "assistant" };
const message: JsonRecord = { role: "assistant" };
if (textContent) {
message.content = textContent;
}
@@ -178,16 +218,21 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
}
// Determine finish reason
let finishReason = (candidate.finishReason || "stop").toLowerCase();
let finishReason = toString(candidate.finishReason, "stop").toLowerCase();
if (finishReason === "stop" && toolCalls.length > 0) {
finishReason = "tool_calls";
}
const result: Record<string, any> = {
id: `chatcmpl-${response.responseId || Date.now()}`,
const createdMs = Date.parse(toString(response.createTime));
const created = Number.isFinite(createdMs)
? Math.floor(createdMs / 1000)
: Math.floor(Date.now() / 1000);
const result: JsonRecord = {
id: `chatcmpl-${toString(response.responseId, String(Date.now()))}`,
object: "chat.completion",
created: Math.floor(new Date(response.createTime || Date.now()).getTime() / 1000),
model: response.modelVersion || "gemini",
created,
model: toString(response.modelVersion, "gemini"),
choices: [
{
index: 0,
@@ -198,15 +243,15 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
};
// Add usage if available (match streaming translator: add thoughtsTokenCount to prompt_tokens)
if (usage) {
if (Object.keys(usage).length > 0) {
result.usage = {
prompt_tokens: (usage.promptTokenCount || 0) + (usage.thoughtsTokenCount || 0),
completion_tokens: usage.candidatesTokenCount || 0,
total_tokens: usage.totalTokenCount || 0,
prompt_tokens: toNumber(usage.promptTokenCount, 0) + toNumber(usage.thoughtsTokenCount, 0),
completion_tokens: toNumber(usage.candidatesTokenCount, 0),
total_tokens: toNumber(usage.totalTokenCount, 0),
};
if (usage.thoughtsTokenCount > 0) {
result.usage.completion_tokens_details = {
reasoning_tokens: usage.thoughtsTokenCount,
if (toNumber(usage.thoughtsTokenCount, 0) > 0) {
(result.usage as JsonRecord).completion_tokens_details = {
reasoning_tokens: toNumber(usage.thoughtsTokenCount, 0),
};
}
}
@@ -216,32 +261,35 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
// Handle Claude format
if (targetFormat === FORMATS.CLAUDE) {
if (!responseBody.content) {
const root = toRecord(responseBody);
const contentBlocks = Array.isArray(root.content) ? root.content : [];
if (contentBlocks.length === 0) {
return responseBody; // Can't translate, return raw
}
let textContent = "";
let thinkingContent = "";
const toolCalls = [];
const toolCalls: JsonRecord[] = [];
for (const block of responseBody.content) {
if (block.type === "text") {
textContent += block.text;
} else if (block.type === "thinking") {
thinkingContent += block.thinking || "";
} else if (block.type === "tool_use") {
for (const block of contentBlocks) {
const blockObj = toRecord(block);
if (blockObj.type === "text") {
textContent += toString(blockObj.text);
} else if (blockObj.type === "thinking") {
thinkingContent += toString(blockObj.thinking);
} else if (blockObj.type === "tool_use") {
toolCalls.push({
id: block.id,
id: toString(blockObj.id, `call_${Date.now()}_${toolCalls.length}`),
type: "function",
function: {
name: block.name,
arguments: JSON.stringify(block.input || {}),
name: toString(blockObj.name),
arguments: JSON.stringify(blockObj.input || {}),
},
});
}
}
const message: Record<string, any> = { role: "assistant" };
const message: JsonRecord = { role: "assistant" };
if (textContent) {
message.content = textContent;
}
@@ -255,15 +303,15 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
message.content = "";
}
let finishReason = responseBody.stop_reason || "stop";
let finishReason = toString(root.stop_reason, "stop");
if (finishReason === "end_turn") finishReason = "stop";
if (finishReason === "tool_use") finishReason = "tool_calls";
const result: Record<string, any> = {
id: `chatcmpl-${responseBody.id || Date.now()}`,
const result: JsonRecord = {
id: `chatcmpl-${toString(root.id, String(Date.now()))}`,
object: "chat.completion",
created: Math.floor(Date.now() / 1000),
model: responseBody.model || "claude",
model: toString(root.model, "claude"),
choices: [
{
index: 0,
@@ -273,12 +321,14 @@ export function translateNonStreamingResponse(responseBody, targetFormat, source
],
};
if (responseBody.usage) {
const usage = toRecord(root.usage);
if (Object.keys(usage).length > 0) {
const promptTokens = toNumber(usage.input_tokens, 0);
const completionTokens = toNumber(usage.output_tokens, 0);
result.usage = {
prompt_tokens: responseBody.usage.input_tokens || 0,
completion_tokens: responseBody.usage.output_tokens || 0,
total_tokens:
(responseBody.usage.input_tokens || 0) + (responseBody.usage.output_tokens || 0),
prompt_tokens: promptTokens,
completion_tokens: completionTokens,
total_tokens: promptTokens + completionTokens,
};
}

View File

@@ -50,7 +50,7 @@ export async function handleResponsesCore({
connectionId,
userAgent: null,
comboName: null,
} as any);
});
if (!result.success || !result.response) {
return result;

View File

@@ -44,14 +44,15 @@ export function parseSSEToOpenAIResponse(rawSSE, fallbackModel) {
}
}
const message: Record<string, any> = { role: "assistant",
const message: Record<string, unknown> = {
role: "assistant",
content: contentParts.join(""),
};
if (reasoningParts.length > 0) {
message.reasoning_content = reasoningParts.join("");
}
const result: Record<string, any> = {
const result: Record<string, unknown> = {
id: first.id || `chatcmpl-${Date.now()}`,
object: "chat.completion",
created: first.created || Math.floor(Date.now() / 1000),

View File

@@ -0,0 +1,587 @@
# OmniRoute MCP Server
> **Model Context Protocol server** that exposes OmniRoute's gateway intelligence as **16 tools** for AI agents.
The MCP Server allows any AI agent (Claude Desktop, Cursor, VS Code Copilot, custom agents) to **monitor, control, and optimize** the OmniRoute AI gateway programmatically.
---
## Architecture
```
┌──────────────────────────────────────────────────────────────────┐
│ AI Agent / IDE │
│ (Claude Desktop, Cursor, VS Code, Custom) │
└──────────────────────┬───────────────────────────────────────────┘
│ MCP Protocol (stdio or HTTP)
┌──────────────────────────────────────────────────────────────────┐
│ OmniRoute MCP Server │
│ ┌──────────────┐ ┌─────────────────┐ ┌────────────────────┐ │
│ │ Scope │ │ 16 MCP Tools │ │ Audit Logger │ │
│ │ Enforcement │──│ (Phase 1 + 2) │──│ (SHA-256/SQLite) │ │
│ └──────────────┘ └────────┬────────┘ └────────────────────┘ │
└─────────────────────────────┼────────────────────────────────────┘
│ HTTP (internal)
┌──────────────────────────────────────────────────────────────────┐
│ OmniRoute Gateway (port 20128) │
│ /v1/chat/completions /api/combos /api/usage ... │
└──────────────────────────────────────────────────────────────────┘
```
---
## Quick Start
### 1. Environment Variables
```bash
# Required: OmniRoute base URL
export OMNIROUTE_BASE_URL="http://localhost:20128"
# Optional: API key for authenticated access
export OMNIROUTE_API_KEY="your-api-key"
# Optional: Scope enforcement (default: disabled)
export OMNIROUTE_MCP_ENFORCE_SCOPES="true"
export OMNIROUTE_MCP_SCOPES="read:health,read:combos,read:quota,read:usage,read:models,execute:completions,write:combos,write:budget,write:resilience"
```
### 2. stdio Transport (IDE Integration)
Add to your MCP client configuration:
**Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"omniroute": {
"command": "node",
"args": ["path/to/9router/open-sse/mcp-server/server.ts"],
"env": {
"OMNIROUTE_BASE_URL": "http://localhost:20128",
"OMNIROUTE_API_KEY": "your-key"
}
}
}
}
```
**Cursor** (`.cursor/mcp.json`):
```json
{
"mcpServers": {
"omniroute": {
"command": "npx",
"args": ["tsx", "open-sse/mcp-server/server.ts"],
"env": {
"OMNIROUTE_BASE_URL": "http://localhost:20128"
}
}
}
}
```
**VS Code** (`.vscode/settings.json`):
```json
{
"mcp": {
"servers": {
"omniroute": {
"command": "npx",
"args": ["tsx", "open-sse/mcp-server/server.ts"],
"env": {
"OMNIROUTE_BASE_URL": "http://localhost:20128"
}
}
}
}
}
```
### 3. Start via CLI
```bash
# Direct start (stdio)
npx tsx open-sse/mcp-server/server.ts
# Or via OmniRoute CLI
omniroute --mcp
```
---
## Tool Reference
### Phase 1: Essential Tools (8)
| # | Tool | Scopes | Description |
| --- | ------------------------------- | --------------------- | -------------------------------------------------------------------------- |
| 1 | `omniroute_get_health` | `read:health` | Gateway health, uptime, memory, circuit breakers, rate limits, cache stats |
| 2 | `omniroute_list_combos` | `read:combos` | List all combos (model chains) with strategies and optional metrics |
| 3 | `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
| 4 | `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo for routing |
| 5 | `omniroute_check_quota` | `read:quota` | Remaining API quota per provider with token health status |
| 6 | `omniroute_route_request` | `execute:completions` | Send a chat completion through intelligent routing |
| 7 | `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) with per-provider breakdown |
| 8 | `omniroute_list_models_catalog` | `read:models` | List all available models across providers with capabilities and pricing |
### Phase 2: Advanced Tools (8)
| # | Tool | Scopes | Description |
| --- | ---------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------- |
| 9 | `omniroute_simulate_route` | `read:health`, `read:combos` | Dry-run routing simulation showing fallback tree and estimated costs |
| 10 | `omniroute_set_budget_guard` | `write:budget` | Set session budget with action on exceed: `degrade`, `block`, or `alert` |
| 11 | `omniroute_set_resilience_profile` | `write:resilience` | Apply resilience profile: `aggressive`, `balanced`, or `conservative` |
| 12 | `omniroute_test_combo` | `execute:completions`, `read:combos` | Test each provider in a combo with a real prompt, report latency/cost |
| 13 | `omniroute_get_provider_metrics` | `read:health` | Per-provider metrics with latency percentiles (p50/p95/p99), circuit breaker |
| 14 | `omniroute_best_combo_for_task` | `read:combos`, `read:health` | AI-powered combo recommendation by task type with budget/latency constraints |
| 15 | `omniroute_explain_route` | `read:health`, `read:usage` | Explain why a request was routed to a provider (scoring factors, fallbacks) |
| 16 | `omniroute_get_session_snapshot` | `read:usage` | Full session snapshot: cost, tokens, top models, errors, budget status |
---
## Client Examples
### Python — Full Agent Workflow
```python
"""
OmniRoute MCP Client — Python example using the mcp SDK.
Install: pip install mcp
"""
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
server = StdioServerParameters(
command="npx",
args=["tsx", "open-sse/mcp-server/server.ts"],
env={
"OMNIROUTE_BASE_URL": "http://localhost:20128",
"OMNIROUTE_API_KEY": "your-key",
},
)
async with stdio_client(server) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# 1. Check gateway health
health = await session.call_tool("omniroute_get_health", {})
print("Health:", health.content[0].text)
# 2. List available combos with metrics
combos = await session.call_tool("omniroute_list_combos", {
"includeMetrics": True
})
print("Combos:", combos.content[0].text)
# 3. Find the best combo for a coding task
best = await session.call_tool("omniroute_best_combo_for_task", {
"taskType": "coding",
"budgetConstraint": 0.50,
"latencyConstraint": 5000,
})
print("Best combo:", best.content[0].text)
# 4. Set a session budget guard
budget = await session.call_tool("omniroute_set_budget_guard", {
"maxCost": 1.00,
"action": "degrade",
"degradeToTier": "cheap",
})
print("Budget guard:", budget.content[0].text)
# 5. Route a request through intelligent pipeline
response = await session.call_tool("omniroute_route_request", {
"model": "claude-sonnet-4",
"messages": [
{"role": "user", "content": "Write a Python hello world"}
],
"role": "coding",
})
print("Response:", response.content[0].text)
# 6. Get the session snapshot
snapshot = await session.call_tool("omniroute_get_session_snapshot", {})
print("Session:", snapshot.content[0].text)
asyncio.run(main())
```
### TypeScript — Programmatic Agent
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function main() {
const transport = new StdioClientTransport({
command: "npx",
args: ["tsx", "open-sse/mcp-server/server.ts"],
env: {
OMNIROUTE_BASE_URL: "http://localhost:20128",
OMNIROUTE_API_KEY: "your-key",
},
});
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);
// Check quota before deciding which model to use
const quota = await client.callTool({
name: "omniroute_check_quota",
arguments: { provider: "claude" },
});
console.log("Claude quota:", quota.content);
// Simulate the route before actually calling
const simulation = await client.callTool({
name: "omniroute_simulate_route",
arguments: {
model: "claude-sonnet-4",
promptTokenEstimate: 2000,
},
});
console.log("Route simulation:", simulation.content);
// Send the actual request
const result = await client.callTool({
name: "omniroute_route_request",
arguments: {
model: "claude-sonnet-4",
messages: [{ role: "user", content: "Explain async/await" }],
},
});
console.log("Result:", result.content);
// Cost report
const costs = await client.callTool({
name: "omniroute_cost_report",
arguments: { period: "session" },
});
console.log("Costs:", costs.content);
await client.close();
}
main();
```
### Go — HTTP Client
```go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// Simplified direct-API approach (bypass MCP, hit OmniRoute APIs directly)
// Useful if you don't need MCP protocol framing.
func callTool(baseURL, tool string, args map[string]any) (string, error) {
// MCP tools map to OmniRoute APIs:
endpoints := map[string]string{
"health": "/api/monitoring/health",
"combos": "/api/combos",
"quota": "/api/usage/quota",
"models": "/v1/models",
}
url := baseURL + endpoints[tool]
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}
func routeRequest(baseURL, model, prompt string) (string, error) {
payload := map[string]any{
"model": model,
"messages": []map[string]string{
{"role": "user", "content": prompt},
},
"stream": false,
}
data, _ := json.Marshal(payload)
resp, err := http.Post(
baseURL+"/v1/chat/completions",
"application/json",
bytes.NewReader(data),
)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}
func main() {
base := "http://localhost:20128"
health, _ := callTool(base, "health", nil)
fmt.Println("Health:", health)
result, _ := routeRequest(base, "auto", "Hello from Go!")
fmt.Println("Result:", result)
}
```
---
## Use Cases
### 🔄 Use Case 1: Auto-Healing Agent
An agent that monitors OmniRoute health and auto-switches combos when providers degrade.
```python
async def auto_healing_loop(session):
"""Monitor health and react to provider issues."""
while True:
# Check health
health = await session.call_tool("omniroute_get_health", {})
data = json.loads(health.content[0].text)
# Find providers with open circuit breakers
broken = [
cb for cb in data["circuitBreakers"]
if cb["state"] == "OPEN"
]
if broken:
# Switch to a different resilience profile
await session.call_tool("omniroute_set_resilience_profile", {
"profile": "conservative"
})
# Find best alternative combo
best = await session.call_tool("omniroute_best_combo_for_task", {
"taskType": "coding"
})
best_data = json.loads(best.content[0].text)
combo_id = best_data["recommendedCombo"]["id"]
# Activate it
await session.call_tool("omniroute_switch_combo", {
"comboId": combo_id, "active": True
})
print(f"⚠️ Auto-healed: switched to {combo_id}")
await asyncio.sleep(30) # Check every 30 seconds
```
### 💰 Use Case 2: Budget-Aware Coding Agent
An agent that monitors costs in real-time and degrades to cheaper models when nearing budget.
```python
async def budget_aware_coding(session, task: str, max_budget: float):
"""Complete a coding task within a budget."""
# Set budget guard
await session.call_tool("omniroute_set_budget_guard", {
"maxCost": max_budget,
"action": "degrade",
"degradeToTier": "cheap",
})
# Simulate first to estimate cost
sim = await session.call_tool("omniroute_simulate_route", {
"model": "claude-sonnet-4",
"promptTokenEstimate": len(task.split()) * 2,
})
sim_data = json.loads(sim.content[0].text)
estimated_cost = sim_data["fallbackTree"]["bestCaseCost"]
print(f"Estimated cost: ${estimated_cost:.4f}")
# Send request
result = await session.call_tool("omniroute_route_request", {
"model": "claude-sonnet-4",
"messages": [{"role": "user", "content": task}],
"role": "coding",
})
# Check remaining budget
snapshot = await session.call_tool("omniroute_get_session_snapshot", {})
snap_data = json.loads(snapshot.content[0].text)
print(f"Session cost: ${snap_data['costTotal']:.4f}")
if snap_data.get("budgetGuard"):
print(f"Budget remaining: ${snap_data['budgetGuard']['remaining']:.4f}")
return json.loads(result.content[0].text)["response"]["content"]
```
### 🧪 Use Case 3: Combo Benchmarking Agent
An agent that periodically benchmarks all combos and reports the fastest/cheapest.
```python
async def benchmark_combos(session):
"""Benchmark all enabled combos and rank them."""
combos = await session.call_tool("omniroute_list_combos", {
"includeMetrics": True,
})
combo_list = json.loads(combos.content[0].text)["combos"]
results = []
for combo in combo_list:
if not combo["enabled"]:
continue
test = await session.call_tool("omniroute_test_combo", {
"comboId": combo["id"],
"testPrompt": "Return the number 42.",
})
test_data = json.loads(test.content[0].text)
results.append({
"combo": combo["name"],
"fastest": test_data["summary"]["fastestProvider"],
"cheapest": test_data["summary"]["cheapestProvider"],
"success_rate": f'{test_data["summary"]["successful"]}/{test_data["summary"]["totalProviders"]}',
})
print("📊 Combo Benchmark Results:")
for r in results:
print(f" {r['combo']}: fastest={r['fastest']}, cheapest={r['cheapest']}, success={r['success_rate']}")
```
### 🔍 Use Case 4: Post-Mortem Debugging Agent
An agent that explains why a request was routed to a specific provider.
```typescript
async function debugRouting(client: Client, requestId: string) {
// Explain the routing decision
const explanation = await client.callTool({
name: "omniroute_explain_route",
arguments: { requestId },
});
const data = JSON.parse(explanation.content[0].text);
console.log(`Request ${requestId}:`);
console.log(` Provider: ${data.decision.providerSelected}`);
console.log(` Model: ${data.decision.modelUsed}`);
console.log(` Score: ${data.decision.score}`);
console.log(` Factors:`);
for (const factor of data.decision.factors) {
console.log(` ${factor.name}: ${factor.value} (weight: ${factor.weight})`);
}
if (data.decision.fallbacksTriggered.length > 0) {
console.log(` Fallbacks triggered:`);
for (const fb of data.decision.fallbacksTriggered) {
console.log(` ${fb.provider}: ${fb.reason}`);
}
}
}
```
### 📋 Use Case 5: Model Discovery Agent
An agent that discovers the cheapest models for a given capability.
```python
async def find_cheapest_models(session, capability="chat"):
"""Find the cheapest available models for a capability."""
catalog = await session.call_tool("omniroute_list_models_catalog", {
"capability": capability,
})
models = json.loads(catalog.content[0].text)["models"]
# Filter available models with pricing
priced = [
m for m in models
if m["status"] == "available" and m.get("pricing")
]
priced.sort(key=lambda m: m["pricing"]["inputPerMillion"] or float("inf"))
print(f"💡 Cheapest {capability} models:")
for m in priced[:5]:
input_cost = m["pricing"]["inputPerMillion"] or 0
output_cost = m["pricing"]["outputPerMillion"] or 0
print(f" {m['id']} ({m['provider']}): ${input_cost}/M in, ${output_cost}/M out")
```
---
## Security & Scope Enforcement
The MCP server supports **fine-grained scope enforcement** for multi-tenant environments:
| Scope | Tools |
| --------------------- | ---------------------------------------------------------------------------------------------- |
| `read:health` | `get_health`, `simulate_route`, `get_provider_metrics`, `best_combo_for_task`, `explain_route` |
| `read:combos` | `list_combos`, `get_combo_metrics`, `simulate_route`, `best_combo_for_task`, `test_combo` |
| `read:quota` | `check_quota` |
| `read:usage` | `cost_report`, `explain_route`, `get_session_snapshot` |
| `read:models` | `list_models_catalog` |
| `write:combos` | `switch_combo` |
| `write:budget` | `set_budget_guard` |
| `write:resilience` | `set_resilience_profile` |
| `execute:completions` | `route_request`, `test_combo` |
**Wildcard scopes:** Use `read:*` to grant all read scopes, or `*` for full access.
---
## Audit Logging
Every tool call is logged to the `mcp_tool_audit` SQLite table:
- **Input:** SHA-256 hashed (never stores raw prompts)
- **Output:** Truncated to 200 chars
- **Metadata:** Tool name, duration, success/error, API key ID
Access audit data via:
```typescript
import { getRecentAuditEntries, getAuditStats } from "./audit";
const entries = await getRecentAuditEntries(50);
const stats = await getAuditStats();
// stats: { totalCalls, successRate, avgDurationMs, topTools }
```
---
## File Structure
```
mcp-server/
├── server.ts # MCP server setup, essential tool handlers, entry point
├── index.ts # Barrel export
├── audit.ts # SQLite audit logger (SHA-256 input hashing)
├── scopeEnforcement.ts # Fine-grained scope enforcement
├── schemas/
│ ├── tools.ts # Zod schemas for all 16 tools (input/output/scopes)
│ ├── a2a.ts # A2A protocol types (Agent Card, Task, JSON-RPC)
│ ├── audit.ts # Audit & routing decision types + hash helpers
│ └── index.ts # Schema barrel export
├── tools/
│ └── advancedTools.ts # Phase 2 tool handlers (8 advanced tools)
└── __tests__/
├── essentialTools.test.ts
├── advancedTools.test.ts
└── a2aLifecycle.test.ts
```
---
## License
Part of [OmniRoute](https://github.com/diegosouzapw/OmniRoute) — MIT License.

View File

@@ -0,0 +1,85 @@
import { afterEach, describe, expect, it } from "vitest";
import { A2ATaskManager } from "../../../src/lib/a2a/taskManager.ts";
import { executeA2ATaskWithState } from "../../../src/lib/a2a/taskExecution.ts";
const managers: A2ATaskManager[] = [];
function createManager(ttlMinutes = 5) {
const manager = new A2ATaskManager(ttlMinutes);
managers.push(manager);
return manager;
}
afterEach(() => {
while (managers.length > 0) {
managers.pop()?.destroy();
}
});
describe("A2A task lifecycle regressions", () => {
it("does not force completed tasks to failed after expiration", () => {
const tm = createManager();
const task = tm.createTask({
skill: "smart-routing",
messages: [{ role: "user", content: "hello" }],
});
tm.updateTask(task.id, "working");
tm.updateTask(task.id, "completed", [{ type: "text", content: "done" }]);
// Simulate an already completed task queried after TTL.
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
expect(() => tm.getTask(task.id)).not.toThrow();
const loaded = tm.getTask(task.id);
expect(loaded?.state).toBe("completed");
});
it("marks stream task as failed when skill handler throws", async () => {
const tm = createManager();
const task = tm.createTask({
skill: "smart-routing",
messages: [{ role: "user", content: "trigger error" }],
});
tm.updateTask(task.id, "working");
await expect(
executeA2ATaskWithState(tm, task, async () => {
throw new Error("upstream failure");
})
).rejects.toThrow("upstream failure");
const loaded = tm.getTask(task.id);
expect(loaded?.state).toBe("failed");
expect(loaded?.artifacts.at(-1)).toEqual({ type: "error", content: "upstream failure" });
});
it("transitions expired submitted tasks to failed without throwing", () => {
const tm = createManager();
const task = tm.createTask({
skill: "smart-routing",
messages: [{ role: "user", content: "hello" }],
});
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
expect(() => tm.getTask(task.id)).not.toThrow();
const loaded = tm.getTask(task.id);
expect(loaded?.state).toBe("failed");
});
it("does not rewrite cancelled tasks to failed during cleanup", () => {
const tm = createManager();
const task = tm.createTask({
skill: "smart-routing",
messages: [{ role: "user", content: "cancel me" }],
});
tm.updateTask(task.id, "cancelled");
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
// private in TS only; callable at runtime for regression test
(tm as any).cleanupExpired();
const loaded = tm.getTask(task.id);
expect(loaded?.state).toBe("cancelled");
});
});

View File

@@ -0,0 +1,141 @@
/**
* Unit tests for MCP Advanced Tools (Phase 3)
*
* Tests all 8 advanced tool handlers.
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
const mockFetch = vi.fn();
vi.stubGlobal("fetch", mockFetch);
describe("MCP Advanced Tools", () => {
beforeEach(() => {
mockFetch.mockReset();
});
describe("simulate_route", () => {
it("should return simulation with fallback tree", async () => {
// Mock combos response
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => [
{
id: "combo-1",
name: "Fast",
enabled: true,
models: [
{ provider: "anthropic", model: "claude-sonnet", costPer1MTokens: 3 },
{ provider: "google", model: "gemini-pro", costPer1MTokens: 1 },
],
},
],
});
const response = await mockFetch("http://localhost:20128/api/combos");
const combos = await response.json();
expect(combos).toHaveLength(1);
expect(combos[0].models).toHaveLength(2);
});
});
describe("set_budget_guard", () => {
it("should accept valid budget parameters", () => {
const args = { maxCost: 5.0, action: "alert", degradeToTier: "cheap" };
expect(args.maxCost).toBeGreaterThan(0);
expect(["degrade", "block", "alert"]).toContain(args.action);
});
it("should reject invalid actions", () => {
const args = { maxCost: 5.0, action: "invalid" };
expect(["degrade", "block", "alert"]).not.toContain(args.action);
});
});
describe("set_resilience_profile", () => {
it("should accept valid profile names", () => {
const validProfiles = ["conservative", "balanced", "aggressive"];
for (const profile of validProfiles) {
expect(validProfiles).toContain(profile);
}
});
});
describe("test_combo", () => {
it("should test combo with all models", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => [
{
id: "test-combo",
models: [
{ provider: "anthropic", model: "claude-sonnet" },
{ provider: "google", model: "gemini-pro" },
],
},
],
});
const response = await mockFetch("http://localhost:20128/api/combos");
const combos = await response.json();
const combo = combos.find((c: { id?: string }) => c.id === "test-combo");
expect(combo).toBeDefined();
expect(combo.models).toHaveLength(2);
});
});
describe("get_provider_metrics", () => {
it("should return detailed metrics for a provider", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
provider: "anthropic",
requests: 100,
avgLatencyMs: 1200,
errorRate: 0.02,
}),
});
const response = await mockFetch("http://localhost:20128/api/usage/analytics");
const data = await response.json();
expect(data).toHaveProperty("provider");
expect(data).toHaveProperty("requests");
expect(data.avgLatencyMs).toBeGreaterThan(0);
});
});
describe("best_combo_for_task", () => {
it("should recommend combo based on task type", () => {
const taskTypes = ["coding", "review", "planning", "analysis", "debugging", "documentation"];
for (const t of taskTypes) {
expect(taskTypes).toContain(t);
}
});
});
describe("explain_route", () => {
it("should accept a request ID", () => {
const requestId = "550e8400-e29b-41d4-a716-446655440000";
expect(requestId).toMatch(/^[0-9a-f-]+$/);
});
});
describe("get_session_snapshot", () => {
it("should return session data", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
sessionStart: "2026-03-03T17:00:00Z",
requestCount: 42,
totalCost: 0.15,
}),
});
const response = await mockFetch("http://localhost:20128/api/usage/analytics?period=session");
const data = await response.json();
expect(data).toHaveProperty("sessionStart");
expect(data).toHaveProperty("requestCount");
expect(data.totalCost).toBeGreaterThanOrEqual(0);
});
});
});

View File

@@ -0,0 +1,139 @@
/**
* Unit tests for MCP Essential Tools (Phase 1)
*
* Tests all 8 essential tool handlers via the tool handler functions.
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { MCP_ESSENTIAL_TOOLS } from "../schemas/tools";
// Mock fetch globally
const mockFetch = vi.fn();
vi.stubGlobal("fetch", mockFetch);
describe("MCP Essential Tools", () => {
beforeEach(() => {
mockFetch.mockReset();
});
describe("Tool schema validation", () => {
it("should have exactly 8 essential tools", () => {
const schemas = MCP_ESSENTIAL_TOOLS;
expect(schemas).toHaveLength(8);
});
it("all tools should have omniroute_ prefix", () => {
const schemas = MCP_ESSENTIAL_TOOLS;
for (const schema of schemas) {
expect(schema.name).toMatch(/^omniroute_/);
}
});
});
describe("get_health handler", () => {
it("should return health data when API is available", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ status: "healthy", uptime: 1000, circuitBreakers: [] }),
});
const response = await mockFetch("http://localhost:20128/api/monitoring/health");
const data = await response.json();
expect(data.status).toBe("healthy");
expect(data).toHaveProperty("uptime");
});
it("should handle API failure gracefully", async () => {
mockFetch.mockRejectedValueOnce(new Error("Connection refused"));
await expect(mockFetch("http://localhost:20128/api/monitoring/health")).rejects.toThrow();
});
});
describe("check_quota handler", () => {
it("should return quota data for all providers", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
providers: [
{ provider: "anthropic", quotaUsed: 50, quotaTotal: 100 },
{ provider: "google", quotaUsed: 20, quotaTotal: 200 },
],
}),
});
const response = await mockFetch("http://localhost:20128/api/usage/quota");
const data = await response.json();
expect(data.providers).toHaveLength(2);
expect(data.providers[0].provider).toBe("anthropic");
});
it("should filter by provider when specified", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
providers: [{ provider: "anthropic", quotaUsed: 50, quotaTotal: 100 }],
}),
});
const response = await mockFetch("http://localhost:20128/api/usage/quota?provider=anthropic");
const data = await response.json();
expect(data.providers).toHaveLength(1);
});
});
describe("list_combos handler", () => {
it("should return array of combos", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => [
{ id: "combo-1", name: "Fast Coding", enabled: true },
{ id: "combo-2", name: "Cost Saver", enabled: false },
],
});
const response = await mockFetch("http://localhost:20128/api/combos");
const data = await response.json();
expect(Array.isArray(data)).toBe(true);
expect(data[0]).toHaveProperty("id");
expect(data[0]).toHaveProperty("name");
});
});
describe("route_request handler", () => {
it("should proxy chat completion request", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
choices: [{ message: { content: "Hello!" } }],
model: "claude-sonnet",
provider: "anthropic",
}),
});
const response = await mockFetch("http://localhost:20128/v1/chat/completions", {
method: "POST",
body: JSON.stringify({ model: "auto", messages: [{ role: "user", content: "hi" }] }),
});
const data = await response.json();
expect(data.choices[0].message.content).toBe("Hello!");
});
});
describe("cost_report handler", () => {
it("should return cost analytics", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
totalCost: 0.05,
requestCount: 10,
period: "session",
}),
});
const response = await mockFetch("http://localhost:20128/api/usage/analytics?period=session");
const data = await response.json();
expect(data).toHaveProperty("totalCost");
expect(data).toHaveProperty("requestCount");
});
});
});

View File

@@ -0,0 +1,320 @@
/**
* MCP Audit Logger — Records all MCP tool invocations for security and observability.
*
* Logs are written to the `mcp_tool_audit` SQLite table.
* Input data is hashed (SHA-256) to avoid storing sensitive prompts.
* Output is truncated to 200 chars for summary.
*/
import { hashInput, summarizeOutput } from "./schemas/audit.ts";
// ============ Database Connection ============
interface StatementLike<TRow = unknown> {
get: (...params: unknown[]) => TRow | undefined;
all: (...params: unknown[]) => TRow[];
run: (...params: unknown[]) => unknown;
}
interface AuditDatabase {
prepare: <TRow = unknown>(sql: string) => StatementLike<TRow>;
}
interface AuditStatsRow {
total: unknown;
successRate: unknown;
avgDuration: unknown;
}
interface AuditTopToolRow {
tool: unknown;
count: unknown;
}
interface AuditCountRow {
total: unknown;
}
interface AuditEntryRow {
id?: unknown;
tool_name?: unknown;
input_hash?: unknown;
output_summary?: unknown;
duration_ms?: unknown;
api_key_id?: unknown;
success?: unknown;
error_code?: unknown;
created_at?: unknown;
}
export interface McpAuditQuery {
limit?: number;
offset?: number;
tool?: string;
success?: boolean;
apiKeyId?: string;
}
export interface McpAuditEntry {
id: number;
toolName: string;
inputHash: string;
outputSummary: string;
durationMs: number;
apiKeyId: string | null;
success: boolean;
errorCode: string | null;
createdAt: string;
}
function toNullableString(value: unknown): string | null {
return typeof value === "string" ? value : null;
}
function toBoolean(value: unknown, fallback = false): boolean {
if (typeof value === "boolean") return value;
if (value === 1 || value === "1") return true;
if (value === 0 || value === "0") return false;
return fallback;
}
function toPositiveInt(value: unknown, fallback: number): number {
const parsed = toNumber(value, fallback);
if (!Number.isFinite(parsed)) return fallback;
return Math.max(0, Math.floor(parsed));
}
function mapAuditEntry(row: AuditEntryRow): McpAuditEntry {
return {
id: toPositiveInt(row.id, 0),
toolName: toString(row.tool_name),
inputHash: toString(row.input_hash),
outputSummary: toString(row.output_summary),
durationMs: toNumber(row.duration_ms, 0),
apiKeyId: toNullableString(row.api_key_id),
success: toBoolean(row.success, false),
errorCode: toNullableString(row.error_code),
createdAt: toString(row.created_at),
};
}
function buildAuditFilterSql(filters: McpAuditQuery): { whereSql: string; params: unknown[] } {
const clauses: string[] = [];
const params: unknown[] = [];
if (typeof filters.tool === "string" && filters.tool.trim().length > 0) {
clauses.push("tool_name = ?");
params.push(filters.tool.trim());
}
if (typeof filters.success === "boolean") {
clauses.push("success = ?");
params.push(filters.success ? 1 : 0);
}
if (typeof filters.apiKeyId === "string" && filters.apiKeyId.trim().length > 0) {
clauses.push("api_key_id = ?");
params.push(filters.apiKeyId.trim());
}
return {
whereSql: clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "",
params,
};
}
let db: AuditDatabase | null = null;
function toNumber(value: unknown, fallback = 0): number {
const parsed =
typeof value === "number"
? value
: typeof value === "string" && value.trim().length > 0
? Number(value)
: Number.NaN;
return Number.isFinite(parsed) ? parsed : fallback;
}
function toString(value: unknown): string {
return typeof value === "string" ? value : "";
}
/**
* Lazy-load the database connection.
* Uses the same SQLite database as the main OmniRoute app.
*/
async function getDb(): Promise<AuditDatabase | null> {
if (db) return db;
try {
// Try importing the db module from the main app
const { homedir } = await import("node:os");
const { join } = await import("node:path");
const { existsSync } = await import("node:fs");
const dbPath = process.env.DATA_DIR
? join(process.env.DATA_DIR, "storage.sqlite")
: join(homedir(), ".omniroute", "storage.sqlite");
if (!existsSync(dbPath)) {
console.error(`[MCP Audit] Database not found at ${dbPath} — audit logging disabled`);
return null;
}
const Database = (await import("better-sqlite3")).default as unknown as new (
dbPath: string
) => AuditDatabase;
db = new Database(dbPath);
return db;
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
console.error("[MCP Audit] Failed to connect to database:", message);
return null;
}
}
// ============ Audit Logger ============
/**
* Log a tool invocation to the mcp_tool_audit table.
*
* Security: Input is hashed, never stored in clear text.
* Output is truncated to a summary.
*/
export async function logToolCall(
toolName: string,
input: unknown,
output: unknown,
durationMs: number,
success: boolean,
errorCode?: string
): Promise<void> {
try {
const database = await getDb();
if (!database) return; // Audit disabled if no DB
const inputHash = await hashInput(input);
const outputSummary = summarizeOutput(output);
const apiKeyId = process.env.OMNIROUTE_API_KEY_ID || null;
database
.prepare(
`INSERT INTO mcp_tool_audit (tool_name, input_hash, output_summary, duration_ms, api_key_id, success, error_code)
VALUES (?, ?, ?, ?, ?, ?, ?)`
)
.run(
toolName,
inputHash,
outputSummary,
durationMs,
apiKeyId,
success ? 1 : 0,
errorCode || null
);
} catch (err: unknown) {
// Never let audit failure break tool execution
const message = err instanceof Error ? err.message : String(err);
console.error("[MCP Audit] Failed to log:", message);
}
}
/**
* Get recent audit entries (for dashboard/monitoring).
*/
export async function queryAuditEntries(
filters: McpAuditQuery = {}
): Promise<{ entries: McpAuditEntry[]; total: number; limit: number; offset: number }> {
try {
const database = await getDb();
const limit = Math.max(1, Math.min(500, toPositiveInt(filters.limit, 50)));
const offset = Math.max(0, toPositiveInt(filters.offset, 0));
if (!database) return { entries: [], total: 0, limit, offset };
const { whereSql, params } = buildAuditFilterSql(filters);
const totalRow = database
.prepare<AuditCountRow>(`SELECT COUNT(*) as total FROM mcp_tool_audit ${whereSql}`)
.get(...params);
const rows = database
.prepare<AuditEntryRow>(
`SELECT
id,
tool_name,
input_hash,
output_summary,
duration_ms,
api_key_id,
success,
error_code,
created_at
FROM mcp_tool_audit
${whereSql}
ORDER BY created_at DESC
LIMIT ? OFFSET ?`
)
.all(...params, limit, offset);
return {
entries: rows.map(mapAuditEntry),
total: toPositiveInt(totalRow?.total, 0),
limit,
offset,
};
} catch {
return { entries: [], total: 0, limit: 50, offset: 0 };
}
}
/**
* Backward compatible helper for existing callers.
*/
export async function getRecentAuditEntries(limit = 50): Promise<McpAuditEntry[]> {
const result = await queryAuditEntries({ limit, offset: 0 });
return result.entries;
}
/**
* Get audit stats for monitoring.
*/
export async function getAuditStats(): Promise<{
totalCalls: number;
successRate: number;
avgDurationMs: number;
topTools: Array<{ tool: string; count: number }>;
}> {
try {
const database = await getDb();
if (!database) return { totalCalls: 0, successRate: 0, avgDurationMs: 0, topTools: [] };
const stats = database
.prepare(
`SELECT
COUNT(*) as total,
AVG(CASE WHEN success = 1 THEN 1.0 ELSE 0.0 END) as successRate,
AVG(duration_ms) as avgDuration
FROM mcp_tool_audit
WHERE created_at > datetime('now', '-24 hours')`
)
.get() as AuditStatsRow | undefined;
const topTools = database
.prepare(
`SELECT tool_name as tool, COUNT(*) as count
FROM mcp_tool_audit
WHERE created_at > datetime('now', '-24 hours')
GROUP BY tool_name
ORDER BY count DESC
LIMIT 10`
)
.all() as AuditTopToolRow[];
return {
totalCalls: toNumber(stats?.total, 0),
successRate: toNumber(stats?.successRate, 0),
avgDurationMs: toNumber(stats?.avgDuration, 0),
topTools: (topTools || []).map((entry) => ({
tool: toString(entry.tool),
count: toNumber(entry.count, 0),
})),
};
} catch {
return { totalCalls: 0, successRate: 0, avgDurationMs: 0, topTools: [] };
}
}

View File

@@ -0,0 +1,120 @@
/**
* MCP HTTP Transport Layer — Singleton server + SSE/Streamable HTTP handlers.
*
* Runs the MCP server **inside** the Next.js process so it can be toggled
* from the dashboard without requiring `omniroute --mcp`.
*
* Transport modes:
* - SSE: GET /api/mcp/sse (event stream) + POST /api/mcp/sse (messages)
* - Streamable HTTP: POST /api/mcp/stream (messages) + GET /api/mcp/stream (SSE stream) + DELETE /api/mcp/stream (session end)
*/
import { randomUUID } from "node:crypto";
import { createMcpServer } from "./server.ts";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// ────── Singleton ──────────────────────────────────────────
let _server: McpServer | null = null;
let _transport: WebStandardStreamableHTTPServerTransport | null = null;
let _startedAt: number | null = null;
let _activeTransportMode: "sse" | "streamable-http" | null = null;
function ensureServer(mode: "sse" | "streamable-http"): {
server: McpServer;
transport: WebStandardStreamableHTTPServerTransport;
} {
if (_server && _transport && _activeTransportMode === mode) {
return { server: _server, transport: _transport };
}
// Shutdown previous if switching modes
if (_transport) {
try { _transport.close(); } catch { /* ignore */ }
}
_server = createMcpServer();
_transport = new WebStandardStreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
});
_activeTransportMode = mode;
_startedAt = Date.now();
// Connect server to transport (fire-and-forget, will be ready by first request)
void _server.connect(_transport);
console.log(`[MCP] HTTP transport started (${mode})`);
return { server: _server, transport: _transport };
}
// ────── Streamable HTTP Handler ────────────────────────────
/**
* Handle Streamable HTTP requests (POST / GET / DELETE).
* Used by the Next.js route at /api/mcp/stream.
*/
export async function handleMcpStreamableHTTP(request: Request): Promise<Response> {
const { transport } = ensureServer("streamable-http");
try {
return await transport.handleRequest(request);
} catch (err) {
console.error("[MCP] Streamable HTTP error:", err);
return new Response(
JSON.stringify({ error: "MCP transport error" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
/**
* Handle SSE requests.
* SSE transport is implemented via Streamable HTTP transport with GET for SSE stream
* and POST for messages (the Streamable HTTP transport supports both patterns).
*/
export async function handleMcpSSE(request: Request): Promise<Response> {
const { transport } = ensureServer("sse");
try {
return await transport.handleRequest(request);
} catch (err) {
console.error("[MCP] SSE error:", err);
return new Response(
JSON.stringify({ error: "MCP SSE transport error" }),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
}
// ────── Status & Lifecycle ─────────────────────────────────
export function getMcpHttpStatus(): {
online: boolean;
transport: string | null;
startedAt: number | null;
uptime: string | null;
} {
const online = _transport !== null && _activeTransportMode !== null;
return {
online,
transport: _activeTransportMode,
startedAt: _startedAt,
uptime: _startedAt ? `${Math.floor((Date.now() - _startedAt) / 1000)}s` : null,
};
}
export function shutdownMcpHttp(): void {
if (_transport) {
try { _transport.close(); } catch { /* ignore */ }
}
_server = null;
_transport = null;
_activeTransportMode = null;
_startedAt = null;
console.log("[MCP] HTTP transport shutdown");
}
export function isMcpHttpActive(): boolean {
return _transport !== null;
}

View File

@@ -0,0 +1,20 @@
/**
* OmniRoute MCP Server — barrel export.
*/
export { createMcpServer, startMcpStdio } from "./server.ts";
export { logToolCall, getRecentAuditEntries, getAuditStats, queryAuditEntries } from "./audit.ts";
export {
resolveMcpHeartbeatPath,
readMcpHeartbeat,
isMcpHeartbeatOnline,
isProcessAlive,
} from "./runtimeHeartbeat.ts";
export {
handleMcpSSE,
handleMcpStreamableHTTP,
getMcpHttpStatus,
shutdownMcpHttp,
isMcpHttpActive,
} from "./httpTransport.ts";
export * from "./schemas/index.ts";

View File

@@ -0,0 +1,162 @@
/**
* MCP Runtime Heartbeat
*
* Persists MCP stdio process liveness into DATA_DIR/runtime/mcp-heartbeat.json
* so dashboard APIs can report real online/offline state.
*/
import { promises as fs } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
export type McpHeartbeatSnapshot = {
pid: number;
startedAt: string;
lastHeartbeatAt: string;
version: string;
transport: "stdio";
scopesEnforced: boolean;
allowedScopes: string[];
toolCount: number;
};
const HEARTBEAT_FILE = "mcp-heartbeat.json";
const RUNTIME_DIR = "runtime";
const DEFAULT_INTERVAL_MS = 5000;
function resolveDataDir(): string {
const configured = process.env.DATA_DIR;
if (typeof configured === "string" && configured.trim().length > 0) {
return configured.trim();
}
return join(homedir(), ".omniroute");
}
export function resolveMcpHeartbeatPath(): string {
return join(resolveDataDir(), RUNTIME_DIR, HEARTBEAT_FILE);
}
async function writeHeartbeat(snapshot: McpHeartbeatSnapshot): Promise<void> {
const heartbeatPath = resolveMcpHeartbeatPath();
const runtimeDir = join(resolveDataDir(), RUNTIME_DIR);
await fs.mkdir(runtimeDir, { recursive: true });
await fs.writeFile(heartbeatPath, JSON.stringify(snapshot, null, 2), "utf-8");
}
export function startMcpHeartbeat(config: {
version: string;
scopesEnforced: boolean;
allowedScopes: string[];
toolCount: number;
intervalMs?: number;
}): () => void {
const startedAt = new Date().toISOString();
let timer: ReturnType<typeof setInterval> | null = null;
let stopped = false;
const intervalMs =
typeof config.intervalMs === "number" && config.intervalMs > 0
? config.intervalMs
: DEFAULT_INTERVAL_MS;
const tick = async () => {
if (stopped) return;
const snapshot: McpHeartbeatSnapshot = {
pid: process.pid,
startedAt,
lastHeartbeatAt: new Date().toISOString(),
version: config.version,
transport: "stdio",
scopesEnforced: config.scopesEnforced,
allowedScopes: [...config.allowedScopes],
toolCount: config.toolCount,
};
try {
await writeHeartbeat(snapshot);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error("[MCP Heartbeat] Failed to write heartbeat:", message);
}
};
void tick();
timer = setInterval(() => {
void tick();
}, intervalMs);
return () => {
if (stopped) return;
stopped = true;
if (timer) {
clearInterval(timer);
timer = null;
}
// Keep last snapshot on disk for post-mortem/offline reporting.
void tick();
};
}
export async function readMcpHeartbeat(): Promise<McpHeartbeatSnapshot | null> {
const heartbeatPath = resolveMcpHeartbeatPath();
try {
const raw = await fs.readFile(heartbeatPath, "utf-8");
const parsed = JSON.parse(raw) as Partial<McpHeartbeatSnapshot>;
if (!parsed || typeof parsed !== "object") return null;
if (
typeof parsed.pid !== "number" ||
typeof parsed.startedAt !== "string" ||
typeof parsed.lastHeartbeatAt !== "string" ||
typeof parsed.version !== "string" ||
parsed.transport !== "stdio" ||
typeof parsed.scopesEnforced !== "boolean" ||
!Array.isArray(parsed.allowedScopes) ||
typeof parsed.toolCount !== "number"
) {
return null;
}
const allowedScopes = parsed.allowedScopes.filter((scope): scope is string => {
return typeof scope === "string";
});
return {
pid: parsed.pid,
startedAt: parsed.startedAt,
lastHeartbeatAt: parsed.lastHeartbeatAt,
version: parsed.version,
transport: "stdio",
scopesEnforced: parsed.scopesEnforced,
allowedScopes,
toolCount: parsed.toolCount,
};
} catch {
return null;
}
}
export function isProcessAlive(pid: number): boolean {
if (!Number.isFinite(pid) || pid <= 0) return false;
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
export function isMcpHeartbeatOnline(
snapshot: McpHeartbeatSnapshot | null,
options?: { staleAfterMs?: number; requireLivePid?: boolean }
): boolean {
if (!snapshot) return false;
const staleAfterMs =
typeof options?.staleAfterMs === "number" && options.staleAfterMs > 0
? options.staleAfterMs
: DEFAULT_INTERVAL_MS * 3;
const elapsed = Date.now() - new Date(snapshot.lastHeartbeatAt).getTime();
if (!Number.isFinite(elapsed) || elapsed > staleAfterMs) return false;
if (options?.requireLivePid === false) return true;
return isProcessAlive(snapshot.pid);
}

View File

@@ -0,0 +1,203 @@
/**
* A2A (Agent-to-Agent) Schemas — Contracts for OmniRoute A2A Server.
*
* Defines the Agent Card structure, Task lifecycle, Message format,
* and all A2A protocol types conforming to A2A Protocol v0.3.
*/
import { z } from "zod";
// ============ Agent Card Schema ============
export const AgentSkillSchema = z.object({
id: z.string(),
name: z.string(),
description: z.string(),
tags: z.array(z.string()),
examples: z.array(z.string()).optional(),
});
export const AgentCardSchema = z.object({
name: z.string(),
description: z.string(),
url: z.string().url(),
version: z.string(),
capabilities: z.object({
streaming: z.boolean(),
pushNotifications: z.boolean(),
}),
skills: z.array(AgentSkillSchema),
authentication: z.object({
schemes: z.array(z.string()),
apiKeyHeader: z.string().optional(),
}),
});
export type AgentCard = z.infer<typeof AgentCardSchema>;
export type AgentSkill = z.infer<typeof AgentSkillSchema>;
// ============ Task Schema ============
export const TaskStateEnum = z.enum(["submitted", "working", "completed", "failed", "cancelled"]);
export type TaskState = z.infer<typeof TaskStateEnum>;
export const TaskInputSchema = z.object({
messages: z
.array(
z.object({
role: z.string(),
content: z.string(),
})
)
.optional(),
model: z.string().optional(),
combo: z.string().optional(),
budget: z.number().optional(),
role: z
.enum(["coding", "review", "planning", "analysis", "debugging", "documentation"])
.optional(),
metadata: z.record(z.unknown()).optional(),
});
export const CostEnvelopeSchema = z.object({
estimated: z.number(),
actual: z.number(),
currency: z.string().default("USD"),
});
export const ResilienceTraceEventSchema = z.object({
event: z.string(),
provider: z.string().optional(),
reason: z.string().optional(),
timestamp: z.string(),
});
export const PolicyVerdictSchema = z.object({
allowed: z.boolean(),
reason: z.string(),
restrictions: z.array(z.string()).optional(),
});
export const TaskOutputSchema = z.object({
response: z
.object({
content: z.string(),
model: z.string(),
tokens: z.object({
prompt: z.number(),
completion: z.number(),
}),
})
.optional(),
routingExplanation: z.string().optional(),
costEnvelope: CostEnvelopeSchema.optional(),
resilienceTrace: z.array(ResilienceTraceEventSchema).optional(),
policyVerdict: PolicyVerdictSchema.optional(),
});
export const TaskSchema = z.object({
id: z.string().uuid(),
state: TaskStateEnum,
skillId: z.string(),
input: TaskInputSchema.optional(),
output: TaskOutputSchema.optional(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime(),
completedAt: z.string().datetime().nullable().optional(),
expiresAt: z.string().datetime().nullable().optional(),
});
export type Task = z.infer<typeof TaskSchema>;
export type TaskInput = z.infer<typeof TaskInputSchema>;
export type TaskOutput = z.infer<typeof TaskOutputSchema>;
export type CostEnvelope = z.infer<typeof CostEnvelopeSchema>;
export type ResilienceTraceEvent = z.infer<typeof ResilienceTraceEventSchema>;
export type PolicyVerdict = z.infer<typeof PolicyVerdictSchema>;
// ============ JSON-RPC 2.0 Schemas ============
export const JsonRpcRequestSchema = z.object({
jsonrpc: z.literal("2.0"),
method: z.enum(["message/send", "message/stream", "tasks/get", "tasks/cancel"]),
params: z.record(z.unknown()),
id: z.union([z.string(), z.number()]),
});
export const JsonRpcResponseSchema = z.object({
jsonrpc: z.literal("2.0"),
result: z.unknown().optional(),
error: z
.object({
code: z.number(),
message: z.string(),
data: z.unknown().optional(),
})
.optional(),
id: z.union([z.string(), z.number()]).nullable(),
});
export type JsonRpcRequest = z.infer<typeof JsonRpcRequestSchema>;
export type JsonRpcResponse = z.infer<typeof JsonRpcResponseSchema>;
// ============ Message Schemas ============
export const MessageSendParamsSchema = z.object({
task: z
.object({
skillId: z.string(),
})
.optional(),
message: z.object({
role: z.string().default("user"),
content: z.string(),
metadata: z.record(z.unknown()).optional(),
}),
config: z
.object({
model: z.string().optional(),
combo: z.string().optional(),
budget: z.number().optional(),
taskRole: z
.enum(["coding", "review", "planning", "analysis", "debugging", "documentation"])
.optional(),
})
.optional(),
});
export const TasksGetParamsSchema = z.object({
taskId: z.string().uuid(),
});
export const TasksCancelParamsSchema = z.object({
taskId: z.string().uuid(),
});
export type MessageSendParams = z.infer<typeof MessageSendParamsSchema>;
export type TasksGetParams = z.infer<typeof TasksGetParamsSchema>;
export type TasksCancelParams = z.infer<typeof TasksCancelParamsSchema>;
// ============ SSE Event Types ============
export const A2A_SSE_EVENTS = {
TASK_STATUS: "task.status",
TASK_ARTIFACT: "task.artifact",
TASK_CHUNK: "task.chunk",
TASK_COMPLETE: "task.complete",
TASK_ERROR: "task.error",
HEARTBEAT: "heartbeat",
} as const;
// ============ A2A Error Codes ============
export const A2A_ERROR_CODES = {
INVALID_REQUEST: -32600,
METHOD_NOT_FOUND: -32601,
INVALID_PARAMS: -32602,
INTERNAL_ERROR: -32603,
TASK_NOT_FOUND: -32001,
TASK_ALREADY_COMPLETED: -32002,
UNAUTHORIZED: -32003,
BUDGET_EXCEEDED: -32004,
PROVIDER_UNAVAILABLE: -32005,
} as const;

View File

@@ -0,0 +1,121 @@
/**
* MCP/A2A Audit Types — Interfaces for audit log entries.
*
* These types define the format of audit log entries stored in the
* `mcp_tool_audit` and `a2a_task_events` tables.
*
* Security: Input data is never stored in clear text. Only SHA-256 hashes
* of input and truncated output summaries are persisted.
*/
// ============ MCP Audit Entry ============
export interface McpAuditEntry {
/** ISO 8601 timestamp */
timestamp: string;
/** MCP tool name that was invoked */
toolName: string;
/** SHA-256 hash of the serialized input (never stores raw data) */
inputHash: string;
/** Truncated first 200 chars of the output, or response type */
outputSummary: string;
/** Execution duration in milliseconds */
durationMs: number;
/** API key ID used for the invocation (null for anonymous/stdio) */
apiKeyId: string | null;
/** Whether the tool execution succeeded */
success: boolean;
/** Error code if execution failed */
errorCode?: string;
/** Error message summary (truncated, no sensitive data) */
errorMessage?: string;
}
// ============ A2A Task Event ============
export interface A2aTaskEvent {
/** ISO 8601 timestamp */
timestamp: string;
/** Task ID this event belongs to */
taskId: string;
/** Type of event */
eventType:
| "task_created"
| "task_working"
| "task_completed"
| "task_failed"
| "task_cancelled"
| "task_expired"
| "provider_selected"
| "fallback_triggered"
| "budget_check"
| "quota_check"
| "streaming_started"
| "streaming_ended";
/** Event-specific data (JSON-serialized) */
data?: Record<string, unknown>;
}
// ============ Routing Decision Log ============
export interface RoutingDecisionLog {
/** Unique request identifier */
requestId: string;
/** Type of task (coding, review, etc.) */
taskType: string | null;
/** Combo used for routing */
comboId: string | null;
/** Provider selected by the routing engine */
providerSelected: string;
/** Model selected */
modelSelected: string;
/** Composite score from the scoring function */
score: number;
/** Breakdown of scoring factors */
factors: RoutingFactor[];
/** Number of fallbacks triggered during execution */
fallbacksTriggered: number;
/** Whether the request succeeded */
success: boolean;
/** Total latency in milliseconds */
latencyMs: number;
/** Actual cost in USD */
cost: number;
/** Source: 'api' | 'mcp' | 'a2a' */
source: "api" | "mcp" | "a2a";
}
export interface RoutingFactor {
/** Factor name (quota, health, cost, latency, task_fit, stability) */
name: string;
/** Raw factor value [0..1] */
value: number;
/** Weight applied to this factor */
weight: number;
/** Weighted contribution (value × weight) */
contribution: number;
}
// ============ Audit Helpers ============
/**
* Create a SHA-256 hash of input data for audit logging.
* This ensures we never store raw prompts/data in audit logs.
*/
export async function hashInput(input: unknown): Promise<string> {
const data = JSON.stringify(input);
const encoder = new TextEncoder();
const hashBuffer = await crypto.subtle.digest("SHA-256", encoder.encode(data));
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
}
/**
* Truncate output to a summary string for audit logging.
*/
export function summarizeOutput(output: unknown, maxLength = 200): string {
if (output === null || output === undefined) return "(null)";
const str = typeof output === "string" ? output : JSON.stringify(output);
if (str.length <= maxLength) return str;
return str.slice(0, maxLength) + "…";
}

View File

@@ -0,0 +1,107 @@
/**
* MCP Server Schemas — barrel export for all contract definitions.
*/
// Tool schemas & registry
export {
type McpToolDefinition,
type AuditLevel,
MCP_TOOLS,
MCP_ESSENTIAL_TOOLS,
MCP_ADVANCED_TOOLS,
MCP_TOOL_MAP,
// Phase 1: Essential tool schemas
getHealthInput,
getHealthOutput,
getHealthTool,
listCombosInput,
listCombosOutput,
listCombosTool,
getComboMetricsInput,
getComboMetricsOutput,
getComboMetricsTool,
switchComboInput,
switchComboOutput,
switchComboTool,
checkQuotaInput,
checkQuotaOutput,
checkQuotaTool,
routeRequestInput,
routeRequestOutput,
routeRequestTool,
costReportInput,
costReportOutput,
costReportTool,
listModelsCatalogInput,
listModelsCatalogOutput,
listModelsCatalogTool,
// Phase 2: Advanced tool schemas
simulateRouteInput,
simulateRouteOutput,
simulateRouteTool,
setBudgetGuardInput,
setBudgetGuardOutput,
setBudgetGuardTool,
setResilienceProfileInput,
setResilienceProfileOutput,
setResilienceProfileTool,
testComboInput,
testComboOutput,
testComboTool,
getProviderMetricsInput,
getProviderMetricsOutput,
getProviderMetricsTool,
bestComboForTaskInput,
bestComboForTaskOutput,
bestComboForTaskTool,
explainRouteInput,
explainRouteOutput,
explainRouteTool,
getSessionSnapshotInput,
getSessionSnapshotOutput,
getSessionSnapshotTool,
} from "./tools.ts";
// A2A schemas
export {
AgentCardSchema,
AgentSkillSchema,
TaskStateEnum,
TaskInputSchema,
TaskOutputSchema,
TaskSchema,
CostEnvelopeSchema,
ResilienceTraceEventSchema,
PolicyVerdictSchema,
JsonRpcRequestSchema,
JsonRpcResponseSchema,
MessageSendParamsSchema,
TasksGetParamsSchema,
TasksCancelParamsSchema,
A2A_SSE_EVENTS,
A2A_ERROR_CODES,
type AgentCard,
type AgentSkill,
type Task,
type TaskState,
type TaskInput,
type TaskOutput,
type CostEnvelope,
type ResilienceTraceEvent,
type PolicyVerdict,
type JsonRpcRequest,
type JsonRpcResponse,
type MessageSendParams,
type TasksGetParams,
type TasksCancelParams,
} from "./a2a.ts";
// Audit types
export {
type McpAuditEntry,
type A2aTaskEvent,
type RoutingDecisionLog,
type RoutingFactor,
hashInput,
summarizeOutput,
} from "./audit.ts";

View File

@@ -0,0 +1,760 @@
/**
* MCP Tool Schemas — Contracts for all 16 OmniRoute MCP tools.
*
* Defines input/output Zod schemas, descriptions, scopes, and audit levels
* for both essential (Phase 1) and advanced (Phase 3) MCP tools.
*
* Each tool wraps existing OmniRoute API endpoints and exposes them through
* the Model Context Protocol, enabling AI agents in IDEs (VS Code, Cursor,
* Copilot, Claude Desktop) to intelligently query gateway state.
*/
import { z } from "zod";
// ============ Shared Types ============
export type AuditLevel = "none" | "basic" | "full";
export interface McpToolDefinition<TInput extends z.ZodTypeAny, TOutput extends z.ZodTypeAny> {
/** Tool name (MCP identifier) */
name: string;
/** Human-readable description for AI agents */
description: string;
/** Zod schema for input validation */
inputSchema: TInput;
/** Zod schema for output validation */
outputSchema: TOutput;
/** Required API key scopes */
scopes: readonly string[];
/** Audit logging level */
auditLevel: AuditLevel;
/** Phase: 1 = essential, 2 = advanced */
phase: 1 | 2;
/** Source endpoints on OmniRoute that this tool wraps */
sourceEndpoints: readonly string[];
}
// ============ Phase 1: Essential Tools (8) ============
// --- Tool 1: omniroute_get_health ---
export const getHealthInput = z.object({}).describe("No parameters required");
export const getHealthOutput = z.object({
uptime: z.string(),
version: z.string(),
memoryUsage: z.object({
heapUsed: z.number(),
heapTotal: z.number(),
}),
circuitBreakers: z.array(
z.object({
provider: z.string(),
state: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
failureCount: z.number(),
lastFailure: z.string().nullable(),
})
),
rateLimits: z.array(
z.object({
provider: z.string(),
rpm: z.number(),
currentUsage: z.number(),
isLimited: z.boolean(),
})
),
cacheStats: z
.object({
hits: z.number(),
misses: z.number(),
hitRate: z.number(),
})
.optional(),
});
export const getHealthTool: McpToolDefinition<typeof getHealthInput, typeof getHealthOutput> = {
name: "omniroute_get_health",
description:
"Returns the current health status of OmniRoute including uptime, memory usage, circuit breaker states for all providers, rate limit status, and cache statistics.",
inputSchema: getHealthInput,
outputSchema: getHealthOutput,
scopes: ["read:health"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/monitoring/health", "/api/resilience", "/api/rate-limits"],
};
// --- Tool 2: omniroute_list_combos ---
export const listCombosInput = z.object({
includeMetrics: z
.boolean()
.optional()
.describe("Include request count, success rate, latency, and cost metrics per combo"),
});
export const listCombosOutput = z.object({
combos: z.array(
z.object({
id: z.string(),
name: z.string(),
models: z.array(
z.object({
provider: z.string(),
model: z.string(),
priority: z.number(),
})
),
strategy: z.enum([
"priority",
"weighted",
"round-robin",
"random",
"least-used",
"cost-optimized",
"auto",
]),
enabled: z.boolean(),
metrics: z
.object({
requestCount: z.number(),
successRate: z.number(),
avgLatencyMs: z.number(),
totalCost: z.number(),
})
.optional(),
})
),
});
export const listCombosTool: McpToolDefinition<typeof listCombosInput, typeof listCombosOutput> = {
name: "omniroute_list_combos",
description:
"Lists all configured combos (model chains) with their strategies and optionally includes performance metrics. Combos define how requests are routed across multiple providers.",
inputSchema: listCombosInput,
outputSchema: listCombosOutput,
scopes: ["read:combos"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/combos", "/api/combos/metrics"],
};
// --- Tool 3: omniroute_get_combo_metrics ---
export const getComboMetricsInput = z.object({
comboId: z.string().describe("ID of the combo to get metrics for"),
});
export const getComboMetricsOutput = z.object({
requests: z.number(),
successRate: z.number(),
avgLatency: z.number(),
costTotal: z.number(),
fallbackCount: z.number(),
byProvider: z.array(
z.object({
provider: z.string(),
requests: z.number(),
successRate: z.number(),
avgLatency: z.number(),
})
),
});
export const getComboMetricsTool: McpToolDefinition<
typeof getComboMetricsInput,
typeof getComboMetricsOutput
> = {
name: "omniroute_get_combo_metrics",
description:
"Returns detailed performance metrics for a specific combo including request count, success rate, average latency, total cost, and per-provider breakdowns.",
inputSchema: getComboMetricsInput,
outputSchema: getComboMetricsOutput,
scopes: ["read:combos"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/combos/metrics"],
};
// --- Tool 4: omniroute_switch_combo ---
export const switchComboInput = z.object({
comboId: z.string().describe("ID of the combo to activate/deactivate"),
active: z.boolean().describe("Whether to enable or disable the combo"),
});
export const switchComboOutput = z.object({
success: z.boolean(),
combo: z.object({
id: z.string(),
name: z.string(),
enabled: z.boolean(),
}),
});
export const switchComboTool: McpToolDefinition<typeof switchComboInput, typeof switchComboOutput> =
{
name: "omniroute_switch_combo",
description:
"Activates or deactivates a combo. When deactivated, requests will not be routed through this combo. Use to toggle between different routing strategies.",
inputSchema: switchComboInput,
outputSchema: switchComboOutput,
scopes: ["write:combos"],
auditLevel: "full",
phase: 1,
sourceEndpoints: ["/api/combos"],
};
// --- Tool 5: omniroute_check_quota ---
export const checkQuotaInput = z.object({
provider: z
.string()
.optional()
.describe(
"Filter by provider name (e.g., 'claude', 'gemini'). If omitted, returns all providers."
),
connectionId: z.string().optional().describe("Filter by specific connection ID"),
});
export const checkQuotaOutput = z.object({
providers: z.array(
z.object({
name: z.string(),
provider: z.string(),
connectionId: z.string(),
quotaUsed: z.number(),
quotaTotal: z.number().nullable(),
percentRemaining: z.number(),
resetAt: z.string().nullable(),
tokenStatus: z.enum(["valid", "expiring", "expired", "refreshing"]),
})
),
meta: z
.object({
generatedAt: z.string(),
filters: z.object({
provider: z.string().nullable(),
connectionId: z.string().nullable(),
}),
totalProviders: z.number(),
})
.optional(),
});
export const checkQuotaTool: McpToolDefinition<typeof checkQuotaInput, typeof checkQuotaOutput> = {
name: "omniroute_check_quota",
description:
"Checks the remaining API quota for one or all providers. Returns quota used/total, percentage remaining, reset time, and token health status.",
inputSchema: checkQuotaInput,
outputSchema: checkQuotaOutput,
scopes: ["read:quota"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/usage/quota", "/api/token-health", "/api/rate-limits"],
};
// --- Tool 6: omniroute_route_request ---
export const routeRequestInput = z.object({
model: z.string().describe("Model identifier (e.g., 'claude-sonnet-4', 'gpt-4o')"),
messages: z
.array(
z.object({
role: z.string(),
content: z.string(),
})
)
.describe("Chat messages in OpenAI format"),
combo: z.string().optional().describe("Specific combo to route through"),
budget: z.number().optional().describe("Maximum cost in USD for this request"),
role: z
.enum(["coding", "review", "planning", "analysis"])
.optional()
.describe("Task role hint for intelligent routing"),
stream: z.boolean().optional().default(false).describe("Whether to stream the response"),
});
export const routeRequestOutput = z.object({
response: z.object({
content: z.string(),
model: z.string(),
tokens: z.object({
prompt: z.number(),
completion: z.number(),
}),
}),
routing: z.object({
provider: z.string(),
combo: z.string().nullable(),
fallbacksTriggered: z.number(),
cost: z.number(),
latencyMs: z.number(),
routingExplanation: z.string(),
}),
});
export const routeRequestTool: McpToolDefinition<
typeof routeRequestInput,
typeof routeRequestOutput
> = {
name: "omniroute_route_request",
description:
"Sends a chat completion request through OmniRoute's intelligent routing pipeline. Supports combo selection, budget limits, and task role hints for optimal provider matching.",
inputSchema: routeRequestInput,
outputSchema: routeRequestOutput,
scopes: ["execute:completions"],
auditLevel: "full",
phase: 1,
sourceEndpoints: ["/v1/chat/completions", "/v1/responses"],
};
// --- Tool 7: omniroute_cost_report ---
export const costReportInput = z.object({
period: z
.enum(["session", "day", "week", "month"])
.optional()
.default("session")
.describe("Time period for the cost report"),
});
export const costReportOutput = z.object({
period: z.string(),
totalCost: z.number(),
requestCount: z.number(),
tokenCount: z.object({
prompt: z.number(),
completion: z.number(),
}),
byProvider: z.array(
z.object({
name: z.string(),
cost: z.number(),
requests: z.number(),
})
),
byModel: z.array(
z.object({
model: z.string(),
cost: z.number(),
requests: z.number(),
})
),
budget: z.object({
limit: z.number().nullable(),
remaining: z.number().nullable(),
}),
});
export const costReportTool: McpToolDefinition<typeof costReportInput, typeof costReportOutput> = {
name: "omniroute_cost_report",
description:
"Generates a cost report for the specified period showing total cost, request count, token usage, and breakdowns by provider and model. Also shows budget status if configured.",
inputSchema: costReportInput,
outputSchema: costReportOutput,
scopes: ["read:usage"],
auditLevel: "basic",
phase: 1,
sourceEndpoints: ["/api/usage/analytics", "/api/usage/budget"],
};
// --- Tool 8: omniroute_list_models_catalog ---
export const listModelsCatalogInput = z.object({
provider: z.string().optional().describe("Filter by provider name"),
capability: z
.enum(["chat", "embedding", "image", "audio", "video", "rerank", "moderation"])
.optional()
.describe("Filter by model capability"),
});
export const listModelsCatalogOutput = z.object({
models: z.array(
z.object({
id: z.string(),
provider: z.string(),
capabilities: z.array(z.string()),
status: z.enum(["available", "degraded", "unavailable"]),
pricing: z
.object({
inputPerMillion: z.number().nullable(),
outputPerMillion: z.number().nullable(),
})
.optional(),
})
),
});
export const listModelsCatalogTool: McpToolDefinition<
typeof listModelsCatalogInput,
typeof listModelsCatalogOutput
> = {
name: "omniroute_list_models_catalog",
description:
"Lists all available AI models across all providers with their capabilities, current status, and pricing information.",
inputSchema: listModelsCatalogInput,
outputSchema: listModelsCatalogOutput,
scopes: ["read:models"],
auditLevel: "none",
phase: 1,
sourceEndpoints: ["/api/models/catalog", "/v1/models"],
};
// ============ Phase 2: Advanced Tools (8) ============
// --- Tool 9: omniroute_simulate_route ---
export const simulateRouteInput = z.object({
model: z.string().describe("Target model for simulation"),
promptTokenEstimate: z.number().describe("Estimated prompt token count"),
combo: z.string().optional().describe("Specific combo to simulate (default: active combo)"),
});
export const simulateRouteOutput = z.object({
simulatedPath: z.array(
z.object({
provider: z.string(),
model: z.string(),
probability: z.number(),
estimatedCost: z.number(),
healthStatus: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
quotaAvailable: z.number(),
})
),
fallbackTree: z.object({
primary: z.string(),
fallbacks: z.array(z.string()),
worstCaseCost: z.number(),
bestCaseCost: z.number(),
}),
});
export const simulateRouteTool: McpToolDefinition<
typeof simulateRouteInput,
typeof simulateRouteOutput
> = {
name: "omniroute_simulate_route",
description:
"Simulates (dry-run) the routing path a request would take without actually executing it. Shows the fallback tree, provider probabilities, estimated costs, and health status.",
inputSchema: simulateRouteInput,
outputSchema: simulateRouteOutput,
scopes: ["read:health", "read:combos"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/combos", "/api/monitoring/health", "/api/resilience"],
};
// --- Tool 10: omniroute_set_budget_guard ---
export const setBudgetGuardInput = z.object({
maxCost: z.number().describe("Maximum cost in USD for this session"),
action: z.enum(["degrade", "block", "alert"]).describe("Action when budget is exceeded"),
degradeToTier: z
.enum(["cheap", "free"])
.optional()
.describe("If action=degrade, which tier to fall back to"),
});
export const setBudgetGuardOutput = z.object({
sessionId: z.string(),
budgetTotal: z.number(),
budgetSpent: z.number(),
budgetRemaining: z.number(),
action: z.string(),
status: z.enum(["active", "warning", "exceeded"]),
});
export const setBudgetGuardTool: McpToolDefinition<
typeof setBudgetGuardInput,
typeof setBudgetGuardOutput
> = {
name: "omniroute_set_budget_guard",
description:
"Sets a budget guard that limits spending for the current session. When the budget is reached, it can degrade to cheaper models, block requests, or send alerts.",
inputSchema: setBudgetGuardInput,
outputSchema: setBudgetGuardOutput,
scopes: ["write:budget"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/usage/budget"],
};
// --- Tool 11: omniroute_set_resilience_profile ---
export const setResilienceProfileInput = z.object({
profile: z
.enum(["aggressive", "balanced", "conservative"])
.describe("Resilience profile to apply"),
});
export const setResilienceProfileOutput = z.object({
applied: z.boolean(),
settings: z.object({
circuitBreakerThreshold: z.number(),
retryCount: z.number(),
timeoutMs: z.number(),
fallbackDepth: z.number(),
}),
});
export const setResilienceProfileTool: McpToolDefinition<
typeof setResilienceProfileInput,
typeof setResilienceProfileOutput
> = {
name: "omniroute_set_resilience_profile",
description:
"Applies a resilience profile that adjusts circuit breaker thresholds, retry counts, timeouts, and fallback depth. 'aggressive' = fast fail, 'conservative' = max retries.",
inputSchema: setResilienceProfileInput,
outputSchema: setResilienceProfileOutput,
scopes: ["write:resilience"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/resilience"],
};
// --- Tool 12: omniroute_test_combo ---
export const testComboInput = z.object({
comboId: z.string().describe("ID of the combo to test"),
testPrompt: z.string().max(500).describe("Short test prompt (max 500 chars)"),
});
export const testComboOutput = z.object({
results: z.array(
z.object({
provider: z.string(),
model: z.string(),
success: z.boolean(),
latencyMs: z.number(),
cost: z.number(),
tokenCount: z.number(),
error: z.string().optional(),
})
),
summary: z.object({
totalProviders: z.number(),
successful: z.number(),
fastestProvider: z.string(),
cheapestProvider: z.string(),
}),
});
export const testComboTool: McpToolDefinition<typeof testComboInput, typeof testComboOutput> = {
name: "omniroute_test_combo",
description:
"Tests a combo by sending a short test prompt to each provider in the combo and reporting individual results including latency, cost, and success status.",
inputSchema: testComboInput,
outputSchema: testComboOutput,
scopes: ["execute:completions", "read:combos"],
auditLevel: "full",
phase: 2,
sourceEndpoints: ["/api/combos/test", "/v1/chat/completions"],
};
// --- Tool 13: omniroute_get_provider_metrics ---
export const getProviderMetricsInput = z.object({
provider: z.string().describe("Provider name (e.g., 'claude', 'gemini-cli', 'codex')"),
});
export const getProviderMetricsOutput = z.object({
provider: z.string(),
successRate: z.number(),
requestCount: z.number(),
avgLatencyMs: z.number(),
p50LatencyMs: z.number(),
p95LatencyMs: z.number(),
p99LatencyMs: z.number(),
errorRate: z.number(),
lastError: z
.object({
message: z.string(),
timestamp: z.string(),
})
.nullable(),
circuitBreakerState: z.enum(["CLOSED", "OPEN", "HALF_OPEN"]),
quotaInfo: z.object({
used: z.number(),
total: z.number().nullable(),
resetAt: z.string().nullable(),
}),
});
export const getProviderMetricsTool: McpToolDefinition<
typeof getProviderMetricsInput,
typeof getProviderMetricsOutput
> = {
name: "omniroute_get_provider_metrics",
description:
"Returns detailed performance metrics for a specific provider including success/error rates, latency percentiles (p50/p95/p99), circuit breaker state, and quota information.",
inputSchema: getProviderMetricsInput,
outputSchema: getProviderMetricsOutput,
scopes: ["read:health"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/provider-metrics", "/api/resilience"],
};
// --- Tool 14: omniroute_best_combo_for_task ---
export const bestComboForTaskInput = z.object({
taskType: z
.enum(["coding", "review", "planning", "analysis", "debugging", "documentation"])
.describe("Type of task to find the best combo for"),
budgetConstraint: z.number().optional().describe("Maximum cost in USD"),
latencyConstraint: z.number().optional().describe("Maximum acceptable latency in ms"),
});
export const bestComboForTaskOutput = z.object({
recommendedCombo: z.object({
id: z.string(),
name: z.string(),
reason: z.string(),
}),
alternatives: z.array(
z.object({
id: z.string(),
name: z.string(),
tradeoff: z.string(),
})
),
freeAlternative: z
.object({
id: z.string(),
name: z.string(),
})
.nullable(),
});
export const bestComboForTaskTool: McpToolDefinition<
typeof bestComboForTaskInput,
typeof bestComboForTaskOutput
> = {
name: "omniroute_best_combo_for_task",
description:
"Recommends the best combo for a given task type (coding, review, planning, etc.) considering budget and latency constraints. Also suggests alternatives and free options.",
inputSchema: bestComboForTaskInput,
outputSchema: bestComboForTaskOutput,
scopes: ["read:combos", "read:health"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: ["/api/combos", "/api/combos/metrics", "/api/monitoring/health"],
};
// --- Tool 15: omniroute_explain_route ---
export const explainRouteInput = z.object({
requestId: z.string().describe("Request ID from the X-Request-Id header"),
});
export const explainRouteOutput = z.object({
requestId: z.string(),
decision: z.object({
comboUsed: z.string(),
providerSelected: z.string(),
modelUsed: z.string(),
score: z.number(),
factors: z.array(
z.object({
name: z.string(),
value: z.number(),
weight: z.number(),
contribution: z.number(),
})
),
fallbacksTriggered: z.array(
z.object({
provider: z.string(),
reason: z.string(),
})
),
costActual: z.number(),
latencyActual: z.number(),
}),
});
export const explainRouteTool: McpToolDefinition<
typeof explainRouteInput,
typeof explainRouteOutput
> = {
name: "omniroute_explain_route",
description:
"Explains why a specific request was routed to a particular provider. Shows the scoring factors, weights, fallbacks triggered, actual cost, and latency.",
inputSchema: explainRouteInput,
outputSchema: explainRouteOutput,
scopes: ["read:health", "read:usage"],
auditLevel: "basic",
phase: 2,
sourceEndpoints: [],
};
// --- Tool 16: omniroute_get_session_snapshot ---
export const getSessionSnapshotInput = z.object({}).describe("No parameters required");
export const getSessionSnapshotOutput = z.object({
sessionStart: z.string(),
duration: z.string(),
requestCount: z.number(),
costTotal: z.number(),
tokenCount: z.object({
prompt: z.number(),
completion: z.number(),
}),
topModels: z.array(
z.object({
model: z.string(),
count: z.number(),
})
),
topProviders: z.array(
z.object({
provider: z.string(),
count: z.number(),
})
),
errors: z.number(),
fallbacks: z.number(),
budgetGuard: z
.object({
active: z.boolean(),
remaining: z.number(),
})
.nullable(),
});
export const getSessionSnapshotTool: McpToolDefinition<
typeof getSessionSnapshotInput,
typeof getSessionSnapshotOutput
> = {
name: "omniroute_get_session_snapshot",
description:
"Returns a snapshot of the current working session including duration, request count, total cost, top models/providers used, error count, and budget guard status.",
inputSchema: getSessionSnapshotInput,
outputSchema: getSessionSnapshotOutput,
scopes: ["read:usage"],
auditLevel: "none",
phase: 2,
sourceEndpoints: ["/api/usage/analytics", "/api/telemetry/summary"],
};
// ============ Tool Registry ============
/** All MCP tool definitions, ordered by phase then name */
export const MCP_TOOLS = [
// Phase 1: Essential
getHealthTool,
listCombosTool,
getComboMetricsTool,
switchComboTool,
checkQuotaTool,
routeRequestTool,
costReportTool,
listModelsCatalogTool,
// Phase 2: Advanced
simulateRouteTool,
setBudgetGuardTool,
setResilienceProfileTool,
testComboTool,
getProviderMetricsTool,
bestComboForTaskTool,
explainRouteTool,
getSessionSnapshotTool,
] as const;
/** Essential tools only (Phase 1) */
export const MCP_ESSENTIAL_TOOLS = MCP_TOOLS.filter((t) => t.phase === 1);
/** Advanced tools only (Phase 2) */
export const MCP_ADVANCED_TOOLS = MCP_TOOLS.filter((t) => t.phase === 2);
/** Map of tool name → tool definition */
export const MCP_TOOL_MAP = Object.fromEntries(MCP_TOOLS.map((t) => [t.name, t])) as Record<
string,
(typeof MCP_TOOLS)[number]
>;

View File

@@ -0,0 +1,133 @@
import { MCP_TOOL_MAP } from "./schemas/tools.ts";
type AuthInfoLike = {
clientId?: string;
scopes?: string[];
};
export type McpToolExtraLike = {
authInfo?: AuthInfoLike;
sessionId?: string;
_meta?: unknown;
};
export type ScopeSource = "authInfo" | "meta" | "env" | "none";
export interface CallerScopeContext {
callerId: string;
scopes: string[];
source: ScopeSource;
}
export interface ScopeCheckResult {
allowed: boolean;
required: string[];
provided: string[];
missing: string[];
reason?: string;
}
function normalizeScopeList(raw: unknown): string[] {
if (!Array.isArray(raw)) return [];
const normalized = raw
.filter((value) => typeof value === "string")
.map((value) => value.trim())
.filter(Boolean);
return Array.from(new Set(normalized));
}
function extractMetaScopeList(meta: unknown): string[] {
if (!meta || typeof meta !== "object") return [];
const metaRecord = meta as Record<string, unknown>;
const direct = normalizeScopeList(metaRecord.scopes);
if (direct.length > 0) return direct;
const auth = metaRecord.auth;
if (auth && typeof auth === "object") {
const authScopes = normalizeScopeList((auth as Record<string, unknown>).scopes);
if (authScopes.length > 0) return authScopes;
}
const omni = metaRecord.omniroute;
if (omni && typeof omni === "object") {
const omniScopes = normalizeScopeList((omni as Record<string, unknown>).scopes);
if (omniScopes.length > 0) return omniScopes;
}
return [];
}
function scopeMatches(grantedScope: string, requiredScope: string): boolean {
if (grantedScope === "*" || grantedScope === requiredScope) {
return true;
}
if (grantedScope.endsWith("*")) {
const prefix = grantedScope.slice(0, -1);
return requiredScope.startsWith(prefix);
}
return false;
}
export function resolveCallerScopeContext(
extra: McpToolExtraLike | undefined,
fallbackScopes: readonly string[] = []
): CallerScopeContext {
const callerId =
(typeof extra?.authInfo?.clientId === "string" && extra.authInfo.clientId.trim()) ||
(typeof extra?.sessionId === "string" && extra.sessionId.trim()) ||
"anonymous";
const authScopes = normalizeScopeList(extra?.authInfo?.scopes);
if (authScopes.length > 0) {
return { callerId, scopes: authScopes, source: "authInfo" };
}
const metaScopes = extractMetaScopeList(extra?._meta);
if (metaScopes.length > 0) {
return { callerId, scopes: metaScopes, source: "meta" };
}
const fallback = normalizeScopeList(fallbackScopes);
if (fallback.length > 0) {
return { callerId, scopes: fallback, source: "env" };
}
return { callerId, scopes: [], source: "none" };
}
export function evaluateToolScopes(
toolName: string,
callerScopes: readonly string[],
enforceScopes: boolean
): ScopeCheckResult {
const toolDef = MCP_TOOL_MAP[toolName];
if (!toolDef) {
return {
allowed: false,
required: [],
provided: Array.from(callerScopes),
missing: [],
reason: "tool_definition_missing",
};
}
const required = Array.isArray(toolDef.scopes) ? Array.from(toolDef.scopes) : [];
const provided = normalizeScopeList(callerScopes);
if (!enforceScopes || required.length === 0) {
return { allowed: true, required, provided, missing: [] };
}
const missing = required.filter(
(requiredScope) => !provided.some((grantedScope) => scopeMatches(grantedScope, requiredScope))
);
return {
allowed: missing.length === 0,
required,
provided,
missing,
reason: missing.length > 0 ? "missing_scopes" : undefined,
};
}

View File

@@ -0,0 +1,711 @@
/**
* OmniRoute MCP Server — Model Context Protocol server exposing
* OmniRoute gateway intelligence as tools for AI agents.
*
* Supports two transports:
* 1. stdio — for IDE integration (VS Code, Cursor, Claude Desktop)
* 2. HTTP — for remote/programmatic access
*
* Tools wrap existing OmniRoute API endpoints and add intelligence
* such as routing simulation, budget guards, and session snapshots.
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
MCP_TOOLS,
getHealthInput,
listCombosInput,
getComboMetricsInput,
switchComboInput,
checkQuotaInput,
routeRequestInput,
costReportInput,
listModelsCatalogInput,
simulateRouteInput,
setBudgetGuardInput,
setResilienceProfileInput,
testComboInput,
getProviderMetricsInput,
bestComboForTaskInput,
explainRouteInput,
getSessionSnapshotInput,
} from "./schemas/tools.ts";
import { startMcpHeartbeat } from "./runtimeHeartbeat.ts";
import { logToolCall } from "./audit.ts";
import {
evaluateToolScopes,
resolveCallerScopeContext,
type McpToolExtraLike,
} from "./scopeEnforcement.ts";
import {
handleSimulateRoute,
handleSetBudgetGuard,
handleSetResilienceProfile,
handleTestCombo,
handleGetProviderMetrics,
handleBestComboForTask,
handleExplainRoute,
handleGetSessionSnapshot,
} from "./tools/advancedTools.ts";
import { normalizeQuotaResponse } from "../../src/shared/contracts/quota.ts";
// ============ Configuration ============
const OMNIROUTE_BASE_URL = process.env.OMNIROUTE_BASE_URL || "http://localhost:20128";
const OMNIROUTE_API_KEY = process.env.OMNIROUTE_API_KEY || "";
const MCP_ENFORCE_SCOPES = process.env.OMNIROUTE_MCP_ENFORCE_SCOPES === "true";
const MCP_ALLOWED_SCOPES = new Set(
(process.env.OMNIROUTE_MCP_SCOPES || "")
.split(",")
.map((s) => s.trim())
.filter(Boolean)
);
type JsonRecord = Record<string, unknown>;
type TextToolResult = {
content: Array<{ type: "text"; text: string }>;
isError?: boolean;
};
function toRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
}
function toArray(value: unknown): unknown[] {
return Array.isArray(value) ? value : [];
}
function toString(value: unknown, fallback = ""): string {
return typeof value === "string" ? value : fallback;
}
function toNumber(value: unknown, fallback = 0): number {
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}
function toStringArray(value: unknown, fallback: string[] = []): string[] {
const values = toArray(value).filter((entry): entry is string => typeof entry === "string");
return values.length > 0 ? values : fallback;
}
function normalizeComboModels(
rawModels: unknown
): Array<{ provider: string; model: string; priority: number }> {
return toArray(rawModels).map((rawModel, index) => {
const model = toRecord(rawModel);
return {
provider: toString(model.provider, "unknown"),
model: toString(model.model, "unknown"),
priority: toNumber(model.priority, index + 1),
};
});
}
/**
* Internal fetch helper that calls OmniRoute API endpoints.
*/
async function omniRouteFetch(path: string, options: RequestInit = {}): Promise<unknown> {
const url = `${OMNIROUTE_BASE_URL}${path}`;
const headers: Record<string, string> = {
"Content-Type": "application/json",
...(OMNIROUTE_API_KEY ? { Authorization: `Bearer ${OMNIROUTE_API_KEY}` } : {}),
...((options.headers as Record<string, string>) || {}),
};
const response = await fetch(url, { ...options, headers, signal: AbortSignal.timeout(10000) });
if (!response.ok) {
const errorText = await response.text().catch(() => "Unknown error");
throw new Error(`OmniRoute API error [${response.status}]: ${errorText}`);
}
return response.json();
}
function withScopeEnforcement(
toolName: string,
handler: (args: unknown, extra?: McpToolExtraLike) => Promise<TextToolResult>
) {
return async (args: unknown, extra?: McpToolExtraLike): Promise<TextToolResult> => {
const scopeContext = resolveCallerScopeContext(extra, Array.from(MCP_ALLOWED_SCOPES));
const scopeCheck = evaluateToolScopes(toolName, scopeContext.scopes, MCP_ENFORCE_SCOPES);
if (!scopeCheck.allowed) {
const missingScopes =
scopeCheck.missing.length > 0 ? scopeCheck.missing.join(", ") : "unavailable";
const reason = scopeCheck.reason || "scope_check_failed";
const msg =
`Insufficient MCP scopes for ${toolName}. ` +
`Missing: ${missingScopes}. ` +
`Caller=${scopeContext.callerId}, source=${scopeContext.source}.`;
const safeArgs = args && typeof args === "object" ? toRecord(args) : { rawArgs: args };
await logToolCall(
toolName,
{
...safeArgs,
_scopeCheck: {
callerId: scopeContext.callerId,
source: scopeContext.source,
required: scopeCheck.required,
provided: scopeCheck.provided,
missing: scopeCheck.missing,
},
},
null,
0,
false,
`scope_denied:${reason}`
);
return {
content: [{ type: "text" as const, text: `Error: ${msg}` }],
isError: true,
};
}
return handler(args, extra);
};
}
// ============ Tool Handlers ============
async function handleGetHealth() {
const start = Date.now();
try {
const [healthRaw, resilienceRaw, rateLimitsRaw] = await Promise.allSettled([
omniRouteFetch("/api/monitoring/health"),
omniRouteFetch("/api/resilience"),
omniRouteFetch("/api/rate-limits"),
]);
const health = healthRaw.status === "fulfilled" ? toRecord(healthRaw.value) : {};
const resilience = resilienceRaw.status === "fulfilled" ? toRecord(resilienceRaw.value) : {};
const rateLimits = rateLimitsRaw.status === "fulfilled" ? toRecord(rateLimitsRaw.value) : {};
const memoryUsageRaw = toRecord(health.memoryUsage);
const cacheStatsRaw = toRecord(health.cacheStats);
const resilienceCircuitBreakers = toArray(resilience.circuitBreakers);
const rateLimitEntries = toArray(rateLimits.limits);
const result = {
uptime: toString(health.uptime, "unknown"),
version: toString(health.version, "unknown"),
memoryUsage: {
heapUsed: toNumber(memoryUsageRaw.heapUsed, 0),
heapTotal: toNumber(memoryUsageRaw.heapTotal, 0),
},
circuitBreakers: resilienceCircuitBreakers,
rateLimits: rateLimitEntries,
cacheStats:
Object.keys(cacheStatsRaw).length > 0
? {
hits: toNumber(cacheStatsRaw.hits, 0),
misses: toNumber(cacheStatsRaw.misses, 0),
hitRate: toNumber(cacheStatsRaw.hitRate, 0),
}
: undefined,
};
await logToolCall("omniroute_get_health", {}, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_get_health", {}, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleListCombos(args: { includeMetrics?: boolean }) {
const start = Date.now();
try {
const combosRaw = await omniRouteFetch("/api/combos");
const combosRecord = toRecord(combosRaw);
const combos = Array.isArray(combosRecord.combos)
? combosRecord.combos
: Array.isArray(combosRaw)
? combosRaw
: [];
let metrics: JsonRecord = {};
if (args.includeMetrics) {
metrics = toRecord(await omniRouteFetch("/api/combos/metrics").catch(() => ({})));
}
const result = {
combos: toArray(combos).map((rawCombo) => {
const combo = toRecord(rawCombo);
const comboData = toRecord(combo.data);
const comboId = toString(combo.id, "");
const modelsSource =
Array.isArray(combo.models) && combo.models.length > 0 ? combo.models : comboData.models;
return {
id: comboId,
name: toString(combo.name, comboId || "unnamed"),
models: normalizeComboModels(modelsSource),
strategy: toString(combo.strategy, toString(comboData.strategy, "priority")),
enabled: combo.enabled !== false,
...(args.includeMetrics ? { metrics: metrics[comboId] ?? null } : {}),
};
}),
};
await logToolCall("omniroute_list_combos", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_list_combos", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleGetComboMetrics(args: { comboId: string }) {
const start = Date.now();
try {
const result = await omniRouteFetch(
`/api/combos/metrics?comboId=${encodeURIComponent(args.comboId)}`
);
await logToolCall("omniroute_get_combo_metrics", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_get_combo_metrics", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleSwitchCombo(args: { comboId: string; active: boolean }) {
const start = Date.now();
try {
const result = await omniRouteFetch(`/api/combos/${encodeURIComponent(args.comboId)}`, {
method: "PUT",
body: JSON.stringify({ isActive: args.active }),
});
await logToolCall("omniroute_switch_combo", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_switch_combo", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleCheckQuota(args: { provider?: string; connectionId?: string }) {
const start = Date.now();
try {
let path = "/api/usage/quota";
if (args.connectionId) path += `?connectionId=${encodeURIComponent(args.connectionId)}`;
else if (args.provider) path += `?provider=${encodeURIComponent(args.provider)}`;
const result = normalizeQuotaResponse(await omniRouteFetch(path), {
provider: args.provider || null,
connectionId: args.connectionId || null,
});
await logToolCall("omniroute_check_quota", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_check_quota", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleRouteRequest(args: {
model: string;
messages: Array<{ role: string; content: string }>;
combo?: string;
budget?: number;
role?: string;
stream?: boolean;
}) {
const start = Date.now();
try {
const body: Record<string, unknown> = {
model: args.model,
messages: args.messages,
stream: false, // MCP tool always returns non-streaming
};
if (args.combo) {
body["x-combo"] = args.combo;
}
const raw = (await omniRouteFetch("/v1/chat/completions", {
method: "POST",
body: JSON.stringify(body),
})) as JsonRecord;
const choices = toArray(raw.choices);
const firstChoice = toRecord(choices[0]);
const firstMessage = toRecord(firstChoice.message);
const usage = toRecord(raw.usage);
const result = {
response: {
content: toString(firstMessage.content, ""),
model: toString(raw.model, args.model),
tokens: {
prompt: toNumber(usage.prompt_tokens, 0),
completion: toNumber(usage.completion_tokens, 0),
},
},
routing: {
provider: toString(raw.provider, "unknown"),
combo: raw.combo ?? null,
fallbacksTriggered: toNumber(raw.fallbacksTriggered, 0),
cost: toNumber(raw.cost, 0),
latencyMs: Date.now() - start,
routingExplanation: toString(
raw.routingExplanation,
"Request routed through primary provider"
),
},
};
await logToolCall(
"omniroute_route_request",
{ model: args.model, messageCount: args.messages.length },
result.routing,
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall(
"omniroute_route_request",
{ model: args.model },
null,
Date.now() - start,
false,
msg
);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleCostReport(args: { period?: string }) {
const start = Date.now();
try {
const period = args.period || "session";
const rangeMap: Record<string, string> = {
session: "1d",
day: "1d",
week: "7d",
month: "30d",
};
const range = rangeMap[period] || "30d";
const raw = toRecord(
await omniRouteFetch(`/api/usage/analytics?range=${encodeURIComponent(range)}`)
);
const tokenCount = toRecord(raw.tokenCount);
const budget = toRecord(raw.budget);
const result = {
period,
totalCost: toNumber(raw.totalCost, 0),
requestCount: toNumber(raw.requestCount, 0),
tokenCount: {
prompt: toNumber(tokenCount.prompt, 0),
completion: toNumber(tokenCount.completion, 0),
},
byProvider: toArray(raw.byProvider),
byModel: toArray(raw.byModel),
budget: {
limit: budget.limit ?? null,
remaining: budget.remaining ?? null,
},
};
await logToolCall("omniroute_cost_report", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_cost_report", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
async function handleListModelsCatalog(args: { provider?: string; capability?: string }) {
const start = Date.now();
try {
let path = "/v1/models";
const params = new URLSearchParams();
if (args.provider) params.set("provider", args.provider);
if (args.capability) params.set("capability", args.capability);
if (params.toString()) path += `?${params.toString()}`;
const raw = toRecord(await omniRouteFetch(path));
const result = {
models: toArray(raw.data).map((rawModel) => {
const model = toRecord(rawModel);
return {
id: toString(model.id, ""),
provider: toString(model.owned_by, toString(model.provider, "unknown")),
capabilities: toStringArray(model.capabilities, ["chat"]),
status: toString(model.status, "available"),
pricing: model.pricing,
};
}),
};
await logToolCall(
"omniroute_list_models_catalog",
args,
{ modelCount: result.models.length },
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_list_models_catalog", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
// ============ MCP Server Setup ============
/**
* Create and configure the OmniRoute MCP Server with all essential tools.
*/
export function createMcpServer(): McpServer {
const server = new McpServer({
name: "omniroute",
version: process.env.npm_package_version || "1.8.1",
});
// Register essential tools
server.registerTool(
"omniroute_get_health",
{
description:
"Returns OmniRoute health status including uptime, memory, circuit breakers, rate limits, and cache stats",
inputSchema: getHealthInput,
},
withScopeEnforcement("omniroute_get_health", async (args) => {
getHealthInput.parse(args ?? {});
return handleGetHealth();
})
);
server.registerTool(
"omniroute_list_combos",
{
description:
"Lists all configured combos (model chains) with strategies and optional metrics",
inputSchema: listCombosInput,
},
withScopeEnforcement("omniroute_list_combos", (args) =>
handleListCombos(listCombosInput.parse(args))
)
);
server.registerTool(
"omniroute_get_combo_metrics",
{
description: "Returns detailed performance metrics for a specific combo",
inputSchema: getComboMetricsInput,
},
withScopeEnforcement("omniroute_get_combo_metrics", (args) =>
handleGetComboMetrics(getComboMetricsInput.parse(args))
)
);
server.registerTool(
"omniroute_switch_combo",
{
description: "Activates or deactivates a combo for routing",
inputSchema: switchComboInput,
},
withScopeEnforcement("omniroute_switch_combo", (args) =>
handleSwitchCombo(switchComboInput.parse(args))
)
);
server.registerTool(
"omniroute_check_quota",
{
description: "Checks remaining API quota for one or all providers",
inputSchema: checkQuotaInput,
},
withScopeEnforcement("omniroute_check_quota", (args) =>
handleCheckQuota(checkQuotaInput.parse(args))
)
);
server.registerTool(
"omniroute_route_request",
{
description: "Sends a chat completion request through OmniRoute intelligent routing",
inputSchema: routeRequestInput,
},
withScopeEnforcement("omniroute_route_request", (args) =>
handleRouteRequest(routeRequestInput.parse(args))
)
);
server.registerTool(
"omniroute_cost_report",
{
description: "Generates a cost report for the specified period",
inputSchema: costReportInput,
},
withScopeEnforcement("omniroute_cost_report", (args) =>
handleCostReport(costReportInput.parse(args))
)
);
server.registerTool(
"omniroute_list_models_catalog",
{
description: "Lists all available AI models across providers with capabilities and pricing",
inputSchema: listModelsCatalogInput,
},
withScopeEnforcement("omniroute_list_models_catalog", (args) =>
handleListModelsCatalog(listModelsCatalogInput.parse(args))
)
);
// ── Advanced Tools (Phase 3) ──────────────────────────────
server.registerTool(
"omniroute_simulate_route",
{
description: "Simulates the routing path a request would take without executing it (dry-run)",
inputSchema: simulateRouteInput,
},
withScopeEnforcement("omniroute_simulate_route", (args) =>
handleSimulateRoute(simulateRouteInput.parse(args))
)
);
server.registerTool(
"omniroute_set_budget_guard",
{
description:
"Sets a session budget limit with configurable action when exceeded (degrade/block/alert)",
inputSchema: setBudgetGuardInput,
},
withScopeEnforcement("omniroute_set_budget_guard", (args) =>
handleSetBudgetGuard(setBudgetGuardInput.parse(args))
)
);
server.registerTool(
"omniroute_set_resilience_profile",
{
description:
"Applies a resilience profile controlling circuit breakers, retries, timeouts, and fallback depth",
inputSchema: setResilienceProfileInput,
},
withScopeEnforcement("omniroute_set_resilience_profile", (args) =>
handleSetResilienceProfile(setResilienceProfileInput.parse(args))
)
);
server.registerTool(
"omniroute_test_combo",
{
description:
"Tests each provider in a combo with a real prompt, reporting latency, cost, and success per provider",
inputSchema: testComboInput,
},
withScopeEnforcement("omniroute_test_combo", (args) =>
handleTestCombo(testComboInput.parse(args))
)
);
server.registerTool(
"omniroute_get_provider_metrics",
{
description:
"Returns detailed metrics for a specific provider including latency percentiles and circuit breaker state",
inputSchema: getProviderMetricsInput,
},
withScopeEnforcement("omniroute_get_provider_metrics", (args) =>
handleGetProviderMetrics(getProviderMetricsInput.parse(args))
)
);
server.registerTool(
"omniroute_best_combo_for_task",
{
description:
"Recommends the best combo for a task type based on provider fitness and constraints",
inputSchema: bestComboForTaskInput,
},
withScopeEnforcement("omniroute_best_combo_for_task", (args) =>
handleBestComboForTask(bestComboForTaskInput.parse(args))
)
);
server.registerTool(
"omniroute_explain_route",
{
description:
"Explains why a request was routed to a specific provider, showing scoring factors and fallbacks",
inputSchema: explainRouteInput,
},
withScopeEnforcement("omniroute_explain_route", (args) =>
handleExplainRoute(explainRouteInput.parse(args))
)
);
server.registerTool(
"omniroute_get_session_snapshot",
{
description:
"Returns a full snapshot of the current working session: cost, tokens, top models, errors, budget status",
inputSchema: getSessionSnapshotInput,
},
withScopeEnforcement("omniroute_get_session_snapshot", async (args) => {
getSessionSnapshotInput.parse(args ?? {});
return handleGetSessionSnapshot();
})
);
return server;
}
// ============ Main Entry Point (stdio) ============
/**
* Start the MCP server with stdio transport.
* Called when `omniroute --mcp` is used.
*/
export async function startMcpStdio(): Promise<void> {
const server = createMcpServer();
const transport = new StdioServerTransport();
const version = process.env.npm_package_version || "1.8.1";
const stopHeartbeat = startMcpHeartbeat({
version,
scopesEnforced: MCP_ENFORCE_SCOPES,
allowedScopes: Array.from(MCP_ALLOWED_SCOPES),
toolCount: MCP_TOOLS.length,
});
const stopHeartbeatOnce = () => {
stopHeartbeat();
};
process.once("exit", stopHeartbeatOnce);
process.once("SIGINT", stopHeartbeatOnce);
process.once("SIGTERM", stopHeartbeatOnce);
console.error("[MCP] OmniRoute MCP Server starting (stdio transport)...");
try {
await server.connect(transport);
console.error("[MCP] OmniRoute MCP Server connected and ready.");
} finally {
stopHeartbeatOnce();
process.off("exit", stopHeartbeatOnce);
process.off("SIGINT", stopHeartbeatOnce);
process.off("SIGTERM", stopHeartbeatOnce);
}
}
// If this file is run directly, start stdio server
if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/"))) {
startMcpStdio().catch((err) => {
console.error("[MCP] Fatal error:", err);
process.exit(1);
});
}

View File

@@ -0,0 +1,732 @@
/**
* OmniRoute MCP Advanced Tools — 8 intelligence tools that differentiate
* OmniRoute from all other AI gateways.
*
* Tools:
* 1. omniroute_simulate_route — Dry-run routing simulation
* 2. omniroute_set_budget_guard — Session budget with degrade/block/alert
* 3. omniroute_set_resilience_profile — Circuit breaker/retry profiles
* 4. omniroute_test_combo — Live test each provider in a combo
* 5. omniroute_get_provider_metrics — Detailed per-provider metrics
* 6. omniroute_best_combo_for_task — AI-powered combo recommendation
* 7. omniroute_explain_route — Post-hoc routing decision explainer
* 8. omniroute_get_session_snapshot — Full session state snapshot
*/
import { logToolCall } from "../audit.ts";
import { normalizeQuotaResponse } from "../../../src/shared/contracts/quota.ts";
const OMNIROUTE_BASE_URL = process.env.OMNIROUTE_BASE_URL || "http://localhost:20128";
const OMNIROUTE_API_KEY = process.env.OMNIROUTE_API_KEY || "";
async function apiFetch(path: string, options: RequestInit = {}): Promise<unknown> {
const url = `${OMNIROUTE_BASE_URL}${path}`;
const headers: Record<string, string> = {
"Content-Type": "application/json",
...(OMNIROUTE_API_KEY ? { Authorization: `Bearer ${OMNIROUTE_API_KEY}` } : {}),
...((options.headers as Record<string, string>) || {}),
};
const response = await fetch(url, { ...options, headers, signal: AbortSignal.timeout(30000) });
if (!response.ok) {
const text = await response.text().catch(() => "Unknown error");
throw new Error(`API [${response.status}]: ${text}`);
}
return response.json();
}
type JsonRecord = Record<string, unknown>;
interface ComboModel {
provider: string;
model: string;
inputCostPer1M: number;
}
function isRecord(value: unknown): value is JsonRecord {
return !!value && typeof value === "object" && !Array.isArray(value);
}
function toRecord(value: unknown): JsonRecord {
return isRecord(value) ? value : {};
}
function toArrayOfRecords(value: unknown): JsonRecord[] {
return Array.isArray(value) ? value.filter(isRecord) : [];
}
function toString(value: unknown, fallback = ""): string {
return typeof value === "string" ? value : fallback;
}
function toNumber(value: unknown, fallback = 0): number {
const parsed =
typeof value === "number"
? value
: typeof value === "string" && value.trim().length > 0
? Number(value)
: Number.NaN;
return Number.isFinite(parsed) ? parsed : fallback;
}
function toBoolean(value: unknown, fallback = false): boolean {
return typeof value === "boolean" ? value : fallback;
}
function getComboModels(combo: JsonRecord): ComboModel[] {
const directModels = toArrayOfRecords(combo.models);
const nestedModels = toArrayOfRecords(toRecord(combo.data).models);
const sourceModels = directModels.length > 0 ? directModels : nestedModels;
return sourceModels.map((model) => ({
provider: toString(model.provider, "unknown"),
model: toString(model.model, ""),
inputCostPer1M: toNumber(model.inputCostPer1M, 3.0),
}));
}
function normalizeCombosResponse(raw: unknown): JsonRecord[] {
if (Array.isArray(raw)) return raw.filter(isRecord);
const source = toRecord(raw);
return Array.isArray(source.combos) ? source.combos.filter(isRecord) : [];
}
// ============ In-Memory State ============
interface BudgetGuardState {
sessionId: string;
maxCost: number;
action: "degrade" | "block" | "alert";
degradeToTier?: "cheap" | "free";
spent: number;
createdAt: string;
}
let activeBudgetGuard: BudgetGuardState | null = null;
type ResilienceProfileConfig = {
profiles: {
oauth: {
transientCooldown: number;
rateLimitCooldown: number;
maxBackoffLevel: number;
circuitBreakerThreshold: number;
circuitBreakerReset: number;
};
apikey: {
transientCooldown: number;
rateLimitCooldown: number;
maxBackoffLevel: number;
circuitBreakerThreshold: number;
circuitBreakerReset: number;
};
};
defaults: {
requestsPerMinute: number;
minTimeBetweenRequests: number;
concurrentRequests: number;
};
};
const RESILIENCE_PROFILES = {
aggressive: {
profiles: {
oauth: {
transientCooldown: 3000,
rateLimitCooldown: 30000,
maxBackoffLevel: 4,
circuitBreakerThreshold: 2,
circuitBreakerReset: 30000,
},
apikey: {
transientCooldown: 2000,
rateLimitCooldown: 0,
maxBackoffLevel: 3,
circuitBreakerThreshold: 3,
circuitBreakerReset: 15000,
},
},
defaults: {
requestsPerMinute: 180,
minTimeBetweenRequests: 100,
concurrentRequests: 16,
},
},
balanced: {
profiles: {
oauth: {
transientCooldown: 5000,
rateLimitCooldown: 60000,
maxBackoffLevel: 8,
circuitBreakerThreshold: 3,
circuitBreakerReset: 60000,
},
apikey: {
transientCooldown: 3000,
rateLimitCooldown: 0,
maxBackoffLevel: 5,
circuitBreakerThreshold: 5,
circuitBreakerReset: 30000,
},
},
defaults: {
requestsPerMinute: 100,
minTimeBetweenRequests: 200,
concurrentRequests: 10,
},
},
conservative: {
profiles: {
oauth: {
transientCooldown: 8000,
rateLimitCooldown: 120000,
maxBackoffLevel: 10,
circuitBreakerThreshold: 8,
circuitBreakerReset: 120000,
},
apikey: {
transientCooldown: 5000,
rateLimitCooldown: 30000,
maxBackoffLevel: 8,
circuitBreakerThreshold: 8,
circuitBreakerReset: 60000,
},
},
defaults: {
requestsPerMinute: 60,
minTimeBetweenRequests: 350,
concurrentRequests: 6,
},
},
} satisfies Record<"aggressive" | "balanced" | "conservative", ResilienceProfileConfig>;
const TASK_FITNESS: Record<string, { preferred: string[]; traits: string[] }> = {
coding: { preferred: ["claude", "deepseek", "codex"], traits: ["fast", "code-optimized"] },
review: { preferred: ["claude", "gemini", "openai"], traits: ["analytical", "thorough"] },
planning: { preferred: ["gemini", "claude", "openai"], traits: ["reasoning", "structured"] },
analysis: { preferred: ["gemini", "claude"], traits: ["deep-reasoning", "large-context"] },
debugging: { preferred: ["claude", "deepseek", "codex"], traits: ["code-aware", "fast"] },
documentation: { preferred: ["gemini", "claude", "openai"], traits: ["clear", "structured"] },
};
// ============ Tool Handlers ============
export async function handleSimulateRoute(args: {
model: string;
promptTokenEstimate: number;
combo?: string;
}) {
const start = Date.now();
try {
// Fetch combos and health data for simulation
const [combosRaw, healthRaw, quotaRaw] = await Promise.allSettled([
apiFetch("/api/combos"),
apiFetch("/api/monitoring/health"),
apiFetch("/api/usage/quota"),
]);
const combos = combosRaw.status === "fulfilled" ? normalizeCombosResponse(combosRaw.value) : [];
const health = healthRaw.status === "fulfilled" ? toRecord(healthRaw.value) : {};
const quota =
quotaRaw.status === "fulfilled"
? normalizeQuotaResponse(quotaRaw.value)
: normalizeQuotaResponse({});
// Find target combo
const targetCombo = args.combo
? combos.find(
(combo) => toString(combo.id) === args.combo || toString(combo.name) === args.combo
)
: combos.find((combo) => combo.enabled !== false);
if (!targetCombo) {
return {
content: [
{ type: "text" as const, text: JSON.stringify({ error: "No matching combo found" }) },
],
isError: true,
};
}
const models = getComboModels(targetCombo);
const breakers = toArrayOfRecords(health.circuitBreakers);
const providers = quota.providers;
// Simulate path
const simulatedPath = models.map((model, idx: number) => {
const cb = breakers.find((breaker) => toString(breaker.provider) === model.provider);
const q = providers.find((providerEntry) => providerEntry.provider === model.provider);
const estimatedCost = (args.promptTokenEstimate / 1_000_000) * model.inputCostPer1M;
return {
provider: model.provider,
model: model.model || args.model,
probability: idx === 0 ? 0.85 : 0.15 / Math.max(models.length - 1, 1),
estimatedCost: Math.round(estimatedCost * 10000) / 10000,
healthStatus: toString(cb?.state, "CLOSED"),
quotaAvailable: q?.percentRemaining ?? 100,
};
});
const costs = simulatedPath.map((pathEntry) => pathEntry.estimatedCost);
const result = {
simulatedPath,
fallbackTree: {
primary: simulatedPath[0]?.provider || "unknown",
fallbacks: simulatedPath.slice(1).map((pathEntry) => pathEntry.provider),
worstCaseCost: Math.max(...costs, 0),
bestCaseCost: Math.min(...costs, 0),
},
};
await logToolCall("omniroute_simulate_route", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_simulate_route", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleSetBudgetGuard(args: {
maxCost: number;
action: "degrade" | "block" | "alert";
degradeToTier?: "cheap" | "free";
}) {
const start = Date.now();
try {
// Get current session cost
let spent = 0;
try {
const analytics = toRecord(await apiFetch("/api/usage/analytics?period=session"));
spent = toNumber(analytics.totalCost, 0);
} catch {
/* ignore if analytics not available */
}
activeBudgetGuard = {
sessionId: `budget_${Date.now()}`,
maxCost: args.maxCost,
action: args.action,
degradeToTier: args.degradeToTier,
spent,
createdAt: new Date().toISOString(),
};
const remaining = Math.max(0, args.maxCost - spent);
const result = {
sessionId: activeBudgetGuard.sessionId,
budgetTotal: args.maxCost,
budgetSpent: Math.round(spent * 10000) / 10000,
budgetRemaining: Math.round(remaining * 10000) / 10000,
action: args.action,
status: remaining <= 0 ? "exceeded" : remaining < args.maxCost * 0.2 ? "warning" : "active",
};
await logToolCall(
"omniroute_set_budget_guard",
{ maxCost: args.maxCost, action: args.action },
result,
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_set_budget_guard", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleSetResilienceProfile(args: {
profile: "aggressive" | "balanced" | "conservative";
}) {
const start = Date.now();
try {
const settings = RESILIENCE_PROFILES[args.profile];
if (!settings) {
return {
content: [{ type: "text" as const, text: `Error: Invalid profile "${args.profile}"` }],
isError: true,
};
}
// Apply to OmniRoute via API (contract: PATCH + { profiles, defaults })
await apiFetch("/api/resilience", {
method: "PATCH",
body: JSON.stringify({
profiles: settings.profiles,
defaults: settings.defaults,
}),
});
const result = { applied: true, profile: args.profile, settings };
await logToolCall("omniroute_set_resilience_profile", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall(
"omniroute_set_resilience_profile",
args,
null,
Date.now() - start,
false,
msg
);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleTestCombo(args: { comboId: string; testPrompt: string }) {
const start = Date.now();
try {
// Get combo details
const combos = normalizeCombosResponse(await apiFetch("/api/combos"));
const combo = combos.find(
(comboEntry) =>
toString(comboEntry.id) === args.comboId || toString(comboEntry.name) === args.comboId
);
if (!combo) {
return {
content: [
{
type: "text" as const,
text: JSON.stringify({ error: `Combo "${args.comboId}" not found` }),
},
],
isError: true,
};
}
const models = getComboModels(combo);
const prompt = (args.testPrompt || "Say hello").slice(0, 200);
// Test each provider in parallel
const results = await Promise.allSettled(
models.map(async (model) => {
const providerStart = Date.now();
try {
const resp = toRecord(
await apiFetch("/v1/chat/completions", {
method: "POST",
body: JSON.stringify({
model: model.model || "auto",
messages: [{ role: "user", content: prompt }],
max_tokens: 50,
stream: false,
"x-provider": model.provider,
}),
})
);
const usage = toRecord(resp.usage);
return {
provider: model.provider,
model: model.model || toString(resp.model, "unknown"),
success: true,
latencyMs: Date.now() - providerStart,
cost: toNumber(resp.cost, 0),
tokenCount: toNumber(usage.prompt_tokens, 0) + toNumber(usage.completion_tokens, 0),
};
} catch (err) {
return {
provider: model.provider,
model: model.model || "unknown",
success: false,
latencyMs: Date.now() - providerStart,
cost: 0,
tokenCount: 0,
error: err instanceof Error ? err.message : String(err),
};
}
})
);
const providerResults = results.map((r) =>
r.status === "fulfilled"
? r.value
: {
provider: "unknown",
model: "unknown",
success: false,
latencyMs: 0,
cost: 0,
tokenCount: 0,
error: "Promise rejected",
}
);
const successful = providerResults.filter((r) => r.success);
const fastest = successful.sort((a, b) => a.latencyMs - b.latencyMs)[0];
const cheapest = successful.sort((a, b) => a.cost - b.cost)[0];
const result = {
results: providerResults,
summary: {
totalProviders: providerResults.length,
successful: successful.length,
fastestProvider: fastest?.provider || "none",
cheapestProvider: cheapest?.provider || "none",
},
};
await logToolCall(
"omniroute_test_combo",
{ comboId: args.comboId },
result.summary,
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_test_combo", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleGetProviderMetrics(args: { provider: string }) {
const start = Date.now();
try {
const [healthRaw, quotaRaw, analyticsRaw] = await Promise.allSettled([
apiFetch("/api/monitoring/health"),
apiFetch(`/api/usage/quota?provider=${encodeURIComponent(args.provider)}`),
apiFetch(`/api/usage/analytics?period=session&provider=${encodeURIComponent(args.provider)}`),
]);
const health = healthRaw.status === "fulfilled" ? toRecord(healthRaw.value) : {};
const quota =
quotaRaw.status === "fulfilled"
? normalizeQuotaResponse(quotaRaw.value, { provider: args.provider })
: normalizeQuotaResponse({});
const analytics = analyticsRaw.status === "fulfilled" ? toRecord(analyticsRaw.value) : {};
const cb = toArrayOfRecords(health.circuitBreakers).find(
(breaker) => toString(breaker.provider) === args.provider
);
const providerQuota = quota.providers.find((p) => p.provider === args.provider) || null;
const result = {
provider: args.provider,
successRate: toNumber(analytics.successRate, 1.0),
requestCount: toNumber(analytics.requestCount, 0),
avgLatencyMs: toNumber(analytics.avgLatencyMs, 0),
p50LatencyMs: toNumber(analytics.p50LatencyMs, 0),
p95LatencyMs: toNumber(analytics.p95LatencyMs, 0),
p99LatencyMs: toNumber(analytics.p99LatencyMs, 0),
errorRate: toNumber(analytics.errorRate, 0),
lastError: toString(analytics.lastError) || null,
circuitBreakerState: toString(cb?.state, "CLOSED"),
quotaInfo: providerQuota
? {
used: providerQuota.quotaUsed,
total: providerQuota.quotaTotal,
resetAt: providerQuota.resetAt,
}
: { used: 0, total: null, resetAt: null },
};
await logToolCall("omniroute_get_provider_metrics", args, result, Date.now() - start, true);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_get_provider_metrics", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleBestComboForTask(args: {
taskType: string;
budgetConstraint?: number;
latencyConstraint?: number;
}) {
const start = Date.now();
try {
const fitness = TASK_FITNESS[args.taskType] || TASK_FITNESS.coding;
const combos = normalizeCombosResponse(await apiFetch("/api/combos"));
const enabledCombos = combos.filter((combo) => combo.enabled !== false);
if (enabledCombos.length === 0) {
return {
content: [
{ type: "text" as const, text: JSON.stringify({ error: "No enabled combos available" }) },
],
isError: true,
};
}
// Score combos by task fitness
const scored = enabledCombos.map((combo) => {
const models = getComboModels(combo);
let score = 0;
// Provider preference scoring
for (const model of models) {
const prefIdx = fitness.preferred.indexOf(model.provider);
if (prefIdx >= 0) score += (fitness.preferred.length - prefIdx) * 10;
}
// Name-based trait scoring
const name = toString(combo.name).toLowerCase();
for (const trait of fitness.traits) {
if (name.includes(trait)) score += 5;
}
// Check if it's a free combo
const isFree =
name.includes("free") ||
models.every((model) => model.provider.toLowerCase().includes("free"));
return { combo, score, isFree };
});
scored.sort((a, b) => b.score - a.score);
const best = scored[0];
const alternatives = scored.slice(1, 4).map((s) => ({
id: s.combo.id,
name: s.combo.name,
tradeoff: s.isFree
? "free but may have limits"
: s.score < best.score * 0.5
? "cheaper but slower"
: "similar quality, different providers",
}));
const freeAlt = scored.find((s) => s.isFree && s !== best);
const result = {
recommendedCombo: {
id: best.combo.id,
name: best.combo.name,
reason: `Best match for "${args.taskType}": preferred providers (${fitness.preferred.slice(0, 3).join(", ")})`,
},
alternatives,
freeAlternative: freeAlt ? { id: freeAlt.combo.id, name: freeAlt.combo.name } : null,
};
await logToolCall(
"omniroute_best_combo_for_task",
args,
result.recommendedCombo,
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_best_combo_for_task", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleExplainRoute(args: { requestId: string }) {
const start = Date.now();
try {
// Query routing_decisions table via API
let decision: JsonRecord | null = null;
try {
decision = toRecord(
await apiFetch(`/api/routing/decisions/${encodeURIComponent(args.requestId)}`)
);
} catch {
// Fall back to a generic explanation
}
const result = decision
? {
requestId: args.requestId,
decision: {
comboUsed: decision.comboUsed || "default",
providerSelected: decision.providerSelected || "unknown",
modelUsed: decision.modelUsed || "unknown",
score: decision.score || 0,
factors: decision.factors || [
{ name: "health", value: 1, weight: 0.3, contribution: 0.3 },
{ name: "quota", value: 1, weight: 0.25, contribution: 0.25 },
{ name: "cost", value: 0.8, weight: 0.2, contribution: 0.16 },
{ name: "latency", value: 0.9, weight: 0.15, contribution: 0.135 },
{ name: "task_fit", value: 0.7, weight: 0.1, contribution: 0.07 },
],
fallbacksTriggered: decision.fallbacksTriggered || [],
costActual: decision.costActual || 0,
latencyActual: decision.latencyActual || 0,
},
}
: {
requestId: args.requestId,
decision: {
comboUsed: "unknown",
providerSelected: "unknown",
modelUsed: "unknown",
score: 0,
factors: [],
fallbacksTriggered: [],
costActual: 0,
latencyActual: 0,
},
note: "Routing decision not found. The /api/routing/decisions endpoint may not be implemented yet, or the requestId is invalid.",
};
await logToolCall(
"omniroute_explain_route",
args,
{ requestId: args.requestId },
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_explain_route", args, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}
export async function handleGetSessionSnapshot() {
const start = Date.now();
try {
const analytics = toRecord(
await apiFetch("/api/usage/analytics?period=session").catch(() => ({}))
);
const tokenCount = toRecord(analytics.tokenCount);
const byModel = toArrayOfRecords(analytics.byModel);
const byProvider = toArrayOfRecords(analytics.byProvider);
const result = {
sessionStart: toString(analytics.sessionStart, new Date().toISOString()),
duration: toString(analytics.duration, "unknown"),
requestCount: toNumber(analytics.requestCount, 0),
costTotal: toNumber(analytics.totalCost, 0),
tokenCount: {
prompt: toNumber(tokenCount.prompt, 0),
completion: toNumber(tokenCount.completion, 0),
},
topModels: byModel.slice(0, 5).map((model) => ({
model: toString(model.model, "unknown"),
count: toNumber(model.requests, 0),
})),
topProviders: byProvider.slice(0, 5).map((provider) => ({
provider: toString(provider.name, "unknown"),
count: toNumber(provider.requests, 0),
})),
errors: toNumber(analytics.errorCount, 0),
fallbacks: toNumber(analytics.fallbackCount, 0),
budgetGuard: activeBudgetGuard
? {
active: true,
remaining: Math.max(0, activeBudgetGuard.maxCost - activeBudgetGuard.spent),
action: activeBudgetGuard.action,
}
: null,
};
await logToolCall(
"omniroute_get_session_snapshot",
{},
{ requestCount: result.requestCount },
Date.now() - start,
true
);
return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
await logToolCall("omniroute_get_session_snapshot", {}, null, Date.now() - start, false, msg);
return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true };
}
}

View File

@@ -24,14 +24,25 @@ export function getProviderProfile(provider) {
// In-memory map: "provider:connectionId:model" → { reason, until, lockedAt }
const modelLockouts = new Map();
// Auto-cleanup expired lockouts every 15 seconds
const _cleanupTimer = setInterval(() => {
const now = Date.now();
for (const [key, entry] of modelLockouts) {
if (now > entry.until) modelLockouts.delete(key);
// Auto-cleanup expired lockouts every 15 seconds (lazy init for Cloudflare Workers compatibility)
let _cleanupTimer: ReturnType<typeof setInterval> | null = null;
function ensureCleanupTimer() {
if (_cleanupTimer) return;
try {
_cleanupTimer = setInterval(() => {
const now = Date.now();
for (const [key, entry] of modelLockouts) {
if (now > entry.until) modelLockouts.delete(key);
}
}, 15_000);
if (typeof _cleanupTimer === "object" && "unref" in _cleanupTimer) {
(_cleanupTimer as { unref?: () => void }).unref?.(); // Don't prevent process exit (Node.js only)
}
} catch {
// Cloudflare Workers may not support setInterval outside handlers — skip cleanup timer
}
}, 15_000);
_cleanupTimer.unref(); // Don't prevent process exit
}
/**
* Lock a specific model on a specific account
@@ -43,6 +54,7 @@ _cleanupTimer.unref(); // Don't prevent process exit
*/
export function lockModel(provider, connectionId, model, reason, cooldownMs) {
if (!model) return; // No model → skip model-level locking
ensureCleanupTimer();
const key = `${provider}:${connectionId}:${model}`;
modelLockouts.set(key, {
reason,
@@ -504,7 +516,7 @@ export function applyErrorState(account, status, errorText, provider = null) {
* @param {object} account
* @returns {number} score 0 = unhealthy, 100 = perfectly healthy
*/
export function getAccountHealth(account, model?: any) {
export function getAccountHealth(account, model?: unknown) {
if (!account) return 0;
let score = 100;
score -= (account.backoffLevel || 0) * 10;

View File

@@ -6,6 +6,7 @@
*/
import { getAccountHealth } from "./accountFallback.ts";
import crypto from "crypto";
/**
* P2C selection: pick 2 random candidates, return the healthier one.
@@ -19,9 +20,9 @@ export function selectAccountP2C(accounts, model = null) {
if (!accounts || accounts.length === 0) return null;
if (accounts.length === 1) return accounts[0];
// Pick 2 random distinct indices
const i = Math.floor(Math.random() * accounts.length);
let j = Math.floor(Math.random() * (accounts.length - 1));
// Pick 2 random distinct indices (cryptographically secure)
const i = crypto.randomInt(accounts.length);
let j = crypto.randomInt(accounts.length - 1);
if (j >= i) j++; // Ensure distinct
const a = accounts[i];
@@ -43,7 +44,12 @@ export function selectAccountP2C(accounts, model = null) {
* @param {string} [model] - Model name
* @returns {{ account: object|null, state: object }}
*/
export function selectAccount(accounts, strategy = "fill-first", state: any = {}, model = null) {
export function selectAccount(
accounts,
strategy = "fill-first",
state: { lastIndex?: number } = {},
model = null
) {
if (!accounts || accounts.length === 0) {
return { account: null, state };
}
@@ -54,7 +60,7 @@ export function selectAccount(accounts, strategy = "fill-first", state: any = {}
case "random":
return {
account: accounts[Math.floor(Math.random() * accounts.length)],
account: accounts[crypto.randomInt(accounts.length)],
state,
};

View File

@@ -0,0 +1,162 @@
/**
* Unit tests for Auto-Combo Engine (Phase 5)
*/
import { describe, it, expect, beforeEach } from "vitest";
import { calculateFactors, calculateScore, DEFAULT_WEIGHTS, validateWeights } from "../scoring";
import type { ProviderCandidate, ScoringWeights } from "../scoring";
import { getTaskFitness, getTaskTypes } from "../taskFitness";
import { SelfHealingManager } from "../selfHealing";
import { MODE_PACKS, getModePack, getModePackNames } from "../modePacks";
describe("Scoring", () => {
const candidate: ProviderCandidate = {
provider: "anthropic",
model: "claude-sonnet",
quotaRemaining: 80,
quotaTotal: 100,
circuitBreakerState: "CLOSED",
costPer1MTokens: 3,
p95LatencyMs: 1200,
latencyStdDev: 120,
errorRate: 0.02,
};
it("should calculate a score between 0 and 1", () => {
const pool: ProviderCandidate[] = [
candidate,
{
...candidate,
provider: "google",
model: "gemini-pro",
costPer1MTokens: 6,
p95LatencyMs: 1800,
latencyStdDev: 300,
quotaRemaining: 70,
},
];
const factors = calculateFactors(candidate, pool, "coding", getTaskFitness);
const score = calculateScore(factors, DEFAULT_WEIGHTS);
expect(score).toBeGreaterThan(0);
expect(score).toBeLessThanOrEqual(1);
});
it("OPEN circuit breaker should reduce score", () => {
const unhealthyCandidate: ProviderCandidate = { ...candidate, circuitBreakerState: "OPEN" };
const pool: ProviderCandidate[] = [candidate, unhealthyCandidate];
const healthyFactors = calculateFactors(candidate, pool, "coding", getTaskFitness);
const unhealthyFactors = calculateFactors(unhealthyCandidate, pool, "coding", getTaskFitness);
const healthy = calculateScore(healthyFactors, DEFAULT_WEIGHTS);
const unhealthy = calculateScore(unhealthyFactors, DEFAULT_WEIGHTS);
expect(healthy).toBeGreaterThan(unhealthy);
});
it("should validate weights sum to 1.0", () => {
expect(validateWeights(DEFAULT_WEIGHTS)).toBe(true);
expect(validateWeights({ ...DEFAULT_WEIGHTS, quota: 0.5 })).toBe(false);
});
});
describe("Task Fitness", () => {
it("should return fitness score for known model+task", () => {
const score = getTaskFitness("claude-sonnet", "coding");
expect(score).toBeGreaterThan(0.5);
});
it("should return 0.5 default for unknown model", () => {
const score = getTaskFitness("totally-unknown-model", "coding");
expect(score).toBe(0.5);
});
it("should list all task types", () => {
const types = getTaskTypes();
expect(types).toContain("coding");
expect(types).toContain("review");
expect(types).toContain("planning");
expect(types.length).toBeGreaterThanOrEqual(6);
});
it("should boost wildcard patterns", () => {
const coderScore = getTaskFitness("some-coder-model", "coding");
const normalScore = getTaskFitness("some-random-model", "coding");
expect(coderScore).toBeGreaterThan(normalScore);
});
});
describe("Self-Healing", () => {
let healer: SelfHealingManager;
beforeEach(() => {
healer = new SelfHealingManager();
});
it("should exclude provider with low score", () => {
const result = healer.evaluate("bad-provider", 0.1, "CLOSED");
expect(result.excluded).toBe(true);
expect(result.reason).toContain("below threshold");
});
it("should keep healthy providers", () => {
const result = healer.evaluate("good-provider", 0.8, "CLOSED");
expect(result.excluded).toBe(false);
});
it("should auto-exclude OPEN circuit breakers", () => {
const result = healer.evaluate("broken-provider", 0.8, "OPEN");
expect(result.excluded).toBe(true);
});
it("should detect incident mode when >50% providers are OPEN", () => {
healer.updateIncidentMode(["OPEN", "OPEN", "CLOSED"]);
expect(healer.isInIncidentMode()).toBe(true);
});
it("should not be in incident mode when most are CLOSED", () => {
healer.updateIncidentMode(["CLOSED", "CLOSED", "OPEN"]);
expect(healer.isInIncidentMode()).toBe(false);
});
it("should track exclusion count", () => {
healer.evaluate("p1", 0.1, "CLOSED");
healer.evaluate("p2", 0.1, "CLOSED");
const status = healer.getStatus();
expect(status.exclusionCount).toBe(2);
});
});
describe("Mode Packs", () => {
it("should have 4 mode packs", () => {
expect(getModePackNames()).toHaveLength(4);
});
it("all mode pack weights should sum to 1.0", () => {
for (const name of getModePackNames()) {
const pack = getModePack(name);
if (pack) {
const sum = Object.values(pack).reduce((a, b) => a + b, 0);
expect(Math.abs(sum - 1.0)).toBeLessThan(0.001);
}
}
});
it("ship-fast should prioritize latency", () => {
const pack = MODE_PACKS["ship-fast"];
expect(pack.latencyInv).toBeGreaterThan(pack.costInv);
});
it("cost-saver should prioritize cost", () => {
const pack = MODE_PACKS["cost-saver"];
expect(pack.costInv).toBeGreaterThan(pack.latencyInv);
});
it("quality-first should prioritize task fit", () => {
const pack = MODE_PACKS["quality-first"];
expect(pack.taskFit).toBeGreaterThan(pack.costInv);
});
it("undefined pack should return undefined", () => {
expect(getModePack("nonexistent")).toBeUndefined();
});
});

View File

@@ -0,0 +1,174 @@
/**
* Auto-Combo Engine — The `auto` combo type that self-manages provider selection.
*
* Features:
* - Scoring-based provider selection from candidate pool
* - Bandit exploration (configurable rate, default 5%)
* - Budget cap enforcement
* - Self-healing integration
* - Mode pack support
*/
import {
scorePool,
validateWeights,
DEFAULT_WEIGHTS,
type ScoringWeights,
type ProviderCandidate,
type ScoredProvider,
} from "./scoring";
import { getTaskFitness } from "./taskFitness";
import { getModePack } from "./modePacks";
import { getSelfHealingManager } from "./selfHealing";
export interface AutoComboConfig {
id: string;
name: string;
type: "auto";
candidatePool: string[]; // provider names (empty = all)
weights: ScoringWeights;
modePack?: string;
budgetCap?: number; // max cost per request in USD
explorationRate: number; // 0.05 = 5% exploratory
}
export interface SelectionResult {
provider: string;
model: string;
score: number;
isExploration: boolean;
factors: Record<string, number>;
excluded: string[];
}
/**
* Select the best provider from an auto-combo pool.
*/
export function selectProvider(
config: AutoComboConfig,
candidates: ProviderCandidate[],
taskType: string = "default"
): SelectionResult {
const healer = getSelfHealingManager();
// Resolve weights from mode pack or config
let weights = config.weights;
if (config.modePack) {
const pack = getModePack(config.modePack);
if (pack) weights = pack;
}
if (!validateWeights(weights)) weights = DEFAULT_WEIGHTS;
// Filter out excluded providers
const excluded: string[] = [];
const pool = candidates.filter((c) => {
// Pool filter
if (config.candidatePool.length > 0 && !config.candidatePool.includes(c.provider)) return false;
// Self-healing exclusion
const evaluation = healer.evaluate(c.provider, 0.5, c.circuitBreakerState);
if (evaluation.excluded) {
excluded.push(c.provider);
return false;
}
return true;
});
if (pool.length === 0) {
// Fallback: allow all candidates regardless of exclusions
pool.push(...candidates);
excluded.length = 0;
}
// Score all providers
const scored = scorePool(pool, taskType, weights, getTaskFitness);
// Apply self-healing re-evaluation with actual scores
const finalCandidates = scored.filter((s) => {
const eval_ = healer.evaluate(s.provider, s.score, "CLOSED");
if (eval_.excluded) {
excluded.push(s.provider);
return false;
}
return true;
});
const candidates_ = finalCandidates.length > 0 ? finalCandidates : scored;
// Incident mode check
const incidentMode = healer.isInIncidentMode();
const effectiveExplorationRate = incidentMode ? 0 : config.explorationRate;
// Selection: exploration vs exploitation
let selected: ScoredProvider;
const isExploration = Math.random() < effectiveExplorationRate && candidates_.length > 1;
if (isExploration) {
// Random selection (bandit exploration)
const idx = Math.floor(Math.random() * candidates_.length);
selected = candidates_[idx];
} else {
// Greedy: highest score
selected = candidates_[0];
}
// Budget cap enforcement
if (config.budgetCap) {
const candidate = candidates.find((c) => c.provider === selected.provider);
if (candidate) {
const estimatedCost = (candidate.costPer1MTokens / 1_000_000) * 1000; // approx for 1K tokens
if (estimatedCost > config.budgetCap) {
// Degrade to cheapest
const cheapest = candidates_
.map((s) => ({
...s,
cost: candidates.find((c) => c.provider === s.provider)?.costPer1MTokens || 0,
}))
.sort((a, b) => a.cost - b.cost)[0];
if (cheapest) selected = cheapest;
}
}
}
return {
provider: selected.provider,
model: selected.model,
score: selected.score,
isExploration,
factors: selected.factors as unknown as Record<string, number>,
excluded,
};
}
// ============ In-Memory Auto-Combo Registry ============
const autoCombos = new Map<string, AutoComboConfig>();
export function createAutoCombo(config: Omit<AutoComboConfig, "type">): AutoComboConfig {
const full: AutoComboConfig = { ...config, type: "auto" };
autoCombos.set(config.id, full);
return full;
}
export function getAutoCombo(id: string): AutoComboConfig | undefined {
return autoCombos.get(id);
}
export function updateAutoCombo(
id: string,
update: Partial<AutoComboConfig>
): AutoComboConfig | undefined {
const existing = autoCombos.get(id);
if (!existing) return undefined;
const updated = { ...existing, ...update, id, type: "auto" as const };
autoCombos.set(id, updated);
return updated;
}
export function deleteAutoCombo(id: string): boolean {
return autoCombos.delete(id);
}
export function listAutoCombos(): AutoComboConfig[] {
return [...autoCombos.values()];
}

View File

@@ -0,0 +1,26 @@
/**
* Auto-Combo barrel export
*/
export {
calculateScore,
scorePool,
validateWeights,
DEFAULT_WEIGHTS,
type ScoringWeights,
type ScoringFactors,
type ProviderCandidate,
type ScoredProvider,
} from "./scoring";
export { getTaskFitness, getTaskTypes } from "./taskFitness";
export { SelfHealingManager, getSelfHealingManager } from "./selfHealing";
export { MODE_PACKS, getModePack, getModePackNames } from "./modePacks";
export {
selectProvider,
createAutoCombo,
getAutoCombo,
updateAutoCombo,
deleteAutoCombo,
listAutoCombos,
type AutoComboConfig,
type SelectionResult,
} from "./engine";

View File

@@ -0,0 +1,60 @@
/**
* Mode Packs — Pre-defined weight profiles for Auto-Combo scoring.
*
* Each pack optimizes for a different priority:
* - ship-fast: Prioritize latency and health
* - cost-saver: Prioritize cost efficiency
* - quality-first: Prioritize task fitness and stability
* - offline-friendly: Prioritize quota availability
*/
import type { ScoringWeights } from "./scoring";
export const MODE_PACKS: Record<string, ScoringWeights> = {
"ship-fast": {
quota: 0.15,
health: 0.3,
costInv: 0.05,
latencyInv: 0.35,
taskFit: 0.1,
stability: 0.05,
},
"cost-saver": {
quota: 0.15,
health: 0.2,
costInv: 0.4,
latencyInv: 0.05,
taskFit: 0.1,
stability: 0.1,
},
"quality-first": {
quota: 0.1,
health: 0.2,
costInv: 0.05,
latencyInv: 0.1,
taskFit: 0.4,
stability: 0.15,
},
"offline-friendly": {
quota: 0.4,
health: 0.3,
costInv: 0.1,
latencyInv: 0.05,
taskFit: 0.05,
stability: 0.1,
},
};
/**
* Get a mode pack by name, falling back to default weights.
*/
export function getModePack(name: string): ScoringWeights | undefined {
return MODE_PACKS[name];
}
/**
* Get all available mode pack names.
*/
export function getModePackNames(): string[] {
return Object.keys(MODE_PACKS);
}

View File

@@ -0,0 +1,123 @@
/**
* Auto-Combo Adaptation Persistence
*
* Saves and restores scoring adaptation state so learned provider
* preferences survive server restarts.
*/
import fs from "fs";
import path from "path";
export interface AdaptationState {
comboId: string;
providerScores: Record<string, number>;
exclusionHistory: Array<{
provider: string;
excludedAt: string;
cooldownMs: number;
reason: string;
}>;
modePackHistory: Array<{ pack: string; activatedAt: string }>;
totalDecisions: number;
explorationHits: number;
lastUpdated: string;
}
const PERSISTENCE_DIR = path.join(process.cwd(), "data");
const STATE_FILE = path.join(PERSISTENCE_DIR, "auto_combo_state.json");
let stateCache = new Map<string, AdaptationState>();
/**
* Save adaptation state for a combo.
*/
export function saveAdaptationState(state: AdaptationState): void {
stateCache.set(state.comboId, { ...state, lastUpdated: new Date().toISOString() });
persistToDisk();
}
/**
* Load adaptation state for a combo.
*/
export function loadAdaptationState(comboId: string): AdaptationState | null {
if (stateCache.size === 0) loadFromDisk();
return stateCache.get(comboId) || null;
}
/**
* List all saved adaptation states.
*/
export function listAdaptationStates(): AdaptationState[] {
if (stateCache.size === 0) loadFromDisk();
return [...stateCache.values()];
}
/**
* Delete adaptation state for a combo.
*/
export function deleteAdaptationState(comboId: string): boolean {
const existed = stateCache.delete(comboId);
if (existed) persistToDisk();
return existed;
}
/**
* Record a routing decision in the adaptation state.
*/
export function recordDecision(
comboId: string,
provider: string,
score: number,
wasExploration: boolean
): void {
let state = stateCache.get(comboId);
if (!state) {
state = {
comboId,
providerScores: {},
exclusionHistory: [],
modePackHistory: [],
totalDecisions: 0,
explorationHits: 0,
lastUpdated: new Date().toISOString(),
};
}
// Exponential moving average for provider scores
const alpha = 0.1;
const prev = state.providerScores[provider] || 0.5;
state.providerScores[provider] = prev * (1 - alpha) + score * alpha;
state.totalDecisions++;
if (wasExploration) state.explorationHits++;
state.lastUpdated = new Date().toISOString();
stateCache.set(comboId, state);
// Persist every 10 decisions
if (state.totalDecisions % 10 === 0) persistToDisk();
}
function persistToDisk(): void {
try {
if (!fs.existsSync(PERSISTENCE_DIR)) {
fs.mkdirSync(PERSISTENCE_DIR, { recursive: true });
}
const data = Object.fromEntries(stateCache);
fs.writeFileSync(STATE_FILE, JSON.stringify(data, null, 2));
} catch {
/* disk write failure — non-fatal */
}
}
function loadFromDisk(): void {
try {
if (fs.existsSync(STATE_FILE)) {
const raw = fs.readFileSync(STATE_FILE, "utf-8");
const data = JSON.parse(raw) as Record<string, AdaptationState>;
stateCache = new Map(Object.entries(data));
}
} catch {
/* disk read failure — start fresh */
}
}

View File

@@ -0,0 +1,130 @@
/**
* Auto-Combo Scoring Function
*
* Calculates a weighted score for each provider candidate based on 6 factors:
* 1. Quota (0.20) — residual capacity [0..1]
* 2. Health (0.25) — circuit breaker state
* 3. CostInv (0.20) — inverse cost normalized to pool
* 4. LatencyInv (0.15) — inverse p95 latency normalized to pool
* 5. TaskFit (0.10) — model × taskType fitness score
* 6. Stability (0.10) — variance-based prediction of consistency
*/
export interface ScoringFactors {
quota: number;
health: number;
costInv: number;
latencyInv: number;
taskFit: number;
stability: number;
}
export interface ScoringWeights {
quota: number;
health: number;
costInv: number;
latencyInv: number;
taskFit: number;
stability: number;
}
export const DEFAULT_WEIGHTS: ScoringWeights = {
quota: 0.2,
health: 0.25,
costInv: 0.2,
latencyInv: 0.15,
taskFit: 0.1,
stability: 0.1,
};
export interface ProviderCandidate {
provider: string;
model: string;
quotaRemaining: number; // percentage 0..100
quotaTotal: number;
circuitBreakerState: "CLOSED" | "HALF_OPEN" | "OPEN";
costPer1MTokens: number;
p95LatencyMs: number;
latencyStdDev: number;
errorRate: number;
}
export interface ScoredProvider {
provider: string;
model: string;
score: number;
factors: ScoringFactors;
}
/**
* Calculate weighted score from factors.
*/
export function calculateScore(factors: ScoringFactors, weights: ScoringWeights): number {
return (
weights.quota * factors.quota +
weights.health * factors.health +
weights.costInv * factors.costInv +
weights.latencyInv * factors.latencyInv +
weights.taskFit * factors.taskFit +
weights.stability * factors.stability
);
}
/**
* Calculate individual factors for a provider within its pool.
*/
export function calculateFactors(
candidate: ProviderCandidate,
pool: ProviderCandidate[],
taskType: string,
getTaskFitness: (model: string, taskType: string) => number
): ScoringFactors {
// Pool-wide maximums for normalization
const maxCost = Math.max(...pool.map((p) => p.costPer1MTokens), 0.001);
const maxLatency = Math.max(...pool.map((p) => p.p95LatencyMs), 1);
const maxStdDev = Math.max(...pool.map((p) => p.latencyStdDev), 0.001);
return {
quota: Math.min(1, candidate.quotaRemaining / 100),
health:
candidate.circuitBreakerState === "CLOSED"
? 1.0
: candidate.circuitBreakerState === "HALF_OPEN"
? 0.5
: 0.0,
costInv: 1 - candidate.costPer1MTokens / maxCost,
latencyInv: 1 - candidate.p95LatencyMs / maxLatency,
taskFit: getTaskFitness(candidate.model, taskType),
stability: 1 - candidate.latencyStdDev / maxStdDev,
};
}
/**
* Score and rank all providers in a pool.
*/
export function scorePool(
pool: ProviderCandidate[],
taskType: string,
weights: ScoringWeights = DEFAULT_WEIGHTS,
getTaskFitness: (model: string, taskType: string) => number = () => 0.5
): ScoredProvider[] {
return pool
.map((candidate) => {
const factors = calculateFactors(candidate, pool, taskType, getTaskFitness);
return {
provider: candidate.provider,
model: candidate.model,
score: calculateScore(factors, weights),
factors,
};
})
.sort((a, b) => b.score - a.score);
}
/**
* Validate that weights sum to 1.0 (±0.01 tolerance).
*/
export function validateWeights(weights: ScoringWeights): boolean {
const sum = Object.values(weights).reduce((a, b) => a + b, 0);
return Math.abs(sum - 1.0) < 0.01;
}

View File

@@ -0,0 +1,167 @@
/**
* Auto-Combo Self-Healing
*
* Features:
* - Temporary exclusion when score < 0.2
* - Circuit breaker awareness (OPEN → excluded, HALF_OPEN → probe)
* - Incident mode (>50% OPEN → exploitation only)
* - Cooldown recovery with progressive backoff
*/
export interface ExclusionEntry {
provider: string;
excludedAt: number;
cooldownMs: number;
reason: string;
probeCount: number;
}
const DEFAULT_COOLDOWN_MS = 5 * 60 * 1000; // 5 min
const MAX_COOLDOWN_MS = 30 * 60 * 1000; // 30 min
const REENTRY_THRESHOLD = 0.3;
const EXCLUSION_THRESHOLD = 0.2;
const INCIDENT_MODE_THRESHOLD = 0.5; // >50% OPEN
export class SelfHealingManager {
private exclusions = new Map<string, ExclusionEntry>();
private incidentMode = false;
/**
* Check if a provider is currently excluded.
*/
isExcluded(provider: string): boolean {
const entry = this.exclusions.get(provider);
if (!entry) return false;
if (Date.now() - entry.excludedAt > entry.cooldownMs) return false; // Cooldown expired
return true;
}
/**
* Evaluate provider health and potentially exclude or re-admit.
*/
evaluate(
provider: string,
score: number,
circuitBreakerState: string
): {
excluded: boolean;
reason?: string;
isProbe?: boolean;
} {
const existing = this.exclusions.get(provider);
// Re-admission: score above threshold and cooldown expired
if (
existing &&
score >= REENTRY_THRESHOLD &&
Date.now() - existing.excludedAt > existing.cooldownMs
) {
this.exclusions.delete(provider);
return {
excluded: false,
reason: `Re-admitted: score ${score.toFixed(2)} >= ${REENTRY_THRESHOLD}`,
};
}
// Already excluded and still in cooldown
if (this.isExcluded(provider)) {
// Allow probe if HALF_OPEN
if (circuitBreakerState === "HALF_OPEN" && existing) {
existing.probeCount++;
return { excluded: false, isProbe: true, reason: `Probe request #${existing.probeCount}` };
}
return { excluded: true, reason: existing?.reason || "Excluded" };
}
// New exclusion: score too low
if (score < EXCLUSION_THRESHOLD) {
const cooldownMs = existing
? Math.min(existing.cooldownMs * 2, MAX_COOLDOWN_MS)
: DEFAULT_COOLDOWN_MS;
this.exclusions.set(provider, {
provider,
excludedAt: Date.now(),
cooldownMs,
reason: `Score ${score.toFixed(2)} < ${EXCLUSION_THRESHOLD}`,
probeCount: 0,
});
return { excluded: true, reason: `Excluded: score ${score.toFixed(2)} below threshold` };
}
// Circuit breaker OPEN → auto-exclude
if (circuitBreakerState === "OPEN") {
this.exclusions.set(provider, {
provider,
excludedAt: Date.now(),
cooldownMs: DEFAULT_COOLDOWN_MS,
reason: "Circuit breaker OPEN",
probeCount: 0,
});
return { excluded: true, reason: "Circuit breaker OPEN" };
}
return { excluded: false };
}
/**
* Record probe result. After 3 successful probes, fully re-admit.
*/
recordProbeResult(provider: string, success: boolean) {
const entry = this.exclusions.get(provider);
if (!entry) return;
if (success && entry.probeCount >= 3) {
this.exclusions.delete(provider);
} else if (!success) {
entry.cooldownMs = Math.min(entry.cooldownMs * 2, MAX_COOLDOWN_MS);
entry.excludedAt = Date.now();
entry.probeCount = 0;
}
}
/**
* Update incident mode based on circuit breaker states.
*/
updateIncidentMode(circuitBreakerStates: string[]): boolean {
const total = circuitBreakerStates.length;
if (total === 0) {
this.incidentMode = false;
return false;
}
const openCount = circuitBreakerStates.filter((s) => s === "OPEN").length;
this.incidentMode = openCount / total > INCIDENT_MODE_THRESHOLD;
return this.incidentMode;
}
isInIncidentMode(): boolean {
return this.incidentMode;
}
getExclusions(): ExclusionEntry[] {
return [...this.exclusions.values()];
}
getStatus(): {
exclusionCount: number;
incidentMode: boolean;
exclusions: Array<{ provider: string; reason: string; remainingMs: number }>;
} {
const now = Date.now();
return {
exclusionCount: this.exclusions.size,
incidentMode: this.incidentMode,
exclusions: [...this.exclusions.values()].map((e) => ({
provider: e.provider,
reason: e.reason,
remainingMs: Math.max(0, e.cooldownMs - (now - e.excludedAt)),
})),
};
}
}
let _instance: SelfHealingManager | null = null;
export function getSelfHealingManager(): SelfHealingManager {
if (!_instance) _instance = new SelfHealingManager();
return _instance;
}

View File

@@ -0,0 +1,134 @@
/**
* Task Fitness Lookup Table
*
* Maps model patterns × task types → fitness score [0..1].
* Supports wildcards and prefix matching.
*/
const FITNESS_TABLE: Record<string, Record<string, number>> = {
coding: {
"claude-sonnet": 0.95,
"claude-opus": 0.92,
"claude-haiku": 0.78,
"gpt-4o": 0.9,
"gpt-4o-mini": 0.8,
"gpt-4-turbo": 0.88,
o1: 0.93,
o3: 0.95,
"o4-mini": 0.88,
codex: 0.98,
"gemini-pro": 0.85,
"gemini-flash": 0.8,
"gemini-2.5-pro": 0.92,
"gemini-2.5-flash": 0.82,
"deepseek-coder": 0.9,
"deepseek-v3": 0.85,
"deepseek-r1": 0.88,
qwen: 0.78,
llama: 0.72,
mistral: 0.75,
mixtral: 0.77,
},
review: {
"claude-sonnet": 0.92,
"claude-opus": 0.95,
"claude-haiku": 0.7,
"gpt-4o": 0.88,
"gpt-4o-mini": 0.72,
o1: 0.9,
o3: 0.92,
"gemini-pro": 0.9,
"gemini-2.5-pro": 0.93,
"gemini-flash": 0.75,
"deepseek-r1": 0.85,
"deepseek-v3": 0.8,
},
planning: {
"claude-opus": 0.95,
"claude-sonnet": 0.9,
"gpt-4o": 0.88,
o1: 0.92,
o3: 0.95,
"gemini-2.5-pro": 0.93,
"gemini-pro": 0.88,
"deepseek-r1": 0.85,
},
analysis: {
"claude-opus": 0.95,
"claude-sonnet": 0.92,
"gemini-2.5-pro": 0.95,
"gemini-pro": 0.88,
"gpt-4o": 0.85,
o1: 0.9,
o3: 0.93,
"deepseek-r1": 0.88,
},
debugging: {
"claude-sonnet": 0.93,
"claude-opus": 0.9,
"gpt-4o": 0.88,
o1: 0.85,
"deepseek-coder": 0.9,
"deepseek-v3": 0.82,
"gemini-flash": 0.78,
codex: 0.92,
},
documentation: {
"claude-sonnet": 0.9,
"claude-opus": 0.88,
"gpt-4o": 0.92,
"gpt-4o-mini": 0.85,
"gemini-pro": 0.88,
"gemini-flash": 0.82,
"deepseek-v3": 0.78,
},
default: {
"claude-sonnet": 0.85,
"claude-opus": 0.85,
"gpt-4o": 0.85,
"gemini-pro": 0.8,
"deepseek-v3": 0.75,
"gemini-flash": 0.72,
},
};
// Wildcard patterns: model substrings → task type boosts
const WILDCARD_BOOSTS: Array<{ pattern: string; taskType: string; boost: number }> = [
{ pattern: "coder", taskType: "coding", boost: 0.15 },
{ pattern: "code", taskType: "coding", boost: 0.1 },
{ pattern: "fast", taskType: "coding", boost: 0.05 },
{ pattern: "thinking", taskType: "planning", boost: 0.1 },
{ pattern: "thinking", taskType: "analysis", boost: 0.1 },
];
/**
* Get task fitness score for a model × taskType combination.
* Returns 0.5 (neutral) if no mapping found.
*/
export function getTaskFitness(model: string, taskType: string): number {
const normalizedModel = model.toLowerCase();
const normalizedTask = taskType.toLowerCase();
const table = FITNESS_TABLE[normalizedTask] || FITNESS_TABLE.default;
// Direct match
for (const [pattern, score] of Object.entries(table)) {
if (normalizedModel.includes(pattern)) return score;
}
// Wildcard boost
let baseScore = 0.5;
for (const wc of WILDCARD_BOOSTS) {
if (normalizedModel.includes(wc.pattern) && normalizedTask === wc.taskType) {
baseScore += wc.boost;
}
}
return Math.min(1.0, baseScore);
}
/**
* Get all task types available.
*/
export function getTaskTypes(): string[] {
return Object.keys(FITNESS_TABLE).filter((k) => k !== "default");
}

View File

@@ -106,6 +106,20 @@ export function resetStats(): void {
// ── Detection ───────────────────────────────────────────────────────────────
interface BackgroundMessage {
role?: string;
content?: unknown;
}
interface BackgroundTaskBody {
messages?: BackgroundMessage[];
input?: BackgroundMessage[];
}
function toMessageArray(value: unknown): BackgroundMessage[] {
return Array.isArray(value) ? (value as BackgroundMessage[]) : [];
}
/**
* Check if a request is a background/utility task.
*
@@ -114,10 +128,11 @@ export function resetStats(): void {
* @returns {boolean} True if the request looks like a background task
*/
export function isBackgroundTask(
body: any,
body: BackgroundTaskBody | unknown,
headers: Record<string, string> | null = null
): boolean {
if (!body || typeof body !== "object") return false;
const typedBody = body as BackgroundTaskBody;
// 1. Check explicit header
if (headers) {
@@ -127,11 +142,13 @@ export function isBackgroundTask(
}
// 2. Check system prompt for background task patterns
const messages = body.messages || body.input || [];
const messages = toMessageArray(typedBody.messages ?? typedBody.input ?? []);
if (!Array.isArray(messages) || messages.length === 0) return false;
// Find system message
const systemMsg = messages.find((m: any) => m.role === "system" || m.role === "developer");
const systemMsg = messages.find(
(message: BackgroundMessage) => message.role === "system" || message.role === "developer"
);
if (!systemMsg) return false;
const systemContent =
@@ -148,7 +165,7 @@ export function isBackgroundTask(
// 3. Additional heuristic: background tasks typically have very few messages
// (system + 1-2 user messages)
const userMessages = messages.filter((m: any) => m.role === "user");
const userMessages = messages.filter((message: BackgroundMessage) => message.role === "user");
if (userMessages.length > 3) return false; // Too many turns for a background task
return true;

View File

@@ -221,7 +221,7 @@ function sortModelsByUsage(models, comboName) {
* @param {Object} options.log - Logger object
* @returns {Promise<Response>}
*/
/** @param {any} options */
/** @param {object} options */
export async function handleComboChat({
body,
combo,
@@ -263,7 +263,7 @@ export async function handleComboChat({
// For weighted + nested, select from original models then fallback sequentially
const selected = selectWeightedModel(models);
orderedModels = orderModelsForWeightedFallback(models, selected);
// But if any were nested, they are already resolved to flat
// If entries were nested, they are already resolved to flat
orderedModels = orderedModels.flatMap((m) => {
const combos = Array.isArray(allCombos) ? allCombos : allCombos?.combos || [];
const nested = combos.find((c) => c.name === m);
@@ -310,7 +310,8 @@ export async function handleComboChat({
const parsed = parseModel(modelStr);
const provider = parsed.provider || parsed.providerAlias || "unknown";
const profile = getProviderProfile(provider);
const breaker = getCircuitBreaker(`combo:${provider}`, {
const breakerKey = `combo:${modelStr}`;
const breaker = getCircuitBreaker(breakerKey, {
failureThreshold: profile.circuitBreakerThreshold,
resetTimeout: profile.circuitBreakerReset,
});
@@ -440,8 +441,7 @@ export async function handleComboChat({
// Early exit: check if all models have breaker OPEN
const allBreakersOpen = orderedModels.every((m) => {
const p = parseModel(m).provider || parseModel(m).providerAlias || "unknown";
return !getCircuitBreaker(`combo:${p}`).canExecute();
return !getCircuitBreaker(`combo:${m}`).canExecute();
});
// All models failed
@@ -532,7 +532,8 @@ async function handleRoundRobinCombo({
const parsed = parseModel(modelStr);
const provider = parsed.provider || parsed.providerAlias || "unknown";
const profile = getProviderProfile(provider);
const breaker = getCircuitBreaker(`combo:${provider}`, {
const breakerKey = `combo:${modelStr}`;
const breaker = getCircuitBreaker(breakerKey, {
failureThreshold: profile.circuitBreakerThreshold,
resetTimeout: profile.circuitBreakerReset,
});
@@ -694,8 +695,7 @@ async function handleRoundRobinCombo({
// Early exit: check if all models have breaker OPEN
const allBreakersOpen = orderedModels.every((m) => {
const p = parseModel(m).provider || parseModel(m).providerAlias || "unknown";
return !getCircuitBreaker(`combo:${p}`).canExecute();
return !getCircuitBreaker(`combo:${m}`).canExecute();
});
if (allBreakersOpen) {

View File

@@ -27,7 +27,7 @@ const DEFAULT_COMBO_CONFIG = {
* @param {string} [provider] - Optional provider to apply provider-level overrides
* @returns {Object} Resolved config
*/
export function resolveComboConfig(combo, settings, provider?: any) {
export function resolveComboConfig(combo, settings, provider?: string | null) {
const global = settings?.comboDefaults || {};
const providerOverride = provider ? settings?.providerOverrides?.[provider] || {} : {};
const comboConfig = combo?.config || {};

View File

@@ -4,8 +4,41 @@
* Provides API for reading metrics from the dashboard
*/
interface ModelMetrics {
requests: number;
successes: number;
failures: number;
totalLatencyMs: number;
lastStatus: "ok" | "error" | null;
lastUsedAt: string | null;
}
interface ComboMetricsEntry {
totalRequests: number;
totalSuccesses: number;
totalFailures: number;
totalFallbacks: number;
totalLatencyMs: number;
strategy: string;
lastUsedAt: string | null;
byModel: Record<string, ModelMetrics>;
}
interface ComboMetricsView extends ComboMetricsEntry {
avgLatencyMs: number;
successRate: number;
fallbackRate: number;
byModel: Record<
string,
ModelMetrics & {
avgLatencyMs: number;
successRate: number;
}
>;
}
// In-memory store
const metrics = new Map();
const metrics = new Map<string, ComboMetricsEntry>();
/**
* Record a combo request result
@@ -18,10 +51,15 @@ const metrics = new Map();
* @param {string} [options.strategy] - "priority" or "weighted"
*/
export function recordComboRequest(
comboName,
modelStr,
{ success, latencyMs, fallbackCount = 0, strategy = "priority" }
) {
comboName: string,
modelStr: string | null,
{
success,
latencyMs,
fallbackCount = 0,
strategy = "priority",
}: { success: boolean; latencyMs: number; fallbackCount?: number; strategy?: string }
): void {
if (!metrics.has(comboName)) {
metrics.set(comboName, {
totalRequests: 0,
@@ -35,7 +73,8 @@ export function recordComboRequest(
});
}
const combo: any = metrics.get(comboName);
const combo = metrics.get(comboName);
if (!combo) return;
combo.totalRequests++;
combo.totalLatencyMs += latencyMs;
combo.totalFallbacks += fallbackCount;
@@ -80,8 +119,8 @@ export function recordComboRequest(
* @param {string} comboName
* @returns {Object|null}
*/
export function getComboMetrics(comboName) {
const combo: any = metrics.get(comboName);
export function getComboMetrics(comboName: string): ComboMetricsView | null {
const combo = metrics.get(comboName);
if (!combo) return null;
return {
@@ -93,7 +132,7 @@ export function getComboMetrics(comboName) {
fallbackRate:
combo.totalRequests > 0 ? Math.round((combo.totalFallbacks / combo.totalRequests) * 100) : 0,
byModel: Object.fromEntries(
Object.entries(combo.byModel).map(([model, m]: [string, any]) => [
Object.entries(combo.byModel).map(([model, m]) => [
model,
{
...m,
@@ -109,8 +148,8 @@ export function getComboMetrics(comboName) {
* Get metrics for all combos
* @returns {Object} Map of comboName → metrics
*/
export function getAllComboMetrics() {
const result: Record<string, any> = {};
export function getAllComboMetrics(): Record<string, ComboMetricsView | null> {
const result: Record<string, ComboMetricsView | null> = {};
for (const [name] of metrics) {
result[name] = getComboMetrics(name);
}
@@ -120,13 +159,13 @@ export function getAllComboMetrics() {
/**
* Reset metrics for a specific combo
*/
export function resetComboMetrics(comboName) {
export function resetComboMetrics(comboName: string): void {
metrics.delete(comboName);
}
/**
* Reset all combo metrics
*/
export function resetAllComboMetrics() {
export function resetAllComboMetrics(): void {
metrics.clear();
}

View File

@@ -34,7 +34,13 @@ export function getTokenLimit(provider, model = null) {
const lower = model.toLowerCase();
if (lower.includes("claude")) return DEFAULT_LIMITS.claude;
if (lower.includes("gemini")) return DEFAULT_LIMITS.gemini;
if (lower.includes("gpt") || lower.includes("o1") || lower.includes("o3") || lower.includes("o4")) return DEFAULT_LIMITS.openai;
if (
lower.includes("gpt") ||
lower.includes("o1") ||
lower.includes("o3") ||
lower.includes("o4")
)
return DEFAULT_LIMITS.openai;
}
return DEFAULT_LIMITS[provider] || DEFAULT_LIMITS.default;
}
@@ -51,7 +57,10 @@ export function getTokenLimit(provider, model = null) {
* @param {object} options - { provider?, model?, maxTokens?, reserveTokens? }
* @returns {{ body: object, compressed: boolean, stats: object }}
*/
export function compressContext(body, options: any = {}) {
export function compressContext(
body,
options: { provider?: string; model?: string; maxTokens?: number; reserveTokens?: number } = {}
) {
if (!body || !body.messages || !Array.isArray(body.messages)) {
return { body, compressed: false, stats: {} };
}
@@ -123,7 +132,11 @@ function trimToolMessages(messages, maxChars) {
return {
...msg,
content: msg.content.map((block) => {
if (block.type === "tool_result" && typeof block.content === "string" && block.content.length > maxChars) {
if (
block.type === "tool_result" &&
typeof block.content === "string" &&
block.content.length > maxChars
) {
return { ...block, content: block.content.slice(0, maxChars) + "\n... [truncated]" };
}
return block;

View File

@@ -156,7 +156,12 @@ export function getProviderFallbackCount(provider) {
}
// Build provider URL
export function buildProviderUrl(provider, model, stream = true, options: any = {}) {
export function buildProviderUrl(
provider,
model,
stream = true,
options: { baseUrl?: string; baseUrlIndex?: number } = {}
) {
if (isOpenAICompatible(provider)) {
const apiType = getOpenAICompatibleType(provider);
const baseUrl = options?.baseUrl || OPENAI_COMPATIBLE_DEFAULTS.baseUrl;

View File

@@ -13,14 +13,46 @@ import { parseRetryAfterFromBody, lockModel } from "./accountFallback.ts";
import { getProviderCategory } from "../config/providerRegistry.ts";
import { DEFAULT_API_LIMITS } from "../config/constants.ts";
interface LearnedLimitEntry {
provider: string;
connectionId: string;
lastUpdated: number;
limit?: number;
remaining?: number;
minTime?: number;
}
interface LimiterUpdateSettings {
minTime: number;
reservoir?: number | null;
reservoirRefreshAmount?: number | null;
reservoirRefreshInterval?: number | null;
}
type JsonRecord = Record<string, unknown>;
function toRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
}
function toNumber(value: unknown, fallback = 0): number {
const parsed =
typeof value === "number"
? value
: typeof value === "string" && value.trim().length > 0
? Number(value)
: Number.NaN;
return Number.isFinite(parsed) ? parsed : fallback;
}
// Store limiters keyed by "provider:connectionId" (and optionally ":model")
const limiters = new Map();
const limiters = new Map<string, Bottleneck>();
// Store connections that have rate limit protection enabled
const enabledConnections = new Set();
const enabledConnections = new Set<string>();
// Store learned limits for persistence (debounced)
const learnedLimits: Record<string, any> = {};
const learnedLimits: Record<string, LearnedLimitEntry> = {};
let persistTimer: ReturnType<typeof setTimeout> | null = null;
const PERSIST_DEBOUNCE_MS = 60_000; // Debounce persistence to every 60s max
@@ -49,23 +81,51 @@ export async function initializeRateLimits() {
const connections = await getProviderConnections();
let explicitCount = 0;
let autoCount = 0;
let customCount = 0;
for (const conn of connections) {
if (conn.rateLimitProtection) {
for (const connRaw of connections as unknown[]) {
const conn = toRecord(connRaw);
const connectionId = typeof conn.id === "string" ? conn.id : "";
const provider = typeof conn.provider === "string" ? conn.provider : "";
const isActive = conn.isActive === true;
const rateLimitProtection = conn.rateLimitProtection === true;
const customRpm = toNumber(conn.customRpm, 0);
const customTpm = toNumber(conn.customTpm, 0);
if (!connectionId || !provider) continue;
// Custom rpm/tpm configured — enable rate limiting with user-defined values (#198)
if (customRpm > 0 || customTpm > 0) {
enabledConnections.add(connectionId);
customCount++;
const key = `${provider}:${connectionId}`;
const rpm = customRpm > 0 ? customRpm : DEFAULT_API_LIMITS.requestsPerMinute;
const minTime = Math.max(0, Math.floor(60000 / rpm) - 10);
if (!limiters.has(key)) {
limiters.set(
key,
new Bottleneck({
maxConcurrent: DEFAULT_API_LIMITS.concurrentRequests,
minTime,
reservoir: rpm,
reservoirRefreshAmount: rpm,
reservoirRefreshInterval: 60 * 1000,
id: key,
})
);
}
} else if (rateLimitProtection) {
// Explicitly enabled by user
enabledConnections.add(conn.id);
enabledConnections.add(connectionId);
explicitCount++;
} else if (
conn.provider &&
getProviderCategory(conn.provider) === "apikey" &&
conn.isActive
) {
} else if (getProviderCategory(provider) === "apikey" && isActive) {
// Auto-enable for API key providers (safety net)
enabledConnections.add(conn.id);
enabledConnections.add(connectionId);
autoCount++;
// Create a pre-configured limiter with conservative defaults
const key = `${conn.provider}:${conn.id}`;
const key = `${provider}:${connectionId}`;
if (!limiters.has(key)) {
limiters.set(
key,
@@ -82,9 +142,9 @@ export async function initializeRateLimits() {
}
}
if (explicitCount > 0 || autoCount > 0) {
if (explicitCount > 0 || autoCount > 0 || customCount > 0) {
console.log(
`🛡️ [RATE-LIMIT] Loaded ${explicitCount} explicit + ${autoCount} auto-enabled (API key) protection(s)`
`🛡️ [RATE-LIMIT] Loaded ${explicitCount} explicit + ${autoCount} auto-enabled + ${customCount} custom rpm/tpm protection(s)`
);
}
@@ -160,7 +220,7 @@ function getLimiter(provider, connectionId, model = null) {
* @param {string} connectionId - Connection ID
* @param {string} model - Model name (optional, for per-model limits)
* @param {Function} fn - The async function to execute (e.g., executor.execute)
* @returns {Promise<any>} Result of fn()
* @returns {Promise<unknown>} Result of fn()
*/
export async function withRateLimit(provider, connectionId, model, fn) {
if (!enabledConnections.has(connectionId)) {
@@ -301,7 +361,7 @@ export function updateFromHeaders(provider, connectionId, headers, status, model
// Calculate optimal minTime from RPM limit
const minTime = Math.max(0, Math.floor(60000 / limit) - 10); // Small buffer
const updates: Record<string, any> = { minTime };
const updates: LimiterUpdateSettings = { minTime };
// If remaining is low (< 10% of limit), set reservoir to throttle immediately
if (!isNaN(remaining)) {
@@ -359,7 +419,7 @@ export function getRateLimitStatus(provider, connectionId) {
* Get all active limiters status (for dashboard overview)
*/
export function getAllRateLimitStatus() {
const result: Record<string, any> = {};
const result: Record<string, { queued: number; running: number; executing: number }> = {};
for (const [key, limiter] of limiters) {
const counts = limiter.counts();
result[key] = {
@@ -383,7 +443,11 @@ export function getLearnedLimits() {
/**
* Record a learned limit for debounced persistence.
*/
function recordLearnedLimit(provider: string, connectionId: string, limits: any) {
function recordLearnedLimit(
provider: string,
connectionId: string,
limits: Partial<Omit<LearnedLimitEntry, "provider" | "connectionId" | "lastUpdated">>
) {
const key = `${provider}:${connectionId}`;
learnedLimits[key] = {
...limits,
@@ -417,23 +481,38 @@ async function loadPersistedLimits() {
const { getSettings } = await import("@/lib/db/settings");
const settings = await getSettings();
const raw = settings?.learnedRateLimits;
if (!raw) return;
if (typeof raw !== "string" || raw.trim().length === 0) return;
const parsed = JSON.parse(raw);
const parsed = toRecord(JSON.parse(raw) as unknown);
let count = 0;
for (const [key, data] of Object.entries<any>(parsed)) {
for (const [key, dataRaw] of Object.entries(parsed)) {
const data = toRecord(dataRaw);
const lastUpdated = toNumber(data.lastUpdated, 0);
// Skip stale entries (older than 24h)
if (data.lastUpdated && Date.now() - data.lastUpdated > 24 * 60 * 60 * 1000) continue;
if (lastUpdated > 0 && Date.now() - lastUpdated > 24 * 60 * 60 * 1000) continue;
learnedLimits[key] = data;
const connectionId = typeof data.connectionId === "string" ? data.connectionId : "";
const provider = typeof data.provider === "string" ? data.provider : "";
const limit = toNumber(data.limit, 0);
const remaining = toNumber(data.remaining, 0);
const minTime = toNumber(data.minTime, 0);
learnedLimits[key] = {
provider,
connectionId,
lastUpdated,
...(limit > 0 ? { limit } : {}),
...(remaining >= 0 ? { remaining } : {}),
...(minTime >= 0 ? { minTime } : {}),
};
// Apply to limiter if it exists and has rate limit enabled
if (data.connectionId && enabledConnections.has(data.connectionId)) {
if (connectionId && enabledConnections.has(connectionId)) {
const limiter = limiters.get(key);
if (limiter && data.limit) {
const minTime = data.minTime || Math.max(0, Math.floor(60000 / data.limit) - 10);
limiter.updateSettings({ minTime });
if (limiter && limit > 0) {
const inferredMinTime = minTime || Math.max(0, Math.floor(60000 / limit) - 10);
limiter.updateSettings({ minTime: inferredMinTime });
count++;
}
}

View File

@@ -116,8 +116,10 @@ export function acquire(modelStr, { maxConcurrency = 3, timeoutMs = 30000 } = {}
// Remove from queue on timeout
const idx = gate.queue.findIndex((item) => item.timer === timer);
if (idx !== -1) gate.queue.splice(idx, 1);
const err = new Error(`Semaphore timeout after ${timeoutMs}ms for ${modelStr}`);
(err as any).code = "SEMAPHORE_TIMEOUT";
const err = new Error(`Semaphore timeout after ${timeoutMs}ms for ${modelStr}`) as Error & {
code?: string;
};
err.code = "SEMAPHORE_TIMEOUT";
reject(err);
}, timeoutMs);

View File

@@ -34,6 +34,33 @@ const MODELS_WITHOUT_SYSTEM_ROLE = [
"ernie-", // Baidu ERNIE models
];
interface MessageContentPart {
type?: string;
text?: string;
[key: string]: unknown;
}
interface NormalizedMessage {
role?: string;
content?: unknown;
[key: string]: unknown;
}
function extractTextFromContent(content: unknown): string {
if (typeof content === "string") return content;
if (!Array.isArray(content)) return "";
return content
.filter(
(part): part is MessageContentPart =>
!!part &&
typeof part === "object" &&
"type" in part &&
(part as MessageContentPart).type === "text"
)
.map((part) => (typeof part.text === "string" ? part.text : ""))
.join("\n");
}
/**
* Check if a provider+model combo supports the system role.
*/
@@ -57,14 +84,17 @@ function supportsSystemRole(provider: string, model: string): boolean {
* @param targetFormat - The target format (e.g., "openai", "claude", "gemini")
* @returns Modified messages array
*/
export function normalizeDeveloperRole(messages: any[], targetFormat: string): any[] {
export function normalizeDeveloperRole(
messages: NormalizedMessage[] | unknown,
targetFormat: string
): NormalizedMessage[] | unknown {
if (!Array.isArray(messages)) return messages;
// For OpenAI format, keep developer role as-is (it's valid)
// For all other formats, convert developer → system
if (targetFormat === "openai") return messages;
return messages.map((msg) => {
return messages.map((msg: NormalizedMessage) => {
if (msg.role === "developer") {
return { ...msg, role: "system" };
}
@@ -82,49 +112,44 @@ export function normalizeDeveloperRole(messages: any[], targetFormat: string): a
* @param model - Model name
* @returns Modified messages array
*/
export function normalizeSystemRole(messages: any[], provider: string, model: string): any[] {
export function normalizeSystemRole(
messages: NormalizedMessage[] | unknown,
provider: string,
model: string
): NormalizedMessage[] | unknown {
if (!Array.isArray(messages) || messages.length === 0) return messages;
if (supportsSystemRole(provider, model)) return messages;
// Extract system messages
const systemMessages = messages.filter((m) => m.role === "system" || m.role === "developer");
const systemMessages = messages.filter(
(message: NormalizedMessage) => message.role === "system" || message.role === "developer"
);
if (systemMessages.length === 0) return messages;
// Build system content string
const systemContent = systemMessages
.map((m) => {
if (typeof m.content === "string") return m.content;
if (Array.isArray(m.content)) {
return m.content
.filter((c: any) => c.type === "text")
.map((c: any) => c.text)
.join("\n");
}
return "";
})
.map((message: NormalizedMessage) => extractTextFromContent(message.content))
.filter(Boolean)
.join("\n\n");
if (!systemContent) {
return messages.filter((m) => m.role !== "system" && m.role !== "developer");
return messages.filter(
(message: NormalizedMessage) => message.role !== "system" && message.role !== "developer"
);
}
// Remove system messages and merge into first user message
const nonSystemMessages = messages.filter((m) => m.role !== "system" && m.role !== "developer");
const nonSystemMessages = messages.filter(
(message: NormalizedMessage) => message.role !== "system" && message.role !== "developer"
);
// Find first user message and prepend system content
const firstUserIdx = nonSystemMessages.findIndex((m) => m.role === "user");
const firstUserIdx = nonSystemMessages.findIndex(
(message: NormalizedMessage) => message.role === "user"
);
if (firstUserIdx >= 0) {
const userMsg = nonSystemMessages[firstUserIdx];
const userContent =
typeof userMsg.content === "string"
? userMsg.content
: Array.isArray(userMsg.content)
? userMsg.content
.filter((c: any) => c.type === "text")
.map((c: any) => c.text)
.join("\n")
: "";
const userContent = extractTextFromContent(userMsg.content);
nonSystemMessages[firstUserIdx] = {
...userMsg,
@@ -152,11 +177,11 @@ export function normalizeSystemRole(messages: any[], provider: string, model: st
* @returns Normalized messages array
*/
export function normalizeRoles(
messages: any[],
messages: NormalizedMessage[] | unknown,
provider: string,
model: string,
targetFormat: string
): any[] {
): NormalizedMessage[] | unknown {
if (!Array.isArray(messages)) return messages;
// Step 1: Normalize developer → system (for non-OpenAI formats)

View File

@@ -7,9 +7,34 @@
import { createHash } from "node:crypto";
interface SessionEntry {
createdAt: number;
lastActive: number;
requestCount: number;
connectionId: string | null;
}
interface SessionFingerprintOptions {
provider?: string;
connectionId?: string;
}
interface SessionMessage {
role?: string;
content?: unknown;
}
interface SessionBody {
model?: string;
system?: unknown;
tools?: Array<{ name?: string; function?: { name?: string } }>;
messages?: SessionMessage[];
input?: SessionMessage[];
}
// In-memory session store with metadata
// key: sessionId → { createdAt, lastActive, requestCount, connectionId? }
const sessions = new Map();
const sessions = new Map<string, SessionEntry>();
// Auto-cleanup sessions older than 30 minutes
const SESSION_TTL_MS = 30 * 60 * 1000;
@@ -36,8 +61,12 @@ _cleanupTimer.unref();
* @param {object} [options] - Extra context
* @returns {string} Session ID (hex hash)
*/
export function generateSessionId(body, options: any = {}) {
const parts = [];
export function generateSessionId(
body: SessionBody | null | undefined,
options: SessionFingerprintOptions = {}
): string | null {
if (!body || typeof body !== "object") return null;
const parts: string[] = [];
// Model contributes to fingerprint
if (body.model) parts.push(`model:${body.model}`);
@@ -79,7 +108,7 @@ export function generateSessionId(body, options: any = {}) {
/**
* Touch or create a session
*/
export function touchSession(sessionId, connectionId = null) {
export function touchSession(sessionId: string | null, connectionId: string | null = null): void {
if (!sessionId) return;
const existing = sessions.get(sessionId);
if (existing) {
@@ -99,7 +128,7 @@ export function touchSession(sessionId, connectionId = null) {
/**
* Get session info (for sticky routing decisions)
*/
export function getSessionInfo(sessionId) {
export function getSessionInfo(sessionId: string | null): SessionEntry | null {
if (!sessionId) return null;
const entry = sessions.get(sessionId);
if (!entry) return null;
@@ -113,7 +142,7 @@ export function getSessionInfo(sessionId) {
/**
* Get the bound connection for a session (sticky routing)
*/
export function getSessionConnection(sessionId) {
export function getSessionConnection(sessionId: string | null): string | null {
const info = getSessionInfo(sessionId);
return info?.connectionId || null;
}
@@ -121,16 +150,16 @@ export function getSessionConnection(sessionId) {
/**
* Get session count (for dashboard)
*/
export function getActiveSessionCount() {
export function getActiveSessionCount(): number {
return sessions.size;
}
/**
* Get all active sessions (for dashboard)
*/
export function getActiveSessions() {
export function getActiveSessions(): Array<SessionEntry & { sessionId: string; ageMs: number }> {
const now = Date.now();
const result = [];
const result: Array<SessionEntry & { sessionId: string; ageMs: number }> = [];
for (const [id, entry] of sessions) {
if (now - entry.lastActive <= SESSION_TTL_MS) {
result.push({ sessionId: id, ...entry, ageMs: now - entry.createdAt });
@@ -142,23 +171,24 @@ export function getActiveSessions() {
/**
* Clear all sessions (for testing)
*/
export function clearSessions() {
export function clearSessions(): void {
sessions.clear();
}
// ─── Internal Helpers ───────────────────────────────────────────────────────
function hashShort(text) {
function hashShort(text: string): string {
return createHash("sha256").update(text).digest("hex").slice(0, 8);
}
function extractSystemPrompt(body) {
function extractSystemPrompt(body: SessionBody | null | undefined): string | null {
if (!body || typeof body !== "object") return null;
// Claude format: body.system
if (body.system) {
return typeof body.system === "string" ? body.system : JSON.stringify(body.system);
}
// OpenAI format: messages[0].role === "system"
if (body.messages && Array.isArray(body.messages)) {
if (Array.isArray(body.messages)) {
const sys = body.messages.find((m) => m.role === "system" || m.role === "developer");
if (sys) {
return typeof sys.content === "string" ? sys.content : JSON.stringify(sys.content);
@@ -167,7 +197,8 @@ function extractSystemPrompt(body) {
return null;
}
function extractFirstUserMessage(body) {
function extractFirstUserMessage(body: SessionBody | null | undefined): string | null {
if (!body || typeof body !== "object") return null;
const messages = body.messages || body.input || [];
if (!Array.isArray(messages)) return null;
for (const msg of messages) {

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