refactor: dedupe `_dump` helper, collapse retry-policy plumbing, scrub test scars
Tools: - Add a single ``dump_tool_result`` helper in ``tools/_decorator.py`` and remove the eight identical ``_dump`` definitions from ``proxy/tools.py``, ``file_edit/tools.py``, ``python/tool.py``, ``terminal/tool.py``, ``todo/tools.py``, ``browser/tool.py``, ``notes/tools.py``, ``agents_graph/tools.py``. Imports trimmed. Net -50 LoC across the tool modules. run_config_factory: - Inline the four retry-policy plumbing pieces (``_RETRYABLE_HTTP_STATUSES``, ``_DEFAULT_MAX_RETRIES``, ``_DEFAULT_BACKOFF``, ``_default_retry_policy()``) into a single module-level ``_DEFAULT_RETRY`` ``ModelRetrySettings`` literal. The inputs were never overridden and the helper had one caller. Tests: - Drop migration scars from ``tests/test_run_config_factory.py`` (``Phase 1`` / ``C1`` / ``C11`` / ``C21`` / ``HARNESS_WIKI`` / ``AUDIT`` references). Replace the ``_RETRYABLE_HTTP_STATUSES``-touching test with a ``retry.policy is not None`` smoke check now that the constant has been inlined. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ Defaults:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Callable
|
||||
from typing import Any, Literal
|
||||
|
||||
@@ -25,6 +26,16 @@ _ToolFn = Callable[..., Any]
|
||||
_ToolBehavior = Literal["error_as_result", "raise_exception"]
|
||||
|
||||
|
||||
def dump_tool_result(result: dict[str, Any]) -> str:
|
||||
"""Serialize a tool's dict result to JSON for the LLM.
|
||||
|
||||
Every Strix tool returns a dict; the SDK passes the tool's return
|
||||
straight into ``str(result)``, which produces ugly Python repr
|
||||
output. JSON is what the model expects.
|
||||
"""
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
def strix_tool(
|
||||
*,
|
||||
timeout: float = 120.0,
|
||||
|
||||
@@ -26,7 +26,7 @@ from agents.items import TResponseInputItem
|
||||
|
||||
from strix.orchestration.hooks import StrixOrchestrationHooks
|
||||
from strix.run_config_factory import make_agent_context, make_run_config
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -38,10 +38,6 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
def _ctx(ctx: RunContextWrapper) -> dict[str, Any]:
|
||||
return ctx.context if isinstance(ctx.context, dict) else {}
|
||||
|
||||
@@ -61,7 +57,7 @@ async def view_agent_graph(ctx: RunContextWrapper) -> str:
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None:
|
||||
return _dump({"success": False, "error": "Bus not initialized in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus not initialized in context."})
|
||||
|
||||
async with bus._lock:
|
||||
parent_of = dict(bus.parent_of)
|
||||
@@ -90,7 +86,7 @@ async def view_agent_graph(ctx: RunContextWrapper) -> str:
|
||||
"crashed": sum(1 for s in statuses.values() if s == "crashed"),
|
||||
"stopped": sum(1 for s in statuses.values() if s == "stopped"),
|
||||
}
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"graph_structure": "\n".join(lines) or "(no agents)",
|
||||
@@ -115,17 +111,17 @@ async def agent_status(ctx: RunContextWrapper, agent_id: str) -> str:
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
if bus is None:
|
||||
return _dump({"success": False, "error": "Bus not initialized in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus not initialized in context."})
|
||||
|
||||
async with bus._lock:
|
||||
if agent_id not in bus.statuses:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": f"Unknown agent_id: {agent_id}",
|
||||
}
|
||||
)
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"agent_id": agent_id,
|
||||
@@ -173,11 +169,11 @@ async def send_message_to_agent(
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
return _dump({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
|
||||
async with bus._lock:
|
||||
if target_agent_id not in bus.statuses:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": f"Target agent '{target_agent_id}' not found.",
|
||||
@@ -186,7 +182,7 @@ async def send_message_to_agent(
|
||||
target_status = bus.statuses.get(target_agent_id)
|
||||
|
||||
if target_status in ("completed", "crashed", "stopped"):
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": f"Target agent '{target_agent_id}' is {target_status}; message dropped.",
|
||||
@@ -204,7 +200,7 @@ async def send_message_to_agent(
|
||||
"priority": priority,
|
||||
},
|
||||
)
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"message_id": msg_id,
|
||||
@@ -255,7 +251,7 @@ async def wait_for_message(
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
return _dump({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
|
||||
async with bus._lock:
|
||||
bus.statuses[me] = "waiting"
|
||||
@@ -268,7 +264,7 @@ async def wait_for_message(
|
||||
if pending > 0:
|
||||
async with bus._lock:
|
||||
bus.statuses[me] = "running"
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"status": "message_arrived",
|
||||
@@ -284,7 +280,7 @@ async def wait_for_message(
|
||||
if bus.statuses.get(me) == "waiting":
|
||||
bus.statuses[me] = "running"
|
||||
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"status": "timeout",
|
||||
@@ -348,9 +344,9 @@ async def create_agent(
|
||||
factory: Callable[..., SDKAgent] | None = inner.get("agent_factory")
|
||||
|
||||
if bus is None or parent_id is None:
|
||||
return _dump({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
if factory is None:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": (
|
||||
@@ -366,7 +362,7 @@ async def create_agent(
|
||||
child_agent = factory(name=name, skills=skills or [])
|
||||
except Exception as e:
|
||||
logger.exception("agent_factory raised while building child '%s'", name)
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": f"agent_factory failed: {e!s}",
|
||||
@@ -444,7 +440,7 @@ async def create_agent(
|
||||
async with bus._lock:
|
||||
bus.tasks[child_id] = task_handle
|
||||
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"agent_id": child_id,
|
||||
@@ -502,11 +498,11 @@ async def agent_finish(
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
return _dump({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
return dump_tool_result({"success": False, "error": "Bus or agent_id missing in context."})
|
||||
|
||||
parent_id = inner.get("parent_id")
|
||||
if parent_id is None:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"agent_completed": False,
|
||||
@@ -547,7 +543,7 @@ async def agent_finish(
|
||||
)
|
||||
parent_notified = True
|
||||
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"agent_completed": True,
|
||||
|
||||
@@ -13,19 +13,14 @@ the model.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Literal
|
||||
from typing import Literal
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
from strix.tools._sandbox_dispatch import post_to_sandbox
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
BrowserAction = Literal[
|
||||
"launch",
|
||||
"goto",
|
||||
@@ -137,7 +132,7 @@ async def browser_action(
|
||||
clear: For ``get_console_logs``, clear logs after retrieval
|
||||
(default False).
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"browser_action",
|
||||
|
||||
@@ -13,19 +13,12 @@ sandbox-only dependency).
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
from strix.tools._sandbox_dispatch import post_to_sandbox
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
@strix_tool(timeout=180)
|
||||
async def str_replace_editor(
|
||||
ctx: RunContextWrapper,
|
||||
@@ -66,7 +59,7 @@ async def str_replace_editor(
|
||||
insert_line: Required for ``insert``; new content goes AFTER
|
||||
this line.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"str_replace_editor",
|
||||
@@ -98,7 +91,7 @@ async def list_files(
|
||||
path: Directory path; relative paths anchor at ``/workspace``.
|
||||
recursive: When True, walks subdirectories.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"list_files",
|
||||
@@ -126,7 +119,7 @@ async def search_files(
|
||||
file_pattern: Glob filter (e.g. ``"*.py"``, ``"*.{js,ts}"``).
|
||||
Defaults to all files.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"search_files",
|
||||
|
||||
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -36,10 +36,6 @@ _loaded_notes_run_dir: str | None = None
|
||||
_DEFAULT_CONTENT_PREVIEW_CHARS = 280
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
def _get_run_dir() -> Path | None:
|
||||
try:
|
||||
from strix.telemetry.tracer import get_global_tracer
|
||||
@@ -441,7 +437,7 @@ async def create_note(
|
||||
category: One of the categories above. Default ``"general"``.
|
||||
tags: Optional free-form tags.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await asyncio.to_thread(_create_note_impl, title, content, category, tags),
|
||||
)
|
||||
|
||||
@@ -472,7 +468,7 @@ async def list_notes(
|
||||
include_content: When False (default) entries have a preview;
|
||||
when True the full ``content`` is included.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await asyncio.to_thread(
|
||||
_list_notes_impl,
|
||||
category=category,
|
||||
@@ -490,7 +486,7 @@ async def get_note(ctx: RunContextWrapper, note_id: str) -> str:
|
||||
Args:
|
||||
note_id: Note id from ``create_note`` or a ``list_notes`` entry.
|
||||
"""
|
||||
return _dump(await asyncio.to_thread(_get_note_impl, note_id))
|
||||
return dump_tool_result(await asyncio.to_thread(_get_note_impl, note_id))
|
||||
|
||||
|
||||
@strix_tool(timeout=30)
|
||||
@@ -513,7 +509,7 @@ async def update_note(
|
||||
content: New content, or ``None`` to keep.
|
||||
tags: New tags list, or ``None`` to keep.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await asyncio.to_thread(
|
||||
_update_note_impl,
|
||||
note_id=note_id,
|
||||
@@ -531,4 +527,4 @@ async def delete_note(ctx: RunContextWrapper, note_id: str) -> str:
|
||||
Args:
|
||||
note_id: Note id to delete.
|
||||
"""
|
||||
return _dump(await asyncio.to_thread(_delete_note_impl, note_id))
|
||||
return dump_tool_result(await asyncio.to_thread(_delete_note_impl, note_id))
|
||||
|
||||
@@ -10,19 +10,14 @@ scope_rules, list_sitemap, view_sitemap_entry.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Literal
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
from strix.tools._sandbox_dispatch import post_to_sandbox
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
RequestPart = Literal["request", "response"]
|
||||
SortBy = Literal[
|
||||
"timestamp",
|
||||
@@ -80,7 +75,7 @@ async def list_requests(
|
||||
sort_order: ``asc`` or ``desc``.
|
||||
scope_id: Restrict to a scope (managed via ``scope_rules``).
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"list_requests",
|
||||
@@ -131,7 +126,7 @@ async def view_request(
|
||||
page: 1-indexed page number (only when no ``search_pattern``).
|
||||
page_size: Lines per page.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"view_request",
|
||||
@@ -172,7 +167,7 @@ async def send_request(
|
||||
body: Optional request body string.
|
||||
timeout: Per-request timeout in seconds (default 30).
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"send_request",
|
||||
@@ -221,7 +216,7 @@ async def repeat_request(
|
||||
- ``body`` — replace the body string entirely.
|
||||
- ``cookies`` — dict of cookies to add/update.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"repeat_request",
|
||||
@@ -280,7 +275,7 @@ async def scope_rules(
|
||||
scope_id: Required for ``get`` / ``update`` / ``delete``.
|
||||
scope_name: Required for ``create`` / ``update``.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"scope_rules",
|
||||
@@ -328,7 +323,7 @@ async def list_sitemap(
|
||||
depth: ``"DIRECT"`` (immediate children) or ``"ALL"`` (recursive).
|
||||
page: 1-indexed page (30 entries/page).
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"list_sitemap",
|
||||
@@ -353,6 +348,6 @@ async def view_sitemap_entry(ctx: RunContextWrapper, entry_id: str) -> str:
|
||||
Args:
|
||||
entry_id: Sitemap entry id from ``list_sitemap``.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(ctx, "view_sitemap_entry", {"entry_id": entry_id}),
|
||||
)
|
||||
|
||||
@@ -7,19 +7,14 @@ across multiple ``execute`` calls. Pure pass-through wrapper.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any, Literal
|
||||
from typing import Literal
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
from strix.tools._sandbox_dispatch import post_to_sandbox
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
PythonAction = Literal["new_session", "execute", "close", "list_sessions"]
|
||||
|
||||
|
||||
@@ -82,7 +77,7 @@ async def python_action(
|
||||
session_id: Required for ``execute`` / ``close``. Optional for
|
||||
``new_session`` (auto-generated when omitted).
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"python_action",
|
||||
|
||||
@@ -7,19 +7,12 @@ host-side wrapper is a thin pass-through.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
from strix.tools._sandbox_dispatch import post_to_sandbox
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
@strix_tool(timeout=180)
|
||||
async def terminal_execute(
|
||||
ctx: RunContextWrapper,
|
||||
@@ -92,7 +85,7 @@ async def terminal_execute(
|
||||
concurrent sessions.
|
||||
no_enter: When True, sends keystrokes without a trailing return.
|
||||
"""
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
await post_to_sandbox(
|
||||
ctx,
|
||||
"terminal_execute",
|
||||
|
||||
+19
-19
@@ -15,7 +15,7 @@ from typing import Any
|
||||
|
||||
from agents import RunContextWrapper
|
||||
|
||||
from strix.tools._decorator import strix_tool
|
||||
from strix.tools._decorator import dump_tool_result, strix_tool
|
||||
|
||||
|
||||
VALID_PRIORITIES = ["low", "normal", "high", "critical"]
|
||||
@@ -39,10 +39,6 @@ def _todo_sort_key(todo: dict[str, Any]) -> tuple[int, int, str]:
|
||||
_todos_storage: dict[str, dict[str, dict[str, Any]]] = {}
|
||||
|
||||
|
||||
def _dump(result: dict[str, Any]) -> str:
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
|
||||
def _agent_id_from(ctx: RunContextWrapper) -> str:
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
return str(inner.get("agent_id") or "default")
|
||||
@@ -252,7 +248,7 @@ async def create_todo(
|
||||
},
|
||||
)
|
||||
if not tasks:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": "Provide a title or 'todos' list to create.",
|
||||
@@ -277,9 +273,11 @@ async def create_todo(
|
||||
}
|
||||
created.append({"todo_id": todo_id, "title": task["title"], "priority": task_priority})
|
||||
except (ValueError, TypeError) as e:
|
||||
return _dump({"success": False, "error": f"Failed to create todo: {e}", "todo_id": None})
|
||||
return dump_tool_result(
|
||||
{"success": False, "error": f"Failed to create todo: {e}", "todo_id": None}
|
||||
)
|
||||
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"created": created,
|
||||
@@ -329,7 +327,7 @@ async def list_todos(
|
||||
sv = todo.get("status", "pending")
|
||||
summary[sv] = summary.get(sv, 0) + 1
|
||||
except (ValueError, TypeError) as e:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": False,
|
||||
"error": f"Failed to list todos: {e}",
|
||||
@@ -339,7 +337,7 @@ async def list_todos(
|
||||
},
|
||||
)
|
||||
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{
|
||||
"success": True,
|
||||
"todos": todos_list,
|
||||
@@ -389,7 +387,7 @@ async def update_todo(
|
||||
},
|
||||
)
|
||||
if not updates_to_apply:
|
||||
return _dump(
|
||||
return dump_tool_result(
|
||||
{"success": False, "error": "Provide todo_id or 'updates' list to update."},
|
||||
)
|
||||
|
||||
@@ -409,7 +407,7 @@ async def update_todo(
|
||||
else:
|
||||
updated.append(upd["todo_id"])
|
||||
except (ValueError, TypeError) as e:
|
||||
return _dump({"success": False, "error": str(e)})
|
||||
return dump_tool_result({"success": False, "error": str(e)})
|
||||
|
||||
response: dict[str, Any] = {
|
||||
"success": len(errors) == 0,
|
||||
@@ -420,7 +418,7 @@ async def update_todo(
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
return _dump(response)
|
||||
return dump_tool_result(response)
|
||||
|
||||
|
||||
def _mark(
|
||||
@@ -439,7 +437,7 @@ def _mark(
|
||||
ids.append(todo_id)
|
||||
if not ids:
|
||||
msg = f"Provide todo_id or todo_ids to mark as {new_status}."
|
||||
return _dump({"success": False, "error": msg})
|
||||
return dump_tool_result({"success": False, "error": msg})
|
||||
|
||||
marked: list[str] = []
|
||||
errors: list[dict[str, Any]] = []
|
||||
@@ -454,7 +452,7 @@ def _mark(
|
||||
todo["updated_at"] = timestamp
|
||||
marked.append(tid)
|
||||
except (ValueError, TypeError) as e:
|
||||
return _dump({"success": False, "error": str(e)})
|
||||
return dump_tool_result({"success": False, "error": str(e)})
|
||||
|
||||
key = "marked_done" if new_status == "done" else "marked_pending"
|
||||
response: dict[str, Any] = {
|
||||
@@ -466,7 +464,7 @@ def _mark(
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
return _dump(response)
|
||||
return dump_tool_result(response)
|
||||
|
||||
|
||||
@strix_tool(timeout=30)
|
||||
@@ -531,7 +529,9 @@ async def delete_todo(
|
||||
if todo_id is not None:
|
||||
ids.append(todo_id)
|
||||
if not ids:
|
||||
return _dump({"success": False, "error": "Provide todo_id or todo_ids to delete."})
|
||||
return dump_tool_result(
|
||||
{"success": False, "error": "Provide todo_id or todo_ids to delete."}
|
||||
)
|
||||
|
||||
deleted: list[str] = []
|
||||
errors: list[dict[str, Any]] = []
|
||||
@@ -542,7 +542,7 @@ async def delete_todo(
|
||||
del agent_todos[tid]
|
||||
deleted.append(tid)
|
||||
except (ValueError, TypeError) as e:
|
||||
return _dump({"success": False, "error": str(e)})
|
||||
return dump_tool_result({"success": False, "error": str(e)})
|
||||
|
||||
response: dict[str, Any] = {
|
||||
"success": len(errors) == 0,
|
||||
@@ -553,4 +553,4 @@ async def delete_todo(
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
return _dump(response)
|
||||
return dump_tool_result(response)
|
||||
|
||||
Reference in New Issue
Block a user