mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-13 10:43:43 +03:00
docs: merge duplicate guides (troubleshooting, chatgpt-web codex, docker channels, memory backend)
This commit is contained in:
@@ -9,7 +9,9 @@ It describes each gate, what it validates, which CI job it runs in, whether it u
|
||||
a ratchet baseline or a pass/fail policy, and whether it blocks the build or is advisory.
|
||||
|
||||
For a short summary and the allowlist policy, see the "Quality Gates & Ratchets" section
|
||||
in `CLAUDE.md`.
|
||||
in `CLAUDE.md`. For the critical assessment, maturity classification, and tool-agnostic
|
||||
replication plan of the same system, see the
|
||||
[Quality Gate Playbook](../ops/QUALITY_GATE_PLAYBOOK.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -888,3 +888,229 @@ To leave it off, simply keep `autoSummarize` at its default (`false`).
|
||||
0 3 * * * curl -X POST http://localhost:20128/api/memory/summarize \
|
||||
-H "Authorization: Bearer $OMNIROUTE_KEY"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
## MemoryBackend Provider Pattern
|
||||
|
||||
> **Source of truth:** `src/lib/memory/backend.ts`, `src/lib/memory/genericBackend.ts`, `src/lib/memory/manager.ts`
|
||||
> **Tests:** `src/lib/memory/__tests__/generic-backend.test.ts`
|
||||
|
||||
The MemoryBackend provider pattern introduces a **pluggable backend abstraction layer** over the existing memory engine. Instead of being tied to a single storage implementation, the memory system now supports multiple backends (SQLite, Obsidian, Notion, custom HTTP backends) with configurable primary/fallback routing.
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ API Routes │
|
||||
│ (src/app/api/memory/route.ts) │
|
||||
└──────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────────────────┐
|
||||
│ MemoryManager │
|
||||
│ Singleton orchestrator (manager.ts) │
|
||||
│ │
|
||||
│ Primary ──► Backend A (e.g. SQLite) │
|
||||
│ Fallback ─► Backend B (e.g. Obsidian) │
|
||||
│ Backend C (e.g. Notion via GenericBackend) │
|
||||
└──────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────────┐ ┌────────────┐ ┌──────────────────┐
|
||||
│ SQLite │ │ Obsidian │ │ GenericMemory │
|
||||
│ Backend │ │ Backend │ │ Backend (HTTP) │
|
||||
└────────────┘ └────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
#### Core Interface (`backend.ts`)
|
||||
|
||||
Every backend must implement the `MemoryBackend` interface:
|
||||
|
||||
```typescript
|
||||
interface MemoryBackend {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
|
||||
// CRUD
|
||||
create(input: CreateMemoryInput): Promise<Memory>;
|
||||
get(id: string): Promise<Memory | null>;
|
||||
update(id: string, updates: Partial<...>): Promise<boolean>;
|
||||
delete(id: string): Promise<boolean>;
|
||||
list(filter: MemoryFilter): Promise<{ data: Memory[]; total: number; byType: Record<string, number> }>;
|
||||
|
||||
// Search
|
||||
search(config: SearchConfig): Promise<Memory[]>;
|
||||
|
||||
// Health
|
||||
health(): Promise<HealthCheckResult>;
|
||||
|
||||
// Lifecycle (optional)
|
||||
initialize?(): Promise<void>;
|
||||
shutdown?(): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
#### MemoryManager (`manager.ts`)
|
||||
|
||||
Singleton orchestrator that:
|
||||
|
||||
- **Registers** backends via `register(backend)` — called at boot from `index.ts`
|
||||
- **Configures** primary + fallback via `configure(primary, fallbacks)`
|
||||
- **Routes** CRUD/search to the primary, with fallback chain on failure
|
||||
- **Health checks** all backends periodically
|
||||
|
||||
**Fallback behavior:**
|
||||
|
||||
| Operation | Primary | Fallbacks |
|
||||
| --------- | -------------------- | ----------------------- |
|
||||
| `create` | ✅ Primary only | ❌ |
|
||||
| `get` | ✅ Try primary first | ✅ Fallback if null |
|
||||
| `update` | ✅ Primary only | ✅ Fire-and-forget sync |
|
||||
| `delete` | ✅ Primary only | ✅ Fire-and-forget sync |
|
||||
| `list` | ✅ Primary only | ❌ |
|
||||
| `search` | ✅ Primary first | ✅ Fallback on error |
|
||||
|
||||
#### GenericMemoryBackend (`genericBackend.ts`)
|
||||
|
||||
A generic HTTP connector that adapts any REST API into a MemoryBackend. Useful for:
|
||||
|
||||
- **Notion** — connect via Notion API
|
||||
- **Obsidian** — connect via Obsidian Local REST API
|
||||
- **Custom backends** — any service that exposes a RESTful memory API
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```typescript
|
||||
interface GenericBackendConfig {
|
||||
baseUrl: string; // Base URL of the backend API
|
||||
apiKey?: string; // Bearer token for auth
|
||||
headers?: Record<string, string>; // Custom HTTP headers
|
||||
timeout?: number; // Request timeout (default: 30000ms)
|
||||
backendType?: string; // For logging
|
||||
|
||||
// Endpoint overrides (defaults use REST conventions)
|
||||
endpoints?: {
|
||||
search?: string; // default: "/memories/search"
|
||||
create?: string; // default: "/memories"
|
||||
list?: string; // default: "/memories"
|
||||
get?: string; // default: "/memories/{id}"
|
||||
update?: string; // default: "/memories/{id}"
|
||||
delete?: string; // default: "/memories/{id}"
|
||||
health?: string; // default: "/health"
|
||||
};
|
||||
|
||||
// Query parameter name mappings
|
||||
queryParams?: {
|
||||
query?/apiKeyId?/limit?/offset?/strategy?/maxTokens?/type?/sessionId?/orderBy?/orderDir?/options?
|
||||
};
|
||||
|
||||
// Path parameter name mappings
|
||||
pathParams?: {
|
||||
id?/memoryId?
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Known backends** are pre-configured in `KNOWN_BACKENDS`:
|
||||
|
||||
```typescript
|
||||
createKnownBackend("obsidian"); // → GenericMemoryBackend pointed at localhost:27123
|
||||
createKnownBackend("notion"); // → GenericMemoryBackend pointed at api.notion.com/v1
|
||||
```
|
||||
|
||||
#### Built-in Backends
|
||||
|
||||
##### SQLiteBackend (`sqliteBackend.ts`)
|
||||
|
||||
The default primary backend. Wraps the existing SQLite-based memory store using `src/lib/memory/store.ts`. Automatically registered at boot.
|
||||
|
||||
```typescript
|
||||
import { sqliteBackend } from "./sqliteBackend";
|
||||
memoryManager.register(sqliteBackend);
|
||||
```
|
||||
|
||||
##### ObsidianBackend (`obsidianBackend.ts`)
|
||||
|
||||
Wraps the existing Obsidian integration (`src/lib/memory/obsidianBackend.ts`). Connects to an Obsidian vault via the Obsidian Local REST API.
|
||||
|
||||
### Settings
|
||||
|
||||
Memory backend settings are stored in the app settings table and managed via `src/lib/memory/settings.ts`:
|
||||
|
||||
| Setting | Env/Config Key | Default | Description |
|
||||
| ----------------- | ------------------------ | ---------- | ---------------------------- |
|
||||
| Primary backend | `memoryPrimaryBackend` | `"sqlite"` | ID of the primary backend |
|
||||
| Fallback backends | `memoryFallbackBackends` | `[]` | Ordered fallback backend IDs |
|
||||
| Backend configs | `memoryBackendConfigs` | `{}` | Per-backend config overrides |
|
||||
|
||||
Settings are normalized via `normalizeMemorySettings()` and cached at `getMemorySettings()`.
|
||||
|
||||
### Initialization Flow
|
||||
|
||||
```
|
||||
App bootstrap
|
||||
→ index.ts imports (side-effect): registers SQLiteBackend
|
||||
→ initMemoryBackends() called from app lifecycle:
|
||||
1. Load settings (getMemorySettings)
|
||||
2. Configure primary + fallback
|
||||
3. Initialize all backends (health check)
|
||||
4. Ready for requests
|
||||
```
|
||||
|
||||
### Adding a New Backend
|
||||
|
||||
1. **Implement `MemoryBackend`** interface in `src/lib/memory/<name>Backend.ts`
|
||||
2. **Export** from `src/lib/memory/index.ts`
|
||||
3. **Register** with `memoryManager.register(yourBackend)` at boot
|
||||
4. **Configure** via settings: set `memoryPrimaryBackend` to your backend ID
|
||||
5. **Test** with `src/lib/memory/__tests__/generic-backend.test.ts` as reference
|
||||
|
||||
#### Example: Brain Backend
|
||||
|
||||
```typescript
|
||||
import { createGenericMemoryBackend } from "./genericBackend";
|
||||
|
||||
const brainBackend = createGenericMemoryBackend("brain", "BK-Brain", {
|
||||
baseUrl: process.env.BRAIN_API_URL || "http://localhost:9099",
|
||||
apiKey: process.env.BRAIN_API_KEY,
|
||||
endpoints: {
|
||||
search: "/api/memory/search",
|
||||
create: "/api/memory",
|
||||
health: "/api/health",
|
||||
},
|
||||
});
|
||||
|
||||
memoryManager.register(brainBackend);
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
#### Unit tests
|
||||
|
||||
```bash
|
||||
npx vitest run src/lib/memory/__tests__/generic-backend.test.ts --reporter=verbose
|
||||
```
|
||||
|
||||
Expected output: **26 tests, all passing** covering:
|
||||
|
||||
- Constructor (2)
|
||||
- Health check (4) — success, failure 500, network error, latency
|
||||
- Initialize (2) — success, failure
|
||||
- Create (2) — default endpoint, custom endpoint
|
||||
- Get (4) — success, 404 → null, non-404 throw, custom path params
|
||||
- Update (2) — success, 404 → false
|
||||
- Delete (2) — success, 404 → false
|
||||
- List (2) — query params, custom param names
|
||||
- Search (3) — query params, custom endpoint, options serialization
|
||||
- Auth headers (2) — Bearer token, custom headers
|
||||
- Factory (1)
|
||||
|
||||
#### Type check
|
||||
|
||||
```bash
|
||||
npm run typecheck:core
|
||||
```
|
||||
|
||||
Expected: **0 errors**.
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
---
|
||||
title: "MemoryBackend Provider Pattern"
|
||||
version: 3.8.49
|
||||
lastUpdated: 2026-07-28
|
||||
---
|
||||
|
||||
# MemoryBackend Provider Pattern
|
||||
|
||||
> **Source of truth:** `src/lib/memory/backend.ts`, `src/lib/memory/genericBackend.ts`, `src/lib/memory/manager.ts`
|
||||
> **Tests:** `src/lib/memory/__tests__/generic-backend.test.ts`
|
||||
|
||||
The MemoryBackend provider pattern introduces a **pluggable backend abstraction layer** over the existing memory engine. Instead of being tied to a single storage implementation, the memory system now supports multiple backends (SQLite, Obsidian, Notion, custom HTTP backends) with configurable primary/fallback routing.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ API Routes │
|
||||
│ (src/app/api/memory/route.ts) │
|
||||
└──────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────────▼───────────────────────────────────┐
|
||||
│ MemoryManager │
|
||||
│ Singleton orchestrator (manager.ts) │
|
||||
│ │
|
||||
│ Primary ──► Backend A (e.g. SQLite) │
|
||||
│ Fallback ─► Backend B (e.g. Obsidian) │
|
||||
│ Backend C (e.g. Notion via GenericBackend) │
|
||||
└──────────────────────┬───────────────────────────────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────────┐ ┌────────────┐ ┌──────────────────┐
|
||||
│ SQLite │ │ Obsidian │ │ GenericMemory │
|
||||
│ Backend │ │ Backend │ │ Backend (HTTP) │
|
||||
└────────────┘ └────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
### Core Interface (`backend.ts`)
|
||||
|
||||
Every backend must implement the `MemoryBackend` interface:
|
||||
|
||||
```typescript
|
||||
interface MemoryBackend {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
|
||||
// CRUD
|
||||
create(input: CreateMemoryInput): Promise<Memory>;
|
||||
get(id: string): Promise<Memory | null>;
|
||||
update(id: string, updates: Partial<...>): Promise<boolean>;
|
||||
delete(id: string): Promise<boolean>;
|
||||
list(filter: MemoryFilter): Promise<{ data: Memory[]; total: number; byType: Record<string, number> }>;
|
||||
|
||||
// Search
|
||||
search(config: SearchConfig): Promise<Memory[]>;
|
||||
|
||||
// Health
|
||||
health(): Promise<HealthCheckResult>;
|
||||
|
||||
// Lifecycle (optional)
|
||||
initialize?(): Promise<void>;
|
||||
shutdown?(): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
### MemoryManager (`manager.ts`)
|
||||
|
||||
Singleton orchestrator that:
|
||||
|
||||
- **Registers** backends via `register(backend)` — called at boot from `index.ts`
|
||||
- **Configures** primary + fallback via `configure(primary, fallbacks)`
|
||||
- **Routes** CRUD/search to the primary, with fallback chain on failure
|
||||
- **Health checks** all backends periodically
|
||||
|
||||
**Fallback behavior:**
|
||||
|
||||
| Operation | Primary | Fallbacks |
|
||||
| --------- | -------------------- | ----------------------- |
|
||||
| `create` | ✅ Primary only | ❌ |
|
||||
| `get` | ✅ Try primary first | ✅ Fallback if null |
|
||||
| `update` | ✅ Primary only | ✅ Fire-and-forget sync |
|
||||
| `delete` | ✅ Primary only | ✅ Fire-and-forget sync |
|
||||
| `list` | ✅ Primary only | ❌ |
|
||||
| `search` | ✅ Primary first | ✅ Fallback on error |
|
||||
|
||||
### GenericMemoryBackend (`genericBackend.ts`)
|
||||
|
||||
A generic HTTP connector that adapts any REST API into a MemoryBackend. Useful for:
|
||||
|
||||
- **Notion** — connect via Notion API
|
||||
- **Obsidian** — connect via Obsidian Local REST API
|
||||
- **Custom backends** — any service that exposes a RESTful memory API
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```typescript
|
||||
interface GenericBackendConfig {
|
||||
baseUrl: string; // Base URL of the backend API
|
||||
apiKey?: string; // Bearer token for auth
|
||||
headers?: Record<string, string>; // Custom HTTP headers
|
||||
timeout?: number; // Request timeout (default: 30000ms)
|
||||
backendType?: string; // For logging
|
||||
|
||||
// Endpoint overrides (defaults use REST conventions)
|
||||
endpoints?: {
|
||||
search?: string; // default: "/memories/search"
|
||||
create?: string; // default: "/memories"
|
||||
list?: string; // default: "/memories"
|
||||
get?: string; // default: "/memories/{id}"
|
||||
update?: string; // default: "/memories/{id}"
|
||||
delete?: string; // default: "/memories/{id}"
|
||||
health?: string; // default: "/health"
|
||||
};
|
||||
|
||||
// Query parameter name mappings
|
||||
queryParams?: {
|
||||
query?/apiKeyId?/limit?/offset?/strategy?/maxTokens?/type?/sessionId?/orderBy?/orderDir?/options?
|
||||
};
|
||||
|
||||
// Path parameter name mappings
|
||||
pathParams?: {
|
||||
id?/memoryId?
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Known backends** are pre-configured in `KNOWN_BACKENDS`:
|
||||
|
||||
```typescript
|
||||
createKnownBackend("obsidian"); // → GenericMemoryBackend pointed at localhost:27123
|
||||
createKnownBackend("notion"); // → GenericMemoryBackend pointed at api.notion.com/v1
|
||||
```
|
||||
|
||||
### Built-in Backends
|
||||
|
||||
#### SQLiteBackend (`sqliteBackend.ts`)
|
||||
|
||||
The default primary backend. Wraps the existing SQLite-based memory store using `src/lib/memory/store.ts`. Automatically registered at boot.
|
||||
|
||||
```typescript
|
||||
import { sqliteBackend } from "./sqliteBackend";
|
||||
memoryManager.register(sqliteBackend);
|
||||
```
|
||||
|
||||
#### ObsidianBackend (`obsidianBackend.ts`)
|
||||
|
||||
Wraps the existing Obsidian integration (`src/lib/memory/obsidianBackend.ts`). Connects to an Obsidian vault via the Obsidian Local REST API.
|
||||
|
||||
## Settings
|
||||
|
||||
Memory backend settings are stored in the app settings table and managed via `src/lib/memory/settings.ts`:
|
||||
|
||||
| Setting | Env/Config Key | Default | Description |
|
||||
| ----------------- | ------------------------ | ---------- | ---------------------------- |
|
||||
| Primary backend | `memoryPrimaryBackend` | `"sqlite"` | ID of the primary backend |
|
||||
| Fallback backends | `memoryFallbackBackends` | `[]` | Ordered fallback backend IDs |
|
||||
| Backend configs | `memoryBackendConfigs` | `{}` | Per-backend config overrides |
|
||||
|
||||
Settings are normalized via `normalizeMemorySettings()` and cached at `getMemorySettings()`.
|
||||
|
||||
## Initialization Flow
|
||||
|
||||
```
|
||||
App bootstrap
|
||||
→ index.ts imports (side-effect): registers SQLiteBackend
|
||||
→ initMemoryBackends() called from app lifecycle:
|
||||
1. Load settings (getMemorySettings)
|
||||
2. Configure primary + fallback
|
||||
3. Initialize all backends (health check)
|
||||
4. Ready for requests
|
||||
```
|
||||
|
||||
## Adding a New Backend
|
||||
|
||||
1. **Implement `MemoryBackend`** interface in `src/lib/memory/<name>Backend.ts`
|
||||
2. **Export** from `src/lib/memory/index.ts`
|
||||
3. **Register** with `memoryManager.register(yourBackend)` at boot
|
||||
4. **Configure** via settings: set `memoryPrimaryBackend` to your backend ID
|
||||
5. **Test** with `src/lib/memory/__tests__/generic-backend.test.ts` as reference
|
||||
|
||||
### Example: Brain Backend
|
||||
|
||||
```typescript
|
||||
import { createGenericMemoryBackend } from "./genericBackend";
|
||||
|
||||
const brainBackend = createGenericMemoryBackend("brain", "BK-Brain", {
|
||||
baseUrl: process.env.BRAIN_API_URL || "http://localhost:9099",
|
||||
apiKey: process.env.BRAIN_API_KEY,
|
||||
endpoints: {
|
||||
search: "/api/memory/search",
|
||||
create: "/api/memory",
|
||||
health: "/api/health",
|
||||
},
|
||||
});
|
||||
|
||||
memoryManager.register(brainBackend);
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Unit tests
|
||||
|
||||
```bash
|
||||
npx vitest run src/lib/memory/__tests__/generic-backend.test.ts --reporter=verbose
|
||||
```
|
||||
|
||||
Expected output: **26 tests, all passing** covering:
|
||||
|
||||
- Constructor (2)
|
||||
- Health check (4) — success, failure 500, network error, latency
|
||||
- Initialize (2) — success, failure
|
||||
- Create (2) — default endpoint, custom endpoint
|
||||
- Get (4) — success, 404 → null, non-404 throw, custom path params
|
||||
- Update (2) — success, 404 → false
|
||||
- Delete (2) — success, 404 → false
|
||||
- List (2) — query params, custom param names
|
||||
- Search (3) — query params, custom endpoint, options serialization
|
||||
- Auth headers (2) — Bearer token, custom headers
|
||||
- Factory (1)
|
||||
|
||||
### Type check
|
||||
|
||||
```bash
|
||||
npm run typecheck:core
|
||||
```
|
||||
|
||||
Expected: **0 errors**.
|
||||
@@ -201,7 +201,7 @@ Round-robin cycles through providers in order. Auto-combo **scores each provider
|
||||
|
||||
- **[Connect a Provider](./PROVIDERS-GUIDE.md)** — Add your first AI provider
|
||||
- **[Free Tiers Guide](./FREE-TIERS-GUIDE.md)** — Get free AI with no credit card
|
||||
- **[Troubleshooting](./TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Troubleshooting](../guides/TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Technical Reference](../routing/AUTO-COMBO.md)** — Deep dive into the scoring algorithm
|
||||
|
||||
---
|
||||
|
||||
@@ -272,5 +272,5 @@ No catch! Providers offer free tiers to attract users. OmniRoute just makes it e
|
||||
|
||||
- **[Auto-Combo Guide](./AUTO-COMBO-GUIDE.md)** — Let OmniRoute pick the best AI for you
|
||||
- **[Providers Guide](./PROVIDERS-GUIDE.md)** — Connect more providers
|
||||
- **[Troubleshooting](./TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Troubleshooting](../guides/TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Free Tiers Reference](../reference/FREE_TIERS.md)** — Full list of free tiers
|
||||
|
||||
@@ -237,5 +237,5 @@ Go to Providers → click on the provider → click **Disconnect**.
|
||||
|
||||
- **[Auto-Combo Guide](./AUTO-COMBO-GUIDE.md)** — Let OmniRoute pick the best AI for you
|
||||
- **[Free Tiers Guide](./FREE-TIERS-GUIDE.md)** — Get free AI with no credit card
|
||||
- **[Troubleshooting](./TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Troubleshooting](../guides/TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Provider Reference](../reference/PROVIDER_REFERENCE.md)** — Full list of 226 providers
|
||||
|
||||
@@ -153,7 +153,7 @@ You can see the details of the request by clicking [Monitoring/Logs](http://loca
|
||||
- **[Auto-Combo Guide](./AUTO-COMBO-GUIDE.md)** — Let OmniRoute pick the best AI for you
|
||||
- **[Providers Guide](./PROVIDERS-GUIDE.md)** — Connect more providers (free and paid)
|
||||
- **[Free Tiers Guide](./FREE-TIERS-GUIDE.md)** — Get free AI with no credit card
|
||||
- **[Troubleshooting](./TROUBLESHOOTING.md)** — Fix common issues
|
||||
- **[Troubleshooting](../guides/TROUBLESHOOTING.md)** — Fix common issues
|
||||
|
||||
---
|
||||
|
||||
@@ -183,6 +183,6 @@ OmniRoute automatically skips failed providers and tries the next one. You don't
|
||||
|
||||
## Need Help?
|
||||
|
||||
- **[Troubleshooting](./TROUBLESHOOTING.md)** — Common issues and fixes
|
||||
- **[Troubleshooting](../guides/TROUBLESHOOTING.md)** — Common issues and fixes
|
||||
- **[Discord](https://discord.gg/U47eFqAXCn)** — Community support
|
||||
- **[GitHub Issues](https://github.com/diegosouzapw/OmniRoute/issues)** — Report bugs
|
||||
|
||||
@@ -1,498 +0,0 @@
|
||||
---
|
||||
title: "Troubleshooting"
|
||||
version: 3.8.40
|
||||
lastUpdated: 2026-06-28
|
||||
---
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
> **For Users**: Looking for quick fixes? See the [Quick Reference](#quick-reference) below.
|
||||
|
||||
🌐 **Languages:** 🇺🇸 [English](./TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](../i18n/pt-BR/docs/guides/TROUBLESHOOTING.md) | 🇪🇸 [Español](../i18n/es/docs/guides/TROUBLESHOOTING.md) | 🇫🇷 [Français](../i18n/fr/docs/guides/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](../i18n/it/docs/guides/TROUBLESHOOTING.md) | 🇷🇺 [Русский](../i18n/ru/docs/guides/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](../i18n/zh-CN/docs/guides/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](../i18n/de/docs/guides/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](../i18n/in/docs/guides/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](../i18n/th/docs/guides/TROUBLESHOOTING.md) | 🇺🇦 [Українська](../i18n/uk-UA/docs/guides/TROUBLESHOOTING.md) | 🇸🇦 [العربية](../i18n/ar/docs/guides/TROUBLESHOOTING.md) | 🇯🇵 [日本語](../i18n/ja/docs/guides/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](../i18n/vi/docs/guides/TROUBLESHOOTING.md) | 🇧🇬 [Български](../i18n/bg/docs/guides/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](../i18n/da/docs/guides/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](../i18n/fi/docs/guides/TROUBLESHOOTING.md) | 🇮🇱 [עברית](../i18n/he/docs/guides/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](../i18n/hu/docs/guides/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](../i18n/id/docs/guides/TROUBLESHOOTING.md) | 🇰🇷 [한국어](../i18n/ko/docs/guides/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](../i18n/ms/docs/guides/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](../i18n/nl/docs/guides/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](../i18n/no/docs/guides/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](../i18n/pt/docs/guides/TROUBLESHOOTING.md) | 🇷🇴 [Română](../i18n/ro/docs/guides/TROUBLESHOOTING.md) | 🇵🇱 [Polski](../i18n/pl/docs/guides/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](../i18n/sk/docs/guides/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](../i18n/sv/docs/guides/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](../i18n/phi/docs/guides/TROUBLESHOOTING.md) | 🇨🇿 [Čeština](../i18n/cs/docs/guides/TROUBLESHOOTING.md)
|
||||
|
||||
Common problems and solutions for OmniRoute.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**New to OmniRoute?** Start here — these solve 90% of problems:
|
||||
|
||||
| I see this | What it means | What to do |
|
||||
| ----------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| "Can't connect" | OmniRoute isn't running | Run `omniroute` or `docker restart omniroute` |
|
||||
| "Invalid API key" | Your key is wrong or expired | Re-copy the key from the provider's website |
|
||||
| "Rate limit exceeded" | You're sending too many requests | Wait 1 minute, or use `model: "auto"` for automatic fallback |
|
||||
| "Quota exceeded" | You've used up your free/paid quota | Connect more providers, or use free providers (Kiro, Pollinations) |
|
||||
| "Slow responses" | Provider is busy or far away | Use `model: "auto/fast"` or connect a faster provider (Groq, Cerebras) |
|
||||
| "Wrong provider used" | `auto` picked a different provider | That's normal! `auto` picks the best one. Force a specific provider with `model: "openai/gpt-4o"` |
|
||||
| "502 Bad Gateway" | Provider is down | Wait and retry, or use `model: "auto"` to switch providers |
|
||||
| "401 Unauthorized" | Your credentials are wrong | Check your API key or re-authenticate with OAuth |
|
||||
| "429 Too Many Requests" | Rate limited | Wait 1 minute, or connect more providers |
|
||||
|
||||
**Still stuck?** See the [Quick Fixes](#quick-fixes) below, or ask on [Discord](https://discord.gg/U47eFqAXCn).
|
||||
|
||||
---
|
||||
|
||||
## npm install Warnings (ERESOLVE / peer / deprecated)
|
||||
|
||||
When you run `npm install -g omniroute`, you may see a wall of warnings like `npm warn ERESOLVE`, peer-dependency notices, and `deprecated` messages. **These are expected and harmless.** Your install succeeded if you see `added <N> packages` in the output.
|
||||
|
||||
The warnings come from stale peer-dependency ranges in third-party packages OmniRoute doesn't control:
|
||||
|
||||
1. **`marked-terminal` wants `marked >=1 <16`, found `marked@18`** — works fine in practice; the upstream peer range is just stale.
|
||||
2. **`deprecated prebuild-install@7.1.3`** — the native-binary fetch helper. Only relevant later if a web-cookie provider reports a missing `tls-client-node` native binary (a separate issue, not caused by this warning).
|
||||
|
||||
**No action needed** — the warnings cannot be fully silenced without forking upstream packages.
|
||||
|
||||
---
|
||||
|
||||
## Quick Fixes
|
||||
|
||||
| Problem | Solution |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| First login not working | Set `INITIAL_PASSWORD` in `.env` (no hardcoded default) |
|
||||
| Dashboard opens on wrong port | Set `PORT=20128` and `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
|
||||
| No logs written to disk | Set `APP_LOG_TO_FILE=true` and verify call log capture is enabled |
|
||||
| EACCES: permission denied | Set `DATA_DIR=/path/to/writable/dir` to override `~/.omniroute` |
|
||||
| Routing strategy not saving | Update to the latest v3.x release (Zod schema fix for settings persistence shipped in earlier versions) |
|
||||
| Login crash / blank page | Check Node.js version — see [Node.js Compatibility](#nodejs-compatibility) below |
|
||||
| `dlopen` / `slice is not valid mach-o file` (macOS) | Run `cd $(npm root -g)/omniroute/app && npm rebuild better-sqlite3 && omniroute` — see [macOS native module rebuild](#macos-native-module-rebuild) below |
|
||||
| Proxy "fetch failed" | Ensure proxy config is set at the correct level — see [Proxy Issues](#proxy-issues) below |
|
||||
|
||||
---
|
||||
|
||||
## Node.js Compatibility
|
||||
|
||||
<a name="nodejs-compatibility"></a>
|
||||
|
||||
### Login page crashes or shows "Module self-registration" error
|
||||
|
||||
**Cause:** You are running a Node.js version outside OmniRoute's approved secure runtime floor. The most common case is running an older Node 22 or 24 patch level that falls below the patched security floor OmniRoute requires.
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Login page shows a blank screen or a server error
|
||||
- Console shows `Error: Module did not self-register` or similar native binding errors
|
||||
- The login page shows an **orange warning banner** with your Node version if the runtime is outside the supported secure policy
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. Install a supported Node.js LTS release (recommended: Node.js 24.x):
|
||||
```bash
|
||||
nvm install 24
|
||||
nvm use 24
|
||||
```
|
||||
2. Verify your version: `node --version` should show `v24.0.0` or newer on the 24.x LTS line
|
||||
3. Reinstall OmniRoute: `npm install -g omniroute`
|
||||
4. Restart: `omniroute`
|
||||
|
||||
> **Supported secure versions:** `>=22.22.2 <23` or `>=24.0.0 <27`. Node.js 24.x LTS (Krypton) and Node.js 26 are fully supported.
|
||||
|
||||
### macOS: `dlopen` / "slice is not valid mach-o file"
|
||||
|
||||
<a name="macos-native-module-rebuild"></a>
|
||||
|
||||
**Cause:** After a global `npm install -g omniroute`, the `better-sqlite3` native binary inside the package may have been compiled for a different architecture or Node.js ABI than what is running locally. This is common on macOS (both Apple Silicon and Intel) when the pre-built binary does not match your environment.
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Server fails immediately on startup with a `dlopen` error
|
||||
- Error contains `slice is not valid mach-o file`
|
||||
- Full example:
|
||||
|
||||
```
|
||||
dlopen(/Users/<user>/.nvm/versions/node/v24.14.1/lib/node_modules/omniroute/app/node_modules/better-sqlite3/build/Release/better_sqlite3.node, 0x0001): tried: '...' (slice is not valid mach-o file)
|
||||
```
|
||||
|
||||
**Fix — rebuild for your local environment (no Node.js downgrade required):**
|
||||
|
||||
```bash
|
||||
cd $(npm root -g)/omniroute/app
|
||||
npm rebuild better-sqlite3
|
||||
omniroute
|
||||
```
|
||||
|
||||
> **Note:** This recompiles the native binding against your local Node.js version and CPU architecture, resolving the binary mismatch. The officially supported runtime range is **`>=22.22.2 <23` or `>=24.0.0 <27`** (`SUPPORTED_NODE_RANGE` in `src/shared/utils/nodeRuntimeSupport.ts`, aligned with the `package.json` `engines` field). Node.js 24.x LTS (Krypton) and Node.js 26 are fully supported with `better-sqlite3` v12.x.
|
||||
|
||||
---
|
||||
|
||||
## Proxy Issues
|
||||
|
||||
<a name="proxy-issues"></a>
|
||||
|
||||
### Provider validation shows "fetch failed"
|
||||
|
||||
**Cause:** The API key validation endpoint (`POST /api/providers/validate`) was previously bypassing proxy configuration, causing failures in environments that require proxy routing.
|
||||
|
||||
**Fix (v3.5.5+):** This is now fixed. Provider validation routes through `runWithProxyContext`, honoring provider-level and global proxy settings automatically.
|
||||
|
||||
### Token health check fails with "fetch failed"
|
||||
|
||||
**Cause:** Background OAuth token refresh was not resolving proxy configuration per connection.
|
||||
|
||||
**Fix (v3.5.5+):** The token health check scheduler now resolves proxy config per connection before attempting refresh. Update to v3.5.5+.
|
||||
|
||||
### SOCKS5 proxy returns "invalid onRequestStart method"
|
||||
|
||||
**Cause:** On Node.js 22, the undici@8 dispatcher is incompatible with Node's built-in `fetch()` implementation.
|
||||
|
||||
**Fix (v3.5.5+):** OmniRoute now uses undici's own `fetch()` function when a proxy dispatcher is active, ensuring consistent behavior. Update to v3.5.5+.
|
||||
|
||||
---
|
||||
|
||||
## 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/qwen3.8-max-preview`
|
||||
- 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
|
||||
|
||||
### Kiro multi-account: second account invalidates the first
|
||||
|
||||
**Cause:** Kiro's backend enforces a single active session per OIDC client registration.
|
||||
When two accounts share the same registered client (connections imported before v3.8.0),
|
||||
refreshing one account's token invalidates the other's refresh token.
|
||||
|
||||
**Fix (v3.8.0+):** Re-import affected connections.
|
||||
Starting with v3.8.0, every new Kiro connection created via **Import Token**,
|
||||
**Google/GitHub social login**, or **Auto-Import** automatically registers its own
|
||||
dedicated OIDC client. The connection is therefore fully isolated and refreshing one
|
||||
account has no effect on any other account.
|
||||
|
||||
Connections that were imported _before_ v3.8.0 do not carry a per-connection client
|
||||
registration. Those connections continue to use the shared social-auth refresh endpoint.
|
||||
To gain isolation, delete the old connection from Dashboard → Providers and re-add it
|
||||
via any of the three import flows.
|
||||
|
||||
For full details and step-by-step instructions for adding two Kiro accounts side by side,
|
||||
see [`docs/guides/KIRO_SETUP.md`](../guides/KIRO_SETUP.md).
|
||||
|
||||
---
|
||||
|
||||
## 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 (Qoder, Kiro) for non-critical tasks
|
||||
4. Set cost budgets per API key: Dashboard → API Keys → Budget
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Log Files
|
||||
|
||||
Set `APP_LOG_TO_FILE=true` in your `.env` file. Application logs are written under `logs/`.
|
||||
Request artifacts are stored under `${DATA_DIR}/call_logs/` when the call log pipeline is
|
||||
enabled in settings.
|
||||
When pipeline capture is enabled, set `CALL_LOG_PIPELINE_CAPTURE_STREAM_CHUNKS=false` to omit
|
||||
stream chunk payloads, or tune `CALL_LOG_PIPELINE_MAX_SIZE_KB` to change the artifact cap in KB.
|
||||
|
||||
### 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}/storage.sqlite` (providers, combos, aliases, keys, settings)
|
||||
- Usage: SQLite tables in `storage.sqlite` (`usage_history`, `call_logs`, `proxy_logs`) + optional `${DATA_DIR}/call_logs/`
|
||||
- Application logs: `<repo>/logs/...` (when `APP_LOG_TO_FILE=true`)
|
||||
- Call log artifacts: `${DATA_DIR}/call_logs/YYYY-MM-DD/...` when the call log pipeline is enabled
|
||||
|
||||
The Request Logs page's **Clean history** action clears `call_logs`, legacy
|
||||
`request_detail_logs`, and the local `${DATA_DIR}/call_logs/` artifact directory.
|
||||
|
||||
---
|
||||
|
||||
## 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** — Resolved in v1.x; response sanitizer strips non-standard fields (`x_groq`, `usage_breakdown`, etc.) that cause OpenAI SDK Pydantic validation failures. If you still see this on v3.x+, please file an issue.
|
||||
- **GLM/ERNIE rejects `system` role** — Resolved in v1.x; role normalizer automatically merges system messages into user messages for incompatible models. If you still see this on v3.x+, please file an issue.
|
||||
- **`developer` role not recognized** — Resolved in v1.x; automatically converted to `system` for non-OpenAI providers. If you still see this on v3.x+, please file an issue.
|
||||
- **`json_schema` not working with Gemini** — Resolved in v1.x; `response_format` is now converted to Gemini's `responseMimeType` + `responseSchema`. If you still see this on v3.x+, please file an issue.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
## v3.8.0 Known Issues
|
||||
|
||||
Issues specific to the v3.8.0 release and their current workarounds. If a fix lands in a later patch, the entry will be updated or removed.
|
||||
|
||||
### Devin CLI auth failures
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- "Devin CLI not found" or "auth failed" when invoking Devin-backed tools
|
||||
- CLI runtime check reports `installed=false`
|
||||
|
||||
**Causes:**
|
||||
|
||||
- `CLI_DEVIN_BIN` points to a path that does not exist
|
||||
- Devin CLI is not installed on the host
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. Install the Devin CLI for your platform
|
||||
2. Set `CLI_DEVIN_BIN=/usr/local/bin/devin` (or the real path) in `.env`
|
||||
3. Restart OmniRoute and re-test from **Dashboard → CLI Tools**
|
||||
|
||||
### Model cooldown stuck (manual reset)
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- A model stays listed in cooldown even after the expiration time has passed
|
||||
- Requests still skip the model in combo routing despite the timestamp being in the past
|
||||
|
||||
**Manual reset:**
|
||||
|
||||
- **Dashboard:** **Settings → Model Cooldowns** → click **Re-enable** on the affected card
|
||||
- **API:** `DELETE /api/resilience/model-cooldowns` with management auth headers
|
||||
|
||||
### Command Code provider connection fails with 403
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- 403 when testing the Command Code provider connection
|
||||
- The provider card shows "unauthorized" after a fresh add
|
||||
|
||||
**Cause:** The OAuth flow did not complete (callback not received or token not persisted).
|
||||
|
||||
**Fix:**
|
||||
|
||||
- Run `omniroute providers` from the CLI to re-trigger the OAuth flow, or
|
||||
- Re-run OAuth from **Dashboard → Providers → Command Code → Reconnect**
|
||||
|
||||
### ModelScope returns aggressive 429 cooldowns
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Very short or immediate cooldowns on ModelScope after a small burst of requests
|
||||
- Combo routing skips ModelScope earlier than expected
|
||||
|
||||
**Cause:** ModelScope emits provider-specific `Retry-After` headers. v3.8.0 ships dedicated handling for those headers, so older versions misread them as generic rate-limit hints.
|
||||
|
||||
**Fix:**
|
||||
|
||||
- Ensure you are on v3.8.0 or later
|
||||
- Verify the `useUpstream429BreakerHints` toggle is enabled under **Settings → Resilience**
|
||||
|
||||
### OMNIROUTE_WS_BRIDGE_SECRET missing in production
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- 401 on every Codex/Responses WebSocket bridge request when running on a remote production host
|
||||
- WebSocket bridge handshake closes immediately after connect
|
||||
|
||||
**Cause:** The `OMNIROUTE_WS_BRIDGE_SECRET` env var is missing from the production environment.
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. Generate a random secret: `openssl rand -hex 32`
|
||||
2. Set `OMNIROUTE_WS_BRIDGE_SECRET=<random-secret>` in the production server env (and any client that talks to the bridge)
|
||||
3. Restart OmniRoute
|
||||
|
||||
### Responses API: background mode degraded to synchronous
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Warning logged: `background mode degraded to synchronous`
|
||||
- A `background: true` request returns a normal synchronous response instead of a background job handle
|
||||
|
||||
**Cause:** v3.8.0 intentionally degrades `background: true` on the Responses API to synchronous execution while emitting a warning. Full async background execution is a future deliverable.
|
||||
|
||||
**Fix:**
|
||||
|
||||
- Adjust the client to call without `background`, or
|
||||
- Wait for a later release that ships full async background mode (track the changelog)
|
||||
|
||||
---
|
||||
|
||||
## Still Stuck?
|
||||
|
||||
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
|
||||
- **Architecture**: See [`docs/architecture/ARCHITECTURE.md`](../architecture/ARCHITECTURE.md) for internal details
|
||||
- **API Reference**: See [`docs/reference/API_REFERENCE.md`](../reference/API_REFERENCE.md) for all endpoints
|
||||
- **Health Dashboard**: Check **Dashboard → Health** for real-time system status
|
||||
- **Translator**: Use **Dashboard → Translator** to debug format issues
|
||||
@@ -336,6 +336,57 @@ Endpoint tunnel panels (Cloudflare, Tailscale, ngrok) can be shown or hidden fro
|
||||
|
||||
Multi-platform manifest: `linux/amd64` + `linux/arm64` native (Apple Silicon, AWS Graviton, Raspberry Pi). Docker selects the matching architecture automatically; pass `--platform linux/amd64` if you need to force AMD64 emulation on ARM hosts.
|
||||
|
||||
### Release Channels
|
||||
|
||||
OmniRoute publishes separate Docker channels for stable releases, active release-branch testing, and development builds.
|
||||
|
||||
| Channel | Source | Mutability | Recommended use |
|
||||
| --- | --- | --- | --- |
|
||||
| `:<version>` / `:<version>-web` | Signed/versioned release | Immutable | Production deployments that pin an exact release |
|
||||
| `:latest` / `:latest-web` | Highest stable release | Mutable stable pointer | Production deployments that intentionally follow stable releases |
|
||||
| `:next` / `:next-web` | Current default `release/v*` branch | Mutable pre-release pointer | Testing fixes that have landed on the active release branch but are not yet in a stable release |
|
||||
| `:main` / `:main-web` | `main` branch | Mutable development pointer | Development and integration testing only |
|
||||
|
||||
#### Using the pre-release channel
|
||||
|
||||
The `next` channel is rebuilt on every push to the current default `release/v*` branch and is published for both AMD64 and ARM64. Older maintenance branches cannot overwrite it. The channel provides a pullable image for fixes that have merged into the active release branch before the next stable tag is cut.
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:next
|
||||
docker pull diegosouzapw/omniroute:next-web
|
||||
```
|
||||
|
||||
For Docker Compose, override the image tag used by the selected profile, then pull and recreate the service:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
omniroute:
|
||||
image: diegosouzapw/omniroute:next
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
#### Safety and rollback
|
||||
|
||||
`next` is a floating pre-release channel. It may change on any push to the active release branch and is **not supported for production use**. Pin the image digest while evaluating a specific build:
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:next
|
||||
docker image inspect diegosouzapw/omniroute:next --format '{{index .RepoDigests 0}}'
|
||||
```
|
||||
|
||||
Before testing, back up the OmniRoute data volume or bind-mounted data directory. To roll back, restore the previously used stable version or digest and recreate the container:
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:<stable-version>
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
A release-branch build can never move `latest`; only an eligible stable semantic version may promote the stable pointer. The `next` images retain the release image inspection and blocking CRITICAL-vulnerability gate.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **SQLite WAL Mode:** `docker stop` should be allowed to finish so OmniRoute can checkpoint the latest changes back into `storage.sqlite`. The bundled Compose files already set a 40s stop grace period. If you run the image directly, keep `--stop-timeout 40`.
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
title: "Docker Release Channels"
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-08-06
|
||||
---
|
||||
|
||||
# Docker Release Channels
|
||||
|
||||
OmniRoute publishes separate Docker channels for stable releases, active release-branch testing, and development builds.
|
||||
|
||||
## Channel summary
|
||||
|
||||
| Channel | Source | Mutability | Recommended use |
|
||||
| --- | --- | --- | --- |
|
||||
| `:<version>` / `:<version>-web` | Signed/versioned release | Immutable | Production deployments that pin an exact release |
|
||||
| `:latest` / `:latest-web` | Highest stable release | Mutable stable pointer | Production deployments that intentionally follow stable releases |
|
||||
| `:next` / `:next-web` | Current default `release/v*` branch | Mutable pre-release pointer | Testing fixes that have landed on the active release branch but are not yet in a stable release |
|
||||
| `:main` / `:main-web` | `main` branch | Mutable development pointer | Development and integration testing only |
|
||||
|
||||
## Using the pre-release channel
|
||||
|
||||
The `next` channel is rebuilt on every push to the current default `release/v*` branch and is published for both AMD64 and ARM64. Older maintenance branches cannot overwrite it. The channel provides a pullable image for fixes that have merged into the active release branch before the next stable tag is cut.
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:next
|
||||
docker pull diegosouzapw/omniroute:next-web
|
||||
```
|
||||
|
||||
For Docker Compose, override the image tag used by the selected profile, then pull and recreate the service:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
omniroute:
|
||||
image: diegosouzapw/omniroute:next
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Safety and rollback
|
||||
|
||||
`next` is a floating pre-release channel. It may change on any push to the active release branch and is **not supported for production use**. Pin the image digest while evaluating a specific build:
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:next
|
||||
docker image inspect diegosouzapw/omniroute:next --format '{{index .RepoDigests 0}}'
|
||||
```
|
||||
|
||||
Before testing, back up the OmniRoute data volume or bind-mounted data directory. To roll back, restore the previously used stable version or digest and recreate the container:
|
||||
|
||||
```bash
|
||||
docker pull diegosouzapw/omniroute:<stable-version>
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
A release-branch build can never move `latest`; only an eligible stable semantic version may promote the stable pointer. The `next` images retain the release image inspection and blocking CRITICAL-vulnerability gate.
|
||||
@@ -38,6 +38,19 @@ Common problems and solutions for OmniRoute.
|
||||
|
||||
---
|
||||
|
||||
## npm install Warnings (ERESOLVE / peer / deprecated)
|
||||
|
||||
When you run `npm install -g omniroute`, you may see a wall of warnings like `npm warn ERESOLVE`, peer-dependency notices, and `deprecated` messages. **These are expected and harmless.** Your install succeeded if you see `added <N> packages` in the output.
|
||||
|
||||
The warnings come from stale peer-dependency ranges in third-party packages OmniRoute doesn't control:
|
||||
|
||||
1. **`marked-terminal` wants `marked >=1 <16`, found `marked@18`** — works fine in practice; the upstream peer range is just stale.
|
||||
2. **`deprecated prebuild-install@7.1.3`** — the native-binary fetch helper. Only relevant later if a web-cookie provider reports a missing `tls-client-node` native binary (a separate issue, not caused by this warning).
|
||||
|
||||
**No action needed** — the warnings cannot be fully silenced without forking upstream packages.
|
||||
|
||||
---
|
||||
|
||||
## Quick Fixes
|
||||
|
||||
| Problem | Solution |
|
||||
|
||||
@@ -1,498 +0,0 @@
|
||||
---
|
||||
title: "Rozwiązywanie problemów"
|
||||
version: 3.8.40
|
||||
lastUpdated: 2026-06-28
|
||||
---
|
||||
|
||||
# Rozwiązywanie problemów
|
||||
|
||||
> **Dla użytkowników**: Szukasz szybkich poprawek? Zobacz [Szybki przewodnik](#quick-reference) poniżej.
|
||||
|
||||
🌐 **Languages:** 🇺🇸 [English](./TROUBLESHOOTING.md) | 🇧🇷 [Português (Brasil)](../i18n/pt-BR/docs/guides/TROUBLESHOOTING.md) | 🇪🇸 [Español](../i18n/es/docs/guides/TROUBLESHOOTING.md) | 🇫🇷 [Français](../i18n/fr/docs/guides/TROUBLESHOOTING.md) | 🇮🇹 [Italiano](../i18n/it/docs/guides/TROUBLESHOOTING.md) | 🇷🇺 [Русский](../i18n/ru/docs/guides/TROUBLESHOOTING.md) | 🇨🇳 [中文 (简体)](../i18n/zh-CN/docs/guides/TROUBLESHOOTING.md) | 🇩🇪 [Deutsch](../i18n/de/docs/guides/TROUBLESHOOTING.md) | 🇮🇳 [हिन्दी](../i18n/in/docs/guides/TROUBLESHOOTING.md) | 🇹🇭 [ไทย](../i18n/th/docs/guides/TROUBLESHOOTING.md) | 🇺🇦 [Українська](../i18n/uk-UA/docs/guides/TROUBLESHOOTING.md) | 🇸🇦 [العربية](../i18n/ar/docs/guides/TROUBLESHOOTING.md) | 🇯🇵 [日本語](../i18n/ja/docs/guides/TROUBLESHOOTING.md) | 🇻🇳 [Tiếng Việt](../i18n/vi/docs/guides/TROUBLESHOOTING.md) | 🇧🇬 [Български](../i18n/bg/docs/guides/TROUBLESHOOTING.md) | 🇩🇰 [Dansk](../i18n/da/docs/guides/TROUBLESHOOTING.md) | 🇫🇮 [Suomi](../i18n/fi/docs/guides/TROUBLESHOOTING.md) | 🇮🇱 [עברית](../i18n/he/docs/guides/TROUBLESHOOTING.md) | 🇭🇺 [Magyar](../i18n/hu/docs/guides/TROUBLESHOOTING.md) | 🇮🇩 [Bahasa Indonesia](../i18n/id/docs/guides/TROUBLESHOOTING.md) | 🇰🇷 [한국어](../i18n/ko/docs/guides/TROUBLESHOOTING.md) | 🇲🇾 [Bahasa Melayu](../i18n/ms/docs/guides/TROUBLESHOOTING.md) | 🇳🇱 [Nederlands](../i18n/nl/docs/guides/TROUBLESHOOTING.md) | 🇳🇴 [Norsk](../i18n/no/docs/guides/TROUBLESHOOTING.md) | 🇵🇹 [Português (Portugal)](../i18n/pt/docs/guides/TROUBLESHOOTING.md) | 🇷🇴 [Română](../i18n/ro/docs/guides/TROUBLESHOOTING.md) | 🇵🇱 [Polski](../i18n/pl/docs/guides/TROUBLESHOOTING.md) | 🇸🇰 [Slovenčina](../i18n/sk/docs/guides/TROUBLESHOOTING.md) | 🇸🇪 [Svenska](../i18n/sv/docs/guides/TROUBLESHOOTING.md) | 🇵🇭 [Filipino](../i18n/phi/docs/guides/TROUBLESHOOTING.md) | 🇨🇿 [Čeština](../i18n/cs/docs/guides/TROUBLESHOOTING.md)
|
||||
|
||||
Typowe problemy i rozwiązania dla OmniRoute.
|
||||
|
||||
---
|
||||
|
||||
## Szybki przewodnik
|
||||
|
||||
**Nowy w OmniRoute?** Zacznij tutaj — te wskazówki rozwiązują 90% problemów:
|
||||
|
||||
| Widzę to | Co to oznacza | Co zrobić |
|
||||
| ----------------------- | ---------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| "Can't connect" | OmniRoute nie działa | Uruchom `omniroute` lub `docker restart omniroute` |
|
||||
| "Invalid API key" | Klucz jest błędny lub wygasł | Skopiuj ponownie klucz ze strony providera |
|
||||
| "Rate limit exceeded" | Wysyłasz zbyt wiele żądań | Poczekaj 1 minutę albo użyj `model: "auto"` do automatycznego fallbacku |
|
||||
| "Quota exceeded" | Wykorzystałeś darmowy/płatny limit | Podłącz więcej providerów albo użyj darmowych (Kiro, Pollinations) |
|
||||
| "Slow responses" | Provider jest obciążony lub daleko | Użyj `model: "auto/fast"` albo podłącz szybszego providera (Groq, Cerebras) |
|
||||
| "Wrong provider used" | `auto` wybrał innego providera | To normalne! `auto` wybiera najlepszego. Wymuś konkretnego: `model: "openai/gpt-4o"` |
|
||||
| "502 Bad Gateway" | Provider nie działa | Poczekaj i spróbuj ponownie albo użyj `model: "auto"`, aby przełączyć providera |
|
||||
| "401 Unauthorized" | Błędne dane uwierzytelniające | Sprawdź klucz API albo ponownie uwierzytelnij się przez OAuth |
|
||||
| "429 Too Many Requests" | Limit zapytań | Poczekaj 1 minutę albo podłącz więcej providerów |
|
||||
|
||||
**Nadal utknąłeś?** Zobacz [Szybkie poprawki](#quick-fixes) poniżej albo zapytaj na [Discordzie](https://discord.gg/U47eFqAXCn).
|
||||
|
||||
---
|
||||
|
||||
## Ostrzeżenia npm install (ERESOLVE / peer / deprecated)
|
||||
|
||||
Po `npm install -g omniroute` możesz zobaczyć lawinę ostrzeżeń typu `npm warn ERESOLVE`, komunikaty o peer-dependency oraz `deprecated`. **Są one oczekiwane i nieszkodliwe.** Instalacja się powiodła, jeśli w wyniku widać `added <N> packages`.
|
||||
|
||||
Ostrzeżenia pochodzą z przestarzałych zakresów peer-dependency w pakietach firm trzecich, których OmniRoute nie kontroluje:
|
||||
|
||||
1. **`marked-terminal` chce `marked >=1 <16`, znaleziono `marked@18`** — w praktyce działa poprawnie; zakres peer po stronie upstream jest po prostu nieaktualny.
|
||||
2. **`deprecated prebuild-install@7.1.3`** — helper do pobierania natywnych binarek. Istotny dopiero później, jeśli provider web-cookie zgłosi brak natywnej binarki `tls-client-node` (osobny problem, nie spowodowany tym ostrzeżeniem).
|
||||
|
||||
**Nie trzeba nic robić** — ostrzeżeń nie da się w pełni wyciszyć bez forka pakietów upstream.
|
||||
|
||||
---
|
||||
|
||||
## Szybkie poprawki
|
||||
|
||||
| Problem | Rozwiązanie |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Pierwsze logowanie nie działa | Ustaw `INITIAL_PASSWORD` w `.env` (brak wbudowanego domyślnego hasła) |
|
||||
| Dashboard otwiera się na złym porcie | Ustaw `PORT=20128` i `NEXT_PUBLIC_BASE_URL=http://localhost:20128` |
|
||||
| Brak logów na dysku | Ustaw `APP_LOG_TO_FILE=true` i upewnij się, że przechwytywanie call log jest włączone |
|
||||
| EACCES: permission denied | Ustaw `DATA_DIR=/path/to/writable/dir`, aby nadpisać `~/.omniroute` |
|
||||
| Strategia routingu się nie zapisuje | Zaktualizuj do najnowszego wydania v3.x (poprawka schematu Zod dla persystencji ustawień weszła we wcześniejszych wersjach) |
|
||||
| Crash logowania / pusta strona | Sprawdź wersję Node.js — zobacz [Zgodność z Node.js](#nodejs-compatibility) poniżej |
|
||||
| `dlopen` / `slice is not valid mach-o file` (macOS) | Uruchom `cd $(npm root -g)/omniroute/app && npm rebuild better-sqlite3 && omniroute` — zobacz [przebudowa modułu natywnego na macOS](#macos-native-module-rebuild) poniżej |
|
||||
| Proxy "fetch failed" | Upewnij się, że konfiguracja proxy jest ustawiona na właściwym poziomie — zobacz [Problemy z proxy](#proxy-issues) poniżej |
|
||||
|
||||
---
|
||||
|
||||
## Zgodność z Node.js
|
||||
|
||||
<a name="nodejs-compatibility"></a>
|
||||
|
||||
### Strona logowania się wykrzacza lub pokazuje błąd "Module self-registration"
|
||||
|
||||
**Przyczyna:** Uruchamiasz wersję Node.js poniżej zatwierdzonego bezpiecznego poziomu runtime OmniRoute. Najczęstszy przypadek to starszy patch Node 22 lub 24 poniżej wymaganego przez OmniRoute poziomu bezpieczeństwa.
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- Strona logowania pokazuje pusty ekran lub błąd serwera
|
||||
- Konsola pokazuje `Error: Module did not self-register` lub podobne błędy natywnych bindingów
|
||||
- Strona logowania pokazuje **pomarańczowy baner ostrzegawczy** z Twoją wersją Node, jeśli runtime jest poza wspieraną bezpieczną polityką
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
1. Zainstaluj wspierane wydanie Node.js LTS (zalecane: Node.js 24.x):
|
||||
```bash
|
||||
nvm install 24
|
||||
nvm use 24
|
||||
```
|
||||
2. Sprawdź wersję: `node --version` powinno pokazać `v24.0.0` lub nowsze w linii LTS 24.x
|
||||
3. Zainstaluj ponownie OmniRoute: `npm install -g omniroute`
|
||||
4. Uruchom ponownie: `omniroute`
|
||||
|
||||
> **Wspierane bezpieczne wersje:** `>=22.22.2 <23` lub `>=24.0.0 <27`. Node.js 24.x LTS (Krypton) oraz Node.js 26 są w pełni wspierane.
|
||||
|
||||
### macOS: `dlopen` / "slice is not valid mach-o file"
|
||||
|
||||
<a name="macos-native-module-rebuild"></a>
|
||||
|
||||
**Przyczyna:** Po globalnym `npm install -g omniroute` natywna binarka `better-sqlite3` w pakiecie mogła zostać skompilowana pod inną architekturę lub ABI Node.js niż ta, która działa lokalnie. To częste na macOS (Apple Silicon i Intel), gdy prebuilt nie pasuje do środowiska.
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- Serwer pada natychmiast przy starcie z błędem `dlopen`
|
||||
- Błąd zawiera `slice is not valid mach-o file`
|
||||
- Pełny przykład:
|
||||
|
||||
```
|
||||
dlopen(/Users/<user>/.nvm/versions/node/v24.14.1/lib/node_modules/omniroute/app/node_modules/better-sqlite3/build/Release/better_sqlite3.node, 0x0001): tried: '...' (slice is not valid mach-o file)
|
||||
```
|
||||
|
||||
**Naprawa — przebuduj pod lokalne środowisko (bez downgrade Node.js):**
|
||||
|
||||
```bash
|
||||
cd $(npm root -g)/omniroute/app
|
||||
npm rebuild better-sqlite3
|
||||
omniroute
|
||||
```
|
||||
|
||||
> **Uwaga:** To rekompiluje natywny binding względem lokalnej wersji Node.js i architektury CPU, usuwając niedopasowanie binarki. Oficjalnie wspierany zakres runtime to **`>=22.22.2 <23` lub `>=24.0.0 <27`** (`SUPPORTED_NODE_RANGE` w `src/shared/utils/nodeRuntimeSupport.ts`, zgodny z polem `engines` w `package.json`). Node.js 24.x LTS (Krypton) oraz Node.js 26 są w pełni wspierane z `better-sqlite3` v12.x.
|
||||
|
||||
---
|
||||
|
||||
## Problemy z proxy
|
||||
|
||||
<a name="proxy-issues"></a>
|
||||
|
||||
### Walidacja providera pokazuje "fetch failed"
|
||||
|
||||
**Przyczyna:** Endpoint walidacji klucza API (`POST /api/providers/validate`) wcześniej omijał konfigurację proxy, co powodowało błędy w środowiskach wymagających routingu przez proxy.
|
||||
|
||||
**Naprawa (v3.5.5+):** To już naprawione. Walidacja providera idzie przez `runWithProxyContext` i automatycznie respektuje ustawienia proxy na poziomie providera oraz globalne.
|
||||
|
||||
### Token health check kończy się "fetch failed"
|
||||
|
||||
**Przyczyna:** Tło odświeżania tokenów OAuth nie rozwiązywało konfiguracji proxy per połączenie.
|
||||
|
||||
**Naprawa (v3.5.5+):** Scheduler token health check rozwiązuje teraz config proxy per połączenie przed odświeżeniem. Zaktualizuj do v3.5.5+.
|
||||
|
||||
### Proxy SOCKS5 zwraca "invalid onRequestStart method"
|
||||
|
||||
**Przyczyna:** Na Node.js 22 dispatcher undici@8 jest niekompatybilny z wbudowaną implementacją `fetch()` w Node.
|
||||
|
||||
**Naprawa (v3.5.5+):** OmniRoute używa teraz własnej funkcji `fetch()` z undici, gdy aktywny jest dispatcher proxy, co zapewnia spójne zachowanie. Zaktualizuj do v3.5.5+.
|
||||
|
||||
---
|
||||
|
||||
## Problemy z providerami
|
||||
|
||||
### "Language model did not provide messages"
|
||||
|
||||
**Przyczyna:** Wyczerpany limit (quota) providera.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
1. Sprawdź tracker limitu w dashboardzie
|
||||
2. Użyj combo z poziomami fallback
|
||||
3. Przełącz się na tańszy/darmowy tier
|
||||
|
||||
### Rate limiting
|
||||
|
||||
**Przyczyna:** Wyczerpany limit subskrypcji.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
- Dodaj fallback: `cc/claude-opus-4-6 → glm/glm-4.7 → if/qwen3.8-max-preview`
|
||||
- Użyj GLM/MiniMax jako taniego zapasowego
|
||||
|
||||
### Wygasły token OAuth
|
||||
|
||||
OmniRoute automatycznie odświeża tokeny. Jeśli problemy trwają:
|
||||
|
||||
1. Dashboard → Provider → Reconnect
|
||||
2. Usuń i dodaj ponownie połączenie providera
|
||||
|
||||
### Kiro multi-account: drugie konto unieważnia pierwsze
|
||||
|
||||
**Przyczyna:** Backend Kiro wymusza jedną aktywną sesję na rejestrację klienta OIDC.
|
||||
Gdy dwa konta współdzielą tego samego zarejestrowanego klienta (połączenia zaimportowane przed v3.8.0),
|
||||
odświeżenie tokenu jednego konta unieważnia refresh token drugiego.
|
||||
|
||||
**Naprawa (v3.8.0+):** Zaimportuj ponownie dotknięte połączenia.
|
||||
Od v3.8.0 każde nowe połączenie Kiro utworzone przez **Import Token**,
|
||||
**Google/GitHub social login** lub **Auto-Import** automatycznie rejestruje własnego
|
||||
dedykowanego klienta OIDC. Połączenie jest więc w pełni izolowane i odświeżenie jednego
|
||||
konta nie wpływa na żadne inne.
|
||||
|
||||
Połączenia zaimportowane _przed_ v3.8.0 nie niosą rejestracji klienta per połączenie.
|
||||
Te połączenia nadal używają współdzielonego endpointu odświeżania social-auth.
|
||||
Aby uzyskać izolację, usuń stare połączenie z Dashboard → Providers i dodaj je ponownie
|
||||
przez dowolny z trzech przepływów importu.
|
||||
|
||||
Pełne szczegóły i instrukcja krok po kroku dodawania dwóch kont Kiro obok siebie:
|
||||
zobacz [`docs/guides/KIRO_SETUP.md`](../guides/KIRO_SETUP.md).
|
||||
|
||||
---
|
||||
|
||||
## Problemy z chmurą
|
||||
|
||||
### Błędy synchronizacji chmury
|
||||
|
||||
1. Sprawdź, czy `BASE_URL` wskazuje na działającą instancję (np. `http://localhost:20128`)
|
||||
2. Sprawdź, czy `CLOUD_URL` wskazuje na endpoint chmury (np. `https://omniroute.dev`)
|
||||
3. Utrzymuj wartości `NEXT_PUBLIC_*` zgodne z wartościami po stronie serwera
|
||||
|
||||
### Cloud `stream=false` zwraca 500
|
||||
|
||||
**Objaw:** `Unexpected token 'd'...` na endpoincie chmury przy wywołaniach bez streamingu.
|
||||
|
||||
**Przyczyna:** Upstream zwraca payload SSE, a klient oczekuje JSON.
|
||||
|
||||
**Obejście:** Użyj `stream=true` przy bezpośrednich wywołaniach cloud. Lokalny runtime ma fallback SSE→JSON.
|
||||
|
||||
### Cloud pokazuje Connected, ale "Invalid API key"
|
||||
|
||||
1. Utwórz świeży klucz z lokalnego dashboardu (`/api/keys`)
|
||||
2. Uruchom synchronizację chmury: Enable Cloud → Sync Now
|
||||
3. Stare/niesynchronizowane klucze mogą nadal zwracać `401` w chmurze
|
||||
|
||||
---
|
||||
|
||||
## Problemy z Dockerem
|
||||
|
||||
### Narzędzie CLI pokazuje Not Installed
|
||||
|
||||
1. Sprawdź pola runtime: `curl http://localhost:20128/api/cli-tools/runtime/codex | jq`
|
||||
2. Dla trybu portable: użyj targetu obrazu `runner-cli` (dołączone CLI)
|
||||
3. Dla trybu host mount: ustaw `CLI_EXTRA_PATHS` i zamontuj katalog bin hosta jako tylko do odczytu
|
||||
4. Jeśli `installed=true` i `runnable=false`: binarka znaleziona, ale healthcheck się nie powiódł
|
||||
|
||||
### Szybka walidacja runtime
|
||||
|
||||
```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}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Problemy z kosztami
|
||||
|
||||
### Wysokie koszty
|
||||
|
||||
1. Sprawdź statystyki użycia w Dashboard → Usage
|
||||
2. Przełącz model główny na GLM/MiniMax
|
||||
3. Używaj darmowego tieru (Qoder, Kiro) do mniej krytycznych zadań
|
||||
4. Ustaw budżety kosztów per klucz API: Dashboard → API Keys → Budget
|
||||
|
||||
---
|
||||
|
||||
## Debugowanie
|
||||
|
||||
### Włącz pliki logów
|
||||
|
||||
Ustaw `APP_LOG_TO_FILE=true` w pliku `.env`. Logi aplikacji trafiają do `logs/`.
|
||||
Artefakty żądań są przechowywane w `${DATA_DIR}/call_logs/`, gdy pipeline call log jest
|
||||
włączony w ustawieniach.
|
||||
Gdy przechwytywanie pipeline jest włączone, ustaw `CALL_LOG_PIPELINE_CAPTURE_STREAM_CHUNKS=false`, aby pominąć
|
||||
payloady chunków streamu, albo dostrój `CALL_LOG_PIPELINE_MAX_SIZE_KB`, aby zmienić limit artefaktu w KB.
|
||||
|
||||
### Sprawdź zdrowie providerów
|
||||
|
||||
```bash
|
||||
# Health dashboard
|
||||
http://localhost:20128/dashboard/health
|
||||
|
||||
# API health check
|
||||
curl http://localhost:20128/api/monitoring/health
|
||||
```
|
||||
|
||||
### Przechowywanie w runtime
|
||||
|
||||
- Stan główny: `${DATA_DIR}/storage.sqlite` (providers, combos, aliases, keys, settings)
|
||||
- Użycie: tabele SQLite w `storage.sqlite` (`usage_history`, `call_logs`, `proxy_logs`) + opcjonalnie `${DATA_DIR}/call_logs/`
|
||||
- Logi aplikacji: `<repo>/logs/...` (gdy `APP_LOG_TO_FILE=true`)
|
||||
- Artefakty call log: `${DATA_DIR}/call_logs/YYYY-MM-DD/...` gdy pipeline call log jest włączony
|
||||
|
||||
Akcja **Clean history** na stronie Request Logs czyści `call_logs`, legacy
|
||||
`request_detail_logs` oraz lokalny katalog artefaktów `${DATA_DIR}/call_logs/`.
|
||||
|
||||
---
|
||||
|
||||
## Problemy z circuit breakerem
|
||||
|
||||
### Provider utknął w stanie OPEN
|
||||
|
||||
Gdy circuit breaker providera jest OPEN, żądania są blokowane do wygaśnięcia cooldownu.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
1. Przejdź do **Dashboard → Settings → Resilience**
|
||||
2. Sprawdź kartę circuit breakera dla dotkniętego providera
|
||||
3. Kliknij **Reset All**, aby wyczyścić wszystkie breakery, albo poczekaj na wygaśnięcie cooldownu
|
||||
4. Upewnij się, że provider jest faktycznie dostępny przed resetem
|
||||
|
||||
### Provider wciąż wyzwala circuit breaker
|
||||
|
||||
Jeśli provider wielokrotnie wchodzi w stan OPEN:
|
||||
|
||||
1. Sprawdź **Dashboard → Health → Provider Health** pod kątem wzorca awarii
|
||||
2. Przejdź do **Settings → Resilience → Provider Profiles** i zwiększ próg awarii
|
||||
3. Sprawdź, czy provider zmienił limity API lub wymaga ponownego uwierzytelnienia
|
||||
4. Przejrzyj telemetrię opóźnień — wysoka latencja może powodować awarie oparte na timeoutach
|
||||
|
||||
---
|
||||
|
||||
## Problemy z transkrypcją audio
|
||||
|
||||
### Błąd "Unsupported model"
|
||||
|
||||
- Upewnij się, że używasz właściwego prefiksu: `deepgram/nova-3` lub `assemblyai/best`
|
||||
- Sprawdź, czy provider jest podłączony w **Dashboard → Providers**
|
||||
|
||||
### Transkrypcja zwraca pusto lub się nie udaje
|
||||
|
||||
- Sprawdź wspierane formaty audio: `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`
|
||||
- Upewnij się, że rozmiar pliku mieści się w limitach providera (zazwyczaj < 25MB)
|
||||
- Sprawdź ważność klucza API na karcie providera
|
||||
|
||||
---
|
||||
|
||||
## Debugowanie translatora
|
||||
|
||||
Użyj **Dashboard → Translator**, aby debugować problemy z tłumaczeniem formatów:
|
||||
|
||||
| Tryb | Kiedy używać |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| **Playground** | Porównaj formaty wejścia/wyjścia obok siebie — wklej padające żądanie, by zobaczyć tłumaczenie |
|
||||
| **Chat Tester** | Wysyłaj żywe wiadomości i przeglądaj pełny payload request/response wraz z nagłówkami |
|
||||
| **Test Bench** | Uruchamiaj testy wsadowe na kombinacjach formatów, by znaleźć zepsute tłumaczenia |
|
||||
| **Live Monitor** | Obserwuj przepływ żądań w czasie rzeczywistym, by wyłapać przerywane problemy z tłumaczeniem |
|
||||
|
||||
### Typowe problemy z formatami
|
||||
|
||||
- **Brak tagów thinking** — Sprawdź, czy docelowy provider wspiera thinking i ustawienie thinking budget
|
||||
- **Znikające tool calls** — Niektóre tłumaczenia formatów mogą usuwać nieobsługiwane pola; sprawdź w trybie Playground
|
||||
- **Brak system prompt** — Claude i Gemini obsługują system prompts inaczej; sprawdź wynik tłumaczenia
|
||||
- **SDK zwraca surowy string zamiast obiektu** — Naprawione w v1.x; sanitizer odpowiedzi usuwa niestandardowe pola (`x_groq`, `usage_breakdown` itd.), które powodują błędy walidacji Pydantic w OpenAI SDK. Jeśli nadal to widzisz na v3.x+, zgłoś issue.
|
||||
- **GLM/ERNIE odrzuca rolę `system`** — Naprawione w v1.x; normalizer ról automatycznie scala wiadomości system w user dla niekompatybilnych modeli. Jeśli nadal to widzisz na v3.x+, zgłoś issue.
|
||||
- **Rola `developer` nierozpoznana** — Naprawione w v1.x; automatycznie konwertowana na `system` dla providerów spoza OpenAI. Jeśli nadal to widzisz na v3.x+, zgłoś issue.
|
||||
- **`json_schema` nie działa z Gemini** — Naprawione w v1.x; `response_format` jest teraz konwertowany na `responseMimeType` + `responseSchema` Gemini. Jeśli nadal to widzisz na v3.x+, zgłoś issue.
|
||||
|
||||
---
|
||||
|
||||
## Ustawienia odporności (Resilience)
|
||||
|
||||
### Auto rate-limit się nie uruchamia
|
||||
|
||||
- Auto rate-limit dotyczy tylko providerów z kluczem API (nie OAuth/subskrypcja)
|
||||
- Sprawdź, czy **Settings → Resilience → Provider Profiles** ma włączony auto-rate-limit
|
||||
- Sprawdź, czy provider zwraca kody `429` lub nagłówki `Retry-After`
|
||||
|
||||
### Dostrajanie exponential backoff
|
||||
|
||||
Profile providerów wspierają te ustawienia:
|
||||
|
||||
- **Base delay** — Początkowy czas oczekiwania po pierwszej awarii (domyślnie: 1s)
|
||||
- **Max delay** — Górny limit czasu oczekiwania (domyślnie: 30s)
|
||||
- **Multiplier** — O ile zwiększać opóźnienie przy kolejnych awariach (domyślnie: 2x)
|
||||
|
||||
### Anti-thundering herd
|
||||
|
||||
Gdy wiele równoległych żądań trafia w providera z limitem zapytań, OmniRoute używa mutexa + auto rate-limiting, aby serializować żądania i zapobiegać awariom kaskadowym. Działa to automatycznie dla providerów z kluczem API.
|
||||
|
||||
---
|
||||
|
||||
## Opcjonalna taksonomia awarii RAG / LLM (16 problemów)
|
||||
|
||||
Część użytkowników OmniRoute stawia bramkę przed stackami RAG lub agentów. W takich setupach często widać dziwny wzorzec: OmniRoute wygląda na zdrowe (providery w górze, profile routingu OK, brak alertów rate limit), a ostateczna odpowiedź i tak jest błędna.
|
||||
|
||||
W praktyce te incydenty zwykle pochodzą z downstreamowego pipeline'u RAG, a nie z samej bramki.
|
||||
|
||||
Jeśli chcesz wspólnego słownika do opisu tych awarii, możesz użyć WFGY ProblemMap — zewnętrznego zasobu tekstowego na licencji MIT, który definiuje szesnaście powtarzających się wzorców awarii RAG / LLM. Na wysokim poziomie obejmuje:
|
||||
|
||||
- drift retrieval i zerwane granice kontekstu
|
||||
- puste lub nieaktualne indeksy i magazyny wektorów
|
||||
- niedopasowanie embeddingów do semantyki
|
||||
- składanie promptów i problemy z oknem kontekstu
|
||||
- zapaść logiki i nadmiernie pewne odpowiedzi
|
||||
- awarie długich łańcuchów i koordynacji agentów
|
||||
- dryf pamięci i ról w multi-agent
|
||||
- problemy z deploymentem i kolejnością bootstrapu
|
||||
|
||||
Idea jest prosta:
|
||||
|
||||
1. Gdy badziesz złą odpowiedź, zbierz:
|
||||
- zadanie użytkownika i żądanie
|
||||
- trasę lub combo providerów w OmniRoute
|
||||
- kontekst RAG użyty downstream (pobrane dokumenty, tool calls itd.)
|
||||
2. Zmapuj incydent na jeden lub dwa numery WFGY ProblemMap (`No.1` … `No.16`).
|
||||
3. Zapisz numer we własnym dashboardzie, runbooku lub trackerze incydentów obok logów OmniRoute.
|
||||
4. Użyj odpowiadającej strony WFGY, by zdecydować, czy zmienić stack RAG, retriever, czy strategię routingu.
|
||||
|
||||
Pełny tekst i konkretne przepisy są tutaj (licencja MIT, tylko tekst):
|
||||
|
||||
- [WFGY ProblemMap README](https://github.com/onestardao/WFGY/blob/main/ProblemMap/README.md)
|
||||
|
||||
Możesz zignorować tę sekcję, jeśli nie uruchamiasz pipeline'ów RAG ani agentów za OmniRoute.
|
||||
|
||||
---
|
||||
|
||||
## Znane problemy v3.8.0
|
||||
|
||||
Problemy specyficzne dla wydania v3.8.0 i ich obecne obejścia. Gdy poprawka wejdzie w późniejszym patchu, wpis zostanie zaktualizowany lub usunięty.
|
||||
|
||||
### Błędy auth Devin CLI
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- "Devin CLI not found" lub "auth failed" przy wywoływaniu narzędzi opartych o Devin
|
||||
- Sprawdzenie runtime CLI raportuje `installed=false`
|
||||
|
||||
**Przyczyny:**
|
||||
|
||||
- `CLI_DEVIN_BIN` wskazuje na nieistniejącą ścieżkę
|
||||
- Devin CLI nie jest zainstalowany na hoście
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
1. Zainstaluj Devin CLI dla swojej platformy
|
||||
2. Ustaw `CLI_DEVIN_BIN=/usr/local/bin/devin` (lub rzeczywistą ścieżkę) w `.env`
|
||||
3. Zrestartuj OmniRoute i przetestuj ponownie w **Dashboard → CLI Tools**
|
||||
|
||||
### Cooldown modelu utknął (ręczny reset)
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- Model pozostaje na liście cooldown nawet po upływie czasu wygaśnięcia
|
||||
- Żądania nadal pomijają model w routingu combo mimo że znacznik czasu jest w przeszłości
|
||||
|
||||
**Ręczny reset:**
|
||||
|
||||
- **Dashboard:** **Settings → Model Cooldowns** → kliknij **Re-enable** na dotkniętej karcie
|
||||
- **API:** `DELETE /api/resilience/model-cooldowns` z nagłówkami auth zarządzania
|
||||
|
||||
### Połączenie providera Command Code kończy się 403
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- 403 przy testowaniu połączenia providera Command Code
|
||||
- Karta providera pokazuje "unauthorized" po świeżym dodaniu
|
||||
|
||||
**Przyczyna:** Przepływ OAuth nie zakończył się (callback nieodebrany lub token niezapisany).
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
- Uruchom `omniroute providers` z CLI, aby ponownie wywołać przepływ OAuth, albo
|
||||
- Ponów OAuth z **Dashboard → Providers → Command Code → Reconnect**
|
||||
|
||||
### ModelScope zwraca agresywne cooldowny 429
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- Bardzo krótkie lub natychmiastowe cooldowny na ModelScope po małej serii żądań
|
||||
- Routing combo pomija ModelScope wcześniej niż oczekiwano
|
||||
|
||||
**Przyczyna:** ModelScope emituje specyficzne dla providera nagłówki `Retry-After`. v3.8.0 zawiera dedykowaną obsługę tych nagłówków, więc starsze wersje odczytują je jako generyczne wskazówki rate-limit.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
- Upewnij się, że jesteś na v3.8.0 lub nowszej
|
||||
- Sprawdź, że przełącznik `useUpstream429BreakerHints` jest włączony w **Settings → Resilience**
|
||||
|
||||
### Brak OMNIROUTE_WS_BRIDGE_SECRET w produkcji
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- 401 na każdym żądaniu mostka WebSocket Codex/Responses na zdalnym hoście produkcyjnym
|
||||
- Handshake mostka WebSocket zamyka się natychmiast po połączeniu
|
||||
|
||||
**Przyczyna:** Zmienna środowiskowa `OMNIROUTE_WS_BRIDGE_SECRET` nie jest ustawiona w środowisku produkcyjnym.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
1. Wygeneruj losowy sekret: `openssl rand -hex 32`
|
||||
2. Ustaw `OMNIROUTE_WS_BRIDGE_SECRET=<random-secret>` w env serwera produkcyjnego (oraz każdego klienta łączącego się z mostkiem)
|
||||
3. Zrestartuj OmniRoute
|
||||
|
||||
### Responses API: tryb background zdegradowany do synchronicznego
|
||||
|
||||
**Objawy:**
|
||||
|
||||
- Zalogowane ostrzeżenie: `background mode degraded to synchronous`
|
||||
- Żądanie z `background: true` zwraca zwykłą odpowiedź synchroniczną zamiast uchwytu zadania w tle
|
||||
|
||||
**Przyczyna:** v3.8.0 celowo degraduje `background: true` w Responses API do wykonania synchronicznego z ostrzeżeniem. Pełne asynchroniczne wykonanie w tle to przyszła funkcjonalność.
|
||||
|
||||
**Naprawa:**
|
||||
|
||||
- Dostosuj klienta, aby wywoływał bez `background`, albo
|
||||
- Poczekaj na późniejsze wydanie z pełnym trybem async background (śledź changelog)
|
||||
|
||||
---
|
||||
|
||||
## Nadal utknąłeś?
|
||||
|
||||
- **GitHub Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
|
||||
- **Architektura**: Zobacz [`docs/architecture/ARCHITECTURE.md`](../architecture/ARCHITECTURE.md) po szczegóły wewnętrzne
|
||||
- **API Reference**: Zobacz [`docs/reference/API_REFERENCE.md`](../reference/API_REFERENCE.md) po wszystkie endpointy
|
||||
- **Health Dashboard**: Sprawdź **Dashboard → Health** pod kątem statusu systemu w czasie rzeczywistym
|
||||
- **Translator**: Użyj **Dashboard → Translator** do debugowania problemów z formatami
|
||||
@@ -11,6 +11,10 @@ title: "Quality Gate Playbook"
|
||||
>
|
||||
> Benchmarks: OWASP DSOMM · OpenSSF Scorecard · SLSA · SonarQube "Clean as You Code" ·
|
||||
> Quality-Ratchet pattern · DORA 2024 · OWASP LLM Top 10 (2025) · mutation-testing best practices.
|
||||
>
|
||||
> For the gate-by-gate authoritative reference (what each gate validates, CI job, ratchet vs
|
||||
> policy, blocking vs advisory), see the
|
||||
> [Quality Gates Reference](../architecture/QUALITY_GATES.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -123,3 +123,99 @@ If you changed the credential contract (new storage key, new cookie name, change
|
||||
| Token missing from live request | Request is not authenticated | Sign in and send a chat message first |
|
||||
| 401 after Test Connection passed | Expired or rotated session | Re-copy from a fresh live request |
|
||||
| Chunked token fails | Only one chunk pasted | Select all `__Secure-next-auth.session-token.*` chunks |
|
||||
|
||||
---
|
||||
|
||||
## ChatGPT Web (Codex)
|
||||
|
||||
`ChatGPT Web (Codex)` is an additional provider. The existing
|
||||
`ChatGPT Web (Plus/Pro)` provider described above stays unchanged for regular
|
||||
chats, images, and its existing tool emulation.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- a full Cookie header from a signed-in ChatGPT session;
|
||||
- Chrome or Chromium for npm, systemd, and PM2 installs;
|
||||
- with the Docker `web` profile, the internal Chromium service from `docker-compose.yml`;
|
||||
- an OpenAI tunnel and a ChatGPT custom connector for local Codex tools.
|
||||
|
||||
The tunnel is only needed for tool turns. `pro` is read-only and does not need a
|
||||
local tool connector.
|
||||
|
||||
### Dashboard setup
|
||||
|
||||
1. Open the **ChatGPT Web (Codex)** provider and add a connection.
|
||||
2. Paste the full ChatGPT cookie, the tunnel ID, the runtime key, and the name of
|
||||
the custom connector.
|
||||
3. Start the check. OmniRoute opens a headless Temporary Chat and also detects
|
||||
whether `pro` is available for the account.
|
||||
4. Save the connection. OmniRoute replaces the pasted cookie with the verified
|
||||
Playwright storage state and stores it together with the runtime key through
|
||||
the encrypted credential abstraction.
|
||||
|
||||
The raw cookie is not retained after a successful save. When the session expires,
|
||||
open the connection, paste a fresh full cookie, and re-run the check. The doctor
|
||||
status in the edit dialog reports browser, storage state, sign-in, Temporary
|
||||
Chat, tunnel, connector, and tool round-trip separately.
|
||||
|
||||
### Models and combos
|
||||
|
||||
The fixed models are:
|
||||
|
||||
- `chatgpt-web-codex/instant`
|
||||
- `chatgpt-web-codex/medium`
|
||||
- `chatgpt-web-codex/high`
|
||||
- `chatgpt-web-codex/extra-high`
|
||||
- `chatgpt-web-codex/pro`
|
||||
|
||||
Add one of them to a combo like any other model. The Codex app sends only the
|
||||
combo name as `model` to the regular Responses endpoint `/v1/responses`. There is
|
||||
no special endpoint and no Codex-mode switch.
|
||||
|
||||
`pro` does not run local tools. A forced tool makes that combo target
|
||||
incompatible; with optional tools the turn runs read-only and reports that
|
||||
limitation as commentary.
|
||||
|
||||
### Security model
|
||||
|
||||
- The native path requires a Responses request, a recognized Codex client, and
|
||||
matching thread and turn identities.
|
||||
- Workspace, sandbox, approval policy, and the tool catalog come from the native
|
||||
Codex shell. Free-form prompt text is not an authority for them.
|
||||
- ChatGPT receives only a short-lived capability per turn. The MCP broker accepts
|
||||
only tools that Codex offered in exactly that turn.
|
||||
- Auto-confirming "Allow once" only returns the tool request to Codex. Codex
|
||||
alone decides on approval and execution.
|
||||
- Before the first output, the combo may fall back to another compatible target.
|
||||
After that, provider, model, connection, and browser turn stay pinned until the
|
||||
turn completes.
|
||||
- Cookies, runtime keys, storage state, and capability tokens do not appear in
|
||||
provider responses or request logs.
|
||||
|
||||
### Headless VPS and Docker
|
||||
|
||||
For npm, systemd, and PM2 installs, OmniRoute detects common Chrome and Chromium
|
||||
paths. Alternatively, set `CHATGPT_WEB_CODEX_CHROME_PATH`.
|
||||
|
||||
The Docker `web` profile starts `chatgpt-web-codex-browser` on the internal
|
||||
Compose network. Its CDP port is not published on the host. The protected profile
|
||||
volume stays separate from the OmniRoute data volume, and the browser gets enough
|
||||
shared memory. The internal CDP proxy listens only on the Compose network on port
|
||||
`9223`; Chrome itself stays bound to loopback inside the sidecar.
|
||||
|
||||
A supervisor lease under `DATA_DIR` prevents multiple OmniRoute processes from
|
||||
owning the same tunnel and broker state. A conflict shows up in the doctor.
|
||||
|
||||
### Interactive recovery
|
||||
|
||||
The normal path is fully headless. When ChatGPT demands an interactive sign-in or
|
||||
challenge, the existing VNC browser infrastructure can be used as a recovery
|
||||
path. Browser UI and CDP must then only be reachable over loopback, an
|
||||
authenticated management connection, or an SSH tunnel; noVNC stays disabled in
|
||||
normal operation.
|
||||
|
||||
### WebSocket fallback
|
||||
|
||||
When a combo contains `ChatGPT Web (Codex)`, the Responses WebSocket bridge
|
||||
requests the HTTP/SSE fallback before connecting upstream. The actual transfer
|
||||
then goes through `/v1/responses`.
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
# ChatGPT Web (Codex)
|
||||
|
||||
`ChatGPT Web (Codex)` ist ein zusätzlicher Provider. Der bestehende Provider
|
||||
`ChatGPT Web (Plus/Pro)` bleibt für normale Chats, Bilder und dessen bisherige
|
||||
Tool-Emulation unverändert.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- ein vollständiger Cookie-Header einer angemeldeten ChatGPT-Sitzung;
|
||||
- Chrome oder Chromium bei npm-, systemd- und PM2-Installationen;
|
||||
- beim Docker-Profil `web` der interne Chromium-Dienst aus `docker-compose.yml`;
|
||||
- ein OpenAI-Tunnel und ein ChatGPT-Custom-Connector für lokale Codex-Tools.
|
||||
|
||||
Der Tunnel ist nur für Tool-Runden nötig. `pro` ist read-only und benötigt keinen
|
||||
lokalen Tool-Connector.
|
||||
|
||||
## Einrichtung in der Weboberfläche
|
||||
|
||||
1. Öffne den Provider `ChatGPT Web (Codex)` und füge eine Connection hinzu.
|
||||
2. Füge den vollständigen ChatGPT-Cookie, die Tunnel-ID, den Runtime-Key und den
|
||||
Namen des Custom Connectors ein.
|
||||
3. Starte die Prüfung. OmniRoute öffnet headless einen Temporary Chat und erkennt
|
||||
dabei auch, ob `pro` für das Konto verfügbar ist.
|
||||
4. Speichere die Connection. OmniRoute ersetzt den eingegebenen Cookie durch den
|
||||
geprüften Playwright-Storage-State und speichert ihn zusammen mit dem Runtime-Key
|
||||
über die verschlüsselte Credential-Abstraktion.
|
||||
|
||||
Der rohe Cookie wird nach erfolgreichem Speichern nicht zusätzlich aufbewahrt.
|
||||
Wenn die Sitzung abläuft, öffne die Connection, gib einen frischen vollständigen
|
||||
Cookie ein und prüfe sie erneut. Der Doctor-Status im Edit-Dialog zeigt Browser,
|
||||
Storage-State, Anmeldung, Temporary Chat, Tunnel, Connector und Tool-Roundtrip
|
||||
getrennt an.
|
||||
|
||||
## Modelle und Combos
|
||||
|
||||
Die festen Modelle sind:
|
||||
|
||||
- `chatgpt-web-codex/instant`
|
||||
- `chatgpt-web-codex/medium`
|
||||
- `chatgpt-web-codex/high`
|
||||
- `chatgpt-web-codex/extra-high`
|
||||
- `chatgpt-web-codex/pro`
|
||||
|
||||
Füge eines davon wie jedes andere Modell zu einer Combo hinzu. Die Codex-App
|
||||
sendet nur den Combo-Namen als `model` an den normalen Responses-Endpunkt
|
||||
`/v1/responses`. Es gibt keinen Sonderendpoint und keinen Codex-Modus-Schalter.
|
||||
|
||||
`pro` führt keine lokalen Tools aus. Ein erzwungenes Tool macht dieses Combo-Ziel
|
||||
inkompatibel; bei optionalen Tools läuft der Turn read-only und meldet diese
|
||||
Einschränkung als Commentary.
|
||||
|
||||
## Sicherheitsmodell
|
||||
|
||||
- Der native Pfad verlangt einen Responses-Request, einen erkannten Codex-Client
|
||||
sowie zusammenpassende Thread- und Turn-Identitäten.
|
||||
- Workspace, Sandbox, Approval-Policy und Toolkatalog stammen aus der nativen
|
||||
Codex-Hülle. Freier Prompttext ist dafür keine Autorität.
|
||||
- ChatGPT erhält pro Turn nur eine kurzlebige Capability. Der MCP-Broker akzeptiert
|
||||
ausschließlich Tools, die Codex in genau diesem Turn angeboten hat.
|
||||
- Das automatische Bestätigen von „Allow once“ gibt nur den Tool-Wunsch an Codex
|
||||
zurück. Codex allein entscheidet über Freigabe und Ausführung.
|
||||
- Vor dem ersten Output darf die Combo auf ein anderes kompatibles Ziel fallen.
|
||||
Danach bleiben Provider, Modell, Connection und Browserturn bis zum Abschluss
|
||||
gepinnt.
|
||||
- Cookies, Runtime-Keys, Storage-State und Capability-Tokens erscheinen nicht in
|
||||
Providerantworten oder Request-Logs.
|
||||
|
||||
## Headless VPS und Docker
|
||||
|
||||
Bei npm-, systemd- und PM2-Betrieb erkennt OmniRoute übliche Chrome- und
|
||||
Chromium-Pfade. Alternativ kann `CHATGPT_WEB_CODEX_CHROME_PATH` gesetzt werden.
|
||||
|
||||
Das Docker-Profil `web` startet `chatgpt-web-codex-browser` im internen
|
||||
Compose-Netz. Sein CDP-Port wird nicht auf dem Host veröffentlicht. Das geschützte
|
||||
Profilvolume bleibt getrennt vom OmniRoute-Datenvolume und der Browser erhält
|
||||
ausreichend Shared Memory. Der interne CDP-Proxy lauscht nur im Compose-Netz auf
|
||||
Port `9223`; Chrome selbst bleibt im Sidecar an Loopback gebunden.
|
||||
|
||||
Eine Supervisor-Lease unter `DATA_DIR` verhindert, dass mehrere OmniRoute-Prozesse
|
||||
denselben Tunnel- und Brokerzustand besitzen. Ein Konflikt erscheint im Doctor.
|
||||
|
||||
## Interaktive Wiederherstellung
|
||||
|
||||
Der normale Pfad ist vollständig headless. Wenn ChatGPT eine interaktive
|
||||
Anmeldung oder Challenge verlangt, kann die bestehende VNC-Browser-Infrastruktur
|
||||
als Recovery-Weg verwendet werden. Browser-UI und CDP dürfen dabei nur über
|
||||
Loopback, eine authentifizierte Managementverbindung oder einen SSH-Tunnel
|
||||
erreichbar sein; noVNC bleibt im normalen Betrieb deaktiviert.
|
||||
|
||||
## WebSocket-Fallback
|
||||
|
||||
Enthält eine Combo `ChatGPT Web (Codex)`, fordert die Responses-WebSocket-Brücke
|
||||
vor der Upstream-Verbindung den HTTP/SSE-Fallback an. Die eigentliche Übertragung
|
||||
erfolgt dann über `/v1/responses`.
|
||||
Reference in New Issue
Block a user