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    /// Token threshold that triggers automatic compaction.
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub compact_at_tokens: Option<i64>,
15
16    /// Number of recent tool call/result pairs to keep uncompacted.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub keep_recent_tool_results: Option<i32>,
19
20    /// Strip thinking blocks from older assistant turns.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub clear_thinking: Option<bool>,
23
24    /// Summarization strategy: "plan_and_tools", "full", "brief".
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub summarize_strategy: Option<String>,
27
28    /// Model to use for summarization (default: gemini-2.5-flash).
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub summarize_model: Option<String>,
31}
32
33/// A tool result to feed back into the session.
34#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35pub struct ToolResult {
36    /// The tool_use ID this result corresponds to.
37    pub tool_call_id: String,
38
39    /// The result content.
40    pub content: String,
41
42    /// Whether this result is an error.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub is_error: Option<bool>,
45}
46
47/// A tool execution result from the client (used in SessionChatRequest.tool_results).
48#[derive(Debug, Clone, Serialize, Deserialize, Default)]
49pub struct SessionToolResult {
50    /// References the tool_use ID from the previous response.
51    pub tool_call_id: String,
52
53    /// The tool execution result content.
54    pub content: String,
55
56    /// Whether the tool execution failed.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub is_error: Option<bool>,
59}
60
61/// Context metadata returned in session responses (includes tools_cleared).
62#[derive(Debug, Clone, Deserialize)]
63pub struct ContextMetadata {
64    /// Total number of turns in the conversation.
65    #[serde(default)]
66    pub turn_count: i64,
67
68    /// Estimated token count of the current context.
69    #[serde(default)]
70    pub estimated_tokens: i64,
71
72    /// Whether the conversation was compacted in this request.
73    #[serde(default)]
74    pub compacted: bool,
75
76    /// Description of the compaction that occurred.
77    #[serde(default)]
78    pub compaction_note: Option<String>,
79
80    /// Number of stale tool results that were cleared.
81    #[serde(default)]
82    pub tools_cleared: Option<i32>,
83}
84
85/// Request body for session-based chat.
86#[derive(Debug, Clone, Serialize, Default)]
87pub struct SessionChatRequest {
88    /// Session identifier. Omit to create a new session.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub session_id: Option<String>,
91
92    /// Model to use for generation.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub model: Option<String>,
95
96    /// The user message.
97    pub message: String,
98
99    /// Tools the model can call.
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub tools: Option<Vec<ChatTool>>,
102
103    /// Results from previous tool calls.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub tool_results: Option<Vec<ToolResult>>,
106
107    /// Enable streaming.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub stream: Option<bool>,
110
111    /// System prompt for the session.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub system_prompt: Option<String>,
114
115    /// Context management configuration.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub context_config: Option<ContextConfig>,
118
119    /// Provider-specific settings.
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub provider_options: Option<HashMap<String, serde_json::Value>>,
122}
123
124/// Context metadata returned with session responses.
125#[derive(Debug, Clone, Deserialize)]
126pub struct SessionContext {
127    /// Number of conversation turns in the session.
128    pub turn_count: i64,
129
130    /// Estimated total tokens in the session context.
131    pub estimated_tokens: i64,
132
133    /// Whether context was compacted during this turn.
134    #[serde(default)]
135    pub compacted: bool,
136
137    /// Note about the compaction, if any.
138    #[serde(default)]
139    pub compaction_note: Option<String>,
140}
141
142/// Response from session-based chat.
143#[derive(Debug, Clone, Deserialize)]
144pub struct SessionChatResponse {
145    /// The session identifier (may be newly created).
146    pub session_id: String,
147
148    /// The chat response.
149    pub response: ChatResponse,
150
151    /// Session context metadata.
152    pub context: SessionContext,
153}
154
155impl Client {
156    /// Sends a message within a persistent session.
157    ///
158    /// Sessions maintain conversation history server-side with automatic
159    /// context compaction. Omit `session_id` to start a new session.
160    pub async fn chat_session(&self, req: &SessionChatRequest) -> Result<SessionChatResponse> {
161        let (resp, _meta) = self
162            .post_json::<SessionChatRequest, SessionChatResponse>("/qai/v1/chat/session", req)
163            .await?;
164        Ok(resp)
165    }
166}