Tool reply meta (#6074)

Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
Douwe Osinga
2025-12-11 19:43:36 -05:00
committed by GitHub
parent 7dd244eff6
commit cdab2fc3a6
52 changed files with 1852 additions and 1083 deletions
+3 -2
View File
@@ -74,9 +74,10 @@ impl ClaudeCodeProvider {
}
}
MessageContent::ToolResponse(tool_response) => {
if let Ok(tool_contents) = &tool_response.tool_result {
if let Ok(result) = &tool_response.tool_result {
// Convert tool result contents to text
let content_text = tool_contents
let content_text = result
.content
.iter()
.filter_map(|content| match &content.raw {
rmcp::model::RawContent::Text(text_content) => {
+3 -2
View File
@@ -86,8 +86,9 @@ impl CursorAgentProvider {
}
}
MessageContent::ToolResponse(tool_response) => {
if let Ok(tool_contents) = &tool_response.tool_result {
let content_text = tool_contents
if let Ok(result) = &tool_response.tool_result {
let content_text = result
.content
.iter()
.filter_map(|content| match &content.raw {
rmcp::model::RawContent::Text(text_content) => {
@@ -68,6 +68,7 @@ pub fn format_messages(messages: &[Message]) -> Vec<Value> {
MessageContent::ToolResponse(tool_response) => match &tool_response.tool_result {
Ok(result) => {
let text = result
.content
.iter()
.filter_map(|c| c.as_text().map(|t| t.text.clone()))
.collect::<Vec<_>>()
@@ -86,8 +86,9 @@ pub fn to_bedrock_message_content(content: &MessageContent) -> Result<bedrock::C
}
MessageContent::ToolResponse(tool_res) => {
let content = match &tool_res.tool_result {
Ok(content) => Some(
content
Ok(result) => Some(
result
.content
.iter()
// Filter out content items that have User in their audience
.filter(|c| {
@@ -318,6 +319,12 @@ pub fn from_bedrock_content_block(block: &bedrock::ContentBlock) -> Result<Messa
.iter()
.map(from_bedrock_tool_result_content_block)
.collect::<ToolResult<Vec<_>>>()
.map(|content| rmcp::model::CallToolResult {
content,
structured_content: None,
is_error: Some(false),
meta: None,
})
},
),
_ => bail!("Unsupported content block type from Bedrock"),
@@ -133,9 +133,10 @@ fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<Data
}
MessageContent::ToolResponse(response) => {
match &response.tool_result {
Ok(contents) => {
Ok(call_result) => {
// Send only contents with no audience or with Assistant in the audience
let abridged: Vec<_> = contents
let abridged: Vec<_> = call_result
.content
.iter()
.filter(|content| {
content
@@ -638,6 +639,7 @@ pub fn create_request(
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::model::CallToolResult;
use rmcp::object;
use serde_json::json;
@@ -727,8 +729,15 @@ mod tests {
panic!("should be tool request");
};
messages
.push(Message::user().with_tool_response(tool_id, Ok(vec![Content::text("Result")])));
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
));
let as_value =
serde_json::to_value(format_messages(&messages, &ImageFormat::OpenAi)).unwrap();
@@ -764,8 +773,15 @@ mod tests {
panic!("should be tool request");
};
messages
.push(Message::user().with_tool_response(tool_id, Ok(vec![Content::text("Result")])));
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
));
let as_value =
serde_json::to_value(format_messages(&messages, &ImageFormat::OpenAi)).unwrap();
+10 -4
View File
@@ -70,9 +70,10 @@ pub fn format_messages(messages: &[Message]) -> Vec<Value> {
},
MessageContent::ToolResponse(response) => {
match &response.tool_result {
Ok(contents) => {
Ok(result) => {
// Send only contents with no audience or with Assistant in the audience
let abridged: Vec<_> = contents
let abridged: Vec<_> = result
.content
.iter()
.filter(|content| {
content.audience().is_none_or(|audience| {
@@ -394,7 +395,7 @@ pub fn create_request(
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::model::CallToolRequestParam;
use rmcp::model::{CallToolRequestParam, CallToolResult};
use rmcp::{model::Content, object};
use serde_json::json;
@@ -429,7 +430,12 @@ mod tests {
0,
vec![MessageContent::tool_response(
id.to_string(),
Ok(tool_response),
Ok(CallToolResult {
content: tool_response,
structured_content: None,
is_error: Some(false),
meta: None,
}),
)],
)
}
+22 -6
View File
@@ -128,9 +128,10 @@ pub fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<
},
MessageContent::ToolResponse(response) => {
match &response.tool_result {
Ok(contents) => {
Ok(result) => {
// Send only contents with no audience or with Assistant in the audience
let abridged: Vec<_> = contents
let abridged: Vec<_> = result
.content
.iter()
.filter(|content| {
content
@@ -710,6 +711,7 @@ pub fn create_request(
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::model::CallToolResult;
use rmcp::object;
use serde_json::json;
use tokio::pin;
@@ -868,8 +870,15 @@ mod tests {
panic!("should be tool request");
};
messages
.push(Message::user().with_tool_response(tool_id, Ok(vec![Content::text("Result")])));
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
));
let spec = format_messages(&messages, &ImageFormat::OpenAi);
@@ -904,8 +913,15 @@ mod tests {
panic!("should be tool request");
};
messages
.push(Message::user().with_tool_response(tool_id, Ok(vec![Content::text("Result")])));
messages.push(Message::user().with_tool_response(
tool_id,
Ok(CallToolResult {
content: vec![Content::text("Result")],
structured_content: None,
is_error: Some(false),
meta: None,
}),
));
let spec = format_messages(&messages, &ImageFormat::OpenAi);
@@ -37,6 +37,7 @@ pub fn format_messages(messages: &[Message]) -> Vec<Value> {
MessageContent::ToolResponse(tool_response) => {
if let Ok(result) = &tool_response.tool_result {
let text = result
.content
.iter()
.filter_map(|c| c.as_text().map(|t| t.text.clone()))
.collect::<Vec<_>>()
+2 -2
View File
@@ -215,9 +215,9 @@ impl LeadWorkerProvider {
if let Err(tool_error) = &tool_response.tool_result {
failure_indicators += 1;
tracing::debug!("Tool execution failure detected: {:?}", tool_error);
} else if let Ok(contents) = &tool_response.tool_result {
} else if let Ok(result) = &tool_response.tool_result {
// Check tool output for error indicators
if self.contains_error_indicators(contents) {
if self.contains_error_indicators(&result.content) {
failure_indicators += 1;
tracing::debug!("Tool output contains error indicators");
}
+3 -2
View File
@@ -343,8 +343,9 @@ pub fn convert_tool_messages_to_text(messages: &[Message]) -> Conversation {
has_tool_content = true;
// Convert tool response to text format
let text = match &res.tool_result {
Ok(contents) => {
let text_contents: Vec<String> = contents
Ok(result) => {
let text_contents: Vec<String> = result
.content
.iter()
.filter_map(|c| match c.deref() {
RawContent::Text(t) => Some(t.text.clone()),