mirror of
https://github.com/openai/codex.git
synced 2026-11-09 08:40:33 +00:00
[codex] Propagate rate limit reached type (#18227)
## Summary First PR in the split from #17956. - adds the core/app-server `RateLimitReachedType` shape - maps backend `rate_limit_reached_type` into Codex rate-limit snapshots - carries the field through app-server notifications/responses and generated schemas - updates existing constructors/tests for the new optional field ## Validation - `cargo test -p codex-backend-client` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-app-server rate_limits` - `cargo test -p codex-tui workspace_` - `cargo test -p codex-tui status_` - `just fmt` - `just fix -p codex-backend-client` - `just fix -p codex-app-server-protocol` - `just fix -p codex-app-server` - `just fix -p codex-tui`
This commit is contained in:
1 parent
f017a23835
commit
139fa8b8f2
27 files changed
+371
-6
No files matched your search
@@ -2046,6 +2046,16 @@
|
|||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"RateLimitSnapshot": {
|
"RateLimitSnapshot": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"credits": {
|
"credits": {
|
||||||
@@ -2090,6 +2100,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10692,6 +10692,16 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"RateLimitSnapshot": {
|
"RateLimitSnapshot": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"credits": {
|
"credits": {
|
||||||
@@ -10736,6 +10746,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/v2/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7444,6 +7444,16 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"RateLimitSnapshot": {
|
"RateLimitSnapshot": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"credits": {
|
"credits": {
|
||||||
@@ -7488,6 +7498,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,16 @@
|
|||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"RateLimitSnapshot": {
|
"RateLimitSnapshot": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"credits": {
|
"credits": {
|
||||||
@@ -83,6 +93,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,16 @@
|
|||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"RateLimitSnapshot": {
|
"RateLimitSnapshot": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"credits": {
|
"credits": {
|
||||||
@@ -83,6 +93,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 RateLimitReachedType = "rate_limit_reached" | "workspace_owner_credits_depleted" | "workspace_member_credits_depleted" | "workspace_owner_usage_limit_reached" | "workspace_member_usage_limit_reached";
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
import type { PlanType } from "../PlanType";
|
import type { PlanType } from "../PlanType";
|
||||||
import type { CreditsSnapshot } from "./CreditsSnapshot";
|
import type { CreditsSnapshot } from "./CreditsSnapshot";
|
||||||
|
import type { RateLimitReachedType } from "./RateLimitReachedType";
|
||||||
import type { RateLimitWindow } from "./RateLimitWindow";
|
import type { RateLimitWindow } from "./RateLimitWindow";
|
||||||
|
|
||||||
export type RateLimitSnapshot = { limitId: string | null, limitName: string | null, primary: RateLimitWindow | null, secondary: RateLimitWindow | null, credits: CreditsSnapshot | null, planType: PlanType | null, };
|
export type RateLimitSnapshot = { limitId: string | null, limitName: string | null, primary: RateLimitWindow | null, secondary: RateLimitWindow | null, credits: CreditsSnapshot | null, planType: PlanType | null, rateLimitReachedType: RateLimitReachedType | null, };
|
||||||
@@ -241,6 +241,7 @@ export type { PluginUninstallParams } from "./PluginUninstallParams";
|
|||||||
export type { PluginUninstallResponse } from "./PluginUninstallResponse";
|
export type { PluginUninstallResponse } from "./PluginUninstallResponse";
|
||||||
export type { PluginsMigration } from "./PluginsMigration";
|
export type { PluginsMigration } from "./PluginsMigration";
|
||||||
export type { ProfileV2 } from "./ProfileV2";
|
export type { ProfileV2 } from "./ProfileV2";
|
||||||
|
export type { RateLimitReachedType } from "./RateLimitReachedType";
|
||||||
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
|
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
|
||||||
export type { RateLimitWindow } from "./RateLimitWindow";
|
export type { RateLimitWindow } from "./RateLimitWindow";
|
||||||
export type { RawResponseItemCompletedNotification } from "./RawResponseItemCompletedNotification";
|
export type { RawResponseItemCompletedNotification } from "./RawResponseItemCompletedNotification";
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ use codex_protocol::protocol::ModelRerouteReason as CoreModelRerouteReason;
|
|||||||
use codex_protocol::protocol::NetworkAccess as CoreNetworkAccess;
|
use codex_protocol::protocol::NetworkAccess as CoreNetworkAccess;
|
||||||
use codex_protocol::protocol::NonSteerableTurnKind as CoreNonSteerableTurnKind;
|
use codex_protocol::protocol::NonSteerableTurnKind as CoreNonSteerableTurnKind;
|
||||||
use codex_protocol::protocol::PatchApplyStatus as CorePatchApplyStatus;
|
use codex_protocol::protocol::PatchApplyStatus as CorePatchApplyStatus;
|
||||||
|
use codex_protocol::protocol::RateLimitReachedType as CoreRateLimitReachedType;
|
||||||
use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot;
|
use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot;
|
||||||
use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow;
|
use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow;
|
||||||
use codex_protocol::protocol::ReadOnlyAccess as CoreReadOnlyAccess;
|
use codex_protocol::protocol::ReadOnlyAccess as CoreReadOnlyAccess;
|
||||||
@@ -6529,6 +6530,7 @@ pub struct RateLimitSnapshot {
|
|||||||
pub secondary: Option<RateLimitWindow>,
|
pub secondary: Option<RateLimitWindow>,
|
||||||
pub credits: Option<CreditsSnapshot>,
|
pub credits: Option<CreditsSnapshot>,
|
||||||
pub plan_type: Option<PlanType>,
|
pub plan_type: Option<PlanType>,
|
||||||
|
pub rate_limit_reached_type: Option<RateLimitReachedType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CoreRateLimitSnapshot> for RateLimitSnapshot {
|
impl From<CoreRateLimitSnapshot> for RateLimitSnapshot {
|
||||||
@@ -6540,6 +6542,60 @@ impl From<CoreRateLimitSnapshot> for RateLimitSnapshot {
|
|||||||
secondary: value.secondary.map(RateLimitWindow::from),
|
secondary: value.secondary.map(RateLimitWindow::from),
|
||||||
credits: value.credits.map(CreditsSnapshot::from),
|
credits: value.credits.map(CreditsSnapshot::from),
|
||||||
plan_type: value.plan_type,
|
plan_type: value.plan_type,
|
||||||
|
rate_limit_reached_type: value
|
||||||
|
.rate_limit_reached_type
|
||||||
|
.map(RateLimitReachedType::from),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 RateLimitReachedType {
|
||||||
|
RateLimitReached,
|
||||||
|
WorkspaceOwnerCreditsDepleted,
|
||||||
|
WorkspaceMemberCreditsDepleted,
|
||||||
|
WorkspaceOwnerUsageLimitReached,
|
||||||
|
WorkspaceMemberUsageLimitReached,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CoreRateLimitReachedType> for RateLimitReachedType {
|
||||||
|
fn from(value: CoreRateLimitReachedType) -> Self {
|
||||||
|
match value {
|
||||||
|
CoreRateLimitReachedType::RateLimitReached => Self::RateLimitReached,
|
||||||
|
CoreRateLimitReachedType::WorkspaceOwnerCreditsDepleted => {
|
||||||
|
Self::WorkspaceOwnerCreditsDepleted
|
||||||
|
}
|
||||||
|
CoreRateLimitReachedType::WorkspaceMemberCreditsDepleted => {
|
||||||
|
Self::WorkspaceMemberCreditsDepleted
|
||||||
|
}
|
||||||
|
CoreRateLimitReachedType::WorkspaceOwnerUsageLimitReached => {
|
||||||
|
Self::WorkspaceOwnerUsageLimitReached
|
||||||
|
}
|
||||||
|
CoreRateLimitReachedType::WorkspaceMemberUsageLimitReached => {
|
||||||
|
Self::WorkspaceMemberUsageLimitReached
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RateLimitReachedType> for CoreRateLimitReachedType {
|
||||||
|
fn from(value: RateLimitReachedType) -> Self {
|
||||||
|
match value {
|
||||||
|
RateLimitReachedType::RateLimitReached => Self::RateLimitReached,
|
||||||
|
RateLimitReachedType::WorkspaceOwnerCreditsDepleted => {
|
||||||
|
Self::WorkspaceOwnerCreditsDepleted
|
||||||
|
}
|
||||||
|
RateLimitReachedType::WorkspaceMemberCreditsDepleted => {
|
||||||
|
Self::WorkspaceMemberCreditsDepleted
|
||||||
|
}
|
||||||
|
RateLimitReachedType::WorkspaceOwnerUsageLimitReached => {
|
||||||
|
Self::WorkspaceOwnerUsageLimitReached
|
||||||
|
}
|
||||||
|
RateLimitReachedType::WorkspaceMemberUsageLimitReached => {
|
||||||
|
Self::WorkspaceMemberUsageLimitReached
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4138,6 +4138,7 @@ mod tests {
|
|||||||
balance: Some("5".to_string()),
|
balance: Some("5".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
handle_token_count_event(
|
handle_token_count_event(
|
||||||
|
|||||||
@@ -736,6 +736,7 @@ mod tests {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(PlanType::Plus),
|
plan_type: Some(PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -754,7 +755,8 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"secondary": null,
|
"secondary": null,
|
||||||
"credits": null,
|
"credits": null,
|
||||||
"planType": "plus"
|
"planType": "plus",
|
||||||
|
"rateLimitReachedType": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use codex_app_server_protocol::GetAccountRateLimitsResponse;
|
|||||||
use codex_app_server_protocol::JSONRPCError;
|
use codex_app_server_protocol::JSONRPCError;
|
||||||
use codex_app_server_protocol::JSONRPCResponse;
|
use codex_app_server_protocol::JSONRPCResponse;
|
||||||
use codex_app_server_protocol::LoginAccountResponse;
|
use codex_app_server_protocol::LoginAccountResponse;
|
||||||
|
use codex_app_server_protocol::RateLimitReachedType;
|
||||||
use codex_app_server_protocol::RateLimitSnapshot;
|
use codex_app_server_protocol::RateLimitSnapshot;
|
||||||
use codex_app_server_protocol::RateLimitWindow;
|
use codex_app_server_protocol::RateLimitWindow;
|
||||||
use codex_app_server_protocol::RequestId;
|
use codex_app_server_protocol::RequestId;
|
||||||
@@ -118,6 +119,9 @@ async fn get_account_rate_limits_returns_snapshot() -> Result<()> {
|
|||||||
"reset_at": secondary_reset_timestamp,
|
"reset_at": secondary_reset_timestamp,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rate_limit_reached_type": {
|
||||||
|
"type": "workspace_member_usage_limit_reached",
|
||||||
|
},
|
||||||
"additional_rate_limits": [
|
"additional_rate_limits": [
|
||||||
{
|
{
|
||||||
"limit_name": "codex_other",
|
"limit_name": "codex_other",
|
||||||
@@ -173,6 +177,7 @@ async fn get_account_rate_limits_returns_snapshot() -> Result<()> {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(AccountPlanType::Pro),
|
plan_type: Some(AccountPlanType::Pro),
|
||||||
|
rate_limit_reached_type: Some(RateLimitReachedType::WorkspaceMemberUsageLimitReached),
|
||||||
},
|
},
|
||||||
rate_limits_by_limit_id: Some(
|
rate_limits_by_limit_id: Some(
|
||||||
[
|
[
|
||||||
@@ -193,6 +198,9 @@ async fn get_account_rate_limits_returns_snapshot() -> Result<()> {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(AccountPlanType::Pro),
|
plan_type: Some(AccountPlanType::Pro),
|
||||||
|
rate_limit_reached_type: Some(
|
||||||
|
RateLimitReachedType::WorkspaceMemberUsageLimitReached,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@@ -208,6 +216,7 @@ async fn get_account_rate_limits_returns_snapshot() -> Result<()> {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(AccountPlanType::Pro),
|
plan_type: Some(AccountPlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::types::CodeTaskDetailsResponse;
|
use crate::types::CodeTaskDetailsResponse;
|
||||||
use crate::types::ConfigFileResponse;
|
use crate::types::ConfigFileResponse;
|
||||||
use crate::types::PaginatedListTaskListItem;
|
use crate::types::PaginatedListTaskListItem;
|
||||||
|
use crate::types::RateLimitReachedKind as BackendRateLimitReachedKind;
|
||||||
use crate::types::RateLimitStatusPayload;
|
use crate::types::RateLimitStatusPayload;
|
||||||
use crate::types::TurnAttemptsSiblingTurnsResponse;
|
use crate::types::TurnAttemptsSiblingTurnsResponse;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -9,6 +10,7 @@ use codex_login::CodexAuth;
|
|||||||
use codex_login::default_client::get_codex_user_agent;
|
use codex_login::default_client::get_codex_user_agent;
|
||||||
use codex_protocol::account::PlanType as AccountPlanType;
|
use codex_protocol::account::PlanType as AccountPlanType;
|
||||||
use codex_protocol::protocol::CreditsSnapshot;
|
use codex_protocol::protocol::CreditsSnapshot;
|
||||||
|
use codex_protocol::protocol::RateLimitReachedType;
|
||||||
use codex_protocol::protocol::RateLimitSnapshot;
|
use codex_protocol::protocol::RateLimitSnapshot;
|
||||||
use codex_protocol::protocol::RateLimitWindow;
|
use codex_protocol::protocol::RateLimitWindow;
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
@@ -412,12 +414,17 @@ impl Client {
|
|||||||
payload: RateLimitStatusPayload,
|
payload: RateLimitStatusPayload,
|
||||||
) -> Vec<RateLimitSnapshot> {
|
) -> Vec<RateLimitSnapshot> {
|
||||||
let plan_type = Some(Self::map_plan_type(payload.plan_type));
|
let plan_type = Some(Self::map_plan_type(payload.plan_type));
|
||||||
|
let rate_limit_reached_type = payload
|
||||||
|
.rate_limit_reached_type
|
||||||
|
.flatten()
|
||||||
|
.and_then(|details| Self::map_rate_limit_reached_type(details.kind));
|
||||||
let mut snapshots = vec![Self::make_rate_limit_snapshot(
|
let mut snapshots = vec![Self::make_rate_limit_snapshot(
|
||||||
Some("codex".to_string()),
|
Some("codex".to_string()),
|
||||||
/*limit_name*/ None,
|
/*limit_name*/ None,
|
||||||
payload.rate_limit.flatten().map(|details| *details),
|
payload.rate_limit.flatten().map(|details| *details),
|
||||||
payload.credits.flatten().map(|details| *details),
|
payload.credits.flatten().map(|details| *details),
|
||||||
plan_type,
|
plan_type,
|
||||||
|
rate_limit_reached_type,
|
||||||
)];
|
)];
|
||||||
if let Some(additional) = payload.additional_rate_limits.flatten() {
|
if let Some(additional) = payload.additional_rate_limits.flatten() {
|
||||||
snapshots.extend(additional.into_iter().map(|details| {
|
snapshots.extend(additional.into_iter().map(|details| {
|
||||||
@@ -427,6 +434,7 @@ impl Client {
|
|||||||
details.rate_limit.flatten().map(|rate_limit| *rate_limit),
|
details.rate_limit.flatten().map(|rate_limit| *rate_limit),
|
||||||
/*credits*/ None,
|
/*credits*/ None,
|
||||||
plan_type,
|
plan_type,
|
||||||
|
/*rate_limit_reached_type*/ None,
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -439,6 +447,7 @@ impl Client {
|
|||||||
rate_limit: Option<crate::types::RateLimitStatusDetails>,
|
rate_limit: Option<crate::types::RateLimitStatusDetails>,
|
||||||
credits: Option<crate::types::CreditStatusDetails>,
|
credits: Option<crate::types::CreditStatusDetails>,
|
||||||
plan_type: Option<AccountPlanType>,
|
plan_type: Option<AccountPlanType>,
|
||||||
|
rate_limit_reached_type: Option<RateLimitReachedType>,
|
||||||
) -> RateLimitSnapshot {
|
) -> RateLimitSnapshot {
|
||||||
let (primary, secondary) = match rate_limit {
|
let (primary, secondary) = match rate_limit {
|
||||||
Some(details) => (
|
Some(details) => (
|
||||||
@@ -454,6 +463,30 @@ impl Client {
|
|||||||
secondary,
|
secondary,
|
||||||
credits: Self::map_credits(credits),
|
credits: Self::map_credits(credits),
|
||||||
plan_type,
|
plan_type,
|
||||||
|
rate_limit_reached_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_rate_limit_reached_type(
|
||||||
|
kind: BackendRateLimitReachedKind,
|
||||||
|
) -> Option<RateLimitReachedType> {
|
||||||
|
match kind {
|
||||||
|
BackendRateLimitReachedKind::RateLimitReached => {
|
||||||
|
Some(RateLimitReachedType::RateLimitReached)
|
||||||
|
}
|
||||||
|
BackendRateLimitReachedKind::WorkspaceOwnerCreditsDepleted => {
|
||||||
|
Some(RateLimitReachedType::WorkspaceOwnerCreditsDepleted)
|
||||||
|
}
|
||||||
|
BackendRateLimitReachedKind::WorkspaceMemberCreditsDepleted => {
|
||||||
|
Some(RateLimitReachedType::WorkspaceMemberCreditsDepleted)
|
||||||
|
}
|
||||||
|
BackendRateLimitReachedKind::WorkspaceOwnerUsageLimitReached => {
|
||||||
|
Some(RateLimitReachedType::WorkspaceOwnerUsageLimitReached)
|
||||||
|
}
|
||||||
|
BackendRateLimitReachedKind::WorkspaceMemberUsageLimitReached => {
|
||||||
|
Some(RateLimitReachedType::WorkspaceMemberUsageLimitReached)
|
||||||
|
}
|
||||||
|
BackendRateLimitReachedKind::Unknown => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,6 +554,8 @@ impl Client {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use codex_backend_openapi_models::models::AdditionalRateLimitDetails;
|
use codex_backend_openapi_models::models::AdditionalRateLimitDetails;
|
||||||
|
use codex_backend_openapi_models::models::RateLimitReachedKind;
|
||||||
|
use codex_backend_openapi_models::models::RateLimitReachedType as BackendRateLimitReachedType;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -574,6 +609,9 @@ mod tests {
|
|||||||
balance: Some(Some("9.99".to_string())),
|
balance: Some(Some("9.99".to_string())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))),
|
}))),
|
||||||
|
rate_limit_reached_type: Some(Some(BackendRateLimitReachedType {
|
||||||
|
kind: RateLimitReachedKind::WorkspaceMemberCreditsDepleted,
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
||||||
@@ -598,6 +636,10 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(snapshots[0].plan_type, Some(AccountPlanType::Pro));
|
assert_eq!(snapshots[0].plan_type, Some(AccountPlanType::Pro));
|
||||||
|
assert_eq!(
|
||||||
|
snapshots[0].rate_limit_reached_type,
|
||||||
|
Some(RateLimitReachedType::WorkspaceMemberCreditsDepleted)
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(snapshots[1].limit_id.as_deref(), Some("codex_other"));
|
assert_eq!(snapshots[1].limit_id.as_deref(), Some("codex_other"));
|
||||||
assert_eq!(snapshots[1].limit_name.as_deref(), Some("codex_other"));
|
assert_eq!(snapshots[1].limit_name.as_deref(), Some("codex_other"));
|
||||||
@@ -607,6 +649,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(snapshots[1].credits, None);
|
assert_eq!(snapshots[1].credits, None);
|
||||||
assert_eq!(snapshots[1].plan_type, Some(AccountPlanType::Pro));
|
assert_eq!(snapshots[1].plan_type, Some(AccountPlanType::Pro));
|
||||||
|
assert_eq!(snapshots[1].rate_limit_reached_type, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -620,6 +663,7 @@ mod tests {
|
|||||||
rate_limit: None,
|
rate_limit: None,
|
||||||
}])),
|
}])),
|
||||||
credits: None,
|
credits: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
||||||
@@ -645,6 +689,7 @@ mod tests {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(AccountPlanType::Pro),
|
plan_type: Some(AccountPlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
},
|
},
|
||||||
RateLimitSnapshot {
|
RateLimitSnapshot {
|
||||||
limit_id: Some("codex".to_string()),
|
limit_id: Some("codex".to_string()),
|
||||||
@@ -657,6 +702,7 @@ mod tests {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(AccountPlanType::Pro),
|
plan_type: Some(AccountPlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -667,4 +713,58 @@ mod tests {
|
|||||||
.unwrap_or_else(|| snapshots[0].clone());
|
.unwrap_or_else(|| snapshots[0].clone());
|
||||||
assert_eq!(preferred.limit_id.as_deref(), Some("codex"));
|
assert_eq!(preferred.limit_id.as_deref(), Some("codex"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn usage_payload_maps_every_rate_limit_reached_type() {
|
||||||
|
let cases = [
|
||||||
|
(
|
||||||
|
RateLimitReachedKind::RateLimitReached,
|
||||||
|
Some(RateLimitReachedType::RateLimitReached),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RateLimitReachedKind::WorkspaceOwnerCreditsDepleted,
|
||||||
|
Some(RateLimitReachedType::WorkspaceOwnerCreditsDepleted),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RateLimitReachedKind::WorkspaceMemberCreditsDepleted,
|
||||||
|
Some(RateLimitReachedType::WorkspaceMemberCreditsDepleted),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RateLimitReachedKind::WorkspaceOwnerUsageLimitReached,
|
||||||
|
Some(RateLimitReachedType::WorkspaceOwnerUsageLimitReached),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RateLimitReachedKind::WorkspaceMemberUsageLimitReached,
|
||||||
|
Some(RateLimitReachedType::WorkspaceMemberUsageLimitReached),
|
||||||
|
),
|
||||||
|
(RateLimitReachedKind::Unknown, None),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (kind, expected) in cases {
|
||||||
|
let payload = RateLimitStatusPayload {
|
||||||
|
plan_type: crate::types::PlanType::Plus,
|
||||||
|
rate_limit: None,
|
||||||
|
credits: None,
|
||||||
|
additional_rate_limits: None,
|
||||||
|
rate_limit_reached_type: Some(Some(BackendRateLimitReachedType { kind })),
|
||||||
|
};
|
||||||
|
|
||||||
|
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
||||||
|
assert_eq!(snapshots[0].rate_limit_reached_type, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn usage_payload_preserves_absent_rate_limit_reached_type() {
|
||||||
|
let payload = RateLimitStatusPayload {
|
||||||
|
plan_type: crate::types::PlanType::Plus,
|
||||||
|
rate_limit: None,
|
||||||
|
credits: None,
|
||||||
|
additional_rate_limits: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let snapshots = Client::rate_limit_snapshots_from_payload(payload);
|
||||||
|
assert_eq!(snapshots[0].rate_limit_reached_type, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ pub use codex_backend_openapi_models::models::ConfigFileResponse;
|
|||||||
pub use codex_backend_openapi_models::models::CreditStatusDetails;
|
pub use codex_backend_openapi_models::models::CreditStatusDetails;
|
||||||
pub use codex_backend_openapi_models::models::PaginatedListTaskListItem;
|
pub use codex_backend_openapi_models::models::PaginatedListTaskListItem;
|
||||||
pub use codex_backend_openapi_models::models::PlanType;
|
pub use codex_backend_openapi_models::models::PlanType;
|
||||||
|
pub use codex_backend_openapi_models::models::RateLimitReachedKind;
|
||||||
pub use codex_backend_openapi_models::models::RateLimitStatusDetails;
|
pub use codex_backend_openapi_models::models::RateLimitStatusDetails;
|
||||||
pub use codex_backend_openapi_models::models::RateLimitStatusPayload;
|
pub use codex_backend_openapi_models::models::RateLimitStatusPayload;
|
||||||
pub use codex_backend_openapi_models::models::RateLimitWindowSnapshot;
|
pub use codex_backend_openapi_models::models::RateLimitWindowSnapshot;
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ pub fn parse_rate_limit_for_limit(
|
|||||||
secondary,
|
secondary,
|
||||||
credits,
|
credits,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +157,7 @@ pub fn parse_rate_limit_event(payload: &str) -> Option<RateLimitSnapshot> {
|
|||||||
secondary,
|
secondary,
|
||||||
credits,
|
credits,
|
||||||
plan_type: event.plan_type,
|
plan_type: event.plan_type,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ pub use self::additional_rate_limit_details::AdditionalRateLimitDetails;
|
|||||||
|
|
||||||
pub(crate) mod rate_limit_status_payload;
|
pub(crate) mod rate_limit_status_payload;
|
||||||
pub use self::rate_limit_status_payload::PlanType;
|
pub use self::rate_limit_status_payload::PlanType;
|
||||||
|
pub use self::rate_limit_status_payload::RateLimitReachedKind;
|
||||||
|
pub use self::rate_limit_status_payload::RateLimitReachedType;
|
||||||
pub use self::rate_limit_status_payload::RateLimitStatusPayload;
|
pub use self::rate_limit_status_payload::RateLimitStatusPayload;
|
||||||
|
|
||||||
pub(crate) mod rate_limit_status_details;
|
pub(crate) mod rate_limit_status_details;
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ pub struct RateLimitStatusPayload {
|
|||||||
skip_serializing_if = "Option::is_none"
|
skip_serializing_if = "Option::is_none"
|
||||||
)]
|
)]
|
||||||
pub additional_rate_limits: Option<Option<Vec<models::AdditionalRateLimitDetails>>>,
|
pub additional_rate_limits: Option<Option<Vec<models::AdditionalRateLimitDetails>>>,
|
||||||
|
#[serde(
|
||||||
|
rename = "rate_limit_reached_type",
|
||||||
|
default,
|
||||||
|
with = "::serde_with::rust::double_option",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub rate_limit_reached_type: Option<Option<RateLimitReachedType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RateLimitStatusPayload {
|
impl RateLimitStatusPayload {
|
||||||
@@ -46,10 +53,36 @@ impl RateLimitStatusPayload {
|
|||||||
rate_limit: None,
|
rate_limit: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
additional_rate_limits: None,
|
additional_rate_limits: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct RateLimitReachedType {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub kind: RateLimitReachedKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Default,
|
||||||
|
)]
|
||||||
|
pub enum RateLimitReachedKind {
|
||||||
|
#[serde(rename = "rate_limit_reached")]
|
||||||
|
RateLimitReached,
|
||||||
|
#[serde(rename = "workspace_owner_credits_depleted")]
|
||||||
|
WorkspaceOwnerCreditsDepleted,
|
||||||
|
#[serde(rename = "workspace_member_credits_depleted")]
|
||||||
|
WorkspaceMemberCreditsDepleted,
|
||||||
|
#[serde(rename = "workspace_owner_usage_limit_reached")]
|
||||||
|
WorkspaceOwnerUsageLimitReached,
|
||||||
|
#[serde(rename = "workspace_member_usage_limit_reached")]
|
||||||
|
WorkspaceMemberUsageLimitReached,
|
||||||
|
#[serde(rename = "unknown", other)]
|
||||||
|
#[default]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Default,
|
Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Default,
|
||||||
)]
|
)]
|
||||||
|
|||||||
@@ -2070,6 +2070,7 @@ async fn set_rate_limits_retains_previous_credits() {
|
|||||||
balance: Some("10.00".to_string()),
|
balance: Some("10.00".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
state.set_rate_limits(initial.clone());
|
state.set_rate_limits(initial.clone());
|
||||||
|
|
||||||
@@ -2088,6 +2089,7 @@ async fn set_rate_limits_retains_previous_credits() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
state.set_rate_limits(update.clone());
|
state.set_rate_limits(update.clone());
|
||||||
|
|
||||||
@@ -2100,6 +2102,7 @@ async fn set_rate_limits_retains_previous_credits() {
|
|||||||
secondary: update.secondary,
|
secondary: update.secondary,
|
||||||
credits: initial.credits,
|
credits: initial.credits,
|
||||||
plan_type: initial.plan_type,
|
plan_type: initial.plan_type,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2176,6 +2179,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
|||||||
balance: Some("15.00".to_string()),
|
balance: Some("15.00".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
state.set_rate_limits(initial.clone());
|
state.set_rate_limits(initial.clone());
|
||||||
|
|
||||||
@@ -2190,6 +2194,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(codex_protocol::account::PlanType::Pro),
|
plan_type: Some(codex_protocol::account::PlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
state.set_rate_limits(update.clone());
|
state.set_rate_limits(update.clone());
|
||||||
|
|
||||||
@@ -2202,6 +2207,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
|||||||
secondary: update.secondary,
|
secondary: update.secondary,
|
||||||
credits: initial.credits,
|
credits: initial.credits,
|
||||||
plan_type: update.plan_type,
|
plan_type: update.plan_type,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ async fn set_rate_limits_defaults_limit_id_to_codex_when_missing() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -114,6 +115,7 @@ async fn set_rate_limits_defaults_to_codex_when_limit_id_missing_after_other_buc
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
});
|
});
|
||||||
state.set_rate_limits(RateLimitSnapshot {
|
state.set_rate_limits(RateLimitSnapshot {
|
||||||
limit_id: None,
|
limit_id: None,
|
||||||
@@ -126,6 +128,7 @@ async fn set_rate_limits_defaults_to_codex_when_limit_id_missing_after_other_buc
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -157,6 +160,7 @@ async fn set_rate_limits_carries_credits_and_plan_type_from_codex_to_codex_other
|
|||||||
balance: Some("50".to_string()),
|
balance: Some("50".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
state.set_rate_limits(RateLimitSnapshot {
|
state.set_rate_limits(RateLimitSnapshot {
|
||||||
@@ -170,6 +174,7 @@ async fn set_rate_limits_carries_credits_and_plan_type_from_codex_to_codex_other
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -189,6 +194,7 @@ async fn set_rate_limits_carries_credits_and_plan_type_from_codex_to_codex_other
|
|||||||
balance: Some("50".to_string()),
|
balance: Some("50".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
plan_type: Some(codex_protocol::account::PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2375,7 +2375,8 @@ async fn token_count_includes_rate_limits_snapshot() {
|
|||||||
"resets_at": 1704074400
|
"resets_at": 1704074400
|
||||||
},
|
},
|
||||||
"credits": null,
|
"credits": null,
|
||||||
"plan_type": null
|
"plan_type": null,
|
||||||
|
"rate_limit_reached_type": null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -2426,7 +2427,8 @@ async fn token_count_includes_rate_limits_snapshot() {
|
|||||||
"resets_at": 1704074400
|
"resets_at": 1704074400
|
||||||
},
|
},
|
||||||
"credits": null,
|
"credits": null,
|
||||||
"plan_type": null
|
"plan_type": null,
|
||||||
|
"rate_limit_reached_type": null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -2500,7 +2502,8 @@ async fn usage_limit_error_emits_rate_limit_event() -> anyhow::Result<()> {
|
|||||||
"resets_at": null
|
"resets_at": null
|
||||||
},
|
},
|
||||||
"credits": null,
|
"credits": null,
|
||||||
"plan_type": null
|
"plan_type": null,
|
||||||
|
"rate_limit_reached_type": null
|
||||||
});
|
});
|
||||||
|
|
||||||
let submission_id = codex
|
let submission_id = codex
|
||||||
|
|||||||
@@ -1033,7 +1033,8 @@ async fn responses_websocket_usage_limit_error_emits_rate_limit_event() {
|
|||||||
"resets_at": null
|
"resets_at": null
|
||||||
},
|
},
|
||||||
"credits": null,
|
"credits": null,
|
||||||
"plan_type": null
|
"plan_type": null,
|
||||||
|
"rate_limit_reached_type": null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ fn rate_limit_snapshot() -> RateLimitSnapshot {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2200,6 +2200,18 @@ pub struct RateLimitSnapshot {
|
|||||||
pub secondary: Option<RateLimitWindow>,
|
pub secondary: Option<RateLimitWindow>,
|
||||||
pub credits: Option<CreditsSnapshot>,
|
pub credits: Option<CreditsSnapshot>,
|
||||||
pub plan_type: Option<crate::account::PlanType>,
|
pub plan_type: Option<crate::account::PlanType>,
|
||||||
|
pub rate_limit_reached_type: Option<RateLimitReachedType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema, TS)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[ts(rename_all = "snake_case")]
|
||||||
|
pub enum RateLimitReachedType {
|
||||||
|
RateLimitReached,
|
||||||
|
WorkspaceOwnerCreditsDepleted,
|
||||||
|
WorkspaceMemberCreditsDepleted,
|
||||||
|
WorkspaceOwnerUsageLimitReached,
|
||||||
|
WorkspaceMemberUsageLimitReached,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]
|
||||||
|
|||||||
@@ -1188,6 +1188,7 @@ pub(crate) fn app_server_rate_limit_snapshot_to_core(
|
|||||||
secondary: snapshot.secondary.map(app_server_rate_limit_window_to_core),
|
secondary: snapshot.secondary.map(app_server_rate_limit_window_to_core),
|
||||||
credits: snapshot.credits.map(app_server_credits_snapshot_to_core),
|
credits: snapshot.credits.map(app_server_credits_snapshot_to_core),
|
||||||
plan_type: snapshot.plan_type,
|
plan_type: snapshot.plan_type,
|
||||||
|
rate_limit_reached_type: snapshot.rate_limit_reached_type.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ pub(super) fn snapshot(percent: f64) -> RateLimitSnapshot {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ async fn rate_limit_snapshot_keeps_prior_credits_when_missing_from_headers() {
|
|||||||
balance: Some("17.5".to_string()),
|
balance: Some("17.5".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
let initial_balance = chat
|
let initial_balance = chat
|
||||||
.rate_limit_snapshots_by_limit_id
|
.rate_limit_snapshots_by_limit_id
|
||||||
@@ -254,6 +255,7 @@ async fn rate_limit_snapshot_keeps_prior_credits_when_missing_from_headers() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let display = chat
|
let display = chat
|
||||||
@@ -292,6 +294,7 @@ async fn rate_limit_snapshot_updates_and_retains_plan_type() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(PlanType::Plus),
|
plan_type: Some(PlanType::Plus),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
assert_eq!(chat.plan_type, Some(PlanType::Plus));
|
assert_eq!(chat.plan_type, Some(PlanType::Plus));
|
||||||
|
|
||||||
@@ -310,6 +313,7 @@ async fn rate_limit_snapshot_updates_and_retains_plan_type() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(PlanType::Pro),
|
plan_type: Some(PlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
assert_eq!(chat.plan_type, Some(PlanType::Pro));
|
assert_eq!(chat.plan_type, Some(PlanType::Pro));
|
||||||
|
|
||||||
@@ -328,6 +332,7 @@ async fn rate_limit_snapshot_updates_and_retains_plan_type() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
assert_eq!(chat.plan_type, Some(PlanType::Pro));
|
assert_eq!(chat.plan_type, Some(PlanType::Pro));
|
||||||
}
|
}
|
||||||
@@ -351,6 +356,7 @@ async fn rate_limit_snapshots_keep_separate_entries_per_limit_id() {
|
|||||||
balance: Some("5.00".to_string()),
|
balance: Some("5.00".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: Some(PlanType::Pro),
|
plan_type: Some(PlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
chat.on_rate_limit_snapshot(Some(RateLimitSnapshot {
|
chat.on_rate_limit_snapshot(Some(RateLimitSnapshot {
|
||||||
@@ -364,6 +370,7 @@ async fn rate_limit_snapshots_keep_separate_entries_per_limit_id() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: Some(PlanType::Pro),
|
plan_type: Some(PlanType::Pro),
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let codex = chat
|
let codex = chat
|
||||||
@@ -416,6 +423,7 @@ async fn rate_limit_switch_prompt_skips_non_codex_limit() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ async fn status_snapshot_includes_reasoning_details() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
|
|
||||||
@@ -322,6 +323,7 @@ async fn status_snapshot_includes_monthly_limit() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
|
|
||||||
@@ -373,6 +375,7 @@ async fn status_snapshot_shows_unlimited_credits() {
|
|||||||
balance: None,
|
balance: None,
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
||||||
@@ -422,6 +425,7 @@ async fn status_snapshot_shows_positive_credits() {
|
|||||||
balance: Some("12.5".to_string()),
|
balance: Some("12.5".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
||||||
@@ -471,6 +475,7 @@ async fn status_snapshot_hides_zero_credits() {
|
|||||||
balance: Some("0".to_string()),
|
balance: Some("0".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
||||||
@@ -518,6 +523,7 @@ async fn status_snapshot_hides_when_has_no_credits_flag() {
|
|||||||
balance: None,
|
balance: None,
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref());
|
||||||
@@ -623,6 +629,7 @@ async fn status_snapshot_truncates_in_narrow_terminal() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
|
|
||||||
@@ -786,6 +793,7 @@ async fn status_snapshot_shows_refreshing_limits_notice() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
|
|
||||||
@@ -856,6 +864,7 @@ async fn status_snapshot_includes_credits_and_limits() {
|
|||||||
balance: Some("37.5".to_string()),
|
balance: Some("37.5".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
|
|
||||||
@@ -909,6 +918,7 @@ async fn status_snapshot_shows_unavailable_limits_message() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let captured_at = chrono::Local
|
let captured_at = chrono::Local
|
||||||
.with_ymd_and_hms(2024, 6, 7, 8, 9, 10)
|
.with_ymd_and_hms(2024, 6, 7, 8, 9, 10)
|
||||||
@@ -965,6 +975,7 @@ async fn status_snapshot_treats_refreshing_empty_limits_as_unavailable() {
|
|||||||
secondary: None,
|
secondary: None,
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let captured_at = chrono::Local
|
let captured_at = chrono::Local
|
||||||
.with_ymd_and_hms(2024, 6, 7, 8, 9, 10)
|
.with_ymd_and_hms(2024, 6, 7, 8, 9, 10)
|
||||||
@@ -1035,6 +1046,7 @@ async fn status_snapshot_shows_stale_limits_message() {
|
|||||||
}),
|
}),
|
||||||
credits: None,
|
credits: None,
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let now = captured_at + ChronoDuration::minutes(20);
|
let now = captured_at + ChronoDuration::minutes(20);
|
||||||
@@ -1105,6 +1117,7 @@ async fn status_snapshot_cached_limits_hide_credits_without_flag() {
|
|||||||
balance: Some("80".to_string()),
|
balance: Some("80".to_string()),
|
||||||
}),
|
}),
|
||||||
plan_type: None,
|
plan_type: None,
|
||||||
|
rate_limit_reached_type: None,
|
||||||
};
|
};
|
||||||
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
let rate_display = rate_limit_snapshot_display(&snapshot, captured_at);
|
||||||
let now = captured_at + ChronoDuration::minutes(20);
|
let now = captured_at + ChronoDuration::minutes(20);
|
||||||
|
|||||||
Reference in new issue
Block a user