1use std::sync::Arc;
2use anyhow::{Result, anyhow};
3
4use praxis_llm::LLMClient;
5use praxis_mcp::MCPToolExecutor;
6use crate::types::GraphConfig;
7
8use crate::graph::Graph;
9
10pub struct PersistenceConfig {
12 pub client: Arc<dyn praxis_persist::PersistenceClient>,
13}
14
15pub struct GraphBuilder {
17 llm_client: Option<Arc<dyn LLMClient>>,
18 mcp_executor: Option<Arc<MCPToolExecutor>>,
19 config: GraphConfig,
20 persistence_config: Option<PersistenceConfig>,
21}
22
23impl GraphBuilder {
24 pub fn new() -> Self {
25 Self {
26 llm_client: None,
27 mcp_executor: None,
28 config: GraphConfig::default(),
29 persistence_config: None,
30 }
31 }
32
33 pub fn llm_client(mut self, client: Arc<dyn LLMClient>) -> Self {
35 self.llm_client = Some(client);
36 self
37 }
38
39 pub fn mcp_executor(mut self, executor: Arc<MCPToolExecutor>) -> Self {
41 self.mcp_executor = Some(executor);
42 self
43 }
44
45 pub fn config(mut self, config: GraphConfig) -> Self {
47 self.config = config;
48 self
49 }
50
51 pub fn with_persistence(mut self, client: Arc<dyn praxis_persist::PersistenceClient>) -> Self {
53 self.persistence_config = Some(PersistenceConfig { client });
54 self
55 }
56
57 pub fn build(self) -> Result<Graph> {
59 let llm_client = self.llm_client
60 .ok_or_else(|| anyhow!("LLM client is required"))?;
61 let mcp_executor = self.mcp_executor
62 .ok_or_else(|| anyhow!("MCP executor is required"))?;
63
64 Ok(Graph::new_with_persistence(
65 llm_client,
66 mcp_executor,
67 self.config,
68 self.persistence_config,
69 ))
70 }
71}
72
73impl Default for GraphBuilder {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78