feat(models): explicit wire protocol declarations for providers#93
Conversation
Providers previously had their wire protocol (openai, anthropic, google) inferred solely from the models.dev npm-package heuristic, with no escape hatch besides --provider-url (which forces the OpenAI-compatible wire). This adopts the explicit provider-type design from charmbracelet/catwalk without switching data sources: - ProviderInfo gains Wire and Headers fields; the wireProtocol enum splits wireOpenAI (Responses API) from wireOpenAICompat (chat completions), removing the npm=="@ai-sdk/openai" dispatch special case - New `providers` config section declares or patches providers: wire, baseUrl, apiKeyEnv, headers, name. Unknown IDs register fresh, so internal gateways work without a database entry - New --provider-wire flag (also kit.Options.ProviderWire, inherited by subagents); with --provider-url it synthesizes unknown providers on the fly and skips the custom/ openai-compat rewrite - Wire resolution precedence: --provider-wire > providers config > npm heuristic > api-URL openaicompat fallback (unchanged long tail) - Per-provider default headers ride an http.RoundTripper wrapper on all four auto-routed constructors, composing with TLS and gemini-proxy transports
Options.ProviderWire landed without a matching functional option; every other provider override field (ProviderAPIKey, ProviderURL) has one.
Covers the --provider-wire flag, the providers config section, and Options.ProviderWire / WithProviderWire: - www/pages/configuration.md: provider-wire config key, new Provider overrides section with field reference, cross-ref from Custom models - www/pages/providers.md: link to field reference, when-to-use-which table comparing custom provider / customModels / providers overrides / --provider-wire - www/pages/cli/flags.md + README flag list: --provider-wire row - www/pages/sdk/options.md: ProviderWire field row + struct example - www/pages/sdk/overview.md: WithProviderWire functional option row Docs site verified with 'tome build'.
|
Connected to Huly®: KIT-94 |
📝 WalkthroughWalkthroughAdds explicit provider wire selection through CLI, SDK, and configuration; introduces provider overrides for registry entries and new providers; updates auto-routing precedence and protocol mappings; and applies configured headers to auto-routed HTTP clients. ChangesProvider wire routing and overrides
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CLIorSDK
participant Viper
participant BuildProviderConfig
participant autoRouteProvider
participant ModelsRegistry
participant ProviderConstructor
CLIorSDK->>Viper: Set provider-wire and provider-url
Viper->>BuildProviderConfig: Read provider configuration
BuildProviderConfig->>autoRouteProvider: Pass ProviderWire and ProviderURL
autoRouteProvider->>ModelsRegistry: Resolve provider metadata and wire
autoRouteProvider->>ProviderConstructor: Create protocol-specific provider
ProviderConstructor->>ProviderConstructor: Apply configured headers
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
pkg/kit/kit.go (1)
2294-2294: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover
ProviderWirein the subagent inheritance test.Extend
TestInheritProviderConfigto setprovider-wireon the parent and assertchild.ProviderWire. This protects the new propagation path from silently regressing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/kit/kit.go` at line 2294, Update TestInheritProviderConfig to configure provider-wire on the parent provider settings, then assert that the inherited child.ProviderWire matches the configured value, covering the ProviderWire propagation path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/models/providers.go`:
- Around line 488-495: Update ProviderResult to carry the resolved wire/protocol
from the auto-routing logic in createAutoRoutedOpenAIProvider and related
provider constructors, then make CreateProvider’s cache-options merge guard use
that resolved protocol instead of only checking provider == "openai". Ensure
providers configured with wireOpenAI skip incompatible cache merging even when
their declared provider name is not "openai".
- Around line 533-539: headerRoundTripper.RoundTrip must distinguish absent
headers from explicitly empty ones. Replace the Header.Get check with
presence-aware lookup (such as checking the map key) so configured values are
added only when the request header is not already present, preserving
intentionally cleared Authorization and other headers.
- Line 540: Update the RoundTrip method to capture the error returned by
h.base.RoundTrip(req) and wrap any failure with fmt.Errorf using the %w verb,
adding request/transport context before returning the response and wrapped
error.
---
Nitpick comments:
In `@pkg/kit/kit.go`:
- Line 2294: Update TestInheritProviderConfig to configure provider-wire on the
parent provider settings, then assert that the inherited child.ProviderWire
matches the configured value, covering the ProviderWire propagation path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f0992ee4-993e-41ad-a2d3-d89a4498f2a6
📒 Files selected for processing (16)
README.mdcmd/root.gointernal/kitsetup/setup.gointernal/models/autoroute_test.gointernal/models/modelsdb.gointernal/models/provider_overrides.gointernal/models/provider_overrides_test.gointernal/models/providers.gointernal/models/registry.gopkg/kit/kit.gopkg/kit/options.gowww/pages/cli/flags.mdwww/pages/configuration.mdwww/pages/providers.mdwww/pages/sdk/options.mdwww/pages/sdk/overview.md
- Make the cache-options merge guard wire-aware: detect ResponsesProviderOptions by type via hasResponsesProviderOptions() instead of checking provider == "openai", so providers auto-routed to the Responses wire (wire: openai / npm @ai-sdk/openai) are guarded too; regression test ties the guard to the real options producer (buildOpenAIProviderOptions) - headerRoundTripper: presence-aware header check so an explicitly cleared (empty) request header is not replaced by the configured default; regression test added - Cover ProviderWire in TestInheritProviderConfig Skipped (intentional): wrapping h.base.RoundTrip errors — http.Client already wraps transport errors in *url.Error with method+URL context, and the sibling geminiProxyTransport uses the same pass-through pattern; wrapping inside middleware adds noise without new context.
Description
Providers have their wire protocol (OpenAI / Anthropic / Google) inferred from the models.dev npm-package heuristic, with no escape hatch besides
--provider-url— which always forces the OpenAI-compatible wire. When the database misroutes a provider, omits one entirely, or an internal gateway speaks a non-OpenAI wire, there was no way to fix it locally.This adopts the explicit provider-type design from charmbracelet/catwalk without switching data sources: the wire protocol becomes a first-class, declarable attribute of a provider, while the npm heuristic remains the default for the 144-provider models.dev long tail.
Before — only workaround was the
custom/provider (openai-compat wire only):After — declare any provider on any wire, in config or ad hoc:
Changes
ProviderInfogainsWireandHeadersfields; the internalwireProtocolenum splitswireOpenAI(Responses API) fromwireOpenAICompat(chat completions), removing thenpm == "@ai-sdk/openai"dispatch special caseprovidersconfig section (internal/models/provider_overrides.go):name,wire,baseUrl,apiKeyEnv,headers. Merged as the final registry layer — non-empty fields win, unset fields inherit models.dev values, unknown IDs register fresh. Invalid wires warn and skip the whole override--provider-wireflag (+kit.Options.ProviderWire/WithProviderWire()in the SDK, inherited by subagents). With--provider-urlit synthesizes unknown providers on the fly and skips thecustom/openai-compat rewrite--provider-wire>providersconfig > npm heuristic > api-URL openaicompat fallback (long-tail behavior unchanged)http.RoundTripperwrapper on all four auto-routed constructors, composing with the existing TLS and gemini-proxy transports (doesn't overwrite request-set headers)Type of Change
Backward Compatibility
ProviderInfochanges are additive (new fields), sopkg/kitSDK consumers are unaffected--provider-urlwithout--provider-wirekeeps its existingcustom/rewrite semanticsTesting
internal/models/provider_overrides_test.go: wire parsing/aliases, explicit-wire routing to all four transports, flag-beats-config-beats-npm precedence, provider synthesis, override merge semantics (patch/declare/invalid-wire skip), config parsing, header round-tripper contractautoroute_test.goupdated for the enum splitgo test -race ./...green;go vetclean<baseUrl>/v1/messageswith env-resolved key; ad-hoc--provider-wire anthropicsynthesized and routed; invalid wires produce targeted errorsChecklist
go fmt,go vet)www/pages/{configuration,providers,cli/flags,sdk/options,sdk/overview}.md, godoc on all new exported symbols; docs site verified withtome build)Summary by CodeRabbit
--provider-wire(and SDKProviderWire) to select the wire protocol for auto-routed providers.wire,baseUrl,apiKeyEnv, and default requestheaders.