mirror of
https://github.com/zed-industries/zed.git
synced 2026-10-19 11:04:06 +00:00
agent: Improve error messages when missing parameters (#65245)
See #62142 Release Notes: - Improved tool call response error messages when an invalid or incomplete response is given by the model Co-authored-by: Tanner Hobson <thobson125@gmail.com>
This commit is contained in:
parent
c3ab5564f8
commit
6ec43d6319
2 changed files with 88 additions and 6 deletions
|
|
@ -9413,6 +9413,88 @@ async fn test_mid_turn_model_and_settings_refresh(cx: &mut TestAppContext) {
|
|||
assert!(model_b_completions[0].thinking_allowed);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_recv_returns_serde_error_not_generic_message(_cx: &mut TestAppContext) {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ToolWithRequiredFields {
|
||||
_command: String,
|
||||
_cd: String,
|
||||
}
|
||||
|
||||
let (mut sender, input): (ToolInputSender, ToolInput<ToolWithRequiredFields>) =
|
||||
ToolInput::test();
|
||||
|
||||
sender.send_full(json!({"_command": "ls"}));
|
||||
|
||||
let error = input
|
||||
.recv()
|
||||
.await
|
||||
.expect_err("should fail with missing field");
|
||||
let error_message = error.to_string();
|
||||
|
||||
assert!(
|
||||
error_message.contains("missing field"),
|
||||
"Expected serde error about missing field, got: {error_message}"
|
||||
);
|
||||
assert!(
|
||||
!error_message.contains("tool input was not fully received"),
|
||||
"Should not contain generic error message, got: {error_message}"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_next_returns_serde_error_for_streaming_tools(_cx: &mut TestAppContext) {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct StreamingToolInput {
|
||||
_text: String,
|
||||
_count: u32,
|
||||
}
|
||||
|
||||
let (mut sender, mut input): (ToolInputSender, ToolInput<StreamingToolInput>) =
|
||||
ToolInput::test();
|
||||
|
||||
sender.send_partial(json!({"_text": "hello"}));
|
||||
sender.send_full(json!({"_text": "hello"}));
|
||||
|
||||
let partial = input.next().await.expect("partial should succeed");
|
||||
assert!(matches!(partial, ToolInputPayload::Partial(_)));
|
||||
|
||||
let error_message = input
|
||||
.next()
|
||||
.await
|
||||
.err()
|
||||
.expect("full with missing field should fail")
|
||||
.to_string();
|
||||
|
||||
assert!(
|
||||
error_message.contains("missing field"),
|
||||
"Expected serde error about missing field, got: {error_message}"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_recv_still_reports_channel_closed_when_no_data(_cx: &mut TestAppContext) {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct AnyInput {
|
||||
_value: String,
|
||||
}
|
||||
|
||||
let (sender, input): (ToolInputSender, ToolInput<AnyInput>) = ToolInput::test();
|
||||
|
||||
drop(sender);
|
||||
|
||||
let error = input
|
||||
.recv()
|
||||
.await
|
||||
.expect_err("should fail when channel closes");
|
||||
let error_message = error.to_string();
|
||||
|
||||
assert!(
|
||||
error_message.contains("tool input was not fully received"),
|
||||
"Expected channel-closed error, got: {error_message}"
|
||||
);
|
||||
}
|
||||
|
||||
const SUBAGENT_CONTEXT_LIMIT_WARNING: &str = "The agent is nearing the end of its context window and has been stopped. You can prompt the thread again to have the agent wrap up or hand off its work.";
|
||||
|
||||
struct SubagentCompactionTest {
|
||||
|
|
|
|||
|
|
@ -5092,16 +5092,16 @@ impl<T: DeserializeOwned> ToolInput<T> {
|
|||
/// Wait for the final deserialized input, ignoring all partial updates.
|
||||
/// Non-streaming tools can use this to wait until the whole input is available.
|
||||
pub async fn recv(mut self) -> Result<T> {
|
||||
while let Ok(value) = self.next().await {
|
||||
match value {
|
||||
ToolInputPayload::Full(value) => return Ok(value),
|
||||
ToolInputPayload::Partial(_) => {}
|
||||
ToolInputPayload::InvalidJson { error_message } => {
|
||||
loop {
|
||||
match self.next().await {
|
||||
Ok(ToolInputPayload::Full(value)) => return Ok(value),
|
||||
Ok(ToolInputPayload::Partial(_)) => {}
|
||||
Ok(ToolInputPayload::InvalidJson { error_message }) => {
|
||||
return Err(anyhow!(error_message));
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Err(anyhow!("tool input was not fully received"))
|
||||
}
|
||||
|
||||
pub async fn next(&mut self) -> Result<ToolInputPayload<T>> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue