Skip to content

feat: add OrcaRouter as a named model catalog source - #190

Open
kuswardhanietidims-svg wants to merge 23 commits into
trycompai:mainfrom
kuswardhanietidims-svg:feat/orcarouter-provider
Open

feat: add OrcaRouter as a named model catalog source#190
kuswardhanietidims-svg wants to merge 23 commits into
trycompai:mainfrom
kuswardhanietidims-svg:feat/orcarouter-provider

Conversation

@kuswardhanietidims-svg

@kuswardhanietidims-svg kuswardhanietidims-svg commented Aug 29, 2026

Copy link
Copy Markdown

Summary

When ORCAROUTER_API_KEY is 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:

File What changed
apps/api/src/settings/model-catalog.service.ts catalogSource() checks ORCAROUTER_API_KEY; parseOrcaCatalog() parses the OrcaRouter /v1/models response into CatalogModel[]; fetchCatalog() picks the right URL, auth header, and parser per source
apps/api/src/settings/settings.contracts.ts modelCatalogOutput now carries a source field ("vercel" or "orcarouter")
apps/api/src/settings/settings.service.ts Passes source from the service into the tRPC response
apps/app/app/(app)/[slug]/settings/agent-model.tsx Reads source, labels the card description and error messages accordingly
apps/api/src/config/env.validation.ts Declares ORCAROUTER_API_KEY as an optional string
apps/api/turbo.json Passes ORCAROUTER_API_KEY through for dev and test
.env.example Documents ORCAROUTER_API_KEY
docs/environment.md Adds ORCAROUTER_API_KEY to the env reference table

Verification

  • biome check — clean
  • tsc --noEmit (API and app) — clean
  • next typegen — clean
  • Live-tested: GET https://api.orcarouter.ai/v1/models with ORCAROUTER_API_KEY returns 200, the 204-model list was parsed through the same zod schema that ModelCatalogService uses, and the resulting CatalogModel[] has the expected shape (id, name, provider, contextWindowTokens, pricing)
  • Live-tested: createOpenAI({ baseURL: "https://api.orcarouter.ai/v1" }) + generateText returns "pong"
  • Regression: the Vercel AI Gateway catalog (225 usable tool-use models) still loads normally when ORCAROUTER_API_KEY is unset

Disclosure

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_KEY is set, the settings model picker lists models from OrcaRouter instead of the Vercel AI Gateway; the rest of the UX is unchanged.

  • Mirrors the existing Vercel catalog wiring: per-source parse, cache key, auth header, and UI labels.
  • Adds an explicit source field to the catalog response so the UI can label the gateway correctly.
  • Requires no migration; users keep the existing Vercel behavior until they set the new env var.

Written for commit 0e4dbbe. Summary will update on new commits.

Review in cubic

carhartlewis and others added 23 commits August 7, 2026 11:38
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
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

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

@github-actions
github-actions Bot changed the base branch from release to main August 29, 2026 09:16
@github-actions

Copy link
Copy Markdown
Contributor

Retargeted this onto main.

release is the default branch so that a plain clone runs the last tagged release, but nothing merges into it — it is fast-forwarded onto the tag by the Release workflow and that is all. Changes go to main, and reach release when a release is cut.

Nothing is wrong with your branch. If the diff now shows commits that are already on main, rebase and force-push:

git fetch origin main
git rebase origin/main
git push --force-with-lease

@cubic-dev-ai cubic-dev-ai 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.

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({

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

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.

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>
Fix with cubic


const CATALOG_TIMEOUT_MS = 5_000;

const DEFAULT_ORCAROUTER_CONTEXT_WINDOW_TOKENS = 128_000;

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

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.

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>
Fix with cubic

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