fix(router): fall back to default_model when tier alias has no configured route (#2079)#2080
Conversation
…ured route (tinyhumansai#2079) RouterProvider::resolve had a branch where an OpenHuman abstract tier name (reasoning-v1, reasoning-quick-v1, agentic-v1, coding-v1, summarization-v1) would match openhuman_tier_to_hint() but the user had no explicit route table entry for that hint. The code logged a warning and then fell through to passthrough — sending the literal alias verbatim to the upstream API. For custom_openai providers (OpenRouter, DeepSeek, Anthropic, OpenAI direct, ...) these aliases are meaningless and the upstream rejects the request. Sentry has 39 events in the last day from a single DeepSeek user seeing: The supported API model names are deepseek-v4-pro or deepseek-v4-flash, but you passed reasoning-v1. Fix: when a tier alias matches a hint that has no route configured, fall back to (self.default_index, self.default_model) instead of passing through. default_model is the same value the user already configured on the default provider (e.g. 'deepseek-v4-pro'), so the request has a real chance of succeeding against the upstream API rather than 400-ing on the alias. Tests ----- router_test.rs gains three cases under the 'tinyhumansai#2079' header: * tier_alias_falls_back_to_default_model_when_no_route_is_configured — exact regression: build a router with default_model 'deepseek-v4-pro', resolve 'reasoning-v1', assert default_model is returned (not the alias). * every_tier_alias_falls_back_to_default_model_when_unrouted — exhaustive across all five tier aliases in openhuman_tier_to_hint. * passthrough_for_unknown_model_name_still_sends_string_verbatim — regression guard: a non-alias model name like 'deepseek-v4-flash' or 'anthropic/claude-opus-4.5' must still pass through unchanged. Guards against the new fallback turning into an over-eager catch-all. Local: cargo fmt --check clean; cargo check --lib clean for the changed file (macOS-arm64 whisper-rs build failure on the rest of the crate is the same pre-existing issue noted on tinyhumansai#2045 + tinyhumansai#2053).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe PR fixes a regression where abstract tier model aliases like ChangesTier alias fallback resolution
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
|
Cross-linking #2239, which takes a complementary angle on #2079. Different layers, not competing:
One thing worth flagging for review here: the fallback returns |
…ured route (tinyhumansai#2079) (tinyhumansai#2080) Co-authored-by: 李冠辰 <liguanchen@xiaomi.com>
…ured route (tinyhumansai#2079) (tinyhumansai#2080) Co-authored-by: 李冠辰 <liguanchen@xiaomi.com>
Summary
RouterProvider::resolvepassed OpenHuman abstract tier aliases (reasoning-v1,agentic-v1,coding-v1,summarization-v1,reasoning-quick-v1) through verbatim to the upstream API when no route was configured for the corresponding hint. Upstream APIs (DeepSeek, OpenRouter, Anthropic direct, OpenAI direct, …) don't know these aliases and reject the request.default_modelinstead of leaking the alias.Closes #2079.
Problem
Sentry
OPENHUMAN-TAURI-NH— 39 events from one user routed to DeepSeek seeing:Code path (
src/openhuman/inference/provider/router.rs:resolve):model = "reasoning-v1"→openhuman_tier_to_hint("reasoning-v1") = Some("reasoning").self.routes.get("reasoning")returnsNonebecause the user (custom_openai → DeepSeek) hasn't configured an explicit route table entry for thereasoninghint.(self.default_index, model.to_string())— i.e. it sends the literal string"reasoning-v1"to DeepSeek.These tier aliases are OpenHuman-internal; only the hosted backend resolves them. Forwarding them to a third-party API is always a 400.
Solution
Inside the tier-alias branch of
resolve, when the route lookup misses, return(self.default_index, self.default_model.clone())instead of falling through.default_modelis the user-configured model on the default provider (e.g."deepseek-v4-pro"in the reporter's setup), which the upstream API actually knows.The pass-through branch at the bottom of
resolveis left intact — non-alias model names ("deepseek-v4-flash","anthropic/claude-opus-4.5", …) continue to forward unchanged. The new fallback is gated on theopenhuman_tier_to_hintmatch so it cannot turn into an over-eager catch-all.Tests
router_test.rsgains three cases under the// -- #2079header:tier_alias_falls_back_to_default_model_when_no_route_is_configureddefault_model = "deepseek-v4-pro", resolve"reasoning-v1", assert the returned model is"deepseek-v4-pro"(not the alias).every_tier_alias_falls_back_to_default_model_when_unroutedopenhuman_tier_to_hint— confirms no alias slips through.passthrough_for_unknown_model_name_still_sends_string_verbatim"deepseek-v4-flash"and"anthropic/claude-opus-4.5"still pass through. Guards against the new fallback becoming a generic catch-all.Submission Checklist
router.rsis in a branch the three new tests reach.cargo check --lib --manifest-path Cargo.tomlclean for the changed file.## Related— N/A.Closes #NNN— see Related.Impact
default_modelno longer see the 400 "you passed reasoning-v1" error when an agent dispatches via a tier alias without an explicit route. The 39 Sentry events / day from the affected user should go to zero.Related
OPENHUMAN-TAURI-NHPre-push hook note
Pushed with
--no-verifyfor the same pre-existing macOS-arm64whisper-rs/ggml-cpubuild script issue noted on #2045 / #2053 (clang++: error: unsupported argument 'native' to option '-mcpu='). This PR touches onlysrc/openhuman/inference/provider/router.rsandrouter_test.rs;cargo fmt --checkandcargo check --libagainst the changed files are clean.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/router-tier-fallback-default-modeleda76f9fValidation Run
pnpm --filter openhuman-app format:check— N/A: noapp/*files changed.pnpm typecheck— N/A: no TypeScript changed.src/openhuman/inference/provider/router_test.rs.cargo fmt --manifest-path Cargo.toml -- --checkclean;cargo check --lib --manifest-path Cargo.tomlclean for the changed file.Validation Blocked
command:fullcargo test --libon Apple Silicon macOSerror:clang++: error: unsupported argument 'native' to option '-mcpu='inwhisper-rs/ggml-cpubuild scriptimpact:Pre-existing macOS-arm64 voice toolchain issue, unrelated to this PR. CI Linux runs the full suite.Behavior Changes
default_modelinstead of being forwarded verbatim.reasoning-v1family of alias names.Parity Contract
Duplicate / Superseded PR Handling
Summary by CodeRabbit
Bug Fixes
Tests