refactor(api): centralize service-tier primitives - #1040
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughOpenAI service tiers are centralized in a shared enum and payload-key constant, then applied to provider request/response handling, pricing calculations, and settings UI components. Tests cover request payloads, resolved-tier pricing, streaming behavior, tier selection, and pricing-table rendering. ChangesService tier integration
Estimated code review effort: 3 (Moderate) | ~25 minutes Suggested labels: Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant OpenAiNativeHandler
participant OpenAIResponsesAPI
participant SSEEventProcessor
participant CostCalculator
OpenAiNativeHandler->>OpenAIResponsesAPI: Send request with service tier
OpenAIResponsesAPI-->>SSEEventProcessor: Stream events with resolved tier
SSEEventProcessor->>CostCalculator: Calculate cost from resolved tier
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/api/providers/openai-native.ts (1)
373-376: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate tier-gating logic between
buildRequestBodyandcompletePrompt.Both methods independently rebuild
allowedTierNamesand re-implement the identical "is tier allowed" condition (requestedTier === OpenAiServiceTier.Default || allowedTierNames.has(requestedTier)). Extracting a shared private helper avoids future divergence if the gating rule changes.♻️ Proposed helper extraction
+ private resolveEffectiveServiceTier(model: OpenAiNativeModel): ServiceTier | undefined { + const requestedTier = (this.options.openAiNativeServiceTier as ServiceTier | undefined) || undefined + if (!requestedTier) return undefined + const allowedTierNames = new Set(model.info.tiers?.map((t) => t.name).filter(Boolean) || []) + return requestedTier === OpenAiServiceTier.Default || allowedTierNames.has(requestedTier) + ? requestedTier + : undefined + } + private buildRequestBody(...): any { ... - const requestedTier = (this.options.openAiNativeServiceTier as ServiceTier | undefined) || undefined - const allowedTierNames = new Set(model.info.tiers?.map((t) => t.name).filter(Boolean) || []) + const effectiveRequestedTier = this.resolveEffectiveServiceTier(model) ... - ...(requestedTier && - (requestedTier === OpenAiServiceTier.Default || allowedTierNames.has(requestedTier)) && { - [SERVICE_TIER_KEY]: requestedTier, - }), + ...(effectiveRequestedTier && { [SERVICE_TIER_KEY]: effectiveRequestedTier }),async completePrompt(prompt: string, options?: CompletePromptOptions): Promise<string> { ... - const requestedTier = (this.options.openAiNativeServiceTier as ServiceTier | undefined) || undefined - const allowedTierNames = new Set(model.info.tiers?.map((t) => t.name).filter(Boolean) || []) - if (requestedTier && (requestedTier === OpenAiServiceTier.Default || allowedTierNames.has(requestedTier))) { - requestBody[SERVICE_TIER_KEY] = requestedTier + const effectiveRequestedTier = this.resolveEffectiveServiceTier(model) + if (effectiveRequestedTier) { + requestBody[SERVICE_TIER_KEY] = effectiveRequestedTier }Also applies to: 1513-1515
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/providers/openai-native.ts` around lines 373 - 376, Extract the shared tier-approval logic from buildRequestBody and completePrompt into a private helper that accepts requestedTier and the allowed tier names, then reuse it in both SERVICE_TIER_KEY construction paths. Remove the duplicated allowedTierNames setup and condition while preserving acceptance of OpenAiServiceTier.Default and configured allowed tiers.webview-ui/src/components/settings/ModelInfoView.tsx (1)
149-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFlex and Priority pricing rows are near-identical; extract a shared row renderer.
Each block repeats the same
td/fmt/tiers.find(...)pattern, differing only by tier enum and label. A small helper removes the duplication and keeps the two rows from drifting.♻️ Proposed row-renderer helper
+ {([ + [OpenAiServiceTier.Flex, t("settings:serviceTier.flex")], + [OpenAiServiceTier.Priority, t("settings:serviceTier.priority")], + ] as const) + .filter(([tierName]) => allowedTierNames.includes(tierName)) + .map(([tierName, label]) => { + const tierInfo = modelInfo?.tiers?.find((t) => t.name === tierName) + return ( + <tr key={tierName} className="border-t border-vscode-dropdown-border/60"> + <td className="px-3 py-1.5">{label}</td> + <td className="px-3 py-1.5 text-right"> + {fmt(tierInfo?.inputPrice ?? modelInfo?.inputPrice)} + </td> + <td className="px-3 py-1.5 text-right"> + {fmt(tierInfo?.outputPrice ?? modelInfo?.outputPrice)} + </td> + <td className="px-3 py-1.5 text-right"> + {fmt(tierInfo?.cacheReadsPrice ?? modelInfo?.cacheReadsPrice)} + </td> + </tr> + ) + })} - {allowedTierNames.includes(OpenAiServiceTier.Flex) && ( ... )} - {allowedTierNames.includes(OpenAiServiceTier.Priority) && ( ... )}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webview-ui/src/components/settings/ModelInfoView.tsx` around lines 149 - 194, In ModelInfoView, extract the duplicated Flex and Priority pricing-row markup into a shared row renderer or component that accepts the tier enum and translated label, while preserving the existing allowedTierNames checks and fallback pricing behavior. Replace both inline blocks with calls to this helper so the tier-specific lookup and labels remain configurable without repeating the td/fmt structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/api/providers/openai-native.ts`:
- Around line 373-376: Extract the shared tier-approval logic from
buildRequestBody and completePrompt into a private helper that accepts
requestedTier and the allowed tier names, then reuse it in both SERVICE_TIER_KEY
construction paths. Remove the duplicated allowedTierNames setup and condition
while preserving acceptance of OpenAiServiceTier.Default and configured allowed
tiers.
In `@webview-ui/src/components/settings/ModelInfoView.tsx`:
- Around line 149-194: In ModelInfoView, extract the duplicated Flex and
Priority pricing-row markup into a shared row renderer or component that accepts
the tier enum and translated label, while preserving the existing
allowedTierNames checks and fallback pricing behavior. Replace both inline
blocks with calls to this helper so the tier-specific lookup and labels remain
configurable without repeating the td/fmt structure.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 56e7c7fe-047d-4f43-8288-851cb3b38ebe
📒 Files selected for processing (12)
packages/types/src/model.tssrc/api/providers/__tests__/bedrock.spec.tssrc/api/providers/__tests__/openai-native-usage.spec.tssrc/api/providers/__tests__/openai-native.spec.tssrc/api/providers/bedrock.tssrc/api/providers/openai-native.tssrc/shared/cost.tssrc/utils/__tests__/cost.spec.tswebview-ui/src/components/settings/ModelInfoView.tsxwebview-ui/src/components/settings/__tests__/ModelInfoView.spec.tsxwebview-ui/src/components/settings/providers/OpenAI.tsxwebview-ui/src/components/settings/providers/__tests__/OpenAI.spec.tsx
edelauna
left a comment
There was a problem hiding this comment.
Nice! Thanks for this PR - had 2 comments related to the implementation.
|
Addressed both review comments in 5f0179c:
Also centralized request-tier gating so streaming requests and Validation completed:
|
edelauna
left a comment
There was a problem hiding this comment.
Since you're touching the file could you include a snapshot of webview-ui/src/components/settings/ModelInfoView.tsx using https://github.com/Zoo-Code-Org/Zoo-Code/blob/main/webview-ui/AGENTS.md#visual-tests-playwright-ct
Anything you want, bro 😄 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/types/package.json`:
- Around line 14-21: Update the package export entries for the “./model” and
“./provider-identifiers” subpaths to support CommonJS consistently with the root
export: add matching require targets that point to their generated CommonJS
build outputs, or explicitly declare both subpaths ESM-only if that is the
intended contract. Ensure the selected approach prevents require() from
producing ERR_PACKAGE_PATH_NOT_EXPORTED.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 85793c52-1c10-42f1-8d66-b1c44e6e66ac
📒 Files selected for processing (6)
packages/types/package.jsonwebview-ui/playwright-ct.config.tswebview-ui/playwright/TranslationContext.tswebview-ui/src/components/settings/ModelDescriptionMarkdown.tsxwebview-ui/src/components/settings/ModelInfoView.tsxwebview-ui/src/components/settings/__tests__/ModelInfoView.visual.fixture.tsx
| }, | ||
| "./model": { | ||
| "types": "./src/model.ts", | ||
| "import": "./src/model.ts" | ||
| }, | ||
| "./provider-identifiers": { | ||
| "types": "./src/provider-identifiers.ts", | ||
| "import": "./src/provider-identifiers.ts" |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
jq '.exports["."], .exports["./model"], .exports["./provider-identifiers"]' packages/types/package.json
rg -nP "require\\(['\"]`@roo-code/types/`(model|provider-identifiers)['\"]\\)" .Repository: Zoo-Code-Org/Zoo-Code
Length of output: 464
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "package exports:"
jq '.exports' packages/types/package.json
echo
echo "package metadata:"
jq '{name, type: .type, scripts, main, module, typings: .typings, types}' packages/types/package.json
echo
echo "source files under package/types relevant:"
fd -a '^(model|provider-identifiers|index)\.(ts|js|cts|cjs)$' packages/types | sed 's#^\./##' | sort
echo
echo "local require/import usages:"
rg -n --glob '!node_modules' --glob '!dist' --glob '!build' "(`@roo-code/`|from '|from \{|require\()" packages | sed -n '1,200p'Repository: Zoo-Code-Org/Zoo-Code
Length of output: 13240
Add CommonJS targets for the new public subpaths.
@roo-code/types is an ESM package, and the root export supports CommonJS via require/dist/index.cjs, but @roo-code/types/model and @roo-code/types/provider-identifiers only expose imports. CommonJS require() consumers for those subpaths will get ERR_PACKAGE_PATH_NOT_EXPORTED; add matching CommonJS build outputs or mark these subpaths as ESM-only.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/types/package.json` around lines 14 - 21, Update the package export
entries for the “./model” and “./provider-identifiers” subpaths to support
CommonJS consistently with the root export: add matching require targets that
point to their generated CommonJS build outputs, or explicitly declare both
subpaths ESM-only if that is the intended contract. Ensure the selected approach
prevents require() from producing ERR_PACKAGE_PATH_NOT_EXPORTED.
Responsibility and scope
Centralizes the shared service-tier primitives used by provider request construction so later stack layers can consume one canonical representation. Tests travel with the behavior in this PR.
Behavior and non-goals
Task.throttle.test.tsfix.Test evidence
Stack dependency
main).Review and merge this PR first; each subsequent PR is based on the preceding contributor branch.
Summary by CodeRabbit