Emit API-key turn cost telemetry from app-server (#39006)

## What changed

- Track app-server turn lifecycle events for OpenAI API-key sessions when OTLP telemetry export is enabled.
- Query the turn-cost endpoint after completed or aborted turns and emit `codex.turn_cost` with the estimated USD cost, interruption state, model, speed, and reasoning effort.
- Preserve provider organization and project headers, wait for all observed responses to be priced, and retry pending or transiently failed queries with bounded tracking.
- Re-probe availability after authentication changes and shut the worker down with other app-server background tasks.

## Testing

- Cover late API-key login, transient probe failures, telemetry after thread removal, and turns with multiple responses.
- Verify turn-cost requests use API-key authentication and provider scope headers and deserialize priced response data.

GitOrigin-RevId: a303162a54798b554fcb2e9e2b372e1cf9f49f39
This commit is contained in:
xli-oai authored and copyberry committed 2026-08-17 13:20:58 +00:00
1 parent 02e9bfaac7
commit 04caa22c82
11 files changed
+934

No files matched your search

@@ -481,6 +481,7 @@ pub(crate) struct ThreadRequestProcessor {
pub(super) log_db: Option<LogDbLayer>,
pub(super) background_tasks: TaskTracker,
pub(super) skills_watcher: Arc<SkillsWatcher>,
pub(super) turn_cost_worker: Option<crate::turn_cost_worker::TurnCostWorkerHandle>,
pub(super) initial_config_warnings: Arc<Vec<ConfigWarningNotification>>,
}
@@ -513,6 +514,7 @@ impl ThreadRequestProcessor {
state_db: Option<StateDbHandle>,
log_db: Option<LogDbLayer>,
skills_watcher: Arc<SkillsWatcher>,
turn_cost_worker: Option<crate::turn_cost_worker::TurnCostWorkerHandle>,
initial_config_warnings: Vec<ConfigWarningNotification>,
) -> Self {
Self {
@@ -532,6 +534,7 @@ impl ThreadRequestProcessor {
log_db,
background_tasks: TaskTracker::new(),
skills_watcher,
turn_cost_worker,
initial_config_warnings: Arc::new(initial_config_warnings),
}
}
@@ -1058,6 +1061,7 @@ impl ThreadRequestProcessor {
fallback_model_provider: self.config.model_provider_id.clone(),
codex_home: self.config.codex_home.to_path_buf(),
skills_watcher: Arc::clone(&self.skills_watcher),
turn_cost_worker: self.turn_cost_worker.clone(),
}
}
@@ -1188,6 +1192,7 @@ impl ThreadRequestProcessor {
fallback_model_provider: self.config.model_provider_id.clone(),
codex_home: self.config.codex_home.to_path_buf(),
skills_watcher: Arc::clone(&self.skills_watcher),
turn_cost_worker: self.turn_cost_worker.clone(),
};
let request_trace = request_context.request_trace();
let config_manager = self.config_manager.clone();