rig_core/providers/anthropic/streaming/
document.rs1use std::collections::{BTreeMap, BTreeSet};
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 closed: BTreeSet<usize>,
29 starts: BTreeMap<usize, Vec<Map<String, Value>>>,
30 positions: BTreeMap<usize, usize>,
31 reconnecting: bool,
32 replayed: BTreeSet<usize>,
33 message_started: bool,
34}
35
36impl Message {
37 fn message(&mut self) -> &mut Map<String, Value> {
38 self.message.get_or_insert_with(Map::new)
39 }
40
41 fn block(&mut self, index: usize) -> Option<&mut Map<String, Value>> {
43 let index = self.positions.get(&index).copied()?;
44 self.message
45 .as_mut()?
46 .get_mut("content")?
47 .as_array_mut()?
48 .get_mut(index)?
49 .as_object_mut()
50 }
51
52 fn place(&mut self, index: usize, block: Map<String, Value>) {
55 let position = match self.message().get("content").and_then(Value::as_array) {
56 Some(content) if content.get(index).is_some_and(|item| !item.is_null()) => {
57 content.len()
58 }
59 _ => index,
60 };
61 self.positions.insert(index, position);
62 let index = position;
63 if let Value::Array(content) = slot(self.message(), "content", Value::Array) {
64 if content.len() <= index {
65 content.resize(index + 1, Value::Null);
66 }
67 if let Some(slot) = content.get_mut(index) {
68 *slot = Value::Object(block);
69 }
70 }
71 }
72
73 fn delta(&mut self, index: usize, delta: &Map<String, Value>) {
74 let kind = delta
75 .get("type")
76 .and_then(Value::as_str)
77 .unwrap_or_default();
78 if self.block(index).is_none() {
81 let opened = match kind {
82 "text_delta" => json!({"type": "text", "text": ""}),
83 "thinking_delta" => json!({"type": "thinking", "thinking": ""}),
84 _ => Value::Null,
85 };
86 if let Value::Object(block) = opened {
87 self.place(index, block);
88 }
89 }
90 if kind == "input_json_delta" {
91 if let Some(fragment) = delta.get("partial_json").and_then(Value::as_str) {
92 self.inputs.entry(index).or_default().push_str(fragment);
93 }
94 return;
95 }
96 let Some(block) = self.block(index) else {
97 return;
98 };
99 if kind == "citations_delta" {
100 let citation = delta.get("citation").cloned().unwrap_or_default();
101 match block.get_mut("citations") {
102 Some(Value::Array(citations)) => citations.push(citation),
103 _ => {
104 block.insert("citations".to_owned(), Value::Array(vec![citation]));
105 }
106 }
107 return;
108 }
109 let mut item = Value::Object(std::mem::take(block));
110 crate::operation::completion::merge(&mut item, delta);
111 if let Value::Object(item) = item {
112 *block = item;
113 }
114 }
115
116 fn settle(&mut self, index: usize) {
120 let Some(json) = self.inputs.remove(&index) else {
121 return;
122 };
123 let Ok(input) = crate::json_utils::parse_tool_arguments(&json) else {
124 return;
125 };
126 if let Some(block) = self.block(index) {
127 block.insert("input".to_owned(), input);
128 }
129 }
130
131 fn message_delta(&mut self, event: &MessagesEvent) {
132 if let Some(Value::Object(delta)) = event.fields.get("delta") {
133 let message = self.message();
134 for (key, value) in delta {
135 keep(message, key, value);
136 }
137 }
138 if let Some(Value::Object(terminal)) = event.fields.get("usage") {
139 let usage = self
140 .message()
141 .entry("usage")
142 .or_insert_with(|| Value::Object(Map::new()));
143 if !usage.is_object() {
144 *usage = Value::Object(Map::new());
145 }
146 if let Value::Object(usage) = usage {
147 let started = usage
150 .get("input_tokens")
151 .and_then(Value::as_u64)
152 .is_some_and(|tokens| tokens > 0);
153 for (key, value) in terminal {
154 if key == "input_tokens" && started && value.as_u64() == Some(0) {
155 continue;
156 }
157 keep(usage, key, value);
158 }
159 }
160 }
161 }
162}
163
164impl crate::wire::document::Serves<crate::operation::Completion> for Message {}
165
166impl Reassemble<MessagesEvent> for Message {
167 fn absorb(&mut self, event: &MessagesEvent) {
168 match event.kind() {
169 "message" => {
170 if let Value::Object(message) = &event.fields {
171 self.message = Some(message.clone());
172 self.inputs.clear();
173 }
174 }
175 "message_start" => {
176 if self.message_started && event.fields.get("message").is_some_and(Value::is_object)
177 {
178 self.reconnecting = true;
179 }
180 if !self.message_started
181 && let Some(Value::Object(start)) = event.fields.get("message")
182 {
183 self.message_started = true;
184 let message = self.message();
185 for (key, value) in start {
186 keep(message, key, value);
187 }
188 }
189 }
190 "content_block_start" => {
191 if let (Ok(index), Ok(block)) = (event.index(), event.item("content_block")) {
192 if self.closed.contains(&index) {
193 if self.starts.get(&index).is_some_and(|previous| {
194 super::replayed_start(previous, block, self.reconnecting)
195 }) {
196 self.replayed.insert(index);
197 return;
198 }
199 self.closed.remove(&index);
200 self.replayed.remove(&index);
201 self.reconnecting = false;
202 self.starts.entry(index).or_default().push(block.clone());
203 self.place(index, block.clone());
204 } else if self.block(index).is_none() {
205 self.reconnecting = false;
206 self.starts.entry(index).or_default().push(block.clone());
207 self.place(index, block.clone());
208 }
209 }
210 }
211 "content_block_delta" => {
212 if let (Ok(index), Ok(delta)) = (event.index(), event.item("delta"))
213 && !self.replayed.contains(&index)
214 {
215 self.delta(index, delta);
216 }
217 }
218 "content_block_stop" => {
219 if let Ok(index) = event.index()
220 && !self.replayed.remove(&index)
221 {
222 self.settle(index);
223 self.closed.insert(index);
224 }
225 }
226 "message_delta" => self.message_delta(event),
227 _ => {}
230 }
231 }
232
233 fn finish(mut self) -> Value {
234 let open: Vec<usize> = self.inputs.keys().copied().collect();
235 for index in open {
236 self.settle(index);
237 }
238 self.message.map_or(Value::Null, Value::Object)
239 }
240}
241
242#[cfg(test)]
243mod tests;