Skip to main content

systemprompt_analytics/services/
ai_provider.rs

1//! `AiSessionProvider` implementation backed by analytics session rows.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use async_trait::async_trait;
7use systemprompt_database::DbPool;
8use systemprompt_identifiers::SessionId;
9use systemprompt_traits::{
10    AiProviderError, AiProviderResult, AiSessionProvider, CreateAiSessionParams,
11};
12
13use crate::repository::{CreateSessionParams, SessionRepository};
14
15#[derive(Debug)]
16pub struct AnalyticsAiSessionProvider {
17    session_repo: SessionRepository,
18}
19
20impl AnalyticsAiSessionProvider {
21    pub fn new(pool: &DbPool) -> crate::Result<Self> {
22        Ok(Self {
23            session_repo: SessionRepository::new(pool)?,
24        })
25    }
26
27    pub const fn from_repository(session_repo: SessionRepository) -> Self {
28        Self { session_repo }
29    }
30}
31
32#[async_trait]
33impl AiSessionProvider for AnalyticsAiSessionProvider {
34    async fn session_exists(&self, session_id: &SessionId) -> AiProviderResult<bool> {
35        self.session_repo
36            .exists(session_id)
37            .await
38            .map_err(|e| AiProviderError::Internal(e.to_string()))
39    }
40
41    async fn create_session(&self, params: CreateAiSessionParams<'_>) -> AiProviderResult<()> {
42        let full_params = CreateSessionParams {
43            session_id: params.session_id,
44            user_id: params.user_id,
45            session_source: params.session_source,
46            fingerprint_hash: None,
47            ip_address: None,
48            user_agent: None,
49            device_type: None,
50            browser: None,
51            os: None,
52            country: None,
53            region: None,
54            city: None,
55            preferred_locale: None,
56            referrer_source: None,
57            referrer_url: None,
58            landing_page: None,
59            entry_url: None,
60            utm_source: None,
61            utm_medium: None,
62            utm_campaign: None,
63            utm_content: None,
64            utm_term: None,
65            is_bot: false,
66            is_ai_crawler: false,
67            expires_at: params.expires_at,
68        };
69
70        self.session_repo
71            .create_session(&full_params)
72            .await
73            .map_err(|e| AiProviderError::Internal(e.to_string()))
74    }
75
76    async fn increment_ai_usage(
77        &self,
78        session_id: &SessionId,
79        tokens: i32,
80        cost_microdollars: i64,
81    ) -> AiProviderResult<()> {
82        self.session_repo
83            .increment_ai_usage(session_id, tokens, cost_microdollars)
84            .await
85            .map_err(|e| AiProviderError::Internal(e.to_string()))
86    }
87}