Skip to content

refactor(provider-mapping): move deactivatedAt and deprecatedAt to mappings - #1071

Merged
steebchen merged 3 commits into
mainfrom
terragon/refactor-model-mapping-dates-6xtvui
Oct 25, 2025
Merged

steebchen merged 3 commits into
mainfrom
terragon/refactor-model-mapping-dates-6xtvui

Conversation

@steebchen

@steebchen steebchen commented Oct 25, 2025

Copy link
Copy Markdown
Member

Summary

  • Move deactivatedAt and deprecatedAt from per-model definitions to provider-level mappings (ProviderModelMapping).
  • Refactor filtering logic across gateway, worker, and API to respect provider-level dates.
  • Update data models, schema, and tests to reflect provider-mapping dates and remove top-level model dates.
  • Ensure cheapest-model selection and model listing reflect provider-level deprecation/deactivation dates.

Changes

Core Functionality

  • Provider-level deprecation and deactivation dates (deprecatedAt and deactivatedAt) are now stored on ProviderModelMapping instead of ModelDefinition.
  • Filtering logic updated to exclude provider mappings that are deprecated/deactivated. If all provider mappings for a model are deactivated, the model is treated as unavailable (410).
  • Cheapest model resolution now filters out models whose provider mappings are deprecated/deactivated as of now.
  • When listing models, the API now computes and exposes the earliest deprecation and deactivation dates derived from provider mappings.

Data Model & Schema

  • Introduced deprecatedAt?: Date and deactivatedAt?: Date on ProviderModelMapping in packages/models/src/models.ts.
  • Removed deprecatedAt and deactivatedAt from ModelDefinition (top-level model fields).
  • Database schema updated:
    • Removed deprecatedAt and deactivatedAt from the model table.
    • Added deprecatedAt and deactivatedAt to the modelProviderMapping table.
  • Sync logic updated to persist deprecatedAt and deactivatedAt on provider mappings.

API / Gateway Behavior

  • Gateway chat flow updated to:
    • Filter out deactivated provider mappings
    • If all providers for a model are deactivated, throw HTTP 410
    • Update modelInfo to include only active providers
  • List models endpoint (gateway/models) now:
    • Considers provider mappings to filter out all-deactivated models when exclude conditions are used
    • Exposes deprecated_at and deactivated_at computed from provider mappings (earliest dates)
  • Model selection (cheapest model for a provider) now excludes models with provider mappings that are deprecated/deactivated.

Data / Seeds & Model Definitions

  • Numerous model definition files updated to remove top-level deprecation/deactivation fields and rely on provider-mapping dates. Some provider mappings now include explicit deprecatedAt/deactivatedAt values where applicable.

Tests

  • Updated tests to verify provider-mapping-level behavior instead of model-level dates.
  • getCheapestModelForProvider tests now assert filtering based on provider mappings’ deprecatedAt/deactivatedAt.
  • listModels tests account for earliest dates pulled from provider mappings.

Worker / Sync

  • Sync workflow now persists deprecation and deactivation data at the provider-mapping level, aligning with the new data model.

Rationale

  • Moving deprecation and deactivation data to provider mappings allows granular control per provider-model combination, enabling more precise lifecycle management and filtering without polluting model-level metadata.
  • This aligns with the need to disable specific provider capabilities while keeping other providers for a model available.

Migration Notes

  • If you previously relied on top-level model deprecatedAt/deactivatedAt, migrate to using provider mappings (ProviderModelMapping.deprecatedAt and ProviderModelMapping.deactivatedAt).
  • Client code querying listModels or cheapest models should continue to work, now with provider-level filtering semantics.
  • The API responses for model listings now reflect earliest provider-mapping dates for deprecated_at and deactivated_at where applicable.

Test Plan

  • Run unit tests for models and provider mappings (getCheapestModelForProvider, listModels, etc.)
  • Run gateway openapi tests and chat e2e tests to validate 410 behavior when all providers are deactivated
  • Validate that model listings show earliest deprecated_at and deactivated_at derived from provider mappings
  • Validate syncing of deprecatedAt/deactivatedAt into provider mappings via worker

