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, RunnerConfig};
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::new(RunnerConfig {
35        app_name,
36        agent: agent.clone(),
37        session_service: session_service.clone(),
38        artifact_service: None,
39        memory_service: None,
40        plugin_manager: None,
41        run_config: None,
42        compaction_config: None,
43        context_cache_config: None,
44        cache_capable: None,
45        request_context: None,
46        cancellation_token: None,
47        intra_compaction_config: None,
48        intra_compaction_summarizer: None,
49    })?;
50
51    let mut rl = DefaultEditor::new()?;
52
53    println!("ADK Console Mode");
54    println!("Agent: {}", agent.name());
55    println!("Type your message and press Enter. Ctrl+C to exit.\n");
56
57    loop {
58        let readline = rl.readline("User -> ");
59        match readline {
60            Ok(line) => {
61                if line.trim().is_empty() {
62                    continue;
63                }
64
65                rl.add_history_entry(&line)?;
66
67                let user_content = adk_core::Content::new("user").with_text(line);
68                print!("\nAgent -> ");
69
70                let session_id = session.id().to_string();
71                let mut events = runner
72                    .run(UserId::new(user_id.clone())?, SessionId::new(session_id)?, user_content)
73                    .await?;
74                let mut printer = StreamPrinter::default();
75
76                while let Some(event) = events.next().await {
77                    match event {
78                        Ok(evt) => {
79                            if let Some(content) = &evt.llm_response.content {
80                                for part in &content.parts {
81                                    printer.handle_part(part);
82                                }
83                            }
84                        }
85                        Err(e) => {
86                            eprintln!("\nError: {e}");
87                        }
88                    }
89                }
90
91                printer.finish();
92                println!("\n");
93            }
94            Err(rustyline::error::ReadlineError::Interrupted) => {
95                println!("Interrupted");
96                break;
97            }
98            Err(rustyline::error::ReadlineError::Eof) => {
99                println!("EOF");
100                break;
101            }
102            Err(err) => {
103                eprintln!("Error: {err}");
104                break;
105            }
106        }
107    }
108
109    Ok(())
110}