MOMO's /v1/models listed opencode-zen-free/exo-free, and a request for it
got 410 "Model exo-free has been deprecated.". OpenCode Zen's own
/zen/v1/models still lists exo-free (checked 2026-10-10), and models.dev
gives it no deprecated status, so the zen-free plugin's discovery keeps it
and a refresh of the list would bring it straight back. No preset
hardcodes it.
What changed:
- fallback.go: retiredWords / modelRetired: a 400, 404, 410 or 422 saying
the model is deprecated/retired (Zen's "ModelDeprecated", OpenAI's
"The model ... has been deprecated"), without quota words. It is
retryable (410 wasn't), and modelRefused, so only that model rests.
- gateway.go: such an answer calls provider.Retire(provider, model);
routing.go: servedCandidate calls Unretire.
- provider/retired.go: retired.json beside providers.json, re-read by
mtime; Retire/Unretire touch the catalog so agents' lists are written
again. buildEntries leaves a retired model out, for that provider only,
for at most a week. provider/model requests are still sent.
- docs: gateway-routing.md failure handling, reference.md.
Tests: retired_test.go with Zen's literal 410 body: the model leaves
/v1/models while the provider's other model stays; a group falls over to
the next member and only the 410's provider is marked; modelRetired
cases. All three fail with the hooks reverted.
Run: gofmt -l; go vet -tags nogui on darwin, linux, windows for provider
and gateway; go test -tags nogui ./internal/provider ./internal/gateway
./internal/agent ./internal/catalog in a sandbox HOME.