Compare commits

..

37 Commits

Author SHA1 Message Date
Diego Rodrigues de Sa e Souza c4cdb52fe6 fix(ci): reference NPM_TOKEN environment for environment-scoped secrets (#18)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-02-14 04:31:26 -03:00
Diego Rodrigues de Sa e Souza 15ec100dcb fix(ci): write .npmrc explicitly for npm auth — support both secrets and vars (#17)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-02-14 04:26:05 -03:00
Diego Rodrigues de Sa e Souza d401ef40f1 fix(ci): support NPM_TOKEN from both secrets and vars, remove --provenance (#16)
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-02-14 04:22:00 -03:00
Diego Rodrigues de Sa e Souza 92b4c59fec feat(npm): add npm package publishing with CLI entry point (#15)
- Add bin/omniroute.mjs CLI with banner, auto-open browser, graceful shutdown
- Add scripts/prepublish.mjs to build Next.js standalone into app/
- Add .github/workflows/npm-publish.yml for automated publish on release
- Update package.json: name=omniroute, bin, files, engines, keywords, prepublishOnly
- Add output: 'standalone' to next.config.mjs
- Add MIT LICENSE
- Update .npmignore and .gitignore for app/ build artifact

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-02-14 04:14:14 -03:00
Diego Rodrigues de Sa e Souza 4f0155eb4a Create SECURITY.md for security policy
Added a security policy document outlining supported versions and vulnerability reporting.
2026-02-13 23:21:18 -03:00
Diego Rodrigues de Sa e Souza e544d81624 Merge pull request #13 from diegosouzapw/dependabot/npm_and_yarn/qs-6.14.2
deps: bump qs from 6.14.1 to 6.14.2
2026-02-13 23:19:59 -03:00
Diego Rodrigues de Sa e Souza b8c50cc62d Merge pull request #14 from diegosouzapw/feature/new-endpoints-and-providers
feat: add new endpoints (rerank, audio, moderations) and providers (Hyperbolic, Deepgram, AssemblyAI, NanoBanana)
2026-02-13 22:58:15 -03:00
diegosouzapw c6000ecc8e feat(providers): add new endpoints (rerank, audio, moderations) and providers (Hyperbolic, Deepgram, AssemblyAI, NanoBanana)
- Add /v1/rerank endpoint with Cohere, Together, NVIDIA, Fireworks
- Add /v1/audio/transcriptions with OpenAI, Groq, Deepgram, AssemblyAI
- Add /v1/audio/speech with OpenAI, Hyperbolic, Deepgram
- Add /v1/moderations with OpenAI
- Add Hyperbolic as chat provider (8 models, OpenAI-compatible)
- Add Hyperbolic image generation (SDXL, SD2, FLUX)
- Add NanoBanana image generation (Flash + Pro via nanobananaapi.ai)
- Add Deepgram STT (Nova 3, Nova 2) with Token auth and binary format
- Add AssemblyAI STT (Universal 3 Pro) with async upload-poll workflow
- Add Deepgram TTS (Aura voices) and Hyperbolic TTS (Melo)
- Update EndpointPageClient to show 7 endpoint sections
- Update /v1/models to return type/subtype for all model categories
- Fix build: remove output:standalone from next.config.mjs
2026-02-13 22:57:32 -03:00
diegosouzapw 4e6ba7d9cc docs: Restructure changelog to Keep a Changelog format and add entries for model selector autocomplete and OpenAPI specification. 2026-02-13 21:35:06 -03:00
diegosouzapw c0c2816671 feat: Implement model selection and dynamic model fetching in ChatTesterMode and TestBenchMode. 2026-02-13 21:11:19 -03:00
diegosouzapw 80cc76d531 fix: Ensure server port is free before startup by killing existing processes. 2026-02-13 20:59:11 -03:00
dependabot[bot] af1ffab63d deps: bump qs from 6.14.1 to 6.14.2
Bumps [qs](https://github.com/ljharb/qs) from 6.14.1 to 6.14.2.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.1...v6.14.2)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 23:58:54 +00:00
diegosouzapw 7ff1ba978a feat: add OpenAPI specification, generate package-lock, and remove various SVG assets from the public directory. 2026-02-13 20:57:44 -03:00
diegosouzapw d43bbf77fe feat: Enhance restart.sh to include clean build, robust server startup with health check, graceful shutdown, and real-time log tailing. 2026-02-13 20:47:12 -03:00
Diego Rodrigues de Sa e Souza 4e5dc6a80b Merge pull request #12 from diegosouzapw/fix/select-dark-theme
fix(ui): fix Select dropdown dark theme inconsistency
2026-02-13 19:22:36 -03:00
diegosouzapw 0be2852af2 fix(ui): fix Select dropdown dark theme inconsistency
Use bg-surface (theme-aware) instead of bg-white for select and
option elements. Prevents white dropdown panels in dark mode.
2026-02-13 19:22:09 -03:00
Diego Rodrigues de Sa e Souza b3c36ed2ca Merge pull request #11 from diegosouzapw/chore/rebrand-ui-omniroute
chore(ui): rebrand to OmniRoute
2026-02-13 19:14:19 -03:00
diegosouzapw 2b1b8e4539 chore(ui): rebrand to OmniRoute
- Sidebar: 'Endpoint Proxy' → 'OmniRoute'
- Page title: 'OmniRoute — AI Gateway for Multi-Provider LLMs'
- Description updated across layout and config
2026-02-13 19:13:57 -03:00
Diego Rodrigues de Sa e Souza 8b7b50f6fb Merge pull request #10 from diegosouzapw/fix/cloud-sync-404-spam
fix(sync): disable cloud sync and truncate error logs
2026-02-13 19:01:53 -03:00
diegosouzapw 9c0ba39ed6 fix(sync): disable cloud sync and truncate error logs
CLOUD_URL was pointing to omniroute.com which doesn't have a /sync/
endpoint, causing repeated 404 HTML dumps in console logs.

- Clear CLOUD_URL to disable cloud sync until server is ready
- Truncate sync error text to 200 chars to prevent HTML spam in logs
2026-02-13 19:01:31 -03:00
Diego Rodrigues de Sa e Souza 801a050995 Merge pull request #9 from diegosouzapw/feat/enable-socks5-proxy
feat(proxy): enable SOCKS5 proxy support by default
2026-02-13 18:30:08 -03:00
diegosouzapw e7532d7189 feat(proxy): enable SOCKS5 proxy support by default
SOCKS5 was already fully implemented in both backend
(proxyDispatcher.js) and frontend (ProxyConfigModal.js).
Enable the feature flags to show SOCKS5 option in the UI.
2026-02-13 18:29:49 -03:00
Diego Rodrigues de Sa e Souza 7349052b33 Merge pull request #8 from diegosouzapw/fix/test-token-corruption
fix(oauth): prevent connection test from corrupting valid tokens
2026-02-13 18:09:52 -03:00
diegosouzapw 0af22a558f fix(oauth): prevent connection test from corrupting valid tokens
Only attempt token refresh on 401/403 during connection tests when
the token is actually expired (isTokenExpired). Previously, any 401/403
triggered an aggressive refresh that could overwrite valid tokens when
the upstream returned transient errors (rate-limiting, etc.).

Fixes Cline, Qwen, and iFlow losing authentication after tests.
2026-02-13 18:09:28 -03:00
Diego Rodrigues de Sa e Souza 3206583299 Merge pull request #7 from diegosouzapw/fix/iflow-secret-env-sync
chore(env): sync .env.example with current .env structure
2026-02-13 17:47:58 -03:00
diegosouzapw 575bda7375 chore(env): sync .env.example with current .env structure
Add missing Storage (SQLite) section, INSTANCE_NAME, and
align all sections with the actual .env file.
2026-02-13 17:47:38 -03:00
Diego Rodrigues de Sa e Souza b3cde151c3 Merge pull request #6 from diegosouzapw/fix/oauth-upsert-broadened
fix(oauth): broaden upsert to match any existing connection
2026-02-13 17:30:16 -03:00
diegosouzapw b7e757f3ba fix(oauth): broaden upsert to match any existing connection
Remove test_status restriction from the no-email upsert fallback.
Now matches any existing OAuth connection for the same provider
(not just failed ones), preventing duplicates regardless of status.
2026-02-13 17:29:51 -03:00
Diego Rodrigues de Sa e Souza 81a78e8733 Merge pull request #5 from diegosouzapw/fix/oauth-reauth-upsert
fix(oauth): prevent duplicate connections on re-authentication
2026-02-13 17:23:19 -03:00
diegosouzapw fbac38b2b5 fix(oauth): prevent duplicate connections on re-authentication
For providers that don't return email (e.g. Codex), re-authenticating
always created a new 'Account N' entry because the upsert check in
createProviderConnection only matched by email.

Added fallback: when no email is available, find the most recent
auth_failed/refresh_failed connection for the same provider and update
it instead of creating a duplicate.
2026-02-13 17:22:50 -03:00
Diego Rodrigues de Sa e Souza f5898d3898 Merge pull request #3 from diegosouzapw/dependabot/npm_and_yarn/development-55a9f41e4a
deps: bump eslint from 9.39.2 to 10.0.0 in the development group
2026-02-13 16:51:58 -03:00
Diego Rodrigues de Sa e Souza 75e9648d06 Merge pull request #2 from diegosouzapw/dependabot/github_actions/actions/github-script-8
build(deps): bump actions/github-script from 7 to 8
2026-02-13 16:51:25 -03:00
Diego Rodrigues de Sa e Souza 878277edc9 Merge pull request #4 from diegosouzapw/feature/versioning-and-model-import
feat(versioning): set initial version to 0.0.1 and restore dynamic model import
2026-02-13 16:50:59 -03:00
diegosouzapw 50fc931086 feat(versioning): set initial version to 0.0.1 and restore dynamic model import
- Set package.json version to 0.0.1 (initial OmniRoute release)
- Set open-sse/package.json version to 0.0.1
- Restore 'Import from /models' button for standard providers (openai, gemini, deepseek, etc.)
- Add handleImportModels function to ProviderDetailPage
2026-02-13 16:49:06 -03:00
dependabot[bot] 172461863e deps: bump eslint from 9.39.2 to 10.0.0 in the development group
Bumps the development group with 1 update: [eslint](https://github.com/eslint/eslint).


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

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:31:36 +00:00
dependabot[bot] 79e10c9a41 build(deps): bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-13 19:30:25 +00:00
diegosouzapw 699329944e feat: initial OmniRoute release (rebranded from 9router)
This project is inspired by and originally forked from 9router by decolua
(https://github.com/decolua/9router).

Full rebrand: 9router → OmniRoute across all source code, configuration,
Docker, documentation, and assets.
2026-02-13 16:29:27 -03:00
960 changed files with 12346 additions and 244497 deletions
+54
View File
@@ -0,0 +1,54 @@
---
description: Git workflow — NEVER commit directly to main. Always use feature branches.
---
# Git Workflow
## ⚠️ CRITICAL RULE: NEVER commit directly to `main`
## Steps
1. **Before starting any work**, create a feature branch from `main`:
```bash
git checkout main && git pull origin main
git checkout -b feature/<feature-name>
```
2. **During development**, commit to the feature branch:
```bash
git add -A && git commit -m "<type>(<scope>): <description>"
```
3. **Before pushing**, verify the build passes:
```bash
npm run build
```
4. **When the feature is complete and verified**, push the branch and STOP:
```bash
git push origin feature/<feature-name>
```
5. **DO NOT** create a PR, merge, or push to `main`. Let the user handle that.
## Branch naming convention
- `feature/<name>` — new features
- `fix/<name>` — bugfixes
- `refactor/<name>` — refactoring
- `docker/<name>` — Docker / infrastructure changes
- `style/<name>` — UI / CSS changes
## Commit types
- `feat` — new feature
- `fix` — bugfix
- `refactor` — code refactoring
- `style` — UI / CSS changes
- `docker` — Docker / infrastructure
- `docs` — documentation
- `chore` — maintenance
-55
View File
@@ -1,55 +0,0 @@
---
description: Deploy the latest OmniRoute code to the Akamai VPS (69.164.221.35) via npm
---
# Deploy to VPS Workflow
Deploy OmniRoute to the production VPS using Node.js + PM2 (no Docker).
**VPS:** `69.164.221.35` (Akamai, Ubuntu 24.04, 1GB RAM + 2.5GB swap)
**App path:** `/opt/omniroute-app`
**Process manager:** PM2 (`omniroute`)
**Port:** `20128`
## Steps
### 1. Push to GitHub
Ensure all changes are committed and pushed:
```bash
git push origin main
```
### 2. SSH into VPS, pull latest code, rebuild, and restart
// turbo-all
```bash
ssh root@69.164.221.35 "
cd /opt/omniroute-app &&
git fetch origin &&
git reset --hard origin/main &&
export NODE_OPTIONS='--max-old-space-size=1536' &&
npm install --no-audit --no-fund &&
npm run build &&
pm2 restart omniroute &&
pm2 save &&
echo '✅ Deploy complete!'
"
```
### 3. Verify the deployment
```bash
ssh root@69.164.221.35 "pm2 list && curl -s -o /dev/null -w 'HTTP %{http_code}' http://localhost:20128/"
```
Expected: PM2 shows `online`, HTTP returns `307` (redirect to login).
## Notes
- The VPS has only 1GB RAM. `NODE_OPTIONS='--max-old-space-size=1536'` uses swap for the build.
- PM2 is configured with `pm2 startup` to auto-restart on reboot.
- The `.env` file is at `/opt/omniroute-app/.env` (copied from the old Docker setup at `/opt/omniroute/.env`).
- Nginx proxies `omniroute.online``localhost:20128`.
-78
View File
@@ -1,78 +0,0 @@
---
description: Create a new release, bump version up to 1.x.10 threshold, update changelog, and manage Pull Requests
---
# Generate Release Workflow
Bump version, finalize CHANGELOG, commit, tag, push, publish to npm, and create GitHub release.
## Steps
### 1. Determine new version
Check current version in `package.json` and increment the patch number:
```bash
grep '"version"' package.json
```
Version format: `1.x.y` — increment `y` for patch, `x` for minor (threshold: y=10 triggers x+1).
### 2. Finalize CHANGELOG.md
Replace `[Unreleased]` header with the new version and date:
```markdown
## [1.x.y] — YYYY-MM-DD
```
### 3. Bump version in package.json
```bash
sed -i 's/"version": "OLD"/"version": "NEW"/' package.json
```
### 4. Stage, commit, and tag
// turbo-all
```bash
git add -A
git commit -m "feat(release): vX.Y.Z — summary of changes"
git tag -a vX.Y.Z -m "Release vX.Y.Z — summary"
```
### 5. Push to GitHub
```bash
git push origin main
git push origin vX.Y.Z
```
### 6. Publish to npm
```bash
npm publish
```
Wait for completion (prepublishOnly runs `npm run build:cli` automatically).
### 7. Create GitHub release
```bash
gh release create vX.Y.Z --title "Release vX.Y.Z" --notes-file /tmp/release_notes.md
```
### 8. Deploy to VPS (if requested)
See `/deploy-vps` workflow for Akamai VPS or use npm for local VPS:
```bash
ssh root@<VPS_IP> "npm install -g omniroute@X.Y.Z && pm2 restart omniroute"
```
## Notes
- Always run `/update-docs` BEFORE this workflow (ensures CHANGELOG and README are current)
- The `prepublishOnly` script runs `npm run build:cli` automatically during `npm publish`
- After npm publish, verify with `npm info omniroute version`
-131
View File
@@ -1,131 +0,0 @@
---
description: Analyze open feature request issues, implement viable ones on dedicated branches, and respond to authors
---
# /implement-features — Feature Request Implementation Workflow
## Overview
Fetches open feature request issues, analyzes each against the current codebase, implements viable ones on dedicated branches, and responds to authors with results. Does NOT merge to main — leaves branches for author validation.
## Steps
### 1. Identify the Repository
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract owner/repo
### 2. Fetch Open Feature Request Issues
// turbo
- Run: `gh issue list --repo <owner>/<repo> --state open --limit 50 --json number,title,labels,body,comments,createdAt,author`
- Filter for issues that are feature requests (label `enhancement`/`feature`, or body describes new functionality, or previously classified as feature request)
- Sort by oldest first
### 3. Analyze Each Feature Request
For each feature request issue, perform a **two-level analysis**:
#### Level 1 — Viability Assessment
Ask yourself:
- Does this feature align with the project's goals and architecture?
- Is the request technically feasible with the current codebase?
- Does it duplicate existing functionality?
- Would it introduce breaking changes or security risks?
- Is there enough detail to implement it?
**Verdict options:**
1.**VIABLE** — Makes sense, enough detail to implement → Go to Level 2
2.**NEEDS MORE INFO** — Good idea but insufficient detail → Post comment asking for specifics
3.**NOT VIABLE** — Doesn't fit the project or is fundamentally flawed → Post comment explaining why, close issue
#### Level 2 — Implementation (only for VIABLE features)
1. **Research** — Read all related source files to understand the current architecture
2. **Design** — Plan the implementation, filling gaps in the original request
3. **Create branch** — Name format: `feat/issue-<NUMBER>-<short-slug>`
```bash
git checkout main
git pull origin main
git checkout -b feat/issue-<NUMBER>-<short-slug>
```
4. **Implement** — Build the complete solution following project patterns
5. **Build** — Run `npm run build` to verify compilation
6. **Commit** — Commit with: `feat: <description> (#<NUMBER>)`
7. **Push** — Push the branch: `git push -u origin feat/issue-<NUMBER>-<short-slug>`
8. **Return to main** — `git checkout main`
### 4. Respond to Authors
#### For VIABLE (implemented) features:
// turbo
Post a comment on the issue:
````markdown
## ✅ Feature Implemented!
Hi @<author>! We've analyzed your request and implemented it on a dedicated branch.
**Branch:** `feat/issue-<NUMBER>-<short-slug>`
### What was implemented:
- <bullet list of what was done>
### How to try it:
```bash
git fetch origin
git checkout feat/issue-<NUMBER>-<short-slug>
npm install && npm run dev
```
````
### Next steps:
1. **Test it** — Please verify it works as you expected
2. **Want to improve it?** — You're welcome to contribute! Just:
```bash
git checkout feat/issue-<NUMBER>-<short-slug>
# Make your improvements
git add -A && git commit -m "improve: <your changes>"
git push origin feat/issue-<NUMBER>-<short-slug>
```
Then open a Pull Request from your branch to `main` 🎉
3. **Not quite right?** — Let us know in this issue what needs to change
Looking forward to your feedback! 🚀
```
#### For NEEDS MORE INFO:
// turbo
Post a comment asking for specific missing details needed to implement, e.g.:
- "Could you describe the exact behavior when X happens?"
- "Which API endpoints should be affected?"
- "Should this apply to all providers or only specific ones?"
Add the context of WHY you need each piece of information.
#### For NOT VIABLE:
// turbo
Post a polite comment explaining why the feature doesn't fit at this time:
- If the idea is decent but timing is wrong: "This is an interesting idea, but it doesn't align with our current priorities. Feel free to open a new issue with more details if you'd like us to reconsider."
- If fundamentally flawed: Explain the technical or architectural reasons why it won't work, suggest alternatives if possible.
- Close the issue after posting the comment.
### 5. Summary Report
Present a summary report to the user via `notify_user`:
| Issue | Title | Verdict | Branch / Action |
|---|---|---|---|
| #N | Title | ✅ Implemented | `feat/issue-N-slug` |
| #N | Title | ❓ Needs Info | Comment posted |
| #N | Title | ❌ Not Viable | Closed with explanation |
```
-50
View File
@@ -1,50 +0,0 @@
---
description: How to respond to GitHub issues with insufficient information
---
# Issue Triage Workflow
Respond to GitHub issues that need more information before they can be investigated.
## Steps
### 1. Identify issues needing triage
```bash
gh issue list --state open --limit 20
```
### 2. Evaluate each issue
Check if the issue has:
- Clear reproduction steps
- Environment details (OS, Node.js version, OmniRoute version)
- Error logs/screenshots
- Expected vs actual behavior
### 3. Respond with triage template
For issues missing information:
```markdown
Thank you for reporting this issue! To help us investigate, please provide:
1. **OmniRoute version**: (`omniroute --version`)
2. **Node.js version**: (`node --version`)
3. **Operating system**: (e.g., Ubuntu 24.04, macOS 15, Windows 11)
4. **Installation method**: (npm, Docker, source)
5. **Steps to reproduce**: (exact commands/actions that trigger the issue)
6. **Error logs**: (paste relevant logs from the console)
7. **Expected behavior**: (what should happen)
This will help us debug and resolve your issue faster. 🙏
```
### 4. Label the issue
Add appropriate labels: `needs-info`, `bug`, `enhancement`, `question`, etc.
```bash
gh issue edit <NUMBER> --add-label "needs-info"
```
-107
View File
@@ -1,107 +0,0 @@
---
description: Fetch all open GitHub issues, analyze bugs, resolve what's possible, triage the rest, wait for user validation, then commit and release
---
# /resolve-issues — Automated Issue Resolution Workflow
## Overview
This workflow fetches all open issues from the project's GitHub repository, classifies them, analyzes bugs, resolves what can be fixed, and triages issues with insufficient information. **It does NOT commit or release automatically** — it presents a report and waits for user validation before proceeding.
## Steps
### 1. Identify the GitHub Repository
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract the owner/repo
- Parse the owner and repo name from the URL
### 2. Fetch All Open Issues
// turbo
- Run: `gh issue list --repo <owner>/<repo> --state open --limit 100 --json number,title,labels,body,comments,createdAt,author`
- Parse the JSON output to get a list of all open issues
- Sort by oldest first (FIFO)
### 3. Classify Each Issue
For each issue, determine its type:
- **Bug** — Has `bug` label, or body contains error messages, stack traces, "doesn't work", "broken", "crash", "error"
- **Feature Request** — Has `enhancement`/`feature` label, or body describes new functionality
- **Question** — Has `question` label, or is asking "how to" something
- **Other** — Anything else
Focus ONLY on **Bugs** for resolution. Feature requests and questions should be skipped with a note in the final report.
### 4. Analyze Each Bug — For each bug issue:
#### 4a. Check Information Sufficiency
Verify the issue contains enough information to reproduce and fix:
- [ ] Clear description of the problem
- [ ] Steps to reproduce
- [ ] Error messages or logs
- [ ] Expected vs actual behavior
#### 4b. If Information Is INSUFFICIENT
Call the `/issue-triage` workflow (located at `~/.gemini/antigravity/global_workflows/issue-triage.md`):
// turbo
- Post a comment asking for more details using `gh issue comment`
- Add `needs-info` label using `gh issue edit`
- Mark this issue as **DEFERRED** and move to the next one
#### 4c. If Information Is SUFFICIENT
Proceed with resolution:
1. **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
### 5. Generate Report & Wait for Validation
Present a summary report to the user via `notify_user` with `BlockedOnUser: true`:
| Issue | Title | Status | Action |
| ----- | ----- | ------------- | ----------------------------- |
| #N | Title | ✅ Ready | Files changed (not committed) |
| #N | Title | ❓ Needs Info | Triage comment posted |
| #N | Title | ⏭️ Skipped | Feature request / not a bug |
> **⚠️ IMPORTANT**: Do NOT commit, close issues, or generate releases at this step.
> Wait for the user to review the changes and respond with **OK** before proceeding.
- If the user says **OK** or approves → Proceed to step 6
- If the user requests changes → Apply the requested adjustments first, then present the report again
- If the user rejects → Revert the changes and stop
### 6. Commit All Fixes (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
### 7. Close Resolved Issues
For each successfully fixed issue:
// turbo
- 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."`
### 8. Update Docs & Release
If any fixes were committed:
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
If NO fixes were committed, skip this step and just present the report.
-121
View File
@@ -1,121 +0,0 @@
---
description: Analyze open Pull Requests from the project's GitHub repository, generate a critical report, and optionally implement approved changes
---
# /review-prs — PR Review & Analysis Workflow
## Overview
This workflow fetches all open PRs from the project's GitHub repository, performs a critical analysis of each one, generates a detailed report, and waits for user approval before proceeding with implementation.
## Steps
### 1. Identify the GitHub Repository
- Read `package.json` to get the repository URL, or use the git remote origin URL
// turbo
- Run: `git -C <project_root> remote get-url origin` to extract the owner/repo
### 2. Fetch Open Pull Requests
- Navigate to `https://github.com/<owner>/<repo>/pulls` and scrape all open PRs
- For each open PR, collect:
- PR number, title, author, branch, number of commits, date
- PR description/body
- Files changed (diff)
- Existing review comments (from bots or humans)
### 3. Analyze Each PR — For each open PR, perform the following analysis:
#### 3a. Feature Assessment
- **Does it make sense?** Evaluate if the feature fills a real gap or solves a valid problem
- **Alignment** — Check if it aligns with the project's architecture and roadmap
- **Complexity** — Assess if the scope is reasonable or if it should be split
#### 3b. Code Quality Review
- Check for code duplication
- Evaluate error handling patterns (consistent with existing codebase?)
- Check naming conventions and code style
- Verify TypeScript types (any `any` usage, missing types?)
#### 3c. Security Review
- Check for missing authentication/authorization on new endpoints
- Check for injection vulnerabilities (URL params, SQL, XSS)
- Verify input validation on all user-controlled data
- Check for hardcoded secrets or credentials
#### 3d. Architecture Review
- Does the change follow existing patterns?
- Are there any breaking changes to public APIs?
- Is the database schema affected? Migration needed?
- Impact on performance (N+1 queries, missing indexes?)
#### 3e. Test Coverage
- Does the PR include tests?
- Are edge cases covered?
- Would existing tests break?
#### 3f. Cross-Layer (Global) Analysis
Perform a **global impact assessment** to verify whether the PR changes are complete across all layers of the application:
- **Backend → Frontend check**: If the PR adds or modifies backend-only resources (new endpoints, services, data models), evaluate whether corresponding frontend changes are missing:
- Does a new endpoint require a new screen/page in the dashboard?
- Should there be a new action button, menu item, or navigation link?
- Are there new data fields that should be displayed or editable in the UI?
- Does a new feature need a toggle, configuration panel, or status indicator?
- **Frontend → Backend check**: If the PR adds frontend elements, verify the backend support exists:
- Are the required API endpoints implemented?
- Is the data model sufficient for the new UI components?
- **Cross-cutting concerns**: Check shared layers (types, DTOs, validation schemas, routes, middleware) for completeness
- **Document gaps** — If missing layers are detected, list them as **IMPORTANT** issues in the report with concrete suggestions for what should be added
### 4. Generate Report — Create a markdown report for each PR including:
- **PR Summary** — What it does, files affected, commit count
- **Improvements/Benefits** — Numbered list with impact level (HIGH/MEDIUM/LOW)
- **Risks & Issues** — Categorized as CRITICAL / IMPORTANT / MINOR
- **Scoring Table** — Rate across: Feature Relevance, Code Quality, Security, Robustness, Tests
- **Verdict** — Ready to merge? With mandatory vs optional fixes
- **Next Steps** — What will happen if approved
### 5. Present to User
- Show the report via `notify_user` with `BlockedOnUser: true`
- Wait for user decision:
- **Approved** → Proceed to step 6
- **Approved with changes** → Implement the fixes and corrections before merging
- **Rejected** → Close the PR or leave a review comment
### 6. Implementation (if approved)
- Checkout the PR branch or apply changes locally
- Implement any required fixes identified in the analysis
- If the Cross-Layer Analysis (3f) identified missing frontend/backend counterparts, implement them in this step
- 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
### 7. Thank the Contributor
- After the PR is approved (and before or after merging), post a **thank-you comment** on the PR via the GitHub UI or API
- The message should:
- Thank the author by name/username for their contribution
- Briefly mention what the PR accomplishes
- 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)
- Update CHANGELOG.md with the new feature
- Consider version bump if warranted
- Follow the `/generate-release` workflow if a release is needed
-105
View File
@@ -1,105 +0,0 @@
---
description: How to automatically summarize recent changes and update README and CHANGELOG
---
# Update Documentation Workflow
Update CHANGELOG.md, README.md, docs/ files, and all multi-language translations whenever features are added or changed.
## Steps
### 1. Summarize recent changes
Review git log and identify new features, fixes, or changes since the last release tag:
```bash
git log $(git describe --tags --abbrev=0)..HEAD --oneline
```
### 2. Update English CHANGELOG.md
Add an `[Unreleased]` section (or version header if releasing) with:
- `### ✨ New Features` — each feature as a bullet point
- `### 🐛 Bug Fixes` — if applicable
- `### 🧪 Tests` — test count changes
- `### 📁 New Files` — table of new files with purpose
### 3. Update English README.md
Update the feature tables in these sections:
- **🧠 Routing & Intelligence** — for routing/model features
- **🛡️ Resilience & Security** — for security/resilience features
- **📊 Observability & Analytics** — for monitoring features
- **☁️ Deploy & Sync** — for deployment features
### 4. Update docs/ files
- `docs/FEATURES.md` — update the Settings section description
- `docs/API_REFERENCE.md` — add new API routes if any
- `docs/ARCHITECTURE.md` — update architecture if structural changes
### 5. 🌐 Sync Multi-Language Documentation (CRITICAL)
// turbo-all
**This step MUST be run after every README or docs update.**
The project has **30 language versions** of documentation:
**README files (root directory):**
```
README.md (English - source of truth)
README.pt-BR.md README.pt.md README.es.md README.fr.md README.it.md
README.de.md README.nl.md README.sv.md README.no.md README.da.md README.fi.md
README.ru.md README.uk-UA.md README.bg.md README.sk.md README.pl.md README.ro.md README.hu.md
README.ar.md README.he.md README.th.md README.in.md README.id.md README.ms.md README.vi.md
README.ja.md README.ko.md README.zh-CN.md README.phi.md
```
**docs/i18n/ directories (29 languages):**
```
docs/i18n/{ar,bg,da,de,es,fi,fr,he,hu,id,in,it,ja,ko,ms,nl,no,phi,pl,pt,pt-BR,ro,ru,sk,sv,th,uk-UA,vi,zh-CN}/
Each contains: API_REFERENCE.md, ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, FEATURES.md, TROUBLESHOOTING.md, USER_GUIDE.md
```
**Sync approach for feature table updates:**
a. Identify which feature table rows were added to English README.md
b. For each translated README, find the corresponding anchor lines:
- **Routing section:** Find the `💬` (System Prompt) table row — the line before it is always the last routing feature. Insert new routing features before System Prompt.
- **Resilience section:** Find the `📊` Rate Limits table row (the one in lines 590-600, NOT the quota tracking one in lines 560-570). Insert new resilience features after it.
c. The new feature entries can stay in English for technical features, matching the pattern used in the existing translations.
d. Use `sed` or similar tool to batch-insert across all 29 translated READMEs.
**Verification:**
```bash
# Verify all READMEs have the new features
grep -l "NEW_FEATURE_NAME" README.*.md | wc -l
# Should return 30 (all language versions)
```
**FEATURES.md sync:**
```bash
# Update Settings description in all docs/i18n/*/FEATURES.md
for dir in docs/i18n/*/; do
# Update the Settings section description to mention new features
# Check FEATURES.md in each directory
done
```
### 6. Verify documentation changes
```bash
# Check all modified files
git status --short
# Verify no broken markdown
# Optional: run markdownlint if available
```
+11 -108
View File
@@ -1,60 +1,37 @@
# OmniRoute environment contract
# This file reflects actual runtime usage in the current codebase.
# ═══════════════════════════════════════════════════
# REQUIRED SECRETS — Generate strong values!
# ═══════════════════════════════════════════════════
# Generate with: openssl rand -base64 48
JWT_SECRET=
# Generate with: openssl rand -hex 32
API_KEY_SECRET=
# Initial admin password — CHANGE THIS before first use!
INITIAL_PASSWORD=CHANGEME
# Required
JWT_SECRET=change-me-to-a-long-random-secret
INITIAL_PASSWORD=123456
DATA_DIR=/var/lib/omniroute
# Storage (SQLite)
STORAGE_DRIVER=sqlite
# Generate with: openssl rand -hex 32
STORAGE_ENCRYPTION_KEY=
STORAGE_ENCRYPTION_KEY=change-me-storage-encryption-key
STORAGE_ENCRYPTION_KEY_VERSION=v1
LOG_RETENTION_DAYS=90
SQLITE_MAX_SIZE_MB=2048
SQLITE_CLEAN_LEGACY_FILES=true
# Recommended runtime variables
# Canonical/base port (keeps backward compatibility)
PORT=20128
# Optional split ports:
# API_PORT=20129
# API_HOST=0.0.0.0
# DASHBOARD_PORT=20128
# Optional Docker production host publish ports:
# PROD_DASHBOARD_PORT=20130
# PROD_API_PORT=20131
NODE_ENV=production
INSTANCE_NAME=omniroute
# Recommended security and ops variables
API_KEY_SECRET=endpoint-proxy-api-key-secret
MACHINE_ID_SALT=endpoint-proxy-salt
ENABLE_REQUEST_LOGS=false
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# Input Sanitizer (FASE-01 — prompt injection & PII protection)
# INPUT_SANITIZER_ENABLED=true
# INPUT_SANITIZER_MODE=warn # warn | block | redact
# PII_REDACTION_ENABLED=false
# Cloud sync variables
# Must point to this running instance so internal sync jobs can call /api/sync/cloud.
# Server-side preferred variables:
BASE_URL=http://localhost:20128
CLOUD_URL=
# Backward-compatible/public variables:
# NEXT_PUBLIC_BASE_URL is also used as the OAuth redirect_uri origin when running behind a
# reverse proxy (e.g., nginx). Set this to your public-facing URL so OAuth callbacks work.
# Example: NEXT_PUBLIC_BASE_URL=https://omniroute.example.com
NEXT_PUBLIC_BASE_URL=http://localhost:20128
NEXT_PUBLIC_CLOUD_URL=
@@ -68,11 +45,6 @@ NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true
# ALL_PROXY=socks5://127.0.0.1:7890
# NO_PROXY=localhost,127.0.0.1
# TLS fingerprint spoofing (opt-in) — mimics Chrome 124 TLS handshake via wreq-js
# Reduces risk of JA3/JA4 fingerprint-based blocking by providers (e.g., Google)
# Requires wreq-js to be installed (included in dependencies)
# ENABLE_TLS_FINGERPRINT=true
# Optional CLI runtime overrides (Docker/host integration)
# CLI_MODE=auto
# CLI_EXTRA_PATHS=/host-cli/bin
@@ -90,61 +62,17 @@ NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true
# Provider OAuth Credentials (optional — override hardcoded defaults)
# These can also be set via data/provider-credentials.json
# CLAUDE_OAUTH_CLIENT_ID=
# ─────────────────────────────────────────────────────────────────────────────
# ⚠️ GOOGLE OAUTH (Antigravity, Gemini CLI) — IMPORTANT FOR REMOTE SERVERS
# ─────────────────────────────────────────────────────────────────────────────
# The built-in Google OAuth credentials ONLY work when OmniRoute runs on
# localhost (127.0.0.1 / local network). They are registered with
# redirect_uri = http://localhost:PORT/callback and Google will reject any
# other redirect URI with: redirect_uri_mismatch.
#
# If you are hosting OmniRoute on a remote server (VPS, Docker, cloud), you
# MUST register your own Google Cloud OAuth 2.0 credentials:
#
# 1. Go to https://console.cloud.google.com/apis/credentials
# 2. Create an OAuth 2.0 Client ID (type: "Web application")
# 3. Add your server URL as Authorized redirect URI:
# https://your-server.com/callback
# 4. Copy the Client ID and Client Secret below.
#
# See the full tutorial in README.md → "OAuth em Servidor Remoto" section.
#
# Antigravity (Google Gemini Code Assist):
# ANTIGRAVITY_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
# ANTIGRAVITY_OAUTH_CLIENT_SECRET=GOCSPX-your-secret
ANTIGRAVITY_OAUTH_CLIENT_SECRET=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
# Gemini CLI (Google AI):
# GEMINI_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
# GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-secret
# GEMINI_OAUTH_CLIENT_ID=
# GEMINI_OAUTH_CLIENT_SECRET=
# GEMINI_CLI_OAUTH_CLIENT_ID=
GEMINI_OAUTH_CLIENT_SECRET=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
GEMINI_CLI_OAUTH_CLIENT_SECRET=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
# ─────────────────────────────────────────────────────────────────────────────
# CLAUDE_OAUTH_CLIENT_ID=
# GEMINI_CLI_OAUTH_CLIENT_SECRET=
# CODEX_OAUTH_CLIENT_ID=
# CODEX_OAUTH_CLIENT_SECRET=
# QWEN_OAUTH_CLIENT_ID=
# IFLOW_OAUTH_CLIENT_ID=
IFLOW_OAUTH_CLIENT_SECRET=4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW
# ─────────────────────────────────────────────────────────────────────────────
# Provider User-Agent Overrides (optional — customize per-provider UA headers)
# ─────────────────────────────────────────────────────────────────────────────
# Format: {PROVIDER_ID}_USER_AGENT=custom-value
# When set, overrides the default User-Agent header sent to that provider.
# Useful when providers update versions or block old user-agents.
CLAUDE_USER_AGENT=claude-cli/1.0.83 (external, cli)
CODEX_USER_AGENT=codex-cli/0.92.0 (Windows 10.0.26100; x64)
GITHUB_USER_AGENT=GitHubCopilotChat/0.26.7
ANTIGRAVITY_USER_AGENT=antigravity/1.104.0 darwin/arm64
KIRO_USER_AGENT=AWS-SDK-JS/3.0.0 kiro-ide/1.0.0
IFLOW_USER_AGENT=iFlow-Cli
QWEN_USER_AGENT=google-api-nodejs-client/9.15.1
CURSOR_USER_AGENT=connect-es/1.6.1
GEMINI_CLI_USER_AGENT=google-api-nodejs-client/9.15.1
# IFLOW_OAUTH_CLIENT_SECRET=
# ANTIGRAVITY_OAUTH_CLIENT_ID=
# ANTIGRAVITY_OAUTH_CLIENT_SECRET=
# API Key Providers (Phase 1 + Phase 4)
# Add via Dashboard → Providers → Add API Key, or set here
@@ -173,28 +101,3 @@ GEMINI_CLI_USER_AGENT=google-api-nodejs-client/9.15.1
# Logging
# LOG_LEVEL=info
# LOG_FORMAT=text
LOG_TO_FILE=true
# LOG_FILE_PATH=logs/application/app.log
# LOG_MAX_FILE_SIZE=50M
# LOG_RETENTION_DAYS=7
# ─────────────────────────────────────────────────────────────────────────────
# Memory Optimization (Low-RAM configurations)
# ─────────────────────────────────────────────────────────────────────────────
# Node.js heap limit in MB (default: 256 for Docker, system default for npm)
# OMNIROUTE_MEMORY_MB=256
# Prompt cache settings
# PROMPT_CACHE_MAX_SIZE=50
# PROMPT_CACHE_MAX_BYTES=2097152
# PROMPT_CACHE_TTL_MS=300000
# Semantic cache settings (temperature=0 responses)
# SEMANTIC_CACHE_MAX_SIZE=100
# SEMANTIC_CACHE_MAX_BYTES=4194304
# SEMANTIC_CACHE_TTL_MS=1800000
# In-memory log buffers
# PROXY_LOG_MAX_ENTRIES=200
# CALL_LOGS_MAX=200
# STREAM_HISTORY_MAX=50
-4
View File
@@ -20,10 +20,6 @@ updates:
update-types: ["version-update:semver-major"]
- dependency-name: "next"
update-types: ["version-update:semver-major"]
- dependency-name: "eslint"
update-types: ["version-update:semver-major"]
- dependency-name: "eslint-config-next"
update-types: ["version-update:semver-major"]
- package-ecosystem: "github-actions"
directory: "/"
-147
View File
@@ -1,147 +0,0 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- name: Dependency audit
run: npm audit --audit-level=high --omit=dev
- name: Check for known vulnerabilities
run: npx is-my-node-vulnerable
continue-on-error: true
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run build
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
node-version: [20, 22]
env:
JWT_SECRET: ci-test-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-test-api-key-secret-long
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run test:unit
test-coverage:
name: Coverage
runs-on: ubuntu-latest
needs: build
env:
JWT_SECRET: ci-test-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-test-api-key-secret-long
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run test:coverage
- name: Check coverage threshold
run: |
echo "Coverage report generated. Check output for threshold compliance."
test-e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: build
env:
JWT_SECRET: ci-test-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-test-api-key-secret-long
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run build
- run: npm run test:e2e
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
needs: build
env:
JWT_SECRET: ci-test-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-test-api-key-secret-long
INITIAL_PASSWORD: ci-test-password-for-integration
DATA_DIR: /tmp/omniroute-ci
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run test:integration
continue-on-error: true
test-security:
name: Security Tests
runs-on: ubuntu-latest
needs: build
env:
JWT_SECRET: ci-test-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-test-api-key-secret-long
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run test:security
continue-on-error: true
+22
View File
@@ -0,0 +1,22 @@
name: Codex PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
request-codex-review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Request Codex Review
uses: actions/github-script@v8
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: '@codex review'
});
-38
View File
@@ -1,38 +0,0 @@
name: Deploy to VPS
on:
workflow_run:
workflows: ["Publish to Docker Hub"]
types: [completed]
workflow_dispatch:
jobs:
deploy:
if: >-
(github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success')
&& vars.DEPLOY_ENABLED == 'true'
name: Deploy OmniRoute to VPS
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
port: 22
timeout: 30s
script: |
echo "=== Updating OmniRoute ==="
npm install -g omniroute@latest 2>&1
INSTALLED_VERSION=$(omniroute --version 2>/dev/null || echo "unknown")
echo "Installed version: $INSTALLED_VERSION"
echo "=== Restarting PM2 ==="
pm2 restart omniroute || pm2 start omniroute --name omniroute -- --port 20128
pm2 save
echo "=== Health Check ==="
sleep 3
curl -sf http://localhost:20128/api/settings > /dev/null && echo "✅ OmniRoute is healthy" || echo "❌ Health check failed"
echo "=== Deploy complete ==="
-117
View File
@@ -1,117 +0,0 @@
name: Publish to Docker Hub
on:
release:
types: [published]
permissions:
contents: read
jobs:
build:
name: Build (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
platform_pair: linux-amd64
runner: ubuntu-latest
- platform: linux/arm64
platform_pair: linux-arm64
runner: ubuntu-24.04-arm
env:
IMAGE_NAME: diegosouzapw/omniroute
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
target: runner-base
platforms: ${{ matrix.platform }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=omniroute-runner-base-${{ matrix.platform_pair }}
cache-to: type=gha,mode=max,scope=omniroute-runner-base-${{ matrix.platform_pair }}
- name: Export digest
run: |
mkdir -p "${{ runner.temp }}/digests"
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.platform_pair }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
name: Merge manifest and publish tags
runs-on: ubuntu-latest
needs: build
env:
IMAGE_NAME: diegosouzapw/omniroute
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Extract version from release tag
id: version
run: |
VERSION="${GITHUB_REF_NAME}"
VERSION="${VERSION#v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing Docker image version: $VERSION"
- name: Download digests
uses: actions/download-artifact@v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create \
-t "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}" \
-t "${{ env.IMAGE_NAME }}:latest" \
$(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect "${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}"
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v5
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: diegosouzapw/omniroute
short-description: "OmniRoute — Unified AI proxy. Route any LLM through one endpoint."
readme-filepath: ./README.md
-171
View File
@@ -1,171 +0,0 @@
name: Build Electron Desktop App
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Release version (e.g., v1.6.8)"
required: true
type: string
permissions:
contents: write
jobs:
validate:
name: Validate version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.validate.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate version format
id: validate
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="${{ inputs.version }}"
fi
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: Invalid version format. Expected: v1.6.8"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "✓ Valid version: $VERSION"
build:
name: Build Electron (${{ matrix.platform }})
needs: validate
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: windows
runner: windows-latest
target: win
ext: .exe
- platform: macos-intel
runner: macos-latest
target: mac
ext: .dmg
- platform: macos-arm64
runner: macos-latest
target: mac
ext: -arm64.dmg
- platform: linux
runner: ubuntu-latest
target: linux
ext: .AppImage
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build Next.js standalone
run: npm run build
- name: Install Electron dependencies
working-directory: electron
run: npm install --no-audit --no-fund
- name: Build Electron for ${{ matrix.platform }}
working-directory: electron
run: npm run build:${{ matrix.target }}
- name: Collect installers
shell: bash
run: |
mkdir -p release-assets
cd electron/dist-electron
# Copy only installer files for this platform
for file in *${{ matrix.ext }}; do
[ -f "$file" ] && cp "$file" ../../release-assets/
done
# Windows: also copy portable standalone exe
if [ "${{ matrix.platform }}" = "windows" ]; then
[ -f "OmniRoute.exe" ] && cp OmniRoute.exe ../../release-assets/
fi
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: electron-${{ matrix.platform }}
path: release-assets/
release:
name: Create Release
needs: [validate, build]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true
- name: Create source archives
run: |
# Create source code archives (excluding dev dependencies and build artifacts)
export TARBALL="OmniRoute-${{ needs.validate.outputs.version }}.source.tar.gz"
export ZIPBALL="OmniRoute-${{ needs.validate.outputs.version }}.source.zip"
# Use git archive for clean source export
git archive --format=tar.gz --prefix=OmniRoute-${{ needs.validate.outputs.version }}/ HEAD -o "release-assets/$TARBALL"
git archive --format=zip --prefix=OmniRoute-${{ needs.validate.outputs.version }}/ HEAD -o "release-assets/$ZIPBALL"
echo "✓ Created source archives:"
ls -lh "release-assets/$TARBALL" "release-assets/$ZIPBALL"
- name: List release files
run: ls -la release-assets/
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.validate.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
files: |
release-assets/*.dmg
release-assets/*-arm64.dmg
release-assets/*.exe
release-assets/*.AppImage
release-assets/*.blockmap
release-assets/*.source.tar.gz
release-assets/*.source.zip
release-assets/OmniRoute.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+2 -2
View File
@@ -14,10 +14,10 @@ jobs:
environment: NPM_TOKEN
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
+3 -44
View File
@@ -1,7 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
node_modules/
/node_modules
/.pnp
.pnp.*
.yarn/*
@@ -11,10 +11,10 @@ node_modules/
!.yarn/versions
# testing
coverage/
/coverage
# next.js
.next/
/.next/
/out/
# production
@@ -47,35 +47,20 @@ next-env.d.ts
data/
logs/*
# analysis directories (generated, not tracked)
.analysis/
antigravity-manager-analysis/
# docs (allow specific tracked files)
docs/*
!docs/ARCHITECTURE.md
!docs/CODEBASE_DOCUMENTATION.md
!docs/CONTRIBUTING.md
!docs/USER_GUIDE.md
!docs/API_REFERENCE.md
!docs/TROUBLESHOOTING.md
!docs/EXECUTION_CONTEXT_PROVIDER_SYNC.md
!docs/TASK_NEBIUS_BACKEND_ENABLEMENT.md
!docs/frontend-backend-provider-gap-report.md
!docs/openapi.yaml
!docs/PLANO-IMPLANTACAO.md
!docs/TASKS.md
!docs/FASE-*.md
!docs/adr/
!docs/cli-tools/
!docs/planning/
!docs/improvement-plans/
!docs/api/
!docs/VM_DEPLOYMENT_GUIDE.md
!docs/FEATURES.md
!docs/screenshots/
!docs/i18n/
!docs/i18n/**
# open-sse tests
open-sse/test/*
@@ -87,29 +72,3 @@ open-sse/test/*
test-results/
playwright-report/
blob-report/
cloud/
omnirouteCloud/
omnirouteSite/
# Security Analysis (standalone project with own git)
security-analysis/
# Deploy workflow (contains sensitive VPS credentials)
.agent/workflows/deploy.md
clipr/
app.log
*.tgz
# Backup directories
app.__qa_backup/
# Production standalone build (created by scripts/prepublish.mjs)
# Conflicts with Next.js App Router detection in dev (root app/ shadows src/app/)
# npm publish still includes it via package.json "files" field
app/
# Electron (subproject dependency lock and build artifacts)
electron/package-lock.json
electron/dist-electron/
electron/node_modules/
icon.iconset/
+17 -18
View File
@@ -8,7 +8,6 @@ Unified AI proxy/router — route any LLM through one endpoint. Multi-provider s
## Stack
- **Runtime**: Next.js 16 (App Router), Node.js, ES Modules
- **Language**: TypeScript 5.9 (`src/`) + JavaScript (`open-sse/`)
- **Database**: better-sqlite3 (SQLite) — `DATA_DIR` configurable, default `~/.omniroute/`
- **Streaming**: SSE via `open-sse` internal package
- **Styling**: Tailwind CSS v4
@@ -22,15 +21,15 @@ All persistence uses SQLite through domain-specific modules:
| Module | Responsibility |
| -------------- | ------------------------------------------ |
| `core.ts` | SQLite engine, migrations, WAL, encryption |
| `providers.ts` | Provider connections & nodes |
| `models.ts` | Model aliases, MITM aliases, custom models |
| `combos.ts` | Combo configurations |
| `apiKeys.ts` | API key management & validation |
| `settings.ts` | Settings, pricing, proxy config |
| `backup.ts` | Backup / restore operations |
| `core.js` | SQLite engine, migrations, WAL, encryption |
| `providers.js` | Provider connections & nodes |
| `models.js` | Model aliases, MITM aliases, custom models |
| `combos.js` | Combo configurations |
| `apiKeys.js` | API key management & validation |
| `settings.js` | Settings, pricing, proxy config |
| `backup.js` | Backup / restore operations |
`src/lib/localDb.ts` is a **re-export layer only** — all 27+ consumers import from it,
`src/lib/localDb.js` is a **re-export layer only** — all 27+ consumers import from it,
but the real logic lives in `src/lib/db/`.
### Request Pipeline (`open-sse/`)
@@ -50,25 +49,25 @@ Translation between provider formats: `open-sse/translator/`
### OAuth & Tokens (`src/lib/oauth/`)
18 modules handling OAuth flows, token refresh, and provider credentials.
Default credentials are hardcoded in `src/lib/oauth/constants/oauth.ts`,
Default credentials are hardcoded in `src/lib/oauth/constants/oauth.js`,
overridable via env vars or `data/provider-credentials.json`.
### Supporting Systems
| System | Location |
| -------------------------- | ------------------------------------------------- |
| Usage tracking & analytics | `src/lib/usageDb.ts`, `src/lib/usageAnalytics.ts` |
| Token health checks | `src/lib/tokenHealthCheck.ts` |
| Cloud sync | `src/lib/cloudSync.ts` |
| Proxy logging | `src/lib/proxyLogger.ts` |
| Data paths resolution | `src/lib/dataPaths.ts` |
| Usage tracking & analytics | `src/lib/usageDb.js`, `src/lib/usageAnalytics.js` |
| Token health checks | `src/lib/tokenHealthCheck.js` |
| Cloud sync | `src/lib/cloudSync.js` |
| Proxy logging | `src/lib/proxyLogger.js` |
| Data paths resolution | `src/lib/dataPaths.js` |
### Adding a New Provider
1. Register in `src/shared/constants/providers.ts`
1. Register in `src/shared/constants/providers.js`
2. Add executor in `open-sse/executors/`
3. Add translator rules in `open-sse/translator/` (if non-OpenAI format)
4. Add OAuth config in `src/lib/oauth/constants/oauth.ts` (if OAuth-based)
4. Add OAuth config in `src/lib/oauth/constants/oauth.js` (if OAuth-based)
## Review Focus
@@ -84,7 +83,7 @@ overridable via env vars or `data/provider-credentials.json`.
- DB operations go through `src/lib/db/` modules, never raw SQL in routes
- 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
- `localDb.js` is re-exports only — add new functions to the proper `db/*.js` module
### Code Quality
+106 -991
View File
File diff suppressed because it is too large Load Diff
-273
View File
@@ -1,273 +0,0 @@
# Contributing to OmniRoute
Thank you for your interest in contributing! This guide covers everything you need to get started.
---
## Development Setup
### Prerequisites
- **Node.js** 20+ (recommended: 22 LTS)
- **npm** 10+
- **Git**
### Clone & Install
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
npm install
```
### Environment Variables
```bash
# Create your .env from the template
cp .env.example .env
# Generate required secrets
echo "JWT_SECRET=$(openssl rand -base64 48)" >> .env
echo "API_KEY_SECRET=$(openssl rand -hex 32)" >> .env
```
Key variables for development:
| Variable | Development Default | Description |
| ---------------------- | ----------------------- | ------------------------- |
| `PORT` | `3000` | Server port |
| `NEXT_PUBLIC_BASE_URL` | `http://localhost:3000` | Base URL for frontend |
| `JWT_SECRET` | (generate above) | JWT signing secret |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `ENABLE_REQUEST_LOGS` | `false` | Enable debug request logs |
### Running Locally
```bash
# Development mode (hot reload)
npm run dev
# Production build
npm run build
npm run start
# Common port configuration
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```
Default URLs:
- **Dashboard**: `http://localhost:3000/dashboard`
- **API**: `http://localhost:3000/v1`
---
## Git Workflow
> ⚠️ **NEVER commit directly to `main`.** Always use feature branches.
```bash
git checkout -b feat/your-feature-name
# ... make changes ...
git commit -m "feat: describe your change"
git push -u origin feat/your-feature-name
# Open a Pull Request on GitHub
```
### Branch Naming
| Prefix | Purpose |
| ----------- | ------------------------- |
| `feat/` | New features |
| `fix/` | Bug fixes |
| `refactor/` | Code restructuring |
| `docs/` | Documentation changes |
| `test/` | Test additions/fixes |
| `chore/` | Tooling, CI, dependencies |
### Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/):
```
feat: add circuit breaker for provider calls
fix: resolve JWT secret validation edge case
docs: update SECURITY.md with PII protection
test: add observability unit tests
refactor(db): consolidate rate limit tables
```
Scopes: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`.
---
## Running Tests
```bash
# All unit tests
npm test
npm run test:unit
# Specific test suites
npm run test:security # Security tests
npm run test:fixes # Fix verification tests
# With coverage
npm run test:coverage
# E2E tests (requires Playwright)
npm run test:e2e
# Lint + format check
npm run lint
npm run check
```
Current test status: **368+ unit tests** covering:
- Provider translators and format conversion
- Rate limiting, circuit breaker, and resilience
- Semantic cache, idempotency, progress tracking
- Database operations and schema
- OAuth flows and authentication
- API endpoint validation
---
## Code Style
- **ESLint** — Run `npm run lint` before committing
- **Prettier** — Auto-formatted via `lint-staged` on commit
- **TypeScript** — All `src/` code uses `.ts`/`.tsx`; document with TSDoc (`@param`, `@returns`, `@throws`)
- **No `eval()`** — ESLint enforces `no-eval`, `no-implied-eval`, `no-new-func`
- **Zod validation** — Use Zod schemas for API input validation
---
## Project Structure
```
src/ # TypeScript (.ts / .tsx)
├── app/ # Next.js App Router
│ ├── (dashboard)/ # Dashboard pages (.tsx)
│ ├── api/ # API routes (.ts)
│ └── login/ # Auth pages (.tsx)
├── domain/ # Domain types and response helpers (.ts)
├── lib/ # Core business logic (.ts)
│ ├── db/ # SQLite database layer
│ ├── oauth/ # OAuth services per provider
│ ├── cacheLayer.ts # LRU cache
│ ├── semanticCache.ts # Semantic response cache
│ ├── idempotencyLayer.ts # Request deduplication
│ └── localDb.ts # Settings facade (LowDB for config, SQLite for domain data)
├── shared/
│ ├── components/ # React components (.tsx)
│ ├── middleware/ # Correlation IDs, etc.
│ ├── utils/ # Circuit breaker, sanitizer, etc.
│ └── validation/ # Zod schemas
└── sse/ # SSE chat handlers (.ts)
open-sse/ # @omniroute/open-sse workspace (JavaScript)
├── handlers/ # chatCore.js — main request handler
├── services/ # Rate limit, fallback
├── translators/ # Format converters (OpenAI ↔ Claude ↔ Gemini)
└── utils/ # Progress tracker, stream helpers
tests/
├── unit/ # Node.js test runner (.test.mjs)
└── e2e/ # Playwright tests
docs/ # Documentation
├── USER_GUIDE.md # Provider setup, CLI integration
├── API_REFERENCE.md # All endpoints
├── TROUBLESHOOTING.md # Common issues
├── ARCHITECTURE.md # System architecture
└── adr/ # Architecture Decision Records
```
---
## Adding a New Provider
### Step 1: OAuth Service (if using OAuth)
Create `src/lib/oauth/services/your-provider.ts` extending `OAuthService`:
```typescript
import { OAuthService } from "../OAuthService";
export class YourProviderService extends OAuthService {
constructor() {
super({
name: "your-provider",
authUrl: "https://provider.com/oauth/authorize",
tokenUrl: "https://provider.com/oauth/token",
clientId: "...",
scopes: ["..."],
});
}
}
```
### Step 2: Register Provider
Add to `src/lib/oauth/providers.ts`:
```typescript
import { YourProviderService } from "./services/your-provider";
// Add to the providers map
```
### Step 3: Add Constants
Add provider constants in `src/lib/providerConstants.ts`:
- Provider prefix (e.g., `yp/`)
- Default models
- Pricing info
### Step 4: Add Translator (if non-OpenAI format)
Create translator in `open-sse/translators/` if the provider uses a custom API format.
### Step 5: Add Timeout
Add request timeout configuration in `src/shared/utils/requestTimeout.ts`.
### Step 6: Add Tests
Write unit tests in `tests/unit/` covering at minimum:
- Provider registration
- Request/response translation
- Error handling
---
## Pull Request Checklist
- [ ] Tests pass (`npm test`)
- [ ] Linting passes (`npm run lint`)
- [ ] Build succeeds (`npm run build`)
- [ ] TypeScript types added for new public functions and interfaces
- [ ] No hardcoded secrets or fallback values
- [ ] CHANGELOG updated (if user-facing change)
- [ ] Documentation updated (if applicable)
---
## Releasing
When a new GitHub Release is created (e.g. `v0.4.0`), the package is **automatically published to npm** via GitHub Actions:
```bash
gh release create v0.4.0 --title "v0.4.0" --generate-notes
```
---
## Getting Help
- **Architecture**: See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **ADRs**: See `docs/adr/` for architectural decision records
+4 -10
View File
@@ -2,7 +2,6 @@ FROM node:22-bookworm-slim AS builder
WORKDIR /app
COPY package*.json ./
COPY scripts/postinstall.mjs ./scripts/postinstall.mjs
RUN if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi
COPY . ./
@@ -13,32 +12,26 @@ WORKDIR /app
LABEL org.opencontainers.image.title="omniroute" \
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint" \
org.opencontainers.image.url="https://omniroute.online" \
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute" \
org.opencontainers.image.licenses="MIT"
ENV NODE_ENV=production
ENV PORT=20128
ENV HOSTNAME=0.0.0.0
ENV NODE_OPTIONS="--max-old-space-size=256"
# Data directory inside Docker — must match the volume mount in docker-compose.yml
ENV DATA_DIR=/app/data
# Runtime writable location for localDb when DATA_DIR is configured to /app/data
RUN mkdir -p /app/data
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/scripts/run-standalone.mjs ./run-standalone.mjs
COPY --from=builder /app/scripts/runtime-env.mjs ./runtime-env.mjs
COPY --from=builder /app/scripts/healthcheck.mjs ./healthcheck.mjs
EXPOSE 20128
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD ["node", "healthcheck.mjs"]
CMD node -e "fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))"
CMD ["node", "run-standalone.mjs"]
CMD ["node", "server.js"]
FROM runner-base AS runner-cli
@@ -50,3 +43,4 @@ RUN apt-get update \
# Install CLI tools globally. Separate layer from apt for better cache reuse.
RUN npm install -g --no-audit --no-fund @openai/codex @anthropic-ai/claude-code droid openclaw@latest
-1367
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1217
View File
File diff suppressed because it is too large Load Diff
-1220
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1218
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1148
View File
File diff suppressed because it is too large Load Diff
-1217
View File
File diff suppressed because it is too large Load Diff
-1367
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
+754 -918
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1294
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1216
View File
File diff suppressed because it is too large Load Diff
-1373
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1363
View File
File diff suppressed because it is too large Load Diff
-1374
View File
File diff suppressed because it is too large Load Diff
-1372
View File
File diff suppressed because it is too large Load Diff
-1216
View File
File diff suppressed because it is too large Load Diff
+13 -161
View File
@@ -1,169 +1,21 @@
# Security Policy
## Reporting Vulnerabilities
If you discover a security vulnerability in OmniRoute, please report it responsibly:
1. **DO NOT** open a public GitHub issue
2. Use [GitHub Security Advisories](https://github.com/diegosouzapw/OmniRoute/security/advisories/new)
3. Include: description, reproduction steps, and potential impact
## Response Timeline
| Stage | Target |
| ------------------- | --------------------------- |
| Acknowledgment | 48 hours |
| Triage & Assessment | 5 business days |
| Patch Release | 14 business days (critical) |
## Supported Versions
| Version | Support Status |
| ------- | -------------- |
| 1.0.x | ✅ Active |
| 0.8.x | ✅ Security |
| < 0.8.0 | ❌ Unsupported |
Use this section to tell people about which versions of your project are
currently being supported with security updates.
---
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Security Architecture
## Reporting a Vulnerability
OmniRoute implements a multi-layered security model:
Use this section to tell people how to report a vulnerability.
```
Request → CORS → API Key Auth → Prompt Injection Guard → Input Sanitizer → Rate Limiter → Circuit Breaker → Provider
```
### 🔐 Authentication & Authorization
| Feature | Implementation |
| -------------------- | ---------------------------------------------------------- |
| **Dashboard Login** | Password-based auth with JWT tokens (HttpOnly cookies) |
| **API Key Auth** | HMAC-signed keys with CRC validation |
| **OAuth 2.0 + PKCE** | Secure provider auth (Claude, Codex, Gemini, Cursor, etc.) |
| **Token Refresh** | Automatic OAuth token refresh before expiry |
| **Secure Cookies** | `AUTH_COOKIE_SECURE=true` for HTTPS environments |
### 🛡️ Encryption at Rest
All sensitive data stored in SQLite is encrypted using **AES-256-GCM** with scrypt key derivation:
- API keys, access tokens, refresh tokens, and ID tokens
- Versioned format: `enc:v1:<iv>:<ciphertext>:<authTag>`
- Passthrough mode (plaintext) when `STORAGE_ENCRYPTION_KEY` is not set
```bash
# Generate encryption key:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
```
### 🧠 Prompt Injection Guard
Middleware that detects and blocks prompt injection attacks in LLM requests:
| Pattern Type | Severity | Example |
| ------------------- | -------- | ---------------------------------------------- |
| System Override | High | "ignore all previous instructions" |
| Role Hijack | High | "you are now DAN, you can do anything" |
| Delimiter Injection | Medium | Encoded separators to break context boundaries |
| DAN/Jailbreak | High | Known jailbreak prompt patterns |
| Instruction Leak | Medium | "show me your system prompt" |
Configure via dashboard (Settings → Security) or `.env`:
```env
INPUT_SANITIZER_ENABLED=true
INPUT_SANITIZER_MODE=block # warn | block | redact
```
### 🔒 PII Redaction
Automatic detection and optional redaction of personally identifiable information:
| PII Type | Pattern | Replacement |
| ------------- | --------------------- | ------------------ |
| Email | `user@domain.com` | `[EMAIL_REDACTED]` |
| CPF (Brazil) | `123.456.789-00` | `[CPF_REDACTED]` |
| CNPJ (Brazil) | `12.345.678/0001-00` | `[CNPJ_REDACTED]` |
| Credit Card | `4111-1111-1111-1111` | `[CC_REDACTED]` |
| Phone | `+55 11 99999-9999` | `[PHONE_REDACTED]` |
| SSN (US) | `123-45-6789` | `[SSN_REDACTED]` |
```env
PII_REDACTION_ENABLED=true
```
### 🌐 Network Security
| Feature | Description |
| ------------------------ | ---------------------------------------------------------------- |
| **CORS** | Configurable origin control (`CORS_ORIGIN` env var, default `*`) |
| **IP Filtering** | Whitelist/blacklist IP ranges in dashboard |
| **Rate Limiting** | Per-provider rate limits with automatic backoff |
| **Anti-Thundering Herd** | Mutex + per-connection locking prevents cascading 502s |
### 🔌 Resilience & Availability
| Feature | Description |
| ----------------------- | ------------------------------------------------------------------ |
| **Circuit Breaker** | 3-state (Closed → Open → Half-Open) per provider, SQLite-persisted |
| **Request Idempotency** | 5-second dedup window for duplicate requests |
| **Exponential Backoff** | Automatic retry with increasing delays |
| **Health Dashboard** | Real-time provider health monitoring |
### 📋 Compliance
| Feature | Description |
| ------------------ | --------------------------------------------------- |
| **Log Retention** | Automatic cleanup after `LOG_RETENTION_DAYS` |
| **No-Log Opt-out** | Per API key `noLog` flag disables request logging |
| **Audit Log** | Administrative actions tracked in `audit_log` table |
---
## Required Environment Variables
All secrets must be set before starting the server. The server will **fail fast** if they are missing or weak.
```bash
# REQUIRED — server will not start without these:
JWT_SECRET=$(openssl rand -base64 48) # min 32 chars
API_KEY_SECRET=$(openssl rand -hex 32) # min 16 chars
# RECOMMENDED — enables encryption at rest:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
```
The server actively rejects known-weak values like `changeme`, `secret`, or `password`.
---
## Docker Security
- Use non-root user in production
- Mount secrets as read-only volumes
- Never copy `.env` files into Docker images
- Use `.dockerignore` to exclude sensitive files
- Set `AUTH_COOKIE_SECURE=true` when behind HTTPS
```bash
docker run -d \
--name omniroute \
--restart unless-stopped \
--read-only \
-p 20128:20128 \
-v omniroute-data:/app/data \
-e JWT_SECRET="$(openssl rand -base64 48)" \
-e API_KEY_SECRET="$(openssl rand -hex 32)" \
-e STORAGE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
diegosouzapw/omniroute:latest
```
---
## Dependencies
- Run `npm audit` regularly
- Keep dependencies updated
- The project uses `husky` + `lint-staged` for pre-commit checks
- CI pipeline runs ESLint security rules on every push
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
+29 -118
View File
@@ -12,69 +12,15 @@
*/
import { spawn } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { existsSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { homedir, platform } from "node:os";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ROOT = join(__dirname, "..");
const APP_DIR = join(ROOT, "app");
// ── Load .env file (for global npm install) ─────────────────
function loadEnvFile() {
const envPaths = [];
// 1. DATA_DIR/.env if set
if (process.env.DATA_DIR) {
envPaths.push(join(process.env.DATA_DIR, ".env"));
}
// 2. ~/.omniroute/.env (default data dir)
const home = homedir();
if (home) {
if (platform() === "win32") {
const appData = process.env.APPDATA || join(home, "AppData", "Roaming");
envPaths.push(join(appData, "omniroute", ".env"));
} else {
envPaths.push(join(home, ".omniroute", ".env"));
}
}
// 3. ./.env (current working directory)
envPaths.push(join(process.cwd(), ".env"));
for (const envPath of envPaths) {
try {
if (existsSync(envPath)) {
const content = readFileSync(envPath, "utf-8");
for (const line of content.split("\n")) {
const trimmed = line.trim();
// Skip empty lines and comments
if (!trimmed || trimmed.startsWith("#")) continue;
const eqIdx = trimmed.indexOf("=");
if (eqIdx > 0) {
const key = trimmed.slice(0, eqIdx).trim();
const value = trimmed.slice(eqIdx + 1).trim();
// Don't override existing env vars
if (process.env[key] === undefined) {
// Remove surrounding quotes
process.env[key] = value.replace(/^["']|["']$/g, "");
}
}
}
console.log(` \x1b[2m📋 Loaded env from ${envPath}\x1b[0m`);
return;
}
} catch {
// Ignore errors reading env files
}
}
}
loadEnvFile();
// ── Parse args ─────────────────────────────────────────────
const args = process.argv.slice(2);
@@ -84,22 +30,18 @@ if (args.includes("--help") || args.includes("-h")) {
\x1b[1mUsage:\x1b[0m
omniroute Start the server
omniroute --port <port> Use custom API port (default: 20128)
omniroute --port <port> Use custom port (default: 20128)
omniroute --no-open Don't open browser automatically
omniroute --help Show this help
omniroute --version Show version
\x1b[1mConfig:\x1b[0m
Loads .env from: ~/.omniroute/.env or ./.env
Memory limit: OMNIROUTE_MEMORY_MB (default: 512)
\x1b[1mAfter starting:\x1b[0m
Dashboard: http://localhost:<dashboard-port>
API: http://localhost:<api-port>/v1
Dashboard: http://localhost:<port>
API: http://localhost:<port>/v1
\x1b[1mConnect your tools:\x1b[0m
Set your CLI tool (Cursor, Cline, Codex, etc.) to use:
\x1b[33mhttp://localhost:<api-port>/v1\x1b[0m
\x1b[33mhttp://localhost:20128/v1\x1b[0m
`);
process.exit(0);
}
@@ -116,58 +58,40 @@ if (args.includes("--version") || args.includes("-v")) {
process.exit(0);
}
function parsePort(value, fallback) {
const parsed = parseInt(String(value), 10);
return Number.isFinite(parsed) && parsed > 0 && parsed <= 65535 ? parsed : fallback;
}
// Parse --port (canonical/base port)
let port = parsePort(process.env.PORT || "20128", 20128);
// Parse --port
let port = 20128;
const portIdx = args.indexOf("--port");
if (portIdx !== -1 && args[portIdx + 1]) {
const cliPort = parsePort(args[portIdx + 1], null);
if (cliPort === null) {
port = parseInt(args[portIdx + 1], 10);
if (isNaN(port)) {
console.error("\x1b[31m✖ Invalid port number\x1b[0m");
process.exit(1);
}
port = cliPort;
}
const apiPort = parsePort(process.env.API_PORT || String(port), port);
const dashboardPort = parsePort(process.env.DASHBOARD_PORT || String(port), port);
const noOpen = args.includes("--no-open");
// ── Banner ─────────────────────────────────────────────────
console.log(`
\x1b[36m ____ _ ____ _
/ __ \\ (_) __ \\ | |
| | | |_ __ ___ _ __ _| |__) |___ _ _| |_ ___
| | | | '_ \` _ \\| '_ \\ | _ // _ \\| | | | __/ _ \\
| |__| | | | | | | | | | | | \\ \\ (_) | |_| | || __/
\\____/|_| |_| |_|_| |_|_|_| \\_\\___/ \\__,_|\\__\\___|
/ __ \\ (_) __ \\ | |
| | | |_ __ ___ _ __ _| |__) |___ _ _| |_ ___
| | | | '_ \` _ \\| '_ \\ | _ // _ \\| | | | __/ _ \\
| |__| | | | | | | | | | | | \\ \\ (_) | |_| | || __/
\\____/|_| |_| |_|_| |_|_|_| \\_\\___/ \\__,_|\\__\\___|
\x1b[0m`);
// ── Node.js version check ──────────────────────────────────
const nodeMajor = parseInt(process.versions.node.split(".")[0], 10);
if (nodeMajor >= 24) {
console.warn(`\x1b[33m ⚠ Warning: You are running Node.js ${process.versions.node}.
OmniRoute uses better-sqlite3, a native addon that does not yet
have compatible prebuilt binaries for Node.js 24+.
You may experience errors like "is not a valid Win32 application"
or "NODE_MODULE_VERSION mismatch".
Recommended: use Node.js 22 LTS (or 20 LTS).
Workaround: npm rebuild better-sqlite3\x1b[0m
`);
}
// ── Resolve server entry ───────────────────────────────────
const serverJs = join(APP_DIR, "server.js");
if (!existsSync(serverJs)) {
console.error("\x1b[31m✖ Server not found at:\x1b[0m", serverJs);
console.error(" This usually means the package was not built correctly.");
console.error(
"\x1b[31m✖ Server not found at:\x1b[0m",
serverJs,
);
console.error(
" This usually means the package was not built correctly.",
);
console.error(" Try reinstalling: npm install -g omniroute");
process.exit(1);
}
@@ -175,23 +99,14 @@ if (!existsSync(serverJs)) {
// ── Start server ───────────────────────────────────────────
console.log(` \x1b[2m⏳ Starting server...\x1b[0m\n`);
// Sanitize memory limit — parseInt to prevent command injection (#150)
const rawMemory = parseInt(process.env.OMNIROUTE_MEMORY_MB || "512", 10);
const memoryLimit =
Number.isFinite(rawMemory) && rawMemory >= 64 && rawMemory <= 16384 ? rawMemory : 512;
const env = {
...process.env,
OMNIROUTE_PORT: String(port),
PORT: String(dashboardPort),
DASHBOARD_PORT: String(dashboardPort),
API_PORT: String(apiPort),
PORT: String(port),
HOSTNAME: "0.0.0.0",
NODE_ENV: "production",
NODE_OPTIONS: `--max-old-space-size=${memoryLimit}`,
};
const server = spawn("node", [`--max-old-space-size=${memoryLimit}`, serverJs], {
const server = spawn("node", [serverJs], {
cwd: APP_DIR,
env,
stdio: "pipe",
@@ -204,10 +119,7 @@ server.stdout.on("data", (data) => {
process.stdout.write(text);
// Detect server ready
if (
!started &&
(text.includes("Ready") || text.includes("started") || text.includes("listening"))
) {
if (!started && (text.includes("Ready") || text.includes("started") || text.includes("listening"))) {
started = true;
onReady();
}
@@ -244,17 +156,16 @@ process.on("SIGTERM", shutdown);
// ── On ready ───────────────────────────────────────────────
async function onReady() {
const dashboardUrl = `http://localhost:${dashboardPort}`;
const apiUrl = `http://localhost:${apiPort}`;
const url = `http://localhost:${port}`;
console.log(`
\x1b[32m OmniRoute is running!\x1b[0m
\x1b[1m Dashboard:\x1b[0m ${dashboardUrl}
\x1b[1m API Base:\x1b[0m ${apiUrl}/v1
\x1b[1m Dashboard:\x1b[0m ${url}
\x1b[1m API Base:\x1b[0m ${url}/v1
\x1b[2m Point your CLI tool (Cursor, Cline, Codex) to:\x1b[0m
\x1b[33m ${apiUrl}/v1\x1b[0m
\x1b[33m ${url}/v1\x1b[0m
\x1b[2m Press Ctrl+C to stop\x1b[0m
`);
@@ -262,7 +173,7 @@ async function onReady() {
if (!noOpen) {
try {
const open = await import("open");
await open.default(dashboardUrl);
await open.default(url);
} catch {
// open is optional — if not available, just skip
}
-116
View File
@@ -1,116 +0,0 @@
#!/usr/bin/env node
/**
* Password Reset CLI T-38
*
* Usage:
* node bin/reset-password.mjs
* npx omniroute reset-password
*
* Resets the admin password for OmniRoute.
* Prompts for a new password and updates the database directly.
*
* @module bin/reset-password
*/
import { createInterface } from "node:readline";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { existsSync } from "node:fs";
import { createHash } from "node:crypto";
const __dirname = dirname(fileURLToPath(import.meta.url));
// Resolve data directory — same logic as the server
const DATA_DIR = process.env.DATA_DIR || resolve(__dirname, "..", "data");
const DB_PATH = resolve(DATA_DIR, "settings.db");
const rl = createInterface({
input: process.stdin,
output: process.stdout,
});
function ask(question) {
return new Promise((resolve) => rl.question(question, resolve));
}
function hashPassword(password) {
return createHash("sha256").update(password).digest("hex");
}
console.log("\n🔑 OmniRoute — Password Reset\n");
async function main() {
// Check if database exists
if (!existsSync(DB_PATH)) {
console.error(`❌ Database not found at: ${DB_PATH}`);
console.error(` Make sure OmniRoute has been started at least once.`);
console.error(` Or set DATA_DIR env var to your data directory.\n`);
process.exit(1);
}
let Database;
try {
Database = (await import("better-sqlite3")).default;
} catch {
console.error("❌ better-sqlite3 not installed. Run: npm install");
process.exit(1);
}
const db = new Database(DB_PATH);
// Check current settings
const row = db.prepare("SELECT value FROM settings WHERE key = 'password'").get();
if (row) {
console.log("️ A password is currently set.");
} else {
console.log("️ No password is currently set.");
}
const password = await ask("Enter new password (min 4 chars): ");
if (!password || password.length < 4) {
console.error("\n❌ Password must be at least 4 characters.\n");
db.close();
rl.close();
process.exit(1);
}
const confirm = await ask("Confirm new password: ");
if (password !== confirm) {
console.error("\n❌ Passwords do not match.\n");
db.close();
rl.close();
process.exit(1);
}
const hashed = hashPassword(password);
// Upsert the password
const stmt = db.prepare(`
INSERT INTO settings (key, value) VALUES ('password', ?)
ON CONFLICT(key) DO UPDATE SET value = excluded.value
`);
stmt.run(hashed);
// Also ensure requireLogin is true
const loginStmt = db.prepare(`
INSERT INTO settings (key, value) VALUES ('requireLogin', 'true')
ON CONFLICT(key) DO UPDATE SET value = excluded.value
`);
loginStmt.run();
db.close();
rl.close();
console.log("\n✅ Password reset successfully!");
console.log(" Restart OmniRoute for changes to take effect.\n");
}
main().catch((err) => {
console.error(`\n❌ Error: ${err.message}\n`);
rl.close();
process.exit(1);
});
+9 -7
View File
@@ -22,19 +22,21 @@ services:
env_file: .env
environment:
- NODE_ENV=production
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
- PORT=20128
- HOSTNAME=0.0.0.0
- DATA_DIR=/app/data
ports:
- "${PROD_DASHBOARD_PORT:-20130}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${PROD_API_PORT:-20131}:${API_PORT:-20129}"
- "20130:20128"
volumes:
- omniroute-prod-data:/app/data
healthcheck:
test: ["CMD", "node", "healthcheck.mjs"]
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 5s
retries: 3
+10 -18
View File
@@ -18,16 +18,16 @@
x-common: &common
restart: unless-stopped
env_file: .env
environment:
- DATA_DIR=/app/data # Must match the volume mount below
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
volumes:
- omniroute-data:/app/data
healthcheck:
test: ["CMD", "node", "healthcheck.mjs"]
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:20128/api/settings').then(r=>{if(!r.ok)throw r.status}).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 5s
retries: 3
@@ -43,8 +43,7 @@ services:
target: runner-base
image: omniroute:base
ports:
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
- "${PORT:-20128}:20128"
profiles:
- base
@@ -57,8 +56,7 @@ services:
target: runner-cli
image: omniroute:cli
ports:
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
- "${PORT:-20128}:20128"
profiles:
- cli
@@ -71,14 +69,8 @@ services:
target: runner-base
image: omniroute:base
ports:
- "${DASHBOARD_PORT:-${PORT:-20128}}:${DASHBOARD_PORT:-${PORT:-20128}}"
- "${API_PORT:-20129}:${API_PORT:-20129}"
- "${PORT:-20128}:20128"
environment:
- DATA_DIR=/app/data
- PORT=${PORT:-20128}
- DASHBOARD_PORT=${DASHBOARD_PORT:-${PORT:-20128}}
- API_PORT=${API_PORT:-20129}
- API_HOST=${API_HOST:-0.0.0.0}
- CLI_MODE=host
- CLI_EXTRA_PATHS=/host-local/bin:/host-node/bin
- CLI_CONFIG_HOME=/host-home
-441
View File
@@ -1,441 +0,0 @@
# API Reference
🌐 **Languages:** 🇺🇸 [English](API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](i18n/es/API_REFERENCE.md) | 🇫🇷 [Français](i18n/fr/API_REFERENCE.md) | 🇮🇹 [Italiano](i18n/it/API_REFERENCE.md) | 🇷🇺 [Русский](i18n/ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](i18n/de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](i18n/in/API_REFERENCE.md) | 🇹🇭 [ไทย](i18n/th/API_REFERENCE.md) | 🇺🇦 [Українська](i18n/uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](i18n/ar/API_REFERENCE.md) | 🇯🇵 [日本語](i18n/ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/API_REFERENCE.md) | 🇧🇬 [Български](i18n/bg/API_REFERENCE.md) | 🇩🇰 [Dansk](i18n/da/API_REFERENCE.md) | 🇫🇮 [Suomi](i18n/fi/API_REFERENCE.md) | 🇮🇱 [עברית](i18n/he/API_REFERENCE.md) | 🇭🇺 [Magyar](i18n/hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/API_REFERENCE.md) | 🇰🇷 [한국어](i18n/ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](i18n/nl/API_REFERENCE.md) | 🇳🇴 [Norsk](i18n/no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/API_REFERENCE.md) | 🇷🇴 [Română](i18n/ro/API_REFERENCE.md) | 🇵🇱 [Polski](i18n/pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](i18n/sk/API_REFERENCE.md) | 🇸🇪 [Svenska](i18n/sv/API_REFERENCE.md) | 🇵🇭 [Filipino](i18n/phi/API_REFERENCE.md)
Complete reference for all OmniRoute API endpoints.
---
## Table of Contents
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [List Models](#list-models)
- [Compatibility Endpoints](#compatibility-endpoints)
- [Semantic Cache](#semantic-cache)
- [Dashboard & Management](#dashboard--management)
- [Request Processing](#request-processing)
- [Authentication](#authentication)
---
## Chat Completions
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### Custom Headers
| Header | Direction | Description |
| ------------------------ | --------- | --------------------------------- |
| `X-OmniRoute-No-Cache` | Request | Set to `true` to bypass cache |
| `X-OmniRoute-Progress` | Request | Set to `true` for progress events |
| `Idempotency-Key` | Request | Dedup key (5s window) |
| `X-Request-Id` | Request | Alternative dedup key |
| `X-OmniRoute-Cache` | Response | `HIT` or `MISS` (non-streaming) |
| `X-OmniRoute-Idempotent` | Response | `true` if deduplicated |
| `X-OmniRoute-Progress` | Response | `enabled` if progress tracking on |
---
## Embeddings
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
Available providers: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## Image Generation
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
Available providers: OpenAI (DALL-E), xAI (Grok Image), Together AI (FLUX), Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## List Models
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## Compatibility Endpoints
| Method | Path | Format |
| ------ | --------------------------- | ---------------------- |
| POST | `/v1/chat/completions` | OpenAI |
| POST | `/v1/messages` | Anthropic |
| POST | `/v1/responses` | OpenAI Responses |
| POST | `/v1/embeddings` | OpenAI |
| POST | `/v1/images/generations` | OpenAI |
| GET | `/v1/models` | OpenAI |
| POST | `/v1/messages/count_tokens` | Anthropic |
| GET | `/v1beta/models` | Gemini |
| POST | `/v1beta/models/{...path}` | Gemini generateContent |
| POST | `/v1/api/chat` | Ollama |
### Dedicated Provider Routes
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
---
## Semantic Cache
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
Response example:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## Dashboard & Management
### Authentication
| Endpoint | Method | Description |
| ----------------------------- | ------- | --------------------- |
| `/api/auth/login` | POST | Login |
| `/api/auth/logout` | POST | Logout |
| `/api/settings/require-login` | GET/PUT | Toggle login required |
### Provider Management
| Endpoint | Method | Description |
| ---------------------------- | --------------- | ------------------------ |
| `/api/providers` | GET/POST | List / create providers |
| `/api/providers/[id]` | GET/PUT/DELETE | Manage a provider |
| `/api/providers/[id]/test` | POST | Test provider connection |
| `/api/providers/[id]/models` | GET | List provider models |
| `/api/providers/validate` | POST | Validate provider config |
| `/api/provider-nodes*` | Various | Provider node management |
| `/api/provider-models` | GET/POST/DELETE | Custom models |
### OAuth Flows
| Endpoint | Method | Description |
| -------------------------------- | ------- | ----------------------- |
| `/api/oauth/[provider]/[action]` | Various | Provider-specific OAuth |
### Routing & Config
| Endpoint | Method | Description |
| --------------------- | -------- | ----------------------------- |
| `/api/models/alias` | GET/POST | Model aliases |
| `/api/models/catalog` | GET | All models by provider + type |
| `/api/combos*` | Various | Combo management |
| `/api/keys*` | Various | API key management |
| `/api/pricing` | GET | Model pricing |
### Usage & Analytics
| Endpoint | Method | Description |
| --------------------------- | ------ | -------------------- |
| `/api/usage/history` | GET | Usage history |
| `/api/usage/logs` | GET | Usage logs |
| `/api/usage/request-logs` | GET | Request-level logs |
| `/api/usage/[connectionId]` | GET | Per-connection usage |
### Settings
| Endpoint | Method | Description |
| ------------------------------- | ------- | ---------------------- |
| `/api/settings` | GET/PUT | General settings |
| `/api/settings/proxy` | GET/PUT | Network proxy config |
| `/api/settings/proxy/test` | POST | Test proxy connection |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt |
### Monitoring
| Endpoint | Method | Description |
| ------------------------ | ---------- | ----------------------- |
| `/api/sessions` | GET | Active session tracking |
| `/api/rate-limits` | GET | Per-account rate limits |
| `/api/monitoring/health` | GET | Health check |
| `/api/cache` | GET/DELETE | Cache stats / clear |
### Backup & Export/Import
| Endpoint | Method | Description |
| --------------------------- | ------ | --------------------------------------- |
| `/api/db-backups` | GET | List available backups |
| `/api/db-backups` | PUT | Create a manual backup |
| `/api/db-backups` | POST | Restore from a specific backup |
| `/api/db-backups/export` | GET | Download database as .sqlite file |
| `/api/db-backups/import` | POST | Upload .sqlite file to replace database |
| `/api/db-backups/exportAll` | GET | Download full backup as .tar.gz archive |
### Cloud Sync
| Endpoint | Method | Description |
| ---------------------- | ------- | --------------------- |
| `/api/sync/cloud` | Various | Cloud sync operations |
| `/api/sync/initialize` | POST | Initialize sync |
| `/api/cloud/*` | Various | Cloud management |
### CLI Tools
| Endpoint | Method | Description |
| ---------------------------------- | ------ | ------------------- |
| `/api/cli-tools/claude-settings` | GET | Claude CLI status |
| `/api/cli-tools/codex-settings` | GET | Codex CLI status |
| `/api/cli-tools/droid-settings` | GET | Droid CLI status |
| `/api/cli-tools/openclaw-settings` | GET | OpenClaw CLI status |
| `/api/cli-tools/runtime/[toolId]` | GET | Generic CLI runtime |
CLI responses include: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`.
### Resilience & Rate Limits
| Endpoint | Method | Description |
| ----------------------- | ------- | ------------------------------- |
| `/api/resilience` | GET/PUT | Get/update resilience profiles |
| `/api/resilience/reset` | POST | Reset circuit breakers |
| `/api/rate-limits` | GET | Per-account rate limit status |
| `/api/rate-limit` | GET | Global rate limit configuration |
### Evals
| Endpoint | Method | Description |
| ------------ | -------- | --------------------------------- |
| `/api/evals` | GET/POST | List eval suites / run evaluation |
### Policies
| Endpoint | Method | Description |
| --------------- | --------------- | ----------------------- |
| `/api/policies` | GET/POST/DELETE | Manage routing policies |
### Compliance
| Endpoint | Method | Description |
| --------------------------- | ------ | ----------------------------- |
| `/api/compliance/audit-log` | GET | Compliance audit log (last N) |
### v1beta (Gemini-Compatible)
| Endpoint | Method | Description |
| -------------------------- | ------ | --------------------------------- |
| `/v1beta/models` | GET | List models in Gemini format |
| `/v1beta/models/{...path}` | POST | Gemini `generateContent` endpoint |
These endpoints mirror Gemini's API format for clients that expect native Gemini SDK compatibility.
### Internal / System APIs
| Endpoint | Method | Description |
| --------------- | ------ | ---------------------------------------------------- |
| `/api/init` | GET | Application initialization check (used on first run) |
| `/api/tags` | GET | Ollama-compatible model tags (for Ollama clients) |
| `/api/restart` | POST | Trigger graceful server restart |
| `/api/shutdown` | POST | Trigger graceful server shutdown |
> **Note:** These endpoints are used internally by the system or for Ollama client compatibility. They are not typically called by end users.
---
## Audio Transcription
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
Transcribe audio files using Deepgram or AssemblyAI.
**Request:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**Response:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**Supported providers:** `deepgram/nova-3`, `assemblyai/best`.
**Supported formats:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
## Ollama Compatibility
For clients that use Ollama's API format:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
Requests are automatically translated between Ollama and internal formats.
---
## Telemetry
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**Response:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## Budget
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## Model Availability
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## Request Processing
1. Client sends request to `/v1/*`
2. Route handler calls `handleChat`, `handleEmbedding`, `handleAudioTranscription`, or `handleImageGeneration`
3. Model is resolved (direct provider/model or alias/combo)
4. Credentials selected from local DB with account availability filtering
5. For chat: `handleChatCore` — format detection, translation, cache check, idempotency check
6. Provider executor sends upstream request
7. Response translated back to client format (chat) or returned as-is (embeddings/images/audio)
8. Usage/logging recorded
9. Fallback applies on errors according to combo rules
Full architecture reference: [`ARCHITECTURE.md`](ARCHITECTURE.md)
---
## Authentication
- Dashboard routes (`/dashboard/*`) use `auth_token` cookie
- Login uses saved password hash; fallback to `INITIAL_PASSWORD`
- `requireLogin` toggleable via `/api/settings/require-login`
- `/v1/*` routes optionally require Bearer API key when `REQUIRE_API_KEY=true`
+56 -171
View File
@@ -1,8 +1,6 @@
# OmniRoute Architecture
🌐 **Languages:** 🇺🇸 [English](ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](i18n/es/ARCHITECTURE.md) | 🇫🇷 [Français](i18n/fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](i18n/it/ARCHITECTURE.md) | 🇷🇺 [Русский](i18n/ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](i18n/de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](i18n/in/ARCHITECTURE.md) | 🇹🇭 [ไทย](i18n/th/ARCHITECTURE.md) | 🇺🇦 [Українська](i18n/uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](i18n/ar/ARCHITECTURE.md) | 🇯🇵 [日本語](i18n/ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/ARCHITECTURE.md) | 🇧🇬 [Български](i18n/bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](i18n/da/ARCHITECTURE.md) | 🇫🇮 [Suomi](i18n/fi/ARCHITECTURE.md) | 🇮🇱 [עברית](i18n/he/ARCHITECTURE.md) | 🇭🇺 [Magyar](i18n/hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/ARCHITECTURE.md) | 🇰🇷 [한국어](i18n/ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](i18n/nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](i18n/no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/ARCHITECTURE.md) | 🇷🇴 [Română](i18n/ro/ARCHITECTURE.md) | 🇵🇱 [Polski](i18n/pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](i18n/sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](i18n/sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](i18n/phi/ARCHITECTURE.md)
_Last updated: 2026-02-18_
_Last updated: 2026-02-09_
## Executive Summary
@@ -19,29 +17,9 @@ Core capabilities:
- Embedding generation via `/v1/embeddings` (6 providers, 9 models)
- Image generation via `/v1/images/generations` (4 providers, 9 models)
- Think tag parsing (`<think>...</think>`) for reasoning models
- Response sanitization for strict OpenAI SDK compatibility
- Role normalization (developer→system, system→user) for cross-provider compatibility
- Structured output conversion (json_schema → Gemini responseSchema)
- Local persistence for providers, keys, aliases, combos, settings, pricing
- Usage/cost tracking and request logging
- Optional cloud sync for multi-device/state sync
- IP allowlist/blocklist for API access control
- Thinking budget management (passthrough/auto/custom/adaptive)
- Global system prompt injection
- Session tracking and fingerprinting
- Per-account enhanced rate limiting with provider-specific profiles
- Circuit breaker pattern for provider resilience
- Anti-thundering herd protection with mutex locking
- Signature-based request deduplication cache
- Domain layer: model availability, cost rules, fallback policy, lockout policy
- Domain state persistence (SQLite write-through cache for fallbacks, budgets, lockouts, circuit breakers)
- Policy engine for centralized request evaluation (lockout → budget → fallback)
- Request telemetry with p50/p95/p99 latency aggregation
- Correlation ID (X-Request-Id) for end-to-end tracing
- Compliance audit logging with opt-out per API key
- Eval framework for LLM quality assurance
- Resilience UI dashboard with real-time circuit breaker status
- Modular OAuth providers (12 individual modules under `src/lib/oauth/providers/`)
Primary runtime model:
@@ -125,18 +103,18 @@ Main directories:
Important compatibility routes:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — includes custom models with `custom: true`
- `src/app/api/v1/embeddings/route.ts` — embedding generation (6 providers)
- `src/app/api/v1/images/generations/route.ts` — image generation (4+ providers incl. Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — dedicated per-provider chat
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — dedicated per-provider embeddings
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — dedicated per-provider images
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
- `src/app/api/v1/chat/completions/route.js`
- `src/app/api/v1/messages/route.js`
- `src/app/api/v1/responses/route.js`
- `src/app/api/v1/models/route.js` — includes custom models with `custom: true`
- `src/app/api/v1/embeddings/route.js` — embedding generation (6 providers)
- `src/app/api/v1/images/generations/route.js` — image generation (4+ providers incl. Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.js`
- `src/app/api/v1/providers/[provider]/chat/completions/route.js` — dedicated per-provider chat
- `src/app/api/v1/providers/[provider]/embeddings/route.js` — dedicated per-provider embeddings
- `src/app/api/v1/providers/[provider]/images/generations/route.js` — dedicated per-provider images
- `src/app/api/v1beta/models/route.js`
- `src/app/api/v1beta/models/[...path]/route.js`
Management domains:
@@ -151,111 +129,52 @@ Management domains:
- Usage: `src/app/api/usage/*`
- Sync/cloud: `src/app/api/sync/*`, `src/app/api/cloud/*`
- CLI tooling helpers: `src/app/api/cli-tools/*`
- IP filter: `src/app/api/settings/ip-filter` (GET/PUT)
- Thinking budget: `src/app/api/settings/thinking-budget` (GET/PUT)
- System prompt: `src/app/api/settings/system-prompt` (GET/PUT)
- Sessions: `src/app/api/sessions` (GET)
- Rate limits: `src/app/api/rate-limits` (GET)
- Resilience: `src/app/api/resilience` (GET/PATCH) — provider profiles, circuit breaker, rate limit state
- Resilience reset: `src/app/api/resilience/reset` (POST) — reset breakers + cooldowns
- Cache stats: `src/app/api/cache/stats` (GET/DELETE)
- Model availability: `src/app/api/models/availability` (GET/POST)
- Telemetry: `src/app/api/telemetry/summary` (GET)
- Budget: `src/app/api/usage/budget` (GET/POST)
- Fallback chains: `src/app/api/fallback/chains` (GET/POST/DELETE)
- Compliance audit: `src/app/api/compliance/audit-log` (GET)
- Evals: `src/app/api/evals` (GET/POST), `src/app/api/evals/[suiteId]` (GET)
- Policies: `src/app/api/policies` (GET/POST)
## 2) SSE + Translation Core
Main flow modules:
- Entry: `src/sse/handlers/chat.ts`
- Core orchestration: `open-sse/handlers/chatCore.ts`
- Entry: `src/sse/handlers/chat.js`
- Core orchestration: `open-sse/handlers/chatCore.js`
- Provider execution adapters: `open-sse/executors/*`
- Format detection/provider config: `open-sse/services/provider.ts`
- Model parse/resolve: `src/sse/services/model.ts`, `open-sse/services/model.ts`
- Account fallback logic: `open-sse/services/accountFallback.ts`
- Translation registry: `open-sse/translator/index.ts`
- Stream transformations: `open-sse/utils/stream.ts`, `open-sse/utils/streamHandler.ts`
- Usage extraction/normalization: `open-sse/utils/usageTracking.ts`
- Think tag parser: `open-sse/utils/thinkTagParser.ts`
- Embedding handler: `open-sse/handlers/embeddings.ts`
- Embedding provider registry: `open-sse/config/embeddingRegistry.ts`
- Image generation handler: `open-sse/handlers/imageGeneration.ts`
- Image provider registry: `open-sse/config/imageRegistry.ts`
- Response sanitization: `open-sse/handlers/responseSanitizer.ts`
- Role normalization: `open-sse/services/roleNormalizer.ts`
Services (business logic):
- Account selection/scoring: `open-sse/services/accountSelector.ts`
- Context lifecycle management: `open-sse/services/contextManager.ts`
- IP filter enforcement: `open-sse/services/ipFilter.ts`
- Session tracking: `open-sse/services/sessionManager.ts`
- Request deduplication: `open-sse/services/signatureCache.ts`
- System prompt injection: `open-sse/services/systemPrompt.ts`
- Thinking budget management: `open-sse/services/thinkingBudget.ts`
- Wildcard model routing: `open-sse/services/wildcardRouter.ts`
- Rate limit management: `open-sse/services/rateLimitManager.ts`
- Circuit breaker: `open-sse/services/circuitBreaker.ts`
Domain layer modules:
- Model availability: `src/lib/domain/modelAvailability.ts`
- Cost rules/budgets: `src/lib/domain/costRules.ts`
- Fallback policy: `src/lib/domain/fallbackPolicy.ts`
- Combo resolver: `src/lib/domain/comboResolver.ts`
- Lockout policy: `src/lib/domain/lockoutPolicy.ts`
- Policy engine: `src/domain/policyEngine.ts` — centralized lockout → budget → fallback evaluation
- Error codes catalog: `src/lib/domain/errorCodes.ts`
- Request ID: `src/lib/domain/requestId.ts`
- Fetch timeout: `src/lib/domain/fetchTimeout.ts`
- Request telemetry: `src/lib/domain/requestTelemetry.ts`
- Compliance/audit: `src/lib/domain/compliance/index.ts`
- Eval runner: `src/lib/domain/evalRunner.ts`
- Domain state persistence: `src/lib/db/domainState.ts` — SQLite CRUD for fallback chains, budgets, cost history, lockout state, circuit breakers
OAuth provider modules (12 individual files under `src/lib/oauth/providers/`):
- Registry index: `src/lib/oauth/providers/index.ts`
- Individual providers: `claude.ts`, `codex.ts`, `gemini.ts`, `antigravity.ts`, `iflow.ts`, `qwen.ts`, `kimi-coding.ts`, `github.ts`, `kiro.ts`, `cursor.ts`, `kilocode.ts`, `cline.ts`
- Thin wrapper: `src/lib/oauth/providers.ts` — re-exports from individual modules
- Format detection/provider config: `open-sse/services/provider.js`
- Model parse/resolve: `src/sse/services/model.js`, `open-sse/services/model.js`
- Account fallback logic: `open-sse/services/accountFallback.js`
- Translation registry: `open-sse/translator/index.js`
- Stream transformations: `open-sse/utils/stream.js`, `open-sse/utils/streamHandler.js`
- Usage extraction/normalization: `open-sse/utils/usageTracking.js`
- Think tag parser: `open-sse/utils/thinkTagParser.js`
- Embedding handler: `open-sse/handlers/embeddings.js`
- Embedding provider registry: `open-sse/config/embeddingRegistry.js`
- Image generation handler: `open-sse/handlers/imageGeneration.js`
- Image provider registry: `open-sse/config/imageRegistry.js`
## 3) Persistence Layer
Primary state DB:
- `src/lib/localDb.ts`
- `src/lib/localDb.js`
- 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**
- entities: providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**
Usage DB:
- `src/lib/usageDb.ts`
- `src/lib/usageDb.js`
- 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`
Domain State DB (SQLite):
- `src/lib/db/domainState.ts` — CRUD operations for domain state
- Tables (created in `src/lib/db/core.ts`): `domain_fallback_chains`, `domain_budgets`, `domain_cost_history`, `domain_lockout_state`, `domain_circuit_breakers`
- Write-through cache pattern: in-memory Maps are authoritative at runtime; mutations are written synchronously to SQLite; state is restored from DB on cold start
## 4) Auth + Security Surfaces
- Dashboard cookie auth: `src/proxy.ts`, `src/app/api/auth/login/route.ts`
- API key generation/verification: `src/shared/utils/apiKey.ts`
- Dashboard cookie auth: `src/proxy.js`, `src/app/api/auth/login/route.js`
- API key generation/verification: `src/shared/utils/apiKey.js`
- Provider secrets persisted in `providerConnections` entries
- Outbound proxy support via `open-sse/utils/proxyFetch.ts` (env vars) and `open-sse/utils/networkProxy.ts` (configurable per-provider or global)
- Outbound proxy support via `open-sse/utils/proxyFetch.js` (env vars) and `open-sse/utils/networkProxy.js` (configurable per-provider or global)
## 5) Cloud Sync
- Scheduler init: `src/lib/initCloudSync.ts`, `src/shared/services/initializeCloudSync.ts`
- Periodic task: `src/shared/services/cloudSyncScheduler.ts`
- Control route: `src/app/api/sync/cloud/route.ts`
- Scheduler init: `src/lib/initCloudSync.js`, `src/shared/services/initializeCloudSync.js`
- Periodic task: `src/shared/services/cloudSyncScheduler.js`
- Control route: `src/app/api/sync/cloud/route.js`
## Request Lifecycle (`/v1/chat/completions`)
@@ -334,7 +253,7 @@ flowchart TD
Q -- No --> R[Return all unavailable]
```
Fallback decisions are driven by `open-sse/services/accountFallback.ts` using status codes and error-message heuristics.
Fallback decisions are driven by `open-sse/services/accountFallback.js` using status codes and error-message heuristics.
## OAuth Onboarding and Token Refresh Lifecycle
@@ -366,7 +285,7 @@ sequenceDiagram
Test-->>UI: validation result
```
Refresh during live traffic is executed inside `open-sse/handlers/chatCore.ts` via executor `refreshCredentials()`.
Refresh during live traffic is executed inside `open-sse/handlers/chatCore.js` via executor `refreshCredentials()`.
## Cloud Sync Lifecycle (Enable / Sync / Disable)
@@ -415,9 +334,6 @@ erDiagram
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
@@ -483,24 +399,6 @@ erDiagram
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
Physical storage files:
@@ -561,33 +459,28 @@ flowchart LR
- `src/app/api/usage/*`: usage and logs APIs
- `src/app/api/sync/*` + `src/app/api/cloud/*`: cloud sync and cloud-facing helpers
- `src/app/api/cli-tools/*`: local CLI config writers/checkers
- `src/app/api/settings/ip-filter`: IP allowlist/blocklist (GET/PUT)
- `src/app/api/settings/thinking-budget`: thinking token budget config (GET/PUT)
- `src/app/api/settings/system-prompt`: global system prompt (GET/PUT)
- `src/app/api/sessions`: active session listing (GET)
- `src/app/api/rate-limits`: per-account rate limit status (GET)
### Routing and Execution Core
- `src/sse/handlers/chat.ts`: request parse, combo handling, account selection loop
- `open-sse/handlers/chatCore.ts`: translation, executor dispatch, retry/refresh handling, stream setup
- `src/sse/handlers/chat.js`: request parse, combo handling, account selection loop
- `open-sse/handlers/chatCore.js`: translation, executor dispatch, retry/refresh handling, stream setup
- `open-sse/executors/*`: provider-specific network and format behavior
### Translation Registry and Format Converters
- `open-sse/translator/index.ts`: translator registry and orchestration
- `open-sse/translator/index.js`: translator registry and orchestration
- Request translators: `open-sse/translator/request/*`
- Response translators: `open-sse/translator/response/*`
- Format constants: `open-sse/translator/formats.ts`
- Format constants: `open-sse/translator/formats.js`
### Persistence
- `src/lib/localDb.ts`: persistent config/state
- `src/lib/usageDb.ts`: usage history and rolling request logs
- `src/lib/localDb.js`: persistent config/state
- `src/lib/usageDb.js`: usage history and rolling request logs
## Provider Executor Coverage (Strategy Pattern)
Each provider has a specialized executor extending `BaseExecutor` (in `open-sse/executors/base.ts`), which provides URL building, header construction, retry with exponential backoff, credential refresh hooks, and the `execute()` orchestration method.
Each provider has a specialized executor extending `BaseExecutor` (in `open-sse/executors/base.js`), which provides URL building, header construction, retry with exponential backoff, credential refresh hooks, and the `execute()` orchestration method.
| Executor | Provider(s) | Special Handling |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
@@ -654,23 +547,16 @@ Source Format → OpenAI (hub) → Target Format
Translations are selected dynamically based on source payload shape and provider target format.
Additional processing layers in the translation pipeline:
- **Response sanitization** — Strips non-standard fields from OpenAI-format responses (both streaming and non-streaming) to ensure strict SDK compliance
- **Role normalization** — Converts `developer``system` for non-OpenAI targets; merges `system``user` for models that reject the system role (GLM, ERNIE)
- **Think tag extraction** — Parses `<think>...</think>` blocks from content into `reasoning_content` field
- **Structured output** — Converts OpenAI `response_format.json_schema` to Gemini's `responseMimeType` + `responseSchema`
## Supported API Endpoints
| Endpoint | Format | Handler |
| -------------------------------------------------- | ------------------ | ---------------------------------------------------- |
| `POST /v1/chat/completions` | OpenAI Chat | `src/sse/handlers/chat.ts` |
| `POST /v1/chat/completions` | OpenAI Chat | `src/sse/handlers/chat.js` |
| `POST /v1/messages` | Claude Messages | Same handler (auto-detected) |
| `POST /v1/responses` | OpenAI Responses | `open-sse/handlers/responsesHandler.ts` |
| `POST /v1/embeddings` | OpenAI Embeddings | `open-sse/handlers/embeddings.ts` |
| `POST /v1/responses` | OpenAI Responses | `open-sse/handlers/responsesHandler.js` |
| `POST /v1/embeddings` | OpenAI Embeddings | `open-sse/handlers/embeddings.js` |
| `GET /v1/embeddings` | Model listing | API route |
| `POST /v1/images/generations` | OpenAI Images | `open-sse/handlers/imageGeneration.ts` |
| `POST /v1/images/generations` | OpenAI Images | `open-sse/handlers/imageGeneration.js` |
| `GET /v1/images/generations` | Model listing | API route |
| `POST /v1/providers/{provider}/chat/completions` | OpenAI Chat | Dedicated per-provider with model validation |
| `POST /v1/providers/{provider}/embeddings` | OpenAI Embeddings | Dedicated per-provider with model validation |
@@ -685,11 +571,11 @@ Additional processing layers in the translation pipeline:
## Bypass Handler
The bypass handler (`open-sse/utils/bypassHandler.ts`) intercepts known "throwaway" requests from Claude CLI — warmup pings, title extractions, and token counts — and returns a **fake response** without consuming upstream provider tokens. This is triggered only when `User-Agent` contains `claude-cli`.
The bypass handler (`open-sse/utils/bypassHandler.js`) intercepts known "throwaway" requests from Claude CLI — warmup pings, title extractions, and token counts — and returns a **fake response** without consuming upstream provider tokens. This is triggered only when `User-Agent` contains `claude-cli`.
## Request Logger Pipeline
The request logger (`open-sse/utils/requestLogger.ts`) provides a 7-stage debug logging pipeline, disabled by default, enabled via `ENABLE_REQUEST_LOGS=true`:
The request logger (`open-sse/utils/requestLogger.js`) provides a 7-stage debug logging pipeline, disabled by default, enabled via `ENABLE_REQUEST_LOGS=true`:
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
@@ -731,7 +617,7 @@ Files are written to `<repo>/logs/<session>/` for each request session.
Runtime visibility sources:
- console logs from `src/sse/utils/logger.ts`
- console logs from `src/sse/utils/logger.js`
- per-request usage aggregates in `usage.json`
- textual request status log in `log.txt`
- optional deep request/translation logs under `logs/` when `ENABLE_REQUEST_LOGS=true`
@@ -763,18 +649,17 @@ 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`.
2. `/api/v1/route.js` returns a static model list and is not the main models source used by `/v1/models`.
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`).
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).
6. Charts in the dashboard use **Recharts** (SVG-based) for accessible, interactive visualizations (bar charts, donut charts).
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`.
## Operational Verification Checklist
- Build from source: `npm run build`
- Build Docker image: `docker build -t omniroute .`
- Build from source: `cd /root/dev/omniroute && npm run build`
- Build Docker image: `cd /root/dev/omniroute && docker build -t omniroute .`
- Start service and verify:
- `GET /api/settings`
- `GET /api/v1/models`
+38 -53
View File
@@ -1,7 +1,5 @@
# omniroute — Codebase Documentation
🌐 **Languages:** 🇺🇸 [English](CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](i18n/es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](i18n/fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](i18n/it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](i18n/ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](i18n/de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](i18n/in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](i18n/th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](i18n/uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](i18n/ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](i18n/ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](i18n/vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](i18n/bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](i18n/da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](i18n/fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](i18n/he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](i18n/hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](i18n/ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](i18n/nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](i18n/no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](i18n/pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](i18n/ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](i18n/pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](i18n/sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](i18n/sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](i18n/phi/CODEBASE_DOCUMENTATION.md)
> A comprehensive, beginner-friendly guide to the **omniroute** multi-provider AI proxy router.
---
@@ -112,18 +110,18 @@ The **single source of truth** for all provider configuration.
| File | Purpose |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constants.ts` | `PROVIDERS` object with base URLs, OAuth credentials (defaults), headers, and default system prompts for every provider. Also defines `HTTP_STATUS`, `ERROR_TYPES`, `COOLDOWN_MS`, `BACKOFF_CONFIG`, and `SKIP_PATTERNS`. |
| `credentialLoader.ts` | Loads external credentials from `data/provider-credentials.json` and merges them over the hardcoded defaults in `PROVIDERS`. Keeps secrets out of source control while maintaining backwards compatibility. |
| `providerModels.ts` | Central model registry: maps provider aliases → model IDs. Functions like `getModels()`, `getProviderByAlias()`. |
| `codexInstructions.ts` | System instructions injected into Codex requests (editing constraints, sandbox rules, approval policies). |
| `defaultThinkingSignature.ts` | Default "thinking" signatures for Claude and Gemini models. |
| `ollamaModels.ts` | Schema definition for local Ollama models (name, size, family, quantization). |
| `constants.js` | `PROVIDERS` object with base URLs, OAuth credentials (defaults), headers, and default system prompts for every provider. Also defines `HTTP_STATUS`, `ERROR_TYPES`, `COOLDOWN_MS`, `BACKOFF_CONFIG`, and `SKIP_PATTERNS`. |
| `credentialLoader.js` | Loads external credentials from `data/provider-credentials.json` and merges them over the hardcoded defaults in `PROVIDERS`. Keeps secrets out of source control while maintaining backwards compatibility. |
| `providerModels.js` | Central model registry: maps provider aliases → model IDs. Functions like `getModels()`, `getProviderByAlias()`. |
| `codexInstructions.js` | System instructions injected into Codex requests (editing constraints, sandbox rules, approval policies). |
| `defaultThinkingSignature.js` | Default "thinking" signatures for Claude and Gemini models. |
| `ollamaModels.js` | Schema definition for local Ollama models (name, size, family, quantization). |
#### Credential Loading Flow
```mermaid
flowchart TD
A["App starts"] --> B["constants.ts defines PROVIDERS\nwith hardcoded defaults"]
A["App starts"] --> B["constants.js defines PROVIDERS\nwith hardcoded defaults"]
B --> C{"data/provider-credentials.json\nexists?"}
C -->|Yes| D["credentialLoader reads JSON"]
C -->|No| E["Use hardcoded defaults"]
@@ -196,15 +194,15 @@ classDiagram
| Executor | Provider | Key Specializations |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `base.ts` | — | Abstract base: URL building, headers, retry logic, credential refresh |
| `default.ts` | Claude, Gemini, OpenAI, GLM, Kimi, MiniMax | Generic OAuth token refresh for standard providers |
| `antigravity.ts` | Google Cloud Code | Project/session ID generation, multi-URL fallback, custom retry parsing from error messages ("reset after 2h7m23s") |
| `cursor.ts` | Cursor IDE | **Most complex**: SHA-256 checksum auth, Protobuf request encoding, binary EventStream → SSE response parsing |
| `codex.ts` | OpenAI Codex | Injects system instructions, manages thinking levels, removes unsupported parameters |
| `gemini-cli.ts` | Google Gemini CLI | Custom URL building (`streamGenerateContent`), Google OAuth token refresh |
| `github.ts` | GitHub Copilot | Dual token system (GitHub OAuth + Copilot token), VSCode header mimicking |
| `kiro.ts` | AWS CodeWhisperer | AWS EventStream binary parsing, AMZN event frames, token estimation |
| `index.ts` | — | Factory: maps provider name → executor class, with default fallback |
| `base.js` | — | Abstract base: URL building, headers, retry logic, credential refresh |
| `default.js` | Claude, Gemini, OpenAI, GLM, Kimi, MiniMax | Generic OAuth token refresh for standard providers |
| `antigravity.js` | Google Cloud Code | Project/session ID generation, multi-URL fallback, custom retry parsing from error messages ("reset after 2h7m23s") |
| `cursor.js` | Cursor IDE | **Most complex**: SHA-256 checksum auth, Protobuf request encoding, binary EventStream → SSE response parsing |
| `codex.js` | OpenAI Codex | Injects system instructions, manages thinking levels, removes unsupported parameters |
| `gemini-cli.js` | Google Gemini CLI | Custom URL building (`streamGenerateContent`), Google OAuth token refresh |
| `github.js` | GitHub Copilot | Dual token system (GitHub OAuth + Copilot token), VSCode header mimicking |
| `kiro.js` | AWS CodeWhisperer | AWS EventStream binary parsing, AMZN event frames, token estimation |
| `index.js` | — | Factory: maps provider name → executor class, with default fallback |
---
@@ -214,12 +212,12 @@ The **orchestration layer** — coordinates translation, execution, streaming, a
| File | Purpose |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chatCore.ts` | **Central orchestrator** (~600 lines). Handles the complete request lifecycle: format detection → translation → executor dispatch → streaming/non-streaming response → token refresh → error handling → usage logging. |
| `responsesHandler.ts` | Adapter for OpenAI's Responses API: converts Responses format → Chat Completions → sends to `chatCore` → converts SSE back to Responses format. |
| `embeddings.ts` | Embedding generation handler: resolves embedding model → provider, dispatches to provider API, returns OpenAI-compatible embedding response. Supports 6+ providers. |
| `imageGeneration.ts` | Image generation handler: resolves image model → provider, supports OpenAI-compatible, Gemini-image (Antigravity), and fallback (Nebius) modes. Returns base64 or URL images. |
| `chatCore.js` | **Central orchestrator** (~600 lines). Handles the complete request lifecycle: format detection → translation → executor dispatch → streaming/non-streaming response → token refresh → error handling → usage logging. |
| `responsesHandler.js` | Adapter for OpenAI's Responses API: converts Responses format → Chat Completions → sends to `chatCore` → converts SSE back to Responses format. |
| `embeddings.js` | Embedding generation handler: resolves embedding model → provider, dispatches to provider API, returns OpenAI-compatible embedding response. Supports 6+ providers. |
| `imageGeneration.js` | Image generation handler: resolves image model → provider, supports OpenAI-compatible, Gemini-image (Antigravity), and fallback (Nebius) modes. Returns base64 or URL images. |
#### Request Lifecycle (chatCore.ts)
#### Request Lifecycle (chatCore.js)
```mermaid
sequenceDiagram
@@ -264,20 +262,12 @@ Business logic that supports the handlers and executors.
| File | Purpose |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider.ts` | **Format detection** (`detectFormat`): analyzes request body structure to identify Claude/OpenAI/Gemini/Antigravity/Responses formats (includes `max_tokens` heuristic for Claude). Also: URL building, header building, thinking config normalization. Supports `openai-compatible-*` and `anthropic-compatible-*` dynamic providers. |
| `model.ts` | Model string parsing (`claude/model-name``{provider: "claude", model: "model-name"}`), alias resolution with collision detection, input sanitization (rejects path traversal/control chars), and model info resolution with async alias getter support. |
| `accountFallback.ts` | Rate-limit handling: exponential backoff (1s → 2s → 4s → max 2min), account cooldown management, error classification (which errors trigger fallback vs. not). |
| `tokenRefresh.ts` | OAuth token refresh for **every provider**: Google (Gemini, Antigravity), Claude, Codex, Qwen, iFlow, GitHub (OAuth + Copilot dual-token), Kiro (AWS SSO OIDC + Social Auth). Includes in-flight promise deduplication cache and retry with exponential backoff. |
| `combo.ts` | **Combo models**: chains of fallback models. If model A fails with a fallback-eligible error, try model B, then C, etc. Returns actual upstream status codes. |
| `usage.ts` | Fetches quota/usage data from provider APIs (GitHub Copilot quotas, Antigravity model quotas, Codex rate limits, Kiro usage breakdowns, Claude settings). |
| `accountSelector.ts` | Smart account selection with scoring algorithm: considers priority, health status, round-robin position, and cooldown state to pick the optimal account for each request. |
| `contextManager.ts` | Request context lifecycle management: creates and tracks per-request context objects with metadata (request ID, timestamps, provider info) for debugging and logging. |
| `ipFilter.ts` | IP-based access control: supports allowlist and blocklist modes. Validates client IP against configured rules before processing API requests. |
| `sessionManager.ts` | Session tracking with client fingerprinting: tracks active sessions using hashed client identifiers, monitors request counts, and provides session metrics. |
| `signatureCache.ts` | Request signature-based deduplication cache: prevents duplicate requests by caching recent request signatures and returning cached responses for identical requests within a time window. |
| `systemPrompt.ts` | Global system prompt injection: prepends or appends a configurable system prompt to all requests, with per-provider compatibility handling. |
| `thinkingBudget.ts` | Reasoning token budget management: supports passthrough, auto (strip thinking config), custom (fixed budget), and adaptive (complexity-scaled) modes for controlling thinking/reasoning tokens. |
| `wildcardRouter.ts` | Wildcard model pattern routing: resolves wildcard patterns (e.g., `*/claude-*`) to concrete provider/model pairs based on availability and priority. |
| `provider.js` | **Format detection** (`detectFormat`): analyzes request body structure to identify Claude/OpenAI/Gemini/Antigravity/Responses formats (includes `max_tokens` heuristic for Claude). Also: URL building, header building, thinking config normalization. Supports `openai-compatible-*` and `anthropic-compatible-*` dynamic providers. |
| `model.js` | Model string parsing (`claude/model-name``{provider: "claude", model: "model-name"}`), alias resolution with collision detection, input sanitization (rejects path traversal/control chars), and model info resolution with async alias getter support. |
| `accountFallback.js` | Rate-limit handling: exponential backoff (1s → 2s → 4s → max 2min), account cooldown management, error classification (which errors trigger fallback vs. not). |
| `tokenRefresh.js` | OAuth token refresh for **every provider**: Google (Gemini, Antigravity), Claude, Codex, Qwen, iFlow, GitHub (OAuth + Copilot dual-token), Kiro (AWS SSO OIDC + Social Auth). Includes in-flight promise deduplication cache and retry with exponential backoff. |
| `combo.js` | **Combo models**: chains of fallback models. If model A fails with a fallback-eligible error, try model B, then C, etc. Returns actual upstream status codes. |
| `usage.js` | Fetches quota/usage data from provider APIs (GitHub Copilot quotas, Antigravity model quotas, Codex rate limits, Kiro usage breakdowns, Claude settings). |
#### Token Refresh Deduplication
@@ -379,8 +369,8 @@ graph TD
| `request/` | 8 translators | Convert request bodies between formats. Each file self-registers via `register(from, to, fn)` on import. |
| `response/` | 7 translators | Convert streaming response chunks between formats. Handles SSE event types, thinking blocks, tool calls. |
| `helpers/` | 6 helpers | Shared utilities: `claudeHelper` (system prompt extraction, thinking config), `geminiHelper` (parts/contents mapping), `openaiHelper` (format filtering), `toolCallHelper` (ID generation, missing response injection), `maxTokensHelper`, `responsesApiHelper`. |
| `index.ts` | — | Translation engine: `translateRequest()`, `translateResponse()`, state management, registry. |
| `formats.ts` | — | Format constants: `OPENAI`, `CLAUDE`, `GEMINI`, `ANTIGRAVITY`, `KIRO`, `CURSOR`, `OPENAI_RESPONSES`. |
| `index.js` | — | Translation engine: `translateRequest()`, `translateResponse()`, state management, registry. |
| `formats.js` | — | Format constants: `OPENAI`, `CLAUDE`, `GEMINI`, `ANTIGRAVITY`, `KIRO`, `CURSOR`, `OPENAI_RESPONSES`. |
#### Key Design: Self-Registering Plugins
@@ -399,13 +389,13 @@ import "./request/claude-to-openai.js"; // ← self-registers
| File | Purpose |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `error.ts` | Error response building (OpenAI-compatible format), upstream error parsing, Antigravity retry-time extraction from error messages, SSE error streaming. |
| `stream.ts` | **SSE Transform Stream** — the core streaming pipeline. Two modes: `TRANSLATE` (full format translation) and `PASSTHROUGH` (normalize + extract usage). Handles chunk buffering, usage estimation, content length tracking. Per-stream encoder/decoder instances avoid shared state. |
| `streamHelpers.ts` | Low-level SSE utilities: `parseSSELine` (whitespace-tolerant), `hasValuableContent` (filters empty chunks for OpenAI/Claude/Gemini), `fixInvalidId`, `formatSSE` (format-aware SSE serialization with `perf_metrics` cleanup). |
| `usageTracking.ts` | Token usage extraction from any format (Claude/OpenAI/Gemini/Responses), estimation with separate tool/message char-per-token ratios, buffer addition (2000 tokens safety margin), format-specific field filtering, console logging with ANSI colors. |
| `requestLogger.ts` | File-based request logging (opt-in via `ENABLE_REQUEST_LOGS=true`). Creates session folders with numbered files: `1_req_client.json``7_res_client.txt`. All I/O is async (fire-and-forget). Masks sensitive headers. |
| `bypassHandler.ts` | Intercepts specific patterns from Claude CLI (title extraction, warmup, count) and returns fake responses without calling any provider. Supports both streaming and non-streaming. Intentionally limited to Claude CLI scope. |
| `networkProxy.ts` | Resolves outbound proxy URL for a given provider with precedence: provider-specific config → global config → environment variables (`HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY`). Supports `NO_PROXY` exclusions. Caches config for 30s. |
| `error.js` | Error response building (OpenAI-compatible format), upstream error parsing, Antigravity retry-time extraction from error messages, SSE error streaming. |
| `stream.js` | **SSE Transform Stream** — the core streaming pipeline. Two modes: `TRANSLATE` (full format translation) and `PASSTHROUGH` (normalize + extract usage). Handles chunk buffering, usage estimation, content length tracking. Per-stream encoder/decoder instances avoid shared state. |
| `streamHelpers.js` | Low-level SSE utilities: `parseSSELine` (whitespace-tolerant), `hasValuableContent` (filters empty chunks for OpenAI/Claude/Gemini), `fixInvalidId`, `formatSSE` (format-aware SSE serialization with `perf_metrics` cleanup). |
| `usageTracking.js` | Token usage extraction from any format (Claude/OpenAI/Gemini/Responses), estimation with separate tool/message char-per-token ratios, buffer addition (2000 tokens safety margin), format-specific field filtering, console logging with ANSI colors. |
| `requestLogger.js` | File-based request logging (opt-in via `ENABLE_REQUEST_LOGS=true`). Creates session folders with numbered files: `1_req_client.json``7_res_client.txt`. All I/O is async (fire-and-forget). Masks sensitive headers. |
| `bypassHandler.js` | Intercepts specific patterns from Claude CLI (title extraction, warmup, count) and returns fake responses without calling any provider. Supports both streaming and non-streaming. Intentionally limited to Claude CLI scope. |
| `networkProxy.js` | Resolves outbound proxy URL for a given provider with precedence: provider-specific config → global config → environment variables (`HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY`). Supports `NO_PROXY` exclusions. Caches config for 30s. |
#### SSE Streaming Pipeline
@@ -452,7 +442,7 @@ logs/
| Directory | Purpose |
| ------------- | ---------------------------------------------------------------------- |
| `src/app/` | Web UI, API routes, Express middleware, OAuth callback handlers |
| `src/lib/` | Database access (`localDb.ts`, `usageDb.ts`), authentication, shared |
| `src/lib/` | Database access (`localDb.js`, `usageDb.js`), authentication, shared |
| `src/mitm/` | Man-in-the-middle proxy utilities for intercepting provider traffic |
| `src/models/` | Database model definitions |
| `src/shared/` | Wrappers around open-sse functions (provider, stream, error, etc.) |
@@ -470,11 +460,6 @@ logs/
| `/v1/providers/[provider]/chat/completions` | POST | Dedicated per-provider chat completions with model validation |
| `/v1/providers/[provider]/embeddings` | POST | Dedicated per-provider embeddings with model validation |
| `/v1/providers/[provider]/images/generations` | POST | Dedicated per-provider image generation with model validation |
| `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist management |
| `/api/settings/thinking-budget` | GET/PUT | Reasoning token budget configuration (passthrough/auto/custom/adaptive) |
| `/api/settings/system-prompt` | GET/PUT | Global system prompt injection for all requests |
| `/api/sessions` | GET | Active session tracking and metrics |
| `/api/rate-limits` | GET | Per-account rate limit status |
---
@@ -486,7 +471,7 @@ All formats translate through **OpenAI format as the hub**. Adding a new provide
### 5.2 Executor Strategy Pattern
Each provider has a dedicated executor class inheriting from `BaseExecutor`. The factory in `executors/index.ts` selects the right one at runtime.
Each provider has a dedicated executor class inheriting from `BaseExecutor`. The factory in `executors/index.js` selects the right one at runtime.
### 5.3 Self-Registering Plugin System
-93
View File
@@ -1,93 +0,0 @@
# OmniRoute — Dashboard Features Gallery
🌐 **Languages:** 🇺🇸 [English](FEATURES.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/FEATURES.md) | 🇪🇸 [Español](i18n/es/FEATURES.md) | 🇫🇷 [Français](i18n/fr/FEATURES.md) | 🇮🇹 [Italiano](i18n/it/FEATURES.md) | 🇷🇺 [Русский](i18n/ru/FEATURES.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](i18n/de/FEATURES.md) | 🇮🇳 [हिन्दी](i18n/in/FEATURES.md) | 🇹🇭 [ไทย](i18n/th/FEATURES.md) | 🇺🇦 [Українська](i18n/uk-UA/FEATURES.md) | 🇸🇦 [العربية](i18n/ar/FEATURES.md) | 🇯🇵 [日本語](i18n/ja/FEATURES.md) | 🇻🇳 [Tiếng Việt](i18n/vi/FEATURES.md) | 🇧🇬 [Български](i18n/bg/FEATURES.md) | 🇩🇰 [Dansk](i18n/da/FEATURES.md) | 🇫🇮 [Suomi](i18n/fi/FEATURES.md) | 🇮🇱 [עברית](i18n/he/FEATURES.md) | 🇭🇺 [Magyar](i18n/hu/FEATURES.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/FEATURES.md) | 🇰🇷 [한국어](i18n/ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/FEATURES.md) | 🇳🇱 [Nederlands](i18n/nl/FEATURES.md) | 🇳🇴 [Norsk](i18n/no/FEATURES.md) | 🇵🇹 [Português (Portugal)](i18n/pt/FEATURES.md) | 🇷🇴 [Română](i18n/ro/FEATURES.md) | 🇵🇱 [Polski](i18n/pl/FEATURES.md) | 🇸🇰 [Slovenčina](i18n/sk/FEATURES.md) | 🇸🇪 [Svenska](i18n/sv/FEATURES.md) | 🇵🇭 [Filipino](i18n/phi/FEATURES.md)
Visual guide to every section of the OmniRoute dashboard.
---
## 🔌 Providers
Manage AI provider connections: OAuth providers (Claude Code, Codex, Gemini CLI), API key providers (Groq, DeepSeek, OpenRouter), and free providers (iFlow, Qwen, Kiro).
![Providers Dashboard](screenshots/01-providers.png)
---
## 🎨 Combos
Create model routing combos with 6 strategies: fill-first, round-robin, power-of-two-choices, random, least-used, and cost-optimized. Each combo chains multiple models with automatic fallback.
![Combos Dashboard](screenshots/02-combos.png)
---
## 📊 Analytics
Comprehensive usage analytics with token consumption, cost estimates, activity heatmaps, weekly distribution charts, and per-provider breakdowns.
![Analytics Dashboard](screenshots/03-analytics.png)
---
## 🏥 System Health
Real-time monitoring: uptime, memory, version, latency percentiles (p50/p95/p99), cache statistics, and provider circuit breaker states.
![Health Dashboard](screenshots/04-health.png)
---
## 🔧 Translator Playground
Four modes for debugging API translations: **Playground** (format converter), **Chat Tester** (live requests), **Test Bench** (batch tests), and **Live Monitor** (real-time stream).
![Translator Playground](screenshots/05-translator.png)
---
## ⚙️ Settings
General settings, system storage, backup management (export/import database), appearance (dark/light mode), security (includes API endpoint protection and custom provider blocking), routing (model aliases, background task degradation), resilience (rate limit persistence), and advanced configuration.
![Settings Dashboard](screenshots/06-settings.png)
---
## 🔧 CLI Tools
One-click configuration for AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenClaw, Kilo Code, Antigravity, and **GitHub Copilot** (config generator for `chatLanguageModels.json`).
![CLI Tools Dashboard](screenshots/07-cli-tools.png)
---
## 📝 Request Logs
Real-time request logging with filtering by provider, model, account, and API key. Shows status codes, token usage, latency, and response details.
![Usage Logs](screenshots/08-usage.png)
---
## 🌐 API Endpoint
Your unified API endpoint with capability breakdown: Chat Completions, Embeddings, Image Generation, Reranking, Audio Transcription, and registered API keys.
![Endpoint Dashboard](screenshots/09-endpoint.png)
---
## 🖥️ Desktop Application
Native Electron desktop app for Windows, macOS, and Linux. Run OmniRoute as a standalone application with system tray integration, offline support, and one-click install.
Key features:
- Server readiness polling (no blank screen on cold start)
- System tray with port management
- Content Security Policy
- Single-instance lock
- Platform-conditional UI (macOS traffic lights, Windows/Linux default titlebar)
📖 See [`electron/README.md`](../electron/README.md) for full documentation.
-113
View File
@@ -1,113 +0,0 @@
# Rate Limiting & Flow Control Overhaul — Tasks
> Referência: [Relatório de Análise](../walkthrough.md) · Fase docs em `/docs/phases/`
---
## Fase 1 — Error Classification & Provider Profiles
### Backend Core
- [x] `constants.ts` — Substituir `COOLDOWN_MS.transient` por `transientInitial` (5s) + `transientMax` (60s)
- [x] `constants.ts` — Adicionar `PROVIDER_PROFILES` (oauth / apikey) com cooldowns diferenciados
- [x] `constants.ts` — Adicionar `DEFAULT_API_LIMITS` (100 RPM, 200ms minTime)
- [x] `providerRegistry.ts` — Criar helper `getProviderCategory(providerId)``"oauth"` | `"apikey"`
- [x] `accountFallback.ts` — Aceitar `provider` como parâmetro em `checkFallbackError`
- [x] `accountFallback.ts` — Implementar backoff exponencial para 502/503/504 transientes
- [x] `accountFallback.ts` — Calcular cooldown baseado no perfil do provedor
- [x] `accountFallback.ts` — Adicionar helper `getProviderProfile(provider)`
### Callers (propagar `provider`)
- [x] `auth.ts``markAccountUnavailable` — Passar `provider` para `checkFallbackError`
- [x] `combo.ts``handleComboChat` / `handleRoundRobinCombo` — Passar `provider` nos erros
### Testes
- [x] Atualizar `rate-limit-enhanced.test.mjs` — Teste "transient errors don't increase backoff" → `newBackoffLevel = 1`
- [x] Criar `error-classification.test.mjs` — Cooldown exponencial 502, perfis OAuth/API, helper `getProviderCategory`
---
## Fase 2 — Circuit Breaker no Combo Pipeline
### Backend
- [x] `combo.ts` — Importar `getCircuitBreaker` e `CircuitBreakerOpenError`
- [x] `combo.ts``handleComboChat` — Verificar `breaker.canExecute()` antes de cada modelo
- [x] `combo.ts``handleRoundRobinCombo` — Integrar breaker per-model
- [x] `combo.ts` — Marcar `semaphore.markRateLimited` para 502/503/504 (não só 429)
- [x] `combo.ts` — Implementar early exit quando todos os modelos têm breaker OPEN
### Testes
- [x] Criar `combo-circuit-breaker.test.mjs` — Combo skip breaker OPEN, early exit, semáforo 502
---
## Fase 3 — Anti-Thundering Herd & Auto Rate Limit
### Backend
- [x] `rateLimitManager.ts` — Auto-enable para `apikey` providers com limites elevados
- [x] `rateLimitManager.ts` — Criar limiter com defaults (100 RPM) quando não configurado
- [x] `auth.ts` — Adicionar mutex na `markAccountUnavailable` para evitar marcação paralela
### Testes
- [x] Criar `thundering-herd.test.mjs` — Mutex, auto-enable, limites não restritivos
---
## Fase 4 — Frontend Resilience UI
### Settings Page
- [x] `settings/page.tsx` — Adicionar tab "Resilience" (icon: `health_and_safety`) entre Routing e Pricing
### Novos Componentes
- [x] Criar `ResilienceTab.tsx` — Layout com 4 cards (Provider Profiles → Rate Limiting → Circuit Breakers → Policies)
- [x] Criar `ProviderProfilesCard.tsx` — Toggle OAuth/API Key, inputs para cooldowns
- [x] Criar `CircuitBreakerCard.tsx` — Status real-time per-provider, auto-refresh 5s, botão reset
- [x] Criar `RateLimitOverviewCard.tsx` — Tabela providers × accounts × cooldown — **agora editável com RPM, Min Gap, Max Concurrent**
### API Routes
- [x] Criar `api/resilience/route.ts` — GET (estado completo + defaults mesclados) + PATCH (salvar perfis + defaults)
- [x] Criar `api/resilience/reset/route.ts` — POST (resetar breakers + cooldowns)
### Migração
- [x] `PoliciesPanel.tsx` movido de Security para Resilience tab
---
## Fase 5 — Settings Page Restructure (v0.9.0)
### Tab Reorganization
- [x] **Security** — Simplificado para Login/Password + IP Access Control
- [x] **Routing** — Expandido para 6 estratégias globais com descrições
- [x] **Resilience** — Reordenado: Provider Profiles → Rate Limiting (editável) → Circuit Breakers → Policies
- [x] **AI** — Thinking Budget + System Prompt + Prompt Cache (movido do Advanced)
- [x] **Advanced** — Simplificado para apenas Global Proxy
### Backend Routing Strategies
- [x] `auth.ts` — Implementar `random` (Fisher-Yates shuffle)
- [x] `auth.ts` — Implementar `least-used` (sorted by lastUsedAt)
- [x] `auth.ts` — Implementar `cost-optimized` (sorted by priority)
- [x] `auth.ts` — Corrigir `p2c` (power-of-two-choices com health scoring)
- [x] `settings.ts` — Expandir tipo `fallbackStrategy` para 6 valores
---
## Verificação Final
- [x] Rodar todos os testes unitários: `node --test tests/unit/*.test.mjs`
- [x] Build do Next.js: `npm run build`
- [x] Verificar aba Resilience no browser
- [x] Testar persistência dos perfis (salvar → reload)
- [x] Testar Reset All Breakers
- [x] Verificar todas as 5 tabs reestruturadas
-254
View File
@@ -1,254 +0,0 @@
# Troubleshooting
🌐 **Languages:** 🇺🇸 [English](TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](i18n/es/TROUBLESHOOTING.md) | 🇫🇷 [Français](i18n/fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](i18n/it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](i18n/ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](i18n/de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](i18n/in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](i18n/th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](i18n/uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](i18n/ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](i18n/ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](i18n/vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](i18n/bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](i18n/da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](i18n/fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](i18n/he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](i18n/hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](i18n/ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](i18n/nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](i18n/no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](i18n/pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](i18n/ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](i18n/pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](i18n/sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](i18n/sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](i18n/phi/TROUBLESHOOTING.md)
Common problems and solutions for OmniRoute.
---
## Quick Fixes
| Problem | Solution |
| ----------------------------- | ------------------------------------------------------------------ |
| First login not working | Check `INITIAL_PASSWORD` in `.env` (default: `123456`) |
| Dashboard opens on wrong port | Set `PORT=20128` and `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
| No request logs under `logs/` | Set `ENABLE_REQUEST_LOGS=true` |
| EACCES: permission denied | Set `DATA_DIR=/path/to/writable/dir` to override `~/.omniroute` |
| Routing strategy not saving | Update to v1.4.11+ (Zod schema fix for settings persistence) |
---
## Provider Issues
### "Language model did not provide messages"
**Cause:** Provider quota exhausted.
**Fix:**
1. Check dashboard quota tracker
2. Use a combo with fallback tiers
3. Switch to cheaper/free tier
### Rate Limiting
**Cause:** Subscription quota exhausted.
**Fix:**
- Add fallback: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
- Use GLM/MiniMax as cheap backup
### OAuth Token Expired
OmniRoute auto-refreshes tokens. If issues persist:
1. Dashboard → Provider → Reconnect
2. Delete and re-add the provider connection
---
## Cloud Issues
### Cloud Sync Errors
1. Verify `BASE_URL` points to your running instance (e.g., `http://localhost:20128`)
2. Verify `CLOUD_URL` points to your cloud endpoint (e.g., `https://omniroute.dev`)
3. Keep `NEXT_PUBLIC_*` values aligned with server-side values
### Cloud `stream=false` Returns 500
**Symptom:** `Unexpected token 'd'...` on cloud endpoint for non-streaming calls.
**Cause:** Upstream returns SSE payload while client expects JSON.
**Workaround:** Use `stream=true` for cloud direct calls. Local runtime includes SSE→JSON fallback.
### Cloud Says Connected but "Invalid API key"
1. Create a fresh key from local dashboard (`/api/keys`)
2. Run cloud sync: Enable Cloud → Sync Now
3. Old/non-synced keys can still return `401` on cloud
---
## Docker Issues
### CLI Tool Shows Not Installed
1. Check runtime fields: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
2. For portable mode: use image target `runner-cli` (bundled CLIs)
3. For host mount mode: set `CLI_EXTRA_PATHS` and mount host bin directory as read-only
4. If `installed=true` and `runnable=false`: binary was found but failed healthcheck
### Quick Runtime Validation
```bash
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
```
---
## Cost Issues
### High Costs
1. Check usage stats in Dashboard → Usage
2. Switch primary model to GLM/MiniMax
3. Use free tier (Gemini CLI, iFlow) for non-critical tasks
4. Set cost budgets per API key: Dashboard → API Keys → Budget
---
## Debugging
### Enable Request Logs
Set `ENABLE_REQUEST_LOGS=true` in your `.env` file. Logs appear under `logs/` directory.
### Check Provider Health
```bash
# Health dashboard
http://localhost:20128/dashboard/health
# API health check
curl http://localhost:20128/api/monitoring/health
```
### Runtime Storage
- Main state: `${DATA_DIR}/db.json` (providers, combos, aliases, keys, settings)
- Usage: `${DATA_DIR}/usage.json`, `${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`
- Request logs: `<repo>/logs/...` (when `ENABLE_REQUEST_LOGS=true`)
---
## Circuit Breaker Issues
### Provider stuck in OPEN state
When a provider's circuit breaker is OPEN, requests are blocked until the cooldown expires.
**Fix:**
1. Go to **Dashboard → Settings → Resilience**
2. Check the circuit breaker card for the affected provider
3. Click **Reset All** to clear all breakers, or wait for the cooldown to expire
4. Verify the provider is actually available before resetting
### Provider keeps tripping the circuit breaker
If a provider repeatedly enters OPEN state:
1. Check **Dashboard → Health → Provider Health** for the failure pattern
2. Go to **Settings → Resilience → Provider Profiles** and increase the failure threshold
3. Check if the provider has changed API limits or requires re-authentication
4. Review latency telemetry — high latency may cause timeout-based failures
---
## Audio Transcription Issues
### "Unsupported model" error
- Ensure you're using the correct prefix: `deepgram/nova-3` or `assemblyai/best`
- Verify the provider is connected in **Dashboard → Providers**
### Transcription returns empty or fails
- Check supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`
- Verify file size is within provider limits (typically < 25MB)
- Check provider API key validity in the provider card
---
## Translator Debugging
Use **Dashboard → Translator** to debug format translation issues:
| Mode | When to Use |
| ---------------- | -------------------------------------------------------------------------------------------- |
| **Playground** | Compare input/output formats side by side — paste a failing request to see how it translates |
| **Chat Tester** | Send live messages and inspect the full request/response payload including headers |
| **Test Bench** | Run batch tests across format combinations to find which translations are broken |
| **Live Monitor** | Watch real-time request flow to catch intermittent translation issues |
### Common format issues
- **Thinking tags not appearing** — Check if the target provider supports thinking and the thinking budget setting
- **Tool calls dropping** — Some format translations may strip unsupported fields; verify in Playground mode
- **System prompt missing** — Claude and Gemini handle system prompts differently; check translation output
- **SDK returns raw string instead of object** — Fixed in v1.1.0: response sanitizer now strips non-standard fields (`x_groq`, `usage_breakdown`, etc.) that cause OpenAI SDK Pydantic validation failures
- **GLM/ERNIE rejects `system` role** — Fixed in v1.1.0: role normalizer automatically merges system messages into user messages for incompatible models
- **`developer` role not recognized** — Fixed in v1.1.0: automatically converted to `system` for non-OpenAI providers
- **`json_schema` not working with Gemini** — Fixed in v1.1.0: `response_format` is now converted to Gemini's `responseMimeType` + `responseSchema`
---
## Resilience Settings
### Auto rate-limit not triggering
- Auto rate-limit only applies to API key providers (not OAuth/subscription)
- Verify **Settings → Resilience → Provider Profiles** has auto-rate-limit enabled
- Check if the provider returns `429` status codes or `Retry-After` headers
### Tuning exponential backoff
Provider profiles support these settings:
- **Base delay** — Initial wait time after first failure (default: 1s)
- **Max delay** — Maximum wait time cap (default: 30s)
- **Multiplier** — How much to increase delay per consecutive failure (default: 2x)
### Anti-thundering herd
When many concurrent requests hit a rate-limited provider, OmniRoute uses mutex + auto rate-limiting to serialize requests and prevent cascading failures. This is automatic for API key providers.
---
## Optional RAG / LLM failure taxonomy (16 problems)
Some OmniRoute users place the gateway in front of RAG or agent stacks. In those setups it is common to see a strange pattern: OmniRoute looks healthy (providers up, routing profiles ok, no rate limit alerts) but the final answer is still wrong.
In practice these incidents usually come from the downstream RAG pipeline, not from the gateway itself.
If you want a shared vocabulary to describe those failures you can use the WFGY ProblemMap, an external MIT license text resource that defines sixteen recurring RAG / LLM failure patterns. At a high level it covers:
- retrieval drift and broken context boundaries
- empty or stale indexes and vector stores
- embedding versus semantic mismatch
- prompt assembly and context window issues
- logic collapse and overconfident answers
- long chain and agent coordination failures
- multi agent memory and role drift
- deployment and bootstrap ordering problems
The idea is simple:
1. When you investigate a bad response, capture:
- user task and request
- route or provider combo in OmniRoute
- any RAG context used downstream (retrieved documents, tool calls, etc)
2. Map the incident to one or two WFGY ProblemMap numbers (`No.1``No.16`).
3. Store the number in your own dashboard, runbook, or incident tracker next to the OmniRoute logs.
4. Use the corresponding WFGY page to decide whether you need to change your RAG stack, retriever, or routing strategy.
Full text and concrete recipes live here (MIT license, text only):
[WFGY ProblemMap README](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
You can ignore this section if you do not run RAG or agent pipelines behind OmniRoute.
---
## Still Stuck?
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **Architecture**: See [`docs/ARCHITECTURE.md`](ARCHITECTURE.md) for internal details
- **API Reference**: See [`docs/API_REFERENCE.md`](API_REFERENCE.md) for all endpoints
- **Health Dashboard**: Check **Dashboard → Health** for real-time system status
- **Translator**: Use **Dashboard → Translator** to debug format issues
-809
View File
@@ -1,809 +0,0 @@
# User Guide
🌐 **Languages:** 🇺🇸 [English](USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](i18n/pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](i18n/es/USER_GUIDE.md) | 🇫🇷 [Français](i18n/fr/USER_GUIDE.md) | 🇮🇹 [Italiano](i18n/it/USER_GUIDE.md) | 🇷🇺 [Русский](i18n/ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](i18n/zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](i18n/de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](i18n/in/USER_GUIDE.md) | 🇹🇭 [ไทย](i18n/th/USER_GUIDE.md) | 🇺🇦 [Українська](i18n/uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](i18n/ar/USER_GUIDE.md) | 🇯🇵 [日本語](i18n/ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](i18n/vi/USER_GUIDE.md) | 🇧🇬 [Български](i18n/bg/USER_GUIDE.md) | 🇩🇰 [Dansk](i18n/da/USER_GUIDE.md) | 🇫🇮 [Suomi](i18n/fi/USER_GUIDE.md) | 🇮🇱 [עברית](i18n/he/USER_GUIDE.md) | 🇭🇺 [Magyar](i18n/hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](i18n/id/USER_GUIDE.md) | 🇰🇷 [한국어](i18n/ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](i18n/ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](i18n/nl/USER_GUIDE.md) | 🇳🇴 [Norsk](i18n/no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](i18n/pt/USER_GUIDE.md) | 🇷🇴 [Română](i18n/ro/USER_GUIDE.md) | 🇵🇱 [Polski](i18n/pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](i18n/sk/USER_GUIDE.md) | 🇸🇪 [Svenska](i18n/sv/USER_GUIDE.md) | 🇵🇭 [Filipino](i18n/phi/USER_GUIDE.md)
Complete guide for configuring providers, creating combos, integrating CLI tools, and deploying OmniRoute.
---
## Table of Contents
- [Pricing at a Glance](#-pricing-at-a-glance)
- [Use Cases](#-use-cases)
- [Provider Setup](#-provider-setup)
- [CLI Integration](#-cli-integration)
- [Deployment](#-deployment)
- [Available Models](#-available-models)
- [Advanced Features](#-advanced-features)
---
## 💰 Pricing at a Glance
| Tier | Provider | Cost | Quota Reset | Best For |
| ------------------- | ----------------- | ----------- | ---------------- | -------------------- |
| **💳 SUBSCRIPTION** | Claude Code (Pro) | $20/mo | 5h + weekly | Already subscribed |
| | Codex (Plus/Pro) | $20-200/mo | 5h + weekly | OpenAI users |
| | Gemini CLI | **FREE** | 180K/mo + 1K/day | Everyone! |
| | GitHub Copilot | $10-19/mo | Monthly | GitHub users |
| **🔑 API KEY** | DeepSeek | Pay per use | None | Cheap reasoning |
| | Groq | Pay per use | None | Ultra-fast inference |
| | xAI (Grok) | Pay per use | None | Grok 4 reasoning |
| | Mistral | Pay per use | None | EU-hosted models |
| | Perplexity | Pay per use | None | Search-augmented |
| | Together AI | Pay per use | None | Open-source models |
| | Fireworks AI | Pay per use | None | Fast FLUX images |
| | Cerebras | Pay per use | None | Wafer-scale speed |
| | Cohere | Pay per use | None | Command R+ RAG |
| | NVIDIA NIM | Pay per use | None | Enterprise models |
| **💰 CHEAP** | GLM-4.7 | $0.6/1M | Daily 10AM | Budget backup |
| | MiniMax M2.1 | $0.2/1M | 5-hour rolling | Cheapest option |
| | Kimi K2 | $9/mo flat | 10M tokens/mo | Predictable cost |
| **🆓 FREE** | iFlow | $0 | Unlimited | 8 models free |
| | Qwen | $0 | Unlimited | 3 models free |
| | Kiro | $0 | Unlimited | Claude free |
**💡 Pro Tip:** Start with Gemini CLI (180K free/month) + iFlow (unlimited free) combo = $0 cost!
---
## 🎯 Use Cases
### Case 1: "I have Claude Pro subscription"
**Problem:** Quota expires unused, rate limits during heavy coding
```
Combo: "maximize-claude"
1. cc/claude-opus-4-6 (use subscription fully)
2. glm/glm-4.7 (cheap backup when quota out)
3. if/kimi-k2-thinking (free emergency fallback)
Monthly cost: $20 (subscription) + ~$5 (backup) = $25 total
vs. $20 + hitting limits = frustration
```
### Case 2: "I want zero cost"
**Problem:** Can't afford subscriptions, need reliable AI coding
```
Combo: "free-forever"
1. gc/gemini-3-flash (180K free/month)
2. if/kimi-k2-thinking (unlimited free)
3. qw/qwen3-coder-plus (unlimited free)
Monthly cost: $0
Quality: Production-ready models
```
### Case 3: "I need 24/7 coding, no interruptions"
**Problem:** Deadlines, can't afford downtime
```
Combo: "always-on"
1. cc/claude-opus-4-6 (best quality)
2. cx/gpt-5.2-codex (second subscription)
3. glm/glm-4.7 (cheap, resets daily)
4. minimax/MiniMax-M2.1 (cheapest, 5h reset)
5. if/kimi-k2-thinking (free unlimited)
Result: 5 layers of fallback = zero downtime
Monthly cost: $20-200 (subscriptions) + $10-20 (backup)
```
### Case 4: "I want FREE AI in OpenClaw"
**Problem:** Need AI assistant in messaging apps, completely free
```
Combo: "openclaw-free"
1. if/glm-4.7 (unlimited free)
2. if/minimax-m2.1 (unlimited free)
3. if/kimi-k2-thinking (unlimited free)
Monthly cost: $0
Access via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
```
---
## 📖 Provider Setup
### 🔐 Subscription Providers
#### Claude Code (Pro/Max)
```bash
Dashboard → Providers → Connect Claude Code
→ OAuth login → Auto token refresh
→ 5-hour + weekly quota tracking
Models:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**Pro Tip:** Use Opus for complex tasks, Sonnet for speed. OmniRoute tracks quota per model!
#### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Providers → Connect Codex
→ OAuth login (port 1455)
→ 5-hour + weekly reset
Models:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
#### Gemini CLI (FREE 180K/month!)
```bash
Dashboard → Providers → Connect Gemini CLI
→ Google OAuth
→ 180K completions/month + 1K/day
Models:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**Best Value:** Huge free tier! Use this before paid tiers.
#### GitHub Copilot
```bash
Dashboard → Providers → Connect GitHub
→ OAuth via GitHub
→ Monthly reset (1st of month)
Models:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
### 💰 Cheap Providers
#### GLM-4.7 (Daily reset, $0.6/1M)
1. Sign up: [Zhipu AI](https://open.bigmodel.cn/)
2. Get API key from Coding Plan
3. Dashboard → Add API Key: Provider: `glm`, API Key: `your-key`
**Use:** `glm/glm-4.7`**Pro Tip:** Coding Plan offers 3× quota at 1/7 cost! Reset daily 10:00 AM.
#### MiniMax M2.1 (5h reset, $0.20/1M)
1. Sign up: [MiniMax](https://www.minimax.io/)
2. Get API key → Dashboard → Add API Key
**Use:** `minimax/MiniMax-M2.1`**Pro Tip:** Cheapest option for long context (1M tokens)!
#### Kimi K2 ($9/month flat)
1. Subscribe: [Moonshot AI](https://platform.moonshot.ai/)
2. Get API key → Dashboard → Add API Key
**Use:** `kimi/kimi-latest`**Pro Tip:** Fixed $9/month for 10M tokens = $0.90/1M effective cost!
### 🆓 FREE Providers
#### iFlow (8 FREE models)
```bash
Dashboard → Connect iFlow → OAuth login → Unlimited usage
Models: if/kimi-k2-thinking, if/qwen3-coder-plus, if/glm-4.7, if/minimax-m2, if/deepseek-r1
```
#### Qwen (3 FREE models)
```bash
Dashboard → Connect Qwen → Device code auth → Unlimited usage
Models: qw/qwen3-coder-plus, qw/qwen3-coder-flash
```
#### Kiro (Claude FREE)
```bash
Dashboard → Connect Kiro → AWS Builder ID or Google/GitHub → Unlimited
Models: kr/claude-sonnet-4.5, kr/claude-haiku-4.5
```
---
## 🎨 Combos
### Example 1: Maximize Subscription → Cheap Backup
```
Dashboard → Combos → Create New
Name: premium-coding
Models:
1. cc/claude-opus-4-6 (Subscription primary)
2. glm/glm-4.7 (Cheap backup, $0.6/1M)
3. minimax/MiniMax-M2.1 (Cheapest fallback, $0.20/1M)
Use in CLI: premium-coding
```
### Example 2: Free-Only (Zero Cost)
```
Name: free-combo
Models:
1. gc/gemini-3-flash-preview (180K free/month)
2. if/kimi-k2-thinking (unlimited)
3. qw/qwen3-coder-plus (unlimited)
Cost: $0 forever!
```
---
## 🔧 CLI Integration
### Cursor IDE
```
Settings → Models → Advanced:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [from omniroute dashboard]
Model: cc/claude-opus-4-6
```
### Claude Code
Edit `~/.claude/config.json`:
```json
{
"anthropic_api_base": "http://localhost:20128/v1",
"anthropic_api_key": "your-omniroute-api-key"
}
```
### Codex CLI
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
Edit `~/.openclaw/openclaw.json`:
```json
{
"agents": {
"defaults": {
"model": { "primary": "omniroute/if/glm-4.7" }
}
},
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://localhost:20128/v1",
"apiKey": "your-omniroute-api-key",
"api": "openai-completions",
"models": [{ "id": "if/glm-4.7", "name": "glm-4.7" }]
}
}
}
}
```
**Or use Dashboard:** CLI Tools → OpenClaw → Auto-config
### Cline / Continue / RooCode
```
Provider: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [from dashboard]
Model: cc/claude-opus-4-6
```
---
## 🚀 Deployment
### Global npm install (Recommended)
```bash
npm install -g omniroute
# Create config directory
mkdir -p ~/.omniroute
# Create .env file (see .env.example)
cp .env.example ~/.omniroute/.env
# Start server
omniroute
# Or with custom port:
omniroute --port 3000
```
The CLI automatically loads `.env` from `~/.omniroute/.env` or `./.env`.
### VPS Deployment
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute && npm install && npm run build
export JWT_SECRET="your-secure-secret-change-this"
export INITIAL_PASSWORD="your-password"
export DATA_DIR="/var/lib/omniroute"
export PORT="20128"
export HOSTNAME="0.0.0.0"
export NODE_ENV="production"
export NEXT_PUBLIC_BASE_URL="http://localhost:20128"
export API_KEY_SECRET="endpoint-proxy-api-key-secret"
npm run start
# Or: pm2 start npm --name omniroute -- start
```
### PM2 Deployment (Low Memory)
For servers with limited RAM, use the memory limit option:
```bash
# With 512MB limit (default)
pm2 start npm --name omniroute -- start
# Or with custom memory limit
OMNIROUTE_MEMORY_MB=512 pm2 start npm --name omniroute -- start
# Or using ecosystem.config.js
pm2 start ecosystem.config.js
```
Create `ecosystem.config.js`:
```javascript
module.exports = {
apps: [
{
name: "omniroute",
script: "npm",
args: "start",
env: {
NODE_ENV: "production",
OMNIROUTE_MEMORY_MB: "512",
JWT_SECRET: "your-secret",
INITIAL_PASSWORD: "your-password",
},
node_args: "--max-old-space-size=512",
max_memory_restart: "300M",
},
],
};
```
### Docker
```bash
# Build image (default = runner-cli with codex/claude/droid preinstalled)
docker build -t omniroute:cli .
# Portable mode (recommended)
docker run -d --name omniroute -p 20128:20128 --env-file ./.env -v omniroute-data:/app/data omniroute:cli
```
For host-integrated mode with CLI binaries, see the Docker section in the main docs.
### Environment Variables
| Variable | Default | Description |
| ------------------------- | ------------------------------------ | ------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | JWT signing secret (**change in production**) |
| `INITIAL_PASSWORD` | `123456` | First login password |
| `DATA_DIR` | `~/.omniroute` | Data directory (db, usage, logs) |
| `PORT` | framework default | Service port (`20128` in examples) |
| `HOSTNAME` | framework default | Bind host (Docker defaults to `0.0.0.0`) |
| `NODE_ENV` | runtime default | Set `production` for deploy |
| `BASE_URL` | `http://localhost:20128` | Server-side internal base URL |
| `CLOUD_URL` | `https://omniroute.dev` | Cloud sync endpoint base URL |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | HMAC secret for generated API keys |
| `REQUIRE_API_KEY` | `false` | Enforce Bearer API key on `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | Enables request/response logs |
| `AUTH_COOKIE_SECURE` | `false` | Force `Secure` auth cookie (behind HTTPS reverse proxy) |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit in MB |
| `PROMPT_CACHE_MAX_SIZE` | `50` | Max prompt cache entries |
| `SEMANTIC_CACHE_MAX_SIZE` | `100` | Max semantic cache entries |
For the full environment variable reference, see the [README](../README.md).
---
## 📊 Available Models
<details>
<summary><b>View all available models</b></summary>
**Claude Code (`cc/`)** — Pro/Max: `cc/claude-opus-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**Codex (`cx/`)** — Plus/Pro: `cx/gpt-5.2-codex`, `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** — FREE: `gc/gemini-3-flash-preview`, `gc/gemini-2.5-pro`
**GitHub Copilot (`gh/`)**: `gh/gpt-5`, `gh/claude-4.5-sonnet`
**GLM (`glm/`)** — $0.6/1M: `glm/glm-4.7`
**MiniMax (`minimax/`)** — $0.2/1M: `minimax/MiniMax-M2.1`
**iFlow (`if/`)** — FREE: `if/kimi-k2-thinking`, `if/qwen3-coder-plus`, `if/deepseek-r1`
**Qwen (`qw/`)** — FREE: `qw/qwen3-coder-plus`, `qw/qwen3-coder-flash`
**Kiro (`kr/`)** — FREE: `kr/claude-sonnet-4.5`, `kr/claude-haiku-4.5`
**DeepSeek (`ds/`)**: `ds/deepseek-chat`, `ds/deepseek-reasoner`
**Groq (`groq/`)**: `groq/llama-3.3-70b-versatile`, `groq/llama-4-maverick-17b-128e-instruct`
**xAI (`xai/`)**: `xai/grok-4`, `xai/grok-4-0709-fast-reasoning`, `xai/grok-code-mini`
**Mistral (`mistral/`)**: `mistral/mistral-large-2501`, `mistral/codestral-2501`
**Perplexity (`pplx/`)**: `pplx/sonar-pro`, `pplx/sonar`
**Together AI (`together/`)**: `together/meta-llama/Llama-3.3-70B-Instruct-Turbo`
**Fireworks AI (`fireworks/`)**: `fireworks/accounts/fireworks/models/deepseek-v3p1`
**Cerebras (`cerebras/`)**: `cerebras/llama-3.3-70b`
**Cohere (`cohere/`)**: `cohere/command-r-plus-08-2024`
**NVIDIA NIM (`nvidia/`)**: `nvidia/nvidia/llama-3.3-70b-instruct`
</details>
---
## 🧩 Advanced Features
### Custom Models
Add any model ID to any provider without waiting for an app update:
```bash
# Via API
curl -X POST http://localhost:20128/api/provider-models \
-H "Content-Type: application/json" \
-d '{"provider": "openai", "modelId": "gpt-4.5-preview", "modelName": "GPT-4.5 Preview"}'
# List: curl http://localhost:20128/api/provider-models?provider=openai
# Remove: curl -X DELETE "http://localhost:20128/api/provider-models?provider=openai&model=gpt-4.5-preview"
```
Or use Dashboard: **Providers → [Provider] → Custom Models**.
### Dedicated Provider Routes
Route requests directly to a specific provider with model validation:
```bash
POST http://localhost:20128/v1/providers/openai/chat/completions
POST http://localhost:20128/v1/providers/openai/embeddings
POST http://localhost:20128/v1/providers/fireworks/images/generations
```
The provider prefix is auto-added if missing. Mismatched models return `400`.
### Network Proxy Configuration
```bash
# Set global proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"global": {"type":"http","host":"proxy.example.com","port":"8080"}}'
# Per-provider proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"providers": {"openai": {"type":"socks5","host":"proxy.example.com","port":"1080"}}}'
# Test proxy
curl -X POST http://localhost:20128/api/settings/proxy/test \
-d '{"proxy":{"type":"socks5","host":"proxy.example.com","port":"1080"}}'
```
**Precedence:** Key-specific → Combo-specific → Provider-specific → Global → Environment.
### Model Catalog API
```bash
curl http://localhost:20128/api/models/catalog
```
Returns models grouped by provider with types (`chat`, `embedding`, `image`).
### Cloud Sync
- Sync providers, combos, and settings across devices
- Automatic background sync with timeout + fail-fast
- Prefer server-side `BASE_URL`/`CLOUD_URL` in production
### LLM Gateway Intelligence (Phase 9)
- **Semantic Cache** — Auto-caches non-streaming, temperature=0 responses (bypass with `X-OmniRoute-No-Cache: true`)
- **Request Idempotency** — Deduplicates requests within 5s via `Idempotency-Key` or `X-Request-Id` header
- **Progress Tracking** — Opt-in SSE `event: progress` events via `X-OmniRoute-Progress: true` header
---
### Translator Playground
Access via **Dashboard → Translator**. Debug and visualize how OmniRoute translates API requests between providers.
| Mode | Purpose |
| ---------------- | -------------------------------------------------------------------------------------- |
| **Playground** | Select source/target formats, paste a request, and see the translated output instantly |
| **Chat Tester** | Send live chat messages through the proxy and inspect the full request/response cycle |
| **Test Bench** | Run batch tests across multiple format combinations to verify translation correctness |
| **Live Monitor** | Watch real-time translations as requests flow through the proxy |
**Use cases:**
- Debug why a specific client/provider combination fails
- Verify that thinking tags, tool calls, and system prompts translate correctly
- Compare format differences between OpenAI, Claude, Gemini, and Responses API formats
---
### Routing Strategies
Configure via **Dashboard → Settings → Routing**.
| Strategy | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------ |
| **Fill First** | Uses accounts in priority order — primary account handles all requests until unavailable |
| **Round Robin** | Cycles through all accounts with a configurable sticky limit (default: 3 calls per account) |
| **P2C (Power of Two Choices)** | Picks 2 random accounts and routes to the healthier one — balances load with awareness of health |
| **Random** | Randomly selects an account for each request using Fisher-Yates shuffle |
| **Least Used** | Routes to the account with the oldest `lastUsedAt` timestamp, distributing traffic evenly |
| **Cost Optimized** | Routes to the account with the lowest priority value, optimizing for lowest-cost providers |
#### Wildcard Model Aliases
Create wildcard patterns to remap model names:
```
Pattern: claude-sonnet-* → Target: cc/claude-sonnet-4-5-20250929
Pattern: gpt-* → Target: gh/gpt-5.1-codex
```
Wildcards support `*` (any characters) and `?` (single character).
#### Fallback Chains
Define global fallback chains that apply across all requests:
```
Chain: production-fallback
1. cc/claude-opus-4-6
2. gh/gpt-5.1-codex
3. glm/glm-4.7
```
---
### Resilience & Circuit Breakers
Configure via **Dashboard → Settings → Resilience**.
OmniRoute implements provider-level resilience with four components:
1. **Provider Profiles** — Per-provider configuration for:
- Failure threshold (how many failures before opening)
- Cooldown duration
- Rate limit detection sensitivity
- Exponential backoff parameters
2. **Editable Rate Limits** — System-level defaults configurable in the dashboard:
- **Requests Per Minute (RPM)** — Maximum requests per minute per account
- **Min Time Between Requests** — Minimum gap in milliseconds between requests
- **Max Concurrent Requests** — Maximum simultaneous requests per account
- Click **Edit** to modify, then **Save** or **Cancel**. Values persist via the resilience API.
3. **Circuit Breaker** — Tracks failures per provider and automatically opens the circuit when a threshold is reached:
- **CLOSED** (Healthy) — Requests flow normally
- **OPEN** — Provider is temporarily blocked after repeated failures
- **HALF_OPEN** — Testing if provider has recovered
4. **Policies & Locked Identifiers** — Shows circuit breaker status and locked identifiers with force-unlock capability.
5. **Rate Limit Auto-Detection** — Monitors `429` and `Retry-After` headers to proactively avoid hitting provider rate limits.
**Pro Tip:** Use **Reset All** button to clear all circuit breakers and cooldowns when a provider recovers from an outage.
---
### Database Export / Import
Manage database backups in **Dashboard → Settings → System & Storage**.
| Action | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| **Export Database** | Downloads the current SQLite database as a `.sqlite` file |
| **Export All (.tar.gz)** | Downloads a full backup archive including: database, settings, combos, provider connections (no credentials), API key metadata |
| **Import Database** | Upload a `.sqlite` file to replace the current database. A pre-import backup is automatically created |
```bash
# API: Export database
curl -o backup.sqlite http://localhost:20128/api/db-backups/export
# API: Export all (full archive)
curl -o backup.tar.gz http://localhost:20128/api/db-backups/exportAll
# API: Import database
curl -X POST http://localhost:20128/api/db-backups/import \
-F "file=@backup.sqlite"
```
**Import Validation:** The imported file is validated for integrity (SQLite pragma check), required tables (`provider_connections`, `provider_nodes`, `combos`, `api_keys`), and size (max 100MB).
**Use Cases:**
- Migrate OmniRoute between machines
- Create external backups for disaster recovery
- Share configurations between team members (export all → share archive)
---
### Settings Dashboard
The settings page is organized into 5 tabs for easy navigation:
| Tab | Contents |
| -------------- | ---------------------------------------------------------------------------------------------- |
| **Security** | Login/Password settings, IP Access Control, API auth for `/models`, and Provider Blocking |
| **Routing** | Global routing strategy (6 options), wildcard model aliases, fallback chains, combo defaults |
| **Resilience** | Provider profiles, editable rate limits, circuit breaker status, policies & locked identifiers |
| **AI** | Thinking budget configuration, global system prompt injection, prompt cache stats |
| **Advanced** | Global proxy configuration (HTTP/SOCKS5) |
---
### Costs & Budget Management
Access via **Dashboard → Costs**.
| Tab | Purpose |
| ----------- | ---------------------------------------------------------------------------------------- |
| **Budget** | Set spending limits per API key with daily/weekly/monthly budgets and real-time tracking |
| **Pricing** | View and edit model pricing entries — cost per 1K input/output tokens per provider |
```bash
# API: Set a budget
curl -X POST http://localhost:20128/api/usage/budget \
-H "Content-Type: application/json" \
-d '{"keyId": "key-123", "limit": 50.00, "period": "monthly"}'
# API: Get current budget status
curl http://localhost:20128/api/usage/budget
```
**Cost Tracking:** Every request logs token usage and calculates cost using the pricing table. View breakdowns in **Dashboard → Usage** by provider, model, and API key.
---
### Audio Transcription
OmniRoute supports audio transcription via the OpenAI-compatible endpoint:
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
# Example with curl
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@audio.mp3" \
-F "model=deepgram/nova-3"
```
Available providers: **Deepgram** (`deepgram/`), **AssemblyAI** (`assemblyai/`).
Supported audio formats: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
### Combo Balancing Strategies
Configure per-combo balancing in **Dashboard → Combos → Create/Edit → Strategy**.
| Strategy | Description |
| ------------------ | ------------------------------------------------------------------------ |
| **Round-Robin** | Rotates through models sequentially |
| **Priority** | Always tries the first model; falls back only on error |
| **Random** | Picks a random model from the combo for each request |
| **Weighted** | Routes proportionally based on assigned weights per model |
| **Least-Used** | Routes to the model with the fewest recent requests (uses combo metrics) |
| **Cost-Optimized** | Routes to the cheapest available model (uses pricing table) |
Global combo defaults can be set in **Dashboard → Settings → Routing → Combo Defaults**.
---
### Health Dashboard
Access via **Dashboard → Health**. Real-time system health overview with 6 cards:
| Card | What It Shows |
| --------------------- | ----------------------------------------------------------- |
| **System Status** | Uptime, version, memory usage, data directory |
| **Provider Health** | Per-provider circuit breaker state (Closed/Open/Half-Open) |
| **Rate Limits** | Active rate limit cooldowns per account with remaining time |
| **Active Lockouts** | Providers temporarily blocked by the lockout policy |
| **Signature Cache** | Deduplication cache stats (active keys, hit rate) |
| **Latency Telemetry** | p50/p95/p99 latency aggregation per provider |
**Pro Tip:** The Health page auto-refreshes every 10 seconds. Use the circuit breaker card to identify which providers are experiencing issues.
---
## 🖥️ Desktop Application (Electron)
OmniRoute is available as a native desktop application for Windows, macOS, and Linux.
### Installation
```bash
# From the electron directory:
cd electron
npm install
# Development mode (connect to running Next.js dev server):
npm run dev
# Production mode (uses standalone build):
npm start
```
### Building Installers
```bash
cd electron
npm run build # Current platform
npm run build:win # Windows (.exe NSIS)
npm run build:mac # macOS (.dmg universal)
npm run build:linux # Linux (.AppImage)
```
Output → `electron/dist-electron/`
### Key Features
| Feature | Description |
| --------------------------- | ---------------------------------------------------- |
| **Server Readiness** | Polls server before showing window (no blank screen) |
| **System Tray** | Minimize to tray, change port, quit from tray menu |
| **Port Management** | Change server port from tray (auto-restarts server) |
| **Content Security Policy** | Restrictive CSP via session headers |
| **Single Instance** | Only one app instance can run at a time |
| **Offline Mode** | Bundled Next.js server works without internet |
### Environment Variables
| Variable | Default | Description |
| --------------------- | ------- | -------------------------------- |
| `OMNIROUTE_PORT` | `20128` | Server port |
| `OMNIROUTE_MEMORY_MB` | `512` | Node.js heap limit (6416384 MB) |
📖 Full documentation: [`electron/README.md`](../electron/README.md)
-399
View File
@@ -1,399 +0,0 @@
# OmniRoute — Guia de Deploy em VM com Cloudflare
Guia completo para instalar e configurar o OmniRoute em uma VM (VPS) com domínio gerenciado via Cloudflare.
---
## Pré-Requisitos
| Item | Mínimo | Recomendado |
| ----------- | ------------------------ | ---------------- |
| **CPU** | 1 vCPU | 2 vCPU |
| **RAM** | 1 GB | 2 GB |
| **Disco** | 10 GB SSD | 25 GB SSD |
| **SO** | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| **Domínio** | Registrado no Cloudflare | — |
| **Docker** | Docker Engine 24+ | Docker 27+ |
**Providers testados**: Akamai (Linode), DigitalOcean, Vultr, Hetzner, AWS Lightsail.
---
## 1. Configurar a VM
### 1.1 Criar a instância
No seu provider de VPS preferido:
- Escolha Ubuntu 24.04 LTS
- Selecione o plano mínimo (1 vCPU / 1 GB RAM)
- Defina uma senha forte para root ou configure SSH key
- Anote o **IP público** (ex: `203.0.113.10`)
### 1.2 Conectar via SSH
```bash
ssh root@203.0.113.10
```
### 1.3 Atualizar o sistema
```bash
apt update && apt upgrade -y
```
### 1.4 Instalar Docker
```bash
# Instalar dependências
apt install -y ca-certificates curl gnupg
# Adicionar repositório oficial do Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
### 1.5 Instalar nginx
```bash
apt install -y nginx
```
### 1.6 Configurar Firewall (UFW)
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP (redirect)
ufw allow 443/tcp # HTTPS
ufw enable
```
> **Dica**: Para segurança máxima, restrinja as portas 80 e 443 apenas para IPs da Cloudflare. Veja a seção [Segurança Avançada](#segurança-avançada).
---
## 2. Instalar o OmniRoute
### 2.1 Criar diretório de configuração
```bash
mkdir -p /opt/omniroute
```
### 2.2 Criar arquivo de variáveis de ambiente
```bash
cat > /opt/omniroute/.env << 'EOF'
# === Segurança ===
JWT_SECRET=ALTERE-PARA-CHAVE-SECRETA-UNICA-64-CHARS
INITIAL_PASSWORD=SuaSenhaSegura123!
API_KEY_SECRET=ALTERE-PARA-OUTRA-CHAVE-SECRETA
STORAGE_ENCRYPTION_KEY=ALTERE-PARA-TERCEIRA-CHAVE-SECRETA
STORAGE_ENCRYPTION_KEY_VERSION=v1
MACHINE_ID_SALT=ALTERE-PARA-SALT-UNICO
# === App ===
PORT=20128
NODE_ENV=production
HOSTNAME=0.0.0.0
DATA_DIR=/app/data
STORAGE_DRIVER=sqlite
ENABLE_REQUEST_LOGS=true
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=false
# === Domain (altere para seu domínio) ===
BASE_URL=https://llms.seudominio.com
NEXT_PUBLIC_BASE_URL=https://llms.seudominio.com
# === Cloud Sync (opcional) ===
# CLOUD_URL=https://cloud.omniroute.online
# NEXT_PUBLIC_CLOUD_URL=https://cloud.omniroute.online
EOF
```
> ⚠️ **IMPORTANTE**: Gere chaves secretas únicas! Use `openssl rand -hex 32` para cada chave.
### 2.3 Iniciar o container
```bash
docker pull diegosouzapw/omniroute:latest
docker run -d \
--name omniroute \
--restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### 2.4 Verificar se está rodando
```bash
docker ps | grep omniroute
docker logs omniroute --tail 20
```
Deve exibir: `[DB] SQLite database ready` e `listening on port 20128`.
---
## 3. Configurar nginx (Reverse Proxy)
### 3.1 Gerar certificado SSL (Cloudflare Origin)
No painel da Cloudflare:
1. Vá em **SSL/TLS → Origin Server**
2. Clique **Create Certificate**
3. Deixe os padrões (15 anos, \*.seudominio.com)
4. Copie o **Origin Certificate** e a **Private Key**
```bash
mkdir -p /etc/nginx/ssl
# Colar o certificado
nano /etc/nginx/ssl/origin.crt
# Colar a chave privada
nano /etc/nginx/ssl/origin.key
chmod 600 /etc/nginx/ssl/origin.key
```
### 3.2 Configuração do nginx
```bash
cat > /etc/nginx/sites-available/omniroute << 'NGINX'
# Default server — bloqueia acesso direto por IP
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
server_name _;
return 444;
}
# OmniRoute — HTTPS
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name llms.seudominio.com; # Altere para seu domínio
ssl_certificate /etc/nginx/ssl/origin.crt;
ssl_certificate_key /etc/nginx/ssl/origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:20128;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# SSE (Server-Sent Events) — streaming AI responses
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name llms.seudominio.com;
return 301 https://$server_name$request_uri;
}
NGINX
```
### 3.3 Ativar e testar
```bash
# Remover config padrão
rm -f /etc/nginx/sites-enabled/default
# Ativar OmniRoute
ln -sf /etc/nginx/sites-available/omniroute /etc/nginx/sites-enabled/omniroute
# Testar e recarregar
nginx -t && systemctl reload nginx
```
---
## 4. Configurar Cloudflare DNS
### 4.1 Adicionar registro DNS
No painel da Cloudflare → DNS:
| Type | Name | Content | Proxy |
| ---- | ------ | ------------------------- | ---------- |
| A | `llms` | `203.0.113.10` (IP da VM) | ✅ Proxied |
### 4.2 Configurar SSL
Em **SSL/TLS → Overview**:
- Modo: **Full (Strict)**
Em **SSL/TLS → Edge Certificates**:
- Always Use HTTPS: ✅ On
- Minimum TLS Version: TLS 1.2
- Automatic HTTPS Rewrites: ✅ On
### 4.3 Testar
```bash
curl -sI https://llms.seudominio.com/health
# Deve retornar HTTP/2 200
```
---
## 5. Operações e Manutenção
### Atualizar para nova versão
```bash
docker pull diegosouzapw/omniroute:latest
docker stop omniroute && docker rm omniroute
docker run -d --name omniroute --restart unless-stopped \
--env-file /opt/omniroute/.env \
-p 20128:20128 \
-v omniroute-data:/app/data \
diegosouzapw/omniroute:latest
```
### Ver logs
```bash
docker logs -f omniroute # Stream em tempo real
docker logs omniroute --tail 50 # Últimas 50 linhas
```
### Backup manual do banco
```bash
# Copiar dados do volume para o host
docker cp omniroute:/app/data ./backup-$(date +%F)
# Ou comprimir todo o volume
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine tar czf /backup/omniroute-data-$(date +%F).tar.gz /data
```
### Restaurar de backup
```bash
docker stop omniroute
docker run --rm -v omniroute-data:/data -v $(pwd):/backup \
alpine sh -c "rm -rf /data/* && tar xzf /backup/omniroute-data-YYYY-MM-DD.tar.gz -C /"
docker start omniroute
```
---
## 6. Segurança Avançada
### Restringir nginx para Cloudflare IPs
```bash
cat > /etc/nginx/cloudflare-ips.conf << 'CF'
# Cloudflare IPv4 ranges — atualizar periodicamente
# https://www.cloudflare.com/ips-v4/
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
CF
```
Adicionar no `nginx.conf` dentro do bloco `http {}`:
```nginx
include /etc/nginx/cloudflare-ips.conf;
```
### Install fail2ban
```bash
apt install -y fail2ban
systemctl enable fail2ban
systemctl start fail2ban
# Verificar status
fail2ban-client status sshd
```
### Bloquear acesso direto na porta do Docker
```bash
# Impedir acesso externo direto à porta 20128
iptables -I DOCKER-USER -p tcp --dport 20128 -j DROP
iptables -I DOCKER-USER -i lo -p tcp --dport 20128 -j ACCEPT
# Persistir as regras
apt install -y iptables-persistent
netfilter-persistent save
```
---
## 7. Deploy do Cloud Worker (Opcional)
Para acesso remoto via Cloudflare Workers (sem expor a VM diretamente):
```bash
# No repositório local
cd omnirouteCloud
npm install
npx wrangler login
npx wrangler deploy
```
Ver documentação completa em [omnirouteCloud/README.md](../omnirouteCloud/README.md).
---
## Resumo de Portas
| Porta | Serviço | Acesso |
| ----- | ----------- | ----------------------------- |
| 22 | SSH | Público (com fail2ban) |
| 80 | nginx HTTP | Redirect → HTTPS |
| 443 | nginx HTTPS | Via Cloudflare Proxy |
| 20128 | OmniRoute | Somente localhost (via nginx) |
-37
View File
@@ -1,37 +0,0 @@
# ADR-001: Next.js as the Foundation for an AI Gateway
## Status: Accepted
## Context
OmniRoute is an AI routing gateway that translates, forwards, and manages requests across 20+ LLM providers. We needed a framework that could serve both the API proxy layer and a management dashboard from a single codebase.
**Alternatives considered:**
- **Express.js only** — Simpler proxy, but requires separate frontend tooling
- **Fastify** — Fast, but no built-in SSR/dashboard support
- **Next.js** — Unified full-stack framework with API routes, SSR, and static pages
## Decision
We chose Next.js because:
1. **Single deployment** — API routes (`/api/*`) and dashboard UI in one process
2. **Middleware layer** — Native request interception for auth guards and request tracing
3. **File-based routing** — Easy to map provider endpoints to handlers
4. **Built-in TypeScript** — Type safety across the entire codebase
## Consequences
**Positive:**
- One `npm run build` produces both API and UI
- Middleware provides centralized auth and request tracing
- Dashboard gets automatic code splitting and optimization
**Negative:**
- Next.js middleware has limitations (no heavy imports, edge runtime constraints)
- Serverless deployment model doesn't align with persistent WebSocket/SSE connections
- Build times are longer than Express-only setups
- The SSE proxy layer (`open-sse/`) operates outside Next.js conventions
-37
View File
@@ -1,37 +0,0 @@
# ADR-002: Hub-and-Spoke Translation with OpenAI as Intermediate Format
## Status: Accepted
## Context
OmniRoute routes requests across 20+ providers, each with its own API format (OpenAI, Anthropic Messages, Google Gemini, AWS Bedrock, etc.). Direct provider-to-provider translation would require O(n²) translators.
**Alternatives considered:**
- **Direct translation** — Each pair needs a dedicated translator (n² complexity)
- **Common intermediate format** — Translate to/from a canonical format (2n complexity)
- **Protocol buffers** — Strong typing but heavy overhead for a proxy
## Decision
We use the **OpenAI Chat Completions format** as the canonical intermediate representation. All incoming requests are normalized to OpenAI format, processed, then translated to the target provider's format.
```
Client → [any format] → OpenAI canonical → [target format] → Provider
Provider → [response] → OpenAI canonical → [original format] → Client
```
## Consequences
**Positive:**
- Only 2 translators per provider (inbound + outbound) instead of n² pairs
- OpenAI format is the de facto standard — most clients already use it
- Adding a new provider requires only implementing one translator pair
- Streaming (SSE) works consistently through the canonical format
**Negative:**
- Some provider-specific features may be lost in translation
- The double translation adds latency (typically < 5ms)
- OpenAI format changes require updating the canonical representation
-39
View File
@@ -1,39 +0,0 @@
# ADR-003: Dual Storage — SQLite Primary with JSON Migration Path
## Status: Accepted
## Context
OmniRoute originally used LowDB (JSON file) for all persistence. As the project grew, JSON-based storage became a bottleneck for concurrent access, querying, and data integrity.
**Alternatives considered:**
- **LowDB only** — Simple but no concurrent access, no ACID, no querying
- **SQLite only** — Fast, ACID-compliant, but breaks existing deployments
- **PostgreSQL** — Production-grade but requires external dependency
- **Dual storage with migration** — SQLite primary + automatic JSON migration
## Decision
We migrated to **SQLite as the primary store** with an automatic one-time migration from `db.json`:
1. On startup, if `db.json` exists and SQLite is empty, auto-migrate all data
2. All new reads/writes go through SQLite
3. The `db.json` file is preserved but no longer written to
Settings remain in a hybrid model where LowDB handles simple key-value configuration for backward compatibility.
## Consequences
**Positive:**
- ACID transactions for provider connections, API keys, and usage data
- Proper SQL queries for analytics and log filtering
- Concurrent read/write safety via WAL mode
- Zero-downtime migration from JSON — users upgrade transparently
**Negative:**
- Two storage engines to maintain (SQLite + LowDB for settings)
- Migration code must handle edge cases and partial data
- SQLite binary dependency needed in deployment environments
-36
View File
@@ -1,36 +0,0 @@
# Task 01 — Home Page (Dashboard)
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `home`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/page.tsx` | 17 | 0 (wrapper) |
| `src/app/(dashboard)/dashboard/HomePageClient.tsx` | 500 | ~25 |
## Strings a Traduzir
### HomePageClient.tsx
| Linha | String EN | Chave i18n | String PT-BR |
|-------|-----------|------------|--------------|
| 138 | "Quick Start" | `home.quickStart` | "Início Rápido" |
| 242 | "Providers Overview" | `home.providersOverview` | "Visão Geral dos Provedores" |
| 436 | "No models available for this provider." | `home.noModelsAvailable` | "Nenhum modelo disponível para este provedor." |
| — | "Total Requests" | `home.totalRequests` | "Total de Requisições" |
| — | "Active Providers" | `home.activeProviders` | "Provedores Ativos" |
| — | "Success Rate" | `home.successRate` | "Taxa de Sucesso" |
| — | "Avg Latency" | `home.avgLatency` | "Latência Média" |
| — | "Configure Endpoint" | `home.configureEndpoint` | "Configurar Endpoint" |
| — | "Add Provider" | `home.addProvider` | "Adicionar Provedor" |
| — | "View Docs" | `home.viewDocs` | "Ver Documentação" |
| — | "Copied!" | `common.copied` | ✅ já existe |
| — | "requests" | `home.requests` | "requisições" |
| — | "models" | `home.models` | "modelos" |
| — | "accounts" | `home.accounts` | "contas" |
## Checklist
- [ ] Adicionar chaves no `en.json` (namespace `home`)
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir strings por `t()` no `HomePageClient.tsx`
- [ ] Testar em EN e PT-BR
-25
View File
@@ -1,25 +0,0 @@
# Task 02 — Analytics Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `analytics`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/analytics/page.tsx` | 46 | ~8 |
## Strings a Traduzir
| Linha | String EN | Chave i18n | String PT-BR |
|-------|-----------|------------|--------------|
| 11 | "Monitor your API usage patterns..." | `analytics.overviewDescription` | "Monitore padrões de uso da API..." |
| 13 | "Run evaluation suites to test..." | `analytics.evalsDescription` | "Execute suítes de avaliação..." |
| 24 | "Analytics" | `analytics.title` | "Análises" |
| 32 | "Overview" | `analytics.overview` | "Visão Geral" |
| 33 | "Evals" | `analytics.evals` | "Avaliações" |
## Checklist
- [ ] Adicionar chaves no `en.json`
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir strings por `t()` em `page.tsx`
- [ ] Testar em EN e PT-BR
-31
View File
@@ -1,31 +0,0 @@
# Task 03 — API Manager Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `apiManager`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx` | ~400 | ~20 |
## Strings a Traduzir (levantamento parcial — abrir código para completar)
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "API Keys" | `apiManager.title` | "Chaves de API" |
| "Create API Key" | `apiManager.createKey` | "Criar Chave de API" |
| "Name" | `apiManager.name` | "Nome" |
| "Key" | `apiManager.key` | "Chave" |
| "Created" | `apiManager.created` | "Criado em" |
| "Last Used" | `apiManager.lastUsed` | "Último Uso" |
| "Actions" | `apiManager.actions` | "Ações" |
| "Delete" | `common.delete` | ✅ já existe |
| "No API keys found" | `apiManager.noKeys` | "Nenhuma chave de API encontrada" |
| ~11 strings adicionais | — | Levantar no código |
## Checklist
- [ ] Levantar todas as strings do `ApiManagerPageClient.tsx`
- [ ] Adicionar chaves no `en.json`
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir strings por `t()`
- [ ] Testar em EN e PT-BR
-31
View File
@@ -1,31 +0,0 @@
# Task 04 — Audit Log Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `auditLog`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/audit-log/page.tsx` | 241 | ~12 |
| `src/app/(dashboard)/dashboard/logs/AuditLogTab.tsx` | ~100 | ~3 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Audit Log" | `auditLog.title` | "Log de Auditoria" |
| "Search actions..." | `auditLog.searchPlaceholder` | "Buscar ações..." |
| "Action" | `auditLog.action` | "Ação" |
| "Actor" | `auditLog.actor` | "Autor" |
| "Target" | `auditLog.target` | "Alvo" |
| "Details" | `auditLog.details` | "Detalhes" |
| "IP Address" | `auditLog.ipAddress` | "Endereço IP" |
| "Timestamp" | `auditLog.timestamp` | "Data/Hora" |
| "No audit entries found" | `auditLog.noEntries` | "Nenhum registro de auditoria" |
| "Load More" | `auditLog.loadMore` | "Carregar Mais" |
## Checklist
- [ ] Adicionar chaves no `en.json`
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir strings em `audit-log/page.tsx` e `AuditLogTab.tsx`
- [ ] Testar em EN e PT-BR
-37
View File
@@ -1,37 +0,0 @@
# Task 05 — CLI Tools Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `cliTools`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `cli-tools/components/AntigravityToolCard.tsx` | ~3 |
| `cli-tools/components/ClaudeToolCard.tsx` | ~3 |
| `cli-tools/components/ClineToolCard.tsx` | ~4 |
| `cli-tools/components/CodexToolCard.tsx` | ~3 |
| `cli-tools/components/DefaultToolCard.tsx` | ~3 |
| `cli-tools/components/DroidToolCard.tsx` | ~2 |
| `cli-tools/components/KiloToolCard.tsx` | ~4 |
| `cli-tools/components/OpenClawToolCard.tsx` | ~2 |
## Strings comuns entre Tool Cards
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Status" | `cliTools.status` | "Status" |
| "Connected" | `cliTools.connected` | "Conectado" |
| "Not Connected" | `cliTools.notConnected` | "Não Conectado" |
| "Configure" | `cliTools.configure` | "Configurar" |
| "Test Connection" | `cliTools.testConnection` | "Testar Conexão" |
| "Models" | `cliTools.models` | "Modelos" |
| "Map Models" | `cliTools.mapModels` | "Mapear Modelos" |
| "Save" | `common.save` | ✅ já existe |
| "Cancel" | `common.cancel` | ✅ já existe |
## Checklist
- [ ] Levantar strings de cada ToolCard
- [ ] Adicionar chaves no `en.json`
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir por `t()` em cada componente
- [ ] Testar em EN e PT-BR
-34
View File
@@ -1,34 +0,0 @@
# Task 06 — Combos Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `combos`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/combos/page.tsx` | ~1000 | ~20 |
## Strings a Traduzir
| Linha | String EN | Chave i18n | String PT-BR |
|-------|-----------|------------|--------------|
| 207 | "Combos" | `combos.title` | "Combos" |
| 372 | "No models" | `combos.noModels` | "Sem modelos" |
| 747 | "Routing Strategy" | `combos.routingStrategy` | "Estratégia de Roteamento" |
| 791 | "Models" | `combos.models` | "Modelos" |
| 807 | "No models added yet" | `combos.noModelsYet` | "Nenhum modelo adicionado" |
| 922 | "Max Retries" | `combos.maxRetries` | "Máximo de Tentativas" |
| 959 | "Timeout (ms)" | `combos.timeout` | "Timeout (ms)" |
| 977 | "Healthcheck" | `combos.healthcheck` | "Verificação de Saúde" |
| — | "Create Combo" | `combos.create` | "Criar Combo" |
| — | "Edit Combo" | `combos.edit` | "Editar Combo" |
| — | "Delete Combo" | `combos.deleteCombo` | "Excluir Combo" |
| — | "Add Model" | `combos.addModel` | "Adicionar Modelo" |
| — | "Priority" | `combos.priority` | "Prioridade" |
| — | "Fallback" | `combos.fallback` | "Fallback" |
## Checklist
- [ ] Adicionar chaves no `en.json`
- [ ] Adicionar traduções no `pt-BR.json`
- [ ] Substituir strings por `t()` em `combos/page.tsx`
- [ ] Testar em EN e PT-BR
-23
View File
@@ -1,23 +0,0 @@
# Task 07 — Costs Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `costs`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/costs/page.tsx` | ~200 | ~5 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Costs" | `costs.title` | "Custos" |
| "Total Cost" | `costs.totalCost` | "Custo Total" |
| "Cost Breakdown" | `costs.breakdown` | "Detalhamento de Custos" |
| "No cost data" | `costs.noData` | "Sem dados de custo" |
## Checklist
- [ ] Levantar strings completas do código
- [ ] Adicionar chaves no `en.json` / `pt-BR.json`
- [ ] Substituir por `t()` e testar
-30
View File
@@ -1,30 +0,0 @@
# Task 08 — Endpoint Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `endpoint`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx` | ~750 | ~20 |
## Strings a Traduzir
| Linha | String EN | Chave i18n | String PT-BR |
|-------|-----------|------------|--------------|
| 320 | "API Endpoint" | `endpoint.title` | "Endpoint da API" |
| 403 | "Available Endpoints" | `endpoint.available` | "Endpoints Disponíveis" |
| 561 | "Cloud Proxy" | `endpoint.cloudProxy` | "Proxy na Nuvem" |
| 632 | "Note" | `endpoint.note` | "Nota" |
| 717 | "Warning" | `endpoint.warning` | "Aviso" |
| 740 | "Are you sure you want to disable cloud proxy?" | `endpoint.disableConfirm` | "Tem certeza que deseja desativar o proxy na nuvem?" |
| — | "Copy" | `common.copy` | ✅ já existe |
| — | "Base URL" | `endpoint.baseUrl` | "URL Base" |
| — | "Connected" | `endpoint.connected` | "Conectado" |
| — | "Enable" | `endpoint.enable` | "Ativar" |
| — | "Disable" | `endpoint.disable` | "Desativar" |
## Checklist
- [ ] Levantar strings restantes
- [ ] Adicionar chaves no `en.json` / `pt-BR.json`
- [ ] Substituir por `t()` e testar
-30
View File
@@ -1,30 +0,0 @@
# Task 09 — Health Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `health`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/health/page.tsx` | ~350 | ~15 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "System Health" | `health.title` | "Saúde do Sistema" |
| "Healthy" | `health.healthy` | "Saudável" |
| "Degraded" | `health.degraded` | "Degradado" |
| "Down" | `health.down` | "Offline" |
| "Uptime" | `health.uptime` | "Tempo Ativo" |
| "Memory" | `health.memory` | "Memória" |
| "CPU" | `health.cpu` | "CPU" |
| "Database" | `health.database` | "Banco de Dados" |
| "Last Check" | `health.lastCheck` | "Última Verificação" |
| "Refresh" | `common.refresh` | ✅ já existe |
| ~5 strings adicionais | — | Levantar |
## Checklist
- [ ] Levantar strings restantes
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-24
View File
@@ -1,24 +0,0 @@
# Task 10 — Limits Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `limits`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/limits/page.tsx` | ~150 | ~5 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Limits & Quotas" | `limits.title` | "Limites e Cotas" |
| "Rate Limit" | `limits.rateLimit` | "Limite de Taxa" |
| "Provider" | `limits.provider` | "Provedor" |
| "Remaining" | `limits.remaining` | "Restante" |
| "Reset" | `limits.reset` | "Reiniciar" |
## Checklist
- [ ] Levantar strings completas
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-24
View File
@@ -1,24 +0,0 @@
# Task 11 — Logs Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `logs`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/logs/` | ~200 | ~5 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Logs" | `logs.title` | "Logs" |
| "Request Logs" | `logs.requestLogs` | "Logs de Requisições" |
| "Proxy Logs" | `logs.proxyLogs` | "Logs do Proxy" |
| "Audit Log" | `logs.auditLog` | "Log de Auditoria" |
| "Console" | `logs.console` | "Console" |
## Checklist
- [ ] Levantar strings completas
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-26
View File
@@ -1,26 +0,0 @@
# Task 12 — Onboarding Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `onboarding`
## Arquivos
| Arquivo | Linhas | Strings |
|---------|--------|---------|
| `src/app/(dashboard)/dashboard/onboarding/page.tsx` | ~300 | ~10 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Welcome to OmniRoute" | `onboarding.welcome` | "Bem-vindo ao OmniRoute" |
| "Set Password" | `onboarding.setPassword` | "Definir Senha" |
| "Add Provider" | `onboarding.addProvider` | "Adicionar Provedor" |
| "Get Started" | `onboarding.getStarted` | "Começar" |
| "Skip" | `onboarding.skip` | "Pular" |
| "Next" | `common.next` | ✅ já existe |
| ~4 strings adicionais | — | Levantar |
## Checklist
- [ ] Levantar strings completas
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-35
View File
@@ -1,35 +0,0 @@
# Task 13 — Providers Pages
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `providers`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `providers/page.tsx` | ~5 |
| `providers/[id]/page.tsx` | ~12 |
| `providers/new/page.tsx` | ~3 |
| `providers/components/ModelAvailabilityPanel.tsx` | ~3 |
| `providers/components/ModelAvailabilityBadge.tsx` | ~1 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Providers" | `providers.title` | "Provedores" |
| "Add Provider" | `providers.add` | "Adicionar Provedor" |
| "Edit Provider" | `providers.edit` | "Editar Provedor" |
| "Test Connection" | `providers.testConnection` | "Testar Conexão" |
| "Connected" | `providers.connected` | "Conectado" |
| "Disconnected" | `providers.disconnected` | "Desconectado" |
| "Models" | `providers.models` | "Modelos" |
| "Accounts" | `providers.accounts` | "Contas" |
| "Delete Provider" | `providers.deleteProvider` | "Excluir Provedor" |
| "No providers configured" | `providers.noProviders` | "Nenhum provedor configurado" |
| "Model Availability" | `providers.modelAvailability` | "Disponibilidade de Modelos" |
| ~9 strings adicionais | — | Levantar |
## Checklist
- [ ] Levantar strings completas de todos os arquivos
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-51
View File
@@ -1,51 +0,0 @@
# Task 14 — Settings Page (MAIOR TAREFA)
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `settings`
## Arquivos (20 componentes!)
| Arquivo | Strings |
|---------|---------|
| `settings/components/AppearanceTab.tsx` | ~4 |
| `settings/components/CacheStatsCard.tsx` | ~4 |
| `settings/components/ComboDefaultsTab.tsx` | ~8 |
| `settings/components/FallbackChainsEditor.tsx` | ~2 |
| `settings/components/IPFilterSection.tsx` | ~2 |
| `settings/components/PoliciesPanel.tsx` | ~5 |
| `settings/components/PricingTab.tsx` | ~8 |
| `settings/components/ProxyTab.tsx` | ~2 |
| `settings/components/ResilienceTab.tsx` | ~7 |
| `settings/components/RoutingTab.tsx` | ~4 |
| `settings/components/SecurityTab.tsx` | ~5 |
| `settings/components/SessionInfoCard.tsx` | ~5 |
| `settings/components/SystemPromptTab.tsx` | ~2 |
| `settings/components/SystemStorageTab.tsx` | ~8 |
| `settings/components/ThinkingBudgetTab.tsx` | ~5 |
| `settings/pricing/page.tsx` | ~17 |
## Strings a Traduzir (amostra)
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "General" | `settings.general` | "Geral" |
| "Security" | `settings.security` | "Segurança" |
| "Appearance" | `settings.appearance` | "Aparência" |
| "Routing" | `settings.routing` | "Roteamento" |
| "Cache" | `settings.cache` | "Cache" |
| "Resilience" | `settings.resilience` | "Resiliência" |
| "System Prompt" | `settings.systemPrompt` | "Prompt do Sistema" |
| "Thinking Budget" | `settings.thinkingBudget` | "Orçamento de Raciocínio" |
| "Proxy" | `settings.proxy` | "Proxy" |
| "Pricing" | `settings.pricing` | "Preços" |
| "Storage" | `settings.storage` | "Armazenamento" |
| "Policies" | `settings.policies` | "Políticas" |
| "IP Filter" | `settings.ipFilter` | "Filtro de IP" |
| "Combo Defaults" | `settings.comboDefaults` | "Padrões de Combo" |
| "Fallback Chains" | `settings.fallbackChains` | "Cadeias de Fallback" |
| ~40 strings adicionais | — | Levantar em cada tab |
## Checklist
- [ ] Levantar strings de CADA componente (16 arquivos)
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em todos os 16 arquivos
- [ ] Testar cada aba em EN e PT-BR
-41
View File
@@ -1,41 +0,0 @@
# Task 15 — Translator Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `translator`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `translator/components/LiveMonitorMode.tsx` | ~11 |
| `translator/components/PlaygroundMode.tsx` | ~5 |
| `translator/components/TestBenchMode.tsx` | ~3 |
| `translator/components/ChatTesterMode.tsx` | ~4 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Real-Time Translation Activity" | `translator.realtime` | "Atividade de Tradução em Tempo Real" |
| "Chat Tester" | `translator.chatTester` | "Testador de Chat" |
| "Test Bench" | `translator.testBench` | "Bancada de Testes" |
| "Recent Translations" | `translator.recentTranslations` | "Traduções Recentes" |
| "No translations yet" | `translator.noTranslations` | "Nenhuma tradução ainda" |
| "Time" | `translator.time` | "Tempo" |
| "Source" | `translator.source` | "Origem" |
| "Target" | `translator.target` | "Destino" |
| "Model" | `translator.model` | "Modelo" |
| "Status" | `translator.status` | "Status" |
| "Latency" | `translator.latency` | "Latência" |
| "Format Converter" | `translator.formatConverter` | "Conversor de Formato" |
| "Input" | `translator.input` | "Entrada" |
| "Output" | `translator.output` | "Saída" |
| "Example Templates" | `translator.exampleTemplates` | "Modelos de Exemplo" |
| "Compatibility Tester" | `translator.compatibilityTester` | "Testador de Compatibilidade" |
| "Compatibility Report" | `translator.compatibilityReport` | "Relatório de Compatibilidade" |
| "Pipeline Debugger" | `translator.pipelineDebugger` | "Depurador de Pipeline" |
| "Translation Pipeline" | `translator.translationPipeline` | "Pipeline de Tradução" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada componente
- [ ] Testar em EN e PT-BR
-57
View File
@@ -1,57 +0,0 @@
# Task 16 — Usage Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `usage`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `usage/components/BudgetTab.tsx` | ~4 |
| `usage/components/BudgetTelemetryCards.tsx` | ~9 |
| `usage/components/EvalsTab.tsx` | ~6 |
| `usage/components/RateLimitStatus.tsx` | ~2 |
| `usage/components/SessionsTab.tsx` | ~7 |
| `usage/components/ProviderLimits/index.tsx` | ~7 |
| `usage/components/ProviderLimits/ProviderLimitCard.tsx` | ~1 |
| `usage/components/ProviderLimits/QuotaTable.tsx` | ~1 |
## Strings a Traduzir
| String EN | Chave i18n | String PT-BR |
|-----------|------------|--------------|
| "Budget Management" | `usage.budgetManagement` | "Gerenciamento de Orçamento" |
| "API Key" | `usage.apiKey` | "Chave de API" |
| "This Month" | `usage.thisMonth` | "Este Mês" |
| "Set Limits" | `usage.setLimits` | "Definir Limites" |
| "Total requests" | `usage.totalRequests` | "Total de requisições" |
| "No data yet" | `usage.noData` | "Sem dados ainda" |
| "Entries" | `usage.entries` | "Entradas" |
| "Hit Rate" | `usage.hitRate` | "Taxa de Acerto" |
| "Circuit Breakers" | `usage.circuitBreakers` | "Disjuntores" |
| "Locked IPs" | `usage.lockedIPs` | "IPs Bloqueados" |
| "How It Works" | `usage.howItWorks` | "Como Funciona" |
| "Define" | `usage.define` | "Definir" |
| "Run" | `usage.run` | "Executar" |
| "Evaluate" | `usage.evaluate` | "Avaliar" |
| "Evaluation Suites" | `usage.evalSuites` | "Suítes de Avaliação" |
| "Model Evaluations" | `usage.modelEvals` | "Avaliações de Modelos" |
| "Model Lockouts" | `usage.modelLockouts` | "Bloqueios de Modelo" |
| "No models currently locked" | `usage.noLockouts` | "Nenhum modelo bloqueado" |
| "Active Sessions" | `usage.activeSessions` | "Sessões Ativas" |
| "No active sessions" | `usage.noSessions` | "Sem sessões ativas" |
| "Session" | `usage.session` | "Sessão" |
| "Age" | `usage.age` | "Idade" |
| "Requests" | `usage.requests` | "Requisições" |
| "Connection" | `usage.connection` | "Conexão" |
| "Provider Limits" | `usage.providerLimits` | "Limites do Provedor" |
| "No Providers Connected" | `usage.noProviders` | "Nenhum Provedor Conectado" |
| "Account" | `usage.account` | "Conta" |
| "Model Quotas" | `usage.modelQuotas` | "Cotas de Modelo" |
| "Last Used" | `usage.lastUsed` | "Último Uso" |
| "Actions" | `usage.actions` | "Ações" |
| "No quota data" | `usage.noQuota` | "Sem dados de cota" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada componente
- [ ] Testar em EN e PT-BR
-44
View File
@@ -1,44 +0,0 @@
# Task 17 — Shared Modals
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `modals`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `shared/components/OAuthModal.tsx` | ~6 |
| `shared/components/KiroAuthModal.tsx` | ~10 |
| `shared/components/KiroSocialOAuthModal.tsx` | ~3 |
| `shared/components/CursorAuthModal.tsx` | ~2 |
| `shared/components/PricingModal.tsx` | ~10 |
| `shared/components/ModelSelectModal.tsx` | ~2 |
| `shared/components/ProxyConfigModal.tsx` | ~1 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "Waiting for Authorization" | "Aguardando Autorização" |
| "Verification URL" | "URL de Verificação" |
| "Your Code" | "Seu Código" |
| "Remote access:" | "Acesso remoto:" |
| "Connected Successfully!" | "Conectado com Sucesso!" |
| "Connection Failed" | "Falha na Conexão" |
| "Choose your authentication method:" | "Escolha seu método de autenticação:" |
| "AWS Builder ID" | "AWS Builder ID" |
| "AWS IAM Identity Center" | "AWS IAM Identity Center" |
| "Google Account" | "Conta Google" |
| "GitHub Account" | "Conta GitHub" |
| "Import Token" | "Importar Token" |
| "Auto-detecting tokens..." | "Detectando tokens automaticamente..." |
| "Pricing Configuration" | "Configuração de Preços" |
| "Loading pricing data..." | "Carregando dados de preços..." |
| "Model" / "Input" / "Output" / "Cached" | "Modelo" / "Entrada" / "Saída" / "Em Cache" |
| "Combos" | "Combos" |
| "No models found" | "Nenhum modelo encontrado" |
| "Connected" | "Conectado" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada modal
- [ ] Testar cada modal em EN e PT-BR
-37
View File
@@ -1,37 +0,0 @@
# Task 18 — Shared Loggers
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `loggers`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `shared/components/RequestLoggerV2.tsx` | ~12 |
| `shared/components/RequestLoggerDetail.tsx` | ~4 |
| `shared/components/ProxyLogger.tsx` | ~7 |
| `shared/components/ProxyLogDetail.tsx` | ~6 |
| `shared/components/ConsoleLogViewer.tsx` | ~2 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "All Providers" | "Todos os Provedores" |
| "All Models" | "Todos os Modelos" |
| "All Accounts" | "Todas as Contas" |
| "All API Keys" | "Todas as Chaves de API" |
| "Newest" / "Oldest" | "Mais Recente" / "Mais Antigo" |
| "Model A-Z" / "Model Z-A" | "Modelo A-Z" / "Modelo Z-A" |
| "Columns" | "Colunas" |
| "Loading logs..." | "Carregando logs..." |
| "All Types" | "Todos os Tipos" |
| "All Levels" | "Todos os Níveis" |
| "Proxy Event" | "Evento do Proxy" |
| "Time" / "Model" / "Combo" | "Tempo" / "Modelo" / "Combo" |
| "No log entries found" | "Nenhuma entrada de log encontrada" |
| "No payload data available" | "Nenhum dado de payload disponível" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada logger
- [ ] Testar em EN e PT-BR
-36
View File
@@ -1,36 +0,0 @@
# Task 19 — Shared Charts & Stats
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `stats`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `shared/components/UsageStats.tsx` | ~6 |
| `shared/components/analytics/charts.tsx` | ~15 |
| `shared/components/TokenHealthBadge.tsx` | ~6 |
| `shared/components/SystemMonitor.tsx` | ~1 |
| `shared/components/Footer.tsx` | ~3 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "Usage Overview" | "Visão Geral de Uso" |
| "Output Tokens" | "Tokens de Saída" |
| "Total Cost" | "Custo Total" |
| "Usage by Model" | "Uso por Modelo" |
| "Usage by Account" | "Uso por Conta" |
| "Failed to load usage statistics." | "Falha ao carregar estatísticas." |
| "Token Health" | "Saúde dos Tokens" |
| "Total OAuth" | "Total OAuth" |
| "Healthy" / "Errored" / "Warning" | "Saudável" / "Com Erro" / "Aviso" |
| "Last check" | "Última verificação" |
| "No data" / "Share" | "Sem dados" / "Compartilhar" |
| "Unable to load system metrics" | "Não foi possível carregar métricas" |
| "Product" / "Resources" / "Company" (Footer) | "Produto" / "Recursos" / "Empresa" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada componente
- [ ] Testar em EN e PT-BR
-36
View File
@@ -1,36 +0,0 @@
# Task 20 — Login & Auth Pages
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `auth`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `src/app/login/page.tsx` | ~8 |
| `src/app/forgot-password/page.tsx` | ~3 |
| `src/app/callback/page.tsx` | ~5 |
| `src/app/forbidden/page.tsx` | ~1 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "Welcome" | "Bem-vindo" |
| "OmniRoute" | "OmniRoute" (não traduzir) |
| "Sign in" | "Entrar" |
| "Enter your password to continue" | "Digite sua senha para continuar" |
| "Password" | "Senha" |
| "Unified AI API Proxy" | "Proxy Unificado de API de IA" |
| "Loading..." | "Carregando..." |
| "Password protection is not enabled" | "Proteção por senha não está ativada" |
| "Reset Password" | "Redefinir Senha" |
| "Choose a method to recover access" | "Escolha um método para recuperar acesso" |
| "Processing..." | "Processando..." |
| "Authorization Successful!" | "Autorização bem-sucedida!" |
| "Copy This URL" | "Copiar esta URL" |
| "Access Denied" | "Acesso Negado" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` em cada página
- [ ] Testar em EN e PT-BR
-34
View File
@@ -1,34 +0,0 @@
# Task 21 — Landing Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `landing`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `landing/components/HeroSection.tsx` | ~3 |
| `landing/components/Features.tsx` | ~10 |
| `landing/components/HowItWorks.tsx` | ~5 |
| `landing/components/GetStarted.tsx` | ~5 |
| `landing/components/Navigation.tsx` | ~2 |
| `landing/components/FlowAnimation.tsx` | ~2 |
| `landing/components/Footer.tsx` | ~5 |
## Strings a Traduzir (amostra)
| String EN | String PT-BR |
|-----------|--------------|
| "All AI Providers" | "Todos os Provedores de IA" |
| "One Endpoint" | "Um Endpoint" |
| "Powerful Features" | "Recursos Poderosos" |
| "How OmniRoute Works" | "Como o OmniRoute Funciona" |
| "Install OmniRoute" | "Instalar o OmniRoute" |
| "Open Dashboard" | "Abrir Painel" |
| "Route Requests" | "Rotear Requisições" |
| "Data Location:" | "Local dos Dados:" |
| "Product" / "Resources" / "Legal" | "Produto" / "Recursos" / "Legal" |
## Checklist
- [ ] Levantar strings completas de cada componente
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-32
View File
@@ -1,32 +0,0 @@
# Task 22 — Docs Page
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `docs`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `src/app/docs/page.tsx` | ~25 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "Quick Start" | "Início Rápido" |
| "Features" | "Recursos" |
| "Supported Providers" | "Provedores Suportados" |
| "Common Use Cases" | "Casos de Uso Comuns" |
| "Client Compatibility" | "Compatibilidade de Clientes" |
| "Cherry Studio" | "Cherry Studio" (não traduzir) |
| "Codex / GitHub Copilot Models" | "Modelos Codex / GitHub Copilot" |
| "Cursor IDE" | "Cursor IDE" (não traduzir) |
| "Claude Code / Antigravity" | "Claude Code / Antigravity" |
| "API Reference" | "Referência da API" |
| "Method" / "Path" / "Notes" | "Método" / "Caminho" / "Notas" |
| "Model Prefixes" | "Prefixos de Modelo" |
| "Prefix" / "Provider" / "Type" | "Prefixo" / "Provedor" / "Tipo" |
| "Troubleshooting" | "Solução de Problemas" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
-31
View File
@@ -1,31 +0,0 @@
# Task 23 — Legal Pages (Privacy & Terms)
**Status:** `[ ]` Não iniciado
**Namespace JSON:** `legal`
## Arquivos
| Arquivo | Strings |
|---------|---------|
| `src/app/privacy/page.tsx` | ~10 |
| `src/app/terms/page.tsx` | ~5 |
## Strings a Traduzir
| String EN | String PT-BR |
|-----------|--------------|
| "Privacy Policy" | "Política de Privacidade" |
| "Terms of Service" | "Termos de Serviço" |
| "Provider configurations" | "Configurações de provedores" |
| "API keys" | "Chaves de API" |
| "Usage logs" | "Logs de uso" |
| "Application settings" | "Configurações do aplicativo" |
| "View and export usage analytics" | "Visualizar e exportar análises de uso" |
| "Clear usage history at any time" | "Limpar histórico de uso a qualquer momento" |
| "Configure log retention policies" | "Configurar políticas de retenção de logs" |
| "Back up and restore your database" | "Fazer backup e restaurar seu banco de dados" |
## Checklist
- [ ] Adicionar chaves / traduções
- [ ] Substituir por `t()` e testar
> **Nota:** Textos legais podem requerer revisão jurídica para tradução formal.
-51
View File
@@ -1,51 +0,0 @@
# i18n Translation Tasks
Cada arquivo `.md` nesta pasta representa **uma tarefa de tradução** para uma página ou componente do OmniRoute.
## Status Legend
- `[ ]` — Não iniciado
- `[/]` — Em progresso
- `[x]` — Concluído
## Dashboard Pages (~260 strings)
| # | Tarefa | Arquivo | Strings | Status |
| --- | ---------------------------------- | ----------------------------------------------------- | ------- | ------ |
| 01 | [Home](./01-home.md) | `HomePageClient.tsx` | ~25 | `[ ]` |
| 02 | [Analytics](./02-analytics.md) | `analytics/page.tsx` | ~8 | `[ ]` |
| 03 | [API Manager](./03-api-manager.md) | `api-manager/` | ~20 | `[ ]` |
| 04 | [Audit Log](./04-audit-log.md) | `audit-log/page.tsx`, `logs/AuditLogTab.tsx` | ~15 | `[ ]` |
| 05 | [CLI Tools](./05-cli-tools.md) | `cli-tools/components/*.tsx` | ~20 | `[ ]` |
| 06 | [Combos](./06-combos.md) | `combos/page.tsx` | ~20 | `[ ]` |
| 07 | [Costs](./07-costs.md) | `costs/page.tsx` | ~5 | `[ ]` |
| 08 | [Endpoint](./08-endpoint.md) | `endpoint/EndpointPageClient.tsx` | ~20 | `[ ]` |
| 09 | [Health](./09-health.md) | `health/page.tsx` | ~15 | `[ ]` |
| 10 | [Limits](./10-limits.md) | `limits/page.tsx` | ~5 | `[ ]` |
| 11 | [Logs](./11-logs.md) | `logs/` | ~5 | `[ ]` |
| 12 | [Onboarding](./12-onboarding.md) | `onboarding/page.tsx` | ~10 | `[ ]` |
| 13 | [Providers](./13-providers.md) | `providers/page.tsx`, `[id]/page.tsx`, `new/page.tsx` | ~20 | `[ ]` |
| 14 | [Settings](./14-settings.md) | `settings/components/*.tsx` | ~55 | `[ ]` |
| 15 | [Translator](./15-translator.md) | `translator/components/*.tsx` | ~25 | `[ ]` |
| 16 | [Usage](./16-usage.md) | `usage/components/*.tsx` | ~35 | `[ ]` |
## Shared Components (~95 strings)
| # | Tarefa | Arquivo(s) | Strings | Status |
| --- | ---------------------------------------------- | ---------------------------------------------------- | ------- | ------ |
| 17 | [Shared Modals](./17-shared-modals.md) | `OAuthModal`, `KiroAuthModal`, `PricingModal`, etc. | ~40 | `[ ]` |
| 18 | [Shared Loggers](./18-shared-loggers.md) | `RequestLoggerV2`, `ProxyLogger`, `ProxyLogDetail` | ~30 | `[ ]` |
| 19 | [Shared Charts & Stats](./19-shared-charts.md) | `UsageStats`, `analytics/charts`, `TokenHealthBadge` | ~25 | `[ ]` |
## Non-Dashboard Pages (~75 strings)
| # | Tarefa | Arquivo(s) | Strings | Status |
| --- | ---------------------------------- | ------------------------------------------------------- | ------- | ------ |
| 20 | [Login & Auth](./20-login-auth.md) | `login/`, `forgot-password/`, `callback/`, `forbidden/` | ~20 | `[ ]` |
| 21 | [Landing Page](./21-landing.md) | `landing/components/*.tsx` | ~25 | `[ ]` |
| 22 | [Docs Page](./22-docs.md) | `docs/page.tsx` | ~25 | `[ ]` |
| 23 | [Legal Pages](./23-legal.md) | `privacy/`, `terms/` | ~15 | `[ ]` |
---
**Total estimado: ~460 strings em 23 tarefas**
-12
View File
@@ -1,12 +0,0 @@
# Multilingual Documentation
This directory contains machine-assisted translations based on the English docs.
- **API_REFERENCE.md**: 🇺🇸 [English](../API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](./es/API_REFERENCE.md) | 🇫🇷 [Français](./fr/API_REFERENCE.md) | 🇮🇹 [Italiano](./it/API_REFERENCE.md) | 🇷🇺 [Русский](./ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](./zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](./de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](./in/API_REFERENCE.md) | 🇹🇭 [ไทย](./th/API_REFERENCE.md) | 🇺🇦 [Українська](./uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](./ar/API_REFERENCE.md) | 🇯🇵 [日本語](./ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](./vi/API_REFERENCE.md) | 🇧🇬 [Български](./bg/API_REFERENCE.md) | 🇩🇰 [Dansk](./da/API_REFERENCE.md) | 🇫🇮 [Suomi](./fi/API_REFERENCE.md) | 🇮🇱 [עברית](./he/API_REFERENCE.md) | 🇭🇺 [Magyar](./hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](./id/API_REFERENCE.md) | 🇰🇷 [한국어](./ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](./ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](./nl/API_REFERENCE.md) | 🇳🇴 [Norsk](./no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](./pt/API_REFERENCE.md) | 🇷🇴 [Română](./ro/API_REFERENCE.md) | 🇵🇱 [Polski](./pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](./sk/API_REFERENCE.md) | 🇸🇪 [Svenska](./sv/API_REFERENCE.md) | 🇵🇭 [Filipino](./phi/API_REFERENCE.md)
- **ARCHITECTURE.md**: 🇺🇸 [English](../ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](./es/ARCHITECTURE.md) | 🇫🇷 [Français](./fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](./it/ARCHITECTURE.md) | 🇷🇺 [Русский](./ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](./zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](./de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](./in/ARCHITECTURE.md) | 🇹🇭 [ไทย](./th/ARCHITECTURE.md) | 🇺🇦 [Українська](./uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](./ar/ARCHITECTURE.md) | 🇯🇵 [日本語](./ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](./vi/ARCHITECTURE.md) | 🇧🇬 [Български](./bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](./da/ARCHITECTURE.md) | 🇫🇮 [Suomi](./fi/ARCHITECTURE.md) | 🇮🇱 [עברית](./he/ARCHITECTURE.md) | 🇭🇺 [Magyar](./hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](./id/ARCHITECTURE.md) | 🇰🇷 [한국어](./ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](./ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](./nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](./no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](./pt/ARCHITECTURE.md) | 🇷🇴 [Română](./ro/ARCHITECTURE.md) | 🇵🇱 [Polski](./pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](./sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](./sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](./phi/ARCHITECTURE.md)
- **CODEBASE_DOCUMENTATION.md**: 🇺🇸 [English](../CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](./pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](./es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](./fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](./it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](./ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](./zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](./de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](./in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](./th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](./uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](./ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](./ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](./vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](./bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](./da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](./fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](./he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](./hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](./id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](./ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](./ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](./nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](./no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](./pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](./ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](./pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](./sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](./sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](./phi/CODEBASE_DOCUMENTATION.md)
- **FEATURES.md**: 🇺🇸 [English](../FEATURES.md) | 🇧🇷 [Português (Brasil)](./pt-BR/FEATURES.md) | 🇪🇸 [Español](./es/FEATURES.md) | 🇫🇷 [Français](./fr/FEATURES.md) | 🇮🇹 [Italiano](./it/FEATURES.md) | 🇷🇺 [Русский](./ru/FEATURES.md) | 🇨🇳 [中文 (简体)](./zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](./de/FEATURES.md) | 🇮🇳 [हिन्दी](./in/FEATURES.md) | 🇹🇭 [ไทย](./th/FEATURES.md) | 🇺🇦 [Українська](./uk-UA/FEATURES.md) | 🇸🇦 [العربية](./ar/FEATURES.md) | 🇯🇵 [日本語](./ja/FEATURES.md) | 🇻🇳 [Tiếng Việt](./vi/FEATURES.md) | 🇧🇬 [Български](./bg/FEATURES.md) | 🇩🇰 [Dansk](./da/FEATURES.md) | 🇫🇮 [Suomi](./fi/FEATURES.md) | 🇮🇱 [עברית](./he/FEATURES.md) | 🇭🇺 [Magyar](./hu/FEATURES.md) | 🇮🇩 [Bahasa Indonesia](./id/FEATURES.md) | 🇰🇷 [한국어](./ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](./ms/FEATURES.md) | 🇳🇱 [Nederlands](./nl/FEATURES.md) | 🇳🇴 [Norsk](./no/FEATURES.md) | 🇵🇹 [Português (Portugal)](./pt/FEATURES.md) | 🇷🇴 [Română](./ro/FEATURES.md) | 🇵🇱 [Polski](./pl/FEATURES.md) | 🇸🇰 [Slovenčina](./sk/FEATURES.md) | 🇸🇪 [Svenska](./sv/FEATURES.md) | 🇵🇭 [Filipino](./phi/FEATURES.md)
- **TROUBLESHOOTING.md**: 🇺🇸 [English](../TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](./pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](./es/TROUBLESHOOTING.md) | 🇫🇷 [Français](./fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](./it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](./ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](./zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](./de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](./in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](./th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](./uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](./ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](./ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](./vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](./bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](./da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](./fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](./he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](./hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](./id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](./ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](./ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](./nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](./no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](./pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](./ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](./pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](./sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](./sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](./phi/TROUBLESHOOTING.md)
- **USER_GUIDE.md**: 🇺🇸 [English](../USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](./pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](./es/USER_GUIDE.md) | 🇫🇷 [Français](./fr/USER_GUIDE.md) | 🇮🇹 [Italiano](./it/USER_GUIDE.md) | 🇷🇺 [Русский](./ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](./zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](./de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](./in/USER_GUIDE.md) | 🇹🇭 [ไทย](./th/USER_GUIDE.md) | 🇺🇦 [Українська](./uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](./ar/USER_GUIDE.md) | 🇯🇵 [日本語](./ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](./vi/USER_GUIDE.md) | 🇧🇬 [Български](./bg/USER_GUIDE.md) | 🇩🇰 [Dansk](./da/USER_GUIDE.md) | 🇫🇮 [Suomi](./fi/USER_GUIDE.md) | 🇮🇱 [עברית](./he/USER_GUIDE.md) | 🇭🇺 [Magyar](./hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](./id/USER_GUIDE.md) | 🇰🇷 [한국어](./ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](./ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](./nl/USER_GUIDE.md) | 🇳🇴 [Norsk](./no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](./pt/USER_GUIDE.md) | 🇷🇴 [Română](./ro/USER_GUIDE.md) | 🇵🇱 [Polski](./pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](./sk/USER_GUIDE.md) | 🇸🇪 [Svenska](./sv/USER_GUIDE.md) | 🇵🇭 [Filipino](./phi/USER_GUIDE.md)
Generated on 2026-02-26.
-441
View File
@@ -1,441 +0,0 @@
# مرجع واجهة برمجة التطبيقات
🌐 **Languages:** 🇺🇸 [English](../../API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](../es/API_REFERENCE.md) | 🇫🇷 [Français](../fr/API_REFERENCE.md) | 🇮🇹 [Italiano](../it/API_REFERENCE.md) | 🇷🇺 [Русский](../ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](../zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](../de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](../in/API_REFERENCE.md) | 🇹🇭 [ไทย](../th/API_REFERENCE.md) | 🇺🇦 [Українська](../uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](../ar/API_REFERENCE.md) | 🇯🇵 [日本語](../ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](../vi/API_REFERENCE.md) | 🇧🇬 [Български](../bg/API_REFERENCE.md) | 🇩🇰 [Dansk](../da/API_REFERENCE.md) | 🇫🇮 [Suomi](../fi/API_REFERENCE.md) | 🇮🇱 [עברית](../he/API_REFERENCE.md) | 🇭🇺 [Magyar](../hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](../id/API_REFERENCE.md) | 🇰🇷 [한국어](../ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](../ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](../nl/API_REFERENCE.md) | 🇳🇴 [Norsk](../no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](../pt/API_REFERENCE.md) | 🇷🇴 [Română](../ro/API_REFERENCE.md) | 🇵🇱 [Polski](../pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](../sk/API_REFERENCE.md) | 🇸🇪 [Svenska](../sv/API_REFERENCE.md) | 🇵🇭 [Filipino](../phi/API_REFERENCE.md)
مرجع كامل لجميع نقاط نهاية OmniRoute API.
---
## جدول المحتويات
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [List Models](#list-models)
- [Compatibility Endpoints](#compatibility-endpoints)
- [Semantic Cache](#semantic-cache)
- [Dashboard & Management](#dashboard--management)
- [Request Processing](#request-processing)
- [Authentication](#authentication)
---
## إكمالات الدردشة
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### رؤوس مخصصة
| رأس | الاتجاه | الوصف |
| ------------------------ | ------- | ------------------------------------------- |
| `X-OmniRoute-No-Cache` | طلب | اضبط على `true` لتجاوز ذاكرة التخزين المؤقت |
| `X-OmniRoute-Progress` | طلب | اضبط على `true` لأحداث التقدم |
| `Idempotency-Key` | طلب | مفتاح Dedup (نافذة 5 ثواني) |
| `X-Request-Id` | طلب | مفتاح إلغاء الحذف البديل |
| `X-OmniRoute-Cache` | الرد | `HIT` أو `MISS` (غير متدفق) |
| `X-OmniRoute-Idempotent` | الرد | `true` إذا تم إلغاء التكرار |
| `X-OmniRoute-Progress` | الرد | `enabled` إذا تم تتبع التقدم على |
---
## التضمينات
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
مقدمو الخدمة المتاحون: Nebius، وOpenAI، وMistral، وTogether AI، وFireworks، وNVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## توليد الصور
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
الموفرون المتاحون: OpenAI (DALL-E)، xAI (Grok Image)، Together AI (FLUX)، Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## قائمة النماذج
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## نقاط نهاية التوافق
| الطريقة | المسار | تنسيق |
| -------- | --------------------------- | --------------------- |
| مشاركة | `/v1/chat/completions` | أوبن آي |
| مشاركة | `/v1/messages` | انثروبي |
| مشاركة | `/v1/responses` | ردود OpenAI |
| مشاركة | `/v1/embeddings` | أوبن آي |
| مشاركة | `/v1/images/generations` | أوبن آي |
| احصل على | `/v1/models` | أوبن آي |
| مشاركة | `/v1/messages/count_tokens` | انثروبي |
| احصل على | `/v1beta/models` | الجوزاء |
| مشاركة | `/v1beta/models/{...path}` | الجوزاء توليد المحتوى |
| مشاركة | `/v1/api/chat` | أولاما |
### مسارات موفر مخصصة
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
تتم إضافة بادئة الموفر تلقائيًا في حالة فقدانها. تُرجع النماذج غير المتطابقة `400`.
---
## ذاكرة التخزين المؤقت الدلالية
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
مثال الاستجابة:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## لوحة القيادة والإدارة
### المصادقة
| نقطة النهاية | الطريقة | الوصف |
| ----------------------------- | -------------- | ------------------------ |
| `/api/auth/login` | مشاركة | تسجيل الدخول |
| `/api/auth/logout` | مشاركة | تسجيل الخروج |
| `/api/settings/require-login` | الحصول على/وضع | تبديل تسجيل الدخول مطلوب |
### إدارة مقدمي الخدمة
| نقطة النهاية | الطريقة | الوصف |
| ---------------------------- | ------------------ | --------------------------- |
| `/api/providers` | الحصول على/النشر | قائمة / إنشاء مقدمي الخدمات |
| `/api/providers/[id]` | الحصول على/وضع/حذف | إدارة مزود |
| `/api/providers/[id]/test` | مشاركة | اختبار اتصال الموفر |
| `/api/providers/[id]/models` | احصل على | قائمة نماذج المزود |
| `/api/providers/validate` | مشاركة | التحقق من صحة تكوين الموفر |
| `/api/provider-nodes*` | متنوع | إدارة عقدة الموفر |
| `/api/provider-models` | الحصول على/نشر/حذف | نماذج مخصصة |
### تدفقات OAuth
| نقطة النهاية | الطريقة | الوصف |
| -------------------------------- | ------- | ------------------------ |
| `/api/oauth/[provider]/[action]` | متنوع | OAuth الخاص بموفر الخدمة |
### التوجيه والتكوين
| نقطة النهاية | الطريقة | الوصف |
| --------------------- | ---------------- | --------------------------------- |
| `/api/models/alias` | الحصول على/النشر | الأسماء المستعارة للنموذج |
| `/api/models/catalog` | احصل على | جميع الموديلات حسب المزود + النوع |
| `/api/combos*` | متنوع | إدارة التحرير والسرد |
| `/api/keys*` | متنوع | إدارة مفاتيح API |
| `/api/pricing` | احصل على | التسعير النموذجي |
### الاستخدام والتحليلات
| نقطة النهاية | الطريقة | الوصف |
| --------------------------- | -------- | --------------------- |
| `/api/usage/history` | احصل على | تاريخ الاستخدام |
| `/api/usage/logs` | احصل على | سجلات الاستخدام |
| `/api/usage/request-logs` | احصل على | سجلات على مستوى الطلب |
| `/api/usage/[connectionId]` | احصل على | الاستخدام لكل اتصال |
### الإعدادات
| نقطة النهاية | الطريقة | الوصف |
| ------------------------------- | -------------- | ----------------------------------------------- |
| `/api/settings` | الحصول على/وضع | الإعدادات العامة |
| `/api/settings/proxy` | الحصول على/وضع | تكوين وكيل الشبكة |
| `/api/settings/proxy/test` | مشاركة | اختبار اتصال الوكيل |
| `/api/settings/ip-filter` | الحصول على/وضع | القائمة المسموح بها/القائمة المحظورة لعناوين IP |
| `/api/settings/thinking-budget` | الحصول على/وضع | الميزانية الرمزية المنطقية |
| `/api/settings/system-prompt` | الحصول على/وضع | موجه النظام العالمي |
### المراقبة
| نقطة النهاية | الطريقة | الوصف |
| ------------------------ | -------------- | ----------------------------------- |
| `/api/sessions` | احصل على | تتبع الجلسة النشطة |
| `/api/rate-limits` | احصل على | حدود المعدل لكل حساب |
| `/api/monitoring/health` | احصل على | فحص الصحة |
| `/api/cache` | الحصول على/حذف | إحصائيات ذاكرة التخزين المؤقت / مسح |
### النسخ الاحتياطي والتصدير/الاستيراد
| نقطة النهاية | الطريقة | الوصف |
| --------------------------- | -------- | -------------------------------------------------- |
| `/api/db-backups` | احصل على | قائمة النسخ الاحتياطية المتاحة |
| `/api/db-backups` | ضع | إنشاء نسخة احتياطية يدوية |
| `/api/db-backups` | مشاركة | استعادة من نسخة احتياطية محددة |
| `/api/db-backups/export` | احصل على | تنزيل قاعدة البيانات كملف .sqlite |
| `/api/db-backups/import` | مشاركة | قم بتحميل ملف .sqlite لاستبدال قاعدة البيانات |
| `/api/db-backups/exportAll` | احصل على | قم بتنزيل النسخة الاحتياطية الكاملة كأرشيف .tar.gz |
### المزامنة السحابية
| نقطة النهاية | الطريقة | الوصف |
| ---------------------- | ------- | ------------------------ |
| `/api/sync/cloud` | متنوع | عمليات المزامنة السحابية |
| `/api/sync/initialize` | مشاركة | تهيئة المزامنة |
| `/api/cloud/*` | متنوع | إدارة السحابة |
### أدوات سطر الأوامر
| نقطة النهاية | الطريقة | الوصف |
| ---------------------------------- | -------- | ------------------- |
| `/api/cli-tools/claude-settings` | احصل على | حالة كلود CLI |
| `/api/cli-tools/codex-settings` | احصل على | حالة Codex CLI |
| `/api/cli-tools/droid-settings` | احصل على | حالة Droid CLI |
| `/api/cli-tools/openclaw-settings` | احصل على | حالة OpenClaw CLI |
| `/api/cli-tools/runtime/[toolId]` | احصل على | وقت تشغيل CLI العام |
تتضمن استجابات واجهة سطر الأوامر: `installed`، `runnable`، `command`، `commandPath`، `runtimeMode`، `reason`.
### المرونة وحدود الأسعار
| نقطة النهاية | الطريقة | الوصف |
| ----------------------- | -------------- | ------------------------------------ |
| `/api/resilience` | الحصول على/وضع | الحصول على/تحديث ملفات تعريف المرونة |
| `/api/resilience/reset` | مشاركة | إعادة ضبط قواطع الدائرة |
| `/api/rate-limits` | احصل على | حالة حد المعدل لكل حساب |
| `/api/rate-limit` | احصل على | تكوين حد المعدل العالمي |
### التقييم
| نقطة النهاية | الطريقة | الوصف |
| ------------ | ---------------- | ------------------------------------- |
| `/api/evals` | الحصول على/النشر | قائمة مجموعات التقييم / تشغيل التقييم |
### السياسات
| نقطة النهاية | الطريقة | الوصف |
| --------------- | ------------------ | -------------------- |
| `/api/policies` | الحصول على/نشر/حذف | إدارة سياسات التوجيه |
###الامتثال
| نقطة النهاية | الطريقة | الوصف |
| --------------------------- | -------- | ---------------------------- |
| `/api/compliance/audit-log` | احصل على | سجل تدقيق الامتثال (آخر رقم) |
### v1beta (متوافق مع الجوزاء)
| نقطة النهاية | الطريقة | الوصف |
| -------------------------- | -------- | -------------------------------------- |
| `/v1beta/models` | احصل على | قائمة النماذج بصيغة الجوزاء |
| `/v1beta/models/{...path}` | مشاركة | الجوزاء `generateContent` نقطة النهاية |
تعكس نقاط النهاية هذه تنسيق Gemini API للعملاء الذين يتوقعون توافق Gemini SDK الأصلي.
### واجهات برمجة التطبيقات الداخلية / النظام
| نقطة النهاية | الطريقة | الوصف |
| --------------- | -------- | -------------------------------------------------- |
| `/api/init` | احصل على | فحص تهيئة التطبيق (يستخدم عند التشغيل لأول مرة) |
| `/api/tags` | احصل على | علامات النماذج المتوافقة مع Ollama (لعملاء Ollama) |
| `/api/restart` | مشاركة | تشغيل إعادة تشغيل الخادم الرشيقة |
| `/api/shutdown` | مشاركة | تشغيل إيقاف تشغيل الخادم بشكل رشيق |
> **ملاحظة:** يتم استخدام نقاط النهاية هذه داخليًا بواسطة النظام أو للتوافق مع عميل Ollama. لا يتم استدعاؤها عادة من قبل المستخدمين النهائيين.
---
## النسخ الصوتي
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
قم بنسخ الملفات الصوتية باستخدام Deepgram أو AssemblyAI.
**الطلب:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**الرد:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**الموفرون المدعمون:** `deepgram/nova-3`، `assemblyai/best`.
**التنسيقات المدعومة:** `mp3`، `wav`، `m4a`، `flac`، `ogg`، `webm`.
---
## التوافق مع أولاما
بالنسبة للعملاء الذين يستخدمون تنسيق واجهة برمجة تطبيقات Olma:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
تتم ترجمة الطلبات تلقائيًا بين تنسيقات Ollama والتنسيقات الداخلية.
---
## القياس عن بعد
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**الرد:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## الميزانية
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## توفر النموذج
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## معالجة الطلب
1. يرسل العميل طلبًا إلى `/v1/*`
2. يستدعي معالج المسار `handleChat`، `handleEmbedding`، `handleAudioTranscription`، أو `handleImageGeneration`
3. تم حل النموذج (المزود/النموذج المباشر أو الاسم المستعار/السرد)
4. تم تحديد بيانات الاعتماد من قاعدة البيانات المحلية مع تصفية توفر الحساب
5. للدردشة: `handleChatCore` — اكتشاف التنسيق، والترجمة، والتحقق من ذاكرة التخزين المؤقت، والتحقق من عدم الكفاءة
6. يقوم منفذ الموفر بإرسال طلب المنبع
7. تتم ترجمة الاستجابة مرة أخرى إلى تنسيق العميل (الدردشة) أو إعادتها كما هي (التضمينات/الصور/الصوت)
8. تم تسجيل الاستخدام/التسجيل
9. يتم تطبيق الإجراء الاحتياطي على الأخطاء وفقًا لقواعد التحرير والسرد
مرجع البنية الكاملة: [link](ARCHITECTURE.md)
---
## المصادقة
- تستخدم مسارات لوحة المعلومات (`/dashboard/*`) ملف تعريف الارتباط `auth_token`
- يستخدم تسجيل الدخول تجزئة كلمة المرور المحفوظة؛ الرجوع إلى `INITIAL_PASSWORD`
- `requireLogin` قابل للتبديل عبر `/api/settings/require-login`
- تتطلب مسارات `/v1/*` بشكل اختياري مفتاح Bearer API عندما `REQUIRE_API_KEY=true`
-781
View File
@@ -1,781 +0,0 @@
# العمارة OmniRoute
🌐 **Languages:** 🇺🇸 [English](../../ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](../es/ARCHITECTURE.md) | 🇫🇷 [Français](../fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](../it/ARCHITECTURE.md) | 🇷🇺 [Русский](../ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](../zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](../de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](../in/ARCHITECTURE.md) | 🇹🇭 [ไทย](../th/ARCHITECTURE.md) | 🇺🇦 [Українська](../uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](../ar/ARCHITECTURE.md) | 🇯🇵 [日本語](../ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](../vi/ARCHITECTURE.md) | 🇧🇬 [Български](../bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](../da/ARCHITECTURE.md) | 🇫🇮 [Suomi](../fi/ARCHITECTURE.md) | 🇮🇱 [עברית](../he/ARCHITECTURE.md) | 🇭🇺 [Magyar](../hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](../id/ARCHITECTURE.md) | 🇰🇷 [한국어](../ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](../ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](../nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](../no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](../pt/ARCHITECTURE.md) | 🇷🇴 [Română](../ro/ARCHITECTURE.md) | 🇵🇱 [Polski](../pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](../sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](../sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](../phi/ARCHITECTURE.md)
_آخر تحديث: 2026-02-18_
## ملخص تنفيذي
OmniRoute عبارة عن بوابة توجيه محلية تعمل بالذكاء الاصطناعي ولوحة معلومات مبنية على Next.js.
فهو يوفر نقطة نهاية واحدة متوافقة مع OpenAI (`/v1/*`) ويوجه حركة المرور عبر العديد من موفري الخدمات الأولية مع الترجمة والاحتياط وتحديث الرمز المميز وتتبع الاستخدام.
القدرات الأساسية:
- سطح API متوافق مع OpenAI لـ CLI/الأدوات (28 مزودًا)
- ترجمة الطلب/الاستجابة عبر تنسيقات الموفر
- نموذج احتياطي التحرير والسرد (تسلسل متعدد النماذج)
- احتياطي على مستوى الحساب (حسابات متعددة لكل مزود)
- إدارة اتصال موفر OAuth + API-key
- إنشاء التضمين عبر `/v1/embeddings` (6 موفري خدمات، 9 نماذج)
- إنشاء الصور عبر `/v1/images/generations` (4 مقدمي خدمات، 9 نماذج)
- فكر في تحليل العلامات (`<think>...</think>`) لنماذج الاستدلال
- تعقيم الاستجابة للتوافق الصارم مع OpenAI SDK
- تطبيع الدور (المطور → النظام، النظام → المستخدم) للتوافق بين الموفرين
- تحويل الإخراج المنظم (json_schema → Gemini ResponseSchema)
- الثبات المحلي لمقدمي الخدمات والمفاتيح والأسماء المستعارة والمجموعات والإعدادات والتسعير
- تتبع الاستخدام/التكلفة وتسجيل الطلب
- مزامنة سحابية اختيارية لمزامنة الأجهزة/الحالة المتعددة
- القائمة المسموح بها/القائمة المحظورة لـ IP للتحكم في الوصول إلى واجهة برمجة التطبيقات
- التفكير في إدارة الميزانية (العبور / التلقائي / المخصص / التكيفي)
- الحقن الفوري للنظام العالمي
- تتبع الجلسة وأخذ البصمات
- تحديد المعدل المحسن لكل حساب مع الملفات الشخصية الخاصة بالمزود
- نمط قاطع الدائرة لمرونة المزود
- حماية القطيع ضد الرعد مع قفل Mutex
- ذاكرة التخزين المؤقت لإلغاء البيانات المكررة للطلب المستندة إلى التوقيع
- طبقة المجال: توفر النموذج، وقواعد التكلفة، والسياسة الاحتياطية، وسياسة الإغلاق
- استمرارية حالة المجال (ذاكرة التخزين المؤقت للكتابة في SQLite للاحتياطيات والميزانيات وعمليات الإغلاق وقواطع الدائرة)
- محرك السياسة لتقييم الطلب المركزي (التأمين → الميزانية → الاحتياطي)
- طلب القياس عن بعد مع تجميع الكمون p50/p95/p99
- معرف الارتباط (X-Request-Id) للتتبع الشامل
- تسجيل تدقيق الامتثال مع إلغاء الاشتراك لكل مفتاح API
- إطار تقييمي لضمان جودة LLM
- لوحة تحكم واجهة المستخدم المرنة مع حالة قاطع الدائرة في الوقت الفعلي
- موفرو OAuth المعياريون (12 وحدة فردية ضمن `src/lib/oauth/providers/`)
نموذج وقت التشغيل الأساسي:
- تقوم مسارات تطبيق Next.js ضمن `src/app/api/*` بتنفيذ كل من واجهات برمجة تطبيقات لوحة المعلومات وواجهات برمجة تطبيقات التوافق
- نواة توجيه/SSE مشتركة في `src/sse/*` + `open-sse/*` تتعامل مع تنفيذ الموفر والترجمة والتدفق والرجوع والاستخدام
## النطاق والحدود
### في النطاق
- وقت تشغيل البوابة المحلية
- واجهات برمجة التطبيقات لإدارة لوحة المعلومات
- مصادقة الموفر وتحديث الرمز المميز
- طلب الترجمة وتدفق SSE
- الحالة المحلية + استمرارية الاستخدام
- تنسيق مزامنة سحابية اختيارية
### خارج النطاق
- تنفيذ الخدمة السحابية خلف `NEXT_PUBLIC_CLOUD_URL`
- مزود مستوى جيش تحرير السودان/مستوى التحكم خارج العملية المحلية
- ثنائيات CLI الخارجية نفسها (Claude CLI، Codex CLI، وما إلى ذلك)
## سياق النظام عالي المستوى
```mermaid
flowchart LR
subgraph Clients[Developer Clients]
C1[Claude Code]
C2[Codex CLI]
C3[OpenClaw / Droid / Cline / Continue / Roo]
C4[Custom OpenAI-compatible clients]
BROWSER[Browser Dashboard]
end
subgraph Router[OmniRoute Local Process]
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(db.json)]
UDB[(usage.json + log.txt)]
end
subgraph Upstreams[Upstream Providers]
P1[OAuth Providers\nClaude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity]
P2[API Key Providers\nOpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax\nDeepSeek/Groq/xAI/Mistral/Perplexity\nTogether/Fireworks/Cerebras/Cohere/NVIDIA]
P3[Compatible Nodes\nOpenAI-compatible / Anthropic-compatible]
end
subgraph Cloud[Optional Cloud Sync]
CLOUD[Cloud Sync Endpoint\nNEXT_PUBLIC_CLOUD_URL]
end
C1 --> API
C2 --> API
C3 --> API
C4 --> API
BROWSER --> DASH
API --> CORE
DASH --> DB
CORE --> DB
CORE --> UDB
CORE --> P1
CORE --> P2
CORE --> P3
DASH --> CLOUD
```
## مكونات وقت التشغيل الأساسية
## 1) واجهة برمجة التطبيقات وطبقة التوجيه (مسارات تطبيق Next.js)
الدلائل الرئيسية:
- `src/app/api/v1/*` و`src/app/api/v1beta/*` لواجهات برمجة تطبيقات التوافق
- `src/app/api/*` لواجهات برمجة التطبيقات للإدارة/التكوين
- تتم إعادة الكتابة التالية في الخريطة `next.config.mjs` من `/v1/*` إلى `/api/v1/*`
طرق التوافق الهامة:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — يتضمن نماذج مخصصة مع `custom: true`
- `src/app/api/v1/embeddings/route.ts` — إنشاء التضمين (6 موفري)
- `src/app/api/v1/images/generations/route.ts` — إنشاء الصور (أكثر من 4 موفري خدمة، بما في ذلك Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — دردشة مخصصة لكل مزود
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — عمليات التضمين المخصصة لكل مزود
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — صور مخصصة لكل مزود
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
مجالات الإدارة:
- المصادقة/الإعدادات: `src/app/api/auth/*`، `src/app/api/settings/*`
- مقدمو الخدمة/الاتصالات: `src/app/api/providers*`
- عقد الموفر: `src/app/api/provider-nodes*`
- النماذج المخصصة: `src/app/api/provider-models` (GET/POST/DELETE)
- كتالوج النماذج: `src/app/api/models/catalog` (GET)
- تكوين الوكيل: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- المفاتيح/الأسماء المستعارة/المجموعات/التسعير: `src/app/api/keys*`، `src/app/api/models/alias`، `src/app/api/combos*`، `src/app/api/pricing`
- الاستخدام: `src/app/api/usage/*`
- المزامنة/السحابة: `src/app/api/sync/*`، `src/app/api/cloud/*`
- مساعدي أدوات CLI: `src/app/api/cli-tools/*`
- مرشح IP: `src/app/api/settings/ip-filter` (GET/PUT)
- ميزانية التفكير: `src/app/api/settings/thinking-budget` (GET/PUT)
- موجه النظام: `src/app/api/settings/system-prompt` (GET/PUT)
- الجلسات: `src/app/api/sessions` (GET)
- حدود الأسعار: `src/app/api/rate-limits` (GET)
- المرونة: `src/app/api/resilience` (GET/PATCH) - ملفات تعريف الموفر، قاطع الدائرة، حالة حد المعدل
- إعادة ضبط المرونة: `src/app/api/resilience/reset` (POST) — إعادة ضبط الفواصل + فترات التهدئة
- إحصائيات ذاكرة التخزين المؤقت: `src/app/api/cache/stats` (الحصول على/الحذف)
- توفر النموذج: `src/app/api/models/availability` (GET/POST)
- القياس عن بعد: `src/app/api/telemetry/summary` (GET)
- الميزانية: `src/app/api/usage/budget` (GET/POST)
- السلاسل الاحتياطية: `src/app/api/fallback/chains` (GET/POST/DELETE)
- تدقيق الامتثال: `src/app/api/compliance/audit-log` (GET)
- التقييمات: `src/app/api/evals` (GET/POST)، `src/app/api/evals/[suiteId]` (GET)
- السياسات: `src/app/api/policies` (GET/POST)
## 2) SSE + جوهر الترجمة
وحدات التدفق الرئيسية:
- الإدخال: `src/sse/handlers/chat.ts`
- التنسيق الأساسي: `open-sse/handlers/chatCore.ts`
- محولات تنفيذ الموفر: `open-sse/executors/*`
- اكتشاف التنسيق/تكوين الموفر: `open-sse/services/provider.ts`
- تحليل/حل النموذج: `src/sse/services/model.ts`، `open-sse/services/model.ts`
- المنطق الاحتياطي للحساب: `open-sse/services/accountFallback.ts`
- سجل الترجمة: `open-sse/translator/index.ts`
- تحويلات الدفق: `open-sse/utils/stream.ts`، `open-sse/utils/streamHandler.ts`
- استخراج/تسوية الاستخدام: `open-sse/utils/usageTracking.ts`
- محلل العلامات: `open-sse/utils/thinkTagParser.ts`
- معالج التضمين: `open-sse/handlers/embeddings.ts`
- تسجيل موفر التضمين: `open-sse/config/embeddingRegistry.ts`
- معالج إنشاء الصور: `open-sse/handlers/imageGeneration.ts`
- سجل موفر الصور: `open-sse/config/imageRegistry.ts`
- تعقيم الاستجابة: `open-sse/handlers/responseSanitizer.ts`
- تطبيع الدور: `open-sse/services/roleNormalizer.ts`
الخدمات (منطق الأعمال):
- اختيار الحساب/تسجيل النقاط: `open-sse/services/accountSelector.ts`
- إدارة دورة حياة السياق: `open-sse/services/contextManager.ts`
- فرض عامل تصفية IP: `open-sse/services/ipFilter.ts`
- تتبع الجلسة: `open-sse/services/sessionManager.ts`
- طلب إلغاء البيانات المكررة: `open-sse/services/signatureCache.ts`
- الحقن الفوري للنظام: `open-sse/services/systemPrompt.ts`
- إدارة ميزانية التفكير: `open-sse/services/thinkingBudget.ts`
- توجيه نموذج حرف البدل: `open-sse/services/wildcardRouter.ts`
- إدارة حدود السعر: `open-sse/services/rateLimitManager.ts`
- قاطع الدائرة: `open-sse/services/circuitBreaker.ts`
وحدات طبقة المجال:
- توفر النموذج: `src/lib/domain/modelAvailability.ts`
- قواعد/ميزانيات التكلفة: `src/lib/domain/costRules.ts`
- السياسة الاحتياطية: `src/lib/domain/fallbackPolicy.ts`
- محلل التحرير والسرد: `src/lib/domain/comboResolver.ts`
- سياسة التأمين: `src/lib/domain/lockoutPolicy.ts`
- محرك السياسة: `src/domain/policyEngine.ts` — الإغلاق المركزي ← الميزانية ← التقييم الاحتياطي
- كتالوج رموز الأخطاء: `src/lib/domain/errorCodes.ts`
- معرف الطلب: `src/lib/domain/requestId.ts`
- مهلة الجلب: `src/lib/domain/fetchTimeout.ts`
- طلب القياس عن بعد: `src/lib/domain/requestTelemetry.ts`
- الامتثال/التدقيق: `src/lib/domain/compliance/index.ts`
- عداء التقييم: `src/lib/domain/evalRunner.ts`
- استمرارية حالة المجال: `src/lib/db/domainState.ts` — SQLite CRUD للسلاسل الاحتياطية، والميزانيات، وتاريخ التكلفة، وحالة الإغلاق، وقواطع الدائرة
وحدات موفر OAuth (12 ملفًا فرديًا ضمن `src/lib/oauth/providers/`):
- فهرس التسجيل: `src/lib/oauth/providers/index.ts`
- مقدمو الخدمات الأفراد: `claude.ts`، `codex.ts`، `gemini.ts`، `antigravity.ts`، `iflow.ts`، `qwen.ts`، `kimi-coding.ts`، `github.ts`، `kiro.ts`، `cursor.ts`، `kilocode.ts`، `cline.ts`
- الغلاف الرقيق: `src/lib/oauth/providers.ts` — إعادة التصدير من الوحدات الفردية
## 3) طبقة الثبات
قاعدة بيانات الحالة الأساسية:
- `src/lib/localDb.ts`
- الملف: `${DATA_DIR}/db.json` (أو `$XDG_CONFIG_HOME/omniroute/db.json` عند التعيين، وإلا `~/.omniroute/db.json`)
- الكيانات:providerConnections، وproviderNodes، وmodelAliases، والمجموعات، وapiKeys، والإعدادات، والتسعير، **customModels**، **proxyConfig**، **ipFilter**، **thinkingBudget**، **systemPrompt**
قاعدة بيانات الاستخدام:
- `src/lib/usageDb.ts`
- الملفات: `${DATA_DIR}/usage.json`، `${DATA_DIR}/log.txt`، `${DATA_DIR}/call_logs/`
- يتبع نفس سياسة الدليل الأساسي مثل `localDb` (`DATA_DIR`، ثم `XDG_CONFIG_HOME/omniroute` عند التعيين)
- مقسمة إلى وحدات فرعية مركزة: `migrations.ts`، `usageHistory.ts`، `costCalculator.ts`، `usageStats.ts`، `callLogs.ts`
قاعدة بيانات حالة المجال (SQLite):
- `src/lib/db/domainState.ts` — عمليات CRUD لحالة المجال
- الجداول (التي تم إنشاؤها في `src/lib/db/core.ts`): `domain_fallback_chains`، `domain_budgets`، `domain_cost_history`، `domain_lockout_state`، `domain_circuit_breakers`
- نمط ذاكرة التخزين المؤقت للكتابة: تعد الخرائط الموجودة في الذاكرة موثوقة في وقت التشغيل؛ تتم كتابة الطفرات بشكل متزامن إلى SQLite؛ تتم استعادة الحالة من قاعدة البيانات عند البداية الباردة
## 4) المصادقة + الأسطح الأمنية
- مصادقة ملف تعريف الارتباط للوحة المعلومات: `src/proxy.ts`، `src/app/api/auth/login/route.ts`
- إنشاء/التحقق من مفتاح واجهة برمجة التطبيقات: `src/shared/utils/apiKey.ts`
- استمرت أسرار الموفر في إدخالات `providerConnections`
- دعم الوكيل الصادر عبر `open-sse/utils/proxyFetch.ts` (env vars) و`open-sse/utils/networkProxy.ts` (قابل للتكوين لكل موفر أو عالمي)
## 5) المزامنة السحابية
- الحرف الأول للمجدول: `src/lib/initCloudSync.ts`، `src/shared/services/initializeCloudSync.ts`
- المهمة الدورية: `src/shared/services/cloudSyncScheduler.ts`
- مسار التحكم: `src/app/api/sync/cloud/route.ts`
## دورة حياة الطلب (`/v1/chat/completions`)
```mermaid
sequenceDiagram
autonumber
participant Client as CLI/SDK Client
participant Route as /api/v1/chat/completions
participant Chat as src/sse/handlers/chat
participant Core as open-sse/handlers/chatCore
participant Model as Model Resolver
participant Auth as Credential Selector
participant Exec as Provider Executor
participant Prov as Upstream Provider
participant Stream as Stream Translator
participant Usage as usageDb
Client->>Route: POST /v1/chat/completions
Route->>Chat: handleChat(request)
Chat->>Model: parse/resolve model or combo
alt Combo model
Chat->>Chat: iterate combo models (handleComboChat)
end
Chat->>Auth: getProviderCredentials(provider)
Auth-->>Chat: active account + tokens/api key
Chat->>Core: handleChatCore(body, modelInfo, credentials)
Core->>Core: detect source format
Core->>Core: translate request to target format
Core->>Exec: execute(provider, transformedBody)
Exec->>Prov: upstream API call
Prov-->>Exec: SSE/JSON response
Exec-->>Core: response + metadata
alt 401/403
Core->>Exec: refreshCredentials()
Exec-->>Core: updated tokens
Core->>Exec: retry request
end
Core->>Stream: translate/normalize stream to client format
Stream-->>Client: SSE chunks / JSON response
Stream->>Usage: extract usage + persist history/log
```
## التحرير والسرد + التدفق الاحتياطي للحساب
```mermaid
flowchart TD
A[Incoming model string] --> B{Is combo name?}
B -- Yes --> C[Load combo models sequence]
B -- No --> D[Single model path]
C --> E[Try model N]
E --> F[Resolve provider/model]
D --> F
F --> G[Select account credentials]
G --> H{Credentials available?}
H -- No --> I[Return provider unavailable]
H -- Yes --> J[Execute request]
J --> K{Success?}
K -- Yes --> L[Return response]
K -- No --> M{Fallback-eligible error?}
M -- No --> N[Return error]
M -- Yes --> O[Mark account unavailable cooldown]
O --> P{Another account for provider?}
P -- Yes --> G
P -- No --> Q{In combo with next model?}
Q -- Yes --> E
Q -- No --> R[Return all unavailable]
```
يتم اتخاذ القرارات الاحتياطية بواسطة `open-sse/services/accountFallback.ts` باستخدام رموز الحالة والاستدلال على رسائل الخطأ.
## دورة حياة OAuth Onboarding وتحديث الرمز المميز
```mermaid
sequenceDiagram
autonumber
participant UI as Dashboard UI
participant OAuth as /api/oauth/[provider]/[action]
participant ProvAuth as Provider Auth Server
participant DB as localDb
participant Test as /api/providers/[id]/test
participant Exec as Provider Executor
UI->>OAuth: GET authorize or device-code
OAuth->>ProvAuth: create auth/device flow
ProvAuth-->>OAuth: auth URL or device code payload
OAuth-->>UI: flow data
UI->>OAuth: POST exchange or poll
OAuth->>ProvAuth: token exchange/poll
ProvAuth-->>OAuth: access/refresh tokens
OAuth->>DB: createProviderConnection(oauth data)
OAuth-->>UI: success + connection id
UI->>Test: POST /api/providers/[id]/test
Test->>Exec: validate credentials / optional refresh
Exec-->>Test: valid or refreshed token info
Test->>DB: update status/tokens/errors
Test-->>UI: validation result
```
يتم تنفيذ التحديث أثناء حركة المرور المباشرة داخل `open-sse/handlers/chatCore.ts` عبر المنفذ `refreshCredentials()`.
## دورة حياة المزامنة السحابية (تمكين / مزامنة / تعطيل)
```mermaid
sequenceDiagram
autonumber
participant UI as Endpoint Page UI
participant Sync as /api/sync/cloud
participant DB as localDb
participant Cloud as External Cloud Sync
participant Claude as ~/.claude/settings.json
UI->>Sync: POST action=enable
Sync->>DB: set cloudEnabled=true
Sync->>DB: ensure API key exists
Sync->>Cloud: POST /sync/{machineId} (providers/aliases/combos/keys)
Cloud-->>Sync: sync result
Sync->>Cloud: GET /{machineId}/v1/verify
Sync-->>UI: enabled + verification status
UI->>Sync: POST action=sync
Sync->>Cloud: POST /sync/{machineId}
Cloud-->>Sync: remote data
Sync->>DB: update newer local tokens/status
Sync-->>UI: synced
UI->>Sync: POST action=disable
Sync->>DB: set cloudEnabled=false
Sync->>Cloud: DELETE /sync/{machineId}
Sync->>Claude: switch ANTHROPIC_BASE_URL back to local (if needed)
Sync-->>UI: disabled
```
يتم تشغيل المزامنة الدورية بواسطة `CloudSyncScheduler` عند تمكين السحابة.
## نموذج البيانات وخريطة التخزين
```mermaid
erDiagram
SETTINGS ||--o{ PROVIDER_CONNECTION : controls
PROVIDER_NODE ||--o{ PROVIDER_CONNECTION : backs_compatible_provider
PROVIDER_CONNECTION ||--o{ USAGE_ENTRY : emits_usage
SETTINGS {
boolean cloudEnabled
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
string id
string provider
string authType
string name
number priority
boolean isActive
string apiKey
string accessToken
string refreshToken
string expiresAt
string testStatus
string lastError
string rateLimitedUntil
json providerSpecificData
}
PROVIDER_NODE {
string id
string type
string name
string prefix
string apiType
string baseUrl
}
MODEL_ALIAS {
string alias
string targetModel
}
COMBO {
string id
string name
string[] models
}
API_KEY {
string id
string name
string key
string machineId
}
USAGE_ENTRY {
string provider
string model
number prompt_tokens
number completion_tokens
string connectionId
string timestamp
}
CUSTOM_MODEL {
string id
string name
string providerId
}
PROXY_CONFIG {
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
ملفات التخزين المادية:
- الحالة الرئيسية: `${DATA_DIR}/db.json` (أو `$XDG_CONFIG_HOME/omniroute/db.json` عند التعيين، وإلا `~/.omniroute/db.json`)
- إحصائيات الاستخدام: `${DATA_DIR}/usage.json`
- خطوط سجل الطلب: `${DATA_DIR}/log.txt`
- جلسات تصحيح أخطاء المترجم/الطلب الاختيارية: `<repo>/logs/...`
## طبولوجيا النشر
```mermaid
flowchart LR
subgraph LocalHost[Developer Host]
CLI[CLI Tools]
Browser[Dashboard Browser]
end
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(db.json)]
UsageDB[(usage.json/log.txt)]
end
subgraph External[External Services]
Providers[AI Providers]
SyncCloud[Cloud Sync Service]
end
CLI --> Next
Browser --> Next
Next --> Core
Next --> MainDB
Core --> MainDB
Core --> UsageDB
Core --> Providers
Next --> SyncCloud
```
## تعيين الوحدة (القرار الحاسم)
### وحدات المسار وواجهة برمجة التطبيقات
- `src/app/api/v1/*`، `src/app/api/v1beta/*`: واجهات برمجة تطبيقات التوافق
- `src/app/api/v1/providers/[provider]/*`: مسارات مخصصة لكل مزود (الدردشة والتضمين والصور)
- `src/app/api/providers*`: موفر CRUD والتحقق من الصحة والاختبار
- `src/app/api/provider-nodes*`: إدارة العقدة المتوافقة المخصصة
- `src/app/api/provider-models`: إدارة النماذج المخصصة (CRUD)
- `src/app/api/models/catalog`: واجهة برمجة تطبيقات كتالوج النموذج الكامل (جميع الأنواع مجمعة حسب الموفر)
- `src/app/api/oauth/*`: تدفقات OAuth/رمز الجهاز
- `src/app/api/keys*`: دورة حياة مفتاح واجهة برمجة التطبيقات المحلية
- `src/app/api/models/alias`: إدارة الاسم المستعار
- `src/app/api/combos*`: إدارة التحرير والسرد الاحتياطية
- `src/app/api/pricing`: تجاوزات التسعير لحساب التكلفة
- `src/app/api/settings/proxy`: تكوين الوكيل (GET/PUT/DELETE)
- `src/app/api/settings/proxy/test`: اختبار اتصال الوكيل الصادر (POST)
- `src/app/api/usage/*`: واجهات برمجة تطبيقات الاستخدام والسجلات
- `src/app/api/sync/*` + `src/app/api/cloud/*`: المزامنة السحابية والمساعدون الذين يواجهون السحابة
- `src/app/api/cli-tools/*`: كاتب/أداة فحص تكوين CLI المحلية
- `src/app/api/settings/ip-filter`: قائمة IP المسموح بها/القائمة المحظورة (GET/PUT)
- `src/app/api/settings/thinking-budget`: تكوين ميزانية الرمز المميز (GET/PUT)
- `src/app/api/settings/system-prompt`: موجه النظام العالمي (GET/PUT)
- `src/app/api/sessions`: قائمة الجلسة النشطة (GET)
- `src/app/api/rate-limits`: حالة حد السعر لكل حساب (GET)
### التوجيه والتنفيذ الأساسي
- `src/sse/handlers/chat.ts`: تحليل الطلب، ومعالجة التحرير والسرد، وحلقة اختيار الحساب
- `open-sse/handlers/chatCore.ts`: الترجمة، إرسال المنفذ، معالجة إعادة المحاولة/التحديث، إعداد الدفق
- `open-sse/executors/*`: سلوك الشبكة والتنسيق الخاص بالموفر
### سجل الترجمة ومحولات التنسيق
- `open-sse/translator/index.ts`: تسجيل المترجم وتنسيقه
- طلب المترجمين: `open-sse/translator/request/*`
- مترجمو الرد: `open-sse/translator/response/*`
- ثوابت التنسيق: `open-sse/translator/formats.ts`
### المثابرة
- `src/lib/localDb.ts`: التكوين/الحالة المستمرة
- `src/lib/usageDb.ts`: سجل الاستخدام وسجلات الطلبات المتجددة
## تغطية منفذي الخدمة (نمط الإستراتيجية)
كل مزود لديه منفذ متخصص يمتد `BaseExecutor` (في `open-sse/executors/base.ts`)، والذي يوفر بناء عنوان URL، وإنشاء الرأس، وإعادة المحاولة مع التراجع الأسي، وخطافات تحديث بيانات الاعتماد، وطريقة التنسيق `execute()`.
| المنفذ | المزود (المقدمون) | التعامل الخاص |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| `DefaultExecutor` | OpenAI، Claude، Gemini، Qwen، iFlow، OpenRouter، GLM، Kimi، MiniMax، DeepSeek، Groq، xAI، Mistral، Perplexity، Together، Fireworks، Cerebras، Cohere، NVIDIA | تكوين عنوان URL/الرأس الديناميكي لكل مزود |
| `AntigravityExecutor` | جوجل مكافحة الجاذبية | معرفات المشروع/الجلسة المخصصة، إعادة المحاولة بعد التحليل |
| `CodexExecutor` | OpenAI Codex | يحقن تعليمات النظام، ويفرض جهدًا منطقيًا |
| `CursorExecutor` | بيئة تطوير متكاملة للمؤشر | بروتوكول ConnectRPC، تشفير Protobuf، طلب التوقيع عبر المجموع الاختباري |
| `GithubExecutor` | جيثب مساعد الطيار | تحديث الرمز المميز لـ Copilot، ورؤوس محاكاة VSCode |
| `KiroExecutor` | AWS CodeWhisperer/كيرو | تنسيق AWS EventStream الثنائي → تحويل SSE |
| `GeminiCLIExecutor` | الجوزاء CLI | دورة تحديث رمز OAuth المميز لـ Google |
يستخدم جميع الموفرين الآخرين (بما في ذلك العقد المتوافقة المخصصة) `DefaultExecutor`.
## مصفوفة توافق الموفر
| مقدم | تنسيق | مصادقة | تيار | غير دفق | تحديث الرمز المميز | واجهة برمجة تطبيقات الاستخدام |
| ----------------------------------- | ---------------- | --------------------------- | --------------- | ------- | ------------------ | ----------------------------- |
| كلود | كلود | مفتاح API / OAuth | ✅ | ✅ | ✅ | ⚠️ المشرف فقط |
| الجوزاء | الجوزاء | مفتاح API / OAuth | ✅ | ✅ | ✅ | ⚠️ وحدة التحكم السحابية |
| الجوزاء CLI | الجوزاء-cli | أووث | ✅ | ✅ | ✅ | ⚠️ وحدة التحكم السحابية |
| مكافحة الجاذبية | ضد الجاذبية | أووث | ✅ | ✅ | ✅ | ✅ الحصة الكاملة API |
| أوبن آي | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| الدستور الغذائي | openai-responses | أووث | ✅ مجبور | ❌ | ✅ | ✅ حدود المعدل |
| جيثب مساعد الطيار | أوبيناي | OAuth + رمز مساعد الطيار | ✅ | ✅ | ✅ | ✅ لقطات الحصص |
| المؤشر | المؤشر | المجموع الاختباري المخصص | ✅ | ✅ | ❌ | ❌ |
| كيرو | كيرو | AWS SSO OIDC | ✅(ايفنت ستريم) | ❌ | ✅ | ✅ حدود الاستخدام |
| كوين | أوبيناي | أووث | ✅ | ✅ | ✅ | ⚠️ حسب الطلب |
| اي فلو | أوبيناي | OAuth (أساسي) | ✅ | ✅ | ✅ | ⚠️ حسب الطلب |
| اوبن راوتر | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| جي إل إم/كيمي/ميني ماكس | كلود | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| ديب سيك | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| جروك | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| xAI (جروك) | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| ميسترال | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| الحيرة | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| معا منظمة العفو الدولية | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| الألعاب النارية منظمة العفو الدولية | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| المخيخ | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| كوهير | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
| نفيديا نيم | أوبيناي | مفتاح واجهة برمجة التطبيقات | ✅ | ✅ | ❌ | ❌ |
## تنسيق تغطية الترجمة
تتضمن تنسيقات المصدر المكتشفة ما يلي:
- `openai`
- `openai-responses`
- `claude`
- `gemini`
تتضمن التنسيقات المستهدفة ما يلي:
- دردشة/ردود OpenAI
- كلود
- الجوزاء/الجوزاء-CLI/الظرف المضاد للجاذبية
- كيرو
- المؤشر
تستخدم الترجمات **OpenAI كتنسيق مركزي** — تمر جميع التحويلات عبر OpenAI كتنسيق وسيط:
```
Source Format → OpenAI (hub) → Target Format
```
يتم تحديد الترجمات ديناميكيًا استنادًا إلى شكل حمولة المصدر والتنسيق المستهدف للموفر.
طبقات معالجة إضافية في مسار الترجمة:
- **تطهير الاستجابة** — يزيل الحقول غير القياسية من استجابات تنسيق OpenAI (سواء المتدفقة أو غير المتدفقة) لضمان الامتثال الصارم لـ SDK
- **تطبيع الدور** — تحويل `developer``system` للأهداف غير التابعة لـ OpenAI؛ يدمج `system``user` للنماذج التي ترفض دور النظام (GLM، ERNIE)
- **فكر في استخراج العلامات** — يوزع كتل `<think>...</think>` من المحتوى إلى حقل `reasoning_content`
- **الإخراج المنظم** — يحول OpenAI `response_format.json_schema` إلى `responseMimeType` + `responseSchema` الخاص بـ Gemini
## نقاط نهاية واجهة برمجة التطبيقات المدعومة
| نقطة النهاية | تنسيق | معالج |
| -------------------------------------------------- | ------------------ | ------------------------------------------------------------------------- |
| `POST /v1/chat/completions` | دردشة OpenAI | `src/sse/handlers/chat.ts` |
| `POST /v1/messages` | رسائل كلود | نفس المعالج (تم اكتشافه تلقائيًا) |
| `POST /v1/responses` | ردود OpenAI | `open-sse/handlers/responsesHandler.ts` |
| `POST /v1/embeddings` | تضمينات OpenAI | `open-sse/handlers/embeddings.ts` |
| `GET /v1/embeddings` | قائمة النماذج | طريق API |
| `POST /v1/images/generations` | صور OpenAI | `open-sse/handlers/imageGeneration.ts` |
| `GET /v1/images/generations` | قائمة النماذج | طريق API |
| `POST /v1/providers/{provider}/chat/completions` | دردشة OpenAI | مخصص لكل مزود مع التحقق من صحة النموذج |
| `POST /v1/providers/{provider}/embeddings` | تضمينات OpenAI | مخصص لكل مزود مع التحقق من صحة النموذج |
| `POST /v1/providers/{provider}/images/generations` | صور OpenAI | مخصص لكل مزود مع التحقق من صحة النموذج |
| `POST /v1/messages/count_tokens` | عدد كلود توكن | طريق API |
| `GET /v1/models` | قائمة نماذج OpenAI | مسار واجهة برمجة التطبيقات (الدردشة + التضمين + الصورة + النماذج المخصصة) |
| `GET /api/models/catalog` | كتالوج | جميع النماذج مجمعة حسب الموفر + النوع |
| `POST /v1beta/models/*:streamGenerateContent` | مولود برج الجوزاء | طريق API |
| `GET/PUT/DELETE /api/settings/proxy` | تكوين الوكيل | تكوين وكيل الشبكة |
| `POST /api/settings/proxy/test` | اتصال الوكيل | نقطة نهاية اختبار صحة الوكيل/الاتصال |
| `GET/POST/DELETE /api/provider-models` | نماذج مخصصة | إدارة النماذج المخصصة لكل مزود |
## تجاوز المعالج
يعترض معالج التجاوز (`open-sse/utils/bypassHandler.ts`) طلبات "الرمي" المعروفة من Claude CLI - أصوات التمهيد، واستخراج العناوين، وعدد الرموز المميزة - ويعيد **استجابة زائفة** دون استهلاك الرموز المميزة للموفر الرئيسي. يتم تشغيل هذا فقط عندما يحتوي `User-Agent` على `claude-cli`.
## طلب خط أنابيب المسجل
يوفر مسجل الطلب (`open-sse/utils/requestLogger.ts`) مسارًا لتسجيل تصحيح الأخطاء مكون من 7 مراحل، معطل افتراضيًا، وممكن عبر `ENABLE_REQUEST_LOGS=true`:
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
→ 5_res_provider.txt → 6_res_openai.txt → 7_res_client.txt
```
تتم كتابة الملفات إلى `<repo>/logs/<session>/` لكل جلسة طلب.
## أوضاع الفشل والمرونة
## 1) توفر الحساب/المزود
- فترة تباطؤ حساب الموفر عند حدوث أخطاء عابرة/معدل/مصادقة
- احتياطي الحساب قبل فشل الطلب
- نموذج التحرير والسرد الاحتياطي عند استنفاد مسار النموذج/المزود الحالي
## 2) انتهاء صلاحية الرمز المميز
- الفحص المسبق والتحديث مع إعادة المحاولة لموفري الخدمة القابلين للتحديث
- 401/403 إعادة المحاولة بعد محاولة التحديث في المسار الأساسي
## 3) سلامة الدفق
- وحدة تحكم تيار قطع الاتصال
- دفق الترجمة مع تدفق نهاية الدفق ومعالجة `[DONE]`
- احتياطي تقدير الاستخدام عندما تكون البيانات الوصفية لاستخدام الموفر مفقودة
## 4) تدهور المزامنة السحابية
- ظهرت أخطاء المزامنة ولكن يستمر وقت التشغيل المحلي
- يحتوي المجدول على منطق قادر على إعادة المحاولة، ولكن التنفيذ الدوري يستدعي حاليًا مزامنة المحاولة الواحدة بشكل افتراضي
## 5) سلامة البيانات
- ترحيل/إصلاح شكل قاعدة البيانات للمفاتيح المفقودة
- ضمانات إعادة تعيين JSON الفاسدة لـ localDb وuseDb
## إمكانية الملاحظة والإشارات التشغيلية
مصادر رؤية وقت التشغيل:
- سجلات وحدة التحكم من `src/sse/utils/logger.ts`
- مجاميع الاستخدام لكل طلب في `usage.json`
- سجل حالة الطلب النصي في `log.txt`
- سجلات الطلب/الترجمة العميقة الاختيارية ضمن `logs/` عندما `ENABLE_REQUEST_LOGS=true`
- نقاط نهاية استخدام لوحة المعلومات (`/api/usage/*`) لاستهلاك واجهة المستخدم
## الحدود الحساسة للأمن
- سر JWT (`JWT_SECRET`) يؤمن التحقق/التوقيع على ملف تعريف الارتباط لجلسة لوحة المعلومات
- يجب تجاوز الاحتياطي الأولي لكلمة المرور (`INITIAL_PASSWORD`، الافتراضي `123456`) في عمليات النشر الحقيقية
- سر HMAC لمفتاح API (`API_KEY_SECRET`) يؤمن تنسيق مفتاح API المحلي الذي تم إنشاؤه
- تظل أسرار الموفر (مفاتيح/رموز واجهة برمجة التطبيقات) موجودة في قاعدة البيانات المحلية ويجب حمايتها على مستوى نظام الملفات
- تعتمد نقاط نهاية المزامنة السحابية على مصادقة مفتاح API + دلالات معرف الجهاز
## مصفوفة البيئة ووقت التشغيل
متغيرات البيئة المستخدمة بشكل نشط بواسطة التعليمات البرمجية:
- التطبيق/المصادقة: `JWT_SECRET`، `INITIAL_PASSWORD`
- التخزين: `DATA_DIR`
- سلوك العقدة المتوافقة: `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE`
- تجاوز قاعدة التخزين الاختيارية (Linux/macOS عند إلغاء تعيين `DATA_DIR`): `XDG_CONFIG_HOME`
- التجزئة الأمنية: `API_KEY_SECRET`، `MACHINE_ID_SALT`
- التسجيل: `ENABLE_REQUEST_LOGS`
- عنوان URL للمزامنة/السحابة: `NEXT_PUBLIC_BASE_URL`، `NEXT_PUBLIC_CLOUD_URL`
- الوكيل الصادر: `HTTP_PROXY`، `HTTPS_PROXY`، `ALL_PROXY`، `NO_PROXY` ومتغيرات الأحرف الصغيرة
- علامات ميزات SOCKS5: `ENABLE_SOCKS5_PROXY`، `NEXT_PUBLIC_ENABLE_SOCKS5_PROXY`
- مساعدو النظام الأساسي/وقت التشغيل (ليس التكوين الخاص بالتطبيق): `APPDATA`، `NODE_ENV`، `PORT`، `HOSTNAME`
## الملاحظات المعمارية المعروفة
1. يتشارك `usageDb` و`localDb` الآن نفس سياسة الدليل الأساسي (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) مع ترحيل الملفات القديمة.
2. يقوم `/api/v1/route.ts` بإرجاع قائمة نماذج ثابتة وهو ليس مصدر النماذج الرئيسي الذي يستخدمه `/v1/models`.
3. يقوم مسجل الطلب بكتابة الرؤوس/النص الكامل عند تمكينه؛ التعامل مع دليل السجل على أنه حساس.
4. يعتمد سلوك السحابة على `NEXT_PUBLIC_BASE_URL` الصحيح وإمكانية الوصول إلى نقطة نهاية السحابة.
5. تم نشر الدليل `open-sse/` باسم `@omniroute/open-sse` **حزمة مساحة عمل npm**. يقوم كود المصدر باستيراده عبر `@omniroute/open-sse/...` (تم حله بواسطة Next.js `transpilePackages`). لا تزال مسارات الملفات في هذا المستند تستخدم اسم الدليل `open-sse/` لتحقيق الاتساق.
6. تستخدم المخططات الموجودة في لوحة المعلومات **Recharts** (المستندة إلى SVG) لتصورات التحليلات التفاعلية التي يمكن الوصول إليها (المخططات الشريطية لاستخدام النموذج، والجداول التفصيلية للموفرين مع معدلات النجاح).
7. تستخدم اختبارات E2E **Playwright** (`tests/e2e/`)، ويتم تشغيلها عبر `npm run test:e2e`. تستخدم اختبارات الوحدة **مشغل اختبار Node.js** (`tests/unit/`)، ويتم تشغيله عبر `npm run test:plan3`. كود المصدر ضمن `src/` هو **TypeScript** (`.ts`/`.tsx`)؛ تظل مساحة العمل `open-sse/` JavaScript (`.js`).
8. تم تنظيم صفحة الإعدادات في 5 علامات تبويب: الأمان، التوجيه (6 إستراتيجيات عالمية: التعبئة أولاً، جولة روبن، p2c، عشوائي، الأقل استخدامًا، تحسين التكلفة)، المرونة (حدود المعدل القابلة للتحرير، قاطع الدائرة، السياسات)، الذكاء الاصطناعي (ميزانية التفكير، موجه النظام، ذاكرة التخزين المؤقت السريعة)، المتقدم (الوكيل).
## قائمة التحقق التشغيلية
- البناء من المصدر: `npm run build`
- إنشاء صورة Docker: `docker build -t omniroute .`
- ابدأ الخدمة وتحقق:
- `GET /api/settings`
- `GET /api/v1/models`
- يجب أن يكون عنوان URL الأساسي لهدف واجهة سطر الأوامر هو `http://<host>:20128/v1` عندما يكون `PORT=20128`
-589
View File
@@ -1,589 +0,0 @@
# الطريق الشامل - وثائق قاعدة التعليمات البرمجية
🌐 **Languages:** 🇺🇸 [English](../../CODEBASE_DOCUMENTATION.md) | 🇧🇷 [Português (Brasil)](../pt-BR/CODEBASE_DOCUMENTATION.md) | 🇪🇸 [Español](../es/CODEBASE_DOCUMENTATION.md) | 🇫🇷 [Français](../fr/CODEBASE_DOCUMENTATION.md) | 🇮🇹 [Italiano](../it/CODEBASE_DOCUMENTATION.md) | 🇷🇺 [Русский](../ru/CODEBASE_DOCUMENTATION.md) | 🇨🇳 [中文 (简体)](../zh-CN/CODEBASE_DOCUMENTATION.md) | 🇩🇪 [Deutsch](../de/CODEBASE_DOCUMENTATION.md) | 🇮🇳 [हिन्दी](../in/CODEBASE_DOCUMENTATION.md) | 🇹🇭 [ไทย](../th/CODEBASE_DOCUMENTATION.md) | 🇺🇦 [Українська](../uk-UA/CODEBASE_DOCUMENTATION.md) | 🇸🇦 [العربية](../ar/CODEBASE_DOCUMENTATION.md) | 🇯🇵 [日本語](../ja/CODEBASE_DOCUMENTATION.md) | 🇻🇳 [Tiếng Việt](../vi/CODEBASE_DOCUMENTATION.md) | 🇧🇬 [Български](../bg/CODEBASE_DOCUMENTATION.md) | 🇩🇰 [Dansk](../da/CODEBASE_DOCUMENTATION.md) | 🇫🇮 [Suomi](../fi/CODEBASE_DOCUMENTATION.md) | 🇮🇱 [עברית](../he/CODEBASE_DOCUMENTATION.md) | 🇭🇺 [Magyar](../hu/CODEBASE_DOCUMENTATION.md) | 🇮🇩 [Bahasa Indonesia](../id/CODEBASE_DOCUMENTATION.md) | 🇰🇷 [한국어](../ko/CODEBASE_DOCUMENTATION.md) | 🇲🇾 [Bahasa Melayu](../ms/CODEBASE_DOCUMENTATION.md) | 🇳🇱 [Nederlands](../nl/CODEBASE_DOCUMENTATION.md) | 🇳🇴 [Norsk](../no/CODEBASE_DOCUMENTATION.md) | 🇵🇹 [Português (Portugal)](../pt/CODEBASE_DOCUMENTATION.md) | 🇷🇴 [Română](../ro/CODEBASE_DOCUMENTATION.md) | 🇵🇱 [Polski](../pl/CODEBASE_DOCUMENTATION.md) | 🇸🇰 [Slovenčina](../sk/CODEBASE_DOCUMENTATION.md) | 🇸🇪 [Svenska](../sv/CODEBASE_DOCUMENTATION.md) | 🇵🇭 [Filipino](../phi/CODEBASE_DOCUMENTATION.md)
> دليل شامل ومناسب للمبتدئين إلى جهاز التوجيه الوكيل AI **omniroute** متعدد الموفرين.
---
## 1. ما هو الطريق الشامل؟
omniroute هو **جهاز توجيه وكيل** يقع بين عملاء الذكاء الاصطناعي (Claude CLI، وCodex، وCursor IDE، وما إلى ذلك) وموفري الذكاء الاصطناعي (Anthropic، وGoogle، وOpenAI، وAWS، وGitHub، وما إلى ذلك). إنه يحل مشكلة واحدة كبيرة:
> **يتحدث عملاء الذكاء الاصطناعي المختلفون "لغات" مختلفة (تنسيقات واجهة برمجة التطبيقات)، ويتوقع مقدمو خدمات الذكاء الاصطناعي المختلفون "لغات" مختلفة أيضًا. ** يترجم المسار الشامل بينهم تلقائيًا.
فكر في الأمر وكأنه مترجم عالمي في الأمم المتحدة - يمكن لأي مندوب التحدث بأي لغة، ويقوم المترجم بتحويلها لأي مندوب آخر.
---
## 2. نظرة عامة على الهندسة المعمارية
```mermaid
graph LR
subgraph Clients
A[Claude CLI]
B[Codex]
C[Cursor IDE]
D[OpenAI-compatible]
end
subgraph omniroute
E[Handler Layer]
F[Translator Layer]
G[Executor Layer]
H[Services Layer]
end
subgraph Providers
I[Anthropic Claude]
J[Google Gemini]
K[OpenAI / Codex]
L[GitHub Copilot]
M[AWS Kiro]
N[Antigravity]
O[Cursor API]
end
A --> E
B --> E
C --> E
D --> E
E --> F
F --> G
G --> I
G --> J
G --> K
G --> L
G --> M
G --> N
G --> O
H -.-> E
H -.-> G
```
### المبدأ الأساسي: الترجمة المحورية
تمر جميع ترجمة التنسيقات عبر **تنسيق OpenAI كمركز**:
```
Client Format → [OpenAI Hub] → Provider Format (request)
Provider Format → [OpenAI Hub] → Client Format (response)
```
هذا يعني أنك تحتاج فقط إلى مترجمين **N** (واحد لكل تنسيق) بدلاً من **N²** (كل زوج).
---
## 3. هيكل المشروع
```
omniroute/
├── open-sse/ ← Core proxy library (portable, framework-agnostic)
│ ├── index.js ← Main entry point, exports everything
│ ├── config/ ← Configuration & constants
│ ├── executors/ ← Provider-specific request execution
│ ├── handlers/ ← Request handling orchestration
│ ├── services/ ← Business logic (auth, models, fallback, usage)
│ ├── translator/ ← Format translation engine
│ │ ├── request/ ← Request translators (8 files)
│ │ ├── response/ ← Response translators (7 files)
│ │ └── helpers/ ← Shared translation utilities (6 files)
│ └── utils/ ← Utility functions
├── src/ ← Application layer (Express/Worker runtime)
│ ├── app/ ← Web UI, API routes, middleware
│ ├── lib/ ← Database, auth, and shared library code
│ ├── mitm/ ← Man-in-the-middle proxy utilities
│ ├── models/ ← Database models
│ ├── shared/ ← Shared utilities (wrappers around open-sse)
│ ├── sse/ ← SSE endpoint handlers
│ └── store/ ← State management
├── data/ ← Runtime data (credentials, logs)
│ └── provider-credentials.json (external credentials override, gitignored)
└── tester/ ← Test utilities
```
---
## 4. تفصيل الوحدة تلو الأخرى
### 4.1 التكوين (`open-sse/config/`)
**المصدر الوحيد للحقيقة** لجميع إعدادات الموفر.
| ملف | الغرض |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `constants.ts` | كائن `PROVIDERS` يحتوي على عناوين URL الأساسية وبيانات اعتماد OAuth (الافتراضية) والرؤوس ومطالبات النظام الافتراضية لكل موفر. يحدد أيضًا `HTTP_STATUS`، و`ERROR_TYPES`، و`COOLDOWN_MS`، و`BACKOFF_CONFIG`، و`SKIP_PATTERNS`. |
| `credentialLoader.ts` | يقوم بتحميل بيانات الاعتماد الخارجية من `data/provider-credentials.json` ويدمجها في الإعدادات الافتراضية المشفرة في `PROVIDERS`. يحافظ على الأسرار خارج نطاق التحكم بالمصدر مع الحفاظ على التوافق مع الإصدارات السابقة. |
| `providerModels.ts` | سجل النموذج المركزي: الأسماء المستعارة لموفر الخرائط → معرفات النموذج. وظائف مثل `getModels()`، `getProviderByAlias()`. |
| `codexInstructions.ts` | تعليمات النظام التي تم إدخالها في طلبات الدستور الغذائي (قيود التحرير، قواعد الاختبار، سياسات الموافقة). |
| `defaultThinkingSignature.ts` | توقيعات "التفكير" الافتراضية لنماذج كلود وجيميني. |
| `ollamaModels.ts` | تعريف المخطط لنماذج أولاما المحلية (الاسم، الحجم، العائلة، التكميم). |
#### تدفق تحميل بيانات الاعتماد
```mermaid
flowchart TD
A["App starts"] --> B["constants.ts defines PROVIDERS\nwith hardcoded defaults"]
B --> C{"data/provider-credentials.json\nexists?"}
C -->|Yes| D["credentialLoader reads JSON"]
C -->|No| E["Use hardcoded defaults"]
D --> F{"For each provider in JSON"}
F --> G{"Provider exists\nin PROVIDERS?"}
G -->|No| H["Log warning, skip"]
G -->|Yes| I{"Value is object?"}
I -->|No| J["Log warning, skip"]
I -->|Yes| K["Merge clientId, clientSecret,\ntokenUrl, authUrl, refreshUrl"]
K --> F
H --> F
J --> F
F -->|Done| L["PROVIDERS ready with\nmerged credentials"]
E --> L
```
---
### 4.2 المنفذون (`open-sse/executors/`)
يقوم المنفذون بتغليف **المنطق الخاص بالمزود** باستخدام **نمط الإستراتيجية**. يتجاوز كل منفذ الأساليب الأساسية حسب الحاجة.
```mermaid
classDiagram
class BaseExecutor {
+buildUrl(model, stream, options)
+buildHeaders(credentials, stream, body)
+transformRequest(body, model, stream, credentials)
+execute(url, options)
+shouldRetry(status, error)
+refreshCredentials(credentials, log)
}
class DefaultExecutor {
+refreshCredentials()
}
class AntigravityExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+shouldRetry()
+refreshCredentials()
}
class CursorExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseResponse()
+generateChecksum()
}
class KiroExecutor {
+buildUrl()
+buildHeaders()
+transformRequest()
+parseEventStream()
+refreshCredentials()
}
BaseExecutor <|-- DefaultExecutor
BaseExecutor <|-- AntigravityExecutor
BaseExecutor <|-- CursorExecutor
BaseExecutor <|-- KiroExecutor
BaseExecutor <|-- CodexExecutor
BaseExecutor <|-- GeminiCLIExecutor
BaseExecutor <|-- GithubExecutor
```
| المنفذ | مقدم | التخصصات الرئيسية |
| ---------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `base.ts` | — | قاعدة الملخصات: إنشاء عنوان URL، والرؤوس، ومنطق إعادة المحاولة، وتحديث بيانات الاعتماد |
| `default.ts` | كلود، جيميني، أوبن آي آي، جي إل إم، كيمي، ميني ماكس | تحديث رمز OAuth العام للموفرين القياسيين |
| `antigravity.ts` | جوجل كلاود كود | إنشاء معرف المشروع/الجلسة، وإرجاع عناوين URL المتعددة، وإعادة محاولة التحليل المخصصة من رسائل الخطأ ("إعادة التعيين بعد 2 ساعة و7 دقائق و23 ثانية") |
| `cursor.ts` | بيئة تطوير متكاملة للمؤشر | **الأكثر تعقيدًا**: مصادقة المجموع الاختباري SHA-256، وترميز طلب Protobuf، وEventStream الثنائي → تحليل استجابة SSE |
| `codex.ts` | OpenAI Codex | إدخال تعليمات النظام، وإدارة مستويات التفكير، وإزالة المعلمات غير المدعومة |
| `gemini-cli.ts` | جوجل الجوزاء CLI | بناء عنوان URL المخصص (`streamGenerateContent`)، تحديث رمز OAuth المميز لـ Google |
| `github.ts` | جيثب مساعد الطيار | نظام الرمز المزدوج (GitHub OAuth + Copilot token)، محاكاة رأس VSCode |
| `kiro.ts` | AWS CodeWhisperer | التحليل الثنائي لـ AWS EventStream، وإطارات أحداث AMZN، وتقدير الرمز المميز |
| `index.ts` | — | المصنع: اسم موفر الخرائط ← فئة المنفذ، مع خيار احتياطي افتراضي |
---
### 4.3 المعالجات (`open-sse/handlers/`)
**طبقة التنسيق** — تتولى تنسيق الترجمة والتنفيذ والتدفق ومعالجة الأخطاء.
| ملف | الغرض |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chatCore.ts` | ** المنسق المركزي ** (~ 600 سطر). يتعامل مع دورة حياة الطلب الكاملة: اكتشاف التنسيق ← الترجمة ← إرسال المنفذ ← استجابة التدفق/غير المتدفق ← تحديث الرمز المميز ← معالجة الأخطاء ← تسجيل الاستخدام. |
| `responsesHandler.ts` | محول واجهة برمجة تطبيقات استجابات OpenAI: يحول تنسيق الردود ← إكمالات الدردشة ← يرسل إلى `chatCore` ← يحول SSE مرة أخرى إلى تنسيق الردود. |
| `embeddings.ts` | معالج إنشاء التضمين: يحل نموذج التضمين → الموفر، ويرسل إلى واجهة برمجة تطبيقات الموفر، ويعيد استجابة التضمين المتوافقة مع OpenAI. يدعم 6+ مقدمي الخدمات. |
| `imageGeneration.ts` | معالج إنشاء الصور: يحل نموذج الصورة → الموفر، ويدعم الأوضاع المتوافقة مع OpenAI، وGemini-image (Antigravity)، والوضع الاحتياطي (Nebius). إرجاع صور base64 أو URL. |
#### دورة حياة الطلب (chatCore.ts)
```mermaid
sequenceDiagram
participant Client
participant chatCore
participant Translator
participant Executor
participant Provider
Client->>chatCore: Request (any format)
chatCore->>chatCore: Detect source format
chatCore->>chatCore: Check bypass patterns
chatCore->>chatCore: Resolve model & provider
chatCore->>Translator: Translate request (source → OpenAI → target)
chatCore->>Executor: Get executor for provider
Executor->>Executor: Build URL, headers, transform request
Executor->>Executor: Refresh credentials if needed
Executor->>Provider: HTTP fetch (streaming or non-streaming)
alt Streaming
Provider-->>chatCore: SSE stream
chatCore->>chatCore: Pipe through SSE transform stream
Note over chatCore: Transform stream translates<br/>each chunk: target → OpenAI → source
chatCore-->>Client: Translated SSE stream
else Non-streaming
Provider-->>chatCore: JSON response
chatCore->>Translator: Translate response
chatCore-->>Client: Translated JSON
end
alt Error (401, 429, 500...)
chatCore->>Executor: Retry with credential refresh
chatCore->>chatCore: Account fallback logic
end
```
---
### 4.4 الخدمات (`open-sse/services/`)
منطق الأعمال الذي يدعم المعالجات والمنفذين.
| ملف | الغرض |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider.ts` | **كشف التنسيق** (`detectFormat`): تحليلات بنية الجسم لتحديد تنسيقات Claude/OpenAI/Gemini/Antigravity/Responses (تتضمن `max_tokens` الاستدلال لكلود). أيضًا: بناء عنوان URL، وبناء الرأس، وتطبيع تكوين التفكير. يدعم موفري الخدمات الديناميكيين `openai-compatible-*` و`anthropic-compatible-*`. |
| `model.ts` | تحليل سلسلة النموذج (`claude/model-name``{provider: "claude", model: "model-name"}`)، ودقة الاسم المستعار مع اكتشاف التصادم، وتعقيم الإدخال (يرفض أحرف اجتياز المسار/التحكم)، ودقة معلومات النموذج مع دعم getter للاسم المستعار غير المتزامن. |
| `accountFallback.ts` | التعامل مع الحد الأقصى للمعدل: التراجع الأسي (1s → 2s → 4s → 2min كحد أقصى)، وإدارة فترة تهدئة الحساب، وتصنيف الأخطاء (أي الأخطاء تؤدي إلى التراجع مقابل عدم حدوثه). |
| `tokenRefresh.ts` | تحديث رمز OAuth المميز **لكل مزود**: Google (Gemini، Antigravity)، Claude، Codex، Qwen، iFlow، GitHub (OAuth + Copilot Dual-Token)، Kiro (AWS SSO OIDC + Social Auth). يتضمن ذاكرة تخزين مؤقت لإلغاء البيانات المكررة أثناء الرحلة وإعادة المحاولة مع التراجع المتسارع. |
| `combo.ts` | **نماذج مجمعة**: سلاسل من النماذج الاحتياطية. إذا فشل النموذج A مع وجود خطأ مؤهل للرجوع إليه، فجرّب النموذج B، ثم C، وما إلى ذلك. يقوم بإرجاع رموز الحالة الأولية الفعلية. |
| `usage.ts` | جلب بيانات الحصص/الاستخدام من واجهات برمجة تطبيقات الموفر (حصص GitHub Copilot، وحصص نماذج Antigravity، وحدود معدل Codex، وأعطال استخدام Kiro، وإعدادات Claude). |
| `accountSelector.ts` | اختيار الحساب الذكي باستخدام خوارزمية التسجيل: يأخذ في الاعتبار الأولوية والحالة الصحية والموضع الدائري وحالة التهدئة لاختيار الحساب الأمثل لكل طلب. |
| `contextManager.ts` | إدارة دورة حياة سياق الطلب: إنشاء وتتبع كائنات السياق لكل طلب باستخدام بيانات التعريف (معرف الطلب، والطوابع الزمنية، ومعلومات الموفر) لتصحيح الأخطاء والتسجيل. |
| `ipFilter.ts` | التحكم في الوصول المستند إلى IP: يدعم وضعي القائمة المسموح بها والقائمة المحظورة. التحقق من صحة عنوان IP للعميل مقابل القواعد التي تم تكوينها قبل معالجة طلبات واجهة برمجة التطبيقات. |
| `sessionManager.ts` | تتبع الجلسة باستخدام بصمة العميل: يتتبع الجلسات النشطة باستخدام معرفات العميل المجزأة، ويراقب عدد الطلبات، ويوفر مقاييس الجلسة. |
| `signatureCache.ts` | طلب ذاكرة التخزين المؤقت لإلغاء البيانات المكررة المستندة إلى التوقيع: يمنع الطلبات المكررة عن طريق تخزين توقيعات الطلب الأخيرة مؤقتًا وإرجاع الاستجابات المخزنة مؤقتًا للطلبات المتطابقة خلال نافذة زمنية. |
| `systemPrompt.ts` | الحقن الفوري للنظام العالمي: يُلحق أو يُلحق موجه نظام قابل للتكوين لجميع الطلبات، مع معالجة التوافق لكل مزود. |
| `thinkingBudget.ts` | إدارة ميزانية الرموز المميزة: تدعم أوضاع المرور، والتلقائي (تكوين التفكير الشريطي)، والمخصص (الميزانية الثابتة)، والتكيفية (مدرجة التعقيد) للتحكم في رموز التفكير/الاستدلال. |
| `wildcardRouter.ts` | توجيه نمط نموذج حرف البدل: يحل أنماط حرف البدل (على سبيل المثال، `*/claude-*`) لأزواج الموفر/النموذج الملموسة بناءً على التوفر والأولوية. |
#### إلغاء البيانات المكررة لتحديث الرمز المميز
```mermaid
sequenceDiagram
participant R1 as Request 1
participant R2 as Request 2
participant Cache as refreshPromiseCache
participant OAuth as OAuth Provider
R1->>Cache: getAccessToken("gemini", token)
Cache->>Cache: No in-flight promise
Cache->>OAuth: Start refresh
R2->>Cache: getAccessToken("gemini", token)
Cache->>Cache: Found in-flight promise
Cache-->>R2: Return existing promise
OAuth-->>Cache: New access token
Cache-->>R1: New access token
Cache-->>R2: Same access token (shared)
Cache->>Cache: Delete cache entry
```
#### آلة الحالة الاحتياطية للحساب
```mermaid
stateDiagram-v2
[*] --> Active
Active --> Error: Request fails (401/429/500)
Error --> Cooldown: Apply backoff
Cooldown --> Active: Cooldown expires
Active --> Active: Request succeeds (reset backoff)
state Error {
[*] --> ClassifyError
ClassifyError --> ShouldFallback: Rate limit / Auth / Transient
ClassifyError --> NoFallback: 400 Bad Request
}
state Cooldown {
[*] --> ExponentialBackoff
ExponentialBackoff: Level 0 = 1s
ExponentialBackoff: Level 1 = 2s
ExponentialBackoff: Level 2 = 4s
ExponentialBackoff: Max = 2min
}
```
#### سلسلة نماذج كومبو
```mermaid
flowchart LR
A["Request with\ncombo model"] --> B["Model A"]
B -->|"2xx Success"| C["Return response"]
B -->|"429/401/500"| D{"Fallback\neligible?"}
D -->|Yes| E["Model B"]
D -->|No| F["Return error"]
E -->|"2xx Success"| C
E -->|"429/401/500"| G{"Fallback\neligible?"}
G -->|Yes| H["Model C"]
G -->|No| F
H -->|"2xx Success"| C
H -->|"Fail"| I["All failed →\nReturn last status"]
```
---
### مترجم 4.5 (`open-sse/translator/`)
**محرك ترجمة التنسيق** باستخدام نظام إضافي للتسجيل الذاتي.
####الهندسة المعمارية
```mermaid
graph TD
subgraph "Request Translation"
A["Claude → OpenAI"]
B["Gemini → OpenAI"]
C["Antigravity → OpenAI"]
D["OpenAI Responses → OpenAI"]
E["OpenAI → Claude"]
F["OpenAI → Gemini"]
G["OpenAI → Kiro"]
H["OpenAI → Cursor"]
end
subgraph "Response Translation"
I["Claude → OpenAI"]
J["Gemini → OpenAI"]
K["Kiro → OpenAI"]
L["Cursor → OpenAI"]
M["OpenAI → Claude"]
N["OpenAI → Antigravity"]
O["OpenAI → Responses"]
end
```
| الدليل | ملفات | الوصف |
| ------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `request/` | 8 مترجمين | تحويل أجسام الطلب بين الصيغ. يتم تسجيل كل ملف ذاتيًا عبر `register(from, to, fn)` عند الاستيراد. |
| `response/` | 7 مترجمين | تحويل قطع الاستجابة المتدفقة بين الصيغ. يتعامل مع أنواع أحداث SSE وكتل التفكير واستدعاءات الأدوات. |
| `helpers/` | 6 مساعدين | الأدوات المساعدة المشتركة: `claudeHelper` (استخراج موجه النظام، تكوين التفكير)، `geminiHelper` (تعيين الأجزاء/المحتويات)، `openaiHelper` (تصفية التنسيق)، `toolCallHelper` (إنشاء المعرف، حقن الاستجابة المفقودة)، `maxTokensHelper`، `responsesApiHelper`. |
| `index.ts` | — | محرك الترجمة: `translateRequest()`، `translateResponse()`، إدارة الحالة، التسجيل. |
| `formats.ts` | — | ثوابت التنسيق: `OPENAI`، `CLAUDE`، `GEMINI`، `ANTIGRAVITY`، `KIRO`، `CURSOR`، `OPENAI_RESPONSES`. |
#### التصميم الرئيسي: المكونات الإضافية للتسجيل الذاتي
```javascript
// Each translator file calls register() on import:
import { register } from "../index.js";
register("claude", "openai", translateClaudeToOpenAI);
// The index.js imports all translator files, triggering registration:
import "./request/claude-to-openai.js"; // ← self-registers
```
---
### 4.6 الأدوات المساعدة (`open-sse/utils/`)
| ملف | الغرض |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `error.ts` | إنشاء استجابة للأخطاء (تنسيق متوافق مع OpenAI)، وتحليل الأخطاء الأولية، واستخراج وقت إعادة محاولة Antigravity من رسائل الخطأ، وتدفق أخطاء SSE. |
| `stream.ts` | **SSE Transform Stream** — خط أنابيب البث الأساسي. وضعان: `TRANSLATE` (ترجمة التنسيق الكامل) و`PASSTHROUGH` (تطبيع + استخراج الاستخدام). يتعامل مع التخزين المؤقت للقطعة وتقدير الاستخدام وتتبع طول المحتوى. تتجنب مثيلات وحدة التشفير/وحدة فك التشفير لكل تيار الحالة المشتركة. |
| `streamHelpers.ts` | أدوات SSE ذات المستوى المنخفض: `parseSSELine` (تتحمل المسافات البيضاء)، `hasValuableContent` (تصفية الأجزاء الفارغة لـ OpenAI/Claude/Gemini)، `fixInvalidId`، `formatSSE` (تسلسل SSE مدرك للتنسيق مع تنظيف `perf_metrics`). |
| `usageTracking.ts` | استخراج استخدام الرمز المميز من أي تنسيق (Claude/OpenAI/Gemini/Responses)، والتقدير باستخدام نسب الأحرف لكل رمز مميز للأداة/الرسالة، وإضافة المخزن المؤقت (هامش أمان 2000 رمز مميز)، وتصفية الحقول الخاصة بالتنسيق، وتسجيل وحدة التحكم بألوان ANSI. |
| `requestLogger.ts` | تسجيل الطلب المستند إلى الملف (الاشتراك عبر `ENABLE_REQUEST_LOGS=true`). ينشئ مجلدات الجلسة بملفات مرقمة: `1_req_client.json``7_res_client.txt`. كل عمليات الإدخال/الإخراج غير متزامنة (أطلق النار وانسى). أقنعة الرؤوس الحساسة. |
| `bypassHandler.ts` | يعترض أنماطًا محددة من Claude CLI (استخراج العنوان، والتحمية، والعد) ويعيد استجابات مزيفة دون الاتصال بأي مزود. يدعم كلا من الدفق وغير الدفق. يقتصر عمدا على نطاق كلود CLI. |
| `networkProxy.ts` | يحل عنوان URL للوكيل الصادر لموفر معين مع الأسبقية: التكوين الخاص بالموفر → التكوين العام → متغيرات البيئة (`HTTPS_PROXY`/`HTTP_PROXY`/`ALL_PROXY`). يدعم استثناءات `NO_PROXY`. تكوين ذاكرة التخزين المؤقت لمدة 30 ثانية. |
#### خط أنابيب تدفق SSE
```mermaid
flowchart TD
A["Provider SSE stream"] --> B["TextDecoder\n(per-stream instance)"]
B --> C["Buffer lines\n(split on newline)"]
C --> D["parseSSELine()\n(trim whitespace, parse JSON)"]
D --> E{"Mode?"}
E -->|TRANSLATE| F["translateResponse()\ntarget → OpenAI → source"]
E -->|PASSTHROUGH| G["fixInvalidId()\nnormalize chunk"]
F --> H["hasValuableContent()\nfilter empty chunks"]
G --> H
H -->|"Has content"| I["extractUsage()\ntrack token counts"]
H -->|"Empty"| J["Skip chunk"]
I --> K["formatSSE()\nserialize + clean perf_metrics"]
K --> L["TextEncoder\n(per-stream instance)"]
L --> M["Enqueue to\nclient stream"]
style A fill:#f9f,stroke:#333
style M fill:#9f9,stroke:#333
```
#### بنية جلسة مسجل الطلب
```
logs/
└── claude_gemini_claude-sonnet_20260208_143045/
├── 1_req_client.json ← Raw client request
├── 2_req_source.json ← After initial conversion
├── 3_req_openai.json ← OpenAI intermediate format
├── 4_req_target.json ← Final target format
├── 5_res_provider.txt ← Provider SSE chunks (streaming)
├── 5_res_provider.json ← Provider response (non-streaming)
├── 6_res_openai.txt ← OpenAI intermediate chunks
├── 7_res_client.txt ← Client-facing SSE chunks
└── 6_error.json ← Error details (if any)
```
---
### 4.7 طبقة التطبيق (`src/`)
| الدليل | الغرض |
| ------------- | ------------------------------------------------------------------------------------------------------- |
| `src/app/` | واجهة مستخدم الويب، مسارات واجهة برمجة التطبيقات (API)، البرامج الوسيطة السريعة، معالجات رد اتصال OAuth |
| `src/lib/` | الوصول إلى قاعدة البيانات (`localDb.ts`، `usageDb.ts`)، المصادقة، مشتركة |
| `src/mitm/` | أدوات مساعدة للوكيل الوسيط لاعتراض حركة مرور الموفر |
| `src/models/` | تعريفات نماذج قواعد البيانات |
| `src/shared/` | أغلفة حول وظائف open-sse (المزود، الدفق، الخطأ، إلخ) |
| `src/sse/` | معالجات نقطة نهاية SSE التي تربط مكتبة open-sse بمسارات Express |
| `src/store/` | إدارة حالة التطبيق |
#### مسارات API البارزة
| الطريق | طرق | الغرض |
| --------------------------------------------- | ------------------ | ------------------------------------------------------------------------------ |
| `/api/provider-models` | الحصول على/نشر/حذف | CRUD للنماذج المخصصة لكل مزود |
| `/api/models/catalog` | احصل على | كتالوج مجمع لجميع النماذج (الدردشة، التضمين، الصورة، المخصصة) مجمعة حسب الموفر |
| `/api/settings/proxy` | الحصول على/وضع/حذف | تكوين الوكيل الصادر الهرمي (`global/providers/combos/keys`) |
| `/api/settings/proxy/test` | مشاركة | التحقق من صحة اتصال الوكيل وإرجاع IP/زمن الوصول العام |
| `/v1/providers/[provider]/chat/completions` | مشاركة | عمليات إكمال الدردشة المخصصة لكل مزود مع التحقق من صحة النموذج |
| `/v1/providers/[provider]/embeddings` | مشاركة | عمليات التضمين المخصصة لكل مزود مع التحقق من صحة النموذج |
| `/v1/providers/[provider]/images/generations` | مشاركة | إنشاء صور مخصصة لكل مزود مع التحقق من صحة النموذج |
| `/api/settings/ip-filter` | الحصول على/وضع | قائمة IP المسموح بها/إدارة القائمة المحظورة |
| `/api/settings/thinking-budget` | الحصول على/وضع | تكوين ميزانية الرمز المميز (العبور/التلقائي/المخصص/التكيفي) |
| `/api/settings/system-prompt` | الحصول على/وضع | الحقن الفوري للنظام العالمي لجميع الطلبات |
| `/api/sessions` | احصل على | تتبع الجلسة النشطة ومقاييسها |
| `/api/rate-limits` | احصل على | حالة حد المعدل لكل حساب |
---
## 5. أنماط التصميم الرئيسية
### 5.1 الترجمة المحورية والمتحدثة
تتم ترجمة جميع التنسيقات من خلال **تنسيق OpenAI كمحور**. لا تتطلب إضافة موفر جديد سوى كتابة **زوج واحد** من المترجمين (من/إلى OpenAI)، وليس عدد N من المترجمين.
### 5.2 نمط استراتيجية المنفذ
كل مزود لديه فئة منفذة مخصصة ترث من `BaseExecutor`. يقوم المصنع في `executors/index.ts` باختيار المصنع المناسب في وقت التشغيل.
### 5.3 نظام البرنامج المساعد للتسجيل الذاتي
تسجل وحدات المترجم نفسها عند الاستيراد عبر `register()`. إن إضافة مترجم جديد يعني مجرد إنشاء ملف واستيراده.
### 5.4 التراجع في الحساب مع التراجع الأسي
عندما يقوم مقدم الخدمة بإرجاع 429/401/500، يمكن للنظام التبديل إلى الحساب التالي، مع تطبيق فترات التباطؤ الأسية (1ث → 2ث → 4ث → 2 دقيقة كحد أقصى).
### 5.5 سلاسل نماذج كومبو
يقوم "التحرير والسرد" بتجميع سلاسل `provider/model` متعددة. إذا فشل الأول، يتم الرجوع إلى التالي تلقائيًا.
### 5.6 ترجمة متدفقة رائعة
تحافظ ترجمة الاستجابة على الحالة عبر أجزاء SSE (تتبع كتلة التفكير، وتراكم استدعاءات الأداة، وفهرسة كتلة المحتوى) عبر آلية `initState()`.
### 5.7 المخزن المؤقت لسلامة الاستخدام
تتم إضافة مخزن مؤقت مكون من 2000 رمز مميز إلى الاستخدام المبلغ عنه لمنع العملاء من الوصول إلى حدود نافذة السياق بسبب الحمل الزائد من مطالبات النظام وترجمة التنسيق.
---
## 6. التنسيقات المدعومة
| تنسيق | الاتجاه | المعرف |
| ----------------------------------- | -------------- | ------------------ |
| استكمالات الدردشة OpenAI | المصدر + الهدف | `openai` |
| واجهة برمجة تطبيقات استجابات OpenAI | المصدر + الهدف | `openai-responses` |
| أنثروبي كلود | المصدر + الهدف | `claude` |
| جوجل الجوزاء | المصدر + الهدف | `gemini` |
| جوجل الجوزاء CLI | الهدف فقط | `gemini-cli` |
| مكافحة الجاذبية | المصدر + الهدف | `antigravity` |
| أوس كيرو | الهدف فقط | `kiro` |
| المؤشر | الهدف فقط | `cursor` |
---
## 7. مقدمو الخدمة المدعومين
| مقدم | طريقة المصادقة | المنفذ | الملاحظات الرئيسية |
| ------------------------- | ------------------------ | --------------- | --------------------------------------------------------- |
| أنثروبي كلود | مفتاح API أو OAuth | الافتراضي | يستخدم رأس `x-api-key` |
| جوجل الجوزاء | مفتاح API أو OAuth | الافتراضي | يستخدم رأس `x-goog-api-key` |
| جوجل الجوزاء CLI | أووث | الجوزاء كلي | يستخدم `streamGenerateContent` نقطة النهاية |
| مكافحة الجاذبية | أووث | مكافحة الجاذبية | احتياطي عناوين URL المتعددة، إعادة محاولة التحليل المخصصة |
| أوبن آي | مفتاح API | الافتراضي | مصادقة حامل المعيار |
| الدستور الغذائي | أووث | الدستور الغذائي | يدخل تعليمات النظام ويدير التفكير |
| جيثب مساعد الطيار | OAuth + رمز مساعد الطيار | جيثب | رمز مزدوج، محاكاة رأس VSCode |
| كيرو (AWS) | AWS SSO OIDC أو Social | كيرو | تحليل دفق الأحداث الثنائية |
| بيئة تطوير متكاملة للمؤشر | مصادقة المجموع الاختباري | المؤشر | ترميز Protobuf، المجموع الاختباري SHA-256 |
| كوين | أووث | الافتراضي | المصادقة القياسية |
| اي فلو | OAuth (أساسي + حامل) | الافتراضي | رأس المصادقة المزدوجة |
| اوبن راوتر | مفتاح API | الافتراضي | مصادقة حامل المعيار |
| جي إل إم، كيمي، ميني ماكس | مفتاح API | الافتراضي | متوافق مع كلود، استخدم `x-api-key` |
| `openai-compatible-*` | مفتاح API | الافتراضي | ديناميكي: أي نقطة نهاية متوافقة مع OpenAI |
| `anthropic-compatible-*` | مفتاح API | الافتراضي | ديناميكي: أي نقطة نهاية متوافقة مع كلود |
---
## 8. ملخص تدفق البيانات
### طلب البث
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor\nbuildUrl + buildHeaders"]
D --> E["fetch(providerURL)"]
E --> F["createSSEStream()\nTRANSLATE mode"]
F --> G["parseSSELine()"]
G --> H["translateResponse()\ntarget → OpenAI → source"]
H --> I["extractUsage()\n+ addBuffer"]
I --> J["formatSSE()"]
J --> K["Client receives\ntranslated SSE"]
K --> L["logUsage()\nsaveRequestUsage()"]
```
### طلب عدم البث
```mermaid
flowchart LR
A["Client"] --> B["detectFormat()"]
B --> C["translateRequest()\nsource → OpenAI → target"]
C --> D["Executor.execute()"]
D --> E["translateResponse()\ntarget → OpenAI → source"]
E --> F["Return JSON\nresponse"]
```
### تجاوز التدفق (كلود CLI)
```mermaid
flowchart LR
A["Claude CLI request"] --> B{"Match bypass\npattern?"}
B -->|"Title/Warmup/Count"| C["Generate fake\nOpenAI response"]
B -->|"No match"| D["Normal flow"]
C --> E["Translate to\nsource format"]
E --> F["Return without\ncalling provider"]
```
-77
View File
@@ -1,77 +0,0 @@
# OmniRoute — معرض ميزات لوحة المعلومات
🌐 **Languages:** 🇺🇸 [English](../../FEATURES.md) | 🇧🇷 [Português (Brasil)](../pt-BR/FEATURES.md) | 🇪🇸 [Español](../es/FEATURES.md) | 🇫🇷 [Français](../fr/FEATURES.md) | 🇮🇹 [Italiano](../it/FEATURES.md) | 🇷🇺 [Русский](../ru/FEATURES.md) | 🇨🇳 [中文 (简体)](../zh-CN/FEATURES.md) | 🇩🇪 [Deutsch](../de/FEATURES.md) | 🇮🇳 [हिन्दी](../in/FEATURES.md) | 🇹🇭 [ไทย](../th/FEATURES.md) | 🇺🇦 [Українська](../uk-UA/FEATURES.md) | 🇸🇦 [العربية](../ar/FEATURES.md) | 🇯🇵 [日本語](../ja/FEATURES.md) | 🇻🇳 [Tiếng Việt](../vi/FEATURES.md) | 🇧🇬 [Български](../bg/FEATURES.md) | 🇩🇰 [Dansk](../da/FEATURES.md) | 🇫🇮 [Suomi](../fi/FEATURES.md) | 🇮🇱 [עברית](../he/FEATURES.md) | 🇭🇺 [Magyar](../hu/FEATURES.md) | 🇮🇩 [Bahasa Indonesia](../id/FEATURES.md) | 🇰🇷 [한국어](../ko/FEATURES.md) | 🇲🇾 [Bahasa Melayu](../ms/FEATURES.md) | 🇳🇱 [Nederlands](../nl/FEATURES.md) | 🇳🇴 [Norsk](../no/FEATURES.md) | 🇵🇹 [Português (Portugal)](../pt/FEATURES.md) | 🇷🇴 [Română](../ro/FEATURES.md) | 🇵🇱 [Polski](../pl/FEATURES.md) | 🇸🇰 [Slovenčina](../sk/FEATURES.md) | 🇸🇪 [Svenska](../sv/FEATURES.md) | 🇵🇭 [Filipino](../phi/FEATURES.md)
دليل مرئي لكل قسم من لوحة معلومات OmniRoute.
---
## 🔌 مقدمو الخدمة
إدارة اتصالات مزودي الذكاء الاصطناعي: موفري OAuth (Claude Code وCodex وGemini CLI) وموفري مفاتيح API (Groq وDeepSeek وOpenRouter) ومقدمي الخدمات المجانية (iFlow وQwen وKiro).
![Providers Dashboard](screenshots/01-providers.png)
---
## 🎨 المجموعات
أنشئ مجموعات توجيه النماذج باستخدام 6 إستراتيجيات: التعبئة أولاً، والتدوير الدائري، وقوة الاختيارين، والعشوائية، والأقل استخدامًا، والمُحسَّنة من حيث التكلفة. تقوم كل مجموعة بتسلسل نماذج متعددة مع الرجوع التلقائي.
![Combos Dashboard](screenshots/02-combos.png)
---
## 📊تحليلات
تحليلات استخدام شاملة مع استهلاك الرمز المميز، وتقديرات التكلفة، وخرائط النشاط، ومخططات التوزيع الأسبوعية، والتفاصيل لكل مزود.
![Analytics Dashboard](screenshots/03-analytics.png)
---
## 🏥 صحة النظام
المراقبة في الوقت الفعلي: وقت التشغيل، والذاكرة، والإصدار، والنسب المئوية لزمن الوصول (p50/p95/p99)، وإحصائيات ذاكرة التخزين المؤقت، وحالات قاطع دائرة الموفر.
![Health Dashboard](screenshots/04-health.png)
---
## 🔧 ملعب المترجم
أربعة أوضاع لتصحيح أخطاء ترجمات واجهة برمجة التطبيقات: **ساحة اللعب** (محول التنسيق)، **اختبار الدردشة** (الطلبات المباشرة)، **منصة الاختبار** (اختبارات الدفعة)، و **المراقب المباشر** (البث في الوقت الفعلي).
![Translator Playground](screenshots/05-translator.png)
---
## ⚙️ الإعدادات
الإعدادات العامة، وتخزين النظام، وإدارة النسخ الاحتياطي (قاعدة بيانات التصدير/الاستيراد)، والمظهر (الوضع الداكن/الفاتح)، والأمان (يتضمن حماية نقطة نهاية واجهة برمجة التطبيقات وحظر الموفر المخصص)، والتوجيه، والمرونة، والتكوين المتقدم.
![Settings Dashboard](screenshots/06-settings.png)
---
## 🔧 أدوات CLI
تكوين بنقرة واحدة لأدوات ترميز الذكاء الاصطناعي: Claude Code، وCodex CLI، وGemini CLI، وOpenClaw، وKilo Code، وAntigravity.
![CLI Tools Dashboard](screenshots/07-cli-tools.png)
---
## 📝 سجلات الطلب
تسجيل الطلبات في الوقت الفعلي مع التصفية حسب الموفر والطراز والحساب ومفتاح واجهة برمجة التطبيقات. يعرض رموز الحالة واستخدام الرمز المميز ووقت الاستجابة وتفاصيل الاستجابة.
![Usage Logs](screenshots/08-usage.png)
---
## 🌐 نقطة نهاية API
نقطة نهاية واجهة برمجة التطبيقات الموحدة الخاصة بك مع تفاصيل الإمكانات: عمليات إكمال الدردشة والتضمين وإنشاء الصور وإعادة الترتيب والنسخ الصوتي ومفاتيح واجهة برمجة التطبيقات المسجلة.
![Endpoint Dashboard](screenshots/09-endpoint.png)
-219
View File
@@ -1,219 +0,0 @@
# استكشاف الأخطاء وإصلاحها
🌐 **Languages:** 🇺🇸 [English](../../TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](../pt-BR/TROUBLESHOOTING.md) | 🇪🇸 [Español](../es/TROUBLESHOOTING.md) | 🇫🇷 [Français](../fr/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](../it/TROUBLESHOOTING.md) | 🇷🇺 [Русский](../ru/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](../zh-CN/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](../de/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](../in/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](../th/TROUBLESHOOTING.md) | 🇺🇦 [Українська](../uk-UA/TROUBLESHOOTING.md) | 🇸🇦 [العربية](../ar/TROUBLESHOOTING.md) | 🇯🇵 [日本語](../ja/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](../vi/TROUBLESHOOTING.md) | 🇧🇬 [Български](../bg/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](../da/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](../fi/TROUBLESHOOTING.md) | 🇮🇱 [עברית](../he/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](../hu/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](../id/TROUBLESHOOTING.md) | 🇰🇷 [한국어](../ko/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](../ms/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](../nl/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](../no/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](../pt/TROUBLESHOOTING.md) | 🇷🇴 [Română](../ro/TROUBLESHOOTING.md) | 🇵🇱 [Polski](../pl/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](../sk/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](../sv/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](../phi/TROUBLESHOOTING.md)
المشاكل والحلول الشائعة لـ OmniRoute.
---
## إصلاحات سريعة
| مشكلة | الحل |
| --------------------------------- | ----------------------------------------------------------------- |
| تسجيل الدخول الأول لا يعمل | تحقق من `INITIAL_PASSWORD` في `.env` (الافتراضي: `123456`) |
| تفتح لوحة المعلومات على منفذ خاطئ | اضبط `PORT=20128` و`NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
| لا توجد سجلات للطلب ضمن `logs/` | تعيين `ENABLE_REQUEST_LOGS=true` |
| EACCES: تم رفض الإذن | اضبط `DATA_DIR=/path/to/writable/dir` لتجاوز `~/.omniroute` |
| استراتيجية التوجيه لا تنقذ | التحديث إلى الإصدار 1.4.11+ (إصلاح مخطط Zod لاستمرارية الإعدادات) |
---
## مشكلات المزود
### "نموذج اللغة لم يقدم رسائل"
**السبب:** استنفدت حصة الموفر.
**الإصلاح:**
1. تحقق من تعقب الحصص في لوحة القيادة
2. استخدم مجموعة من المستويات الاحتياطية
3. قم بالتبديل إلى الطبقة الأرخص/المجانية
### تحديد المعدل
**السبب:** استنفدت حصة الاشتراك.
**الإصلاح:**
- إضافة احتياطي: `cc/claude-opus-4-6 → glm/glm-4.7 → if/kimi-k2-thinking`
- استخدم GLM/MiniMax كنسخة احتياطية رخيصة الثمن
### انتهت صلاحية رمز OAuth
يقوم OmniRoute بتحديث الرموز المميزة تلقائيًا. إذا استمرت المشكلات:
1. لوحة المعلومات → الموفر → إعادة الاتصال
2. قم بحذف وإعادة إضافة اتصال الموفر
---
## مشكلات السحابة
### أخطاء المزامنة السحابية
1. تحقق من نقاط `BASE_URL` لمثيلك قيد التشغيل (على سبيل المثال، `http://localhost:20128`)
2. تحقق من نقاط `CLOUD_URL` إلى نقطة نهاية السحابة الخاصة بك (على سبيل المثال، `https://omniroute.dev`)
3. حافظ على محاذاة قيم `NEXT_PUBLIC_*` مع القيم من جانب الخادم
### السحابة `stream=false` تُرجع 500
**العَرَض:** `Unexpected token 'd'...` على نقطة نهاية السحابة للمكالمات غير المتدفقة.
**السبب:** يقوم المنبع بإرجاع حمولة SSE بينما يتوقع العميل JSON.
**الحل البديل:** استخدم `stream=true` للمكالمات السحابية المباشرة. يتضمن وقت التشغيل المحلي SSE → JSON الاحتياطي.
### تقول السحابة إنها متصلة ولكن "مفتاح واجهة برمجة التطبيقات غير صالح"
1. قم بإنشاء مفتاح جديد من لوحة المعلومات المحلية (`/api/keys`)
2. قم بتشغيل المزامنة السحابية: قم بتمكين السحابة → المزامنة الآن
3. لا يزال بإمكان المفاتيح القديمة/غير المتزامنة إرجاع `401` على السحابة
---
## مشكلات عامل الميناء
### تظهر أداة CLI غير مثبتة
1. تحقق من حقول وقت التشغيل: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
2. بالنسبة للوضع المحمول: استخدم هدف الصورة `runner-cli` (CLIs المجمعة)
3. بالنسبة لوضع تثبيت المضيف: قم بتعيين `CLI_EXTRA_PATHS` وتثبيت دليل حاوية المضيف للقراءة فقط
4. إذا تم العثور على `installed=true` و`runnable=false`: ثنائي ولكن فشل التحقق من الصحة
### التحقق السريع من وقت التشغيل
```bash
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
```
---
## قضايا التكلفة
### ارتفاع التكاليف
1. تحقق من إحصائيات الاستخدام في لوحة المعلومات → الاستخدام
2. قم بتبديل النموذج الأساسي إلى GLM/MiniMax
3. استخدم الطبقة المجانية (Gemini CLI، iFlow) للمهام غير الحرجة
4. قم بتعيين ميزانيات التكلفة لكل مفتاح واجهة برمجة التطبيقات: لوحة المعلومات ← مفاتيح واجهة برمجة التطبيقات ← الميزانية
---
## التصحيح
### تمكين سجلات الطلبات
قم بتعيين `ENABLE_REQUEST_LOGS=true` في ملف `.env` الخاص بك. تظهر السجلات ضمن الدليل `logs/`.
### التحقق من صحة مقدم الخدمة
```bash
# Health dashboard
http://localhost:20128/dashboard/health
# API health check
curl http://localhost:20128/api/monitoring/health
```
### تخزين وقت التشغيل
- الحالة الرئيسية: `${DATA_DIR}/db.json` (المزودون، المجموعات، الأسماء المستعارة، المفاتيح، الإعدادات)
- الاستخدام: `${DATA_DIR}/usage.json`، `${DATA_DIR}/log.txt`، `${DATA_DIR}/call_logs/`
- سجلات الطلب: `<repo>/logs/...` (عندما `ENABLE_REQUEST_LOGS=true`)
---
## مشكلات قواطع الدائرة
### الموفر عالق في الحالة المفتوحة
عندما يكون قاطع دائرة الموفر مفتوحًا، يتم حظر الطلبات حتى تنتهي فترة التهدئة.
**الإصلاح:**
1. انتقل إلى **لوحة التحكم ← الإعدادات ← المرونة**
2. تحقق من بطاقة قاطع الدائرة الكهربائية الخاصة بالمزود المتأثر
3. انقر فوق **إعادة تعيين الكل** لمسح جميع القواطع، أو انتظر حتى تنتهي فترة التهدئة
4. تحقق من أن الموفر متاح فعليًا قبل إعادة التعيين
### يستمر المزود في تعطيل قاطع الدائرة
إذا دخل مقدم الخدمة بشكل متكرر في الحالة المفتوحة:
1. تحقق من **Dashboard → Health → Provider Health** لمعرفة نمط الفشل
2. انتقل إلى **الإعدادات → المرونة → ملفات تعريف الموفر** وقم بزيادة حد الفشل
3. تحقق مما إذا كان الموفر قد قام بتغيير حدود واجهة برمجة التطبيقات (API) أو طلب إعادة المصادقة
4. قم بمراجعة القياس عن بعد لزمن الاستجابة - قد يتسبب زمن الاستجابة العالي في حدوث أعطال بسبب انتهاء المهلة
---
## مشكلات النسخ الصوتي
### خطأ "نموذج غير مدعوم".
- تأكد من أنك تستخدم البادئة الصحيحة: `deepgram/nova-3` أو `assemblyai/best`
- تحقق من أن الموفر متصل في **لوحة التحكم ← الموفرون**
### يعود النسخ فارغًا أو يفشل
- تحقق من تنسيقات الصوت المدعومة: `mp3`، `wav`، `m4a`، `flac`، `ogg`، `webm`
- التحقق من أن حجم الملف يقع ضمن حدود الموفر (عادةً أقل من 25 ميجابايت)
- التحقق من صلاحية مفتاح API الخاص بالموفر في بطاقة المزود
---
## تصحيح أخطاء المترجم
استخدم **لوحة المعلومات → المترجم** لتصحيح مشكلات ترجمة التنسيق:
| الوضع | متى تستخدم |
| -------------------- | ---------------------------------------------------------------------------------- |
| **ساحة اللعب** | قارن تنسيقات الإدخال/الإخراج جنبًا إلى جنب — الصق طلبًا فاشلاً لترى كيف تتم ترجمته |
| ** اختبار الدردشة ** | أرسل رسائل مباشرة وافحص حمولة الطلب/الاستجابة الكاملة بما في ذلك الرؤوس |
| ** مقعد الاختبار ** | قم بإجراء اختبارات مجمعة عبر مجموعات التنسيق للعثور على الترجمات المعطلة |
| **مراقبة حية** | شاهد تدفق الطلبات في الوقت الفعلي للتعرف على مشكلات الترجمة المتقطعة |
### مشكلات التنسيق الشائعة
- **لا تظهر علامات التفكير** — تحقق مما إذا كان الموفر المستهدف يدعم التفكير وإعداد ميزانية التفكير
- **استدعاءات الأداة** — قد تؤدي بعض ترجمات التنسيق إلى إزالة الحقول غير المدعومة؛ تحقق في وضع الملعب
- **مطالبة النظام مفقودة** — يتعامل نظام Claude وGemini مع المطالبات بشكل مختلف؛ التحقق من إخراج الترجمة
- ** تقوم SDK بإرجاع سلسلة أولية بدلاً من الكائن ** - تم الإصلاح في الإصدار 1.1.0: تقوم أداة معالجة الاستجابة الآن بإزالة الحقول غير القياسية (`x_groq`، `usage_breakdown`، وما إلى ذلك) التي تتسبب في فشل التحقق من صحة OpenAI SDK Pydantic
- **GLM/ERNIE يرفض دور `system`** — تم إصلاحه في الإصدار 1.1.0: يقوم مُطبيع الدور تلقائيًا بدمج رسائل النظام في رسائل المستخدم للنماذج غير المتوافقة
- **`developer` لم يتم التعرف على الدور** — تم إصلاحه في الإصدار 1.1.0: تم تحويله تلقائيًا إلى `system` لمقدمي الخدمات غير التابعين لـ OpenAI
- **`json_schema` لا يعمل مع Gemini** — تم إصلاحه في الإصدار 1.1.0: `response_format` تم تحويله الآن إلى `responseMimeType` + `responseSchema` الخاص بـ Gemini\_\_
---
## إعدادات المرونة
### لا يتم تشغيل حد المعدل التلقائي
- ينطبق حد المعدل التلقائي فقط على موفري مفاتيح واجهة برمجة التطبيقات (وليس OAuth/الاشتراك)
- تحقق من أن **الإعدادات → المرونة → ملفات تعريف الموفر** تم تمكين حد المعدل التلقائي
- تحقق مما إذا كان الموفر يعرض `429` رموز الحالة أو رؤوس `Retry-After`
### ضبط التراجع الأسي
تدعم ملفات تعريف الموفر هذه الإعدادات:
- **التأخير الأساسي** — وقت الانتظار الأولي بعد الفشل الأول (الافتراضي: 1 ثانية)
- **الحد الأقصى للتأخير** — الحد الأقصى لوقت الانتظار (الافتراضي: 30 ثانية)
- **المضاعف** — مقدار زيادة التأخير لكل فشل متتالي (الافتراضي: 2x)
### قطيع مضاد للرعد
عندما تصل العديد من الطلبات المتزامنة إلى موفر محدود السعر، يستخدم OmniRoute تحديد المعدل التلقائي + mutex لإجراء تسلسل للطلبات ومنع حالات الفشل المتتالية. وهذا تلقائي لموفري مفاتيح API.
---
## هل مازلت عالقًا؟
- **مشكلات GitHub**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **الهندسة المعمارية**: راجع [link](ARCHITECTURE.md) للحصول على التفاصيل الداخلية
- **مرجع واجهة برمجة التطبيقات**: راجع [link](API_REFERENCE.md) لجميع نقاط النهاية
- **لوحة معلومات الصحة**: تحقق من **لوحة المعلومات ← الصحة** لمعرفة حالة النظام في الوقت الفعلي
- **المترجم**: استخدم **لوحة المعلومات ← المترجم** لتصحيح مشكلات التنسيق
-698
View File
@@ -1,698 +0,0 @@
# دليل المستخدم
🌐 **Languages:** 🇺🇸 [English](../../USER_GUIDE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/USER_GUIDE.md) | 🇪🇸 [Español](../es/USER_GUIDE.md) | 🇫🇷 [Français](../fr/USER_GUIDE.md) | 🇮🇹 [Italiano](../it/USER_GUIDE.md) | 🇷🇺 [Русский](../ru/USER_GUIDE.md) | 🇨🇳 [中文 (简体)](../zh-CN/USER_GUIDE.md) | 🇩🇪 [Deutsch](../de/USER_GUIDE.md) | 🇮🇳 [हिन्दी](../in/USER_GUIDE.md) | 🇹🇭 [ไทย](../th/USER_GUIDE.md) | 🇺🇦 [Українська](../uk-UA/USER_GUIDE.md) | 🇸🇦 [العربية](../ar/USER_GUIDE.md) | 🇯🇵 [日本語](../ja/USER_GUIDE.md) | 🇻🇳 [Tiếng Việt](../vi/USER_GUIDE.md) | 🇧🇬 [Български](../bg/USER_GUIDE.md) | 🇩🇰 [Dansk](../da/USER_GUIDE.md) | 🇫🇮 [Suomi](../fi/USER_GUIDE.md) | 🇮🇱 [עברית](../he/USER_GUIDE.md) | 🇭🇺 [Magyar](../hu/USER_GUIDE.md) | 🇮🇩 [Bahasa Indonesia](../id/USER_GUIDE.md) | 🇰🇷 [한국어](../ko/USER_GUIDE.md) | 🇲🇾 [Bahasa Melayu](../ms/USER_GUIDE.md) | 🇳🇱 [Nederlands](../nl/USER_GUIDE.md) | 🇳🇴 [Norsk](../no/USER_GUIDE.md) | 🇵🇹 [Português (Portugal)](../pt/USER_GUIDE.md) | 🇷🇴 [Română](../ro/USER_GUIDE.md) | 🇵🇱 [Polski](../pl/USER_GUIDE.md) | 🇸🇰 [Slovenčina](../sk/USER_GUIDE.md) | 🇸🇪 [Svenska](../sv/USER_GUIDE.md) | 🇵🇭 [Filipino](../phi/USER_GUIDE.md)
الدليل الكامل لتكوين مقدمي الخدمات، وإنشاء المجموعات، ودمج أدوات CLI، ونشر OmniRoute.
---
## جدول المحتويات
- [Pricing at a Glance](#-pricing-at-a-glance)
- [Use Cases](#-use-cases)
- [Provider Setup](#-provider-setup)
- [CLI Integration](#-cli-integration)
- [Deployment](#-deployment)
- [Available Models](#-available-models)
- [Advanced Features](#-advanced-features)
---
## 💰 لمحة سريعة عن الأسعار
| الطبقة | مقدم | التكلفة | إعادة ضبط الحصص | الأفضل لـ |
| ---------------------------------- | ----------------------------------- | ---------------------- | ----------------------- | -------------------------------------- |
| **💳الإشتراك** | كلود كود (برو) | 20 دولارًا شهريًا | 5 ساعات + أسبوعي | اشتركت بالفعل |
| | الدستور الغذائي (زائد / برو) | 20-200 دولار شهريًا | 5 ساعات + أسبوعي | مستخدمي OpenAI |
| | الجوزاء CLI | **مجاني** | 180 ألف/شهر + 1 ألف/يوم | الجميع! |
| | جيثب مساعد الطيار | 10-19 دولارًا شهريًا | شهري | مستخدمي جيثب |
| **🔑 مفتاح واجهة برمجة التطبيقات** | ديب سيك | الدفع لكل استخدام | لا شيء | الاستدلال الرخيص |
| | جروك | الدفع لكل استخدام | لا شيء | الاستدلال فائق السرعة |
| | xAI (جروك) | الدفع لكل استخدام | لا شيء | جروك 4 المنطق |
| | ميسترال | الدفع لكل استخدام | لا شيء | النماذج التي يستضيفها الاتحاد الأوروبي |
| | الحيرة | الدفع لكل استخدام | لا شيء | البحث المعزز |
| | معا منظمة العفو الدولية | الدفع لكل استخدام | لا شيء | نماذج مفتوحة المصدر |
| | الألعاب النارية منظمة العفو الدولية | الدفع لكل استخدام | لا شيء | صور التدفق السريع |
| | المخيخ | الدفع لكل استخدام | لا شيء | سرعة على نطاق الرقاقة |
| | كوهير | الدفع لكل استخدام | لا شيء | الأمر R+ RAG |
| | نفيديا نيم | الدفع لكل استخدام | لا شيء | نماذج المؤسسات |
| **💰 رخيص** | جي إل إم-4.7 | 0.6 دولار/1 مليون | يوميا 10 صباحا | نسخة احتياطية للميزانية |
| | ميني ماكس M2.1 | 0.2 دولار/1 مليون | المتداول لمدة 5 ساعات | الخيار الأرخص |
| | كيمي ك2 | 9 دولارات شهريًا مسطحة | 10 مليون رمز/شهر | التكلفة المتوقعة |
| **🆓مجانًا** | اي فلو | $0 | غير محدود | 8 نماذج مجانية |
| | كوين | $0 | غير محدود | 3 نماذج مجانية |
| | كيرو | $0 | غير محدود | كلود مجاني |
**💡 نصيحة احترافية:** ابدأ مع مجموعة Gemini CLI (180 ألفًا مجانًا شهريًا) + مجموعة iFlow (مجانية غير محدودة) = تكلفة 0 دولار!
---
## 🎯 حالات الاستخدام
### الحالة 1: "لدي اشتراك Claude Pro"
**المشكلة:** تنتهي صلاحية الحصة غير المستخدمة، وحدود المعدل أثناء عملية الترميز المكثف
```
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
```
### الحالة 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 ساعة طوال أيام الأسبوع، دون انقطاع"
**المشكلة:** المواعيد النهائية، لا أستطيع تحمل فترات التوقف عن العمل
```
Combo: "always-on"
1. cc/claude-opus-4-6 (best quality)
2. cx/gpt-5.2-codex (second subscription)
3. glm/glm-4.7 (cheap, resets daily)
4. minimax/MiniMax-M2.1 (cheapest, 5h reset)
5. if/kimi-k2-thinking (free unlimited)
Result: 5 layers of fallback = zero downtime
Monthly cost: $20-200 (subscriptions) + $10-20 (backup)
```
### الحالة 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...
```
---
## 📖 إعداد الموفر
### 🔐 مقدمي الاشتراكات
#### كلود كود (برو/ماكس)
```bash
Dashboard → Providers → Connect Claude Code
→ OAuth login → Auto token refresh
→ 5-hour + weekly quota tracking
Models:
cc/claude-opus-4-6
cc/claude-sonnet-4-5-20250929
cc/claude-haiku-4-5-20251001
```
**نصيحة احترافية:** استخدم Opus للمهام المعقدة، وSonnet للسرعة. OmniRoute يتتبع الحصة لكل نموذج!
#### OpenAI Codex (Plus/Pro)
```bash
Dashboard → Providers → Connect Codex
→ OAuth login (port 1455)
→ 5-hour + weekly reset
Models:
cx/gpt-5.2-codex
cx/gpt-5.1-codex-max
```
#### Gemini CLI (180 ألفًا شهريًا مجانًا!)
```bash
Dashboard → Providers → Connect Gemini CLI
→ Google OAuth
→ 180K completions/month + 1K/day
Models:
gc/gemini-3-flash-preview
gc/gemini-2.5-pro
```
**أفضل قيمة:** طبقة مجانية ضخمة! استخدم هذا قبل المستويات المدفوعة.
#### مساعد جيثب
```bash
Dashboard → Providers → Connect GitHub
→ OAuth via GitHub
→ Monthly reset (1st of month)
Models:
gh/gpt-5
gh/claude-4.5-sonnet
gh/gemini-3-pro
```
### 💰 مقدمو خدمات رخيصون
#### GLM-4.7 (إعادة التعيين اليومي، 0.6 دولار/1 مليون)
1. قم بالتسجيل: [Zhipu AI](https://open.bigmodel.cn/)
2. احصل على مفتاح API من خطة الترميز
3. لوحة المعلومات → إضافة مفتاح واجهة برمجة التطبيقات: الموفر: `glm`، مفتاح واجهة برمجة التطبيقات: `your-key`
**الاستخدام:** `glm/glm-4.7`**نصيحة احترافية:** توفر خطة البرمجة حصة 3× بتكلفة 1/7! إعادة الضبط يوميًا الساعة 10:00 صباحًا.
#### MiniMax M2.1 (إعادة الضبط لمدة 5 ساعات، 0.20 دولار/1 مليون)
1. قم بالتسجيل: [MiniMax](https://www.minimax.io/)
2. احصل على مفتاح API → لوحة المعلومات → إضافة مفتاح API
**الاستخدام:** `minimax/MiniMax-M2.1`**نصيحة احترافية:** الخيار الأرخص للسياق الطويل (مليون رمز)!
#### كيمي K2 (شقة بقيمة 9 دولارات في الشهر)
1. الاشتراك: [Moonshot AI](https://platform.moonshot.ai/)
2. احصل على مفتاح API → لوحة المعلومات → إضافة مفتاح API
**الاستخدام:** `kimi/kimi-latest`**نصيحة احترافية:** سعر ثابت قدره 9 دولارات شهريًا مقابل 10 ملايين رمز مميز = 0.90 دولارًا أمريكيًا/التكلفة الفعلية لمليون واحد!
### 🆓 مقدمي الخدمة مجانًا
#### iFlow (8 نماذج مجانية)
```bash
Dashboard → Connect iFlow → OAuth login → Unlimited usage
Models: if/kimi-k2-thinking, if/qwen3-coder-plus, if/glm-4.7, if/minimax-m2, if/deepseek-r1
```
#### كوين (3 موديلات مجانية)
```bash
Dashboard → Connect Qwen → Device code auth → Unlimited usage
Models: qw/qwen3-coder-plus, qw/qwen3-coder-flash
```
#### كيرو (كلود فري)
```bash
Dashboard → Connect Kiro → AWS Builder ID or Google/GitHub → Unlimited
Models: kr/claude-sonnet-4.5, kr/claude-haiku-4.5
```
---
## 🎨 المجموعات
### مثال 1: زيادة الاشتراك إلى الحد الأقصى → النسخ الاحتياطي الرخيص
```
Dashboard → Combos → Create New
Name: premium-coding
Models:
1. cc/claude-opus-4-6 (Subscription primary)
2. glm/glm-4.7 (Cheap backup, $0.6/1M)
3. minimax/MiniMax-M2.1 (Cheapest fallback, $0.20/1M)
Use in CLI: premium-coding
```
### المثال 2: مجاني فقط (بدون تكلفة)
```
Name: free-combo
Models:
1. gc/gemini-3-flash-preview (180K free/month)
2. if/kimi-k2-thinking (unlimited)
3. qw/qwen3-coder-plus (unlimited)
Cost: $0 forever!
```
---
## 🔧 تكامل CLI
### بيئة تطوير متكاملة للمؤشر
```
Settings → Models → Advanced:
OpenAI API Base URL: http://localhost:20128/v1
OpenAI API Key: [from omniroute dashboard]
Model: cc/claude-opus-4-6
```
### كلود كود
تحرير `~/.claude/config.json`:
```json
{
"anthropic_api_base": "http://localhost:20128/v1",
"anthropic_api_key": "your-omniroute-api-key"
}
```
### كوديكس سطر الأوامر
```bash
export OPENAI_BASE_URL="http://localhost:20128"
export OPENAI_API_KEY="your-omniroute-api-key"
codex "your prompt"
```
### OpenClaw
تحرير `~/.openclaw/openclaw.json`:
```json
{
"agents": {
"defaults": {
"model": { "primary": "omniroute/if/glm-4.7" }
}
},
"models": {
"providers": {
"omniroute": {
"baseUrl": "http://localhost:20128/v1",
"apiKey": "your-omniroute-api-key",
"api": "openai-completions",
"models": [{ "id": "if/glm-4.7", "name": "glm-4.7" }]
}
}
}
}
```
**أو استخدم لوحة المعلومات:** أدوات CLI → OpenClaw → التكوين التلقائي
### كلاين / متابعة / RooCode
```
Provider: OpenAI Compatible
Base URL: http://localhost:20128/v1
API Key: [from dashboard]
Model: cc/claude-opus-4-6
```
---
## 🚀 النشر
### نشر VPS
```bash
git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute && npm install && npm run build
export JWT_SECRET="your-secure-secret-change-this"
export INITIAL_PASSWORD="your-password"
export DATA_DIR="/var/lib/omniroute"
export PORT="20128"
export HOSTNAME="0.0.0.0"
export NODE_ENV="production"
export NEXT_PUBLIC_BASE_URL="http://localhost:20128"
export API_KEY_SECRET="endpoint-proxy-api-key-secret"
npm run start
# Or: pm2 start npm --name omniroute -- start
```
### عامل الميناء
```bash
# Build image (default = runner-cli with codex/claude/droid preinstalled)
docker build -t omniroute:cli .
# Portable mode (recommended)
docker run -d --name omniroute -p 20128:20128 --env-file ./.env -v omniroute-data:/app/data omniroute:cli
```
بالنسبة للوضع المدمج مع المضيف مع ثنائيات CLI، راجع قسم Docker في المستندات الرئيسية.
### متغيرات البيئة
| متغير | الافتراضي | الوصف |
| --------------------- | ------------------------------------ | ---------------------------------------------------------------- |
| `JWT_SECRET` | `omniroute-default-secret-change-me` | سر توقيع JWT (**تغيير في الإنتاج**) |
| `INITIAL_PASSWORD` | `123456` | كلمة المرور الأولى لتسجيل الدخول |
| `DATA_DIR` | `~/.omniroute` | دليل البيانات (ديسيبل، الاستخدام، السجلات) |
| `PORT` | الإطار الافتراضي | منفذ الخدمة (`20128` في الأمثلة) |
| `HOSTNAME` | الإطار الافتراضي | ربط المضيف (إعدادات Docker الافتراضية هي `0.0.0.0`) |
| `NODE_ENV` | وقت التشغيل الافتراضي | قم بتعيين `production` للنشر |
| `BASE_URL` | `http://localhost:20128` | عنوان URL الأساسي الداخلي من جانب الخادم |
| `CLOUD_URL` | `https://omniroute.dev` | عنوان URL الأساسي لنقطة نهاية المزامنة السحابية |
| `API_KEY_SECRET` | `endpoint-proxy-api-key-secret` | سر HMAC لمفاتيح API التي تم إنشاؤها |
| `REQUIRE_API_KEY` | `false` | فرض مفتاح Bearer API على `/v1/*` |
| `ENABLE_REQUEST_LOGS` | `false` | تمكين سجلات الطلب/الاستجابة |
| `AUTH_COOKIE_SECURE` | `false` | فرض ملف تعريف ارتباط المصادقة `Secure` (خلف الوكيل العكسي HTTPS) |
للحصول على مرجع متغير البيئة الكامل، راجع [README](../README.md).
---
## 📊 الموديلات المتوفرة
<details>
<summary><b>عرض جميع الموديلات المتاحة</b></summary>
**كود كلود (`cc/`)** — Pro/Max: `cc/claude-opus-4-6`, `cc/claude-sonnet-4-5-20250929`, `cc/claude-haiku-4-5-20251001`
**المخطوطة (`cx/`)** — Plus/Pro: `cx/gpt-5.2-codex`، `cx/gpt-5.1-codex-max`
**Gemini CLI (`gc/`)** — مجانًا: `gc/gemini-3-flash-preview`، `gc/gemini-2.5-pro`
**مساعد GitHub (`gh/`)**: `gh/gpt-5`, `gh/claude-4.5-sonnet`
**GLM (`glm/`)** — 0.6 دولار/1 مليون: `glm/glm-4.7`
**ميني ماكس (`minimax/`)** — 0.2 دولار/1 مليون: `minimax/MiniMax-M2.1`
**iFlow (`if/`)** — مجانًا: `if/kimi-k2-thinking`، `if/qwen3-coder-plus`، `if/deepseek-r1`
**كوين (`qw/`)** — مجانًا: `qw/qwen3-coder-plus`، `qw/qwen3-coder-flash`
**كيرو (`kr/`)** — مجانًا: `kr/claude-sonnet-4.5`، `kr/claude-haiku-4.5`
**DeepSeek (`ds/`)**: `ds/deepseek-chat`، `ds/deepseek-reasoner`
** جروك (`groq/`)**: `groq/llama-3.3-70b-versatile`، `groq/llama-4-maverick-17b-128e-instruct`
**xAI (`xai/`)**: `xai/grok-4`، `xai/grok-4-0709-fast-reasoning`، `xai/grok-code-mini`
**ميسترال (`mistral/`)**: `mistral/mistral-large-2501`، `mistral/codestral-2501`
**الحيرة (`pplx/`)**: `pplx/sonar-pro`, `pplx/sonar`
** معًا الذكاء الاصطناعي (`together/`)**: `together/meta-llama/Llama-3.3-70B-Instruct-Turbo`
**الذكاء الاصطناعي للألعاب النارية (`fireworks/`)**: `fireworks/accounts/fireworks/models/deepseek-v3p1`
** سيريبراس (`cerebras/`)**: `cerebras/llama-3.3-70b`
**الترابط (`cohere/`)**: `cohere/command-r-plus-08-2024`
** نفيديا نيم (`nvidia/`)**: `nvidia/nvidia/llama-3.3-70b-instruct`
</details>
---
## 🧩 ميزات متقدمة
### نماذج مخصصة
أضف أي معرف نموذج إلى أي مزود دون انتظار تحديث التطبيق:
```bash
# Via API
curl -X POST http://localhost:20128/api/provider-models \
-H "Content-Type: application/json" \
-d '{"provider": "openai", "modelId": "gpt-4.5-preview", "modelName": "GPT-4.5 Preview"}'
# List: curl http://localhost:20128/api/provider-models?provider=openai
# Remove: curl -X DELETE "http://localhost:20128/api/provider-models?provider=openai&model=gpt-4.5-preview"
```
أو استخدم لوحة المعلومات: **المزودون → [الموفر] → النماذج المخصصة**.
### مسارات موفر مخصصة
توجيه الطلبات مباشرة إلى موفر محدد مع التحقق من صحة النموذج:
```bash
POST http://localhost:20128/v1/providers/openai/chat/completions
POST http://localhost:20128/v1/providers/openai/embeddings
POST http://localhost:20128/v1/providers/fireworks/images/generations
```
تتم إضافة بادئة الموفر تلقائيًا في حالة فقدانها. تُرجع النماذج غير المتطابقة `400`.
### تكوين وكيل الشبكة
```bash
# Set global proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"global": {"type":"http","host":"proxy.example.com","port":"8080"}}'
# Per-provider proxy
curl -X PUT http://localhost:20128/api/settings/proxy \
-d '{"providers": {"openai": {"type":"socks5","host":"proxy.example.com","port":"1080"}}}'
# Test proxy
curl -X POST http://localhost:20128/api/settings/proxy/test \
-d '{"proxy":{"type":"socks5","host":"proxy.example.com","port":"1080"}}'
```
**الأسبقية:** خاص بالمفتاح ← خاص بالسرد والسرد ← خاص بالموفر ← عالمي ← البيئة.
### واجهة برمجة تطبيقات الكتالوج النموذجي
```bash
curl http://localhost:20128/api/models/catalog
```
إرجاع النماذج المجمعة حسب الموفر مع الأنواع (`chat`، `embedding`، `image`).
### المزامنة السحابية
- موفري المزامنة والمجموعات والإعدادات عبر الأجهزة
- مزامنة الخلفية التلقائية مع انتهاء المهلة + الفشل السريع
- تفضيل جانب الخادم `BASE_URL`/`CLOUD_URL` في الإنتاج
### LLM Gateway Intelligence (المرحلة 9)
- **ذاكرة التخزين المؤقت الدلالية** — ذاكرة تخزين مؤقت تلقائية غير متدفقة، درجة الحرارة = 0 استجابات (تجاوز باستخدام `X-OmniRoute-No-Cache: true`)
- **صلاحية الطلب** — إلغاء تكرار الطلبات خلال 5 ثوانٍ عبر رأس `Idempotency-Key` أو `X-Request-Id`
- **تتبع التقدم** — الاشتراك في أحداث SSE `event: progress` عبر رأس `X-OmniRoute-Progress: true`
---
### ملعب المترجم
الوصول عبر **لوحة المعلومات → المترجم**. تصحيح الأخطاء وتصور كيفية قيام OmniRoute بترجمة طلبات واجهة برمجة التطبيقات (API) بين مقدمي الخدمة.
| الوضع | الغرض |
| -------------------- | ----------------------------------------------------------------------------- |
| **ساحة اللعب** | حدد تنسيقات المصدر/الهدف، والصق طلبًا، وشاهد المخرجات المترجمة على الفور |
| ** اختبار الدردشة ** | أرسل رسائل الدردشة المباشرة من خلال الوكيل وافحص دورة الطلب/الاستجابة الكاملة |
| ** مقعد الاختبار ** | قم بإجراء اختبارات مجمعة عبر مجموعات تنسيقات متعددة للتحقق من صحة الترجمة |
| **مراقبة حية** | شاهد الترجمات في الوقت الفعلي أثناء تدفق الطلبات عبر الوكيل |
**حالات الاستخدام:**
- تصحيح سبب فشل مجموعة محددة من العميل/الموفر
- التحقق من ترجمة علامات التفكير واستدعاءات الأدوات ومطالبات النظام بشكل صحيح
- مقارنة اختلافات التنسيق بين تنسيقات OpenAI وClaude وGemini وResponsions API
---
### استراتيجيات التوجيه
قم بالتكوين عبر **لوحة المعلومات → الإعدادات → التوجيه**.
| استراتيجية | الوصف |
| ------------------------ | ---------------------------------------------------------------------------------------- |
| ** املأ أولا ** | يستخدم الحسابات بترتيب الأولوية — يعالج الحساب الأساسي جميع الطلبات حتى تصبح غير متاحة |
| ** راوند روبن ** | للتنقل عبر جميع الحسابات بحد ثابت قابل للتكوين (الافتراضي: 3 مكالمات لكل حساب) |
| **P2C (قوة الاختيارين)** | يختار حسابين عشوائيين ويوجهك إلى الحساب الأكثر صحة - الأرصدة محملة بالوعي الصحي |
| **عشوائي** | تحديد حساب عشوائيًا لكل طلب باستخدام خلط Fisher-Yates |
| **الأقل استخدامًا** | التوجيهات إلى الحساب ذو الطابع الزمني الأقدم `lastUsedAt`، مع توزيع حركة المرور بالتساوي |
| **التكلفة الأمثل** | التوجيهات إلى الحساب ذي أقل قيمة أولوية، مع تحسين موفري الخدمة الأقل تكلفة |
#### الأسماء المستعارة لنموذج البدل
قم بإنشاء أنماط أحرف البدل لإعادة تعيين أسماء النماذج:
```
Pattern: claude-sonnet-* → Target: cc/claude-sonnet-4-5-20250929
Pattern: gpt-* → Target: gh/gpt-5.1-codex
```
تدعم أحرف البدل `*` (أي أحرف) و`?` (حرف واحد).
#### سلاسل احتياطية
تحديد السلاسل الاحتياطية العالمية التي تنطبق على جميع الطلبات:
```
Chain: production-fallback
1. cc/claude-opus-4-6
2. gh/gpt-5.1-codex
3. glm/glm-4.7
```
---
### المرونة وقواطع الدائرة
قم بالتكوين عبر **لوحة المعلومات → الإعدادات → المرونة**.
تطبق OmniRoute المرونة على مستوى المزود من خلال أربعة مكونات:
1. **ملفات تعريف الموفر** — التكوين لكل موفر لـ:
- عتبة الفشل (كم عدد حالات الفشل قبل الفتح)
- مدة التهدئة
- حساسية الكشف عن حد المعدل
- معلمات التراجع الأسي
2. **حدود المعدل القابلة للتحرير** — الإعدادات الافتراضية على مستوى النظام قابلة للتكوين في لوحة المعلومات:
- **الطلبات في الدقيقة (RPM)** — الحد الأقصى للطلبات في الدقيقة لكل حساب
- **الحد الأدنى للوقت بين الطلبات** — الحد الأدنى للفجوة بالمللي ثانية بين الطلبات
- **الحد الأقصى للطلبات المتزامنة** — الحد الأقصى للطلبات المتزامنة لكل حساب
- انقر **تحرير** للتعديل، ثم **حفظ** أو **إلغاء**. تستمر القيم عبر واجهة برمجة تطبيقات المرونة.
3. **قاطع الدائرة** — يتتبع حالات الفشل لكل مزود ويفتح الدائرة تلقائيًا عند الوصول إلى الحد الأدنى:
- **مغلق** (صحي) — تتدفق الطلبات بشكل طبيعي
- **مفتوح** — تم حظر الموفر مؤقتًا بعد الفشل المتكرر
- **HALF_OPEN** — اختبار ما إذا كان الموفر قد استعاد عافيته
4. **السياسات والمعرفات المقفلة** — تعرض حالة قاطع الدائرة والمعرفات المقفلة مع إمكانية إلغاء القفل بالقوة.
5. **الاكتشاف التلقائي لحدود المعدل** — يراقب الرؤوس `429` و`Retry-After` لتجنب الوصول إلى حدود معدل الموفر بشكل استباقي.
**نصيحة احترافية:** استخدم زر **إعادة تعيين الكل** لمسح جميع قواطع الدائرة وفترات التباطؤ عندما يتعافى المزود من انقطاع الخدمة.
---
### تصدير / استيراد قاعدة البيانات
إدارة النسخ الاحتياطية لقاعدة البيانات في **لوحة المعلومات → الإعدادات → النظام والتخزين**.
| العمل | الوصف |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **تصدير قاعدة البيانات** | يقوم بتنزيل قاعدة بيانات SQLite الحالية كملف `.sqlite` |
| **تصدير الكل (.tar.gz)** | تنزيل أرشيف نسخ احتياطي كامل بما في ذلك: قاعدة البيانات، والإعدادات، والمجموعات، واتصالات الموفر (بدون بيانات اعتماد)، وبيانات تعريف مفتاح API |
| **استيراد قاعدة البيانات** | قم بتحميل ملف `.sqlite` لاستبدال قاعدة البيانات الحالية. يتم إنشاء نسخة احتياطية للاستيراد المسبق تلقائيًا |
```bash
# API: Export database
curl -o backup.sqlite http://localhost:20128/api/db-backups/export
# API: Export all (full archive)
curl -o backup.tar.gz http://localhost:20128/api/db-backups/exportAll
# API: Import database
curl -X POST http://localhost:20128/api/db-backups/import \
-F "file=@backup.sqlite"
```
**التحقق من صحة الاستيراد:** يتم التحقق من صحة الملف المستورد للتأكد من سلامته (فحص براغما SQLite)، والجداول المطلوبة (`provider_connections`، `provider_nodes`، `combos`، `api_keys`)، والحجم (100 ميجابايت كحد أقصى).
**حالات الاستخدام:**
- ترحيل OmniRoute بين الأجهزة
- إنشاء نسخ احتياطية خارجية للتعافي من الكوارث
- مشاركة التكوينات بين أعضاء الفريق (تصدير الكل → مشاركة الأرشيف)
---
### لوحة تحكم الإعدادات
يتم تنظيم صفحة الإعدادات في 5 علامات تبويب لسهولة التنقل:
| علامة التبويب | المحتويات |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **الأمن** | إعدادات تسجيل الدخول/كلمة المرور، والتحكم في الوصول إلى IP، ومصادقة API لـ `/models`، وحظر الموفر |
| **التوجيه** | استراتيجية التوجيه العالمية (6 خيارات)، والأسماء المستعارة لنماذج أحرف البدل، والسلاسل الاحتياطية، وافتراضيات التحرير والسرد |
| **المرونة** | ملفات تعريف الموفر، وحدود الأسعار القابلة للتحرير، وحالة قاطع الدائرة، والسياسات والمعرفات المقفلة |
| **الذكاء الاصطناعي** | تكوين ميزانية التفكير، والحقن الفوري للنظام العالمي، وإحصائيات ذاكرة التخزين المؤقت السريعة |
| **متقدم** | تكوين الوكيل العالمي (HTTP/SOCKS5) |
---
### إدارة التكاليف والميزانية
الوصول عبر **لوحة التحكم ← التكاليف**.
| علامة التبويب | الغرض |
| ------------- | ------------------------------------------------------------------------------------------------ |
| **الميزانية** | قم بتعيين حدود الإنفاق لكل مفتاح API باستخدام ميزانيات يومية/أسبوعية/شهرية وتتبع في الوقت الفعلي |
| **التسعير** | عرض وتحرير إدخالات تسعير النموذج - التكلفة لكل ألف رمز إدخال/إخراج لكل مزود |
```bash
# API: Set a budget
curl -X POST http://localhost:20128/api/usage/budget \
-H "Content-Type: application/json" \
-d '{"keyId": "key-123", "limit": 50.00, "period": "monthly"}'
# API: Get current budget status
curl http://localhost:20128/api/usage/budget
```
**تتبع التكلفة:** يقوم كل طلب بتسجيل استخدام الرمز المميز وحساب التكلفة باستخدام جدول التسعير. عرض التفاصيل في **لوحة المعلومات → الاستخدام** حسب الموفر والطراز ومفتاح واجهة برمجة التطبيقات.
---
### النسخ الصوتي
يدعم OmniRoute النسخ الصوتي عبر نقطة النهاية المتوافقة مع OpenAI:
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
# Example with curl
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@audio.mp3" \
-F "model=deepgram/nova-3"
```
الموفرون المتاحون: **Deepgram** (`deepgram/`**AssemblyAI** (`assemblyai/`).
تنسيقات الصوت المدعومة: `mp3`، `wav`، `m4a`، `flac`، `ogg`، `webm`.
---
### استراتيجيات موازنة التحرير والسرد
قم بتكوين التوازن لكل مجموعة في **لوحة المعلومات → المجموعات → إنشاء/تحرير → الإستراتيجية**.
| استراتيجية | الوصف |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| **جولة روبن** | يدور عبر النماذج بالتتابع |
| **الأولوية** | يحاول دائمًا النموذج الأول؛ لا يعود إلا على الخطأ |
| **عشوائي** | يختار نموذجًا عشوائيًا من المجموعة لكل طلب |
| **المرجح** | تعتمد المسارات بشكل متناسب على الأوزان المخصصة لكل نموذج |
| **الأقل استخدامًا** | التوجيهات إلى النموذج الذي يحتوي على أقل عدد من الطلبات الأخيرة (يستخدم مقاييس التحرير والسرد) |
| **التكلفة الأمثل** | الطرق إلى أرخص طراز متاح (يستخدم جدول التسعير) |
يمكن ضبط إعدادات التحرير والسرد العامة في **لوحة المعلومات → الإعدادات → التوجيه → إعدادات التحرير والسرد الافتراضية**.
---
### لوحة المعلومات الصحية
الوصول عبر **لوحة التحكم → الصحة**. نظرة عامة على صحة النظام في الوقت الحقيقي مع 6 بطاقات:
| بطاقة | ما يظهر |
| ---------------------------------- | -------------------------------------------------------------- |
| **حالة النظام** | وقت التشغيل، الإصدار، استخدام الذاكرة، دليل البيانات |
| ** صحة المزود ** | حالة قاطع الدائرة الكهربائية لكل مزود (مغلق/مفتوح/نصف مفتوح) |
| ** حدود المعدل ** | فترات تهدئة حد المعدل النشط لكل حساب مع الوقت المتبقي |
| ** عمليات التأمين النشطة ** | تم حظر مقدمي الخدمة مؤقتًا بواسطة سياسة التأمين |
| ** ذاكرة التخزين المؤقت للتوقيع ** | إحصائيات إلغاء البيانات المكررة (المفاتيح النشطة، معدل الدخول) |
| ** قياس زمن الوصول ** | p50/p95/p99 تجميع زمن الوصول لكل مزود |
**نصيحة احترافية:** يتم تحديث صفحة الصحة تلقائيًا كل 10 ثوانٍ. استخدم بطاقة قاطع الدائرة لتحديد مقدمي الخدمة الذين يواجهون مشكلات.
-441
View File
@@ -1,441 +0,0 @@
# Справка за API
🌐 **Languages:** 🇺🇸 [English](../../API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/API_REFERENCE.md) | 🇪🇸 [Español](../es/API_REFERENCE.md) | 🇫🇷 [Français](../fr/API_REFERENCE.md) | 🇮🇹 [Italiano](../it/API_REFERENCE.md) | 🇷🇺 [Русский](../ru/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](../zh-CN/API_REFERENCE.md) | 🇩🇪 [Deutsch](../de/API_REFERENCE.md) | 🇮🇳 [हिन्दी](../in/API_REFERENCE.md) | 🇹🇭 [ไทย](../th/API_REFERENCE.md) | 🇺🇦 [Українська](../uk-UA/API_REFERENCE.md) | 🇸🇦 [العربية](../ar/API_REFERENCE.md) | 🇯🇵 [日本語](../ja/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](../vi/API_REFERENCE.md) | 🇧🇬 [Български](../bg/API_REFERENCE.md) | 🇩🇰 [Dansk](../da/API_REFERENCE.md) | 🇫🇮 [Suomi](../fi/API_REFERENCE.md) | 🇮🇱 [עברית](../he/API_REFERENCE.md) | 🇭🇺 [Magyar](../hu/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](../id/API_REFERENCE.md) | 🇰🇷 [한국어](../ko/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](../ms/API_REFERENCE.md) | 🇳🇱 [Nederlands](../nl/API_REFERENCE.md) | 🇳🇴 [Norsk](../no/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](../pt/API_REFERENCE.md) | 🇷🇴 [Română](../ro/API_REFERENCE.md) | 🇵🇱 [Polski](../pl/API_REFERENCE.md) | 🇸🇰 [Slovenčina](../sk/API_REFERENCE.md) | 🇸🇪 [Svenska](../sv/API_REFERENCE.md) | 🇵🇭 [Filipino](../phi/API_REFERENCE.md)
Пълна справка за всички крайни точки на OmniRoute API.
---
## Съдържание
- [Chat Completions](#chat-completions)
- [Embeddings](#embeddings)
- [Image Generation](#image-generation)
- [List Models](#list-models)
- [Compatibility Endpoints](#compatibility-endpoints)
- [Semantic Cache](#semantic-cache)
- [Dashboard & Management](#dashboard--management)
- [Request Processing](#request-processing)
- [Authentication](#authentication)
---
## Завършвания на чат
```bash
POST /v1/chat/completions
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "cc/claude-opus-4-6",
"messages": [
{"role": "user", "content": "Write a function to..."}
],
"stream": true
}
```
### Персонализирани заглавки
| Заглавка | Посока | Описание |
| ------------------------ | ------- | ------------------------------------------ |
| `X-OmniRoute-No-Cache` | Заявка | Задайте `true` за заобикаляне на кеша |
| `X-OmniRoute-Progress` | Заявка | Задайте `true` за събития за прогрес |
| `Idempotency-Key` | Заявка | Ключ за дедупиране (5s прозорец) |
| `X-Request-Id` | Заявка | Алтернативен дедуп ключ |
| `X-OmniRoute-Cache` | Отговор | `HIT` или `MISS` (без поточно предаване) |
| `X-OmniRoute-Idempotent` | Отговор | `true` ако е дедупликиран |
| `X-OmniRoute-Progress` | Отговор | `enabled` ако проследяване на напредъка на |
---
## Вграждания
```bash
POST /v1/embeddings
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "nebius/Qwen/Qwen3-Embedding-8B",
"input": "The food was delicious"
}
```
Налични доставчици: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA.
```bash
# List all embedding models
GET /v1/embeddings
```
---
## Генериране на изображения
```bash
POST /v1/images/generations
Authorization: Bearer your-api-key
Content-Type: application/json
{
"model": "openai/dall-e-3",
"prompt": "A beautiful sunset over mountains",
"size": "1024x1024"
}
```
Налични доставчици: OpenAI (DALL-E), xAI (Grok Image), Together AI (FLUX), Fireworks AI.
```bash
# List all image models
GET /v1/images/generations
```
---
## Списък с модели
```bash
GET /v1/models
Authorization: Bearer your-api-key
→ Returns all chat, embedding, and image models + combos in OpenAI format
```
---
## Крайни точки за съвместимост
| Метод | Път | Формат |
| ---------- | --------------------------- | -------------------------- |
| ПУБЛИКАЦИЯ | `/v1/chat/completions` | OpenAI |
| ПУБЛИКАЦИЯ | `/v1/messages` | Антропен |
| ПУБЛИКАЦИЯ | `/v1/responses` | OpenAI отговори |
| ПУБЛИКАЦИЯ | `/v1/embeddings` | OpenAI |
| ПУБЛИКАЦИЯ | `/v1/images/generations` | OpenAI |
| ВЗЕМЕТЕ | `/v1/models` | OpenAI |
| ПУБЛИКАЦИЯ | `/v1/messages/count_tokens` | Антропен |
| ВЗЕМЕТЕ | `/v1beta/models` | Близнаци |
| ПУБЛИКАЦИЯ | `/v1beta/models/{...path}` | Gemini генерира съдържание |
| ПУБЛИКАЦИЯ | `/v1/api/chat` | Олама |
### Специализирани маршрути на доставчик
```bash
POST /v1/providers/{provider}/chat/completions
POST /v1/providers/{provider}/embeddings
POST /v1/providers/{provider}/images/generations
```
Префиксът на доставчика се добавя автоматично, ако липсва. Несъответстващите модели връщат `400`.
---
## Семантичен кеш
```bash
# Get cache stats
GET /api/cache
# Clear all caches
DELETE /api/cache
```
Пример за отговор:
```json
{
"semanticCache": {
"memorySize": 42,
"memoryMaxSize": 500,
"dbSize": 128,
"hitRate": 0.65
},
"idempotency": {
"activeKeys": 3,
"windowMs": 5000
}
}
```
---
## Табло за управление и управление
### Удостоверяване
| Крайна точка | Метод | Описание |
| ----------------------------- | ------------- | ---------------------------------- |
| `/api/auth/login` | ПУБЛИКАЦИЯ | Вход |
| `/api/auth/logout` | ПУБЛИКАЦИЯ | Изход |
| `/api/settings/require-login` | ВЗЕМИ/ПОСТАВИ | Изисква се превключване на влизане |
### Управление на доставчика
| Крайна точка | Метод | Описание |
| ---------------------------- | -------------------------------- | ---------------------------------------- |
| `/api/providers` | ВЗЕМЕТЕ/ПУБЛИКУВАЙТЕ | Списък / създаване на доставчици |
| `/api/providers/[id]` | ПОЛУЧАВАНЕ/ПОСТАВЯНЕ/ИЗТРИВАНЕ | Управление на доставчик |
| `/api/providers/[id]/test` | ПУБЛИКАЦИЯ | Тествайте връзката с доставчик |
| `/api/providers/[id]/models` | ВЗЕМЕТЕ | Избройте модели на доставчици |
| `/api/providers/validate` | ПУБЛИКАЦИЯ | Проверка на конфигурацията на доставчика |
| `/api/provider-nodes*` | Различни | Управление на възел на доставчик |
| `/api/provider-models` | ПОЛУЧАВАНЕ/ПУБЛИКУВАНЕ/ИЗТРИВАНЕ | Персонализирани модели |
### OAuth потоци
| Крайна точка | Метод | Описание |
| -------------------------------- | -------- | ------------------------------ |
| `/api/oauth/[provider]/[action]` | Различни | Специфичен за доставчика OAuth |
### Маршрутизиране и конфигурация
| Крайна точка | Метод | Описание |
| --------------------- | -------------------- | -------------------------------- |
| `/api/models/alias` | ВЗЕМЕТЕ/ПУБЛИКУВАЙТЕ | Псевдоними на модели |
| `/api/models/catalog` | ВЗЕМЕТЕ | Всички модели по доставчик + тип |
| `/api/combos*` | Различни | Комбо управление |
| `/api/keys*` | Различни | Управление на API ключове |
| `/api/pricing` | ВЗЕМЕТЕ | Моделна цена |
### Използване и анализ
| Крайна точка | Метод | Описание |
| --------------------------- | ------- | ----------------------- |
| `/api/usage/history` | ВЗЕМЕТЕ | История на използването |
| `/api/usage/logs` | ВЗЕМЕТЕ | Дневници за използване |
| `/api/usage/request-logs` | ВЗЕМЕТЕ | Дневници на ниво заявка |
| `/api/usage/[connectionId]` | ВЗЕМЕТЕ | Използване на връзка |
### Настройки
| Крайна точка | Метод | Описание |
| ------------------------------- | ------------- | -------------------------------------- |
| `/api/settings` | ВЗЕМИ/ПОСТАВИ | Общи настройки |
| `/api/settings/proxy` | ВЗЕМИ/ПОСТАВИ | Конфигурация на мрежов прокси |
| `/api/settings/proxy/test` | ПУБЛИКАЦИЯ | Тествайте прокси връзката |
| `/api/settings/ip-filter` | ВЗЕМИ/ПОСТАВИ | Списък с разрешени/блокирани IP адреси |
| `/api/settings/thinking-budget` | ВЗЕМИ/ПОСТАВИ | Бюджет на жетон за разсъждение |
| `/api/settings/system-prompt` | ВЗЕМИ/ПОСТАВИ | Глобална системна подкана |
### Мониторинг
| Крайна точка | Метод | Описание |
| ------------------------ | -------------------- | ----------------------------- |
| `/api/sessions` | ВЗЕМЕТЕ | Проследяване на активна сесия |
| `/api/rate-limits` | ВЗЕМЕТЕ | Лимити за лихви по сметка |
| `/api/monitoring/health` | ВЗЕМЕТЕ | Здравна проверка |
| `/api/cache` | ПОЛУЧАВАНЕ/ИЗТРИВАНЕ | Кеш статистики / изчистване |
### Архивиране и експортиране/импортиране
| Крайна точка | Метод | Описание |
| --------------------------- | ---------- | ------------------------------------------------ |
| `/api/db-backups` | ВЗЕМЕТЕ | Избройте наличните резервни копия |
| `/api/db-backups` | ПОСТАВЕТЕ | Създайте ръчно архивиране |
| `/api/db-backups` | ПУБЛИКАЦИЯ | Възстановяване от конкретен архив |
| `/api/db-backups/export` | ВЗЕМЕТЕ | Изтегляне на база данни като .sqlite файл |
| `/api/db-backups/import` | ПУБЛИКАЦИЯ | Качете .sqlite файл, за да замените базата данни |
| `/api/db-backups/exportAll` | ВЗЕМЕТЕ | Изтеглете пълното архивиране като .tar.gz архив |
### Облачно синхронизиране
| Крайна точка | Метод | Описание |
| ---------------------- | ---------- | ---------------------------------- |
| `/api/sync/cloud` | Различни | Операции за синхронизиране в облак |
| `/api/sync/initialize` | ПУБЛИКАЦИЯ | Инициализиране на синхронизиране |
| `/api/cloud/*` | Различни | Облачно управление |
### CLI инструменти
| Крайна точка | Метод | Описание |
| ---------------------------------- | ------- | ---------------------- |
| `/api/cli-tools/claude-settings` | ВЗЕМЕТЕ | Клод CLI състояние |
| `/api/cli-tools/codex-settings` | ВЗЕМЕТЕ | Codex CLI състояние |
| `/api/cli-tools/droid-settings` | ВЗЕМЕТЕ | Droid CLI състояние |
| `/api/cli-tools/openclaw-settings` | ВЗЕМЕТЕ | OpenClaw CLI състояние |
| `/api/cli-tools/runtime/[toolId]` | ВЗЕМЕТЕ | Generic CLI runtime |
CLI отговорите включват: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`.
### Устойчивост и ограничения на скоростта
| Крайна точка | Метод | Описание |
| ----------------------- | ------------- | --------------------------------------------- |
| `/api/resilience` | ВЗЕМИ/ПОСТАВИ | Вземете/актуализирайте профили за устойчивост |
| `/api/resilience/reset` | ПУБЛИКАЦИЯ | Нулиране на прекъсвачи |
| `/api/rate-limits` | ВЗЕМЕТЕ | Състояние на ограничение на лимита по сметка |
| `/api/rate-limit` | ВЗЕМЕТЕ | Конфигурация на глобален лимит на скоростта |
### Оценки
| Крайна точка | Метод | Описание |
| ------------ | -------------------- | --------------------------------------- |
| `/api/evals` | ВЗЕМЕТЕ/ПУБЛИКУВАЙТЕ | Избройте eval пакети / изпълнете оценка |
### Политики
| Крайна точка | Метод | Описание |
| --------------- | -------------------------------- | ----------------------------------------- |
| `/api/policies` | ПОЛУЧАВАНЕ/ПУБЛИКУВАНЕ/ИЗТРИВАНЕ | Управление на правилата за маршрутизиране |
### Съответствие
| Крайна точка | Метод | Описание |
| --------------------------- | ------- | -------------------------------------------------- |
| `/api/compliance/audit-log` | ВЗЕМЕТЕ | Дневник за проверка на съответствието (последно N) |
### v1beta (съвместим с Gemini)
| Крайна точка | Метод | Описание |
| -------------------------- | ---------- | ------------------------------------- |
| `/v1beta/models` | ВЗЕМЕТЕ | Избройте модели във формат Gemini |
| `/v1beta/models/{...path}` | ПУБЛИКАЦИЯ | Gemini `generateContent` крайна точка |
Тези крайни точки отразяват API формата на Gemini за клиенти, които очакват естествена съвместимост с Gemini SDK.
### Вътрешен/системен API
| Крайна точка | Метод | Описание |
| --------------- | ---------- | ------------------------------------------------------------------------------ |
| `/api/init` | ВЗЕМЕТЕ | Проверка за инициализация на приложението (използва се при първото стартиране) |
| `/api/tags` | ВЗЕМЕТЕ | Тагове за модели, съвместими с Ollama (за клиенти на Ollama) |
| `/api/restart` | ПУБЛИКАЦИЯ | Задейства грациозно рестартиране на сървъра |
| `/api/shutdown` | ПУБЛИКАЦИЯ | Задействайте грациозно изключване на сървъра |
> **Забележка:** Тези крайни точки се използват вътрешно от системата или за съвместимост с клиента Ollama. Те обикновено не се извикват от крайните потребители.
---
## Аудио транскрипция
```bash
POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data
```
Транскрибирайте аудио файлове с помощта на Deepgram или AssemblyAI.
**Заявка:**
```bash
curl -X POST http://localhost:20128/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F "file=@recording.mp3" \
-F "model=deepgram/nova-3"
```
**Отговор:**
```json
{
"text": "Hello, this is the transcribed audio content.",
"task": "transcribe",
"language": "en",
"duration": 12.5
}
```
**Поддържани доставчици:** `deepgram/nova-3`, `assemblyai/best`.
**Поддържани формати:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`.
---
## Съвместимост с Ollama
За клиенти, които използват API формат на Ollama:
```bash
# Chat endpoint (Ollama format)
POST /v1/api/chat
# Model listing (Ollama format)
GET /api/tags
```
Заявките се превеждат автоматично между Ollama и вътрешни формати.
---
## Телеметрия
```bash
# Get latency telemetry summary (p50/p95/p99 per provider)
GET /api/telemetry/summary
```
**Отговор:**
```json
{
"providers": {
"claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
"github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
}
}
```
---
## Бюджет
```bash
# Get budget status for all API keys
GET /api/usage/budget
# Set or update a budget
POST /api/usage/budget
Content-Type: application/json
{
"keyId": "key-123",
"limit": 50.00,
"period": "monthly"
}
```
---
## Наличност на модела
```bash
# Get real-time model availability across all providers
GET /api/models/availability
# Check availability for a specific model
POST /api/models/availability
Content-Type: application/json
{
"model": "claude-sonnet-4-5-20250929"
}
```
---
## Обработка на заявка
1. Клиентът изпраща заявка до `/v1/*`
2. Обработчикът на маршрута извиква `handleChat`, `handleEmbedding`, `handleAudioTranscription` или `handleImageGeneration`
3. Моделът е разрешен (директен доставчик/модел или псевдоним/комбо)
4. Идентификационни данни, избрани от локална база данни с филтриране на наличността на акаунта
5. За чат: `handleChatCore` — откриване на формат, превод, проверка на кеша, проверка на идемпотентност
6. Изпълнителят на доставчика изпраща заявка нагоре по веригата
7. Отговор, преведен обратно във формат на клиента (чат) или върнат такъв, какъвто е (вграждания/изображения/аудио)
8. Записано използване/регистриране
9. Резервният вариант се прилага при грешки според комбо правилата
Пълна справка за архитектурата: [link](ARCHITECTURE.md)
---
## Удостоверяване
- Маршрутите на таблото за управление (`/dashboard/*`) използват бисквитка `auth_token`
- Входът използва запазен хеш на паролата; връщане към `INITIAL_PASSWORD`
- `requireLogin` превключваем чрез `/api/settings/require-login`
- `/v1/*` маршрутите по избор изискват Bearer API ключ, когато `REQUIRE_API_KEY=true`
-781
View File
@@ -1,781 +0,0 @@
# Архитектура OmniRoute
🌐 **Languages:** 🇺🇸 [English](../../ARCHITECTURE.md) | 🇧🇷 [Português (Brasil)](../pt-BR/ARCHITECTURE.md) | 🇪🇸 [Español](../es/ARCHITECTURE.md) | 🇫🇷 [Français](../fr/ARCHITECTURE.md) | 🇮🇹 [Italiano](../it/ARCHITECTURE.md) | 🇷🇺 [Русский](../ru/ARCHITECTURE.md) | 🇨🇳 [中文 (简体)](../zh-CN/ARCHITECTURE.md) | 🇩🇪 [Deutsch](../de/ARCHITECTURE.md) | 🇮🇳 [हिन्दी](../in/ARCHITECTURE.md) | 🇹🇭 [ไทย](../th/ARCHITECTURE.md) | 🇺🇦 [Українська](../uk-UA/ARCHITECTURE.md) | 🇸🇦 [العربية](../ar/ARCHITECTURE.md) | 🇯🇵 [日本語](../ja/ARCHITECTURE.md) | 🇻🇳 [Tiếng Việt](../vi/ARCHITECTURE.md) | 🇧🇬 [Български](../bg/ARCHITECTURE.md) | 🇩🇰 [Dansk](../da/ARCHITECTURE.md) | 🇫🇮 [Suomi](../fi/ARCHITECTURE.md) | 🇮🇱 [עברית](../he/ARCHITECTURE.md) | 🇭🇺 [Magyar](../hu/ARCHITECTURE.md) | 🇮🇩 [Bahasa Indonesia](../id/ARCHITECTURE.md) | 🇰🇷 [한국어](../ko/ARCHITECTURE.md) | 🇲🇾 [Bahasa Melayu](../ms/ARCHITECTURE.md) | 🇳🇱 [Nederlands](../nl/ARCHITECTURE.md) | 🇳🇴 [Norsk](../no/ARCHITECTURE.md) | 🇵🇹 [Português (Portugal)](../pt/ARCHITECTURE.md) | 🇷🇴 [Română](../ro/ARCHITECTURE.md) | 🇵🇱 [Polski](../pl/ARCHITECTURE.md) | 🇸🇰 [Slovenčina](../sk/ARCHITECTURE.md) | 🇸🇪 [Svenska](../sv/ARCHITECTURE.md) | 🇵🇭 [Filipino](../phi/ARCHITECTURE.md)
_Последна актуализация: 2026-02-18_
## Резюме
OmniRoute е локален AI маршрутизиращ шлюз и табло за управление, изградено на Next.js.
Той осигурява една крайна точка, съвместима с OpenAI (`/v1/*`) и маршрутизира трафика през множество доставчици нагоре по веригата с превод, резервен вариант, опресняване на токени и проследяване на използването.
Основни възможности:
- OpenAI-съвместима API повърхност за CLI/инструменти (28 доставчици)
- Превод на заявка/отговор във форматите на доставчика
- Резервна комбинация от модели (последователност от няколко модела)
- Резервен вариант на ниво акаунт (мулти акаунт на доставчик)
- OAuth + API-ключ управление на връзката на доставчика
- Генериране на вграждане чрез `/v1/embeddings` (6 доставчика, 9 модела)
- Генериране на изображения чрез `/v1/images/generations` (4 доставчика, 9 модела)
- Мислен синтактичен анализ на етикет (`<think>...</think>`) за модели на разсъждение
- Дезинфекция на отговора за стриктна съвместимост с OpenAI SDK
- Нормализиране на ролята (разработчик→система, система→потребител) за съвместимост между доставчици
- Структурирано преобразуване на изход (json_schema → Gemini responseSchema)
- Локална устойчивост за доставчици, ключове, псевдоними, комбинации, настройки, ценообразуване
- Проследяване на използване/разходи и регистриране на заявки
- Допълнителна облачна синхронизация за синхронизиране на множество устройства/състояние
- Списък с разрешени/блокирани IP адреси за контрол на достъпа до API
- Мислещо управление на бюджета (преминаване/автоматично/персонализирано/адаптивно)
- Бързо инжектиране на глобалната система
- Проследяване на сесии и пръстови отпечатъци
- Подобрено ограничаване на скоростта за всеки акаунт със специфични за доставчика профили
- Модел на прекъсвача за устойчивост на доставчика
- Анти-гръмотевична стадна защита с mutex заключване
- Кеш за дедупликация на заявки, базиран на подпис
- Слой на домейна: наличност на модела, правила за разходите, резервна политика, политика за блокиране
- Устойчивост на състоянието на домейна (кеш за запис на SQLite за резервни варианти, бюджети, блокировки, прекъсвачи на верига)
- Механизъм за правила за централизирана оценка на заявката (заключване → бюджет → резервен)
- Заявка за телеметрия с p50/p95/p99 агрегиране на латентност
- ID на корелация (X-Request-Id) за проследяване от край до край
- Регистриране на одит за съответствие с отказ за всеки API ключ
- Eval framework за осигуряване на качеството на LLM
- Resilience UI табло със статус на прекъсвача в реално време
- Модулни OAuth доставчици (12 отделни модула под `src/lib/oauth/providers/`)
Основен модел на изпълнение:
- Маршрутите на приложението Next.js под `src/app/api/*` прилагат както API на таблото за управление, така и API за съвместимост
- Споделено SSE/маршрутизиращо ядро в `src/sse/*` + `open-sse/*` обработва изпълнението на доставчика, превода, стрийминг, резервен вариант и използване
## Обхват и граници
### В обхват
- Време за изпълнение на локален шлюз
- API за управление на таблото
- Удостоверяване на доставчика и опресняване на токена
- Заявка за превод и SSE стрийминг
- Локално състояние + постоянство на използване
- Допълнителна синхронизация в облака
### Извън обхвата
- Внедряване на облачна услуга зад `NEXT_PUBLIC_CLOUD_URL`
- SLA/контролна равнина на доставчика извън локалния процес
- Самите външни CLI двоични файлове (Claude CLI, Codex CLI и т.н.)
## Системен контекст на високо ниво
```mermaid
flowchart LR
subgraph Clients[Developer Clients]
C1[Claude Code]
C2[Codex CLI]
C3[OpenClaw / Droid / Cline / Continue / Roo]
C4[Custom OpenAI-compatible clients]
BROWSER[Browser Dashboard]
end
subgraph Router[OmniRoute Local Process]
API[V1 Compatibility API\n/v1/*]
DASH[Dashboard + Management API\n/api/*]
CORE[SSE + Translation Core\nopen-sse + src/sse]
DB[(db.json)]
UDB[(usage.json + log.txt)]
end
subgraph Upstreams[Upstream Providers]
P1[OAuth Providers\nClaude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity]
P2[API Key Providers\nOpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax\nDeepSeek/Groq/xAI/Mistral/Perplexity\nTogether/Fireworks/Cerebras/Cohere/NVIDIA]
P3[Compatible Nodes\nOpenAI-compatible / Anthropic-compatible]
end
subgraph Cloud[Optional Cloud Sync]
CLOUD[Cloud Sync Endpoint\nNEXT_PUBLIC_CLOUD_URL]
end
C1 --> API
C2 --> API
C3 --> API
C4 --> API
BROWSER --> DASH
API --> CORE
DASH --> DB
CORE --> DB
CORE --> UDB
CORE --> P1
CORE --> P2
CORE --> P3
DASH --> CLOUD
```
## Основни компоненти по време на изпълнение
## 1) API и слой за маршрутизиране (Маршрути на приложението Next.js)
Основни директории:
- `src/app/api/v1/*` и `src/app/api/v1beta/*` за API за съвместимост
- `src/app/api/*` за API за управление/конфигуриране
- Следващото пренаписване в `next.config.mjs` преобразува `/v1/*` в `/api/v1/*`
Важни пътища за съвместимост:
- `src/app/api/v1/chat/completions/route.ts`
- `src/app/api/v1/messages/route.ts`
- `src/app/api/v1/responses/route.ts`
- `src/app/api/v1/models/route.ts` — включва потребителски модели с `custom: true`
- `src/app/api/v1/embeddings/route.ts` — генериране на вграждане (6 доставчика)
- `src/app/api/v1/images/generations/route.ts` — генериране на изображения (4+ доставчици, вкл. Antigravity/Nebius)
- `src/app/api/v1/messages/count_tokens/route.ts`
- `src/app/api/v1/providers/[provider]/chat/completions/route.ts` — специален чат за всеки доставчик
- `src/app/api/v1/providers/[provider]/embeddings/route.ts` — специални вграждания за всеки доставчик
- `src/app/api/v1/providers/[provider]/images/generations/route.ts` — специални изображения за всеки доставчик
- `src/app/api/v1beta/models/route.ts`
- `src/app/api/v1beta/models/[...path]/route.ts`
Домейни за управление:
- Удостоверяване/настройки: `src/app/api/auth/*`, `src/app/api/settings/*`
- Доставчици/връзки: `src/app/api/providers*`
- Възли на доставчик: `src/app/api/provider-nodes*`
- Персонализирани модели: `src/app/api/provider-models` (GET/POST/DELETE)
- Каталог с модели: `src/app/api/models/catalog` (GET)
- Прокси конфигурация: `src/app/api/settings/proxy` (GET/PUT/DELETE) + `src/app/api/settings/proxy/test` (POST)
- OAuth: `src/app/api/oauth/*`
- Ключове/псевдоними/комбота/цени: `src/app/api/keys*`, `src/app/api/models/alias`, `src/app/api/combos*`, `src/app/api/pricing`
- Използване: `src/app/api/usage/*`
- Синхронизиране/облак: `src/app/api/sync/*`, `src/app/api/cloud/*`
- Помощни инструменти за CLI: `src/app/api/cli-tools/*`
- IP филтър: `src/app/api/settings/ip-filter` (GET/PUT)
- Бюджет за мислене: `src/app/api/settings/thinking-budget` (GET/PUT)
- Системна подкана: `src/app/api/settings/system-prompt` (GET/PUT)
- Сесии: `src/app/api/sessions` (GET)
- Ограничения на скоростта: `src/app/api/rate-limits` (GET)
- Устойчивост: `src/app/api/resilience` (GET/PATCH) — профили на доставчик, прекъсвач, състояние на ограничение на скоростта
- Нулиране на устойчивостта: `src/app/api/resilience/reset` (POST) — нулиране на прекъсвачи + охлаждане
- Кеш статистики: `src/app/api/cache/stats` (ПОЛУЧАВАНЕ/ИЗТРИВАНЕ)
- Наличност на модела: `src/app/api/models/availability` (GET/POST)
- Телеметрия: `src/app/api/telemetry/summary` (GET)
- Бюджет: `src/app/api/usage/budget` (GET/POST)
- Резервни вериги: `src/app/api/fallback/chains` (GET/POST/DELETE)
- Одит за съответствие: `src/app/api/compliance/audit-log` (GET)
- Стойности: `src/app/api/evals` (GET/POST), `src/app/api/evals/[suiteId]` (GET)
- Правила: `src/app/api/policies` (GET/POST)
## 2) SSE + ядро за превод
Основни модули на потока:
- Запис: `src/sse/handlers/chat.ts`
- Основна оркестрация: `open-sse/handlers/chatCore.ts`
- Адаптери за изпълнение на доставчика: `open-sse/executors/*`
- Откриване на формат/конфигурация на доставчика: `open-sse/services/provider.ts`
- Разбор/разрешаване на модела: `src/sse/services/model.ts`, `open-sse/services/model.ts`
- Резервна логика на акаунта: `open-sse/services/accountFallback.ts`
- Регистър на преводите: `open-sse/translator/index.ts`
- Трансформации на потока: `open-sse/utils/stream.ts`, `open-sse/utils/streamHandler.ts`
- Извличане/нормализиране на използването: `open-sse/utils/usageTracking.ts`
- Мислен анализатор на етикети: `open-sse/utils/thinkTagParser.ts`
- Манипулатор за вграждане: `open-sse/handlers/embeddings.ts`
- Регистър на доставчика на вграждане: `open-sse/config/embeddingRegistry.ts`
- Манипулатор за генериране на изображения: `open-sse/handlers/imageGeneration.ts`
- Регистър на доставчика на изображения: `open-sse/config/imageRegistry.ts`
- Саниране на отговора: `open-sse/handlers/responseSanitizer.ts`
- Нормализация на ролята: `open-sse/services/roleNormalizer.ts`
Услуги (бизнес логика):
- Избор/точкуване на акаунт: `open-sse/services/accountSelector.ts`
- Управление на жизнения цикъл на контекста: `open-sse/services/contextManager.ts`
- Налагане на IP филтър: `open-sse/services/ipFilter.ts`
- Проследяване на сесии: `open-sse/services/sessionManager.ts`
- Искане за дедупликация: `open-sse/services/signatureCache.ts`
- Системно бързо инжектиране: `open-sse/services/systemPrompt.ts`
- Мислещо управление на бюджета: `open-sse/services/thinkingBudget.ts`
- Маршрутизиране на модела със заместващи знаци: `open-sse/services/wildcardRouter.ts`
- Управление на лимита на скоростта: `open-sse/services/rateLimitManager.ts`
- Прекъсвач: `open-sse/services/circuitBreaker.ts`
Модули на ниво домейн:
- Наличност на модела: `src/lib/domain/modelAvailability.ts`
- Правила/бюджети за разходите: `src/lib/domain/costRules.ts`
- Резервна политика: `src/lib/domain/fallbackPolicy.ts`
- Комбо резолвер: `src/lib/domain/comboResolver.ts`
- Правила за блокиране: `src/lib/domain/lockoutPolicy.ts`
- Механизъм за правила: `src/domain/policyEngine.ts` — централизирано блокиране → бюджет → резервна оценка
- Каталог с кодове за грешки: `src/lib/domain/errorCodes.ts`
- ID на заявката: `src/lib/domain/requestId.ts`
- Време за изчакване на извличане: `src/lib/domain/fetchTimeout.ts`
- Заявка за телеметрия: `src/lib/domain/requestTelemetry.ts`
- Съответствие/одит: `src/lib/domain/compliance/index.ts`
- Евал бегач: `src/lib/domain/evalRunner.ts`
- Устойчивост на състоянието на домейна: `src/lib/db/domainState.ts` — SQLite CRUD за резервни вериги, бюджети, история на разходите, състояние на блокиране, прекъсвачи
Модули за доставчик на OAuth (12 отделни файла под `src/lib/oauth/providers/`):
- Индекс на регистъра: `src/lib/oauth/providers/index.ts`
- Индивидуални доставчици: `claude.ts`, `codex.ts`, `gemini.ts`, `antigravity.ts`, `iflow.ts`, `qwen.ts`, `kimi-coding.ts`, `github.ts`, `kiro.ts`, `cursor.ts`, `kilocode.ts`, `cline.ts`
- Тънка обвивка: `src/lib/oauth/providers.ts` — повторно експортиране от отделни модули
## 3) Слой за устойчивост
Основно състояние DB:
- `src/lib/localDb.ts`
- файл: `${DATA_DIR}/db.json` (или `$XDG_CONFIG_HOME/omniroute/db.json`, когато е зададено, в противен случай `~/.omniroute/db.json`)
- обекти: providerConnections, providerNodes, modelAliases, комбинации, apiKeys, настройки, ценообразуване, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
DB за използване:
- `src/lib/usageDb.ts`
- файлове: `${DATA_DIR}/usage.json`, `${DATA_DIR}/log.txt`, `${DATA_DIR}/call_logs/`
- следва същата основна политика за директория като `localDb` (`DATA_DIR`, след това `XDG_CONFIG_HOME/omniroute`, когато е зададено)
- разложен на фокусирани подмодули: `migrations.ts`, `usageHistory.ts`, `costCalculator.ts`, `usageStats.ts`, `callLogs.ts`
DB на състоянието на домейна (SQLite):
- `src/lib/db/domainState.ts` — CRUD операции за състояние на домейна
- Таблици (създадени в `src/lib/db/core.ts`): `domain_fallback_chains`, `domain_budgets`, `domain_cost_history`, `domain_lockout_state`, `domain_circuit_breakers`
- Модел на кеша за запис: Картите в паметта са авторитетни по време на изпълнение; мутациите се записват синхронно в SQLite; състоянието се възстановява от DB при студен старт
## 4) Удостоверяване + повърхности за сигурност
- Удостоверяване на бисквитките на таблото за управление: `src/proxy.ts`, `src/app/api/auth/login/route.ts`
- Генериране/проверка на API ключ: `src/shared/utils/apiKey.ts`
- Тайните на доставчика се запазват в `providerConnections` записи
- Поддръжка на изходящ прокси чрез `open-sse/utils/proxyFetch.ts` (env vars) и `open-sse/utils/networkProxy.ts` (конфигурируем за всеки доставчик или глобално)
## 5) Синхронизиране в облак
- Инициализация на планировчика: `src/lib/initCloudSync.ts`, `src/shared/services/initializeCloudSync.ts`
- Периодична задача: `src/shared/services/cloudSyncScheduler.ts`
- Контролен маршрут: `src/app/api/sync/cloud/route.ts`
## Жизнен цикъл на заявка (`/v1/chat/completions`)
```mermaid
sequenceDiagram
autonumber
participant Client as CLI/SDK Client
participant Route as /api/v1/chat/completions
participant Chat as src/sse/handlers/chat
participant Core as open-sse/handlers/chatCore
participant Model as Model Resolver
participant Auth as Credential Selector
participant Exec as Provider Executor
participant Prov as Upstream Provider
participant Stream as Stream Translator
participant Usage as usageDb
Client->>Route: POST /v1/chat/completions
Route->>Chat: handleChat(request)
Chat->>Model: parse/resolve model or combo
alt Combo model
Chat->>Chat: iterate combo models (handleComboChat)
end
Chat->>Auth: getProviderCredentials(provider)
Auth-->>Chat: active account + tokens/api key
Chat->>Core: handleChatCore(body, modelInfo, credentials)
Core->>Core: detect source format
Core->>Core: translate request to target format
Core->>Exec: execute(provider, transformedBody)
Exec->>Prov: upstream API call
Prov-->>Exec: SSE/JSON response
Exec-->>Core: response + metadata
alt 401/403
Core->>Exec: refreshCredentials()
Exec-->>Core: updated tokens
Core->>Exec: retry request
end
Core->>Stream: translate/normalize stream to client format
Stream-->>Client: SSE chunks / JSON response
Stream->>Usage: extract usage + persist history/log
```
## Комбо + Резервен поток на акаунт
```mermaid
flowchart TD
A[Incoming model string] --> B{Is combo name?}
B -- Yes --> C[Load combo models sequence]
B -- No --> D[Single model path]
C --> E[Try model N]
E --> F[Resolve provider/model]
D --> F
F --> G[Select account credentials]
G --> H{Credentials available?}
H -- No --> I[Return provider unavailable]
H -- Yes --> J[Execute request]
J --> K{Success?}
K -- Yes --> L[Return response]
K -- No --> M{Fallback-eligible error?}
M -- No --> N[Return error]
M -- Yes --> O[Mark account unavailable cooldown]
O --> P{Another account for provider?}
P -- Yes --> G
P -- No --> Q{In combo with next model?}
Q -- Yes --> E
Q -- No --> R[Return all unavailable]
```
Резервните решения се управляват от `open-sse/services/accountFallback.ts` с помощта на кодове за състояние и евристика за съобщения за грешка.
## Жизнен цикъл на внедряване на OAuth и опресняване на токени
```mermaid
sequenceDiagram
autonumber
participant UI as Dashboard UI
participant OAuth as /api/oauth/[provider]/[action]
participant ProvAuth as Provider Auth Server
participant DB as localDb
participant Test as /api/providers/[id]/test
participant Exec as Provider Executor
UI->>OAuth: GET authorize or device-code
OAuth->>ProvAuth: create auth/device flow
ProvAuth-->>OAuth: auth URL or device code payload
OAuth-->>UI: flow data
UI->>OAuth: POST exchange or poll
OAuth->>ProvAuth: token exchange/poll
ProvAuth-->>OAuth: access/refresh tokens
OAuth->>DB: createProviderConnection(oauth data)
OAuth-->>UI: success + connection id
UI->>Test: POST /api/providers/[id]/test
Test->>Exec: validate credentials / optional refresh
Exec-->>Test: valid or refreshed token info
Test->>DB: update status/tokens/errors
Test-->>UI: validation result
```
Опресняването по време на трафик на живо се изпълнява вътре в `open-sse/handlers/chatCore.ts` чрез изпълнител `refreshCredentials()`.
## Жизнен цикъл на Cloud Sync (Активиране / Синхронизиране / Деактивиране)
```mermaid
sequenceDiagram
autonumber
participant UI as Endpoint Page UI
participant Sync as /api/sync/cloud
participant DB as localDb
participant Cloud as External Cloud Sync
participant Claude as ~/.claude/settings.json
UI->>Sync: POST action=enable
Sync->>DB: set cloudEnabled=true
Sync->>DB: ensure API key exists
Sync->>Cloud: POST /sync/{machineId} (providers/aliases/combos/keys)
Cloud-->>Sync: sync result
Sync->>Cloud: GET /{machineId}/v1/verify
Sync-->>UI: enabled + verification status
UI->>Sync: POST action=sync
Sync->>Cloud: POST /sync/{machineId}
Cloud-->>Sync: remote data
Sync->>DB: update newer local tokens/status
Sync-->>UI: synced
UI->>Sync: POST action=disable
Sync->>DB: set cloudEnabled=false
Sync->>Cloud: DELETE /sync/{machineId}
Sync->>Claude: switch ANTHROPIC_BASE_URL back to local (if needed)
Sync-->>UI: disabled
```
Периодичното синхронизиране се задейства от `CloudSyncScheduler`, когато облакът е активиран.
## Модел на данни и карта за съхранение
```mermaid
erDiagram
SETTINGS ||--o{ PROVIDER_CONNECTION : controls
PROVIDER_NODE ||--o{ PROVIDER_CONNECTION : backs_compatible_provider
PROVIDER_CONNECTION ||--o{ USAGE_ENTRY : emits_usage
SETTINGS {
boolean cloudEnabled
number stickyRoundRobinLimit
boolean requireLogin
string password_hash
string fallbackStrategy
json rateLimitDefaults
json providerProfiles
}
PROVIDER_CONNECTION {
string id
string provider
string authType
string name
number priority
boolean isActive
string apiKey
string accessToken
string refreshToken
string expiresAt
string testStatus
string lastError
string rateLimitedUntil
json providerSpecificData
}
PROVIDER_NODE {
string id
string type
string name
string prefix
string apiType
string baseUrl
}
MODEL_ALIAS {
string alias
string targetModel
}
COMBO {
string id
string name
string[] models
}
API_KEY {
string id
string name
string key
string machineId
}
USAGE_ENTRY {
string provider
string model
number prompt_tokens
number completion_tokens
string connectionId
string timestamp
}
CUSTOM_MODEL {
string id
string name
string providerId
}
PROXY_CONFIG {
string global
json providers
}
IP_FILTER {
string mode
string[] allowlist
string[] blocklist
}
THINKING_BUDGET {
string mode
number customBudget
string effortLevel
}
SYSTEM_PROMPT {
boolean enabled
string prompt
string position
}
```
Файлове за физическо съхранение:
- основно състояние: `${DATA_DIR}/db.json` (или `$XDG_CONFIG_HOME/omniroute/db.json`, когато е зададено, в противен случай `~/.omniroute/db.json`)
- статистика за използване: `${DATA_DIR}/usage.json`
- Редове на заявката: `${DATA_DIR}/log.txt`
- незадължителни сесии за преводач/заявка за отстраняване на грешки: `<repo>/logs/...`
## Топология на разполагане
```mermaid
flowchart LR
subgraph LocalHost[Developer Host]
CLI[CLI Tools]
Browser[Dashboard Browser]
end
subgraph ContainerOrProcess[OmniRoute Runtime]
Next[Next.js Server\nPORT=20128]
Core[SSE Core + Executors]
MainDB[(db.json)]
UsageDB[(usage.json/log.txt)]
end
subgraph External[External Services]
Providers[AI Providers]
SyncCloud[Cloud Sync Service]
end
CLI --> Next
Browser --> Next
Next --> Core
Next --> MainDB
Core --> MainDB
Core --> UsageDB
Core --> Providers
Next --> SyncCloud
```
## Съпоставяне на модул (критично за вземане на решения)
### Модули за маршрут и API
- `src/app/api/v1/*`, `src/app/api/v1beta/*`: API за съвместимост
- `src/app/api/v1/providers/[provider]/*`: специални маршрути за всеки доставчик (чат, вграждания, изображения)
- `src/app/api/providers*`: доставчик CRUD, валидиране, тестване
- `src/app/api/provider-nodes*`: персонализирано съвместимо управление на възли
- `src/app/api/provider-models`: персонализирано управление на модела (CRUD)
- `src/app/api/models/catalog`: пълен модел каталог API (всички типове групирани по доставчик)
- `src/app/api/oauth/*`: OAuth/код на устройство протича
- `src/app/api/keys*`: жизнен цикъл на локален API ключ
- `src/app/api/models/alias`: управление на псевдоними
- `src/app/api/combos*`: резервно комбо управление
- `src/app/api/pricing`: ценообразуване отменя за изчисляване на разходите
- `src/app/api/settings/proxy`: конфигурация на прокси (GET/PUT/DELETE)
- `src/app/api/settings/proxy/test`: тест за изходяща прокси връзка (POST)
- `src/app/api/usage/*`: API за използване и регистрационни файлове
- `src/app/api/sync/*` + `src/app/api/cloud/*`: облачно синхронизиране и помощници в облака
- `src/app/api/cli-tools/*`: локални писатели/контролери на CLI конфигурация
- `src/app/api/settings/ip-filter`: списък с разрешени/блокирани IP адреси (GET/PUT)
- `src/app/api/settings/thinking-budget`: конфигурация на бюджета на мислещ токен (GET/PUT)
- `src/app/api/settings/system-prompt`: глобална системна подкана (GET/PUT)
- `src/app/api/sessions`: списък с активни сесии (GET)
- `src/app/api/rate-limits`: състояние на ограничение на скоростта на сметка (GET)
### Ядро за маршрутизиране и изпълнение
- `src/sse/handlers/chat.ts`: анализ на заявка, комбо обработка, цикъл за избор на акаунт
- `open-sse/handlers/chatCore.ts`: превод, изпращане на изпълнителя, обработка на повторен опит/опресняване, настройка на потока
- `open-sse/executors/*`: специфично за доставчика поведение на мрежата и формата
### Регистър за преводи и конвертори на формати
- `open-sse/translator/index.ts`: регистър на преводача и оркестрация
- Заявка за преводачи: `open-sse/translator/request/*`
- Преводачи на отговори: `open-sse/translator/response/*`
- Константи на формата: `open-sse/translator/formats.ts`
### Постоянство
- `src/lib/localDb.ts`: постоянна конфигурация/състояние
- `src/lib/usageDb.ts`: хронология на използването и регистрационни файлове на текущи заявки
## Покритие на изпълнител на доставчик (стратегически модел)
Всеки доставчик има специализиран изпълнител, разширяващ `BaseExecutor``open-sse/executors/base.ts`), който осигурява изграждане на URL адрес, изграждане на заглавка, повторен опит с експоненциално забавяне, кукички за опресняване на идентификационни данни и метода за оркестрация `execute()`.
| Изпълнител | Доставчик(и) | Специална обработка |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| `DefaultExecutor` | OpenAI, Claude, Gemini, Qwen, iFlow, OpenRouter, GLM, Kimi, MiniMax, DeepSeek, Groq, xAI, Mistral, Perplexity, Together, Fireworks, Cerebras, Cohere, NVIDIA | Конфигурация на динамичен URL/заглавие за доставчик |
| `AntigravityExecutor` | Google Антигравитация | Идентификационни номера на персонализирани проекти/сесии, повторен опит след анализ |
| `CodexExecutor` | OpenAI Codex | Вкарва системни инструкции, налага усилие за разсъждение |
| `CursorExecutor` | Курсор IDE | ConnectRPC протокол, Protobuf кодиране, подписване на заявка чрез контролна сума |
| `GithubExecutor` | Копилот на GitHub | Опресняване на Copilot token, заглавки, имитиращи VSCode |
| `KiroExecutor` | AWS CodeWhisperer/Киро | AWS EventStream двоичен формат → SSE конвертиране |
| `GeminiCLIExecutor` | Gemini CLI | Цикъл на опресняване на Google OAuth токен |
Всички други доставчици (включително персонализирани съвместими възли) използват `DefaultExecutor`.
## Матрица за съвместимост на доставчика
| Доставчик | Формат | Удостоверяване | Поток | Непоточно | Опресняване на токена | API за използване |
| ----------------- | --------------- | ------------------------------ | ---------------- | --------- | --------------------- | ---------------------------- |
| Клод | Клод | API ключ / OAuth | ✅ | ✅ | ✅ | ⚠️ Само администратор |
| Близнаци | близнаци | API ключ / OAuth | ✅ | ✅ | ✅ | ⚠️ Облачна конзола |
| Gemini CLI | gemini-cli | OAuth | ✅ | ✅ | ✅ | ⚠️ Облачна конзола |
| Антигравитация | антигравитация | OAuth | ✅ | ✅ | ✅ | ✅ API с пълна квота |
| OpenAI | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Кодекс | openai-отговори | OAuth | ✅ принуден | ❌ | ✅ | ✅ Ограничения на скоростта |
| Копилот на GitHub | openai | OAuth + Copilot Token | ✅ | ✅ | ✅ | ✅ Моментни снимки на квоти |
| Курсор | курсор | Персонализирана контролна сума | ✅ | ✅ | ❌ | ❌ |
| Киро | киро | AWS SSO OIDC | ✅ (EventStream) | ❌ | ✅ | ✅ Ограничения за използване |
| Куен | openai | OAuth | ✅ | ✅ | ✅ | ⚠️ По заявка |
| iFlow | openai | OAuth (основен) | ✅ | ✅ | ✅ | ⚠️ По заявка |
| OpenRouter | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| GLM/Кими/МиниМакс | Клод | API ключ | ✅ | ✅ | ❌ | ❌ |
| DeepSeek | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Groq | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| xAI (Grok) | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Мистрал | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Недоумение | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Заедно AI | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Фойерверки AI | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Мозъци | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| Cohere | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
| NVIDIA NIM | openai | API ключ | ✅ | ✅ | ❌ | ❌ |
## Обхват на превод на формат
Откритите изходни формати включват:
- `openai`
- `openai-responses`
- `claude`
- `gemini`
Целевите формати включват:
- OpenAI чат/Отговори
- Клод
- Gemini/Gemini-CLI/Антигравитационен плик
- Киро
- Курсор
Преводите използват **OpenAI като хъб формат** — всички реализации преминават през OpenAI като междинен:
```
Source Format → OpenAI (hub) → Target Format
```
Преводите се избират динамично въз основа на формата на изходния полезен товар и целевия формат на доставчика.
Допълнителни слоеве за обработка в тръбопровода за превод:
- **Дефектификация на отговора** — Премахва нестандартните полета от отговорите във формат OpenAI (както стрийминг, така и без стрийминг), за да се гарантира стриктно съответствие с SDK
- **Нормализиране на ролята** — Преобразува `developer``system` за цели, които не са OpenAI; обединява `system``user` за модели, които отхвърлят системната роля (GLM, ERNIE)
- **Извличане на мислен етикет** — Анализира `<think>...</think>` блокове от съдържание в поле `reasoning_content`
- **Структуриран изход** — Преобразува OpenAI `response_format.json_schema` в `responseMimeType` + `responseSchema` на Gemini
## Поддържани API крайни точки
| Крайна точка | Формат | Манипулатор |
| -------------------------------------------------- | ------------------------- | ------------------------------------------------------------------ |
| `POST /v1/chat/completions` | OpenAI чат | `src/sse/handlers/chat.ts` |
| `POST /v1/messages` | Съобщения на Клод | Същият манипулатор (автоматично разпознат) |
| `POST /v1/responses` | OpenAI отговори | `open-sse/handlers/responsesHandler.ts` |
| `POST /v1/embeddings` | OpenAI вграждания | `open-sse/handlers/embeddings.ts` |
| `GET /v1/embeddings` | Списък на модели | API маршрут |
| `POST /v1/images/generations` | OpenAI изображения | `open-sse/handlers/imageGeneration.ts` |
| `GET /v1/images/generations` | Списък на модели | API маршрут |
| `POST /v1/providers/{provider}/chat/completions` | OpenAI чат | Специализиран за всеки доставчик с валидиране на модел |
| `POST /v1/providers/{provider}/embeddings` | OpenAI вграждания | Специализиран за всеки доставчик с валидиране на модел |
| `POST /v1/providers/{provider}/images/generations` | OpenAI изображения | Специализиран за всеки доставчик с валидиране на модел |
| `POST /v1/messages/count_tokens` | Клод Токен Брой | API маршрут |
| `GET /v1/models` | Списък с модели на OpenAI | API маршрут (чат + вграждане + изображение + потребителски модели) |
| `GET /api/models/catalog` | Каталог | Всички модели, групирани по доставчик + тип |
| `POST /v1beta/models/*:streamGenerateContent` | Родом от Близнаци | API маршрут |
| `GET/PUT/DELETE /api/settings/proxy` | Прокси конфигурация | Конфигурация на мрежов прокси |
| `POST /api/settings/proxy/test` | Прокси връзка | Крайна точка на прокси тест за изправност/свързаност |
| `GET/POST/DELETE /api/provider-models` | Персонализирани модели | Персонализирано управление на модели за всеки доставчик |
## Обходен манипулатор
Обходният манипулатор (`open-sse/utils/bypassHandler.ts`) прихваща известни заявки за „изхвърляне“ от Claude CLI — пингове за загряване, извличане на заглавия и преброяване на токени — и връща **фалшив отговор**, без да консумира токени на доставчика нагоре по веригата. Това се задейства само когато `User-Agent` съдържа `claude-cli`.
## Тръбопровод за регистратор на заявки
Регистраторът на заявки (`open-sse/utils/requestLogger.ts`) осигурява 7-етапен конвейер за регистриране на грешки, деактивиран по подразбиране, активиран чрез `ENABLE_REQUEST_LOGS=true`:
```
1_req_client.json → 2_req_source.json → 3_req_openai.json → 4_req_target.json
→ 5_res_provider.txt → 6_res_openai.txt → 7_res_client.txt
```
Файловете се записват в `<repo>/logs/<session>/` за всяка сесия на заявка.
## Режими на отказ и устойчивост
## 1) Наличност на акаунт/доставчик
- изчакване на акаунта на доставчика при преходни/скоростни/удостоверителни грешки
- резервен акаунт преди неуспешна заявка
- резервен комбиниран модел, когато пътят на текущия модел/доставчик е изчерпан
## 2) Изтичане на токена
- предварителна проверка и опресняване с повторен опит за опресняващи доставчици
- 401/403 повторен опит след опит за опресняване в основния път
## 3) Безопасност на потока
- контролер на потоци, който се изключва
- поток за превод с промиване в края на потока и обработка на `[DONE]`
- резервна оценка на използването, когато липсват метаданни за използване на доставчика
## 4) Влошаване на облачната синхронизация
- появяват се грешки при синхронизиране, но локалното изпълнение продължава
- планировчикът има логика с възможност за повторен опит, но периодичното изпълнение в момента извиква синхронизиране с един опит по подразбиране
## 5) Цялост на данните
- Миграция/поправка на DB форма за липсващи ключове
- повредени предпазни мерки за нулиране на JSON за localDb и usageDb
## Наблюдаемост и оперативни сигнали
Източници на видимост по време на изпълнение:
- регистрационни файлове на конзолата от `src/sse/utils/logger.ts`
- агрегати за използване на заявка в `usage.json`
- влизане на състоянието на текстова заявка `log.txt`
- незадължителни дълбоки регистрационни файлове за заявка/превод под `logs/`, когато `ENABLE_REQUEST_LOGS=true`
- крайни точки за използване на таблото за управление (`/api/usage/*`) за потребление на UI
## Граници, чувствителни към сигурността
- JWT тайна (`JWT_SECRET`) защитава проверката/подписването на бисквитките на таблото за управление
- Първоначалната резервна парола (`INITIAL_PASSWORD`, по подразбиране `123456`) трябва да бъде заменена при реални внедрявания
- API ключ HMAC secret (`API_KEY_SECRET`) защитава генерирания локален формат на API ключ
- Тайните на доставчика (API ключове/токени) се съхраняват в локалната база данни и трябва да бъдат защитени на ниво файлова система
- Крайните точки за синхронизиране в облак разчитат на удостоверяване на API ключ + семантика на идентификатор на машина
## Околна среда и матрица за изпълнение
Променливите на средата, използвани активно от кода:
- Приложение/удостоверяване: `JWT_SECRET`, `INITIAL_PASSWORD`
- Съхранение: `DATA_DIR`
- Съвместимо поведение на възел: `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE`
- Допълнителна отмяна на базата за съхранение (Linux/macOS, когато `DATA_DIR` не е зададен): `XDG_CONFIG_HOME`
- Хеширане на сигурността: `API_KEY_SECRET`, `MACHINE_ID_SALT`
- Регистриране: `ENABLE_REQUEST_LOGS`
- Синхронизиране/облачно URL адресиране: `NEXT_PUBLIC_BASE_URL`, `NEXT_PUBLIC_CLOUD_URL`
- Изходящ прокси: `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY` и варианти с малки букви
- Флагове за функция SOCKS5: `ENABLE_SOCKS5_PROXY`, `NEXT_PUBLIC_ENABLE_SOCKS5_PROXY`
- Помощници за платформа/време на изпълнение (не специфична за приложението конфигурация): `APPDATA`, `NODE_ENV`, `PORT`, `HOSTNAME`
## Известни архитектурни бележки
1. `usageDb` и `localDb` сега споделят една и съща основна политика за директория (`DATA_DIR` -> `XDG_CONFIG_HOME/omniroute` -> `~/.omniroute`) с мигриране на наследени файлове.
2. `/api/v1/route.ts` връща списък със статичен модел и не е основният източник на модели, използван от `/v1/models`.
3. Request logger записва пълни заглавки/тяло, когато е разрешено; третира регистрационната директория като чувствителна.
4. Поведението в облака зависи от правилния `NEXT_PUBLIC_BASE_URL` и достижимостта на крайната точка на облака.
5. Директорията `open-sse/` е публикувана като `@omniroute/open-sse` **npm workspace package**. Изходният код го импортира чрез `@omniroute/open-sse/...` (разрешено от Next.js `transpilePackages`). Пътищата на файловете в този документ все още използват името на директорията `open-sse/` за последователност.
6. Диаграмите в таблото за управление използват **Recharts** (базирани на SVG) за достъпни, интерактивни аналитични визуализации (стълбовидни диаграми на използването на модела, таблици с разбивка на доставчиците с проценти на успех).
7. E2E тестовете използват **Playwright** (`tests/e2e/`), изпълняват се чрез `npm run test:e2e`. Модулните тестове използват **Node.js test runner** (`tests/unit/`), изпълняват се чрез `npm run test:plan3`. Изходният код под `src/` е **TypeScript** (`.ts`/`.tsx`); работното пространство `open-sse/` остава JavaScript (`.js`).
8. Страницата с настройки е организирана в 5 раздела: Сигурност, Маршрутизиране (6 глобални стратегии: първо попълване, кръгъл-робин, p2c, произволна, най-малко използвана, оптимизирана по отношение на разходите), Устойчивост (ограничения на скоростта за редактиране, прекъсвач, политики), AI (мислещ бюджет, системна подкана, кеш за подкана), Разширени (прокси).
## Контролен списък за оперативна проверка
- Създаване от източник: `npm run build`
- Изграждане на Docker изображение: `docker build -t omniroute .`
- Стартирайте услугата и проверете:
- `GET /api/settings`
- `GET /api/v1/models`
- CLI целеви базов URL трябва да бъде `http://<host>:20128/v1`, когато `PORT=20128`

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