Track history notes thread hint outcomes (#42247)

## What changed

- Emit a `codex_thread_hint_status` analytics event for each native history-notes thread hint attempt.
- Report whether retrieval was successful or failed along with thread context and timing, without including hint contents.
- Treat valid empty responses as successful retrievals while continuing to omit them from the context window.

## Testing

- Extend the app-server history-notes tests to verify success, empty-result success, and backend failure statuses.

GitOrigin-RevId: b9462f312847e8c871ed2be0c8cf8df0928a7fdd
This commit is contained in:
pmccrary-oai
2026-09-02 09:12:17 +00:00
committed by copyberry
parent eb10d91e48
commit bdfd769640
10 changed files with 118 additions and 10 deletions
+1
View File
@@ -13,6 +13,7 @@ doctest = false
workspace = true
[dependencies]
codex-analytics = { workspace = true }
codex-api = { workspace = true }
codex-client = { workspace = true }
codex-core = { workspace = true }
+20 -1
View File
@@ -1,5 +1,8 @@
use std::sync::Arc;
use codex_analytics::AnalyticsEventsClient;
use codex_analytics::ThreadHintStatus;
use codex_analytics::ThreadHintStatusEvent;
use codex_core::config::Config;
use codex_extension_api::ConfigContributor;
use codex_extension_api::ContentItemKind;
@@ -104,6 +107,15 @@ impl ContextContributor for HistoryNotesExtension {
let Some(identity) = thread_store.get::<HistoryNotesAgentIdentity>() else {
return Vec::new();
};
let track_status = |status| {
if let Some(analytics) = session_store.get::<AnalyticsEventsClient>() {
analytics.track_thread_hint_status(ThreadHintStatusEvent {
thread_id: thread_store.level_id().to_string(),
status,
occurred_at_ms: codex_analytics::now_unix_millis(),
});
}
};
let Ok(result) = config
.backend
.call(
@@ -115,12 +127,19 @@ impl ContextContributor for HistoryNotesExtension {
)
.await
else {
track_status(ThreadHintStatus::Failed);
return Vec::new();
};
let Some(text) = result.get("text").and_then(serde_json::Value::as_str) else {
track_status(ThreadHintStatus::Failed);
return Vec::new();
};
if text.is_empty() || text.len() > MAX_THREAD_HINT_BYTES {
if text.len() > MAX_THREAD_HINT_BYTES {
track_status(ThreadHintStatus::Failed);
return Vec::new();
}
track_status(ThreadHintStatus::Succeeded);
if text.is_empty() {
return Vec::new();
}
vec![PromptFragment::new(