Les ids de modèles n'ont rien à faire dans du TypeScript

· 6 min de lecture

Un id de modèle est le fait qui évolue le plus vite dans tout ce système. Les fournisseurs les renomment, les retirent, publient une variante datée, modifient discrètement la cible de l'alias non daté, et en réservent la moitié selon le compte qui les demande. Compilez cela dans un paquet et vous êtes certain que le paquet sera faux en quelques semaines — pas cassé de façon évidente, ce qui donnerait au moins lieu à un rapport de bug, mais faux de cette manière particulière où un sélecteur propose à quelqu'un un modèle que sa clé ne peut pas appeler.

Le catalogue est donc un fichier JSON, et l'intéressant n'est pas qu'il soit en JSON. C'est ce que la superposition de couches en dessous avoue sur le degré de certitude.

Cinq couches, les dernières l'emportent

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

Lisez cette colonne de chiffres comme un classement de confiance plutôt que comme un ordre de chargement. La couche 0 est l'instantané du monde pris par quelqu'un d'autre. La couche 1 est ce que nous étions prêts à affirmer explicitement. La couche 5, c'est le fournisseur qui répond au sujet de votre compte, maintenant — et elle l'emporte, car rien de ce que nous avons publié il y a trois mois n'en sait plus sur vos droits d'accès que l'endpoint que vous êtes sur le point d'appeler.

La couche intégrée contient vingt-sept fournisseurs et six modèles vérifiés, et ce ratio résume toute la conception. Les informations sur les fournisseurs — l'endpoint, la variable d'environnement, le protocole de transmission — sont assez stables pour être livrées. Les ids de modèles ne le sont pas : les seuls affirmés explicitement sont donc ceux qui ont pu être réellement vérifiés, et tout le reste provient de la découverte, qui interroge le /models propre à chaque fournisseur.

Six est un chiffre inconfortable à publier. C'est aussi le chiffre honnête.

Les surcharges se font champ par champ

Si cela compte au quotidien, c'est pour une raison plus modeste et plus ennuyeuse : faire pointer Kimi vers son endpoint de Chine continentale ne devrait pas obliger à redéclarer tout le reste sur Kimi.

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

C'est toute la modification. Les surcharges d'entrées complètes sont la façon dont les formats de configuration pourrissent : quelqu'un copie le bloc livré pour changer une URL, et deux versions plus tard, sa copie est la seule chose qui le prive d'un correctif que tout le monde a déjà reçu.

Où s'arrête la base de départ

La couche 0 mérite une remarque, car c'est celle qui surprend : un fournisseur que vous n'avez jamais connecté a tout de même des modèles à afficher. Ils viennent de pi-ai, la couche de transmission, qui livre un catalogue généré de ce qu'elle connaît. Ils portent des fenêtres de contexte, des tarifs et des niveaux de raisonnement, et ignorent tout de ce que votre compte peut appeler — une entrée déclarée comme tout ce que renvoie la découverte l'emporte donc sur eux, et OHARNESS_NO_BUILTIN_MODELS=1 désactive entièrement cette base.

Deux limites empêchent cette base de faire des dégâts.

Un modèle n'est ajouté qu'à une entrée dont le protocole correspond à l'API sous laquelle pi-ai le catalogue. Les modèles de Mistral sont répertoriés sous l'API de conversations propre à pi-ai ; ils sont donc laissés à la découverte plutôt qu'envoyés à un endpoint compatible OpenAI dans une forme qu'il ne parle pas. Envoyer la mauvaise forme, c'est une erreur 400 à déboguer, pas une réponse dégradée dont on peut s'accommoder.

Et lorsque les deux catalogues ne s'accordent pas sur l'id d'un fournisseur, on les réconcilie en nommant l'autre plutôt qu'en devinant :

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

Un fournisseur sans base de départ et encore sans découverte — un serveur local, une passerelle dont personne ne livre les noms — apparaît tout de même dans le sélecteur, sous la forme d'une ligne unique qui ouvre le panneau où vous le connectez. Un état vide qui s'explique vaut mieux qu'un fournisseur simplement absent tant qu'une condition invisible n'est pas remplie.

Le protocole est la seule chose qui mérite d'être nommée

Le protocol d'une entrée du catalogue désigne le format que parle son endpoint :

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

openai-codex est celui qui justifie de garder cette liste explicite plutôt que de la déduire d'un nom de fournisseur. C'est le backend auquel parle la Codex CLI, et c'est un format de transmission réellement différent de openai-responses, pas le même sur un autre hôte : store est refusé, max_output_tokens n'est pas envoyé, et l'id de compte circule dans son propre en-tête. Un système qui se dirait « c'est OpenAI, utilisons la forme OpenAI » se tromperait à son sujet de trois façons distinctes.

Les SDK correspondants sont importés à la demande : une session qui ne parle jamais qu'à Anthropic ne charge donc jamais les clients AWS ou Google.

Ce qui n'a pas bougé

L'authentification. Les identifiants sont résolus à chaque requête par l'AuthManager propre au harnais, car un token d'abonnement valide au démarrage ne l'est plus une heure plus tard. Les implémentations d'API de pi-ai sont donc appelées directement, avec une clé et des en-têtes déjà résolus, au lieu de passer par son authentification de fournisseur et son magasin d'identifiants.

C'est pourquoi certaines entrées ne sont pas livrées du tout. Bedrock et Vertex fonctionnent comme protocoles, mais seulement avec des identifiants déjà présents dans l'environnement — la signature SigV4 complète et gcloud ADC résident précisément dans la couche fournisseur que ce harnais refuse d'utiliser pour l'authentification. Azure OpenAI n'a pas d'URL de base fixe à cataloguer, car l'endpoint dépend de chaque déploiement. Tous deux peuvent être déclarés par quiconque dispose d'un environnement déjà configuré ; aucun ne sera livré comme une valeur par défaut fonctionnelle qui, en silence, ne l'est pas.

Le principe sous-jacent : énoncer les faits qui restent stables, interroger sur ceux qui ne le sont pas, et garder la différence visible dans le fichier plutôt qu'enfouie dans une note de version.


OHarness est un harnais d'agent open source, sous licence MIT. La référence des fournisseurs documente chaque couche, surcharge et protocole évoqués ci-dessus, et le hub des fournisseurs liste ce que contient aujourd'hui le catalogue intégré.