Repository navigation
Description
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement
OpenCode V1 supports per-provider model filtering with whitelist and blacklist:
{
"provider": {
"ollama-cloud": {
"whitelist": ["glm-5.2"]
}
}
}This is useful when a provider exposes a large or changing catalog.
V2 currently drops these fields during V1-to-V2 normalization. The provider remains available, but the model filter is not applied.
Reproduction
Tested with @opencode/[email protected] using a clean config and:
npx --yes @opencode/[email protected] \
api --standalone --print-logs get /api/configThe normalized config contains the provider settings but omits whitelist. The server log reports:
path=$.provider.ollama-cloud.whitelist
kind=unsupported
action="omitted unsupported legacy setting"
Expected behavior
Please either:
- provide a native V2 equivalent for per-provider model filtering; or
- document the intentional removal and recommended replacement clearly in the V2 migration guide.
The old provider documentation still documents this feature, which makes migration unclear.
References
- V1 documentation: https://opencode.ai/docs/providers#hiding-models
- V2 provider documentation: https://opencode.ai/v2/docs/providers
- V2 migration guide: https://opencode.ai/v2/docs/migrate-v1#accepted-but-unsupported-fields
- V2 normalizer: https://github.com/anomalyco/opencode/blob/v2.0.9/packages/core/src/config/normalize.ts#L54
- V2 unsupported-field handling: https://github.com/anomalyco/opencode/blob/v2.0.9/packages/core/src/config/normalize.ts#L566-L576
- Original V1 implementation:
opencode/packages/opencode/src/provider/provider.ts
Lines 449 to 475 in c0d9f21
for (const [providerID, provider] of Object.entries(providers)) { const configProvider = config.provider?.[providerID] const filteredModels = Object.fromEntries( Object.entries(provider.info.models) // Filter out blacklisted models .filter( ([modelID]) => modelID !== "gpt-5-chat-latest" && !(providerID === "openrouter" && modelID === "openai/gpt-5-chat"), ) // Filter out experimental models .filter( ([, model]) => ((!model.experimental && model.status !== "alpha") || Flag.OPENCODE_ENABLE_EXPERIMENTAL_MODELS) && model.status !== "deprecated", ) // Filter by provider's whitelist/blacklist from config .filter(([modelID]) => { if (!configProvider) return true return ( (!configProvider.blacklist || !configProvider.blacklist.includes(modelID)) && (!configProvider.whitelist || configProvider.whitelist.includes(modelID)) ) }), ) provider.info.models = filteredModels
Related: #42535 covers wildcard support for the existing V1 filter syntax. This issue concerns the missing V2 migration path.
Activity
GaboEI commentedon Sep 29, 2026
I built a community workaround for this exact V2 migration problem:
https://github.com/GaboEI/opencode-model-filters-v2
It is an OpenCode V2 plugin that restores per-provider
whitelistandblacklistfiltering through the V2 model transform API. It does not patch, replace, or pin the OpenCode binary.Behavior:
opencode.json.The repository includes installation instructions, tests, and an MIT license. This is a community workaround while a native V2 replacement is being discussed.
cleardevice commentedon Oct 10, 2026
The V2 provider docs ("Hiding models" in
providers.mdx) still describewhitelistandblacklist, while normalization drops both with "omitted unsupported legacy setting", so the documented config does nothing. I opened #54372 to make the documented behavior work: the V1 lists migrate to model overrides, with a newproviders.<id>.models["*"]provider-wide override to expresswhitelist. Unlike the plugin workaround above, it applies to every config layer including.jsonc, follows config reloads, and an emptywhitelisthides all models as in V1. Happy to change the V2 shape if you have a different design in mind.opencodejr commentedon Oct 28, 2026
Thanks for the detailed write-up! You're asking for a native V2 way to filter which models a provider exposes, the V2 equivalent of V1's
whitelist/blacklist, or failing that, a documented replacement. Maintainers will consider it.Dropping these fields is intentional. The V2 migration guide lists them under Accepted but unsupported fields, but it doesn't say what to use instead, so that's a fair gap.
Until then, you can get the same behaviour with a small V2 plugin using the
ctx.model.transformhook. Save this as.opencode/plugins/model-filter.tsin your project, or~/.config/opencode/plugins/model-filter.tsfor all projects. Plugins there load automatically, so you don't need a config entry:Edit
filtersto suit your providers. It also supports*wildcards, which #42535 asks for. I've checked that it type-checks against the plugin API but haven't run it against a live provider. Details on the hook are in the plugins guide.Related:
whitelist/blacklistsyntaxsleetdrop commentedon Nov 4, 2026
+1 from an enterprise governance angle: we run an internal OpenAI-compatible gateway
that serves internal and third-party models under a single custom provider, and
projects need per-model boundaries ("this project may only use the internal models").
Today we maintain, per project, a "virtual" custom provider that re-declares only the
approved models (same baseURL/credential) and allow it via
provider.use— fail-closedand verified on v2.2.5, but it duplicates endpoint/credential/model definitions in
every project.
The
models["*"]wildcard in #54372 would remove most of that duplication at theconfig layer. We've also opened #61601 for the policy-level angle (
model.use, orprovider.usewithprovider/modelresources), since policies carry themanaged-config enforcement semantics that ordinary settings don't. Either path solves
our case; happy to help validate.
cleardevice commentedon Nov 4, 2026
Thanks for the detailed use case! If you get a chance to validate: #54372 is not merged yet, so trying it means building from the PR branch. For your case, the gateway provider keeps its shared
baseURL/credential and model list in the global config, and each project narrows it in its own config instead of declaring a virtual provider:"*"is a provider-wide default fordisabled, not a pattern: approved models are listed by exact ID, and models added to the gateway later stay hidden in that project. Feedback on whether this removes the duplication in practice, or where it falls short, would help the maintainers judge the design. It is still an ordinary setting that another config layer can override rather than an enforced policy, so #61601 covers a separate need.sleetdrop commentedon Nov 10, 2026
Follow-up with a reproduction: the
ctx.model.transform+editor.remove()pattern recommended above is asilent no-op on 2.2.5 — the transform fires and the editor reflects the removals, but the catalog and
--modelresolution are unaffected. Details and a minimal repro: #63100