Skip to content

fix: apply db discounts to routing - #2573

Merged
steebchen merged 3 commits into
mainfrom
db-discounts-pr-feedback
Jun 8, 2026
Merged

steebchen merged 3 commits into
mainfrom
db-discounts-pr-feedback

Conversation

@steebchen

@steebchen steebchen commented Jun 7, 2026 •

Copy link
Copy Markdown
Member

Summary

  • apply effective DB discounts when selecting cheapest providers for chat and video routing
  • cache gateway effective-discount lookups with SWR, including stale fallback when Postgres is unavailable
  • use discounted prices in routing metadata fallback/content-filter/rate-limit paths
  • count discounted model OG images from API-backed mapping discounts instead of a hardcoded zero

Validation

  • pnpm format
  • pnpm vitest run apps/gateway/src/lib/cached-queries-swr.spec.ts packages/actions/src/models.spec.ts --no-file-parallelism
  • pnpm build:core
  • pnpm build
  • pnpm vitest run packages/actions/src/models.spec.ts --no-file-parallelism
  • pnpm vitest run apps/worker/src/services/sync-models.spec.ts --no-file-parallelism

Notes

  • pnpm test:unit was also run earlier. It failed only in apps/worker/src/services/sync-models.spec.ts with 6 timeout failures during the full serial suite; rerunning that spec in isolation passed all 9 tests.

Summary by CodeRabbit

  • New Features

    • Organization-aware discounted pricing applied to chat and video routing
    • New effective discount lookup used across routing and pricing
  • Improvements

    • Model category pages now reflect discounted-model counts and pricing
    • Concurrent async pricing improves routing performance and reliability
    • Discount caching and fallback behavior added for more robust price lookups

Copilot AI review requested due to automatic review settings June 7, 2026 20:00
@coderabbitai

coderabbitai Bot commented Jun 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8e93185d-f9a7-49e4-8fc6-47ddc469f80c

📥 Commits

Reviewing files that changed from the base of the PR and between a16c98c and 99b5021.

📒 Files selected for processing (4)
  • apps/gateway/src/chat/chat.ts
  • apps/gateway/src/lib/cached-queries-swr.spec.ts
  • apps/gateway/src/lib/cached-queries.ts
  • apps/gateway/src/videos/videos.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/gateway/src/videos/videos.ts

Walkthrough

This PR makes provider selection discount-aware and asynchronous, adds an SWR-backed effective-discount lookup, threads discount resolvers and discounted price/discount metadata through chat and video routing, updates OG image counting for discounted models, and converts affected tests to async usage.

Changes

Discounted provider selection and routing integration