Notes for reviewers

  • Review the places where provider mappings are now used for filtering (gateway chat.ts, chat-helpers.e2e.ts).
  • Pay attention to schema changes in packages/db/src/schema.ts and ensure migrations align with the new provider-mapping fields.
  • Confirm that tests referencing provider-level dates align with the new semantics (provider mappings instead of per-model dates).

🌿 Generated by Terry


ℹ️ Tag @terragon-labs to ask questions and address PR feedback

📎 Task: https://www.terragonlabs.com/task/e3e3189b-ca86-491b-aae7-7d13c406d571

Summary by CodeRabbit

  • New Features
    • Models are now deactivated per provider rather than globally, enabling partial availability when at least one provider remains active.
    • Enhanced auto-routing with improved provider selection based on deprecation status and reasoning capabilities.
    • Added automatic reasoning effort handling for compatible models.
    • Improved JSON output format validation with provider-level support checks.

…apping

- Introduce deprecatedAt and deactivatedAt properties on ProviderModelMapping interface.
- Update model filtering and selection to consider provider-level deprecation and deactivation dates.
- Remove deprecatedAt and deactivatedAt from ModelDefinition, reflecting per-provider handling.
- Update model syncing service to persist these new fields per mapping.
- Adjust model definitions to remove redundant deprecatedAt and deactivatedAt props.
- Enhance filtering logic in gateway and model APIs to exclude models where all providers are deprecated or deactivated.
- Ensure filtering respects provider mapping status rather than model-level dates.
- Update tests and continuous integration to align with new deprecation model.

This enables more granular control over model availability based on provider mappings.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@bunnyshell

bunnyshell Bot commented Oct 25, 2025

Copy link
Copy Markdown

❌ Preview Environment deleted from Bunnyshell

Available commands (reply to this comment):

  • 🚀 /bns:deploy to deploy the environment

@coderabbitai

coderabbitai Bot commented Oct 25, 2025

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@steebchen has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 21 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1075e03 and b5288c3.

📒 Files selected for processing (2)
  • packages/db/migrations/1761401197_silky_mindworm.sql (1 hunks)
  • packages/db/migrations/meta/_journal.json (1 hunks)

Walkthrough

This PR migrates deprecation and deactivation metadata from model-level to provider-mapping-level. Models are now deactivated/deprecated only when all their provider mappings are deactivated/deprecated. Database schema, type definitions, gateway filtering logic, and model definitions are updated to reflect this per-provider-mapping lifecycle tracking.

Changes

