1use serde::{Deserialize, Serialize};
4
5use super::{ContentBlock, ToolCall};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ChatResponse {
10 pub content: Vec<ContentBlock>,
12 pub tool_calls: Vec<ToolCall>,
14 pub usage: TokenUsage,
15 pub raw: serde_json::Value,
16}
17
18impl ChatResponse {
19 pub fn new(content: Vec<ContentBlock>, usage: TokenUsage, raw: serde_json::Value) -> Self {
21 let tool_calls = content
22 .iter()
23 .filter_map(|b| match b {
24 ContentBlock::ToolCall(tc) => Some(tc.clone()),
25 _ => None,
26 })
27 .collect();
28 Self {
29 content,
30 tool_calls,
31 usage,
32 raw,
33 }
34 }
35}
36
37#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
39pub struct TokenUsage {
40 pub prompt_tokens: u32,
41 pub completion_tokens: u32,
42 pub total_tokens: u32,
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::{ContentBlock, ToolCall};
49
50 #[test]
51 fn test_chat_response_new_extracts_tool_calls() {
52 let tc = ToolCall {
53 id: "1".into(),
54 name: "test".into(),
55 arguments: serde_json::json!({}),
56 };
57 let content = vec![
58 ContentBlock::text("hello".to_string()),
59 ContentBlock::ToolCall(tc.clone()),
60 ];
61 let resp = ChatResponse::new(content, TokenUsage::default(), serde_json::json!(null));
62 assert_eq!(resp.tool_calls.len(), 1);
63 assert_eq!(resp.tool_calls[0].id, "1");
64 }
65
66 #[test]
67 fn test_chat_response_no_tool_calls() {
68 let content = vec![ContentBlock::text("hello".to_string())];
69 let resp = ChatResponse::new(content, TokenUsage::default(), serde_json::json!(null));
70 assert!(resp.tool_calls.is_empty());
71 }
72}