diff --git a/crates/agent/src/tools/spawn_agent_tool.rs b/crates/agent/src/tools/spawn_agent_tool.rs index 9fa26bf29ad48f..bc871a2f2c7171 100644 --- a/crates/agent/src/tools/spawn_agent_tool.rs +++ b/crates/agent/src/tools/spawn_agent_tool.rs @@ -4,7 +4,7 @@ use anyhow::Result; use gpui::{App, SharedString, Task}; use language_model::LanguageModelToolResultContent; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use std::rc::Rc; use std::sync::Arc; @@ -41,11 +41,31 @@ pub struct SpawnAgentToolInput { pub label: String, /// The prompt for the agent. For new sessions, include full context needed for the task. For follow-ups (with session_id), you can rely on the agent already having the previous message. pub message: String, - /// Session ID of an existing agent session to continue instead of creating a new one. - #[serde(default)] + /// Session ID of an existing agent session to continue instead of creating a new one. Omit to create a new agent. + #[serde(default, deserialize_with = "deserialize_session_id")] pub session_id: Option, } +fn deserialize_session_id<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let Some(value) = Option::::deserialize(deserializer)? else { + return Ok(None); + }; + + if value + .as_str() + .is_some_and(|session_id| session_id.trim().is_empty()) + { + return Ok(None); + } + + serde_json::from_value(value) + .map(Some) + .map_err(serde::de::Error::custom) +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] #[serde(rename_all = "snake_case")] @@ -254,3 +274,38 @@ impl AgentTool for SpawnAgentTool { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn deserializes_blank_session_id_as_absent() { + for session_id in [json!(null), json!(""), json!(" ")] { + let input: SpawnAgentToolInput = serde_json::from_value(json!({ + "label": "label", + "message": "message", + "session_id": session_id, + })) + .unwrap(); + + assert!(input.session_id.is_none()); + } + + let input: SpawnAgentToolInput = serde_json::from_value(json!({ + "label": "label", + "message": "message", + })) + .unwrap(); + assert!(input.session_id.is_none()); + + let input: SpawnAgentToolInput = serde_json::from_value(json!({ + "label": "label", + "message": "message", + "session_id": "existing-session", + })) + .unwrap(); + assert_eq!(input.session_id.unwrap().to_string(), "existing-session"); + } +}