fix: refresh OpenCode's model catalog before listing its models - #6082
Merged
Conversation
The Harnesses page's "Refresh models" button for OpenCode reported a model list weeks out of date — a model already listed on another machine signed in to the same account never appeared here, and the refresh still reported success. `opencode models` does not go to the network: it prints from `~/.cache/opencode/models.json`, which OpenCode refreshes from a task forked at startup whose failures it swallows (`opencode models --refresh` prints "Models cache refreshed" either way). Its HTTP client connects without Happy Eyeballs, so a host advertising an IPv6 default route it cannot actually reach — a VPN interface installing one with no global v6 address — fails instantly with "Unable to connect" and the catalog freezes at whatever day the fetch last worked. Fetch that catalog from PortOS (Node falls back to IPv4) and write it where OpenCode reads it, just before the probe. This unsticks the vendor's own TUI as well as the page. It refuses to write when `OPENCODE_MODELS_PATH`, a custom `OPENCODE_MODELS_URL`, or `OPENCODE_DISABLE_MODELS_FETCH` means PortOS cannot be sure which file OpenCode reads, when the file is under five minutes old, or when the body did not parse as a catalog — a stale list beats an empty picker. Every refusal is best-effort: the probe runs regardless. Claude-Session: https://claude.ai/code/session_01BKLx7uomKwxNJgnzVwbXiU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Harnesses page's Refresh models button for OpenCode reported a model list weeks out of date — a model already listed by another machine signed in to the same account never appeared, and the refresh still reported success.
opencode modelsdoes not go to the network. It prints from~/.cache/opencode/models.json, which OpenCode refreshes from a task forked at startup whose failures it swallows —opencode models --refreshprintsModels cache refreshedwhether or not the fetch worked. Its HTTP client also connects without Happy Eyeballs, so a host advertising an IPv6 default route it cannot actually reach (a VPN interface installing one, with no global v6 address) fails instantly withUnable to connectwhilecurland Node fetch the same URL fine. The catalog then freezes at whatever day the fetch last succeeded, and every consumer — OpenCode's own TUI included — silently shows the stale list.server/lib/opencodeCatalogCache.jsfetches that catalog from PortOS (Node falls back to IPv4) and atomically writes it where OpenCode reads it, just before the probe runs. That unsticks the vendor's TUI as well as the page.Because this writes another tool's cache file, it is deliberately narrow. It refuses to fetch or write when:
OPENCODE_MODELS_PATHpins a different file, a customOPENCODE_MODELS_URLmoves the cache to a hash-derived name, orOPENCODE_DISABLE_MODELS_FETCHopts out — PortOS cannot be sure which file OpenCode reads, or whether it should read one at all;Every refusal is best-effort: the probe runs regardless and returns exactly what it would have before.
Test plan
server/lib/opencodeCatalogCache.test.js— writes to the path the harness reads; skips a fresh cache without fetching; re-fetches once aged out; keeps the existing catalog on an unreachable endpoint, a non-2xx, a gateway error page, a truncated body, and valid-JSON-that-is-not-a-catalog; neither fetches nor writes under each of the three env refusals.server/services/harnesses.test.js— the refresh primes the catalog for OpenCode and only for OpenCode.opencode modelsafter priming.https://claude.ai/code/session_01BKLx7uomKwxNJgnzVwbXiU