anomalyco / anomalyco/opencode
web: config-declared models are hidden by default — released:0 is coerced to "1970-01-01" and fails the client visibility window
@Hona is already working on this.
Since Sep 17, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
Custom, config-declared models (a provider entry whose models live only in config, with no models.dev catalog entry) are toggled hidden by default in every fresh client of the web/desktop app: the server reports time.released: 0 ("unknown"), the client normalizes that into the valid date "1970-01-01", and the default-visibility rule (visible() in the models context) then treats the model as 56 years old and hides it. Because visibility preferences are persisted only in client-local storage (browser localStorage / desktop storage), nothing on the server remembers the user's "show" toggle — every new browser profile, cleared storage, or another machine starts with these models hidden again.
Environment
- opencode version: 2.0.6 (
opencode serve --service, channellatest; same code path verified on 2.0.4 from the served bundle) - OS: Linux x86_64 (server host)
- Terminal: N/A — defect is in the web/desktop app served by
opencode serve - Shell: /bin/bash (server host)
- Install/channel: npm, latest
- Active plugins: none needed; reproduces with a single custom-provider config entry
Reproduction
- Add a custom provider whose models exist only in configuration (no
models.devmatch):{ "$schema": "https://opencode.ai/config.json", "providers": { "acme-ai": { "name": "Acme AI", "package": "@opencode/ai/providers/openai-compatible", "settings": { "baseURL": "https://api.example.com/v1" }, "models": { "acme-model-1": { "name": "Acme Model 1" } } } } } - (Re)start the server. In
GET /api/model,acme-ai/acme-model-1is returned with"enabled": truebut"time": { "released": 0 }. - Open the web app in a fresh browser profile (or incognito window).
- Settings → Models: "Acme Model 1" is toggled OFF ("hidden") despite there being no stored preference. The model picker does not list it either.
- Toggle it ON — it becomes usable in that browser.
- Clear site data (or open another browser/machine). The model is hidden again.
Expected Behavior
Models whose release date is unknown should be visible by default — the client fallback even encodes that intent (!date.isValid → visible). Alternatively, configuration should let me set a model's release date so catalog-less models can be dated.
Actual Behavior
Every config-declared model is hidden by default in every fresh client. The only toggle lives in per-browser/per-app storage, so the setting appears to "reset" whenever client state is fresh or lost.
Root cause (verified on served v2.0.6 bundle + live /api/model output)
- Server: models without a catalog entry are emitted with
"time": { "released": 0 }(epoch 0 = unknown). - Client normalization coerces that epoch-0 into a real date string (in the served runtime chunk):
release_date: new Date(e.time.released).toISOString().slice(0, 10) // -> "1970-01-01" - Default visibility rule (models context), minimally de-minified:
wherevisible(model) = stored !== "hide" && (stored === "show" || latestSet.has(key) || !releaseDate.isValid)latestSet= models whose parsed release date is within the last 6 months."1970-01-01"parses as a valid Luxon date, so the!isValidescape never fires, and the 6-month window fails → hidden. - Storage:
visibleoverrides are kept viaPersist.global("model", ...)targeting client-local storage only; none of it is posted back to the server. Selecting a model also writessetVisibility(key, true), which is why "my main models stay visible in the browser I usually use" while other clients reset. - Config cannot override: the native V2 config model schema offers exactly
family,name,api,capabilities,request,variants,cost,disabled,limit— no date field. The V1 schema'smodels.<id>.release_dateexists but is dropped silently bymigrateModel()in the V1→V2 compatibility layer.
Suggested fix
Either of:
- Treat
released === 0as unknown when building the client catalog entry (leaverelease_dateunset/null), so the existing!isValidfallback defaults them to visible; and/or - expose a per-model release-date field in config (or preserve V1
release_datethrough migration).
Separately, persisting visibility preferences per-server (not per-browser) would fix the "loses toggles" half of the experience — tracked by #21310 (closed as not planned).
Additional Context
- Found while investigating why custom-provider models "disappeared from the picker after every server restart" — the restarts merely coincided with fresh/cleared clients; the defaults do the hiding.
- Only catalog-declared models are immune: they carry real release dates and (when <6 months old) pass the
latestSetwindow. - Possibly related older reports: #6169 (TUI picker missing custom models), #6798 (web UI cannot select configured custom models). This one is a narrower, mechanistically identifiable defect.
- Related feature requests: #21035, #9203 (per-model hiding support).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.