refactor: migrate hand-rolled error envelopes to shared tool_error()

Replace json.dumps({"error": ...}) boilerplate with the documented
tools/registry.py tool_error() helper across 13 files.

Migrated: 59 sites (58 code sites + 1 docstring example in
path_security.py), incl. multi-key envelopes passed via kwargs
(available_actions, path/already_read, pattern/already_searched,
parameters/hint, needs_reauth/server, error_type/tool/result_type).
Also removed 2 now-redundant local tool_error imports in mcp_tool.py
in favor of a module-level import.

Skipped (not byte/shape-compatible with tool_error):
- {"success": false, "error": ...} envelopes (browser_tool,
  browser_camofox, browser_dialog_tool, web_tools, tts_tool,
  skills_tool, image_generation_tool, project_tools, memory_tool,
  cronjob_tools, x_search_tool, xai_video_tools) — leading keys
  differ; key order would change.
- terminal_tool/code_execution_tool envelopes carrying output/
  exit_code/status leading keys.
- tool_search.py:912-area multi-key success paths (non-error).
- mcp_tool.py MCPSampling._error — returns MCP-spec ErrorData
  object, not a JSON string; incompatible.
- send_message_tool._error — returns a dict (not str) and applies
  secret redaction; return type must be preserved.

Behavior note: sites that previously omitted ensure_ascii=False now
emit raw UTF-8 (tool_error's canonical behavior) — JSON-equivalent.

Tests: 23 targeted files (tool_search, discord, file_tools/read
guards/operations, registry, clarify, homeassistant, code_execution,
send_message, delegate, terminal, mcp, model_tools, sanitize_tool_error,
retaindb plugin) — all pass. ruff clean.
This commit is contained in:
teknium1 2026-07-29 09:02:14 -07:00 committed by Teknium
parent f57cb2e482
commit 1a7f73b8ea
13 changed files with 181 additions and 251 deletions

View file

@ -621,7 +621,7 @@ def _rpc_server_loop(
# sandbox-script-supplied JSON.
str(request.get("token") or "").encode(), rpc_token.encode()
):
resp = json.dumps({"error": "Unauthorized RPC request"})
resp = tool_error("Unauthorized RPC request")
conn.sendall((resp + "\n").encode())
continue
@ -631,23 +631,19 @@ def _rpc_server_loop(
# Enforce the allow-list
if tool_name not in allowed_tools:
available = ", ".join(sorted(allowed_tools))
resp = json.dumps({
"error": (
f"Tool '{tool_name}' is not available in execute_code. "
f"Available: {available}"
)
})
resp = tool_error(
f"Tool '{tool_name}' is not available in execute_code. "
f"Available: {available}"
)
conn.sendall((resp + "\n").encode())
continue
# Enforce tool call limit
if tool_call_counter[0] >= max_tool_calls:
resp = json.dumps({
"error": (
f"Tool call limit reached ({max_tool_calls}). "
"No more tool calls allowed in this execution."
)
})
resp = tool_error(
f"Tool call limit reached ({max_tool_calls}). "
"No more tool calls allowed in this execution."
)
conn.sendall((resp + "\n").encode())
continue
@ -923,20 +919,16 @@ def _rpc_poll_loop(
# Enforce allow-list
if tool_name not in allowed_tools:
available = ", ".join(sorted(allowed_tools))
tool_result = json.dumps({
"error": (
f"Tool '{tool_name}' is not available in execute_code. "
f"Available: {available}"
)
})
tool_result = tool_error(
f"Tool '{tool_name}' is not available in execute_code. "
f"Available: {available}"
)
# Enforce tool call limit
elif tool_call_counter[0] >= max_tool_calls:
tool_result = json.dumps({
"error": (
f"Tool call limit reached ({max_tool_calls}). "
"No more tool calls allowed in this execution."
)
})
tool_result = tool_error(
f"Tool call limit reached ({max_tool_calls}). "
"No more tool calls allowed in this execution."
)
else:
# Strip forbidden terminal parameters
if tool_name == "terminal" and isinstance(tool_args, dict):
@ -1207,10 +1199,10 @@ def execute_code(
JSON string with execution results.
"""
if not SANDBOX_AVAILABLE:
return json.dumps({
"error": "execute_code sandbox is unavailable in this environment. "
"Use normal tool calls (terminal, read_file, write_file, ...) instead."
})
return tool_error(
"execute_code sandbox is unavailable in this environment. "
"Use normal tool calls (terminal, read_file, write_file, ...) instead."
)
if not code or not code.strip():
return tool_error("No code provided.")