From 094106eda9bbef889f4d4c60c9fa485d57034a14 Mon Sep 17 00:00:00 2001 From: James Chu Date: Thu, 23 Apr 2026 17:08:09 -0400 Subject: [PATCH] Add usage-limit banner analytics plumbing --- .../analytics/src/analytics_client_tests.rs | 6 ++--- codex-rs/analytics/src/events.rs | 22 ++++++++++--------- .../schema/json/ClientRequest.json | 15 +++++++++---- .../codex_app_server_protocol.schemas.json | 15 +++++++++---- .../codex_app_server_protocol.v2.schemas.json | 15 +++++++++---- .../RawResponseItemCompletedNotification.json | 2 +- .../schema/json/v2/ThreadResumeParams.json | 2 +- .../json/v2/TrackUsageLimitBannerParams.json | 20 ++++++++--------- .../v2/TrackUsageLimitBannerParams.ts | 4 ++-- .../typescript/v2/UsageLimitBannerType.ts | 5 +++++ .../schema/typescript/v2/index.ts | 1 + .../src/protocol/common.rs | 4 ++-- .../app-server-protocol/src/protocol/v2.rs | 10 ++++++++- codex-rs/app-server/README.md | 6 ++--- 14 files changed, 82 insertions(+), 45 deletions(-) create mode 100644 codex-rs/app-server-protocol/schema/typescript/v2/UsageLimitBannerType.ts diff --git a/codex-rs/analytics/src/analytics_client_tests.rs b/codex-rs/analytics/src/analytics_client_tests.rs index 04e7d14629..4f8a05fee7 100644 --- a/codex-rs/analytics/src/analytics_client_tests.rs +++ b/codex-rs/analytics/src/analytics_client_tests.rs @@ -55,7 +55,6 @@ use crate::facts::TurnTokenUsageFact; use crate::reducer::AnalyticsReducer; use crate::reducer::normalize_path_for_skill_id; use crate::reducer::skill_id_for_local_skill; -use codex_app_server_protocol::AddCreditsNudgeCreditType; use codex_app_server_protocol::ApprovalsReviewer as AppServerApprovalsReviewer; use codex_app_server_protocol::AskForApproval as AppServerAskForApproval; use codex_app_server_protocol::ClientInfo; @@ -77,6 +76,7 @@ use codex_app_server_protocol::ThreadStartResponse; use codex_app_server_protocol::ThreadStatus as AppServerThreadStatus; use codex_app_server_protocol::TrackUsageLimitBannerAction; use codex_app_server_protocol::TrackUsageLimitBannerParams; +use codex_app_server_protocol::UsageLimitBannerType; use codex_app_server_protocol::Turn; use codex_app_server_protocol::TurnCompletedNotification; use codex_app_server_protocol::TurnError as AppServerTurnError; @@ -2421,7 +2421,7 @@ async fn usage_limit_banner_shown_request_emits_credits_event() { request_id: RequestId::Integer(1), params: TrackUsageLimitBannerParams { action: TrackUsageLimitBannerAction::Shown, - credit_type: AddCreditsNudgeCreditType::Credits, + banner_type: UsageLimitBannerType::WorkspaceMemberCreditsDepleted, }, }), }, @@ -2457,7 +2457,7 @@ async fn usage_limit_banner_click_request_emits_usage_limit_event() { request_id: RequestId::Integer(1), params: TrackUsageLimitBannerParams { action: TrackUsageLimitBannerAction::CtaClicked, - credit_type: AddCreditsNudgeCreditType::UsageLimit, + banner_type: UsageLimitBannerType::WorkspaceMemberUsageLimitReached, }, }), }, diff --git a/codex-rs/analytics/src/events.rs b/codex-rs/analytics/src/events.rs index c2f32a4d59..61b0f6d829 100644 --- a/codex-rs/analytics/src/events.rs +++ b/codex-rs/analytics/src/events.rs @@ -19,10 +19,10 @@ use crate::facts::TurnSteerRejectionReason; use crate::facts::TurnSteerResult; use crate::facts::TurnSubmissionType; use crate::now_unix_seconds; -use codex_app_server_protocol::AddCreditsNudgeCreditType; use codex_app_server_protocol::CodexErrorInfo; use codex_app_server_protocol::TrackUsageLimitBannerAction; use codex_app_server_protocol::TrackUsageLimitBannerParams; +use codex_app_server_protocol::UsageLimitBannerType; use codex_login::default_client::originator; use codex_plugin::PluginTelemetryMetadata; use codex_protocol::approvals::NetworkApprovalProtocol; @@ -593,17 +593,19 @@ pub(crate) fn plugin_state_event_type(state: PluginState) -> &'static str { pub(crate) fn usage_limit_banner_event_request( params: TrackUsageLimitBannerParams, ) -> UsageLimitBannerEventRequest { - let limit_reason = match params.credit_type { - AddCreditsNudgeCreditType::Credits => "credits", - AddCreditsNudgeCreditType::UsageLimit => "usage_limit", + let limit_reason = match params.banner_type { + UsageLimitBannerType::WorkspaceMemberCreditsDepleted => "credits", + UsageLimitBannerType::WorkspaceMemberUsageLimitReached => "usage_limit", }; - let banner_type = match params.credit_type { - AddCreditsNudgeCreditType::Credits => "workspace_member_credits_depleted", - AddCreditsNudgeCreditType::UsageLimit => "workspace_member_usage_limit_reached", + let banner_type = match params.banner_type { + UsageLimitBannerType::WorkspaceMemberCreditsDepleted => "workspace_member_credits_depleted", + UsageLimitBannerType::WorkspaceMemberUsageLimitReached => { + "workspace_member_usage_limit_reached" + } }; - let cta_action = match params.credit_type { - AddCreditsNudgeCreditType::Credits => "notify_owner", - AddCreditsNudgeCreditType::UsageLimit => "request_increase", + let cta_action = match params.banner_type { + UsageLimitBannerType::WorkspaceMemberCreditsDepleted => "notify_owner", + UsageLimitBannerType::WorkspaceMemberUsageLimitReached => "request_increase", }; let cta_action = match params.action { TrackUsageLimitBannerAction::Shown => None, diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index 14e02c1188..0ee16b662c 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -4094,13 +4094,13 @@ "action": { "$ref": "#/definitions/TrackUsageLimitBannerAction" }, - "creditType": { - "$ref": "#/definitions/AddCreditsNudgeCreditType" + "bannerType": { + "$ref": "#/definitions/UsageLimitBannerType" } }, "required": [ "action", - "creditType" + "bannerType" ], "type": "object" }, @@ -4287,6 +4287,13 @@ ], "type": "object" }, + "UsageLimitBannerType": { + "enum": [ + "workspace_member_credits_depleted", + "workspace_member_usage_limit_reached" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { @@ -6170,4 +6177,4 @@ } ], "title": "ClientRequest" -} +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 0397cca7af..650e6ab575 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -16930,13 +16930,13 @@ "action": { "$ref": "#/definitions/v2/TrackUsageLimitBannerAction" }, - "creditType": { - "$ref": "#/definitions/v2/AddCreditsNudgeCreditType" + "bannerType": { + "$ref": "#/definitions/v2/UsageLimitBannerType" } }, "required": [ "action", - "creditType" + "bannerType" ], "title": "TrackUsageLimitBannerParams", "type": "object" @@ -17370,6 +17370,13 @@ "title": "TurnSteerResponse", "type": "object" }, + "UsageLimitBannerType": { + "enum": [ + "workspace_member_credits_depleted", + "workspace_member_usage_limit_reached" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { @@ -17805,4 +17812,4 @@ }, "title": "CodexAppServerProtocol", "type": "object" -} +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 2a48819d84..c55362a25e 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -14816,13 +14816,13 @@ "action": { "$ref": "#/definitions/TrackUsageLimitBannerAction" }, - "creditType": { - "$ref": "#/definitions/AddCreditsNudgeCreditType" + "bannerType": { + "$ref": "#/definitions/UsageLimitBannerType" } }, "required": [ "action", - "creditType" + "bannerType" ], "title": "TrackUsageLimitBannerParams", "type": "object" @@ -15256,6 +15256,13 @@ "title": "TurnSteerResponse", "type": "object" }, + "UsageLimitBannerType": { + "enum": [ + "workspace_member_credits_depleted", + "workspace_member_usage_limit_reached" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { @@ -15690,4 +15697,4 @@ }, "title": "CodexAppServerProtocolV2", "type": "object" -} +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/RawResponseItemCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/RawResponseItemCompletedNotification.json index 34e4086c59..d877286d89 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/RawResponseItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/RawResponseItemCompletedNotification.json @@ -922,4 +922,4 @@ ], "title": "RawResponseItemCompletedNotification", "type": "object" -} +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json index 872a3eb324..f3fe5648bf 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json @@ -1452,4 +1452,4 @@ ], "title": "ThreadResumeParams", "type": "object" -} +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/json/v2/TrackUsageLimitBannerParams.json b/codex-rs/app-server-protocol/schema/json/v2/TrackUsageLimitBannerParams.json index 8564e305b8..702b002192 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TrackUsageLimitBannerParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TrackUsageLimitBannerParams.json @@ -1,32 +1,32 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { - "AddCreditsNudgeCreditType": { - "enum": [ - "credits", - "usage_limit" - ], - "type": "string" - }, "TrackUsageLimitBannerAction": { "enum": [ "shown", "cta_clicked" ], "type": "string" + }, + "UsageLimitBannerType": { + "enum": [ + "workspace_member_credits_depleted", + "workspace_member_usage_limit_reached" + ], + "type": "string" } }, "properties": { "action": { "$ref": "#/definitions/TrackUsageLimitBannerAction" }, - "creditType": { - "$ref": "#/definitions/AddCreditsNudgeCreditType" + "bannerType": { + "$ref": "#/definitions/UsageLimitBannerType" } }, "required": [ "action", - "creditType" + "bannerType" ], "title": "TrackUsageLimitBannerParams", "type": "object" diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/TrackUsageLimitBannerParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/TrackUsageLimitBannerParams.ts index 0a5244c6c0..3dde025b2b 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/TrackUsageLimitBannerParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/TrackUsageLimitBannerParams.ts @@ -1,7 +1,7 @@ // GENERATED CODE! DO NOT MODIFY BY HAND! // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { AddCreditsNudgeCreditType } from "./AddCreditsNudgeCreditType"; import type { TrackUsageLimitBannerAction } from "./TrackUsageLimitBannerAction"; +import type { UsageLimitBannerType } from "./UsageLimitBannerType"; -export type TrackUsageLimitBannerParams = { action: TrackUsageLimitBannerAction, creditType: AddCreditsNudgeCreditType, }; +export type TrackUsageLimitBannerParams = { action: TrackUsageLimitBannerAction, bannerType: UsageLimitBannerType, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/UsageLimitBannerType.ts b/codex-rs/app-server-protocol/schema/typescript/v2/UsageLimitBannerType.ts new file mode 100644 index 0000000000..924c3d7865 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/UsageLimitBannerType.ts @@ -0,0 +1,5 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type UsageLimitBannerType = "workspace_member_credits_depleted" | "workspace_member_usage_limit_reached"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index bf7b450fb0..a667d35a32 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -405,6 +405,7 @@ export type { TurnStartedNotification } from "./TurnStartedNotification"; export type { TurnStatus } from "./TurnStatus"; export type { TurnSteerParams } from "./TurnSteerParams"; export type { TurnSteerResponse } from "./TurnSteerResponse"; +export type { UsageLimitBannerType } from "./UsageLimitBannerType"; export type { UserInput } from "./UserInput"; export type { WarningNotification } from "./WarningNotification"; export type { WebSearchAction } from "./WebSearchAction"; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index 8bfff5fea5..7a3720066a 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -1473,7 +1473,7 @@ mod tests { request_id: RequestId::Integer(2), params: v2::TrackUsageLimitBannerParams { action: v2::TrackUsageLimitBannerAction::CtaClicked, - credit_type: v2::AddCreditsNudgeCreditType::UsageLimit, + banner_type: v2::UsageLimitBannerType::WorkspaceMemberUsageLimitReached, }, }; assert_eq!(request.id(), &RequestId::Integer(2)); @@ -1484,7 +1484,7 @@ mod tests { "id": 2, "params": { "action": "cta_clicked", - "creditType": "usage_limit", + "bannerType": "workspace_member_usage_limit_reached", }, }), serde_json::to_value(&request)?, diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 02797903b8..10d03404ce 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -2255,7 +2255,7 @@ pub struct SendAddCreditsNudgeEmailParams { #[ts(export_to = "v2/")] pub struct TrackUsageLimitBannerParams { pub action: TrackUsageLimitBannerAction, - pub credit_type: AddCreditsNudgeCreditType, + pub banner_type: UsageLimitBannerType, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] @@ -2266,6 +2266,14 @@ pub enum TrackUsageLimitBannerAction { CtaClicked, } +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "snake_case")] +#[ts(export_to = "v2/", rename_all = "snake_case")] +pub enum UsageLimitBannerType { + WorkspaceMemberCreditsDepleted, + WorkspaceMemberUsageLimitReached, +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 91c3f8ac4f..d2260ddb72 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -1672,14 +1672,14 @@ Field notes: Use `creditType: "credits"` when workspace credits are depleted, or `creditType: "usage_limit"` when the workspace usage limit has been reached. If the owner was already notified recently, the response status is `cooldown_active`. -### 9) Track the workspace-owner nudge prompt +### 9) Track a usage-limit banner ```json -{ "method": "account/usageLimitBanner/track", "id": 9, "params": { "action": "shown", "creditType": "usage_limit" } } +{ "method": "account/usageLimitBanner/track", "id": 9, "params": { "action": "shown", "bannerType": "workspace_member_usage_limit_reached" } } { "id": 9, "result": {} } ``` -Use `action: "shown"` when the prompt is displayed, and `action: "cta_clicked"` when the user confirms the prompt. +Use `action: "shown"` when the banner is displayed, and `action: "cta_clicked"` when the user confirms it. The current workspace-owner nudge variants are `workspace_member_credits_depleted` and `workspace_member_usage_limit_reached`. ## Experimental API Opt-in