chore: re-pin openrouter_dart at 0.30.0 and address the catalog by its entry #189
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/repin-openrouter-0.30"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Re-pins the submodule from 0.27.0 to 0.30.0 (openrouter_dart #14, merged), migrates the breaking
ModelIdchange from 0.29.0, and fixes a bug that migration made visible.This is the first of two PRs; the assistant's routing and thinking settings are the second, and nothing user-facing changes here except the fix below.
What's in
modelis aModelIdnow. 0.29.0 changed it wherever a request names a model.flutter analyzefound exactly three call sites — the turn, the reflection pass, the blind-mode captioner — and nothing else. The id is sent verbatim, so OpenRouter's request log still matches what the user typed.The catalog is not addressed the same way as a request. Conflating the two was already a bug:
A routing variant has no catalog entry of its own, so a model configured with one matched nothing in the listing.
_modelHasVisionreturned null — "the listing does not know this model" — which the caller reads as no verdict, so a configured vision model stayed in blind mode captioning for a main model that can see images perfectly well. And the verdict is sticky per session, so it persisted for every turn until restart.ADR 0024 already promises the opposite ("the blind-mode captioner only engages when the main model actually lacks image input"), so this is the code keeping a promise the ADR already made — no amendment needed.
The rule is now a pure function beside the file's other helpers:
resolved through
ModelId.catalogId— routing variants (:nitro,:floor,:exacto) dropped, catalog variants (:free,:batch) kept, because those are separate entries with their own modalities and pricing. Stripping:freewould report the paid entry's capabilities.Why
pubspec.lockmoves two unrelated packagesimage4.8.0 → 4.10.1 andpuppeteer3.25.1 → 3.26.0. Not drift: 0.29.1 tightened openrouter_dart's own dependency floors to the versions it is actually tested against, so the app's resolution has to follow. Both are transitive; the app declares neither.Verification
scripts/verify.sh(all) — verify OK, backend + app, 1423 app tests.flutter analyzeclean.7 new tests, and I mutation-probed them before opening:
catalogEntryFormatches the written id, notcatalogIdcatalogEntryFornever matches_modelHasVisionbypasses the rule with an inline written-id matchThe third probe survived the first round. My unit tests covered the pure rule and my end-to-end test covered the sent model id, so the wiring between them could be deleted with everything green — the classic "green test, untested branch". Fixed by adding a turn-driving test: a
view_imagesround where blind mode engaging would put a request to the configured vision model on the wire. Re-probed, all five red.Layers exercised: use case (
catalogEntryFor), agent service end-to-end throughAgentService.runwith a scripted provider and image server. Not exercised: the real OpenRouter API, and the settings UI (unchanged here).Follow-ups
None deferred from this PR. The assistant settings work that motivated the bump is the next PR, and the two upstream gaps it will run into (
reasoning.enabledandreasoning.max_tokensare reportable but not settable) are recorded in openrouter_dart #14 and will reachdocs/BACKLOG.mdwith the PR that hits them.🤖 Generated with Claude Code
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A migration PR that doesn't just bump the pin and walk away — it stops, notices the conceptual bug the new types made visible, and fixes the conflation of two different addresses (request-id vs catalog-entry) with a pure, documented function. This is the kind of thing I get genuinely giddy over~ ♡ And your mutation table admitting a probe survived the first round and then fixing the green-test-untested-branch trap with a turn-driving test? Fufu~, you know the way to my heart.
Verdict: ✅ Looks good to me~
✅ What I liked~
catalogEntryForis exactly the right shape — a pure function beside the file's helpers, doc comment explains why written-id matching fails (:nitrohas no catalog entry) and why:freemust be kept (separate entry, own modalities). I verifiedModelId.catalogIdin the submodule source: routing variants dropped, catalog variants AND unrecognized suffixes kept — your doc comment's claims map to the implementation sentence-by-sentence.createAgentsites migrated (turn :585, reflection :398, captioner :842); the settings/UI layer correctly keeps raw strings — that's the app boundary, not a miss. And'model': model.valuein the vendored request builder confirms the verbatim-wire claim: OpenRouter's log matches what the user typed. The wire test pins exactly that._modelHasVisionmatching the written id meant a vision model configured asx/y:nitromatched nothing, read as "no verdict", stayed sticky-cached as blind mode... forever. ADR 0024's vision-model note ("only engages when the main model actually lacks image input") already promised this; now the code keeps the ADR's promise. No amendment needed — I checked, the note is at docs/adr/0024 §Vision-model note.catalogEntryFormatchesmodel.valueinstead ofcatalogId_modelHasVisionbypasses the rule with an inline written-id matchwithoutRoutingVariants()(strips variant before wire)if (seesImages ?? false) blindMode = false;deleted)catalogEntryFor—agent_history_test.dartstill pins "a vision-capable main model skips blind mode entirely" (plain-slug catalog entry) and the transient-403-on-cold-cache turn-2 flap test. Both arms of the ADR 0024 contract remain witnessed.image: ^4.10.1andpuppeteer: ^3.26.0floors (I read the vendored pubspec.yaml); both lock entries are exactly those resolutions. Not drift, as claimed.:free:nitro→:freeentry) and thecatalogEntryFor(base) isNullcompanion assertion are lovely little pins~Local verification (CI absent for head
e77cebe):flutter analyze— No issues found; new suite 7/7; agent family 61/61 (agent_history, agent_vision, agent_console_log, agent_model_id, assistant_agent).Fufu~ a chore PR that ships a real fix, documents the distinction it's built on, and tests the wiring rather than just the rule. Approved with a smile~ ♪
Automated review by Jibril · 2026-09-20
CI/CD: absent for head SHA · Local checks: analyze clean, 7/7 new suite, 61/61 agent family, 4/4 mutation probes directional