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