Cohort / File(s) Summary
Database schema migration
packages/db/src/schema.ts
Moved deprecatedAt and deactivatedAt timestamp fields from the model table to the model_provider_mapping table, enabling per-provider deactivation/deprecation tracking.
Type system updates
packages/models/src/models.ts
Removed deprecatedAt and deactivatedAt from ModelDefinition interface; added them to ProviderModelMapping interface with documentation comments.
Sync service
apps/worker/src/services/sync-models.ts
Changed model sync logic to remove deprecatedAt/deactivatedAt from model records and conditionally propagate them into provider mapping records during updates and inserts.
Gateway model filtering
apps/gateway/src/models/models.ts
Replaced model-level deactivation/deprecation checks with provider-mapping-level checks; models now filtered only when all their provider mappings are deactivated/deprecated; output timestamps derive from earliest dates across mappings.
Gateway chat routing
apps/gateway/src/chat/chat.ts
Added provider-mapping-level deactivation/deprecation filtering in request validation; expanded auto-routing to filter and validate provider mappings by deprecation and reasoning capability; automatically propagate reasoning_effort for auto-resolved models.
Chat helper filtering
apps/gateway/src/chat-helpers.e2e.ts
Replaced model-level deactivation filter with provider-mapping-level check; models excluded only when all provider mappings are deactivated.
Helper functions
packages/models/src/get-cheapest-model-for-provider.ts
Updated to filter provider mappings by deprecatedAt/deactivatedAt against current date instead of checking model-level fields.
Model spec tests
packages/models/src/models.spec.ts
Updated deprecation test to check provider-mapping deprecatedAt for the cheapest model rather than model-level field.
Model definitions — Alibaba
packages/models/src/models/alibaba.ts
Removed top-level deprecatedAt/deactivatedAt from all entries; added provider-scoped deactivatedAt for two Qwen models (deactivated 2025-09-10).
Model definitions — Anthropic
packages/models/src/models/anthropic.ts
Removed top-level deprecatedAt/deactivatedAt from entries; moved deactivatedAt into provider-specific configurations for Claude models.
Model definitions — DeepSeek
packages/models/src/models/deepseek.ts
Removed top-level deprecatedAt/deactivatedAt from entries; added provider-scoped deactivatedAt for deepseek-r1-distill-llama-70b (Groq) and deepseek-v3.1 (DeepSeek provider).
Model definitions — Google
packages/models/src/models/google.ts
Removed top-level deprecatedAt: undefined from multiple entries; added provider-level deactivatedAt with concrete dates to preview and Gemini models.
Model definitions — XAI
packages/models/src/models/xai.ts
Removed top-level deprecatedAt/deactivatedAt from Grok models; added provider-scoped deprecatedAt and deactivatedAt to specific models (grok-3-fast, grok-3-mini-fast, grok-2 variants, grok-4-fast variants, grok-code-fast-1).
Model definitions — Other providers
packages/models/src/models/{llmgateway,meta,mistral,moonshot,nousresearch,openai,perplexity,routeway,zai}.ts
Removed top-level deprecatedAt: undefined and/or deactivatedAt: undefined from model entries across all files; no provider-scoped additions for these providers.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Gateway
    participant ModelRegistry
    participant Database

    Client->>Gateway: Request with model ID
    Gateway->>ModelRegistry: Get model details
    ModelRegistry->>Database: Query model + provider mappings
    Database-->>ModelRegistry: Model with all provider mappings
    
    rect rgb(200, 220, 240)
    Note over ModelRegistry: OLD: Check model.deactivatedAt
    end
    
    rect rgb(200, 240, 200)
    Note over ModelRegistry: NEW: Check each provider mapping.deactivatedAt
    ModelRegistry->>ModelRegistry: Filter: active provider mappings = mappings without past deactivatedAt
    alt No active provider mappings remain
        ModelRegistry-->>Gateway: Model unavailable (410)
    else At least one active provider mapping
        ModelRegistry-->>Gateway: Model with filtered provider mappings
    end
    end
    
    Gateway-->>Client: Response (or error)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Key areas requiring attention:
    • Logic changes in apps/gateway/src/chat/chat.ts for provider selection, auto-routing, and JSON schema validation with provider-mapping filters
    • Provider-mapping filtering logic in apps/gateway/src/models/models.ts and packages/models/src/get-cheapest-model-for-provider.ts to ensure "all deactivated" logic is correct
    • Database schema migration implications and sync service updates in apps/worker/src/services/sync-models.ts
    • Model definition changes across multiple providers to verify provider-scoped timestamps are correctly positioned

Possibly related PRs

Suggested labels

auto-merge

Suggested reviewers

  • smakosh

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "refactor(provider-mapping): move deactivatedAt and deprecatedAt to mappings" accurately and directly describes the main structural change across the entire changeset. The raw summary confirms the core refactor involves moving the deprecatedAt and deactivatedAt timestamps from model-level definitions (ModelDefinition and the model database table) to provider-level mappings (ProviderModelMapping and the model_provider_mapping table). The title uses clear, conventional commit format without vague terms or excessive detail, and a teammate reviewing the commit history would immediately understand this is about relocating timestamp fields to a new location in the architecture. All the cascading changes to filtering logic, gateway/worker code, and model definition files stem directly from this primary refactor.

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.

@github-actions github-actions Bot changed the title Refactor: move deactivatedAt and deprecatedAt to provider mappings refactor(provider-mapping): move deactivatedAt and deprecatedAt to mappings Oct 25, 2025
steebchen and others added 2 commits October 25, 2025 14:05
Added a non-null assertion operator to deactivatedAt property to ensure it is not undefined during date comparison, preventing possible runtime errors in chat helpers E2E tests.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>

