mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
Replace the single 3300-line generate-models.ts with declarative provider definitions and ordered rule packs under scripts/model-generation/. Each provider is a defineProvider() call: an upstream source (usually the generic modelsDev() mapper), static models upstream lacks, and rules scoped to that provider. Cross-provider facts live in rule packs applied in a fixed order. Every rule() carries a why, matches models with plain data, and patches them with typed set/replace/apply semantics. Generated model data is unchanged: 1443 models across 41 providers compare equal against a snapshot of the same upstream responses, apart from a now stable key order. Committed models.generated.ts and provider shards are byte-identical. Also: - Bring packages/ai/scripts under tsgo and biome; the old generator had 20+ type errors that nothing checked. - Add --upstream-snapshot <dir> to record and replay upstream catalogs and --explain <provider>:<model> to list the rules applied to a model. - Report rules that matched no model so stale corrections get removed. - Export parseRadiusGatewayConfig so the generator can replay Radius too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ExCU9zaZnN8vB5fKpTAjP
97 lines
3.4 KiB
TypeScript
97 lines
3.4 KiB
TypeScript
import type { Model } from "../../../src/types.ts";
|
|
import { defineProvider, rule } from "../dsl.ts";
|
|
import { modelsDev } from "../models-dev.ts";
|
|
import {
|
|
OPENAI_BASE_URL,
|
|
OPENAI_GPT_6_ASTRA_COST,
|
|
OPENAI_GPT_56_SOL_COST,
|
|
OPENAI_GPT_56_STANDARD_COSTS,
|
|
OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
|
|
OPENAI_LONG_CONTEXT_PRICING_MODEL_IDS,
|
|
withOpenAiLongContextPricing,
|
|
} from "../shared.ts";
|
|
|
|
// models.dev lists this alias, but it is not accepted by OpenAI APIs.
|
|
const MODELS_DEV_OPENAI_UNSUPPORTED_MODEL_IDS = new Set(["gpt-5.6"]);
|
|
|
|
// Keep direct OpenAI requests in the short-context pricing tier by default. Users can opt into the
|
|
// larger context through model overrides, so retain long-context cost metadata on the capped models.
|
|
const OPENAI_SHORT_CONTEXT_CAPPED_MODEL_IDS = [
|
|
"gpt-5.4",
|
|
"gpt-5.5",
|
|
"gpt-5.6-sol",
|
|
"gpt-5.6-terra",
|
|
"gpt-5.6-luna",
|
|
"gpt-6-astra",
|
|
];
|
|
|
|
function openAiResponsesModel(
|
|
id: string,
|
|
name: string,
|
|
model: Pick<Model<"openai-responses">, "reasoning" | "input" | "cost" | "contextWindow" | "maxTokens">,
|
|
): Model<"openai-responses"> {
|
|
return { id, name, api: "openai-responses", provider: "openai", baseUrl: OPENAI_BASE_URL, ...model };
|
|
}
|
|
|
|
const shortContextFrontier: Pick<Model<"openai-responses">, "reasoning" | "input" | "contextWindow" | "maxTokens"> = {
|
|
reasoning: true,
|
|
input: ["text", "image"],
|
|
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
|
|
maxTokens: 128000,
|
|
};
|
|
|
|
export const openai = defineProvider({
|
|
id: "openai",
|
|
source: modelsDev({
|
|
provider: "openai",
|
|
key: "openai",
|
|
api: "openai-responses",
|
|
baseUrl: OPENAI_BASE_URL,
|
|
include: (id) => !MODELS_DEV_OPENAI_UNSUPPORTED_MODEL_IDS.has(id),
|
|
}),
|
|
// Models missing from models.dev.
|
|
models: [
|
|
openAiResponsesModel("gpt-6-astra", "GPT-6 Astra", {
|
|
...shortContextFrontier,
|
|
cost: withOpenAiLongContextPricing(OPENAI_GPT_6_ASTRA_COST),
|
|
}),
|
|
openAiResponsesModel("gpt-5.6-sol", "GPT-5.6 Sol", {
|
|
...shortContextFrontier,
|
|
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_SOL_COST),
|
|
}),
|
|
openAiResponsesModel("gpt-5.6-terra", "GPT-5.6 Terra", {
|
|
...shortContextFrontier,
|
|
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-terra"]),
|
|
}),
|
|
openAiResponsesModel("gpt-5.6-luna", "GPT-5.6 Luna", {
|
|
...shortContextFrontier,
|
|
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-luna"]),
|
|
}),
|
|
openAiResponsesModel("gpt-5-chat-latest", "GPT-5 Chat Latest", {
|
|
reasoning: false,
|
|
input: ["text", "image"],
|
|
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
|
contextWindow: 128000,
|
|
maxTokens: 16384,
|
|
}),
|
|
],
|
|
rules: [
|
|
rule({
|
|
why: "Keep direct OpenAI requests in the short-context pricing tier by default; users opt into the larger context via model overrides.",
|
|
match: { id: OPENAI_SHORT_CONTEXT_CAPPED_MODEL_IDS },
|
|
set: { contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD, maxTokens: 128000 },
|
|
}),
|
|
rule({
|
|
why: "Long-context requests are billed at higher rates; models.dev only carries the short-context price. GPT-5.6 Terra/Luna use the 2026-07-30 price cut.",
|
|
match: { id: OPENAI_LONG_CONTEXT_PRICING_MODEL_IDS },
|
|
apply: (model) => {
|
|
model.cost = withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS[model.id] ?? model.cost);
|
|
},
|
|
}),
|
|
rule({
|
|
why: "models.dev reports gpt-5-pro output as 272000 (a duplicate of the input sub-limit); the actual max output is 128000.",
|
|
match: { id: "gpt-5-pro" },
|
|
set: { maxTokens: 128000 },
|
|
}),
|
|
],
|
|
});
|