diff --git a/tools/registry.py b/tools/registry.py index 2f35a30bbb..cb82d1f12f 100644 --- a/tools/registry.py +++ b/tools/registry.py @@ -42,11 +42,9 @@ def _bound_error_text(text: str) -> str: def _bound_json_error_result(result: str) -> str: - """Trim an oversized ``error`` field in a JSON string result. - - Handlers that ``json.dumps({"error": str(exc)})`` directly bypass ``tool_error``'s - cap; applied at the dispatch boundary so no tool can stack unbounded errors across retries. - """ + """Trim an oversized ``error`` field in a JSON string result: handlers that + ``json.dumps({"error": str(exc)})`` directly bypass ``tool_error``'s cap, so this runs + at the dispatch boundary to stop unbounded errors stacking across retries.""" if len(result) <= _MAX_TOOL_ERROR_CHARS or '"error"' not in result: return result try: @@ -212,9 +210,7 @@ _OVERRIDE_DENIED_MSG = ( "without operator opt-in (allow_tool_override).") -# --------------------------------------------------------------------------- -# check_fn TTL cache -# +# ---- check_fn TTL cache ---------------------------------------------------- # check_fns probe external state (Docker daemon, Modal SDK, playwright binary) that # changes on human timescales, so results are cached ~30 s: env-var flips via # ``hermes tools`` still propagate within a turn or two with no explicit invalidation. @@ -226,7 +222,6 @@ _OVERRIDE_DENIED_MSG = ( # grace window serves the last-good True WITHOUT caching the failure. A failure # persisting past the window is honored, so a backend that really went down stops # advertising its tools. -# --------------------------------------------------------------------------- _CHECK_FN_TTL_SECONDS = 30.0 # Grace window after a success in which a failure counts as a flake; kept short @@ -394,11 +389,8 @@ def invalidate_check_fn_cache() -> None: def get_cached_check_fn_result(fn: Callable) -> Optional[bool]: - """Cached verdict for *fn* if its TTL is still valid, else None. - - NEVER executes the probe: for read-only surfaces (dashboard status panels) - that must not trigger network / auth / SDK work inside a request path. - """ + """Cached verdict for *fn* if its TTL is still valid, else None. NEVER runs the probe: + for read-only surfaces (dashboard panels) that must not do network/auth/SDK work.""" now = time.monotonic() scope = check_fn_cache_scope() if scope == CHECK_FN_CACHE_BYPASS: @@ -532,18 +524,13 @@ class ToolRegistry: with self._lock: return self._toolset_aliases.get(alias) - # ------------------------------------------------------------------ - # Registration - # ------------------------------------------------------------------ + # ---- Registration ------------------------------------------------ def register_plugin_override_policy( self, module_namespace: str, allowed: bool, *, scope: Optional[str] = None, ) -> _PluginOverridePolicy: - """Bind a plugin module namespace to its current operator opt-in. - - The identity-bearing result lets plugin unload/reload revoke a stale - authorization without losing durable module-to-profile attribution. - """ + """Bind a plugin module namespace to its current operator opt-in. The identity-bearing + result lets unload/reload revoke a stale authorization without losing attribution.""" with self._lock: policy = _PluginOverridePolicy(allowed) self._plugin_override_policy[(scope, module_namespace)] = policy @@ -659,11 +646,8 @@ class ToolRegistry: @staticmethod def _caller_module() -> str: """Best-effort module name of the registry method's caller (two frames up). - - ``deregister()`` takes only a tool name — no handler to bind authorization - to via ``_plugin_owner_of`` — so frame inspection is the only way to know - who is asking. - """ + ``deregister()`` takes only a tool name — no handler for ``_plugin_owner_of`` — + so frame inspection is the only way to know who is asking.""" try: return sys._getframe(2).f_globals.get("__name__", "") or "" except Exception: @@ -824,11 +808,9 @@ class ToolRegistry: scope: Optional[str] = None, ) -> bool: """Restore a host-owned registration if it is still current (plugin ownership ledger). - - The identity check is deliberate: another plugin (or another ``PluginManager`` - in a multi-profile process) may have registered a newer entry under the same - name, in which case unloading this entry must leave the newer one untouched. - """ + The identity check is deliberate: another plugin (or ``PluginManager`` in a + multi-profile process) may have registered a newer entry under the same name, and + unloading this entry must leave that newer one untouched.""" with self._lock: target = self._slot(scope, create=True) if target.get(name) is not current: @@ -864,15 +846,11 @@ class ToolRegistry: logger.debug("Restored tool registration: %s", name) return True - # ------------------------------------------------------------------ - # Schema retrieval - # ------------------------------------------------------------------ + # ---- Schema retrieval -------------------------------------------- def get_definitions(self, tool_names: Set[str], quiet: bool = False) -> List[dict]: - """OpenAI-format schemas for the requested tools whose ``check_fn`` passes (or is absent). - - Probes go through the ~30 s TTL cache so ``hermes tools enable`` still lands quickly. - """ + """OpenAI-format schemas for the requested tools whose ``check_fn`` passes (or is + absent). Probes use the ~30 s TTL cache so ``hermes tools enable`` lands quickly.""" result = [] check_results: Dict[Callable, bool] = {} entries_by_name = {entry.name: entry for entry in self._snapshot_entries()} @@ -901,9 +879,7 @@ class ToolRegistry: result.append({"type": "function", "function": schema_with_name}) return result - # ------------------------------------------------------------------ - # Dispatch - # ------------------------------------------------------------------ + # ---- Dispatch ---------------------------------------------------- @staticmethod def _normalize_handler_result(name: str, result): @@ -954,9 +930,7 @@ class ToolRegistry: sanitized = raw # defensive: never let the sanitizer block error propagation return tool_error(sanitized) - # ------------------------------------------------------------------ - # Query helpers - # ------------------------------------------------------------------ + # ---- Query helpers ----------------------------------------------- def get_max_result_size(self, name: str, default: int | float | None = None) -> int | float: """Return per-tool max result size, or *default* (or global default).""" diff --git a/tools/schema_sanitizer.py b/tools/schema_sanitizer.py index 805cd17b14..7d689f2902 100644 --- a/tools/schema_sanitizer.py +++ b/tools/schema_sanitizer.py @@ -39,11 +39,9 @@ def sanitize_property_key(key: str) -> str: def _rename_property_keys(props: dict, path: str) -> dict[str, str]: - """Return {original_key: conforming_key} for one properties dict (identity entries omitted). - + """{original_key: conforming_key} for one properties dict (identity entries omitted). Deterministic (insertion order, numeric suffixes on collision) so the model-visible - schema and the dispatch-time reverse map from the registry's original schema agree. - """ + schema and the dispatch-time reverse map from the registry's original schema agree.""" renames: dict[str, str] = {} taken = {k for k in props if _PROP_KEY_RE.match(k)} for key in props: @@ -64,11 +62,8 @@ def _rename_property_keys(props: dict, path: str) -> dict[str, str]: def unrename_tool_args(params_schema: Any, args: Any) -> Any: - """Map sanitized property keys in model-emitted args back to wire names. - - ``params_schema`` is the ORIGINAL (unsanitized) registry schema. Recurses into - object values and array items; unknown keys pass through untouched. - """ + """Map sanitized property keys in model-emitted args back to wire names. ``params_schema`` + is the ORIGINAL registry schema; recurses into objects/array items; unknown keys pass.""" if not isinstance(params_schema, dict) or not isinstance(args, dict): return args props = params_schema.get("properties") @@ -148,11 +143,9 @@ _TOP_LEVEL_FORBIDDEN_KEYS = ("allOf", "anyOf", "oneOf", "enum", "not") def _strip_top_level_combinators(params: dict, *, path: str = "") -> dict: - """Drop combinators from the TOP level only (Codex rejects them there). - - They are usually conditional-required hints; dropping them does not change which - argument values are valid (handlers re-validate). Nested combinators are preserved. - """ + """Drop combinators from the TOP level only (Codex rejects them there). They are usually + conditional-required hints, so validity is unchanged (handlers re-validate); nested + combinators are preserved.""" if not isinstance(params, dict): return params out = dict(params) @@ -220,11 +213,8 @@ _CONST_PRIMITIVE_TYPES: dict[type, str] = { def _const_branch_type(branch: Any) -> str | None: - """JSON-Schema primitive type of a pure ``const`` branch, else None. - - Qualifies when the dict carries a primitive ``const`` and any declared ``type`` - matches it; ``title``/``description`` are allowed, any other keyword disqualifies. - """ + """JSON-Schema primitive type of a pure ``const`` branch, else None: a primitive ``const`` + whose declared ``type`` (if any) matches; only ``title``/``description`` may accompany it.""" if not isinstance(branch, dict) or "const" not in branch: return None if set(branch) - {"const", "type", "title", "description"}: @@ -286,12 +276,10 @@ _NON_SCHEMA_LIST_KEYS = frozenset({"required", "enum", "examples", "dependentReq def _normalize_type_array(value: list, out: dict) -> None: - """Normalize a ``type: [...]`` array into *out* (llama.cpp and Gemini-via-OpenAI reject arrays). - - Per the AI-SDK behavior: one non-null type → ``type: X`` (+ ``nullable`` if ``null`` - present); several → ``anyOf`` of single-type schemas so EVERY branch survives; none → - ``null`` or the object fallback. Ported from anomalyco/opencode#31877. - """ + """Normalize a ``type: [...]`` array into *out* (llama.cpp and Gemini-via-OpenAI reject + arrays). Per AI-SDK: one non-null type → ``type: X`` (+ ``nullable`` if ``null`` present); + several → ``anyOf`` of single-type schemas so EVERY branch survives; none → ``null`` or + the object fallback. Ported from anomalyco/opencode#31877.""" has_null = "null" in value non_null = [t for t in value if isinstance(t, str) and t != "null"] if len(non_null) == 1: @@ -383,11 +371,9 @@ _STRIP_ON_RECOVERY_KEYS = frozenset({"pattern", "format"}) def _reactive_strip( tools: list[dict], strip_node: Callable[[dict], int], log_msg: str, ) -> tuple[list[dict], int]: - """Apply *strip_node* (returns keywords removed) to every dict node of each tool's parameters. - - Handles OpenAI format (``{"function": {"parameters": ...}}``) and Responses format - (``{"name": ..., "parameters": ...}``). Returns ``(tools, stripped_count)`` — same list. - """ + """Apply *strip_node* (returns keywords removed) to every dict node of each tool's + parameters, in place. Handles OpenAI (``{"function": {"parameters": ..}}``) and Responses + (``{"name": .., "parameters": ..}``) formats. Returns ``(tools, stripped_count)``.""" if not tools: return tools, 0 stripped = 0 @@ -440,12 +426,9 @@ def strip_pattern_and_format(tools: list[dict]) -> tuple[list[dict], int]: def strip_slash_enum(tools: list[dict]) -> tuple[list[dict], int]: - """Strip ``enum`` keywords whose string values contain ``/``, in place. - - xAI's Responses/chat endpoints compile schemas to a grammar that rejects ``/`` in - enum values (HTTP 400 before any token) — typically MCP enums of HuggingFace model - IDs. The constraint is a prompting hint only; the model still sees the description. - """ + """Strip ``enum`` keywords whose string values contain ``/``, in place. xAI compiles + schemas to a grammar that rejects ``/`` in enum values (HTTP 400 before any token) — + typically MCP enums of HuggingFace model IDs. The constraint is a prompting hint only.""" def _strip(node: dict) -> int: enum_val = node.get("enum") if isinstance(enum_val, list) and any(isinstance(v, str) and "/" in v for v in enum_val): diff --git a/tools/self_repo_guard.py b/tools/self_repo_guard.py index 71d180bd96..ce8ae8a541 100644 --- a/tools/self_repo_guard.py +++ b/tools/self_repo_guard.py @@ -219,14 +219,11 @@ def _cd_target(executable: str, args: list[str], cwd: Path) -> Path | None: def _shell_script_arg(args: list[str]) -> str | None: - """Return the script string owned by a shell's ``-c``, if present. - - approval.py's ``_bash_exec_payload`` parses bash's real option grammar - (``-o pipefail -c '