chore(orchestration): drop XML wrappers + close remaining audit gaps

Final pass after re-audit. Three sub-specs landed:

**XML simplification** — the legacy XML envelopes were prompt-engineering
ceremony, not parser primitives (the SDK uses native tool-calling). Drop
the verbose wrappers in favor of one-liner labeled headers. Side benefit:
fixes the unescaped-content XML-injection bug the audit caught (peer
content containing ``</content>`` no longer breaks the wrapper).

- ``_format_inter_agent_message``: ``<inter_agent_message><sender>...
  <content>...`` 9-line XML → ``[Message from {name} ({id}) | type=... |
  priority=...]\n{content}``.
- ``_render_completion_report``: ``<agent_completion_report><agent_info>
  ...<results>...`` XML → human-readable structured text with section
  headers and bulleted lists.
- ``inherited_context``: ``<inherited_context_from_parent>...`` →
  ``== Inherited context from parent (background only) ==``.

**MG1: TUI stop-agent uses graceful cancel.** ``tui.py`` was calling
``bus.cancel_descendants`` (hard, ``task.cancel()`` mid-stream) for the
stop-agent button. Switched to ``bus.cancel_descendants_graceful``, which
uses ``RunResultStreaming.cancel(mode="after_turn")`` to let each agent
finish its current turn (and save to session) before honoring the cancel.
The hard path remains in ``entry.py`` for KeyboardInterrupt where
graceful isn't possible.

**MG2: Document hook lock-free stats mutation.** Added a comment in
``hooks.on_llm_start`` explaining why ``warned_85`` / ``warned_final``
are mutated lock-free: SDK serializes ``on_llm_start`` per agent, so this
hook is the sole writer to those keys; ``record_usage`` only writes
disjoint keys (in/out/cached/calls).

**AG3: Auto-load ``coordination/root_agent`` skill for the root.**
Legacy auto-loaded the orchestration-guidance skill for root agents
only. Threaded ``is_root`` through ``render_system_prompt`` →
``_resolve_skills``; root agents now get the skill, children don't.

