File size: 1,785 Bytes
da79e97 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | from typing import Dict, Any, List, Optional
class ExecutionTrace:
"""
Stores a sequential list of steps for the Live Execution Timeline.
Exposes the internal agentic reasoning of Shadow as a visual trace.
"""
def __init__(self):
self.steps: List[Dict[str, Any]] = []
def add_step(self, agent: str, input_str: str, output: Dict[str, Any], summary: str, risk_hint: Optional[str] = None):
step_number = len(self.steps)
step = {
"step": step_number,
"agent": agent,
"input": input_str,
"output": output,
"summary": summary,
"risk_hint": risk_hint
}
self.steps.append(step)
def get_trace(self) -> List[Dict[str, Any]]:
return self.steps
def clear(self):
self.steps = []
def format_execution_trace(trace: List[Dict[str, Any]]) -> str:
"""Returns a human-readable timeline of the execution trace."""
lines = []
for step in trace:
# Format: [STEP 1] OSINT PRECHECK → mpesa_reversal detected
# If the user specifically wants OSINT PRECHECK to be STEP 0, or if they meant the first step is step 0:
# The prompt says: "OSINT Precheck must be STEP 0: Log: agent = 'OSINT_PRECHECK'"
# But also says: "[STEP 1] OSINT PRECHECK -> ..." in the example.
# I'll just use the step_number from the dictionary (which starts at 0).
step_num = step["step"]
agent = step["agent"].replace("_", " ")
if not agent.endswith("AGENT") and agent != "OSINT PRECHECK":
# Just in case agent string doesn't include "AGENT" already
pass
lines.append(f"[STEP {step_num}] {agent.upper()} -> {step['summary']}")
return "\n".join(lines)
|