How the Provider Registry Resolves Model References in DeepSeek-Reasonix

DeepSeek-Reasonix resolves model references through a three-step algorithm in Config.ResolveModel that handles full provider/model paths, provider-only strings, and bare model names by scanning the configuration catalog and returning an immutable ProviderEntry ready for instantiation.

The DeepSeek-Reasonix provider registry serves as the central authority for translating user-supplied model references into concrete provider configurations. When you specify a model like deepseek/deepseek-v4-pro, deepseek, or just deepseek-v4-pro, the system must locate the correct endpoint configuration and determine which specific model variant to use. This resolution process, implemented in internal/config/config.go, ensures that every reference maps to a valid ProviderEntry that the runtime can instantiate through the provider factory.

The Three-Step Resolution Algorithm

The resolution logic lives in Config.ResolveModel at [internal/config/config.go lines 33-77](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/config/config.go#L33-L77). The algorithm processes input strings in strict priority order, attempting three distinct matching strategies before returning the result.

Step 1: Full Provider/Model References

When the input contains a forward slash (/), the system interprets it as a provider/model pattern. The implementation uses strings.Cut to split the string into provider name and model name components.

  • The provider name is validated against c.Provider (the configured provider catalog)
  • The model name is checked via e.HasModel to confirm the provider supports that specific model
  • If both conditions pass, the function returns a copy of the ProviderEntry with the Model field explicitly set to the requested model name

This pattern allows precise selection of models across different vendors, such as deepseek/deepseek-v4-pro or openai/gpt-4.

Step 2: Provider-Only References

If the input contains no slash, the algorithm treats it as a provider name lookup. The system searches the configuration for a provider matching the exact string.

When found, the entry's default model is automatically selected via e.DefaultModel(). This enables shorthand references where users specify just deepseek and receive the provider's configured default (for example, deepseek-v4-flash).

Step 3: Bare Model Names

For inputs that match neither previous pattern, the system performs a catalog scan across all configured providers. The algorithm iterates through the provider list and selects the first provider where HasModel(ref) returns true.

Upon finding a match:

  • The provider entry is copied
  • The entry's Model field is set to the bare model name provided by the user
  • The entry's Name field retains the provider that owns the model

This fallback mechanism allows users to reference models without knowing which provider hosts them, such as specifying deepseek-v4-pro without the deepseek/ prefix.

ProviderEntry Construction and Immutability

The ResolveModel function guarantees configuration immutability by returning a copy of the stored ProviderEntry rather than a pointer to the original configuration. This prevents runtime mutations from affecting the global configuration state.

Before returning the entry, the system applies model-specific overrides:

  • applyModelPrice updates pricing information based on the resolved model
  • applyModelOverride applies any model-specific configuration overrides defined in the config

If the reference cannot be resolved through any of the three steps, ResolveModel returns nil, false (as implemented at lines 78-79).

The Provider Factory Integration

While Config.ResolveModel handles the reference-to-entry mapping, the actual provider instantiation occurs through the provider registry in [internal/provider/provider.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/provider/provider.go).

The registry maintains a mapping from provider kind (such as "openai" or "deepseek") to factory functions that create concrete implementations. Each provider sub-package registers itself via an init() function, ensuring that NewProvider(entry) can instantiate the correct backend once ResolveModel has populated the Model field.

// Example: Resolving and instantiating a provider
entry, ok := cfg.ResolveModel("deepseek/deepseek-v4-pro")
if ok {
    // entry.Model is now "deepseek-v4-pro"
    // entry.Name remains "deepseek"
    prov, err := provider.NewProvider(entry)
    // prov is now a concrete DeepSeek provider ready for API calls
}

Higher-Level Resolution Helpers

The base ResolveModel function powers several convenience methods that implement fallback strategies for specific use cases:

  • ResolveModelWithFallback: Attempts primary resolution, then falls back to a default provider if the reference is empty or unresolvable
  • ResolveNewSessionChatModel: Specialized resolution for new chat sessions that applies session-specific defaults

These helpers are wired into the system through the ProviderResolver interface, which merges static configuration with extension sidecars during the boot process ([internal/boot/boot.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/boot/boot.go)). The controller ([internal/control/controller.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/control/controller.go)) exposes this resolver to the rest of the runtime for processing turns that require model inference.

Summary

  • Three-step resolution handles provider/model, provider, and bare model patterns in strict priority order
  • Immutability guarantee ensures ResolveModel returns copies of ProviderEntry objects, protecting the global configuration
  • Automatic defaults select the provider's default model when only a provider name is specified
  • Catalog scanning enables bare model references by searching across all configured providers
  • Factory integration connects resolved entries to concrete provider implementations via the registry in internal/provider/provider.go

Frequently Asked Questions

What happens if I specify a model that doesn't exist in the provider catalog?

ResolveModel returns nil, false when no match is found through any of the three resolution steps. Higher-level helpers like ResolveModelWithFallback typically catch this condition and substitute a configured default provider instead.

Can I use the same model name across different providers?

Yes. The resolution algorithm prioritizes the provider/model syntax to disambiguate conflicts. When using bare model names (Step 3), the first provider in the configuration listing that model wins, making provider order significant for ambiguous references.

How does the system handle pricing configuration for specific models?

After resolving the entry, ResolveModel invokes applyModelPrice to attach model-specific pricing data from the configuration. This ensures that cost calculations reflect the actual model being used, even when the reference was resolved through a provider-only or bare-model pattern.

Where is the provider registry initialized?

The registry map is populated during package initialization via init() functions in each provider sub-package (such as the OpenAI or DeepSeek implementations). This registration pattern ensures that NewProvider in internal/provider/provider.go can instantiate any supported backend without explicit imports in the configuration layer.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →