feat: add OrcaRouter as a named model catalog source - #190
feat: add OrcaRouter as a named model catalog source#190kuswardhanietidims-svg wants to merge 23 commits into
Conversation
release: promote main
…es--release chore: release release
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: promote main
release: v1.8.1
release: v1.8.2
release: v1.9.0
release: v1.10.0
release: v1.11.0
release: v1.12.0
release: v1.13.0
release: v1.14.0
release: v1.15.0
release: v1.15.1
release: v1.15.2
release: v1.15.3
When ORCAROUTER_API_KEY is set, the model picker on the settings page lists models from OrcaRouter's /v1/models endpoint instead of the Vercel AI Gateway. The same UX applies — choose a model, the agent uses it. The change mirrors the existing Vercel AI Gateway catalog service: - ModelCatalogService detects the source from the env var - Each source has its own parse function, cache key, and /v1/models URL - The front end reads the source field from the API response to label the card description and error messages - The new env var is declared in env.validation.ts, turbo.json pass- through, .env.example, and docs/environment.md
|
@kuswardhanietidims-svg is attempting to deploy a commit to the Comp AI - PoC Team on Vercel. A member of the Team first needs to authorize it. |
|
Retargeted this onto
Nothing is wrong with your branch. If the diff now shows commits that are already on git fetch origin main
git rebase origin/main
git push --force-with-lease |
There was a problem hiding this comment.
2 issues found across 8 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/settings/model-catalog.service.ts">
<violation number="1" location="apps/api/src/settings/model-catalog.service.ts:18">
P3: This tunable default is defined at the top of the service file, but AGENTS.md "Constants in One File per Area" requires tunable numbers to live in a named config module for their area, never at the top of the file that first needed them. Move the 128_000 default into the settings area config and import it.</violation>
<violation number="2" location="apps/api/src/settings/model-catalog.service.ts:121">
P1: When OrcaRouter is selected, this adds every `/v1/models` entry, including models with no supported endpoint and video-only models. Filter entries for an OpenAI text/tool-capable model before adding them, or users can select IDs the agent cannot execute.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| const input = model.data.pricing?.prompt ?? null; | ||
| const output = model.data.pricing?.completion ?? null; | ||
|
|
||
| models.push({ |
There was a problem hiding this comment.
P1: When OrcaRouter is selected, this adds every /v1/models entry, including models with no supported endpoint and video-only models. Filter entries for an OpenAI text/tool-capable model before adding them, or users can select IDs the agent cannot execute.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/settings/model-catalog.service.ts, line 121:
<comment>When OrcaRouter is selected, this adds every `/v1/models` entry, including models with no supported endpoint and video-only models. Filter entries for an OpenAI text/tool-capable model before adding them, or users can select IDs the agent cannot execute.</comment>
<file context>
@@ -62,20 +85,84 @@ function toCatalogModel(model: GatewayModel): CatalogModel {
+ const input = model.data.pricing?.prompt ?? null;
+ const output = model.data.pricing?.completion ?? null;
+
+ models.push({
+ id: model.data.id,
+ name: model.data.name || model.data.id,
</file context>
|
|
||
| const CATALOG_TIMEOUT_MS = 5_000; | ||
|
|
||
| const DEFAULT_ORCAROUTER_CONTEXT_WINDOW_TOKENS = 128_000; |
There was a problem hiding this comment.
P3: This tunable default is defined at the top of the service file, but AGENTS.md "Constants in One File per Area" requires tunable numbers to live in a named config module for their area, never at the top of the file that first needed them. Move the 128_000 default into the settings area config and import it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/settings/model-catalog.service.ts, line 18:
<comment>This tunable default is defined at the top of the service file, but AGENTS.md "Constants in One File per Area" requires tunable numbers to live in a named config module for their area, never at the top of the file that first needed them. Move the 128_000 default into the settings area config and import it.</comment>
<file context>
@@ -3,14 +3,22 @@ import { Inject, Injectable, Logger } from "@nestjs/common";
const CATALOG_TIMEOUT_MS = 5_000;
+const DEFAULT_ORCAROUTER_CONTEXT_WINDOW_TOKENS = 128_000;
+
+export type ModelCatalogSource = "vercel" | "orcarouter";
</file context>
Summary
When
ORCAROUTER_API_KEYis set, the model picker on the settings page lists models from OrcaRouter instead of the Vercel AI Gateway. Same UX — choose a model, the agent uses it.OrcaRouter is an OpenAI-compatible AI gateway built for both models and agents. Like OpenRouter, it exposes a provider/model namespace across many models — but it also combines adaptive routing, automatic failover, zero-markup inference, observability, guardrails, and agent-tool governance behind the same endpoint. Adding orcarouter as a first-class provider means Comp AI CRM's users can use that stack directly, without treating OrcaRouter as an anonymous custom base URL.
It also runs gateway-level, zero-trust security for AI agents on the same endpoint — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes.
How it works
The change mirrors the existing Vercel AI Gateway catalog wiring end to end:
apps/api/src/settings/model-catalog.service.tscatalogSource()checksORCAROUTER_API_KEY;parseOrcaCatalog()parses the OrcaRouter/v1/modelsresponse intoCatalogModel[];fetchCatalog()picks the right URL, auth header, and parser per sourceapps/api/src/settings/settings.contracts.tsmodelCatalogOutputnow carries asourcefield ("vercel"or"orcarouter")apps/api/src/settings/settings.service.tssourcefrom the service into the tRPC responseapps/app/app/(app)/[slug]/settings/agent-model.tsxsource, labels the card description and error messages accordinglyapps/api/src/config/env.validation.tsORCAROUTER_API_KEYas an optional stringapps/api/turbo.jsonORCAROUTER_API_KEYthrough for dev and test.env.exampleORCAROUTER_API_KEYdocs/environment.mdORCAROUTER_API_KEYto the env reference tableVerification
biome check— cleantsc --noEmit(API and app) — cleannext typegen— cleanGET https://api.orcarouter.ai/v1/modelswithORCAROUTER_API_KEYreturns 200, the 204-model list was parsed through the same zod schema thatModelCatalogServiceuses, and the resultingCatalogModel[]has the expected shape (id, name, provider, contextWindowTokens, pricing)createOpenAI({ baseURL: "https://api.orcarouter.ai/v1" })+generateTextreturns "pong"ORCAROUTER_API_KEYis unsetDisclosure
I'm an engineer on the OrcaRouter team.
Contact
Discord: discord.gg/YEubt8enRA · X: https://x.com/OrcaRouter
Summary by cubic
Adds OrcaRouter as a first-class model catalog source. When
ORCAROUTER_API_KEYis set, the settings model picker lists models from OrcaRouter instead of the Vercel AI Gateway; the rest of the UX is unchanged.sourcefield to the catalog response so the UI can label the gateway correctly.Written for commit 0e4dbbe. Summary will update on new commits.