mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336)
ruff check --fix --select F541 . on current main. Pure prefix removals; adjacent-string concatenations keep the f only on interpolating fragments. No string content or live placeholder altered.
This commit is contained in:
parent
3d0276182a
commit
55e3ee1ab8
65 changed files with 215 additions and 215 deletions
|
|
@ -617,7 +617,7 @@ def _format_session_search_result(result: Optional[str]) -> Optional[str]:
|
|||
return None
|
||||
mode = data.get("mode") or "search"
|
||||
query = data.get("query")
|
||||
lines = ["Recent sessions" if mode == "recent" else f"Session search results" + (f" for `{query}`" if query else "")]
|
||||
lines = ["Recent sessions" if mode == "recent" else "Session search results" + (f" for `{query}`" if query else "")]
|
||||
if not results:
|
||||
lines.append(str(data.get("message") or "No matching sessions found."))
|
||||
return "\n".join(lines)
|
||||
|
|
|
|||
|
|
@ -1509,7 +1509,7 @@ def run_conversation(
|
|||
elif _resp_error_code == 504:
|
||||
_failure_hint = f"upstream gateway timeout (504, {api_duration:.0f}s)"
|
||||
elif _resp_error_code == 429:
|
||||
_failure_hint = f"rate limited by upstream provider (429)"
|
||||
_failure_hint = "rate limited by upstream provider (429)"
|
||||
elif _resp_error_code in {500, 502}:
|
||||
_failure_hint = f"upstream server error ({_resp_error_code}, {api_duration:.0f}s)"
|
||||
elif _resp_error_code in {503, 529}:
|
||||
|
|
@ -2350,11 +2350,11 @@ def run_conversation(
|
|||
agent._unicode_sanitization_passes += 1
|
||||
if _surrogates_found:
|
||||
agent._buffer_vprint(
|
||||
f"⚠️ Stripped invalid surrogate characters from messages. Retrying..."
|
||||
"⚠️ Stripped invalid surrogate characters from messages. Retrying..."
|
||||
)
|
||||
else:
|
||||
agent._buffer_vprint(
|
||||
f"⚠️ Surrogate encoding error — retrying after full-payload sanitization..."
|
||||
"⚠️ Surrogate encoding error — retrying after full-payload sanitization..."
|
||||
)
|
||||
continue
|
||||
if _is_ascii_codec:
|
||||
|
|
@ -2761,7 +2761,7 @@ def run_conversation(
|
|||
):
|
||||
_retry.copilot_auth_retry_attempted = True
|
||||
if agent._try_refresh_copilot_client_credentials():
|
||||
agent._buffer_vprint(f"🔐 Copilot credentials refreshed after 401. Retrying request...")
|
||||
agent._buffer_vprint("🔐 Copilot credentials refreshed after 401. Retrying request...")
|
||||
continue
|
||||
if (
|
||||
agent.api_mode == "anthropic_messages"
|
||||
|
|
@ -2984,10 +2984,10 @@ def run_conversation(
|
|||
)
|
||||
if agent.providers_allowed:
|
||||
agent._buffer_vprint(
|
||||
f" Your provider_routing.only restriction is filtering out tool-capable providers."
|
||||
" Your provider_routing.only restriction is filtering out tool-capable providers."
|
||||
)
|
||||
agent._buffer_vprint(
|
||||
f" Try removing the restriction or adding providers that support tools for this model."
|
||||
" Try removing the restriction or adding providers that support tools for this model."
|
||||
)
|
||||
agent._buffer_vprint(
|
||||
f" Check which providers support tools: https://openrouter.ai/models/{_model}"
|
||||
|
|
@ -4314,7 +4314,7 @@ def run_conversation(
|
|||
if has_incomplete_scratchpad(assistant_message.content or ""):
|
||||
agent._incomplete_scratchpad_retries += 1
|
||||
|
||||
agent._buffer_vprint(f"⚠️ Incomplete <REASONING_SCRATCHPAD> detected (opened but never closed)")
|
||||
agent._buffer_vprint("⚠️ Incomplete <REASONING_SCRATCHPAD> detected (opened but never closed)")
|
||||
|
||||
if agent._incomplete_scratchpad_retries <= 2:
|
||||
agent._buffer_vprint(f"🔄 Retrying API call ({agent._incomplete_scratchpad_retries}/2)...")
|
||||
|
|
@ -4549,7 +4549,7 @@ def run_conversation(
|
|||
else:
|
||||
# Instead of returning partial, inject tool error results so the model can recover.
|
||||
# Using tool results (not user messages) preserves role alternation.
|
||||
agent._buffer_vprint(f"⚠️ Injecting recovery tool results for invalid JSON...")
|
||||
agent._buffer_vprint("⚠️ Injecting recovery tool results for invalid JSON...")
|
||||
agent._invalid_json_retries = 0 # Reset for next attempt
|
||||
|
||||
# Append the assistant message with its (broken) tool_calls
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ def rollback(backup_id: Optional[str] = None) -> Tuple[bool, str, Optional[Path]
|
|||
if target is None:
|
||||
return (
|
||||
False,
|
||||
f"no matching backup found"
|
||||
"no matching backup found"
|
||||
+ (f" for id '{backup_id}'" if backup_id else "")
|
||||
+ " (use `hermes curator rollback --list` to see available snapshots)",
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ async def read_message(reader: asyncio.StreamReader) -> Optional[dict]:
|
|||
header_bytes += len(line)
|
||||
if header_bytes > 8192:
|
||||
raise LSPProtocolError(
|
||||
f"LSP header block exceeded 8 KiB without terminator"
|
||||
"LSP header block exceeded 8 KiB without terminator"
|
||||
)
|
||||
line = line[:-2] # strip CRLF
|
||||
if not line:
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ def _encode_iterm(frame, *, cell_cols: int | None = None, cell_rows: int | None
|
|||
"""Encode one frame as an iTerm2 inline image (OSC 1337 File)."""
|
||||
payload = base64.standard_b64encode(_png_bytes(frame)).decode("ascii")
|
||||
size = len(payload)
|
||||
args = [f"inline=1", f"size={size}", "preserveAspectRatio=1"]
|
||||
args = ["inline=1", f"size={size}", "preserveAspectRatio=1"]
|
||||
if cell_cols:
|
||||
args.append(f"width={cell_cols}")
|
||||
if cell_rows:
|
||||
|
|
|
|||
4
cli.py
4
cli.py
|
|
@ -10048,8 +10048,8 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
_time.sleep(interval)
|
||||
|
||||
# Past the cap with no terminal state = timeout (not an error).
|
||||
print(f" 🟡 Still processing after 5 minutes — this is a timeout, not a "
|
||||
f"failure. Check /billing or the portal shortly.")
|
||||
print(" 🟡 Still processing after 5 minutes — this is a timeout, not a "
|
||||
"failure. Check /billing or the portal shortly.")
|
||||
self._billing_portal_hint(state)
|
||||
|
||||
def _billing_render_charge_failed(self, state, reason):
|
||||
|
|
|
|||
|
|
@ -2677,7 +2677,7 @@ class QQAdapter(BasePlatformAdapter):
|
|||
|
||||
req = ApprovalRequest(
|
||||
session_key=session_key,
|
||||
title=f"Execute this command?",
|
||||
title="Execute this command?",
|
||||
description=description,
|
||||
command_preview=command,
|
||||
timeout_sec=self._APPROVAL_TIMEOUT_SECONDS,
|
||||
|
|
|
|||
|
|
@ -536,7 +536,7 @@ def _interactive_auth() -> None:
|
|||
if has_aws_credentials():
|
||||
auth_source = resolve_aws_auth_env_var() or "unknown"
|
||||
region = resolve_bedrock_region()
|
||||
print(f"bedrock (AWS SDK credential chain):")
|
||||
print("bedrock (AWS SDK credential chain):")
|
||||
print(f" Auth: {auth_source}")
|
||||
print(f" Region: {region}")
|
||||
try:
|
||||
|
|
@ -546,7 +546,7 @@ def _interactive_auth() -> None:
|
|||
arn = identity.get("Arn", "unknown")
|
||||
print(f" Identity: {arn}")
|
||||
except Exception:
|
||||
print(f" Identity: (could not resolve — boto3 STS call failed)")
|
||||
print(" Identity: (could not resolve — boto3 STS call failed)")
|
||||
print()
|
||||
except ImportError:
|
||||
pass # boto3 or bedrock_adapter not available
|
||||
|
|
@ -574,7 +574,7 @@ def _interactive_auth() -> None:
|
|||
str(_entra.get("scope") or "").strip()
|
||||
or SCOPE_AI_AZURE_DEFAULT
|
||||
)
|
||||
print(f"azure-foundry (Microsoft Entra ID):")
|
||||
print("azure-foundry (Microsoft Entra ID):")
|
||||
print(f" Endpoint: {_base_url or '(not configured)'}")
|
||||
print(f" Scope: {_scope}")
|
||||
if not has_azure_identity_installed():
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ def run_backup(args) -> None:
|
|||
print(f" {p}")
|
||||
|
||||
if skipped_dirs:
|
||||
print(f"\n Excluded directories:")
|
||||
print("\n Excluded directories:")
|
||||
for d in sorted(skipped_dirs):
|
||||
print(f" {d}/")
|
||||
|
||||
|
|
@ -721,8 +721,8 @@ def run_import(args) -> None:
|
|||
except ImportError:
|
||||
# hermes_cli.profiles might not be available (fresh install)
|
||||
if any(profiles_dir.iterdir()):
|
||||
print(f"\n Profiles detected but aliases could not be created.")
|
||||
print(f" Run: hermes profile list (after installing hermes)")
|
||||
print("\n Profiles detected but aliases could not be created.")
|
||||
print(" Run: hermes profile list (after installing hermes)")
|
||||
|
||||
# Guidance
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ class CLICommandsMixin:
|
|||
home = gw_config.get_home_channel(platform)
|
||||
if not home or not home.chat_id:
|
||||
_cprint(f" No home channel configured for {platform_name}.")
|
||||
_cprint(f" Set one with /sethome on the destination chat first.")
|
||||
_cprint(" Set one with /sethome on the destination chat first.")
|
||||
return True
|
||||
|
||||
# Refuse mid-turn: an in-flight agent run would race with the
|
||||
|
|
@ -626,7 +626,7 @@ class CLICommandsMixin:
|
|||
return True
|
||||
|
||||
_cprint(f" Queued handoff of '{session_title}' → {platform_name} (home: {home.name}).")
|
||||
_cprint(f" Waiting for the gateway to pick it up...")
|
||||
_cprint(" Waiting for the gateway to pick it up...")
|
||||
|
||||
# Poll-block on terminal state. Tick every 0.5s; bail at ~60s.
|
||||
import time as _time
|
||||
|
|
@ -1872,7 +1872,7 @@ class CLICommandsMixin:
|
|||
sys_name = _plat.system()
|
||||
chrome_cmd = manual_chrome_debug_command(_port, sys_name)
|
||||
if chrome_cmd:
|
||||
print(f" Launch a Chromium-family browser manually:")
|
||||
print(" Launch a Chromium-family browser manually:")
|
||||
print(f" {chrome_cmd}")
|
||||
else:
|
||||
print(" No supported Chromium-family browser executable found in this environment")
|
||||
|
|
|
|||
|
|
@ -5282,8 +5282,8 @@ def warn_deprecated_cwd_env_vars(config: Optional[Dict[str, Any]] = None) -> Non
|
|||
hint_path = os.environ.get("HERMES_HOME", "~/.hermes")
|
||||
lines.insert(0, "\033[33m⚠ Deprecated .env settings detected:\033[0m")
|
||||
lines.append(
|
||||
f" \033[2mMove to config.yaml instead: "
|
||||
f"terminal:\\n cwd: /your/project/path\033[0m"
|
||||
" \033[2mMove to config.yaml instead: "
|
||||
"terminal:\\n cwd: /your/project/path\033[0m"
|
||||
)
|
||||
lines.append(
|
||||
f" \033[2mThen remove the old entries from {hint_path}/.env\033[0m"
|
||||
|
|
@ -5516,7 +5516,7 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
|
|||
config["stt"] = stt
|
||||
_persist_migration(config)
|
||||
if not quiet:
|
||||
print(f" ✓ Migrated legacy stt.model to provider-specific config")
|
||||
print(" ✓ Migrated legacy stt.model to provider-specific config")
|
||||
|
||||
# ── Version 14 → 15: add explicit gateway interim-message gate ──
|
||||
if current_ver < 15:
|
||||
|
|
@ -7261,8 +7261,8 @@ def _check_non_ascii_credential(key: str, value: str) -> str:
|
|||
f"\n"
|
||||
+ "\n".join(f" {line}" for line in bad_chars[:5])
|
||||
+ ("\n ... and more" if len(bad_chars) > 5 else "")
|
||||
+ f"\n\n The non-ASCII characters have been stripped automatically.\n"
|
||||
f" If authentication fails, re-copy the key from the provider's dashboard.\n",
|
||||
+ "\n\n The non-ASCII characters have been stripped automatically.\n"
|
||||
" If authentication fails, re-copy the key from the provider's dashboard.\n",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return sanitized
|
||||
|
|
|
|||
|
|
@ -863,7 +863,7 @@ def run_debug_share(args):
|
|||
|
||||
# Print results
|
||||
label_width = max(len(k) for k in result.urls)
|
||||
print(f"\nDebug report uploaded:")
|
||||
print("\nDebug report uploaded:")
|
||||
for label, url in result.urls.items():
|
||||
print(f" {label:<{label_width}} {url}")
|
||||
|
||||
|
|
@ -874,9 +874,9 @@ def run_debug_share(args):
|
|||
print(f"\n⏱ Pastes will auto-delete in {hours} hours.")
|
||||
|
||||
# Manual delete fallback
|
||||
print(f"To delete now: hermes debug delete <url>")
|
||||
print("To delete now: hermes debug delete <url>")
|
||||
|
||||
print(f"\nShare these links with the Hermes team for support.")
|
||||
print("\nShare these links with the Hermes team for support.")
|
||||
|
||||
|
||||
_NOUS_PRIVACY_NOTICE = """\
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ def dingtalk_qr_auth() -> Optional[Tuple[str, str]]:
|
|||
print()
|
||||
|
||||
if not render_qr_to_terminal(url):
|
||||
print_warning(f" QR code render failed, please open the link below to authorize:")
|
||||
print_warning(" QR code render failed, please open the link below to authorize:")
|
||||
|
||||
print()
|
||||
print_info(f" Or open this link manually: {url}")
|
||||
|
|
|
|||
|
|
@ -3169,7 +3169,7 @@ def _require_service_installed(action: str, system: bool = False) -> None:
|
|||
unit_path = get_systemd_unit_path(system=system)
|
||||
if not unit_path.exists():
|
||||
scope_flag = " --system" if system else ""
|
||||
print(f"✗ Gateway service is not installed")
|
||||
print("✗ Gateway service is not installed")
|
||||
print(f" Run: {'sudo ' if system else ''}hermes gateway install{scope_flag}")
|
||||
sys.exit(1)
|
||||
|
||||
|
|
|
|||
|
|
@ -355,11 +355,11 @@ def _rule_hallucinated_cards(task, events, runs, now, cfg) -> list[Diagnostic]:
|
|||
severity="error",
|
||||
title="Worker claimed cards that don't exist",
|
||||
detail=(
|
||||
f"The completing worker declared created_cards that either didn't "
|
||||
f"exist or weren't created by its profile. The completion was "
|
||||
f"blocked and the task stayed in its prior state. "
|
||||
f"Usually means the worker hallucinated ids instead of capturing "
|
||||
f"return values from kanban_create."
|
||||
"The completing worker declared created_cards that either didn't "
|
||||
"exist or weren't created by its profile. The completion was "
|
||||
"blocked and the task stayed in its prior state. "
|
||||
"Usually means the worker hallucinated ids instead of capturing "
|
||||
"return values from kanban_create."
|
||||
),
|
||||
actions=actions,
|
||||
first_seen_at=first,
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ def tail_log(
|
|||
log_path = get_hermes_home() / "logs" / filename
|
||||
if not log_path.exists():
|
||||
print(f"Log file not found: {log_path}")
|
||||
print(f"(Logs are created when Hermes runs — try 'hermes chat' first)")
|
||||
print("(Logs are created when Hermes runs — try 'hermes chat' first)")
|
||||
sys.exit(1)
|
||||
|
||||
# Parse --since into a datetime cutoff
|
||||
|
|
|
|||
|
|
@ -8716,8 +8716,8 @@ def _run_pre_update_backup(args) -> None:
|
|||
|
||||
print(f" Saved: {display_path} ({size_str}, {elapsed:.1f}s)")
|
||||
print(f" Restore: hermes import {out_path}")
|
||||
print(f" Disable: omit --backup (backups are off by default)")
|
||||
print(f" set updates.pre_update_backup: false in config.yaml")
|
||||
print(" Disable: omit --backup (backups are off by default)")
|
||||
print(" set updates.pre_update_backup: false in config.yaml")
|
||||
print()
|
||||
|
||||
|
||||
|
|
@ -9537,7 +9537,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
"✗ Authentication failed — check your git credentials or SSH key."
|
||||
)
|
||||
else:
|
||||
print(f"✗ Failed to fetch updates from origin.")
|
||||
print("✗ Failed to fetch updates from origin.")
|
||||
if stderr:
|
||||
print(f" {stderr.splitlines()[0]}")
|
||||
sys.exit(1)
|
||||
|
|
@ -9801,7 +9801,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
print(
|
||||
f" ℹ️ Local changes preserved in stash (ref: {auto_stash_ref})"
|
||||
)
|
||||
print(f" Restore manually with: git stash apply")
|
||||
print(" Restore manually with: git stash apply")
|
||||
elif discard_local_changes:
|
||||
# Non-interactive update + user opted into discarding local
|
||||
# source edits (updates.non_interactive_local_changes:
|
||||
|
|
@ -11150,7 +11150,7 @@ def cmd_profile(args):
|
|||
try:
|
||||
set_active_profile(name)
|
||||
if name == "default":
|
||||
print(f"Switched to: default (~/.hermes)")
|
||||
print("Switched to: default (~/.hermes)")
|
||||
else:
|
||||
print(f"Switched to: {name}")
|
||||
except (ValueError, FileNotFoundError) as e:
|
||||
|
|
@ -11239,9 +11239,9 @@ def cmd_profile(args):
|
|||
if not _is_wrapper_dir_in_path():
|
||||
print(f"\n⚠ {_get_wrapper_dir()} is not in your PATH.")
|
||||
print(
|
||||
f" Add to your shell config (~/.bashrc or ~/.zshrc):"
|
||||
" Add to your shell config (~/.bashrc or ~/.zshrc):"
|
||||
)
|
||||
print(f' export PATH="$HOME/.local/bin:$PATH"')
|
||||
print(' export PATH="$HOME/.local/bin:$PATH"')
|
||||
|
||||
# Profile dir for display
|
||||
try:
|
||||
|
|
@ -11250,7 +11250,7 @@ def cmd_profile(args):
|
|||
profile_dir_display = str(profile_dir)
|
||||
|
||||
# Next steps
|
||||
print(f"\nNext steps:")
|
||||
print("\nNext steps:")
|
||||
print(f" {name} setup Configure API keys and model")
|
||||
print(f" {name} chat Start chatting")
|
||||
print(f" {name} gateway start Start the messaging gateway")
|
||||
|
|
@ -11261,7 +11261,7 @@ def cmd_profile(args):
|
|||
print(
|
||||
f"\n ⚠ This profile has no API keys yet. Run '{name} setup' first,"
|
||||
)
|
||||
print(f" or it will inherit keys from your shell environment.")
|
||||
print(" or it will inherit keys from your shell environment.")
|
||||
print(f" Edit {profile_dir_display}/SOUL.md to customize personality")
|
||||
print()
|
||||
|
||||
|
|
@ -12559,7 +12559,7 @@ def cmd_memory(args):
|
|||
)
|
||||
return
|
||||
|
||||
print(f"\n This will permanently erase the following memory files:")
|
||||
print("\n This will permanently erase the following memory files:")
|
||||
for f, desc in existing:
|
||||
path = mem_dir / f
|
||||
size = path.stat().st_size
|
||||
|
|
@ -12580,7 +12580,7 @@ def cmd_memory(args):
|
|||
print(f" ✓ Deleted {f} ({desc})")
|
||||
|
||||
print(
|
||||
f"\n Memory reset complete. New sessions will start with a blank slate."
|
||||
"\n Memory reset complete. New sessions will start with a blank slate."
|
||||
)
|
||||
print(f" Files were in: {display_hermes_home()}/memories/\n")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -766,13 +766,13 @@ def _reauth_oauth_server(name: str, server_config: dict) -> bool:
|
|||
"OAuth client yourself and add its credentials to config.yaml:"
|
||||
)
|
||||
print()
|
||||
print(color(f" mcp_servers:", Colors.DIM))
|
||||
print(color(" mcp_servers:", Colors.DIM))
|
||||
print(color(f" {name}:", Colors.DIM))
|
||||
print(color(f" url: {url}", Colors.DIM))
|
||||
print(color(f" auth: oauth", Colors.DIM))
|
||||
print(color(f" oauth:", Colors.DIM))
|
||||
print(color(f" client_id: \"<your-oauth-client-id>\"", Colors.DIM))
|
||||
print(color(f" client_secret: \"<your-oauth-client-secret>\"", Colors.DIM))
|
||||
print(color(" auth: oauth", Colors.DIM))
|
||||
print(color(" oauth:", Colors.DIM))
|
||||
print(color(" client_id: \"<your-oauth-client-id>\"", Colors.DIM))
|
||||
print(color(" client_secret: \"<your-oauth-client-secret>\"", Colors.DIM))
|
||||
print()
|
||||
_info("Then re-run `hermes mcp login " + name + "`.")
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -131,11 +131,11 @@ def _install_dependencies(provider_name: str) -> None:
|
|||
else:
|
||||
pip_cmd = shutil.which("pip3") or shutil.which("pip")
|
||||
if not pip_cmd:
|
||||
print(f" ⚠ uv not found — cannot install dependencies")
|
||||
print(f" Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh")
|
||||
print(f" Then re-run: hermes memory setup")
|
||||
print(" ⚠ uv not found — cannot install dependencies")
|
||||
print(" Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh")
|
||||
print(" Then re-run: hermes memory setup")
|
||||
return
|
||||
print(f" ⚠ uv not found. Falling back to standard pip...")
|
||||
print(" ⚠ uv not found. Falling back to standard pip...")
|
||||
install_cmd = [sys.executable, "-m", "pip", "install", "--quiet"] + missing
|
||||
manual_cmd = f"{sys.executable} -m pip install {' '.join(missing)}"
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ def cmd_setup_provider(provider_name: str) -> None:
|
|||
config["memory"]["provider"] = name
|
||||
save_config(config)
|
||||
print(f"\n Memory provider: {name}")
|
||||
print(f" Activation saved to config.yaml\n")
|
||||
print(" Activation saved to config.yaml\n")
|
||||
|
||||
|
||||
def cmd_setup(args) -> None:
|
||||
|
|
@ -388,12 +388,12 @@ def cmd_setup(args) -> None:
|
|||
_write_env_vars(env_path, env_writes)
|
||||
|
||||
print(f"\n Memory provider: {name}")
|
||||
print(f" Activation saved to config.yaml")
|
||||
print(" Activation saved to config.yaml")
|
||||
if provider_config:
|
||||
print(f" Provider config saved")
|
||||
print(" Provider config saved")
|
||||
if env_writes:
|
||||
print(f" API keys saved to .env")
|
||||
print(f"\n Start a new session to activate.\n")
|
||||
print(" API keys saved to .env")
|
||||
print("\n Start a new session to activate.\n")
|
||||
|
||||
|
||||
def _write_env_vars(env_path: Path, env_writes: dict) -> None:
|
||||
|
|
@ -439,8 +439,8 @@ def cmd_status(args) -> None:
|
|||
mem_config = config.get("memory", {})
|
||||
provider_name = mem_config.get("provider", "")
|
||||
|
||||
print(f"\nMemory status\n" + "─" * 40)
|
||||
print(f" Built-in: always active")
|
||||
print("\nMemory status\n" + "─" * 40)
|
||||
print(" Built-in: always active")
|
||||
print(f" Provider: {provider_name or '(none — built-in only)'}")
|
||||
|
||||
providers = _get_available_providers()
|
||||
|
|
@ -467,16 +467,16 @@ def cmd_status(args) -> None:
|
|||
print(f" {key}: {val}")
|
||||
|
||||
if provider:
|
||||
print(f"\n Plugin: installed ✓")
|
||||
print("\n Plugin: installed ✓")
|
||||
if provider.is_available():
|
||||
print(f" Status: available ✓")
|
||||
print(" Status: available ✓")
|
||||
else:
|
||||
print(f" Status: not available ✗")
|
||||
print(" Status: not available ✗")
|
||||
schema = provider.get_config_schema() if hasattr(provider, "get_config_schema") else []
|
||||
# Check all fields that have env_var (both secret and non-secret)
|
||||
required_fields = [f for f in schema if f.get("env_var")]
|
||||
if required_fields:
|
||||
print(f" Missing:")
|
||||
print(" Missing:")
|
||||
for f in required_fields:
|
||||
env_var = f.get("env_var", "")
|
||||
url = f.get("url", "")
|
||||
|
|
@ -487,11 +487,11 @@ def cmd_status(args) -> None:
|
|||
line += f" → {url}"
|
||||
print(line)
|
||||
else:
|
||||
print(f"\n Plugin: NOT installed ✗")
|
||||
print("\n Plugin: NOT installed ✗")
|
||||
print(f" Install the '{provider_name}' memory plugin to ~/.hermes/plugins/")
|
||||
|
||||
if providers:
|
||||
print(f"\n Installed plugins:")
|
||||
print("\n Installed plugins:")
|
||||
for pname, desc, _ in providers:
|
||||
active = " ← active" if pname == provider_name else ""
|
||||
print(f" • {pname} ({desc}){active}")
|
||||
|
|
|
|||
|
|
@ -831,8 +831,8 @@ def _model_flow_custom(config):
|
|||
)
|
||||
if _looks_local and not _url_lower.endswith("/v1"):
|
||||
print()
|
||||
print(f" Hint: Did you mean to add /v1 at the end?")
|
||||
print(f" Most local model servers (Ollama, vLLM, llama.cpp) require it.")
|
||||
print(" Hint: Did you mean to add /v1 at the end?")
|
||||
print(" Most local model servers (Ollama, vLLM, llama.cpp) require it.")
|
||||
print(f" e.g. {effective_url.rstrip('/')}/v1")
|
||||
try:
|
||||
_add_v1 = input(" Add /v1? [Y/n]: ").strip().lower()
|
||||
|
|
@ -1079,7 +1079,7 @@ def _model_flow_azure_foundry(config, current_model=""):
|
|||
)
|
||||
print(f" Current API mode: {_lbl}")
|
||||
if current_auth_mode == "entra_id":
|
||||
print(f" Current auth mode: Microsoft Entra ID (keyless)")
|
||||
print(" Current auth mode: Microsoft Entra ID (keyless)")
|
||||
elif current_api_key:
|
||||
print(f" Current auth mode: API key ({current_api_key[:8]}...)")
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ def _cmd_status(args) -> int:
|
|||
else:
|
||||
print(f" Auth: {color('not logged in', Colors.YELLOW)}")
|
||||
print(f" Sign up: {SUBSCRIPTION_URL}")
|
||||
print(f" Login: hermes portal")
|
||||
print(" Login: hermes portal")
|
||||
|
||||
# Provider selection (independent of auth)
|
||||
model_cfg = config.get("model") if isinstance(config.get("model"), dict) else {}
|
||||
|
|
|
|||
|
|
@ -1508,11 +1508,11 @@ def delete_profile(name: str, yes: bool = False) -> Path:
|
|||
if has_wrapper:
|
||||
items.append(f"Command alias ({wrapper_path})")
|
||||
|
||||
print(f"\nThis will permanently delete:")
|
||||
print("\nThis will permanently delete:")
|
||||
for item in items:
|
||||
print(f" • {item}")
|
||||
if gw_running:
|
||||
print(f" ⚠ Gateway is running — it will be stopped.")
|
||||
print(" ⚠ Gateway is running — it will be stopped.")
|
||||
|
||||
# Confirmation
|
||||
if not yes:
|
||||
|
|
@ -1736,7 +1736,7 @@ def _cleanup_gateway_service(name: str, profile_dir: Path) -> None:
|
|||
capture_output=True, check=False, timeout=10,
|
||||
)
|
||||
plist_path.unlink(missing_ok=True)
|
||||
print(f"✓ Launchd service removed")
|
||||
print("✓ Launchd service removed")
|
||||
except Exception as e:
|
||||
print(f"⚠ Service cleanup: {e}")
|
||||
finally:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ def handle_suggestions_command(
|
|||
return "Usage: /suggestions dismiss <number|id>"
|
||||
ok = store.dismiss_suggestion(rest)
|
||||
return (
|
||||
f"Dismissed. Won't suggest that again."
|
||||
"Dismissed. Won't suggest that again."
|
||||
if ok
|
||||
else f"No pending suggestion matches '{rest}'."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -212,9 +212,9 @@ def _cmd_subscribe(args):
|
|||
prompt_preview = route["prompt"][:80] + ("..." if len(route["prompt"]) > 80 else "")
|
||||
label = "Message" if route.get("deliver_only") else "Prompt"
|
||||
print(f" {label}: {prompt_preview}")
|
||||
print(f"\n Configure your service to POST to the URL above.")
|
||||
print(f" Use the secret for HMAC-SHA256 signature validation.")
|
||||
print(f" The gateway must be running to receive events (hermes gateway run).\n")
|
||||
print("\n Configure your service to POST to the URL above.")
|
||||
print(" Use the secret for HMAC-SHA256 signature validation.")
|
||||
print(" The gateway must be running to receive events (hermes gateway run).\n")
|
||||
|
||||
|
||||
def _cmd_list(args):
|
||||
|
|
|
|||
|
|
@ -311,12 +311,12 @@ def render_team_md(plan: dict) -> str:
|
|||
"",
|
||||
"## Per-task workspace requirement",
|
||||
"",
|
||||
f"All `kanban_create` calls MUST pass:",
|
||||
f"```",
|
||||
f'workspace_kind="dir"',
|
||||
"All `kanban_create` calls MUST pass:",
|
||||
"```",
|
||||
'workspace_kind="dir"',
|
||||
f'workspace_path="$HOME/projects/video-pipeline/{plan["slug"]}"',
|
||||
f'tenant="{plan["tenant"]}"',
|
||||
f"```",
|
||||
"```",
|
||||
])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ def bmi(weight_kg, height_cm):
|
|||
print(f"BMI: {val:.1f} — {cat}")
|
||||
print()
|
||||
print("Ranges:")
|
||||
print(f" Underweight : < 18.5")
|
||||
print(f" Normal : 18.5 – 24.9")
|
||||
print(f" Overweight : 25.0 – 29.9")
|
||||
print(f" Obese : 30.0+")
|
||||
print(" Underweight : < 18.5")
|
||||
print(" Normal : 18.5 – 24.9")
|
||||
print(" Overweight : 25.0 – 29.9")
|
||||
print(" Obese : 30.0+")
|
||||
|
||||
|
||||
def tdee(weight_kg, height_cm, age, sex, activity):
|
||||
|
|
@ -160,7 +160,7 @@ def bodyfat(sex, neck_cm, waist_cm, hip_cm, height_cm):
|
|||
break
|
||||
|
||||
print(f"Category: {cat}")
|
||||
print(f"Method: US Navy circumference formula")
|
||||
print("Method: US Navy circumference formula")
|
||||
|
||||
|
||||
def usage():
|
||||
|
|
|
|||
|
|
@ -3043,16 +3043,16 @@ def main() -> int:
|
|||
total = sum(s.values())
|
||||
|
||||
print()
|
||||
print(f" ╔══════════════════════════════════════════════════════╗")
|
||||
print(" ╔══════════════════════════════════════════════════════╗")
|
||||
print(f" ║ OpenClaw -> Hermes Migration [{mode_label:>8s}] ║")
|
||||
print(f" ╠══════════════════════════════════════════════════════╣")
|
||||
print(" ╠══════════════════════════════════════════════════════╣")
|
||||
print(f" ║ Source: {str(report['source_root'])[:42]:<42s} ║")
|
||||
print(f" ║ Target: {str(report['target_root'])[:42]:<42s} ║")
|
||||
print(f" ╠══════════════════════════════════════════════════════╣")
|
||||
print(" ╠══════════════════════════════════════════════════════╣")
|
||||
print(f" ║ ✔ Migrated: {s.get('migrated', 0):>3d} ◆ Archived: {s.get('archived', 0):>3d} ║")
|
||||
print(f" ║ ⊘ Skipped: {s.get('skipped', 0):>3d} ⚠ Conflicts: {s.get('conflict', 0):>3d} ║")
|
||||
print(f" ║ ✖ Errors: {s.get('error', 0):>3d} Total: {total:>3d} ║")
|
||||
print(f" ╚══════════════════════════════════════════════════════╝")
|
||||
print(" ╚══════════════════════════════════════════════════════╝")
|
||||
|
||||
# Show what was migrated
|
||||
migrated = [i for i in items if i["status"] == "migrated"]
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ def auto_jailbreak(model=None, base_url=None, api_key=None,
|
|||
|
||||
# Try with system prompt + prefill combined
|
||||
if verbose:
|
||||
print(f" [RETRY] Adding prefill messages...")
|
||||
print(" [RETRY] Adding prefill messages...")
|
||||
msgs = _build_messages(
|
||||
system_prompt=system_prompt,
|
||||
prefill=STANDARD_PREFILL,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class AudioBridge:
|
|||
"load-module",
|
||||
"module-null-sink",
|
||||
f"sink_name={sink_name}",
|
||||
f"sink_properties=device.description=HermesMeetSink",
|
||||
"sink_properties=device.description=HermesMeetSink",
|
||||
],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ def _cmd_auth() -> int:
|
|||
path = _auth_state_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print(f"opening Chromium — sign in to Google, then return here and press Enter.")
|
||||
print("opening Chromium — sign in to Google, then return here and press Enter.")
|
||||
print(f"saving storage state to: {path}")
|
||||
try:
|
||||
with sync_playwright() as pw:
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ def node_command(args: argparse.Namespace) -> int:
|
|||
print(f"[meet-node] display_name={server.display_name}")
|
||||
print(f"[meet-node] listening on ws://{args.host}:{args.port}")
|
||||
print(f"[meet-node] token (copy to gateway): {token}")
|
||||
print(f"[meet-node] approve with:")
|
||||
print("[meet-node] approve with:")
|
||||
print(f" hermes meet node approve <name> ws://<host>:{args.port} {token}")
|
||||
try:
|
||||
asyncio.run(server.serve())
|
||||
|
|
|
|||
|
|
@ -1092,7 +1092,7 @@ def cmd_status(args) -> None:
|
|||
if write_path != active_path:
|
||||
print(f" Write to: {write_path} (profile-local)")
|
||||
if active_path == global_path:
|
||||
print(f" Fallback: (none — using global ~/.honcho/config.json)")
|
||||
print(" Fallback: (none — using global ~/.honcho/config.json)")
|
||||
elif global_path.exists():
|
||||
print(f" Fallback: {global_path} (exists, cross-app interop)")
|
||||
|
||||
|
|
@ -1152,7 +1152,7 @@ def _show_peer_cards(hcfg, client) -> None:
|
|||
if ai_text:
|
||||
# Truncate to first 200 chars
|
||||
display = ai_text[:200] + ("..." if len(ai_text) > 200 else "")
|
||||
print(f"\n AI peer representation:")
|
||||
print("\n AI peer representation:")
|
||||
print(f" {display}")
|
||||
|
||||
if not card and not ai_text:
|
||||
|
|
@ -1186,7 +1186,7 @@ def _cmd_status_all() -> None:
|
|||
marker = " *" if name == active else ""
|
||||
print(f" {name + marker:<14} {host:<22} {enabled_str:<9} {recall:<9} {write}")
|
||||
|
||||
print(f"\n * active profile\n")
|
||||
print("\n * active profile\n")
|
||||
|
||||
|
||||
def cmd_peers(args) -> None:
|
||||
|
|
@ -1326,7 +1326,7 @@ def cmd_mode(args) -> None:
|
|||
for m, desc in MODES.items():
|
||||
marker = " <-" if m == current else ""
|
||||
print(f" {m:<10} {desc}{marker}")
|
||||
print(f"\n Set with: hermes honcho mode [hybrid|context|tools]\n")
|
||||
print("\n Set with: hermes honcho mode [hybrid|context|tools]\n")
|
||||
return
|
||||
|
||||
if mode_arg not in MODES:
|
||||
|
|
@ -1361,7 +1361,7 @@ def cmd_strategy(args) -> None:
|
|||
for s, desc in STRATEGIES.items():
|
||||
marker = " <-" if s == current else ""
|
||||
print(f" {s:<15} {desc}{marker}")
|
||||
print(f"\n Set with: hermes honcho strategy [per-session|per-directory|per-repo|global]\n")
|
||||
print("\n Set with: hermes honcho strategy [per-session|per-directory|per-repo|global]\n")
|
||||
return
|
||||
|
||||
if strat_arg not in STRATEGIES:
|
||||
|
|
|
|||
|
|
@ -305,12 +305,12 @@ def _setup_platform(hermes_home: str, config: dict, flags: dict[str, str]) -> No
|
|||
if env_writes:
|
||||
_write_env(Path(hermes_home) / ".env", env_writes)
|
||||
|
||||
print(f"\n Memory provider: mem0")
|
||||
print(f" Activation saved to config.yaml")
|
||||
print(f" Provider config saved")
|
||||
print("\n Memory provider: mem0")
|
||||
print(" Activation saved to config.yaml")
|
||||
print(" Provider config saved")
|
||||
if env_writes:
|
||||
print(f" API keys saved to .env")
|
||||
print(f"\n Start a new session to activate.\n")
|
||||
print(" API keys saved to .env")
|
||||
print("\n Start a new session to activate.\n")
|
||||
|
||||
|
||||
def _setup_oss(hermes_home: str, config: dict, flags: dict[str, str]) -> None:
|
||||
|
|
@ -358,14 +358,14 @@ def _setup_oss(hermes_home: str, config: dict, flags: dict[str, str]) -> None:
|
|||
save_config(config)
|
||||
|
||||
_run_connectivity_checks(oss_config)
|
||||
print(f"\n ✓ Mem0 configured (OSS mode)")
|
||||
print("\n ✓ Mem0 configured (OSS mode)")
|
||||
print(f" LLM: {oss_config['llm']['provider']} ({oss_config['llm']['config'].get('model', '')})")
|
||||
print(f" Embedder: {oss_config['embedder']['provider']} ({oss_config['embedder']['config'].get('model', '')})")
|
||||
print(f" Vector: {vector_id}")
|
||||
if env_writes:
|
||||
print(f" API keys saved to .env")
|
||||
print(f" Config saved to mem0.json")
|
||||
print(f" Provider set in config.yaml")
|
||||
print(" API keys saved to .env")
|
||||
print(" Config saved to mem0.json")
|
||||
print(" Provider set in config.yaml")
|
||||
print("\n Start a new session to activate.\n")
|
||||
|
||||
|
||||
|
|
@ -417,7 +417,7 @@ def _ensure_pgvector(host: str = "localhost", port: int = 5432) -> dict | None:
|
|||
_wait_for_port(host, port, timeout=15)
|
||||
ok, _ = _check_pgvector(host, port)
|
||||
if ok:
|
||||
print(f" ✓ PostgreSQL container restarted")
|
||||
print(" ✓ PostgreSQL container restarted")
|
||||
return None
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -711,14 +711,14 @@ def _setup_oss_interactive(hermes_home: str, config: dict) -> None:
|
|||
save_config(config)
|
||||
|
||||
_run_connectivity_checks(oss_config)
|
||||
print(f"\n ✓ Mem0 configured (OSS mode)")
|
||||
print("\n ✓ Mem0 configured (OSS mode)")
|
||||
print(f" LLM: {oss_config['llm']['provider']} ({oss_config['llm']['config'].get('model', '')})")
|
||||
print(f" Embedder: {oss_config['embedder']['provider']} ({oss_config['embedder']['config'].get('model', '')})")
|
||||
print(f" Vector: {vector_id}")
|
||||
if env_writes:
|
||||
print(f" API keys saved to .env")
|
||||
print(f" Config saved to mem0.json")
|
||||
print(f" Provider set in config.yaml")
|
||||
print(" API keys saved to .env")
|
||||
print(" Config saved to mem0.json")
|
||||
print(" Provider set in config.yaml")
|
||||
print("\n Start a new session to activate.\n")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ def _print_status() -> None:
|
|||
print(f"Pairing file: {PAIRING_FILE}")
|
||||
print(f" exists: {PAIRING_FILE.exists()}")
|
||||
print()
|
||||
print(f"Top-level:")
|
||||
print("Top-level:")
|
||||
print(f" enabled: {cfg.enabled}")
|
||||
print(f" policy: {cfg.policy}")
|
||||
print(f" allow_from: {sorted(cfg.allow_from) if cfg.allow_from else '[]'}")
|
||||
|
|
@ -339,7 +339,7 @@ def _do_check(doc_key: str, user_open_id: str) -> None:
|
|||
allowed = is_user_allowed(rule, user_open_id)
|
||||
print(f"Document: {doc_key}")
|
||||
print(f"User: {user_open_id}")
|
||||
print(f"Resolved rule:")
|
||||
print("Resolved rule:")
|
||||
print(f" enabled: {rule.enabled}")
|
||||
print(f" policy: {rule.policy}")
|
||||
print(f" allow_from: {sorted(rule.allow_from) if rule.allow_from else '[]'}")
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ class GoogleChatAdapter(BasePlatformAdapter):
|
|||
)
|
||||
if not os.path.exists(sa_path):
|
||||
raise FileNotFoundError(
|
||||
f"Service Account JSON file not found at configured path."
|
||||
"Service Account JSON file not found at configured path."
|
||||
)
|
||||
# Validate file parses before handing to google-auth for nicer error.
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ def main():
|
|||
scenarios = sorted({row["scenario"] for row in summary})
|
||||
|
||||
print(f"{'='*78}")
|
||||
print(f" Live test results: tool_search ENABLED vs DISABLED")
|
||||
print(" Live test results: tool_search ENABLED vs DISABLED")
|
||||
print(f"{'='*78}\n")
|
||||
|
||||
fails = 0
|
||||
|
|
@ -73,7 +73,7 @@ def main():
|
|||
print(f"┌─ {sid} ({en['scenario_description']})")
|
||||
print(f"│ Prompt: {en['prompt'][:120]}")
|
||||
print(f"│ Expected underlying tools: {sorted(expected) or '(none)'}")
|
||||
print(f"│")
|
||||
print("│")
|
||||
|
||||
for label, rec in [("ENABLED ", en), ("DISABLED", di)]:
|
||||
called_under = [c["name"] for c in rec["underlying_tool_calls"]]
|
||||
|
|
@ -104,7 +104,7 @@ def main():
|
|||
print(f"│ Δ round-trip cost: enabled used {en_bridges + en_underlying} calls vs disabled {di_underlying} → +{overhead}")
|
||||
print(f"│ Final (enabled): {(en.get('final_response') or '')[:140]}")
|
||||
print(f"│ Final (disabled): {(di.get('final_response') or '')[:140]}")
|
||||
print(f"└──")
|
||||
print("└──")
|
||||
print()
|
||||
|
||||
print(f"\nFails: {fails}/{2*len(scenarios)}")
|
||||
|
|
|
|||
|
|
@ -2360,7 +2360,7 @@ def main():
|
|||
return
|
||||
|
||||
print(f"{'='*60}")
|
||||
print(f" Hermes Agent Release Preview")
|
||||
print(" Hermes Agent Release Preview")
|
||||
print(f"{'='*60}")
|
||||
print(f" CalVer tag: {tag_name}")
|
||||
print(f" SemVer: v{current_version} → v{new_version}")
|
||||
|
|
@ -2409,7 +2409,7 @@ def main():
|
|||
if commit_result.returncode != 0:
|
||||
print(f" ✗ Failed to commit version bump: {commit_result.stderr.strip()}")
|
||||
return
|
||||
print(f" ✓ Committed version bump")
|
||||
print(" ✓ Committed version bump")
|
||||
|
||||
# Create annotated tag
|
||||
tag_result = git_result(
|
||||
|
|
@ -2424,7 +2424,7 @@ def main():
|
|||
# Push
|
||||
push_result = git_result("push", "origin", "HEAD", "--tags")
|
||||
if push_result.returncode == 0:
|
||||
print(f" ✓ Pushed to origin")
|
||||
print(" ✓ Pushed to origin")
|
||||
else:
|
||||
print(f" ✗ Failed to push to origin: {push_result.stderr.strip()}")
|
||||
print(" Continue manually after fixing access:")
|
||||
|
|
@ -2469,7 +2469,7 @@ def main():
|
|||
else:
|
||||
print(f" ✗ GitHub release failed: {result.stderr.strip()}")
|
||||
print(f" Release notes kept at: {changelog_file}")
|
||||
print(f" Tag was created locally. Create the release manually:")
|
||||
print(" Tag was created locally. Create the release manually:")
|
||||
print(
|
||||
f" gh release create {tag_name} --title 'Hermes Agent v{new_version} ({calver_date})' "
|
||||
f"--notes-file .release_notes.md {' '.join(str(path) for path in artifacts)}"
|
||||
|
|
@ -2477,8 +2477,8 @@ def main():
|
|||
print(f"\n ✓ Release artifacts prepared for manual publish: v{new_version} ({tag_name})")
|
||||
else:
|
||||
print(f"\n{'='*60}")
|
||||
print(f" Dry run complete. To publish, add --publish")
|
||||
print(f" Example: python scripts/release.py --bump minor --publish")
|
||||
print(" Dry run complete. To publish, add --publish")
|
||||
print(" Example: python scripts/release.py --bump minor --publish")
|
||||
print(f"{'='*60}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -462,9 +462,9 @@ def _print_inline_failure(
|
|||
print(f" ╔╍ Failed: {rel} ╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍", flush=True)
|
||||
for line in tail.splitlines():
|
||||
print(f" ║ {line}", flush=True)
|
||||
print(f" ║", flush=True)
|
||||
print(" ║", flush=True)
|
||||
print(f" ║ Repro: {repro}", flush=True)
|
||||
print(f" ╚╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍", flush=True)
|
||||
print(" ╚╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍", flush=True)
|
||||
print(flush=True)
|
||||
|
||||
|
||||
|
|
@ -767,7 +767,7 @@ def main() -> int:
|
|||
files = _discover_files(roots)
|
||||
|
||||
if not files:
|
||||
print(f"No test files to run", file=sys.stderr)
|
||||
print("No test files to run", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# --generate-slices: compute LPT distribution and emit JSON, then exit.
|
||||
|
|
@ -914,14 +914,14 @@ def main() -> int:
|
|||
fast = sum(1 for t in times if t < 1.0)
|
||||
fast_2s = sum(1 for t in times if t < 2.0)
|
||||
print()
|
||||
print(f"=== Per-file subprocess time distribution ===")
|
||||
print("=== Per-file subprocess time distribution ===")
|
||||
print(f" Files: {len(times)}")
|
||||
print(f" Total subprocess CPU-wall: {total_subproc:.1f}s (runner wall: {elapsed:.1f}s, parallelism: {args.jobs}x)")
|
||||
print(f" P50: {p50:.2f}s P90: {p90:.2f}s P95: {p95:.2f}s P99: {p99:.2f}s Max: {max_t:.2f}s")
|
||||
print(f" <1s: {fast} files ({fast/len(times)*100:.0f}%) <2s: {fast_2s} files ({fast_2s/len(times)*100:.0f}%)")
|
||||
# Top 10 slowest files — likely the ones dragging the run.
|
||||
slowest = sorted(file_times, key=lambda x: x[1], reverse=True)[:10]
|
||||
print(f" Top 10 slowest:")
|
||||
print(" Top 10 slowest:")
|
||||
for f, t in slowest:
|
||||
print(f" {t:>6.2f}s {_format_file(f, repo_root)}")
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ def sample_from_datasets(
|
|||
source = entry.get("_source_dataset", "unknown").split("/")[-1]
|
||||
source_counts[source] = source_counts.get(source, 0) + 1
|
||||
|
||||
print(f"\n📌 Sample distribution by source:")
|
||||
print("\n📌 Sample distribution by source:")
|
||||
for source, count in sorted(source_counts.items()):
|
||||
print(f" {source}: {count:,}")
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ def run_compression(input_dir: Path, output_dir: Path, config_path: str):
|
|||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from trajectory_compressor import TrajectoryCompressor, CompressionConfig
|
||||
|
||||
print(f"\n🗜️ Running trajectory compression...")
|
||||
print("\n🗜️ Running trajectory compression...")
|
||||
print(f" Input: {input_dir}")
|
||||
print(f" Output: {output_dir}")
|
||||
print(f" Config: {config_path}")
|
||||
|
|
@ -348,7 +348,7 @@ def main(
|
|||
else:
|
||||
dataset_list = DEFAULT_DATASETS
|
||||
|
||||
print(f"\n📋 Configuration:")
|
||||
print("\n📋 Configuration:")
|
||||
print(f" Total samples: {total_samples:,}")
|
||||
print(f" Min tokens filter: {min_tokens:,}")
|
||||
print(f" Parallel workers: {num_proc}")
|
||||
|
|
@ -401,7 +401,7 @@ def main(
|
|||
print(f"\n📁 Raw samples: {sampled_dir}")
|
||||
print(f"📁 Compressed batches: {compressed_dir}")
|
||||
print(f"📁 Final output: {final_output}")
|
||||
print(f"\nTo upload to HuggingFace:")
|
||||
print("\nTo upload to HuggingFace:")
|
||||
print(f" huggingface-cli upload NousResearch/{output_name} {final_output}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ def main():
|
|||
if "disabled" in error_msg.lower():
|
||||
print(json.dumps({"error": "Transcripts are disabled for this video."}))
|
||||
elif "no transcript" in error_msg.lower():
|
||||
print(json.dumps({"error": f"No transcript found. Try specifying a language with --language."}))
|
||||
print(json.dumps({"error": "No transcript found. Try specifying a language with --language."}))
|
||||
else:
|
||||
print(json.dumps({"error": error_msg}))
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ def test_classify_no_false_positive_short_name_in_file_path(curator_env):
|
|||
],
|
||||
)
|
||||
assert result["consolidated"] == [], (
|
||||
f"Short name 'api' should NOT match file_path 'references/api-design.md'"
|
||||
"Short name 'api' should NOT match file_path 'references/api-design.md'"
|
||||
)
|
||||
assert len(result["pruned"]) == 1
|
||||
assert result["pruned"][0]["name"] == "api"
|
||||
|
|
@ -266,7 +266,7 @@ def test_classify_no_false_positive_short_name_in_content(curator_env):
|
|||
],
|
||||
)
|
||||
assert result["consolidated"] == [], (
|
||||
f"Short name 'test' should NOT match 'latest' via word boundary"
|
||||
"Short name 'test' should NOT match 'latest' via word boundary"
|
||||
)
|
||||
assert len(result["pruned"]) == 1
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ def test_classify_still_matches_exact_word_in_content(curator_env):
|
|||
],
|
||||
)
|
||||
assert len(result["consolidated"]) == 1, (
|
||||
f"'api' should match as a standalone word in content"
|
||||
"'api' should match as a standalone word in content"
|
||||
)
|
||||
assert result["consolidated"][0]["into"] == "gateway"
|
||||
|
||||
|
|
|
|||
|
|
@ -308,5 +308,5 @@ def test_multiple_tables_in_one_text():
|
|||
for block in blocks:
|
||||
offsets = [_column_offsets(row) for row in block]
|
||||
assert all(o == offsets[0] for o in offsets), (
|
||||
f"block did not align:\n" + "\n".join(block)
|
||||
"block did not align:\n" + "\n".join(block)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ def _make_bundle_yaml(
|
|||
for s in skills:
|
||||
lines.append(f" - {s}")
|
||||
if instruction:
|
||||
lines.append(f"instruction: |")
|
||||
lines.append("instruction: |")
|
||||
for ln in instruction.splitlines():
|
||||
lines.append(f" {ln}")
|
||||
path = bundles_dir / f"{slug}.yaml"
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ def test_install_method_stamp_is_code_scoped(
|
|||
timeout=10,
|
||||
)
|
||||
assert r.stdout.strip() != "docker", (
|
||||
f"$HERMES_HOME/.install_method is stamped 'docker' - stage2 must "
|
||||
f"not stamp the data volume (shared with host installs)"
|
||||
"$HERMES_HOME/.install_method is stamped 'docker' - stage2 must "
|
||||
"not stamp the data volume (shared with host installs)"
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ async def test_shutdown_notification_sent_to_active_sessions():
|
|||
"""Active sessions receive a notification when the gateway starts shutting down."""
|
||||
runner, adapter = make_restart_runner()
|
||||
source = make_restart_source(chat_id="999", chat_type="dm")
|
||||
session_key = f"agent:main:telegram:dm:999"
|
||||
session_key = "agent:main:telegram:dm:999"
|
||||
runner._running_agents[session_key] = MagicMock()
|
||||
|
||||
await runner._notify_active_sessions_of_shutdown()
|
||||
|
|
|
|||
|
|
@ -3615,7 +3615,7 @@ class TestProgressMessageThread:
|
|||
"channel": "C_CHAN",
|
||||
"channel_type": "channel",
|
||||
"user": "U_USER",
|
||||
"text": f"<@U_BOT> help me",
|
||||
"text": "<@U_BOT> help me",
|
||||
"ts": "2000000000.000001",
|
||||
# No thread_ts — top-level channel message
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1384,7 +1384,7 @@ class TestLaunchdDomainDetection:
|
|||
monkeypatch.setattr(gateway_cli.subprocess, "run", fake_run)
|
||||
|
||||
domain = gateway_cli._launchd_domain()
|
||||
assert domain == f"gui/501"
|
||||
assert domain == "gui/501"
|
||||
# Should have probed gui first
|
||||
assert run_calls[0] == ["launchctl", "print", f"gui/501/{label}"]
|
||||
|
||||
|
|
@ -1406,7 +1406,7 @@ class TestLaunchdDomainDetection:
|
|||
monkeypatch.setattr(gateway_cli.subprocess, "run", fake_run)
|
||||
|
||||
domain = gateway_cli._launchd_domain()
|
||||
assert domain == f"user/501"
|
||||
assert domain == "user/501"
|
||||
# Should have tried gui first, then user
|
||||
assert len(run_calls) >= 2
|
||||
|
||||
|
|
@ -1427,7 +1427,7 @@ class TestLaunchdDomainDetection:
|
|||
monkeypatch.setattr(gateway_cli.subprocess, "run", fake_run)
|
||||
|
||||
domain = gateway_cli._launchd_domain()
|
||||
assert domain == f"gui/501"
|
||||
assert domain == "gui/501"
|
||||
|
||||
def test_managername_background_selects_user_domain(self, monkeypatch):
|
||||
"""When managername is Background (non-Aqua), use user/<uid>."""
|
||||
|
|
@ -1444,7 +1444,7 @@ class TestLaunchdDomainDetection:
|
|||
monkeypatch.setattr(gateway_cli.subprocess, "run", fake_run)
|
||||
|
||||
domain = gateway_cli._launchd_domain()
|
||||
assert domain == f"user/501"
|
||||
assert domain == "user/501"
|
||||
|
||||
def test_caches_result_across_calls(self, monkeypatch):
|
||||
"""Domain detection should run once and cache the result."""
|
||||
|
|
@ -2769,7 +2769,7 @@ class TestLegacyHermesUnitDetection:
|
|||
"ExecStart=/venv/bin/python /opt/hermes/gateway/run.py",
|
||||
]
|
||||
for i, execstart in enumerate(variants):
|
||||
name = f"hermes.service" if i == 0 else f"hermes.service" # same name
|
||||
name = "hermes.service" if i == 0 else "hermes.service" # same name
|
||||
# Test each variant fresh
|
||||
(user_dir / "hermes.service").write_text(
|
||||
f"[Unit]\nDescription=Old Hermes\n[Service]\n{execstart}\n",
|
||||
|
|
|
|||
|
|
@ -160,8 +160,8 @@ def test_sigterm_with_kanban_task_env_terminates_quickly():
|
|||
return
|
||||
time.sleep(0.02)
|
||||
pytest.fail(
|
||||
f"process still alive 2s after SIGTERM with HERMES_KANBAN_TASK set "
|
||||
f"(dispatcher would keep extending claim) — fix regressed"
|
||||
"process still alive 2s after SIGTERM with HERMES_KANBAN_TASK set "
|
||||
"(dispatcher would keep extending claim) — fix regressed"
|
||||
)
|
||||
finally:
|
||||
_cleanup(proc)
|
||||
|
|
|
|||
|
|
@ -3196,7 +3196,7 @@ class TestConfigRoundTrip:
|
|||
mismatches.append(f"{key}: expected bool, got {type(val).__name__}")
|
||||
elif expected == "list" and not isinstance(val, list):
|
||||
mismatches.append(f"{key}: expected list, got {type(val).__name__}")
|
||||
assert not mismatches, f"Type mismatches:\n" + "\n".join(mismatches)
|
||||
assert not mismatches, "Type mismatches:\n" + "\n".join(mismatches)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ def verify_output(run_name):
|
|||
print(f"❌ No batch files found in: {output_dir}")
|
||||
return False
|
||||
|
||||
print(f"✅ Output verification passed:")
|
||||
print("✅ Output verification passed:")
|
||||
print(f" - Checkpoint: {checkpoint_file}")
|
||||
print(f" - Statistics: {stats_file}")
|
||||
print(f" - Batch files: {len(batch_files)}")
|
||||
|
|
@ -77,13 +77,13 @@ def verify_output(run_name):
|
|||
with open(stats_file) as f:
|
||||
stats = json.load(f)
|
||||
|
||||
print(f"\n📊 Statistics Summary:")
|
||||
print("\n📊 Statistics Summary:")
|
||||
print(f" - Total prompts: {stats['total_prompts']}")
|
||||
print(f" - Total batches: {stats['total_batches']}")
|
||||
print(f" - Duration: {stats['duration_seconds']}s")
|
||||
|
||||
if stats.get('tool_statistics'):
|
||||
print(f" - Tool calls:")
|
||||
print(" - Tool calls:")
|
||||
for tool, tool_stats in stats['tool_statistics'].items():
|
||||
print(f" • {tool}: {tool_stats['count']} calls, {tool_stats['success_rate']:.1f}% success")
|
||||
|
||||
|
|
@ -103,19 +103,19 @@ def main():
|
|||
# Create test dataset
|
||||
test_file = create_test_dataset()
|
||||
|
||||
print(f"\n📝 To run the test manually:")
|
||||
print(f" python batch_runner.py \\")
|
||||
print("\n📝 To run the test manually:")
|
||||
print(" python batch_runner.py \\")
|
||||
print(f" --dataset_file={test_file} \\")
|
||||
print(f" --batch_size=2 \\")
|
||||
print(" --batch_size=2 \\")
|
||||
print(f" --run_name={run_name} \\")
|
||||
print(f" --distribution=minimal \\")
|
||||
print(f" --num_workers=2")
|
||||
print(" --distribution=minimal \\")
|
||||
print(" --num_workers=2")
|
||||
|
||||
print(f"\n💡 Or test with different distributions:")
|
||||
print(f" python batch_runner.py --list_distributions")
|
||||
print("\n💡 Or test with different distributions:")
|
||||
print(" python batch_runner.py --list_distributions")
|
||||
|
||||
print(f"\n🔍 After running, you can verify output with:")
|
||||
print(f" python tests/test_batch_runner.py --verify")
|
||||
print("\n🔍 After running, you can verify output with:")
|
||||
print(" python tests/test_batch_runner.py --verify")
|
||||
|
||||
# Note: We don't actually run the batch runner here to avoid API calls during testing
|
||||
# Users should run it manually with their API keys configured
|
||||
|
|
|
|||
|
|
@ -140,11 +140,11 @@ def test_current_implementation():
|
|||
|
||||
# Start monitoring in a separate process would be ideal, but for simplicity
|
||||
# we'll just check before and after
|
||||
print(f"\n▶️ Starting batch run...")
|
||||
print("\n▶️ Starting batch run...")
|
||||
print(f" Dataset: {dataset_file}")
|
||||
print(f" Batch size: 3 (4 batches total)")
|
||||
print(f" Workers: 2")
|
||||
print(f" Expected behavior: If incremental, checkpoint should update during run")
|
||||
print(" Batch size: 3 (4 batches total)")
|
||||
print(" Workers: 2")
|
||||
print(" Expected behavior: If incremental, checkpoint should update during run")
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ def test_interruption_and_resume():
|
|||
|
||||
checkpoint_file = output_dir / "checkpoint.json"
|
||||
|
||||
print(f"\n▶️ Starting first run (will process 5 prompts, then simulate interruption)...")
|
||||
print("\n▶️ Starting first run (will process 5 prompts, then simulate interruption)...")
|
||||
|
||||
temp_dataset = Path("tests/test_data/checkpoint_test_resume_partial.jsonl")
|
||||
try:
|
||||
|
|
@ -267,7 +267,7 @@ def test_interruption_and_resume():
|
|||
print(f"✅ First run completed: {initial_completed} prompts saved to checkpoint")
|
||||
|
||||
# Now try to resume with full dataset
|
||||
print(f"\n▶️ Starting resume run with full dataset (15 prompts)...")
|
||||
print("\n▶️ Starting resume run with full dataset (15 prompts)...")
|
||||
|
||||
runner2 = BatchRunner(
|
||||
dataset_file=str(dataset_file),
|
||||
|
|
@ -293,7 +293,7 @@ def test_interruption_and_resume():
|
|||
print("=" * 70)
|
||||
print(f"Initial completed: {initial_completed}")
|
||||
print(f"Final completed: {final_completed}")
|
||||
print(f"Expected: 15")
|
||||
print("Expected: 15")
|
||||
|
||||
if final_completed == 15:
|
||||
print("\n✅ PASS: Resume successfully completed all prompts")
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ def test_modal_requirements():
|
|||
modal_token = os.getenv("MODAL_TOKEN_ID")
|
||||
modal_toml = Path.home() / ".modal.toml"
|
||||
|
||||
print(f"\nModal authentication:")
|
||||
print("\nModal authentication:")
|
||||
print(f" MODAL_TOKEN_ID env var: {'✅ Set' if modal_token else '❌ Not set'}")
|
||||
print(f" ~/.modal.toml file: {'✅ Exists' if modal_toml.exists() else '❌ Not found'}")
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ def test_simple_command():
|
|||
result = terminal_tool("echo 'Hello from Modal!'", task_id=test_task_id)
|
||||
result_json = json.loads(result)
|
||||
|
||||
print(f"\nResult:")
|
||||
print("\nResult:")
|
||||
print(f" Output: {result_json.get('output', '')[:200]}")
|
||||
print(f" Exit code: {result_json.get('exit_code')}")
|
||||
print(f" Error: {result_json.get('error')}")
|
||||
|
|
@ -124,7 +124,7 @@ def test_python_execution():
|
|||
result = terminal_tool(python_cmd, task_id=test_task_id)
|
||||
result_json = json.loads(result)
|
||||
|
||||
print(f"\nResult:")
|
||||
print("\nResult:")
|
||||
print(f" Output: {result_json.get('output', '')[:200]}")
|
||||
print(f" Exit code: {result_json.get('exit_code')}")
|
||||
print(f" Error: {result_json.get('error')}")
|
||||
|
|
@ -156,7 +156,7 @@ def test_pip_install():
|
|||
)
|
||||
result_json = json.loads(result)
|
||||
|
||||
print(f"\nResult:")
|
||||
print("\nResult:")
|
||||
output = result_json.get('output', '')
|
||||
print(f" Output (last 500 chars): ...{output[-500:] if len(output) > 500 else output}")
|
||||
print(f" Exit code: {result_json.get('exit_code')}")
|
||||
|
|
@ -244,7 +244,7 @@ def main():
|
|||
|
||||
# Check current config
|
||||
config = _get_env_config()
|
||||
print(f"\nCurrent configuration:")
|
||||
print("\nCurrent configuration:")
|
||||
print(f" TERMINAL_ENV: {config['env_type']}")
|
||||
print(f" TERMINAL_MODAL_IMAGE: {config['modal_image']}")
|
||||
print(f" TERMINAL_TIMEOUT: {config['timeout']}s")
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ class WebToolsTester:
|
|||
"https://docs.firecrawl.dev/introduction",
|
||||
"https://www.python.org/about/"
|
||||
]
|
||||
print(f" Using default URLs for testing")
|
||||
print(" Using default URLs for testing")
|
||||
else:
|
||||
print(f" Using {len(urls)} URLs from search results")
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ class WebToolsTester:
|
|||
f"No valid content. {failed_results} errors, {len(results) - failed_results} empty"
|
||||
)
|
||||
if self.verbose:
|
||||
print(f"\n Extraction details:")
|
||||
print("\n Extraction details:")
|
||||
for detail in extraction_details:
|
||||
print(f" {detail}")
|
||||
|
||||
|
|
@ -387,7 +387,7 @@ class WebToolsTester:
|
|||
)
|
||||
|
||||
if self.verbose:
|
||||
print(f"\n First 300 chars of processed content:")
|
||||
print("\n First 300 chars of processed content:")
|
||||
print(f" {content[:300]}...")
|
||||
else:
|
||||
self.log_result("Extract (with LLM)", "failed", "No content after processing")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ def make_slow_response(delay=2.0):
|
|||
def create(**kwargs):
|
||||
log.info(f" 🌐 Mock API call starting (will take {delay}s)...")
|
||||
time.sleep(delay)
|
||||
log.info(f" 🌐 Mock API call completed")
|
||||
log.info(" 🌐 Mock API call completed")
|
||||
resp = MagicMock()
|
||||
resp.choices = [MagicMock()]
|
||||
resp.choices[0].message.content = "Done with the task"
|
||||
|
|
|
|||
|
|
@ -6998,7 +6998,7 @@ class TestInterruptVprintForceTrue:
|
|||
if "force=True" not in stripped:
|
||||
violations.append(f"line {i}: {stripped}")
|
||||
assert not violations, (
|
||||
f"Interrupt _vprint calls missing force=True:\n"
|
||||
"Interrupt _vprint calls missing force=True:\n"
|
||||
+ "\n".join(violations)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -121,11 +121,11 @@ def _(home, kb):
|
|||
metadata=meta,
|
||||
)
|
||||
run = kb.latest_run(conn, tid)
|
||||
assert run.summary == "完成了 📝 résumé", f"summary round-trip failed"
|
||||
assert run.summary == "完成了 📝 résumé", "summary round-trip failed"
|
||||
assert run.metadata == meta, (
|
||||
f"metadata round-trip failed: {run.metadata} != {meta}"
|
||||
)
|
||||
print(f" metadata with CJK + emoji round-tripped")
|
||||
print(" metadata with CJK + emoji round-tripped")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ def _(home, kb):
|
|||
run = kb.latest_run(conn, tid)
|
||||
assert run.summary == huge_summary
|
||||
assert run.metadata == meta
|
||||
print(f" 1 MB body + 1 MB summary + 50-deep metadata OK")
|
||||
print(" 1 MB body + 1 MB summary + 50-deep metadata OK")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ def _(home, kb):
|
|||
f"leaf should promote with both parents done, got "
|
||||
f"{kb.get_task(conn, leaf).status}"
|
||||
)
|
||||
print(f" diamond dependency resolved correctly")
|
||||
print(" diamond dependency resolved correctly")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ def _(home, kb):
|
|||
kb.complete_task(conn, parents[-1])
|
||||
kb.recompute_ready(conn)
|
||||
assert kb.get_task(conn, child).status == "ready"
|
||||
print(f" 500 parents → 1 child promotion works")
|
||||
print(" 500 parents → 1 child promotion works")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -441,7 +441,7 @@ def _(home, kb):
|
|||
# This is escaping the home dir. Whether that's actually
|
||||
# a problem depends on the threat model. Flag for attention.
|
||||
print(f" ⚠ workspace resolved OUTSIDE hermes_home: {resolved}")
|
||||
print(f" (not necessarily a bug — dir: workspaces are intentionally arbitrary, but worth documenting)")
|
||||
print(" (not necessarily a bug — dir: workspaces are intentionally arbitrary, but worth documenting)")
|
||||
except Exception as e:
|
||||
print(f" resolve_workspace rejected: {e}")
|
||||
finally:
|
||||
|
|
@ -515,7 +515,7 @@ def _(home, kb):
|
|||
# doesn't produce "-1800s" elapsed.
|
||||
elapsed = run.ended_at - run.started_at
|
||||
print(f" clock-skewed run: elapsed = {elapsed}s (negative)")
|
||||
print(f" ⚠ kernel stores this; UI should clamp to 0 or handle")
|
||||
print(" ⚠ kernel stores this; UI should clamp to 0 or handle")
|
||||
# Don't fail — document the behavior.
|
||||
else:
|
||||
print(" kernel normalized ended_at >= started_at")
|
||||
|
|
@ -875,7 +875,7 @@ def _(home, kb):
|
|||
elapsed = (time.monotonic() - t0) * 1000
|
||||
print(f" 1000 comments: list in {elapsed:.0f}ms, context size = {len(ctx)} chars")
|
||||
if len(ctx) > 200_000:
|
||||
print(f" ⚠ comment thread unbounded in worker context")
|
||||
print(" ⚠ comment thread unbounded in worker context")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -907,7 +907,7 @@ def _(home, kb):
|
|||
kb.complete_task(conn, tid, summary="")
|
||||
run = kb.latest_run(conn, tid)
|
||||
# Empty summary falls back to result; both empty → None on run
|
||||
print(f" empty body accepted, empty-title rejected")
|
||||
print(" empty body accepted, empty-title rejected")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
@ -926,7 +926,7 @@ def _(home, kb):
|
|||
assert back.tenant == weird_tenant
|
||||
# board_stats groups by tenant — verify it doesn't fall over
|
||||
stats = kb.board_stats(conn)
|
||||
print(f" multiline tenant stored and stats still work")
|
||||
print(" multiline tenant stored and stats still work")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ def main():
|
|||
print(f"Lost claim races: {total_lost_races} (expected contention; not a bug)")
|
||||
print(f"Elapsed: {elapsed:.2f}s")
|
||||
print(f"Throughput: {NUM_TASKS/elapsed:.1f} tasks/sec")
|
||||
print(f"Per-worker completions:")
|
||||
print("Per-worker completions:")
|
||||
for w in sorted(per_worker.keys()):
|
||||
print(f" worker-{w}: {per_worker[w]}")
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ def main():
|
|||
tenant="reclaim-race")
|
||||
conn.close()
|
||||
print(f"Seeded {NUM_TASKS} tasks. TTL={TTL}s, work_duration={WORK_DURATION_S}s")
|
||||
print(f"(worker work > TTL guarantees reclaims)")
|
||||
print("(worker work > TTL guarantees reclaims)")
|
||||
|
||||
ctx = mp.get_context("spawn")
|
||||
worker_results = [f"/tmp/rc_worker_{i}.json" for i in range(NUM_WORKERS)]
|
||||
|
|
|
|||
|
|
@ -1197,7 +1197,7 @@ class TestNormalizationBypass:
|
|||
"""ANSI CSI color codes wrapping 'rm' must be stripped and caught."""
|
||||
cmd = "\x1b[31mrm\x1b[0m -rf /"
|
||||
dangerous, key, desc = detect_dangerous_command(cmd)
|
||||
assert dangerous is True, f"ANSI-wrapped 'rm -rf /' was not detected"
|
||||
assert dangerous is True, "ANSI-wrapped 'rm -rf /' was not detected"
|
||||
|
||||
def test_ansi_osc_embedded_rm(self):
|
||||
"""ANSI OSC sequences embedded in command must be stripped."""
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ class TestScanFile:
|
|||
|
||||
def test_detect_invisible_unicode(self, tmp_path):
|
||||
f = tmp_path / "hidden.md"
|
||||
f.write_text(f"normal text\u200b with zero-width space\n")
|
||||
f.write_text("normal text\u200b with zero-width space\n")
|
||||
findings = scan_file(f, "hidden.md")
|
||||
assert any(fi.pattern_id == "invisible_unicode" for fi in findings)
|
||||
|
||||
|
|
|
|||
|
|
@ -513,8 +513,8 @@ class TestEdgeTTSLazyImport:
|
|||
if isinstance(n, _ast.Name) and n.id == "edge_tts"
|
||||
]
|
||||
assert bare_refs == [], (
|
||||
f"_generate_edge_tts uses bare 'edge_tts' name — "
|
||||
f"should use _import_edge_tts() lazy helper"
|
||||
"_generate_edge_tts uses bare 'edge_tts' name — "
|
||||
"should use _import_edge_tts() lazy helper"
|
||||
)
|
||||
|
||||
# Must have a call to _import_edge_tts
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ class CheckpointManager:
|
|||
|
||||
ref = _ref_name(_project_hash(abs_dir))
|
||||
ok, stdout, _ = _run_git(
|
||||
["log", ref, f"--format=%H|%h|%aI|%s", "-n", str(self.max_snapshots)],
|
||||
["log", ref, "--format=%H|%h|%aI|%s", "-n", str(self.max_snapshots)],
|
||||
store, abs_dir,
|
||||
allowed_returncodes={128, 129},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1438,7 +1438,7 @@ def _dump_subagent_timeout_diagnostic(
|
|||
def _w(line: str = "") -> None:
|
||||
lines.append(line)
|
||||
|
||||
_w(f"# Subagent timeout diagnostic — issue #14726")
|
||||
_w("# Subagent timeout diagnostic — issue #14726")
|
||||
_w(f"# Generated: {_dt.datetime.now().isoformat()}")
|
||||
_w("")
|
||||
_w("## Timeout")
|
||||
|
|
|
|||
|
|
@ -1710,7 +1710,7 @@ async def _send_qqbot(pconfig, chat_id, message):
|
|||
token_data = token_resp.json()
|
||||
access_token = token_data.get("access_token")
|
||||
if not access_token:
|
||||
return _error(f"QQBot: no access_token in response")
|
||||
return _error("QQBot: no access_token in response")
|
||||
|
||||
# Step 2: Send message via REST
|
||||
# QQ Bot API has separate endpoints for channels, C2C, and groups.
|
||||
|
|
|
|||
|
|
@ -1265,7 +1265,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
skipped_pct = (skipped / max(total, 1)) * 100
|
||||
over_limit_pct = (over_limit / max(total, 1)) * 100
|
||||
|
||||
print(f"\n")
|
||||
print("\n")
|
||||
print(f"╔{'═'*70}╗")
|
||||
print(f"║{'TRAJECTORY COMPRESSION REPORT':^70}║")
|
||||
print(f"╠{'═'*70}╣")
|
||||
|
|
@ -1348,7 +1348,7 @@ Write only the summary, starting with "[CONTEXT SUMMARY]:" prefix."""
|
|||
ratios = self.aggregate_metrics.compression_ratios
|
||||
tokens_saved_list = self.aggregate_metrics.tokens_saved_list
|
||||
|
||||
print(f"\n📊 Distribution Summary:")
|
||||
print("\n📊 Distribution Summary:")
|
||||
print(f" Compression ratios: min={min(ratios):.2%}, max={max(ratios):.2%}, median={sorted(ratios)[len(ratios)//2]:.2%}")
|
||||
print(f" Tokens saved: min={min(tokens_saved_list):,}, max={max(tokens_saved_list):,}, median={sorted(tokens_saved_list)[len(tokens_saved_list)//2]:,}")
|
||||
|
||||
|
|
@ -1431,7 +1431,7 @@ def main(
|
|||
is_file_input = input_path.is_file()
|
||||
|
||||
if is_file_input:
|
||||
print(f"📄 Input mode: Single JSONL file")
|
||||
print("📄 Input mode: Single JSONL file")
|
||||
|
||||
# For file input, default output is file with _compressed suffix
|
||||
if output:
|
||||
|
|
@ -1461,7 +1461,7 @@ def main(
|
|||
print(f" Sampled {len(entries):,} trajectories ({sample_percent}% of {total_entries:,})")
|
||||
|
||||
if dry_run:
|
||||
print(f"\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print("\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print(f"📄 Would process: {len(entries):,} trajectories")
|
||||
print(f"📄 Would output to: {output_path}")
|
||||
return
|
||||
|
|
@ -1497,12 +1497,12 @@ def main(
|
|||
shutil.copy(metrics_file, metrics_output)
|
||||
print(f"💾 Metrics saved to {metrics_output}")
|
||||
|
||||
print(f"\n✅ Compression complete!")
|
||||
print("\n✅ Compression complete!")
|
||||
print(f"📄 Output: {output_path}")
|
||||
|
||||
else:
|
||||
# Directory input - original behavior
|
||||
print(f"📁 Input mode: Directory of JSONL files")
|
||||
print("📁 Input mode: Directory of JSONL files")
|
||||
|
||||
if output:
|
||||
output_path = Path(output)
|
||||
|
|
@ -1548,7 +1548,7 @@ def main(
|
|||
print(f" Sampled {total_sampled:,} from {total_original:,} total trajectories")
|
||||
|
||||
if dry_run:
|
||||
print(f"\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print("\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print(f"📁 Would process: {temp_input_dir}")
|
||||
print(f"📁 Would output to: {output_path}")
|
||||
return
|
||||
|
|
@ -1558,7 +1558,7 @@ def main(
|
|||
compressor.process_directory(temp_input_dir, output_path)
|
||||
else:
|
||||
if dry_run:
|
||||
print(f"\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print("\n🔍 DRY RUN MODE - analyzing without writing")
|
||||
print(f"📁 Would process: {input_path}")
|
||||
print(f"📁 Would output to: {output_path}")
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue