refactor: migrate tool progress configuration from environment variables to config.yaml

This commit is contained in:
teknium1 2026-02-28 00:05:58 -08:00
parent 0862fa96fd
commit de5a88bd97
9 changed files with 114 additions and 52 deletions

View file

@ -248,9 +248,7 @@ DISCORD_ALLOWED_USERS=123456789012345678 # Comma-separated user IDs
HERMES_MAX_ITERATIONS=60 # Max tool-calling iterations
MESSAGING_CWD=/home/myuser # Terminal working directory for messaging
# Tool Progress (optional)
HERMES_TOOL_PROGRESS=true # Send progress messages
HERMES_TOOL_PROGRESS_MODE=new # "new" or "all"
# Tool progress is configured in config.yaml (display.tool_progress: off|new|all|verbose)
```
### Working Directory Behavior
@ -301,7 +299,7 @@ Files: `gateway/hooks.py`
### Tool Progress Notifications
When `HERMES_TOOL_PROGRESS=true`, the bot sends status messages as it works:
When `tool_progress` is enabled in `config.yaml`, the bot sends status messages as it works:
- `💻 \`ls -la\`...` (terminal commands show the actual command)
- `🔍 web_search...`
- `📄 web_extract...`
@ -411,8 +409,7 @@ Terminal tool configuration (in `~/.hermes/config.yaml`):
Agent behavior (in `~/.hermes/.env`):
- `HERMES_MAX_ITERATIONS` - Max tool-calling iterations (default: 60)
- `MESSAGING_CWD` - Working directory for messaging platforms (default: ~)
- `HERMES_TOOL_PROGRESS` - Enable tool progress messages (`true`/`false`)
- `HERMES_TOOL_PROGRESS_MODE` - Progress mode: `new` (tool changes) or `all`
- `display.tool_progress` in config.yaml - Tool progress: `off`, `new`, `all`, `verbose`
- `OPENAI_API_KEY` - Voice transcription (Whisper STT)
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` - Slack integration (Socket Mode)
- `SLACK_ALLOWED_USERS` - Comma-separated Slack user IDs

View file

@ -325,14 +325,22 @@ TERMINAL_CWD=/workspace # All terminal sessions (local or contain
### Tool Progress Notifications
Get real-time updates as the agent works:
Control how much tool activity is displayed. Set in `~/.hermes/config.yaml`:
```bash
# Enable in ~/.hermes/.env
HERMES_TOOL_PROGRESS=true
HERMES_TOOL_PROGRESS_MODE=all # or "new" for only when tool changes
```yaml
display:
tool_progress: all # off | new | all | verbose
```
| Mode | What you see |
|------|-------------|
| `off` | Silent — just the final response |
| `new` | Tool indicator only when the tool changes (skip repeats) |
| `all` | Every tool call with a short preview (default) |
| `verbose` | Full args, results, and debug logs |
Toggle at runtime in the CLI with `/verbose` (cycles through all four modes).
---
## Commands
@ -1568,8 +1576,6 @@ All variables go in `~/.hermes/.env`. Run `hermes config set VAR value` to set t
| Variable | Description |
|----------|-------------|
| `HERMES_MAX_ITERATIONS` | Max tool-calling iterations per conversation (default: 60) |
| `HERMES_TOOL_PROGRESS` | Send progress messages when using tools (`true`/`false`) |
| `HERMES_TOOL_PROGRESS_MODE` | `all` (every call, default) or `new` (only when tool changes) |
**Context Compression:**
| Variable | Description |

View file

@ -487,3 +487,11 @@ delegation:
display:
# Use compact banner mode
compact: false
# Tool progress display level (CLI and gateway)
# off: Silent — no tool activity shown, just the final response
# new: Show a tool indicator only when the tool changes (skip repeats)
# all: Show every tool call with a short preview (default)
# verbose: Full args, results, and debug logs (same as /verbose)
# Toggle at runtime with /verbose in the CLI
tool_progress: all

25
cli.py
View file