@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 (4)
packages/models/src/get-cheapest-model-for-provider.ts (1)

67-73: Fix discount multiplier semantics in two locations (currently inverted).

Spec: "Discount multiplier (0-1), where 0.5 = 50% off" (models.ts line 52). Current code treats it as percentage off via 1 - discount, which breaks for values other than 0.5. Example: discount=0.9 should be 10% off, but current code produces 90% off.

Two files need identical fixes:

packages/models/src/get-cheapest-model-for-provider.ts (lines 68–72)

-    const discount = (providerInfo as ProviderModelMapping).discount ?? 0;
-    const discountMultiplier = 1 - discount;
-    const totalPrice =
-      ((providerInfo.inputPrice! + providerInfo.outputPrice!) / 2) *
-      discountMultiplier;
+    const discountMultiplier =
+      (providerInfo as ProviderModelMapping).discount ?? 1;
+    const basePrice =
+      (providerInfo.inputPrice! + providerInfo.outputPrice!) / 2;
+    const totalPrice = basePrice * discountMultiplier;

packages/models/src/get-cheapest-from-available-providers.ts (lines 44–49)

-    const discount = (providerInfo as ProviderModelMapping)?.discount || 0;
-    const discountMultiplier = 1 - discount;
-    const totalPrice =
-      (((providerInfo?.inputPrice || 0) + (providerInfo?.outputPrice || 0)) /
-        2) *
-      discountMultiplier;
+    const discountMultiplier =
+      (providerInfo as ProviderModelMapping)?.discount ?? 1;
+    const totalPrice =
+      (((providerInfo?.inputPrice || 0) + (providerInfo?.outputPrice || 0)) /
+        2) *
+      discountMultiplier;

Verify seed data uses multipliers correctly (1 = no discount, 0.8 = 20% off, etc.).

apps/gateway/src/models/models.ts (2)

118-146: Model-level filtering OK; but provider entries aren’t filtered.

You compute allDeactivated/allDeprecated correctly, but the response still includes deprecated/deactivated provider mappings, contrary to the PR objective. Filter provider mappings using the query flags (include_deactivated, exclude_deprecated) before building the response.

Apply this focused patch in the mapping phase (next comment shows full diff).


147-215: Apply provider filtering throughout model construction, but resolve inconsistency in deprecated_at/deactivated_at calculations.

The suggested diff correctly filters providers for capabilities and response, but leaves deprecated_at and deactivated_at calculations using unfiltered model.providers. Either:

  1. Update deprecated_at/deactivated_at to use providersForResponse if deprecation status should reflect only active providers in the response, or
  2. Keep them unfiltered and add a comment explaining they represent global model deprecation regardless of filtering

The current diff creates ambiguity. Also verify the "Also applies to: 216-233, 239-251" locations are addressed consistently.

apps/worker/src/services/sync-models.ts (1)

120-137: Fix || null operators throughout both INSERT and UPDATE blocks to preserve falsy values like false and 0.

The || null pattern collapses any falsy value (false, 0, empty strings, etc.) to null. This affects not just boolean fields (vision, reasoning, tools) but also numeric fields (contextSize, maxOutput), date fields (deprecatedAt, deactivatedAt), and other typed fields (reasoningOutput, supportedParameters, test). Use ?? null to only default when undefined or null.

Both INSERT (lines 120–137) and UPDATE (lines 180–210) blocks require fixes for:

  • vision, reasoning, tools
  • contextSize, maxOutput
  • reasoningOutput, supportedParameters, test
  • deprecatedAt, deactivatedAt

Replace all instances of field || null with field ?? null in both blocks.

(Optional) Avoid hardcoding status: "active" when the mapping is past its deactivation date:

-        status: "active",
+        status:
+          "deactivatedAt" in mapping && mapping.deactivatedAt && new Date() > mapping.deactivatedAt
+            ? "inactive"
+            : "active",
🧹 Nitpick comments (8)
packages/models/src/models.spec.ts (1)

355-363: Use strict “<” to mirror selection predicate.

Cheapest-model filter excludes mappings when now >= deprecatedAt. The assertion should be now < deprecatedAt for exact alignment and to avoid boundary flakiness.

Apply this diff:

-          expect(new Date() <= providerMapping.deprecatedAt).toBe(true);
+          expect(new Date() < providerMapping.deprecatedAt).toBe(true);
packages/models/src/models.ts (1)

112-119: Fields addition matches provider-mapping lifecycle move: LGTM.

Types/docs look good. Optional: clarify in docstrings that timestamps are compared using UTC and that deprecatedAt is a soft filter while deactivatedAt is hard block, to prevent misuse across modules.

packages/db/src/schema.ts (1)

651-652: Use timestamptz and add a time-based index for filtering.

Storing lifecycle gates as timestamp without TZ risks drift. Prefer timestamptz and consider an index to speed “active as of now” scans.

Example:

-    deprecatedAt: timestamp(),
-    deactivatedAt: timestamp(),
+    deprecatedAt: timestamp({ withTimezone: true }),
+    deactivatedAt: timestamp({ withTimezone: true }),

Optional index:

// e.g., mappings where (deactivatedAt IS NULL OR deactivatedAt > now())
index("model_provider_mapping_deactivated_at_idx").on(table.deactivatedAt)
packages/models/src/models/alibaba.ts (1)

325-326: Confirm dates and consider consistent ISO format.

The new deactivations are fine. For consistency across files, prefer ISO with timezone (e.g., new Date("2025-09-10T00:00:00Z")) like in anthropic.ts. Please confirm these dates are correct.

Also applies to: 366-367

packages/models/src/models/deepseek.ts (1)

138-139: Verify deactivation date and consider ISO-Z format.

deactivatedAt: new Date("2025-10-09") is in the past (today is 2025-10-25). If intentional, all good; otherwise adjust. Consider new Date("2025-10-09T00:00:00Z") for consistency.

packages/models/src/models/anthropic.ts (1)

135-136: Dates look aligned; standardize format for consistency.

Values are consistent with per-provider mapping policy. For uniformity with other files, consider ISO with Z suffix across the board (e.g., keep using ...T00:00:00Z here and elsewhere).

Also applies to: 149-150, 169-171

packages/models/src/models/google.ts (1)

59-60: Make deactivation timestamps explicit UTC to avoid off-by-one “day-of” issues

new Date("YYYY-MM-DD") parses as UTC midnight but is easy to misinterpret and can create equality-edge cases with runtime checks. Prefer explicit UTC timestamps.

Apply pattern like:

- deactivatedAt: new Date("2025-07-15"),
+ deactivatedAt: new Date("2025-07-15T00:00:00Z"),

Also consider aligning gateway comparisons to be inclusive (now >= deactivatedAt) for clearer “effective on date” semantics, see chat.ts suggestions.

Also applies to: 81-82, 102-103, 123-124, 285-286, 306-307, 327-328, 348-349, 512-513

apps/gateway/src/chat/chat.ts (1)

551-559: Provider-level deactivation filter looks good; make comparison inclusive and reuse one clock

Current check uses now > deactivatedAt. For “effective on date” semantics, use >=. Also reuse a single now across the handler (or function-scope) for consistency.

- const now = new Date();
+ const now = new Date(); // consider hoisting once near top of handler

 const activeProviders = modelInfo.providers.filter((provider) =>
-  !((provider as ProviderModelMapping).deactivatedAt && now > (provider as ProviderModelMapping).deactivatedAt!)
+  !((provider as ProviderModelMapping).deactivatedAt && now >= (provider as ProviderModelMapping).deactivatedAt!)
 );

Also applies to: 561-566, 568-573

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12cce5e and 1075e03.

