mentra 0.6.0

An agent runtime for tool-using LLM applications
Documentation
mod agents;
mod construction;
mod execution;
mod tooling;

use std::{
    any::{Any, TypeId},
    collections::{BTreeSet, HashMap},
    path::{Path, PathBuf},
    sync::{Arc, Mutex, RwLock},
    time::Duration,
};

use tokio::sync::watch;

use crate::{
    agent::{AgentEventBus, AgentSnapshot},
    background::{BackgroundNotification, BackgroundTaskManager, BackgroundTaskSummary},
    compaction::CompactionEngine,
    memory::MemoryEngine,
    runtime::{
        control::{
            AuditHook, CommandOutput, CommandRequest, CommandSpec, LocalRuntimeExecutor,
            PreExecutionHooks, RuntimeExecutor, RuntimeHookEvent, RuntimeHooks, RuntimePolicy,
            read_limited_file,
        },
        error::RuntimeError,
        store::{RuntimeStore, SqliteRuntimeStore},
        task::{self, TaskAccess},
    },
    team::{
        TeamDispatch, TeamManager, TeamMemberSummary, TeamMessage, TeamProtocolRequestSummary,
        TeamRequestFilter, TeammateHost,
    },
    tool::{ExecutableTool, ToolAuthorizer, ToolRegistry},
};

use super::skill::SkillLoader;

#[derive(Clone)]
pub struct RuntimeHandle {
    pub(crate) execution: ExecutionServices,
    pub(crate) persistence: PersistenceServices,
    pub(crate) collaboration: CollaborationServices,
    pub(crate) tooling: ToolingServices,
    pub(crate) runtime_intrinsics_enabled: bool,
    runtime_instance_id: String,
    persisted_runtime_identifier: Arc<str>,
    lease_keys: Arc<Mutex<BTreeSet<String>>>,
    agent_contexts: Arc<RwLock<HashMap<String, AgentExecutionConfig>>>,
}

#[derive(Clone)]
pub(crate) struct ExecutionServices {
    pub(crate) executor: Arc<dyn RuntimeExecutor>,
    pub(crate) policy: Arc<RuntimePolicy>,
    pub(crate) tool_authorizer: Option<Arc<dyn ToolAuthorizer>>,
    pub(crate) hooks: RuntimeHooks,
    pub(crate) pre_hooks: PreExecutionHooks,
}

#[derive(Clone)]
pub(crate) struct PersistenceServices {
    pub(crate) store: Arc<dyn RuntimeStore>,
    pub(crate) memory: Arc<MemoryEngine>,
    pub(crate) compaction: Arc<dyn CompactionEngine>,
}

#[derive(Clone)]
pub(crate) struct CollaborationServices {
    pub(crate) background_tasks: BackgroundTaskManager,
    pub(crate) team: TeamManager,
    pub(crate) teammate_host: TeammateHost,
}

#[derive(Clone)]
pub(crate) struct ToolingServices {
    pub(crate) tool_registry: Arc<RwLock<ToolRegistry>>,
    pub(crate) skill_loader: Arc<RwLock<Option<SkillLoader>>>,
    pub(crate) app_contexts: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
}

#[derive(Clone)]
pub(crate) struct AgentObserver {
    pub(crate) events: AgentEventBus,
    pub(crate) snapshot_tx: watch::Sender<AgentSnapshot>,
    pub(crate) snapshot: Arc<Mutex<AgentSnapshot>>,
}

#[derive(Debug, Clone)]
pub(crate) struct AgentExecutionConfig {
    pub(crate) name: String,
    pub(crate) team_dir: PathBuf,
    pub(crate) tasks_dir: PathBuf,
    pub(crate) base_dir: PathBuf,
    pub(crate) memory_tool_search_limit: usize,
    pub(crate) auto_route_shell: bool,
    pub(crate) is_teammate: bool,
}

impl Drop for RuntimeHandle {
    fn drop(&mut self) {
        if Arc::strong_count(&self.lease_keys) != 1 {
            return;
        }

        let lease_keys = {
            let lease_keys = self.lease_keys.lock().expect("lease key registry poisoned");
            lease_keys.iter().cloned().collect::<Vec<_>>()
        };

        for key in lease_keys {
            let _ = self
                .persistence
                .store
                .release_lease(&key, &self.runtime_instance_id);
        }
    }
}

impl RuntimeHandle {
    pub(crate) fn memory_engine(&self) -> Arc<MemoryEngine> {
        self.persistence.memory.clone()
    }

    pub(crate) fn compaction_engine(&self) -> Arc<dyn CompactionEngine> {
        self.persistence.compaction.clone()
    }

    pub(crate) fn pre_hooks(&self) -> &PreExecutionHooks {
        &self.execution.pre_hooks
    }
}