@ -793,7 +793,9 @@ class HermesCLI:
# Initialize Rich console
self.console = Console()
self.compact = compact if compact is not None else CLI_CONFIG["display"].get("compact", False)
self.verbose = verbose if verbose is not None else CLI_CONFIG["agent"].get("verbose", False)
# tool_progress: "off", "new", "all", "verbose" (from config.yaml display section)
self.tool_progress_mode = CLI_CONFIG["display"].get("tool_progress", "all")
self.verbose = verbose if verbose is not None else (self.tool_progress_mode == "verbose")
# Configuration - priority: CLI args > env vars > config file
# Model can come from: CLI arg, LLM_MODEL env, OPENAI_MODEL env (custom endpoint), or config
@ -1697,24 +1699,35 @@ class HermesCLI:
return True
def _toggle_verbose(self):
"""Toggle verbose mode on/off at runtime."""
self.verbose = not self.verbose
"""Cycle tool progress mode: off → new → all → verbose → off."""
cycle = ["off", "new", "all", "verbose"]
try:
idx = cycle.index(self.tool_progress_mode)
except ValueError:
idx = 2 # default to "all"
self.tool_progress_mode = cycle[(idx + 1) % len(cycle)]
self.verbose = self.tool_progress_mode == "verbose"
if self.agent:
self.agent.verbose_logging = self.verbose
self.agent.quiet_mode = not self.verbose
# Reconfigure logging level to match new state
labels = {
"off": "[dim]Tool progress: OFF[/] — silent mode, just the final response.",
"new": "[yellow]Tool progress: NEW[/] — show each new tool (skip repeats).",
"all": "[green]Tool progress: ALL[/] — show every tool call.",
"verbose": "[bold green]Tool progress: VERBOSE[/] — full args, results, and debug logs.",
}
self.console.print(labels.get(self.tool_progress_mode, ""))
if self.verbose:
logging.getLogger().setLevel(logging.DEBUG)
for noisy in ('openai', 'openai._base_client', 'httpx', 'httpcore', 'asyncio', 'hpack', 'grpc', 'modal'):
logging.getLogger(noisy).setLevel(logging.WARNING)
self.console.print("[bold green]Verbose mode ON[/] — tool calls, parameters, and results will be shown.")
else:
logging.getLogger().setLevel(logging.INFO)
for quiet_logger in ('tools', 'minisweagent', 'run_agent', 'trajectory_compressor', 'cron', 'hermes_cli'):
logging.getLogger(quiet_logger).setLevel(logging.ERROR)
self.console.print("[dim]Verbose mode OFF[/] — returning to normal display.")
def _clarify_callback(self, question, choices):
"""

View file

@ -223,11 +223,9 @@ MESSAGING_CWD=/home/myuser
# TOOL PROGRESS NOTIFICATIONS
# =============================================================================
# Show progress messages as agent uses tools
HERMES_TOOL_PROGRESS=true
# Mode: "new" (only when tool changes) or "all" (every tool call)
HERMES_TOOL_PROGRESS_MODE=new
# Tool progress is now configured in config.yaml:
# display:
# tool_progress: all # off | new | all | verbose
# =============================================================================
# SESSION SETTINGS
@ -301,7 +299,7 @@ The gateway keeps the "typing..." indicator active throughout processing, refres
### Tool Progress Notifications
When `HERMES_TOOL_PROGRESS=true`, the bot sends status messages as it works:
When `tool_progress` is enabled in `config.yaml`, the bot sends status messages as it works:
```text
💻 `ls -la`...

View file

@ -1462,9 +1462,24 @@ class GatewayRunner:
default_toolset = default_toolset_map.get(source.platform, "hermes-telegram")
enabled_toolsets = [default_toolset]
# Check if tool progress notifications are enabled
tool_progress_enabled = os.getenv("HERMES_TOOL_PROGRESS", "true").lower() in ("1", "true", "yes")
progress_mode = os.getenv("HERMES_TOOL_PROGRESS_MODE", "all") # "all" or "new" (only new tools)
# Tool progress mode from config.yaml: "all", "new", "verbose", "off"
# Falls back to env vars for backward compatibility
_progress_cfg = {}
try:
_tp_cfg_path = _hermes_home / "config.yaml"
if _tp_cfg_path.exists():
import yaml as _tp_yaml
with open(_tp_cfg_path) as _tp_f:
_tp_data = _tp_yaml.safe_load(_tp_f) or {}
_progress_cfg = _tp_data.get("display", {})
except Exception:
pass
progress_mode = (
_progress_cfg.get("tool_progress")
or os.getenv("HERMES_TOOL_PROGRESS_MODE")
or "all"
)
tool_progress_enabled = progress_mode != "off"
# Queue for progress messages (thread-safe)
progress_queue = queue.Queue() if tool_progress_enabled else None
@ -1627,6 +1642,7 @@ class GatewayRunner:
base_url=base_url,
max_iterations=max_iterations,
quiet_mode=True,
verbose_logging=False,
enabled_toolsets=enabled_toolsets,
ephemeral_system_prompt=combined_ephemeral or None,
prefill_messages=self._prefill_messages or None,

View file

@ -25,7 +25,7 @@ COMMANDS = {
"/cron": "Manage scheduled tasks (list, add, remove)",
"/skills": "Search, install, inspect, or manage skills from online registries",
"/platforms": "Show gateway/messaging platform status",
"/verbose": "Toggle verbose mode (show tool calls, parameters, and results)",
"/verbose": "Cycle tool progress display: off → new → all → verbose",
"/quit": "Exit the CLI (also: /exit, /q)",
}

View file

@ -136,7 +136,7 @@ DEFAULT_CONFIG = {
"command_allowlist": [],
# Config schema version - bump this when adding new required fields
"_config_version": 3,
"_config_version": 4,
}
# =============================================================================
@ -318,16 +318,19 @@ OPTIONAL_ENV_VARS = {
"password": False,
"category": "setting",
},
# HERMES_TOOL_PROGRESS and HERMES_TOOL_PROGRESS_MODE are deprecated —
# now configured via display.tool_progress in config.yaml (off|new|all|verbose).
# Gateway falls back to these env vars for backward compatibility.
"HERMES_TOOL_PROGRESS": {
"description": "Send tool progress messages in messaging channels (true/false)",
"prompt": "Enable tool progress messages",
"description": "(deprecated) Use display.tool_progress in config.yaml instead",
"prompt": "Tool progress (deprecated — use config.yaml)",
"url": None,
"password": False,
"category": "setting",
},
"HERMES_TOOL_PROGRESS_MODE": {
"description": "Progress mode: 'all' (every tool) or 'new' (only when tool changes)",
"prompt": "Progress mode (all/new)",
"description": "(deprecated) Use display.tool_progress in config.yaml instead",
"prompt": "Progress mode (deprecated — use config.yaml)",
"url": None,
"password": False,
"category": "setting",
@ -442,6 +445,29 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
# Check config version
current_ver, latest_ver = check_config_version()
# ── Version 3 → 4: migrate tool progress from .env to config.yaml ──
if current_ver < 4:
config = load_config()
display = config.get("display", {})
if not isinstance(display, dict):
display = {}
if "tool_progress" not in display:
old_enabled = get_env_value("HERMES_TOOL_PROGRESS")
old_mode = get_env_value("HERMES_TOOL_PROGRESS_MODE")
if old_enabled and old_enabled.lower() in ("false", "0", "no"):
display["tool_progress"] = "off"
results["config_added"].append("display.tool_progress=off (from HERMES_TOOL_PROGRESS=false)")
elif old_mode and old_mode.lower() in ("new", "all"):
display["tool_progress"] = old_mode.lower()
results["config_added"].append(f"display.tool_progress={old_mode.lower()} (from HERMES_TOOL_PROGRESS_MODE)")
else:
display["tool_progress"] = "all"
results["config_added"].append("display.tool_progress=all (default)")
config["display"] = display
save_config(config)
if not quiet:
print(f" ✓ Migrated tool progress to config.yaml: {display['tool_progress']}")
if current_ver < latest_ver and not quiet:
print(f"Config version: {current_ver}{latest_ver}")

View file

@ -1044,27 +1044,25 @@ def run_setup_wizard(args):
except ValueError:
print_warning("Invalid number, keeping current value")
# Tool progress notifications (for messaging)
# Tool progress notifications
print_info("")
print_info("Tool Progress Notifications (Messaging only)")
print_info("Send status messages when the agent uses tools.")
print_info("Example: '💻 ls -la...' or '🔍 web_search...'")
print_info("Tool Progress Display")
print_info("Controls how much tool activity is shown (CLI and messaging).")
print_info(" off — Silent, just the final response")
print_info(" new — Show tool name only when it changes (less noise)")
print_info(" all — Show every tool call with a short preview")
print_info(" verbose — Full args, results, and debug logs")
current_progress = get_env_value('HERMES_TOOL_PROGRESS') or 'true'
if prompt_yes_no("Enable tool progress messages?", current_progress.lower() in ('1', 'true', 'yes')):
save_env_value("HERMES_TOOL_PROGRESS", "true")
# Progress mode
current_mode = get_env_value('HERMES_TOOL_PROGRESS_MODE') or 'all'
print_info(" Mode options:")
print_info(" 'new' - Only when switching tools (less spam)")
print_info(" 'all' - Every tool call")
mode = prompt(" Progress mode", current_mode)
if mode.lower() in ('all', 'new'):
save_env_value("HERMES_TOOL_PROGRESS_MODE", mode.lower())
print_success("Tool progress enabled")
current_mode = config.get("display", {}).get("tool_progress", "all")
mode = prompt("Tool progress mode", current_mode)
if mode.lower() in ("off", "new", "all", "verbose"):
if "display" not in config:
config["display"] = {}
config["display"]["tool_progress"] = mode.lower()
save_config(config)
print_success(f"Tool progress set to: {mode.lower()}")
else:
save_env_value("HERMES_TOOL_PROGRESS", "false")
print_warning(f"Unknown mode '{mode}', keeping '{current_mode}'")
# =========================================================================
# Step 6: Context Compression