refactor(tools): fold tool_search_names into tool_search_catalog (single importer pair), dict-dispatch modal backend selection, compact registry.register calls and shebangs

This commit is contained in:
Teknium
2026-09-03 00:59:55 -07:00
parent 2ad265ea78
commit 5645bc3cd0
8 changed files with 30 additions and 64 deletions
+2 -7
View File
@@ -1,4 +1,3 @@
#!/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) with no scrim/spotlight/paging.
Fire-and-forget: a tip is not a question, so blocking on a round-trip would stall the
@@ -76,11 +75,7 @@ def check_tips_enabled() -> bool:
registry.register(
name="show_tip",
toolset="desktop_ui",
schema=TIP_SCHEMA,
name="show_tip", toolset="desktop_ui", schema=TIP_SCHEMA, check_fn=check_tips_enabled,
handler=lambda args, **kw: tip_tool(
**{k: args.get(k, "") for k in ("text", "selector", "title", "side")}),
check_fn=check_tips_enabled,
emoji="💡",
)
emoji="💡")
+2 -7
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
"""Todo tool: in-memory, revisioned task list for multi-step work. State lives on the
AIAgent (one per session), is re-injected after context compression, and every write bumps
a monotonic revision so UI clients can reject stale updates. One ``todo_list`` tool: pass
@@ -293,11 +292,7 @@ TODO_SCHEMA = {
from tools.registry import registry, tool_error
registry.register(
name="todo_list",
toolset="todo",
schema=TODO_SCHEMA,
name="todo_list", toolset="todo", schema=TODO_SCHEMA, check_fn=check_todo_requirements,
handler=lambda args, **kw: todo_tool(
todos=args.get("todos"), merge=args.get("merge", False), store=kw.get("store")),
check_fn=check_todo_requirements,
emoji="📋",
)
emoji="📋")
+8 -15
View File
@@ -10,8 +10,6 @@ from typing import Any, Dict, Optional
from utils import is_truthy_value
logger = logging.getLogger(__name__)
_DEFAULT_BROWSER_PROVIDER = "local"
_DEFAULT_MODAL_MODE = "auto"
_VALID_MODAL_MODES = {"auto", "direct", "managed"}
@@ -83,19 +81,14 @@ def resolve_modal_backend_state(
if managed_enabled is None:
managed_enabled = managed_nous_tools_enabled()
managed_ok = managed_enabled and managed_ready
if requested_mode == "managed":
selected_backend = "managed" if managed_ok else None
elif requested_mode == "direct":
selected_backend = "direct" if has_direct else None
else:
selected_backend = "managed" if managed_ok else "direct" if has_direct else None
return {
"requested_mode": requested_mode,
"mode": requested_mode,
"has_direct": has_direct,
"managed_ready": managed_ready,
"managed_mode_blocked": requested_mode == "managed" and not managed_enabled,
"selected_backend": selected_backend}
exclusive = {"managed": "managed" if managed_ok else None,
"direct": "direct" if has_direct else None}
selected_backend = exclusive.get(
requested_mode, "managed" if managed_ok else "direct" if has_direct else None)
return {"requested_mode": requested_mode, "mode": requested_mode, "has_direct": has_direct,
"managed_ready": managed_ready,
"managed_mode_blocked": requested_mode == "managed" and not managed_enabled,
"selected_backend": selected_backend}
def _scoped_credential(name: str) -> str:
+2 -3
View File
@@ -214,9 +214,8 @@ def maybe_persist_tool_result(
preview, has_more = generate_preview(content, max_chars=config.preview_size)
def _persisted(path: str, host_suffix: str = "") -> str:
logger.info(
"Persisted large tool result: %s (%s, %d chars -> %s%s)",
tool_name, tool_use_id, len(content), path, host_suffix)
logger.info("Persisted large tool result: %s (%s, %d chars -> %s%s)",
tool_name, tool_use_id, len(content), path, host_suffix)
return _build_persisted_message(preview, has_more, len(content), path)
# Always persist host-side first: cache/spillover is the single canonical home.
+5 -10
View File
@@ -17,25 +17,21 @@ from dataclasses import dataclass
from typing import Any, Dict, Iterable, List, Optional, Tuple
from tools.registry import tool_error
from tools.tool_search_names import ( # noqa: F401 — re-exported public names
BRIDGE_TOOL_NAMES, TOOL_CALL_NAME, TOOL_DESCRIBE_NAME, TOOL_SEARCH_NAME)
from tools.tool_search_catalog import ( # noqa: F401 — re-exported public/test names
CHARS_PER_TOKEN, CatalogEntry, _corpus_stats, _entry_search_text, _fn,
_listing_group_label, _registry_entry, _short_desc, _stem, _tokenize,
build_catalog, build_catalog_listing_with_form, search_catalog)
BRIDGE_TOOL_NAMES, CHARS_PER_TOKEN, TOOL_CALL_NAME, TOOL_DESCRIBE_NAME, TOOL_SEARCH_NAME,
CatalogEntry, _corpus_stats, _entry_search_text, _fn, _listing_group_label,
_registry_entry, _short_desc, _stem, _tokenize, build_catalog,
build_catalog_listing_with_form, search_catalog)
from tools.tool_search_validation import validate_deferred_call_args # noqa: F401
logger = logging.getLogger("tools.tool_search")
# Bound the work one bridge call can request.
_MAX_QUERIES_PER_CALL = 10
_MAX_QUERIES_PER_CALL = 10 # bound the work one bridge call can request
_MAX_DESCRIBE_NAMES_PER_CALL = 10
@dataclass(frozen=True)
class ToolSearchConfig:
"""Resolved, validated tool-search configuration for a single assembly."""
enabled: str # "auto" | "on" | "off" — "auto" is an alias of "on" today
# Listing budget as % of context; does NOT gate activation, only bounds how much
# the embedded manifest may consume before it degrades (full -> names -> bare).
@@ -313,7 +309,6 @@ def bridge_tool_schemas(
@dataclass
class AssemblyResult:
"""Outcome of one assembly (tests and observability)."""
tool_defs: List[Dict[str, Any]]
activated: bool
deferred_count: int = 0
+6 -2
View File
@@ -13,8 +13,12 @@ from typing import Any, Dict, List, Optional, Tuple
import snowballstemmer
from tools.tool_search_names import TOOL_CALL_NAME, TOOL_DESCRIBE_NAME, TOOL_SEARCH_NAME
# Reserved bridge names: a user/plugin/MCP tool may not take them (registry override
# protection rejects such registrations).
TOOL_SEARCH_NAME = "tool_search"
TOOL_DESCRIBE_NAME = "tool_describe"
TOOL_CALL_NAME = "tool_call"
BRIDGE_TOOL_NAMES = frozenset({TOOL_SEARCH_NAME, TOOL_DESCRIBE_NAME, TOOL_CALL_NAME})
# Chars-per-token rule of thumb; 4.0 slightly underestimates (fewer false activations).
CHARS_PER_TOKEN = 4.0
-9
View File
@@ -1,9 +0,0 @@
"""Reserved bridge tool names shared by tool_search and its catalog module."""
# Reserved: a user/plugin/MCP tool may not take these names — the registry's
# override protection rejects such registrations.
TOOL_SEARCH_NAME = "tool_search"
TOOL_DESCRIBE_NAME = "tool_describe"
TOOL_CALL_NAME = "tool_call"
BRIDGE_TOOL_NAMES = frozenset({TOOL_SEARCH_NAME, TOOL_DESCRIBE_NAME, TOOL_CALL_NAME})
+5 -11
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
"""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
@@ -139,14 +138,9 @@ def check_tours_enabled() -> bool:
registry.register(
name="gui_tour",
toolset="desktop_ui",
schema=TOUR_SCHEMA,
name="gui_tour", toolset="desktop_ui", schema=TOUR_SCHEMA, check_fn=check_tours_enabled,
handler=lambda args, **kw: tour_tool(
action=args.get("action", ""),
**{k: args.get(k) for k in ("surface", "selector", "title", "text", "side", "steps", "step_index")},
callback=kw.get("callback"),
),
check_fn=check_tours_enabled,
emoji="🧭",
)
action=args.get("action", ""), callback=kw.get("callback"),
**{k: args.get(k) for k in ("surface", "selector", "title", "text", "side", "steps",
"step_index")}),
emoji="🧭")