Gli id dei modelli non vanno nel codice TypeScript

· 5 min di lettura

L'id di un modello è il dato che cambia più in fretta in tutto questo sistema. I fornitori li rinominano, li ritirano, rilasciano una variante datata, cambiano in silenzio ciò a cui punta l'alias senza data e ne vincolano metà all'account che fa la richiesta. Compila tutto questo in un pacchetto e hai la garanzia che il pacchetto sarà sbagliato nel giro di settimane — non rotto in modo evidente, che almeno sarebbe una segnalazione di bug, ma sbagliato in quel modo specifico in cui un selettore offre a qualcuno un modello che la sua chiave non può chiamare.

Quindi il catalogo è un file JSON, e la parte interessante non è che sia JSON. È ciò che la stratificazione sottostante ammette sulla certezza.

Cinque livelli, i successivi battono i precedenti

0. pi-ai's built-in models      whatever it knows about the catalogued vendors
1. the bundled catalog.json     27 providers, 6 verified models
2. ~/.oharness/catalog.json     your edits, and what discovery found
3. a catalog path in config
4. providers / models in config
5. /models refresh              asks the vendor directly

Leggi quella colonna di numeri come una classifica di affidabilità più che come un ordine di caricamento. Il livello 0 è l'istantanea del mondo fatta da qualcun altro. Il livello 1 è ciò che eravamo disposti ad affermare esplicitamente. Il livello 5 è il fornitore che risponde sul tuo account, adesso — e vince, perché nulla di ciò che abbiamo rilasciato tre mesi fa sa più dei tuoi diritti di accesso dell'endpoint che stai per chiamare.

Il livello incluso contiene ventisette provider e sei modelli verificati, e quel rapporto è l'intero progetto. I dati sui provider — l'endpoint, la variabile d'ambiente, il protocollo di trasmissione — sono abbastanza stabili da essere distribuiti. Gli id dei modelli no, quindi gli unici dichiarati esplicitamente sono quelli che è stato davvero possibile verificare, e tutto il resto arriva dalla discovery, che interroga il /models di ciascun fornitore.

Sei è un numero scomodo da pubblicare. È anche quello onesto.

Le sostituzioni sono a livello di campo

Il motivo per cui questo conta nell'uso quotidiano è più piccolo e più noioso: puntare Kimi al suo endpoint per la Cina continentale non dovrebbe significare riscrivere tutto il resto su Kimi.

{ "providers": { "moonshot": { "baseUrl": "https://api.moonshot.cn/v1" } } }

Questa è l'intera modifica. Le sostituzioni dell'intera voce sono il modo in cui i formati di configurazione marciscono: qualcuno copia il blocco distribuito per cambiare un URL e, due release dopo, la sua copia è l'unica cosa che lo separa da una correzione che tutti gli altri hanno già ricevuto.

Dove si ferma il seed

Il livello 0 merita una nota, perché è quello che sorprende: un provider che non hai mai collegato ha comunque dei modelli da mostrare. Provengono da pi-ai, il livello di trasmissione, che distribuisce un catalogo generato di ciò che conosce. Riportano finestre di contesto, prezzi e livelli di ragionamento, e non sanno assolutamente nulla di ciò che il tuo account può chiamare — quindi sia una voce dichiarata sia qualsiasi risultato della discovery li battono, e OHARNESS_NO_BUILTIN_MODELS=1 disattiva del tutto il seed.

Due limiti impediscono a quel seed di fare danni.

Un modello viene inserito tramite seed solo in una voce il cui protocollo corrisponde all'API rispetto a cui pi-ai lo cataloga. I modelli di Mistral sono elencati rispetto all'API conversations di pi-ai, quindi sono lasciati alla discovery invece di essere inviati a un endpoint compatibile con OpenAI in una forma che non parla. Inviare la forma sbagliata è un 400 da debuggare, non una risposta degradata con cui si può convivere.

E dove i due cataloghi non concordano sull'id di un fornitore, vengono riconciliati nominando l'altro, non tirando a indovinare:

{ "providers": { "moonshot": { "piProvider": "moonshotai" } } }

Un provider senza seed e ancora senza discovery — un server locale, un gateway per cui nessuno include nomi — compare comunque nel selettore come una singola riga che apre il pannello in cui collegarlo. Uno stato vuoto che si spiega da solo è meglio di un provider semplicemente assente finché non si verifica una condizione invisibile.

Il protocollo è l'unica cosa che vale la pena nominare

Il protocol di una voce del catalogo indica il formato parlato dal suo endpoint:

anthropic-messages   openai-chat      openai-responses
gemini               bedrock          vertex
openai-codex

openai-codex è quello che giustifica il fatto di mantenere questa lista esplicita invece di dedurla dal nome di un fornitore. È il backend con cui parla Codex CLI, ed è un formato di trasmissione davvero diverso da openai-responses, non lo stesso su un altro host: store viene rifiutato, max_output_tokens non viene inviato e l'id dell'account viaggia in un header dedicato. Un sistema che tirasse a indovinare "è OpenAI, usa la forma di OpenAI" sbaglierebbe in tre modi diversi.

Gli SDK dietro questi protocolli vengono importati in modo lazy, quindi una sessione che parla solo con Anthropic non carica mai i client AWS o Google.

Cosa non si è spostato

L'autenticazione. Le credenziali vengono risolte a ogni richiesta dall'AuthManager dell'harness stesso, perché un token di abbonamento valido all'avvio non lo è più un'ora dopo. Per questo le implementazioni API di pi-ai vengono chiamate direttamente, ricevendo una chiave e degli header già risolti, invece di passare dall'autenticazione dei provider e dall'archivio credenziali di pi-ai.

Ecco perché alcune voci non vengono distribuite affatto. Bedrock e Vertex funzionano come protocolli, ma solo con credenziali già presenti nell'ambiente: la firma SigV4 completa e le ADC di gcloud stanno esattamente nel livello provider che questo harness rinuncia a usare per l'autenticazione. Azure OpenAI non ha un URL di base fisso da catalogare, perché l'endpoint dipende dal singolo deployment. Entrambi possono essere dichiarati da chiunque abbia l'ambiente già configurato; nessuno dei due verrà distribuito come impostazione predefinita funzionante che in silenzio non lo è.

Lo schema alla base di tutto: dichiarare i fatti che restano fermi, chiedere di quelli che cambiano, e mantenere la differenza visibile nel file invece di seppellirla in una nota di rilascio.


OHarness è un harness per agenti open source, con licenza MIT. Il riferimento sui provider documenta ogni livello, sostituzione e protocollo descritti sopra, e l'hub dei provider elenca ciò che oggi è incluso nel catalogo distribuito.