Type: Bug
Version: v0.68.0
Severity: High (models become unselectable in /model for hours at a time)
Summary
In remote sessions, models whose ids contain / (e.g. vendouple/gpt-5.6-sol, MarcosFRG/deepseek-v4-pro, gggff123/glm-5.2) get classified as OpenRouter "auto" routes and rendered with a × (unavailable) in the picker, which hard-blocks selection. This happens even when a configured OpenAI-compatible profile (pollinations, opencode zen, etc.) has the exact model id in its live catalog and the server can serve it fine.
Repro context
- jcode running in remote mode (
remote=true on every model_picker_open event in the log).
- Providers are configured as OpenAI-compatible profiles (
pollinations, opencode_zen, nvidia_nim, ...) with live model catalogs.
- No
OPENROUTER_API_KEY is set locally (the models come from the configured profiles, not OpenRouter).
Observed behavior (from ~/.jcode/logs/jcode-2026-08-07.log)
Same session, two picker states:
| State |
model_picker_open event |
Available |
| Full catalog (detailed routes attached) |
entries=751 entries_available=532 (13:00–14:53) |
Mostly selectable |
| Names-only catalog (no route frame) |
entries=1225 entries_available=243, by_provider=auto:804 (12:43) |
804 slash-model rows X'd |
| Names-only catalog (no route frame) |
entries=1528 entries_available=275, by_provider=auto:1074 (23:30) |
1074 slash-model rows X'd |
The pattern "models get X'd after a few hours": the session runs on the good full catalog, then a names-only catalog update/refresh race drops the detailed route frame, the picker falls back to remote_model_routes_fallback, and every slash-prefixed model becomes unselectable.
Root cause
jcode-base/src/provider/catalog_routes.rs, remote_model_routes_fallback (lines 841–1053):
- Any model id containing
/ is assumed to be an OpenRouter model (lines 892–920): it's routed to build_openrouter_auto_route(model, auth.openrouter != AuthState::NotConfigured, ...), so with no local OPENROUTER_API_KEY the route is available: false with no detail.
- That branch
continues before remote_openai_compatible_route_for_model(model) (line 1006) is ever consulted, so a configured profile whose live catalog contains the exact id is never given a chance to produce an available route.
remote_current_openai_compatible_route_for_model (lines 1102–1127) also bails on /-containing ids (if model.contains('/') { return None }), so the "current provider" fallback can't help either.
- The TUI then hard-blocks selection on any
!route.available row: jcode-tui/src/tui/app/inline_interactive.rs lines 3348–3359 (PickerAction::Model → unavailable_model_route_message → "Model unavailable"), with the × rendered by picker_row_marker in jcode-tui/src/tui/ui_inline_interactive.rs lines 115–125.
The client mislabels working models as unconfigured OpenRouter purely because of the / heuristic; the server-side catalog (pollinations, opencode zen) contains them and serves them fine.
Suggested fix
In remote_model_routes_fallback, before the model.contains('/') → build_openrouter_auto_route branch, consult remote_openai_compatible_route_for_model(model) first:
- If a configured profile's live cache (or static model list) contains the exact id → emit that profile's route with
available: true and continue.
- Only fall back to the OpenRouter "auto" route when no profile matches (and mark unavailable only then, if OpenRouter is genuinely unconfigured).
Also relax remote_current_openai_compatible_route_for_model so slash-ids are matched when the current provider profile's catalog actually contains them (instead of blanket-skipping all / ids).
Optionally: consider not hard-blocking selection on !available rows — show the reason but still let the user attempt the switch when a route exists (the server is the real authority on whether a model is servable).
Workarounds (no rebuild needed)
- Type
/model <name> instead of using the picker — the typed path (backend.rs:692, Request::SetModel) sends the bare id to the server with no availability gate.
- Set a dummy
OPENROUTER_API_KEY locally — the availability check is presence-only, so the picker rows flip to selectable; the dummy key is never used since selection still sends the bare model id.
Type: Bug
Version: v0.68.0
Severity: High (models become unselectable in
/modelfor hours at a time)Summary
In remote sessions, models whose ids contain
/(e.g.vendouple/gpt-5.6-sol,MarcosFRG/deepseek-v4-pro,gggff123/glm-5.2) get classified as OpenRouter "auto" routes and rendered with a × (unavailable) in the picker, which hard-blocks selection. This happens even when a configured OpenAI-compatible profile (pollinations, opencode zen, etc.) has the exact model id in its live catalog and the server can serve it fine.Repro context
remote=trueon everymodel_picker_openevent in the log).pollinations,opencode_zen,nvidia_nim, ...) with live model catalogs.OPENROUTER_API_KEYis set locally (the models come from the configured profiles, not OpenRouter).Observed behavior (from
~/.jcode/logs/jcode-2026-08-07.log)Same session, two picker states:
model_picker_openevententries=751 entries_available=532(13:00–14:53)entries=1225 entries_available=243,by_provider=auto:804(12:43)entries=1528 entries_available=275,by_provider=auto:1074(23:30)The pattern "models get X'd after a few hours": the session runs on the good full catalog, then a names-only catalog update/refresh race drops the detailed route frame, the picker falls back to
remote_model_routes_fallback, and every slash-prefixed model becomes unselectable.Root cause
jcode-base/src/provider/catalog_routes.rs,remote_model_routes_fallback(lines 841–1053):/is assumed to be an OpenRouter model (lines 892–920): it's routed tobuild_openrouter_auto_route(model, auth.openrouter != AuthState::NotConfigured, ...), so with no localOPENROUTER_API_KEYthe route isavailable: falsewith no detail.continues beforeremote_openai_compatible_route_for_model(model)(line 1006) is ever consulted, so a configured profile whose live catalog contains the exact id is never given a chance to produce an available route.remote_current_openai_compatible_route_for_model(lines 1102–1127) also bails on/-containing ids (if model.contains('/') { return None }), so the "current provider" fallback can't help either.!route.availablerow:jcode-tui/src/tui/app/inline_interactive.rslines 3348–3359 (PickerAction::Model→unavailable_model_route_message→ "Model unavailable"), with the × rendered bypicker_row_markerinjcode-tui/src/tui/ui_inline_interactive.rslines 115–125.The client mislabels working models as unconfigured OpenRouter purely because of the
/heuristic; the server-side catalog (pollinations, opencode zen) contains them and serves them fine.Suggested fix
In
remote_model_routes_fallback, before themodel.contains('/')→build_openrouter_auto_routebranch, consultremote_openai_compatible_route_for_model(model)first:available: trueandcontinue.Also relax
remote_current_openai_compatible_route_for_modelso slash-ids are matched when the current provider profile's catalog actually contains them (instead of blanket-skipping all/ids).Optionally: consider not hard-blocking selection on
!availablerows — show the reason but still let the user attempt the switch when a route exists (the server is the real authority on whether a model is servable).Workarounds (no rebuild needed)
/model <name>instead of using the picker — the typed path (backend.rs:692,Request::SetModel) sends the bare id to the server with no availability gate.OPENROUTER_API_KEYlocally — the availability check is presence-only, so the picker rows flip to selectable; the dummy key is never used since selection still sends the bare model id.