Repository Public
1import "./_env";2import { env } from "../src/lib/env";3import { VIDEO_CAPS } from "../src/providers/capabilities";4import { IMAGE_USD, ticksToUsd } from "../src/providers/pricing";56/**7 * Capability discovery without any paid call: lists the models this key can use and compares them with the8 * matrix and price table compiled into the app. Run after any provider announcement, then update9 * docs/provider-capabilities.md, src/providers/capabilities.ts and src/providers/pricing.ts together.10 */11async function get<T>(path: string): Promise<T> {12 const r = await fetch(`https://api.x.ai/v1${path}`, { headers: { Authorization: `Bearer ${env.xaiKey}` }, signal: AbortSignal.timeout(30_000) });13 if (!r.ok) throw new Error(`${path}: HTTP ${r.status}`);14 return (await r.json()) as T;15}1617async function main() {18 const video = await get<{ models: { id: string; input_modalities: string[] }[] }>("/video-generation-models");19 const image = await get<{ models: { id: string; image_price?: number; pricing?: { quality: string; resolution: string; price_per_image: number }[] }[] }>("/image-generation-models");20 const voices = await get<{ voices: { voice_id: string }[] }>("/tts/voices");21 const llm = await get<{ models: { id: string }[] }>("/language-models");22 let drift = 0;23 console.log(`retrieved ${new Date().toISOString()}`);2425 console.log("\nvideo models");26 for (const m of video.models) {27 const known = !!VIDEO_CAPS[m.id];28 if (!known) drift++;29 console.log(` ${m.id.padEnd(30)} inputs ${m.input_modalities.join(",").padEnd(18)} ${known ? "in capability matrix" : "NOT in capability matrix"}`);30 }31 for (const id of Object.keys(VIDEO_CAPS)) {32 if (!video.models.some((m) => m.id === id)) { drift++; console.log(` ${id.padEnd(30)} in the matrix but NO LONGER LISTED by the provider`); }33 }3435 console.log("\nimage models");36 for (const m of image.models) {37 const live = m.pricing?.find((p) => p.quality === "low" && p.resolution === "1k")?.price_per_image ?? m.image_price;38 const table = IMAGE_USD[m.id]?.["low:1k"] ?? IMAGE_USD[m.id]?.["*"];39 const liveUsd = live === undefined ? null : ticksToUsd(live);40 const same = liveUsd !== null && table !== undefined && Math.abs(liveUsd - table) < 1e-9;41 if (!same) drift++;42 console.log(` ${m.id.padEnd(30)} live $${liveUsd ?? "?"} / image, table $${table ?? "?"} ${same ? "match" : "PRICE DRIFT"}`);43 }4445 console.log(`\nLLM models: ${llm.models.map((m) => m.id).join(", ")}`);46 const all = [...llm.models, ...image.models, ...video.models];47 for (const [role, id] of [["LLM", env.llmModel], ["image", env.imageModel], ["video", env.videoModel], ["video draft", env.videoDraftModel]] as const) {48 const listed = all.some((m) => m.id === id);49 if (!listed) drift++;50 console.log(` configured ${role.padEnd(12)} ${id.padEnd(30)} ${listed ? "available" : "NOT AVAILABLE to this key"}`);51 }52 console.log(`\nTTS voices: ${voices.voices.length} (${voices.voices.slice(0, 8).map((v) => v.voice_id).join(", ")}, …)`);53 console.log(drift ? `\n${drift} difference(s): update the capability matrix and price table.` : "\nNo drift: the compiled matrix and prices match the live API.");54 process.exit(drift ? 2 : 0);55}56main().catch((e) => { console.error(e.message); process.exit(1); });57