Source code for understudy.check

"""Check: validate a trace against scene expectations."""

from dataclasses import dataclass, field

from .models import Expectations
from .trace import Trace


[docs] @dataclass class CheckResult: """Result of checking a trace against expectations.""" checks: list["CheckItem"] = field(default_factory=list) @property def passed(self) -> bool: return all(c.passed for c in self.checks) @property def failed_checks(self) -> list["CheckItem"]: return [c for c in self.checks if not c.passed]
[docs] def summary(self) -> str: lines = [] for c in self.checks: mark = "✓" if c.passed else "✗" lines.append(f" {mark} {c.label}: {c.detail}") return "\n".join(lines)
def __repr__(self) -> str: n_pass = sum(1 for c in self.checks if c.passed) return f"CheckResult({n_pass}/{len(self.checks)} passed)"
@dataclass class CheckItem: """A single check result.""" label: str passed: bool detail: str
[docs] def check(trace: Trace, expectations: Expectations) -> CheckResult: """Validate a trace against expectations. Args: trace: The execution trace from a rehearsal. expectations: The expectations from a scene. Returns: A CheckResult with individual check outcomes. """ result = CheckResult() called_tools = set(trace.call_sequence()) # required tools for tool in expectations.required_tools: result.checks.append( CheckItem( label="required_tool", passed=tool in called_tools, detail=f"{tool} {'called' if tool in called_tools else 'NOT called'}", ) ) # forbidden tools for tool in expectations.forbidden_tools: was_called = tool in called_tools result.checks.append( CheckItem( label="forbidden_tool", passed=not was_called, detail=f"{tool} {'CALLED (violation)' if was_called else 'not called'}", ) ) # terminal state if expectations.allowed_terminal_states: in_allowed = trace.terminal_state in expectations.allowed_terminal_states result.checks.append( CheckItem( label="terminal_state", passed=in_allowed, detail=( f"{trace.terminal_state} ({'allowed' if in_allowed else 'NOT in allowed'})" ), ) ) if expectations.forbidden_terminal_states: in_forbidden = trace.terminal_state in expectations.forbidden_terminal_states result.checks.append( CheckItem( label="forbidden_terminal_state", passed=not in_forbidden, detail=( f"{trace.terminal_state} " f"{'FORBIDDEN (violation)' if in_forbidden else 'not forbidden'}" ), ) ) # required agents invoked_agents = set(trace.agents_invoked()) for agent in expectations.required_agents: result.checks.append( CheckItem( label="required_agent", passed=agent in invoked_agents, detail=f"{agent} {'invoked' if agent in invoked_agents else 'NOT invoked'}", ) ) # forbidden agents for agent in expectations.forbidden_agents: was_invoked = agent in invoked_agents result.checks.append( CheckItem( label="forbidden_agent", passed=not was_invoked, detail=f"{agent} {'INVOKED (violation)' if was_invoked else 'not invoked'}", ) ) # required agent tools for agent, tools in expectations.required_agent_tools.items(): for tool in tools: called = trace.agent_called(agent, tool) result.checks.append( CheckItem( label="required_agent_tool", passed=called, detail=f"{agent}.{tool} {'called' if called else 'NOT called'}", ) ) return result