Compare commits

...

1 Commits

Author SHA1 Message Date
Test
bd774d5495 fix: /model command — bare provider names, custom endpoint display
Two issues with /model preventing proper provider switching:

1. Bare provider names not detected: typing '/model nous' treated 'nous'
   as a model name instead of triggering a provider switch. Fixed by adding
   step 0 in detect_provider_for_model() that checks if the input matches
   a known provider name/alias (excluding 'custom'/'openrouter' which need
   explicit model names) and returns that provider's default model.

2. Custom endpoint details hidden: /model (no args) showed '[custom]' with
   just a usage hint but no endpoint URL or model name. Now displays the
   configured base_url for custom providers in both CLI and gateway.

Note: config base_url and OPENAI_BASE_URL are intentionally NOT cleared on
provider switch — dedicated provider paths (nous, anthropic, codex) have
their own credential resolution that ignores these, and clearing them would
destroy the user's custom endpoint config, preventing switching back.
2026-03-19 11:53:40 -07:00
3 changed files with 34 additions and 2 deletions

10
cli.py
View File

@@ -973,6 +973,8 @@ def save_config_value(key_path: str, value: any) -> bool:
return False
# ============================================================================
# HermesCLI Class
# ============================================================================
@@ -2890,6 +2892,14 @@ class HermesCLI:
for mid, desc in curated:
current_marker = " ← current" if (is_active and mid == self.model) else ""
print(f" {mid}{current_marker}")
elif p["id"] == "custom":
from hermes_cli.models import _get_custom_base_url
custom_url = _get_custom_base_url() or os.getenv("OPENAI_BASE_URL", "")
if custom_url:
print(f" endpoint: {custom_url}")
if is_active:
print(f" model: {self.model} ← current")
print(f" (use /model custom:<model-name>)")
else:
print(f" (use /model {p['id']}:<model-name>)")
print()

View File

@@ -2380,8 +2380,14 @@ class GatewayRunner:
lines = [
f"🤖 **Current model:** `{current}`",
f"**Provider:** {provider_label}",
"",
]
# Show custom endpoint URL when using a custom provider
if current_provider == "custom":
from hermes_cli.models import _get_custom_base_url
custom_url = _get_custom_base_url() or os.getenv("OPENAI_BASE_URL", "")
if custom_url:
lines.append(f"**Endpoint:** `{custom_url}`")
lines.append("")
curated = curated_models_for_provider(current_provider)
if curated:
lines.append(f"**Available models ({provider_label}):**")
@@ -2391,7 +2397,7 @@ class GatewayRunner:
lines.append(f"• `{mid}`{label}{marker}")
lines.append("")
lines.append("To change: `/model model-name`")
lines.append("Switch provider: `/model provider:model-name`")
lines.append("Switch provider: `/model provider-name` or `/model provider:model-name`")
return "\n".join(lines)
# Parse provider:model syntax

View File

@@ -389,6 +389,7 @@ def detect_provider_for_model(
Returns ``None`` when no confident match is found.
Priority:
0. Bare provider name → switch to that provider's default model
1. Direct provider with credentials (highest)
2. Direct provider without credentials → remap to OpenRouter slug
3. OpenRouter catalog match
@@ -399,6 +400,21 @@ def detect_provider_for_model(
name_lower = name.lower()
# --- Step 0: bare provider name typed as model ---
# If someone types `/model nous` or `/model anthropic`, treat it as a
# provider switch and pick the first model from that provider's catalog.
# Skip "custom" and "openrouter" — custom has no model catalog, and
# openrouter requires an explicit model name to be useful.
resolved_provider = _PROVIDER_ALIASES.get(name_lower, name_lower)
if resolved_provider not in {"custom", "openrouter"}:
default_models = _PROVIDER_MODELS.get(resolved_provider, [])
if (
resolved_provider in _PROVIDER_LABELS
and default_models
and resolved_provider != normalize_provider(current_provider)
):
return (resolved_provider, default_models[0])
# Aggregators list other providers' models — never auto-switch TO them
_AGGREGATORS = {"nous", "openrouter"}