# API Reference (Italiano) 🌐 **Languages:** 🇺🇸 [English](../../../../reference/API_REFERENCE.md) · 🇪🇹 [am](../../../am/docs/reference/API_REFERENCE.md) · 🇸🇦 [ar](../../../ar/docs/reference/API_REFERENCE.md) · 🇦🇿 [az](../../../az/docs/reference/API_REFERENCE.md) · 🇧🇬 [bg](../../../bg/docs/reference/API_REFERENCE.md) · 🇧🇩 [bn](../../../bn/docs/reference/API_REFERENCE.md) · 🇧🇦 [bs](../../../bs/docs/reference/API_REFERENCE.md) · 🇨🇿 [cs](../../../cs/docs/reference/API_REFERENCE.md) · 🇩🇰 [da](../../../da/docs/reference/API_REFERENCE.md) · 🇩🇪 [de](../../../de/docs/reference/API_REFERENCE.md) · 🇬🇷 [el](../../../el/docs/reference/API_REFERENCE.md) · 🇪🇸 [es](../../../es/docs/reference/API_REFERENCE.md) · 🇪🇪 [et](../../../et/docs/reference/API_REFERENCE.md) · 🇮🇷 [fa](../../../fa/docs/reference/API_REFERENCE.md) · 🇫🇮 [fi](../../../fi/docs/reference/API_REFERENCE.md) · 🇫🇷 [fr](../../../fr/docs/reference/API_REFERENCE.md) · 🇮🇪 [ga](../../../ga/docs/reference/API_REFERENCE.md) · 🇮🇳 [gu](../../../gu/docs/reference/API_REFERENCE.md) · 🇳🇬 [ha](../../../ha/docs/reference/API_REFERENCE.md) · 🇮🇱 [he](../../../he/docs/reference/API_REFERENCE.md) · 🇮🇳 [hi](../../../hi/docs/reference/API_REFERENCE.md) · 🇭🇷 [hr](../../../hr/docs/reference/API_REFERENCE.md) · 🇭🇺 [hu](../../../hu/docs/reference/API_REFERENCE.md) · 🇦🇲 [hy](../../../hy/docs/reference/API_REFERENCE.md) · 🇮🇩 [id](../../../id/docs/reference/API_REFERENCE.md) · 🇳🇬 [ig](../../../ig/docs/reference/API_REFERENCE.md) · 🇯🇵 [ja](../../../ja/docs/reference/API_REFERENCE.md) · 🇬🇪 [ka](../../../ka/docs/reference/API_REFERENCE.md) · 🇰🇭 [km](../../../km/docs/reference/API_REFERENCE.md) · 🇮🇳 [kn](../../../kn/docs/reference/API_REFERENCE.md) · 🇰🇷 [ko](../../../ko/docs/reference/API_REFERENCE.md) · 🇱🇹 [lt](../../../lt/docs/reference/API_REFERENCE.md) · 🇱🇻 [lv](../../../lv/docs/reference/API_REFERENCE.md) · 🇮🇳 [ml](../../../ml/docs/reference/API_REFERENCE.md) · 🇮🇳 [mr](../../../mr/docs/reference/API_REFERENCE.md) · 🇲🇾 [ms](../../../ms/docs/reference/API_REFERENCE.md) · 🇲🇹 [mt](../../../mt/docs/reference/API_REFERENCE.md) · 🇲🇲 [my](../../../my/docs/reference/API_REFERENCE.md) · 🇳🇵 [ne](../../../ne/docs/reference/API_REFERENCE.md) · 🇳🇱 [nl](../../../nl/docs/reference/API_REFERENCE.md) · 🇳🇴 [no](../../../no/docs/reference/API_REFERENCE.md) · 🇮🇳 [or](../../../or/docs/reference/API_REFERENCE.md) · 🇮🇳 [pa](../../../pa/docs/reference/API_REFERENCE.md) · 🇵🇭 [phi](../../../phi/docs/reference/API_REFERENCE.md) · 🇵🇱 [pl](../../../pl/docs/reference/API_REFERENCE.md) · 🇵🇹 [pt](../../../pt/docs/reference/API_REFERENCE.md) · 🇧🇷 [pt-BR](../../../pt-BR/docs/reference/API_REFERENCE.md) · 🇷🇴 [ro](../../../ro/docs/reference/API_REFERENCE.md) · 🇷🇺 [ru](../../../ru/docs/reference/API_REFERENCE.md) · 🇱🇰 [si](../../../si/docs/reference/API_REFERENCE.md) · 🇸🇰 [sk](../../../sk/docs/reference/API_REFERENCE.md) · 🇸🇮 [sl](../../../sl/docs/reference/API_REFERENCE.md) · 🇷🇸 [sr](../../../sr/docs/reference/API_REFERENCE.md) · 🇸🇪 [sv](../../../sv/docs/reference/API_REFERENCE.md) · 🇰🇪 [sw](../../../sw/docs/reference/API_REFERENCE.md) · 🇮🇳 [ta](../../../ta/docs/reference/API_REFERENCE.md) · 🇮🇳 [te](../../../te/docs/reference/API_REFERENCE.md) · 🇹🇭 [th](../../../th/docs/reference/API_REFERENCE.md) · 🇹🇷 [tr](../../../tr/docs/reference/API_REFERENCE.md) · 🇺🇦 [uk-UA](../../../uk-UA/docs/reference/API_REFERENCE.md) · 🇵🇰 [ur](../../../ur/docs/reference/API_REFERENCE.md) · 🇺🇿 [uz](../../../uz/docs/reference/API_REFERENCE.md) · 🇻🇳 [vi](../../../vi/docs/reference/API_REFERENCE.md) · 🇳🇬 [yo](../../../yo/docs/reference/API_REFERENCE.md) · 🇨🇳 [zh-CN](../../../zh-CN/docs/reference/API_REFERENCE.md) · 🇹🇼 [zh-TW](../../../zh-TW/docs/reference/API_REFERENCE.md) --- 🌐 **Lingue:** 🇺🇸 [English](./API_REFERENCE.md) | 🇪🇹 [አማርኛ](../i18n/am/docs/reference/API_REFERENCE.md) | 🇸🇦 [العربية](../i18n/ar/docs/reference/API_REFERENCE.md) | 🇦🇿 [Azərbaycan dili](../i18n/az/docs/reference/API_REFERENCE.md) | 🇧🇬 [Български](../i18n/bg/docs/reference/API_REFERENCE.md) | 🇧🇩 [বাংলা](../i18n/bn/docs/reference/API_REFERENCE.md) | 🇧🇦 [Bosanski](../i18n/bs/docs/reference/API_REFERENCE.md) | 🇨🇿 [Čeština](../i18n/cs/docs/reference/API_REFERENCE.md) | 🇩🇰 [Dansk](../i18n/da/docs/reference/API_REFERENCE.md) | 🇩🇪 [Deutsch](../i18n/de/docs/reference/API_REFERENCE.md) | 🇬🇷 [Ελληνικά](../i18n/el/docs/reference/API_REFERENCE.md) | 🇪🇸 [Español](../i18n/es/docs/reference/API_REFERENCE.md) | 🇪🇪 [Eesti](../i18n/et/docs/reference/API_REFERENCE.md) | 🇮🇷 [فارسی](../i18n/fa/docs/reference/API_REFERENCE.md) | 🇫🇮 [Suomi](../i18n/fi/docs/reference/API_REFERENCE.md) | 🇫🇷 [Français](../i18n/fr/docs/reference/API_REFERENCE.md) | 🇮🇪 [Gaeilge](../i18n/ga/docs/reference/API_REFERENCE.md) | 🇮🇳 [ગુજરાતી](../i18n/gu/docs/reference/API_REFERENCE.md) | 🇳🇬 [Hausa](../i18n/ha/docs/reference/API_REFERENCE.md) | 🇮🇱 [עברית](../i18n/he/docs/reference/API_REFERENCE.md) | 🇮🇳 [हिन्दी](../i18n/hi/docs/reference/API_REFERENCE.md) | 🇭🇷 [Hrvatski](../i18n/hr/docs/reference/API_REFERENCE.md) | 🇭🇺 [Magyar](../i18n/hu/docs/reference/API_REFERENCE.md) | 🇦🇲 [Հայերեն](../i18n/hy/docs/reference/API_REFERENCE.md) | 🇮🇩 [Bahasa Indonesia](../i18n/id/docs/reference/API_REFERENCE.md) | 🇳🇬 [Igbo](../i18n/ig/docs/reference/API_REFERENCE.md) | 🇮🇹 [Italiano](../i18n/it/docs/reference/API_REFERENCE.md) | 🇯🇵 [日本語](../i18n/ja/docs/reference/API_REFERENCE.md) | 🇬🇪 [ქართული](../i18n/ka/docs/reference/API_REFERENCE.md) | 🇰🇭 [ខ្មែរ](../i18n/km/docs/reference/API_REFERENCE.md) | 🇮🇳 [ಕನ್ನಡ](../i18n/kn/docs/reference/API_REFERENCE.md) | 🇰🇷 [한국어](../i18n/ko/docs/reference/API_REFERENCE.md) | 🇱🇹 [Lietuvių](../i18n/lt/docs/reference/API_REFERENCE.md) | 🇱🇻 [Latviešu](../i18n/lv/docs/reference/API_REFERENCE.md) | 🇮🇳 [മലയാളം](../i18n/ml/docs/reference/API_REFERENCE.md) | 🇮🇳 [मराठी](../i18n/mr/docs/reference/API_REFERENCE.md) | 🇲🇾 [Bahasa Melayu](../i18n/ms/docs/reference/API_REFERENCE.md) | 🇲🇹 [Malti](../i18n/mt/docs/reference/API_REFERENCE.md) | 🇲🇲 [မြန်မာ](../i18n/my/docs/reference/API_REFERENCE.md) | 🇳🇵 [नेपाली](../i18n/ne/docs/reference/API_REFERENCE.md) | 🇳🇱 [Nederlands](../i18n/nl/docs/reference/API_REFERENCE.md) | 🇳🇴 [Norsk](../i18n/no/docs/reference/API_REFERENCE.md) | 🇮🇳 [ଓଡ଼ିଆ](../i18n/or/docs/reference/API_REFERENCE.md) | 🇮🇳 [ਪੰਜਾਬੀ](../i18n/pa/docs/reference/API_REFERENCE.md) | 🇵🇭 [Filipino](../i18n/phi/docs/reference/API_REFERENCE.md) | 🇵🇱 [Polski](../i18n/pl/docs/reference/API_REFERENCE.md) | 🇵🇹 [Português (Portugal)](../i18n/pt/docs/reference/API_REFERENCE.md) | 🇧🇷 [Português (Brasil)](../i18n/pt-BR/docs/reference/API_REFERENCE.md) | 🇷🇴 [Română](../i18n/ro/docs/reference/API_REFERENCE.md) | 🇷🇺 [Русский](../i18n/ru/docs/reference/API_REFERENCE.md) | 🇱🇰 [සිංහල](../i18n/si/docs/reference/API_REFERENCE.md) | 🇸🇰 [Slovenčina](../i18n/sk/docs/reference/API_REFERENCE.md) | 🇸🇮 [Slovenščina](../i18n/sl/docs/reference/API_REFERENCE.md) | 🇷🇸 [Српски](../i18n/sr/docs/reference/API_REFERENCE.md) | 🇸🇪 [Svenska](../i18n/sv/docs/reference/API_REFERENCE.md) | 🇰🇪 [Kiswahili](../i18n/sw/docs/reference/API_REFERENCE.md) | 🇮🇳 [தமிழ்](../i18n/ta/docs/reference/API_REFERENCE.md) | 🇮🇳 [తెలుగు](../i18n/te/docs/reference/API_REFERENCE.md) | 🇹🇭 [ไทย](../i18n/th/docs/reference/API_REFERENCE.md) | 🇹🇷 [Türkçe](../i18n/tr/docs/reference/API_REFERENCE.md) | 🇺🇦 [Українська](../i18n/uk-UA/docs/reference/API_REFERENCE.md) | 🇵🇰 [اردو](../i18n/ur/docs/reference/API_REFERENCE.md) | 🇺🇿 [Oʻzbekcha](../i18n/uz/docs/reference/API_REFERENCE.md) | 🇻🇳 [Tiếng Việt](../i18n/vi/docs/reference/API_REFERENCE.md) | 🇳🇬 [Yorùbá](../i18n/yo/docs/reference/API_REFERENCE.md) | 🇨🇳 [中文 (简体)](../i18n/zh-CN/docs/reference/API_REFERENCE.md) | 🇹🇼 [中文 (繁體)](../i18n/zh-TW/docs/reference/API_REFERENCE.md) Riferimento fondamentale per l'API OmniRoute. Copre la superficie pubblica `/v1` e gli endpoint di gestione più utilizzati; il file leggibile dalle macchine [`docs/openapi.yaml`](../openapi.yaml) e l'albero delle route in `src/app/api/` sono le fonti esaustive. Per il protocollo incentrato sulla compatibilità con OpenAI e la matrice delle funzionalità dei provider, consulta [`OPENAI_COMPATIBILITY.md`](./OPENAI_COMPATIBILITY.md). Ogni distribuzione fornisce la propria copia della specifica all'indirizzo `/openapi.yaml`, generata da `docs/openapi.yaml` durante la compilazione. Contiene la versione della build e un URL relativo del server (`./`), in modo che le richieste rimangano sull'host che ha fornito il documento. Uno strumento che importa il file scaricato non dispone di tale host e deve impostare manualmente l'URL di base. --- ## Indice - [Completamenti chat](#chat-completions) - [Lease esclusivi delle sessioni gestite](#exclusive-managed-session-leases) - [Embedding](#embeddings) - [Generazione di immagini](#image-generation) - [OCR dei documenti](#document-ocr) - [Elenco dei modelli](#list-models) - [Manifest del plugin del provider](#provider-plugin-manifest) - [Endpoint di compatibilità](#compatibility-endpoints) - [API dei file](#files-api) - [API dei batch](#batches-api) - [API di ricerca](#search-api) - [Streaming WebSocket](#websocket-streaming) - [Quote e segnalazione dei problemi](#quotas--issues-reporting) - [Cache semantica](#semantic-cache) - [Compatibilità di gestione di CLIProxyAPI](#cliproxyapi-management-compatibility) - [Dashboard e gestione](#dashboard--management) - [Gestione delle combinazioni](#combo-management) - [Webhook](#webhooks) - [Chiavi registrate (gestione automatica)](#registered-keys-auto-management) - [Protocollo degli agenti](#agents-protocol) - [Proxy di gestione](#management-proxies) - [Resilienza (estesa)](#resilience-extended) - [Competenze](#skills) - [Memoria](#memory) - [Server MCP](#mcp-server) - [Server A2A](#a2a-server) - [Cloud, valutazioni e assessment](#cloud-evals--assess) - [Elaborazione delle richieste](#request-processing) - [Autenticazione](#authentication) --- ## Completamenti chat ```bash POST /v1/chat/completions Authorization: Bearer your-api-key Content-Type: application/json { "model": "cc/claude-opus-4-6", "messages": [ {"role": "user", "content": "Write a function to..."} ], "stream": true } ``` ### Intestazioni personalizzate | Header | Direzione | Descrizione | | ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `X-OmniRoute-No-Cache` | Richiesta | Impostare su `true` per bypassare la cache | | `x-omniroute-no-memory` | Richiesta | Impostare su `true` per ignorare l'iniezione di memoria + competenze per questa richiesta (rispecchia no-cache; evita il sovraccarico di token/costi per chiamata) | | `X-OmniRoute-Progress` | Richiesta | Impostare su `true` per gli eventi di avanzamento | | `X-Session-Id` | Richiesta | Chiave di sessione persistente per l'affinità della sessione esterna | | `x_session_id` | Richiesta | È accettata anche la variante con carattere di sottolineatura (HTTP diretto) | | `X-OmniRoute-Session-Id` | Richiesta | Tag della sessione/conversazione fornito dal chiamante (alimenta anche la memoria). Quando presente, viene salvato verbatim in `call_logs.session_tag` per l'attribuzione dei costi per sessione (#8249) — non viene mai generato quando assente | | `Idempotency-Key` | Richiesta | Chiave di deduplicazione (finestra di 5 s) | | `X-Request-Id` | Richiesta | Chiave di deduplicazione alternativa | | `x-omniroute-connection` | Richiesta | Associa una richiesta a modello singolo a una connessione del provider (account) tramite il relativo ID — vedere [Associazione dell'account per richiesta](#account-pinning-per-request) | | `X-OmniRoute-Cache` | Risposta | `HIT` o `MISS` (senza streaming) | | `X-OmniRoute-Idempotent` | Risposta | `true` se deduplicata | | `X-OmniRoute-Progress` | Risposta | `enabled` se il monitoraggio dell'avanzamento è attivo | | `X-OmniRoute-Session-Id` | Risposta | ID di sessione effettivo utilizzato da OmniRoute | | `X-OmniRoute-Request-Id` | Risposta | ID di correlazione della richiesta (quando noto) | | `X-OmniRoute-Version` | Risposta | Versione della build di OmniRoute (sempre presente) | | `X-OmniRoute-Cost-Saved` | Risposta | Valore in USD risparmiato dalla cache in caso di HIT (solo cache hit) | | `X-OmniRoute-Decision` | Risposta | Traccia del routing: `strategy=; provider=; latency_ms=` (`` è la strategia combinata oppure `single` per una richiesta non combinata) — sempre presente nelle risposte al completamento | > Nota su Nginx: se si utilizzano intestazioni con caratteri di sottolineatura (ad esempio `x_session_id`), abilitare `underscores_in_headers on;`. #### Associazione dell'account per richiesta Quando un provider dispone di più connessioni (account o chiavi), OmniRoute normalmente ne seleziona una tramite la propria strategia di selezione degli account. In alternativa, una richiesta può essere associata a una connessione specifica con l'intestazione `x-omniroute-connection`: ```bash curl http://localhost:20128/v1/chat/completions \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "x-omniroute-connection: " \ -d '{"model": "codex/gpt-5.5", "messages": [{"role": "user", "content": "hi"}]}' ``` - **Dove trovare l'id.** Apri la pagina del provider nella dashboard (**Dashboard → Provider → **) e fai clic sul chip dell'id `xxxxxxxx…` in una riga di connessione: copierà l'id completo della connessione. - **Quali richieste lo rispettano.** Le richieste a modello singolo (`provider/model`) su `/v1/chat/completions`, `/v1/messages` e `/v1/responses`. Le combinazioni ignorano l'header: fissa un account per ogni passaggio della combinazione tramite la connessione specifica del passaggio. - **Il pin è vincolante, non una preferenza.** La connessione fissata viene utilizzata esclusivamente. Un errore all'interno della richiesta registra il cooldown dell'account, ma **non** passa a un account associato dello stesso provider. - **Il cooldown e la quota rilasciano il pin.** Mentre la connessione fissata è in cooldown, ha esaurito la quota o è bloccata da una policy di quota, le richieste successive passano alle altre connessioni del provider, esattamente come il traffico senza pin. - **Gli id sconosciuti o disabilitati causano un errore.** Un id che non si trova nel pool attivo del provider (eliminato, disattivato o appartenente a un altro provider) non lascia alcun account idoneo, quindi la richiesta fallisce invece di essere instradata silenziosamente altrove. Claude Code invia gli header personalizzati tramite `ANTHROPIC_CUSTOM_HEADERS`. Inseriscilo nel blocco `env` di `~/.claude/settings.json`, oppure in un file `.claude/settings.json` a livello di progetto per fissare un account diverso per ogni progetto: ```jsonc { "env": { "ANTHROPIC_BASE_URL": "http://:20128", "ANTHROPIC_AUTH_TOKEN": "", "ANTHROPIC_CUSTOM_HEADERS": "x-omniroute-connection: ", }, } ``` Fonte: `src/sse/handlers/chat.ts` (lettura dell'header), `src/sse/services/auth.ts` e `src/sse/services/sessionAffinityPin.ts` (rilascio del pin e controllo dell'assenza dal pool). > **Header di telemetria dei costi:** le risposte con esito positivo senza streaming includono anche l'insieme di telemetria dei costi `X-OmniRoute-*` — `X-OmniRoute-Response-Cost` (USD, 10 decimali fissi; `0.0000000000` per contenuti gratuiti o senza prezzo), `X-OmniRoute-Tokens-In` / `X-OmniRoute-Tokens-Out`, `X-OmniRoute-Model`, `X-OmniRoute-Provider`, `X-OmniRoute-Latency-Ms`, `X-OmniRoute-Cache-Hit` e `X-OmniRoute-Fallback-Attempts` (solo quando > 0), oltre a `X-OmniRoute-Request-Id` e `X-OmniRoute-Version`. Questi header vengono emessi da chat completions, `/v1/responses`, `/v1/messages` **e dagli endpoint multimediali** — `/v1/embeddings`, `/v1/images/generations`, `/v1/audio/speech`, `/v1/audio/transcriptions`, `/v1/rerank`, `/v1/videos/generations`, `/v1/music/generations` e `/v1/moderations` (sempre con costo `0`). Il costo dei contenuti multimediali viene calcolato per modalità (per immagine, per secondo, per carattere, per unità di ricerca) quando il prezzo è disponibile, altrimenti è `0` (fail-open). > **Semantica dei costi per i cache hit:** in caso di HIT della cache semantica (`X-OmniRoute-Cache-Hit: true`) non viene effettuata alcuna chiamata upstream, quindi `X-OmniRoute-Response-Cost` è `0.0000000000` (il costo **incrementale** della gestione dell'hit). Il costo originale/che si sarebbe sostenuto viene riportato separatamente in `X-OmniRoute-Cost-Saved`. I sistemi di fatturazione devono sommare `X-OmniRoute-Response-Cost` (gli hit non hanno costi); le analisi della cache possono aggregare `X-OmniRoute-Cost-Saved`. ## Lease di sessione gestite esclusive Il leasing esclusivo di sessioni gestite è un contratto di instradamento opt-in e neutrale rispetto al client: un unico proprietario attivo detiene una connessione OmniRoute idonea. Non concede in leasing un modello, non richiede OAuth, non identifica un client specifico e non richiede un provider specifico. La chiave API di autenticazione deve avere l'ambito `lease:exclusive` e un elenco `allowedConnections` esplicito e non vuoto. Il confine di mutazione del database applica entrambi i campi insieme durante la creazione delle chiavi e negli aggiornamenti parziali. ```http POST /api/v1/session-leases Authorization: Bearer Content-Type: application/json X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters> {"action":"acquire","model":"glm/glm-4.6"} ``` Le risposte riuscite di acquisizione, rinnovo e rilascio espongono i timestamp, `state` e il valore `generation` positivo esatto, ma mai la connessione selezionata o le credenziali. Il rinnovo e il rilascio forniscono `generation` nel corpo JSON: ```json { "action": "renew", "generation": 1 } ``` ```json { "action": "release", "generation": 1, "reason": "OWNER_EXIT" } ``` Il proprietario di un lease attivo può richiedere esplicitamente metadati di visualizzazione sicuri per la privacy relativi al proprio binding corrente: ```json { "action": "status", "generation": 1 } ``` ```json { "state": "ACTIVE", "generation": 1, "acquiredAt": "2026-08-28T12:00:00.000Z", "renewedAt": "2026-08-28T12:00:30.000Z", "expiresAt": "2026-08-28T12:02:30.000Z", "connection": { "displayName": "Primary Codex", "provider": "codex" } } ``` Questa azione di stato opt-in è vincolata dal proprietario opaco, dalla chiave API gestita autenticata e dalla generazione attiva esatta in un'unica transazione del database. `displayName` è esclusivamente il nome della connessione configurato e sottoposto a trim; è `null` quando non esiste alcun nome configurato sicuro. OmniRoute non sostituisce mai il nome con un indirizzo email o con un'identità dell'account generata. Il valore del provider è un'etichetta di visualizzazione non sensibile e non è mai un identificatore di provider compatibile generato. Credenziali, token, cookie, ID grezzi delle connessioni o delle chiavi API, hash dei proprietari, segreti di fencing e dati interni di instradamento sono esclusi. Le ricerche con chiave errata, proprietario errato, generazione obsoleta, dati mancanti, lease scaduto, rilasciato o invalidato restituiscono tutte lo stesso errore `409 LEASE_FENCE_STALE`, senza metadati della connessione. Un client che ha ricevuto la risposta di attesa della capacità non ha alcun binding attivo da ispezionare. Quando l'instradamento effettua la transizione di un lease attivo, la stessa generazione rimane valida e lo stato restituisce atomicamente il nuovo binding, mai quello precedente. I client esistenti rimangono invariati perché le risposte di acquisizione, rinnovo, rilascio e attesa mantengono i formati precedenti. Questo contratto del server non modifica `/status` di OpenAI Codex standard. Attualmente Codex standard segnala il provider del modello e lo stato integrato di autenticazione/account, ma non visualizza metadati arbitrari dell'account di provider personalizzati; una successiva integrazione client dovrà chiamare questa azione e decidere come visualizzare `connection.displayName`. Ogni richiesta di inferenza gestita fornisce quindi entrambe le intestazioni di controllo: ```http X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters> X-OmniRoute-Lease-Generation: 1 ``` Il proprietario esatto, la generazione, la connessione attiva e la chiave API autenticata vengono sottoposti a fencing immediatamente prima di ogni tentativo upstream supportato. La riproduzione di proprietario e generazione con un'altra chiave non va a buon fine, anche quando tale chiave consente la stessa connessione. I proprietari grezzi non vengono persistiti, registrati nei log, conservati nello snapshot della richiesta né inoltrati upstream. La contesa temporanea restituisce HTTP `429` con `Retry-After` e: ```json { "state": "WAITING_FOR_CAPACITY", "error": { "type": "lease_error", "code": "LEASE_CAPACITY_UNAVAILABLE" }, "reason": "NO_FREE_ELIGIBLE_CONNECTION", "retryAfter": 30 } ``` Questa risposta significa soltanto che l'insieme ordinario delle connessioni idonee non era vuoto e che ogni candidato libero era detenuto da un lease attivo esterno. Modelli/provider non supportati, mancata corrispondenza dei criteri, cooldown, quota, stato di integrità e altri normali errori di idoneità mantengono le risposte OmniRoute esistenti. ### `x-omniroute-compression` Override per richiesta del piano di compressione. Ha la precedenza massima: prevale sull'override della combinazione di instradamento, sul profilo attivo, sull'attivazione automatica e sul valore predefinito del pannello. Valori: | Valore | Effetto | | ------------- | --------------------------------------------------------------------------------------------------------------------- | | `off` | Nessuna compressione per questa richiesta. | | `default` | Il profilo predefinito derivato dal pannello (ignora il profilo attivo). I motori lossy vengono lasciati disattivati. | | `safe` | Solo deduplicazione e fusione degli spazi bianchi. | | `allow-lossy` | Mantiene il piano dell'operatore per questa richiesta, inclusi riepiloghi e riscritture dello stile. | | `engine:` | Un singolo motore quando abilitato, ad esempio `engine:rtk`. Opt-in per richiesta per quel motore. | | `` | Una combinazione denominata, confrontata prima per nome (senza distinzione tra maiuscole e minuscole), quindi per ID. | Note: - I valori sconosciuti vengono ignorati (la richiesta non viene mai rifiutata); la risoluzione prosegue secondo la normale precedenza dell'operatore. - Se più combinazioni condividono lo stesso nome, passa l'**ID** della combinazione per ottenere una corrispondenza deterministica. - Una combinazione il cui nome è `off` o `default` non può essere selezionata per nome (le parole chiave vengono interpretate per prime); fai riferimento a tale combinazione tramite il relativo ID. - L'interruttore principale della compressione è un vincolo rigido: quando la compressione è disabilitata globalmente, questa intestazione non può abilitarla. Il piano applicato viene restituito nell'intestazione della risposta: ``` X-OmniRoute-Compression: ; source= ``` dove `` è uno tra `request-header`, `routing-override`, `active-profile`, `auto-trigger`, `default` o `off`. --- ## Embedding ```bash POST /v1/embeddings Authorization: Bearer your-api-key Content-Type: application/json { "model": "nebius/Qwen/Qwen3-Embedding-8B", "input": "The food was delicious" } ``` Provider disponibili: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA, **OpenRouter**, Jina AI. Gli ID del catalogo sono `provider/model` (esempio: `jina-ai/jina-embeddings-v5-omni-small`). Anche gli ID dei modelli Jina senza prefisso presenti nel registro (ad esempio `jina-embeddings-v5-text-small`, `jina-reranker-v3.5`) vengono risolti. Jina embed/rerank/classify/segment utilizzano prima le credenziali `jina-ai` della dashboard; `JINA_AI_API_KEY` è un fallback solo quando non esiste alcuna chiave della dashboard. La scheda `jina-reader` è esclusivamente Reader / `r.jina.ai` (`POST /v1/web/fetch`) e non fornisce mai embedding o rerank. I modelli del registro che dichiarano il supporto multimodale accettano anche fino a 32 elementi strutturati indipendenti dal provider. I tipi di elementi multimediali sono `text`, `image`, `audio`, `video` e `document`. La `source` dei relativi media è `{"type":"url","url":"https://..."}` oppure `{"type":"base64","data":"...","media_type":"..."}`. Jina v5 Omni (`jina-ai/jina-embeddings-v5-omni-small`, `jina-ai/jina-embeddings-v5-omni-nano`, e l'alias della famiglia `jina-ai/jina-embeddings-v5-omni` → omni-small) accetta anche la documentazione nativa EmbeddingsV5Request di Jina e li **inoltra intatti** a `https://api.jina.ai/v1/embeddings`: ```json { "model": "jina-ai/jina-embeddings-v5-omni-small", "task": "retrieval.query", "normalized": true, "input": [ { "text": "a red bicycle" }, { "image": "https://example.com/bike.png" }, { "content": [{ "text": "caption" }, { "image": "data:image/png;base64,..." }] } ] } ``` I valori nativi `{ image | audio | video | pdf }` possono essere un URL HTTPS pubblico, un URI `data:` o base64 grezzo. OmniRoute non converte questi oggetti in stringhe né recupera gli URL nativi delle immagini: è Jina a recuperare direttamente i media pubblici. I campi Jina aggiuntivi (`task`, `normalized`, `truncate`, `embedding_type`) vengono inoltrati. Le SKU Jina di solo testo rifiutano comunque i documenti non testuali. Limiti di sicurezza e trasporto: - Gli URL dei media remoti devono essere HTTPS pubblici. Gli elementi canonici `{type,source:url}` vengono recuperati lato server (riverifica dei reindirizzamenti, timeout, limiti di dimensione, DNS pubblico, fissaggio della connessione) e incorporati prima della chiamata al provider. Gli elementi nativi Jina `{image:"https://..."}` vengono inoltrati così come sono dopo lo stesso controllo HTTPS pubblico; è Jina a recuperare l'URL. - I media base64 incorporati sono limitati a 8 MiB decodificati per elemento e a 16 MiB decodificati per richiesta. Traduzione del provider (gli elementi canonici non vengono mai inoltrati invariati): - Modelli multimodali Jina: ogni elemento di primo livello diventa un oggetto con una chiave per modalità (`text` / `image` / `audio` / `video` / `pdf`) usando URI data per i media incorporati; un vettore per ogni elemento di primo livello. - Famiglia Gemini Embedding 2: un unico array di primo livello diventa una singola richiesta nativa `models/{model}:embedContent` con `content.parts` (`text` o `inline_data`). - llama.cpp (`llama-cpp/`, qualsiasi modello caricato dal server locale): gli elementi canonici `text` diventano stringhe semplici, mentre `image` / `audio` / `video` diventano ciascuno un oggetto `{"content": [part]}`, usando le parti di contenuto della chat di llama-server (`image_url`, `input_audio` con formato `wav` / `mp3` / `flac`, `input_video`) con dati incorporati; un vettore per ogni elemento di primo livello. Il server deve essere eseguito con `--embedding --mmproj …`; senza un proiettore rifiuta direttamente i media. `document` non è supportato. - I modelli sconosciuti/dinamici senza metadati espliciti sulle modalità rifiutano l'input strutturato con HTTP 400. ```json { "model": "jina-ai/jina-embeddings-v5-omni-small", "input": [ { "type": "text", "text": "A red bicycle" }, { "type": "image", "source": { "type": "url", "url": "https://example.com/bicycle.png" } } ], "dimensions": 512, "encoding_format": "float" } ``` Le combinazioni modello/modalità non supportate restituiscono HTTP 400 invece di forzare la conversione dell'elemento. I campi di estensione non relativi all'input nelle richieste legacy con stringhe/token continuano a essere trasmessi invariati. ```bash # Elenca tutti i modelli di embedding GET /v1/embeddings ``` --- ## Generazione di immagini ```bash POST /v1/images/generations Authorization: Bearer your-api-key Content-Type: application/json { "model": "openai/gpt-image-2", "prompt": "A beautiful sunset over mountains", "size": "1024x1024" } ``` I fornitori disponibili includono OpenAI (GPT Image 2), xAI (Grok Image), Together AI (FLUX), Fireworks AI, Nebius (FLUX), Hyperbolic, NanoBanana,**OpenRouter** ,**ZenMux** , SD WebUI (locale), ComfyUI (locale). `n` restituisce le immagini `n` in `data[]`. I fornitori il cui API upstream restituisce un'immagine per chiamata (Black Forest Labs, Stability AI, Leonardo, Ideogram, Haiper, Hyperbolic, Magnific/Freepik, NVIDIA NIM, Cloudflare Workers AI) ricevono `n` chiamate upstream separate, al massimo 4 in volo. Uno `seed` fisso è compensato dall'indice di chiamata (`seed`, `seed + 1`, ...), quindi le immagini differiscono ma rimangono riproducibili. `n` è limitato a 10. La richiesta fallisce nel suo complesso se una qualsiasi chiamata fallisce. L'elenco dei formati fan-out è `SINGLE_IMAGE_FANOUT_FORMATS` in `open-sse/handlers/imageGeneration/fanOut.ts`. ZenMux riutilizza la connessione della chiave API esistente e accetta i prefissi `zenmux/` o `zm/` : - `zenmux/openai/gpt-image-2` utilizza le immagini ZenMuxAPI di OpenAI. Le opzioni includono `size`, `quality`, `n`, `output_format`, `output_compression`, `background` e `response_format`. - Altri editori, come `zm/meta/muse-image-1.0`, utilizzano l'endpoint Vertex AI `:predict` di ZenMux. `n` viene mappato su `sampleCount`, `aspect_ratio` su `aspectRatio` e `image_size` (`1K`, `2K`, `4K`) su `sampleImageSize`. Un pixel `size` fornisce solo le proporzioni, non le dimensioni dei pixel garantite. I rapporti, le risoluzioni e i conteggi supportati variano in base al modello. - `zm/inclusionai/ming-image-0.1-design` sceglie le proprie dimensioni. Omettere `size`, `aspect_ratio` e `image_size`; i valori espliciti restituiscono HTTP 400. PNG, JPEG e WebP possono essere richiesti con `output_format`. Questa integrazione supporta la generazione di testo in immagine, non la modifica di immagini di riferimento. L'output del vertice è normalizzato in `data[].b64_json`; `response_format: "url"` restituisce uno HTTPS URL upstream o uno URL di dati base64 quando sono disponibili solo byte di immagine. Gli output Empty/filtered restituiscono un errore anziché un successo vuoto. L'accesso al modello dipende dall'account ZenMux. Vedi le immagini [ZenMux del vertice API](https://docs.zenmux.ai/api/vertexai/generate-images) e [OpenAI API](https://docs.zenmux.ai/api/openai/generate-an-image). Una connessione di accesso Microsoft 365 Copilot serve `copilot-m365-web/m365-copilot-image` tramite lo strumento immagine integrato di Copilot: un giro Copilot per immagine (`n` 1–4), `size` che controlla solo l'orientamento e le immagini vengono restituite in linea (`b64_json` o un dato URL per `response_format: "url"`). Vedi [Microsoft 365 Copilot](../providers/COPILOT-M365.md#image-generation). ```bash # List all image models GET /v1/images/generations ``` --- ## OCR dei documenti ```bash POST /v1/ocr Authorization: Bearer your-api-key Content-Type: application/json { "model": "mistral/mistral-ocr-latest", "document": { "type": "document_url", "document_url": "https://example.com/invoice.pdf" } } ``` `model` seleziona il provider OCR tramite un prefisso `provider/model`; un ID modello semplice (ad es. `mistral-ocr-latest`) viene risolto nel provider registrato corrispondente, mentre se `model` viene omesso viene utilizzato Mistral (`mistral-ocr-latest`). Provider registrati (`open-sse/config/ocrRegistry.ts`): | Provider id | Model id | Valore di `model` | Note | | ----------------------------- | -------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `mistral` | `mistral-ocr-latest` | `mistral/mistral-ocr-latest` (o `mistral-ocr-latest`) | Sincrono — la risposta viene restituita direttamente dalla singola chiamata upstream. | | `azure-document-intelligence` | `prebuilt-read` | `azure-document-intelligence/prebuilt-read` | Upstream asincrono (`analyze` + polling) — vedi sotto. | | `vertex-deepseek-ocr` | `deepseek-ocr-maas` | `vertex-deepseek-ocr/deepseek-ocr-maas` | Sincrono, tramite l'endpoint partner `openapi/chat/completions` di Vertex AI — vedi sotto per l'autenticazione e l'URL. | Tutti e tre i provider rispondono con lo stesso corpo nel formato Mistral: ```json { "pages": [{ "index": 0, "markdown": "# Extracted text..." }], "model": "mistral-ocr-latest", "usage_info": { "pages_processed": 1 } } ``` ### Flusso di polling di Azure Document Intelligence L'API `analyze` di Azure Document Intelligence è asincrona: la richiesta iniziale restituisce un'intestazione `Operation-Location` invece di un corpo e il risultato deve essere sottoposto a polling. Il gestore (`open-sse/handlers/ocr.ts`) esegue il polling di quell'URL ogni secondo per un massimo di 30 tentativi, interrompe immediatamente (senza continuare il polling) in caso di risposta di polling non `ok` o di stato `"failed"` e restituisce `504` se l'operazione è ancora in esecuzione dopo l'esaurimento dei tentativi disponibili. La risposta Azure finale viene normalizzata nella stessa struttura `pages`/`markdown` utilizzata da Mistral prima di essere restituita al chiamante, perciò il codice client non deve gestire casi specifici per il provider. ### Autenticazione e risoluzione dell'endpoint OCR DeepSeek di Vertex AI `vertex-deepseek-ocr` riutilizza la stessa autenticazione Vertex AI che OmniRoute supporta già per il traffico di chat/immagini (`open-sse/executors/vertex.ts`): la chiave API della connessione è una credenziale JSON di Service Account (scambiata con un token di accesso OAuth di breve durata tramite il flusso JWT-bearer) oppure un token di accesso OAuth già emesso, utilizzato così com'è. L'URL dell'endpoint upstream è l'endpoint partner generico `openapi/chat/completions` di Vertex, costruito a partire dal progetto e dalla regione della connessione: un valore esplicito `providerSpecificData.project`/`providerSpecificData.region` ha sempre la precedenza; in caso contrario, il progetto viene derivato dal valore `project_id` del JSON del Service Account e la regione predefinita è `us-central1`. Entrambe le risoluzioni avvengono in `open-sse/handlers/ocr.ts` (`resolveVertexOcrAccessToken`, `resolveVertexOcrBaseUrl`) e vengono utilizzate da `src/app/api/v1/ocr/route.ts` prima dell'invio a `handleOcr`. --- ## Elenca modelli ```bash GET /v1/models Authorization: Bearer your-api-key → Restituisce tutti i modelli di chat, embedding e immagini + le combinazioni in formato OpenAI ``` ### Prezzi dei modelli (`pricing`) Una voce include un oggetto `pricing` quando OmniRoute conosce il prezzo del modello. Il prezzo proviene dalla tabella dei prezzi utilizzata dalla contabilizzazione dei costi: valori predefiniti integrati, prezzi sincronizzati e override impostati tramite `/api/pricing`. Questi sono prezzi di listino, quindi anche i provider in abbonamento mostrano un prezzo per token. ```json "pricing": { "prompt": "0.000005", "completion": "0.000025", "input_cache_read": "0.0000005", "input_cache_write": "0.00000625", "input": 5, "output": 25, "cached": 0.5, "cache_creation": 6.25 } ``` | Fields | Unit | Notes | | --------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `prompt`, `completion`, `input_cache_read`, `input_cache_write` | USD per token, decimal string | Compatibile con OpenRouter, mai in notazione esponenziale. I due campi della cache compaiono solo quando esiste un prezzo della cache. | | `input`, `output`, `cached`, `cache_creation` | USD per 1M tokens, number | Campi delle versioni precedenti del catalogo, mantenuti per i client esistenti. `reasoning` e `long_context` compaiono anch'essi quando la riga dei prezzi li contiene. | - Le **combinazioni** riportano il prezzo della loro prima destinazione visibile. Le combinazioni integrate `auto/*` scelgono una destinazione al momento della richiesta, quindi non hanno `pricing`. - I **modelli gratuiti** mostrano `"0"` (e `0`) quando il loro prezzo è zero. Un modello senza una riga dei prezzi mostra anch'esso `"0"` quando il catalogo lo contrassegna come gratuito (`free: true`) oppure quando è incluso nel catalogo integrato dei modelli gratuiti. - **Prezzo sconosciuto:** la voce non contiene la chiave `pricing`. - I **provider con tariffazione a crediti** (come Kiro) fatturano per richiesta anziché per token. Le loro voci mantengono i campi numerici per 1M che avevano in precedenza e non contengono campi stringa per token. - Le **varianti** (id per il livello di ragionamento, alias senza ragionamento, mirror di discovery e gateway) copiano il prezzo del modello a cui effettuano il routing. - I campi riportano solo le tariffe di base. I livelli per contesto esteso (il campo numerico `long_context`) e i moltiplicatori del livello di servizio (ad esempio Codex fast o flex) non modificano `prompt` o `completion`. - L'oggetto è lo stesso per ogni stile di autenticazione, inclusa una richiesta in stile Anthropic con `x-api-key` e `anthropic-version` (la risposta rimane `{ "object": "list", "data": [...] }`). Implementazione: `src/app/api/v1/models/catalogPricing.ts`. ### Prefissi degli id dei modelli (`?prefix=`) La maggior parte dei modelli viene pubblicizzata con un **prefisso del provider**. Il prefisso ottenuto è controllato dal feature flag `MODELS_CATALOG_PREFIX_MODE` e può essere sovrascritto **per richiesta** con un parametro di query — utile per un client che desidera un elenco più pulito senza modificare l'impostazione dell'intero server per tutti gli altri: ```bash GET /v1/models?prefix=alias # un id per modello — il prefisso alias breve GET /v1/models?prefix=dual # entrambe le forme (predefinito del server) GET /v1/models?prefix=canonical # solo il prefisso completo dell'id del provider ``` | Mode | Emits | Notes | | ----------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `dual` | `cc/claude-sonnet-4-6` **and** `claude/claude-sonnet-4-6` | **Predefinito.** Entrambi gli id effettuano il routing allo stesso modello; mantenuti affinché le configurazioni dei client che hanno codificato hardcoded una delle due forme continuino a funzionare. Il catalogo raddoppia all'incirca. | | `alias` | `cc/claude-sonnet-4-6` | Una voce per modello. I provider senza un alias distinto emettono comunque la propria voce, quindi non si perde nulla. | | `canonical` | `claude/claude-sonnet-4-6` | Una voce per modello con il prefisso completo dell'id del provider. I provider senza un alias distinto (ad es. `antigravity/…`, `agy/…`) emettono qui anch'essi il loro singolo id, quindi non si perde nulla. | Un mirror in modalità `dual` può anche essere riconosciuto senza il parametro di query: contiene un campo `parent` che punta all'id principale. I client che visualizzano un selettore di modelli dovrebbero richiedere `?prefix=alias` — è ciò che fa l'[estensione OmniCopilot per VS Code](../guides/VSCODE-COPILOT.md). ### Filtri di discovery (`?capability=`, `?min_context=`, `?kind=`, `?q=`) `GET /v1/models` accetta filtri di discovery facoltativi. In assenza di questi filtri, la risposta rimane invariata. Restringono il catalogo già visibile al chiamante (le autorizzazioni della chiave API vengono applicate per prime) e vengono eseguiti prima della paginazione `limit` / `after` in stile OpenAI: ```bash GET /v1/models?capability=vision&capability=tool_calling # ogni capacità elencata deve essere true GET /v1/models?capability=vision,reasoning&min_context=200000 GET /v1/models?kind=embedding # `type` del catalogo; le righe senza questo campo sono `chat` GET /v1/models?q=sonnet&limit=10 # corrispondenza senza distinzione tra maiuscole e minuscole su id o nome ``` | Param | Valori | | ------------- | --------------------------------------------------------------------------------------------------- | | `capability` | `attachment`, `reasoning`, `structured_output`, `temperature`, `thinking`, `tool_calling`, `vision` | | `min_context` | intero non negativo, confrontato con `context_length` | | `kind` | `chat`, `audio`, `embedding`, `image`, `moderation`, `music`, `rerank`, `video` | | `q` | 1–200 caratteri | Un valore sconosciuto o un valore `min_context` che non sia un intero non negativo (ad esempio `1.5`) restituisce HTTP `400` e il messaggio elenca i valori validi. Implementazione: `src/app/api/v1/models/catalogFilters.ts`. ### Elenco ridotto dei modelli (`POST /v1/models/query`) `POST /v1/models/query` restituisce un elenco breve e deterministico dallo stesso catalogo, con la stessa autenticazione e visibilità per chiave di `GET /v1/models`: ```bash POST /v1/models/query Authorization: Bearer your-api-key Content-Type: application/json { "capabilities": ["vision", "tool_calling"], "min_context": 128000, "max_output": 16000, "kind": "chat", "q": "gpt", "owned_by": "openai", "exclude": ["openai/gpt-4o"], "limit": 5 } → { "object": "list", "data": [ ...models ] } ``` Ogni campo è facoltativo. `capabilities` ed `exclude` accettano un array o una stringa separata da virgole; `max_output` viene confrontato con `max_output_tokens`. I risultati sono ordinati per `owned_by`, quindi per `id`. `limit` ha come valore predefinito `20` e i valori superiori a `100` vengono limitati a `100`. JSON non valido, un campo sconosciuto o un valore non valido restituisce HTTP `400`. ### Modelli chat nascosti individualmente Un modello contrassegnato come **Nascosto** nella pagina del provider viene escluso dal catalogo e rifiutato con HTTP `404` / `model_not_found` quando richiesto esplicitamente. Il controllo utilizza il provider e il modello risolti, inclusi gli alias dei provider, i prefissi dei nodi dei provider compatibili e i valori predefiniti della connessione. Una combinazione ignora le destinazioni nascoste e può utilizzare un elemento visibile dello stesso gruppo; quando non rimane alcuna destinazione eseguibile, restituisce lo stesso codice di errore. La rimozione dello stato nascosto ha effetto sulla richiesta successiva. Le sovrascritture della visibilità solo per le immagini non nascondono il modello chat con lo stesso ID. Questa impostazione del singolo modello è separata dalle [liste di consentiti/negati per l'esposizione dei modelli](../routing/MODEL_EXPOSURE_LIST.md), che filtrano la pubblicità nel catalogo e i candidati per l'instradamento automatico, mantenendo al contempo l'invio esplicito. Le autorizzazioni dei modelli per chiave API continuano ad applicarsi in modo indipendente. La modalità predefinita del prefisso del catalogo rimane `dual`. ### Varianti dei modelli senza thinking Per i modelli Claude che supportano il thinking, `/v1/models` pubblicizza anche una variante **senza thinking** il cui id è preceduto da `claude-3-omniroute-no-thinking/`: ``` claude-3-omniroute-no-thinking// ``` La selezione di questo id (ad esempio in una configurazione di Claude Code che allega sempre un blocco `thinking`) risolve nuovamente al vero `/` con il ragionamento soppresso: `thinking:{type:"disabled"}` sul percorso `/v1/messages`, oppure i campi `reasoning`/`reasoning_effort` rimossi sul percorso `/v1/chat/completions`. La variante viene elencata solo per i modelli della famiglia Claude che supportano il thinking **e** rispettano `disabled` (quindi, ad esempio, i modelli che supportano solo la modalità adattiva e rifiutano `disabled` sono esclusi). Gli operatori possono forzare l'attivazione o la disattivazione della variante per modello tramite `ModelSpec.noThinkingAlias`. --- ## Manifest del plugin provider ```bash GET /api/v1/provider-plugin-manifest ``` Restituisce il manifest del plugin provider in formato JSON utilizzato da Bifrost, CLIProxyAPI e dai futuri router sidecar. La risposta viene generata dal registro dei provider TypeScript ed esclude intenzionalmente i segreti client OAuth, la risoluzione dell'ambiente di runtime, le funzioni executor, gli header delle richieste e i dati degli account. Utilizza questo endpoint quando un sidecar viene eseguito out-of-process e non può importare direttamente `open-sse/config/providerPluginManifestRegistry.ts`. --- ## Generazione audio ElevenLabs Configura una connessione del provider `elevenlabs` in OmniRoute con la tua chiave API ElevenLabs. I client effettuano l'autenticazione con la propria chiave **OmniRoute** (`Authorization: Bearer $OMNIROUTE_API_KEY`); il gateway fornisce la chiave del provider memorizzata come `xi-api-key`. Non inviare mai una chiave ElevenLabs come token bearer del gateway. | Metodo | Percorso | Risposta | Categoria endpoint chiave API | | ------ | --------------------------- | ---------------------------------------------- | ----------------------------- | | POST | `/v1/sound-generation` | Byte audio nativi | `elevenlabs` | | POST | `/v1/music` | Byte audio nativi | `music` | | POST | `/v1/music/stream` | Byte audio in streaming | `music` | | POST | `/v1/music/detailed` | Audio multipart nativo e piano di composizione | `music` | | POST | `/v1/music/detailed/stream` | Metadati SSE nativi e segmenti audio | `music` | | POST | `/v1/music/plan` | Piano di composizione JSON | `music` | Questi endpoint completano le route esistenti `/v1/audio/speech`, `/v1/audio/transcriptions`, `/v1/voices`, `/v1/text-to-speech/{voiceId}` e `/v1/speech-to-text`. I campi JSON nativi e i parametri di query come `output_format` e `enable_logging` vengono preservati. Le risposte di `/v1/music/detailed` mantengono i relativi delimitatori multipart; analizzale come multipart. `/v1/music/detailed/stream` restituisce `text/event-stream` con metadati della composizione e segmenti audio codificati in base64 negli eventi SSE. Tutte e sei le route supportano il preflight CORS. ```bash export OMNIROUTE_BASE_URL="http://localhost:20128" export OMNIROUTE_API_KEY="your-omniroute-api-key" # Un breve effetto sonoro. Durata: da 0,5 a 30 secondi. curl --fail-with-body "$OMNIROUTE_BASE_URL/v1/sound-generation?output_format=mp3_44100_128" \ -H "Authorization: Bearer $OMNIROUTE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text":"A single soft bell chime","duration_seconds":1,"model_id":"eleven_text_to_sound_v2"}' \ --output effect.mp3 # La durata della musica è espressa in millisecondi: da 3000 a 600000. curl --fail-with-body "$OMNIROUTE_BASE_URL/v1/music?output_format=mp3_44100_128" \ -H "Authorization: Bearer $OMNIROUTE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt":"Gentle instrumental piano","music_length_ms":10000,"force_instrumental":true,"model_id":"music_v1"}' \ --output music.mp3 ``` Utilizza `/v1/music/stream` con lo stesso corpo JSON per la distribuzione incrementale dell'audio. La composizione accetta esattamente uno tra `prompt` e `composition_plan`; `/v1/music/plan` richiede `prompt` e accetta facoltativamente `source_composition_plan`. Gli schemi nativi preservano campi aggiuntivi del provider, così le versioni dei piani di composizione e le opzioni di ottimizzazione raggiungono ElevenLabs. L'endpoint unificato `/v1/music/generations` accetta anche `elevenlabs/music_v1`, `elevenlabs/music_v2` e `elevenlabs/music_v2_5`. Con una connessione ElevenLabs attiva, questi modelli vengono esposti dal catalogo musicale. Questo endpoint restituisce `{"created":...,"data":[{"b64_json":"...","format":"mp3"}]}`. Il campo `duration` è espresso in secondi e viene mappato a `music_length_ms`; un valore esplicito di `music_length_ms` ha la precedenza. `instrumental` viene mappato a `force_instrumental`, con il campo nativo che ha la precedenza. Utilizza gli endpoint nativi di streaming per lo streaming e l'endpoint nativo di composizione per le richieste basate esclusivamente su un piano di composizione. ```bash curl --fail-with-body "$OMNIROUTE_BASE_URL/v1/music/generations" \ -H "Authorization: Bearer $OMNIROUTE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"elevenlabs/music_v1","prompt":"Gentle instrumental piano","duration":10,"instrumental":true}' ``` Le restrizioni relative a endpoint, modello, budget e connessione vengono applicate prima della chiamata upstream. Le route native restituiscono i codici di stato e i corpi degli errori upstream invariati, incluso `402` per una restrizione del piano e `429` per un limite di quota. Gli header `character-cost`, `song-id`, `request-id` e `retry-after` vengono preservati quando presenti. Un saldo di crediti gratuito non garantisce l'accesso a ogni modello musicale, formato di output o funzionalità API: ElevenLabs stabilisce i diritti per ogni richiesta. L'endpoint unificato preserva i codici di stato degli errori nell'envelope di errore normalizzato di OmniRoute. Contratti upstream: [effetti sonori](https://elevenlabs.io/docs/api-reference/text-to-sound-effects/convert), [composizione musicale](https://elevenlabs.io/docs/api-reference/music/compose) e [dettagli della musica in streaming](https://elevenlabs.io/docs/api-reference/music/compose-detailed-stream). --- ## Endpoint di compatibilità | Metodo | Percorso | Formato | | ------ | ----------------------------------------- | --------------------------------------- | | POST | `/v1/chat/completions` | OpenAI | | POST | `/v1/messages` | Anthropic | | POST | `/v1/responses` | OpenAI Responses | | POST | `/v1/embeddings` | OpenAI | | POST | `/v1/images/generations` | OpenAI Images | | POST | `/v1/images/edits` | OpenAI Images (modifica/inpainting) | | POST | `/v1/videos/generations` | Generazione video in stile OpenAI | | POST | `/v1/music/generations` | Generazione musicale in stile OpenAI | | POST | `/v1/audio/transcriptions` | OpenAI Audio (STT) | | POST | `/v1/audio/speech` | OpenAI TTS (restituisce il corpo audio) | | POST | `/v1/rerank` | Reranking in stile Cohere/Voyage | | POST | `/v1/classify` | Classificazione Jina (`api.jina.ai`) | | POST | `/v1/segment` | Segmentatore Jina (`segment.jina.ai`) | | POST | `/v1/moderations` | Moderazioni OpenAI | | GET | `/v1/models` | OpenAI | | POST | `/v1/models/query` | Elenco ristretto di modelli filtrato | | POST | `/v1/messages/count_tokens` | Anthropic | | GET | `/v1beta/models` | Gemini | | POST | `/v1beta/models/{...path}` | Gemini generateContent | | POST | `/v1/api/chat` | Ollama | | GET | `/api/v1/vscode/{token}/` | Alias del catalogo OpenAI | | GET | `/api/v1/vscode/{token}/models` | Alias dei modelli OpenAI | | POST | `/api/v1/vscode/{token}/chat/completions` | Alias OpenAI con token | | POST | `/api/v1/vscode/{token}/responses` | Alias OpenAI Responses con token | | POST | `/api/v1/vscode/{token}/api/chat` | Alias Ollama con token | | GET | `/api/v1/vscode/{token}/api/tags` | Alias dei tag Ollama con token | Tutte le route POST seguono la stessa struttura: `Bearer your-api-key` + corpo JSON convalidato da Zod (`v1RerankSchema`, `v1ModerationSchema`, `v1AudioSpeechSchema`, ecc.; vedere `src/shared/validation/schemas.ts`). In caso di errore dello schema viene restituito un codice 4xx. Per i client che non possono aggiungere `Authorization: Bearer ...`, OmniRoute accetta anche le chiavi API nell'URL tramite la compatibilità con stringa di query (`?token=...`, `?apiKey=...`, `?api_key=...`, `?key=...`) oppure tramite gli endpoint dedicati `/api/v1/vscode/{token}/...` documentati di seguito. ```bash # Reranking (provider del registro cloud oppure un nodo provider compatibile con OpenAI come "/") POST /v1/rerank { "model": "jina-ai/jina-reranker-v3.5", "query": "...", "documents": ["..."] } # Classificazione Jina (credenziali API Foundation) POST /v1/classify { "model": "jina-embeddings-v5-text-small", "input": ["..."], "labels": ["a", "b"] } # Segmentatore Jina POST /v1/segment { "content": "...", "return_chunks": true } # Ricerca Jina (s.jina.ai; alias dei provider: jina-search, jina-ai, jina) POST /v1/search { "query": "...", "provider": "jina-search" } # Moderazioni POST /v1/moderations { "model": "omni-moderation-latest", "input": "..." } # TTS — restituisce il corpo audio/mpeg (o il formato richiesto) POST /v1/audio/speech { "model": "openai/tts-1", "input": "Hello", "voice": "alloy" } # Il TTS Soniox richiede una lingua e una voce: `language` assume "en" per impostazione predefinita; una # voce mancante o un nome di voce standard OpenAI (alloy, nova, …) diventa "Adrian" POST /v1/audio/speech { "model": "soniox/tts-rt-v1", "input": "Xin chào", "voice": "Adrian", "language": "vi" } # Modifica immagine (multipart) POST /v1/images/edits -F image=@input.png -F prompt="..." -F mask=@mask.png # Generazione video / musicale (ID modello con prefisso del provider) POST /v1/videos/generations { "model": "runway/gen-3", "prompt": "..." } POST /v1/music/generations { "model": "kie/suno-v4.0", "prompt": "..." } ``` > **Nodi provider per il reranking:** `POST /v1/rerank` instrada anche verso nodi provider compatibili con OpenAI > (oMLX, vLLM, Infinity, TEI dietro un gateway, …) indirizzati come `/`. I nodi di loopback > (`localhost`, `127.0.0.1`, `172.16.0.0/12`) sono sempre idonei, così come i nomi host elencati dall'operatore in > `OMNIROUTE_LOCAL_PROVIDER_NODE_HOSTS` (ad esempio un nome di servizio Docker/Compose come > `http://reranker:8080/v1`; questi vengono contattati direttamente, mai tramite `HTTP(S)_PROXY` o il proxy > associato alla connessione). I nodi su qualsiasi altro > host — un dispositivo della LAN o un peer Tailscale — sono idonei solo quando l'operatore abilita il > flag di funzionalità `RERANK_REMOTE_PROVIDER_NODES` **e** l'URL di base del nodo supera i criteri per gli URL in uscita dei provider > (`OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS` / `OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS`). > Il passaggio di reranking del motore di memoria chiama questa route tramite > loopback, quindi la stessa regola disciplina `rerankProviderModel` nelle impostazioni della memoria. > > **Formati dei server locali:** il nodo viene chiamato a `/v1/rerank` e, in caso di 404, a `/rerank` > (Infinity, TEI). Il corpo inviato al servizio upstream contiene entrambe le convenzioni di denominazione Cohere/OpenAI (`documents`, > `return_documents`) e quella di TEI (`texts`, `return_text`), mentre la risposta upstream > viene normalizzata nel contenitore Cohere: l'array TEI semplice `[{index, score, text}]`, `{results: [{index, score}]}` > dei gateway minimali e `{data: [...]}` nello stile Voyage vengono tutti restituiti al client come > `{results: [{index, relevance_score, document?}]}`, ordinati per punteggio e limitati a `top_n`. > **Individuazione dei nodi provider:** i modelli su un nodo provider compatibile con OpenAI compaiono in `GET /v1/models` > con il prefisso del nodo. Le righe che non contengono metadati sull'endpoint (tipico degli elenchi locali di `/v1/models`) > ereditano il relativo `apiType` del nodo, quindi i modelli di un nodo `embeddings` hanno > `type: "embedding"` e quelli di un nodo `rerank` hanno `type: "rerank"` invece di impostare per impostazione predefinita il tipo chat; > un valore `supportedEndpoints` esplicito in una riga sincronizzata o aggiunta manualmente mantiene comunque la precedenza. ### Route dedicate dei provider ```bash POST /v1/providers/{provider}/chat/completions POST /v1/providers/{provider}/embeddings POST /v1/providers/{provider}/images/generations ``` Il prefisso del provider viene aggiunto automaticamente se manca. I modelli non corrispondenti restituiscono `400`. --- ## API dei file Endpoint dei file compatibile con OpenAI per l'input/output dei batch e i caricamenti di file per scopi specifici. | Metodo | Percorso | Descrizione | | ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------ | | POST | `/v1/files` | Carica un file (multipart: `file`, `purpose`, `expires_after[anchor]`, `expires_after[seconds]`) — massimo 512 MiB | | GET | `/v1/files` | Elenca i file per la chiave API autenticata | | GET | `/v1/files/[id]` | Recupera i metadati di un file | | DELETE | `/v1/files/[id]` | Elimina un file | | GET | `/v1/files/[id]/content` | Trasmette il corpo grezzo del file | **Autenticazione:** chiave API Bearer — i file sono associati a ciascuna chiave API tramite `getApiKeyRequestScope`. Una chiave può visualizzare, scaricare ed eliminare solo i propri file; una sessione della dashboard senza chiave legge l'intera istanza; un file senza proprietario (caricato anonimamente o tramite una sessione della dashboard) viene negato a ogni chiamante non appartenente a una sessione. `GET /v1/files` rifiuta con `401` un chiamante anonimo — e una chiave presentata che non viene risolta — anche quando `REQUIRE_API_KEY=false`, invece di elencare i file di ogni tenant (GHSA-m3hp-hq9g-fpmv, GHSA-2jm2-mpx8-6523). --- ## API dei batch Elaborazione dei batch compatibile con OpenAI. | Metodo | Percorso | Descrizione | | ------ | ------------------------- | ------------------------------------------------------------------------------------------------------------- | | POST | `/v1/batches` | Crea un batch — corpo convalidato da `v1BatchCreateSchema` (`input_file_id`, `endpoint`, `completion_window`) | | GET | `/v1/batches` | Elenca i batch | | GET | `/v1/batches/[id]` | Recupera lo stato del batch e `request_counts` | | DELETE | `/v1/batches/[id]` | Elimina un batch terminato o non riuscito | | POST | `/v1/batches/[id]/cancel` | Annulla un batch in corso | **Autenticazione:** chiave API Bearer. I batch sono associati a ciascuna chiave API secondo la stessa regola a tre vie dei file: solo la propria chiave, sessione della dashboard a livello di istanza, record senza proprietario negati a ogni chiamante non appartenente a una sessione (recupero, eliminazione, annullamento e controllo di `input_file_id` durante la creazione). `GET /v1/batches` rifiuta con `401` un chiamante anonimo anche quando `REQUIRE_API_KEY=false`. --- ## Cerca API astrazione del provider Web/search (Tavily, Brave, Exa, Serper, ecc.). | Metodo | Sentiero | Descrizione | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------ | | GET | `/v1/search` | Elenca le funzionalità + dei provider di ricerca configurati | | POST | `/v1/search` | Esegui una query di ricerca corpo — convalidato da `v1SearchSchema`, supporta caching/coalescing | | GET | `/v1/search/analytics` | Statistiche hit/latency/cache per fornitore | **Autenticazione:** Chiave API portatrice (`extractApiKey` + `isValidApiKey`). Politica di ricerca applicata tramite `enforceApiKeyPolicy`. **Selezione automatica:** senza `provider`, il provider più economico con una connessione configurata viene eseguito per primo e il successivo più economico è il failover. I fornitori di ultima istanza gratuiti (`duckduckgo-free`) vengono utilizzati solo quando non è configurato nient'altro. Uno SearXNG self-hosted conta come configurato una volta che la sua connessione memorizza un vero `baseUrl` (non lo `http://localhost:8888/search` predefinito del catalogo): si classifica quindi come un provider $ 0 davanti a quelli con chiave, con il provider con chiave più economico come failover, anche quando SearXNG risponde 400, 401, 403 o 404. Uno `baseUrl` che non è uno `http(s)` URL valido o che punta a un indirizzo di metadati cloud non conta. Una connessione SearXNG che memorizza un token si classifica in questo modo solo su `https://` o loopback `http://`. Su `http://` semplice remoto non si verifica mai un failover e rimane l'ultima risorsa, utilizzata solo quando nessun altro provider è configurato o quando richiesto per nome, quindi in questi due casi invia il token in chiaro. ### Exa e Tavily `provider_options` Exa e Tavily leggono i campi specifici del provider da un sacchetto con spazio dei nomi: `provider_options.exa` (o `provider_options["exa-search"]`) e `provider_options.tavily` (o `provider_options["tavily-search"]`). Vengono inoltrate solo le chiavi sottostanti. Ognuno viene controllato rispetto al proprio schema Zod in `open-sse/handlers/search/providerOptionsPassthrough.ts` e una chiave con il tipo sbagliato viene eliminata. Qualsiasi altra chiave viene ignorata, incluse auth, base URL, `stream` e `outputSchema`. I tasti piatti utilizzati da altri provider (`cx`, `depth`, ...) funzionano come prima. | Fornitore | Campi di primo livello | Nidificato | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | Es | `type`, `category`, `userLocation`, `moderation`, `additionalQueries`, `objective`, `systemPrompt`, `compliance` (primitive piatte), `startPublishedDate`, `endPublishedDate` | `contents.{text, highlights, summary, extras, livecrawlTimeout, maxAgeHours}` unito al `{ text: true, highlights: true }` predefinito | | Tavily | `search_depth`, `chunks_per_source`, `time_range`, `start_date`, `end_date`, `include_published_date`, `filter_by_published_date`, `include_answer`, `include_raw_content`, `include_images`, `include_image_descriptions`, `include_favicon`, `include_domains_mode`, `language`, `filter_by_language`, `auto_parameters`, `exact_match`, `include_usage`, `safe_search` | — | Vincono sempre i campi generici: `query`, `max_results`, `filters` (domini), `country` e il topic derivato da `search_type`. Su Exa, `search_type: "news"` mantiene `category: "news"`. Tavily accetta anche `search_type: "finance"` (`topic: "finance"`). Il costo della ricerca Firecrawl viene registrato per blocco avviato di 10 risultati restituiti, a $ 0,002 (2 crediti) per blocco e almeno un blocco per chiamata ( [fatturazione Firecrawl](https://docs.firecrawl.dev/billing) ): 11 risultati costano $ 0,004. Il generico `time_range` ora raggiunge entrambi i fornitori: Exa ottiene `startPublishedDate` (ISO timestamp) e Tavily ottiene `start_date` (`YYYY-MM-DD`). Una data esplicita in `provider_options` sovrascrive quella mappata. I risultati Exa mantengono `id`, `highlights` (ogni evidenziazione, non solo la prima usata come `snippet`), `highlight_scores`, `summary`, `subpages`, `entities` e `extras` in `provider_raw`. I risultati di Tavily mantengono `images` e `favicon`. Il costo della ricerca di collegamento è registrato a $ 0,005 per `depth` `fast` e `standard` e $ 0,05 per `deep` ( [prezzo di collegamento](https://docs.linkup.so/pages/documentation/development/pricing) ), indipendentemente dal fatto che `depth` provenga da `provider_options` o dalle impostazioni della connessione. Exa `type: "lite"` (Exa 3.0) accetta un insieme più piccolo di campi e rifiuta l'intera richiesta quando viene impostato qualsiasi altro campo. Per lite, `additionalQueries`, `systemPrompt` e tutti i tasti `contents` tranne `text` e `highlights` vengono eliminati prima della chiamata. I deprecati `subpages`, `subpageTarget`, `highlights.numSentences` e `highlights.highlightsPerUrl` non vengono più inoltrati. La contabilità dei costi è il registro piatto `costPerQuery`, ad eccezione di Exa, che segue i prezzi di Exa: $ 0,007 per chiamata per `auto` (e l'eredità `fast`) o $ 0,004 per `lite` (e l'eredità `instant`), coprendo 10 risultati; $ 0,001 per ogni ulteriore risultato; e $ 0,001 per risultato restituito quando è impostato `contents.summary`. Tavily è registrato a 1 credito ($ 0,008) per `search_depth` `basic`, `fast` e `ultra-fast` e 2 crediti ($ 0,016) per `advanced` ( [crediti Tavily API](https://docs.tavily.com/documentation/api-credits) ). Una chiamata con `auto_parameters: true` che Tavily aggiorna ad avanzato viene comunque registrata a 1 credito. --- ## API Web Fetch Estrae contenuti da un URL tramite un provider di web fetch configurato (Firecrawl, Jina Reader, Tavily Extract, TinyFish Fetch, Nimble Extract, Parallel Extract). Parallel Extract (`parallel-search`, con la stessa chiave API di Parallel Search) restituisce solo Markdown — qualsiasi altro `format` genera un `400` — e limita il contenuto a 100.000 caratteri. Quando non è possibile estrarre direttamente la pagina di destinazione, il servizio upstream lo segnala all'interno di un HTTP 200; OmniRoute lo espone come `422` con un messaggio fisso. | Metodo | Percorso | Descrizione | | ------ | --------------- | ---------------------------------------------------------------------------- | | POST | `/v1/web/fetch` | Esegue il fetch/scraping di un URL — corpo convalidato da `v1WebFetchSchema` | **Autenticazione:** chiave API Bearer (`extractApiKey` + `isValidApiKey`). La policy viene applicata tramite `enforceApiKeyPolicy`. **Fallback consapevole della quota (#8297):** quando non viene specificato alcun `provider`, il pool (`firecrawl` → `jina-reader` → `tavily-search` → `tinyfish` → `nimble-search` → `parallel-search`) viene percorso in ordine di priorità fisso (fill-first) — un provider limitato dalla frequenza ma configurato viene saltato invece di interrompere la richiesta, e un errore upstream ritentabile/relativo alla quota (HTTP 429 sempre; 402/403 per i free tier con quota in stile Firecrawl/Tavily/TinyFish — non per Jina Reader e mai per un semplice 400 dovuto a una richiesta non valida) passa al provider successivo non ancora tentato e dotato di credenziali al momento della richiesta. Quando tutti i provider del pool sono esauriti, l'endpoint restituisce un singolo `429` (con un'intestazione `Retry-After`) invece del precedente `400` generico. Quando viene richiesto un `provider` esplicito, **non** è previsto alcun fallback silenzioso — un provider esplicito limitato dalla frequenza o in errore espone il proprio errore (`429` se limitato dalla frequenza, altrimenti lo stato upstream). --- ## Streaming WebSocket ```bash GET /v1/ws?handshake=1 ``` Convalida un handshake di aggiornamento WebSocket e restituisce i messaggi di esempio del protocollo wire (`request`, `cancel`). I frame WS effettivi vengono gestiti dal server WS incluso, al di fuori della tabella delle route di Next.js. **Autenticazione:** chiave API Bearer durante l'handshake. ### API Responses tramite WebSocket (solo codex) ```bash # Stesso host:port dell'API HTTP (predefinito 20128); aggiorna la connessione: wscat -c "ws://localhost:20128/v1/responses?api_key=" # (oppure: -H "Authorization: Bearer ") # Il primo frame DEVE essere response.create: { "type": "response.create", "model": "gpt-5.5", "input": [ { "role": "user", "content": "hi" } ] } ``` Un proxy Responses-API-over-WebSocket è collegato **esclusivamente a `codex`** (backend ChatGPT). È in ascolto sulla stessa porta dell'API/dashboard nei percorsi `/v1/responses`, `/responses` e `/api/v1/responses`. Al primo frame `response.create` esegue l'autenticazione e la preparazione tramite il bridge interno `codex-responses-ws`, seleziona una connessione OAuth codex e crea un tunnel verso `wss://chatgpt.com/backend-api/codex/responses` tramite il trasporto `wreq-js`. I modelli diversi da codex vengono rifiutati (`codex_ws_provider_required`). Per il routing della condivisione della quota, usare `model: "qtSd//codex/"`. Implementato in `app/server-ws.mjs` + `scripts/dev/responses-ws-proxy.mjs` + `src/app/api/internal/codex-responses-ws/route.ts`. **Autenticazione:** chiave API Bearer durante l'handshake. Il server HTTP incluso (`server-ws.mjs`) deve essere l'entrypoint attivo (lo è per impostazione predefinita quando esiste `app/server-ws.mjs`). #### ID del modello: usare l'ID ChatGPT senza prefisso `codex/` **Codex CLI** di OpenAI convalida il nome del modello lato client quando `supports_websockets = true` e rifiuta gli ID con prefisso del provider come `codex/gpt-5.5` (`The 'codex/gpt-5.5' model is not supported when using Codex with a ChatGPT account`). Inviare l'ID **senza prefisso** (ad es. `gpt-5.5`). Il bridge di OmniRoute è solo codex, quindi risolve nuovamente un ID senza prefisso come modello codex (`resolveCodexWsModelInfo`) prima di creare il tunnel upstream — anche se un semplice `gpt-5.5` verrebbe altrimenti instradato verso un altro provider tramite HTTP. #### Configurazione di OpenAI Codex CLI Indirizzare Codex CLI a OmniRoute aggiungendo un provider personalizzato con supporto WebSocket a `~/.codex/config.toml` (usare un `CODEX_HOME` separato per evitare di modificare una configurazione esistente): ```toml model = "gpt-5.5" # id senza prefisso — NON "codex/gpt-5.5" model_provider = "omniroute" [model_providers.omniroute] name = "OmniRoute (WS)" base_url = "http://localhost:20128/v1" # nessuna slash finale; l'URL WS viene derivato (usare https/wss in produzione) wire_api = "responses" # unico valore supportato da febbraio 2026 supports_websockets = true # abilita il trasporto Responses-over-WS env_key = "OMNIROUTE_API_KEY" # contiene la chiave API OmniRoute (Bearer) ``` ```bash export OMNIROUTE_API_KEY=sk-... # una chiave API OmniRoute (qualsiasi chiave se REQUIRE_API_KEY=false) codex exec "Responda apenas: PONG" ``` La CLI aggiorna `base_url + /responses` a un WebSocket e OmniRoute crea un tunnel verso la connessione OAuth codex selezionata. Convalidato end-to-end sul server locale: ChatGPT restituisce `codex.rate_limits` + `response.created` e trasmette in streaming il completamento. --- ## Report di quote e problemi | Metodo | Percorso | Descrizione | | ------ | ------------------- | -------------------------------------------------------------------------------------------------------------- | | GET | `/v1/quotas/check` | Preconvalida la quota per una combinazione di `provider` + `accountId` prima di emettere una chiave registrata | | POST | `/v1/issues/report` | Segnala a GitHub un errore di emissione di quota/chiave (richiede `GITHUB_ISSUES_REPO` + token) | **Autenticazione:** chiave API Bearer (`isAuthenticated`). ### Recupero della sessione di quota (facoltativo) Una richiesta `POST /v1/chat/completions` o `POST /v1/responses` non in streaming che restituisce un errore di quota terminale (`402`/`429`/`503` il cui corpo indica che la quota o i crediti sono esauriti) può essere messa in attesa e riprodotta in seguito invece di restituire l'errore. Il chiamante abilita questa opzione per ogni richiesta con tre intestazioni: | Intestazione | Valore | | ---------------------------- | --------------------------------------------------- | | `x-omniroute-quota-recovery` | `auto` | | `x-omniroute-session` | ID sessione, `[A-Za-z0-9._:-]{1,128}` | | `x-omniroute-recovery-turn` | ID del turno univoco nella sessione (stessa regola) | Sono idonei solo i turni con `stream: false`, senza strumenti, cronologia degli strumenti o `previous_response_id`, e senza un pin `x-omniroute-connection`; inoltre, `STORAGE_ENCRYPTION_KEY` deve essere impostata (la richiesta viene archiviata in forma crittografata per un massimo di 24 ore). La risposta è quindi `202` con `recovery.poll`; eseguire il polling su `GET /v1/quota-recoveries/{id}` (`202` mentre è in sospeso, `200` con il corpo recuperato al completamento) oppure annullare con `DELETE`. I ticket sono visibili solo alla chiave API che li ha creati. Una riproduzione il cui esito è incerto termina in `needs_confirmation` invece di essere inviata due volte. Fonte: `src/lib/quota/quotaSessionRecovery.ts`. --- ## Utilizzo self-service (`/api/usage/om-usage`) Qualsiasi chiave API può leggere** il suo** utilizzo e quote — nessuna autenticazione di gestione. Questo è l'endpoint che un cliente (CLI, il pannello OmniCopilot ) utilizza per mostrare al detentore delle chiavi la propria spesa. ```bash # Text form (the historical contract — plain text for a terminal) curl -H "Authorization: Bearer " \ http://localhost:20128/api/usage/om-usage # Structured form — what a UI consumes curl -H "Authorization: Bearer " \ "http://localhost:20128/api/usage/om-usage?format=json" ``` La chiave deve avere**`allowUsageCommand`** abilitato (disattivato per impostazione predefinita — il gestore delle chiavi API della dashboard lo attiva/disattiva per chiave). Senza di esso l'endpoint risponde `403`. `?format=json` restituisce una forma discriminata in modo che un chiamante non legga mai un campo dati da un rifiuto. In caso di successo: ```jsonc { "allowed": true, // present only when the key opted into per-key usage limits (daily/weekly/5-hour USD): "personal": { "dailySpentUsd": 1.25, "dailyLimitUsd": 5, "dailyResetAtIso": "…", "weeklySpentUsd": 8, "weeklyLimitUsd": 20, "weeklyResetAtIso": "…" /* … */, }, // the selected provider quota snapshot, or null when nothing is cached yet: "provider": { "connectionId": "…", "provider": "claude", "plan": "…", "quotas": {/* … */} }, // every connection's snapshot, so a UI can render several providers side by side: "providers": [ { "connectionId": "…", "provider": "claude" /* … */ }, { "provider": "codex" /* … */ }, ], } ``` In caso di rifiuto (`401` chiave errata / `403` non consentita) lo stesso percorso restituisce `{ "allowed": false, "error": { "message": "…" } }` — un presente ma vuoto `personal`/`provider` (chiave consentita, ancora nulla imparato) è uno stato diverso da un rifiuto e solo la forma JSON li distingue. **Autenticazione:** la chiave Bearer API del chiamante, convalidata con `isValidApiKey` — questa _non_ è la superficie di gestione (`/api/keys/…`), che rimane dietro `requireManagementAuth`. ### Percentuali di quota grezza e corretta per il limite massimo Quando si consuma `/api/usage/om-usage`, i chiamanti dovrebbero notare la distinzione tra le percentuali presentate dal** output in testo semplice** e quello strutturato** uscita JSON** : | Aspetto | Formato testo normale (`/api/usage/om-usage` / `@@om-usage`) | formato JSON (`?format=json`) | | :------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------- | | **Campo di uscita** | `NN% left` (ad esempio, `20% left`) | `provider.quotas` / `providers[].quotas` | | **Misurazione** | **Indennità utilizzabile adeguata al limite** : capacità residua superiore alla soglia di interruzione | **Quota grezza a monte** : misurazione del fornitore non corretta | | **Ridimensionamento del taglio** | Ridimensionato tramite `effectiveRemainingPercent()` in modo che la riserva protetta venga letta come `0% left` | Nessuno (valori dell'istantanea grezza come riportati dal provider) | | **Dati soglia** | Incorporato nella percentuale visualizzata | Memorizzato in `quotaWindowThresholds` per connessione (o impostazioni predefinite del server) | | **Consumatore primario** | CLIs interattivo, istruzioni del terminale, operatori umani | Integrazioni programmatiche, dashboard, analisi, tracker di fatturazione | #### La formula di aggiustamento del cutoff OmniRoute supporta tagli proattivi delle quote per prevenire l'esaurimento dell'upstream (configurato tramite connessione `quotaWindowThresholds`, impostazioni predefinite del provider o impostazioni di resilienza globale). Quando una soglia limite (ad esempio, `cutoff = 25%`) è attiva in una finestra di quota, il renderer del testo calcola la quota rimanente come: - Se `remaining <= cutoff`: restituisce `0%`. - Se `remaining > cutoff`: restituisce `((remaining - cutoff) / (100 - cutoff)) * 100`. L'output di testo formattato lo arrotonda al numero intero più vicino (`Math.round(...)`). #### Esempio illustrativo Considera una finestra del provider con** Utilizzo grezzo del 60%.** (quindi** Quota rimanente grezza del 40%.** ) e un configurato** Limite della quota rimanente del 25%.** soglia: | Rappresentazione | Calcolo | Rimanente | Usato implicito | | :------------------------------- | :------------------------------------------------- | :-------: | :---------------------------------------: | | **JSON grezzo (`?format=json`)** | Istantanea a monte (`quotas[window]`) | **40%** | **60%** | | **Formato testo (`NN% left`)** | `((40 - 25) / (100 - 25)) * 100 = (15 / 75) * 100` | **20%** | **80%** (se si calcola `100 - remaining`) | - **Perché il testo mostra il 20% rimasto:** Della quota fisica del 40% rimasta sul conto, il 25% è riservato dalla politica di interruzione. Al chiamante rimane solo il 15% del 75% di margine utilizzabile prima che il router interrompa l'instradamento a questa connessione. Lo scaling garantisce che la connessione segnali l'esaurimento (`0% left`) esattamente quando il routing cesserà. - **Perché JSON preserva i valori grezzi:** Il payload JSON restituisce l'esatta istantanea del provider (`UsageSnapshot`) in modo che gli strumenti esterni abbiano accesso all'utilizzo upstream attendibile e a `quotaWindowThresholds` a livello di connessione senza ridimensionamento con perdite lato server. #### Guida alla migrazione dei consumatori Se un'integrazione esterna (come un plug-in dell'editor o un'estensione dell'agente) ha precedentemente eliminato l'endpoint di testo (`NN% left`) e calcolato la percentuale utilizzata come `100 - NN`, la migrazione a `?format=json` significa: - La lettura dei valori JSON grezzi rifletterà** consumo effettivo a monte** (60% utilizzato nell'esempio sopra). - Se l'integrazione desidera preservare la semantica di tolleranza utilizzabile dell'endpoint di testo, può valutare l'effettiva formula rimanente lato client utilizzando `quotaWindowThresholds` per le sostituzioni a livello di connessione. --- ## Cache semantica ```bash # Ottieni le statistiche della cache GET /api/cache/stats # Cancella tutte le cache DELETE /api/cache/stats ``` Esempio di risposta: ```json { "semanticCache": { "memorySize": 42, "memoryMaxSize": 500, "dbSize": 128, "hitRate": 0.65 }, "idempotency": { "activeKeys": 3, "windowMs": 5000 } } ``` ### Impatto sulla latenza Un HIT della cache semantica restituisce la risposta dalla cache **senza una chiamata upstream**, pertanto `X-OmniRoute-Response-Latency` riportato è quasi zero (indipendentemente dalla latenza upstream originale). I client sensibili alla latenza (benchmark, monitoraggio p50/p99) devono controllare l'header di risposta `X-OmniRoute-Cache-Latency`: | Valore | Significato | | ----------- | -------------------------------------------------------------------------- | | `synthetic` | Risposta fornita dalla cache; la latenza non è il tempo upstream effettivo | | _(absent)_ | Risposta da una chiamata upstream reale | ### Esclusione della cache per chiave Le chiavi API possono disattivare le letture dalla cache semantica tramite `cacheDefaultMode`: | Valore | Comportamento | | -------- | ----------------------------------------------------------------------- | | `legacy` | Comportamento normale della cache (predefinito) | | `bypass` | Ignora completamente la ricerca nella cache; accede sempre all'upstream | Impostare alla creazione della chiave (`POST /api/keys`) o durante l'aggiornamento (`PATCH /api/keys/[id]`): ```json { "cacheDefaultMode": "bypass" } ``` ### Esclusione della cache per richiesta Qualsiasi richiesta può ignorare la cache indipendentemente dalle impostazioni della chiave: ``` X-OmniRoute-No-Cache: true ``` --- ## Compatibilità con la gestione di CLIProxyAPI OmniRoute risponde ai tre endpoint di gestione di [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) che i dashboard di utilizzo chiamano per leggere i limiti degli abbonamenti Claude e Codex (ad esempio, la sorgente dei limiti di utilizzo `cliproxy` di T3 Code). Impostare l'URL di base del client su OmniRoute e utilizzare una chiave API con lo scope `manage` come chiave di gestione. Le route sono disponibili in `/v0/management/*` e `/api/v0/management/*`. | Metodo | Percorso | Descrizione | | ------ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/v0/management/auth-files` | Connessioni OAuth Claude e Codex come `{ files: [{ id, auth_index, provider, email, disabled, id_token }] }`. Nessun token | | POST | `/v0/management/api-call` | Corpo `{ auth_index, method, url, header?, data? }`. Invia una richiesta consentita con il token dell'account e restituisce `{ status_code, body }` | | POST | `/v0/management/reset-quota` | Corpo `{ auth_index }`. Cancella il cooldown della connessione, i blocchi del modello e i cooldown per ambito di Codex di un account | - `auth_index` è l'ID della connessione OmniRoute. `provider` è `claude` o `codex` (solo connessioni OAuth; il provider con chiave API `anthropic` non è elencato). Per Codex, `id_token.chatgpt_account_id` è l'ID dello spazio di lavoro memorizzato e `plan_type` il piano memorizzato. - `api-call` non è un proxy generico. Accetta solo Claude `GET https://api.anthropic.com/api/oauth/usage` e Codex `GET https://chatgpt.com/backend-api/wham/usage`, `GET .../wham/rate-limit-reset-credits` e `POST .../wham/rate-limit-reset-credits/consume`, ciascuno esclusivamente per un account del provider corrispondente. Qualsiasi altra richiesta restituisce `403` senza contattare l'upstream. L'header `Authorization` del chiamante (incluso il segnaposto `$TOKEN$`) viene ignorato: OmniRoute inserisce il token di accesso della connessione, aggiornandolo prima quando è vicino alla scadenza, e inoltra solo gli header consentiti (`anthropic-beta`; `OpenAI-Beta`, `Originator`, `Chatgpt-Account-Id`; `Accept`, `Content-Type`). Se `Chatgpt-Account-Id` è assente, viene utilizzato per impostazione predefinita l'ID dello spazio di lavoro memorizzato. Le richieste scadono dopo 15 secondi e utilizzano il proxy della connessione. - `reset-quota` lascia invariati gli stati terminali (banned, expired, credits_exhausted). Un `auth_index` sconosciuto restituisce `404`. **Autenticazione:** sessione del dashboard o chiave API con scope `manage`, obbligatoria anche quando l'accesso è disabilitato (i percorsi sono inclusi in `ALWAYS_PROTECTED_API_PATHS`). Le chiavi utilizzabili solo per l'inferenza ricevono `403`. Sorgente: `src/lib/cliproxyCompat/managementApi.ts`. --- ## Cruscotto e gestione Sono percorsi di gestione (`/api/*` eccetto auth/login pubblici).** non** autorizzato dalle chiavi API di inferenza ordinaria. Famiglie di credenziali, ambiti ed esempi di curl: [autenticazione di gestione](../guides/MANAGEMENT-AUTH.md). ### Autenticazione | Punto finale | Metodo | Descrizione | | ----------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/auth/login` | POST | Login | | `/api/auth/logout` | POST | Esci | | `/api/settings/require-login` | GET/POST | Stato di accesso (GET, pubblico). POST imposta la password/attiva/disattiva l'accesso: solo operatore una volta che esiste una password (sessione del dashboard, CLI locale o accesso disabilitato — Le chiavi API e i token `oma_` ottengono `403`); una sessione del dashboard invia `currentPassword` per sostituire la password | ### Gestione dei fornitori | Punto finale | Metodo | Descrizione | | --------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/api/providers` | GET/POST | Elenca/crea fornitori | | `/api/providers/[id]` | GET/PUT/DELETE | Gestisci un fornitore | | `/api/providers/[id]/test` | POST | Testare la connessione al fornitore | | `/api/providers/[id]/models` | GET | Elenca i modelli del provider | | `/api/providers/validate` | POST | Convalida la configurazione del provider | | `/api/providers/bulk` | POST | Aggiunta in blocco di chiavi API per il provider ONE | | `/api/providers/import` | POST | Importa un provider eterogeneo LIST da un file CSV/JSON analizzato (#6836); risultati di guasto parziale per riga | | `/api/provider-nodes*` | Vari | Gestione dei nodi del fornitore | | `/api/provider-models` | GET/POST/PUT/PATCH/DELETE | Modelli personalizzati e sostituzioni per modello (aggiungi, aggiorna, hide/show, elimina) | | `/api/provider-models/validate-and-add` | POST | Convalida rigorosa della connessione con autenticazione gestionale e registrazione atomica del modello personalizzato; vedere [Convalida del modello](../guides/MODEL-VALIDATION.md) | Per i modelli synced/imported, `PUT /api/provider-models` accetta `provider`, `modelId` e `maxOutputTokenOverride`: un numero intero positivo imposta il limite del token di output manuale e `null` lo cancella per ripristinare l'impostazione predefinita. `GET /api/provider-models?provider=` restituisce questi valori in `modelOutputOverrides`, inclusi i modelli senza una riga del modello personalizzato. L'override utilizza la funzionalità `max_output_tokens` di runtime e sopravvive alla risincronizzazione del modello. La pagina del provider compatibile con OpenAI offre gli stessi controlli edit/clear e contrassegna i modelli con supporto visivo esplicito. Su un nodo provider compatibile, i percorsi di scrittura (`POST`, `PUT`, `PATCH`, `DELETE` e `/api/provider-models/validate-and-add`) memorizzano l'id del modello come semplice ID upstream: un id incollato da un elenco con prefisso ha qualsiasi stack iniziale del prefisso del nodo collassato e le risposte fanno eco all'id memorizzato. Gli ID barrati dei provider canonici (ad esempio `nvidia/nemotron-…`) vengono archiviati parola per parola. `/v1/models` non emette mai un ID `//` in pila. I nodi Completamenti chat personalizzati adattano le rinuncia al ragionamento esplicito al backend upstream. Un test di connessione riuscito seleziona automaticamente i controlli del modello di chat per ciascun modello esatto ID la cui voce `/models` dimostra un valore `owned_by` riconosciuto: `vllm`, `sglang` o `llamacpp`. I wrapper trasparenti compatibili con OpenAI possono preservare la voce del modello originale all'interno di un oggetto `openai` annidato; il rilevamento segue fino a tre inviluppi di questo tipo. I modelli con proprietà mancante, sconosciuta o in conflitto mantengono il comportamento OpenAI ordinario. Il rilevamento riutilizza la richiesta del catalogo esistente, non genera token di completamento e viene invalidato quando cambia l'endpoint di connessione. Per bloccare il comportamento per un backend che non espone tali metadati, utilizza l'aggiornamento parziale del provider esistente API: ```json { "providerSpecificData": { "reasoningControl": "chat-template" } } ``` Manda quel corpo con `PUT /api/providers/`. A questo proposito, uno sforzo di ragionamento esplicito di `none` viene inviato come `chat_template_kwargs.thinking=false` e `chat_template_kwargs.enable_thinking=false`. I valori espliciti del modello nativo rimangono autorevoli a meno che una regola di ragionamento lato server non imponga uno sforzo. L'impostazione si applica solo quando una connessione personalizzata compatibile con OpenAI invia un corpo di Completamenti chat; Le richieste di risposta e i fornitori ordinari mantengono la forma della richiesta nativa. Imposta `reasoningControl` su `openai` per forzare il passthrough OpenAI `reasoning_effort` ordinario oppure ometti it/set su `null` per utilizzare il rilevamento automatico. Claude Il classificatore in modalità automatica del codice richiede la disabilitazione del pensiero nativo predefinito quando non contengono controlli di ragionamento espliciti. Il rilevamento utilizza il contrassegno di sistema del classificatore nelle richieste in formato Claude, non i nomi dei modelli o i limiti di completamento. I controlli espliciti del corpo, le intestazioni effort/thinking supportate, le regole di routing e il lavoro del modello risolto mantengono la priorità esistente. Entrambe le fasi del classificatore mantengono i propri prompt, limiti di completamento, sequenze di arresto e verdetti di autorizzazione upstream reali; la seconda fase può ancora produrre il ragionamento visibile richiesto come testo ordinario. ### OAuth scorre | Punto finale | Metodo | Descrizione | | -------------------------------- | ------ | ----------------------------- | | `/api/oauth/[provider]/[action]` | Vari | OAuth specifico del fornitore | ### Routing e configurazione | Punto finale | Metodo | Descrizione | | --------------------- | -------- | --------------------------------------- | | `/api/models` | GET/PUT | Aggiornamento elenco modelli/alias | | `/api/models/alias` | GET/POST | Alias del modello | | `/api/models/catalog` | GET | Tutti i modelli per tipo di fornitore + | | `/api/combos*` | Vari | Gestione combinata | | `/api/keys*` | Vari | API gestione delle chiavi | | `/api/pricing` | GET | Prezzi del modello | #### Provenienza limite del modello `GET /api/models?withLimits=1` (anche `true`; `0`/`false` o omettendolo mantiene invariato il payload predefinito) aggiunge `contextWindow`, `maxInputTokens`, `maxOutputTokens` e un oggetto `capsSource` a ogni riga del modello. `capsSource` nomina la regola che ha fornito ciascun limite, quindi è possibile risalire alla sua origine un limite sorprendente (ad esempio 128k su un modello da 1 milione). I valori risolti sono gli stessi utilizzati dal routing; il flag aggiunge solo campi e non modifica mai un valore. Qualsiasi altro valore `withLimits` viene rifiutato con `400`. | valore `capsSource` | Origine | | -------------------------------------------- | -------------------------------------------------------------------------------- | | `override:context` | Override persistente della finestra di contesto (`model_context_overrides`) | | `override:max_input` / `override:max_output` | Override persistente della funzionalità `max_input_tokens` / `max_output_tokens` | | `static-authoritative:/` | Tabella della finestra di contesto autorevole statica | | `synced:/` | riga di capacità sincronizzata models.dev | | `registry:/` | Voce del registro del fornitore | | `spec:` | Specifiche del modello statico | | prefisso `effort-base:` | Riga presa in prestito dal modello base di una variante con suffisso sforzo | | `none` | Nessuna fonte dichiara il limite (il valore è `null`) | Implementazione: `getResolvedModelCapabilitiesWithLimitSources()` in `src/lib/modelCapabilities.ts` e le catene di precedenza in `src/lib/modelCapabilityLimits.ts`. ### Utilizzo e analisi | Punto finale | Metodo | Descrizione | | -------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/usage/history` | GET | Cronologia dell'utilizzo | | `/api/usage/logs` | GET | Registri di utilizzo | | `/api/usage/request-logs` | GET | Log a livello di richiesta | | `/api/usage/[connectionId]` | GET | Utilizzo per connessione | | `/api/usage/token-limits` | GET/POST/DELETE | Budget limite token per chiave API | | `/api/usage/model-latency-stats` | GET | Aggregato di latenza Rolling per-provider/model (avg/p50/p95/p99, tasso di successo); filtri: `windowHours`/`minSamples`/`maxRows`/`provider`/`model` (#6873) | | `/api/usage/cache-health` | GET | Riepilogo dello stato della cache richiesta sul rapporto `call_logs` — write/read, distribuzione delle dimensioni di scrittura p50/p90/p99, concentrazione delle scritture pesanti, suddivisione per modello e verdetto `healthy`/`degraded`/`thrash`/`no-data` ; parametri di query `range` (`1h`\| `24h`\| `7d`\| `30d`, default `24h`) e `model` opzionale (#8827) | ### API autorizzazioni chiave `PATCH /api/keys/{id}` aggiorna le autorizzazioni di una chiave esistente. Come ogni percorso `/api/keys*` necessita dell'autorizzazione di gestione (vedi [Autenticazione di gestione](../guides/MANAGEMENT-AUTH.md) ), non di una chiave di inferenza. Invia solo i campi che desideri modificare; una richiesta senza nessuno di essi viene respinta con `No valid fields to update`. I campi accettati sono definiti da `updateKeyPermissionsSchema` in `src/shared/validation/schemas/keys.ts`. | Campo | Tipo | Note | | ------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | stringa, 1-200 caratteri | | | `isActive` | booleano | | | `isBanned` | booleano | | | `expiresAt` | ISO 8601 datetime o `null` | `null` cancella la scadenza | | `modelAccessMode` | `all` \| `restricted` | `allowedModels` deve essere vuoto quando la modalità è `all` | | `allowedModels`, `blockedModels` | array di stringhe, fino a 1000 | | | `allowedCombos` | array di stringhe, fino a 500 | Porte che la combinazione può chiamare; i modelli diretti sono disciplinati dalle `modelAccessMode` / `allowedModels` | | `connectionAccessMode` | `all` \| `restricted` | `allowedConnections` deve essere non vuoto quando `restricted` e vuoto quando `all` | | `allowedConnections` | array di UUIDs, fino a 100 | | | `allowAutoCombos` | booleano | `false` rifiuta le richieste di modelli `auto/*` con questa chiave; sono ammesse chiavi che non lo impostano mai | | `catalogScope` | `all` \| `combos` \| `models` | Cosa elenca `GET /v1/models` per questa chiave (solo combo, solo modelli o entrambi); non cambia ciò che la chiave può chiamare | | `forcedModel` | stringa fino a 300 caratteri o `null` | Instrada le richieste di chat a questo model/combo, su `X-Route-Model` e `body.model`; si applicano ancora i limiti della chiave | | `noLog`, `autoResolve` | booleano | | | `throttleDelayMs` | numero intero, 0-300000 | | | `maxSessions` | intero, 0-10000 | | | `rateLimits` | array di `{ limit, window }` (interi positivi, fino a 50) o `null` | `null` cancella i limiti | | `accessSchedule` | oggetto pianificazione o `null` | `null` cancella il programma | | `scopes` | array di stringhe, fino a 32 | | | `allowedEndpoints` | array di stringhe, fino a 20 | | | `streamDefaultMode` | `legacy` \| `json` | | | `cacheDefaultMode` | `legacy` \| `bypass` | Vedi [Bypass della cache per chiave](#per-key-cache-bypass) | | `compressionEnabled` | booleano | | | `codexServiceMode` | una delle modalità di servizio Codex | | | `disableNonPublicModels` | booleano | | | `allowUsageCommand` | booleano | | | `usageLimitEnabled` | booleano | | | `dailyUsageLimitUsd`, `weeklyUsageLimitUsd` | numero >= 0 o `null` | | | `fiveHourUsageLimitUsd` | numero >= 0 o `null` | Budget USD mobile di 5 ore, applicato come i limiti giornalieri e settimanali (`usageLimitEnabled`, `UNPRICED_USAGE_BUDGET_POLICY`). `retry-after` avviene quando la spesa più vecchia nella finestra invecchia, il che può lasciare una chiave ben oltre il suo limite ancora bloccata. | | `chaosModeEnabled` | booleano | | ```bash curl -X PATCH "$OMNIROUTE_URL/api/keys/$KEY_ID" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "allowAutoCombos": false, "catalogScope": "combos" }' ``` ### Impostazioni | Punto finale | Metodo | Descrizione | | ------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/settings` | GET/PUT/PATCH | Impostazioni generali. Le chiavi della politica di sicurezza (`requireLogin`, `newPassword`, `oidc*`, `corsOrigins`, `bruteForceProtection`) necessitano `currentPassword` e di una credenziale dell'operatore — Le chiavi API e i token `oma_` ottengono `403`; ogni mutazione necessita dell'ambito del token di accesso `admin` | | `/api/settings/proxy` | GET/PUT | Configurazione proxy di rete | | `/api/settings/proxy/test` | POST | Testare la connessione proxy | | `/api/settings/ip-filter` | GET/PUT | IP allowlist/blocklist | | `/api/settings/thinking-budget` | GET/PUT | Thinking/reasoning** richiesta** modalità di riscrittura (passthrough/auto-strip/personalizzato/adattivo). Indipendente dalla compressione. Vedi [THINKING_BUDGET.md](../guides/THINKING_BUDGET.md). | | `/api/settings/system-prompt` | GET/PUT | Prompt del sistema globale | | `/api/settings/compression` | GET/PUT | Configurazione di compressione globale | | `/api/settings/purge-request-history` | POST | Cancella le righe del registro delle richieste e gli artefatti del registro delle chiamate locali | ### Contesto e compressione | Punto finale | Metodo | Descrizione | | -------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------- | | `/api/compression/preview` | POST | Anteprima della compressione off/lite/standard/aggressive/ultra/RTK/stacked | | `/api/compression/language-packs` | GET | Elenca i pacchetti linguistici Caveman disponibili | | `/api/compression/rules` | GET | Elenca i metadati delle regole Caveman | | `/api/context/caveman/config` | GET/PUT | Alias delle impostazioni specifiche di Caveman | | `/api/context/rtk/config` | GET/PUT | Impostazioni specifiche per RTK, inclusi filtri personalizzati e conservazione dell'output non elaborato | | `/api/context/rtk/filters` | GET | Catalogo dei filtri RTK e diagnostica dei filtri personalizzati | | `/api/context/rtk/test` | POST | Esegui RTK preview/test contro un payload di testo | | `/api/context/rtk/raw-output/[id]` | GET | Leggi l'output grezzo redatto e conservato in base all'ID del puntatore | | `/api/context/combos` | GET/POST | Combo di compressione list/create | | `/api/context/combos/[id]` | GET/PUT/DELETE | Combo di compressione detail/update/delete | | `/api/context/combos/[id]/assignments` | GET/PUT | Assegna combo di compressione alle combo di routing | | `/api/context/analytics` | GET | Alias di analisi di compressione | ### Monitoraggio | Punto finale | Metodo | Descrizione | | ------------------------------------ | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/sessions` | GET | Monitoraggio della sessione attiva | | `/api/rate-limits` | GET | Limiti di tasso per account | | `/api/monitoring/health` | GET | Riepilogo del fornitore di controllo dello stato + (`catalogCount`, `configuredCount`, `activeCount`, `monitoredCount`). La visualizzazione di gestione include `credentialHealth`: scalari sonda-cache, `failedConnections` quando `failed>0` e `staleDbNonOkCount` (SQLite sticky `test_status`, non il misuratore). Vedi [MONITORING_GUIDE.md](../ops/MONITORING_GUIDE.md#credentialhealth-probe-cache-vs-sqlite-test_status). | | `/api/cache/stats` | GET/DELETE | Statistiche cache/cancella | | `/api/modality-bridge/stats` | GET | In memoria `attempts`, successi/`bridged`, errori, riscontri nella cache, `totalLatencyMs`, `latencySamples`, `averageLatencyMs` denominati in campioni e ora dell'ultimo utilizzo (reimpostato al riavvio; autenticazione di gestione) | | `/api/modality-bridge/video/runtime` | GET | Controllo rigoroso del loopback attendibile prima della gestione auth/probe; disponibilità e versioni FFmpeg/ffprobe sanitizzati (no-store) | | `/api/modality-bridge/video/extract` | POST | Broker di byte di loopback attendibile autenticato interno; 50 MiB input, output queue/32 MiB limitato, capacità `503`, disconnessione `499`, scadenza `504` ; non un caricamento pubblico API | ### Drill-down del fotogramma video `GET /api/v1/video-bridge/drilldown` legge un handle opaco associato al tenant restituito in `x-omniroute-video-drilldown` dopo una richiesta Video Bridge esplicitamente acconsentita. Sia le letture che `DELETE` richiedono sempre una chiave API valida e l'autorizzazione `modalityBridgeVideoDrilldownRemoteEnabled` indipendente dell'operatore. La conservazione della produzione richiede inoltre `modalityBridgeVideoDrilldownEnabled` e `drilldown: true` rigoroso per parte. Se la chiave ha una lista consentita di endpoint non vuota, deve includere `video` sia per GET che DELETE, indipendentemente dal fatto che il chiamante utilizzi `/v1` o `/api/v1`. query GET : richiesta `handle`; facoltativo `variant` (`preview`, `standard`, `detail`), `limit` (1–8; `frames` legacy è accettato ma non può essere combinato con `limit`), `page` in base zero e `start`/`end` secondi. Quando vengono forniti entrambi i limiti del focus, `end` deve essere maggiore di `start`. Le chiavi di query Duplicate/unknown vengono rifiutate. Le risposte riuscite contengono `derivation`, `durationSeconds`, `frames`, `hasMore`, `page`, `variant` e `focusWindow` facoltativo ; no-store JSON è limitato a 32 MiB incluso Base64. L'output sovradimensionato restituisce 413; richiedere meno fotogrammi. `DELETE /api/v1/video-bridge/drilldown?handle=...` restituisce `{ "removed": 0|1 }`. GETs sconosciuto, scaduto e con chiave incrociata sono risposte 404 indistinguibili; cross-key DELETE non può rimuovere la voce del proprietario. L'accesso disabilitato restituisce 403, autenticazione missing/invalid 401, query non valide 400, annullamento 499 ed errori temporanei 503. Gli handle sono locali del processo, scadono dopo dieci minuti e non sopravvivono al riavvio. I nuovi handle utilizzano `v1.` più un token Base64URL casuale da 32 byte; vengono conservati solo gli hash dei token. I token legacy a 64 esadecimali rimangono sintatticamente leggibili per compatibilità. Consulta [i guardrail del Video Bridge](../security/GUARDRAILS.md#video-bridge-videobridgets-videobridgepipelinets) per i dettagli su consenso, quote e derivazione delle varianti. ### Backup e Export/Import | Punto finale | Metodo | Descrizione | | --------------------------- | ------ | --------------------------------------------------------------------------------------- | | `/api/db-backups` | GET | Elenca i backup disponibili | | `/api/db-backups` | PUT | Crea un backup manuale | | `/api/db-backups` | POST | Ripristina da un backup specifico | | `/api/db-backups` | PATCH | Salva le impostazioni di conservazione del backup (solo operatore) | | `/api/db-backups` | DELETE | Elimina i backup archiviati in base alle impostazioni di conservazione (solo operatore) | | `/api/db-backups/export` | GET | Scarica il database come file .sqlite | | `/api/db-backups/import` | POST | Carica il file .sqlite per sostituire il database (solo convalida `?dryRun=true` ) | | `/api/db-backups/exportAll` | GET | Scarica il backup completo come archivio .tar.gz | `/api/db-backups/export`, `/api/db-backups/exportAll` e `/api/settings/export-json` distribuiscono tutte le credenziali archiviate, quindi richiedono la sessione del dashboard o lo CLI locale (o l'accesso disabilitato). Le chiavi API di qualsiasi ambito e i token di accesso `oma_` ottengono `403`. I ripristini mantengono lo stesso limite: `POST /api/db-backups/import` (`dryRun=true` incluso), `POST /api/db-backups` (ripristino tramite ID) e `POST /api/settings/import-json` sostituiscono il database o le impostazioni live, quindi anche le credenziali della macchina ottengono `403` lì; `omniroute sync import` invia le credenziali CLI locali. Lo stesso vale per `DELETE /api/db-backups` (eliminazione dei backup archiviati) e `PATCH /api/db-backups` (impostazioni di conservazione: i valori persistenti guidano l'eliminazione automatica dopo ogni backup). L'elenco (`GET`) e la creazione di un backup manuale (`PUT`) mantengono l'autenticazione di gestione ordinaria. ### Sincronizzazione nel cloud | Punto finale | Metodo | Descrizione | | ---------------------- | ------ | ---------------------------------------- | | `/api/sync/cloud` | Vari | Operazioni di sincronizzazione nel cloud | | `/api/sync/initialize` | POST | Inizializza la sincronizzazione | | `/api/cloud/*` | Vari | Gestione della nuvola | ### Tunnel | Punto finale | Metodo | Descrizione | | -------------------------- | ------ | ----------------------------------------------------------------------- | | `/api/tunnels/cloudflared` | GET | Leggi lo stato Cloudflare Quick Tunnel install/runtime per la dashboard | | `/api/tunnels/cloudflared` | POST | Abilita o disabilita Cloudflare Quick Tunnel (`action=enable/disable`) | | `/api/tunnels/ngrok` | GET | Leggi lo stato di runtime del tunnel ngrok per il dashboard | | `/api/tunnels/ngrok` | POST | Abilita o disabilita il tunnel ngrok (`action=enable/disable`) | ### CLI Strumenti | Punto finale | Metodo | Descrizione | | ---------------------------------- | ------ | -------------------- | | `/api/cli-tools/claude-settings` | GET | stato Claude CLI | | `/api/cli-tools/codex-settings` | GET | stato Codex CLI | | `/api/cli-tools/droid-settings` | GET | Stato del droide CLI | | `/api/cli-tools/openclaw-settings` | GET | stato OpenClaw CLI | | `/api/cli-tools/runtime/[toolId]` | GET | Runtime CLI generico | Le risposte CLI includono: `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`. ### ACP Agenti | Punto finale | Metodo | Descrizione | | ----------------- | ------ | --------------------------------------------------------------------------- | | `/api/acp/agents` | GET | Elenca tutti gli agenti rilevati ( + personalizzato integrato) con lo stato | | `/api/acp/agents` | POST | Aggiungi un agente personalizzato o aggiorna la cache di rilevamento | | `/api/acp/agents` | DELETE | Rimuovere un agente personalizzato tramite il parametro di query `id` | La risposta GET include `agents[]` (id, nome, binario, versione, installato, protocollo, isCustom) e `summary` (totale, installato, notFound, builtIn, personalizzato). ### Resilienza e limiti di velocità | Punto finale | Metodo | Descrizione | | --------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/resilience` | GET/PATCH | coda di richiesta Get/update, tempo di recupero della connessione, interruttore del provider e impostazioni di attesa | | `/api/resilience/reset` | POST | Reimpostare gli interruttori automatici del provider | | `/api/resilience/model-cooldowns` | GET | Elenca i blocchi attivi per (provider, connessione, modello), ordinati per tempo rimanente | | `/api/resilience/model-cooldowns` | DELETE | Cancella un modello di blocco — body `{provider, model}` o `{all: true}` per cancellare tutto | | `/api/rate-limits` | GET/POST | Stato del limite di velocità per account (GET) o attiva/disattiva la protezione del limite di velocità per una connessione (POST `{connectionId, enabled}`). Percorso di scrittura supportato per `rateLimitProtection` (mai modificato tramite `PUT /api/providers/[id]`). Nota: `enabled: false` disabilita la protezione esplicita ma non esclude una connessione attiva della chiave API dalla rete di sicurezza di abilitazione automatica globale (`autoEnableApiKeyProviders`). | | `/api/rate-limit` | GET | Configurazione del limite di velocità globale (obsoleto; alias per `/api/rate-limits`) | > Richiedono tutti e quattro i percorsi `/api/resilience/*`** autorizzazione gestione** (`requireManagementAuth`). Vedere [Resilienza (estesa)](#resilience-extended) per un'analisi completa dell'interruzione del provider, del tempo di recupero della connessione e del blocco del modello. ### Valutazioni | Punto finale | Metodo | Descrizione | | ------------ | -------- | ---------------------------------------------------- | | `/api/evals` | GET/POST | Elenca le suite di valutazione/esegui la valutazione | ### Politiche | Punto finale | Metodo | Descrizione | | --------------- | --------------- | ------------------------------- | | `/api/policies` | GET/POST/DELETE | Gestire le politiche di routing | ### Conformità | Punto finale | Metodo | Descrizione | | --------------------------- | ------ | ------------------------------------------------- | | `/api/compliance/audit-log` | GET | Registro di controllo della conformità (ultimi N) | ### v1beta (compatibile con Gemini) | Punto finale | Metodo | Descrizione | | -------------------------- | ------ | ------------------------------------- | | `/v1beta/models` | GET | Elenca i modelli in formato Gemini | | `/v1beta/models/{...path}` | POST | punto finale Gemini `generateContent` | Questi endpoint rispecchiano il formato API Gemini i client che si aspettano la compatibilità nativa Gemini SDK. ### Interno/Sistema APIs | Punto finale | Metodo | Descrizione | | ------------------------ | ------ | --------------------------------------------------------------------------------- | | `/api/init` | GET | Avvia servizi di sincronizzazione in background (autenticazione di gestione) | | `/api/tags` | GET | Tag modello compatibili con Ollama (per client Ollama ) | | `/api/restart` | POST | Attiva il riavvio regolare del server | | `/api/shutdown` | POST | Attiva l'arresto regolare del server | | `/api/system/env/repair` | POST | Riparare le variabili di ambiente del provider OAuth | | `/api/system/version` | GET | versione Current/latest, stato dell'aggiornamento, canale di rilascio | | `/api/system/version` | POST | Avvia un aggiornamento compatibile con la distribuzione alla versione più recente | > **Nota:** Questi endpoint vengono utilizzati internamente dal sistema o per la compatibilità del client Ollama. In genere non vengono chiamati dagli utenti finali. ### Riparazione dell'ambiente OAuth _(v3.6.1 +)_ ```bash POST /api/system/env/repair Content-Type: application/json { "provider": "claude-code" } ``` Ripara le variabili di ambiente OAuth mancanti o danneggiate per un provider specifico. Resi: ```json { "success": true, "repaired": ["CLAUDE_CODE_OAUTH_CLIENT_ID", "CLAUDE_CODE_OAUTH_CLIENT_SECRET"], "backupPath": "/home/user/.omniroute/backups/env-repair-2026-04-11.bak" } ``` ### Versione e canale di rilascio ```bash GET /api/system/version ``` Percorso di gestione solo loopback (autenticazione amministratore). Restituisce la versione in esecuzione, l'ultima versione pubblicata e lo stato dell'aggiornamento automatico. `releaseChannel` e `channels` sono campi additivi (rail 3.8.54); `channel` mantiene il suo significato — la modalità di distribuzione utilizzata dal programma di aggiornamento del dashboard (`npm`, `source` o `docker-compose`). ```json { "current": "3.8.52", "latest": "3.8.52", "updateAvailable": false, "channel": "npm", "autoUpdateSupported": true, "autoUpdateError": null, "news": null, "releaseChannel": "latest", "channels": { "latest": "3.8.52", "next": "3.8.53-rc.1" } } ``` - `releaseChannel` — npm canale della build in esecuzione: `nightly` per le versioni `-nightly.*`, `next` per altre pre-release (`-rc.*`, `-beta.*`, `-alpha.*`), `lts` per una versione stabile di una major precedente a `channels.latest`, altrimenti `latest`. Stesse regole di `scripts/release/dist-tag.mjs`, che seleziona il tag dist npm al momento della pubblicazione. - `channels` — ha pubblicato l'intestazione di ciascun tag dist, da `npm view omniroute dist-tags` (registro HTTP fallback), memorizzato nella cache con lo stesso TTL di 10 minuti di `latest`. `latest` è sempre presente (ricade nel campo `latest`, quindi `"unavailable"`); `next`, `nightly` e `lts` appaiono solo quando esiste quel tag dist. Una richiesta `Cache-Control: no-cache` aggiorna entrambe le ricerche. Il modello di canale (`latest` = v3 fino alla versione 4.0 GA, `next` = rc, `nightly` = `develop` build, `lts` = v3 patch dopo la versione 4.0 GA) è descritto in `docs/ops/RELEASE_STRATEGY.md`. --- ## Trascrizione audio ```bash POST /v1/audio/transcriptions Authorization: Bearer your-api-key Content-Type: multipart/form-data ``` Trascrivi file audio utilizzando qualsiasi provider STT configurato. Il primo segmento del percorso seleziona il provider nativo (`openai/…`, `deepgram/…`). I gateway che riesportano il modello di un altro fornitore utilizzano un ID qualificato (`openrouter/deepgram/nova-3`). **Richiesta:** ```bash curl -X POST http://localhost:20128/v1/audio/transcriptions \ -H "Authorization: Bearer your-api-key" \ -F "file=@recording.mp3" \ -F "model=openai/whisper-1" ``` **Risposta:** ```json { "text": "Hello, this is the transcribed audio content.", "task": "transcribe", "language": "en", "duration": 12.5 } ``` **ID modello di esempio:** `openai/whisper-1` (richiede una chiave OpenAI), `openrouter/deepgram/nova-3` (richiede una chiave OpenRouter), `deepgram/nova-3` (richiede una chiave Deepgram nativa). Una richiesta `deepgram/nova-3` semplice **non** utilizza OpenRouter. **Formati supportati:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`. **Gemini Live (`gemini/gemini-3.5-transcribe-live`):** trascrizione in modalità file tramite il WebSocket Gemini Live (richiede una chiave API Gemini). Il caricamento viene convertito in PCM mono a 16 kHz con `ffmpeg` (deve essere disponibile in `PATH`, a meno che il file non sia già un WAV PCM mono a 16 kHz), trasmesso alla sessione e il testo finalizzato viene restituito come `{ "text": "..." }`. I campi modulo facoltativi `language` e `prompt` vengono inoltrati. Limiti: i caricamenti superiori a 25 MiB o l'audio decodificato più lungo di 10 minuti restituiscono `413`; una conversione che dura più di 60 s viene terminata e restituisce `504`. La chiave API viene inviata solo nell'header `x-goog-api-key`, mai nell'URL WebSocket. --- ## Compatibilità con Ollama Per i client che utilizzano il formato API di Ollama: ```bash # Endpoint di chat (formato Ollama) POST /v1/api/chat # Elenco dei modelli (formato Ollama) GET /api/tags ``` Le richieste vengono convertite automaticamente tra i formati di Ollama e quelli interni. ## Alias tokenizzati per VS Code / senza intestazioni Utilizza questi alias quando un'integrazione non può inserire un'intestazione `Authorization` e deve includere la chiave API nell'URL di base. ```bash # Alias del catalogo in stile OpenAI GET /api/v1/vscode/{token}/ GET /api/v1/vscode/{token}/models # Alias di chat in stile OpenAI POST /api/v1/vscode/{token}/chat/completions POST /api/v1/vscode/{token}/responses # Alias in stile Ollama POST /api/v1/vscode/{token}/api/chat GET /api/v1/vscode/{token}/api/tags ``` Esempio: ```bash curl https://your-host.example/api/v1/vscode/YOUR_API_KEY/models curl -X POST https://your-host.example/api/v1/vscode/YOUR_API_KEY/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"auto","messages":[{"role":"user","content":"hello"}]}' ``` Note: - Gli alias tokenizzati riutilizzano gli stessi handler di `/v1/*` e `/api/tags`; i formati delle risposte rimangono identici. - Preferisci `Authorization: Bearer ...` quando il client supporta intestazioni personalizzate. - I token basati sull'URL possono comparire nei log del reverse proxy, nella cronologia del browser e nei dati di telemetria esterni a OmniRoute. Trattali come un'opzione di compatibilità, non come la modalità di autenticazione predefinita. --- ## Telemetria ```bash # Ottieni il riepilogo della telemetria della latenza (p50/p95/p99 per provider) GET /api/telemetry/summary ``` **Risposta:** ```json { "providers": { "claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 }, "github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 } } } ``` --- ## Budget ```bash # Ottieni lo stato del budget per tutte le chiavi API GET /api/usage/budget # Imposta o aggiorna un budget POST /api/usage/budget Content-Type: application/json { "apiKeyId": "key-123", "dailyLimitUsd": 5.00, "weeklyLimitUsd": 30.00, "monthlyLimitUsd": 100.00, "warningThreshold": 0.8, "resetInterval": "monthly" } ``` > **Note sullo schema** (`setBudgetSchema`): `apiKeyId` è obbligatorio; almeno uno tra `dailyLimitUsd`, `weeklyLimitUsd` o `monthlyLimitUsd` deve essere maggiore di zero. Campi facoltativi: `warningThreshold` (0–1), `resetInterval` (`daily` | `weekly` | `monthly`), `resetTime` (`HH:MM`). Il formato legacy `{keyId, limit, period}` restituisce `400 Bad Request`. ## Limiti dei token Budget di **token** per chiave API (distinti dal Budget basato su USD descritto sopra). Applicati inline nel percorso della richiesta: quando l'utilizzo della finestra corrente di una chiave raggiunge il relativo limite, le richieste vengono rifiutate con `429 Too Many Requests`. I limiti possono essere associati a un `model` o a un `provider` specifico, oppure applicati in modo `global` alla chiave; quando più limiti corrispondono a una richiesta, viene applicato quello più restrittivo. ```bash # Elenca i limiti di token di una chiave (include l'utilizzo live della finestra) GET /api/usage/token-limits?apiKeyId=key-123 # Crea o aggiorna un limite di token POST /api/usage/token-limits Content-Type: application/json { "apiKeyId": "key-123", "scopeType": "model", "scopeValue": "openai/gpt-4o", "tokenLimit": 1000000, "resetInterval": "monthly", "enabled": true } # Elimina un limite di token tramite id DELETE /api/usage/token-limits?id=tl-abc ``` > **Note sullo schema** (`setTokenLimitSchema`): `apiKeyId` e `scopeType` (`model` | `provider` | `global`) sono obbligatori. `scopeValue` è obbligatorio a meno che `scopeType` non sia `global` (ad esempio, un id del modello per l'ambito `model`, un id del provider per l'ambito `provider`). `tokenLimit` deve essere un intero positivo (convertito da stringa). Opzionali: `id` (omettere per la creazione, fornire per l'aggiornamento), `resetInterval` (`daily` | `weekly` | `monthly`, valore predefinito `monthly`), `resetTime` (`HH:MM`), `enabled` (valore predefinito `true`). Le risposte `GET` arricchiscono ogni limite con `tokensUsed`, `remaining`, `windowStart`, `periodStartAt` e `nextResetAt`. Questo è un endpoint di classe di gestione (l'autenticazione viene applicata centralmente dalla pipeline authz). ## Elaborazione delle richieste 1. Il client invia la richiesta a `/v1/*` 2. Il gestore della route chiama `handleChat`, `handleEmbedding`, `handleAudioTranscription` o `handleImageGeneration` 3. Il modello viene risolto (provider/modello diretto o alias/combinazione) 4. Le credenziali vengono selezionate dal database locale con il filtraggio della disponibilità degli account 5. Per la chat: `handleChatCore` controlla la cache semantica/delle firme e risolve le impostazioni di compressione della combinazione 6. La compressione proattiva viene eseguita prima della traduzione verso il provider quando abilitata (`lite`, Caveman, RTK o impilata) 7. L'esecutore del provider invia la richiesta upstream 8. La risposta viene riconvertita nel formato del client (chat) oppure restituita così com'è (embedding/immagini/audio) 9. Vengono registrati l'utilizzo, le analisi della compressione e i log delle richieste 10. Il fallback viene applicato in caso di errori secondo le regole della combinazione Riferimento completo all'architettura: [`ARCHITECTURE.md`](../architecture/ARCHITECTURE.md) --- ## Gestione delle combinazioni Le combinazioni di routing di livello superiore (già riepilogate in `/api/combos*`) possono anche essere mappate 1:1 a partire da un pattern di id del modello, consentendo il reindirizzamento trasparente di un id del modello in stile OpenAI a una combinazione. | Metodo | Percorso | Descrizione | | ------ | -------------------------------- | ----------------------------------------------------------------------------------- | | GET | `/api/model-combo-mappings` | Elenca tutte le mappature modello→combinazione | | POST | `/api/model-combo-mappings` | Crea una mappatura — corpo: `{pattern, comboId, priority?, enabled?, description?}` | | GET | `/api/model-combo-mappings/[id]` | Recupera una singola mappatura | | PUT | `/api/model-combo-mappings/[id]` | Aggiorna i campi di una mappatura esistente | | DELETE | `/api/model-combo-mappings/[id]` | Rimuove una mappatura | **Autenticazione:** sessione/chiave API di gestione (`requireManagementAuth`). --- ## Webhook Sottoscrizioni a webhook in uscita per gli eventi di OmniRoute (completamento delle richieste, esaurimento della quota, rotazione delle chiavi, ecc.). | Metodo | Percorso | Descrizione | | ------ | ------------------------- | ---------------------------------------------------------------------------------- | | GET | `/api/webhooks` | Elenca i webhook (i segreti sono mascherati come `...`) | | POST | `/api/webhooks` | Crea un webhook — corpo: `{url, events?: ["*"], secret?, description?}` | | GET | `/api/webhooks/[id]` | Recupera un webhook | | PUT | `/api/webhooks/[id]` | Aggiorna url/events/secret/description | | DELETE | `/api/webhooks/[id]` | Rimuove un webhook | | POST | `/api/webhooks/[id]/test` | Invia un payload di test all'URL del webhook e restituisce lo stato della consegna | **Autenticazione:** sessione/chiave API di gestione (`requireManagementAuth`). --- ## Chiavi registrate (gestione automatica) Utilizzate dal sottosistema di gestione automatica delle chiavi per emettere e ruotare chiavi API tramite un provider/account di supporto, con quote giornaliere/orarie. | Metodo | Percorso | Descrizione | | ------ | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/registered-keys` | Elenca le chiavi registrate (solo il prefisso mascherato) | | POST | `/api/v1/registered-keys` | Emette una nuova chiave registrata — corpo: `{name, provider?, accountId?, idempotencyKey?, expiresAt?, dailyBudget?, hourlyBudget?}`. Restituisce la chiave grezza **una sola volta**. Restituisce `429` in caso di rifiuto per quota. | | GET | `/api/v1/registered-keys/[id]` | Recupera i metadati di una chiave registrata (nessun materiale grezzo) | | DELETE | `/api/v1/registered-keys/[id]` | Revoca una chiave registrata | | POST | `/api/v1/registered-keys/[id]/revoke` | Endpoint di revoca esplicita (stesso effetto di DELETE) | **Autenticazione:** sessione/chiave API di gestione (`requireManagementAuth`) — la stessa protezione di `/api/keys`: una sessione della dashboard, il token CLI locale o una chiave API con ambito `manage`/`admin`; le chiavi API di sola inferenza ricevono `403`. Vedi anche `/v1/quotas/check` e `/v1/issues/report`. --- ## Protocollo degli agenti Attività degli agenti cloud (Claude Code, Codex Cloud, OpenHands, ecc.) eseguite da remoto per conto degli utenti di OmniRoute. | Metodo | Percorso | Descrizione | | ------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/agents/tasks` | Elenca le attività — `?provider=`, `?status=`, `?limit=` opzionali (1–500, valore predefinito 50) | | POST | `/api/v1/agents/tasks` | Crea un'attività — corpo convalidato da `CreateCloudAgentTaskSchema` (`providerId`, `prompt`, `source`, `options?`). Restituisce `201` con l'envelope dell'attività | | DELETE | `/api/v1/agents/tasks?id=...` | Elimina un'attività | | GET | `/api/v1/agents/tasks/[id]` | Legge l'attività — aggiorna sincronicamente lo stato dall'agente cloud upstream quando è impostato un `external_id` | | POST | `/api/v1/agents/tasks/[id]` | Azione discriminata: `{action: "approve"}`, `{action: "message", message}` oppure `{action: "cancel"}` | | DELETE | `/api/v1/agents/tasks/[id]` | Elimina un'attività specifica tramite id | > **Autenticazione:** autenticazione di gestione richiesta per ogni metodo (`requireCloudAgentManagementAuth`). Prima della v3.8.0 questi endpoint non richiedevano autenticazione — consulta il commit `588a0333` per la modifica incompatibile. ```bash # Crea un'attività cloud di Claude Code curl -X POST http://localhost:20128/api/v1/agents/tasks \ -H "Authorization: Bearer your-management-key" \ -H "Content-Type: application/json" \ -d '{"providerId":"claude-code-cloud","prompt":"Correggi il test non riuscito","source":{"repo":"...","branch":"..."}}' ``` --- ## Proxy di gestione Proxy HTTP(S)/SOCKS in uscita che possono essere assegnati a provider, account o globalmente. | Metodo | Percorso | Descrizione | | ------ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/management/proxies` | Elenca i proxy (con `?id=` ne restituisce uno; con `?id=&where_used=1` restituisce il grafo delle assegnazioni) | | POST | `/api/v1/management/proxies` | Crea un proxy — corpo convalidato da `createProxyRegistrySchema` | | PATCH | `/api/v1/management/proxies` | Aggiorna un proxy — corpo convalidato da `updateProxyRegistrySchema` (richiede `id`) | | DELETE | `/api/v1/management/proxies?id=...&force=1` | Elimina un proxy (usa `force=1` per rimuovere le assegnazioni) | | GET | `/api/v1/management/proxies/assignments` | Elenca le assegnazioni — filtrabile per `proxy_id`, `scope`, `scope_id`; passa `resolve_connection_id=` per risolvere il proxy attivo per una connessione | | PUT | `/api/v1/management/proxies/assignments` | Assegna — corpo convalidato da `proxyAssignmentSchema` (`{scope, scopeId?, proxyId?}`). Svuota la cache del dispatcher | | PUT | `/api/v1/management/proxies/bulk-assign` | Assegnazione in blocco — corpo convalidato da `bulkProxyAssignmentSchema` (`{scope, scopeIds[], proxyId?}`) | | GET | `/api/v1/management/proxies/health?hours=24` | Stato aggregato dei proxy (conteggi di successi/fallimenti, latenza) nell'intervallo specificato | **Autenticazione:** sessione/chiave API di gestione su ogni route (`requireManagementAuth`). > Le descrizioni delle attività relative a `POST /api/v1/management/proxies/[id]/assignments` e `POST /api/v1/management/proxies/[id]/health` sono gestite dalle route piatte `/assignments` e `/health` mostrate sopra — nel codebase non esistono subroute per singolo id. --- ## Resilienza (estesa) OmniRoute espone tre meccanismi indipendenti per la gestione degli errori temporanei; gli endpoint di gestione seguenti consentono agli operatori di leggerne lo stato e sovrascriverlo: | Ambito | Archiviazione dello stato | Lettura | Reimpostazione / cancellazione | | ---------------------------- | --------------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------- | | Circuit breaker del provider | `domain_circuit_breakers` + memoria | `/api/monitoring/health` | `POST /api/resilience/reset` | | Cooldown della connessione | `rateLimitedUntil` sulle connessioni del provider | `/api/rate-limits`, `/api/providers/[id]` | (riabilitazione lazy; cancellare tramite PUT del provider) | | Blocco del modello | Registro della disponibilità dei modelli in memoria | `GET /api/resilience/model-cooldowns` | `DELETE /api/resilience/model-cooldowns` | `PATCH /api/resilience` accetta override del circuit breaker del provider tramite `providerBreaker.oauth` e `providerBreaker.apikey`. Ogni profilo supporta `degradationThreshold`, `failureThreshold` e `resetTimeoutMs`; gli stessi campi sono esposti in Dashboard → Impostazioni → Resilienza. ```bash # Cancella il blocco di un singolo modello curl -X DELETE http://localhost:20128/api/resilience/model-cooldowns \ -H "Cookie: auth_token=..." \ -H "Content-Type: application/json" \ -d '{"provider":"openai","model":"gpt-4o-mini"}' # Cancella tutti i blocchi curl -X DELETE http://localhost:20128/api/resilience/model-cooldowns \ -H "Cookie: auth_token=..." \ -d '{"all":true}' ``` Per il riferimento concettuale completo e i valori predefiniti del circuit breaker, vedere [`CLAUDE.md`](../../CLAUDE.md) → "Stato runtime della resilienza" e [`docs/architecture/RESILIENCE_GUIDE.md`](../architecture/RESILIENCE_GUIDE.md). ### Coda per il limite di frequenza e rete di sicurezza per l'abilitazione automatica - **Percorso di scrittura supportato**: `POST /api/rate-limits` con body `{"connectionId": "", "enabled": true|false}` è l'endpoint di gestione supportato per attivare o disattivare la protezione dal limite di frequenza per una connessione. `PUT /api/providers/[id]` deliberatamente non modifica né inverte `rateLimitProtection` (#11278). - **Semantica di `enabled: false`**: l'impostazione di `enabled: false` rimuove la protezione esplicita per la connessione, ma **non** esclude una connessione con chiave API attiva dalla rete di sicurezza globale per l'abilitazione automatica (`autoEnableApiKeyProviders = true`). In `reconcileEnabledConnections` (`open-sse/services/rateLimitManager.ts`), `false` e `undefined` sono equivalenti; le connessioni con chiave API attive senza protezione esplicita rimangono protette dalla rete di sicurezza per l'abilitazione automatica. - **Disabilitazione globale**: per eseguire connessioni con chiave API senza code per il limite di frequenza, disabilitare globalmente la rete di sicurezza tramite `RATE_LIMIT_AUTO_ENABLE=false` (env) oppure `resilienceSettings.requestQueue.autoEnableApiKeyProviders = false` (Impostazioni → Resilienza / `PATCH /api/resilience`). --- ## Competenze Framework delle competenze per estendere OmniRoute con gestori eseguibili personalizzati e integrazioni con marketplace. | Metodo | Percorso | Descrizione | | ------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/skills` | Elenca le competenze installate — filtrabili tramite `?q=`, `?mode=on\|off\|auto`, `?source=skillsmp\|skillssh\|local`, con paginazione | | GET | `/api/skills/[id]` | Recupera una competenza | | PUT | `/api/skills/[id]` | Aggiorna una competenza (nome, descrizione, modalità, schema, gestore, tag) | | DELETE | `/api/skills/[id]` | Disinstalla una competenza | | POST | `/api/skills/install` | Installa una competenza da un manifest raw — body: `{name, version, description, schema:{input, output}, handlerCode, apiKeyId?}` | | GET | `/api/skills/executions` | Elenca le esecuzioni recenti delle competenze (traccia di audit con input/output/durata) | | GET | `/api/skills/marketplace?q=...` | Cerca o elenca gli elementi più popolari del marketplace SkillsMP (richiede l'impostazione `skillsmpApiKey`) | | POST | `/api/skills/marketplace/install` | Installa una competenza tramite id da SkillsMP | | GET | `/api/skills/skillssh?q=&limit=` | Cerca nel registro skills.sh | | POST | `/api/skills/skillssh/install` | Installa una competenza tramite id da skills.sh | **Autenticazione:** sessione di gestione/chiave API. Le route di ricerca del marketplace accettano l'autenticazione di gestione oppure una chiave API Bearer (`isAuthenticated`). --- ## Memoria Archivio persistente della memoria conversazionale e fattuale, con ambito per chiave API / sessione. | Metodo | Percorso | Descrizione | | ------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------ | | GET | `/api/memory` | Elenca le memorie — `?apiKeyId=`, `?type=`, `?sessionId=`, `?q=`, con paginazione `offset/limit` o `page/limit` | | POST | `/api/memory` | Crea una memoria — corpo convalidato da Zod: `{content, key, type?, sessionId?, apiKeyId?, metadata?, expiresAt?}` | | GET | `/api/memory/[id]` | Recupera una memoria | | DELETE | `/api/memory/[id]` | Elimina una memoria | | GET | `/api/memory/health` | Stato di salute del sottosistema di memoria (connettività del DB, backend degli embedding, stato dell'indice vettoriale) | **Autenticazione:** sessione/chiave API di gestione (`requireManagementAuth`). Enumerazione `type`: `FACTUAL`, `EPISODIC`, `SEMANTIC`, `PROCEDURAL` (vedere `MemoryType` in `src/lib/memory/types.ts`). --- ## Server MCP OmniRoute include un server Model Context Protocol integrato con 3 trasporti (stdio, SSE, streamable-http) e strumenti con ambito limitato. Gli endpoint della dashboard riportati di seguito leggono i dati sullo stato e sull'audit e fungono da proxy per i trasporti HTTP. | Metodo | Percorso | Descrizione | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | | GET | `/api/mcp/status` | Heartbeat, trasporto, stato online, ultima chiamata, strumenti principali, tasso di successo nelle 24 ore | | GET | `/api/mcp/tools` | Elenco degli strumenti MCP con `name`, `description`, `scopes`, `phase`, `auditLevel`, `sourceEndpoints` | | GET | `/api/mcp/sse` | Apre il flusso SSE per il trasporto SSE (restituisce `503` se MCP è disabilitato o se il trasporto non corrisponde) | | POST | `/api/mcp/sse` | Invia un frame JSON-RPC sul trasporto SSE | | GET | `/api/mcp/stream` | Apre il lato SSE del trasporto Streamable HTTP (messaggi avviati dal server) | | POST | `/api/mcp/stream` | Invia un frame JSON-RPC sul trasporto Streamable HTTP | | DELETE | `/api/mcp/stream` | Termina una sessione Streamable HTTP | | GET | `/api/mcp/audit` | Interroga il registro di audit — `?limit=`, `?offset=`, `?tool=`, `?success=true | false`, `?apiKeyId=` | | GET | `/api/mcp/audit/stats` | Statistiche aggregate dell'audit (totali, tasso di successo, durata media, strumenti principali) | **Autenticazione:** i trasporti `sse`/`stream` rispettano la superficie di autenticazione specifica di MCP (chiave API Bearer con ambito `mcp`); le route `status`/`tools`/`audit*` sono leggibili dalla dashboard (non è richiesta alcuna autenticazione aggiuntiva oltre all'accesso all'host della dashboard). > Entrambi i trasporti HTTP sono regolati da `settings.mcpEnabled` e `settings.mcpTransport` — una mancata corrispondenza del trasporto restituisce `400`, mentre uno stato MCP disabilitato restituisce `503`. --- ## Server A2A OmniRoute espone un endpoint A2A (Agent-to-Agent) JSON-RPC 2.0 oltre a un wrapper REST per l'ispezione e l'uso tramite dashboard. ### JSON-RPC ```bash POST /a2a Authorization: Bearer your-api-key # facoltativo, a meno che non sia impostato OMNIROUTE_API_KEY Content-Type: application/json { "jsonrpc": "2.0", "id": 1, "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Route this coding task"}] } } ``` Metodi supportati (tutti subordinati a `settings.a2aEnabled`): | Metodo | Descrizione | | ---------------- | -------------------------------------------------------------------------- | | `message/send` | Esecuzione sincrona della skill; restituisce `{task, artifacts, metadata}` | | `message/stream` | Esecuzione SSE in streaming dello stesso set di skill | | `tasks/get` | Recupera un'attività tramite `taskId` | | `tasks/cancel` | Annulla un'attività tramite `taskId` | Skill integrate: `smart-routing`, `quota-management`, `provider-discovery`, `cost-analysis`, `health-report`. ### Scheda dell'agente ```bash GET /.well-known/agent.json ``` Restituisce la scheda pubblica dell'agente A2A (nome, descrizione, funzionalità, catalogo delle skill, schema di autenticazione), memorizzata pubblicamente nella cache per 1 ora. Non è richiesta alcuna autenticazione. ### Helper REST | Metodo | Percorso | Descrizione | | ------ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | GET | `/api/a2a/status` | Stato A2A abilitato + statistiche delle attività + riepilogo della scheda dell'agente memorizzata nella cache | | GET | `/api/a2a/tasks` | Elenca le attività — `?state=submitted\|working\|completed\|failed\|cancelled`, `?skill=`, `?limit=` (≤200), `?offset=` | | POST | `/api/a2a/tasks` | (Non implementato come helper REST — crea tramite JSON-RPC `message/send`) | | GET | `/api/a2a/tasks/[id]` | Recupera una singola attività | | POST | `/api/a2a/tasks/[id]/cancel` | Annulla un'attività | **Autenticazione:** gli helper REST vengono eseguiti senza autenticazione di gestione (leggibili dalla dashboard); la route JSON-RPC `/a2a` usa Bearer `OMNIROUTE_API_KEY` se configurato. --- ## Cloud, valutazioni e Assess | Metodo | Percorso | Descrizione | | ------ | ------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------- | ----------------------------------- | | POST | `/api/cloud/auth` | Verifica una chiave Bearer e restituisce le connessioni dei provider mascherate + gli alias dei modelli per i client di sincronizzazione cloud | | POST | `/api/cloud/credentials/update` | Aggiorna le credenziali crittografate per un provider sincronizzato con il cloud | | POST | `/api/cloud/model/resolve` | Risolve un ID modello logico in un provider/modello concreto usando la tabella di routing locale | | GET | `/api/cloud/models/alias` | Elenca gli alias dei modelli come esposti alla sincronizzazione cloud | | GET | `/api/assess` | Legge le categorizzazioni della valutazione più recente (per provider/modello) | | POST | `/api/assess` | Esegue una valutazione — corpo: `{scope: {type:"all"} | {type:"provider", providerId} | {type:"model", modelId}, trigger?}` | | GET | `/api/evals` | Elenca le suite di valutazione integrate + le esecuzioni più recenti | | POST | `/api/evals` | Avvia un'esecuzione di valutazione | | POST | `/api/evals/suites` | Crea una suite di valutazione personalizzata — corpo convalidato da `evalSuiteSaveSchema` | | GET | `/api/evals/suites/[id]` | Recupera una suite di valutazione personalizzata | **Autenticazione:** `/api/cloud/auth` convalida direttamente una chiave Bearer e restituisce la chiave mascherata e `projectId` di ciascuna connessione solo per una chiave con l'ambito `manage` / `admin`; le altre route `/api/cloud/*`, `/api/evals/*` e `/api/assess` richiedono una sessione/chiave API di gestione. Il metodo POST `/api/assess` usa `validateBody` con uno schema di ambito a unione discriminata. --- ## Gestione di ACP (Agent Client Protocol) come processi figlio. Questi endpoint gestiscono il rilevamento degli agenti ACP e la registrazione di agenti personalizzati. | Metodo | Percorso | Descrizione | | ------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | GET | `/api/acp/agents` | Elenca tutti gli agenti CLI conosciuti (integrati + personalizzati) con stato di installazione, versione e binario | | POST | `/api/acp/agents` | Registra un agente ACP personalizzato o aggiorna la cache — corpo: `{id, name, binary, versionCommand, providerAlias, spawnArgs, protocol}` oppure `{action: "refresh"}` | | DELETE | `/api/acp/agents` | Rimuove un agente ACP personalizzato — parametro query: `?id=` | **Esempio di risposta** (`GET /api/acp/agents`): ```json { "agents": [ { "id": "claude", "name": "Claude Code CLI", "binary": "claude", "version": "1.0.45", "installed": true, "protocol": "stdio", "providerAlias": "claude", "isCustom": false }, { "id": "my-custom-cli", "name": "My Custom CLI", "installed": false, "protocol": "stdio", "providerAlias": "my-provider", "isCustom": true } ], "cacheTtlMs": 60000, "cacheAge": 1234 } ``` **Autenticazione:** richiede una sessione di gestione (cookie `auth_token` del dashboard) oppure una chiave API con ambito di gestione. Per tutti i dettagli, consulta [Framework ACP](../frameworks/ACP.md). --- ## Analisi e osservabilità Endpoint di analisi in tempo reale per monitorare il routing, la compressione e la diversità dei provider. Questi alimentano le pagine `/dashboard/analytics/*`. ### Analisi del routing automatico | Metodo | Percorso | Descrizione | | ------ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/analytics/auto-routing` | Statistiche aggregate sul routing automatico: chiamate totali, distribuzione delle strategie, distribuzione dei livelli, principali provider | | GET | `/api/analytics/auto-routing?days=7` | Statistiche su un intervallo temporale (predefinito: 24 h) | **Esempio di risposta**: ```json { "window": "24h", "totalCalls": 1234, "strategyBreakdown": { "rules": 800, "cost": 200, "latency": 150, "sla-aware": 50, "lkgp": 34 }, "tierBreakdown": { "ultra": 100, "pro": 500, "standard": 400, "free": 234 }, "topProviders": [ { "provider": "openai", "calls": 500, "avgLatencyMs": 850 }, { "provider": "anthropic", "calls": 300, "avgLatencyMs": 1200 } ] } ``` ### Analisi della compressione | Metodo | Percorso | Descrizione | | ------ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/analytics/compression` | Statistiche aggregate sulla compressione: token risparmiati, risparmio %, distribuzione delle modalità, utilizzo dei motori | **Esempio di risposta**: ```json { "window": "24h", "totalOriginalTokens": 5000000, "totalCompressedTokens": 3500000, "totalSavings": 1500000, "savingsPct": 30.0, "modeBreakdown": { "lite": 400, "standard": 600, "aggressive": 100, "ultra": 50, "rtk": 84 }, "engineBreakdown": { "caveman": 800, "rtk": 434 } } ``` ### Monitoraggio della diversità dei provider | Metodo | Percorso | Descrizione | | ------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | GET | `/api/analytics/diversity` | Monitoraggio della diversità basato sull'entropia di Shannon: previene i singoli punti di errore misurando la distribuzione tra i provider | **Esempio di risposta**: ```json { "window": "24h", "shannonEntropy": 2.45, "maxEntropy": 3.17, "diversityRatio": 0.77, "providerUsage": { "openai": 0.4, "anthropic": 0.25, "google": 0.2, "kiro": 0.15 }, "warnings": ["OpenAI accounts for 40% of traffic — consider diversifying"] } ``` **Autenticazione:** richiede una sessione di gestione oppure una chiave API con ambito di gestione. --- ## Operazioni amministrative Endpoint accessibili solo agli amministratori per la gestione operativa. | Metodo | Percorso | Descrizione | | ------ | ------------------------ | --------------------------------------------------------------------------------------------------- | | GET | `/api/admin/concurrency` | Legge i limiti di concorrenza correnti (globali + per provider) | | POST | `/api/admin/concurrency` | Aggiorna i limiti di concorrenza — corpo: `{global?: number, perProvider?: Record}` | **Autenticazione:** richiede una sessione di gestione con ambito amministratore. --- ## Gestione degli strumenti CLI Gestisce gli strumenti CLI che si integrano con OmniRoute (antigravity, commandCode, devin-cli, ecc.). Vedere [Riferimento dei provider](./PROVIDER_REFERENCE.md) per l'elenco completo. | Metodo | Percorso | Descrizione | | ------ | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/cli-tools/all-statuses` | Stato di tutti gli strumenti CLI (installato, versione, ultima rilevazione) | | GET | `/api/cli-tools/status` | Dettagli sullo stato di un singolo strumento CLI (query `?tool=`) | | POST | `/api/cli-tools/apply` | Scrive la configurazione generata di uno strumento (`dryRun` mostra un'anteprima; `422` + `containerEphemeralTarget` quando è containerizzato; `migration` indica un YAML Codex legacy) | | GET | `/api/cli-tools/backups` | Elenca i backup delle configurazioni degli strumenti CLI | | POST | `/api/cli-tools/backups` | Crea un backup di tutte le configurazioni degli strumenti CLI | | POST | `/api/cli-tools/backups` | Ripristina: lo stesso endpoint con `{tool, backupId}` nel corpo ripristina quel backup | | GET | `/api/cli-tools/antigravity-mitm` | Stato del proxy MITM di Antigravity (lo strumento CLI "antigravity-mitm") | | POST | `/api/cli-tools/antigravity-mitm/alias` | Configura gli alias di antigravity-mitm | **Autenticazione:** richiede una sessione di gestione. --- ## Competenze degli agenti Gestisce le competenze degli agenti IA (simili ai GPT personalizzati di OpenAI, ma per gli agenti). | Metodo | Percorso | Descrizione | | ------ | ---------------------------- | ----------------------------------------------------------------------------------------------------------- | | GET | `/api/agent-skills` | Elenca tutte le competenze degli agenti (integrate + personalizzate) | | GET | `/api/agent-skills/[id]` | Recupera una competenza specifica dell'agente | | POST | `/api/agent-skills` | Crea una competenza personalizzata dell'agente — corpo: `{name, description, prompt, model?, temperature?}` | | PUT | `/api/agent-skills/[id]` | Aggiorna una competenza personalizzata dell'agente | | DELETE | `/api/agent-skills/[id]` | Elimina una competenza personalizzata dell'agente | | GET | `/api/agent-skills/[id]/raw` | Recupera il prompt non elaborato + i metadati (senza esecuzione) | | POST | `/api/agent-skills/generate` | Genera una nuova competenza tramite IA a partire da una descrizione in linguaggio naturale | **Autenticazione:** richiede una sessione di gestione o una chiave API con ambito di gestione. --- ## Gestione della cache Gestisci la cache semantica e la cache di ragionamento. | Metodo | Percorso | Descrizione | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | GET | `/api/cache` | Panoramica della cache: numero totale di voci, percentuale di hit, dimensioni su disco | | GET | `/api/cache/entries` | Elenca le voci memorizzate nella cache (con paginazione) | | DELETE | `/api/cache/entries` | Elimina le voci della cache (filtra in base ai parametri di query) | | GET | `/api/cache/stats` | Statistiche dettagliate della cache (per provider e per modello) | | GET | `/api/cache/reasoning` | Stato della cache di ragionamento (per la riproduzione del ragionamento) | | DELETE | `/api/cache/reasoning` | Svuota la cache di ragionamento — parametri di query: `?toolCallId=` (singolo), `?provider=

