1use base64::Engine;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13fn deserialize_audio_bytes<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
16where
17 D: serde::Deserializer<'de>,
18{
19 let s = String::deserialize(deserializer)?;
20 base64::engine::general_purpose::STANDARD.decode(&s).map_err(serde::de::Error::custom)
21}
22
23fn serialize_audio_bytes<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
24where
25 S: serde::Serializer,
26{
27 let s = base64::engine::general_purpose::STANDARD.encode(bytes);
28 serializer.serialize_str(&s)
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
35#[serde(tag = "type")]
36pub enum ClientEvent {
37 #[serde(rename = "session.update")]
39 SessionUpdate {
40 session: Value,
42 },
43
44 #[serde(rename = "input_audio_buffer.append")]
46 AudioDelta {
47 #[serde(skip_serializing_if = "Option::is_none")]
49 event_id: Option<String>,
50 #[serde(
52 serialize_with = "serialize_audio_bytes",
53 deserialize_with = "deserialize_audio_bytes"
54 )]
55 audio: Vec<u8>,
56 #[serde(skip)]
59 format: Option<crate::audio::AudioFormat>,
60 },
61
62 #[serde(rename = "input_audio_buffer.commit")]
64 InputAudioBufferCommit,
65
66 #[serde(rename = "input_audio_buffer.clear")]
68 InputAudioBufferClear,
69
70 #[serde(rename = "conversation.item.create")]
72 ConversationItemCreate {
73 item: Value,
75 },
76
77 #[serde(rename = "response.create")]
79 ResponseCreate {
80 #[serde(skip_serializing_if = "Option::is_none")]
82 config: Option<Value>,
83 },
84
85 #[serde(rename = "response.cancel")]
87 ResponseCancel,
88
89 #[serde(rename = "message")]
91 Message {
92 role: String,
94 parts: Vec<adk_core::types::Part>,
96 },
97
98 #[serde(skip_serializing)]
105 UpdateSession {
106 #[serde(skip_serializing_if = "Option::is_none")]
108 instructions: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
111 tools: Option<Vec<crate::config::ToolDefinition>>,
112 },
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct ConversationItem {
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub id: Option<String>,
121 #[serde(rename = "type")]
123 pub item_type: String,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub role: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub content: Option<Vec<ContentPart>>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub call_id: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub output: Option<String>,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct ContentPart {
141 #[serde(rename = "type")]
143 pub content_type: String,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub text: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub audio: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub transcript: Option<String>,
153}
154
155impl ConversationItem {
156 pub fn user_text(text: impl Into<String>) -> Self {
158 Self {
159 id: None,
160 item_type: "message".to_string(),
161 role: Some("user".to_string()),
162 content: Some(vec![ContentPart {
163 content_type: "input_text".to_string(),
164 text: Some(text.into()),
165 audio: None,
166 transcript: None,
167 }]),
168 call_id: None,
169 output: None,
170 }
171 }
172
173 pub fn tool_response(call_id: impl Into<String>, output: impl Into<String>) -> Self {
175 Self {
176 id: None,
177 item_type: "function_call_output".to_string(),
178 role: None,
179 content: None,
180 call_id: Some(call_id.into()),
181 output: Some(output.into()),
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
194#[serde(tag = "type")]
195pub enum ServerEvent {
196 #[serde(rename = "session.created")]
198 SessionCreated {
199 event_id: String,
201 session: Value,
203 },
204
205 #[serde(rename = "session.updated")]
207 SessionUpdated {
208 event_id: String,
210 session: Value,
212 },
213
214 #[serde(rename = "error")]
216 Error {
217 event_id: String,
219 error: ErrorInfo,
221 },
222
223 #[serde(rename = "input_audio_buffer.speech_started")]
225 SpeechStarted {
226 event_id: String,
228 audio_start_ms: u64,
230 },
231
232 #[serde(rename = "input_audio_buffer.speech_stopped")]
234 SpeechStopped {
235 event_id: String,
237 audio_end_ms: u64,
239 },
240
241 #[serde(rename = "input_audio_buffer.committed")]
243 AudioCommitted {
244 event_id: String,
246 item_id: String,
248 },
249
250 #[serde(rename = "input_audio_buffer.cleared")]
252 AudioCleared {
253 event_id: String,
255 },
256
257 #[serde(rename = "conversation.item.created")]
259 ItemCreated {
260 event_id: String,
262 item: Value,
264 },
265
266 #[serde(rename = "response.created")]
268 ResponseCreated {
269 event_id: String,
271 response: Value,
273 },
274
275 #[serde(rename = "response.done")]
277 ResponseDone {
278 event_id: String,
280 response: Value,
282 },
283
284 #[serde(rename = "response.output_item.added")]
286 OutputItemAdded {
287 event_id: String,
289 response_id: String,
291 output_index: u32,
293 item: Value,
295 },
296
297 #[serde(rename = "response.output_item.done")]
299 OutputItemDone {
300 event_id: String,
302 response_id: String,
304 output_index: u32,
306 item: Value,
308 },
309
310 #[serde(rename = "response.audio.delta")]
312 AudioDelta {
313 event_id: String,
315 response_id: String,
317 item_id: String,
319 output_index: u32,
321 content_index: u32,
323 #[serde(
325 serialize_with = "serialize_audio_bytes",
326 deserialize_with = "deserialize_audio_bytes"
327 )]
328 delta: Vec<u8>,
329 },
330
331 #[serde(rename = "response.audio.done")]
333 AudioDone {
334 event_id: String,
336 response_id: String,
338 item_id: String,
340 output_index: u32,
342 content_index: u32,
344 },
345
346 #[serde(rename = "response.text.delta")]
348 TextDelta {
349 event_id: String,
351 response_id: String,
353 item_id: String,
355 output_index: u32,
357 content_index: u32,
359 delta: String,
361 },
362
363 #[serde(rename = "response.text.done")]
365 TextDone {
366 event_id: String,
368 response_id: String,
370 item_id: String,
372 output_index: u32,
374 content_index: u32,
376 text: String,
378 },
379
380 #[serde(rename = "response.audio_transcript.delta")]
382 TranscriptDelta {
383 event_id: String,
385 response_id: String,
387 item_id: String,
389 output_index: u32,
391 content_index: u32,
393 delta: String,
395 },
396
397 #[serde(rename = "response.audio_transcript.done")]
399 TranscriptDone {
400 event_id: String,
402 response_id: String,
404 item_id: String,
406 output_index: u32,
408 content_index: u32,
410 transcript: String,
412 },
413
414 #[serde(rename = "response.function_call_arguments.delta")]
416 FunctionCallDelta {
417 event_id: String,
419 response_id: String,
421 item_id: String,
423 output_index: u32,
425 call_id: String,
427 delta: String,
429 },
430
431 #[serde(rename = "response.function_call_arguments.done")]
433 FunctionCallDone {
434 event_id: String,
436 response_id: String,
438 item_id: String,
440 output_index: u32,
442 call_id: String,
444 name: String,
446 arguments: String,
448 },
449
450 #[serde(rename = "rate_limits.updated")]
452 RateLimitsUpdated {
453 event_id: String,
455 rate_limits: Vec<RateLimit>,
457 },
458
459 #[serde(other)]
461 Unknown,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
466pub struct ErrorInfo {
467 #[serde(rename = "type")]
469 pub error_type: String,
470 #[serde(skip_serializing_if = "Option::is_none")]
472 pub code: Option<String>,
473 pub message: String,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub param: Option<String>,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
482pub struct RateLimit {
483 pub name: String,
485 pub limit: u64,
487 pub remaining: u64,
489 pub reset_seconds: f64,
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct ToolCall {
496 pub call_id: String,
498 pub name: String,
500 pub arguments: Value,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct ToolResponse {
507 pub call_id: String,
509 pub output: Value,
511}
512
513impl ToolResponse {
514 pub fn new(call_id: impl Into<String>, output: impl Serialize) -> Self {
516 Self {
517 call_id: call_id.into(),
518 output: serde_json::to_value(output).unwrap_or(Value::Null),
519 }
520 }
521
522 pub fn from_string(call_id: impl Into<String>, output: impl Into<String>) -> Self {
524 Self { call_id: call_id.into(), output: Value::String(output.into()) }
525 }
526}