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. Co-authored-by: Test <test@test.com>
This commit is contained in:
parent
04b6ecadc4
commit
4c0c7f4c6e
3 changed files with 34 additions and 2 deletions
10
cli.py
10
cli.py
|
|
@ -973,6 +973,8 @@ def save_config_value(key_path: str, value: any) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# HermesCLI Class
|
# HermesCLI Class
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
@ -2890,6 +2892,14 @@ class HermesCLI:
|
||||||
for mid, desc in curated:
|
for mid, desc in curated:
|
||||||
current_marker = " ← current" if (is_active and mid == self.model) else ""
|
current_marker = " ← current" if (is_active and mid == self.model) else ""
|
||||||
print(f" {mid}{current_marker}")
|
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:
|
else:
|
||||||
print(f" (use /model {p['id']}:<model-name>)")
|
print(f" (use /model {p['id']}:<model-name>)")
|
||||||
print()
|
print()
|
||||||
|
|
|
||||||
|
|
@ -2380,8 +2380,14 @@ class GatewayRunner:
|
||||||
lines = [
|
lines = [
|
||||||
f"🤖 **Current model:** `{current}`",
|
f"🤖 **Current model:** `{current}`",
|
||||||
f"**Provider:** {provider_label}",
|
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)
|
curated = curated_models_for_provider(current_provider)
|
||||||
if curated:
|
if curated:
|
||||||
lines.append(f"**Available models ({provider_label}):**")
|
lines.append(f"**Available models ({provider_label}):**")
|
||||||
|
|
@ -2391,7 +2397,7 @@ class GatewayRunner:
|
||||||
lines.append(f"• `{mid}`{label}{marker}")
|
lines.append(f"• `{mid}`{label}{marker}")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("To change: `/model model-name`")
|
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)
|
return "\n".join(lines)
|
||||||
|
|
||||||
# Parse provider:model syntax
|
# Parse provider:model syntax
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,7 @@ def detect_provider_for_model(
|
||||||
Returns ``None`` when no confident match is found.
|
Returns ``None`` when no confident match is found.
|
||||||
|
|
||||||
Priority:
|
Priority:
|
||||||
|
0. Bare provider name → switch to that provider's default model
|
||||||
1. Direct provider with credentials (highest)
|
1. Direct provider with credentials (highest)
|
||||||
2. Direct provider without credentials → remap to OpenRouter slug
|
2. Direct provider without credentials → remap to OpenRouter slug
|
||||||
3. OpenRouter catalog match
|
3. OpenRouter catalog match
|
||||||
|
|
@ -399,6 +400,21 @@ def detect_provider_for_model(
|
||||||
|
|
||||||
name_lower = name.lower()
|
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 list other providers' models — never auto-switch TO them
|
||||||
_AGGREGATORS = {"nous", "openrouter"}
|
_AGGREGATORS = {"nous", "openrouter"}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue