rig_core/providers/anthropic/streaming/
document.rs1use std::collections::BTreeMap;
5
6use serde_json::{Map, Value, json};
7
8use super::MessagesEvent;
9use crate::wire::document::{Reassemble, keep, slot};
10
11#[derive(Debug, Default)]
23pub struct Message {
24 message: Option<Map<String, Value>>,
26 inputs: BTreeMap<usize, String>,
28}
29
30impl Message {
31 fn message(&mut self) -> &mut Map<String, Value> {
32 self.message.get_or_insert_with(Map::new)
33 }
34
35 fn block(&mut self, index: usize) -> Option<&mut Map<String, Value>> {
37 self.message
38 .as_mut()?
39 .get_mut("content")?
40 .as_array_mut()?
41 .get_mut(index)?
42 .as_object_mut()
43 }
44
45 fn place(&mut self, index: usize, block: Map<String, Value>) {
47 if let Value::Array(content) = slot(self.message(), "content", Value::Array) {
48 if content.len() <= index {
49 content.resize(index + 1, Value::Null);
50 }
51 if let Some(slot) = content.get_mut(index) {
52 *slot = Value::Object(block);
53 }
54 }
55 }
56
57 fn delta(&mut self, index: usize, delta: &Map<String, Value>) {
58 let kind = delta
59 .get("type")
60 .and_then(Value::as_str)
61 .unwrap_or_default();
62 if self.block(index).is_none() {
65 let opened = match kind {
66 "text_delta" => json!({"type": "text", "text": ""}),
67 "thinking_delta" => json!({"type": "thinking", "thinking": ""}),
68 _ => Value::Null,
69 };
70 if let Value::Object(block) = opened {
71 self.place(index, block);
72 }
73 }
74 if kind == "input_json_delta" {
75 if let Some(fragment) = delta.get("partial_json").and_then(Value::as_str) {
76 self.inputs.entry(index).or_default().push_str(fragment);
77 }
78 return;
79 }
80 let Some(block) = self.block(index) else {
81 return;
82 };
83 if kind == "citations_delta" {
84 let citation = delta.get("citation").cloned().unwrap_or_default();
85 match block.get_mut("citations") {
86 Some(Value::Array(citations)) => citations.push(citation),
87 _ => {
88 block.insert("citations".to_owned(), Value::Array(vec![citation]));
89 }
90 }
91 return;
92 }
93 let mut item = Value::Object(std::mem::take(block));
94 crate::operation::completion::merge(&mut item, delta);
95 if let Value::Object(item) = item {
96 *block = item;
97 }
98 }
99
100 fn settle(&mut self, index: usize) {
104 let Some(json) = self.inputs.remove(&index) else {
105 return;
106 };
107 let Ok(input) = crate::json_utils::parse_tool_arguments(&json) else {
108 return;
109 };
110 if let Some(block) = self.block(index) {
111 block.insert("input".to_owned(), input);
112 }
113 }
114
115 fn message_delta(&mut self, event: &MessagesEvent) {
116 if let Some(Value::Object(delta)) = event.fields.get("delta") {
117 let message = self.message();
118 for (key, value) in delta {
119 keep(message, key, value);
120 }
121 }
122 if let Some(Value::Object(terminal)) = event.fields.get("usage") {
123 let usage = self
124 .message()
125 .entry("usage")
126 .or_insert_with(|| Value::Object(Map::new()));
127 if !usage.is_object() {
128 *usage = Value::Object(Map::new());
129 }
130 if let Value::Object(usage) = usage {
131 let started = usage
134 .get("input_tokens")
135 .and_then(Value::as_u64)
136 .is_some_and(|tokens| tokens > 0);
137 for (key, value) in terminal {
138 if key == "input_tokens" && started && value.as_u64() == Some(0) {
139 continue;
140 }
141 keep(usage, key, value);
142 }
143 }
144 }
145 }
146}
147
148impl crate::wire::document::Serves<crate::operation::Completion> for Message {}
149
150impl Reassemble<MessagesEvent> for Message {
151 fn absorb(&mut self, event: &MessagesEvent) {
152 match event.kind() {
153 "message" => {
154 if let Value::Object(message) = &event.fields {
155 self.message = Some(message.clone());
156 self.inputs.clear();
157 }
158 }
159 "message_start" => {
160 if let Some(Value::Object(start)) = event.fields.get("message") {
161 let message = self.message();
162 for (key, value) in start {
163 keep(message, key, value);
164 }
165 }
166 }
167 "content_block_start" => {
168 if let (Ok(index), Ok(block)) = (event.index(), event.item("content_block")) {
169 self.inputs.remove(&index);
170 self.place(index, block.clone());
171 }
172 }
173 "content_block_delta" => {
174 if let (Ok(index), Ok(delta)) = (event.index(), event.item("delta")) {
175 self.delta(index, delta);
176 }
177 }
178 "content_block_stop" => {
179 if let Ok(index) = event.index() {
180 self.settle(index);
181 }
182 }
183 "message_delta" => self.message_delta(event),
184 _ => {}
187 }
188 }
189
190 fn finish(mut self) -> Value {
191 let open: Vec<usize> = self.inputs.keys().copied().collect();
192 for index in open {
193 self.settle(index);
194 }
195 self.message.map_or(Value::Null, Value::Object)
196 }
197}
198
199#[cfg(test)]
200mod tests;