From 5fff8f38fcfbf1156481e7fd1cbdd4d04c8a7b84 Mon Sep 17 00:00:00 2001 From: Ben Navetta Date: Sat, 2 May 2026 19:56:05 +0000 Subject: [PATCH 1/2] Add agent UID flag for cloud runs Co-Authored-By: Oz --- app/src/ai/agent_sdk/ambient.rs | 1 + app/src/ai/agent_sdk/mcp_config_tests.rs | 1 + app/src/ai/ambient_agents/spawn_tests.rs | 2 ++ app/src/pane_group/pane/terminal_pane.rs | 1 + app/src/server/server_api/ai.rs | 6 +++++ app/src/server/server_api/ai_test.rs | 28 +++++++++++++++++++- app/src/terminal/view/ambient_agent/model.rs | 1 + crates/warp_cli/src/agent.rs | 5 ++++ crates/warp_cli/src/lib_tests.rs | 23 ++++++++++++++++ 9 files changed, 67 insertions(+), 1 deletion(-) diff --git a/app/src/ai/agent_sdk/ambient.rs b/app/src/ai/agent_sdk/ambient.rs index 9da79dfac..5dab336fe 100644 --- a/app/src/ai/agent_sdk/ambient.rs +++ b/app/src/ai/agent_sdk/ambient.rs @@ -483,6 +483,7 @@ impl AmbientAgentRunner { (_, true) => Some(false), _ => None, }, + agent_identity_uid: args.agent_uid, skill, attachments, interactive: None, diff --git a/app/src/ai/agent_sdk/mcp_config_tests.rs b/app/src/ai/agent_sdk/mcp_config_tests.rs index 77879672a..ec95d7e5c 100644 --- a/app/src/ai/agent_sdk/mcp_config_tests.rs +++ b/app/src/ai/agent_sdk/mcp_config_tests.rs @@ -278,6 +278,7 @@ fn serializes_mcp_servers_as_object_not_string() { }), title: None, team: None, + agent_identity_uid: None, skill: None, attachments: vec![], interactive: None, diff --git a/app/src/ai/ambient_agents/spawn_tests.rs b/app/src/ai/ambient_agents/spawn_tests.rs index d42083af8..f38c84920 100644 --- a/app/src/ai/ambient_agents/spawn_tests.rs +++ b/app/src/ai/ambient_agents/spawn_tests.rs @@ -335,6 +335,7 @@ async fn poll_stops_on_terminal_failure_like_state() { config: None, title: None, team: None, + agent_identity_uid: None, skill: None, attachments: vec![], interactive: None, @@ -451,6 +452,7 @@ async fn poll_for_session_join_info_waits_until_link_is_available() { config: None, title: None, team: None, + agent_identity_uid: None, skill: None, attachments: vec![], interactive: None, diff --git a/app/src/pane_group/pane/terminal_pane.rs b/app/src/pane_group/pane/terminal_pane.rs index 3f5d6660d..3a551a271 100644 --- a/app/src/pane_group/pane/terminal_pane.rs +++ b/app/src/pane_group/pane/terminal_pane.rs @@ -1391,6 +1391,7 @@ fn handle_terminal_view_event( }), title: (!title.is_empty()).then_some(title), team: None, + agent_identity_uid: None, skill: None, attachments: vec![], interactive: Some(true), diff --git a/app/src/server/server_api/ai.rs b/app/src/server/server_api/ai.rs index 0b3fe2c28..673504d58 100644 --- a/app/src/server/server_api/ai.rs +++ b/app/src/server/server_api/ai.rs @@ -207,6 +207,12 @@ pub struct SpawnAgentRequest { pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub team: Option, + /// Agent identity UID to use as the execution principal for the run. + #[serde( + rename = "agent_identity_uid", + skip_serializing_if = "Option::is_none" + )] + pub agent_identity_uid: Option, /// Use a Claude-compatible skill as the base prompt. /// Format: "repo:skill_name" or just "skill_name". /// The skill is resolved at runtime in the agent environment. diff --git a/app/src/server/server_api/ai_test.rs b/app/src/server/server_api/ai_test.rs index d38aaea21..929b7f0c8 100644 --- a/app/src/server/server_api/ai_test.rs +++ b/app/src/server/server_api/ai_test.rs @@ -8,7 +8,7 @@ use super::{ build_list_agent_runs_url, build_run_followup_url, AgentMessageHeader, AgentRunEvent, AgentSource, AmbientAgentTaskState, Artifact, ArtifactDownloadResponse, ArtifactType, ExecutionLocation, ListRunsResponse, ReadAgentMessageResponse, RunFollowupRequest, RunSortBy, - RunSortOrder, TaskListFilter, + RunSortOrder, SpawnAgentRequest, TaskListFilter, UserQueryMode, }; use crate::notebooks::NotebookId; @@ -33,6 +33,32 @@ fn ambient_agent_headers_for_task_overrides_existing_cloud_agent_header() { ); } +#[test] +fn spawn_agent_request_serializes_agent_uid_as_agent_identity_uid() { + let request = SpawnAgentRequest { + prompt: "hello".to_string(), + mode: UserQueryMode::Normal, + config: None, + title: None, + team: None, + agent_identity_uid: Some("agent_123".to_string()), + skill: None, + attachments: vec![], + interactive: None, + parent_run_id: None, + runtime_skills: vec![], + referenced_attachments: vec![], + }; + + let value = serde_json::to_value(&request).unwrap(); + + assert_eq!( + value.get("agent_identity_uid").and_then(|v| v.as_str()), + Some("agent_123") + ); + assert!(value.get("agent_uid").is_none()); +} + #[test] fn test_deserialize_file_artifact_download_response() { let json = r#"{ diff --git a/app/src/terminal/view/ambient_agent/model.rs b/app/src/terminal/view/ambient_agent/model.rs index dc2361f78..93fa30aeb 100644 --- a/app/src/terminal/view/ambient_agent/model.rs +++ b/app/src/terminal/view/ambient_agent/model.rs @@ -576,6 +576,7 @@ impl AmbientAgentViewModel { config, title: None, team: None, + agent_identity_uid: None, skill: None, attachments, interactive: None, diff --git a/crates/warp_cli/src/agent.rs b/crates/warp_cli/src/agent.rs index 5f95e5ca3..387224c5a 100644 --- a/crates/warp_cli/src/agent.rs +++ b/crates/warp_cli/src/agent.rs @@ -435,6 +435,11 @@ pub struct RunCloudArgs { #[command(flatten)] pub scope: ObjectScope, + /// Agent UID to use as the execution principal for this run. + /// + /// This is only valid for team-owned runs. + #[arg(long = "agent", value_name = "UID")] + pub agent_uid: Option, /// Where this job should be hosted. Setting "warp" runs it on Warp's infrastructure. Any other /// value is treated is a self-hosted job and the value will be matched with the self-hosted diff --git a/crates/warp_cli/src/lib_tests.rs b/crates/warp_cli/src/lib_tests.rs index f64ec3a18..023c46813 100644 --- a/crates/warp_cli/src/lib_tests.rs +++ b/crates/warp_cli/src/lib_tests.rs @@ -275,6 +275,29 @@ fn agent_run_cloud_accepts_model() { assert_eq!(run_args.model.model.as_deref(), Some("gpt-4o")); } +#[test] +fn agent_run_cloud_accepts_agent_flag() { + let args = Args::try_parse_from([ + "warp", + "agent", + "run-cloud", + "--prompt", + "hello", + "--agent", + "agent_123", + ]) + .unwrap(); + + let Some(Command::CommandLine(boxed_cmd)) = args.command else { + panic!("Expected `warp agent run-cloud` command"); + }; + let CliCommand::Agent(AgentCommand::RunCloud(run_args)) = boxed_cmd.as_ref() else { + panic!("Expected `warp agent run-cloud` command"); + }; + + assert_eq!(run_args.agent_uid.as_deref(), Some("agent_123")); +} + #[test] fn agent_run_cloud_accepts_mcp() { let uuid = uuid::Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); From 0ae477da82d13b869a073b2417b92d7e72512673 Mon Sep 17 00:00:00 2001 From: Ben Navetta Date: Sat, 2 May 2026 21:52:25 +0100 Subject: [PATCH 2/2] Tweak CLI help --- crates/warp_cli/src/agent.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/warp_cli/src/agent.rs b/crates/warp_cli/src/agent.rs index 387224c5a..29d24234f 100644 --- a/crates/warp_cli/src/agent.rs +++ b/crates/warp_cli/src/agent.rs @@ -435,9 +435,12 @@ pub struct RunCloudArgs { #[command(flatten)] pub scope: ObjectScope, - /// Agent UID to use as the execution principal for this run. + + /// UID of the agent to execute this run as. /// - /// This is only valid for team-owned runs. + /// This will apply the agent's configuration, such + /// as its skills and base model, and attribute + /// credit usage back to the agent. #[arg(long = "agent", value_name = "UID")] pub agent_uid: Option,