Skip to main content

quantum_sdk/
session.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::chat::{ChatResponse, ChatTool};
6use crate::client::Client;
7use crate::error::Result;
8
9/// Configuration for session context management.
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct ContextConfig {
12    /// Maximum number of tokens to retain before compaction.
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub max_tokens: Option<i64>,
15
16    /// Whether to enable automatic context compaction.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub auto_compact: Option<bool>,
19}
20
21/// A tool result to feed back into the session.
22#[derive(Debug, Clone, Serialize, Deserialize, Default)]
23pub struct ToolResult {
24    /// The tool_use ID this result corresponds to.
25    pub tool_call_id: String,
26
27    /// The result content.
28    pub content: String,
29
30    /// Whether this result is an error.
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub is_error: Option<bool>,
33}
34
35/// Request body for session-based chat.
36#[derive(Debug, Clone, Serialize, Default)]
37pub struct SessionChatRequest {
38    /// Session identifier. Omit to create a new session.
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub session_id: Option<String>,
41
42    /// Model to use for generation.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub model: Option<String>,
45
46    /// The user message.
47    pub message: String,
48
49    /// Tools the model can call.
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub tools: Option<Vec<ChatTool>>,
52
53    /// Results from previous tool calls.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub tool_results: Option<Vec<ToolResult>>,
56
57    /// Enable streaming.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub stream: Option<bool>,
60
61    /// System prompt for the session.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub system_prompt: Option<String>,
64
65    /// Context management configuration.
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub context_config: Option<ContextConfig>,
68
69    /// Provider-specific settings.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub provider_options: Option<HashMap<String, serde_json::Value>>,
72}
73
74/// Context metadata returned with session responses.
75#[derive(Debug, Clone, Deserialize)]
76pub struct SessionContext {
77    /// Number of conversation turns in the session.
78    pub turn_count: i64,
79
80    /// Estimated total tokens in the session context.
81    pub estimated_tokens: i64,
82
83    /// Whether context was compacted during this turn.
84    #[serde(default)]
85    pub compacted: bool,
86
87    /// Note about the compaction, if any.
88    #[serde(default)]
89    pub compaction_note: Option<String>,
90}
91
92/// Response from session-based chat.
93#[derive(Debug, Clone, Deserialize)]
94pub struct SessionChatResponse {
95    /// The session identifier (may be newly created).
96    pub session_id: String,
97
98    /// The chat response.
99    pub response: ChatResponse,
100
101    /// Session context metadata.
102    pub context: SessionContext,
103}
104
105impl Client {
106    /// Sends a message within a persistent session.
107    ///
108    /// Sessions maintain conversation history server-side with automatic
109    /// context compaction. Omit `session_id` to start a new session.
110    pub async fn chat_session(&self, req: &SessionChatRequest) -> Result<SessionChatResponse> {
111        let (resp, _meta) = self
112            .post_json::<SessionChatRequest, SessionChatResponse>("/qai/v1/chat/session", req)
113            .await?;
114        Ok(resp)
115    }
116}