From 9c4d68685a4164fae8eda6da24edbc98ee5f5b6b Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Sat, 30 May 2026 14:08:17 -0300 Subject: [PATCH] fix(usage): hide mirrored app plugin entries --- codex-rs/state/src/runtime/usage.rs | 81 ++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/codex-rs/state/src/runtime/usage.rs b/codex-rs/state/src/runtime/usage.rs index c4cdd03dd6..95409a7485 100644 --- a/codex-rs/state/src/runtime/usage.rs +++ b/codex-rs/state/src/runtime/usage.rs @@ -133,6 +133,14 @@ INSERT INTO usage_sample_contributors ( .bind(until) .fetch_one(self.pool.as_ref()) .await?; + let apps = self + .read_usage_contributors(since, until, UsageContributorKind::App, total_tokens) + .await?; + let plugins = suppress_app_mirror_plugins( + &apps, + self.read_usage_contributors(since, until, UsageContributorKind::Plugin, total_tokens) + .await?, + ); let mut report = UsageReport { range, generated_at: now, @@ -146,9 +154,7 @@ INSERT INTO usage_sample_contributors ( agent_tasks: self .read_agent_task_usage(since, until, total_tokens) .await?, - apps: self - .read_usage_contributors(since, until, UsageContributorKind::App, total_tokens) - .await?, + apps, mcp_servers: self .read_usage_contributors( since, @@ -157,9 +163,7 @@ INSERT INTO usage_sample_contributors ( total_tokens, ) .await?, - plugins: self - .read_usage_contributors(since, until, UsageContributorKind::Plugin, total_tokens) - .await?, + plugins, }; report.headline = usage_headline(&report); Ok(report) @@ -423,6 +427,17 @@ fn usage_headline(report: &UsageReport) -> Option { Some(UsageHeadline { entry, note }) } +fn suppress_app_mirror_plugins(apps: &[UsageEntry], plugins: Vec) -> Vec { + plugins + .into_iter() + .filter(|plugin| { + !apps.iter().any(|app| { + app.label == plugin.label && app.attributed_tokens == plugin.attributed_tokens + }) + }) + .collect() +} + fn agent_task_label(source: &str) -> String { let parsed_source = serde_json::from_str(source) .or_else(|_| serde_json::from_value::(Value::String(source.to_string()))); @@ -714,6 +729,44 @@ mod tests { ); } + #[test] + fn suppress_app_mirror_plugins_keeps_non_mirror_plugins() { + let apps = vec![usage_entry( + UsageContributorKind::App, + "connector_gmail", + "Gmail", + /*attributed_tokens*/ 340, + /*percent_of_usage*/ 10, + )]; + let plugins = vec![ + usage_entry( + UsageContributorKind::Plugin, + "Gmail", + "Gmail", + /*attributed_tokens*/ 340, + /*percent_of_usage*/ 10, + ), + usage_entry( + UsageContributorKind::Plugin, + "Workspace", + "Workspace", + /*attributed_tokens*/ 500, + /*percent_of_usage*/ 15, + ), + ]; + + assert_eq!( + suppress_app_mirror_plugins(&apps, plugins), + vec![usage_entry( + UsageContributorKind::Plugin, + "Workspace", + "Workspace", + /*attributed_tokens*/ 500, + /*percent_of_usage*/ 15, + )] + ); + } + #[tokio::test] async fn usage_report_groups_agent_tasks_by_subagent_source() { let (codex_home, runtime) = usage_runtime().await; @@ -1127,6 +1180,22 @@ mod tests { } } + fn usage_entry( + kind: UsageContributorKind, + id: &str, + label: &str, + attributed_tokens: i64, + percent_of_usage: u8, + ) -> UsageEntry { + UsageEntry { + kind, + id: id.to_string(), + label: label.to_string(), + attributed_tokens, + percent_of_usage, + } + } + async fn usage_sample_count(runtime: &StateRuntime) -> i64 { sqlx::query_scalar("SELECT COUNT(*) FROM usage_samples") .fetch_one(runtime.pool.as_ref())