Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion strix/core/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ async def _run_noninteractive_until_lifecycle(
result: RunResultBase | None = None
input_data: Any = initial_input
invalid_final_outputs = 0
invalid_final_output_limit = max(1, max_turns)
invalid_final_output_limit = min(5, max(1, max_turns))

while True:
if coordinator.budget_stopped:
Expand Down Expand Up @@ -581,6 +581,16 @@ async def _child_loop() -> None:
)
except BudgetExceededError:
logger.info("child %s stopped after reaching the scan budget limit", child_id)
except MaxTurnsExceeded as exc:
logger.warning("child %s crashed due to MaxTurnsExceeded: %s", child_id, exc)
with contextlib.suppress(Exception):
await coordinator.set_status(child_id, "crashed")
await _notify_parent_on_crash(coordinator, child_id, "crashed")
except Exception:
logger.exception("child %s crashed with unhandled exception", child_id)
Comment thread
Tanmay9223 marked this conversation as resolved.
with contextlib.suppress(Exception):
await coordinator.set_status(child_id, "crashed")
await _notify_parent_on_crash(coordinator, child_id, "crashed")

task_handle = asyncio.create_task(_child_loop(), name=f"agent-{name}-{child_id}")
await coordinator.attach_runtime(child_id, task=task_handle)
12 changes: 12 additions & 0 deletions strix/core/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from agents import RunConfig
from agents.sandbox import SandboxRunConfig
from agents.exceptions import MaxTurnsExceeded
from openai import RateLimitError

from strix.agents.factory import build_strix_agent, make_child_factory
Expand Down Expand Up @@ -391,6 +392,17 @@ async def spawn_child_agent(**kwargs: Any) -> dict[str, Any]:
with contextlib.suppress(Exception):
await coordinator.set_status(root_id, "stopped")
return None
except MaxTurnsExceeded as exc:
logger.warning(
"Scan %s stopped: MaxTurnsExceeded (%s).",
scan_id,
exc,
)
if root_id is not None:
await coordinator.cancel_descendants(root_id)
with contextlib.suppress(Exception):
await coordinator.set_status(root_id, "failed")
return None
except BaseException:
logger.exception("Strix scan %s failed", scan_id)
if root_id is not None:
Expand Down
4 changes: 4 additions & 0 deletions strix/tools/agents_graph/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from agents import RunContextWrapper, function_tool

from strix.core.agents import Status, coordinator_from_context
from strix.report.state import get_global_report_state
from strix.skills import validate_requested_skills


Expand Down Expand Up @@ -574,6 +575,9 @@ async def agent_finish(
)
await coordinator.set_status(me, "completed")

if report_state := get_global_report_state():
report_state.save_run_data()

return json.dumps(
{
"success": True,
Expand Down