Skip to content

fix: restore provider registry after cf5a430d2 emptied the default#3196

Open
dgageot wants to merge 1 commit into
docker:mainfrom
dgageot:worktree-board-d67e78535844c4de
Open

fix: restore provider registry after cf5a430d2 emptied the default#3196
dgageot wants to merge 1 commit into
docker:mainfrom
dgageot:worktree-board-d67e78535844c4de

Conversation

@dgageot

@dgageot dgageot commented Jun 22, 2026

Copy link
Copy Markdown
Member

Commit cf5a430 (refactor: make toolsets and providers explicit) emptied provider.DefaultRegistry() and required callers to pass the full provider set explicitly via providers.NewDefaultRegistry(). The main agent model loading and runtime model switcher were updated at that time, but three code paths still fell through to the now-empty default registry and failed at runtime with unknown provider type "openai".

This commit restores the three broken paths. RAG toolsets now receive the resolved provider registry via a new ProviderRegistry field on config.RuntimeConfig (with a nil-safe ProviderRegistryOrDefault() getter); teamloader.LoadWithConfig populates it, and pkg/rag/builder.go and pkg/rag/strategy/strategy.go consume it instead of the empty default. The js/wasm build gets its own restored defaultFactories in pkg/model/provider/factory_js.go (openai, anthropic, google) because pkg/model/provider/providers cannot compile to wasm — it pulls in cloud SDKs that have no wasm-safe build. The eval judge in pkg/evaluation/eval.go previously called the empty default directly; cmd/root/eval.go now sets runConfig.ProviderRegistry = providers.NewDefaultRegistry() and createJudgeModel uses runConfig.ProviderRegistryOrDefault().

No behavior changes outside these three error paths. The fix is self-contained and all existing tests continue to pass.

RAG toolsets, the eval judge, and the js/wasm build all broke with
'unknown provider type' because the default registry is now empty.
Thread the resolved registry through RuntimeConfig and repopulate
the wasm-safe provider set directly in factory_js.go.

Assisted-By: Claude
@dgageot dgageot requested a review from a team as a code owner June 22, 2026 09:25

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

The three broken provider-registry paths are correctly restored. The nil-safe ProviderRegistryOrDefault() getter, the new ProviderRegistry field on config.RuntimeConfig, and the teamloader.LoadWithConfig wiring all look sound.

Key areas checked:

  • teamloader.LoadWithConfig recursive safety: loadExternalAgent explicitly forwards the parent's registry via WithProviderRegistry(loadOpts.providerRegistry), so recursive loads for external agent refs correctly propagate the full registry — no overwrite with the empty default.
  • js/wasm factory_js.go: The missing vertexai.IsModelGardenConfig branch is intentional and documented; Vertex AI cloud SDKs don't compile to wasm, and the comment in the new file makes this explicit.
  • Eval judge path (cmd/root/eval.go): ProviderRegistry is set before createJudgeModel is invoked — ordering is correct.
  • RAG builder/strategy: Both now consume runConfig.ProviderRegistryOrDefault(), which falls back to DefaultRegistry() (populated in wasm, empty in non-wasm — but LoadWithConfig always sets it before RAG toolsets are created).

No bugs found in the changed code.

@aheritier aheritier added area/providers For features/issues/fixes related to LLM providers (Bedrock, LiteLLM, Qwen, custom, etc.) kind/fix PR fixes a bug (maps to fix: commit prefix) labels Jun 22, 2026

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

This PR correctly restores provider registry wiring for three broken code paths (RAG builder/strategy, eval judge, js/wasm build). The structural fix is sound and all current callers are wired correctly via loaderdefaults.Opts().

Three related medium-severity concerns were identified around the empty-registry fallback behavior: ProviderRegistryOrDefault() silently falls back to an empty DefaultRegistry() in non-js builds, and teamloader.LoadWithConfig initializes loadOpts.providerRegistry to that same empty registry before callers can override it. No current production path triggers these issues, but they are latent traps for future callers.

Comment thread pkg/rag/builder.go
// without it, model creation fails with "unknown provider type".
func (c ManagersBuildConfig) NewProvider(ctx context.Context, cfg *latest.ModelConfig) (provider.Provider, error) {
return provider.New(ctx, cfg, c.Env,
return c.RuntimeConfig.ProviderRegistryOrDefault().New(ctx, cfg, c.Env,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM/LIKELY] Silent fallback to empty provider registry when RuntimeConfig.ProviderRegistry is unset

c.RuntimeConfig.ProviderRegistryOrDefault() falls back to provider.DefaultRegistry() when RuntimeConfig is nil or its ProviderRegistry field is not set. In non-js builds, provider.DefaultRegistry() returns an empty registry (no factories registered), so any call to NewProvider in that state will produce "unknown provider type" errors — exactly the runtime failure this PR is fixing elsewhere.

All current callers go through loaderdefaults.Opts() (which injects providers.NewDefaultRegistry()), so the happy path is fine. However, the fallback provider.DefaultRegistry() returns an empty registry in non-js builds, so any future call site that constructs ManagersBuildConfig without going through teamloader.LoadWithConfig + loaderdefaults.Opts() will fail silently.

Consider logging a warning or returning an explicit error if RuntimeConfig is nil, rather than silently falling back to an unusable registry.

// without it, model creation fails with "unknown provider type".
func (c BuildContext) NewProvider(ctx context.Context, cfg *latest.ModelConfig) (provider.Provider, error) {
return provider.New(ctx, cfg, c.Env,
return c.RuntimeConfig.ProviderRegistryOrDefault().New(ctx, cfg, c.Env,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM/LIKELY] Same silent empty-registry fallback as in pkg/rag/builder.go

c.RuntimeConfig.ProviderRegistryOrDefault() falls back to provider.DefaultRegistry() (empty in non-js builds) when RuntimeConfig is nil or ProviderRegistry is unset. The same analysis applies as the parallel issue in pkg/rag/builder.go: all current production paths are safe because all callers go through loaderdefaults.Opts(), but any future caller that constructs BuildContext without a populated RuntimeConfig will silently receive a broken provider registry and fail at model creation time with "unknown provider type".

runConfig.Providers = cfg.Providers
// Share the resolved provider registry so toolsets that build providers at
// load time (e.g. RAG embeddings/reranking) use the same one as agent models.
runConfig.ProviderRegistry = loadOpts.providerRegistry

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM/LIKELY] loadOpts.providerRegistry may be empty when WithProviderRegistry is not passed; callers get a non-nil but unusable registry

loadOpts.providerRegistry is initialized to provider.DefaultRegistry() (an empty registry in non-js builds) before opts are applied. runConfig.ProviderRegistry is then set to this value. Because ProviderRegistryOrDefault() checks only != nil, a caller that omits WithProviderRegistry(...) will silently receive an empty (non-nil) registry and fail at RAG model creation time with "unknown provider type" — the same failure this PR intends to fix.

All current callers pass loaderdefaults.Opts() (which includes WithProviderRegistry(providers.NewDefaultRegistry())), so this is safe today. However the default is a footgun: consider initializing loadOpts.providerRegistry to nil instead of provider.DefaultRegistry(), so that ProviderRegistryOrDefault() can provide a meaningful fallback, or enforce that callers must always pass WithProviderRegistry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/providers For features/issues/fixes related to LLM providers (Bedrock, LiteLLM, Qwen, custom, etc.) kind/fix PR fixes a bug (maps to fix: commit prefix)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants