refactor(tools): group H — compact module/function docstrings by hand (keep WHY/invariants)

This commit is contained in:
Teknium
2026-09-02 22:51:44 -07:00
parent cffc1df516
commit 5db38e3a4e
7 changed files with 57 additions and 97 deletions

View File

@@ -1,17 +1,11 @@
"""Symlink-safe creation helpers for spill/cache files.
Spill files live in predictable directories under ``~/.hermes``; a plain
``open(path, "w")`` there would follow a pre-planted symlink and let a local
process redirect the write onto ``~/.bashrc``, ``authorized_keys``, etc. Every
helper refuses symlinks by construction: new files use ``O_CREAT | O_EXCL``
(fails on ANY existing path, including a dangling link); overwrites ``lstat`` +
``unlink`` the existing path first (removes the link, never its target), then
create exclusively, so the pair can't be raced. ``private=True`` (default)
forces ``0o700`` dirs / ``0o600`` files for spills that may hold pre-redaction
secrets; ``private=False`` keeps umask perms for cache dirs bind-mounted into
remote backends (``credential_files._CACHE_DIRS``) where a non-root container
UID must read them. Disk failures are the caller's concern: helpers raise ``OSError``.
"""
"""Symlink-safe creation helpers for spill/cache files under ``~/.hermes``, where a
plain ``open(path, "w")`` would follow a pre-planted symlink onto ``~/.bashrc`` etc.
New files use ``O_CREAT | O_EXCL`` (fails on ANY existing path, even a dangling
link); overwrites ``lstat`` + ``unlink`` first (removes the link, never its target)
then create exclusively, so the pair can't be raced. ``private=True`` (default) =
``0o700`` dirs / ``0o600`` files for spills that may hold pre-redaction secrets;
``private=False`` keeps umask perms for cache dirs bind-mounted into remote backends
(``credential_files._CACHE_DIRS``). Disk failures raise ``OSError`` to the caller."""
from __future__ import annotations

View File

@@ -1,13 +1,8 @@
#!/usr/bin/env python3
"""Point at something in the Hermes desktop GUI and say one line about it.
The quiet sibling of ``tour``: same ``data-tour`` handles and discovery call,
but an arrow bubble with no scrim/spotlight/paging. Fire-and-forget — a tip is
not a question, so blocking the turn on a round-trip would stall the reply.
Lives in ``desktop_ui`` (GUI sessions only) and withdraws itself when the user
turns tips off, so the model is never offered a tool whose call would fail.
"""
"""Point at something in the Hermes desktop GUI and say one line about it — the quiet
sibling of ``tour`` (same ``data-tour`` handles) with no scrim/spotlight/paging.
Fire-and-forget: a tip is not a question, so blocking on a round-trip would stall the
reply. Lives in ``desktop_ui`` and withdraws itself when the user turns tips off."""
import json

View File

@@ -18,18 +18,14 @@ _VALID_MODAL_MODES = {"auto", "direct", "managed"}
def managed_nous_tools_enabled(*, force_fresh: bool = False) -> bool:
"""True when the user is entitled to the Nous Tool Gateway (coarse gate:
paid Portal service access OR a live free tool pool). Fails closed on
unknown/error entitlement — never blocks startup. Per-category coverage is
narrowed by callers via ``tool_gateway_entitled_for``. ``force_fresh=True``
is for interactive flows that must see a just-purchased grant."""
"""Coarse gate: entitled to the Nous Tool Gateway (paid Portal access OR a live free
pool). Fails closed on unknown/error — never blocks startup. Callers narrow per category
via ``tool_gateway_entitled_for``; ``force_fresh`` is for flows needing a just-bought grant."""
try:
from hermes_cli.nous_account import get_nous_portal_account_info
if force_fresh:
account_info = get_nous_portal_account_info(force_fresh=True)
else:
account_info = get_nous_portal_account_info()
account_info = (get_nous_portal_account_info(force_fresh=True) if force_fresh
else get_nous_portal_account_info())
return bool(account_info.logged_in) and account_info.tool_gateway_entitled
except Exception:
return False

View File

@@ -1,15 +1,8 @@
"""Configurable tool-output truncation limits (``tool_output`` in config.yaml).
Centralises the caps once hardcoded in ``terminal_tool`` (``max_bytes``) and
``file_operations`` (``max_lines`` / ``max_line_length``). Defaults equal the
old constants and the reader never raises, so behaviour is unchanged when the
section is absent or malformed::
tool_output:
max_bytes: 100000 # terminal output cap (chars)
max_lines: 5000 # read_file pagination + truncation cap
max_line_length: 2000 # per-line cap before '... [truncated]'
"""
"""Configurable tool-output truncation limits (``tool_output`` in config.yaml):
``max_bytes`` (terminal output cap), ``max_lines`` (read_file pagination cap),
``max_line_length`` (per-line cap before '... [truncated]'). Defaults equal the
constants once hardcoded in terminal_tool / file_operations and the reader never
raises, so behaviour is unchanged when the section is absent or malformed."""
from __future__ import annotations

View File

@@ -1,15 +1,11 @@
"""Tool result persistence -- preserves large outputs instead of truncating.
Three layers against context-window overflow: (1) per-tool output caps inside
each tool; (2) ``maybe_persist_tool_result`` — output over the tool's threshold
is persisted and replaced in-context by a preview + path. The canonical home is
ALWAYS host-side ``$HERMES_HOME/cache/spillover/{tool_use_id}.txt`` (works for
MCP-only/cron/gateway sessions that never ran a terminal); remote backends see
the translated in-sandbox path (``cache/spillover`` is in the auto-mounted cache
list), probed for readability, else a copy written into the sandbox temp dir.
(3) ``enforce_turn_budget`` — spills the largest results of a turn until the
aggregate fits.
"""
Layers against context overflow: (1) per-tool caps inside each tool; (2)
``maybe_persist_tool_result`` — output over the tool's threshold is persisted and
replaced by a preview + path. Canonical home is ALWAYS host-side
``$HERMES_HOME/cache/spillover/{id}.txt`` (works for sessions that never ran a
terminal); remote backends get the translated in-sandbox path (probed for
readability) else a copy in the sandbox temp dir. (3) ``enforce_turn_budget``."""
import hashlib
import logging

View File

@@ -1,15 +1,11 @@
"""Progressive tool disclosure ("tool search"): MCP/plugin tools and a curated set
of event-triggered core tools are replaced in the model-visible array by three
bridge tools — tool_search / tool_describe / tool_call.
Invariants: working-set core tools (``toolsets._HERMES_CORE_TOOLS``) and
session-gated GUI toolsets never defer unless named in ``defer``; ANY deferrable
tool activates the bridge (the listing scales with budget, not activation); the
catalog is stateless — rebuilt from the live tool-defs on every assembly (a
session-keyed catalog drifts from the registry and silently drops tools); bridge
calls route through ``model_tools.handle_function_call`` so guardrails, hooks,
approvals and truncation fire identically.
"""
bridge tools — tool_search / tool_describe / tool_call. Invariants: core tools
(``toolsets._HERMES_CORE_TOOLS``) and session-gated GUI toolsets never defer unless
named in ``defer``; ANY deferrable tool activates the bridge (the listing scales
with budget, not activation); the catalog is stateless — rebuilt from the live
tool-defs every assembly (a session-keyed one drifts and silently drops tools);
bridge calls route through ``model_tools.handle_function_call`` (same guardrails)."""
from __future__ import annotations
@@ -111,6 +107,7 @@ def _safe_float(value: Any, fallback: float) -> float:
def _config_from_loader(loader_name: str) -> ToolSearchConfig:
"""Tool-search config via ``hermes_cli.config.<loader_name>`` (defaults on any failure)."""
try:
import hermes_cli.config as _cfg_mod
cfg = getattr(_cfg_mod, loader_name)() or {}
@@ -122,12 +119,11 @@ def _config_from_loader(loader_name: str) -> ToolSearchConfig:
def load_config() -> ToolSearchConfig:
"""Load tool-search config from the user config file."""
return _config_from_loader("load_config")
def load_config_readonly() -> ToolSearchConfig:
"""Load tool-search config without copying the cached full config."""
"""Same as ``load_config`` without copying the cached full config."""
return _config_from_loader("load_config_readonly")
@@ -221,11 +217,9 @@ def should_activate(
config: ToolSearchConfig,
deferrable_tokens: int,
context_length: Optional[int]) -> bool:
"""``"off"`` never activates; ``"on"``/``"auto"`` activate whenever any
deferrable tool exists. ``"auto"`` is an alias of ``"on"`` reserved for a
future budget-gated mode — do not distinguish them without that design.
``context_length`` stays in the signature for caller compatibility; the
threshold governs the listing budget, not activation."""
"""``"off"`` never activates; ``"on"``/``"auto"`` activate whenever any deferrable
tool exists ("auto" is reserved for a future budget-gated mode — do not distinguish
them without that design). ``context_length`` is kept for caller compatibility."""
return config.enabled != "off" and deferrable_tokens > 0
@@ -363,9 +357,8 @@ def assemble_tool_defs(
*,
context_length: Optional[int] = None,
config: Optional[ToolSearchConfig] = None) -> AssemblyResult:
"""Return the tool-defs list the model should actually see: passthrough
when inactive, otherwise deferrable tools replaced by the three bridge
tools. Idempotent — bridge tools already present are stripped first."""
"""Tool-defs the model should see: passthrough when inactive, else deferrable tools
replaced by the three bridge tools. Idempotent — existing bridge tools are stripped first."""
if config is None:
config = load_config()
incoming = [td for td, name in zip(tool_defs, _tool_def_names(tool_defs))
@@ -404,9 +397,8 @@ def is_bridge_tool(name: str) -> bool:
def _shared_tool_record(entry: CatalogEntry) -> Dict[str, Any]:
"""One record for the response's shared ``tools`` map (held once per tool;
per-query groups carry names only). ``required`` lets the model attempt a
trivial call without a ``tool_describe`` round-trip."""
"""One record for the shared ``tools`` map (per-query groups carry names only);
``required`` lets the model attempt a trivial call without a ``tool_describe`` round-trip."""
schema = entry.schema if isinstance(entry.schema, dict) else {}
fn = schema.get("function")
params = fn.get("parameters") if isinstance(fn, dict) else None
@@ -430,9 +422,8 @@ def _available_source_summary(catalog: List[CatalogEntry]) -> List[Dict[str, Any
def _string_list_arg(
args: Dict[str, Any], key: str, *, dedupe: bool, max_items: int, retry_hint: str,
) -> Tuple[Optional[List[str]], Optional[str]]:
"""Read a list-of-strings bridge argument -> ``(items, error_json)``. A bare
string (a common model slip) counts as a one-item list. Rejects non-list
input, an empty list (after stripping blanks), and more than ``max_items``."""
"""Read a list-of-strings bridge argument -> ``(items, error_json)``. A bare string (a
common model slip) is a one-item list; rejects non-lists, all-blank lists, > ``max_items``."""
raw = args.get(key)
if isinstance(raw, str):
raw = [raw]
@@ -552,10 +543,9 @@ def dispatch_tool_describe(args: Dict[str, Any],
def scoped_deferrable_names(tool_defs: List[Dict[str, Any]]) -> frozenset[str]:
"""Deferrable tool names in the *pre-assembly* ``tool_defs`` of the session's
toolset scope — the universe ``tool_call`` may reach. Gates both bridge
dispatch and the executor unwrap so a restricted session cannot invoke an
out-of-scope tool via the bridge."""
"""Deferrable names in the *pre-assembly* ``tool_defs`` of the session scope — the
universe ``tool_call`` may reach. Gates bridge dispatch AND the executor unwrap so a
restricted session cannot invoke an out-of-scope tool via the bridge."""
defer_tools = load_config_readonly().effective_defer_tools
return frozenset(
name for name in _tool_def_names(tool_defs)
@@ -563,9 +553,8 @@ def scoped_deferrable_names(tool_defs: List[Dict[str, Any]]) -> frozenset[str]:
def resolve_underlying_call(args: Dict[str, Any]) -> Tuple[Optional[str], Dict[str, Any], Optional[str]]:
"""Parse a ``tool_call`` invocation into (underlying_name, args, error_msg);
``(None, {}, msg)`` on parse error. Shared by dispatch, display, and the
trajectory recorder so all three agree on the underlying tool."""
"""Parse a ``tool_call`` invocation -> (underlying_name, args, error_msg); ``(None, {}, msg)``
on error. Shared by dispatch, display and the trajectory recorder so all three agree."""
name = str(args.get("name") or "").strip()
if not name:
return None, {}, "tool_call requires a 'name' argument"

View File

@@ -1,14 +1,11 @@
#!/usr/bin/env python3
"""Guided tour (highlight + narrate UI elements) in the Hermes desktop GUI.
Generic, no baked-in tours: the agent discovers targets (``action="targets"``),
then highlights by CSS selector one step at a time (``show``) or hands over a
step list the user pages with Next/Prev (``start``). Round-trips through the
gateway blocking-prompt bridge (``tour.request``/``tour.respond``) so the agent
learns whether the selector matched. Lives in ``desktop_ui`` and withdraws itself
when the user turns tours off: a tour takes the whole screen, so "off" must mean
the model is never told the tool exists rather than offered a call that fails.
"""
"""Guided tour (highlight + narrate UI elements) in the Hermes desktop GUI. Generic:
the agent discovers targets (``action="targets"``), then highlights one step at a
time (``show``) or hands over a step list the user pages (``start``). Round-trips
through the gateway blocking-prompt bridge (``tour.request``/``tour.respond``) so the
agent learns whether the selector matched. Lives in ``desktop_ui`` and withdraws
itself when tours are off: a tour takes the whole screen, so "off" must mean the
model is never told the tool exists rather than offered a call that fails."""
import json
from typing import Callable, Optional