chore: import upstream snapshot with attribution
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: "Diagrams"
|
||||
version: 3.8.40
|
||||
lastUpdated: 2026-06-28
|
||||
---
|
||||
|
||||
# Diagrams
|
||||
|
||||
Mermaid sources (`.mmd`) and exported SVGs for OmniRoute v3.8.0 architecture flows.
|
||||
|
||||
## Canonical diagrams
|
||||
|
||||
| Source | Exported | Used in |
|
||||
| ---------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| [request-pipeline.mmd](./request-pipeline.mmd) | [SVG](./exported/request-pipeline.svg) | docs/architecture/ARCHITECTURE.md, docs/architecture/CODEBASE_DOCUMENTATION.md |
|
||||
| [auto-combo-12factor.mmd](./auto-combo-12factor.mmd) | [SVG](./exported/auto-combo-12factor.svg) | docs/routing/AUTO-COMBO.md |
|
||||
| [resilience-3layers.mmd](./resilience-3layers.mmd) | [SVG](./exported/resilience-3layers.svg) | docs/architecture/RESILIENCE_GUIDE.md, CLAUDE.md |
|
||||
| [i18n-flow.mmd](./i18n-flow.mmd) | [SVG](./exported/i18n-flow.svg) | docs/guides/I18N.md |
|
||||
| [mcp-tools-94.mmd](./mcp-tools-94.mmd) | [SVG](./exported/mcp-tools-94.svg) | docs/frameworks/MCP-SERVER.md |
|
||||
| [cloud-agent-flow.mmd](./cloud-agent-flow.mmd) | [SVG](./exported/cloud-agent-flow.svg) | docs/frameworks/CLOUD_AGENT.md |
|
||||
| [authz-pipeline.mmd](./authz-pipeline.mmd) | [SVG](./exported/authz-pipeline.svg) | docs/architecture/AUTHZ_GUIDE.md |
|
||||
| [db-schema-overview.mmd](./db-schema-overview.mmd) | [SVG](./exported/db-schema-overview.svg) | docs/architecture/CODEBASE_DOCUMENTATION.md |
|
||||
|
||||
## How to update
|
||||
|
||||
1. Edit `*.mmd`.
|
||||
2. Re-render: `npm run docs:render-diagrams` (uses `@mermaid-js/mermaid-cli`).
|
||||
3. Commit both `.mmd` and `.svg`.
|
||||
|
||||
If `@mermaid-js/mermaid-cli` is not available locally, install it once:
|
||||
|
||||
```bash
|
||||
npm install -g @mermaid-js/mermaid-cli
|
||||
```
|
||||
|
||||
The script renders every `.mmd` in `docs/diagrams/` into `docs/diagrams/exported/*.svg`
|
||||
with a white background, suitable for both dark and light themes.
|
||||
|
||||
## Linking from a doc
|
||||
|
||||
From a doc in `docs/<subfolder>/`, the relative path becomes `../diagrams/...`:
|
||||
|
||||
```markdown
|
||||

|
||||
|
||||
> Source: [../diagrams/request-pipeline.mmd](../diagrams/request-pipeline.mmd)
|
||||
```
|
||||
|
||||
From the repo root (e.g. `CLAUDE.md`):
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- One concept per diagram. Don't try to fit the whole platform in one chart.
|
||||
- Keep node labels short (3-6 words). Use `<br/>` for line breaks inside nodes.
|
||||
- Prefer `flowchart LR` for pipelines and `flowchart TB` for layered models.
|
||||
- Use `sequenceDiagram` for interactive (request/response) flows.
|
||||
- Use `erDiagram` for database schema overviews.
|
||||
- Update both `.mmd` and `.svg` in the same commit. Keep them in lock-step.
|
||||
@@ -0,0 +1,23 @@
|
||||
%% AuthZ pipeline (3 route classes + policy evaluation)
|
||||
%% Reflects: src/middleware.ts, src/server/authz/pipeline.ts,
|
||||
%% src/server/authz/policies/{public,clientApi,management}.ts
|
||||
%% v3.8.0
|
||||
flowchart LR
|
||||
Req["Incoming request"] --> Strip["Strip trusted internal headers<br/>(x-omniroute-auth-*)"]
|
||||
Strip --> Classify["classifyRoute()"]
|
||||
Classify -->|PUBLIC| PubP["publicPolicy<br/>(login, health, status)"]
|
||||
Classify -->|CLIENT_API| CliP["clientApiPolicy<br/>(/api/v1/*, /v1/*)"]
|
||||
Classify -->|MANAGEMENT| MgmtP["managementPolicy<br/>(dashboard, settings, admin)"]
|
||||
|
||||
PubP -->|allow| Stamp["Stamp x-omniroute-auth-*<br/>(kind / id / label / scopes)"]
|
||||
CliP -->|extract Bearer| Validate["validateApiKey()"]
|
||||
Validate -->|valid| Stamp
|
||||
Validate -->|"invalid (REQUIRE_API_KEY=true)"| Reject401["401 AUTH_002"]
|
||||
Validate -->|"absent (REQUIRE_API_KEY=false)"| Anon["anonymous fallthrough"] --> Stamp
|
||||
|
||||
MgmtP -->|session ok| Stamp
|
||||
MgmtP -->|Bearer w/ manage scope| Stamp
|
||||
MgmtP -->|"Bearer invalid"| Reject403["403 AUTH_001"]
|
||||
MgmtP -->|no auth| Reject401Mgmt["401 / 302 /login"]
|
||||
|
||||
Stamp --> Handler["Handler<br/>(uses assertAuth)"]
|
||||
@@ -0,0 +1,26 @@
|
||||
%% Auto-Combo 12-factor scoring
|
||||
%% Reflects: open-sse/services/autoCombo/scoring.ts (DEFAULT_WEIGHTS, sum = 1.0)
|
||||
%% v3.8.40
|
||||
flowchart TB
|
||||
Request["Incoming request"] --> Candidates["Eligible candidates<br/>(provider × model × account)"]
|
||||
Candidates --> Score["Compute composite score<br/>per candidate"]
|
||||
|
||||
subgraph Factors["12-factor scoring weights (sum = 1.0)"]
|
||||
f1["health (0.20)"]
|
||||
f2["quota (0.15)"]
|
||||
f3["costInv (0.15)"]
|
||||
f4["latencyInv (0.12)"]
|
||||
f5["taskFit (0.08)"]
|
||||
f6["stability (0.05)"]
|
||||
f7["tierPriority (0.05)"]
|
||||
f8["tierAffinity (0.05)"]
|
||||
f9["specificityMatch (0.05)"]
|
||||
f10["contextAffinity (0.05)"]
|
||||
f11["connectionDensity (0.05)"]
|
||||
f12["resetWindowAffinity (0.00)"]
|
||||
end
|
||||
|
||||
Score --> Factors
|
||||
Factors --> Final["Sort by score<br/>(desc)"]
|
||||
Final --> Top["Pick top-N targets"]
|
||||
Top --> Dispatch["Dispatch sequentially<br/>(short-circuit on success)"]
|
||||
@@ -0,0 +1,32 @@
|
||||
%% Cloud Agent task lifecycle
|
||||
%% Reflects: src/lib/cloudAgent/* and src/app/api/v1/agents/tasks/*
|
||||
%% Supported agents: codex-cloud, devin, jules
|
||||
%% v3.8.0
|
||||
sequenceDiagram
|
||||
participant U as User
|
||||
participant API as /v1/agents/tasks
|
||||
participant Reg as Cloud Agent Registry
|
||||
participant Ag as Cloud Agent<br/>(codex-cloud / devin / jules)
|
||||
participant DB as SQLite domain DB
|
||||
|
||||
U->>API: POST createTask (description, sources)
|
||||
API->>API: Zod validation + AuthZ (management)
|
||||
API->>Reg: getAgent(providerId)
|
||||
Reg->>Ag: instantiate with credentials
|
||||
Ag->>Ag: createTask() returns planning
|
||||
Ag-->>API: taskId + status: planning
|
||||
API->>DB: insertCloudAgentTask
|
||||
API-->>U: taskId
|
||||
|
||||
U->>API: GET /tasks/:id (poll)
|
||||
API->>Ag: getStatus(externalId)
|
||||
Ag-->>API: status, plan, messages
|
||||
API->>DB: updateCloudAgentTask
|
||||
API-->>U: snapshot
|
||||
|
||||
U->>API: POST approvePlan
|
||||
API->>Ag: approvePlan(externalId)
|
||||
Ag-->>API: status: running
|
||||
Note over Ag: Async execution upstream
|
||||
|
||||
Ag-->>DB: stream events / final result
|
||||
@@ -0,0 +1,16 @@
|
||||
%% Database schema overview (selected core tables)
|
||||
%% Reflects: src/lib/db/* (95+ modules, 110+ migrations)
|
||||
%% v3.8.0
|
||||
erDiagram
|
||||
api_keys ||--o{ api_key_usage : tracks
|
||||
api_keys ||--o{ rate_limits : enforces
|
||||
providers ||--o{ provider_connections : holds
|
||||
provider_connections ||--o{ domain_circuit_breakers : protected_by
|
||||
combos ||--o{ combo_targets : contains
|
||||
combos ||--o{ combo_executions : logs
|
||||
spend_buffer ||--o{ usage_aggregations : flushed_to
|
||||
memory_documents ||--o{ memory_chunks : split_into
|
||||
skills_runs ||--o{ skills_logs : produced
|
||||
agent_tasks ||--o{ agent_task_events : streams
|
||||
audit_log }|--|| api_keys : by
|
||||
mcp_audit }|--|| api_keys : by
|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,14 @@
|
||||
%% Incremental hash-based i18n pipeline
|
||||
%% Reflects: scripts/i18n/* and docs/i18n/<locale>/*.md mirror layout
|
||||
%% v3.8.0
|
||||
flowchart LR
|
||||
Src["Source MDs<br/>(CLAUDE.md, docs/**/*.md)"] --> Hash["sha256 hash"]
|
||||
Hash --> State[".i18n-state.json"]
|
||||
State -->|diff| Dirty["Mark source dirty"]
|
||||
Dirty --> Loop{"For each locale<br/>(39 langs)"}
|
||||
Loop --> LLM["OmniRoute<br/>/chat/completions<br/>(cx/gpt-5.4-mini)"]
|
||||
LLM --> Target["Write<br/>docs/i18n/<locale>/<rel-path>.md"]
|
||||
Target --> State
|
||||
Target --> CI{"CI drift check<br/>(npm run i18n:check)"}
|
||||
CI -->|in sync| Pass["pass"]
|
||||
CI -->|drift| Fail["fail<br/>(exit 1)"]
|
||||
@@ -0,0 +1,16 @@
|
||||
%% MCP Server tool inventory by category
|
||||
%% Reflects: open-sse/mcp-server/ — TOTAL_MCP_TOOL_COUNT in server.ts
|
||||
%% (MCP_TOOLS 34 + memory 3 + skill 4 + agentSkill 3 + pool 6 + gamification 8 + plugin 8 + notion 6 + obsidian 22 = 94)
|
||||
%% Regenerate the SVG with: npm run docs:render-diagrams
|
||||
%% v3.8.40
|
||||
flowchart LR
|
||||
MCP["MCP Server<br/>94 tools total"]
|
||||
MCP --> Core["Core (34)<br/>routing, cache, compression,<br/>quota, proxy, tunnels, search, web_fetch"]
|
||||
MCP --> Mem["Memory (3)<br/>memory_search, memory_save,<br/>memory_delete"]
|
||||
MCP --> Skl["Skills (4)<br/>skill_invoke, skill_list,<br/>skill_diagnose, skill_uninstall"]
|
||||
MCP --> ASkl["Agent-Skills (3)<br/>cli-registry discovery"]
|
||||
MCP --> Pool["Pool (6)<br/>pool_status, pool_sessions, pool_reset,<br/>pool_warm, pool_health, browser_pool_status"]
|
||||
MCP --> Gam["Gamification (8)"]
|
||||
MCP --> Plg["Plugins (8)"]
|
||||
MCP --> Notion["Notion (6)<br/>search, get_page, query_database,<br/>get_database, list_block_children,<br/>append_blocks"]
|
||||
MCP --> Obs["Obsidian (22)<br/>vault read/write, search,<br/>frontmatter, daily notes, …"]
|
||||
@@ -0,0 +1,24 @@
|
||||
%% Request pipeline for /v1/chat/completions
|
||||
%% Reflects: src/app/api/v1/chat/completions/route.ts → open-sse/handlers/chatCore.ts
|
||||
%% v3.8.0
|
||||
flowchart LR
|
||||
Client["Client<br/>(IDE/CLI/SDK)"] --> Route["Next.js Route<br/>/v1/chat/completions"]
|
||||
Route --> CORS["CORS preflight"]
|
||||
CORS --> Validate["Zod validation<br/>(request body)"]
|
||||
Validate --> Authz["AuthZ pipeline<br/>(extractApiKey +<br/>isValidApiKey)"]
|
||||
Authz --> Policy["API key policy<br/>(allowlist + scopes)"]
|
||||
Policy --> Guard["Prompt-injection<br/>guardrail"]
|
||||
Guard --> ChatCore["handleChatCore"]
|
||||
ChatCore --> Cache{"Cache hit?"}
|
||||
Cache -->|yes| Return["Return cached"]
|
||||
Cache -->|no| Rate["Rate limit<br/>(per-key, per-IP)"]
|
||||
Rate --> Combo{"Combo<br/>target?"}
|
||||
Combo -->|combo| Resolve["resolveComboTargets<br/>(17 strategies)"]
|
||||
Resolve --> Single["handleSingleModel<br/>(per target)"]
|
||||
Combo -->|single| Single
|
||||
Single --> Translate["translateRequest<br/>(OpenAI↔Claude↔Gemini)"]
|
||||
Translate --> Exec["getExecutor<br/>(31 executors)"]
|
||||
Exec --> Upstream["Upstream Provider<br/>(177 providers)"]
|
||||
Upstream --> Stream["SSE / JSON"]
|
||||
Stream --> Transformer["responsesTransformer<br/>(Responses↔Chat)"]
|
||||
Transformer --> Client
|
||||
@@ -0,0 +1,21 @@
|
||||
%% 3-layer resilience model
|
||||
%% Reflects: src/shared/utils/circuitBreaker.ts, src/sse/services/auth.ts,
|
||||
%% open-sse/services/accountFallback.ts
|
||||
%% v3.8.0
|
||||
flowchart TB
|
||||
Req["Request"] --> L1{"Provider Circuit Breaker<br/>(scope: whole provider)"}
|
||||
L1 -->|CLOSED| L2
|
||||
L1 -->|OPEN| Block1["Skip provider<br/>(or 503 retry-after)"]
|
||||
L1 -->|HALF_OPEN| Probe["Allow probe"]
|
||||
Probe --> L2
|
||||
|
||||
L2{"Connection Cooldown<br/>(scope: one account/key)"} -->|available| L3
|
||||
L2 -->|cooling down| Skip2["Skip this connection<br/>fall back to next"]
|
||||
|
||||
L3{"Model Lockout<br/>(scope: provider × conn × model)"} -->|allowed| Exec["Execute upstream"]
|
||||
L3 -->|locked| Skip3["Fall back to next model"]
|
||||
|
||||
Exec -->|success| Clear["Clear cooldowns/lockouts"]
|
||||
Exec -->|"408 / 500 / 502 / 503 / 504"| TripL1["Trip provider breaker"]
|
||||
Exec -->|"401 / 403 (account)"| TripL2["Start connection cooldown"]
|
||||
Exec -->|"429 quota (model)"| TripL3["Start model lockout"]
|
||||