Model-id's horen niet in TypeScript
· 5 min lezen
Een model-id is het snelst veranderende gegeven in dit hele systeem. Aanbieders hernoemen ze, trekken ze in, brengen een gedateerde variant uit, veranderen stilletjes waar de ongedateerde alias naar verwijst, en schermen de helft af op basis van welk account erom vraagt. Compileer dat in een package en je weet zeker dat het package binnen een paar weken niet meer klopt — niet kapot op een duidelijke manier, wat op zijn minst een bugmelding zou opleveren, maar fout op precies die manier waarbij een keuzelijst iemand een model aanbiedt dat zijn sleutel niet kan aanroepen.
Dus is de catalogus een JSON-bestand, en het interessante is niet dat het JSON is. Het is wat de gelaagdheid eronder toegeeft over zekerheid.
Vijf lagen, later wint van eerder
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
Lees die kolom met nummers als een rangorde van betrouwbaarheid, niet als een laadvolgorde. Laag 0 is een momentopname van de wereld door iemand anders. Laag 1 is wat wij zonder voorbehoud wilden vastleggen. Laag 5 is de aanbieder die antwoordt over jouw account, op dit moment — en die wint, want niets wat wij drie maanden geleden hebben uitgebracht, weet meer over jouw rechten dan het endpoint dat je zo meteen aanroept.
De meegeleverde laag bevat zevenentwintig aanbieders en zes geverifieerde modellen, en die verhouding is het hele ontwerp. Gegevens over aanbieders — het endpoint, de omgevingsvariabele, het wire-protocol — zijn stabiel genoeg om mee te leveren. Model-id's zijn dat niet, dus de enige die zonder voorbehoud worden vastgelegd, zijn die echt geverifieerd konden worden, en al het andere komt binnen via discovery die de eigen /models van elke aanbieder bevraagt.
Zes is een ongemakkelijk getal om te publiceren. Het is ook het eerlijke.
Overrides werken per veld
De reden dat dit in het dagelijks gebruik telt, is kleiner en saaier: Kimi naar zijn endpoint op het Chinese vasteland laten wijzen, zou niet moeten betekenen dat je al het andere over Kimi opnieuw moet opgeven.
{ "providers": { "moonshot": { "baseUrl": "https://api.moonshot.cn/v1" } } }
Dat is de hele wijziging. Overrides van complete items zijn de manier waarop configuratieformaten verrotten — iemand kopieert het meegeleverde blok om een URL te wijzigen, en twee releases later is die kopie het enige wat tussen hem en een fix staat die iedereen al heeft gekregen.
Waar de seed ophoudt
Laag 0 verdient een toelichting, omdat die mensen verrast: een aanbieder die je nooit hebt gekoppeld, heeft toch modellen om te tonen. Die komen van pi-ai, de wire-laag, die een gegenereerde catalogus meelevert van wat hij kent. Ze hebben contextvensters, prijzen en redeneerniveaus, en ze weten helemaal niets over wat jouw account mag aanroepen — dus zowel een vastgelegd item als alles wat discovery teruggeeft wint ervan, en OHARNESS_NO_BUILTIN_MODELS=1 zet de seed volledig uit.
Twee grenzen voorkomen dat die seed schade aanricht.
Een model wordt alleen als seed toegevoegd aan een item waarvan het protocol overeenkomt met de API waaronder pi-ai het catalogiseert. De modellen van Mistral staan vermeld onder pi-ai's eigen conversations-API, dus die worden aan discovery overgelaten in plaats van naar een OpenAI-compatibel endpoint gestuurd in een vorm die het niet spreekt. De verkeerde vorm sturen is een 400 die je mag debuggen, geen minder goed antwoord waarmee je kunt leven.
En waar de twee catalogi het oneens zijn over het id van een aanbieder, worden ze verzoend door de andere bij naam te noemen in plaats van te gokken:
{ "providers": { "moonshot": { "piProvider": "moonshotai" } } }
Een aanbieder zonder seed en nog zonder discovery — een lokale server, een gateway waarvoor niemand namen meelevert — verschijnt toch in de keuzelijst, als één regel die het paneel opent waarin je hem koppelt. Een lege toestand die zichzelf uitlegt, is beter dan een aanbieder die gewoon ontbreekt tot aan een of andere onzichtbare voorwaarde is voldaan.
Het protocol is het enige wat het benoemen waard is
Het protocol van een catalogusitem benoemt het formaat dat zijn endpoint spreekt:
anthropic-messages openai-chat openai-responses
gemini bedrock vertex
openai-codex
openai-codex is degene die rechtvaardigt dat deze lijst expliciet blijft in plaats van hem af te leiden uit de naam van een aanbieder. Het is de backend waarmee de Codex CLI praat, en het is een werkelijk ander wire-formaat dan openai-responses, niet hetzelfde op een andere host: store wordt geweigerd, max_output_tokens wordt niet meegestuurd en het account-id reist in een eigen header. Een systeem dat gokte „het is OpenAI, gebruik de OpenAI-vorm”, zou er op drie verschillende punten naast zitten.
De SDK's hierachter worden lazy geïmporteerd, dus een sessie die alleen met Anthropic praat, laadt nooit de clients van AWS of Google.
Wat niet is verplaatst
Authenticatie. Inloggegevens worden per verzoek opgelost door de eigen AuthManager van het harness, omdat een abonnementstoken dat bij het opstarten geldig was, een uur later niet meer geldig is. Daarom worden de API-implementaties van pi-ai rechtstreeks aangeroepen en krijgen ze een al opgeloste sleutel en headers mee, in plaats van via de aanbiederauthenticatie en credential store van pi-ai te gaan.
Daarom worden sommige items helemaal niet meegeleverd. Bedrock en Vertex werken als protocol, maar alleen met inloggegevens die al in de omgeving staan — volledige SigV4-ondertekening en gcloud ADC zitten precies in de aanbiederlaag die dit harness voor authenticatie niet wil gebruiken. Azure OpenAI heeft geen vaste basis-URL om te catalogiseren, omdat het endpoint per deployment verschilt. Beide kan iedereen declareren van wie de omgeving al is ingericht; geen van beide wordt meegeleverd als werkende standaard die stilletjes geen werkende standaard is.
Het patroon onder dit alles: leg de feiten vast die stil blijven staan, vraag naar de feiten die dat niet doen, en houd het verschil zichtbaar in het bestand in plaats van het te begraven in release notes.
OHarness is een open source agent-harness met een MIT-licentie. De aanbiedersreferentie documenteert elke laag, override en elk protocol hierboven, en de aanbiedershub toont wat er vandaag in de meegeleverde catalogus zit.