mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(ai): expose Jev on Vercel AI Gateway and OpenCode Zen
Vercel evaluation models are generated from the AI Gateway catalog and routed through its TypeSafe-compatible /typesafe/v1/systemone endpoint. OpenCode Zen's jev-1.13 and jev-1.13-free are routed through /zen/v1/systemone.
This commit is contained in:
parent
5257d0d5f3
commit
33e2033543
7 changed files with 123 additions and 16 deletions
|
|
@ -151,6 +151,7 @@ interface NvidiaNimModelListItem {
|
|||
interface AiGatewayModel {
|
||||
id: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
context_window?: number;
|
||||
max_tokens?: number;
|
||||
tags?: string[];
|
||||
|
|
@ -222,6 +223,9 @@ const TOGETHER_TOGGLE_REASONING_LEVEL_MAP = {
|
|||
|
||||
const AI_GATEWAY_MODELS_URL = "https://ai-gateway.vercel.sh/v1";
|
||||
const AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
|
||||
// TypeSafe-compatible System One endpoint for evaluation models.
|
||||
// https://vercel.com/docs/ai-gateway/sdks-and-apis/typesafe
|
||||
const AI_GATEWAY_TYPESAFE_BASE_URL = "https://ai-gateway.vercel.sh/typesafe/v1";
|
||||
const VERTEX_BASE_URL = "https://{location}-aiplatform.googleapis.com";
|
||||
const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
|
||||
const NVIDIA_HEADERS = {
|
||||
|
|
@ -1328,13 +1332,17 @@ async function fetchRadiusModels(): Promise<Model<"pi-messages">[]> {
|
|||
}
|
||||
}
|
||||
|
||||
async function fetchAiGatewayModels(): Promise<Model<any>[]> {
|
||||
async function fetchAiGatewayModels(): Promise<{
|
||||
chat: Model<any>[];
|
||||
classifiers: ClassifierModel<"typesafe-system-one">[];
|
||||
}> {
|
||||
try {
|
||||
console.log("Fetching models from Vercel AI Gateway API...");
|
||||
const response = await fetch(`${AI_GATEWAY_MODELS_URL}/models`);
|
||||
if (!response.ok) throw new Error(`Vercel AI Gateway API returned ${response.status}`);
|
||||
const data = await response.json();
|
||||
const models: Model<any>[] = [];
|
||||
const classifiers: ClassifierModel<"typesafe-system-one">[] = [];
|
||||
|
||||
const toNumber = (value: string | number | undefined): number => {
|
||||
if (typeof value === "number") {
|
||||
|
|
@ -1346,6 +1354,27 @@ async function fetchAiGatewayModels(): Promise<Model<any>[]> {
|
|||
|
||||
const items = Array.isArray(data.data) ? (data.data as AiGatewayModel[]) : [];
|
||||
for (const model of items) {
|
||||
// Evaluation models such as TypeSafe's Jev are served through the
|
||||
// TypeSafe-compatible System One endpoint.
|
||||
if (model.type === "evaluation") {
|
||||
classifiers.push({
|
||||
type: "classifier",
|
||||
id: model.id,
|
||||
name: model.name || model.id,
|
||||
api: "typesafe-system-one",
|
||||
provider: "vercel-ai-gateway",
|
||||
baseUrl: AI_GATEWAY_TYPESAFE_BASE_URL,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
input: roundCost(toNumber(model.pricing?.input) * 1_000_000),
|
||||
output: roundCost(toNumber(model.pricing?.output) * 1_000_000),
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
contextWindow: model.context_window || 4096,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const tags = Array.isArray(model.tags) ? model.tags : [];
|
||||
// Only include models that support tools
|
||||
if (!tags.includes("tool-use")) continue;
|
||||
|
|
@ -1380,12 +1409,14 @@ async function fetchAiGatewayModels(): Promise<Model<any>[]> {
|
|||
});
|
||||
}
|
||||
|
||||
console.log(`Fetched ${models.length} tool-capable models from Vercel AI Gateway`);
|
||||
return models;
|
||||
console.log(
|
||||
`Fetched ${models.length} tool-capable and ${classifiers.length} classifier models from Vercel AI Gateway`,
|
||||
);
|
||||
return { chat: models, classifiers };
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch Vercel AI Gateway models:", error);
|
||||
if (generatorOptions.strict) throw error;
|
||||
return [];
|
||||
return { chat: [], classifiers: [] };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2665,6 +2696,34 @@ async function loadModelsDevClassifierModels(): Promise<ClassifierModel<"typesaf
|
|||
// Workers AI has no unauthenticated catalog and models.dev does not list its
|
||||
// System One models yet. Cloudflare publishes pricing only in the dashboard.
|
||||
// https://developers.cloudflare.com/ai/models/typesafe/jev/
|
||||
// OpenCode Zen serves Jev through its TypeSafe-compatible System One endpoint.
|
||||
// Neither its /zen/v1/models listing nor models.dev carries metadata for it.
|
||||
// https://opencode.ai/docs/zen
|
||||
const OPENCODE_CLASSIFIER_MODELS: ClassifierModel<"typesafe-system-one">[] = [
|
||||
{
|
||||
type: "classifier",
|
||||
id: "jev-1.13",
|
||||
name: "Jev 1.13",
|
||||
api: "typesafe-system-one",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
input: ["text"],
|
||||
cost: { input: 0.042, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 32000,
|
||||
},
|
||||
{
|
||||
type: "classifier",
|
||||
id: "jev-1.13-free",
|
||||
name: "Jev 1.13 Free",
|
||||
api: "typesafe-system-one",
|
||||
provider: "opencode",
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 32000,
|
||||
},
|
||||
];
|
||||
|
||||
const CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS: ClassifierModel<"cloudflare-workers-ai-system-one">[] = [
|
||||
{
|
||||
type: "classifier",
|
||||
|
|
@ -2688,11 +2747,11 @@ async function generateModels() {
|
|||
const modelsDevModels = await loadModelsDevData();
|
||||
const modelsDevClassifierModels = await loadModelsDevClassifierModels();
|
||||
const openRouterCatalog = await fetchOpenRouterModels();
|
||||
const aiGatewayModels = await fetchAiGatewayModels();
|
||||
const aiGatewayCatalog = await fetchAiGatewayModels();
|
||||
const radiusModels = await fetchRadiusModels();
|
||||
|
||||
// Combine chat models (models.dev has priority where sources overlap).
|
||||
const allModels = [...modelsDevModels, ...openRouterCatalog.chat, ...aiGatewayModels, ...radiusModels].filter(
|
||||
const allModels = [...modelsDevModels, ...openRouterCatalog.chat, ...aiGatewayCatalog.chat, ...radiusModels].filter(
|
||||
(model) =>
|
||||
!(model.provider === "xai" && XAI_BUILTIN_EXCLUDED_MODEL_IDS.has(model.id)) &&
|
||||
!((model.provider === "opencode" || model.provider === "opencode-go") && model.id === "gpt-5.3-codex-spark"),
|
||||
|
|
@ -3357,6 +3416,8 @@ async function generateModels() {
|
|||
const classifierModels: ClassifierModel<ClassifierApi>[] = [
|
||||
...modelsDevClassifierModels,
|
||||
...openRouterCatalog.classifiers,
|
||||
...aiGatewayCatalog.classifiers,
|
||||
...OPENCODE_CLASSIFIER_MODELS,
|
||||
...CLOUDFLARE_WORKERS_AI_CLASSIFIER_MODELS,
|
||||
];
|
||||
for (const model of classifierModels) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue