mirror of
https://github.com/openai/codex.git
synced 2026-11-15 14:52:36 +00:00
Propagate response tickets to Guardian reviews (#42758)
## What changed - Request and parse server-issued Guardian tickets for eligible Codex backend responses. - Scope each ticket to the response that produced a Guardian review or classifier request, including HTTP and WebSocket retries, without adding it to model-visible or persisted context. - Validate ticket shape, reserve its metadata keys, redact it from debug and request-body logging, and attach it only at the Guardian transport boundary. ## Testing - Cover ticket parsing, endpoint and authentication routing, retry scoping, classifier retries, and redaction for compressed and uncompressed requests. GitOrigin-RevId: 6219dd15c9f19ed3387de516aac1b8e7c9cdb0e3
This commit is contained in:
1 parent
97e46694e1
commit
cc4b8bdeb8
32 files changed
+562
-44
No files matched your search
@@ -140,6 +140,7 @@ pub(super) async fn spawn_review_thread(
|
||||
extension_data.insert(parent_turn_context.skills_snapshot().as_ref().clone());
|
||||
|
||||
let review_turn_context = TurnContext {
|
||||
guardian_ticket: None,
|
||||
sub_id: review_turn_id.clone(),
|
||||
trace_id: current_span_trace_id(),
|
||||
realtime_active: parent_turn_context.realtime_active,
|
||||
|
||||
@@ -619,6 +619,7 @@ impl Session {
|
||||
request_kind,
|
||||
);
|
||||
CodexResponsesMetadata {
|
||||
guardian_ticket: turn_context.guardian_ticket.clone(),
|
||||
window_number: Some(window_number),
|
||||
context_window_id: Some(context_window_id),
|
||||
history_ingest_requested: turn_context
|
||||
|
||||
@@ -1437,6 +1437,10 @@ async fn run_sampling_request(
|
||||
let mut original_input = None;
|
||||
let mut executed_tool_calls_by_output = HashMap::new();
|
||||
loop {
|
||||
// A retry must not lend a previous response's ticket to the next tool call.
|
||||
turn_context
|
||||
.extension_data
|
||||
.remove::<codex_protocol::guardian_ticket::GuardianTicket>();
|
||||
let prompt_input = if let Some(input) = initial_input.take() {
|
||||
input
|
||||
} else {
|
||||
@@ -2372,7 +2376,11 @@ async fn try_run_sampling_request(
|
||||
record_turn_ttft_metric(&turn_context, &event).await;
|
||||
|
||||
match event {
|
||||
ResponseEvent::Created => {}
|
||||
ResponseEvent::Created { guardian_ticket } => {
|
||||
if let Some(ticket) = guardian_ticket {
|
||||
turn_context.extension_data.insert(ticket);
|
||||
}
|
||||
}
|
||||
ResponseEvent::OutputItemDone(mut item) => {
|
||||
assign_missing_streamed_response_item_id(&mut item, active_item.as_ref());
|
||||
if analytics_tool_call_ids.len() < MAX_ANALYTICS_TOOL_CALL_IDS_PER_RESPONSE {
|
||||
|
||||
@@ -185,6 +185,7 @@ impl std::fmt::Debug for TurnEnvironment {
|
||||
/// Request options for one turn, separate from persistent thread settings.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct NewTurnContextOptions {
|
||||
pub(crate) guardian_ticket: Option<codex_protocol::guardian_ticket::GuardianTicket>,
|
||||
pub(crate) final_output_json_schema: Option<Value>,
|
||||
pub(crate) cyber_access_program: Option<CyberAccessProgram>,
|
||||
}
|
||||
@@ -192,6 +193,8 @@ pub(crate) struct NewTurnContextOptions {
|
||||
/// The context needed for a single turn of the thread.
|
||||
#[derive(Debug)]
|
||||
pub struct TurnContext {
|
||||
/// Receipt selected for this Guardian turn, separate from its own responses.
|
||||
pub(crate) guardian_ticket: Option<codex_protocol::guardian_ticket::GuardianTicket>,
|
||||
pub(crate) sub_id: String,
|
||||
pub(crate) trace_id: Option<String>,
|
||||
pub(crate) realtime_active: bool,
|
||||
@@ -537,6 +540,7 @@ impl TurnContext {
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
available_models,
|
||||
unified_exec_shell_mode: self.unified_exec_shell_mode.clone(),
|
||||
guardian_ticket: self.guardian_ticket.clone(),
|
||||
final_output_json_schema: self.final_output_json_schema.clone(),
|
||||
dynamic_tools: self.dynamic_tools.clone(),
|
||||
turn_metadata_state: self.turn_metadata_state.clone(),
|
||||
@@ -781,6 +785,7 @@ impl Session {
|
||||
let extension_data = Arc::new(codex_extension_api::ExtensionData::new(sub_id.clone()));
|
||||
extension_data.insert(skills_snapshot);
|
||||
TurnContext {
|
||||
guardian_ticket: None,
|
||||
sub_id,
|
||||
trace_id: current_span_trace_id(),
|
||||
realtime_active: false,
|
||||
@@ -1024,6 +1029,7 @@ impl Session {
|
||||
turn_context.extension_data.insert(trusted_plugin_roots);
|
||||
turn_context.realtime_active = self.conversation.running_state().await.is_some();
|
||||
|
||||
turn_context.guardian_ticket = options.guardian_ticket;
|
||||
turn_context.final_output_json_schema = options.final_output_json_schema;
|
||||
if turn_context.config.model_provider_id == codex_model_provider_info::OPENAI_PROVIDER_ID {
|
||||
turn_context.cyber_access_program = options.cyber_access_program;
|
||||
|
||||
@@ -121,6 +121,7 @@ impl PreparedTurnInputSettings {
|
||||
kind: TurnStartKind,
|
||||
) -> CodexResult<Option<Arc<TurnContext>>> {
|
||||
let TurnStartOptions {
|
||||
guardian_ticket,
|
||||
turn_trigger,
|
||||
final_output_json_schema,
|
||||
service_tier,
|
||||
@@ -138,6 +139,7 @@ impl PreparedTurnInputSettings {
|
||||
updates.service_tier_for_turn = service_tier;
|
||||
|
||||
let options = NewTurnContextOptions {
|
||||
guardian_ticket,
|
||||
final_output_json_schema,
|
||||
cyber_access_program,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user