Add per-turn cyber access program selection (#40687)

## What changed

- Add the experimental `turn/start.cyberAccessProgram` option with `standard`,
  `daybreakBlue`, and `daybreakRed` values.
- Forward the selection as `access_programs.cyber` on Responses, WebSocket,
  and remote-compaction requests made with ChatGPT authentication, while
  omitting it for API-key and custom-provider requests.
- Preserve the per-turn selection across recovery, compaction, and child-agent
  turns without making it a persistent thread setting.

## Testing

- Cover app-server forwarding, authentication boundaries, WebSocket reuse,
  turn recovery, compaction, and child-agent inheritance.

GitOrigin-RevId: d2eb468f365b2214c5099bc21741cf30f8bd2eb5
This commit is contained in:
faizan-oai authored and copyberry committed 2026-08-25 19:54:52 +00:00
1 parent a6e63f9f32
commit 94967e03e5
72 files changed
+1323 -273

No files matched your search

+14 -12
View File
@@ -111,9 +111,11 @@ fn captured_op_matches(actual: &(ThreadId, Op), expected: &(ThreadId, Op)) -> bo
(
Op::InterAgentCommunication {
communication: actual,
..
},
Op::InterAgentCommunication {
communication: expected,
..
},
) => actual == expected,
_ => false,
@@ -450,8 +452,7 @@ async fn send_input_errors_when_manager_dropped() {
text: "hello".to_string(),
text_elements: Vec::new(),
}],
/*parent_turn_id*/ None,
/*root_turn_id*/ None,
Default::default(),
)
.await
.expect_err("send_input should fail without a manager");
@@ -576,8 +577,7 @@ async fn send_input_errors_when_thread_missing() {
text: "hello".to_string(),
text_elements: Vec::new(),
}],
/*parent_turn_id*/ None,
/*root_turn_id*/ None,
Default::default(),
)
.await
.expect_err("send_input should fail for missing thread");
@@ -650,8 +650,7 @@ async fn send_input_submits_user_message() {
text: "hello from tests".to_string(),
text_elements: Vec::new(),
}],
/*parent_turn_id*/ None,
/*root_turn_id*/ None,
Default::default(),
)
.await
.expect("send_input should succeed");
@@ -677,8 +676,7 @@ async fn send_inter_agent_communication_without_turn_queues_message_without_trig
thread_id,
communication.clone(),
AgentCommunicationContext::new(AgentCommunicationKind::Message, ThreadId::new()),
/*parent_turn_id*/ None,
/*root_turn_id*/ None,
Default::default(),
)
.await
.expect("send_inter_agent_communication should succeed");
@@ -688,6 +686,7 @@ async fn send_inter_agent_communication_without_turn_queues_message_without_trig
thread_id,
Op::InterAgentCommunication {
communication: communication.clone(),
start_options: Default::default(),
},
);
let captured = harness
@@ -959,14 +958,16 @@ async fn check_v2_agent_reload(route: V2ReloadRoute) {
spawned_agent.thread_id,
communication.clone(),
AgentCommunicationContext::new(AgentCommunicationKind::Message, ThreadId::new()),
/*parent_turn_id*/ None,
/*root_turn_id*/ None,
Default::default(),
)
.await
.expect("send_inter_agent_communication should succeed after reload");
let expected = (
spawned_agent.thread_id,
Op::InterAgentCommunication { communication },
Op::InterAgentCommunication {
communication,
start_options: Default::default(),
},
);
let captured = harness
.manager
@@ -3129,7 +3130,7 @@ async fn multi_agent_v2_completion_ignores_dead_direct_parent() {
thread_id == worker_thread_id
&& matches!(
op,
Op::InterAgentCommunication { communication }
Op::InterAgentCommunication { communication, .. }
if communication.author == tester_path
&& communication.recipient == worker_path
&& communication.content == "done"
@@ -3216,6 +3217,7 @@ async fn multi_agent_v2_completion_queues_message_for_direct_parent() {
expected_message.clone(),
/*trigger_turn*/ false,
),
start_options: Default::default(),
},
);