Skip to main content

gemini_rust/interactions/
handle.rs

1use std::{sync::Arc, time::Duration};
2
3use tokio::time::sleep;
4use tracing::instrument;
5
6use crate::client::{Error, GeminiClient};
7use crate::interactions::model::*;
8use crate::interactions::stream::InteractionStream;
9
10/// Handle to an Interaction, usable for get / cancel / delete / poll operations.
11#[derive(Clone)]
12pub struct InteractionHandle {
13    id: String,
14    client: Arc<GeminiClient>,
15}
16
17impl InteractionHandle {
18    pub(crate) fn new(id: String, client: Arc<GeminiClient>) -> Self {
19        Self { id, client }
20    }
21
22    /// Get the interaction ID.
23    pub fn id(&self) -> &str {
24        &self.id
25    }
26
27    /// Get the full interaction resource.
28    #[instrument(skip(self))]
29    pub async fn get(&self) -> Result<Interaction, Error> {
30        self.client.get_interaction(&self.id).await
31    }
32
33    /// Get the interaction in streaming mode (can resume from last_event_id).
34    #[instrument(skip(self), fields(last_event_id = last_event_id.unwrap_or("")))]
35    pub async fn get_stream(
36        &self,
37        last_event_id: Option<&str>,
38    ) -> Result<InteractionStream, Error> {
39        self.client
40            .get_interaction_stream(&self.id, last_event_id)
41            .await
42    }
43
44    /// Cancel the interaction (only applicable to background executions).
45    #[instrument(skip(self))]
46    pub async fn cancel(&self) -> Result<Interaction, Error> {
47        self.client.cancel_interaction(&self.id).await
48    }
49
50    /// Delete the interaction.
51    #[instrument(skip(self))]
52    pub async fn delete(&self) -> Result<(), Error> {
53        self.client.delete_interaction(&self.id).await
54    }
55
56    /// Poll until the interaction reaches a terminal state.
57    ///
58    /// Continuously calls `get()` until the status becomes
59    /// completed / failed / cancelled / incomplete / budget_exceeded.
60    /// Suitable for background interactions.
61    #[instrument(skip(self), fields(poll.interval = ?interval))]
62    pub async fn poll_until_completed(&self, interval: Duration) -> Result<Interaction, Error> {
63        loop {
64            let interaction = self.get().await?;
65
66            if interaction.status.is_terminal() {
67                return Ok(interaction);
68            }
69
70            sleep(interval).await;
71        }
72    }
73
74    /// Get this interaction's ID for use as `previous_interaction_id` in the next turn.
75    pub fn as_previous_interaction_id(&self) -> &str {
76        &self.id
77    }
78}