use crate::{arf::config::Config, arf::types::*, error::Result};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct ArfRuntime {
_config: Config,
state_manager: Arc<StateManager>,
plugin_manager: Arc<PluginManager>,
active_sessions: Arc<RwLock<HashMap<SessionId, ReasoningSession>>>,
}
impl ArfRuntime {
pub async fn new(
config: Config,
state_manager: StateManager,
plugin_manager: PluginManager,
) -> Result<Self> {
let runtime = Self {
_config: config,
state_manager: Arc::new(state_manager),
plugin_manager: Arc::new(plugin_manager),
active_sessions: Arc::new(RwLock::new(HashMap::new())),
};
runtime.initialize().await?;
Ok(runtime)
}
async fn initialize(&self) -> Result<()> {
tracing::info!("Initializing ARF Runtime v{}", crate::VERSION);
self.state_manager.initialize().await?;
self.plugin_manager.load_plugins().await?;
self.start_background_tasks();
tracing::info!("ARF Runtime initialized successfully");
Ok(())
}
pub async fn start_session(&self, problem_statement: String) -> Result<ReasoningSession> {
let session_id = format!("session_{}", uuid::Uuid::new_v4().simple());
let session = ReasoningSession {
id: session_id.clone(),
problem_statement,
status: SessionStatus::Initialized,
current_step: 0,
total_steps: 10, steps: Vec::new(),
metadata: HashMap::new(),
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
};
self.state_manager.save_session(&session).await?;
self.active_sessions
.write()
.await
.insert(session_id.clone(), session.clone());
tracing::info!("Started reasoning session: {}", session_id);
Ok(session)
}
pub async fn execute_step(
&self,
session_id: &str,
step_output: serde_json::Value,
) -> Result<ReasoningStep> {
let mut sessions = self.active_sessions.write().await;
let session = sessions
.get_mut(session_id)
.ok_or_else(|| ArfError::engine("Session not found"))?;
if session.status != SessionStatus::Running && session.status != SessionStatus::Initialized
{
return Err(ArfError::engine("Session not in executable state"));
}
let current_step_index = session.current_step;
let step_config = self.get_step_config(current_step_index)?;
self.validate_step_output(&step_config, &step_output)?;
let step = ReasoningStep {
id: format!("step_{}_{}", session_id, current_step_index + 1),
step_number: current_step_index + 1,
name: step_config.name.clone(),
instruction: step_config.instruction.clone(),
cognitive_stance: step_config.cognitive_stance.clone(),
time_allocation: step_config.time_allocation.clone(),
status: StepStatus::Completed,
input: Some(step_output),
output: None, validation_result: Some(ValidationResult {
is_valid: true,
score: 1.0,
errors: vec![],
warnings: vec![],
suggestions: vec![],
}),
started_at: Some(chrono::Utc::now()),
completed_at: Some(chrono::Utc::now()),
};
session.steps.push(step.clone());
session.current_step += 1;
session.updated_at = chrono::Utc::now();
if session.current_step >= session.total_steps {
session.status = SessionStatus::Completed;
} else {
session.status = SessionStatus::Running;
}
self.state_manager.save_session(session).await?;
Ok(step)
}
pub async fn get_current_step(&self, session_id: &str) -> Result<Option<ReasoningStep>> {
let sessions = self.active_sessions.read().await;
let session = sessions
.get(session_id)
.ok_or_else(|| ArfError::engine("Session not found"))?;
if session.current_step >= session.total_steps {
return Ok(None); }
let step_config = self.get_step_config(session.current_step)?;
let step = ReasoningStep {
id: format!("step_{}_{}", session_id, session.current_step + 1),
step_number: session.current_step + 1,
name: step_config.name.clone(),
instruction: step_config.instruction.clone(),
cognitive_stance: step_config.cognitive_stance.clone(),
time_allocation: step_config.time_allocation.clone(),
status: StepStatus::Pending,
input: None,
output: None,
validation_result: None,
started_at: None,
completed_at: None,
};
Ok(Some(step))
}
pub async fn get_session_status(&self, session_id: &str) -> Result<ReasoningSession> {
let sessions = self.active_sessions.read().await;
sessions
.get(session_id)
.cloned()
.ok_or_else(|| ArfError::engine("Session not found"))
}
pub async fn list_sessions(&self) -> Vec<ReasoningSession> {
let sessions = self.active_sessions.read().await;
sessions.values().cloned().collect()
}
fn get_step_config(&self, step_number: usize) -> Result<StepConfig> {
match step_number {
0 => Ok(StepConfig {
name: "Define Scope".to_string(),
instruction:
"Delineate the exact boundaries of the problem. What is IN and what is OUT?"
.to_string(),
cognitive_stance: "boundary_setting".to_string(),
time_allocation: "10%_of_total_process".to_string(),
_output_schema: serde_json::json!({
"primary_objective": "string",
"boundary_inclusions": ["string"],
"boundary_exclusions": ["string"],
"success_definition": "string"
}),
}),
1 => Ok(StepConfig {
name: "Identify Constraints".to_string(),
instruction: "List every limiting factor: resources, time, physics, laws, ethics."
.to_string(),
cognitive_stance: "reality_check".to_string(),
time_allocation: "15%_of_total_process".to_string(),
_output_schema: serde_json::json!({
"hard_constraints": ["string"],
"soft_constraints": ["string"],
"resource_limits": {}
}),
}),
_ => Err(ArfError::engine("Step configuration not found")),
}
}
fn validate_step_output(
&self,
_step_config: &StepConfig,
output: &serde_json::Value,
) -> Result<()> {
if !output.is_object() {
return Err(ArfError::validation("output", "Must be a JSON object"));
}
Ok(())
}
fn start_background_tasks(&self) {
let sessions = Arc::clone(&self.active_sessions);
let state_manager = Arc::clone(&self.state_manager);
tokio::spawn(async move {
let mut interval = tokio::time::interval(std::time::Duration::from_secs(60));
loop {
interval.tick().await;
let mut sessions_write = sessions.write().await;
let expired_sessions: Vec<SessionId> = sessions_write
.iter()
.filter(|(_, session)| {
chrono::Utc::now()
.signed_duration_since(session.updated_at)
.num_hours()
> 24
})
.map(|(id, _)| id.clone())
.collect();
for session_id in expired_sessions {
if let Some(session) = sessions_write.remove(&session_id) {
if let Err(e) = state_manager.save_session(&session).await {
tracing::error!("Failed to save expired session {}: {}", session_id, e);
}
}
}
}
});
}
}
#[derive(Debug, Clone)]
struct StepConfig {
name: String,
instruction: String,
cognitive_stance: String,
time_allocation: String,
_output_schema: serde_json::Value,
}