BladeSzaSza's picture
fix: define REPO_NAME in hf_upload.sh (ensure_blade_space referenced it)
4948993 verified
Raw
History Blame Contribute Delete
2.27 kB
"""
Structured per-agent I/O tracing for FormScout.
Records every agent's input/output as JSON-serializable dicts.
Used for the Sharing-is-Caring badge (publish full trace to Hub).
"""
from __future__ import annotations
import json
import time
from dataclasses import asdict, is_dataclass
from pathlib import Path
from typing import Any
class TraceRecord:
"""A single agent execution record."""
def __init__(self, agent_name: str, input_data: Any, output_data: Any, duration_ms: float):
self.agent_name = agent_name
self.input_summary = self._summarize(input_data)
self.output_summary = self._summarize(output_data)
self.duration_ms = duration_ms
self.timestamp = time.time()
def _summarize(self, data: Any) -> dict:
"""Convert dataclass or dict to JSON-safe summary."""
if is_dataclass(data) and not isinstance(data, type):
d = asdict(data)
# Don't serialize raw frames (numpy arrays)
if "frames" in d:
d["frames"] = f"[{len(d['frames'])} frames]"
return d
if isinstance(data, dict):
return data
return {"value": str(data)}
def to_dict(self) -> dict:
return {
"agent": self.agent_name,
"timestamp": self.timestamp,
"duration_ms": self.duration_ms,
"input": self.input_summary,
"output": self.output_summary,
}
class PipelineTrace:
"""Collects trace records for a full pipeline run."""
def __init__(self):
self.records: list[TraceRecord] = []
self.start_time = time.time()
def add(self, record: TraceRecord):
self.records.append(record)
def to_dict(self) -> dict:
return {
"total_duration_ms": (time.time() - self.start_time) * 1000,
"n_agents": len(self.records),
"agents": [r.to_dict() for r in self.records],
}
def save(self, path: str | Path):
"""Save trace as JSON."""
p = Path(path)
p.parent.mkdir(parents=True, exist_ok=True)
with open(p, "w") as f:
json.dump(self.to_dict(), f, indent=2, default=str)