Skip to content

Commit 98aaece

Browse files
authored
Add auth secret dropdown picker for non-Oz orchestration (#10885)
1 parent 7225e82 commit 98aaece

19 files changed

Lines changed: 530 additions & 24 deletions

app/src/ai/agent/api/convert_from.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ fn convert_run_agents(run_agents: api::RunAgents) -> AIAgentActionType {
154154
})
155155
.collect(),
156156
plan_id,
157+
// Auth secret is a client-side dispatch concern populated by the
158+
// confirmation card from `CloudAgentSettings.last_selected_auth_secret`
159+
// before Accept. The proto does not carry it.
160+
harness_auth_secret_name: None,
157161
})
158162
}
159163

@@ -175,6 +179,9 @@ fn convert_start_agent_v2_execution_mode(
175179
harness_type: convert_start_agent_v2_harness_type(remote.harness)
176180
.unwrap_or_default(),
177181
title: remote.title,
182+
// Auth secret is plumbed client-side via `RunAgentsRequest`;
183+
// StartAgentV2 from the server never carries it.
184+
auth_secret_name: None,
178185
}
179186
}
180187
Some(api::start_agent_v2::execution_mode::Mode::Local(local)) => {

app/src/ai/agent/api/convert_from_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ fn converts_remote_start_agent_with_environment_id() {
520520
worker_host: String::new(),
521521
harness_type: String::new(),
522522
title: String::new(),
523+
auth_secret_name: None,
523524
}
524525
);
525526
assert_eq!(lifecycle_subscription, None);
@@ -560,6 +561,7 @@ fn converts_remote_start_agent_v2_with_skill_references() {
560561
worker_host: "worker-host".to_string(),
561562
harness_type: "claude-code".to_string(),
562563
title: "Remote child".to_string(),
564+
auth_secret_name: None,
563565
}
564566
);
565567
assert_eq!(lifecycle_subscription, None);

app/src/ai/blocklist/action_model/execute/run_agents.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ impl RunAgentsExecutor {
119119
skills,
120120
agent_run_configs,
121121
base_prompt,
122+
harness_auth_secret_name,
122123
..
123124
} = request;
124125