📒 Files selected for processing (22)
  • apps/gateway/src/chat-helpers.e2e.ts (1 hunks)
  • apps/gateway/src/chat/chat.ts (2 hunks)
  • apps/gateway/src/models/models.ts (2 hunks)
  • apps/worker/src/services/sync-models.ts (2 hunks)
  • packages/db/src/schema.ts (1 hunks)
  • packages/models/src/get-cheapest-model-for-provider.ts (2 hunks)
  • packages/models/src/models.spec.ts (1 hunks)
  • packages/models/src/models.ts (1 hunks)
  • packages/models/src/models/alibaba.ts (2 hunks)
  • packages/models/src/models/anthropic.ts (3 hunks)
  • packages/models/src/models/deepseek.ts (1 hunks)
  • packages/models/src/models/google.ts (9 hunks)
  • packages/models/src/models/llmgateway.ts (0 hunks)
  • packages/models/src/models/meta.ts (0 hunks)
  • packages/models/src/models/mistral.ts (0 hunks)
  • packages/models/src/models/moonshot.ts (0 hunks)
  • packages/models/src/models/nousresearch.ts (0 hunks)
  • packages/models/src/models/openai.ts (0 hunks)
  • packages/models/src/models/perplexity.ts (0 hunks)
  • packages/models/src/models/routeway.ts (0 hunks)
  • packages/models/src/models/xai.ts (4 hunks)
  • packages/models/src/models/zai.ts (0 hunks)
💤 Files with no reviewable changes (9)
  • packages/models/src/models/llmgateway.ts
  • packages/models/src/models/mistral.ts
  • packages/models/src/models/zai.ts
  • packages/models/src/models/routeway.ts
  • packages/models/src/models/nousresearch.ts
  • packages/models/src/models/perplexity.ts
  • packages/models/src/models/meta.ts
  • packages/models/src/models/openai.ts
  • packages/models/src/models/moonshot.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Always use top-level import; never use require() or dynamic import()

Files:

  • packages/models/src/models.spec.ts
  • packages/models/src/models.ts
  • apps/worker/src/services/sync-models.ts
  • apps/gateway/src/models/models.ts
  • apps/gateway/src/chat/chat.ts
  • packages/models/src/models/alibaba.ts
  • packages/db/src/schema.ts
  • apps/gateway/src/chat-helpers.e2e.ts
  • packages/models/src/models/deepseek.ts
  • packages/models/src/get-cheapest-model-for-provider.ts
  • packages/models/src/models/anthropic.ts
  • packages/models/src/models/google.ts
  • packages/models/src/models/xai.ts
**/*.spec.ts

📄 CodeRabbit inference engine (AGENTS.md)

Unit tests should be written in *.spec.ts files

Unit test files should be named with the .spec.ts suffix

Files:

  • packages/models/src/models.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Never use any or as any in this TypeScript project unless absolutely necessary
Always use top-level import; do not use require or dynamic import()

Files:

  • packages/models/src/models.spec.ts
  • packages/models/src/models.ts
  • apps/worker/src/services/sync-models.ts
  • apps/gateway/src/models/models.ts
  • apps/gateway/src/chat/chat.ts
  • packages/models/src/models/alibaba.ts
  • packages/db/src/schema.ts
  • apps/gateway/src/chat-helpers.e2e.ts
  • packages/models/src/models/deepseek.ts
  • packages/models/src/get-cheapest-model-for-provider.ts
  • packages/models/src/models/anthropic.ts
  • packages/models/src/models/google.ts
  • packages/models/src/models/xai.ts
apps/{gateway,api}/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

apps/{gateway,api}/**/*.ts: Use Hono for HTTP routing in Gateway and API services
Use Zod schemas for request/response validation in server routes

