Skip to main content

adk_cli/
console.rs

1//! Legacy console entry point.
2//!
3//! New code should use [`Launcher`](crate::Launcher) instead, which provides
4//! the same REPL with additional configuration options (memory, artifacts,
5//! streaming mode, etc.).
6
7use adk_core::{Agent, SessionId, UserId};
8use adk_runner::Runner;
9use adk_session::{CreateRequest, InMemorySessionService, SessionService};
10use anyhow::Result;
11use futures::StreamExt;
12use rustyline::DefaultEditor;
13use std::collections::HashMap;
14use std::sync::Arc;
15
16use crate::launcher::StreamPrinter;
17
18/// Run an interactive console session with the given agent.
19///
20/// This is a convenience wrapper kept for backward compatibility with
21/// existing examples. Prefer [`Launcher`](crate::Launcher) for new code.
22pub async fn run_console(agent: Arc<dyn Agent>, app_name: String, user_id: String) -> Result<()> {
23    let session_service = Arc::new(InMemorySessionService::new());
24
25    let session = session_service
26        .create(CreateRequest {
27            app_name: app_name.clone(),
28            user_id: user_id.clone(),
29            session_id: None,
30            state: HashMap::new(),
31        })
32        .await?;
33
34    let runner = Runner::builder()
35        .app_name(app_name)
36        .agent(agent.clone())
37        .session_service(session_service.clone())
38        .build()?;
39
40    let mut rl = DefaultEditor::new()?;
41
42    println!("ADK Console Mode");
43    println!("Agent: {}", agent.name());
44    println!("Type your message and press Enter. Ctrl+C to exit.\n");
45
46    loop {
47        let readline = rl.readline("User -> ");
48        match readline {
49            Ok(line) => {
50                if line.trim().is_empty() {
51                    continue;
52                }
53
54                rl.add_history_entry(&line)?;
55
56                let user_content = adk_core::Content::new("user").with_text(line);
57                print!("\nAgent -> ");
58
59                let session_id = session.id().to_string();
60                let mut events = runner
61                    .run(UserId::new(user_id.clone())?, SessionId::new(session_id)?, user_content)
62                    .await?;
63                let mut printer = StreamPrinter::default();
64
65                while let Some(event) = events.next().await {
66                    match event {
67                        Ok(evt) => {
68                            if let Some(content) = &evt.llm_response.content {
69                                for part in &content.parts {
70                                    printer.handle_part(part);
71                                }
72                            }
73                        }
74                        Err(e) => {
75                            eprintln!("\nError: {e}");
76                        }
77                    }
78                }
79
80                printer.finish();
81                println!("\n");
82            }
83            Err(rustyline::error::ReadlineError::Interrupted) => {
84                println!("Interrupted");
85                break;
86            }
87            Err(rustyline::error::ReadlineError::Eof) => {
88                println!("EOF");
89                break;
90            }
91            Err(err) => {
92                eprintln!("Error: {err}");
93                break;
94            }
95        }
96    }
97
98    Ok(())
99}