/model picker is unusable for users with 5+ custom providers
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 19.9k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 30
Description
/model picker is unusable for users with 5+ custom providers
TL;DR
The model picker is designed for users who want the entire global catalog (500+ models). Users who configure a small set of custom providers (e.g. 5 openai-compatible servers) get a picker that is:
- Flooded with 504 fallback routes (
api_method="remote-catalog") on the current provider — the picker shows 504 entries even when the user only has 5 configured providers - Filter bypassed —
model_picker_providersmatches routes byproviderfield, but fallback routes use the current provider as the transport, so they pass the filter - Intercepts Enter even when the user has typed
/model <name>in the input bar — the picker picks whatever is at row 0 instead of executing the command - No aliases —
NamedProviderConfighas noaliasfield, so users can't type/model llama1to switch to a long-path local model - Layout breaks when the picker renders into a narrow area — 3-column box rendered into a 20-character area
This is not a "small terminal" problem. The picker is broken on any terminal width when the user has 5+ custom providers configured.
Reproduction
config.toml:
default_provider = "minimax-m3"
[provider]
model_picker_providers = ["llama-local", "llama-qwen35", "minimax-m3", "openrouter-ai", "nicho8083"]
[providers.llama-local]
type = "open-ai-compatible"
base_url = "http://192.168.2.111:8081/v1"
api_key_env = "..."
[providers.llama-qwen35]
type = "open-ai-compatible"
base_url = "http://192.168.2.111:8082/v1"
api_key_env = "..."
[providers.minimax-m3]
type = "open-ai-compatible"
base_url = "https://api.minimax.io/v1"
api_key_env = "OPENAI_API_KEY"
[providers.openrouter-ai]
type = "open-ai-compatible"
base_url = "https://openrouter.ai/api/v1"
api_key_env = "OPENROUTER_API_KEY"
[providers.nicho8083]
type = "openai-compatible"
base_url = "http://192.168.2.111:8083/v1"
api_key_env = "..."
Expected: /model shows ~7 routes (one per provider, plus 2-3 extra models per openrouter-style provider).
Actual: /model shows 504 routes.
Root cause for the 504-entry flood
crates/jcode-tui/src/tui/app/inline_interactive.rs:228 (filter_routes_by_provider_allowlist):
let route_matches = |route: &crate::provider::ModelRoute| -> bool {
let provider = normalize(&route.provider);
let api_method = normalize(&route.api_method);
let profile_id = route.api_method.split_once(':').map(|(_, profile)| normalize(profile)).unwrap_or_default();
allowed.iter().any(|entry| {
*entry == provider
|| *entry == api_method
|| (!profile_id.is_empty() && *entry == profile_id)
|| crate::provider::model_route_provider_labels_match(&route.provider, entry)
})
};
The filter matches by provider field. The fallback routes (crates/jcode-base/src/provider/catalog_routes.rs:1060) are created with provider = current_provider_name, so allowlist = ["llama-qwen35", ...] lets every fallback route with provider="llama-qwen35" pass through.
Workaround: change the filter to use full api_method strings:
model_picker_providers = ["openai-compatible:llama-local", "openai-compatible:llama-qwen35", ...]
This works because the fallback routes have api_method="remote-catalog", which doesn't match any of the real openai-compatible api_methods.
Bugs to fix
1. Filter matches fallback routes
Fix: exclude fallback routes by default. The filter should match only real routes, not placeholders.
allowed.iter().any(|entry| {
!route.is_placeholder()
&& (*entry == provider || *entry == api_method || ...)
})
2. Picker intercepts Enter with command in input
When the picker is open and the user has /model poolside/laguna-s-2.1:free in the input bar, pressing Enter does NOT execute the command. Instead, it picks the currently selected entry in the picker (which is whatever was at row 0, likely the current model).
Fix: when the input has a complete command (/model <name>), Enter should execute the command even if the picker is open. Or, close the picker when the user types a space after /model.
3. No aliases for short names
Users with long model paths (e.g. C:\models\Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.gguf) can't type /model llama1 to switch. The NamedProviderConfig struct (crates/jcode-config-types/src/lib.rs:425) has no alias field.
Fix: add an alias field to NamedProviderConfig. The picker should show the alias instead of the provider name.
4. Picker layout breaks on narrow areas
crates/jcode-tui/src/tui/ui_inline_interactive.rs:445: Block::default().borders(Borders::ALL) doesn't check if inner.width is enough for the column layout. Result: 3-column box rendered into a 20-character area, even when the rest of the terminal has plenty of space.
Fix: when inner.width < needed_width, either:
- Render a single-column vertical list
- Or refuse to draw and show "resize terminal" message
Severity
The picker is the primary way users switch between providers. Five hours of debugging a 5-provider setup is not acceptable. Comparable tools (OpenCode, Hermes, Claude Code, OMP) don't have this problem — they show only the user's configured routes, or they have a clear "favorites only" mode.
Environment
- jcode v0.75.3
- cli: client mode (not remote)
- providers: 3 local llama.cpp servers, 2 openai-compatible remote (minimax-m3, openrouter-ai)
- terminal: 80+ cols
Suggested fix priority
- Filter excludes fallback routes (one-line fix)
- Enter on input command bypasses picker (small interaction refactor)
- Aliases for short names (one field on NamedProviderConfig)
- Picker refuses to render when too narrow (one-line fix)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with filter_routes_by_provider_allowlist in crates/jcode-tui/src/tui/app/inline_interactive.rs and the fallback route creation in crates/jcode-base/src/provider/catalog_routes.rs. Then inspect NamedProviderConfig in crates/jcode-config-types/src/lib.rs and picker rendering in crates/jcode-tui/src/tui/ui_inline_interactive.rs. Done means configured providers no longer expose fallback floods, complete /model commands execute, aliases work, and narrow layouts remain usable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100