[plugins] Track plugin install requests by ID (#29684)

Summary
- Emit `codex_plugin_install_requested` when a validated plugin install
request is made, before the user accepts or declines the elicitation.
- Record the exact model-visible plugin ID, remote plugin ID, required
connector IDs, stable suggestion ID, and `endpoint_recommendation` vs
`legacy_discovery` source.
- Keep `suggest_reason` out of telemetry and leave connector-only
install requests unchanged.

Rollout
- Backend/schema dependency:
https://github.com/openai/openai/pull/1065270
- Land the backend PR before this producer starts sending the event.

Validation
- `just test -p codex-analytics` (83 passed)
- `just test -p codex-core request_plugin_install` (17 passed)
- `just fix -p codex-analytics`
- `just fix -p codex-core`
- `just fmt`
- `git diff --check`
This commit is contained in:
Alex Daley authored and GitHub committed 2026-06-24 21:29:11 +00:00
1 parent df1ee09ec5
commit 24423f5712
8 files changed
+266 -2

No files matched your search

+51
View File
@@ -14,6 +14,7 @@ use crate::facts::CompactionTrigger;
use crate::facts::GoalEventKind;
use crate::facts::HookRunFact;
use crate::facts::InvocationType;
use crate::facts::PluginInstallRequested;
use crate::facts::PluginState;
use crate::facts::SubAgentThreadStartedInput;
use crate::facts::ThreadInitializationMode;
@@ -80,6 +81,7 @@ pub(crate) enum TrackEventRequest {
#[allow(dead_code)]
ReviewEvent(CodexReviewEventRequest),
PluginUsed(CodexPluginUsedEventRequest),
PluginInstallRequested(CodexPluginInstallRequestedEventRequest),
PluginInstalled(CodexPluginEventRequest),
PluginUninstalled(CodexPluginEventRequest),
PluginEnabled(CodexPluginEventRequest),
@@ -954,6 +956,31 @@ pub(crate) struct CodexPluginUsedMetadata {
pub(crate) model_slug: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedPluginMetadata {
pub(crate) plugin_id: String,
pub(crate) remote_plugin_id: Option<String>,
pub(crate) plugin_name: String,
pub(crate) connector_ids: Vec<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedMetadata {
pub(crate) suggestion_id: String,
pub(crate) plugins: Vec<CodexPluginInstallRequestedPluginMetadata>,
pub(crate) source: crate::facts::PluginInstallRequestSource,
pub(crate) thread_id: String,
pub(crate) turn_id: String,
pub(crate) model_slug: String,
pub(crate) product_client_id: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallRequestedEventRequest {
pub(crate) event_type: &'static str,
pub(crate) event_params: CodexPluginInstallRequestedMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginEventRequest {
pub(crate) event_type: &'static str,
@@ -1074,6 +1101,30 @@ fn codex_plugin_metadata_with_product_client_id(
}
}
pub(crate) fn codex_plugin_install_requested_metadata(
tracking: &TrackEventsContext,
request: PluginInstallRequested,
) -> CodexPluginInstallRequestedMetadata {
CodexPluginInstallRequestedMetadata {
suggestion_id: request.suggestion_id,
plugins: request
.plugins
.into_iter()
.map(|plugin| CodexPluginInstallRequestedPluginMetadata {
plugin_id: plugin.plugin_id,
remote_plugin_id: plugin.remote_plugin_id,
plugin_name: plugin.plugin_name,
connector_ids: plugin.connector_ids,
})
.collect(),
source: request.source,
thread_id: tracking.thread_id.clone(),
turn_id: tracking.turn_id.clone(),
model_slug: tracking.model_slug.clone(),
product_client_id: Some(originator().value),
}
}
pub(crate) fn codex_compaction_event_params(
input: CodexCompactionEvent,
session_id: String,