mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
## What changed - Accept optional `account/rateLimits/read` capabilities for Luna Reserve support and lightweight background polling while preserving omitted and `null` params. - Forward the Luna Reserve capability only for eligible ChatGPT sessions, and let lightweight polls skip the separate reset-credit detail request. - Return the backend's `ordinaryUsageAllowed` decision only when its account and user identity match the active session. ## Testing - Cover capability defaults, eligible and restricted authentication modes, lightweight polling, identity filtering, and backend permission handling. GitOrigin-RevId: f407a3ae1e70e411fdf245f072a16e453f59cd87
748 lines
28 KiB
Rust
748 lines
28 KiB
Rust
use super::ThreadUsage;
|
|
use crate::JsonSchema;
|
|
use crate::TS;
|
|
use crate::protocol::common::AuthMode;
|
|
use codex_experimental_api_macros::ExperimentalApi;
|
|
use codex_protocol::account::PlanType;
|
|
use codex_protocol::account::ProviderAccount;
|
|
use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot;
|
|
use codex_protocol::protocol::RateLimitReachedType as CoreRateLimitReachedType;
|
|
use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot;
|
|
use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow;
|
|
use codex_protocol::protocol::SpendControlLimitSnapshot as CoreSpendControlLimitSnapshot;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::collections::HashMap;
|
|
use std::fmt;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
#[ts(tag = "type")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum Account {
|
|
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
|
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
|
ApiKey {},
|
|
|
|
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
|
Chatgpt {
|
|
#[schemars(
|
|
required,
|
|
schema_with = "crate::protocol::serde_helpers::nullable_string_schema"
|
|
)]
|
|
email: Option<String>,
|
|
plan_type: PlanType,
|
|
},
|
|
|
|
#[serde(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
#[ts(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
AmazonBedrock {
|
|
#[serde(default)]
|
|
uses_codex_managed_credentials: bool,
|
|
},
|
|
}
|
|
|
|
impl From<ProviderAccount> for Account {
|
|
fn from(account: ProviderAccount) -> Self {
|
|
match account {
|
|
ProviderAccount::ApiKey => Self::ApiKey {},
|
|
ProviderAccount::Chatgpt { email, plan_type } => Self::Chatgpt { email, plan_type },
|
|
ProviderAccount::AmazonBedrock {
|
|
uses_codex_managed_credentials,
|
|
} => Self::AmazonBedrock {
|
|
uses_codex_managed_credentials,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
#[serde(tag = "type")]
|
|
#[ts(tag = "type")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum LoginAccountParams {
|
|
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
|
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
|
ApiKey {
|
|
#[serde(rename = "apiKey")]
|
|
#[ts(rename = "apiKey")]
|
|
api_key: String,
|
|
},
|
|
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
|
Chatgpt {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
codex_streamlined_login: bool,
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
use_hosted_login_success_page: bool,
|
|
#[serde(default)]
|
|
#[ts(optional = nullable)]
|
|
app_brand: Option<LoginAppBrand>,
|
|
},
|
|
#[serde(rename = "chatgptDeviceCode")]
|
|
#[ts(rename = "chatgptDeviceCode")]
|
|
ChatgptDeviceCode,
|
|
/// [UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE.
|
|
/// The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have.
|
|
#[experimental("account/login/start.chatgptAuthTokens")]
|
|
#[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
|
ChatgptAuthTokens {
|
|
/// Access token (JWT) supplied by the client.
|
|
/// This token is used for backend API requests and email extraction.
|
|
access_token: String,
|
|
/// Workspace/account identifier supplied by the client.
|
|
chatgpt_account_id: String,
|
|
/// Optional plan type supplied by the client.
|
|
///
|
|
/// When `null`, Codex attempts to derive the plan type from access-token
|
|
/// claims. If unavailable, the plan defaults to `unknown`.
|
|
#[ts(optional = nullable)]
|
|
chatgpt_plan_type: Option<String>,
|
|
},
|
|
/// [UNSTABLE] Managed Amazon Bedrock login is experimental.
|
|
#[experimental("account/login/start.amazonBedrock")]
|
|
#[serde(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
#[ts(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
AmazonBedrock { api_key: String, region: String },
|
|
/// [UNSTABLE] Managed Amazon Bedrock AWS access key login is experimental.
|
|
#[experimental("account/login/start.amazonBedrockAccessKeys")]
|
|
#[serde(rename = "amazonBedrockAccessKeys", rename_all = "camelCase")]
|
|
#[ts(rename = "amazonBedrockAccessKeys", rename_all = "camelCase")]
|
|
AmazonBedrockAccessKeys {
|
|
access_key_id: String,
|
|
secret_access_key: String,
|
|
#[ts(optional = nullable)]
|
|
session_token: Option<String>,
|
|
region: String,
|
|
},
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "lowercase")]
|
|
#[ts(rename_all = "lowercase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum LoginAppBrand {
|
|
#[default]
|
|
Codex,
|
|
Chatgpt,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
#[ts(tag = "type")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum LoginAccountResponse {
|
|
#[serde(rename = "apiKey", rename_all = "camelCase")]
|
|
#[ts(rename = "apiKey", rename_all = "camelCase")]
|
|
ApiKey {},
|
|
#[serde(rename = "chatgpt", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgpt", rename_all = "camelCase")]
|
|
Chatgpt {
|
|
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
|
// Convert to/from UUIDs at the application layer as needed.
|
|
login_id: String,
|
|
/// URL the client should open in a browser to initiate the OAuth flow.
|
|
auth_url: String,
|
|
},
|
|
#[serde(rename = "chatgptDeviceCode", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgptDeviceCode", rename_all = "camelCase")]
|
|
ChatgptDeviceCode {
|
|
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
|
// Convert to/from UUIDs at the application layer as needed.
|
|
login_id: String,
|
|
/// URL the client should open in a browser to complete device code authorization.
|
|
verification_url: String,
|
|
/// One-time code the user must enter after signing in.
|
|
user_code: String,
|
|
},
|
|
#[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
|
#[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")]
|
|
ChatgptAuthTokens {},
|
|
#[serde(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
#[ts(rename = "amazonBedrock", rename_all = "camelCase")]
|
|
AmazonBedrock {},
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CancelLoginAccountParams {
|
|
pub login_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum CancelLoginAccountStatus {
|
|
Canceled,
|
|
NotFound,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CancelLoginAccountResponse {
|
|
pub status: CancelLoginAccountStatus,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionsAddParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub switch_to_added_account: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionsListParams {
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub refresh_workspace_metadata: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionsLogoutParams {
|
|
pub session_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionsSwitchParams {
|
|
pub session_id: String,
|
|
pub account_id: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionsResponse {
|
|
pub active_session_id: Option<String>,
|
|
pub sessions: Vec<AccountSession>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSession {
|
|
pub session_id: String,
|
|
pub email: Option<String>,
|
|
pub user_id: Option<String>,
|
|
pub display_name: Option<String>,
|
|
pub image_url: Option<String>,
|
|
pub last_used_at: i64,
|
|
pub is_active: bool,
|
|
pub selected_workspace_account_id: Option<String>,
|
|
pub workspaces: Vec<AccountSessionWorkspace>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountSessionWorkspace {
|
|
pub account_id: String,
|
|
pub name: Option<String>,
|
|
pub image_url: Option<String>,
|
|
pub kind: Option<AccountSessionWorkspaceKind>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum AccountSessionWorkspaceKind {
|
|
Personal,
|
|
Workspace,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct LogoutAccountResponse {}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum ChatgptAuthTokensRefreshReason {
|
|
/// Codex attempted a backend request and received `401 Unauthorized`.
|
|
Unauthorized,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ChatgptAuthTokensRefreshParams {
|
|
pub reason: ChatgptAuthTokensRefreshReason,
|
|
/// Workspace/account identifier that Codex was previously using.
|
|
///
|
|
/// Clients that manage multiple accounts/workspaces can use this as a hint
|
|
/// to refresh the token for the correct workspace.
|
|
///
|
|
/// This may be `null` when the prior auth state did not include a workspace
|
|
/// identifier (`chatgpt_account_id`).
|
|
#[ts(optional = nullable)]
|
|
pub previous_account_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ChatgptAuthTokensRefreshResponse {
|
|
pub access_token: String,
|
|
pub chatgpt_account_id: String,
|
|
pub chatgpt_plan_type: Option<String>,
|
|
}
|
|
|
|
impl fmt::Debug for ChatgptAuthTokensRefreshResponse {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("ChatgptAuthTokensRefreshResponse")
|
|
.field("access_token", &"<redacted>")
|
|
.field("chatgpt_account_id", &self.chatgpt_account_id)
|
|
.field("chatgpt_plan_type", &self.chatgpt_plan_type)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
/// Usage-read capabilities of the requesting client, never inferred from its experiment arm.
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountRateLimitsParams {
|
|
/// The client supports automatic Luna Reserve fallback. For eligible ChatGPT CLI users,
|
|
/// allow the backend to record experiment exposure after ordinary usage is blocked.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub supports_luna_reserve: bool,
|
|
/// Skip the separate reset-credit detail lookup for background usage polls. The usage
|
|
/// response still includes the available count; omitted/false preserves detailed reads.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub exclude_reset_credit_details: bool,
|
|
}
|
|
|
|
pub type NullableGetAccountRateLimitsParams = Option<GetAccountRateLimitsParams>;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountRateLimitsResponse {
|
|
/// Backend permission for ordinary included usage, validated against the active account.
|
|
/// Null means unavailable; clients must not infer recovery from percentages or reset times.
|
|
pub ordinary_usage_allowed: Option<bool>,
|
|
/// Backward-compatible single-bucket view; mirrors the historical payload.
|
|
pub rate_limits: RateLimitSnapshot,
|
|
/// Multi-bucket view keyed by metered `limit_id` (for example, `codex`).
|
|
pub rate_limits_by_limit_id: Option<HashMap<String, RateLimitSnapshot>>,
|
|
pub rate_limit_reset_credits: Option<RateLimitResetCreditsSummary>,
|
|
/// Account associated with this usage snapshot, when supplied by the backend.
|
|
pub account_id: Option<String>,
|
|
/// Optional backend-owned banner from the same usage read. Its nested keys retain the
|
|
/// backend's snake_case contract; an absent banner leaves the client's existing UI unchanged.
|
|
pub rate_limit_upsell: Option<serde_json::Value>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RateLimitResetCreditsSummary {
|
|
pub available_count: i64,
|
|
/// Detail rows for available reset credits, when the backend provides them.
|
|
///
|
|
/// `null` means only `availableCount` is known, while an empty array means details were fetched
|
|
/// and no available credits were returned. The backend may cap this list, so its length can be
|
|
/// less than `availableCount`.
|
|
pub credits: Option<Vec<RateLimitResetCredit>>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RateLimitResetCredit {
|
|
/// Opaque backend identifier for this reset credit.
|
|
pub id: String,
|
|
pub reset_type: RateLimitResetType,
|
|
pub status: RateLimitResetCreditStatus,
|
|
/// Unix timestamp in seconds when the credit was granted.
|
|
#[ts(type = "number")]
|
|
pub granted_at: i64,
|
|
/// Unix timestamp in seconds when the credit expires, or `null` if it does not expire.
|
|
#[ts(type = "number | null")]
|
|
pub expires_at: Option<i64>,
|
|
/// Backend-provided display title for this credit, or `null` when unavailable.
|
|
pub title: Option<String>,
|
|
/// Backend-provided display description for this credit, or `null` when unavailable.
|
|
pub description: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/", rename_all = "camelCase")]
|
|
pub enum RateLimitResetType {
|
|
CodexRateLimits,
|
|
#[serde(other)]
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/", rename_all = "camelCase")]
|
|
pub enum RateLimitResetCreditStatus {
|
|
Available,
|
|
Redeeming,
|
|
Redeemed,
|
|
#[serde(other)]
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConsumeAccountRateLimitResetCreditParams {
|
|
/// Identifies one logical reset attempt. A UUID is recommended; reuse the same value when
|
|
/// retrying that attempt.
|
|
pub idempotency_key: String,
|
|
/// Opaque reset-credit identifier to redeem. When omitted, the backend selects the next
|
|
/// available credit.
|
|
#[ts(optional = nullable)]
|
|
pub credit_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct ConsumeAccountRateLimitResetCreditResponse {
|
|
pub outcome: ConsumeAccountRateLimitResetCreditOutcome,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/", rename_all = "camelCase")]
|
|
pub enum ConsumeAccountRateLimitResetCreditOutcome {
|
|
/// A reset credit was consumed and the eligible rate-limit windows were reset.
|
|
Reset,
|
|
/// No current rate-limit window is eligible for a reset.
|
|
NothingToReset,
|
|
/// The account has no earned reset credits available.
|
|
NoCredit,
|
|
/// The same idempotency key already completed a reset successfully.
|
|
AlreadyRedeemed,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountTokenUsageParams {
|
|
/// When present, read estimated usage for this thread instead of account-wide token activity.
|
|
#[ts(optional = nullable)]
|
|
pub thread_id: Option<String>,
|
|
}
|
|
|
|
pub type NullableGetAccountTokenUsageParams = Option<GetAccountTokenUsageParams>;
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountTokenUsageResponse {
|
|
pub summary: AccountTokenUsageSummary,
|
|
pub daily_usage_buckets: Option<Vec<AccountTokenUsageDailyBucket>>,
|
|
/// Estimated usage when a thread was requested and its billing route is available.
|
|
#[serde(default)]
|
|
#[ts(optional, as = "Option<Option<ThreadUsage>>")]
|
|
pub thread_usage: Option<ThreadUsage>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetWorkspaceMessagesResponse {
|
|
/// Whether the workspace-message backend route is available for this client.
|
|
pub feature_enabled: bool,
|
|
/// Active workspace messages returned by the backend.
|
|
pub messages: Vec<WorkspaceMessage>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct WorkspaceMessage {
|
|
pub message_id: String,
|
|
pub message_type: WorkspaceMessageType,
|
|
pub message_body: String,
|
|
/// Unix timestamp (in seconds) when the message was created.
|
|
#[ts(type = "number | null")]
|
|
pub created_at: Option<i64>,
|
|
/// Unix timestamp (in seconds) when the message was archived.
|
|
#[ts(type = "number | null")]
|
|
pub archived_at: Option<i64>,
|
|
}
|
|
|
|
#[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 WorkspaceMessageType {
|
|
Headline,
|
|
Announcement,
|
|
#[serde(other)]
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountTokenUsageSummary {
|
|
pub lifetime_tokens: Option<i64>,
|
|
pub peak_daily_tokens: Option<i64>,
|
|
pub longest_running_turn_sec: Option<i64>,
|
|
pub current_streak_days: Option<i64>,
|
|
pub longest_streak_days: Option<i64>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountTokenUsageDailyBucket {
|
|
pub start_date: String,
|
|
pub tokens: i64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SendAddCreditsNudgeEmailParams {
|
|
pub credit_type: AddCreditsNudgeCreditType,
|
|
}
|
|
|
|
#[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 AddCreditsNudgeCreditType {
|
|
Credits,
|
|
UsageLimit,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SendAddCreditsNudgeEmailResponse {
|
|
pub status: AddCreditsNudgeEmailStatus,
|
|
}
|
|
|
|
#[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 AddCreditsNudgeEmailStatus {
|
|
Sent,
|
|
CooldownActive,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountParams {
|
|
/// When `true`, requests a proactive token refresh before returning.
|
|
///
|
|
/// In managed auth mode this triggers the normal refresh-token flow. In
|
|
/// external auth mode this flag is ignored. Clients should refresh tokens
|
|
/// themselves and call `account/login/start` with `chatgptAuthTokens`.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub refresh_token: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct GetAccountResponse {
|
|
pub account: Option<Account>,
|
|
pub requires_openai_auth: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountUpdatedNotification {
|
|
pub auth_mode: Option<AuthMode>,
|
|
pub plan_type: Option<PlanType>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
/// Sparse rolling rate-limit update.
|
|
///
|
|
/// Clients should merge available values into the most recent `account/rateLimits/read` response
|
|
/// or refetch that snapshot. Nullable account metadata may be unavailable in a rolling update and
|
|
/// does not clear a previously observed value.
|
|
pub struct AccountRateLimitsUpdatedNotification {
|
|
pub rate_limits: RateLimitSnapshot,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RateLimitSnapshot {
|
|
pub limit_id: Option<String>,
|
|
pub limit_name: Option<String>,
|
|
pub primary: Option<RateLimitWindow>,
|
|
pub secondary: Option<RateLimitWindow>,
|
|
pub credits: Option<CreditsSnapshot>,
|
|
pub individual_limit: Option<SpendControlLimitSnapshot>,
|
|
/// Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery.
|
|
pub spend_control_reached: Option<bool>,
|
|
pub plan_type: Option<PlanType>,
|
|
pub rate_limit_reached_type: Option<RateLimitReachedType>,
|
|
}
|
|
|
|
impl From<CoreRateLimitSnapshot> for RateLimitSnapshot {
|
|
fn from(value: CoreRateLimitSnapshot) -> Self {
|
|
Self {
|
|
limit_id: value.limit_id,
|
|
limit_name: value.limit_name,
|
|
primary: value.primary.map(RateLimitWindow::from),
|
|
secondary: value.secondary.map(RateLimitWindow::from),
|
|
credits: value.credits.map(CreditsSnapshot::from),
|
|
individual_limit: value.individual_limit.map(SpendControlLimitSnapshot::from),
|
|
spend_control_reached: value.spend_control_reached,
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct RateLimitWindow {
|
|
pub used_percent: i32,
|
|
#[ts(type = "number | null")]
|
|
pub window_duration_mins: Option<i64>,
|
|
#[ts(type = "number | null")]
|
|
pub resets_at: Option<i64>,
|
|
}
|
|
|
|
impl From<CoreRateLimitWindow> for RateLimitWindow {
|
|
fn from(value: CoreRateLimitWindow) -> Self {
|
|
Self {
|
|
used_percent: value.used_percent.round() as i32,
|
|
window_duration_mins: value.window_minutes,
|
|
resets_at: value.resets_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct CreditsSnapshot {
|
|
pub has_credits: bool,
|
|
pub unlimited: bool,
|
|
pub balance: Option<String>,
|
|
}
|
|
|
|
impl From<CoreCreditsSnapshot> for CreditsSnapshot {
|
|
fn from(value: CoreCreditsSnapshot) -> Self {
|
|
Self {
|
|
has_credits: value.has_credits,
|
|
unlimited: value.unlimited,
|
|
balance: value.balance,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct SpendControlLimitSnapshot {
|
|
pub limit: String,
|
|
pub used: String,
|
|
pub remaining_percent: i32,
|
|
#[ts(type = "number")]
|
|
pub resets_at: i64,
|
|
}
|
|
|
|
impl From<CoreSpendControlLimitSnapshot> for SpendControlLimitSnapshot {
|
|
fn from(value: CoreSpendControlLimitSnapshot) -> Self {
|
|
Self {
|
|
limit: value.limit,
|
|
used: value.used,
|
|
remaining_percent: value.remaining_percent,
|
|
resets_at: value.resets_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export_to = "v2/")]
|
|
pub struct AccountLoginCompletedNotification {
|
|
// Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types.
|
|
// Convert to/from UUIDs at the application layer as needed.
|
|
pub login_id: Option<String>,
|
|
pub success: bool,
|
|
pub error: Option<String>,
|
|
pub onboarding_entrypoint: Option<DesktopOnboardingEntrypoint>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(rename_all = "snake_case")]
|
|
#[ts(export_to = "v2/")]
|
|
pub enum DesktopOnboardingEntrypoint {
|
|
LifeSciences,
|
|
}
|