feat: enhance README and CLI with multi-provider model selection
- Added a comprehensive "Getting Started" section in the README to guide users through selecting inference providers. - Implemented an interactive model selection feature in the CLI, allowing users to choose from available models or enter a custom model name. - Improved user experience by displaying the current model and active provider during selection, with clear instructions for each provider type. - Updated the model selection process to prioritize the currently active model, enhancing usability and clarity.
This commit is contained in:
parent
f6daceb449
commit
77a3dda59d
3 changed files with 362 additions and 40 deletions
64
README.md
64
README.md
|
|
@ -31,6 +31,33 @@ hermes # Start chatting!
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Hermes supports multiple inference providers. Pick one to get going:
|
||||||
|
|
||||||
|
**Option A — Nous Portal (subscription):**
|
||||||
|
```bash
|
||||||
|
hermes login # Opens browser to authenticate with Nous Portal
|
||||||
|
hermes # Start chatting!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B — OpenRouter (pay-per-use, 100+ models):**
|
||||||
|
```bash
|
||||||
|
hermes model # Interactive provider & model selector
|
||||||
|
# → choose OpenRouter, paste your API key, pick a model
|
||||||
|
hermes # Start chatting!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option C — Custom endpoint (VLLM, SGLang, etc.):**
|
||||||
|
```bash
|
||||||
|
hermes model # → choose Custom endpoint, enter URL + API key + model name
|
||||||
|
hermes # Start chatting!
|
||||||
|
```
|
||||||
|
|
||||||
|
You can switch providers and models at any time with `hermes model`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|
||||||
**Quick update (installer version):**
|
**Quick update (installer version):**
|
||||||
|
|
@ -117,23 +144,15 @@ hermes config set OPENROUTER_API_KEY sk-or-... # Saves to .env
|
||||||
|
|
||||||
### Inference Providers
|
### Inference Providers
|
||||||
|
|
||||||
You need at least one way to connect to an LLM:
|
You need at least one way to connect to an LLM. Use `hermes model` to switch providers and models interactively, or configure directly:
|
||||||
|
|
||||||
| Method | Description | Setup |
|
| Provider | Setup |
|
||||||
|--------|-------------|-------|
|
|----------|-------|
|
||||||
| **Nous Portal** | Nous Research subscription with OAuth login | `hermes login` |
|
| **Nous Portal** | `hermes login` (OAuth, subscription-based) |
|
||||||
| **OpenRouter** (recommended for flexibility) | Pay-per-use access to 100+ models | `OPENROUTER_API_KEY` in `.env` |
|
| **OpenRouter** | `OPENROUTER_API_KEY` in `~/.hermes/.env` |
|
||||||
| **Custom Endpoint** | Any OpenAI-compatible API (VLLM, SGLang, etc.) | `OPENAI_BASE_URL` + `OPENAI_API_KEY` in `.env` |
|
| **Custom Endpoint** | `OPENAI_BASE_URL` + `OPENAI_API_KEY` in `~/.hermes/.env` |
|
||||||
|
|
||||||
The setup wizard (`hermes setup`) walks you through choosing a provider. You can also log in directly:
|
**Note:** Even when using Nous Portal or a custom endpoint, some tools (vision, web summarization, MoA) use OpenRouter independently. An `OPENROUTER_API_KEY` enables these tools.
|
||||||
|
|
||||||
```bash
|
|
||||||
hermes login # Authenticate with Nous Portal
|
|
||||||
hermes login --provider nous # Same, explicit
|
|
||||||
hermes logout # Clear stored credentials
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** Even when using Nous Portal or a custom endpoint as your main provider, some tools (vision analysis, web summarization, Mixture of Agents) use OpenRouter independently. Adding an `OPENROUTER_API_KEY` enables these tools.
|
|
||||||
|
|
||||||
### Optional API Keys
|
### Optional API Keys
|
||||||
|
|
||||||
|
|
@ -281,19 +300,28 @@ See [docs/messaging.md](docs/messaging.md) for WhatsApp and advanced setup.
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Chat
|
||||||
hermes # Interactive chat (default)
|
hermes # Interactive chat (default)
|
||||||
hermes chat -q "Hello" # Single query mode
|
hermes chat -q "Hello" # Single query mode
|
||||||
hermes chat --provider nous # Chat using Nous Portal
|
|
||||||
hermes setup # Configure provider, API keys, and settings
|
# Provider & model management
|
||||||
|
hermes model # Switch provider and model interactively
|
||||||
hermes login # Authenticate with Nous Portal (OAuth)
|
hermes login # Authenticate with Nous Portal (OAuth)
|
||||||
hermes logout # Clear stored OAuth credentials
|
hermes logout # Clear stored OAuth credentials
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
hermes setup # Full setup wizard (provider, terminal, messaging, etc.)
|
||||||
hermes config # View/edit configuration
|
hermes config # View/edit configuration
|
||||||
hermes config check # Check for missing config (useful after updates)
|
hermes config check # Check for missing config (useful after updates)
|
||||||
hermes config migrate # Interactively add missing options
|
hermes config migrate # Interactively add missing options
|
||||||
hermes status # Show configuration status (incl. auth)
|
hermes status # Show configuration status (incl. auth)
|
||||||
hermes doctor # Diagnose issues
|
hermes doctor # Diagnose issues
|
||||||
hermes update # Update to latest version (prompts for new config)
|
|
||||||
|
# Maintenance
|
||||||
|
hermes update # Update to latest version
|
||||||
hermes uninstall # Uninstall (can keep configs for later reinstall)
|
hermes uninstall # Uninstall (can keep configs for later reinstall)
|
||||||
|
|
||||||
|
# Messaging, skills, cron
|
||||||
hermes gateway # Start messaging gateway
|
hermes gateway # Start messaging gateway
|
||||||
hermes skills search k8s # Search skill registries
|
hermes skills search k8s # Search skill registries
|
||||||
hermes skills install ... # Install a skill (with security scan)
|
hermes skills install ... # Install a skill (with security scan)
|
||||||
|
|
|
||||||
|
|
@ -851,24 +851,34 @@ def _reset_config_provider() -> Path:
|
||||||
return config_path
|
return config_path
|
||||||
|
|
||||||
|
|
||||||
def _prompt_model_selection(model_ids: List[str]) -> Optional[str]:
|
def _prompt_model_selection(model_ids: List[str], current_model: str = "") -> Optional[str]:
|
||||||
"""Interactive model selection after login. Returns chosen model ID or None."""
|
"""Interactive model selection. Puts current_model first with a marker. Returns chosen model ID or None."""
|
||||||
print(f"Available models ({len(model_ids)}):")
|
# Reorder: current model first, then the rest (deduplicated)
|
||||||
for i, mid in enumerate(model_ids, 1):
|
ordered = []
|
||||||
print(f" {i}. {mid}")
|
if current_model and current_model in model_ids:
|
||||||
print(f" {len(model_ids) + 1}. Custom model name")
|
ordered.append(current_model)
|
||||||
print(f" {len(model_ids) + 2}. Skip (keep current)")
|
for mid in model_ids:
|
||||||
print()
|
if mid not in ordered:
|
||||||
|
ordered.append(mid)
|
||||||
|
|
||||||
|
# Build display labels with marker on current
|
||||||
|
def _label(mid):
|
||||||
|
if mid == current_model:
|
||||||
|
return f"{mid} ← currently in use"
|
||||||
|
return mid
|
||||||
|
|
||||||
|
# Default cursor on the current model (index 0 if it was reordered to top)
|
||||||
|
default_idx = 0
|
||||||
|
|
||||||
# Try arrow-key menu first, fall back to number input
|
# Try arrow-key menu first, fall back to number input
|
||||||
try:
|
try:
|
||||||
from simple_term_menu import TerminalMenu
|
from simple_term_menu import TerminalMenu
|
||||||
choices = [f" {mid}" for mid in model_ids]
|
choices = [f" {_label(mid)}" for mid in ordered]
|
||||||
choices.append(" Custom model name")
|
choices.append(" Enter custom model name")
|
||||||
choices.append(" Skip (keep current)")
|
choices.append(" Skip (keep current)")
|
||||||
menu = TerminalMenu(
|
menu = TerminalMenu(
|
||||||
choices,
|
choices,
|
||||||
cursor_index=0,
|
cursor_index=default_idx,
|
||||||
menu_cursor="-> ",
|
menu_cursor="-> ",
|
||||||
menu_cursor_style=("fg_green", "bold"),
|
menu_cursor_style=("fg_green", "bold"),
|
||||||
menu_highlight_style=("fg_green",),
|
menu_highlight_style=("fg_green",),
|
||||||
|
|
@ -880,30 +890,38 @@ def _prompt_model_selection(model_ids: List[str]) -> Optional[str]:
|
||||||
if idx is None:
|
if idx is None:
|
||||||
return None
|
return None
|
||||||
print()
|
print()
|
||||||
if idx < len(model_ids):
|
if idx < len(ordered):
|
||||||
return model_ids[idx]
|
return ordered[idx]
|
||||||
elif idx == len(model_ids):
|
elif idx == len(ordered):
|
||||||
custom = input("Enter model name: ").strip()
|
custom = input("Enter model name: ").strip()
|
||||||
return custom if custom else None
|
return custom if custom else None
|
||||||
return None
|
return None
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Fallback: number-based selection
|
# Fallback: numbered list
|
||||||
|
print("Select default model:")
|
||||||
|
for i, mid in enumerate(ordered, 1):
|
||||||
|
print(f" {i}. {_label(mid)}")
|
||||||
|
n = len(ordered)
|
||||||
|
print(f" {n + 1}. Enter custom model name")
|
||||||
|
print(f" {n + 2}. Skip (keep current)")
|
||||||
|
print()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
choice = input(f"Select model [1-{len(model_ids) + 2}] (default: skip): ").strip()
|
choice = input(f"Choice [1-{n + 2}] (default: skip): ").strip()
|
||||||
if not choice:
|
if not choice:
|
||||||
return None
|
return None
|
||||||
idx = int(choice)
|
idx = int(choice)
|
||||||
if 1 <= idx <= len(model_ids):
|
if 1 <= idx <= n:
|
||||||
return model_ids[idx - 1]
|
return ordered[idx - 1]
|
||||||
elif idx == len(model_ids) + 1:
|
elif idx == n + 1:
|
||||||
custom = input("Enter model name: ").strip()
|
custom = input("Enter model name: ").strip()
|
||||||
return custom if custom else None
|
return custom if custom else None
|
||||||
elif idx == len(model_ids) + 2:
|
elif idx == n + 2:
|
||||||
return None
|
return None
|
||||||
print(f"Please enter a number between 1 and {len(model_ids) + 2}")
|
print(f"Please enter 1-{n + 2}")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Please enter a number")
|
print("Please enter a number")
|
||||||
except (KeyboardInterrupt, EOFError):
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,271 @@ def cmd_setup(args):
|
||||||
run_setup_wizard(args)
|
run_setup_wizard(args)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_model(args):
|
||||||
|
"""Select default model — starts with provider selection, then model picker."""
|
||||||
|
from hermes_cli.auth import (
|
||||||
|
resolve_provider, get_provider_auth_state, PROVIDER_REGISTRY,
|
||||||
|
_prompt_model_selection, _save_model_choice, _update_config_for_provider,
|
||||||
|
resolve_nous_runtime_credentials, fetch_nous_models, AuthError, format_auth_error,
|
||||||
|
_login_nous, ProviderConfig,
|
||||||
|
)
|
||||||
|
from hermes_cli.config import load_config, save_config, get_env_value, save_env_value
|
||||||
|
|
||||||
|
config = load_config()
|
||||||
|
current_model = config.get("model")
|
||||||
|
if isinstance(current_model, dict):
|
||||||
|
current_model = current_model.get("default", "")
|
||||||
|
current_model = current_model or "(not set)"
|
||||||
|
|
||||||
|
active = resolve_provider("auto")
|
||||||
|
|
||||||
|
# Map active provider to a display name
|
||||||
|
provider_labels = {
|
||||||
|
"openrouter": "OpenRouter",
|
||||||
|
"nous": "Nous Portal",
|
||||||
|
}
|
||||||
|
active_label = provider_labels.get(active, "Custom endpoint")
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(f" Current model: {current_model}")
|
||||||
|
print(f" Active provider: {active_label}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Step 1: Provider selection — put active provider first with marker
|
||||||
|
providers = [
|
||||||
|
("openrouter", "OpenRouter (100+ models, pay-per-use)"),
|
||||||
|
("nous", "Nous Portal (Nous Research subscription)"),
|
||||||
|
("custom", "Custom endpoint (self-hosted / VLLM / etc.)"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Reorder so the active provider is at the top
|
||||||
|
active_key = active if active in ("openrouter", "nous") else "custom"
|
||||||
|
ordered = []
|
||||||
|
for key, label in providers:
|
||||||
|
if key == active_key:
|
||||||
|
ordered.insert(0, (key, f"{label} ← currently active"))
|
||||||
|
else:
|
||||||
|
ordered.append((key, label))
|
||||||
|
ordered.append(("cancel", "Cancel"))
|
||||||
|
|
||||||
|
provider_idx = _prompt_provider_choice([label for _, label in ordered])
|
||||||
|
if provider_idx is None or ordered[provider_idx][0] == "cancel":
|
||||||
|
print("No change.")
|
||||||
|
return
|
||||||
|
|
||||||
|
selected_provider = ordered[provider_idx][0]
|
||||||
|
|
||||||
|
# Step 2: Provider-specific setup + model selection
|
||||||
|
if selected_provider == "openrouter":
|
||||||
|
_model_flow_openrouter(config, current_model)
|
||||||
|
elif selected_provider == "nous":
|
||||||
|
_model_flow_nous(config, current_model)
|
||||||
|
elif selected_provider == "custom":
|
||||||
|
_model_flow_custom(config)
|
||||||
|
|
||||||
|
|
||||||
|
def _prompt_provider_choice(choices):
|
||||||
|
"""Show provider selection menu. Returns index or None."""
|
||||||
|
try:
|
||||||
|
from simple_term_menu import TerminalMenu
|
||||||
|
menu_items = [f" {c}" for c in choices]
|
||||||
|
menu = TerminalMenu(
|
||||||
|
menu_items, cursor_index=0,
|
||||||
|
menu_cursor="-> ", menu_cursor_style=("fg_green", "bold"),
|
||||||
|
menu_highlight_style=("fg_green",),
|
||||||
|
cycle_cursor=True, clear_screen=False,
|
||||||
|
title="Select provider:",
|
||||||
|
)
|
||||||
|
idx = menu.show()
|
||||||
|
print()
|
||||||
|
return idx
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback: numbered list
|
||||||
|
print("Select provider:")
|
||||||
|
for i, c in enumerate(choices, 1):
|
||||||
|
print(f" {i}. {c}")
|
||||||
|
print()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
val = input(f"Choice [1-{len(choices)}]: ").strip()
|
||||||
|
if not val:
|
||||||
|
return None
|
||||||
|
idx = int(val) - 1
|
||||||
|
if 0 <= idx < len(choices):
|
||||||
|
return idx
|
||||||
|
print(f"Please enter 1-{len(choices)}")
|
||||||
|
except ValueError:
|
||||||
|
print("Please enter a number")
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
print()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _model_flow_openrouter(config, current_model=""):
|
||||||
|
"""OpenRouter provider: ensure API key, then pick model."""
|
||||||
|
from hermes_cli.auth import _prompt_model_selection, _save_model_choice
|
||||||
|
from hermes_cli.config import get_env_value, save_env_value
|
||||||
|
|
||||||
|
api_key = get_env_value("OPENROUTER_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
print("No OpenRouter API key configured.")
|
||||||
|
print("Get one at: https://openrouter.ai/keys")
|
||||||
|
print()
|
||||||
|
try:
|
||||||
|
key = input("OpenRouter API key (or Enter to cancel): ").strip()
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
print()
|
||||||
|
return
|
||||||
|
if not key:
|
||||||
|
print("Cancelled.")
|
||||||
|
return
|
||||||
|
save_env_value("OPENROUTER_API_KEY", key)
|
||||||
|
print("API key saved.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
OPENROUTER_MODELS = [
|
||||||
|
"anthropic/claude-opus-4.6",
|
||||||
|
"anthropic/claude-sonnet-4.5",
|
||||||
|
"anthropic/claude-opus-4.5",
|
||||||
|
"openai/gpt-5.2",
|
||||||
|
"openai/gpt-5.2-codex",
|
||||||
|
"google/gemini-3-pro-preview",
|
||||||
|
"google/gemini-3-flash-preview",
|
||||||
|
"z-ai/glm-4.7",
|
||||||
|
"moonshotai/kimi-k2.5",
|
||||||
|
"minimax/minimax-m2.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
selected = _prompt_model_selection(OPENROUTER_MODELS, current_model=current_model)
|
||||||
|
if selected:
|
||||||
|
# Clear any custom endpoint and set provider to openrouter
|
||||||
|
if get_env_value("OPENAI_BASE_URL"):
|
||||||
|
save_env_value("OPENAI_BASE_URL", "")
|
||||||
|
save_env_value("OPENAI_API_KEY", "")
|
||||||
|
_save_model_choice(selected)
|
||||||
|
# Update config provider
|
||||||
|
from hermes_cli.config import load_config, save_config
|
||||||
|
cfg = load_config()
|
||||||
|
model = cfg.get("model")
|
||||||
|
if isinstance(model, dict):
|
||||||
|
model["provider"] = "openrouter"
|
||||||
|
model["base_url"] = "https://openrouter.ai/api/v1"
|
||||||
|
save_config(cfg)
|
||||||
|
print(f"Default model set to: {selected} (via OpenRouter)")
|
||||||
|
else:
|
||||||
|
print("No change.")
|
||||||
|
|
||||||
|
|
||||||
|
def _model_flow_nous(config, current_model=""):
|
||||||
|
"""Nous Portal provider: ensure logged in, then pick model."""
|
||||||
|
from hermes_cli.auth import (
|
||||||
|
get_provider_auth_state, _prompt_model_selection, _save_model_choice,
|
||||||
|
resolve_nous_runtime_credentials, fetch_nous_models,
|
||||||
|
AuthError, format_auth_error, _login_nous, PROVIDER_REGISTRY,
|
||||||
|
)
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
state = get_provider_auth_state("nous")
|
||||||
|
if not state or not state.get("access_token"):
|
||||||
|
print("Not logged into Nous Portal. Starting login...")
|
||||||
|
print()
|
||||||
|
try:
|
||||||
|
mock_args = argparse.Namespace(
|
||||||
|
portal_url=None, inference_url=None, client_id=None,
|
||||||
|
scope=None, no_browser=False, timeout=15.0,
|
||||||
|
ca_bundle=None, insecure=False,
|
||||||
|
)
|
||||||
|
_login_nous(mock_args, PROVIDER_REGISTRY["nous"])
|
||||||
|
except SystemExit:
|
||||||
|
print("Login cancelled or failed.")
|
||||||
|
return
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"Login failed: {exc}")
|
||||||
|
return
|
||||||
|
# login_nous already handles model selection, so we're done
|
||||||
|
return
|
||||||
|
|
||||||
|
# Already logged in — fetch models and select
|
||||||
|
print("Fetching models from Nous Portal...")
|
||||||
|
try:
|
||||||
|
creds = resolve_nous_runtime_credentials(min_key_ttl_seconds=5 * 60)
|
||||||
|
model_ids = fetch_nous_models(
|
||||||
|
inference_base_url=creds.get("base_url", ""),
|
||||||
|
api_key=creds.get("api_key", ""),
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
msg = format_auth_error(exc) if isinstance(exc, AuthError) else str(exc)
|
||||||
|
print(f"Could not fetch models: {msg}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not model_ids:
|
||||||
|
print("No models returned by the inference API.")
|
||||||
|
return
|
||||||
|
|
||||||
|
selected = _prompt_model_selection(model_ids, current_model=current_model)
|
||||||
|
if selected:
|
||||||
|
_save_model_choice(selected)
|
||||||
|
print(f"Default model set to: {selected} (via Nous Portal)")
|
||||||
|
else:
|
||||||
|
print("No change.")
|
||||||
|
|
||||||
|
|
||||||
|
def _model_flow_custom(config):
|
||||||
|
"""Custom endpoint: collect URL, API key, and model name."""
|
||||||
|
from hermes_cli.auth import _save_model_choice
|
||||||
|
from hermes_cli.config import get_env_value, save_env_value, load_config, save_config
|
||||||
|
|
||||||
|
current_url = get_env_value("OPENAI_BASE_URL") or ""
|
||||||
|
current_key = get_env_value("OPENAI_API_KEY") or ""
|
||||||
|
|
||||||
|
print("Custom OpenAI-compatible endpoint configuration:")
|
||||||
|
if current_url:
|
||||||
|
print(f" Current URL: {current_url}")
|
||||||
|
if current_key:
|
||||||
|
print(f" Current key: {current_key[:8]}...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
base_url = input(f"API base URL [{current_url or 'e.g. https://api.example.com/v1'}]: ").strip()
|
||||||
|
api_key = input(f"API key [{current_key[:8] + '...' if current_key else 'optional'}]: ").strip()
|
||||||
|
model_name = input("Model name (e.g. gpt-4, llama-3-70b): ").strip()
|
||||||
|
except (KeyboardInterrupt, EOFError):
|
||||||
|
print("\nCancelled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not base_url and not current_url:
|
||||||
|
print("No URL provided. Cancelled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Validate URL format
|
||||||
|
effective_url = base_url or current_url
|
||||||
|
if not effective_url.startswith(("http://", "https://")):
|
||||||
|
print(f"Invalid URL: {effective_url} (must start with http:// or https://)")
|
||||||
|
return
|
||||||
|
|
||||||
|
if base_url:
|
||||||
|
save_env_value("OPENAI_BASE_URL", base_url)
|
||||||
|
if api_key:
|
||||||
|
save_env_value("OPENAI_API_KEY", api_key)
|
||||||
|
|
||||||
|
if model_name:
|
||||||
|
_save_model_choice(model_name)
|
||||||
|
|
||||||
|
# Update config to reflect custom provider
|
||||||
|
cfg = load_config()
|
||||||
|
model = cfg.get("model")
|
||||||
|
if isinstance(model, dict):
|
||||||
|
model["provider"] = "auto"
|
||||||
|
model["base_url"] = effective_url
|
||||||
|
save_config(cfg)
|
||||||
|
|
||||||
|
print(f"Default model set to: {model_name} (via {effective_url})")
|
||||||
|
else:
|
||||||
|
print("Endpoint saved. Use `/model` in chat or `hermes model` to set a model.")
|
||||||
|
|
||||||
|
|
||||||
def cmd_login(args):
|
def cmd_login(args):
|
||||||
"""Authenticate Hermes CLI with a provider."""
|
"""Authenticate Hermes CLI with a provider."""
|
||||||
from hermes_cli.auth import login_command
|
from hermes_cli.auth import login_command
|
||||||
|
|
@ -283,6 +548,7 @@ Examples:
|
||||||
hermes setup Run setup wizard
|
hermes setup Run setup wizard
|
||||||
hermes login Authenticate with an inference provider
|
hermes login Authenticate with an inference provider
|
||||||
hermes logout Clear stored authentication
|
hermes logout Clear stored authentication
|
||||||
|
hermes model Select default model
|
||||||
hermes config View configuration
|
hermes config View configuration
|
||||||
hermes config edit Edit config in $EDITOR
|
hermes config edit Edit config in $EDITOR
|
||||||
hermes config set model gpt-4 Set a config value
|
hermes config set model gpt-4 Set a config value
|
||||||
|
|
@ -335,7 +601,17 @@ For more help on a command:
|
||||||
help="Verbose output"
|
help="Verbose output"
|
||||||
)
|
)
|
||||||
chat_parser.set_defaults(func=cmd_chat)
|
chat_parser.set_defaults(func=cmd_chat)
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# model command
|
||||||
|
# =========================================================================
|
||||||
|
model_parser = subparsers.add_parser(
|
||||||
|
"model",
|
||||||
|
help="Select default model and provider",
|
||||||
|
description="Interactively select your inference provider and default model"
|
||||||
|
)
|
||||||
|
model_parser.set_defaults(func=cmd_model)
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# gateway command
|
# gateway command
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue