Detailed changes
@@ -145,6 +145,10 @@ impl Message {
}
}
+ pub fn push_redacted_thinking(&mut self, data: String) {
+ self.segments.push(MessageSegment::RedactedThinking(data));
+ }
+
pub fn push_text(&mut self, text: &str) {
if let Some(MessageSegment::Text(segment)) = self.segments.last_mut() {
segment.push_str(text);
@@ -183,7 +187,7 @@ pub enum MessageSegment {
text: String,
signature: Option<String>,
},
- RedactedThinking(Vec<u8>),
+ RedactedThinking(String),
}
impl MessageSegment {
@@ -1643,6 +1647,25 @@ impl Thread {
};
}
}
+ LanguageModelCompletionEvent::RedactedThinking {
+ data
+ } => {
+ thread.received_chunk();
+
+ if let Some(last_message) = thread.messages.last_mut() {
+ if last_message.role == Role::Assistant
+ && !thread.tool_use.has_tool_results(last_message.id)
+ {
+ last_message.push_redacted_thinking(data);
+ } else {
+ request_assistant_message_id =
+ Some(thread.insert_assistant_message(
+ vec![MessageSegment::RedactedThinking(data)],
+ cx,
+ ));
+ };
+ }
+ }
LanguageModelCompletionEvent::ToolUse(tool_use) => {
let last_assistant_message_id = request_assistant_message_id
.unwrap_or_else(|| {
@@ -731,7 +731,7 @@ pub enum SerializedMessageSegment {
signature: Option<String>,
},
RedactedThinking {
- data: Vec<u8>,
+ data: String,
},
}
@@ -2117,6 +2117,7 @@ impl AssistantContext {
);
}
}
+ LanguageModelCompletionEvent::RedactedThinking { .. } => {},
LanguageModelCompletionEvent::Text(mut chunk) => {
if let Some(start) = thought_process_stack.pop() {
let end = buffer.anchor_before(message_old_end_offset);
@@ -1030,6 +1030,7 @@ pub fn response_events_to_markdown(
Ok(LanguageModelCompletionEvent::Thinking { text, .. }) => {
thinking_buffer.push_str(text);
}
+ Ok(LanguageModelCompletionEvent::RedactedThinking { .. }) => {}
Ok(LanguageModelCompletionEvent::Stop(reason)) => {
flush_buffers(&mut response, &mut text_buffer, &mut thinking_buffer);
response.push_str(&format!("**Stop**: {:?}\n\n", reason));
@@ -1126,6 +1127,7 @@ impl ThreadDialog {
// Skip these
Ok(LanguageModelCompletionEvent::UsageUpdate(_))
+ | Ok(LanguageModelCompletionEvent::RedactedThinking { .. })
| Ok(LanguageModelCompletionEvent::StatusUpdate { .. })
| Ok(LanguageModelCompletionEvent::StartMessage { .. })
| Ok(LanguageModelCompletionEvent::Stop(_)) => {}
@@ -67,6 +67,9 @@ pub enum LanguageModelCompletionEvent {
text: String,
signature: Option<String>,
},
+ RedactedThinking {
+ data: String,
+ },
ToolUse(LanguageModelToolUse),
StartMessage {
message_id: String,
@@ -359,6 +362,7 @@ pub trait LanguageModel: Send + Sync {
Ok(LanguageModelCompletionEvent::StartMessage { .. }) => None,
Ok(LanguageModelCompletionEvent::Text(text)) => Some(Ok(text)),
Ok(LanguageModelCompletionEvent::Thinking { .. }) => None,
+ Ok(LanguageModelCompletionEvent::RedactedThinking { .. }) => None,
Ok(LanguageModelCompletionEvent::Stop(_)) => None,
Ok(LanguageModelCompletionEvent::ToolUse(_)) => None,
Ok(LanguageModelCompletionEvent::UsageUpdate(token_usage)) => {
@@ -303,7 +303,7 @@ pub enum MessageContent {
text: String,
signature: Option<String>,
},
- RedactedThinking(Vec<u8>),
+ RedactedThinking(String),
Image(LanguageModelImage),
ToolUse(LanguageModelToolUse),
ToolResult(LanguageModelToolResult),
@@ -554,9 +554,7 @@ pub fn into_anthropic(
}
MessageContent::RedactedThinking(data) => {
if !data.is_empty() {
- Some(anthropic::RequestContent::RedactedThinking {
- data: String::from_utf8(data).ok()?,
- })
+ Some(anthropic::RequestContent::RedactedThinking { data })
} else {
None
}
@@ -730,10 +728,8 @@ impl AnthropicEventMapper {
signature: None,
})]
}
- ResponseContent::RedactedThinking { .. } => {
- // Redacted thinking is encrypted and not accessible to the user, see:
- // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#suggestions-for-handling-redacted-thinking-in-production
- Vec::new()
+ ResponseContent::RedactedThinking { data } => {
+ vec![Ok(LanguageModelCompletionEvent::RedactedThinking { data })]
}
ResponseContent::ToolUse { id, name, .. } => {
self.tool_uses_by_index.insert(