use super::branch::Branch;
use super::rag::TypeEmbeddings;
use crate::core::SharedUniverse;
use crate::query::QueryEngine;
use crate::validate::StreamingChecker;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SessionId(pub Uuid);
impl SessionId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl Default for SessionId {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct SessionConfig {
pub name: String,
pub agent_type: AgentType,
pub enable_rag: bool,
pub max_branches: usize,
pub isolation_level: IsolationLevel,
}
impl Default for SessionConfig {
fn default() -> Self {
Self {
name: "unnamed".to_string(),
agent_type: AgentType::Generic,
enable_rag: true,
max_branches: 10,
isolation_level: IsolationLevel::Full,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AgentType {
Cursor,
ClaudeCode,
GeminiCLI,
GitHubCopilot,
Generic,
}
impl AgentType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Cursor => "cursor",
Self::ClaudeCode => "claude_code",
Self::GeminiCLI => "gemini_cli",
Self::GitHubCopilot => "github_copilot",
Self::Generic => "generic",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IsolationLevel {
Full,
SharedRead,
Snapshot,
}
pub struct AgentSession {
pub id: SessionId,
pub config: SessionConfig,
universe: Arc<RwLock<Branch>>,
query_engine: QueryEngine,
checker: StreamingChecker,
embeddings: Option<Arc<TypeEmbeddings>>,
metrics: RwLock<SessionMetrics>,
}
#[derive(Debug, Clone, Default)]
pub struct SessionMetrics {
pub queries_processed: u64,
pub validations_performed: u64,
pub branches_created: u64,
pub errors_encountered: u64,
pub latency_us_total: u64,
}
impl AgentSession {
pub async fn new(base_universe: SharedUniverse, config: SessionConfig) -> Self {
let branch = Branch::new(base_universe, config.isolation_level).await;
let branch_arc = Arc::new(RwLock::new(branch));
let universe: crate::core::SharedUniverse = branch_arc.read().await.universe().clone();
let query_engine = QueryEngine::new(universe.clone());
let checker = StreamingChecker::new(universe);
let embeddings = if config.enable_rag {
Some(Arc::new(TypeEmbeddings::new()))
} else {
None
};
Self {
id: SessionId::new(),
config,
universe: branch_arc,
query_engine,
checker,
embeddings,
metrics: RwLock::new(SessionMetrics::default()),
}
}
pub fn query_engine(&self) -> &QueryEngine {
&self.query_engine
}
pub fn checker(&self) -> &StreamingChecker {
&self.checker
}
pub fn branch(&self) -> &Arc<RwLock<Branch>> {
&self.universe
}
pub async fn semantic_search(
&self,
query: &str,
limit: usize,
) -> Vec<super::rag::SearchResult> {
if let Some(embeddings) = &self.embeddings {
embeddings.search(query, limit).await
} else {
Vec::new()
}
}
pub async fn commit(&self) -> Result<CommitResult, CommitError> {
let branch: tokio::sync::RwLockReadGuard<'_, super::branch::Branch> =
self.universe.read().await;
branch.commit().await
}
pub async fn rollback(&self) -> Result<(), RollbackError> {
let branch = self.universe.write().await;
branch.rollback().await
}
pub async fn fork(&self, _name: impl Into<String>) -> Result<SessionId, ForkError> {
Err(ForkError::NotImplemented)
}
pub async fn metrics(&self) -> SessionMetrics {
self.metrics.read().await.clone()
}
pub async fn record_query(&self, latency_us: u64) {
let mut metrics = self.metrics.write().await;
metrics.queries_processed += 1;
metrics.latency_us_total += latency_us;
}
pub async fn close(self) -> SessionSummary {
SessionSummary {
id: self.id,
config: self.config,
metrics: self.metrics.read().await.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct SearchResult {
pub type_id: crate::core::TypeId,
pub similarity: f32,
pub description: String,
}
#[derive(Debug, Clone)]
pub struct CommitResult {
pub types_added: usize,
pub types_modified: usize,
pub conflicts: Vec<Conflict>,
}
#[derive(Debug, Clone)]
pub struct Conflict {
pub type_id: crate::core::TypeId,
pub reason: ConflictReason,
}
#[derive(Debug, Clone)]
pub enum ConflictReason {
ConcurrentModification,
TypeMismatch,
SymbolCollision,
}
#[derive(Debug, Clone)]
pub enum CommitError {
AlreadyCommitted,
ParentChanged,
ValidationFailed(Vec<String>),
}
#[derive(Debug, Clone)]
pub enum RollbackError {
NothingToRollback,
CheckpointCorrupted,
}
#[derive(Debug, Clone)]
pub enum ForkError {
MaxBranchesReached,
NotImplemented,
}
#[derive(Debug, Clone)]
pub struct SessionSummary {
pub id: SessionId,
pub config: SessionConfig,
pub metrics: SessionMetrics,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::TypeUniverse;
#[tokio::test]
async fn test_session_creation() {
let universe = Arc::new(TypeUniverse::new());
let config = SessionConfig::default();
let session = AgentSession::new(universe, config).await;
assert_eq!(session.config.name, "unnamed");
}
#[test]
fn test_session_id() {
let id1 = SessionId::new();
let id2 = SessionId::new();
assert_ne!(id1, id2);
}
}