Skip to main content

adk_runner/
builder.rs

1//! Typestate builder for [`RunnerConfig`] / [`Runner`].
2//!
3//! The builder enforces at compile time that the three required fields
4//! (`app_name`, `agent`, `session_service`) are set before `build()` is
5//! callable.
6//!
7//! # Example
8//!
9//! ```rust,ignore
10//! let runner = Runner::builder()
11//!     .app_name("my-app")
12//!     .agent(agent)
13//!     .session_service(session_service)
14//!     .memory_service(memory)
15//!     .build()?;
16//! ```
17
18use std::marker::PhantomData;
19use std::sync::Arc;
20
21#[cfg(feature = "artifacts")]
22use adk_artifact::ArtifactService;
23use adk_core::{Agent, CacheCapable, ContextCacheConfig, Memory, Result, RunConfig};
24#[cfg(feature = "plugins")]
25use adk_plugin::PluginManager;
26use adk_session::SessionService;
27use tokio_util::sync::CancellationToken;
28
29use crate::runner::{Runner, RunnerConfig};
30
31// ---------------------------------------------------------------------------
32// Typestate marker types
33// ---------------------------------------------------------------------------
34
35/// Marker: `app_name` has not been set.
36pub struct NoAppName;
37/// Marker: `app_name` has been set.
38pub struct HasAppName;
39/// Marker: `agent` has not been set.
40pub struct NoAgent;
41/// Marker: `agent` has been set.
42pub struct HasAgent;
43/// Marker: `session_service` has not been set.
44pub struct NoSessionService;
45/// Marker: `session_service` has been set.
46pub struct HasSessionService;
47
48// ---------------------------------------------------------------------------
49// Builder
50// ---------------------------------------------------------------------------
51
52/// A typestate builder for constructing a [`Runner`].
53///
54/// The three type parameters track whether the required fields have been
55/// provided. `build()` is only available when all three are `Has*`.
56pub struct RunnerConfigBuilder<A, G, S> {
57    app_name: Option<String>,
58    agent: Option<Arc<dyn Agent>>,
59    session_service: Option<Arc<dyn SessionService>>,
60    #[cfg(feature = "artifacts")]
61    artifact_service: Option<Arc<dyn ArtifactService>>,
62    memory_service: Option<Arc<dyn Memory>>,
63    #[cfg(feature = "plugins")]
64    plugin_manager: Option<Arc<PluginManager>>,
65    run_config: Option<RunConfig>,
66    compaction_config: Option<adk_core::EventsCompactionConfig>,
67    context_cache_config: Option<ContextCacheConfig>,
68    cache_capable: Option<Arc<dyn CacheCapable>>,
69    request_context: Option<adk_core::RequestContext>,
70    cancellation_token: Option<CancellationToken>,
71    intra_compaction_config: Option<adk_core::IntraCompactionConfig>,
72    intra_compaction_summarizer: Option<Arc<dyn adk_core::BaseEventsSummarizer>>,
73    _marker: PhantomData<(A, G, S)>,
74}
75
76impl RunnerConfigBuilder<NoAppName, NoAgent, NoSessionService> {
77    /// Create a new builder with all fields unset and defaults applied.
78    pub fn new() -> Self {
79        Self {
80            app_name: None,
81            agent: None,
82            session_service: None,
83            #[cfg(feature = "artifacts")]
84            artifact_service: None,
85            memory_service: None,
86            #[cfg(feature = "plugins")]
87            plugin_manager: None,
88            run_config: None,
89            compaction_config: None,
90            context_cache_config: None,
91            cache_capable: None,
92            request_context: None,
93            cancellation_token: None,
94            intra_compaction_config: None,
95            intra_compaction_summarizer: None,
96            _marker: PhantomData,
97        }
98    }
99}
100
101impl Default for RunnerConfigBuilder<NoAppName, NoAgent, NoSessionService> {
102    fn default() -> Self {
103        Self::new()
104    }
105}
106
107// ---------------------------------------------------------------------------
108// Required-field setters (transition type state)
109// ---------------------------------------------------------------------------
110
111impl<A, G, S> RunnerConfigBuilder<A, G, S> {
112    /// Set the application name (required).
113    pub fn app_name(self, name: impl Into<String>) -> RunnerConfigBuilder<HasAppName, G, S> {
114        RunnerConfigBuilder {
115            app_name: Some(name.into()),
116            agent: self.agent,
117            session_service: self.session_service,
118            #[cfg(feature = "artifacts")]
119            artifact_service: self.artifact_service,
120            memory_service: self.memory_service,
121            #[cfg(feature = "plugins")]
122            plugin_manager: self.plugin_manager,
123            run_config: self.run_config,
124            compaction_config: self.compaction_config,
125            context_cache_config: self.context_cache_config,
126            cache_capable: self.cache_capable,
127            request_context: self.request_context,
128            cancellation_token: self.cancellation_token,
129            intra_compaction_config: self.intra_compaction_config,
130            intra_compaction_summarizer: self.intra_compaction_summarizer,
131            _marker: PhantomData,
132        }
133    }
134
135    /// Set the root agent (required).
136    pub fn agent(self, agent: Arc<dyn Agent>) -> RunnerConfigBuilder<A, HasAgent, S> {
137        RunnerConfigBuilder {
138            app_name: self.app_name,
139            agent: Some(agent),
140            session_service: self.session_service,
141            #[cfg(feature = "artifacts")]
142            artifact_service: self.artifact_service,
143            memory_service: self.memory_service,
144            #[cfg(feature = "plugins")]
145            plugin_manager: self.plugin_manager,
146            run_config: self.run_config,
147            compaction_config: self.compaction_config,
148            context_cache_config: self.context_cache_config,
149            cache_capable: self.cache_capable,
150            request_context: self.request_context,
151            cancellation_token: self.cancellation_token,
152            intra_compaction_config: self.intra_compaction_config,
153            intra_compaction_summarizer: self.intra_compaction_summarizer,
154            _marker: PhantomData,
155        }
156    }
157
158    /// Set the session service (required).
159    pub fn session_service(
160        self,
161        service: Arc<dyn SessionService>,
162    ) -> RunnerConfigBuilder<A, G, HasSessionService> {
163        RunnerConfigBuilder {
164            app_name: self.app_name,
165            agent: self.agent,
166            session_service: Some(service),
167            #[cfg(feature = "artifacts")]
168            artifact_service: self.artifact_service,
169            memory_service: self.memory_service,
170            #[cfg(feature = "plugins")]
171            plugin_manager: self.plugin_manager,
172            run_config: self.run_config,
173            compaction_config: self.compaction_config,
174            context_cache_config: self.context_cache_config,
175            cache_capable: self.cache_capable,
176            request_context: self.request_context,
177            cancellation_token: self.cancellation_token,
178            intra_compaction_config: self.intra_compaction_config,
179            intra_compaction_summarizer: self.intra_compaction_summarizer,
180            _marker: PhantomData,
181        }
182    }
183}
184
185// ---------------------------------------------------------------------------
186// Optional-field setters (no type-state change)
187// ---------------------------------------------------------------------------
188
189impl<A, G, S> RunnerConfigBuilder<A, G, S> {
190    /// Set the artifact service (optional).
191    #[cfg(feature = "artifacts")]
192    pub fn artifact_service(mut self, service: Arc<dyn ArtifactService>) -> Self {
193        self.artifact_service = Some(service);
194        self
195    }
196
197    /// Set the memory service (optional).
198    pub fn memory_service(mut self, service: Arc<dyn Memory>) -> Self {
199        self.memory_service = Some(service);
200        self
201    }
202
203    /// Set the plugin manager (optional).
204    #[cfg(feature = "plugins")]
205    pub fn plugin_manager(mut self, manager: Arc<PluginManager>) -> Self {
206        self.plugin_manager = Some(manager);
207        self
208    }
209
210    /// Set the run configuration (optional).
211    pub fn run_config(mut self, config: RunConfig) -> Self {
212        self.run_config = Some(config);
213        self
214    }
215
216    /// Set the events compaction configuration (optional).
217    pub fn compaction_config(mut self, config: adk_core::EventsCompactionConfig) -> Self {
218        self.compaction_config = Some(config);
219        self
220    }
221
222    /// Set the context cache configuration (optional).
223    pub fn context_cache_config(mut self, config: ContextCacheConfig) -> Self {
224        self.context_cache_config = Some(config);
225        self
226    }
227
228    /// Set the cache-capable model reference (optional).
229    pub fn cache_capable(mut self, model: Arc<dyn CacheCapable>) -> Self {
230        self.cache_capable = Some(model);
231        self
232    }
233
234    /// Set the request context from auth middleware (optional).
235    pub fn request_context(mut self, ctx: adk_core::RequestContext) -> Self {
236        self.request_context = Some(ctx);
237        self
238    }
239
240    /// Set a cooperative cancellation token (optional).
241    pub fn cancellation_token(mut self, token: CancellationToken) -> Self {
242        self.cancellation_token = Some(token);
243        self
244    }
245
246    /// Set the intra-invocation compaction configuration (optional).
247    pub fn intra_compaction_config(mut self, config: adk_core::IntraCompactionConfig) -> Self {
248        self.intra_compaction_config = Some(config);
249        self
250    }
251
252    /// Set the summarizer for intra-invocation compaction (optional).
253    pub fn intra_compaction_summarizer(
254        mut self,
255        summarizer: Arc<dyn adk_core::BaseEventsSummarizer>,
256    ) -> Self {
257        self.intra_compaction_summarizer = Some(summarizer);
258        self
259    }
260}
261
262// ---------------------------------------------------------------------------
263// build() — only available when all required fields are set
264// ---------------------------------------------------------------------------
265
266impl RunnerConfigBuilder<HasAppName, HasAgent, HasSessionService> {
267    /// Consume the builder and create a [`Runner`].
268    ///
269    /// Delegates to [`Runner::new()`] internally.
270    ///
271    /// # Errors
272    ///
273    /// Returns an error if `Runner::new()` fails (e.g. invalid `app_name`).
274    pub fn build(self) -> Result<Runner> {
275        let config = RunnerConfig {
276            // SAFETY: typestate guarantees these are `Some`.
277            app_name: self.app_name.expect("typestate guarantees app_name is set"),
278            agent: self.agent.expect("typestate guarantees agent is set"),
279            session_service: self
280                .session_service
281                .expect("typestate guarantees session_service is set"),
282            #[cfg(feature = "artifacts")]
283            artifact_service: self.artifact_service,
284            memory_service: self.memory_service,
285            #[cfg(feature = "plugins")]
286            plugin_manager: self.plugin_manager,
287            run_config: self.run_config,
288            compaction_config: self.compaction_config,
289            context_cache_config: self.context_cache_config,
290            cache_capable: self.cache_capable,
291            request_context: self.request_context,
292            cancellation_token: self.cancellation_token,
293            intra_compaction_config: self.intra_compaction_config,
294            intra_compaction_summarizer: self.intra_compaction_summarizer,
295        };
296        Runner::new(config)
297    }
298}