From 0437834b37238686346f5b36092936bd18f2b945 Mon Sep 17 00:00:00 2001 From: Meagan Date: Thu, 23 Jul 2026 18:35:08 -0700 Subject: [PATCH] feat(rust): expose quota credits used metadata Teach Rust codegen about the optional dotcom creditsUsed quota field and cover camelCase round-tripping plus backward-compatible omission. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- rust/src/generated/api_types.rs | 3 +++ rust/tests/api_types_test.rs | 44 +++++++++++++++++++++++++++++++-- scripts/codegen/rust.ts | 19 ++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index bd32d490cd..25bb511179 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -703,6 +703,9 @@ pub struct AccountGetQuotaRequest { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AccountQuotaSnapshot { + /// Number of AI credits used so far this period, when reported by dotcom + #[serde(skip_serializing_if = "Option::is_none")] + pub credits_used: Option, /// Number of requests included in the entitlement, or -1 for unlimited entitlements pub entitlement_requests: i64, /// Whether the user has an unlimited usage entitlement diff --git a/rust/tests/api_types_test.rs b/rust/tests/api_types_test.rs index bcf2266916..7c01bdba96 100644 --- a/rust/tests/api_types_test.rs +++ b/rust/tests/api_types_test.rs @@ -4,8 +4,9 @@ #![allow(clippy::unwrap_used)] use github_copilot_sdk::rpc::{ - Extension, ExtensionList, ExtensionSource, ExtensionStatus, ExtensionsDisableRequest, - ExtensionsEnableRequest, FleetStartRequest, FleetStartResult, TasksStartAgentRequest, + AccountQuotaSnapshot, Extension, ExtensionList, ExtensionSource, ExtensionStatus, + ExtensionsDisableRequest, ExtensionsEnableRequest, FleetStartRequest, FleetStartResult, + TasksStartAgentRequest, }; #[test] @@ -84,6 +85,45 @@ fn tasks_start_agent_request_fields_are_accessible() { assert_eq!(request.description.as_deref(), Some("SDK task agent")); } +#[test] +fn account_quota_snapshot_supports_omitted_credits_used() { + let snapshot: AccountQuotaSnapshot = + serde_json::from_value(account_quota_snapshot_json()).unwrap(); + + assert_eq!(snapshot.credits_used, None); + assert!( + serde_json::to_value(snapshot) + .unwrap() + .get("creditsUsed") + .is_none() + ); +} + +#[test] +fn account_quota_snapshot_credits_used_round_trips_as_camel_case() { + let mut json = account_quota_snapshot_json(); + json["creditsUsed"] = serde_json::json!(12.5); + + let snapshot: AccountQuotaSnapshot = serde_json::from_value(json).unwrap(); + assert_eq!(snapshot.credits_used, Some(12.5)); + + let serialized = serde_json::to_value(snapshot).unwrap(); + assert_eq!(serialized["creditsUsed"], serde_json::json!(12.5)); + assert!(serialized.get("credits_used").is_none()); +} + +fn account_quota_snapshot_json() -> serde_json::Value { + serde_json::json!({ + "entitlementRequests": 100, + "isUnlimitedEntitlement": false, + "overage": 0, + "overageAllowedWithExhaustedQuota": false, + "remainingPercentage": 75, + "usageAllowedWithExhaustedQuota": true, + "usedRequests": 25 + }) +} + fn running_extension(id: &str, name: &str) -> Extension { Extension { id: id.to_string(), diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts index a04f5a21c5..fc6d0c09f9 100644 --- a/scripts/codegen/rust.ts +++ b/scripts/codegen/rust.ts @@ -68,6 +68,24 @@ const EXTERNAL_SCHEMA_RUST_TYPE_MODULE: Record> = }, }; +// account.getQuota can include this dotcom metadata before the bundled CLI schema advertises it. +function addAccountQuotaCreditsUsed(schema: ApiSchema): void { + for (const definitions of [schema.definitions, schema.$defs]) { + const snapshot = definitions?.AccountQuotaSnapshot; + if (!snapshot || typeof snapshot !== "object") continue; + + const properties = snapshot.properties; + if (!properties) continue; + + properties.creditsUsed ??= { + type: "number", + minimum: 0, + description: + "Number of AI credits used so far this period, when reported by dotcom", + }; + } +} + function rustDeprecatedAttributes(indent = ""): string[] { return [`${indent}#[doc(hidden)]`, `${indent}#[deprecated]`]; } @@ -2165,6 +2183,7 @@ async function generate(): Promise { const apiRaw = normalizeSchemaBrandCasing( JSON.parse(await fs.readFile(apiSchemaPath, "utf-8")) as ApiSchema, ); + addAccountQuotaCreditsUsed(apiRaw); const sessionEventsSchema = propagateInternalVisibility( postProcessSchema(