systemprompt_api/services/gateway/
parse.rs1use serde_json::Value;
2
3use super::audit::{CapturedToolUse, CapturedUsage};
4
5pub fn extract_from_anthropic_response(bytes: &[u8]) -> (CapturedUsage, Vec<CapturedToolUse>) {
6 let Ok(value) = serde_json::from_slice::<Value>(bytes) else {
7 return (CapturedUsage::default(), Vec::new());
8 };
9 extract_from_anthropic_value(&value)
10}
11
12pub fn extract_assistant_text(bytes: &[u8]) -> Option<String> {
13 let value = serde_json::from_slice::<Value>(bytes).ok()?;
14 let content = value.get("content")?.as_array()?;
15 let mut out = String::new();
16 for block in content {
17 if block.get("type").and_then(Value::as_str) == Some("text") {
18 if let Some(text) = block.get("text").and_then(Value::as_str) {
19 if !out.is_empty() {
20 out.push('\n');
21 }
22 out.push_str(text);
23 }
24 }
25 }
26 if out.is_empty() { None } else { Some(out) }
27}
28
29pub fn extract_from_anthropic_value(value: &Value) -> (CapturedUsage, Vec<CapturedToolUse>) {
30 let usage = CapturedUsage {
31 input_tokens: value
32 .get("usage")
33 .and_then(|u| u.get("input_tokens"))
34 .and_then(Value::as_u64)
35 .unwrap_or(0) as u32,
36 output_tokens: value
37 .get("usage")
38 .and_then(|u| u.get("output_tokens"))
39 .and_then(Value::as_u64)
40 .unwrap_or(0) as u32,
41 };
42
43 let mut tool_calls = Vec::new();
44 if let Some(content) = value.get("content").and_then(Value::as_array) {
45 for block in content {
46 if block.get("type").and_then(Value::as_str) == Some("tool_use") {
47 let id = block
48 .get("id")
49 .and_then(Value::as_str)
50 .unwrap_or("")
51 .to_string();
52 let name = block
53 .get("name")
54 .and_then(Value::as_str)
55 .unwrap_or("")
56 .to_string();
57 let input = block
58 .get("input")
59 .map(|v| serde_json::to_string(v).unwrap_or_default())
60 .unwrap_or_default();
61 tool_calls.push(CapturedToolUse {
62 ai_tool_call_id: id,
63 tool_name: name,
64 tool_input: input,
65 });
66 }
67 }
68 }
69
70 (usage, tool_calls)
71}