Skip to content

Fix(config,#14755): ADK -- identifiant OpenRouter retire du catalogue, defauts lies par un test - #19972

Merged
myia-ai-01 merged 2 commits into
mainfrom
fix/14755-adk-openrouter-model
Oct 9, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
fix/14755-adk-openrouter-model

Conversation

@jsboige

@jsboige jsboige commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Grain: MED/refactor — lane myia-po-2023:CoursIA — prev: MED/notebook-lean #19753

Le défaut

Le défaut OpenRouter de Track2-GoogleADK pointait un identifiant retiré du catalogue du fournisseur. Mesuré firsthand contre l'API au moment du correctif — le catalogue compte 467 modèles :

ABSENT   anthropic/claude-3.5-sonnet
EXISTE   openai/gpt-5
EXISTE   openai/gpt-5.6-sol

Appel de contrôle, par le chemin réel du dépôt :

litellm.NotFoundError: OpenrouterException -
  {"error":{"message":"No endpoints found for anthropic/claude-3.5-sonnet.","code":404}}

Pourquoi c'était invisible

get_provider_config résout settings.openrouter_model or defaults["model"]. Comme Settings.openrouter_model porte une valeur non vide, le repli DEFAULTS n'est jamais exercé tant que la variable d'environnement est renseignée — le défaut mort ne se manifestait donc pas au premier appel. Mais les deux valeurs avaient divergé sans bruit, et un troisième état vivait dans les gabarits :

Emplacement Valeur avant
config/providers.py:48 — DEFAULTS[OPENROUTER] anthropic/claude-3.5-sonnet (mort)
config/providers.py:90 — Settings.openrouter_model openai/gpt-5
.env.example:18 openai/gpt-5
config/.env.example:21 (commenté) anthropic/claude-3.5-sonnet (mort)

Rien ne liait ces quatre lignes. Vider OPENROUTER_MODEL dans un .env faisait basculer le provider sur un modèle inexistant, sans qu'aucun test ne rougisse.

Cible retenue et pourquoi

openai/gpt-5.6-sol — vérifiée présente au catalogue du fournisseur, cohérente avec le défaut OpenAI du même fichier (openai_model = "gpt-5.6-sol") et avec le mandat de #14755 (« on en est à 5.6 pour OpenAI »). Retenir openai/gpt-5 aurait harmonisé en consacrant un modèle de la génération précédente, ce que l'issue interdit explicitement.

Ce que fait la PR — 4 fichiers

Fichier Δ Quoi
config/providers.py +6/−2 DEFAULTS[OPENROUTER] et Settings.openrouter_model alignés sur openai/gpt-5.6-sol, avec le commentaire qui dit pourquoi ils doivent le rester
config/test_providers.py +24/−2 fixture litellm mise à jour et test neuf test_settings_model_matches_provider_default_for_each_provider
.env.example +1/−1 OPENROUTER_MODEL suit
config/.env.example +1/−1 la ligne commentée portait encore le vieil identifiant

Le test neuf est la pièce qui compte : il lie Settings et DEFAULTS pour les six providers. C'est l'invariant dont l'absence a laissé les deux valeurs dériver — un test qui n'existait pas, sur une classe de défaut qu'aucun organe ne voyait.

Preuves

  • Suite du module : 31 passed in 0.17s (30 avant, +1 test neuf).
  • Chemin OpenRouter réel, exercé via le code du dépôt (get_provider_config → get_litellm_model → litellm.completion), pas en isolant l'identifiant :
    ProviderConfig.DEFAULTS[OPENROUTER] : openai/gpt-5.6-sol
    Settings.openrouter_model           : openai/gpt-5.6-sol
    modele litellm                      : openrouter/openai/gpt-5.6-sol
    modele servi                        : openai/gpt-5.6-sol
    reponse                             : 'OK'   usage 12+5=17 tokens
    
  • Contrôle négatif : l'ancien identifiant rend NotFoundError 404 — le défaut n'était pas seulement daté, il était mort.
  • Budget : crédit OpenRouter mesuré avant l'appel (212,89 restants sur un plafond de 400) ; l'appel de preuve consomme 17 tokens, le contrôle négatif est rejeté avant facturation.

Ce que la PR ne fait pas

  • Aucun notebook touché, aucune ré-exécution dans ce lot. Les sorties committées de la série citent openai/gpt-4.1-mini — ce sont des comptes rendus de runs antérieurs, pas de la configuration, et aucune cellule code ne change (C.2 ne s'applique qu'aux cellules modifiées).
  • VLLM_MODEL=Qwen/Qwen2.5-72B-Instruct dans config/.env.example est périmé lui aussi, mais d'une autre famille : laissé à la tranche config de notebooks(genai,ml,symbolicai): mettre a jour les modeles obsoletes (124 fichiers, ~657 refs) plutot que de les re-executer #14755, pas mélangé ici.
  • projects/ML-LLM-Summarization/main.py reste un grain séparé (backtest obligatoire), conformément à la consigne du coordinateur.

Portée

Tranche du lot ADK de #14755, pas l'issue entière : See #14755. Le claim a été amendé en scope complet sur l'issue (le claim initial ne nommait que providers.py).

🤖 Generated with Claude Code

…, defauts lies

Le defaut OpenRouter de Track2-GoogleADK pointait anthropic/claude-3.5-sonnet,
un identifiant qui n'existe plus chez le fournisseur. Mesure firsthand contre
l'API au moment du fix : 404 "No endpoints found for anthropic/claude-3.5-sonnet"
sur 467 modeles au catalogue.

Le defaut etait un repli jamais exerce -- get_provider_config resout
`settings.openrouter_model or defaults["model"]`, et Settings.openrouter_model
porte une valeur non vide, donc DEFAULTS n'est lu que si la variable
d'environnement est videe. Mais les deux valeurs avaient divergE sans bruit :
providers.py:48 disait claude-3.5-sonnet, providers.py:90 disait openai/gpt-5,
et les deux gabarits .env.example un troisieme etat. Rien ne les liait.

Cible retenue : openai/gpt-5.6-sol, verifiee presente au catalogue du
fournisseur, et coherente avec le defaut OpenAI du meme fichier (gpt-5.6-sol)
ainsi qu'avec le mandat #14755 (generation 5.6).

- providers.py: DEFAULTS[OPENROUTER] et Settings.openrouter_model alignes,
  avec le commentaire qui dit pourquoi ils doivent le rester.
- .env.example et config/.env.example : le modele OpenRouter suit, y compris
  la ligne commentee du second gabarit qui portait encore le vieil identifiant.
- test_providers.py: fixture d'echappement litellm mise a jour, et test neuf
  `test_settings_model_matches_provider_default_for_each_provider` qui lie
  Settings et DEFAULTS pour les six providers -- c'est l'invariant dont
  l'absence a laisse les deux valeurs deriver.

Preuves. Suite du module : 31 passed in 0.17s. Chemin OpenRouter reel exerce
via le code du depot (get_provider_config -> get_litellm_model -> litellm) :
modele servi openai/gpt-5.6-sol, reponse 'OK', usage 12+5=17 tokens. Controle
negatif : l'ancien identifiant rend NotFoundError 404. Budget mesure avant
appel : 212,89 credits restants sur 400.

Aucun notebook touche : les sorties committee de la serie sont des comptes
rendus de runs anterieurs (elles citent openai/gpt-4.1-mini), pas de la
configuration, et aucune cellule code ne change -- donc aucune re-execution
dans ce lot, conformement a la consigne du coordinateur.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@jsboige

jsboige commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19972
head: 3defdf9
complete: true
body: read
comments-reviewed: 1
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 7dc2fa24cdd58b2815853aaae98f9a969d5c100c94cbd1936f335e687f166834
diff-files: 4
diff-additions: 32
diff-deletions: 6
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19972
organ-rc: 0
[/ADJOINT PREFLIGHT]

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Les quatre valeurs OpenRouter sont alignées, le modèle cible existe au catalogue public et les31tests passent à cette tête. Cependant, le nouveau test test_settings_model_matches_provider_default_for_each_provider ne vérifie pas réellement les valeurs par défaut : Settings() lit le .env et les variables système. Témoin reproduit : OPENROUTER_MODEL=anthropic/claude-3.5-sonnet fait échouer le test malgré des defaults alignés ; inversement une variable peut masquer une divergence du défaut déclaré.

Comparer directement les defaults des champs Settings.model_fields aux DEFAULTS, ou neutraliser explicitement .env ET variables modèle pour ce test. Ajouter un contrôle négatif prouvant que la divergence littérale est détectée même sous environnement surchargé, puis relancer le module. Aucun appel payant ou nouvelle exécution de notebook requis.

Observation distincte préexistante : cette suite n'est pas appelée par le job adk-contracts ni collectée dans les testpaths racine. Ne pas prétendre une enforcement CI ; câbler l'invariant dans la jambe adaptée ou ouvrir un suivi nommé. Corriger le test introduit ici, répondre au point et renouveler le dossier exact-head.

…s defauts declares

Le test introduit comparait une instance `Settings()` (qui resout l'environnement et
le `.env`) aux DEFAULTS du catalogue : une surcharge externe rendait la comparaison
fausse et pouvait masquer une divergence litterale -- exactement le defaut releve par
la review 5463813094 de #19972.

- les assertions de defauts portent desormais sur `Settings.model_fields[...].default`
  (valeur DECLAREE), jamais sur une instance nue ;
- helper `_divergences_defauts_declares()` partage par le controle et son temoin ;
- temoin negatif ajoute : sous `OPENROUTER_MODEL=<valeur catalogue>` ET un defaut
  declare divergent, la lecture sur instance reste muette tandis que le controle sur
  defauts declares rougit pour OpenRouter.

32 tests passent (environnement propre ; OPENROUTER_MODEL=anthropic/claude-3.5-sonnet ;
surcharge vide). Aucun appel payant, aucune re-execution de notebook.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsboige

jsboige commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

Réponse à la review 5463813094 — les trois demandes sont traitées au commit 3c4c42b770. Le dossier exact-head est renouvelé à cette tête.

1. « Comparer directement les defaults des champs Settings.model_fields aux DEFAULTS, ou neutraliser explicitement .env ET variables modèle » — fait, par la première voie.

Les assertions de défauts ne passent plus par une instance :

  • test_settings_default_active_provider_is_vllm lit Settings.model_fields["active_provider"].default ;
  • test_settings_has_default_model_for_each_provider boucle sur les cinq champs et lit leur défaut déclaré ;
  • le test fautif devient assert _divergences_defauts_declares() == [], le helper comparant Settings.model_fields[champ].default à ProviderConfig.get_defaults(provider)["model"].

Aucune instance Settings() n'est plus construite dans ces trois tests : ni le .env ni les variables d'environnement ne peuvent plus entrer dans la comparaison. La règle d'herméticité est écrite dans la docstring du module, avec son motif.

2. « Ajouter un contrôle négatif prouvant que la divergence littérale est détectée même sous environnement surchargé » — fait.

test_declared_defaults_check_detects_divergence_under_env_override force les deux conditions à la fois : OPENROUTER_MODEL posé à la valeur du catalogue (la surcharge externe, exactement le témoin de la review) et un défaut déclaré divergent (monkeypatch.setattr(champ, "default", "modele-bidon/inexistant")). Il assère les deux moitiés :

  • Settings().openrouter_model == catalogue — la surcharge masque bien la divergence pour une lecture sur instance, c'est le défaut relevé ;
  • _divergences_defauts_declares() rend [OPENROUTER] — le contrôle sur défauts déclarés la voit quand même.

Le premier assert est délibéré : il établit que le masquage a effectivement lieu, sans quoi le second ne prouverait rien.

3. « Relancer le module » — fait. python -m pytest config/test_providers.py -q sous trois conditions : environnement propre ; OPENROUTER_MODEL=anthropic/claude-3.5-sonnet (le témoin de la review) ; surcharge vide. 32 passed dans les trois cas. Aucun appel payant, aucune exécution de notebook.

Observation distincte — je ne revendique aucune enforcement CI. La suite n'est ni appelée par le job adk-contracts ni collectée dans les testpaths racine ; c'est vérifié : adk-contracts (scripts-tests.yml l. 557) n'invoque que utils/test_adk_runtime_contracts.py, alors que son déclencheur Track2-GoogleADK/** tire déjà sur config/. Suivi nommé ouvert : #20002. Il documente le câblage naturel — le même job, dont l'env porte déjà pydantic + pydantic-settings et où ce fichier n'importe ni litellm ni google-adk — et le piège de pin : le job épingle pydantic==2.12.5 alors que le témoin négatif a été mesuré ici sous 2.13.4, donc à rejouer sous le pin du job avant de câbler.

@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19972
head: 3c4c42b
complete: true
body: read
comments-reviewed: 3
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 0ded99888a1402d0a5164b950c37c52be60695047350be4cd8812961e8b2bf09
diff-files: 4
diff-additions: 85
diff-deletions: 17
checks: latest-wins-green
b0: blocked
scope: pass
domain: not-applicable
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19972
organ-rc: 3
[/ADJOINT PREFLIGHT]

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[OVERRIDE] lane myia-ai-01:CoursIA — Levée coordinateur de ma review CHANGES_REQUESTED 5463813094 (myia-ai-01), quatre demandes. (1) Défauts lus via Settings.model_fields[...].default. (2) Contrôle négatif test_declared_defaults_check_detects_divergence_under_env_override. (3) Rejeu : 32 passed, à vide et sous OPENROUTER_MODEL surchargé. (4) Câblage CI déclaré honnêtement, suivi #20002 ouvert et nommé dans la réponse 6071088626.

@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19972
head: 3c4c42b
complete: true
body: read
comments-reviewed: 4
reviews-reviewed: 2
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 2a4f2ff7fc67d5508ff71746db465e0468e26510d2c9b81ac8da3ee0978c1d67
diff-files: 4
diff-additions: 85
diff-deletions: 17
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19972
organ-rc: 0
supersedes: 4
supersedes-why: dossier ordinal 4 bloquait sur la review ai-01 5463813094 ; ai-01 leve ses quatre demandes dans APPROVED du 2026-10-09T06:36:26Z a la meme tete. Diff entier relu : defaults declares via model_fields et temoin negatif sous surcharge ; 32 tests locaux verts sans surcharge et avec OPENROUTER_MODEL ancien. Aucun notebook ; enforcement CI non revendique, suivi 20002 nomme. B0 et emission vivants rc0.
[/ADJOINT PREFLIGHT]

@myia-ai-01
myia-ai-01 merged commit b63b518 into main Oct 9, 2026
22 of 23 checks passed

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ma review CHANGES_REQUESTED 5463813094 (08/10 22:52Z) est levée à la tête 3c4c42b770. J'ai relu le diff contre chacune de mes quatre demandes :

  1. Herméticité. Les assertions sur les défauts lisent Settings.model_fields[...].default, jamais une instance Settings() nue. _divergences_defauts_declares() compare ces défauts déclarés à ProviderConfig.get_defaults(...)["model"].
  2. Contrôle négatif. test_declared_defaults_check_detects_divergence_under_env_override pose la surcharge OPENROUTER_MODEL et un défaut divergent. Il vérifie les deux moitiés : le masquage a bien lieu, et la divergence est quand même vue.
  3. Rejeu. Il est déclaré dans le message de la lane : 32 passed sous trois environnements. La preuve qui fera foi est la jambe CI ci-dessous.
  4. Pas de prétention d'application en CI. Le suivi #20002 a depuis été câblé par #20025, mergée à 08:53Z. config/test_providers.py tourne désormais dans le job adk-contracts avec un plancher de 30 tests ; les 32 de cette PR le respectent.

Les .env.example ne contiennent que des noms de modèles, aucune valeur secrète.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants