use std::collections::HashMap;
use std::sync::Arc;
use adk_core::Tool;
use adk_memory::MemoryService;
use adk_plugin::EnhancedPluginManager;
use adk_session::SessionService;
use crate::config::{RealtimeConfig, ToolDefinition};
use crate::error::RealtimeError;
use crate::model::BoxedModel;
use crate::runner::{EventHandler, RealtimeRunner, RunnerConfig, ToolHandler};
use super::context::DefaultToolContextFactory;
use super::tool_bridge::ToolBridgeAdapter;
use super::{IntegrationConfig, SessionIdentity};
pub struct IntegratedRealtimeRunnerBuilder {
pub(crate) model: Option<BoxedModel>,
pub(crate) config: RealtimeConfig,
pub(crate) runner_config: RunnerConfig,
pub(crate) session_service: Option<Arc<dyn SessionService>>,
pub(crate) memory_service: Option<Arc<dyn MemoryService>>,
pub(crate) plugin_manager: Option<Arc<EnhancedPluginManager>>,
pub(crate) adk_tools: Vec<Arc<dyn Tool>>,
pub(crate) native_tools: HashMap<String, (ToolDefinition, Arc<dyn ToolHandler>)>,
pub(crate) event_handler: Option<Arc<dyn EventHandler>>,
pub(crate) identity: Option<SessionIdentity>,
pub(crate) integration_config: IntegrationConfig,
}
impl Default for IntegratedRealtimeRunnerBuilder {
fn default() -> Self {
Self::new()
}
}
impl IntegratedRealtimeRunnerBuilder {
pub fn new() -> Self {
Self {
model: None,
config: RealtimeConfig::default(),
runner_config: RunnerConfig::default(),
session_service: None,
memory_service: None,
plugin_manager: None,
adk_tools: Vec::new(),
native_tools: HashMap::new(),
event_handler: None,
identity: None,
integration_config: IntegrationConfig::default(),
}
}
pub fn model(mut self, model: BoxedModel) -> Self {
self.model = Some(model);
self
}
pub fn config(mut self, config: RealtimeConfig) -> Self {
self.config = config;
self
}
pub fn runner_config(mut self, runner_config: RunnerConfig) -> Self {
self.runner_config = runner_config;
self
}
pub fn session_service(mut self, service: Arc<dyn SessionService>) -> Self {
self.session_service = Some(service);
self
}
pub fn memory_service(mut self, service: Arc<dyn MemoryService>) -> Self {
self.memory_service = Some(service);
self
}
pub fn plugin_manager(mut self, pm: Arc<EnhancedPluginManager>) -> Self {
self.plugin_manager = Some(pm);
self
}
pub fn identity(
mut self,
app_name: impl Into<String>,
user_id: impl Into<String>,
session_id: impl Into<String>,
) -> Self {
self.identity = Some(SessionIdentity {
app_name: app_name.into(),
user_id: user_id.into(),
session_id: session_id.into(),
});
self
}
pub fn adk_tool(mut self, tool: Arc<dyn Tool>) -> Self {
self.adk_tools.push(tool);
self
}
pub fn tool(mut self, definition: ToolDefinition, handler: impl ToolHandler + 'static) -> Self {
let name = definition.name.clone();
self.native_tools.insert(name, (definition, Arc::new(handler)));
self
}
pub fn event_handler(mut self, handler: Arc<dyn EventHandler>) -> Self {
self.event_handler = Some(handler);
self
}
pub fn integration_config(mut self, config: IntegrationConfig) -> Self {
self.integration_config = config;
self
}
pub fn build(self) -> crate::error::Result<super::IntegratedRealtimeRunner> {
let model = self.model.ok_or_else(|| RealtimeError::config("Model is required"))?;
let identity = self.identity.ok_or_else(|| {
RealtimeError::config("Identity (app_name, user_id, session_id) is required")
})?;
let context_factory = Arc::new(DefaultToolContextFactory {
identity: identity.clone(),
memory_service: self.memory_service.clone(),
});
let mut all_tools = self.native_tools;
for tool in &self.adk_tools {
let def = ToolBridgeAdapter::definition(tool.as_ref());
let adapter = Arc::new(ToolBridgeAdapter::new(tool.clone(), context_factory.clone()));
all_tools.insert(def.name.clone(), (def, adapter as Arc<dyn ToolHandler>));
}
let mut runner_builder = RealtimeRunner::builder()
.model(model)
.config(self.config)
.runner_config(self.runner_config);
for (_, (def, handler)) in all_tools {
runner_builder = runner_builder.tool_arc(def, handler);
}
if let Some(handler) = self.event_handler {
runner_builder = runner_builder.event_handler_arc(handler);
}
let runner = Arc::new(runner_builder.build()?);
let adk_tools_by_name =
self.adk_tools.iter().map(|tool| (tool.name().to_string(), Arc::clone(tool))).collect();
Ok(super::IntegratedRealtimeRunner {
runner,
session_service: self.session_service,
memory_service: self.memory_service,
plugin_manager: self.plugin_manager,
aggregator: tokio::sync::RwLock::new(super::transcript::TranscriptAggregator::new()),
identity,
config: self.integration_config,
adk_tools: adk_tools_by_name,
})
}
}