-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat: OpenAI Native service tier support (selection, API fallback, resolved-tier costing, tiered pricing UI) #7643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… hide redundant price rows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds comprehensive support for OpenAI Native service tiers (default, flex, priority) including tier selection, API fallback handling, resolved-tier costing, and tiered pricing UI display.
Key changes:
- Added service tier types and pricing fields to model definitions
- Implemented OpenAI Native provider tier support with API fallback on unsupported tiers
- Created UI components for tier selection dropdown and tiered pricing table display
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| webview-ui/src/components/settings/providers/OpenAI.tsx | Added service tier dropdown with tooltip for models supporting flex/priority tiers |
| webview-ui/src/components/settings/ModelInfoView.tsx | Added tiered pricing table and conditional display logic to hide single-line prices when table is shown |
| webview-ui/src/components/settings/ApiOptions.tsx | Updated OpenAI component to pass selectedModelInfo prop for tier support detection |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| const allowedTiers = | ||
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? [] |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nullish coalescing operator (??) is redundant since the logical OR (||) already provides an empty array as fallback. Remove the ?? [] at the end.
| const allowedTiers = | |
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? [] | |
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") |
| <tr className="border-t border-vscode-dropdown-border/60"> | ||
| <td className="px-3 py-1.5">Flex</td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.flex?.inputPrice ?? modelInfo?.inputPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| {fmt(tierPricing?.flex?.inputPrice ?? modelInfo?.inputPrice)} | ||
| </td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.flex?.outputPrice ?? modelInfo?.outputPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| {fmt(tierPricing?.flex?.outputPrice ?? modelInfo?.outputPrice)} | ||
| </td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.flex?.cacheReadsPrice ?? modelInfo?.cacheReadsPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| <tr className="border-t border-vscode-dropdown-border/60"> | ||
| <td className="px-3 py-1.5">Priority</td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.priority?.inputPrice ?? modelInfo?.inputPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| {fmt(tierPricing?.priority?.inputPrice ?? modelInfo?.inputPrice)} | ||
| </td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.priority?.outputPrice ?? modelInfo?.outputPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| {fmt(tierPricing?.priority?.outputPrice ?? modelInfo?.outputPrice)} | ||
| </td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.priority?.cacheReadsPrice ?? modelInfo?.cacheReadsPrice)} |
Copilot
AI
Sep 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated across multiple rows. Consider extracting this into a helper function that takes the tier name and price type to reduce duplication.
| {shouldShowTierPricingTable && ( | ||
| <div className="mt-2"> | ||
| <div className="text-xs text-vscode-descriptionForeground mb-1"> | ||
| Pricing by service tier (price per 1M tokens) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User‐facing text in the tiered pricing table header and column labels is hard-coded. Consider internationalizing these strings using t() for consistency.
| Pricing by service tier (price per 1M tokens) | |
| {t('settings:modelInfo.tierPricingHeader')} |
This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.
| return ( | ||
| <div className="flex flex-col gap-1 mt-2" data-testid="openai-service-tier"> | ||
| <div className="flex items-center gap-1"> | ||
| <label className="block font-medium mb-1">Service tier</label> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The service tier dropdown label, tooltip content, and option texts ('Service tier', 'Standard', 'Flex', 'Priority') are hard-coded. Please use the translation function (t()) for these UI strings.
| <label className="block font-medium mb-1">Service tier</label> | |
| <label className="block font-medium mb-1">{t("settings:providers.serviceTier")}</label> |
This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution! I've reviewed the changes and found several critical issues that need attention before this PR can be merged.
The main concern is that this appears to be an incomplete implementation - only the UI components have been added, but all the backend support mentioned in the PR description is missing.
| const infoItems = [ | ||
| // Show tiered pricing table for OpenAI Native when model supports non-standard tiers | ||
| const allowedTiers = | ||
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nullish coalescing operator (??) is redundant here since the logical OR (||) already provides an empty array as fallback.
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? [] | |
| const allowedTiers = | |
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") |
| const infoItems = [ | ||
| // Show tiered pricing table for OpenAI Native when model supports non-standard tiers | ||
| const allowedTiers = | ||
| (modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical issue: The properties allowedServiceTiers and serviceTierPricing don't exist in the ModelInfo type. This will cause TypeScript compilation errors. The type definitions need to be added to packages/types/src/model.ts first.
| {shouldShowTierPricingTable && ( | ||
| <div className="mt-2"> | ||
| <div className="text-xs text-vscode-descriptionForeground mb-1"> | ||
| Pricing by service tier (price per 1M tokens) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This hardcoded text needs internationalization. Consider using:
| Pricing by service tier (price per 1M tokens) | |
| <div className="text-xs text-vscode-descriptionForeground mb-1"> | |
| {t('settings:modelInfo.tierPricingHeader')} | |
| </div> |
| <tr className="border-t border-vscode-dropdown-border/60"> | ||
| <td className="px-3 py-1.5">Flex</td> | ||
| <td className="px-3 py-1.5 text-right"> | ||
| {fmt(tierPricing?.flex?.inputPrice ?? modelInfo?.inputPrice)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tier pricing fallback logic is duplicated 6 times across this component. Could we extract this into a helper function? For example:
const getTierPrice = (tier: string, priceType: 'inputPrice' | 'outputPrice' | 'cacheReadsPrice') => {
return tierPricing?.[tier]?.[priceType] ?? modelInfo?.[priceType]
}Then use it like: {fmt(getTierPrice('flex', 'inputPrice'))}
| return ( | ||
| <div className="flex flex-col gap-1 mt-2" data-testid="openai-service-tier"> | ||
| <div className="flex items-center gap-1"> | ||
| <label className="block font-medium mb-1">Service tier</label> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These UI strings need internationalization. The label "Service tier" and the dropdown options "Standard", "Flex", "Priority" should use translation keys:
| <label className="block font-medium mb-1">Service tier</label> | |
| <label className="block font-medium mb-1">{t("settings:providers.serviceTier")}</label> |
| </div> | ||
|
|
||
| <Select | ||
| value={apiConfiguration.openAiNativeServiceTier || "default"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical issue: The property openAiNativeServiceTier doesn't exist in ProviderSettings type. This needs to be added to packages/types/src/provider-settings.ts in the openAiNativeSchema.
| <OpenAI | ||
| apiConfiguration={apiConfiguration} | ||
| setApiConfigurationField={setApiConfigurationField} | ||
| selectedModelInfo={selectedModelInfo} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this implementation complete? The UI is passing selectedModelInfo to the OpenAI component, but there's no backend implementation to actually use the service tier selection. The following files mentioned in the PR description are missing their implementations:
packages/types/src/providers/openai.ts- No service tier supportsrc/api/providers/openai-native.ts- No service tier handlingsrc/api/providers/__tests__/openai-native-service-tier.spec.ts- Test file doesn't exist
Without these backend changes, the UI will set the service tier but it won't actually be used in API requests.
Related GitHub Issue
Closes: No linked issue (OpenAI Native service tiers follow-up)
Roo Code Task Context (Optional)
No Roo Code task context for this PR
Description
End-to-end support for OpenAI Native service tiers (default, flex, priority):
What’s included:
ServiceTierand tiered pricing fields toModelInfoallowedServiceTiersandserviceTierPricingopenAiNativeServiceTierto the OpenAI Native schema inprovider-settingsallowedServiceTiersandserviceTierPricingfor applicable models inopenai.tsservice_tierin Responses API requests when requested and supported; retry without it on 400 invalid/unsupported tierresponse.service_tierfrom the stream and derive effective pricingservice_tierin non‑streamingcompletePrompt()callsopenai-native.tsOpenAI.tsx,ApiOptions.tsx,ModelInfoView.tsxservice_tierfrom the stream, and tiered pricing cost computationopenai-native-service-tier.spec.tsWhy:
Test Procedure
Automated:
cd src && npx vitest run api/providers/__tests__/openai-native-service-tier.spec.tscd webview-ui && npx vitest runManual:
gpt-5-2025-08-07,o4-mini,o3)Pre-Submission Checklist
Screenshots / Videos
No screenshots attached
Documentation Updates
Additional Notes
applyServiceTierPricingto produce an effectiveModelInfobefore calling shared cost helpers.service_tier.Get in Touch
@username
Important
Adds support for OpenAI Native service tiers, including API handling, UI updates, and pricing logic.
ServiceTierand pricing fields toModelInfoinmodel.ts.openAiNativeServiceTierto OpenAI Native schema inprovider-settings.ts.service_tierin API requests and retries on unsupported tiers inopenai-native.ts.response.service_tierand applies tiered pricing in cost computation.OpenAI.tsx,ApiOptions.tsx, andModelInfoView.tsx.openai-native-service-tier.spec.ts.This description was created by
for 5d6fc17. You can customize this summary. It will automatically update as commits are pushed.