Skipped (per user direction): whitebox-wiki integration (CG2-4) — the
auto-injection / auto-update of the shared repo wiki was a pre-migration
feature; user opted not to restore it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
0xallam
2026-04-25 17:48:55 -07:00
parent f4834cd6f7
commit 25decb0685
6 changed files with 66 additions and 46 deletions
+1
View File
@@ -151,6 +151,7 @@ def build_strix_agent(
skills=skills,
scan_mode=scan_mode,
is_whitebox=is_whitebox,
is_root=is_root,
interactive=interactive,
system_prompt_context=system_prompt_context,
)
+10 -1
View File
@@ -27,6 +27,7 @@ def _resolve_skills(
requested: list[str] | None,
scan_mode: str = "deep",
is_whitebox: bool = False,
is_root: bool = False,
) -> list[str]:
"""Build the deduped, ordered skills list for the prompt render.
@@ -36,11 +37,15 @@ def _resolve_skills(
2. ``scan_modes/<mode>`` (always).
3. ``tooling/agent_browser`` (always — every agent has shell + the
agent-browser CLI).
4. Whitebox-specific skills if applicable.
4. ``coordination/root_agent`` for the root agent only — orchestration
guidance for delegating to specialist subagents.
5. Whitebox-specific skills if applicable.
"""
ordered: list[str] = list(requested or [])
ordered.append(f"scan_modes/{scan_mode}")
ordered.append("tooling/agent_browser")
if is_root:
ordered.append("coordination/root_agent")
if is_whitebox:
ordered.append("coordination/source_aware_whitebox")
ordered.append("custom/source_aware_sast")
@@ -59,6 +64,7 @@ def render_system_prompt(
skills: list[str] | None = None,
scan_mode: str = "deep",
is_whitebox: bool = False,
is_root: bool = False,
interactive: bool = False,
system_prompt_context: dict[str, Any] | None = None,
) -> str:
@@ -70,6 +76,8 @@ def render_system_prompt(
skill.
is_whitebox: When True, the source-aware whitebox skill stack
is loaded too.
is_root: When True, ``coordination/root_agent`` orchestration
guidance is auto-loaded.
interactive: When True, the prompt renders the interactive-mode
communication rules block.
system_prompt_context: Free-form dict that the template's
@@ -96,6 +104,7 @@ def render_system_prompt(
requested=skills,
scan_mode=scan_mode,
is_whitebox=is_whitebox,
is_root=is_root,
)
skill_content = load_skills(skills_to_load)
env.globals["get_skill"] = lambda name: skill_content.get(name, "")
+6 -1
View File
@@ -1843,11 +1843,16 @@ class StrixTUIApp(App): # type: ignore[misc]
return agent_name, False
def action_confirm_stop_agent(self, agent_id: str) -> None:
# Graceful stop: each agent's current turn finishes (and is saved to
# session) before the run loop honors the cancel. The interactive
# outer loop sees ``stopping`` and exits with status="stopped".
# The hard ``cancel_descendants`` path remains for KeyboardInterrupt
# in entry.py where graceful isn't possible.
if self._scan_loop is None or self._scan_loop.is_closed():
logging.warning("No active scan loop; cannot stop agent %s", agent_id)
return
asyncio.run_coroutine_threadsafe(
self.bus.cancel_descendants(agent_id),
self.bus.cancel_descendants_graceful(agent_id),
self._scan_loop,
)
+14 -25
View File
@@ -8,7 +8,6 @@ retries — so a single drain per turn doesn't lose messages on retry.
from __future__ import annotations
import logging
from datetime import UTC, datetime
from typing import TYPE_CHECKING
from agents.run_config import CallModelData, ModelInputData
@@ -26,11 +25,8 @@ logger = logging.getLogger(__name__)
async def inject_messages_filter(data: CallModelData) -> ModelInputData:
"""Drain bus inbox and append messages as user-role items before the LLM call.
Peer-agent messages are wrapped in the legacy ``<inter_agent_message>``
XML envelope (sender / metadata / content / delivery_info) so the
receiving model gets the same prompt-shape as pre-migration — including
the explicit "DO NOT echo back" instruction. Direct user messages
(``from="user"``) are passed plain.
Peer-agent messages get a one-line labeled header followed by the
body. Direct user messages (``from="user"``) are passed plain.
Any exception inside the filter — malformed message dict, bug in
``bus.drain``, etc. — is caught and the original ``data.model_data``
@@ -72,31 +68,24 @@ async def inject_messages_filter(data: CallModelData) -> ModelInputData:
def _format_inter_agent_message(bus: AgentMessageBus, msg: dict[str, Any]) -> str:
"""Render a peer-agent message in the legacy XML envelope.
"""Render a peer-agent message as a labeled header + body.
The wrapper carries an explicit "do not echo back" instruction that
the legacy harness used to keep models from quoting the entire
received message dict in their own next turn.
Format:
[Message from {name} ({id}) | type={type} | priority={priority}]
{content}
Plain text by design — no XML wrapping, no escaping concerns. The
label line tells the receiver who sent this and why so it doesn't
confuse a peer message with its own work; the rest of the body is
delivered as-is.
"""
sender_id = str(msg.get("from", "unknown"))
sender_name = bus.names.get(sender_id, sender_id)
msg_type = msg.get("type", "information")
priority = msg.get("priority", "normal")
timestamp = msg.get("timestamp") or datetime.now(UTC).isoformat()
content = str(msg.get("content", ""))
return (
"<inter_agent_message>\n"
" <delivery_notice><important>You have received a message from another "
"agent. Acknowledge and respond to the sender if needed; DO NOT echo "
"back this entire message block.</important></delivery_notice>\n"
f" <sender><agent_name>{sender_name}</agent_name>"
f"<agent_id>{sender_id}</agent_id></sender>\n"
f" <message_metadata><type>{msg_type}</type>"
f"<priority>{priority}</priority>"
f"<timestamp>{timestamp}</timestamp></message_metadata>\n"
f" <content>{content}</content>\n"
" <delivery_info><note>This message was delivered during your task "
"execution. Please acknowledge and respond if needed.</note>"
"</delivery_info>\n"
"</inter_agent_message>"
f"[Message from {sender_name} ({sender_id}) "
f"| type={msg_type} | priority={priority}]\n"
f"{content}"
)
+7
View File
@@ -56,6 +56,13 @@ class StrixOrchestrationHooks(RunHooks[Any]):
# warnings fire exactly once per agent lifetime — surviving
# ``run_with_continuation`` cycles, mirroring legacy
# ``state.max_iterations_warning_sent``.
#
# The flags are mutated lock-free below. Safe because the SDK
# serializes ``on_llm_start`` per agent (one in-flight LLM call
# per ``Runner.run`` instance), so this hook is the sole writer
# to ``warned_85`` / ``warned_final`` for this agent_id.
# ``record_usage`` (which acquires the lock) only writes
# ``in`` / ``out`` / ``cached`` / ``calls`` — disjoint keys.
if cur >= int(max_turns * 0.85) and not stats.get("warned_85"):
stats["warned_85"] = True
input_items.append(
+28 -19
View File
@@ -19,6 +19,7 @@ import asyncio
import json
import logging
import uuid
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any, Literal
from agents import RunContextWrapper, function_tool
@@ -52,26 +53,34 @@ def _render_completion_report(
findings: list[str],
recommendations: list[str],
) -> str:
"""Render an ``<agent_completion_report>`` XML payload (legacy parity)."""
from datetime import UTC, datetime
from html import escape
"""Render a child's completion report as plain structured text.
Goes into the parent's bus inbox; the inject filter prepends a
``[Message from ...]`` header on top, so this body just carries the
contents. No XML — no escaping concerns, no parser ambiguity.
"""
status = "SUCCESS" if success else "FAILED"
completion_time = datetime.now(UTC).isoformat()
findings_xml = "".join(f"<finding>{escape(f)}</finding>" for f in findings)
recs_xml = "".join(f"<recommendation>{escape(r)}</recommendation>" for r in recommendations)
return (
"<agent_completion_report>\n"
f" <agent_info><agent_name>{escape(agent_name)}</agent_name>"
f"<agent_id>{escape(agent_id)}</agent_id>"
f"<task>{escape(task)}</task>"
f"<status>{status}</status>"
f"<completion_time>{completion_time}</completion_time></agent_info>\n"
f" <results><summary>{escape(result_summary)}</summary>"
f"<findings>{findings_xml}</findings>"
f"<recommendations>{recs_xml}</recommendations></results>\n"
"</agent_completion_report>"
)
lines: list[str] = [
f"== Completion report from {agent_name} ({agent_id}) ==",
f"Status: {status}",
f"Time: {completion_time}",
]
if task:
lines.append(f"Task: {task}")
lines.append("")
lines.append("Summary:")
lines.append(result_summary or "(none)")
if findings:
lines.append("")
lines.append("Findings:")
lines.extend(f"- {f}" for f in findings)
if recommendations:
lines.append("")
lines.append("Recommendations:")
lines.extend(f"- {r}" for r in recommendations)
return "\n".join(lines)
@function_tool(timeout=30)
@@ -456,9 +465,9 @@ async def create_agent(
{
"role": "user",
"content": (
"<inherited_context_from_parent>\n"
"== Inherited context from parent (background only) ==\n"
f"{rendered}\n"
"</inherited_context_from_parent>\n"
"== End of inherited context ==\n"
"Use the above as background only; do not continue the "
"parent's work. Your task follows."
),