Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Repository map and Reference Documentation sections below.
| 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 (193 migrations) |
| Database | `src/lib/db/` | SQLite domain modules (195 migrations) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 110 tools (45 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,7 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>&gt;=22.22.2 &lt;23 || &gt;=24.0.0 &lt;27</code></td></tr>
<tr><td nowrap><b>Language</b></td><td>TypeScript 6.0 — <b>100% TypeScript</b> across <code>src/</code> and <code>open-sse/</code> (zero <code>any</code> in core since v2.0)</td></tr>
<tr><td nowrap><b>Framework</b></td><td>Next.js 16 + React 19 + Tailwind CSS 4</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 137 domain modules, 193 migrations</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 138 domain modules, 195 migrations</td></tr>
<tr><td nowrap><b>Memory</b></td><td>SQLite FTS5 full-text + int8-quantized vector embeddings, typed decay</td></tr>
<tr><td nowrap><b>Schemas</b></td><td>Zod 4 — MCP tool I/O validation + API contracts</td></tr>
<tr><td nowrap><b>Protocols</b></td><td>MCP (stdio / HTTP / SSE) + A2A v0.3 (JSON-RPC 2.0 + SSE)</td></tr>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(usage):** attribute proxied requests to coding-agent sessions and projects for team usage reporting, recording session token counters, priced cost, working directory, and project repo ([#14833](https://github.com/diegosouzapw/OmniRoute/pull/14833)) — thanks @fouadSalkini
1 change: 1 addition & 0 deletions config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"_rebaseline_2026_09_28_13969_observed_reasoning_chars": "PR #13969 own growth, re-measured after merging release/v3.8.51 (post #13373 TTFT tile): src/shared/components/RequestLoggerDetail.tsx 1240->1241 (+1 = the reasoningChars field in the existing tokenStats object, so the reasoning badge can show observed characters when usage reports no reasoning tokens). The badge formatting itself lives in formatReasoningStat in src/shared/utils/formatting.ts (under cap); the formatting imports are already the minimal two lines Prettier allows. Covered by tests/unit/ui/request-logger-observed-reasoning-13965.test.tsx (5) and tests/unit/reasoning-thinking-blocks-13965.test.ts (7).",
"_rebaseline_2026_09_27_14917_oauth_401_backoff": "PR #14917 own growth (OAuth 401 backoff), irreducible call-site lines after moving the logic into the new src/sse/services/oauthAuthFailureBackoff.ts (under cap): src/sse/services/auth.ts 3602->3614, re-measured 3605->3617 after merging release/v3.8.51 with #14816 (+12 = one namespace import, the nextCooldownMs call in markAccountUnavailable with its input object as Prettier prints it, the `?? resolvedCooldownMs` fallback line, and resetStreak in clearAccountError; the testStatus spread replaces the existing line) and src/sse/handlers/chat.ts 2583->2584 (+1 = lastErrorCode forwarded to getCooldownAwareRetryDecision at the single cooldown-retry call site). Covered by tests/unit/oauth-401-backoff.test.ts.",
"_rebaseline_2026_09_28_14816_quota_park_skip_5xx": "PR #14816 own growth: src/sse/services/auth.ts 3602->3605 (+3 = a two-line comment and the known-5xx guard in the cachedQuotaResetAt condition of markAccountUnavailable, which Prettier splits over its own line). Irreducible: the guard belongs in the one condition that decides whether a failure parks until the cached quota reset. Covered by tests/unit/quota-park-skips-server-errors.test.ts (4 tests).",
"_rebaseline_2026_09_25_agent_sessions_attribution": "Own growth, re-measured with split(\"\\n\").length after merging release/v3.8.51 @ae2ba358: open-sse/handlers/chatCore.ts 6441->6442 (tip file 6439 under the #14810 ceiling 6441; +3 own = the resolveUsageAgentContext import, the single extraction call before persistFailureUsage, and the agentContext property on the failure-usage record; the streaming and non-streaming call sites reuse the existing endpoint line). Extraction lives in the new open-sse/handlers/chatCore/agentContext.ts and persistence in src/lib/db/agentSessions.ts (both under the cap). Covered by tests/unit/agent-context.test.ts and tests/unit/agent-sessions-usage.test.ts.",
"_rebaseline_2026_09_25_14756_request_added_wait": "PR #14756 own growth (per-request added wait before dispatch, migration 192), re-measured with split(\"\\n\").length after merging release/v3.8.51 @96f6aee2 (post #14750/#14795/#14810/#14659; replaces the PR's earlier entry, which had rewound unrelated tip ceilings): open-sse/executors/opencode.ts 1419->1452 (+33 = request-scoped accumulator + park-sleep counting wrapper + wall-clock around the paced acquire + publish to the capture sink, at the existing dispatch chokepoint); open-sse/utils/proxyFetch.ts 1341->1383 (tip file 1338; +45 = two AppliedProxySink fields + noteAddedWait/readAddedWait on the existing applied-proxy ALS sink, which is private to this module); src/lib/db/core.ts 1800->1802 (+2 = added_wait_ms/added_wait_cause in the call_logs base schema); src/shared/components/RequestLoggerDetail.tsx 1216->1226 (+10 = the Added wait cell next to the existing duration cells). Additive and null-safe. Covered by tests/unit/opencode-added-wait.test.ts.",
"_rebaseline_2026_09_25_14810_resilience_actions_wiring": "PR #14810 own growth (resilience-actions observability wiring, irreducible call-site lines after extraction of the note logic into chatCore/*_notes modules + opencodeResilienceNotes + requestLoggerResilience, all under cap): open-sse/handlers/chatCore.ts 6426->6441 (+15 = wrapper handleChatCore/handleChatCoreInner + resumed-flag param/note/strip + 3 one-line note calls, logic in chatCore/resilienceAttemptContext + resumedResilienceNotes + emptyTurnResilienceNotes + continuationResilienceNotes + recoveryTraceLogging); open-sse/executors/opencode.ts 1338->1354, re-measured 1354->1370 after merging release/v3.8.51 @86870a82 (the tip itself had grown to 1354 via the applied-egress tracker) (+16 = served-account tracker + park/replay/stored notes wiring, logic in opencodeResilienceNotes); src/sse/handlers/chat.ts 2567->2582 (+15 on the reconciled tip = resumed-flag threading via body marker + dispatch param + 2 combo forwards); src/shared/components/RequestLoggerDetail.tsx 1210->1216, re-measured on release/v3.8.51 @4b9388a1 (tip file 1205 after #14795; +11 = one import + badge computation + badge render loop, badge logic in requestLoggerResilience); src/lib/usage/callLogs.ts stays under the 1200 cap (resilience-actions parser moved to src/lib/usage/resilienceActionsParse.ts). Measured with split(\"\\n\").length. Covered by tests/unit/resilience-actions-context (11) + sink (5) + notes (9) + badges (5) + db/migration-191 (2).",
"_rebaseline_2026_09_24_14802_transport_setaside": "PR #14802 own growth: open-sse/utils/proxyFetch.ts 1334->1341 (+7 = two-symbol import + proxied-success hook at the single dispatch return + tagged-failure guard at the single final throw; full evidence helpers live in open-sse/utils/proxyRefusalMemory.ts (not frozen), irreducible call-site wiring at the two existing chokepoints). Covered by tests/unit/proxy-transport-setaside-cross-evidence.test.ts (10/10) + tests/unit/proxy-transport-traffic-simulation.test.ts (4/4).",
Expand Down
58 changes: 57 additions & 1 deletion docs/guides/CLAUDE-CODE-CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Claude Code CLI — Configuration with OmniRoute"
version: 3.8.40
lastUpdated: 2026-07-24
lastUpdated: 2026-09-25
---

# Claude Code CLI — Configuration with OmniRoute
Expand Down Expand Up @@ -50,6 +50,62 @@ just works), health-checks the server, and execs `claude`.

---

## Usage attribution: sessions and projects

OmniRoute groups each API key's requests into **agent sessions** and records which **project**
each session worked on (`agent_sessions` table), so usage and cost can be reported per team member,
per project and per session.

What is recorded without any client setup:

| Field | Source |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Session | `x-claude-code-session-id` header (same value as `metadata.user_id.session_id`), stable per session |
| Project | The `Primary working directory:` line Claude Code sends in its environment message; worktree folders under `.claude/worktrees/` resolve to the repository name |
| Branch | `Current branch:` from the git status Claude Code sends with the first message |
| Client | `user-agent` (`claude-cli/<version>`) |

Codex (`<environment_context><cwd>`) and OpenCode (`x-opencode-session`) are recognized the same
way. Keys with **no-log** enabled keep only the session id and header-supplied project fields;
nothing read from the prompt (path, branch) is stored.

### Naming the project explicitly (recommended)

The working directory differs between machines, so the same repository can show up under different
paths. Send the project explicitly instead: Claude Code adds any headers listed in
`ANTHROPIC_CUSTOM_HEADERS` to every model request, and OmniRoute reads two of them:

| Header | Value |
| -------------------------- | ----------------------------------------------------------- |
| `x-omniroute-project` | Project name, e.g. `omniroute` |
| `x-omniroute-project-repo` | Normalized remote, e.g. `github.com/diegosouzapw/OmniRoute` |

Both are only read for attribution; they are never forwarded to the upstream provider.

`ANTHROPIC_CUSTOM_HEADERS` is read once at startup, and settings files store literal values, so
compute it when Claude Code launches. Add this to `~/.zshrc` or `~/.bashrc` and keep starting
`claude` from the project folder:

```bash
claude() {
local common name repo
if common=$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null); then
name=$(basename "$(dirname "$common")") # repository name, also inside worktrees
repo=$(git remote get-url origin 2>/dev/null \
| sed -E 's#^[a-zA-Z][a-zA-Z0-9+.-]*://([^@/]*@)?##; s#^[^@/]+@([^:]+):#\1/#; s#\.git$##')
else
name=$(basename "$PWD") # not a git repository: folder name
fi
ANTHROPIC_CUSTOM_HEADERS="x-omniroute-project: ${name}${repo:+
x-omniroute-project-repo: ${repo}}" command claude "$@"
}
```

The `sed` expression strips any credentials embedded in the remote URL. IDE extensions launch
Claude Code without your shell, so their sessions fall back to the working directory.

---

## Discovery aliases — surface non-Claude models in the `/model` picker

Claude Code's gateway model discovery only lists ids that begin with `claude`
Expand Down
12 changes: 6 additions & 6 deletions docs/i18n/am/llm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo

- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 193 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 195 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
Expand Down Expand Up @@ -106,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ └── streaming.ts # SSE streaming for A2A
│ │ ├── acp/ # Agent Communication Protocol registry and manager
│ │ ├── compliance/ # Compliance policy engine
│ │ ├── db/ # SQLite database layer (137 modules + migrations)
│ │ ├── db/ # SQLite database layer (138 modules + migrations)
│ │ │ ├── core.ts # Database initialization, connection, schema
│ │ │ ├── providers.ts # Provider connection CRUD
│ │ │ ├── models.ts # Model catalog management
Expand All @@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 193 versioned SQL migration files
│ │ │ └── migrations/ # 195 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
Expand Down Expand Up @@ -387,13 +387,13 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool

5. **SSE proxy pipeline:** The proxy pipeline is middleware-based: request → auth resolution → rate limiting → circuit breaker → format translation → upstream call → response translation → SSE streaming back to client.

6. **SQLite for persistence:** All state (providers, combos, logs, settings, API keys, memory, skills) stored in a single SQLite database via 137 domain-specific modules. All DB operations go through `src/lib/db/` modules, never raw SQL in routes.
6. **SQLite for persistence:** All state (providers, combos, logs, settings, API keys, memory, skills) stored in a single SQLite database via 138 domain-specific modules. All DB operations go through `src/lib/db/` modules, never raw SQL in routes.

7. **OAuth with PKCE:** OAuth flows use PKCE for security. Token refresh handled by background job (`tokenHealthCheck.ts`).

8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.

9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 137 `src/lib/db/` modules with 193 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 138 `src/lib/db/` modules with 195 SQL migrations.

10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.

Expand Down Expand Up @@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool

4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.

5. **Database layer:** Operations go through `src/lib/db/` modules (137 domain-specific files, 193 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (138 domain-specific files, 195 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.

6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

Expand Down
Loading
Loading