@@ -130,6 +131,7 @@ impl RunAgentsExecutor {
130131
&harness_type,
131132
&model_id,
132133
&skills,
134+
harness_auth_secret_name.as_deref(),
133135
cfg,
134136
) {
135137
Ok(mode) => mode,
@@ -368,11 +370,16 @@ pub fn compose_run_agents_child_prompt(base_prompt: &str, per_agent_prompt: &str
368370
/// Translates run-wide config into a per-child
369371
/// [`StartAgentExecutionMode`]. Returns `Err` for rejected
370372
/// combinations (e.g. OpenCode+Remote).
373+
///
374+
/// `run_auth_secret_name` is the managed-secret name the orchestration UI
375+
/// resolved for the run-wide harness; only Remote mode currently consumes
376+
/// it (Local children inherit auth from the user's shell environment).
371377
pub fn run_agents_to_start_agent_mode(
372378
run_execution_mode: &RunAgentsExecutionMode,
373379
run_harness_type: &str,
374380
run_model_id: &str,
375381
run_skills: &[SkillReference],
382+
run_auth_secret_name: Option<&str>,
376383
cfg: &RunAgentsAgentRunConfig,
377384
) -> Result<StartAgentExecutionMode, String> {
378385
match run_execution_mode {
@@ -412,6 +419,9 @@ pub fn run_agents_to_start_agent_mode(
412419
worker_host: worker_host.clone(),
413420
harness_type: run_harness_type.to_string(),
414421
title: cfg.title.clone(),
422+
auth_secret_name: run_auth_secret_name
423+
.map(str::to_string)
424+
.filter(|s| !s.trim().is_empty()),
415425
})
416426
}
417427
}

app/src/ai/blocklist/action_model/execute/start_agent.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ impl StartAgentExecutor {
374374
worker_host,
375375
harness_type,
376376
title,
377+
auth_secret_name,
377378
} => {
378379
if !FeatureFlag::OrchestrationV2.is_enabled() {
379380
return ActionExecution::Sync(AIAgentActionResultType::StartAgent(
@@ -430,6 +431,7 @@ impl StartAgentExecutor {
430431
worker_host,
431432
harness_type,
432433
title,
434+
auth_secret_name,
433435
},
434436
Some(parent_run_id),
435437
)

app/src/ai/blocklist/action_model/execute/start_agent_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ fn execute_returns_error_when_remote_opencode_harness_is_requested() {
643643
worker_host: String::new(),
644644
harness_type: "opencode".to_string(),
645645
title: String::new(),
646+
auth_secret_name: None,
646647
},
647648
);
648649

app/src/ai/blocklist/block/view_impl/orchestration_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn start_agent_copy_uses_remote_labels_for_remote_children() {
7777
worker_host: String::new(),
7878
harness_type: String::new(),
7979
title: String::new(),
80+
auth_secret_name: None,
8081
};
8182

8283
assert_eq!(start_agent_success_suffix(&execution_mode), " remotely.");

app/src/ai/blocklist/block_tests.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ fn remote_arm_propagates_skills_into_skill_references() {
156156
"oz",
157157
"auto",
158158
&skills,
159+
None,
159160
&agent_cfg(),
160161
)
161162
.expect("Remote+oz must convert");
@@ -167,6 +168,7 @@ fn remote_arm_propagates_skills_into_skill_references() {
167168
model_id,
168169
computer_use_enabled,
169170
title,
171+
auth_secret_name,
170172
} = mode
171173
else {
172174
panic!("expected Remote start-agent mode");
@@ -178,6 +180,7 @@ fn remote_arm_propagates_skills_into_skill_references() {
178180
assert_eq!(model_id, "auto");
179181
assert!(computer_use_enabled);
180182
assert_eq!(title, "Child");
183+
assert_eq!(auth_secret_name, None);
181184
}
182185

183186
#[test]
@@ -191,6 +194,7 @@ fn remote_arm_with_empty_skills_propagates_empty_vec() {
191194
"claude",
192195
"auto",
193196
&[],
197+
None,
194198
&agent_cfg(),
195199
)
196200
.expect("Remote+claude must convert");
@@ -214,12 +218,76 @@ fn remote_arm_rejects_opencode() {
214218
"opencode",
215219
"auto",
216220
&[],
221+
None,
217222
&agent_cfg(),
218223
)
219224
.expect_err("Remote+opencode must be rejected");
220225
assert!(err.to_lowercase().contains("opencode"));
221226
}
222227

228+
#[test]
229+
fn remote_arm_propagates_claude_auth_secret_into_mode() {
230+
let mode = run_agents_to_start_agent_mode(
231+
&RunAgentsExecutionMode::Remote {
232+
environment_id: "env-1".to_string(),
233+
worker_host: "warp".to_string(),
234+
computer_use_enabled: false,
235+
},
236+
"claude",
237+
"auto",
238+
&[],
239+
Some("my-claude-key"),
240+
&agent_cfg(),
241+
)
242+
.expect("Remote+claude must convert");
243+
let StartAgentExecutionMode::Remote {
244+
auth_secret_name, ..
245+
} = mode
246+
else {
247+
panic!("expected Remote start-agent mode");
248+
};
249+
assert_eq!(auth_secret_name.as_deref(), Some("my-claude-key"));
250+
}
251+
252+
#[test]
253+
fn remote_arm_filters_whitespace_auth_secret_name_to_none() {
254+
let mode = run_agents_to_start_agent_mode(
255+
&RunAgentsExecutionMode::Remote {
256+
environment_id: "env-1".to_string(),
257+
worker_host: "warp".to_string(),
258+
computer_use_enabled: false,
259+
},
260+
"codex",
261+
"auto",
262+
&[],
263+
Some(" "),
264+
&agent_cfg(),
265+
)
266+
.expect("Remote+codex must convert");
267+
let StartAgentExecutionMode::Remote {
268+
auth_secret_name, ..
269+
} = mode
270+
else {
271+
panic!("expected Remote start-agent mode");
272+
};
273+
assert_eq!(auth_secret_name, None);
274+
}
275+
276+
#[test]
277+
fn local_arm_ignores_auth_secret_name() {
278+
let mode = run_agents_to_start_agent_mode(
279+
&RunAgentsExecutionMode::Local,
280+
"claude",
281+
"auto",
282+
&[],
283+
Some("my-claude-key"),
284+
&agent_cfg(),
285+
)
286+
.expect("Local+claude must convert");
287+
// Local children don't carry an auth_secret_name field.
288+
assert!(matches!(mode, StartAgentExecutionMode::Local { .. }));
289+
}
290+
223291
#[test]
224292
fn should_show_agent_mode_ask_user_question_speedbump_defaults_to_true() {
225293
App::test((), |mut app| async move {

0 commit comments

Comments
 (0)