Skip to content

fix(models): route auto-discovered providers by wire protocol (#41)#43

Merged
ezynda3 merged 1 commit into
masterfrom
fix/41-autoroute-google-wire-protocol
Jun 2, 2026
Merged

fix(models): route auto-discovered providers by wire protocol (#41)#43
ezynda3 merged 1 commit into
masterfrom
fix/41-autoroute-google-wire-protocol

Conversation

@ezynda3
Copy link
Copy Markdown
Contributor

@ezynda3 ezynda3 commented Jun 2, 2026

Description

autoRouteProvider previously routed models.dev providers through a flat npm→LLM-provider-name map (npmToLLMProvider) that listed 10 entries but only handled 3 in its switch. Any model whose resolved npm package fell outside anthropic/openai/openaicompat hit a dead default branch and failed with unsupported provider: … has no LLM provider mapping. This broke every Gemini model proxied through aggregators like opencode, whose gemini-* models carry a per-model @ai-sdk/google override.

This change refactors auto-routing to dispatch on wire protocol (OpenAI / Anthropic / Google) — matching fantasy's actual architecture of three native protocols plus thin wrappers — using the provider's api URL from models.dev as the base. Providers with an api URL but an unrecognized npm package fall back to the OpenAI-compatible wire, preserving prior behaviour.

It also fixes a second-order bug surfaced by the new Google path: the underlying genai SDK always injects its own v1beta version segment, so a proxy base URL that already carries a version (e.g. opencode's /zen/v1) produced a doubled /zen/v1/v1beta/... path that 404'd. A small URL-rewriting transport (mirroring the existing codexTransport pattern) strips the redundant segment only for versioned proxy base URLs; the native google/ path is untouched.

Before: kit -m opencode/gemini-3.5-flash "say hi"ERROR … @ai-sdk/google has no LLM provider mapping
After: routes through the Google wire and returns a real Gemini response.

Fixes #41

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change
  • Documentation update

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally (go test -race ./internal/models/..., golangci-lint run)
  • I have updated the documentation accordingly

Additional Information

Files changed:

  • internal/models/modelsdb.go — replace npmToLLMProvider with a wireProtocol type + 4-entry npmToWireProtocol map (bundle packages intentionally omitted; they have native top-level cases)
  • internal/models/providers.go — switch autoRouteProvider on wire protocol; add createAutoRoutedGoogleProvider and the geminiProxyTransport version-path fix; update CreateProvider godoc
  • internal/models/registry.goisProviderLLMSupported consults npmToWireProtocol
  • internal/models/autoroute_test.go — new regression tests for wire routing, error paths, and version-segment rewriting
  • README.md, www/pages/providers.md — document auto-routing by wire protocol

Backwards compatibility: All previously-working flows are preserved — the openai/anthropic/openaicompat cases collapse cleanly into their wire protocols, the unknown-npm→openai-compat fallback is retained, and native top-level provider cases are untouched. Verified end-to-end via CLI and the TUI /model picker.

Summary by CodeRabbit

  • New Features
    • Added automatic routing of providers from the models.dev database using the provider/model format.
    • Extended support for Google Gemini models alongside existing OpenAI and Anthropic providers.
    • Improved fallback behavior for unknown providers when an API URL is available.
  • Documentation
    • Added "Auto-routed Providers" section to README with routing details and example commands.
    • Updated providers guide explaining auto-routed provider selection and configuration.

- replace npmToLLMProvider map with npmToWireProtocol (openai/anthropic/google)
- add createAutoRoutedGoogleProvider so @ai-sdk/google proxies work
  (fixes opencode/gemini-* failing with "no LLM provider mapping")
- strip the genai-injected v1beta segment for proxies whose base URL
  already carries a version (e.g. opencode's /zen/v1)
- preserve openai-compat fallback and clearer error for unroutable providers
- document auto-routing in README and providers docs; update CreateProvider godoc
- add regression tests for wire routing and version-path rewriting

Fixes #41
@mark-iii-labs-huly
Copy link
Copy Markdown

Connected to Huly®: KIT-44

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements wire-protocol-based auto-routing for LLM providers, replacing direct npm-to-LLM-provider mappings with a wire-protocol abstraction. It adds Google Gemini support with a custom HTTP transport that normalizes proxy base paths, updates registry LLM support checks, and includes comprehensive tests and documentation.

Changes

Wire-Protocol Auto-Routing

Layer / File(s) Summary
Wire protocol contract and npm-to-protocol mapping
internal/models/modelsdb.go
Introduces wireProtocol enum (unknown/openai/anthropic/google) and npmToWireProtocol map routing npm packages to wire protocols, replacing the prior direct LLM-provider mapping model.
Auto-routing core logic by wire protocol
internal/models/providers.go
autoRouteProvider refactored to select npm packages with per-model overrides, map to wire protocol via npmToWireProtocol, dispatch to protocol-specific providers, fall back to OpenAI-compatible for unknown packages with API URLs, and set provider URLs from registry. Includes new imports for URL parsing and regex.
Google/Gemini auto-routed provider with proxy transport
internal/models/providers.go
createAutoRoutedGoogleProvider constructs Gemini-compatible providers and installs a custom HTTP transport that strips genai SDK–injected version segments when the proxy base URL already contains a version, preventing doubled paths. Includes version detection regex, base-path parsing, HTTP client construction, and request path rewriting utilities.
Registry LLM support eligibility by wire protocol
internal/models/registry.go
isProviderLLMSupported now checks npmToWireProtocol mapping instead of npmToLLMProvider to determine LLM eligibility for npm-based providers.
Wire-protocol routing and Gemini proxy tests
internal/models/autoroute_test.go
Comprehensive test suite validating wire-protocol mappings, auto-routing by default and per-model npm overrides (including Google override regression), error messaging, LLM support detection, URL version-path normalization, and Gemini proxy transport rewriting behavior.
User and developer documentation
README.md, www/pages/providers.md
Documentation explaining wire-protocol-based auto-routing from models.dev, npm-to-transport mapping, fallback behavior, per-model overrides, and CLI examples demonstrating routing to different wire protocols.

Sequence Diagram

sequenceDiagram
  participant AutoRoute as autoRouteProvider
  participant NPMMap as npmToWireProtocol
  participant Dispatch as Protocol Dispatcher
  participant OpenAI as createAutoRoutedOpenAIProvider
  participant Anthropic as createAutoRoutedAnthropicProvider
  participant Google as createAutoRoutedGoogleProvider
  participant Compat as createAutoRoutedOpenAICompatProvider
  AutoRoute->>NPMMap: Select npm, map to wireProtocol
  NPMMap-->>AutoRoute: wireProtocol enum
  AutoRoute->>Dispatch: Dispatch by protocol
  alt OpenAI wire
    Dispatch->>OpenAI: Create OpenAI provider
  else Anthropic wire
    Dispatch->>Anthropic: Create Anthropic provider
  else Google wire
    Dispatch->>Google: Create Google/Gemini provider
  else Unknown npm + API URL
    Dispatch->>Compat: Fall back to OpenAI-compatible
  else Unknown npm, no API URL
    Dispatch-->>AutoRoute: Error: unknown npm
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

🐰 A protocol maze, now wired so neat,
Wire to wire, each provider's beat,
Gemini proxies strip their excess load,
Auto-routing flows down a cleaner road,
Routes converge where unknown paths dare tread! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: refactoring provider auto-routing to dispatch on wire protocol instead of a flat npm package map, which directly addresses the PR's core objective of fixing auto-routing for providers like Google-backed Gemini models.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/41-autoroute-google-wire-protocol

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/models/autoroute_test.go (1)

17-42: ⚡ Quick win

Make the mapping regression guard exact.

This test checks the expected entries and a few forbidden ones, but it still passes if some other unintended package is added to npmToWireProtocol. Adding a size check here would make the contract precise and catch the same class of drift this test is meant to prevent.

Suggested change
 	want := map[string]wireProtocol{
 		"`@ai-sdk/openai`":            wireOpenAI,
 		"`@ai-sdk/openai-compatible`": wireOpenAI,
 		"`@ai-sdk/anthropic`":         wireAnthropic,
 		"`@ai-sdk/google`":            wireGoogle,
 	}
+	if len(npmToWireProtocol) != len(want) {
+		t.Fatalf("npmToWireProtocol has %d entries, want %d", len(npmToWireProtocol), len(want))
+	}
 	for npm, wire := range want {
 		if got := npmToWireProtocol[npm]; got != wire {
 			t.Errorf("npmToWireProtocol[%q] = %d, want %d", npm, got, wire)
 		}
 	}
-
-	// Bundle packages must NOT be in the table (regression guard against the
-	// old npmToLLMProvider map that listed 10 entries but only handled 3).
-	for _, npm := range []string{
-		"`@ai-sdk/google-vertex`",
-		"`@ai-sdk/google-vertex/anthropic`",
-		"`@ai-sdk/amazon-bedrock`",
-		"`@ai-sdk/azure`",
-		"`@openrouter/ai-sdk-provider`",
-		"`@ai-sdk/vercel`",
-	} {
-		if _, ok := npmToWireProtocol[npm]; ok {
-			t.Errorf("npmToWireProtocol unexpectedly contains bundle package %q", npm)
-		}
-	}
🤖 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 `@internal/models/autoroute_test.go` around lines 17 - 42, The test should
assert the exact size of the npmToWireProtocol map to prevent unexpected
entries; after verifying the specific expected keys (wireOpenAI, wireAnthropic,
wireGoogle) and ensuring the forbidden bundle keys are absent, add a length
check like: compare len(npmToWireProtocol) to the number of expected entries
(len(want)) and fail the test if they differ so the test fails when any extra
mapping is added.
🤖 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.

Nitpick comments:
In `@internal/models/autoroute_test.go`:
- Around line 17-42: The test should assert the exact size of the
npmToWireProtocol map to prevent unexpected entries; after verifying the
specific expected keys (wireOpenAI, wireAnthropic, wireGoogle) and ensuring the
forbidden bundle keys are absent, add a length check like: compare
len(npmToWireProtocol) to the number of expected entries (len(want)) and fail
the test if they differ so the test fails when any extra mapping is added.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 556e5eb4-9f36-4858-9855-5ce749e35ba0

📥 Commits

Reviewing files that changed from the base of the PR and between 7a04bdf and 10abb29.

📒 Files selected for processing (6)
  • README.md
  • internal/models/autoroute_test.go
  • internal/models/modelsdb.go
  • internal/models/providers.go
  • internal/models/registry.go
  • www/pages/providers.md

@ezynda3 ezynda3 merged commit ae722d5 into master Jun 2, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

autoRouteProvider fails for any non-OpenAI/Anthropic npm mapping (breaks opencode/gemini-*, plus 5 other providers); TUI hides the error

1 participant