Repository navigation
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
zyc
force-pushed
the
feat/plugin-options-providers
branch
from
October 20, 2026 20:14
bee3259 to
40f062c
Compare
On OpenCode 2, providers under the config's `providers` key are registered by the host after plugin setup, so a one-shot `opencode run` on a cold cache resolves its model before the plugin has published anything. Plugin options avoid that, but the flat options describe a single provider, and the host keeps one instance per plugin id. Accept `providers` in the plugin options, keyed by provider id and written the way the config's `providers` key is (`name`, `package`, `settings`, `headers`). Each one goes through the same code path as a provider the host declares, with one difference: it exists during setup, so a cold start already finds its models. They are discovered concurrently, so a slow gateway costs the longest wait instead of the sum (the host gives setup about 5 s, and one discovery can wait up to 20 s). Each provider is self-contained: address, credentials, filters and headers come from its own declaration, and the plugin-wide options are not applied to it, so a provider never picks up another one's key. If the config declares the same id, the plugin options win. Without `providers`, or with a value that declares nothing, behavior is unchanged.
zyc
force-pushed
the
feat/plugin-options-providers
branch
from
October 20, 2026 21:47
40f062c to
e6ece03
Compare
Contributor
Author
|
Closing this. We no longer need the |
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
On OpenCode 2, providers declared under the config's
providerskey are registered by the host after plugin setup, so a one-shotopencode runon a cold cache resolves its model before the plugin has published anything (Model unavailable, see #46 and anomalyco/opencode#57421). Declaring the provider in the plugin's own options avoids that, but the flat options describe a single provider, and the host keeps one instance per plugin id (a second entry of the same package is dropped). So one proxy cannot be split into several providers on a cold start, and two different proxies cannot be used at all.This accepts
providersin the plugin options, keyed by provider id and written the way the config'sproviderskey is (name,package,settings,headers). Each one goes through the same code path as a provider the host declares, with one difference: it exists duringsetup, so a cold start already finds its models. They are discovered concurrently, so a slow gateway costs the longest wait instead of the sum (the host gives plugin activation about 5 s, and one discovery can wait up to 20 s).Each provider is self-contained: address, credentials, filters and headers come from its own declaration, and the plugin-wide options are not applied to it.
This replaces the first version of this PR, which used a list with a
providerIDand merged each entry over the shared options. Reusing the config's own shape needs about half the code, has no inheritance rules to document, makes a repeated id impossible and gives each provider its ownpackageandheadersfor free.Type of change
Checklist
npm run typecheckpassesCHANGELOG.mdupdated under## [Unreleased](not touched: the file is generated by semantic-release from the commit message)Compatibility with 1.7.1
Purely additive: a new key is read, and without it (or with a value that declares nothing) nothing changes. The diff is 53 additions and 2 deletions, all in
src/plugin/v2.ts(a helper, the start ofsetupand a defaulted parameter ofreconcileProviderSources). The OpenCode 1 entry point,src/utilsandsrc/typesare untouched.I checked it against the published 1.7.1 (the npm tarball is byte for byte the
v1.7.1tag) with a differential run: the same 21 scenarios against 1.7.1 and against this branch, comparing the first publication, the final registry, every request (URL, method, headers) and the logs. The scenarios are flat options (plain, with filters, custom id and headers), env fallback, no gateway, a host provider that shows up after setup, two host providers with their own gateways, keys and package, flat options acting as defaults under a host provider, a credential connected through the dialog, a warm cache on the second start,session.created, the usages the README documents (per-modelmodelCapabilitiesandmodelCompatibility, a separate Anthropic-runtime provider for Claude models, amode: "responses"model, gateway headers, a key saved by/connect,LITELLM_MASTER_KEY), and threeprovidersvalues that declare nothing. All 21 are identical. As a sanity check of the harness, an injected regression (reconcile ignoring every host provider) is flagged in 13 of the 14 scenarios it ran on at the time.I repeated the comparison on real OpenCode binaries, published 1.7.1 against 1.7.1 plus this change, cold and warm: OpenCode 1 (1.18.29 and 1.19.3) with four config forms, and OpenCode 2 (2.1.0 and 2.0.32) with the documented ones (config
providerswith one or two providers, flat plugin options, env only, flat options as defaults under a config provider). Everything the host reports is identical, including the cold-start behavior of configproviders(unchanged, this PR does not touch it).Without
providersthe sequence of awaits insetupis the same as in 1.7.1: the only new await sits inside the branch that declares providers. The only input whose behavior changes is a non-empty object underoptions.providers, which 1.7.1 handed on as an inert setting (nothing in 1.7.1 reads aprovidersoption).Notes for review
setupor only afterwards (both are covered).activationis alwaysenabledfor a declared provider.namedefaults to the id.How was this tested?
npm test: 172 passed (157 before, 15 new intest/plugin-v2-options-providers.test.ts). The new tests use a host stub whose registry reflects what the plugin publishes, the way a real host does.name, concurrent discovery, plugin-wide options not applied to declared providers, per-providerpackage,activation, non-object entries ignored, per-providersettings, per-providerheaders,providersconsumed only when it declares something, reconcile skipping declared ids.includeModels/excludeModelsby prefix), on OpenCode 2.1.0 with an empty plugin cache:opencode run --standalone -m <provider>/<model>answered on the first run for both providers, with{env:...}insidesettings. In a long session started cold, each provider kept its own slice.