chore: fix 154 f-strings, simplify getattr/URL patterns, remove dead code (#3119)
Three categories of cleanup, all zero-behavioral-change:
1. F-strings without placeholders (154 fixes across 29 files)
- Converted f'...' to '...' where no {expression} was present
- Heaviest files: run_agent.py (24), cli.py (20), honcho_integration/cli.py (34)
2. Simplify defensive patterns in run_agent.py
- Added explicit self._is_anthropic_oauth = False in __init__ (before
the api_mode branch that conditionally sets it)
- Replaced 7x getattr(self, '_is_anthropic_oauth', False) with direct
self._is_anthropic_oauth (attribute always initialized now)
- Added _is_openrouter_url() and _is_anthropic_url() helper methods
- Replaced 3 inline 'openrouter' in self._base_url_lower checks
3. Remove dead code in small files
- hermes_cli/claw.py: removed unused 'total' computation
- tools/fuzzy_match.py: removed unused strip_indent() function and
pattern_stripped variable
Full test suite: 6184 passed, 0 failures
E2E PTY: banner clean, tool calls work, zero garbled ANSI
This commit is contained in:
@@ -2012,7 +2012,7 @@ def _login_openai_codex(args, pconfig: ProviderConfig) -> None:
|
||||
config_path = _update_config_for_provider("openai-codex", creds.get("base_url", DEFAULT_CODEX_BASE_URL))
|
||||
print()
|
||||
print("Login successful!")
|
||||
print(f" Auth state: ~/.hermes/auth.json")
|
||||
print(" Auth state: ~/.hermes/auth.json")
|
||||
print(f" Config updated: {config_path} (model.provider=openai-codex)")
|
||||
|
||||
|
||||
@@ -2056,9 +2056,9 @@ def _codex_device_code_login() -> Dict[str, Any]:
|
||||
|
||||
# Step 2: Show user the code
|
||||
print("To continue, follow these steps:\n")
|
||||
print(f" 1. Open this URL in your browser:")
|
||||
print(" 1. Open this URL in your browser:")
|
||||
print(f" \033[94m{issuer}/codex/device\033[0m\n")
|
||||
print(f" 2. Enter this code:")
|
||||
print(" 2. Enter this code:")
|
||||
print(f" \033[94m{user_code}\033[0m\n")
|
||||
print("Waiting for sign-in... (press Ctrl+C to cancel)")
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ def _cmd_migrate(args):
|
||||
print()
|
||||
print_error(f"OpenClaw directory not found: {source_dir}")
|
||||
print_info("Make sure your OpenClaw installation is at the expected path.")
|
||||
print_info(f"You can specify a custom path: hermes claw migrate --source /path/to/.openclaw")
|
||||
print_info("You can specify a custom path: hermes claw migrate --source /path/to/.openclaw")
|
||||
return
|
||||
|
||||
# Find the migration script
|
||||
@@ -206,7 +206,6 @@ def _print_migration_report(report: dict, dry_run: bool):
|
||||
skipped = summary.get("skipped", 0)
|
||||
conflicts = summary.get("conflict", 0)
|
||||
errors = summary.get("error", 0)
|
||||
total = migrated + skipped + conflicts + errors
|
||||
|
||||
print()
|
||||
if dry_run:
|
||||
@@ -240,7 +239,7 @@ def _print_migration_report(report: dict, dry_run: bool):
|
||||
print()
|
||||
|
||||
if conflict_items:
|
||||
print(color(f" ⚠ Conflicts (skipped — use --overwrite to force):", Colors.YELLOW))
|
||||
print(color(" ⚠ Conflicts (skipped — use --overwrite to force):", Colors.YELLOW))
|
||||
for item in conflict_items:
|
||||
kind = item.get("kind", "unknown")
|
||||
reason = item.get("reason", "already exists")
|
||||
@@ -248,7 +247,7 @@ def _print_migration_report(report: dict, dry_run: bool):
|
||||
print()
|
||||
|
||||
if skipped_items:
|
||||
print(color(f" ─ Skipped:", Colors.DIM))
|
||||
print(color(" ─ Skipped:", Colors.DIM))
|
||||
for item in skipped_items:
|
||||
kind = item.get("kind", "unknown")
|
||||
reason = item.get("reason", "")
|
||||
@@ -256,7 +255,7 @@ def _print_migration_report(report: dict, dry_run: bool):
|
||||
print()
|
||||
|
||||
if error_items:
|
||||
print(color(f" ✗ Errors:", Colors.RED))
|
||||
print(color(" ✗ Errors:", Colors.RED))
|
||||
for item in error_items:
|
||||
kind = item.get("kind", "unknown")
|
||||
reason = item.get("reason", "unknown error")
|
||||
|
||||
@@ -705,7 +705,7 @@ def run_doctor(args):
|
||||
_honcho_cfg_path = resolve_config_path()
|
||||
|
||||
if not _honcho_cfg_path.exists():
|
||||
check_warn("Honcho config not found", f"run: hermes honcho setup")
|
||||
check_warn("Honcho config not found", "run: hermes honcho setup")
|
||||
elif not hcfg.enabled:
|
||||
check_info(f"Honcho disabled (set enabled: true in {_honcho_cfg_path} to activate)")
|
||||
elif not hcfg.api_key:
|
||||
|
||||
@@ -1332,9 +1332,9 @@ def _setup_standard_platform(platform: dict):
|
||||
|
||||
# Allowlist fields get special handling for the deny-by-default security model
|
||||
if var.get("is_allowlist"):
|
||||
print_info(f" The gateway DENIES all users by default for security.")
|
||||
print_info(f" Enter user IDs to create an allowlist, or leave empty")
|
||||
print_info(f" and you'll be asked about open access next.")
|
||||
print_info(" The gateway DENIES all users by default for security.")
|
||||
print_info(" Enter user IDs to create an allowlist, or leave empty")
|
||||
print_info(" and you'll be asked about open access next.")
|
||||
value = prompt(f" {var['prompt']}", password=False)
|
||||
if value:
|
||||
cleaned = value.replace(" ", "")
|
||||
@@ -1351,7 +1351,7 @@ def _setup_standard_platform(platform: dict):
|
||||
parts.append(uid)
|
||||
cleaned = ",".join(parts)
|
||||
save_env_value(var["name"], cleaned)
|
||||
print_success(f" Saved — only these users can interact with the bot.")
|
||||
print_success(" Saved — only these users can interact with the bot.")
|
||||
allowed_val_set = cleaned
|
||||
else:
|
||||
# No allowlist — ask about open access vs DM pairing
|
||||
@@ -1380,7 +1380,7 @@ def _setup_standard_platform(platform: dict):
|
||||
print_warning(f" Skipped — {label} won't work without this.")
|
||||
return
|
||||
else:
|
||||
print_info(f" Skipped (can configure later)")
|
||||
print_info(" Skipped (can configure later)")
|
||||
|
||||
# If an allowlist was set and home channel wasn't, offer to reuse
|
||||
# the first user ID (common for Telegram DMs).
|
||||
@@ -1556,7 +1556,7 @@ def _setup_signal():
|
||||
print_success("Signal configured!")
|
||||
print_info(f" URL: {url}")
|
||||
print_info(f" Account: {account}")
|
||||
print_info(f" DM auth: via SIGNAL_ALLOWED_USERS + DM pairing")
|
||||
print_info(" DM auth: via SIGNAL_ALLOWED_USERS + DM pairing")
|
||||
print_info(f" Groups: {'enabled' if get_env_value('SIGNAL_GROUP_ALLOWED_USERS') else 'disabled'}")
|
||||
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ def _session_browse_picker(sessions: list) -> Optional[str]:
|
||||
return sessions[idx]["id"]
|
||||
print(f" Invalid selection. Enter 1-{len(sessions)} or q to cancel.")
|
||||
except ValueError:
|
||||
print(f" Invalid input. Enter a number or q to cancel.")
|
||||
print(" Invalid input. Enter a number or q to cancel.")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print()
|
||||
return None
|
||||
@@ -2038,8 +2038,8 @@ def _model_flow_api_key_provider(config, provider_id, current_model=""):
|
||||
else:
|
||||
model_list = _PROVIDER_MODELS.get(provider_id, [])
|
||||
if model_list:
|
||||
print(f" ⚠ Could not auto-detect models from API — showing defaults.")
|
||||
print(f" Use \"Enter custom model name\" if you don't see your model.")
|
||||
print(" ⚠ Could not auto-detect models from API — showing defaults.")
|
||||
print(" Use \"Enter custom model name\" if you don't see your model.")
|
||||
# else: no defaults either, will fall through to raw input
|
||||
|
||||
if model_list:
|
||||
|
||||
@@ -72,10 +72,10 @@ def _cmd_approve(store, platform: str, code: str):
|
||||
name = result.get("user_name", "")
|
||||
display = f"{name} ({uid})" if name else uid
|
||||
print(f"\n Approved! User {display} on {platform} can now use the bot~")
|
||||
print(f" They'll be recognized automatically on their next message.\n")
|
||||
print(" They'll be recognized automatically on their next message.\n")
|
||||
else:
|
||||
print(f"\n Code '{code}' not found or expired for platform '{platform}'.")
|
||||
print(f" Run 'hermes pairing list' to see pending codes.\n")
|
||||
print(" Run 'hermes pairing list' to see pending codes.\n")
|
||||
|
||||
|
||||
def _cmd_revoke(store, platform: str, user_id: str):
|
||||
|
||||
@@ -390,7 +390,7 @@ def cmd_list() -> None:
|
||||
dirs = sorted(d for d in plugins_dir.iterdir() if d.is_dir())
|
||||
if not dirs:
|
||||
console.print("[dim]No plugins installed.[/dim]")
|
||||
console.print(f"[dim]Install with:[/dim] hermes plugins install owner/repo")
|
||||
console.print("[dim]Install with:[/dim] hermes plugins install owner/repo")
|
||||
return
|
||||
|
||||
table = Table(title="Installed Plugins", show_lines=False)
|
||||
|
||||
@@ -548,9 +548,9 @@ def _prompt_api_key(var: dict):
|
||||
|
||||
if value:
|
||||
save_env_value(var["name"], value)
|
||||
print_success(f" ✓ Saved")
|
||||
print_success(" ✓ Saved")
|
||||
else:
|
||||
print_warning(f" Skipped (configure later with 'hermes setup')")
|
||||
print_warning(" Skipped (configure later with 'hermes setup')")
|
||||
|
||||
|
||||
def _print_setup_summary(config: dict, hermes_home):
|
||||
@@ -725,9 +725,9 @@ def _print_setup_summary(config: dict, hermes_home):
|
||||
f" {color('hermes config edit', Colors.GREEN)} Open config in your editor"
|
||||
)
|
||||
print(f" {color('hermes config set <key> <value>', Colors.GREEN)}")
|
||||
print(f" Set a specific value")
|
||||
print(" Set a specific value")
|
||||
print()
|
||||
print(f" Or edit the files directly:")
|
||||
print(" Or edit the files directly:")
|
||||
print(f" {color(f'nano {get_config_path()}', Colors.DIM)}")
|
||||
print(f" {color(f'nano {get_env_path()}', Colors.DIM)}")
|
||||
print()
|
||||
@@ -755,13 +755,13 @@ def _prompt_container_resources(config: dict):
|
||||
print_info(" Persistent filesystem keeps files between sessions.")
|
||||
print_info(" Set to 'no' for ephemeral sandboxes that reset each time.")
|
||||
persist_str = prompt(
|
||||
f" Persist filesystem across sessions? (yes/no)", persist_label
|
||||
" Persist filesystem across sessions? (yes/no)", persist_label
|
||||
)
|
||||
terminal["container_persistent"] = persist_str.lower() in ("yes", "true", "y", "1")
|
||||
|
||||
# CPU
|
||||
current_cpu = terminal.get("container_cpu", 1)
|
||||
cpu_str = prompt(f" CPU cores", str(current_cpu))
|
||||
cpu_str = prompt(" CPU cores", str(current_cpu))
|
||||
try:
|
||||
terminal["container_cpu"] = float(cpu_str)
|
||||
except ValueError:
|
||||
@@ -769,7 +769,7 @@ def _prompt_container_resources(config: dict):
|
||||
|
||||
# Memory
|
||||
current_mem = terminal.get("container_memory", 5120)
|
||||
mem_str = prompt(f" Memory in MB (5120 = 5GB)", str(current_mem))
|
||||
mem_str = prompt(" Memory in MB (5120 = 5GB)", str(current_mem))
|
||||
try:
|
||||
terminal["container_memory"] = int(mem_str)
|
||||
except ValueError:
|
||||
@@ -777,7 +777,7 @@ def _prompt_container_resources(config: dict):
|
||||
|
||||
# Disk
|
||||
current_disk = terminal.get("container_disk", 51200)
|
||||
disk_str = prompt(f" Disk in MB (51200 = 50GB)", str(current_disk))
|
||||
disk_str = prompt(" Disk in MB (51200 = 50GB)", str(current_disk))
|
||||
try:
|
||||
terminal["container_disk"] = int(disk_str)
|
||||
except ValueError:
|
||||
@@ -3441,9 +3441,9 @@ def _run_quick_setup(config: dict, hermes_home):
|
||||
value = prompt(f" {var.get('prompt', var['name'])}")
|
||||
if value:
|
||||
save_env_value(var["name"], value)
|
||||
print_success(f" ✓ Saved")
|
||||
print_success(" ✓ Saved")
|
||||
else:
|
||||
print_warning(f" Skipped")
|
||||
print_warning(" Skipped")
|
||||
print()
|
||||
|
||||
# Handle missing config fields
|
||||
|
||||
@@ -289,7 +289,7 @@ def show_status(args):
|
||||
)
|
||||
is_active = result.stdout.strip() == "active"
|
||||
print(f" Status: {check_mark(is_active)} {'running' if is_active else 'stopped'}")
|
||||
print(f" Manager: systemd (user)")
|
||||
print(" Manager: systemd (user)")
|
||||
|
||||
elif sys.platform == 'darwin':
|
||||
result = subprocess.run(
|
||||
@@ -299,10 +299,10 @@ def show_status(args):
|
||||
)
|
||||
is_loaded = result.returncode == 0
|
||||
print(f" Status: {check_mark(is_loaded)} {'loaded' if is_loaded else 'not loaded'}")
|
||||
print(f" Manager: launchd")
|
||||
print(" Manager: launchd")
|
||||
else:
|
||||
print(f" Status: {color('N/A', Colors.DIM)}")
|
||||
print(f" Manager: (not supported on this platform)")
|
||||
print(" Manager: (not supported on this platform)")
|
||||
|
||||
# =========================================================================
|
||||
# Cron Jobs
|
||||
@@ -320,9 +320,9 @@ def show_status(args):
|
||||
enabled_jobs = [j for j in jobs if j.get("enabled", True)]
|
||||
print(f" Jobs: {len(enabled_jobs)} active, {len(jobs)} total")
|
||||
except Exception:
|
||||
print(f" Jobs: (error reading jobs file)")
|
||||
print(" Jobs: (error reading jobs file)")
|
||||
else:
|
||||
print(f" Jobs: 0")
|
||||
print(" Jobs: 0")
|
||||
|
||||
# =========================================================================
|
||||
# Sessions
|
||||
@@ -338,9 +338,9 @@ def show_status(args):
|
||||
data = json.load(f)
|
||||
print(f" Active: {len(data)} session(s)")
|
||||
except Exception:
|
||||
print(f" Active: (error reading sessions file)")
|
||||
print(" Active: (error reading sessions file)")
|
||||
else:
|
||||
print(f" Active: 0")
|
||||
print(" Active: 0")
|
||||
|
||||
# =========================================================================
|
||||
# Deep checks
|
||||
|
||||
@@ -659,7 +659,7 @@ def _configure_tool_category(ts_key: str, cat: dict, config: dict):
|
||||
# Multiple providers - let user choose
|
||||
print()
|
||||
# Use custom title if provided (e.g. "Select Search Provider")
|
||||
title = cat.get("setup_title", f"Choose a provider")
|
||||
title = cat.get("setup_title", "Choose a provider")
|
||||
print(color(f" --- {icon} {name} - {title} ---", Colors.CYAN))
|
||||
if cat.get("setup_note"):
|
||||
_print_info(f" {cat['setup_note']}")
|
||||
@@ -768,9 +768,9 @@ def _configure_provider(provider: dict, config: dict):
|
||||
|
||||
if value:
|
||||
save_env_value(var["key"], value)
|
||||
_print_success(f" Saved")
|
||||
_print_success(" Saved")
|
||||
else:
|
||||
_print_warning(f" Skipped")
|
||||
_print_warning(" Skipped")
|
||||
all_configured = False
|
||||
|
||||
# Run post-setup hooks if needed
|
||||
@@ -834,9 +834,9 @@ def _configure_simple_requirements(ts_key: str):
|
||||
value = _prompt(f" {var}", password=True)
|
||||
if value and value.strip():
|
||||
save_env_value(var, value.strip())
|
||||
_print_success(f" Saved")
|
||||
_print_success(" Saved")
|
||||
else:
|
||||
_print_warning(f" Skipped")
|
||||
_print_warning(" Skipped")
|
||||
|
||||
|
||||
def _reconfigure_tool(config: dict):
|
||||
@@ -924,7 +924,7 @@ def _reconfigure_provider(provider: dict, config: dict):
|
||||
_print_success(f" Browser cloud provider set to: {bp}")
|
||||
else:
|
||||
config.get("browser", {}).pop("cloud_provider", None)
|
||||
_print_success(f" Browser set to local mode")
|
||||
_print_success(" Browser set to local mode")
|
||||
|
||||
# Set web search backend in config if applicable
|
||||
if provider.get("web_backend"):
|
||||
@@ -946,9 +946,9 @@ def _reconfigure_provider(provider: dict, config: dict):
|
||||
value = _prompt(f" {var.get('prompt', var['key'])} (Enter to keep current)", password=not default_val)
|
||||
if value and value.strip():
|
||||
save_env_value(var["key"], value.strip())
|
||||
_print_success(f" Updated")
|
||||
_print_success(" Updated")
|
||||
else:
|
||||
_print_info(f" Kept current")
|
||||
_print_info(" Kept current")
|
||||
|
||||
|
||||
def _reconfigure_simple_requirements(ts_key: str):
|
||||
@@ -970,9 +970,9 @@ def _reconfigure_simple_requirements(ts_key: str):
|
||||
value = _prompt(f" {var} (Enter to keep current)", password=True)
|
||||
if value and value.strip():
|
||||
save_env_value(var, value.strip())
|
||||
_print_success(f" Updated")
|
||||
_print_success(" Updated")
|
||||
else:
|
||||
_print_info(f" Kept current")
|
||||
_print_info(" Kept current")
|
||||
|
||||
|
||||
# ─── Main Entry Point ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -273,7 +273,7 @@ def run_uninstall(args):
|
||||
log_info("No wrapper script found")
|
||||
|
||||
# 4. Remove installation directory (code)
|
||||
log_info(f"Removing installation directory...")
|
||||
log_info("Removing installation directory...")
|
||||
|
||||
# Check if we're running from within the install dir
|
||||
# We need to be careful here
|
||||
|
||||
Reference in New Issue
Block a user