refactor: migrate tool progress configuration from environment variables to config.yaml
This commit is contained in:
parent
0862fa96fd
commit
de5a88bd97
9 changed files with 114 additions and 52 deletions
|
|
@ -248,9 +248,7 @@ DISCORD_ALLOWED_USERS=123456789012345678 # Comma-separated user IDs
|
||||||
HERMES_MAX_ITERATIONS=60 # Max tool-calling iterations
|
HERMES_MAX_ITERATIONS=60 # Max tool-calling iterations
|
||||||
MESSAGING_CWD=/home/myuser # Terminal working directory for messaging
|
MESSAGING_CWD=/home/myuser # Terminal working directory for messaging
|
||||||
|
|
||||||
# Tool Progress (optional)
|
# Tool progress is configured in config.yaml (display.tool_progress: off|new|all|verbose)
|
||||||
HERMES_TOOL_PROGRESS=true # Send progress messages
|
|
||||||
HERMES_TOOL_PROGRESS_MODE=new # "new" or "all"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working Directory Behavior
|
### Working Directory Behavior
|
||||||
|
|
@ -301,7 +299,7 @@ Files: `gateway/hooks.py`
|
||||||
|
|
||||||
### Tool Progress Notifications
|
### 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)
|
- `💻 \`ls -la\`...` (terminal commands show the actual command)
|
||||||
- `🔍 web_search...`
|
- `🔍 web_search...`
|
||||||
- `📄 web_extract...`
|
- `📄 web_extract...`
|
||||||
|
|
@ -411,8 +409,7 @@ Terminal tool configuration (in `~/.hermes/config.yaml`):
|
||||||
Agent behavior (in `~/.hermes/.env`):
|
Agent behavior (in `~/.hermes/.env`):
|
||||||
- `HERMES_MAX_ITERATIONS` - Max tool-calling iterations (default: 60)
|
- `HERMES_MAX_ITERATIONS` - Max tool-calling iterations (default: 60)
|
||||||
- `MESSAGING_CWD` - Working directory for messaging platforms (default: ~)
|
- `MESSAGING_CWD` - Working directory for messaging platforms (default: ~)
|
||||||
- `HERMES_TOOL_PROGRESS` - Enable tool progress messages (`true`/`false`)
|
- `display.tool_progress` in config.yaml - Tool progress: `off`, `new`, `all`, `verbose`
|
||||||
- `HERMES_TOOL_PROGRESS_MODE` - Progress mode: `new` (tool changes) or `all`
|
|
||||||
- `OPENAI_API_KEY` - Voice transcription (Whisper STT)
|
- `OPENAI_API_KEY` - Voice transcription (Whisper STT)
|
||||||
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` - Slack integration (Socket Mode)
|
- `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` - Slack integration (Socket Mode)
|
||||||
- `SLACK_ALLOWED_USERS` - Comma-separated Slack user IDs
|
- `SLACK_ALLOWED_USERS` - Comma-separated Slack user IDs
|
||||||
|
|
|
||||||
20
README.md
20
README.md
|
|
@ -325,14 +325,22 @@ TERMINAL_CWD=/workspace # All terminal sessions (local or contain
|
||||||
|
|
||||||
### Tool Progress Notifications
|
### Tool Progress Notifications
|
||||||
|
|
||||||
Get real-time updates as the agent works:
|
Control how much tool activity is displayed. Set in `~/.hermes/config.yaml`:
|
||||||
|
|
||||||
```bash
|
```yaml
|
||||||
# Enable in ~/.hermes/.env
|
display:
|
||||||
HERMES_TOOL_PROGRESS=true
|
tool_progress: all # off | new | all | verbose
|
||||||
HERMES_TOOL_PROGRESS_MODE=all # or "new" for only when tool changes
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
| 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
|
## Commands
|
||||||
|
|
@ -1568,8 +1576,6 @@ All variables go in `~/.hermes/.env`. Run `hermes config set VAR value` to set t
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
| `HERMES_MAX_ITERATIONS` | Max tool-calling iterations per conversation (default: 60) |
|
| `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:**
|
**Context Compression:**
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
|
|
|
||||||
|
|
@ -487,3 +487,11 @@ delegation:
|
||||||
display:
|
display:
|
||||||
# Use compact banner mode
|
# Use compact banner mode
|
||||||
compact: false
|
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
25
cli.py
|
|
@ -793,7 +793,9 @@ class HermesCLI:
|
||||||
# Initialize Rich console
|
# Initialize Rich console
|
||||||
self.console = Console()
|
self.console = Console()
|
||||||
self.compact = compact if compact is not None else CLI_CONFIG["display"].get("compact", False)
|
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
|
# Configuration - priority: CLI args > env vars > config file
|
||||||
# Model can come from: CLI arg, LLM_MODEL env, OPENAI_MODEL env (custom endpoint), or config
|
# Model can come from: CLI arg, LLM_MODEL env, OPENAI_MODEL env (custom endpoint), or config
|
||||||
|
|
@ -1697,24 +1699,35 @@ class HermesCLI:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _toggle_verbose(self):
|
def _toggle_verbose(self):
|
||||||
"""Toggle verbose mode on/off at runtime."""
|
"""Cycle tool progress mode: off → new → all → verbose → off."""
|
||||||
self.verbose = not self.verbose
|
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:
|
if self.agent:
|
||||||
self.agent.verbose_logging = self.verbose
|
self.agent.verbose_logging = self.verbose
|
||||||
self.agent.quiet_mode = not 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:
|
if self.verbose:
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
for noisy in ('openai', 'openai._base_client', 'httpx', 'httpcore', 'asyncio', 'hpack', 'grpc', 'modal'):
|
for noisy in ('openai', 'openai._base_client', 'httpx', 'httpcore', 'asyncio', 'hpack', 'grpc', 'modal'):
|
||||||
logging.getLogger(noisy).setLevel(logging.WARNING)
|
logging.getLogger(noisy).setLevel(logging.WARNING)
|
||||||
self.console.print("[bold green]Verbose mode ON[/] — tool calls, parameters, and results will be shown.")
|
|
||||||
else:
|
else:
|
||||||
logging.getLogger().setLevel(logging.INFO)
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
for quiet_logger in ('tools', 'minisweagent', 'run_agent', 'trajectory_compressor', 'cron', 'hermes_cli'):
|
for quiet_logger in ('tools', 'minisweagent', 'run_agent', 'trajectory_compressor', 'cron', 'hermes_cli'):
|
||||||
logging.getLogger(quiet_logger).setLevel(logging.ERROR)
|
logging.getLogger(quiet_logger).setLevel(logging.ERROR)
|
||||||
self.console.print("[dim]Verbose mode OFF[/] — returning to normal display.")
|
|
||||||
|
|
||||||
def _clarify_callback(self, question, choices):
|
def _clarify_callback(self, question, choices):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -223,11 +223,9 @@ MESSAGING_CWD=/home/myuser
|
||||||
# TOOL PROGRESS NOTIFICATIONS
|
# TOOL PROGRESS NOTIFICATIONS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
# Show progress messages as agent uses tools
|
# Tool progress is now configured in config.yaml:
|
||||||
HERMES_TOOL_PROGRESS=true
|
# display:
|
||||||
|
# tool_progress: all # off | new | all | verbose
|
||||||
# Mode: "new" (only when tool changes) or "all" (every tool call)
|
|
||||||
HERMES_TOOL_PROGRESS_MODE=new
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# SESSION SETTINGS
|
# SESSION SETTINGS
|
||||||
|
|
@ -301,7 +299,7 @@ The gateway keeps the "typing..." indicator active throughout processing, refres
|
||||||
|
|
||||||
### Tool Progress Notifications
|
### 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
|
```text
|
||||||
💻 `ls -la`...
|
💻 `ls -la`...
|
||||||
|
|
|
||||||
|
|
@ -1462,9 +1462,24 @@ class GatewayRunner:
|
||||||
default_toolset = default_toolset_map.get(source.platform, "hermes-telegram")
|
default_toolset = default_toolset_map.get(source.platform, "hermes-telegram")
|
||||||
enabled_toolsets = [default_toolset]
|
enabled_toolsets = [default_toolset]
|
||||||
|
|
||||||
# Check if tool progress notifications are enabled
|
# Tool progress mode from config.yaml: "all", "new", "verbose", "off"
|
||||||
tool_progress_enabled = os.getenv("HERMES_TOOL_PROGRESS", "true").lower() in ("1", "true", "yes")
|
# Falls back to env vars for backward compatibility
|
||||||
progress_mode = os.getenv("HERMES_TOOL_PROGRESS_MODE", "all") # "all" or "new" (only new tools)
|
_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)
|
# Queue for progress messages (thread-safe)
|
||||||
progress_queue = queue.Queue() if tool_progress_enabled else None
|
progress_queue = queue.Queue() if tool_progress_enabled else None
|
||||||
|
|
@ -1627,6 +1642,7 @@ class GatewayRunner:
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
max_iterations=max_iterations,
|
max_iterations=max_iterations,
|
||||||
quiet_mode=True,
|
quiet_mode=True,
|
||||||
|
verbose_logging=False,
|
||||||
enabled_toolsets=enabled_toolsets,
|
enabled_toolsets=enabled_toolsets,
|
||||||
ephemeral_system_prompt=combined_ephemeral or None,
|
ephemeral_system_prompt=combined_ephemeral or None,
|
||||||
prefill_messages=self._prefill_messages or None,
|
prefill_messages=self._prefill_messages or None,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ COMMANDS = {
|
||||||
"/cron": "Manage scheduled tasks (list, add, remove)",
|
"/cron": "Manage scheduled tasks (list, add, remove)",
|
||||||
"/skills": "Search, install, inspect, or manage skills from online registries",
|
"/skills": "Search, install, inspect, or manage skills from online registries",
|
||||||
"/platforms": "Show gateway/messaging platform status",
|
"/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)",
|
"/quit": "Exit the CLI (also: /exit, /q)",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ DEFAULT_CONFIG = {
|
||||||
"command_allowlist": [],
|
"command_allowlist": [],
|
||||||
|
|
||||||
# Config schema version - bump this when adding new required fields
|
# 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,
|
"password": False,
|
||||||
"category": "setting",
|
"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": {
|
"HERMES_TOOL_PROGRESS": {
|
||||||
"description": "Send tool progress messages in messaging channels (true/false)",
|
"description": "(deprecated) Use display.tool_progress in config.yaml instead",
|
||||||
"prompt": "Enable tool progress messages",
|
"prompt": "Tool progress (deprecated — use config.yaml)",
|
||||||
"url": None,
|
"url": None,
|
||||||
"password": False,
|
"password": False,
|
||||||
"category": "setting",
|
"category": "setting",
|
||||||
},
|
},
|
||||||
"HERMES_TOOL_PROGRESS_MODE": {
|
"HERMES_TOOL_PROGRESS_MODE": {
|
||||||
"description": "Progress mode: 'all' (every tool) or 'new' (only when tool changes)",
|
"description": "(deprecated) Use display.tool_progress in config.yaml instead",
|
||||||
"prompt": "Progress mode (all/new)",
|
"prompt": "Progress mode (deprecated — use config.yaml)",
|
||||||
"url": None,
|
"url": None,
|
||||||
"password": False,
|
"password": False,
|
||||||
"category": "setting",
|
"category": "setting",
|
||||||
|
|
@ -442,6 +445,29 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
|
||||||
# Check config version
|
# Check config version
|
||||||
current_ver, latest_ver = 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:
|
if current_ver < latest_ver and not quiet:
|
||||||
print(f"Config version: {current_ver} → {latest_ver}")
|
print(f"Config version: {current_ver} → {latest_ver}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1044,27 +1044,25 @@ def run_setup_wizard(args):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print_warning("Invalid number, keeping current value")
|
print_warning("Invalid number, keeping current value")
|
||||||
|
|
||||||
# Tool progress notifications (for messaging)
|
# Tool progress notifications
|
||||||
print_info("")
|
print_info("")
|
||||||
print_info("Tool Progress Notifications (Messaging only)")
|
print_info("Tool Progress Display")
|
||||||
print_info("Send status messages when the agent uses tools.")
|
print_info("Controls how much tool activity is shown (CLI and messaging).")
|
||||||
print_info("Example: '💻 ls -la...' or '🔍 web_search...'")
|
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'
|
current_mode = config.get("display", {}).get("tool_progress", "all")
|
||||||
if prompt_yes_no("Enable tool progress messages?", current_progress.lower() in ('1', 'true', 'yes')):
|
mode = prompt("Tool progress mode", current_mode)
|
||||||
save_env_value("HERMES_TOOL_PROGRESS", "true")
|
if mode.lower() in ("off", "new", "all", "verbose"):
|
||||||
|
if "display" not in config:
|
||||||
# Progress mode
|
config["display"] = {}
|
||||||
current_mode = get_env_value('HERMES_TOOL_PROGRESS_MODE') or 'all'
|
config["display"]["tool_progress"] = mode.lower()
|
||||||
print_info(" Mode options:")
|
save_config(config)
|
||||||
print_info(" 'new' - Only when switching tools (less spam)")
|
print_success(f"Tool progress set to: {mode.lower()}")
|
||||||
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")
|
|
||||||
else:
|
else:
|
||||||
save_env_value("HERMES_TOOL_PROGRESS", "false")
|
print_warning(f"Unknown mode '{mode}', keeping '{current_mode}'")
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# Step 6: Context Compression
|
# Step 6: Context Compression
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue