gemini_genai_rs/
quick.rs

1//! Quick-start convenience functions for connecting to the Gemini Multimodal Live API.
2//!
3//! These are thin wrappers over [`SessionConfig`] + [`connect()`] that provide
4//! sensible defaults for the common case. For advanced configuration (custom
5//! transport, codec, modalities, etc.), use [`SessionConfig`] directly.
6//!
7//! # Google AI (API key)
8//!
9//! ```rust,no_run
10//! # async fn example() -> Result<(), gemini_genai_rs::session::SessionError> {
11//! use gemini_genai_rs::prelude::*;
12//!
13//! let session = gemini_genai_rs::quick_connect("API_KEY", "gemini-2.0-flash-live-001").await?;
14//! session.send_text("What is the speed of light?").await?;
15//! let mut events = session.subscribe();
16//! while let Ok(event) = events.recv().await {
17//!     if let SessionEvent::TextDelta(ref text) = event { print!("{text}"); }
18//!     if let SessionEvent::TurnComplete = event { break; }
19//! }
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! # Vertex AI
25//!
26//! ```rust,no_run
27//! # async fn example() -> Result<(), gemini_genai_rs::session::SessionError> {
28//! use gemini_genai_rs::prelude::*;
29//!
30//! let session = gemini_genai_rs::quick_connect_vertex(
31//!     "ya29.ACCESS_TOKEN",
32//!     "my-project",
33//!     "us-central1",
34//!     "gemini-2.0-flash-live-001",
35//! ).await?;
36//! # Ok(())
37//! # }
38//! ```
39
40use crate::protocol::types::{GeminiModel, SessionConfig};
41use crate::session::{SessionError, SessionHandle};
42use crate::transport::{connect, TransportConfig};
43
44/// Connect to Gemini Live with minimal configuration.
45///
46/// Uses sensible defaults: [`TransportConfig::default()`], audio output modality.
47/// For advanced configuration, use [`SessionConfig`] + [`connect()`] directly.
48pub async fn quick_connect(api_key: &str, model: &str) -> Result<SessionHandle, SessionError> {
49    let config = SessionConfig::new(api_key).model(GeminiModel::Custom(model.to_string()));
50    connect(config, TransportConfig::default()).await
51}
52
53/// Connect via Vertex AI with minimal configuration.
54///
55/// Uses sensible defaults: [`TransportConfig::default()`], audio output modality.
56/// For advanced configuration, use [`SessionConfig::from_vertex()`] + [`connect()`] directly.
57pub async fn quick_connect_vertex(
58    access_token: &str,
59    project: &str,
60    location: &str,
61    model: &str,
62) -> Result<SessionHandle, SessionError> {
63    let config = SessionConfig::from_vertex(project, location, access_token)
64        .model(GeminiModel::Custom(model.to_string()));
65    connect(config, TransportConfig::default()).await
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use crate::session::SessionPhase;
72    use crate::transport::codec::JsonCodec;
73    use crate::transport::connect_with;
74    use crate::transport::ws::MockTransport;
75
76    /// Verify that `quick_connect` builds a valid SessionConfig internally.
77    ///
78    /// We can't call `quick_connect` directly because it opens a real WebSocket.
79    /// Instead we replicate its config construction and verify it works with a mock.
80    #[tokio::test]
81    async fn quick_connect_creates_valid_config() {
82        let config = SessionConfig::new("test-api-key")
83            .model(GeminiModel::Custom("gemini-2.0-flash-live-001".to_string()));
84
85        // Verify the config fields
86        assert_eq!(
87            config.model,
88            GeminiModel::Custom("gemini-2.0-flash-live-001".to_string())
89        );
90
91        // Verify it connects successfully with a mock transport
92        let mut transport = MockTransport::new();
93        transport.script_recv(br#"{"setupComplete":{}}"#.to_vec());
94
95        let transport_config = TransportConfig {
96            max_reconnect_attempts: 0,
97            ..TransportConfig::default()
98        };
99
100        let handle = connect_with(config, transport_config, transport, JsonCodec)
101            .await
102            .unwrap();
103
104        handle.wait_for_phase(SessionPhase::Active).await;
105        assert_eq!(handle.phase(), SessionPhase::Active);
106    }
107
108    /// Verify that `quick_connect_vertex` builds a valid Vertex AI config.
109    #[tokio::test]
110    async fn quick_connect_vertex_creates_valid_config() {
111        let config = SessionConfig::from_vertex("my-project", "us-central1", "ya29.TOKEN")
112            .model(GeminiModel::Custom("gemini-2.0-flash-live-001".to_string()));
113
114        // Verify model
115        assert_eq!(
116            config.model,
117            GeminiModel::Custom("gemini-2.0-flash-live-001".to_string())
118        );
119
120        // Verify Vertex AI endpoint
121        assert!(config.is_vertex(), "should target Vertex AI");
122        let url = config.ws_url();
123        assert!(
124            url.contains("aiplatform.googleapis.com"),
125            "URL should use Vertex AI endpoint"
126        );
127
128        // Verify model URI contains project and location
129        let model_uri = config.model_uri();
130        assert!(
131            model_uri.contains("my-project"),
132            "model URI should contain project ID"
133        );
134        assert!(
135            model_uri.contains("us-central1"),
136            "model URI should contain location"
137        );
138
139        // Verify bearer token is set
140        assert_eq!(config.bearer_token(), Some("ya29.TOKEN"));
141
142        // Verify it connects successfully with a mock transport
143        let mut transport = MockTransport::new();
144        transport.script_recv(br#"{"setupComplete":{}}"#.to_vec());
145
146        let transport_config = TransportConfig {
147            max_reconnect_attempts: 0,
148            ..TransportConfig::default()
149        };
150
151        let handle = connect_with(config, transport_config, transport, JsonCodec)
152            .await
153            .unwrap();
154
155        handle.wait_for_phase(SessionPhase::Active).await;
156        assert_eq!(handle.phase(), SessionPhase::Active);
157    }
158}