Layer / File(s) Summary
Provider selection async/discount helpers
packages/actions/src/get-cheapest-from-available-providers.ts
getCheapestFromAvailableProviders becomes async and precomputes discounted provider prices via new getDiscountedProviderSelectionPrice. ProviderSelectionOptions gains organizationId and providerDiscountResolver; per-provider {price, discount} maps are used across sticky, exploration, weighted-score, and price-only paths. RoutingMetadata.providerScores and ProviderScore<T> gain optional discount.
Chat & Video routing async/discounted wiring
apps/gateway/src/chat/chat.ts, apps/gateway/src/videos/videos.ts
Routing now creates a request-scoped providerDiscountResolver(project.organizationId), awaits async collapse/cheapest helpers, passes organizationId and the resolver into selection calls, and populates routing metadata providerScores with both discounted price and discount across auto-routing, explicit-provider, rate-limit, low-uptime, content-filter exclusions, and direct-provider flows.
Effective-discount cached lookup (SWR)
apps/gateway/src/lib/cached-queries.ts, apps/gateway/src/lib/cached-queries-swr.spec.ts
Add findEffectiveDiscount(organizationId, provider, model) that queries non-expired discounts with NULL-scoped fallbacks, selects the most specific match, wraps results in SWR, and tests seeding and DB-failure fallback to the SWR mirror key.
OG image generation async counting & await normalization
apps/ui/src/components/models/category-og-image.tsx, apps/ui/src/app/models/*/opengraph-image.tsx (10 files)
generateCategoryOgImage becomes async and uses getCategoryModelCount, which for "discounted" fetches models and counts those with positive discountFraction. Ten category OG exports now await generateCategoryOgImage(...) before returning.
Tests: async provider selection coverage
packages/actions/src/models.spec.ts
Convert many tests to async/await for the new async getCheapestFromAvailableProviders, updating assertions and adding promise-rejection checks where applicable (exploration-rate validation, sticky/session behavior, pricing/discount expectations, cache-weight scenarios, and routing overrides).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: apply db discounts to routing' accurately summarizes the main change: integrating database discounts into the provider routing logic.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch db-discounts-pr-feedback

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a16c98cd4c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

: new Decimal(0);

return {
price: basePrice.times(new Decimal(1).minus(discount)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve price ordering for full discounts

When a DB discount is exactly 1 (the helper accepts it as valid), this line turns that provider's routing price into 0. In the weighted-score path with metrics, minPrice then becomes zero and the existing minPrice.gt(0) ? ... : 0 guard makes every provider's price score zero, so a 100%-discounted provider no longer gets any price advantage and can lose to a more expensive provider on uptime/latency. This affects normal gateway routing whenever metrics are present and a provider/model has a full discount; either special-case zero prices in the score calculation or avoid feeding a single zero into the ratio normalization.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

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 updates routing selection and routing metadata to consistently use effective database-driven discounts when computing “cheapest” provider choices (including chat/video fallback paths), and updates UI OG image generation to reflect discounted model counts based on API-backed mapping discounts.

Changes:

  • Apply effective discounts (DB or injected resolver) before comparing provider prices, and surface the applied discount in routing metadata scores.
  • Update Gateway chat/video routing to pass organization context and to use discounted prices in fallback/content-filter/rate-limit metadata paths.
  • Make category OG image generation async and compute the “discounted” category count from API model mapping discounts instead of a hardcoded zero.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/actions/src/get-cheapest-from-available-providers.ts Applies effective discounts during provider price scoring/selection and includes discount in routing metadata.
packages/actions/src/models.spec.ts Updates routing tests for async selection and adds coverage for discount-applied price comparison.
apps/gateway/src/chat/chat.ts Passes organization context and uses discounted prices/discount fields in routing metadata across fallback paths.
apps/gateway/src/videos/videos.ts Uses discounted prices/discount fields for video routing selection metadata and low-uptime fallback metadata.
apps/ui/src/components/models/category-og-image.tsx Makes category OG generation async and computes discounted model count from API-fetched mappings.
apps/ui/src/app/models/web-search/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/vision/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/video/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/tools/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/text/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/text-to-image/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/reasoning/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/image-to-image/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/embeddings/opengraph-image.tsx Awaits async category OG generation.
apps/ui/src/app/models/discounted/opengraph-image.tsx Awaits async category OG generation for discounted category.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +342 to +353
const basePrice = getProviderSelectionPrice(
providerInfo,
options?.videoPricing,
);
const discount = providerInfo
? await getProviderSelectionDiscount(providerInfo, modelId, options)
: new Decimal(0);

return {
price: basePrice.times(new Decimal(1).minus(discount)),
discount,
};

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/gateway/src/chat/chat.ts (1)

2748-2758: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use discounted pricing for originalProviderScore in fallback metadata

Line 2764 and Line 2970 still build originalProviderScore from raw inputPrice/outputPrice and omit discount, while the rest of provider scores in these paths are now discount-aware. This produces inconsistent routing metadata in rate-limit/low-uptime fallback responses.

🛠️ Suggested patch
-						const originalProviderPrice = originalProviderInfo
-							? Number(originalProviderInfo.inputPrice ?? "0") +
-								Number(originalProviderInfo.outputPrice ?? "0")
-							: 0;
+						const originalProviderPricing = originalProviderInfo
+							? await getDiscountedProviderSelectionPrice(
+									originalProviderInfo,
+									modelWithPricing.id,
+									{
+										organizationId: project.organizationId,
+									},
+								)
+							: null;
 
 						const originalProviderScore = {
 							providerId: requestedProvider,
 							score: -1,
-							price: originalProviderPrice,
+							price: originalProviderPricing?.price.toNumber() ?? 0,
+							discount: originalProviderPricing?.discount.toNumber() ?? 0,
 							rate_limited: true as const,
 						};
-							const originalProviderPrice = originalProviderInfo
-								? Number(originalProviderInfo.inputPrice ?? "0") +
-									Number(originalProviderInfo.outputPrice ?? "0")
-								: 0;
+							const originalProviderPricing = originalProviderInfo
+								? await getDiscountedProviderSelectionPrice(
+										originalProviderInfo,
+										modelWithPricing.id,
+										{
+											organizationId: project.organizationId,
+										},
+									)
+								: null;
 
 							// Create score entry for the original requested provider
 							const originalProviderScore = {
 								providerId: requestedProvider,
 								score: -1, // Negative score indicates this provider was skipped due to low uptime
-								price: originalProviderPrice,
+								price: originalProviderPricing?.price.toNumber() ?? 0,
+								discount: originalProviderPricing?.discount.toNumber() ?? 0,
 								uptime: currentUptime,
 								latency: metrics.averageLatency,
 								throughput: metrics.throughput,
 							};

Also applies to: 2764-2774, 2953-2963, 2970-2983

🤖 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 `@apps/gateway/src/chat/chat.ts` around lines 2748 - 2758, The fallback
metadata builds originalProviderScore using raw inputPrice/outputPrice (e.g.,
where originalProviderScore is constructed in the
getCheapestFromAvailableProviders fallback paths around candidatesForRouting and
modelWithPricing) but omits the provider discount; update those constructions
(the occurrences around originalProviderScore at the
getCheapestFromAvailableProviders call sites and the later fallback blocks) to
compute originalProviderScore using the discounted prices (apply the existing
discount field or reuse the already-discounted price variable instead of raw
inputPrice/outputPrice) so that originalProviderScore is discount-aware and
consistent with other provider scores.
apps/gateway/src/videos/videos.ts (1)

1691-1702: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update the routing metadata contract for providerScores[].discount.

apps/ui/src/lib/api/v1.d.ts:2770-2807 still omits discount on routingMetadata.providerScores[], so this new field is invisible to typed consumers even though the gateway now writes it here. Please update the schema/source type that generates that client shape before relying on this field downstream.

Also applies to: 1780-1798

🤖 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 `@apps/gateway/src/videos/videos.ts` around lines 1691 - 1702, The gateway now
writes a discount number into routingMetadata.providerScores[].discount but the
generated client type for routingMetadata.providerScores omits that field;
update the source schema/type generation so the providerScores entry includes
discount: number (and regenerate the client types), ensuring the
routingMetadata/providerScores type (and any references used by the UI client)
reflect the new discount property so typed consumers can access it; update any
relevant codegen inputs and re-run generation to propagate the change.
🤖 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/actions/src/get-cheapest-from-available-providers.ts`:
- Around line 392-408: The loop in getCheapestFromAvailableProviders currently
calls getDiscountedProviderSelectionPrice (which in turn calls
getEffectiveDiscount) for each provider causing N DB reads; instead, before
mapping providers call a batched discount fetch for the (organizationId,
modelWithPricing.id) pair (or add a helper like
getEffectiveDiscountsForOrganizationModel) and return a map of
provider->discount, then change the providerPrices creation (the providers.map
using findProviderMapping, getDiscountedProviderSelectionPrice, and
providerSelectionKey) to read discounts from that in-memory map and compute
price/discount locally; apply the same batching refactor to the other occurrence
around the code referenced (the block at ~473-478) so no per-provider DB queries
occur.
- Around line 379-380: The discount check currently allows parsedDiscount === 1
which yields a resolved price of 0 and then makes minPrice === 0 force every
priceScore to 0; update the logic so fully discounted providers are handled
explicitly: either reject exact 1 by changing the validation from
parsedDiscount.lte(0) || parsedDiscount.gt(1) to treat parsedDiscount.gte(1) as
invalid (so parsedDiscount === 1 returns Decimal(0)), or keep accepting 1 but
modify the weighted scorer logic (where minPrice and priceScore are computed) to
special-case zero-priced providers so only free provider(s) receive the best
priceScore and others do not get zeroed out; apply the same change in the other
occurrence referenced (around lines 679-681). Ensure you touch symbols
parsedDiscount, minPrice, and priceScore in
get-cheapest-from-available-providers.ts.

---

Outside diff comments:
In `@apps/gateway/src/chat/chat.ts`:
- Around line 2748-2758: The fallback metadata builds originalProviderScore
using raw inputPrice/outputPrice (e.g., where originalProviderScore is
constructed in the getCheapestFromAvailableProviders fallback paths around
candidatesForRouting and modelWithPricing) but omits the provider discount;
update those constructions (the occurrences around originalProviderScore at the
getCheapestFromAvailableProviders call sites and the later fallback blocks) to
compute originalProviderScore using the discounted prices (apply the existing
discount field or reuse the already-discounted price variable instead of raw
inputPrice/outputPrice) so that originalProviderScore is discount-aware and
consistent with other provider scores.

In `@apps/gateway/src/videos/videos.ts`:
- Around line 1691-1702: The gateway now writes a discount number into
routingMetadata.providerScores[].discount but the generated client type for
routingMetadata.providerScores omits that field; update the source schema/type
generation so the providerScores entry includes discount: number (and regenerate
the client types), ensuring the routingMetadata/providerScores type (and any
references used by the UI client) reflect the new discount property so typed
consumers can access it; update any relevant codegen inputs and re-run
generation to propagate the change.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ea32d9d0-029f-45c1-b8b1-f1c807f39f1f

📥 Commits

Reviewing files that changed from the base of the PR and between 1a1606d and a16c98c.

📒 Files selected for processing (15)
  • apps/gateway/src/chat/chat.ts
  • apps/gateway/src/videos/videos.ts
  • apps/ui/src/app/models/discounted/opengraph-image.tsx
  • apps/ui/src/app/models/embeddings/opengraph-image.tsx
  • apps/ui/src/app/models/image-to-image/opengraph-image.tsx
  • apps/ui/src/app/models/reasoning/opengraph-image.tsx
  • apps/ui/src/app/models/text-to-image/opengraph-image.tsx
  • apps/ui/src/app/models/text/opengraph-image.tsx
  • apps/ui/src/app/models/tools/opengraph-image.tsx
  • apps/ui/src/app/models/video/opengraph-image.tsx
  • apps/ui/src/app/models/vision/opengraph-image.tsx
  • apps/ui/src/app/models/web-search/opengraph-image.tsx
  • apps/ui/src/components/models/category-og-image.tsx
  • packages/actions/src/get-cheapest-from-available-providers.ts
  • packages/actions/src/models.spec.ts

Comment on lines +379 to +380
if (parsedDiscount.lte(0) || parsedDiscount.gt(1)) {
return new Decimal(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle fully discounted providers explicitly in weighted scoring.

discount === 1 is accepted here, which makes the resolved price 0. In the weighted path, minPrice === 0 then forces every priceScore to 0, so routing can ignore a free provider and still pick a paid one. Either reject exact 1 here, or special-case zero-priced providers in the scorer so only the free provider(s) get the best price score.

Suggested fix
-		const priceScore = minPrice.gt(0)
-			? providerScore.price.div(minPrice).minus(1)
-			: new Decimal(0);
+		const priceScore = minPrice.gt(0)
+			? providerScore.price.div(minPrice).minus(1)
+			: providerScore.price.eq(0)
+				? new Decimal(0)
+				: new Decimal(1);

Also applies to: 679-681

🤖 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/actions/src/get-cheapest-from-available-providers.ts` around lines
379 - 380, The discount check currently allows parsedDiscount === 1 which yields
a resolved price of 0 and then makes minPrice === 0 force every priceScore to 0;
update the logic so fully discounted providers are handled explicitly: either
reject exact 1 by changing the validation from parsedDiscount.lte(0) ||
parsedDiscount.gt(1) to treat parsedDiscount.gte(1) as invalid (so
parsedDiscount === 1 returns Decimal(0)), or keep accepting 1 but modify the
weighted scorer logic (where minPrice and priceScore are computed) to
special-case zero-priced providers so only free provider(s) receive the best
priceScore and others do not get zeroed out; apply the same change in the other
occurrence referenced (around lines 679-681). Ensure you touch symbols
parsedDiscount, minPrice, and priceScore in
get-cheapest-from-available-providers.ts.

Comment on lines +392 to +408
const providerPrices = await Promise.all(
providers.map(async (provider) => {
const providerInfo = findProviderMapping(
modelWithPricing.providers,
provider,
);
const { price, discount } = await getDiscountedProviderSelectionPrice(
providerInfo,
modelWithPricing.id,
{
...options,
videoPricing,
},
);

return [providerSelectionKey(provider), { price, discount }] as const;
}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Batch discount resolution instead of querying once per provider.

When organizationId is set, this loop fans out into one getEffectiveDiscount() call per stable provider, and getCheapestFromAvailableProviders() does that eagerly before the sticky/exploration early returns. On the gateway request path, that turns a single routing decision into N DB reads and adds avoidable latency/load as provider counts grow. Please fetch the applicable discounts once per (organizationId, modelId) and resolve precedence in-memory, or add a batched DB helper for this path.

Also applies to: 473-478

🤖 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/actions/src/get-cheapest-from-available-providers.ts` around lines
392 - 408, The loop in getCheapestFromAvailableProviders currently calls
getDiscountedProviderSelectionPrice (which in turn calls getEffectiveDiscount)
for each provider causing N DB reads; instead, before mapping providers call a
batched discount fetch for the (organizationId, modelWithPricing.id) pair (or
add a helper like getEffectiveDiscountsForOrganizationModel) and return a map of
provider->discount, then change the providerPrices creation (the providers.map
using findProviderMapping, getDiscountedProviderSelectionPrice, and
providerSelectionKey) to read discounts from that in-memory map and compute
price/discount locally; apply the same batching refactor to the other occurrence
around the code referenced (the block at ~473-478) so no per-provider DB queries
occur.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99b5021406

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +532 to +535
return await swrWrap(
`discount:${orgPart}:${provider}:${model}`,
[discountTableName],
async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat discount lookup failures as no discount

When Postgres is unavailable and this specific discount:{org}:{provider}:{model} SWR key has not already been primed, swrWrap rethrows the database error. Because the new routing path calls findEffectiveDiscount for every candidate provider, otherwise cache-warmed gateway requests can now fail solely because a discount lookup missed its stale mirror; the existing DB helper for discounts falls back to a zero discount on lookup errors, so this wrapper should preserve that fail-open behavior.

Useful? React with 👍 / 👎.

@steebchen
steebchen added this pull request to the merge queue Jun 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@apps/gateway/src/chat/chat.ts`:
- Around line 1804-1936: The service_tier check is being applied too early by
mutating modelInfo.providers (the block guarded by isRequestedServiceTier and
the supportsRequestedTier filter that calls providerMatchesRequestedProvider and
mappingSupportsRequestedServiceTier), which causes auto-routing and
provider-key/region locking to validate against a synthetic candidate set;
revert removing entries from
modelInfo.providers/routingExpandedModelProviders/allModelProviders here and
instead apply
mappingSupportsRequestedServiceTier(providerMatchesRequestedProvider(...)) when
assembling each concrete candidate list (the same place the auto-routing loop
builds per-request candidateProviders and the later concrete-mapping selection
runs), i.e., remove the early filter and call the supportsRequestedTier
predicate at the point where you finalize candidate providers for
routing/selection so the tier check is enforced on final concrete mappings only.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8e93185d-f9a7-49e4-8fc6-47ddc469f80c

📥 Commits

Reviewing files that changed from the base of the PR and between a16c98c and 99b5021.

📒 Files selected for processing (4)
  • apps/gateway/src/chat/chat.ts
  • apps/gateway/src/lib/cached-queries-swr.spec.ts
  • apps/gateway/src/lib/cached-queries.ts
  • apps/gateway/src/videos/videos.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/gateway/src/videos/videos.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

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 `@apps/gateway/src/chat/chat.ts`:
- Around line 1804-1936: The service_tier check is being applied too early by
mutating modelInfo.providers (the block guarded by isRequestedServiceTier and
the supportsRequestedTier filter that calls providerMatchesRequestedProvider and
mappingSupportsRequestedServiceTier), which causes auto-routing and
provider-key/region locking to validate against a synthetic candidate set;
revert removing entries from
modelInfo.providers/routingExpandedModelProviders/allModelProviders here and
instead apply
mappingSupportsRequestedServiceTier(providerMatchesRequestedProvider(...)) when
assembling each concrete candidate list (the same place the auto-routing loop
builds per-request candidateProviders and the later concrete-mapping selection
runs), i.e., remove the early filter and call the supportsRequestedTier
predicate at the point where you finalize candidate providers for
routing/selection so the tier check is enforced on final concrete mappings only.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8e93185d-f9a7-49e4-8fc6-47ddc469f80c

📥 Commits

Reviewing files that changed from the base of the PR and between a16c98c and 99b5021.

📒 Files selected for processing (4)
  • apps/gateway/src/chat/chat.ts
  • apps/gateway/src/lib/cached-queries-swr.spec.ts
  • apps/gateway/src/lib/cached-queries.ts
  • apps/gateway/src/videos/videos.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/gateway/src/videos/videos.ts
🛑 Comments failed to post (1)
apps/gateway/src/chat/chat.ts (1)

1804-1936: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Defer service_tier filtering until the candidate set is concrete.

Line 1804 prunes modelInfo.providers before auto-routing, provider-key region locking, or env-key selection are resolved. That means auto requests get validated against the synthetic pre-routing state instead of the real model/provider candidates, and direct-provider requests can lose the provider-key-locked region before the later concrete-mapping selection runs. The auto-routing loop at Lines 2460-2564 also never re-applies the tier check, so the real candidate set is being built without the constraint that triggered the early 400. Move the service_tier check to the point where each concrete candidate list is assembled instead of mutating modelInfo.providers up front.

Also applies to: 2460-2564, 2730-2865

🤖 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 `@apps/gateway/src/chat/chat.ts` around lines 1804 - 1936, The service_tier
check is being applied too early by mutating modelInfo.providers (the block
guarded by isRequestedServiceTier and the supportsRequestedTier filter that
calls providerMatchesRequestedProvider and mappingSupportsRequestedServiceTier),
which causes auto-routing and provider-key/region locking to validate against a
synthetic candidate set; revert removing entries from
modelInfo.providers/routingExpandedModelProviders/allModelProviders here and
instead apply
mappingSupportsRequestedServiceTier(providerMatchesRequestedProvider(...)) when
assembling each concrete candidate list (the same place the auto-routing loop
builds per-request candidateProviders and the later concrete-mapping selection
runs), i.e., remove the early filter and call the supportsRequestedTier
predicate at the point where you finalize candidate providers for
routing/selection so the tier check is enforced on final concrete mappings only.

Merged via the queue into main with commit 4786744 Jun 8, 2026
18 checks passed
@steebchen
steebchen deleted the db-discounts-pr-feedback branch June 8, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants