Skip to main content

codei_sdk/
client.rs

1//! High-level one-shot client built on shared runtime helpers.
2
3use std::path::PathBuf;
4use std::sync::Arc;
5
6use codei_agent::{AgentEvent, TurnOutcome};
7use codei_config::{load, LoadOptions, ResolvedConfig};
8use codei_session::{Session, SessionStore};
9
10use crate::error::SdkError;
11use crate::runtime::build_interactive_launch;
12use crate::turn::{approval_policy, run_turn_with_events};
13
14/// Result of a single agent run.
15#[derive(Debug, Clone)]
16pub struct RunResult {
17    pub session_id: String,
18    pub outcome: TurnOutcome,
19}
20
21/// Builder for [`CodeiClient`].
22pub struct CodeiClientBuilder {
23    cwd: Option<PathBuf>,
24    model: Option<String>,
25    provider: Option<String>,
26    auto_approve: bool,
27}
28
29impl Default for CodeiClientBuilder {
30    fn default() -> Self {
31        Self {
32            cwd: None,
33            model: None,
34            provider: None,
35            auto_approve: true,
36        }
37    }
38}
39
40impl CodeiClientBuilder {
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    pub fn cwd(mut self, cwd: impl Into<PathBuf>) -> Self {
46        self.cwd = Some(cwd.into());
47        self
48    }
49
50    pub fn model(mut self, model: impl Into<String>) -> Self {
51        self.model = Some(model.into());
52        self
53    }
54
55    pub fn provider(mut self, provider: impl Into<String>) -> Self {
56        self.provider = Some(provider.into());
57        self
58    }
59
60    pub fn auto_approve(mut self, yes: bool) -> Self {
61        self.auto_approve = yes;
62        self
63    }
64
65    pub async fn build(self) -> Result<CodeiClient, SdkError> {
66        let resolved = load(&LoadOptions {
67            cwd: self.cwd,
68            model: self.model.clone(),
69            provider: self.provider.clone(),
70            language: None,
71        })?;
72
73        let config = Arc::new(resolved);
74        let store = Arc::new(SessionStore::open_for_config(&config.config.session)?);
75        let session = Session::new(config.cwd.clone());
76        let launch = build_interactive_launch(config, session, store).await?;
77
78        Ok(CodeiClient {
79            launch,
80            auto_approve: self.auto_approve,
81        })
82    }
83}
84
85/// Programmatic entry point for running CodeI agents.
86pub struct CodeiClient {
87    launch: crate::runtime::InteractiveLaunch,
88    auto_approve: bool,
89}
90
91impl CodeiClient {
92    pub fn builder() -> CodeiClientBuilder {
93        CodeiClientBuilder::new()
94    }
95
96    pub fn config(&self) -> &Arc<ResolvedConfig> {
97        &self.launch.config
98    }
99
100    /// Run a prompt and invoke `on_event` for each agent event.
101    pub async fn run_with_handler<F>(
102        &mut self,
103        prompt: &str,
104        on_event: F,
105    ) -> Result<RunResult, SdkError>
106    where
107        F: FnMut(AgentEvent),
108    {
109        let policy = approval_policy(self.auto_approve);
110        let session_id = self.launch.session.id.clone();
111        let runtime = self.launch.runtime();
112
113        let outcome =
114            run_turn_with_events(&runtime, &mut self.launch.session, prompt, policy, on_event)
115                .await?;
116
117        Ok(RunResult {
118            session_id,
119            outcome,
120        })
121    }
122
123    /// Convenience wrapper that collects events only for completion.
124    pub async fn run(&mut self, prompt: &str) -> Result<RunResult, SdkError> {
125        self.run_with_handler(prompt, |_| {}).await
126    }
127}