mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
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:
@@ -8,6 +8,7 @@ use codex_protocol::protocol::RateLimitSnapshot;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TurnModerationMetadataEvent;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_protocol::turn_input::CyberAccessProgram;
|
||||
use futures::Stream;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
@@ -23,6 +24,24 @@ use tokio::sync::mpsc;
|
||||
pub const WS_REQUEST_HEADER_TRACEPARENT_CLIENT_METADATA_KEY: &str = "ws_request_header_traceparent";
|
||||
pub const WS_REQUEST_HEADER_TRACESTATE_CLIENT_METADATA_KEY: &str = "ws_request_header_tracestate";
|
||||
|
||||
/// Explicit per-request access selection using the Responses API wire values.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
|
||||
pub struct AccessPrograms {
|
||||
cyber: &'static str,
|
||||
}
|
||||
|
||||
impl From<CyberAccessProgram> for AccessPrograms {
|
||||
fn from(program: CyberAccessProgram) -> Self {
|
||||
Self {
|
||||
cyber: match program {
|
||||
CyberAccessProgram::Standard => "standard",
|
||||
CyberAccessProgram::DaybreakBlue => "daybreak_blue",
|
||||
CyberAccessProgram::DaybreakRed => "daybreak_red",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Canonical input payload for the compaction endpoint.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct CompactionInput<'a> {
|
||||
@@ -41,6 +60,8 @@ pub struct CompactionInput<'a> {
|
||||
pub prompt_cache_key: Option<&'a str>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub text: Option<TextControls>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub access_programs: Option<AccessPrograms>,
|
||||
}
|
||||
|
||||
/// Canonical input payload for the memory summarize endpoint.
|
||||
@@ -272,6 +293,8 @@ pub struct ResponsesApiRequest {
|
||||
pub text: Option<TextControls>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_metadata: Option<HashMap<String, String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub access_programs: Option<AccessPrograms>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ResponsesApiRequest> for ResponseCreateWsRequest<'a> {
|
||||
@@ -294,6 +317,7 @@ impl<'a> From<&'a ResponsesApiRequest> for ResponseCreateWsRequest<'a> {
|
||||
text: request.text.as_ref(),
|
||||
generate: None,
|
||||
client_metadata: request.client_metadata.clone(),
|
||||
access_programs: request.access_programs,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,6 +350,8 @@ pub struct ResponseCreateWsRequest<'a> {
|
||||
pub generate: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_metadata: Option<HashMap<String, String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub access_programs: Option<AccessPrograms>,
|
||||
}
|
||||
|
||||
pub fn response_create_client_metadata(
|
||||
|
||||
@@ -955,6 +955,9 @@ mod tests {
|
||||
service_tier: Some("priority".to_string()),
|
||||
prompt_cache_key: Some("cache-key".to_string()),
|
||||
text: None,
|
||||
access_programs: Some(
|
||||
codex_protocol::turn_input::CyberAccessProgram::DaybreakBlue.into(),
|
||||
),
|
||||
client_metadata: Some(HashMap::from([(
|
||||
"traceparent".to_string(),
|
||||
"00-0123456789abcdef0123456789abcdef-0123456789abcdef-01".to_string(),
|
||||
|
||||
@@ -27,6 +27,7 @@ pub use crate::auth::AuthProvider;
|
||||
pub use crate::auth::AuthProviderFuture;
|
||||
pub use crate::auth::SharedAuthProvider;
|
||||
pub use crate::auth::auth_header_telemetry;
|
||||
pub use crate::common::AccessPrograms;
|
||||
pub use crate::common::CompactionInput;
|
||||
pub use crate::common::MemorySummarizeInput;
|
||||
pub use crate::common::MemorySummarizeOutput;
|
||||
|
||||
@@ -333,6 +333,7 @@ async fn responses_client_stream_request_preserves_item_ids() -> Result<()> {
|
||||
prompt_cache_key: None,
|
||||
text: None,
|
||||
client_metadata: None,
|
||||
access_programs: None,
|
||||
};
|
||||
let expected = serde_json::to_value(&request)?;
|
||||
|
||||
@@ -420,6 +421,7 @@ async fn streaming_client_retries_on_transport_error() -> Result<()> {
|
||||
prompt_cache_key: None,
|
||||
text: None,
|
||||
client_metadata: None,
|
||||
access_programs: None,
|
||||
};
|
||||
let client = ResponsesClient::new(transport.clone(), provider, Arc::new(NoAuth));
|
||||
|
||||
@@ -540,6 +542,7 @@ async fn azure_store_sends_ids_and_headers() -> Result<()> {
|
||||
prompt_cache_key: None,
|
||||
text: None,
|
||||
client_metadata: None,
|
||||
access_programs: None,
|
||||
};
|
||||
|
||||
let mut extra_headers = HeaderMap::new();
|
||||
|
||||
Reference in New Issue
Block a user