Use request originator for analytics attribution

This commit is contained in:
Owen Lin
2026-05-19 14:37:55 -07:00
parent c41a7b9aa7
commit 9e3c311dfc
13 changed files with 166 additions and 41 deletions
@@ -155,6 +155,10 @@ use std::sync::Arc;
use std::sync::Mutex;
use tokio::sync::mpsc;
fn default_product_client_id() -> String {
Originator::process_default().value().to_string()
}
fn sample_thread_with_metadata(
thread_id: &str,
ephemeral: bool,
@@ -941,6 +945,7 @@ fn app_mentioned_event_serializes_expected_shape() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: "codex_ios".to_string(),
};
let event = TrackEventRequest::AppMentioned(CodexAppMentionedEventRequest {
event_type: "codex_app_mentioned",
@@ -965,7 +970,7 @@ fn app_mentioned_event_serializes_expected_shape() {
"thread_id": "thread-1",
"turn_id": "turn-1",
"app_name": "Calendar",
"product_client_id": Originator::process_default().value().to_string(),
"product_client_id": "codex_ios",
"invoke_type": "explicit",
"model_slug": "gpt-5"
}
@@ -979,6 +984,7 @@ fn app_used_event_serializes_expected_shape() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-2".to_string(),
turn_id: "turn-2".to_string(),
product_client_id: default_product_client_id(),
};
let event = TrackEventRequest::AppUsed(CodexAppUsedEventRequest {
event_type: "codex_app_used",
@@ -1280,11 +1286,13 @@ fn app_used_dedupe_is_keyed_by_turn_and_connector() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
let turn_2 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-2".to_string(),
product_client_id: default_product_client_id(),
};
assert_eq!(queue.should_enqueue_app_used(&turn_1, &app), true);
@@ -2755,6 +2763,7 @@ fn plugin_used_event_serializes_expected_shape() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-3".to_string(),
turn_id: "turn-3".to_string(),
product_client_id: default_product_client_id(),
};
let event = TrackEventRequest::PluginUsed(CodexPluginUsedEventRequest {
event_type: "codex_plugin_used",
@@ -2785,9 +2794,10 @@ fn plugin_used_event_serializes_expected_shape() {
#[test]
fn plugin_management_event_serializes_expected_shape() {
let product_client_id = "codex_desktop".to_string();
let event = TrackEventRequest::PluginInstalled(CodexPluginEventRequest {
event_type: "codex_plugin_installed",
event_params: codex_plugin_metadata(sample_plugin_metadata()),
event_params: codex_plugin_metadata(sample_plugin_metadata(), product_client_id),
});
let payload = serde_json::to_value(&event).expect("serialize plugin installed event");
@@ -2803,7 +2813,7 @@ fn plugin_management_event_serializes_expected_shape() {
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": Originator::process_default().value().to_string()
"product_client_id": "codex_desktop"
}
})
);
@@ -2815,7 +2825,7 @@ fn plugin_management_event_can_use_remote_plugin_id_override() {
plugin.remote_plugin_id = Some("plugins~Plugin_remote".to_string());
let event = TrackEventRequest::PluginInstalled(CodexPluginEventRequest {
event_type: "codex_plugin_installed",
event_params: codex_plugin_metadata(plugin),
event_params: codex_plugin_metadata(plugin, default_product_client_id()),
});
let payload = serde_json::to_value(&event).expect("serialize plugin installed event");
@@ -2834,6 +2844,7 @@ fn hook_run_event_serializes_expected_shape() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-3".to_string(),
turn_id: "turn-3".to_string(),
product_client_id: default_product_client_id(),
};
let event = TrackEventRequest::HookRun(CodexHookRunEventRequest {
event_type: "codex_hook_run",
@@ -2871,6 +2882,7 @@ fn hook_run_metadata_maps_sources_and_statuses() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
let system = serde_json::to_value(codex_hook_run_metadata(
@@ -2926,6 +2938,7 @@ fn hook_run_metadata_maps_stopped_status() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: "codex_web".to_string(),
};
let stopped = serde_json::to_value(codex_hook_run_metadata(
@@ -2956,11 +2969,13 @@ fn plugin_used_dedupe_is_keyed_by_turn_and_plugin() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
let turn_2 = TrackEventsContext {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-2".to_string(),
product_client_id: default_product_client_id(),
};
assert_eq!(queue.should_enqueue_plugin_used(&turn_1, &plugin), true);
@@ -2976,6 +2991,7 @@ async fn reducer_ingests_skill_invoked_fact() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
let skill_path = PathBuf::from("/Users/abc/.codex/skills/doc/SKILL.md");
let expected_skill_id = skill_id_for_local_skill(
@@ -3009,7 +3025,7 @@ async fn reducer_ingests_skill_invoked_fact() {
"skill_id": expected_skill_id,
"skill_name": "doc",
"event_params": {
"product_client_id": Originator::process_default().value().to_string(),
"product_client_id": "codex_web",
"skill_scope": "user",
"plugin_id": null,
"repo_url": null,
@@ -3030,6 +3046,7 @@ async fn reducer_includes_plugin_id_for_plugin_skill_invocations() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
let skill_path =
PathBuf::from("/Users/abc/.codex/plugins/cache/test/sample/skills/doc/SKILL.md");
@@ -3069,6 +3086,7 @@ async fn reducer_ingests_hook_run_fact() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
},
hook: HookRunFact {
event_name: HookEventName::PostToolUse,
@@ -3096,6 +3114,7 @@ async fn reducer_ingests_app_and_plugin_facts() {
model_slug: "gpt-5".to_string(),
thread_id: "thread-1".to_string(),
turn_id: "turn-1".to_string(),
product_client_id: default_product_client_id(),
};
reducer
@@ -3152,6 +3171,7 @@ async fn reducer_ingests_plugin_state_changed_fact() {
PluginStateChangedInput {
plugin: sample_plugin_metadata(),
state: PluginState::Disabled,
product_client_id: default_product_client_id(),
},
)),
&mut events,
+36
View File
@@ -258,37 +258,73 @@ impl AnalyticsEventsClient {
}
pub fn track_plugin_installed(&self, plugin: PluginTelemetryMetadata) {
self.track_plugin_installed_with_originator(plugin, &Originator::process_default());
}
pub fn track_plugin_installed_with_originator(
&self,
plugin: PluginTelemetryMetadata,
originator: &Originator,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
plugin,
state: PluginState::Installed,
product_client_id: originator.value().to_string(),
}),
));
}
pub fn track_plugin_uninstalled(&self, plugin: PluginTelemetryMetadata) {
self.track_plugin_uninstalled_with_originator(plugin, &Originator::process_default());
}
pub fn track_plugin_uninstalled_with_originator(
&self,
plugin: PluginTelemetryMetadata,
originator: &Originator,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
plugin,
state: PluginState::Uninstalled,
product_client_id: originator.value().to_string(),
}),
));
}
pub fn track_plugin_enabled(&self, plugin: PluginTelemetryMetadata) {
self.track_plugin_enabled_with_originator(plugin, &Originator::process_default());
}
pub fn track_plugin_enabled_with_originator(
&self,
plugin: PluginTelemetryMetadata,
originator: &Originator,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
plugin,
state: PluginState::Enabled,
product_client_id: originator.value().to_string(),
}),
));
}
pub fn track_plugin_disabled(&self, plugin: PluginTelemetryMetadata) {
self.track_plugin_disabled_with_originator(plugin, &Originator::process_default());
}
pub fn track_plugin_disabled_with_originator(
&self,
plugin: PluginTelemetryMetadata,
originator: &Originator,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
plugin,
state: PluginState::Disabled,
product_client_id: originator.value().to_string(),
}),
));
}
+7 -5
View File
@@ -22,7 +22,6 @@ use crate::facts::TurnSubmissionType;
use crate::now_unix_millis;
use codex_app_server_protocol::CodexErrorInfo;
use codex_app_server_protocol::CommandExecutionSource;
use codex_login::default_client::Originator;
use codex_plugin::PluginTelemetryMetadata;
use codex_protocol::approvals::NetworkApprovalProtocol;
use codex_protocol::models::AdditionalPermissionProfile;
@@ -890,13 +889,16 @@ pub(crate) fn codex_app_metadata(
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
app_name: app.app_name,
product_client_id: Some(Originator::process_default().value().to_string()),
product_client_id: Some(tracking.product_client_id.clone()),
invoke_type: app.invocation_type,
model_slug: Some(tracking.model_slug.clone()),
}
}
pub(crate) fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPluginMetadata {
pub(crate) fn codex_plugin_metadata(
plugin: PluginTelemetryMetadata,
product_client_id: String,
) -> CodexPluginMetadata {
let PluginTelemetryMetadata {
plugin_id,
remote_plugin_id,
@@ -920,7 +922,7 @@ pub(crate) fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPlu
.map(|connector_id| connector_id.0)
.collect()
}),
product_client_id: Some(Originator::process_default().value().to_string()),
product_client_id: Some(product_client_id),
}
}
@@ -960,7 +962,7 @@ pub(crate) fn codex_plugin_used_metadata(
plugin: PluginTelemetryMetadata,
) -> CodexPluginUsedMetadata {
CodexPluginUsedMetadata {
plugin: codex_plugin_metadata(plugin),
plugin: codex_plugin_metadata(plugin, tracking.product_client_id.clone()),
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
model_slug: Some(tracking.model_slug.clone()),
+4
View File
@@ -40,17 +40,20 @@ pub struct TrackEventsContext {
pub model_slug: String,
pub thread_id: String,
pub turn_id: String,
pub product_client_id: String,
}
pub fn build_track_events_context(
model_slug: String,
thread_id: String,
turn_id: String,
product_client_id: String,
) -> TrackEventsContext {
TrackEventsContext {
model_slug,
thread_id,
turn_id,
product_client_id,
}
}
@@ -369,6 +372,7 @@ pub(crate) struct PluginUsedInput {
pub(crate) struct PluginStateChangedInput {
pub plugin: PluginTelemetryMetadata,
pub state: PluginState,
pub product_client_id: String,
}
#[derive(Clone, Copy)]
+7 -4
View File
@@ -111,7 +111,6 @@ use codex_app_server_protocol::UserInput;
use codex_app_server_protocol::WebSearchAction;
use codex_git_utils::collect_git_info;
use codex_git_utils::get_git_repo_root;
use codex_login::default_client::Originator;
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary;
@@ -680,7 +679,7 @@ impl AnalyticsReducer {
turn_id: Some(tracking.turn_id.clone()),
invoke_type: Some(invocation.invocation_type),
model_slug: Some(tracking.model_slug.clone()),
product_client_id: Some(Originator::process_default().value().to_string()),
product_client_id: Some(tracking.product_client_id.clone()),
repo_url,
skill_scope: Some(skill_scope.to_string()),
plugin_id: invocation.plugin_id,
@@ -731,10 +730,14 @@ impl AnalyticsReducer {
input: PluginStateChangedInput,
out: &mut Vec<TrackEventRequest>,
) {
let PluginStateChangedInput { plugin, state } = input;
let PluginStateChangedInput {
plugin,
state,
product_client_id,
} = input;
let event = CodexPluginEventRequest {
event_type: plugin_state_event_type(state),
event_params: codex_plugin_metadata(plugin),
event_params: codex_plugin_metadata(plugin, product_client_id),
};
out.push(match state {
PluginState::Installed => TrackEventRequest::PluginInstalled(event),
+16 -8
View File
@@ -887,12 +887,16 @@ impl MessageProcessor {
.import(request_id.clone(), params, &request_context)
.await
.map(|()| None),
ClientRequest::ConfigValueWrite { params, .. } => {
self.config_processor.value_write(params).await.map(Some)
}
ClientRequest::ConfigBatchWrite { params, .. } => {
self.config_processor.batch_write(params).await.map(Some)
}
ClientRequest::ConfigValueWrite { params, .. } => self
.config_processor
.value_write(params, request_context.originator())
.await
.map(Some),
ClientRequest::ConfigBatchWrite { params, .. } => self
.config_processor
.batch_write(params, request_context.originator())
.await
.map(Some),
ClientRequest::ExperimentalFeatureEnablementSet { params, .. } => {
self.config_processor
.experimental_feature_enablement_set(request_id.clone(), params)
@@ -1127,10 +1131,14 @@ impl MessageProcessor {
self.catalog_processor.skills_config_write(params).await
}
ClientRequest::PluginInstall { params, .. } => {
self.plugin_processor.plugin_install(params).await
self.plugin_processor
.plugin_install(params, request_context.originator())
.await
}
ClientRequest::PluginUninstall { params, .. } => {
self.plugin_processor.plugin_uninstall(params).await
self.plugin_processor
.plugin_uninstall(params, request_context.originator())
.await
}
ClientRequest::ModelList { params, .. } => {
self.catalog_processor.model_list(params).await
@@ -41,6 +41,7 @@ use codex_core::ThreadManager;
use codex_features::canonical_feature_for_key;
use codex_features::feature_for_key;
use codex_login::AuthManager;
use codex_login::default_client::Originator;
use codex_model_provider::create_model_provider;
use codex_plugin::PluginId;
use codex_protocol::config_types::WebSearchMode;
@@ -128,8 +129,9 @@ impl ConfigRequestProcessor {
pub(crate) async fn value_write(
&self,
params: ConfigValueWriteParams,
originator: &Originator,
) -> Result<ClientResponsePayload, JSONRPCErrorError> {
self.handle_config_mutation_result(self.write_value(params).await)
self.handle_config_mutation_result(self.write_value(params, originator).await)
.await
.map(ClientResponsePayload::ConfigValueWrite)
}
@@ -137,8 +139,9 @@ impl ConfigRequestProcessor {
pub(crate) async fn batch_write(
&self,
params: ConfigBatchWriteParams,
originator: &Originator,
) -> Result<ClientResponsePayload, JSONRPCErrorError> {
self.handle_config_mutation_result(self.batch_write_inner(params).await)
self.handle_config_mutation_result(self.batch_write_inner(params, originator).await)
.await
.map(ClientResponsePayload::ConfigBatchWrite)
}
@@ -274,6 +277,7 @@ impl ConfigRequestProcessor {
async fn write_value(
&self,
params: ConfigValueWriteParams,
originator: &Originator,
) -> Result<ConfigWriteResponse, JSONRPCErrorError> {
let pending_changes = codex_core_plugins::toggles::collect_plugin_enabled_candidates(
[(&params.key_path, &params.value)].into_iter(),
@@ -283,13 +287,15 @@ impl ConfigRequestProcessor {
.write_value(params)
.await
.map_err(map_error)?;
self.emit_plugin_toggle_events(pending_changes).await;
self.emit_plugin_toggle_events(pending_changes, originator)
.await;
Ok(response)
}
async fn batch_write_inner(
&self,
params: ConfigBatchWriteParams,
originator: &Originator,
) -> Result<ConfigWriteResponse, JSONRPCErrorError> {
let reload_user_config = params.reload_user_config;
let pending_changes = codex_core_plugins::toggles::collect_plugin_enabled_candidates(
@@ -303,7 +309,8 @@ impl ConfigRequestProcessor {
.batch_write(params)
.await
.map_err(map_error)?;
self.emit_plugin_toggle_events(pending_changes).await;
self.emit_plugin_toggle_events(pending_changes, originator)
.await;
if reload_user_config {
self.reload_user_config().await;
}
@@ -379,6 +386,7 @@ impl ConfigRequestProcessor {
async fn emit_plugin_toggle_events(
&self,
pending_changes: std::collections::BTreeMap<String, bool>,
originator: &Originator,
) {
for (plugin_id, enabled) in pending_changes {
let Ok(plugin_id) = PluginId::parse(&plugin_id) else {
@@ -390,9 +398,11 @@ impl ConfigRequestProcessor {
)
.await;
if enabled {
self.analytics_events_client.track_plugin_enabled(metadata);
self.analytics_events_client
.track_plugin_enabled_with_originator(metadata, originator);
} else {
self.analytics_events_client.track_plugin_disabled(metadata);
self.analytics_events_client
.track_plugin_disabled_with_originator(metadata, originator);
}
}
}
@@ -9,6 +9,7 @@ use codex_config::types::McpServerConfig;
use codex_core_plugins::remote::RemotePluginScope;
use codex_core_plugins::remote::is_valid_remote_plugin_id;
use codex_core_plugins::remote::validate_remote_plugin_id;
use codex_login::default_client::Originator;
use codex_mcp::McpOAuthLoginSupport;
use codex_mcp::oauth_login_support;
use codex_mcp::should_retry_without_scopes;
@@ -377,8 +378,9 @@ impl PluginRequestProcessor {
pub(crate) async fn plugin_install(
&self,
params: PluginInstallParams,
originator: &Originator,
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
self.plugin_install_response(params)
self.plugin_install_response(params, originator)
.await
.map(|response| Some(response.into()))
}
@@ -386,8 +388,9 @@ impl PluginRequestProcessor {
pub(crate) async fn plugin_uninstall(
&self,
params: PluginUninstallParams,
originator: &Originator,
) -> Result<Option<ClientResponsePayload>, JSONRPCErrorError> {
self.plugin_uninstall_response(params)
self.plugin_uninstall_response(params, originator)
.await
.map(|response| Some(response.into()))
}
@@ -1274,6 +1277,7 @@ impl PluginRequestProcessor {
async fn plugin_install_response(
&self,
params: PluginInstallParams,
originator: &Originator,
) -> Result<PluginInstallResponse, JSONRPCErrorError> {
let PluginInstallParams {
marketplace_path,
@@ -1284,7 +1288,11 @@ impl PluginRequestProcessor {
(Some(marketplace_path), None) => marketplace_path,
(None, Some(remote_marketplace_name)) => {
return self
.remote_plugin_install_response(remote_marketplace_name, plugin_name)
.remote_plugin_install_response(
remote_marketplace_name,
plugin_name,
originator,
)
.await;
}
(Some(_), Some(_)) | (None, None) => {
@@ -1313,7 +1321,7 @@ impl PluginRequestProcessor {
};
let result = plugins_manager
.install_plugin(request)
.install_plugin_with_originator(request, originator)
.await
.map_err(Self::plugin_install_error)?;
let config = match self.load_latest_config(config_cwd).await {
@@ -1355,6 +1363,7 @@ impl PluginRequestProcessor {
&self,
remote_marketplace_name: String,
remote_plugin_id: String,
originator: &Originator,
) -> Result<PluginInstallResponse, JSONRPCErrorError> {
let config = self.load_latest_config(/*fallback_cwd*/ None).await?;
if !config.features.enabled(Feature::Plugins) {
@@ -1441,7 +1450,7 @@ impl PluginRequestProcessor {
plugin_telemetry_metadata_from_root(&result.plugin_id, &result.installed_path).await;
plugin_metadata.remote_plugin_id = Some(remote_plugin_id);
self.analytics_events_client
.track_plugin_installed(plugin_metadata);
.track_plugin_installed_with_originator(plugin_metadata, originator);
let plugin_mcp_servers = load_plugin_mcp_servers(result.installed_path.as_path()).await;
if !plugin_mcp_servers.is_empty() {
@@ -1613,6 +1622,7 @@ impl PluginRequestProcessor {
async fn plugin_uninstall_response(
&self,
params: PluginUninstallParams,
originator: &Originator,
) -> Result<PluginUninstallResponse, JSONRPCErrorError> {
let PluginUninstallParams { plugin_id } = params;
if codex_plugin::PluginId::parse(&plugin_id).is_err()
@@ -1626,7 +1636,7 @@ impl PluginRequestProcessor {
let plugins_manager = self.thread_manager.plugins_manager();
plugins_manager
.uninstall_plugin(plugin_id)
.uninstall_plugin_with_originator(plugin_id, originator)
.await
.map_err(Self::plugin_uninstall_error)?;
match self.load_latest_config(/*fallback_cwd*/ None).await {
+35 -7
View File
@@ -59,6 +59,7 @@ use codex_core_skills::SkillMetadata;
use codex_hooks::plugin_hook_declarations;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::Originator;
use codex_plugin::AppConnectorId;
use codex_plugin::PluginCapabilitySummary;
use codex_plugin::PluginId;
@@ -831,13 +832,22 @@ impl PluginsManager {
pub async fn install_plugin(
&self,
request: PluginInstallRequest,
) -> Result<PluginInstallOutcome, PluginInstallError> {
self.install_plugin_with_originator(request, &Originator::process_default())
.await
}
pub async fn install_plugin_with_originator(
&self,
request: PluginInstallRequest,
originator: &Originator,
) -> Result<PluginInstallOutcome, PluginInstallError> {
let resolved = find_installable_marketplace_plugin(
&request.marketplace_path,
&request.plugin_name,
self.restriction_product,
)?;
self.install_resolved_plugin(resolved).await
self.install_resolved_plugin(resolved, originator).await
}
pub async fn install_plugin_with_remote_sync(
@@ -860,12 +870,14 @@ impl PluginsManager {
)
.await
.map_err(PluginInstallError::from)?;
self.install_resolved_plugin(resolved).await
self.install_resolved_plugin(resolved, &Originator::process_default())
.await
}
async fn install_resolved_plugin(
&self,
resolved: ResolvedMarketplacePlugin,
originator: &Originator,
) -> Result<PluginInstallOutcome, PluginInstallError> {
let auth_policy = resolved.policy.authentication;
let plugin_version =
@@ -909,9 +921,10 @@ impl PluginsManager {
Err(err) => err.into_inner().clone(),
};
if let Some(analytics_events_client) = analytics_events_client {
analytics_events_client.track_plugin_installed(
analytics_events_client.track_plugin_installed_with_originator(
plugin_telemetry_metadata_from_root(&result.plugin_id, &result.installed_path)
.await,
originator,
);
}
@@ -924,8 +937,17 @@ impl PluginsManager {
}
pub async fn uninstall_plugin(&self, plugin_id: String) -> Result<(), PluginUninstallError> {
self.uninstall_plugin_with_originator(plugin_id, &Originator::process_default())
.await
}
pub async fn uninstall_plugin_with_originator(
&self,
plugin_id: String,
originator: &Originator,
) -> Result<(), PluginUninstallError> {
let plugin_id = PluginId::parse(&plugin_id)?;
self.uninstall_plugin_id(plugin_id).await
self.uninstall_plugin_id(plugin_id, originator).await
}
pub async fn uninstall_plugin_with_remote_sync(
@@ -946,10 +968,15 @@ impl PluginsManager {
)
.await
.map_err(PluginUninstallError::from)?;
self.uninstall_plugin_id(plugin_id).await
self.uninstall_plugin_id(plugin_id, &Originator::process_default())
.await
}
async fn uninstall_plugin_id(&self, plugin_id: PluginId) -> Result<(), PluginUninstallError> {
async fn uninstall_plugin_id(
&self,
plugin_id: PluginId,
originator: &Originator,
) -> Result<(), PluginUninstallError> {
let plugin_telemetry = if self.store.active_plugin_root(&plugin_id).is_some() {
Some(installed_plugin_telemetry_metadata(self.codex_home.as_path(), &plugin_id).await)
} else {
@@ -972,7 +999,8 @@ impl PluginsManager {
if let Some(plugin_telemetry) = plugin_telemetry
&& let Some(analytics_events_client) = analytics_events_client
{
analytics_events_client.track_plugin_uninstalled(plugin_telemetry);
analytics_events_client
.track_plugin_uninstalled_with_originator(plugin_telemetry, originator);
}
Ok(())
+1
View File
@@ -589,6 +589,7 @@ fn hook_run_analytics_payload(
.turn_id
.clone()
.unwrap_or_else(|| turn_context.sub_id.clone()),
turn_context.originator.value().to_string(),
),
HookRunFact {
event_name: completed.run.event_name,
+1
View File
@@ -948,6 +948,7 @@ async fn maybe_track_codex_app_used(
turn_context.model_info.slug.clone(),
sess.conversation_id.to_string(),
turn_context.sub_id.clone(),
turn_context.originator.value().to_string(),
);
sess.services.analytics_events_client.track_app_used(
tracking,
+1
View File
@@ -464,6 +464,7 @@ async fn build_skills_and_plugins(
turn_context.model_info.slug.clone(),
sess.conversation_id.to_string(),
turn_context.sub_id.clone(),
turn_context.originator.value().to_string(),
);
let loaded_plugins = sess
.services
+1
View File
@@ -102,6 +102,7 @@ pub(crate) async fn maybe_emit_implicit_skill_invocation(
turn_context.model_info.slug.clone(),
sess.conversation_id.to_string(),
turn_context.sub_id.clone(),
turn_context.originator.value().to_string(),
),
vec![invocation],
);