Surface ModelBilling.tokenPrices on public SDK types#1633
Surface ModelBilling.tokenPrices on public SDK types#1633MackinnonBuck wants to merge 2 commits into
Conversation
The generated wire types already carry `ModelBilling.tokenPrices`, but the hand-curated public `ModelBilling` types exposed only `multiplier`, forcing consumers to augment locally to read tier pricing. Add `tokenPrices` (with `inputPrice`, `outputPrice`, `cachePrice`, `batchSize`, `contextMax`, and a `longContext` tier) to the curated public `ModelBilling` across all SDKs: - Node, Python, Go, .NET, Java: declare curated `ModelBillingTokenPrices` and `ModelBillingTokenPricesLongContext` types matching each repo's conventions, plus the required public exports/registrations. - Rust: re-export the two nested generated types alongside `ModelBilling`. Add tests exercising the new field in every SDK. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR surfaces ModelBilling.tokenPrices on the curated, public-facing ModelBilling types across the SDKs (Node, Python, Go, .NET, Java, Rust), aligning the hand-authored public API with an already-present wire/generated schema field so consumers can read tiered token pricing (including long-context tier details).
Changes:
- Added public
ModelBillingTokenPrices/...LongContexttypes (or re-exports) and exposedtokenPricesonModelBillingacross SDKs. - Updated per-language serialization/deserialization paths (where applicable) to carry
tokenPrices. - Added/expanded tests in each SDK to validate the new field is preserved through (de)serialization and public exports.
Show a summary per file
| File | Description |
|---|---|
| rust/tests/session_test.rs | Extends model-list test payload and asserts access to re-exported token price types. |
| rust/src/types.rs | Re-exports generated ModelBillingTokenPrices* types via the public types module. |
| python/test_client.py | Adds round-trip tests for ModelBilling.tokenPrices and the nested long-context tier. |
| python/copilot/client.py | Introduces dataclasses + (de)serialization for tokenPrices and wires into ModelBilling. |
| python/copilot/init.py | Exports the new Python billing token price types at package level. |
| nodejs/test/client.test.ts | Adds billing.tokenPrices to test model payload and asserts deep access. |
| nodejs/src/types.ts | Adds curated public TS interfaces for ModelBillingTokenPrices* and ModelBilling.tokenPrices. |
| nodejs/src/index.ts | Exports the new TS public types from the package entrypoint. |
| java/src/test/java/com/github/copilot/MetadataApiTest.java | Extends deserialization test to assert token price fields and long-context tier parsing. |
| java/src/main/java/com/github/copilot/rpc/ModelBillingTokenPricesLongContext.java | Adds public RPC type for long-context tier pricing. |
| java/src/main/java/com/github/copilot/rpc/ModelBillingTokenPrices.java | Adds public RPC type for token-level pricing, including long-context tier. |
| java/src/main/java/com/github/copilot/rpc/ModelBilling.java | Adds tokenPrices field to ModelBilling. |
| go/types.go | Adds TokenPrices pointer field to ModelBilling and new pricing structs. |
| go/client_test.go | Adds JSON (un)marshal + round-trip test for ModelBilling.tokenPrices. |
| dotnet/test/Unit/SerializationTests.cs | Adds serializer round-trip test for ModelBilling.TokenPrices using SDK options. |
| dotnet/src/Types.cs | Adds new .NET types for token prices + source-gen registrations and adds TokenPrices to ModelBilling. |
Copilot's findings
- Files reviewed: 16/16 changed files
- Comments generated: 3
This comment has been minimized.
This comment has been minimized.
Honor the "all billing fields optional" contract surfaced in review:
- Python: deserialize present-but-empty `tokenPrices`/`longContext` objects
(`{}`) into instances with all fields None rather than collapsing them to
None, using presence (`is not None`) checks instead of truthiness.
- Java: change `ModelBilling.multiplier` from primitive `double` to boxed
`Double` so "not present on the wire" is distinguishable from an explicit
0.0; the global NON_NULL ObjectMapper omits it when null.
Add tests covering both behaviors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review ✅This PR adds Coverage
API Shape ConsistencyAll fields are correctly mapped to language-idiomatic types and names:
Noteworthy: Java
|
SteveSandersonMS
left a comment
There was a problem hiding this comment.
Looks great.
@edburns Can you give an opinion on the Java breaking change (double -> Double) here? Will this be acceptable in a patch release or do we need to find an alternative?
Summary
ModelBilling.tokenPricesis present on the wire and in every SDK's generated protocol types, but the hand-curated publicModelBillingtypes exposed onlymultiplier. Consumers had to narrow through local augmentations to read tier pricing (e.g. to detect a distinct long-context tier and label tiers like 200K / 1M in a model picker).This adds
tokenPricesto the curated publicModelBillingacross all SDKs, mirroring the shape already published in the generated schema.Shape
ModelBillingTokenPrices:inputPrice,outputPrice,cachePrice(numbers),batchSize,contextMax(ints),longContextModelBillingTokenPricesLongContext:inputPrice,outputPrice,cachePrice(numbers),contextMax(int)All fields optional; JSDoc/descriptions copied from the runtime schema.
Per-SDK changes
types.ts: curated interfaces +tokenPrices?; exported fromindex.tsclient.py: dataclasses withfrom_dict/to_dict, wired intoModelBilling; exported in__init__.pytypes.go: structs +TokenPricespointer fieldTypes.cs: sealed classes + property +[JsonSerializable]registrationsModelBillingTokenPrices.java/...LongContext.java+ field onModelBilling.javatypes.rs: re-export the two nested generated types (generatedModelBillingalready carriestoken_prices)No generated files were modified — they already carry the field. No runtime changes required.
Tests
Added coverage exercising the new field in every SDK (round-trip (de)serialization for Python/Go/.NET, deserialization assertions for Java, type + passthrough for Node, and re-export verification for Rust). All passing.