Files:

  • apps/gateway/src/models/models.ts
  • apps/gateway/src/chat/chat.ts
  • apps/gateway/src/chat-helpers.e2e.ts
{apps/{api,gateway}/**/*.ts,packages/db/**/*.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

For read operations, use db().query.<table>.findMany() or db().query.<table>.findFirst()

Files:

  • apps/gateway/src/models/models.ts
  • apps/gateway/src/chat/chat.ts
  • packages/db/src/schema.ts
  • apps/gateway/src/chat-helpers.e2e.ts
packages/db/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use Drizzle ORM with the latest object syntax for database schema and code

Files:

  • packages/db/src/schema.ts
**/*.e2e.ts

📄 CodeRabbit inference engine (AGENTS.md)

End-to-end tests should be written in *.e2e.ts files

End-to-end test files should be named with the .e2e.ts suffix

Files:

  • apps/gateway/src/chat-helpers.e2e.ts
🧬 Code graph analysis (5)
packages/models/src/models.spec.ts (1)
packages/models/src/models.ts (1)
  • ProviderModelMapping (23-120)
apps/gateway/src/models/models.ts (2)
apps/gateway/src/chat-helpers.e2e.ts (1)
  • filteredModels (59-156)
packages/models/src/models.ts (2)
  • ModelDefinition (124-165)
  • ProviderModelMapping (23-120)
apps/gateway/src/chat/chat.ts (1)
packages/models/src/models.ts (1)
  • ProviderModelMapping (23-120)
apps/gateway/src/chat-helpers.e2e.ts (1)
packages/models/src/models.ts (1)
  • ProviderModelMapping (23-120)
packages/models/src/get-cheapest-model-for-provider.ts (1)
packages/models/src/models.ts (1)
  • ProviderModelMapping (23-120)
🔇 Additional comments (3)
packages/models/src/models/xai.ts (2)

63-64: LGTM! Deprecation lifecycle correctly implemented.

The provider-level deprecation and deactivation dates are properly ordered with a reasonable transition period (approximately 5 weeks between deprecation and deactivation).


85-86: Consistent deprecation dates across legacy models.

All four deprecated models (grok-3-mini-fast, grok-2-1212, grok-2-vision-1212) share identical deprecation and deactivation dates, which appropriately groups the sunset of older model generations.

Also applies to: 108-109, 131-132

packages/models/src/get-cheapest-model-for-provider.ts (1)

23-32: Provider-mapping deprecation/deactivation filter: LGTM.

The time-gated exclusion at mapping level matches the new semantics and uses a single captured currentDate.
Please confirm other call sites use the same >= boundary to stay consistent.

Comment on lines +62 to +70
// Filter out models where all provider mappings are deactivated
.filter((model) => {
const allDeactivated = model.providers.every(
(provider) =>
(provider as ProviderModelMapping).deactivatedAt &&
new Date() > (provider as ProviderModelMapping).deactivatedAt!,
);
return !allDeactivated;
})

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 | 🟡 Minor

Align deactivation boundary with model-selection logic (>= vs >).

Use >= to match getCheapestModelForProvider and avoid edge-case inconsistencies at exact deactivation time.

Apply this diff:

-        (provider as ProviderModelMapping).deactivatedAt &&
-        new Date() > (provider as ProviderModelMapping).deactivatedAt!,
+        (provider as ProviderModelMapping).deactivatedAt &&
+        new Date() >= (provider as ProviderModelMapping).deactivatedAt!,

Optional: capture the timestamp once (const now = new Date()) to avoid repeated calls.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Filter out models where all provider mappings are deactivated
.filter((model) => {
const allDeactivated = model.providers.every(
(provider) =>
(provider as ProviderModelMapping).deactivatedAt &&
new Date() > (provider as ProviderModelMapping).deactivatedAt!,
);
return !allDeactivated;
})
// Filter out models where all provider mappings are deactivated
.filter((model) => {
const allDeactivated = model.providers.every(
(provider) =>
(provider as ProviderModelMapping).deactivatedAt &&
new Date() >= (provider as ProviderModelMapping).deactivatedAt!,
);
return !allDeactivated;
})
🤖 Prompt for AI Agents
In apps/gateway/src/chat-helpers.e2e.ts around lines 62 to 70, the filter uses
strict greater-than when comparing current time to provider.deactivatedAt which
mismatches model-selection logic that treats deactivation time as inclusive;
change the comparison to >= so providers deactivated exactly at the timestamp
are considered deactivated, and update the condition accordingly (i.e., mark
allDeactivated when deactivatedAt is present and now >= deactivatedAt). Also,
capture the current time once (const now = new Date()) before the filter to
avoid repeated Date() calls.

Comment on lines +892 to +901
// Filter by context size requirement, reasoning capability, and deprecation status
const suitableProviders = availableModelProviders.filter((provider) => {
// Skip deprecated provider mappings
if (
(provider as ProviderModelMapping).deprecatedAt &&
new Date() > (provider as ProviderModelMapping).deprecatedAt!
) {
return false;
}

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 | 🔴 Critical

Auto-routing can select deactivated providers — exclude them too

In the auto path, only deprecated mappings are skipped. Deactivated mappings must also be excluded; otherwise we can resolve to an unavailable provider and fail downstream.

Apply this diff to filter both deactivated and deprecated mappings and avoid repeated new Date() calls:

- // Filter by context size requirement, reasoning capability, and deprecation status
- const suitableProviders = availableModelProviders.filter((provider) => {
-   // Skip deprecated provider mappings
-   if (
-     (provider as ProviderModelMapping).deprecatedAt &&
-     new Date() > (provider as ProviderModelMapping).deprecatedAt!
-   ) {
-     return false;
-   }
+ // Filter by context size, reasoning capability, and lifecycle status
+ const now = new Date();
+ const suitableProviders = availableModelProviders.filter((provider) => {
+   const mapping = provider as ProviderModelMapping;
+   // Skip deactivated provider mappings
+   if (mapping.deactivatedAt && now >= mapping.deactivatedAt) {
+     return false;
+   }
+   // Skip deprecated provider mappings
+   if (mapping.deprecatedAt && now >= mapping.deprecatedAt) {
+     return false;
+   }

   // Use the provider's context size, defaulting to a reasonable value if not specified
   const modelContextSize = provider.contextSize ?? 8192;
   const contextSizeMet = modelContextSize >= requiredContextSize;

   // If reasoning_effort is specified, only include providers that support reasoning
   if (reasoning_effort !== undefined) {
     return (
       contextSizeMet &&
-      (provider as ProviderModelMapping).reasoning === true
+      mapping.reasoning === true
     );
   }

   return contextSizeMet;
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Filter by context size requirement, reasoning capability, and deprecation status
const suitableProviders = availableModelProviders.filter((provider) => {
// Skip deprecated provider mappings
if (
(provider as ProviderModelMapping).deprecatedAt &&
new Date() > (provider as ProviderModelMapping).deprecatedAt!
) {
return false;
}
// Filter by context size, reasoning capability, and lifecycle status
const now = new Date();
const suitableProviders = availableModelProviders.filter((provider) => {
const mapping = provider as ProviderModelMapping;
// Skip deactivated provider mappings
if (mapping.deactivatedAt && now >= mapping.deactivatedAt) {
return false;
}
// Skip deprecated provider mappings
if (mapping.deprecatedAt && now >= mapping.deprecatedAt) {
return false;
}
// Use the provider's context size, defaulting to a reasonable value if not specified
const modelContextSize = provider.contextSize ?? 8192;
const contextSizeMet = modelContextSize >= requiredContextSize;
// If reasoning_effort is specified, only include providers that support reasoning
if (reasoning_effort !== undefined) {
return (
contextSizeMet &&
mapping.reasoning === true
);
}
return contextSizeMet;
});
🤖 Prompt for AI Agents
In apps/gateway/src/chat/chat.ts around lines 892 to 901, the
availableModelProviders filter only excludes deprecated mappings but not
deactivated ones and calls new Date() repeatedly; update the predicate to also
skip providers with a deactivatedAt timestamp and compute const now = new Date()
once before the filter, then use now to compare both deprecatedAt and
deactivatedAt (return false if either timestamp exists and is <= now), keeping
existing context-size and reasoning checks unchanged.

@steebchen
steebchen merged commit 9bb4c08 into main Oct 25, 2025
13 checks passed
@steebchen
steebchen deleted the terragon/refactor-model-mapping-dates-6xtvui branch October 25, 2025 14:22
@coderabbitai coderabbitai Bot mentioned this pull request Jan 14, 2026
6 tasks
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.

1 participant