Madhav189's picture
Sync project files from main repo
1ba65c9
Raw
History Blame Contribute Delete
8.07 kB
"""Shared typed state for the rebuilt SPECTRA benchmark."""
from __future__ import annotations
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, model_validator
from .openenv_compat import Action, State
ServiceName = Literal["api-gateway", "database", "cache", "worker", "auth_service"]
Difficulty = Literal["easy", "medium", "hard"]
HealthStatus = Literal["healthy", "degraded", "critical"]
WorkflowStage = Literal["triage", "containment", "remediation", "recovery", "retrospective", "done"]
CommanderActionType = Literal[
"investigate_service",
"request_followup",
"isolate_service",
"rollback_config",
"scale_service",
"restart_service",
"submit_resolution",
]
AgentName = Literal["infra", "log", "security"]
SERVICE_NAMES: tuple[ServiceName, ...] = (
"api-gateway",
"database",
"cache",
"worker",
"auth_service",
)
AGENT_NAMES: tuple[AgentName, ...] = ("infra", "log", "security")
class ScenarioObjective(BaseModel):
"""Scenario-specific hidden objective."""
model_config = ConfigDict(extra="forbid")
scenario_id: str
name: str
domain: str
description: str
difficulty: Difficulty
root_cause_service: ServiceName
root_cause_vector: str
decoy_agent: AgentName | None = None
decoy_service: ServiceName | None = None
best_followup_agent: AgentName | None = None
required_plan: list[tuple[CommanderActionType, ServiceName | None]] = Field(default_factory=list)
common_trap: str
specialist_signal_map: dict[AgentName, str] = Field(default_factory=dict)
class CommanderAction(Action):
"""Structured action taken by the commander."""
model_config = ConfigDict(extra="forbid")
action_type: CommanderActionType
target_service: ServiceName | None = None
target_agent: AgentName | None = None
reasoning: str | None = None
resolution_summary: str | None = None
@model_validator(mode="after")
def _validate_payload(self) -> "CommanderAction":
if self.action_type in {
"investigate_service",
"isolate_service",
"rollback_config",
"scale_service",
"restart_service",
} and self.target_service is None:
raise ValueError(f"target_service is required for {self.action_type}")
if self.action_type == "request_followup" and self.target_agent is None:
raise ValueError("target_agent is required for request_followup")
if self.action_type == "submit_resolution" and not self.resolution_summary:
raise ValueError("resolution_summary is required for submit_resolution")
return self
@property
def rendered(self) -> str:
if self.action_type == "request_followup":
return f"{self.action_type}({self.target_agent})"
if self.action_type == "submit_resolution":
return f"{self.action_type}(summary)"
return f"{self.action_type}({self.target_service})"
class ActionResult(State):
"""Judge output for one commander action."""
model_config = ConfigDict(extra="forbid")
message: str
changed: bool
resolved: bool
targeted_root_cause: bool
phase_advanced: bool = False
trap: bool = False
follow_up_used: bool = False
class SpecialistRoundExecution(BaseModel):
"""One specialist's execution artifact for a round."""
model_config = ConfigDict(extra="forbid")
agent: AgentName
channel: Literal["metrics", "logs", "security"]
mode: Literal["rule", "llm"]
observation_digest: str
raw_response: str
latency_ms: float
followup_applied: bool = False
report: dict[str, Any]
class CommanderExecution(State):
"""One commander's decision artifact."""
model_config = ConfigDict(extra="forbid")
mode: Literal["heuristic", "llm"]
raw_response: str
latency_ms: float
trust_weights: dict[str, float] = Field(default_factory=dict)
action: dict[str, Any]
class MultiAgentRound(State):
"""Full parallel analysis round for one step."""
model_config = ConfigDict(extra="forbid")
round_index: int
workflow_stage: WorkflowStage
specialist_executions: list[SpecialistRoundExecution] = Field(default_factory=list)
commander_execution: CommanderExecution | None = None
environment_feedback: str = ""
reward_breakdown: dict[str, float | str | int] = Field(default_factory=dict)
class MasterSREState(State):
"""The full hidden benchmark state."""
model_config = ConfigDict(extra="forbid")
objective: ScenarioObjective
episode_id: str
tick: int = 0
step_budget: int = 0
total_step_budget: int = 0
workflow_stage: WorkflowStage = "triage"
cpu_pct: dict[ServiceName, float]
mem_pct: dict[ServiceName, float]
latency_ms: dict[ServiceName, float]
error_rate: dict[ServiceName, float]
health: dict[ServiceName, HealthStatus]
log_lines: list[str] = Field(default_factory=list)
error_types: dict[str, int] = Field(default_factory=dict)
stack_traces: list[str] = Field(default_factory=list)
query_patterns: list[str] = Field(default_factory=list)
event_sequence: list[dict[str, Any]] = Field(default_factory=list)
alert_strings: list[str] = Field(default_factory=list)
auth_fail_count: int = 0
suspicious_ips: list[str] = Field(default_factory=list)
injection_patterns: list[str] = Field(default_factory=list)
cve_flags: list[str] = Field(default_factory=list)
service_graph: dict[ServiceName, list[ServiceName]] = Field(default_factory=dict)
causal_chain: list[str] = Field(default_factory=list)
follow_up_count: int = 0
pending_followup_agent: AgentName | None = None
followup_history: list[AgentName] = Field(default_factory=list)
followup_answers_seen: dict[AgentName, int] = Field(default_factory=dict)
root_cause_confirmed: bool = False
attack_isolated: bool = False
config_remediated: bool = False
service_recovered: bool = False
resolution_submitted: bool = False
incident_resolved: bool = False
action_history: list[str] = Field(default_factory=list)
last_action_result: str = ""
resolution_history: list[str] = Field(default_factory=list)
progress_flags: dict[str, bool] = Field(default_factory=dict)
round_history: list[dict[str, Any]] = Field(default_factory=list)
@property
def scenario_id(self) -> str:
return self.objective.scenario_id
@property
def difficulty(self) -> Difficulty:
return self.objective.difficulty
@property
def root_cause_service(self) -> ServiceName:
return self.objective.root_cause_service
@property
def root_cause_vector(self) -> str:
return self.objective.root_cause_vector
@property
def common_trap(self) -> str:
return self.objective.common_trap
@property
def best_followup_agent(self) -> AgentName | None:
return self.objective.best_followup_agent
@property
def decoy_agent(self) -> AgentName | None:
return self.objective.decoy_agent
@property
def decoy_service(self) -> ServiceName | None:
return self.objective.decoy_service
@model_validator(mode="after")
def _validate_service_keys(self) -> "MasterSREState":
for mapping_name in ("cpu_pct", "mem_pct", "latency_ms", "error_rate", "health"):
mapping = getattr(self, mapping_name)
if set(mapping) != set(SERVICE_NAMES):
raise ValueError(f"{mapping_name} must contain all services")
return self
def refresh_progress_flags(self) -> None:
self.progress_flags = {
"root_cause_confirmed": self.root_cause_confirmed,
"attack_isolated": self.attack_isolated,
"config_remediated": self.config_remediated,
"service_recovered": self.service_recovered,
"resolution_submitted": self.resolution_submitted,
"incident_resolved": self.incident_resolved,
}