Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c86c43f
feat(api-keys): add rename support in permissions modal
andrewmunsell Apr 29, 2026
76d2958
chore(release): bump version to 3.7.6
Apr 30, 2026
f4bd7f9
Merge release/v3.7.6 into emdash/rename-api-keys-45un3
Apr 30, 2026
00926cd
Merge pull request #1796 from emdash/rename-api-keys-45un3
Apr 30, 2026
44d4cb8
chore(release): v3.7.6 — merge API key rename feature and sync docs
Apr 30, 2026
c7df426
chore(release): expand contributor credits to 155 PRs across full pro…
Apr 30, 2026
fc7f71d
fix: resolve security ReDoS in codex and bugs #1797 #1789
Apr 30, 2026
832c912
feat(dashboard): implement remaining v3.7.6 dashboard features and fixes
Apr 30, 2026
dff22ad
fix(xiaomi-mimo): update models to V2.5, fix Token Plan validation an…
Gi99lin Apr 30, 2026
42daf74
fix(dashboard): correct loadPresets ReferenceError in CostOverviewTab
Apr 30, 2026
bc11f63
fix(codex): omit compact client metadata (#1822)
Tr0sT Apr 30, 2026
ef62283
feat(chatgpt-web): support thinking_effort (Standard/Extended) for th…
payne0420 Apr 30, 2026
2bdc72a
Fix endpoint visibility, A2A status, and API catalog (#1806)
rdself Apr 30, 2026
950fdba
fix(analytics): use pure SQL aggregations — no history rows loaded (#…
oyi77 Apr 30, 2026
09b5dee
fix(stability): resolve codex input validation, enable combo circuit …
Apr 30, 2026
285a565
docs(changelog): update for stability bug fixes #1804 #1805
Apr 30, 2026
19df647
fix: clear active requests and recover providers (#1824)
bypanghu Apr 30, 2026
b2572ac
feat: inject fallback tool names to prevent upstream 400 errors (#1775)
Apr 30, 2026
c61ae8d
feat: auto-restore probe-failed database to prevent data loss (#1810)
Apr 30, 2026
5cb9cde
fix: safely cast inputs to strings before calling trim() to avoid cra…
Apr 30, 2026
3207a84
chore(release): v3.7.6 — final stability patches for production
Apr 30, 2026
1d067f3
test: update expected db probe-failure error message for auto-restore…
Apr 30, 2026
6a2fdac
chore(workflow): mandate implementation plan generation in resolve-is…
Apr 30, 2026
486c370
docs(changelog): rewrite v3.7.6 with complete commit-accurate entries
Apr 30, 2026
9d9d177
feat(analytics): add cost-based usage insights and activity streaks
Apr 30, 2026
b5ae2af
fix(mitm): enforce transparent interception on port 443 only
Apr 30, 2026
12b29ba
docs(changelog): update for analytics and mitm features
Apr 30, 2026
f9e1e7f
chore(release): attribute community contributors
Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .agents/workflows/resolve-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ Before coding, perform deep source analysis to formulate a plan:
3. **Read the full source file** — don't rely on grep snippets; understand the surrounding logic
4. **Verify the root cause** — confirm the bug is reproducible based on the code, not just a user misconfiguration
5. **Formulate a proposed solution** — detail the exact files and lines you will change and how you will solve it.
6. **DO NOT modify the codebase yet** — wait for user approval on your report first.
6. **Create an Implementation Plan file** — write your proposed solution to `_tasks/features-vX.Y.Z/<ISSUE_NUMBER>-<short-description>.plan.md` (e.g. `_tasks/features-v3.7.6/1810-auto-restore-probe-failed-db.plan.md`) where `vX.Y.Z` is the current branch version. The plan should contain an Overview, Pre-Implementation Checklist, and detailed Implementation Steps (Files, Changes).
7. **DO NOT modify the codebase yet** — wait for user approval on your report and plan first.

#### 5e. For "RESPOND" Issues

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build-fork.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
with:
ref: fix/claude-thinking-mapping
ref: fix/xiaomi-mimo-provider

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
Expand All @@ -35,7 +35,7 @@ jobs:
platforms: linux/amd64
push: true
tags: |
ghcr.io/inkorcloud/omniroute:fix-claude-thinking-mapping
ghcr.io/inkorcloud/omniroute:latest
ghcr.io/gi99lin/omniroute:fix-xiaomi-mimo-provider
ghcr.io/gi99lin/omniroute:latest
cache-from: type=gha
cache-to: type=gha,mode=max
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ docs/*
!docs/CONTRIBUTING.md
!docs/USER_GUIDE.md
!docs/API_REFERENCE.md
!docs/TERMUX_GUIDE.md
!docs/TROUBLESHOOTING.md
!docs/EXECUTION_CONTEXT_PROVIDER_SYNC.md
!docs/TASK_NEBIUS_BACKEND_ENABLEMENT.md
Expand Down
31 changes: 31 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Dev Server",
"type": "node",
"request": "launch",
"runtimeExecutable": "${env:HOME}/.nvm/versions/node/v22.22.2/bin/node",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The runtimeExecutable path is hardcoded to a specific user's NVM installation and Node.js version. This will not work for other developers with different setups and breaks the portability of this shared configuration.

It's better to remove this line entirely and let VS Code's debugger find the node executable in the system's PATH. Developers can manage their Node.js version using .nvmrc and their shell configuration, which VS Code will respect.

"program": "${workspaceFolder}/scripts/run-next.mjs",
"args": ["dev"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**", "node_modules/**"]
},
{
"name": "Debug Prod Server",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/scripts/run-next.mjs",
"args": ["start"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**", "node_modules/**"]
},
{
"name": "Attach to Running Server",
"type": "node",
"request": "attach",
"port": 9229,
"skipFiles": ["<node_internals>/**", "node_modules/**"]
}
]
}
133 changes: 93 additions & 40 deletions CHANGELOG.md

Large diffs are not rendered by default.

167 changes: 78 additions & 89 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# CLAUDE.md — AI Agent Session Bootstrap
# CLAUDE.md

> Quick-start context for AI coding agents. For deep architecture details, see `AGENTS.md`.
> For contribution workflow, see `CONTRIBUTING.md`.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Quick Start

Expand All @@ -17,55 +16,47 @@ npm run check # lint + test combined
npm run check:cycles # Detect circular dependencies
```

### Running a Single Test
### Running Tests

```bash
# Node.js native test runner (most tests)
node --import tsx/esm --test tests/unit/your-file.test.mjs
# Single test file (Node.js native test runner — most tests)
node --import tsx/esm --test tests/unit/your-file.test.ts

# Vitest (MCP server, autoCombo, cache)
npm run test:vitest

# All suites
npm run test:all
```

For full test matrix, see `CONTRIBUTING.md` → "Running Tests". For deep architecture, see `AGENTS.md`.

---

## Project at a Glance

**OmniRoute** — unified AI proxy/router. One endpoint, 100+ LLM providers, auto-fallback.

| Layer | Location | Purpose |
| --------------- | ------------------------ | ------------------------------------------ |
| API Routes | `src/app/api/v1/` | Next.js App Router — entry points |
| Handlers | `open-sse/handlers/` | Request processing (chat, embeddings, etc) |
| Executors | `open-sse/executors/` | Provider-specific HTTP dispatch |
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
| Database | `src/lib/db/` | SQLite domain modules (22 files) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 25 tools, 3 transports, 10 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
| Skills | `src/lib/skills/` | Extensible skill framework |
| Memory | `src/lib/memory/` | Persistent conversational memory |
| UI Components | `src/shared/components/` | React components (Tailwind CSS v4) |
| Provider Consts | `src/shared/constants/` | Provider registry (Zod-validated) |
| Validation | `src/shared/validation/` | Zod v4 schemas |
| Tests | `tests/` | Unit, integration, e2e, security, load |

### Monorepo Layout

```
OmniRoute/ # Root package
├── src/ # Next.js 16 app (TypeScript)
├── open-sse/ # @omniroute/open-sse workspace (streaming engine)
├── electron/ # Desktop app (Electron)
├── tests/ # All test suites
├── docs/ # Documentation
└── bin/ # CLI entry point
```
**OmniRoute** — unified AI proxy/router. One endpoint, 160+ LLM providers, auto-fallback.

| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------ |
| API Routes | `src/app/api/v1/` | Next.js App Router — entry points |
| Handlers | `open-sse/handlers/` | Request processing (chat, embeddings, etc) |
| Executors | `open-sse/executors/` | Provider-specific HTTP dispatch |
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
| Transformer | `open-sse/transformer/` | Responses API ↔ Chat Completions |
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
| Database | `src/lib/db/` | SQLite domain modules (22 files) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 29 tools, 3 transports, 10 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
| Skills | `src/lib/skills/` | Extensible skill framework |
| Memory | `src/lib/memory/` | Persistent conversational memory |

Monorepo: `src/` (Next.js 16 app), `open-sse/` (streaming engine workspace), `electron/` (desktop app), `tests/`, `bin/` (CLI entry point).

---

## Request Pipeline (Abbreviated)
## Request Pipeline

```
Client → /v1/chat/completions (Next.js route)
Expand All @@ -76,39 +67,45 @@ Client → /v1/chat/completions (Next.js route)
→ translateRequest() → getExecutor() → executor.execute()
→ fetch() upstream → retry w/ backoff
→ response translation → SSE stream or JSON
→ If Responses API: responsesTransformer.ts TransformStream
```

API routes follow a consistent pattern: `Route → CORS preflight → Zod body validation → Optional auth (extractApiKey/isValidApiKey) → API key policy enforcement → Handler delegation (open-sse)`. No global Next.js middleware — interception is route-specific.

**Combo routing** (`open-sse/services/combo.ts`): 13 strategies (priority, weighted, fill-first, round-robin, P2C, random, least-used, cost-optimized, strict-random, auto, lkgp, context-optimized, context-relay). Each target calls `handleSingleModel()` which wraps `handleChatCore()` with per-target error handling and circuit breaker checks.

---

## Key Conventions

### Code Style

- **2 spaces**, semicolons, double quotes, 100 char width, es5 trailing commas
- **2 spaces**, semicolons, double quotes, 100 char width, es5 trailing commas (enforced by lint-staged via Prettier)
- **Imports**: external → internal (`@/`, `@omniroute/open-sse`) → relative
- **Naming**: files=camelCase/kebab, components=PascalCase, constants=UPPER_SNAKE
- **ESLint**: `no-eval`, `no-implied-eval`, `no-new-func` = error everywhere; `no-explicit-any` = warn in `open-sse/` and `tests/`
- **TypeScript**: `strict: false`, target ES2022, module esnext, resolution bundler. Prefer explicit types.

### Database Access
### Database

- **Always** go through `src/lib/db/` domain modules
- **Never** write raw SQL in routes or handlers
- **Always** go through `src/lib/db/` domain modules — **never** write raw SQL in routes or handlers
- **Never** add logic to `src/lib/localDb.ts` (re-export layer only)
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules instead
- DB singleton: `getDbInstance()` from `src/lib/db/core.ts` (WAL journaling)
- Migrations: `src/lib/db/migrations/` — 21 versioned SQL files
- Migrations: `src/lib/db/migrations/` — versioned SQL files, idempotent, run in transactions

### Error Handling

- try/catch with specific error types, log with pino context
- Never swallow errors in SSE streams — use abort signals
- Never swallow errors in SSE streams — use abort signals for cleanup
- Return proper HTTP status codes (4xx/5xx)

### Security

- **Never** commit secrets/credentials
- **Never** use `eval()`, `new Function()`, or implied eval
- Validate all inputs with Zod schemas
- Encrypt credentials at rest (AES-256-GCM)
- Upstream header denylist: `src/shared/constants/upstreamHeaders.ts` — keep sanitize, Zod schemas, and unit tests aligned when editing

---

Expand All @@ -117,11 +114,11 @@ Client → /v1/chat/completions (Next.js route)
### Adding a New Provider

1. Register in `src/shared/constants/providers.ts` (Zod-validated at load)
2. Add executor in `open-sse/executors/` if custom logic needed
2. Add executor in `open-sse/executors/` if custom logic needed (extend `BaseExecutor`)
3. Add translator in `open-sse/translator/` if non-OpenAI format
4. Add OAuth config in `src/lib/oauth/constants/oauth.ts` if OAuth-based
5. Register models in `open-sse/config/providerRegistry.ts`
6. Write tests in `tests/unit/` (registration, translation, error handling)
6. Write tests in `tests/unit/`

### Adding a New API Route

Expand All @@ -133,20 +130,18 @@ Client → /v1/chat/completions (Next.js route)

### Adding a New DB Module

1. Create `src/lib/db/yourModule.ts`
2. Import `getDbInstance` from `./core.ts`
3. Export CRUD functions for your domain table(s)
4. Add migration in `src/lib/db/migrations/` if new tables needed
5. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
6. Write tests
1. Create `src/lib/db/yourModule.ts` — import `getDbInstance` from `./core.ts`
2. Export CRUD functions for your domain table(s)
3. Add migration in `src/lib/db/migrations/` if new tables needed
4. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
5. Write tests

### Adding a New MCP Tool

1. Add tool definition in `open-sse/mcp-server/tools/`
2. Define Zod input schema + async handler
3. Register in tool set (wired by `createMcpServer()`)
4. Assign to appropriate scope(s)
5. Write tests (tool invocation logged to `mcp_audit` table)
1. Add tool definition in `open-sse/mcp-server/tools/` with Zod input schema + async handler
2. Register in tool set (wired by `createMcpServer()`)
3. Assign to appropriate scope(s)
4. Write tests (tool invocation logged to `mcp_audit` table)

### Adding a New A2A Skill

Expand All @@ -157,66 +152,60 @@ Client → /v1/chat/completions (Next.js route)

---

## Testing Cheat Sheet
## Testing

| What | Command |
| ----------------------- | ------------------------------------------------------- |
| All tests | `npm run test:all` |
| Unit tests | `npm run test:unit` |
| Single file | `node --import tsx/esm --test tests/unit/file.test.mjs` |
| Vitest (MCP, autoCombo) | `npm run test:vitest` |
| E2E (Playwright) | `npm run test:e2e` |
| Protocol E2E (MCP+A2A) | `npm run test:protocols:e2e` |
| Ecosystem | `npm run test:ecosystem` |
| Coverage gate | `npm run test:coverage` (60% min all metrics) |
| Coverage report | `npm run coverage:report` |
| What | Command |
| ----------------------- | ------------------------------------------------------ |
| Unit tests | `npm run test:unit` |
| Single file | `node --import tsx/esm --test tests/unit/file.test.ts` |
| Vitest (MCP, autoCombo) | `npm run test:vitest` |
| E2E (Playwright) | `npm run test:e2e` |
| Protocol E2E (MCP+A2A) | `npm run test:protocols:e2e` |
| Ecosystem | `npm run test:ecosystem` |
| Coverage gate | `npm run test:coverage` (60% min all metrics) |
| Coverage report | `npm run coverage:report` |

**PR rule**: If you change production code in `src/`, `open-sse/`, `electron/`, or `bin/`,
you must include or update tests in the same PR.
**PR rule**: If you change production code in `src/`, `open-sse/`, `electron/`, or `bin/`, you must include or update tests in the same PR.

**Test layer preference**: unit first → integration (multi-module or DB state) → e2e (UI/workflow only). Encode bug reproductions as automated tests before or alongside the fix.

**Copilot coverage policy**: When a PR changes production code and coverage is below 60%, do not just report — add or update tests, rerun the coverage gate, then ask for confirmation. Include commands run, changed test files, and final coverage result in the PR report.

---

## Git Workflow

```bash
# Never commit directly to main
git checkout -b feat/your-feature
# ... make changes ...
git commit -m "feat: describe your change"
git push -u origin feat/your-feature
```

**Branch prefixes**: `feat/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`

**Commit format** ([Conventional Commits](https://www.conventionalcommits.org/)):
**Commit format** (Conventional Commits): `feat(db): add circuit breaker` — scopes: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`

```
feat: add circuit breaker for provider calls
fix: resolve JWT secret validation edge case
docs: update AGENTS.md with pipeline internals
test: add MCP tool unit tests
refactor(db): consolidate rate limit tables
```
**Husky hooks**:

**Scopes**: `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`,
`memory`, `skills`.
- **pre-commit**: lint-staged + `check-docs-sync` + `check:any-budget:t11`
- **pre-push**: `npm run test:unit`

---

## Environment

- **Runtime**: Node.js ≥18 <24, ES Modules
- **TypeScript**: 5.9, target ES2022, module esnext, resolution bundler
- **Path aliases**: `@/*` → `src/`, `@omniroute/open-sse` → `open-sse/`
- **Runtime**: Node.js ≥20.20.2 <21 || ≥22.22.2 <23 || ≥24 <25, ES Modules
- **TypeScript**: 5.9+, target ES2022, module esnext, resolution bundler
- **Path aliases**: `@/*` → `src/`, `@omniroute/open-sse` → `open-sse/`, `@omniroute/open-sse/*` → `open-sse/*`
- **Default port**: 20128 (API + dashboard on same port)
- **Data directory**: `DATA_DIR` env var, defaults to `~/.omniroute/`
- **Key env vars**: `PORT`, `JWT_SECRET`, `INITIAL_PASSWORD`, `REQUIRE_API_KEY`, `APP_LOG_LEVEL`
- **Key env vars**: `PORT`, `JWT_SECRET`, `API_KEY_SECRET`, `INITIAL_PASSWORD`, `REQUIRE_API_KEY`, `APP_LOG_LEVEL`
- Setup: `cp .env.example .env` then generate `JWT_SECRET` (`openssl rand -base64 48`) and `API_KEY_SECRET` (`openssl rand -hex 32`)

---

## Hard Rules (Never Violate)
## Hard Rules

1. Never commit secrets or credentials
2. Never add logic to `localDb.ts`
Expand Down
Loading
Loading