Skip to main content

codei_sdk/
runtime.rs

1use std::path::{Path, PathBuf};
2use std::sync::{Arc, RwLock};
3
4use codei_config::{load, LoadOptions, ResolvedConfig};
5use codei_llm::{create_provider, LlmProvider};
6use codei_mcp::McpManager;
7use codei_session::{Session, SessionStore};
8
9use crate::error::SdkError;
10
11/// Shared LLM / tool runtime for an interactive session.
12#[derive(Clone)]
13pub struct AgentRuntime {
14    pub config: Arc<ResolvedConfig>,
15    pub provider: Arc<dyn LlmProvider>,
16    pub provider_name: String,
17    pub model: Arc<RwLock<String>>,
18    pub store: Arc<SessionStore>,
19    pub mcp: Option<Arc<McpManager>>,
20}
21
22/// Launch bundle for TUI / REPL interactive modes.
23pub struct InteractiveLaunch {
24    pub config: Arc<ResolvedConfig>,
25    pub provider: Arc<dyn LlmProvider>,
26    pub provider_name: String,
27    pub model: Arc<RwLock<String>>,
28    pub session: Session,
29    pub store: Arc<SessionStore>,
30    pub mcp: Option<Arc<McpManager>>,
31}
32
33impl InteractiveLaunch {
34    pub fn runtime(&self) -> AgentRuntime {
35        AgentRuntime {
36            config: Arc::clone(&self.config),
37            provider: Arc::clone(&self.provider),
38            provider_name: self.provider_name.clone(),
39            model: Arc::clone(&self.model),
40            store: Arc::clone(&self.store),
41            mcp: self.mcp.clone(),
42        }
43    }
44}
45
46pub fn resolve_session(
47    store: &SessionStore,
48    cwd: &Path,
49    resume: Option<&str>,
50    continue_latest: bool,
51) -> Result<Session, codei_session::SessionError> {
52    if let Some(id) = resume {
53        return store.load(id);
54    }
55    if continue_latest {
56        if let Some(session) = store.latest()? {
57            return Ok(session);
58        }
59    }
60    Ok(Session::new(cwd.to_path_buf()))
61}
62
63pub async fn build_interactive_launch(
64    config: Arc<ResolvedConfig>,
65    session: Session,
66    store: Arc<SessionStore>,
67) -> Result<InteractiveLaunch, SdkError> {
68    let runtime = build_agent_runtime(config, store).await?;
69    Ok(InteractiveLaunch {
70        config: runtime.config,
71        provider: runtime.provider,
72        provider_name: runtime.provider_name,
73        model: runtime.model,
74        session,
75        store: runtime.store,
76        mcp: runtime.mcp,
77    })
78}
79
80pub async fn build_agent_runtime(
81    config: Arc<ResolvedConfig>,
82    store: Arc<SessionStore>,
83) -> Result<AgentRuntime, SdkError> {
84    let provider_name = config.config.defaults.provider.clone();
85    let provider = create_provider(&config)?;
86    let mcp = McpManager::connect_optional().await;
87    let model = Arc::new(RwLock::new(config.config.defaults.model.clone()));
88    Ok(AgentRuntime {
89        config,
90        provider,
91        provider_name,
92        model,
93        store,
94        mcp,
95    })
96}
97
98pub async fn open_session_store(default_cwd: PathBuf) -> Result<Arc<SessionStore>, SdkError> {
99    let resolved = load(&LoadOptions {
100        cwd: Some(default_cwd),
101        ..Default::default()
102    })?;
103    Ok(Arc::new(SessionStore::open_for_config(
104        &resolved.config.session,
105    )?))
106}