Skip to content

feat(gateway): exact reset time in premium cap error - #3076

Merged
smakosh merged 1 commit into
mainfrom
feat/premium-cap-exact-reset-time
Jul 15, 2026
Merged

smakosh merged 1 commit into
mainfrom
feat/premium-cap-exact-reset-time

Conversation

@smakosh

@smakosh smakosh commented Jul 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Follow-up to #3074. The DevPass weekly premium-cap 402 error rounded the remaining wait up to whole days: 6 days and a few hours displayed as "Resets in 7 days", and even a 20-minute wait showed "Resets in 1 day".

The message now shows the remaining time as days and hours, e.g. "Resets in 6 days and 3 hours.":

  • Rounds up to the next hour so the wait is never understated.
  • Drops zero components ("7 days", "5 hours") and pluralizes correctly ("1 day and 1 hour").
  • Sub-hour waits display as "Resets in less than an hour."

Changes

  • apps/gateway/src/chat/tools/resolve-provider-context.ts: replaced the whole-day ceil with a formatTimeUntilReset() helper used in the 402 message.
  • apps/gateway/src/chat/tools/resolve-provider-context.spec.ts: unit tests for the formatter (rounding, zero components, singular/plural, sub-hour).

Testing

  • vitest run apps/gateway/src/chat/tools/resolve-provider-context.spec.ts — 10/10 passing
  • turbo run build --filter=gateway — builds clean

https://claude.ai/code/session_01NeqtWHWHmyug3BXUv3JmV9

Summary by CodeRabbit

  • Bug Fixes
    • Improved premium usage limit messages with more accurate reset wait times.
    • Reset times now display days and hours when applicable, use correct singular/plural wording, and clearly identify waits under one hour.

The weekly premium-cap 402 message rounded the wait up to whole days
(6 days and a few hours displayed as "Resets in 7 days", and even a
20-minute wait as "1 day"). Format the remaining time as days and
hours instead (e.g. "Resets in 6 days and 3 hours."), rounding up to
the next hour and reporting sub-hour waits as "less than an hour".

Claude-Session: https://claude.ai/code/session_01NeqtWHWHmyug3BXUv3JmV9
@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Premium reset formatting

Layer / File(s) Summary
Reset formatter and premium cap message
apps/gateway/src/chat/tools/resolve-provider-context.ts, apps/gateway/src/chat/tools/resolve-provider-context.spec.ts
Adds formatTimeUntilReset for day/hour and sub-hour durations, uses it in the premium cap 402 message, and tests rounding, omitted units, and singular/plural output.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: steebchen

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: more exact premium cap reset timing in the gateway error message.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 feat/premium-cap-exact-reset-time

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.

@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.

🧹 Nitpick comments (1)
apps/gateway/src/chat/tools/resolve-provider-context.ts (1)

218-233: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the millisecond multiplier to a constant.

You can apply DRY principles by extracting 60 * 60 * 1000 into a local constant, such as HOUR_IN_MS, to avoid duplicating the magic number.

