refactor: collapse dual stat buckets, prune unused params, kill dead helpers
Tracer:
- Collapse the ``live`` / ``completed`` LLM stat buckets into one
flat dict. The ``completed`` bucket was only ever written by tests
— production never moved stats across, and ``get_total_llm_stats``
always summed both for display.
- Drop ``record_llm_usage(agent_id=...)``: argument was unused, and
the per-call ``bucket=`` knob is gone with the buckets.
run_config_factory:
- Drop unused ``parallel_tool_calls``, ``tool_choice`` parameters
from ``make_run_config`` — no caller ever overrode them.
- Drop ``agent_name`` from ``make_agent_context`` — set into the
context dict but no consumer ever read it; the bus's ``names`` map
is the source of truth.
Wire reasoning_effort through:
- ``Config.get("strix_reasoning_effort")`` is now actually plumbed
to ``make_run_config`` from ``entry.py``. Previously the env var
was advertised but never consumed.
Multi-agent graph tools:
- Replace six copies of
``inner = ctx.context if isinstance(ctx.context, dict) else {}``
with a single ``_ctx(ctx)`` helper.
Todo tools:
- Lift the duplicated ``priority_order`` / ``status_order`` dicts
to module-level ``_PRIORITY_RANK`` / ``_STATUS_RANK`` and replace
both inline sort lambdas with ``_todo_sort_key``.
Notes tools:
- Delete ``append_note_content`` (and its test): docstring claimed
it was for an "agents-graph wiki-update hook on agent_finish" that
was never wired up. Pure dead public API.
Style:
- Drop the ``del ctx`` no-ops from notes / reporting / web_search
tools. ``ARG001`` is already silenced project-wide for tool
modules; the ``del`` was cargo-culted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,10 @@ 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 {}
|
||||
|
||||
|
||||
@strix_tool(timeout=30)
|
||||
async def view_agent_graph(ctx: RunContextWrapper) -> str:
|
||||
"""Print the multi-agent tree — every agent, its parent, its status.
|
||||
@@ -53,7 +57,7 @@ async def view_agent_graph(ctx: RunContextWrapper) -> str:
|
||||
bullet list with status in brackets; the agent that called this tool
|
||||
is marked ``← you``.
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None:
|
||||
@@ -108,7 +112,7 @@ async def agent_status(ctx: RunContextWrapper, agent_id: str) -> str:
|
||||
agent_id: The 8-char id from ``view_agent_graph`` /
|
||||
``create_agent``.
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
if bus is None:
|
||||
return _dump({"success": False, "error": "Bus not initialized in context."})
|
||||
@@ -165,7 +169,7 @@ async def send_message_to_agent(
|
||||
expected). Default ``information``.
|
||||
priority: ``low`` / ``normal`` / ``high`` / ``urgent``.
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
@@ -247,7 +251,7 @@ async def wait_for_message(
|
||||
returns and you decide whether to keep working or wait
|
||||
again.
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
@@ -338,7 +342,7 @@ async def create_agent(
|
||||
when starting a clean-slate task.
|
||||
skills: Comma-separated skill names. Max 5; prefer 1-3.
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
parent_id = inner.get("agent_id")
|
||||
factory: Callable[..., SDKAgent] | None = inner.get("agent_factory")
|
||||
@@ -408,7 +412,6 @@ async def create_agent(
|
||||
caido_host_port=inner.get("caido_host_port"),
|
||||
caido_capability=inner.get("caido_capability"),
|
||||
agent_id=child_id,
|
||||
agent_name=name,
|
||||
parent_id=parent_id,
|
||||
tracer=inner.get("tracer"),
|
||||
model=inner.get("model", "anthropic/claude-sonnet-4-6"),
|
||||
@@ -495,7 +498,7 @@ async def agent_finish(
|
||||
parent (e.g., "prioritize testing X", "spawn an agent to
|
||||
cover Y").
|
||||
"""
|
||||
inner = ctx.context if isinstance(ctx.context, dict) else {}
|
||||
inner = _ctx(ctx)
|
||||
bus = inner.get("bus")
|
||||
me = inner.get("agent_id")
|
||||
if bus is None or me is None:
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
from .tools import (
|
||||
append_note_content,
|
||||
create_note,
|
||||
delete_note,
|
||||
get_note,
|
||||
list_notes,
|
||||
update_note,
|
||||
)
|
||||
from .tools import create_note, delete_note, get_note, list_notes, update_note
|
||||
|
||||
|
||||
__all__ = [
|
||||
"append_note_content",
|
||||
"create_note",
|
||||
"delete_note",
|
||||
"get_note",
|
||||
|
||||
@@ -246,7 +246,7 @@ def _create_note_impl( # noqa: PLR0911
|
||||
category: str = "general",
|
||||
tags: list[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Create one note. Public — used by ``append_note_content`` and tests."""
|
||||
"""Create one note. Public — used by tests."""
|
||||
with _notes_lock:
|
||||
try:
|
||||
_ensure_notes_loaded()
|
||||
@@ -398,22 +398,6 @@ def _delete_note_impl(note_id: str) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def append_note_content(note_id: str, delta: str) -> dict[str, Any]:
|
||||
"""Append text to an existing note's content. Used by the agents-graph
|
||||
wiki-update hook on agent_finish."""
|
||||
with _notes_lock:
|
||||
try:
|
||||
_ensure_notes_loaded()
|
||||
if note_id not in _notes_storage:
|
||||
return {"success": False, "error": f"Note with ID '{note_id}' not found"}
|
||||
note = _notes_storage[note_id]
|
||||
existing = str(note.get("content") or "")
|
||||
updated = f"{existing.rstrip()}{delta}"
|
||||
return _update_note_impl(note_id=note_id, content=updated)
|
||||
except (ValueError, TypeError) as e:
|
||||
return {"success": False, "error": f"Failed to append note content: {e}"}
|
||||
|
||||
|
||||
# --- public tools ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -457,7 +441,6 @@ async def create_note(
|
||||
category: One of the categories above. Default ``"general"``.
|
||||
tags: Optional free-form tags.
|
||||
"""
|
||||
del ctx
|
||||
return _dump(
|
||||
await asyncio.to_thread(_create_note_impl, title, content, category, tags),
|
||||
)
|
||||
@@ -489,7 +472,6 @@ async def list_notes(
|
||||
include_content: When False (default) entries have a preview;
|
||||
when True the full ``content`` is included.
|
||||
"""
|
||||
del ctx
|
||||
return _dump(
|
||||
await asyncio.to_thread(
|
||||
_list_notes_impl,
|
||||
@@ -508,7 +490,6 @@ async def get_note(ctx: RunContextWrapper, note_id: str) -> str:
|
||||
Args:
|
||||
note_id: Note id from ``create_note`` or a ``list_notes`` entry.
|
||||
"""
|
||||
del ctx
|
||||
return _dump(await asyncio.to_thread(_get_note_impl, note_id))
|
||||
|
||||
|
||||
@@ -532,7 +513,6 @@ async def update_note(
|
||||
content: New content, or ``None`` to keep.
|
||||
tags: New tags list, or ``None`` to keep.
|
||||
"""
|
||||
del ctx
|
||||
return _dump(
|
||||
await asyncio.to_thread(
|
||||
_update_note_impl,
|
||||
@@ -551,5 +531,4 @@ async def delete_note(ctx: RunContextWrapper, note_id: str) -> str:
|
||||
Args:
|
||||
note_id: Note id to delete.
|
||||
"""
|
||||
del ctx
|
||||
return _dump(await asyncio.to_thread(_delete_note_impl, note_id))
|
||||
|
||||
@@ -399,7 +399,6 @@ async def create_vulnerability_report(
|
||||
``fix_before`` (verbatim source), ``fix_after`` (suggested
|
||||
replacement).
|
||||
"""
|
||||
del ctx
|
||||
result = await asyncio.to_thread(
|
||||
_do_create,
|
||||
title=title,
|
||||
|
||||
+16
-25
@@ -21,6 +21,17 @@ from strix.tools._decorator import strix_tool
|
||||
VALID_PRIORITIES = ["low", "normal", "high", "critical"]
|
||||
VALID_STATUSES = ["pending", "in_progress", "done"]
|
||||
|
||||
_PRIORITY_RANK = {"critical": 0, "high": 1, "normal": 2, "low": 3}
|
||||
_STATUS_RANK = {"done": 0, "in_progress": 1, "pending": 2}
|
||||
|
||||
|
||||
def _todo_sort_key(todo: dict[str, Any]) -> tuple[int, int, str]:
|
||||
return (
|
||||
_STATUS_RANK.get(todo.get("status", "pending"), 99),
|
||||
_PRIORITY_RANK.get(todo.get("priority", "normal"), 99),
|
||||
todo.get("created_at", ""),
|
||||
)
|
||||
|
||||
|
||||
# Per-agent silo: ``_todos_storage[agent_id][todo_id] = todo_dict``.
|
||||
# Keyed by ``ctx.context['agent_id']`` so two agents in the same scan
|
||||
@@ -49,22 +60,10 @@ def _normalize_priority(priority: str | None, default: str = "normal") -> str:
|
||||
|
||||
|
||||
def _sorted_todos(agent_id: str) -> list[dict[str, Any]]:
|
||||
agent_todos = _get_agent_todos(agent_id)
|
||||
todos_list: list[dict[str, Any]] = []
|
||||
for todo_id, todo in agent_todos.items():
|
||||
entry = todo.copy()
|
||||
entry["todo_id"] = todo_id
|
||||
todos_list.append(entry)
|
||||
|
||||
priority_order = {"critical": 0, "high": 1, "normal": 2, "low": 3}
|
||||
status_order = {"done": 0, "in_progress": 1, "pending": 2}
|
||||
todos_list.sort(
|
||||
key=lambda x: (
|
||||
status_order.get(x.get("status", "pending"), 99),
|
||||
priority_order.get(x.get("priority", "normal"), 99),
|
||||
x.get("created_at", ""),
|
||||
),
|
||||
)
|
||||
todos_list = [
|
||||
{**todo, "todo_id": todo_id} for todo_id, todo in _get_agent_todos(agent_id).items()
|
||||
]
|
||||
todos_list.sort(key=_todo_sort_key)
|
||||
return todos_list
|
||||
|
||||
|
||||
@@ -323,15 +322,7 @@ async def list_todos(
|
||||
entry["todo_id"] = todo_id
|
||||
todos_list.append(entry)
|
||||
|
||||
priority_order = {"critical": 0, "high": 1, "normal": 2, "low": 3}
|
||||
status_order = {"done": 0, "in_progress": 1, "pending": 2}
|
||||
todos_list.sort(
|
||||
key=lambda x: (
|
||||
status_order.get(x.get("status", "pending"), 99),
|
||||
priority_order.get(x.get("priority", "normal"), 99),
|
||||
x.get("created_at", ""),
|
||||
),
|
||||
)
|
||||
todos_list.sort(key=_todo_sort_key)
|
||||
|
||||
summary: dict[str, int] = {"pending": 0, "in_progress": 0, "done": 0}
|
||||
for todo in todos_list:
|
||||
|
||||
@@ -121,6 +121,5 @@ async def web_search(ctx: RunContextWrapper, query: str) -> str:
|
||||
target tech, and the specific question. Treat it like a
|
||||
ticket title for a senior security engineer.
|
||||
"""
|
||||
del ctx
|
||||
result = await asyncio.to_thread(_do_search, query)
|
||||
return json.dumps(result, ensure_ascii=False, default=str)
|
||||
|
||||
Reference in New Issue
Block a user