Skip to main content
Glama
fsm.py4.83 kB
"""Finite State Machine for scenario execution.""" import time from dataclasses import dataclass, field from enum import Enum from typing import Any, Dict, List, Optional from ..models.scenario import Scenario class State(Enum): """Scenario execution states.""" INIT = "INIT" PRECHECK = "PRECHECK" FAULT_INJECT = "FAULT_INJECT" STABILIZE = "STABILIZE" ASSISTANT_RCA = "ASSISTANT_RCA" EVAL_RCA = "EVAL_RCA" ASSISTANT_REMEDY = "ASSISTANT_REMEDY" EVAL_REMEDY = "EVAL_REMEDY" EXECUTE_REMEDY = "EXECUTE_REMEDY" VERIFY = "VERIFY" PASS = "PASS" FAIL = "FAIL" CLEANUP = "CLEANUP" @dataclass class StepResult: """Result of a single execution step.""" state: State success: bool message: str score: Optional[float] = None artifacts: Dict[str, str] = field(default_factory=dict) metadata: Dict[str, Any] = field(default_factory=dict) timestamp: float = field(default_factory=time.time) @dataclass class ScenarioContext: """Execution context for a scenario run.""" run_id: str scenario: Scenario bindings: Dict[str, str] # Execution state current_state: State = State.INIT start_time: float = field(default_factory=time.time) end_time: Optional[float] = None # Results tracking step_results: List[StepResult] = field(default_factory=list) final_state: Optional[State] = None # Remediation tracking fault_id: Optional[str] = None thread_id: Optional[str] = None interrupt_id: Optional[str] = None rca_response: Optional[str] = None remedy_response: Optional[str] = None def add_result(self, result: StepResult) -> None: """Add a step result to context.""" self.step_results.append(result) self.current_state = result.state def set_final_state(self, state: State) -> None: """Set the final state and end time.""" self.final_state = state self.end_time = time.time() @property def duration(self) -> float: """Get execution duration in seconds.""" end = self.end_time or time.time() return end - self.start_time @property def passed(self) -> bool: """Check if scenario passed.""" return self.final_state == State.PASS def to_dict(self) -> Dict[str, Any]: """Convert context to dictionary.""" return { "run_id": self.run_id, "scenario_id": self.scenario.meta.id, "start_time": self.start_time, "end_time": self.end_time, "duration": self.duration, "current_state": self.current_state.value, "final_state": self.final_state.value if self.final_state else None, "passed": self.passed, "step_results": [ { "state": r.state.value, "success": r.success, "message": r.message, "score": r.score, "timestamp": r.timestamp, } for r in self.step_results ], } @dataclass class ScenarioResult: """Final result of scenario execution.""" run_id: str scenario_id: str passed: bool final_state: State duration: float step_results: List[StepResult] artifacts: Dict[str, str] = field(default_factory=dict) message: str = "" @classmethod def from_context(cls, context: ScenarioContext) -> "ScenarioResult": """Create result from context.""" # Collect all artifacts artifacts = {} for step in context.step_results: artifacts.update(step.artifacts) return cls( run_id=context.run_id, scenario_id=context.scenario.meta.id, passed=context.passed, final_state=context.final_state or context.current_state, duration=context.duration, step_results=context.step_results, artifacts=artifacts, message=f"Scenario {'PASSED' if context.passed else 'FAILED'}", ) def to_dict(self) -> Dict[str, Any]: """Convert result to dictionary.""" return { "run_id": self.run_id, "scenario_id": self.scenario_id, "passed": self.passed, "final_state": self.final_state.value, "duration": self.duration, "message": self.message, "artifacts": self.artifacts, "step_results": [ { "state": r.state.value, "success": r.success, "message": r.message, "score": r.score, "timestamp": r.timestamp, } for r in self.step_results ], }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Purv123/Remidiation-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server