Skip to main content

juncture_core/
prebuilt.rs

1// Pre-built agent configurations
2//
3// This module provides pre-built agent configurations like `ReactAgentConfig`
4// for common agent patterns.
5
6use std::marker::PhantomData;
7use std::sync::Arc;
8
9use crate::llm::{ChatModel, ResponseFormat};
10use crate::node::Node;
11use crate::state::State;
12use crate::store::Store;
13
14/// `ReAct` agent configuration
15///
16/// Configuration for creating `ReAct` (Reasoning + Acting) agents with tools.
17#[allow(
18    missing_debug_implementations,
19    reason = "Contains Arc<dyn Node> and Arc<dyn Fn> which don't implement Debug"
20)]
21pub struct ReactAgentConfig<S: State, M: ChatModel> {
22    /// LLM model
23    pub model: M,
24    /// List of tools
25    pub tools: Vec<Box<dyn crate::Tool>>,
26    /// System prompt
27    pub prompt: Option<PromptSource<S>>,
28    /// Response format for structured output
29    pub response_format: Option<ResponseFormat>,
30    /// Pre-model hook node
31    pub pre_model_hook: Option<Arc<dyn Node<S>>>,
32    /// Post-model hook node
33    pub post_model_hook: Option<Arc<dyn Node<S>>>,
34    /// State schema marker
35    pub state_schema: PhantomData<S>,
36    /// Store for cross-thread data
37    pub store: Option<Arc<dyn Store>>,
38    /// Interrupt before these nodes
39    pub interrupt_before: Vec<String>,
40    /// Interrupt after these nodes
41    pub interrupt_after: Vec<String>,
42    /// Dynamic model selector
43    pub model_selector: Option<ModelSelector<S, M>>,
44}
45
46/// Type alias for model selector function
47pub type ModelSelector<S, M> = Arc<dyn Fn(&S) -> M + Send + Sync>;
48
49impl<S: State, M: ChatModel> ReactAgentConfig<S, M> {
50    /// Create new `ReAct` agent configuration
51    ///
52    /// # Arguments
53    ///
54    /// * `model` - LLM model
55    /// * `tools` - List of tools
56    pub fn new(model: M, tools: Vec<Box<dyn crate::Tool>>) -> Self {
57        Self {
58            model,
59            tools,
60            prompt: None,
61            response_format: None,
62            pre_model_hook: None,
63            post_model_hook: None,
64            state_schema: PhantomData,
65            store: None,
66            interrupt_before: vec![],
67            interrupt_after: vec![],
68            model_selector: None,
69        }
70    }
71
72    /// Set system prompt
73    ///
74    /// # Arguments
75    ///
76    /// * `prompt` - Prompt source
77    #[must_use]
78    pub fn with_prompt(mut self, prompt: PromptSource<S>) -> Self {
79        self.prompt = Some(prompt);
80        self
81    }
82
83    /// Set response format
84    ///
85    /// # Arguments
86    ///
87    /// * `format` - Response format
88    #[must_use]
89    pub fn with_response_format(mut self, format: ResponseFormat) -> Self {
90        self.response_format = Some(format);
91        self
92    }
93
94    /// Set pre-model hook
95    ///
96    /// # Arguments
97    ///
98    /// * `hook` - Hook node
99    #[must_use]
100    pub fn with_pre_model_hook(mut self, hook: Arc<dyn Node<S>>) -> Self {
101        self.pre_model_hook = Some(hook);
102        self
103    }
104
105    /// Set post-model hook
106    ///
107    /// # Arguments
108    ///
109    /// * `hook` - Hook node
110    #[must_use]
111    pub fn with_post_model_hook(mut self, hook: Arc<dyn Node<S>>) -> Self {
112        self.post_model_hook = Some(hook);
113        self
114    }
115
116    /// Set store
117    ///
118    /// # Arguments
119    ///
120    /// * `store` - Store instance
121    #[must_use]
122    pub fn with_store(mut self, store: Arc<dyn Store>) -> Self {
123        self.store = Some(store);
124        self
125    }
126
127    /// Set interrupt before
128    ///
129    /// # Arguments
130    ///
131    /// * `nodes` - List of node names
132    #[must_use]
133    pub fn with_interrupt_before(mut self, nodes: Vec<String>) -> Self {
134        self.interrupt_before = nodes;
135        self
136    }
137
138    /// Set interrupt after
139    ///
140    /// # Arguments
141    ///
142    /// * `nodes` - List of node names
143    #[must_use]
144    pub fn with_interrupt_after(mut self, nodes: Vec<String>) -> Self {
145        self.interrupt_after = nodes;
146        self
147    }
148
149    /// Set model selector
150    ///
151    /// # Arguments
152    ///
153    /// * `selector` - Function to select model based on state
154    #[must_use]
155    pub fn with_model_selector(mut self, selector: ModelSelector<S, M>) -> Self {
156        self.model_selector = Some(selector);
157        self
158    }
159}
160
161/// Prompt source for agents
162///
163/// Can be a static string or a dynamic function.
164#[allow(
165    missing_debug_implementations,
166    reason = "Contains Arc<dyn Fn> which doesn't implement Debug"
167)]
168pub enum PromptSource<S: State> {
169    /// Static prompt string
170    Static(String),
171    /// Dynamic prompt function
172    Dynamic(Arc<dyn Fn(&S) -> String + Send + Sync>),
173}
174
175// Rust guideline compliant 2026-05-19