From 0999dffdd30813df4cc979c9bb0cf3e886715b88 Mon Sep 17 00:00:00 2001 From: nevo-ts Date: Mon, 13 Jul 2026 13:05:57 +0300 Subject: [PATCH 1/3] Handle blank spawn_agent session IDs --- crates/agent/src/tools/spawn_agent_tool.rs | 61 ++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/crates/agent/src/tools/spawn_agent_tool.rs b/crates/agent/src/tools/spawn_agent_tool.rs index 9fa26bf29ad48f..53f45a3e5939c3 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, pass null, or pass an empty string to create a new subagent. + #[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"); + } +} From 85f52de74df57aa6f85f32d95a0827757fdcd1c8 Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner Date: Fri, 24 Jul 2026 15:52:41 +0200 Subject: [PATCH 2/3] Update crates/agent/src/tools/spawn_agent_tool.rs --- crates/agent/src/tools/spawn_agent_tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/agent/src/tools/spawn_agent_tool.rs b/crates/agent/src/tools/spawn_agent_tool.rs index 53f45a3e5939c3..ad19a8713b7be2 100644 --- a/crates/agent/src/tools/spawn_agent_tool.rs +++ b/crates/agent/src/tools/spawn_agent_tool.rs @@ -41,7 +41,7 @@ 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. Omit, pass null, or pass an empty string to create a new subagent. + /// Session ID of an existing agent session to continue instead of creating a new one. Omit to create a new subagent. #[serde(default, deserialize_with = "deserialize_session_id")] pub session_id: Option, } From 31cad17f14cdc42fb4ac196ee44d6b8a80204e62 Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner Date: Fri, 24 Jul 2026 15:53:56 +0200 Subject: [PATCH 3/3] Apply suggestion from @bennetbo --- crates/agent/src/tools/spawn_agent_tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/agent/src/tools/spawn_agent_tool.rs b/crates/agent/src/tools/spawn_agent_tool.rs index ad19a8713b7be2..bc871a2f2c7171 100644 --- a/crates/agent/src/tools/spawn_agent_tool.rs +++ b/crates/agent/src/tools/spawn_agent_tool.rs @@ -41,7 +41,7 @@ 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. Omit to create a new subagent. + /// 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, }