Skip to content

feat(ai-gateway): list and route virtual models in providers snapshot - #6738

Merged
chrarnoldus merged 7 commits into
mainfrom
feat/snapshot-virtual-models
Sep 28, 2026
Merged

chrarnoldus merged 7 commits into
mainfrom
feat/snapshot-virtual-models

Conversation

@chrarnoldus

@chrarnoldus chrarnoldus commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The Providers & Models snapshot (models_by_provider.data) is built from OpenRouter's per-provider model lists. Models without a provider of their own therefore never made it in, even though /api/openrouter/models lists them. That covers latest aliases such as ~anthropic/claude-sonnet-latest and routers such as typesafe/jev-router and openrouter/auto. The result was that Enterprise orgs could not see them on the Providers & Models page, and requests for them were always denied as "not in current snapshot".

Snapshot. During sync, injectVirtualModels (virtual-models.ts) adds every OpenRouter catalog model that no provider lists:

  • Latest aliases (~ ids with an alias_target) go under each provider that serves the standard variant of the target. They copy that provider's pricing and data policy, so provider allow lists, routing and data-collection checks treat an alias like its target.
  • Everything else (routers, or an alias whose target no provider serves) goes under a synthetic virtual provider with display name "Virtual". It uses catalog pricing; free routers are marked as potentially training.
  • formatPrice now renders the -1 router price as Varies.

Model access. A router picks a real provider per request. When an allow list (the org provider ceiling, or a member provider grant) includes virtual, a router's eligible routes are virtual plus the real providers on that same list (getEligibleProviderRoutes in model-access.server.ts).

  • If the list has no real provider, the router is denied with organization_provider.
  • Without a provider allow list, routers are unrestricted, like any other model.
  • Models served by real providers are unaffected.

Upstream. virtual is a Kilo-only slug and is never forwarded. withoutVirtualProvider strips it at every point where Kilo builds provider.only:

  • the org provider allow list in checkOrganizationModelRestrictions, which is used by the embeddings, transcription, TypeSafe, FIM and edit handlers;
  • the eligible-route only lists in llm-proxy, embeddings and the TypeSafe handler.

A router therefore only reaches providers the org allows.

Live data today gives 18 aliases placed under real providers. These routers go to "Virtual": typesafe/jev-router, openrouter/auto, openrouter/auto-beta, openrouter/free, openrouter/pareto-code, openrouter/fusion, openrouter/bodybuilder. kilo-auto/* stays out of the snapshot because it is already exempt from model restrictions.

Verification

  • Ran the same provider/catalog comparison against live OpenRouter data. The models missing from the snapshot are exactly the latest aliases and routers above, and every alias target resolves to at least one snapshot provider.
  • No manual end-to-end run of the sync cron or of a router request under a provider allow list. Both need live gateway credentials.

Visual Changes

N/A (new rows appear on the Providers & Models page; no layout changes).

Reviewer Notes

  • A member provider grant can already exceed the org ceiling for ordinary models. Routers follow the same existing rule, so under a member grant a router can use the grant's real providers.
  • Paid routers are stored as not requiring data collection. OpenRouter routers honor the request's provider.data_collection, which the gateway sets from org settings.
  • The first sync after deploy adds these models to the snapshot. Enterprise orgs with restrictions get one round of auto-change audit log entries from that.

@chrarnoldus chrarnoldus self-assigned this Sep 25, 2026
Comment thread apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts
Comment thread apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts Outdated
Comment thread apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts
@kilo-code-bot

kilo-code-bot Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit adds withoutVirtualProvider and strips the snapshot-only virtual slug from every provider.only list before it is forwarded upstream (the org allow list in checkOrganizationModelRestrictions, and the eligible-route lists in llm-proxy, embeddings and the TypeSafe handler); the strip sites, empty-list denials, and added tests are consistent and no new issues were found.

Files Reviewed (6 files)
  • apps/web/src/lib/ai-gateway/handlers/embeddings.ts
  • apps/web/src/lib/ai-gateway/handlers/llm-proxy.test.ts
  • apps/web/src/lib/ai-gateway/handlers/llm-proxy.ts
  • apps/web/src/lib/ai-gateway/llm-proxy-helpers.test.ts
  • apps/web/src/lib/ai-gateway/llm-proxy-helpers.ts
  • apps/web/src/lib/ai-gateway/typesafe/handler.ts
Previous Review Summaries (4 snapshots, latest commit 9fb5d00)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 9fb5d00)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit routes virtual routers through the organization's allowed real providers and strips the snapshot-only virtual slug before forwarding provider.only; the model-access, route, and test changes are internally consistent and no new issues were found.

Files Reviewed (6 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts
  • apps/web/src/lib/ai-gateway/providers/openrouter/models-by-provider-index.server.ts
  • apps/web/src/lib/ai-gateway/providers/openrouter/models-by-provider-index.server.test.ts
  • apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts
  • apps/web/src/lib/organizations/effective-model-access.server.test.ts
  • apps/web/src/lib/organizations/group-policies/model-access/model-access.server.ts

Previous review (commit 091c204)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit adds toUpstreamProviderOnly, which rewrites the snapshot-only virtual provider in an organization's provider.only allow list to all real providers for virtual routers and strips it otherwise; the routing, snapshot-failure fallback, group/org authorization and data-collection interactions check out, and no new issues were found.

Files Reviewed (3 files)
  • apps/web/src/app/api/openrouter/[...path]/route.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/models-by-provider-index.server.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/models-by-provider-index.server.test.ts - 0 issues

Previous review (commit 9f744f8)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit resolves the prior alias-prefix finding by gating the alias branch on ~ ids (matching resolveOpenRouterModelAlias) and adds a regression test; the remaining prior findings were confirmed intentional by the author and no new issues were found in the changed code.

Files Reviewed (4 files)
  • apps/web/src/components/models/util.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/sync-providers.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.test.ts - 0 issues

Previous review (commit 2ef5df6)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts 56 Non-free virtual routers are persisted as not training on prompts, which can bypass data-collection restrictions.

SUGGESTION

File Line Issue
apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts 87 Normalized-id guard drops one variant per model family when the catalog lists both the base and :free ids.
apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts 89 Alias branch does not verify the ~ alias prefix before treating alias_target as an alias.
Files Reviewed (4 files)
  • apps/web/src/components/models/util.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/sync-providers.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.ts - 3 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/virtual-models.test.ts - 0 issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@chrarnoldus chrarnoldus changed the title feat(ai-gateway): include virtual models in providers snapshot feat(ai-gateway): list and route virtual models in providers snapshot Sep 28, 2026
: [...decision.eligibleProviderRoutes];
const only = withoutVirtualProvider(
currentOnly
? currentOnly.filter(route => decision.eligibleProviderRoutes?.has(route))

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.

bot: Member-granted providers outside the organization list are filtered out

Suggested fix: When an effective member-policy decision supplies eligible routes, do not intersect those routes with the legacy Enterprise providerConfig.only list. This handler currently narrows the member grant to that list and returns a denial when the two sets do not overlap, although the PR says member provider grants may exceed the organization ceiling. Apply the same correction to the TypeSafe handler while preserving the provider privacy settings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will consider this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid. Group grants are meant to be additive (#5435), and only the chat gateway honored that. The fix is in #6812: the member decision is now the only enforcement point in the embeddings, TypeSafe, transcription, FIM and edit handlers, and org privacy settings are still applied.

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