diff --git a/codex-rs/core/src/guardian/review_session.rs b/codex-rs/core/src/guardian/review_session.rs index f7a4bfb8d7..d96af8764c 100644 --- a/codex-rs/core/src/guardian/review_session.rs +++ b/codex-rs/core/src/guardian/review_session.rs @@ -692,6 +692,7 @@ async fn run_review_on_session( .map(|id| HashMap::from([("parent_response_id".to_owned(), id.clone())])), ) .on_start(TurnStartOptions { + turn_trigger: Some("guardian_review".to_owned()), final_output_json_schema: Some(params.schema.clone()), service_tier: None, parent_turn_id: Some(parent_turn.sub_id.clone()), diff --git a/codex-rs/core/src/guardian/tests.rs b/codex-rs/core/src/guardian/tests.rs index 1a88cc4659..91be43f71a 100644 --- a/codex-rs/core/src/guardian/tests.rs +++ b/codex-rs/core/src/guardian/tests.rs @@ -2192,6 +2192,12 @@ async fn guardian_review_request_layout_matches_model_visible_request_snapshot() Some(codex_analytics::GuardianReviewSessionKind::TrunkNew) )); let request = request_log.single_request(); + let turn_metadata: serde_json::Value = serde_json::from_str( + &request + .header("x-codex-turn-metadata") + .expect("guardian turn metadata"), + )?; + assert_eq!(turn_metadata["turn_trigger"], "guardian_review"); let request_body = request.body_json(); assert!( request_body.get("tools").is_none(), diff --git a/codex-rs/core/src/turn_metadata.rs b/codex-rs/core/src/turn_metadata.rs index 5c30fd202f..772345e1ac 100644 --- a/codex-rs/core/src/turn_metadata.rs +++ b/codex-rs/core/src/turn_metadata.rs @@ -99,6 +99,7 @@ pub async fn detached_memory_responses_metadata( root_turn_id: Some(turn_id), request_kind: Some(CodexResponsesRequestKind::Memory), thread_source: Some(ThreadSource::MemoryConsolidation), + turn_trigger: Some("memory_consolidation".to_owned()), subagent_header: subagent_header_value(session_source), sandbox: sandbox.map(ToString::to_string), workspaces: memory_workspaces( diff --git a/codex-rs/core/src/turn_metadata_tests.rs b/codex-rs/core/src/turn_metadata_tests.rs index fb6c118cc3..be1c2a98d7 100644 --- a/codex-rs/core/src/turn_metadata_tests.rs +++ b/codex-rs/core/src/turn_metadata_tests.rs @@ -241,6 +241,7 @@ async fn detached_memory_responses_metadata_omits_empty_workspace_metadata() { "request_kind": "memory", "sandbox_mode": "read-only", "thread_source": "memory_consolidation", + "turn_trigger": "memory_consolidation", }) ); } diff --git a/codex-rs/ext/guardian-v2/src/async_scorer/extension_tests.rs b/codex-rs/ext/guardian-v2/src/async_scorer/extension_tests.rs index e6fd490624..2d462841d5 100644 --- a/codex-rs/ext/guardian-v2/src/async_scorer/extension_tests.rs +++ b/codex-rs/ext/guardian-v2/src/async_scorer/extension_tests.rs @@ -1958,6 +1958,7 @@ async fn assert_luna_pool_context(thread_context_enabled: bool) -> Result<()> { "parent_turn_id": "turn-1", "root_turn_id": "root-turn", "thread_source": "guardian_classifier", + "turn_trigger": "guardian_classifier", }) ); assert_eq!(request["client_metadata"]["x-openai-subagent"], "guardian"); diff --git a/codex-rs/ext/guardian-v2/src/async_scorer/sampler.rs b/codex-rs/ext/guardian-v2/src/async_scorer/sampler.rs index 15e8de428c..c89cc49414 100644 --- a/codex-rs/ext/guardian-v2/src/async_scorer/sampler.rs +++ b/codex-rs/ext/guardian-v2/src/async_scorer/sampler.rs @@ -400,6 +400,7 @@ impl LunaSampler { "turn_id": turn_id, "parent_turn_id": parent_turn_id, "thread_source": "guardian_classifier", + "turn_trigger": "guardian_classifier", }); let mut client_metadata = HashMap::from([ ("session_id".to_owned(), self.config.session_id.clone()), diff --git a/codex-rs/ext/guardian-v2/src/async_scorer/sampler_tests.rs b/codex-rs/ext/guardian-v2/src/async_scorer/sampler_tests.rs index 23635baf6e..9a5018b028 100644 --- a/codex-rs/ext/guardian-v2/src/async_scorer/sampler_tests.rs +++ b/codex-rs/ext/guardian-v2/src/async_scorer/sampler_tests.rs @@ -111,6 +111,7 @@ fn assert_connection_metadata( "turn_id": turn_id, "parent_turn_id": parent_turn_id, "thread_source": "guardian_classifier", + "turn_trigger": "guardian_classifier", }, }); if let Some(root_turn_id) = root_turn_id { diff --git a/codex-rs/memories/write/src/runtime.rs b/codex-rs/memories/write/src/runtime.rs index cbd4a06978..d9079c48bb 100644 --- a/codex-rs/memories/write/src/runtime.rs +++ b/codex-rs/memories/write/src/runtime.rs @@ -7,6 +7,7 @@ use codex_core::StartIfIdleSubmission; use codex_core::StartThreadOptions; use codex_core::ThreadManager; use codex_core::TurnInputRequest; +use codex_core::TurnStartOptions; use codex_core::config::Config; use codex_core::content_items_to_text; use codex_core::detached_memory_responses_metadata; @@ -379,7 +380,12 @@ impl MemoryStartupContext { let agent = SpawnedConsolidationAgent { thread_id, thread }; let submit_result = match agent .thread - .start_turn_if_idle(TurnInputRequest::user_input(prompt)) + .start_turn_if_idle( + TurnInputRequest::user_input(prompt).on_start(TurnStartOptions { + turn_trigger: Some("memory_consolidation".to_owned()), + ..Default::default() + }), + ) .await { Ok(StartIfIdleSubmission::Started { .. }) => Ok(()), diff --git a/codex-rs/memories/write/src/startup_tests.rs b/codex-rs/memories/write/src/startup_tests.rs index 6a93d6754a..d7a9a7ad6b 100644 --- a/codex-rs/memories/write/src/startup_tests.rs +++ b/codex-rs/memories/write/src/startup_tests.rs @@ -694,6 +694,10 @@ async fn memories_startup_phase1_uses_live_thread_service_tier_and_detached_meta .expect("client metadata json"); assert_eq!(client_metadata, metadata); assert_eq!(metadata["request_kind"].as_str(), Some("memory")); + assert_eq!( + metadata["turn_trigger"].as_str(), + Some("memory_consolidation") + ); assert_eq!( metadata["thread_source"].as_str(), Some("memory_consolidation") @@ -1025,6 +1029,12 @@ async fn run_memory_phase_two_model_request_test( let parent_permission_profile = config.permissions.effective_permission_profile(); phase2::run(context, config, parent_permission_profile).await; let request = wait_for_single_request(&response).await; + let turn_metadata: serde_json::Value = serde_json::from_str( + request.body_json()["client_metadata"]["x-codex-turn-metadata"] + .as_str() + .expect("consolidation turn metadata"), + )?; + assert_eq!(turn_metadata["turn_trigger"], "memory_consolidation"); let consolidation_thread_id = ThreadId::from_string( request.body_json()["client_metadata"]["thread_id"] .as_str()