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