Implement tool result conversion for anyhow errors (#55001)
Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - N/A
This commit is contained in:
1 parent
6e8b8b2fbd
commit
418e5fe615
3 files changed
+34
-22
No files matched your search
+16
-13
@@ -2448,9 +2448,10 @@ impl Thread {
|
||||
.collect();
|
||||
(false, output)
|
||||
} else {
|
||||
let output = AgentToolOutput::from_error(
|
||||
let output = anyhow::anyhow!(
|
||||
"Attempted to read an image, but this model doesn't support it.",
|
||||
);
|
||||
)
|
||||
.into();
|
||||
(true, output)
|
||||
}
|
||||
} else {
|
||||
@@ -3426,14 +3427,15 @@ pub struct AgentToolOutput {
|
||||
pub raw_output: serde_json::Value,
|
||||
}
|
||||
|
||||
impl AgentToolOutput {
|
||||
pub fn from_error(message: impl Into<String>) -> Self {
|
||||
let message = message.into();
|
||||
let llm_output = vec![LanguageModelToolResultContent::Text(Arc::from(
|
||||
message.as_str(),
|
||||
))];
|
||||
impl From<anyhow::Error> for AgentToolOutput {
|
||||
fn from(error: anyhow::Error) -> Self {
|
||||
let llm_output = vec![error.into()];
|
||||
let raw_output = serde_json::to_value(&llm_output).unwrap_or_else(|e| {
|
||||
log::error!("Failed to serialize tool output: {e}");
|
||||
serde_json::Value::Null
|
||||
});
|
||||
Self {
|
||||
raw_output: serde_json::Value::String(message),
|
||||
raw_output,
|
||||
llm_output,
|
||||
}
|
||||
}
|
||||
@@ -3512,12 +3514,13 @@ where
|
||||
let task = self.0.clone().run(tool_input, event_stream, cx);
|
||||
cx.spawn(async move |_cx| match task.await {
|
||||
Ok(output) => {
|
||||
let raw_output = serde_json::to_value(&output).map_err(|e| {
|
||||
AgentToolOutput::from_error(format!("Failed to serialize tool output: {e}"))
|
||||
})?;
|
||||
let raw_output = serde_json::to_value(&output).unwrap_or_else(|e| {
|
||||
log::error!("Failed to serialize tool output: {e}");
|
||||
serde_json::Value::Null
|
||||
});
|
||||
Ok(AgentToolOutput {
|
||||
llm_output: vec![output.into()],
|
||||
raw_output,
|
||||
llm_output: vec![output.into()],
|
||||
})
|
||||
}
|
||||
Err(error_output) => {
|
||||
|
||||
@@ -337,7 +337,7 @@ impl AnyAgentTool for ContextServerTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<AgentToolOutput, AgentToolOutput>> {
|
||||
let Some(server) = self.store.read(cx).get_running_server(&self.server_id) else {
|
||||
return Task::ready(Err(AgentToolOutput::from_error("Context server not found")));
|
||||
return Task::ready(Err(anyhow::anyhow!("Context server not found").into()));
|
||||
};
|
||||
let tool_name = self.tool.name.clone();
|
||||
let tool_id = mcp_tool_id(&self.server_id.0, &self.tool.name);
|
||||
@@ -347,14 +347,17 @@ impl AnyAgentTool for ContextServerTool {
|
||||
event_stream.authorize_third_party_tool(initial_title, tool_id, display_name, cx);
|
||||
|
||||
cx.spawn(async move |_cx| {
|
||||
let input = input.recv().await.map_err(|e| {
|
||||
AgentToolOutput::from_error(format!("Failed to receive tool input: {e}"))
|
||||
})?;
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(format!("Failed to receive tool input: {e}")))?;
|
||||
|
||||
authorize.await.map_err(|e| AgentToolOutput::from_error(e.to_string()))?;
|
||||
authorize
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
|
||||
let Some(protocol) = server.client() else {
|
||||
return Err(AgentToolOutput::from_error("Context server not initialized"));
|
||||
return Err(anyhow::anyhow!("Context server not initialized").into());
|
||||
};
|
||||
|
||||
let arguments = if let serde_json::Value::Object(map) = input {
|
||||
@@ -378,16 +381,16 @@ impl AnyAgentTool for ContextServerTool {
|
||||
);
|
||||
|
||||
let response = futures::select! {
|
||||
response = request.fuse() => response.map_err(|e| AgentToolOutput::from_error(e.to_string()))?,
|
||||
response = request.fuse() => response?,
|
||||
_ = event_stream.cancelled_by_user().fuse() => {
|
||||
return Err(AgentToolOutput::from_error("MCP tool cancelled by user"));
|
||||
return Err(anyhow::anyhow!("MCP tool cancelled by user").into());
|
||||
}
|
||||
};
|
||||
|
||||
if response.is_error == Some(true) {
|
||||
let error_message: String =
|
||||
response.content.iter().filter_map(|c| c.text()).collect();
|
||||
return Err(AgentToolOutput::from_error(error_message));
|
||||
return Err(anyhow::anyhow!(error_message).into());
|
||||
}
|
||||
|
||||
let mut llm_output = Vec::new();
|
||||
|
||||
@@ -273,6 +273,12 @@ impl From<String> for LanguageModelToolResultContent {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for LanguageModelToolResultContent {
|
||||
fn from(error: anyhow::Error) -> Self {
|
||||
Self::Text(Arc::from(error.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LanguageModelImage> for LanguageModelToolResultContent {
|
||||
fn from(image: LanguageModelImage) -> Self {
|
||||
Self::Image(image)
|
||||
|
||||
Reference in new issue
Block a user