1use adk_artifact::ArtifactService;
33use adk_core::{Agent, AgentLoader, Result, RunConfig, StreamingMode};
34use adk_server::{ServerConfig, create_app};
35use adk_session::InMemorySessionService;
36use clap::{Parser, Subcommand};
37use std::sync::Arc;
38
39#[derive(Parser)]
41#[command(name = "agent")]
42#[command(about = "ADK Agent", long_about = None)]
43struct Cli {
44 #[command(subcommand)]
45 command: Option<Commands>,
46}
47
48#[derive(Subcommand)]
49enum Commands {
50 Chat,
52 Serve {
54 #[arg(long, default_value_t = 8080)]
56 port: u16,
57 },
58}
59
60pub struct SingleAgentLoader {
62 agent: Arc<dyn Agent>,
63}
64
65impl SingleAgentLoader {
66 pub fn new(agent: Arc<dyn Agent>) -> Self {
68 Self { agent }
69 }
70}
71
72#[async_trait::async_trait]
73impl AgentLoader for SingleAgentLoader {
74 async fn load_agent(&self, _name: &str) -> Result<Arc<dyn Agent>> {
75 Ok(self.agent.clone())
76 }
77
78 fn list_agents(&self) -> Vec<String> {
79 vec![self.agent.name().to_string()]
80 }
81
82 fn root_agent(&self) -> Arc<dyn Agent> {
83 self.agent.clone()
84 }
85}
86
87pub struct Launcher {
91 agent: Arc<dyn Agent>,
92 app_name: Option<String>,
93 artifact_service: Option<Arc<dyn ArtifactService>>,
94 run_config: Option<RunConfig>,
95}
96
97impl Launcher {
98 pub fn new(agent: Arc<dyn Agent>) -> Self {
100 Self { agent, app_name: None, artifact_service: None, run_config: None }
101 }
102
103 pub fn app_name(mut self, name: impl Into<String>) -> Self {
105 self.app_name = Some(name.into());
106 self
107 }
108
109 pub fn with_artifact_service(mut self, service: Arc<dyn ArtifactService>) -> Self {
111 self.artifact_service = Some(service);
112 self
113 }
114
115 pub fn with_streaming_mode(mut self, mode: StreamingMode) -> Self {
117 self.run_config = Some(RunConfig { streaming_mode: mode });
118 self
119 }
120
121 pub async fn run(self) -> Result<()> {
126 let cli = Cli::parse();
127
128 match cli.command.unwrap_or(Commands::Chat) {
129 Commands::Chat => self.run_console().await,
130 Commands::Serve { port } => self.run_serve(port).await,
131 }
132 }
133
134 async fn run_console(self) -> Result<()> {
136 use adk_runner::{Runner, RunnerConfig};
137 use adk_session::{CreateRequest, SessionService};
138 use futures::StreamExt;
139 use std::collections::HashMap;
140 use std::io::{self, BufRead, Write};
141
142 let app_name = self.app_name.unwrap_or_else(|| self.agent.name().to_string());
143 let user_id = "user".to_string();
144
145 let session_service = Arc::new(InMemorySessionService::new());
146
147 let session = session_service
149 .create(CreateRequest {
150 app_name: app_name.clone(),
151 user_id: user_id.clone(),
152 session_id: None,
153 state: HashMap::new(),
154 })
155 .await?;
156
157 let session_id = session.id().to_string();
158
159 let runner = Runner::new(RunnerConfig {
161 app_name,
162 agent: self.agent,
163 session_service,
164 artifact_service: self.artifact_service,
165 memory_service: None,
166 run_config: self.run_config,
167 })?;
168
169 println!("š¤ Agent ready! Type your questions (or 'exit' to quit).\n");
170
171 let stdin = io::stdin();
172 let mut stdout = io::stdout();
173
174 loop {
175 print!("You: ");
176 stdout.flush()?;
177
178 let mut input = String::new();
179 let bytes_read = stdin.lock().read_line(&mut input)?;
180
181 if bytes_read == 0 {
183 println!("\nš Goodbye!");
184 break;
185 }
186
187 let input = input.trim();
188
189 if input == "exit" || input == "quit" {
190 println!("š Goodbye!");
191 break;
192 }
193
194 if input.is_empty() {
195 continue;
196 }
197
198 let content = adk_core::Content::new("user").with_text(input);
199 let mut events = runner.run(user_id.clone(), session_id.clone(), content).await?;
200
201 print!("Assistant: ");
202 stdout.flush()?;
203
204 let mut current_agent = String::new();
205
206 while let Some(event) = events.next().await {
207 match event {
208 Ok(evt) => {
209 if !evt.author.is_empty()
211 && evt.author != "user"
212 && evt.author != current_agent
213 {
214 if !current_agent.is_empty() {
215 println!();
216 }
217 current_agent = evt.author.clone();
218 println!("\n[Agent: {}]", current_agent);
219 print!("Assistant: ");
220 stdout.flush()?;
221 }
222
223 if let Some(target) = &evt.actions.transfer_to_agent {
225 println!("\nš [Transfer requested to: {}]", target);
226 }
227
228 if let Some(content) = evt.llm_response.content {
229 for part in content.parts {
230 if let Some(text) = part.text() {
231 print!("{}", text);
232 stdout.flush()?;
233 }
234 }
235 }
236 }
237 Err(e) => eprintln!("\nError: {}", e),
238 }
239 }
240 println!("\n");
241 }
242
243 Ok(())
244 }
245
246 async fn run_serve(self, port: u16) -> Result<()> {
248 let span_exporter = match adk_telemetry::init_with_adk_exporter("adk-server") {
250 Ok(exporter) => Some(exporter),
251 Err(e) => {
252 eprintln!("Warning: Failed to initialize telemetry: {}", e);
253 None
254 }
255 };
256
257 let session_service = Arc::new(InMemorySessionService::new());
258 let agent_loader = Arc::new(SingleAgentLoader::new(self.agent));
259
260 let mut config = ServerConfig::new(agent_loader, session_service)
261 .with_artifact_service_opt(self.artifact_service);
262
263 if let Some(exporter) = span_exporter {
264 config = config.with_span_exporter(exporter);
265 }
266
267 let app = create_app(config);
268
269 let addr = format!("0.0.0.0:{}", port);
270 let listener = tokio::net::TcpListener::bind(&addr).await?;
271
272 println!("š ADK Server starting on http://localhost:{}", port);
273 println!("š± Open http://localhost:{} in your browser", port);
274 println!("Press Ctrl+C to stop\n");
275
276 axum::serve(listener, app).await?;
277
278 Ok(())
279 }
280}