feat(model): /model command overhaul — Phases 2, 3, 5

* feat(model): persist base_url on /model switch, auto-detect for bare /model custom

Phase 2+3 of the /model command overhaul:

Phase 2 — Persist base_url on model switch:
- CLI: save model.base_url when switching to a non-OpenRouter endpoint;
  clear it when switching away from custom to prevent stale URLs
  leaking into the new provider's resolution
- Gateway: same logic using direct YAML write

Phase 3 — Better feedback and edge cases:
- Bare '/model custom' now auto-detects the model from the endpoint
  using _auto_detect_local_model() and saves all three config values
  (model, provider, base_url) atomically
- Shows endpoint URL in success messages when switching to/from
  custom providers (both CLI and gateway)
- Clear error messages when no custom endpoint is configured
- Updated test assertions for the additional save_config_value call

Fixes #2562 (Phase 2+3)

* feat(model): support custom:name:model triple syntax for named custom providers

Phase 5 of the /model command overhaul.

Extends parse_model_input() to handle the triple syntax:
  /model custom:local-server:qwen → provider='custom:local-server', model='qwen'
  /model custom:my-model          → provider='custom', model='my-model' (unchanged)

The 'custom:local-server' provider string is already supported by
_get_named_custom_provider() in runtime_provider.py, which matches
it against the custom_providers list in config.yaml. This just wires
the parsing so users can do it from the /model slash command.

Added 4 tests covering single, triple, whitespace, and empty model cases.
This commit is contained in:
Teknium 2026-03-24 06:58:04 -07:00 committed by GitHub
parent 2f1c4fb01f
commit b641ee88f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 166 additions and 15 deletions

View file

@ -111,8 +111,13 @@ class TestModelCommand:
assert cli_obj.model == "glm-5"
assert cli_obj.provider == "zai"
assert cli_obj.base_url == "https://api.z.ai/api/paas/v4"
# Both model and provider should be saved
assert save_mock.call_count == 2
# Model, provider, and base_url should be saved
assert save_mock.call_count == 3
save_calls = [c.args for c in save_mock.call_args_list]
assert ("model.default", "glm-5") in save_calls
assert ("model.provider", "zai") in save_calls
# base_url is also persisted on provider change (Phase 2 fix)
assert any(c[0] == "model.base_url" for c in save_calls)
def test_provider_switch_fails_on_bad_credentials(self, capsys):
cli_obj = self._make_cli()