♻️ Proposed refactor
 export function formatTimeUntilReset(ms: number): string {
-	if (ms < 60 * 60 * 1000) {
+	const HOUR_IN_MS = 60 * 60 * 1000;
+	if (ms < HOUR_IN_MS) {
 		return "less than an hour";
 	}
-	const totalHours = Math.ceil(ms / (60 * 60 * 1000));
+	const totalHours = Math.ceil(ms / HOUR_IN_MS);
 	const days = Math.floor(totalHours / 24);
 	const hours = totalHours % 24;
🤖 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/tools/resolve-provider-context.ts` around lines 218 -
233, In formatTimeUntilReset, extract the repeated 60 * 60 * 1000 expression
into a local constant such as HOUR_IN_MS, then reuse it for both the threshold
check and totalHours calculation without changing the existing behavior.

Source: Coding guidelines

🤖 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 `@apps/gateway/src/chat/tools/resolve-provider-context.ts`:
- Around line 218-233: In formatTimeUntilReset, extract the repeated 60 * 60 *
1000 expression into a local constant such as HOUR_IN_MS, then reuse it for both
the threshold check and totalHours calculation without changing the existing
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 78b2b81d-3980-4fd2-8249-4cc694195b0e

📥 Commits

Reviewing files that changed from the base of the PR and between 3bf6604 and 3c09e23.

📒 Files selected for processing (2)
  • apps/gateway/src/chat/tools/resolve-provider-context.spec.ts
  • apps/gateway/src/chat/tools/resolve-provider-context.ts

@smakosh
smakosh added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit 25ad946 Jul 15, 2026
22 of 23 checks passed
@smakosh
smakosh deleted the feat/premium-cap-exact-reset-time branch July 15, 2026 16:09
huangyingting pushed a commit to repomesh/llmgateway that referenced this pull request Jul 15, 2026
## Summary

DevPass users had no way to see which models actually count against the
weekly premium allowance — the docs described a $5/$15 threshold while
marketing surfaces used informal "flagship"/"cheap" tags, and the
allowance itself was only visible when you hit the 402. This PR surfaces
the exact classification the gateway enforces (`isPremiumModel`: $5+/M
input or $15+/M output on any provider mapping) across all user-facing
surfaces.

## Changes

### llmgateway.io /models (apps/ui)
- **Pricing Tier filter** (All/Premium/Standard) with `?tier=` URL
param, stacked under Use Case so the filter panel stays on one row.
Since the tier only matters for DevPass fair-use limits, it is **hidden
by default** on llmgateway.io — it appears when the visitor arrives from
DevPass (`?from=devpass`), or when a `?tier=` deep link is active, and
is labeled "Pricing Tier (DevPass)"
- **Gem icon** on premium model rows with a tooltip explaining the
threshold and DevPass weekly cap
- Models are annotated with `premium` **server-side** in `fetchModels()`
using the same `isPremiumModel` function the gateway uses for
enforcement — the catalogue never enters the client bundle
- **New `/models/premium` SEO category page** listing exactly the
premium models, with FAQs; linked from the directory, sitemap, and the
docs model-categories page

### devpass.llmgateway.io /models (apps/code, new page)
- Full models directory with the **same search, filters (incl. pricing
tier, always visible here), sorting, and pagination** as llmgateway.io —
the `AllModels` component tree (all-models, model-card, status badge,
code-example dialog, category filters, API types/fetchers) moved to
`@llmgateway/shared/components` and is now rendered by both apps
- App-specific bits are injected per app: footer, CTA (`renderCta`
render prop — ui passes ModelCtaButton, DevPass passes a Get DevPass
button), and `modelHrefBase` so model detail links point at
llmgateway.io
- DevPass links to the main directory carry `from=devpass` so the tier
filter shows there
- apps/ui keeps thin shims at the old paths so its ~15 existing
consumers are unchanged
- Premium vs standard explainer with the weekly allowance percentages
derived from `DEV_PLAN_PREMIUM_WEEKLY_PERCENT`

### DevPass dashboard (apps/code)
- **Weekly premium allowance progress bar** in the usage card, reusing
the existing `UsageBar`, with premium-specific warning copy and a
"Resets in N days and M hours" countdown (mirrors the gateway 402
formatting from theopenco#3076)
- Backed by new fields on `GET /dev-plans/status`:
`devPlanPremiumWeeklyLimit`, `devPlanPremiumCreditsUsed`,
`devPlanPremiumWeekResetsAt`, computed with the same shared helpers the
gateway/worker use (expired window ⇒ zero usage, no reset date)

### packages/shared
- New `components/models-directory/` module + card/table/toggle shadcn
primitives; adds `next` and `prism-react-renderer` deps; `@source`
entries added to ui/code globals.css for Tailwind scanning;
`showPricingTierFilter` prop controls tier-filter visibility per surface

## Verification
- Full monorepo build green; `dev-plans.spec.ts` 14/14 passing
- Verified live against the seeded DB: /models/premium server-filtered
JSON-LD (40 premium models, no standard leakage), DevPass /models
premium/standard split (Gemini 3.1 Pro correctly standard, Opus 4.8
premium), `/dev-plans/status` fields for fresh + active windows (Pro:
35.55 limit, resets exactly weekStart+7d), and the dashboard bar
rendered in-browser; user verified the running stack manually

https://claude.ai/code/session_01NeqtWHWHmyug3BXUv3JmV9

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Premium models browsing (directory + Premium models page) with
table/card views, filtering, sorting, provider/pricing details, and
updated CTA.
* Updated the dashboard Usage view to display weekly Premium fair-use
usage/allowance and the next reset time.
* **Documentation**
* Refreshed Premium vs Standard guidance to describe automatic
classification and fair-use behavior.
* **SEO / Navigation**
* Added Premium models and `/models` routes to the sitemap, and improved
internal links to surface Premium context across the app.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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