diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 7d5433ff3e..a9e4c8463f 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -50,6 +50,7 @@ use crate::stream_events_utils::last_assistant_message_from_item; use crate::stream_events_utils::mark_thread_memory_mode_polluted_if_external_context; use crate::stream_events_utils::raw_assistant_output_text_from_item; use crate::stream_events_utils::record_completed_response_item_with_finalized_facts; +use crate::tasks::emit_compact_metric; use crate::tools::ToolRouter; use crate::tools::context::SharedTurnDiffTracker; use crate::tools::parallel::ToolCallRuntime; @@ -778,6 +779,11 @@ async fn run_auto_compact( ) -> CodexResult<()> { if should_use_remote_compact_task(turn_context.provider.info()) { if turn_context.features.enabled(Feature::RemoteCompactionV2) { + emit_compact_metric( + &sess.services.session_telemetry, + "remote_v2", + /*manual*/ false, + ); run_inline_remote_auto_compact_task_v2( Arc::clone(sess), Arc::clone(turn_context), @@ -789,6 +795,11 @@ async fn run_auto_compact( .await?; return Ok(()); } + emit_compact_metric( + &sess.services.session_telemetry, + "remote", + /*manual*/ false, + ); run_inline_remote_auto_compact_task( Arc::clone(sess), Arc::clone(turn_context), @@ -798,6 +809,11 @@ async fn run_auto_compact( ) .await?; } else { + emit_compact_metric( + &sess.services.session_telemetry, + "local", + /*manual*/ false, + ); run_inline_auto_compact_task( Arc::clone(sess), Arc::clone(turn_context), diff --git a/codex-rs/core/src/tasks/compact.rs b/codex-rs/core/src/tasks/compact.rs index 77914633a2..adc98e413a 100644 --- a/codex-rs/core/src/tasks/compact.rs +++ b/codex-rs/core/src/tasks/compact.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use super::SessionTask; use super::SessionTaskContext; +use super::emit_compact_metric; use crate::session::TurnInput; use crate::session::turn_context::TurnContext; use crate::state::TaskKind; @@ -29,24 +30,29 @@ impl SessionTask for CompactTask { ) -> Option { let session = session.clone_session(); let _ = if crate::compact::should_use_remote_compact_task(ctx.provider.info()) { - session.services.session_telemetry.counter( - "codex.task.compact", - /*inc*/ 1, - &[("type", "remote")], - ); if ctx .features .enabled(codex_features::Feature::RemoteCompactionV2) { + emit_compact_metric( + &session.services.session_telemetry, + "remote_v2", + /*manual*/ true, + ); crate::compact_remote_v2::run_remote_compact_task(session.clone(), ctx).await } else { + emit_compact_metric( + &session.services.session_telemetry, + "remote", + /*manual*/ true, + ); crate::compact_remote::run_remote_compact_task(session.clone(), ctx).await } } else { - session.services.session_telemetry.counter( - "codex.task.compact", - /*inc*/ 1, - &[("type", "local")], + emit_compact_metric( + &session.services.session_telemetry, + "local", + /*manual*/ true, ); let input = vec![UserInput::Text { text: ctx.compact_prompt().to_string(), diff --git a/codex-rs/core/src/tasks/mod.rs b/codex-rs/core/src/tasks/mod.rs index 51d236526e..e6e7663e50 100644 --- a/codex-rs/core/src/tasks/mod.rs +++ b/codex-rs/core/src/tasks/mod.rs @@ -62,6 +62,7 @@ pub(crate) use user_shell::UserShellCommandTask; pub(crate) use user_shell::execute_user_shell_command; const GRACEFULL_INTERRUPTION_TIMEOUT_MS: u64 = 100; +const TASK_COMPACT_METRIC: &str = "codex.task.compact"; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum InterruptedTurnHistoryMarker { @@ -145,6 +146,18 @@ fn emit_turn_memory_metric( ); } +pub(crate) fn emit_compact_metric( + session_telemetry: &SessionTelemetry, + compact_type: &'static str, + manual: bool, +) { + session_telemetry.counter( + TASK_COMPACT_METRIC, + /*inc*/ 1, + &[("type", compact_type), ("manual", bool_tag(manual))], + ); +} + fn bool_tag(value: bool) -> &'static str { if value { "true" } else { "false" } } diff --git a/codex-rs/core/src/tasks/mod_tests.rs b/codex-rs/core/src/tasks/mod_tests.rs index 2aa0253dec..e426b0b710 100644 --- a/codex-rs/core/src/tasks/mod_tests.rs +++ b/codex-rs/core/src/tasks/mod_tests.rs @@ -1,3 +1,5 @@ +use super::TASK_COMPACT_METRIC; +use super::emit_compact_metric; use super::emit_turn_memory_metric; use super::emit_turn_network_proxy_metric; use codex_otel::MetricsClient; @@ -178,3 +180,45 @@ fn emit_turn_memory_metric_records_config_disabled_without_citations() { ]) ); } + +#[test] +fn emit_compact_metric_records_manual_remote_v2() { + let session_telemetry = test_session_telemetry(); + + emit_compact_metric(&session_telemetry, "remote_v2", /*manual*/ true); + + let snapshot = session_telemetry + .snapshot_metrics() + .expect("runtime metrics snapshot"); + let (attrs, value) = metric_point(&snapshot, TASK_COMPACT_METRIC); + + assert_eq!(value, 1); + assert_eq!( + attrs, + BTreeMap::from([ + ("manual".to_string(), "true".to_string()), + ("type".to_string(), "remote_v2".to_string()), + ]) + ); +} + +#[test] +fn emit_compact_metric_records_auto_local() { + let session_telemetry = test_session_telemetry(); + + emit_compact_metric(&session_telemetry, "local", /*manual*/ false); + + let snapshot = session_telemetry + .snapshot_metrics() + .expect("runtime metrics snapshot"); + let (attrs, value) = metric_point(&snapshot, TASK_COMPACT_METRIC); + + assert_eq!(value, 1); + assert_eq!( + attrs, + BTreeMap::from([ + ("manual".to_string(), "false".to_string()), + ("type".to_string(), "local".to_string()), + ]) + ); +}