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#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct ContextConfig {
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub compact_at_tokens: Option<i64>,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub keep_recent_tool_results: Option<i32>,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub clear_thinking: Option<bool>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub summarize_strategy: Option<String>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub summarize_model: Option<String>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35pub struct ToolResult {
36 pub tool_call_id: String,
38
39 pub content: String,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub is_error: Option<bool>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, Default)]
49pub struct SessionToolResult {
50 pub tool_call_id: String,
52
53 pub content: String,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub is_error: Option<bool>,
59}
60
61#[derive(Debug, Clone, Deserialize)]
63pub struct ContextMetadata {
64 #[serde(default)]
66 pub turn_count: i64,
67
68 #[serde(default)]
70 pub estimated_tokens: i64,
71
72 #[serde(default)]
74 pub compacted: bool,
75
76 #[serde(default)]
78 pub compaction_note: Option<String>,
79
80 #[serde(default)]
82 pub tools_cleared: Option<i32>,
83}
84
85#[derive(Debug, Clone, Serialize, Default)]
87pub struct SessionChatRequest {
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub session_id: Option<String>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub model: Option<String>,
95
96 pub message: String,
98
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub tools: Option<Vec<ChatTool>>,
102
103 #[serde(skip_serializing_if = "Option::is_none")]
105 pub tool_results: Option<Vec<ToolResult>>,
106
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub stream: Option<bool>,
110
111 #[serde(skip_serializing_if = "Option::is_none")]
113 pub system_prompt: Option<String>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub context_config: Option<ContextConfig>,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub provider_options: Option<HashMap<String, serde_json::Value>>,
122}
123
124#[derive(Debug, Clone, Deserialize)]
126pub struct SessionContext {
127 pub turn_count: i64,
129
130 pub estimated_tokens: i64,
132
133 #[serde(default)]
135 pub compacted: bool,
136
137 #[serde(default)]
139 pub compaction_note: Option<String>,
140}
141
142#[derive(Debug, Clone, Deserialize)]
144pub struct SessionChatResponse {
145 pub session_id: String,
147
148 pub response: ChatResponse,
150
151 pub context: SessionContext,
153}
154
155impl Client {
156 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}