chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:28:55 +08:00
commit db42b91b75
6397 changed files with 146012 additions and 0 deletions
@@ -0,0 +1,402 @@
#!/usr/bin/env bun
import path from "node:path";
import { cp, mkdir, rm, writeFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import { tmpdir } from "node:os";
import { mergeDeep } from "remeda";
import { z } from "zod";
import { generate } from "../src/generate.js";
import { AuthoredModel, AuthoredModelShape, Model, Provider } from "../src/schema.js";
const root = path.join(import.meta.dirname, "..", "..", "..");
const providersPath = path.join(root, "providers");
const modelsPath = path.join(root, "models");
const LegacyExtendsModel = AuthoredModelShape
.partial()
.extend({
extends: z
.object({
from: z.string(),
omit: z.array(z.string()).optional(),
})
.strict(),
})
.strict();
const diffOutput = await Bun.$`git diff --name-only HEAD -- providers`.cwd(root).text();
const changedProviderPaths = diffOutput
.split("\n")
.filter(Boolean)
.filter((filePath) => /^providers\/[^/]+\/models\/.+\.toml$/.test(filePath));
if (changedProviderPaths.length === 0) {
process.exit(0);
}
const baselineRoot = path.join(tmpdir(), `models-dev-compare-${Date.now()}`);
await mkdir(baselineRoot, { recursive: true });
try {
const baselineProvidersPath = path.join(baselineRoot, "providers");
await cp(providersPath, baselineProvidersPath, { recursive: true });
const baselineModelsPath = path.join(baselineRoot, "models");
await cp(modelsPath, baselineModelsPath, { recursive: true });
await installModelNamespaceAliases(baselineModelsPath);
for (const filePath of changedProviderPaths) {
const tempFilePath = path.join(baselineRoot, filePath);
const show = Bun.spawn(["git", "show", `HEAD:${filePath}`], {
cwd: root,
stdout: "pipe",
stderr: "pipe",
});
const exitCode = await show.exited;
if (exitCode !== 0) {
await rm(tempFilePath, { force: true });
continue;
}
const contents = await new Response(show.stdout).text();
await mkdir(path.dirname(tempFilePath), { recursive: true });
await writeFile(tempFilePath, contents);
}
const before = await generateForComparison(baselineProvidersPath);
const after = await generate(providersPath);
for (const filePath of changedProviderPaths) {
const match = /^providers\/([^/]+)\/models\/(.+)\.toml$/.exec(filePath);
if (!match) continue;
const [, providerID, modelID] = match;
if (providerID === undefined || modelID === undefined) continue;
const beforeModel = before[providerID]?.models[modelID];
const afterModel = after[providerID]?.models[modelID];
const beforeJson = sortedJson(beforeModel);
const afterJson = sortedJson(afterModel);
if (beforeJson === afterJson) {
continue;
}
const beforeFilePath = path.join(baselineRoot, "before.json");
const afterFilePath = path.join(baselineRoot, "after.json");
await writeFile(beforeFilePath, `${beforeJson}\n`);
await writeFile(afterFilePath, `${afterJson}\n`);
const diff = Bun.spawn(
[
"diff",
"-u",
"-L",
`${filePath} (before)`,
"-L",
`${filePath} (after)`,
beforeFilePath,
afterFilePath,
],
{
stdout: "pipe",
stderr: "pipe",
},
);
const output = await new Response(diff.stdout).text();
process.stdout.write(output);
}
} finally {
await rm(baselineRoot, { recursive: true, force: true });
}
async function installModelNamespaceAliases(directory: string) {
await copyModelAlias(
directory,
"deepseek/deepseek-r1",
"amazon-bedrock/deepseek.r1-v1:0",
);
await copyModelAlias(
directory,
"meta/llama-4-maverick-17b-instruct",
"amazon-bedrock/meta.llama4-maverick-17b-instruct-v1:0",
);
await copyModelAlias(
directory,
"meta/llama-4-scout-17b-instruct",
"amazon-bedrock/meta.llama4-scout-17b-instruct-v1:0",
);
await copyModelAlias(
directory,
"meta/llama-3.3-70b-instruct",
"llama/llama-3.3-70b-instruct",
);
await copyModelAliasWithReplacements(
directory,
"openai/gpt-5.5-pro",
"opencode/gpt-5.5-pro",
[
[/release_date = "2026-04-23"/, 'release_date = "2026-04-24"'],
[/last_updated = "2026-04-23"/, 'last_updated = "2026-04-24"'],
[/structured_output = true/, "structured_output = false"],
],
);
await copyModelAlias(
directory,
"tencent/hy3-preview",
"tencent-tokenhub/hy3-preview",
);
}
async function copyModelAlias(directory: string, from: string, to: string) {
return copyModelAliasWithReplacements(directory, from, to, []);
}
async function copyModelAliasWithReplacements(
directory: string,
from: string,
to: string,
replacements: Array<[RegExp, string]>,
) {
const source = path.join(directory, `${from}.toml`);
const target = path.join(directory, `${to}.toml`);
if (!existsSync(source) || existsSync(target)) return;
await mkdir(path.dirname(target), { recursive: true });
if (replacements.length === 0) {
await cp(source, target);
return;
}
let text = await Bun.file(source).text();
for (const [pattern, replacement] of replacements) {
text = text.replace(pattern, replacement);
}
await writeFile(target, text);
}
async function generateForComparison(directory: string) {
for await (const file of new Bun.Glob("**/*.toml").scan({ cwd: directory })) {
const text = await Bun.file(path.join(directory, file)).text();
if (/^\[extends\]/m.test(text)) {
return generateLegacyExtends(directory);
}
}
return generate(directory);
}
async function generateLegacyExtends(directory: string) {
const result: Record<string, Provider> = {};
const pendingModels: Array<{
providerID: string;
modelID: string;
modelPath: string;
model: z.infer<typeof LegacyExtendsModel>;
}> = [];
for await (const providerPath of new Bun.Glob("*/provider.toml").scan({
cwd: directory,
absolute: true,
})) {
const providerID = path.basename(path.dirname(providerPath));
const toml = await import(providerPath, { with: { type: "toml" } }).then(
(mod) => mod.default,
);
toml.id = providerID;
toml.models = {};
const provider = Provider.safeParse(toml);
if (!provider.success) {
provider.error.cause = { providerPath, toml };
throw provider.error;
}
const modelsPath = path.join(directory, providerID, "models");
for await (const modelPath of new Bun.Glob("**/*.toml").scan({
cwd: modelsPath,
absolute: true,
followSymlinks: true,
})) {
const modelID = path.relative(modelsPath, modelPath).slice(0, -5);
const toml = await import(modelPath, { with: { type: "toml" } }).then(
(mod) => mod.default,
);
toml.id = modelID;
if (toml.extends !== undefined) {
const model = LegacyExtendsModel.safeParse(toml);
if (!model.success) {
model.error.cause = { modelPath, toml };
throw model.error;
}
pendingModels.push({
providerID,
modelID,
modelPath,
model: model.data,
});
continue;
}
const model = AuthoredModel.safeParse(toml);
if (!model.success) {
model.error.cause = { modelPath, toml };
throw model.error;
}
provider.data.models[modelID] = normalizeModelCost(model.data);
}
result[providerID] = provider.data;
}
const nameToProviderID = new Map<string, string>();
for (const provider of Object.values(result)) {
const nameKey = provider.name.toLowerCase();
const existingID = nameToProviderID.get(nameKey);
if (existingID !== undefined) {
throw new Error(
`Duplicate provider name "${provider.name}" used by both "${existingID}" and "${provider.id}". Provider names must be unique.`,
);
}
nameToProviderID.set(nameKey, provider.id);
}
for (const pendingModel of pendingModels) {
const [providerID, ...modelParts] = pendingModel.model.extends.from.split("/");
const modelID = modelParts.join("/");
if (providerID === undefined) {
throw new Error(`Invalid legacy extends.from: ${pendingModel.model.extends.from}`);
}
const baseModel = result[providerID]?.models[modelID];
if (baseModel === undefined) {
throw new Error(`Unable to resolve legacy extends.from: ${pendingModel.model.extends.from}`, {
cause: { modelPath: pendingModel.modelPath, toml: pendingModel.model },
});
}
const { extends: extendsConfig, ...overrides } = pendingModel.model;
const { reasoning_options: _reasoningOptions, ...inherited } = baseModel;
const merged: Record<string, unknown> = structuredClone(
mergeDeep(inherited, overrides),
);
applyOmit(merged, extendsConfig.omit ?? []);
const model = Model.safeParse(normalizeCost(merged));
if (!model.success) {
model.error.cause = { modelPath: pendingModel.modelPath, toml: merged };
throw model.error;
}
result[pendingModel.providerID]!.models[pendingModel.modelID] = model.data;
}
return result;
}
function normalizeModelCost(model: z.infer<typeof AuthoredModel>): Model {
return normalizeCost(model) as Model;
}
function normalizeCost(model: Record<string, unknown>) {
const cost = model.cost;
if (cost === undefined || cost === null || typeof cost !== "object" || Array.isArray(cost)) {
return model;
}
const tiers = (cost as { tiers?: unknown }).tiers;
if (!Array.isArray(tiers) || tiers.length !== 1) {
return model;
}
const contextOver200k = tiers.find((tier) => {
if (tier === null || typeof tier !== "object" || Array.isArray(tier)) return false;
const tierConfig = (tier as { tier?: unknown }).tier;
if (tierConfig === null || typeof tierConfig !== "object" || Array.isArray(tierConfig)) return false;
const type = (tierConfig as { type?: unknown }).type;
const size = (tierConfig as { size?: unknown }).size;
return (
(type === undefined || type === "context") &&
typeof size === "number" &&
size >= 200_000
);
});
if (contextOver200k === undefined) {
return model;
}
const { tier: _tier, ...legacyCost } = contextOver200k as Record<string, unknown>;
return {
...model,
cost: {
...(cost as Record<string, unknown>),
context_over_200k: legacyCost,
},
};
}
function applyOmit(target: Record<string, unknown>, paths: string[]) {
omitLoop: for (const omit of paths) {
const parts = omit.split(".");
const parents: Array<{
value: Record<string, unknown>;
key: string;
}> = [];
let current = target;
for (const part of parts.slice(0, -1)) {
const next = current[part];
if (
next === undefined ||
next === null ||
typeof next !== "object" ||
Array.isArray(next)
) {
continue omitLoop;
}
parents.push({ value: current, key: part });
current = next as Record<string, unknown>;
}
const lastPart = parts.at(-1);
if (lastPart === undefined || !(lastPart in current)) {
continue;
}
delete current[lastPart];
for (let index = parents.length - 1; index >= 0; index--) {
const parent = parents[index];
if (parent === undefined) continue;
const value = parent.value[parent.key];
if (
value === null ||
value === undefined ||
typeof value !== "object" ||
Array.isArray(value) ||
Object.keys(value).length > 0
) {
break;
}
delete parent.value[parent.key];
}
}
}
function sortedJson(value: unknown) {
return JSON.stringify(sortJson(value), null, 2);
}
function sortJson(value: unknown): unknown {
if (Array.isArray(value)) {
return value.map(sortJson);
}
if (value !== null && typeof value === "object") {
return Object.fromEntries(
Object.entries(value)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, item]) => [key, sortJson(item)]),
);
}
return value;
}
+291
View File
@@ -0,0 +1,291 @@
#!/usr/bin/env bun
/**
* Generates Databricks model TOML files from the Foundation Model API endpoint.
*
* Each Databricks endpoint exposes a model from another provider (Anthropic,
* OpenAI, Google, etc.), so the generated TOML uses base_model to inherit
* provider-agnostic metadata from models.dev.
*
* Usage:
* DATABRICKS_HOST=<host> DATABRICKS_TOKEN=<pat> bun run databricks:generate
* bun run databricks:generate --workspace <host> --token <pat>
*
* Flags:
* --dry-run: Preview changes without writing files
* --new-only: Only create new models, skip updating existing ones
*/
import { z } from "zod";
import path from "node:path";
import { mkdir, readFile } from "node:fs/promises";
import { existsSync } from "node:fs";
const args = process.argv.slice(2);
const flag = (name: string) => {
const i = args.indexOf(`--${name}`);
return i !== -1 ? args[i + 1] : undefined;
};
const dryRun = args.includes("--dry-run");
const newOnly = args.includes("--new-only");
const host = flag("workspace") ?? process.env.DATABRICKS_HOST;
const token = flag("token") ?? process.env.DATABRICKS_TOKEN;
if (!host || !token) {
console.error(
"Usage: DATABRICKS_HOST=<host> DATABRICKS_TOKEN=<pat> bun run databricks:generate",
);
process.exit(1);
}
const workspace = host.replace(/^https?:\/\//, "").replace(/\/$/, "");
const PROVIDERS_DIR = path.join(import.meta.dirname, "..", "..", "..", "providers");
const MODEL_METADATA_DIR = path.join(import.meta.dirname, "..", "..", "..", "models");
const MODELS_DIR = path.join(PROVIDERS_DIR, "databricks", "models");
// ---------------------------------------------------------------------------
// API schemas
// ---------------------------------------------------------------------------
const FoundationModel = z
.object({
ai_gateway_v2_supported: z.boolean().optional(),
api_types: z.array(z.string()).optional(),
})
.passthrough();
const ServedEntity = z
.object({
foundation_model: FoundationModel.optional(),
})
.passthrough();
const Endpoint = z
.object({
name: z.string(),
config: z
.object({
served_entities: z.array(ServedEntity).optional(),
})
.passthrough()
.optional(),
})
.passthrough();
const FoundationModelsResponse = z
.object({
endpoints: z.array(Endpoint),
})
.passthrough();
// ---------------------------------------------------------------------------
// Canonical resolution: map a Databricks endpoint name to a models.dev entry
// ---------------------------------------------------------------------------
const PREFIX_TO_PROVIDER: [string, string][] = [
["claude-", "anthropic"],
["gpt-", "openai"],
["gemini-", "google"],
["mistral-", "mistral"],
["mixtral-", "mistral"],
];
type Resolution =
| { type: "base_model"; from: string }
| { type: "inline"; content: string }
| null;
async function resolveCanonical(endpointName: string): Promise<Resolution> {
const bare = endpointName.replace(/^databricks-/, "");
// Models in provider subdirectories may not have provider-agnostic metadata
// yet, so inline when no model-only entry exists.
if (bare.startsWith("gpt-oss-")) {
const p = path.join(PROVIDERS_DIR, "openrouter", "models", "openai", `${bare}.toml`);
if (existsSync(p)) {
return { type: "inline", content: await readFile(p, "utf8") };
}
}
// Meta Llama: "meta-llama-3-3-70b-instruct" → "llama-3.3-70b-instruct"
if (bare.startsWith("meta-llama-") || bare.startsWith("llama-")) {
const llamaId = bare
.replace(/^meta-llama-/, "llama-")
.replace(/^(llama-\d+)-(\d+)-/, "$1.$2-");
const p = path.join(PROVIDERS_DIR, "llama", "models", `${llamaId}.toml`);
const metadata = path.join(MODEL_METADATA_DIR, "meta", `${llamaId}.toml`);
if (existsSync(p) && existsSync(metadata)) {
return { type: "base_model", from: `meta/${llamaId}` };
}
}
for (const [prefix, provider] of PREFIX_TO_PROVIDER) {
if (!bare.startsWith(prefix)) continue;
const exact = path.join(PROVIDERS_DIR, provider, "models", `${bare}.toml`);
if (existsSync(exact)) return { type: "base_model", from: `${provider}/${bare}` };
// Try with hyphens-as-dots in version (e.g. gpt-5-4 → gpt-5.4)
const dotted = bare.replace(/^((?:[a-z]+-)+\d+)-(\d)/, "$1.$2");
if (dotted !== bare) {
const dottedExact = path.join(PROVIDERS_DIR, provider, "models", `${dotted}.toml`);
if (existsSync(dottedExact)) return { type: "base_model", from: `${provider}/${dotted}` };
}
// Fuzzy: longest filename that shares a prefix with bare or its dotted form
const candidates = [bare, ...(dotted !== bare ? [dotted] : [])];
const files: string[] = [];
try {
for await (const f of new Bun.Glob("*.toml").scan({
cwd: path.join(PROVIDERS_DIR, provider, "models"),
})) {
files.push(f);
}
} catch {
// provider directory may not exist
}
const match = files
.map((f) => f.replace(/\.toml$/, ""))
.filter((id) => candidates.some((c) => id.startsWith(c) || c.startsWith(id)))
.sort((a, b) => b.length - a.length)[0];
if (match) return { type: "base_model", from: `${provider}/${match}` };
}
return null;
}
function formatToml(resolution: Resolution, endpointName: string): string {
if (resolution?.type === "base_model") {
return `base_model = "${resolution.from}"\n`;
}
if (resolution?.type === "inline") {
return resolution.content;
}
return `# TODO: fill in details for ${endpointName}\nname = "${endpointName}"\n`;
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
const IGNORE_PREFIXES = [
"databricks-llama-",
"databricks-meta-llama-",
"databricks-qwen",
"databricks-gemma-",
];
async function main() {
console.log(
`${dryRun ? "[DRY RUN] " : ""}${newOnly ? "[NEW ONLY] " : ""}Fetching Databricks foundation-models...`,
);
const url = `https://${workspace}/api/2.0/serving-endpoints:foundation-models`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
console.error(`Failed to fetch API: ${res.status} ${res.statusText}`);
console.error(await res.text().catch(() => ""));
process.exit(1);
}
const json = await res.json();
const parsed = FoundationModelsResponse.safeParse(json);
if (!parsed.success) {
console.error("Invalid API response:", parsed.error.errors);
process.exit(1);
}
const endpoints = parsed.data.endpoints.filter(
(e) =>
!IGNORE_PREFIXES.some((p) => e.name.startsWith(p)) &&
e.config?.served_entities?.some(
(se) =>
se.foundation_model?.ai_gateway_v2_supported === true &&
se.foundation_model?.api_types?.includes("mlflow/v1/chat/completions"),
),
);
const existingFiles = new Set<string>();
try {
for await (const f of new Bun.Glob("*.toml").scan({ cwd: MODELS_DIR })) {
existingFiles.add(f);
}
} catch {
// directory may not exist yet
}
console.log(
`Found ${endpoints.length} models in API, ${existingFiles.size} existing files\n`,
);
const apiModelIds = new Set<string>();
let created = 0;
let updated = 0;
let unchanged = 0;
for (const ep of endpoints) {
const filename = `${ep.name}.toml`;
apiModelIds.add(filename);
const filePath = path.join(MODELS_DIR, filename);
const resolution = await resolveCanonical(ep.name);
const newContent = formatToml(resolution, ep.name);
const tag = resolution?.type === "base_model" ? `base_model ${resolution.from}` : resolution?.type ?? "stub";
const existed = existsSync(filePath);
if (!existed) {
created++;
if (dryRun) {
console.log(`[DRY RUN] Would create: ${filename}${tag}`);
} else {
await mkdir(MODELS_DIR, { recursive: true });
await Bun.write(filePath, newContent);
console.log(`Created: ${filename}${tag}`);
}
continue;
}
if (newOnly) {
unchanged++;
continue;
}
const existingContent = await readFile(filePath, "utf8");
if (existingContent === newContent) {
unchanged++;
continue;
}
updated++;
if (dryRun) {
console.log(`[DRY RUN] Would update: ${filename}${tag}`);
} else {
await Bun.write(filePath, newContent);
console.log(`Updated: ${filename}${tag}`);
}
}
const orphaned: string[] = [];
for (const file of existingFiles) {
if (!apiModelIds.has(file)) {
orphaned.push(file);
console.log(`Warning: Orphaned file (not in API): ${file}`);
}
}
console.log("");
if (dryRun) {
console.log(
`Summary: ${created} would be created, ${updated} would be updated, ${unchanged} unchanged, ${orphaned.length} orphaned`,
);
} else {
console.log(
`Summary: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned.length} orphaned`,
);
}
}
await main();
+505
View File
@@ -0,0 +1,505 @@
#!/usr/bin/env bun
import { mkdir } from "node:fs/promises";
import path from "node:path";
import { z } from "zod";
import { inferKimiFamily } from "../src/family.js";
// Friendli API endpoint
const API_ENDPOINT = "https://api.friendli.ai/serverless/v1/models";
// Zod schemas for API response validation
const Functionality = z.object({
tool_call: z.boolean(),
parallel_tool_call: z.boolean(),
structured_output: z.boolean(),
});
const Pricing = z.object({
input: z.number(),
output: z.number(),
response_time: z.number(),
unit_type: z.enum(["TOKEN", "SECOND"]),
});
const FriendliModel = z
.object({
id: z.string(),
name: z.string(),
max_completion_tokens: z.number(),
context_length: z.number(),
functionality: Functionality,
pricing: Pricing,
hugging_face_url: z.string().optional(),
description: z.string().optional(),
license: z.string().optional(),
policy: z.string().optional().nullable(),
created: z.number(), // Unix timestamp
})
.passthrough();
const FriendliResponse = z.object({
data: z.array(FriendliModel),
});
// Family inference patterns
const familyPatterns: [RegExp, string][] = [
[/qwen3/i, "qwen3"],
[/deepseek-r1/i, "deepseek-r1"],
[/glm-4/i, "glm-4"],
[/glm-5/i, "glm"],
];
function inferFamily(modelId: string, modelName: string): string | undefined {
const kimiFamily = inferKimiFamily(modelId, modelName);
if (kimiFamily !== undefined) return kimiFamily;
for (const [pattern, family] of familyPatterns) {
if (pattern.test(modelId) || pattern.test(modelName)) {
return family;
}
}
return undefined;
}
function extractModelName(fullName: string): string {
// "meta-llama/Llama-3.3-70B-Instruct" -> "Llama 3.3 70B Instruct"
const parts = fullName.split("/");
const modelName = parts.at(-1) ?? fullName;
return modelName
.replace(/-/g, " ")
.replace(/\b\w/g, (l) => l.toUpperCase());
}
// TODO: Replace with functionality.parse_reasoning from API when available
function isReasoningModel(modelId: string): boolean {
const nonReasoningPatterns = [
/qwen3.*instruct/i,
];
for (const pattern of nonReasoningPatterns) {
if (pattern.test(modelId)) {
return false;
}
}
// Everything else is reasoning or hybrid reasoning
return true;
}
function formatNumber(n: number): string {
if (n >= 1000) {
// Format with underscores for readability (e.g., 131_072)
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "_");
}
return n.toString();
}
function timestampToDate(timestamp: number): string {
const date = new Date(timestamp * 1000);
return date.toISOString().slice(0, 10);
}
function getTodayDate(): string {
return new Date().toISOString().slice(0, 10);
}
interface ExistingModel {
name?: string;
family?: string;
attachment?: boolean;
reasoning?: boolean;
tool_call?: boolean;
structured_output?: boolean;
temperature?: boolean;
knowledge?: string;
release_date?: string;
last_updated?: string;
open_weights?: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input?: number;
output?: number;
reasoning?: number;
cache_read?: number;
cache_write?: number;
};
limit?: {
context?: number;
input?: number;
output?: number;
};
modalities?: {
input?: string[];
output?: string[];
};
provider?: {
npm?: string;
api?: string;
};
}
async function loadExistingModel(
filePath: string,
): Promise<ExistingModel | null> {
try {
const file = Bun.file(filePath);
if (!(await file.exists())) {
return null;
}
const toml = await import(filePath, { with: { type: "toml" } }).then(
(mod) => mod.default,
);
return toml as ExistingModel;
} catch (e) {
console.warn(`Warning: Failed to parse existing file ${filePath}:`, e);
return null;
}
}
interface MergedModel {
name: string;
family?: string;
attachment: boolean;
reasoning: boolean;
tool_call: boolean;
structured_output?: boolean;
temperature: boolean;
knowledge?: string;
release_date: string;
last_updated: string;
open_weights: boolean;
interleaved?: boolean | { field: string };
status?: string;
cost?: {
input: number;
output: number;
};
limit: {
context: number;
output: number;
};
modalities: {
input: string[];
output: string[];
};
}
function mergeModel(
apiModel: z.infer<typeof FriendliModel>,
existing: ExistingModel | null,
): MergedModel {
const contextTokens = apiModel.context_length;
const outputTokens = apiModel.max_completion_tokens;
const openWeights = Boolean(apiModel.hugging_face_url);
const merged: MergedModel = {
// Always from API
name: extractModelName(apiModel.name),
attachment: false, // All Friendli models are text-only currently
reasoning: isReasoningModel(apiModel.id),
tool_call: apiModel.functionality.tool_call,
temperature: true,
release_date: timestampToDate(apiModel.created),
last_updated: getTodayDate(),
open_weights: openWeights,
limit: {
context: contextTokens,
output: outputTokens,
},
modalities: {
input: ["text"],
output: ["text"],
},
};
// structured_output only if true
if (apiModel.functionality.structured_output === true) {
merged.structured_output = true;
}
// Cost from API - ONLY include if unit_type is TOKEN
if (apiModel.pricing.unit_type === "TOKEN") {
merged.cost = {
input: apiModel.pricing.input,
output: apiModel.pricing.output,
};
} else {
console.log(
` Note: ${apiModel.id} uses ${apiModel.pricing.unit_type} pricing - cost section omitted`,
);
}
// Preserve from existing OR infer
if (existing?.family) {
merged.family = existing.family;
} else {
const inferred = inferFamily(apiModel.id, apiModel.name);
if (inferred) {
merged.family = inferred;
}
}
// Preserve manual fields from existing
if (existing?.knowledge) {
merged.knowledge = existing.knowledge;
}
if (existing?.interleaved !== undefined) {
merged.interleaved = existing.interleaved;
}
if (existing?.status !== undefined) {
merged.status = existing.status;
}
return merged;
}
function formatToml(model: MergedModel): string {
const lines: string[] = [];
// Basic fields
lines.push(`name = "${model.name.replace(/"/g, '\\"')}"`);
if (model.family) {
lines.push(`family = "${model.family}"`);
}
lines.push(`attachment = ${model.attachment}`);
lines.push(`reasoning = ${model.reasoning}`);
lines.push(`tool_call = ${model.tool_call}`);
if (model.structured_output !== undefined) {
lines.push(`structured_output = ${model.structured_output}`);
}
lines.push(`temperature = ${model.temperature}`);
if (model.knowledge) {
lines.push(`knowledge = "${model.knowledge}"`);
}
lines.push(`release_date = "${model.release_date}"`);
lines.push(`last_updated = "${model.last_updated}"`);
lines.push(`open_weights = ${model.open_weights}`);
if (model.status) {
lines.push(`status = "${model.status}"`);
}
// Interleaved section (if present)
if (model.interleaved !== undefined) {
lines.push("");
if (model.interleaved === true) {
lines.push(`interleaved = true`);
} else if (typeof model.interleaved === "object") {
lines.push(`[interleaved]`);
lines.push(`field = "${model.interleaved.field}"`);
}
}
// Cost section (only if present)
if (model.cost) {
lines.push("");
lines.push(`[cost]`);
lines.push(`input = ${model.cost.input}`);
lines.push(`output = ${model.cost.output}`);
}
// Limit section
lines.push("");
lines.push(`[limit]`);
lines.push(`context = ${formatNumber(model.limit.context)}`);
lines.push(`output = ${formatNumber(model.limit.output)}`);
// Modalities section
lines.push("");
lines.push(`[modalities]`);
lines.push(
`input = [${model.modalities.input.map((m) => `"${m}"`).join(", ")}]`,
);
lines.push(
`output = [${model.modalities.output.map((m) => `"${m}"`).join(", ")}]`,
);
return lines.join("\n") + "\n";
}
interface Changes {
field: string;
oldValue: string;
newValue: string;
}
function detectChanges(
existing: ExistingModel | null,
merged: MergedModel,
): Changes[] {
if (!existing) return [];
const changes: Changes[] = [];
const compare = (field: string, oldVal: unknown, newVal: unknown) => {
const oldStr = JSON.stringify(oldVal);
const newStr = JSON.stringify(newVal);
if (oldStr !== newStr) {
changes.push({
field,
oldValue: formatValue(oldVal),
newValue: formatValue(newVal),
});
}
};
const formatValue = (val: unknown): string => {
if (typeof val === "number") return formatNumber(val);
if (Array.isArray(val)) return `[${val.join(", ")}]`;
if (val === undefined) return "(none)";
return String(val);
};
compare("name", existing.name, merged.name);
compare("family", existing.family, merged.family);
compare("attachment", existing.attachment, merged.attachment);
compare("reasoning", existing.reasoning, merged.reasoning);
compare("tool_call", existing.tool_call, merged.tool_call);
compare(
"structured_output",
existing.structured_output,
merged.structured_output,
);
compare("open_weights", existing.open_weights, merged.open_weights);
compare("release_date", existing.release_date, merged.release_date);
compare("cost.input", existing.cost?.input, merged.cost?.input);
compare("cost.output", existing.cost?.output, merged.cost?.output);
compare("limit.context", existing.limit?.context, merged.limit.context);
compare("limit.output", existing.limit?.output, merged.limit.output);
compare("modalities.input", existing.modalities?.input, merged.modalities.input);
return changes;
}
async function main() {
const args = process.argv.slice(2);
const dryRun = args.includes("--dry-run");
const modelsDir = path.join(
import.meta.dirname,
"..",
"..",
"..",
"providers",
"friendli",
"models",
);
if (dryRun) {
console.log(`[DRY RUN] Fetching Friendli models from API...`);
} else {
console.log(`Fetching Friendli models from API...`);
}
// Fetch API data
const res = await fetch(API_ENDPOINT);
if (!res.ok) {
console.error(`Failed to fetch API: ${res.status} ${res.statusText}`);
process.exit(1);
}
const json = await res.json();
const parsed = FriendliResponse.safeParse(json);
if (!parsed.success) {
console.error("Invalid API response:", parsed.error.errors);
process.exit(1);
}
const apiModels = parsed.data.data;
// Get existing files (recursively)
const existingFiles = new Set<string>();
try {
for await (const file of new Bun.Glob("**/*.toml").scan({
cwd: modelsDir,
absolute: false,
})) {
existingFiles.add(file);
}
} catch {
// Directory might not exist yet
}
console.log(
`Found ${apiModels.length} models in API, ${existingFiles.size} existing files\n`,
);
// Track API model IDs for orphan detection
const apiModelIds = new Set<string>();
let created = 0;
let updated = 0;
let unchanged = 0;
for (const apiModel of apiModels) {
const relativePath = `${apiModel.id}.toml`;
const filePath = path.join(modelsDir, relativePath);
const dirPath = path.dirname(filePath);
apiModelIds.add(relativePath);
const existing = await loadExistingModel(filePath);
const merged = mergeModel(apiModel, existing);
const tomlContent = formatToml(merged);
if (existing === null) {
created++;
if (dryRun) {
console.log(`[DRY RUN] Would create: ${relativePath}`);
console.log(` name = "${merged.name}"`);
if (merged.family) {
console.log(` family = "${merged.family}" (inferred)`);
}
console.log("");
} else {
await mkdir(dirPath, { recursive: true });
await Bun.write(filePath, tomlContent);
console.log(`Created: ${relativePath}`);
}
} else {
const changes = detectChanges(existing, merged);
if (changes.length > 0) {
updated++;
if (dryRun) {
console.log(`[DRY RUN] Would update: ${relativePath}`);
} else {
await Bun.write(filePath, tomlContent);
console.log(`Updated: ${relativePath}`);
}
for (const change of changes) {
console.log(` ${change.field}: ${change.oldValue}${change.newValue}`);
}
console.log("");
} else {
unchanged++;
}
}
}
// Check for orphaned files
const orphaned: string[] = [];
for (const file of existingFiles) {
if (!apiModelIds.has(file)) {
orphaned.push(file);
console.log(`Warning: Orphaned file (not in API): ${file}`);
}
}
// Summary
console.log("");
if (dryRun) {
console.log(
`Summary: ${created} would be created, ${updated} would be updated, ${unchanged} unchanged, ${orphaned.length} orphaned`,
);
} else {
console.log(
`Summary: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned.length} orphaned`,
);
}
}
await main();
+235
View File
@@ -0,0 +1,235 @@
#!/usr/bin/env bun
import { z } from "zod";
import path from "node:path";
import { mkdir, rm, readdir, stat } from "node:fs/promises";
// Helicone public model registry endpoint
const DEFAULT_ENDPOINT =
"https://jawn.helicone.ai/v1/public/model-registry/models";
// Zod schemas to validate the Helicone response
const Pricing = z
.object({
prompt: z.number().optional(),
completion: z.number().optional(),
cacheRead: z.number().optional(),
cacheWrite: z.number().optional(),
reasoning: z.number().optional(),
})
.passthrough();
const Endpoint = z
.object({
provider: z.string(),
providerSlug: z.string().optional(),
supportsPtb: z.boolean().optional(),
pricing: Pricing.optional(),
})
.passthrough();
const ModelItem = z
.object({
id: z.string(),
name: z.string(),
author: z.string().optional(),
contextLength: z.number().optional(),
maxOutput: z.number().optional(),
trainingDate: z.string().optional(),
description: z.string().optional(),
inputModalities: z.array(z.string()).optional(),
outputModalities: z.array(z.string()).optional(),
supportedParameters: z.array(z.string()).optional(),
endpoints: z.array(Endpoint).optional(),
})
.passthrough();
const HeliconeResponse = z
.object({
data: z.object({
models: z.array(ModelItem),
total: z.number().optional(),
filters: z.any().optional(),
}),
})
.passthrough();
interface ExistingModel {
base_model?: string;
base_model_omit?: string[];
}
async function loadExistingModel(filePath: string): Promise<ExistingModel | undefined> {
const file = Bun.file(filePath);
if (!(await file.exists())) return undefined;
return await import(filePath, { with: { type: "toml" } }).then(
(mod) => mod.default as ExistingModel,
);
}
function pickEndpoint(m: z.infer<typeof ModelItem>) {
if (!m.endpoints || m.endpoints.length === 0) return undefined;
// Prefer endpoint that matches author if available
if (m.author) {
const match = m.endpoints.find((e) => e.provider === m.author);
if (match) return match;
}
return m.endpoints[0];
}
function boolFromParams(params: string[] | undefined, keys: string[]): boolean {
if (!params) return false;
const set = new Set(params.map((p) => p.toLowerCase()));
return keys.some((k) => set.has(k.toLowerCase()));
}
function sanitizeModalities(values: string[] | undefined): string[] {
if (!values) return ["text"]; // default to text
const allowed = new Set(["text", "audio", "image", "video", "pdf"]);
const out = values.map((v) => v.toLowerCase()).filter((v) => allowed.has(v));
return out.length > 0 ? out : ["text"];
}
function formatToml(model: z.infer<typeof ModelItem>, existing: ExistingModel | undefined) {
const ep = pickEndpoint(model);
const pricing = ep?.pricing;
const supported = model.supportedParameters ?? [];
const nowISO = new Date().toISOString().slice(0, 10);
const rdRaw = model.trainingDate ? String(model.trainingDate) : nowISO;
const releaseDate = rdRaw.slice(0, 10);
const lastUpdated = releaseDate;
const knowledge = model.trainingDate
? String(model.trainingDate).slice(0, 7)
: undefined;
const attachment = false; // Not exposed by Helicone registry
const temperature = boolFromParams(supported, ["temperature"]);
const toolCall = boolFromParams(supported, ["tools", "tool_choice"]);
const reasoning = boolFromParams(supported, [
"reasoning",
"include_reasoning",
]);
const inputMods = sanitizeModalities(model.inputModalities);
const outputMods = sanitizeModalities(model.outputModalities);
const lines: string[] = [];
if (existing?.base_model !== undefined) {
lines.push(`base_model = "${existing.base_model}"`);
}
if (existing?.base_model_omit !== undefined) {
lines.push(
`base_model_omit = [${existing.base_model_omit.map((item) => `"${item}"`).join(", ")}]`,
);
}
lines.push(`name = "${model.name.replaceAll('"', '\\"')}"`);
lines.push(`release_date = "${releaseDate}"`);
lines.push(`last_updated = "${lastUpdated}"`);
lines.push(`attachment = ${attachment}`);
lines.push(`reasoning = ${reasoning}`);
lines.push(`temperature = ${temperature}`);
lines.push(`tool_call = ${toolCall}`);
if (knowledge) lines.push(`knowledge = "${knowledge}"`);
lines.push(`open_weights = false`);
lines.push("");
if (
pricing &&
(pricing.prompt ??
pricing.completion ??
pricing.cacheRead ??
pricing.cacheWrite ??
(reasoning && pricing.reasoning)) !== undefined
) {
lines.push(`[cost]`);
if (pricing.prompt !== undefined) lines.push(`input = ${pricing.prompt}`);
if (pricing.completion !== undefined)
lines.push(`output = ${pricing.completion}`);
if (reasoning && pricing.reasoning !== undefined)
lines.push(`reasoning = ${pricing.reasoning}`);
if (pricing.cacheRead !== undefined)
lines.push(`cache_read = ${pricing.cacheRead}`);
if (pricing.cacheWrite !== undefined)
lines.push(`cache_write = ${pricing.cacheWrite}`);
lines.push("");
}
const context = model.contextLength ?? 0;
const output = model.maxOutput ?? 4096;
lines.push(`[limit]`);
lines.push(`context = ${context}`);
lines.push(`output = ${output}`);
lines.push("");
lines.push(`[modalities]`);
lines.push(`input = [${inputMods.map((m) => `"${m}"`).join(", ")}]`);
lines.push(`output = [${outputMods.map((m) => `"${m}"`).join(", ")}]`);
return lines.join("\n") + "\n";
}
async function main() {
const endpoint = DEFAULT_ENDPOINT;
const outDir = path.join(
import.meta.dirname,
"..",
"..",
"..",
"providers",
"helicone",
"models",
);
const res = await fetch(endpoint);
if (!res.ok) {
console.error(`Failed to fetch registry: ${res.status} ${res.statusText}`);
process.exit(1);
}
const json = await res.json();
const parsed = HeliconeResponse.safeParse(json);
if (!parsed.success) {
parsed.error.cause = json;
console.error("Invalid Helicone response:", parsed.error.errors);
console.error("When parsing:", parsed.error.cause);
process.exit(1);
}
const models = parsed.data.data.models;
const existing = new Map<string, ExistingModel>();
await mkdir(outDir, { recursive: true });
for await (const file of new Bun.Glob("**/*.toml").scan({ cwd: outDir })) {
const filePath = path.join(outDir, file);
const model = await loadExistingModel(filePath);
if (model !== undefined) existing.set(file, model);
}
// Clean output directory: remove subfolders and existing TOML files
for (const entry of await readdir(outDir)) {
const p = path.join(outDir, entry);
const st = await stat(p);
if (st.isDirectory()) {
await rm(p, { recursive: true, force: true });
} else if (st.isFile() && entry.endsWith(".toml")) {
await rm(p, { force: true });
}
}
let created = 0;
for (const m of models) {
const fileSafeId = m.id.replaceAll("/", "-");
const filePath = path.join(outDir, `${fileSafeId}.toml`);
const toml = formatToml(m, existing.get(`${fileSafeId}.toml`));
await Bun.write(filePath, toml);
created++;
}
console.log(
`Generated ${created} model file(s) under providers/helicone/models/*.toml`,
);
}
await main();
+239
View File
@@ -0,0 +1,239 @@
#!/usr/bin/env bun
/**
* Generates model files from the data in Ollama Cloud's API.
*
* Ollama Cloud does not provide some data fields, such as release date or
* knowledge cutoff. The `family` field provided by Ollama Cloud may not match
* the values in family.ts. We expect that when TOML validaton fails, the
* maintainer will manually source those data points (such as from other
* provider TOML files, or from the internet at large). This script preserves
* those fields when overwriting Ollama Cloud's TOML files.
*/
import { z } from "zod";
import path from "node:path";
import type { Model } from "../src/schema";
import type { ModelFamily } from "../src/family";
const modelsDir = path.join(
import.meta.dirname,
"..",
"..",
"..",
"providers",
"ollama-cloud",
"models"
);
function modelFileName(modelName: string): string {
return modelName + ".toml";
}
type OllamaModel = Omit<Model, "id" | "description" | "release_date" | "limit"> & {
description?: Model["description"];
release_date?: Model["release_date"];
limit: Omit<Model["limit"], "output"> & { output?: number };
};
type ComparableModel = Pick<Model,
| "name"
| "attachment"
| "reasoning"
| "tool_call"
| "knowledge"
| "open_weights"
| "modalities"
> & {
limit: Pick<Model["limit"], "context">;
};
function normalizeForComparison(model: OllamaModel | Omit<Model, "id">): ComparableModel {
return {
name: model.name,
attachment: model.attachment,
reasoning: model.reasoning,
tool_call: model.tool_call,
knowledge: model.knowledge,
open_weights: model.open_weights,
limit: { context: model.limit.context },
modalities: model.modalities,
};
}
const OllamaTagsResponse = z.object({
models: z.array(
z.object({
name: z.string(),
})
),
});
type OllamaTagsResponse = z.infer<typeof OllamaTagsResponse>;
const OllamaModelDetails = z.object({
modified_at: z.string(),
details: z.object({
parent_model: z.string(),
format: z.string(),
family: z.string(),
families: z.array(z.string()).nullable(),
parameter_size: z.string().transform(Number),
quantization_level: z.string(),
}),
model_info: z.record(z.union([z.string(), z.number()])),
capabilities: z.array(z.enum(["thinking", "completion", "tools", "vision"])),
});
type OllamaModelDetails = z.infer<typeof OllamaModelDetails>;
function generateToml(modelName: string, model: OllamaModel): string {
const lines: string[] = [];
lines.push(`name = "${modelName}"`);
lines.push(`family = "${model.family}"`);
lines.push(`attachment = ${model.attachment}`);
lines.push(`reasoning = ${model.reasoning}`);
lines.push(`tool_call = ${model.tool_call}`);
if (model.release_date) {
lines.push(`release_date = "${model.release_date}"`);
}
if (model.knowledge) {
lines.push(`knowledge = "${model.knowledge}"`);
}
lines.push(`last_updated = "${model.last_updated}"`);
lines.push(`open_weights = ${model.open_weights}`);
lines.push("");
lines.push("[limit]");
lines.push(`context = ${model.limit.context}`);
if (model.limit.output !== undefined) {
lines.push(`output = ${model.limit.output}`);
}
lines.push("");
lines.push("[modalities]");
lines.push(`input = ${JSON.stringify(model.modalities.input)}`);
lines.push(`output = ${JSON.stringify(model.modalities.output)}`);
return lines.join("\n") + "\n";
}
const tagsResponse = await fetch("https://ollama.com/api/tags");
if (!tagsResponse.ok) {
console.error(
`Failed to fetch tags: ${tagsResponse.status} ${tagsResponse.statusText}`
);
process.exit(1);
}
const tagsJson = await tagsResponse.json();
const tagsParsed = OllamaTagsResponse.safeParse(tagsJson);
if (!tagsParsed.success) {
console.error("Invalid tags response:", tagsParsed.error.errors);
process.exit(1);
}
const tagsData: OllamaTagsResponse = tagsParsed.data;
const modelNames = tagsData.models.map((m) => m.name);
console.log(`Fetching details for ${modelNames.length} models...`);
const modelsData: Array<{ name: string; data: OllamaModelDetails }> = [];
for (const modelName of modelNames) {
const showResponse = await fetch("https://ollama.com/api/show", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ model: modelName }),
});
if (!showResponse.ok) {
console.error(
`Failed to fetch details for ${modelName}: ${showResponse.status} ${showResponse.statusText}`
);
process.exit(1);
}
const showJson = await showResponse.json();
const showParsed = OllamaModelDetails.safeParse(showJson);
if (!showParsed.success) {
console.error(
`Invalid response for ${modelName}:`,
showParsed.error.errors
);
process.exit(1);
}
modelsData.push({ name: modelName, data: showParsed.data });
}
console.log(`Fetched all models. Syncing files...`);
const existingFiles = Array.from(new Bun.Glob("*.toml").scanSync(modelsDir));
const existingModelNames = new Set(existingFiles.map((f) => f.replace(/\.toml$/, "")));
const apiModelNames = new Set(modelNames);
let deleted = 0;
for (const existingName of existingModelNames) {
if (!apiModelNames.has(existingName)) {
const filePath = path.join(modelsDir, modelFileName(existingName));
await Bun.file(filePath).delete();
console.log(`Deleted: ${modelFileName(existingName)}`);
deleted++;
}
}
let created = 0;
let skipped = 0;
for (const { name, data } of modelsData) {
const fileName = modelFileName(name);
const filePath = path.join(modelsDir, fileName);
let existingData: Omit<Model, "id"> | null = null;
try {
const existingToml = await Bun.file(filePath).text();
existingData = Bun.TOML.parse(existingToml) as Omit<Model, "id">;
} catch {
// File doesn't exist
}
const family = existingData?.family ?? (data.details.family as ModelFamily);
const contextLength =
(data.model_info[`${data.details.family}.context_length`] as number) ?? 0;
const ollamaModel: OllamaModel = {
name,
family,
attachment: data.capabilities.includes("vision"),
reasoning: data.capabilities.includes("thinking"),
tool_call: data.capabilities.includes("tools"),
release_date: existingData?.release_date,
knowledge: existingData?.knowledge,
last_updated: new Date().toISOString().slice(0, 10),
open_weights: true,
modalities: {
input: data.capabilities.includes("vision")
? ["text", "image"]
: ["text"],
output: ["text"],
},
limit: {
context: contextLength,
output: existingData?.limit.output,
},
};
if (existingData) {
const normalizedExisting = normalizeForComparison(existingData);
const normalizedIncoming = normalizeForComparison(ollamaModel);
if (Bun.deepEquals(normalizedExisting, normalizedIncoming)) {
console.log(`Skipped (no changes): ${fileName}`);
skipped++;
continue;
}
}
await Bun.write(filePath, generateToml(name, ollamaModel));
console.log(`Created: ${fileName}`);
created++;
}
console.log(`\nDone. Created: ${created}, Skipped: ${skipped}, Deleted: ${deleted}`);
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bun
import { main } from "../src/sync/index.js";
await main(["wandb", ...process.argv.slice(2)]);
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bun
import { main } from "../src/sync/index.js";
await main();
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bun
import { generate } from "../src/generate";
import path from "path";
import { ZodError } from "zod";
try {
const result = await generate(
path.join(import.meta.dirname, "..", "..", "..", "providers"),
);
console.log(JSON.stringify(result, null, 2));
} catch (e: any) {
if (e instanceof ZodError) {
console.error("Validation error:", e.errors);
console.error("When parsing:", e.cause);
process.exit(1);
}
throw e;
}