feat: restore /model slash command for CLI and gateway#3360
feat: restore /model slash command for CLI and gateway#3360virtaava wants to merge 2 commits intoNousResearch:mainfrom
Conversation
…3080 revert) PR NousResearch#3080 removed the /model slash command from both the interactive CLI and all messenger gateways (Telegram/Discord/Slack/WhatsApp), leaving only `hermes model` CLI subcommand and config.yaml editing as alternatives. This breaks the workflow for: - **All remote users** who access Hermes via Telegram, Discord, Slack, WhatsApp, or the API server — they have no shell access to run CLI subcommands and cannot edit config.yaml on the host machine - **Gateway-only deployments** (headless servers, Docker, cloud) where the only interface is a messenger bot — model switching becomes impossible without SSH access to the physical machine - **CLI users** who must exit their chat session or open a second terminal to run `hermes model`, breaking conversational flow - **Custom endpoint users** who relied on `/model custom` for live API probe and auto-detection The ACP adapter (VS Code/Zed/JetBrains) kept its own `/model` handler, creating an inconsistency where IDE users can switch models but CLI and gateway users cannot. The underlying `model_switch.py` module was left intact by NousResearch#3080 (used by ACP/IDE adapters), so the switching logic already exists. The /model command is a thin wrapper calling it. Restores: - CommandDef entry in COMMAND_REGISTRY with help text and examples - CLI process_command() handler delegating to model_switch.py - Gateway _handle_model_command() for all messenger platforms - All /model-specific tests Does NOT restore (intentionally removed as unnecessary): - SlashCommandCompleter model_completer_provider (Tab autocomplete) - Two-stage ghost text suggestions The autocomplete was complex (~95 lines) and fragile. The command itself is simple enough without it: `/model deepseek:deepseek-chat` or `/model custom` works without Tab completion. Co-Authored-By: Sona <sona_openclaw@proton.me>
|
I reviewed and locally reimplemented/tested this flow on a separate branch before noticing this PR already covered the same area. One subtle thing I’d recommend double-checking before merge: preserve any existing model.api_key config reference (for example model.api_key: ) when /model updates provider/default/base_url, and avoid writing resolved runtime API keys back into config.yaml during command handling.\n\nI also added/reran focused gateway-side tests locally around:\n- /model registration + dispatch\n- /model show current model/provider\n- provider:model persistence\n- /model custom persisting base_url\n- preserving existing config api_key references\n\nLocal validation on my side passed for the targeted gateway tests.\n\nThanks for restoring this — gateway /model is definitely important for Telegram/headless deployments. |
…witch
When /model updates config.yaml via yaml.dump, preserve any existing
model.api_key value (e.g. env var placeholder like ${ANTHROPIC_API_KEY}).
Never write resolved runtime API keys back into the config file.
Also handle the case where model config is a bare string (e.g.
"model: claude-opus-4.6") by converting to dict format while preserving
the original value as model.default.
Addresses review feedback from NousResearch#3360.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…witch
When /model updates config.yaml via yaml.dump, preserve any existing
model.api_key value (e.g. env var placeholder like ${ANTHROPIC_API_KEY}).
Never write resolved runtime API keys back into the config file.
Also handle the case where model config is a bare string (e.g.
"model: claude-opus-4.6") by converting to dict format while preserving
the original value as model.default.
Addresses review feedback from NousResearch#3360.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Good catch @NivOO5. Pushed a fix in 9c0f07b: What changed:
The CLI side was already safe — it uses Thanks for catching this before merge. |
Example plugin demonstrating the lifecycle hooks activated in NousResearch#3542. Auto-manages a local llama-server (or any OpenAI-compatible server) when the active model matches a locally configured model name. Features: - pre_llm_call hook: auto-starts the correct server on first message when hermes is configured with a local model name - on_session_end hook: kills the server on exit - switch_local_llm tool: mid-session model switching — the agent swaps the server when asked ("switch to the code model") - Declarative YAML config for model definitions (GGUF paths, context sizes, KV cache quantization, sampling params) replacing shell scripts The plugin is self-contained in docs/llm-switch-plugin-example/ with a README, example config, and full implementation. Users copy it to ~/.hermes/plugins/llm-switch/ to install. Complements NousResearch#3360 and NousResearch#3548 which restore /model as a slash command — once merged, /model custom:write would trigger the pre_llm_call hook to auto-start the right server seamlessly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
+1 on restoring The plugin works today via the This is a concrete use case where |
|
Really need this, it's a pain to change model when running hermes on a vps without the /model command |
Summary
Reverts the functional removal from #3080 which deleted the
/modelslash command from both CLI and all messenger gateways.The problem: #3080 left
hermes modelCLI subcommand and config.yaml editing as the only ways to switch models. This works for users with shell access but completely breaks model switching for:The ACP adapter (VS Code/Zed/JetBrains) kept its own
/modelhandler, creating an inconsistency where IDE users can switch models but CLI and gateway users cannot.Related Issues
This PR addresses or unblocks several open issues that depend on
/modelexisting:/model. Cannot be implemented if/modeldoesn't exist in the gateway./modeldisplay. The display was deleted entirely by refactor: remove /model slash command from CLI and gateway #3080 instead of being fixed./model customflow is the UX solution, but it was removed./modelswitching is the user-facing half./modelis the interactive equivalent.What this PR does
Restores
/modelas a thin wrapper around the existingmodel_switch.pymodule (which #3080 left intact for ACP use). No new logic — just reconnects the UI to the existing switching infrastructure.Restored:
CommandDefentry inCOMMAND_REGISTRYprocess_command()handler delegating tomodel_switch.py_handle_model_command()for all messenger platforms/model-specific tests (210 lines)NOT restored (intentionally):
SlashCommandCompletermodel_completer_provider— Tab autocomplete (~95 lines, complex and fragile)Test plan
/modelwith no args shows current model + available providers/model deepseek:deepseek-chatswitches model and provider/model customauto-detects model from custom endpoint/model invalid:nonexistentshows clear error/modelworks in chatpytest tests/test_cli_model_command.py tests/hermes_cli/test_commands.py