` o nessun parametro (tutti) | **Autenticazione:** richiede una sessione di gestione. --- ## Sistema di memoria Gestisci la memoria persistente (FTS5 + incorporamenti vettoriali). | Metodo | Percorso | Descrizione | | ------ | ------------------ | ------------------------------------------------------------------------------------------- | | GET | `/api/memory` | Elenca le voci di memoria (filtra per ambito, tipo e query di ricerca) | | POST | `/api/memory` | Crea una nuova voce di memoria — corpo: `{scope, type, content, metadata?}` | | GET | `/api/memory/[id]` | Recupera una voce di memoria specifica | | PUT | `/api/memory/[id]` | Aggiorna una voce di memoria | | DELETE | `/api/memory/[id]` | Elimina una voce di memoria | | GET | `/api/memory?q=` | Cerca nella memoria (FTS5 + vettoriale) — le statistiche sono incluse nella stessa risposta | **Autenticazione:** richiede una sessione di gestione o una chiave API con ambito di gestione. --- ## Webhook Gestisci le sottoscrizioni ai webhook per gli eventi. | Metodo | Percorso | Descrizione | | ------ | ------------------------------- | ------------------------------------------------------------------------------------ | | GET | `/api/webhooks` | Elenca tutte le sottoscrizioni ai webhook | | POST | `/api/webhooks` | Crea una sottoscrizione a un webhook — corpo: `{url, events[], secret?, active?}` | | GET | `/api/webhooks/[id]` | Recupera una sottoscrizione a un webhook specifica | | PUT | `/api/webhooks/[id]` | Aggiorna una sottoscrizione a un webhook | | DELETE | `/api/webhooks/[id]` | Elimina una sottoscrizione a un webhook | | GET | `/api/webhooks/[id]/deliveries` | Elenca la cronologia delle consegne per un webhook (registro di successi/insuccessi) | | POST | `/api/webhooks/[id]/test` | Invia un evento di test a un webhook | **Autenticazione:** richiede una sessione di gestione. Consulta il [framework dei webhook](../frameworks/WEBHOOKS.md) per l'elenco completo dei tipi di evento. --- ## Framework delle competenze Gestisci le competenze (framework delle estensioni agentiche). | Metodo | Percorso | Descrizione | | ------ | ------------------------ | -------------------------------------------------------------------------------------------------- | | GET | `/api/skills` | Elenca tutte le competenze installate (integrate + personalizzate) | | POST | `/api/skills/install` | Installa una competenza da un percorso locale o da un URL | | DELETE | `/api/skills/[id]` | Disinstalla una competenza | | PUT | `/api/skills/[id]` | Abilita o disabilita una competenza — corpo: `{enabled?: boolean, mode?: "on" \| "off" \| "auto"}` | | POST | `/api/skills/executions` | Esegue una competenza — corpo: `{skillName, apiKeyId, input?, sessionId?}` | | GET | `/api/skills/executions` | Elenca la cronologia delle esecuzioni per tutte le competenze (filtro con `?apiKeyId=`) | **Autenticazione:** richiede una sessione di gestione o una chiave API con ambito di gestione. Per tutti i dettagli, consulta [Framework delle competenze](../frameworks/SKILLS.md). --- ## Plugin Gestisci i plugin di OmniRoute (estensioni di terze parti). | Metodo | Percorso | Descrizione | | ------ | ---------------------------------- | ------------------------------------- | | GET | `/api/plugins` | Elenca i plugin installati | | POST | `/api/plugins/marketplace/install` | Installa un plugin dal marketplace | | DELETE | `/api/plugins/[name]` | Disinstalla un plugin | | POST | `/api/plugins/[name]/activate` | Attiva un plugin | | POST | `/api/plugins/[name]/deactivate` | Disattiva un plugin | | GET | `/api/plugins/[name]/config` | Recupera la configurazione del plugin | | PUT | `/api/plugins/[name]/config` | Aggiorna la configurazione del plugin | **Autenticazione:** richiede una sessione di gestione. Per tutti i dettagli, consulta [Framework dei plugin](../frameworks/PLUGIN_SDK.md). --- ## Routing Shadow Il confronto Shadow / A-B tra provider **non è una superficie REST autonoma** — viene configurato tramite il routing combinato (consulta [Auto-Combo](../routing/AUTO-COMBO.md)). Le metriche di confronto per combo sono fornite da `GET /api/combos/metrics`. --- ## Guardrail Ispeziona i guardrail di runtime (rilevamento di PII, rilevamento di prompt injection, bridging della visione). I guardrail vengono eseguiti su ogni richiesta; la disattivazione per singola chiamata avviene tramite l'header della richiesta `x-omniroute-disabled-guardrails` — non esiste una superficie persistente per abilitarli/disabilitarli. | Metodo | Percorso | Descrizione | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------------ | | GET | `/api/guardrails` | Elenca i guardrail registrati e il loro stato (nome / abilitato / priorità) | | POST | `/api/guardrails/test` | Esegue a secco la pipeline pre-chiamata su un input di esempio — corpo: `{input, disabledGuardrails?}` | **Autenticazione:** richiede una sessione di gestione. Per tutti i dettagli, consulta [Sicurezza > Guardrail](../security/GUARDRAILS.md). --- --- ## Autenticazione Consulta [Autenticazione della gestione](../guides/MANAGEMENT-AUTH.md) per le quattro famiglie di credenziali (sessione del dashboard, token CLI locale, token di accesso `oma_live_…`, chiave API con ambito di gestione) e per le differenze rispetto alle chiavi di inferenza. - Le route del dashboard (`/dashboard/*`) usano il cookie `auth_token` - L'accesso usa l'hash della password salvata; fallback a `INITIAL_PASSWORD` - L'opzione `requireLogin` può essere attivata o disattivata tramite `/api/settings/require-login` - Le route `/v1/*` richiedono facoltativamente una chiave API Bearer quando `REQUIRE_API_KEY=true` - In questo riferimento, "token di gestione" / "chiave API con ambito di gestione" indica una delle famiglie descritte in quella guida — non un tipo aggiuntivo di segreto non definito > **Modifica che interrompe la compatibilità (v3.8.0)** — `/api/v1/agents/tasks/*` e gli endpoint di gestione del cooldown ora richiedono **autenticazione di gestione** (cookie `auth_token` del dashboard o una chiave API con ambito di gestione). I client che in precedenza chiamavano queste route senza autenticazione riceveranno `401 Unauthorized`. Consulta il commit `588a0333` (`fix(auth): require management auth for agent and cooldown APIs`).