Skip to content

Conversation

@hannesrudolph
Copy link
Collaborator

@hannesrudolph hannesrudolph commented Sep 3, 2025

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:

  • Types
    • Add ServiceTier and tiered pricing fields to ModelInfo
    • Allow per-model allowedServiceTiers and serviceTierPricing
  • Provider settings
  • Model catalog
    • Populate allowedServiceTiers and serviceTierPricing for applicable models in openai.ts
  • OpenAI Native provider
    • Include service_tier in Responses API requests when requested and supported; retry without it on 400 invalid/unsupported tier
    • Capture resolved response.service_tier from the stream and derive effective pricing
    • Apply tiered pricing in usage cost computation without changing shared cost logic
    • Include service_tier in non‑streaming completePrompt() calls
    • Files: openai-native.ts
  • UI (webview)
    • Add “Service tier” dropdown with an info tooltip; shown only when the selected model supports flex/priority
    • Add a tiered pricing table and hide the old single‑line price bullets when the table is shown
    • Files: OpenAI.tsx, ApiOptions.tsx, ModelInfoView.tsx
  • Tests
    • New unit tests covering request body tier inclusion, retry on unsupported tier, capturing service_tier from the stream, and tiered pricing cost computation
    • File: openai-native-service-tier.spec.ts

Why:

  • Enables users to explicitly select “flex” (lower cost, higher latency) or “priority” (faster processing) where supported.
  • Ensures usage/cost reporting reflects the actual tier used by OpenAI’s Responses API.

Test Procedure

Automated:

  • Run backend tests:
    • cd src && npx vitest run api/providers/__tests__/openai-native-service-tier.spec.ts
  • Run UI tests:
    • cd webview-ui && npx vitest run

Manual:

  1. Settings → select provider “OpenAI (openai-native)”
  2. Choose a model with tier support (e.g., gpt-5-2025-08-07, o4-mini, o3)
  3. Verify:
    • “Service tier” dropdown is visible and includes only supported non‑standard tiers
    • When table is shown, single-line price bullets are hidden
    • Tiered pricing table shows “Standard”, plus Flex/Priority with per‑1M token prices
  4. Choose a model without tier support → no dropdown and no table; single‑line prices remain
  5. Make a request and confirm usage cost aligns with chosen/resolved tier.

Pre-Submission Checklist

  • Scope: Changes focused on OpenAI Native service tiers end‑to‑end
  • Self-Review: Code and UX paths verified
  • Testing: Added/updated unit tests and ran UI tests
  • Docs Impact: None required in this repo

Screenshots / Videos

No screenshots attached

Documentation Updates

  • [] No documentation updates are required.

Additional Notes

  • Costing relies on applyServiceTierPricing to produce an effective ModelInfo before calling shared cost helpers.
  • Request fallback behavior gracefully handles unsupported/invalid service_tier.

Get in Touch

@username


Important

Adds support for OpenAI Native service tiers, including API handling, UI updates, and pricing logic.

  • Behavior:
    • Adds ServiceTier and pricing fields to ModelInfo in model.ts.
    • Adds openAiNativeServiceTier to OpenAI Native schema in provider-settings.ts.
    • Handles service_tier in API requests and retries on unsupported tiers in openai-native.ts.
    • Captures response.service_tier and applies tiered pricing in cost computation.
  • UI:
    • Adds "Service tier" dropdown and pricing table in OpenAI.tsx, ApiOptions.tsx, and ModelInfoView.tsx.
    • Hides single-line price bullets when tiered pricing is shown.
  • Tests:
    • Adds tests for tier inclusion in requests, retry logic, and pricing computation in openai-native-service-tier.spec.ts.

This description was created by Ellipsis for 5d6fc17. You can customize this summary. It will automatically update as commits are pushed.

Copilot AI review requested due to automatic review settings September 3, 2025 22:19
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Sep 3, 2025
@hannesrudolph hannesrudolph marked this pull request as draft September 3, 2025 22:20
Copy link
Contributor

Copilot AI left a 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.

Comment on lines +29 to +30
const allowedTiers =
(modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? []
Copy link

Copilot AI Sep 3, 2025

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.

Suggested change
const allowedTiers =
(modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority") ?? []
(modelInfo?.allowedServiceTiers || []).filter((tier) => tier === "flex" || tier === "priority")

Copilot uses AI. Check for mistakes.
<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)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
{fmt(tierPricing?.flex?.inputPrice ?? modelInfo?.inputPrice)}
</td>
<td className="px-3 py-1.5 text-right">
{fmt(tierPricing?.flex?.outputPrice ?? modelInfo?.outputPrice)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
{fmt(tierPricing?.flex?.outputPrice ?? modelInfo?.outputPrice)}
</td>
<td className="px-3 py-1.5 text-right">
{fmt(tierPricing?.flex?.cacheReadsPrice ?? modelInfo?.cacheReadsPrice)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
<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)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
{fmt(tierPricing?.priority?.inputPrice ?? modelInfo?.inputPrice)}
</td>
<td className="px-3 py-1.5 text-right">
{fmt(tierPricing?.priority?.outputPrice ?? modelInfo?.outputPrice)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
{fmt(tierPricing?.priority?.outputPrice ?? modelInfo?.outputPrice)}
</td>
<td className="px-3 py-1.5 text-right">
{fmt(tierPricing?.priority?.cacheReadsPrice ?? modelInfo?.cacheReadsPrice)}
Copy link

Copilot AI Sep 3, 2025

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.

Copilot uses AI. Check for mistakes.
{shouldShowTierPricingTable && (
<div className="mt-2">
<div className="text-xs text-vscode-descriptionForeground mb-1">
Pricing by service tier (price per 1M tokens)
Copy link
Contributor

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.

Suggested change
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>
Copy link
Contributor

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.

Suggested change
<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.

@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Sep 3, 2025
@github-project-automation github-project-automation bot moved this from Triage to Done in Roo Code Roadmap Sep 3, 2025
Copy link
Contributor

@roomote roomote bot left a 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") ?? []
Copy link
Contributor

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.

Suggested change
(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") ?? []
Copy link
Contributor

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)
Copy link
Contributor

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:

Suggested change
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)}
Copy link
Contributor

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>
Copy link
Contributor

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:

Suggested change
<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"}
Copy link
Contributor

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}
Copy link
Contributor

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 support
  • src/api/providers/openai-native.ts - No service tier handling
  • src/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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants