gemini_genai_rs/protocol/messages/
client.rs1use serde::{Deserialize, Serialize};
4
5use crate::protocol::types::*;
6
7#[derive(Debug, Clone, Serialize)]
9pub struct SetupMessage {
10 pub setup: SetupPayload,
12}
13
14#[derive(Debug, Clone, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub struct SetupPayload {
18 pub model: String,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub generation_config: Option<GenerationConfig>,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub system_instruction: Option<Content>,
26 #[serde(skip_serializing_if = "Vec::is_empty")]
28 pub tools: Vec<Tool>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub tool_config: Option<ToolConfig>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub input_audio_transcription: Option<InputAudioTranscription>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub output_audio_transcription: Option<OutputAudioTranscription>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub realtime_input_config: Option<RealtimeInputConfig>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub session_resumption: Option<SessionResumptionConfig>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub context_window_compression: Option<ContextWindowCompressionConfig>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub proactivity: Option<ProactivityConfig>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub explicit_vad_signal: Option<bool>,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub history_config: Option<HistoryConfig>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub avatar_config: Option<AvatarConfig>,
59}
60
61impl SessionConfig {
62 pub fn to_setup_message(&self) -> SetupMessage {
77 let profile = self.model_profile();
78 let tools = if self.supports_async_tools() {
79 self.tools.clone()
80 } else {
81 self.tools
82 .iter()
83 .map(|tool| {
84 let mut t = tool.clone();
85 if let Some(ref mut decls) = t.function_declarations {
86 for d in decls.iter_mut() {
87 d.behavior = None;
88 }
89 }
90 t
91 })
92 .collect()
93 };
94
95 let mut generation_config = self.generation_config.clone();
96 let mut output_audio_transcription = self.output_audio_transcription.clone();
97 if self.text_via_transcription() {
98 generation_config.response_modalities = Some(vec![Modality::Audio]);
99 output_audio_transcription.get_or_insert_with(Default::default);
100 }
101 if !self.supports_thinking() {
102 generation_config.thinking_config = None;
103 }
104 if !profile.affective_dialog_flag {
105 generation_config.enable_affective_dialog = None;
106 }
107
108 SetupMessage {
109 setup: SetupPayload {
110 model: self.model_uri(),
111 generation_config: Some(generation_config),
112 system_instruction: self.system_instruction.clone(),
113 tools,
114 tool_config: self.tool_config.clone(),
115 input_audio_transcription: self.input_audio_transcription.clone(),
116 output_audio_transcription,
117 realtime_input_config: self.realtime_input_config.clone(),
118 session_resumption: self.session_resumption.clone().map(|mut r| {
119 if !self.is_vertex() {
120 r.transparent = None;
121 }
122 r
123 }),
124 context_window_compression: self.context_window_compression.clone(),
125 proactivity: self
126 .proactivity
127 .clone()
128 .filter(|_| self.is_vertex() && profile.proactivity_flag),
129 explicit_vad_signal: self.explicit_vad_signal.filter(|_| self.is_vertex()),
130 history_config: self.history_config.clone(),
131 avatar_config: self.avatar_config.clone().map(|mut a| {
132 if !self.is_vertex() {
133 a.avatar_name = None;
134 a.customized_avatar = None;
135 }
136 a
137 }),
138 },
139 }
140 }
141
142 pub fn to_setup_json(&self) -> String {
144 serde_json::to_string(&self.to_setup_message())
145 .expect("setup message serialization is infallible for valid config")
146 }
147}
148
149#[derive(Debug, Clone, Serialize)]
151#[serde(rename_all = "camelCase")]
152pub struct RealtimeInputMessage {
153 pub realtime_input: RealtimeInputPayload,
155}
156
157#[derive(Debug, Clone, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct RealtimeInputPayload {
161 #[serde(skip_serializing_if = "Vec::is_empty")]
163 pub media_chunks: Vec<MediaChunk>,
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub audio: Option<Blob>,
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub video: Option<Blob>,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub audio_stream_end: Option<bool>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub text: Option<String>,
176}
177
178#[derive(Debug, Clone, Serialize)]
180#[serde(rename_all = "camelCase")]
181pub struct MediaChunk {
182 pub mime_type: String,
184 pub data: String, }
187
188#[derive(Debug, Clone, Serialize)]
190#[serde(rename_all = "camelCase")]
191pub struct ClientContentMessage {
192 pub client_content: ClientContentPayload,
194}
195
196#[derive(Debug, Clone, Serialize)]
198#[serde(rename_all = "camelCase")]
199pub struct ClientContentPayload {
200 pub turns: Vec<Content>,
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub turn_complete: Option<bool>,
205}
206
207#[derive(Debug, Clone, Serialize)]
209#[serde(rename_all = "camelCase")]
210pub struct ToolResponseMessage {
211 pub tool_response: ToolResponsePayload,
213}
214
215#[derive(Debug, Clone, Serialize)]
217#[serde(rename_all = "camelCase")]
218pub struct ToolResponsePayload {
219 pub function_responses: Vec<FunctionResponse>,
221}
222
223#[derive(Debug, Clone, Serialize)]
225#[serde(rename_all = "camelCase")]
226pub struct ActivitySignalMessage {
227 pub realtime_input: ActivitySignalPayload,
229}
230
231#[derive(Debug, Clone, Serialize)]
233#[serde(rename_all = "camelCase")]
234pub struct ActivitySignalPayload {
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub activity_start: Option<ActivityStart>,
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub activity_end: Option<ActivityEnd>,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct ActivityStart {}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct ActivityEnd {}