agent: Better error messages when tool fails (#55616)
Does not actually seem useful to the LLM to include `Failed to receive tool input: ...` in the error message. We now only include the actual error. 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) - [ ] 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
8a8293b3bd
commit
193a8c75a3
21 files changed
+30
-93
No files matched your search
@@ -4063,14 +4063,8 @@ async fn test_streaming_tool_completes_when_llm_stream_ends_without_final_input(
|
||||
tool_use_id: tool_use.id.clone(),
|
||||
tool_name: tool_use.name,
|
||||
is_error: true,
|
||||
content: vec![
|
||||
"Failed to receive tool input: tool input was not fully received"
|
||||
.into(),
|
||||
],
|
||||
output: Some(
|
||||
"Failed to receive tool input: tool input was not fully received"
|
||||
.into()
|
||||
),
|
||||
content: vec!["tool input was not fully received".into(),],
|
||||
output: Some("tool input was not fully received".into()),
|
||||
}
|
||||
)],
|
||||
cache: true,
|
||||
|
||||
@@ -61,10 +61,7 @@ impl AgentTool for StreamingEchoTool {
|
||||
) -> Task<Result<String, String>> {
|
||||
let wait_until_complete_rx = self.wait_until_complete_rx.lock().unwrap().take();
|
||||
cx.spawn(async move |_cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
if let Some(rx) = wait_until_complete_rx {
|
||||
rx.await.ok();
|
||||
}
|
||||
@@ -127,7 +124,7 @@ impl AgentTool for StreamingJsonErrorContextTool {
|
||||
));
|
||||
}
|
||||
Err(error) => {
|
||||
return Err(format!("Failed to receive tool input: {error}"));
|
||||
return Err(error.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,10 +217,7 @@ impl AgentTool for EchoTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.spawn(async move |_cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
Ok(input.text)
|
||||
})
|
||||
}
|
||||
@@ -271,10 +265,7 @@ impl AgentTool for DelayTool {
|
||||
{
|
||||
let executor = cx.background_executor().clone();
|
||||
cx.foreground_executor().spawn(async move {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
executor.timer(Duration::from_millis(input.ms)).await;
|
||||
Ok("Ding".to_string())
|
||||
})
|
||||
@@ -311,10 +302,7 @@ impl AgentTool for ToolRequiringPermission {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let _input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let _input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let authorize = cx.update(|cx| {
|
||||
let context = crate::ToolPermissionContext::new(Self::NAME, vec![String::new()]);
|
||||
@@ -359,10 +347,7 @@ impl AgentTool for ToolRequiringPermission2 {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let _input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let _input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let authorize = cx.update(|cx| {
|
||||
let context = crate::ToolPermissionContext::new(Self::NAME, vec![String::new()]);
|
||||
@@ -404,10 +389,7 @@ impl AgentTool for InfiniteTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.foreground_executor().spawn(async move {
|
||||
let _input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let _input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
future::pending::<()>().await;
|
||||
unreachable!()
|
||||
})
|
||||
@@ -460,10 +442,7 @@ impl AgentTool for CancellationAwareTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.foreground_executor().spawn(async move {
|
||||
let _input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let _input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
// Wait for cancellation - this tool does nothing but wait to be cancelled
|
||||
event_stream.cancelled_by_user().await;
|
||||
self.was_cancelled.store(true, Ordering::SeqCst);
|
||||
@@ -519,10 +498,7 @@ impl AgentTool for WordListTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.spawn(async move |_cx| {
|
||||
let _input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let _input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
Ok("ok".to_string())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ impl AnyAgentTool for ContextServerTool {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(format!("Failed to receive tool input: {e}")))?;
|
||||
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
|
||||
authorize
|
||||
.await
|
||||
|
||||
@@ -88,10 +88,7 @@ impl AgentTool for CopyPathTool {
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
let project = self.project.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
let paths = vec![input.source_path.clone(), input.destination_path.clone()];
|
||||
let decision = cx.update(|cx| {
|
||||
decide_permission_for_paths(Self::NAME, &paths, &AgentSettings::get_global(cx))
|
||||
|
||||
@@ -77,10 +77,7 @@ impl AgentTool for CreateDirectoryTool {
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
let project = self.project.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
let decision = cx.update(|cx| {
|
||||
decide_permission_for_path(Self::NAME, &input.path, AgentSettings::get_global(cx))
|
||||
});
|
||||
|
||||
@@ -81,10 +81,7 @@ impl AgentTool for DeletePathTool {
|
||||
let project = self.project.clone();
|
||||
let action_log = self.action_log.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
let path = input.path;
|
||||
|
||||
let decision = cx.update(|cx| {
|
||||
|
||||
@@ -93,10 +93,7 @@ impl AgentTool for DiagnosticsTool {
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
let project = self.project.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
match input.path {
|
||||
Some(path) if !path.is_empty() => {
|
||||
|
||||
@@ -439,7 +439,7 @@ impl EditFileTool {
|
||||
},
|
||||
Err(error) => {
|
||||
return EditSessionResult::Failed {
|
||||
error: format!("Failed to receive tool input: {error}"),
|
||||
error: error.to_string(),
|
||||
session,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,10 +143,7 @@ impl AgentTool for FetchTool {
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
let http_client = self.http_client.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input: FetchToolInput = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input: FetchToolInput = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let authorize = cx.update(|cx| {
|
||||
let context =
|
||||
|
||||
@@ -128,7 +128,7 @@ impl AgentTool for FindPathTool {
|
||||
let project = self.project.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input.recv().await.map_err(|e| FindPathToolOutput::Error {
|
||||
error: format!("Failed to receive tool input: {e}"),
|
||||
error: e.to_string(),
|
||||
})?;
|
||||
|
||||
let search_paths_task = cx.update(|cx| search_paths(&input.glob, project, cx));
|
||||
|
||||
@@ -126,7 +126,7 @@ impl AgentTool for GrepTool {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let results = cx.update(|cx| {
|
||||
let path_style = project.read(cx).path_style(cx);
|
||||
|
||||
@@ -155,7 +155,7 @@ impl AgentTool for ListDirectoryTool {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Sometimes models will return these even though we tell it to give a path and not a glob.
|
||||
// When this happens, just list the root worktree directories.
|
||||
|
||||
@@ -104,7 +104,7 @@ impl AgentTool for MovePathTool {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
.map_err(|e| e.to_string())?;
|
||||
let paths = vec![input.source_path.clone(), input.destination_path.clone()];
|
||||
let decision = cx.update(|cx| {
|
||||
decide_permission_for_paths(Self::NAME, &paths, AgentSettings::get_global(cx))
|
||||
|
||||
@@ -55,10 +55,7 @@ impl AgentTool for NowTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String, String>> {
|
||||
cx.spawn(async move |_cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
let now = match input.timezone {
|
||||
Timezone::Utc => Utc::now().to_rfc3339(),
|
||||
Timezone::Local => Local::now().to_rfc3339(),
|
||||
|
||||
@@ -67,10 +67,7 @@ impl AgentTool for OpenTool {
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
let project = self.project.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
// If path_or_url turns out to be a path in the project, make it absolute.
|
||||
let (abs_path, initial_title) = cx.update(|cx| {
|
||||
|
||||
@@ -75,10 +75,7 @@ impl AgentTool for RestoreFileFromDiskTool {
|
||||
let project = self.project.clone();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
// Check for any immediate deny before doing async work.
|
||||
for path in &input.paths {
|
||||
|
||||
@@ -72,10 +72,7 @@ impl AgentTool for SaveFileTool {
|
||||
let project = self.project.clone();
|
||||
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
// Check for any immediate deny before doing async work.
|
||||
for path in &input.paths {
|
||||
|
||||
@@ -137,7 +137,7 @@ impl AgentTool for SpawnAgentTool {
|
||||
.await
|
||||
.map_err(|e| SpawnAgentToolOutput::Error {
|
||||
session_id: None,
|
||||
error: format!("Failed to receive tool input: {e}"),
|
||||
error: e.to_string(),
|
||||
session_info: None,
|
||||
})?;
|
||||
|
||||
|
||||
@@ -89,10 +89,7 @@ impl AgentTool for TerminalTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
cx.spawn(async move |cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
let (working_dir, authorize) = cx.update(|cx| {
|
||||
let working_dir =
|
||||
|
||||
@@ -90,10 +90,7 @@ impl AgentTool for UpdatePlanTool {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Self::Output, Self::Output>> {
|
||||
cx.spawn(async move |_cx| {
|
||||
let input = input
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to receive tool input: {e}"))?;
|
||||
let input = input.recv().await.map_err(|e| e.to_string())?;
|
||||
|
||||
event_stream.update_plan(Self::to_plan(input));
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ impl AgentTool for WebSearchTool {
|
||||
.recv()
|
||||
.await
|
||||
.map_err(|e| WebSearchToolOutput::Error {
|
||||
error: format!("Failed to receive tool input: {e}"),
|
||||
error: e.to_string(),
|
||||
})?;
|
||||
|
||||
let authorize = cx.update(|cx| {
|
||||
|
||||
Reference in new issue
Block a user