cline--cline
158 行
4.6 KiB
TypeScript
158 行
4.6 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import type { ModelInfo } from "@cline/shared";
|
|
import {
|
|
fetchClineRecommendedModelsPayload,
|
|
normalizeClineRecommendedProviderModels,
|
|
} from "../src/catalog/catalog-cline-recommended";
|
|
import { loadModelsDevProviderModels } from "./models/generate-models-dev";
|
|
|
|
const OUTPUT_FILE = "src/catalog/catalog.generated.ts";
|
|
|
|
function sortObjectByKey<T>(
|
|
input: Record<string, T>,
|
|
order: "asc" | "desc" = "asc",
|
|
): Record<string, T> {
|
|
return Object.fromEntries(
|
|
Object.entries(input).sort(([a], [b]) =>
|
|
order === "asc" ? a.localeCompare(b) : b.localeCompare(a),
|
|
),
|
|
);
|
|
}
|
|
|
|
function normalizeValue(value: unknown): unknown {
|
|
if (Array.isArray(value)) {
|
|
return value.map(normalizeValue);
|
|
}
|
|
if (value && typeof value === "object") {
|
|
const objectValue = value as Record<string, unknown>;
|
|
return Object.fromEntries(
|
|
Object.entries(objectValue)
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
.map(([key, nestedValue]) => [key, normalizeValue(nestedValue)]),
|
|
);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
async function generate(): Promise<void> {
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const root = join(__dirname, "..");
|
|
const outputPath = join(root, OUTPUT_FILE);
|
|
|
|
const providerModels: Record<string, Record<string, ModelInfo>> = {};
|
|
let loadError: Error | undefined;
|
|
|
|
const [modelsDevResult, clineRecommendedPayloadResult] = await Promise.all([
|
|
loadModelsDevProviderModels().catch((error) => {
|
|
loadError =
|
|
error instanceof Error ? error : new Error(String(error ?? "unknown"));
|
|
return {};
|
|
}),
|
|
fetchClineRecommendedModelsPayload(fetch).catch((error) => {
|
|
loadError =
|
|
error instanceof Error ? error : new Error(String(error ?? "unknown"));
|
|
return undefined;
|
|
}),
|
|
]);
|
|
|
|
Object.assign(providerModels, modelsDevResult);
|
|
|
|
if (clineRecommendedPayloadResult) {
|
|
Object.assign(
|
|
providerModels,
|
|
normalizeClineRecommendedProviderModels(
|
|
clineRecommendedPayloadResult,
|
|
providerModels.openrouter || {},
|
|
),
|
|
);
|
|
}
|
|
|
|
if (Object.keys(providerModels).length === 0) {
|
|
const details = loadError?.message ?? "unknown error";
|
|
if (existsSync(outputPath)) {
|
|
console.warn(
|
|
`Skipping model generation: no provider models were loaded (${details}). Existing generated catalog was left unchanged.`,
|
|
);
|
|
return;
|
|
}
|
|
throw new Error(
|
|
`Aborting model generation: no provider models were loaded (${details}). No existing generated catalog was found.`,
|
|
);
|
|
}
|
|
|
|
const sortedProviders = sortObjectByKey(providerModels);
|
|
const generatedModelsVersion = Date.now();
|
|
const output = `/**
|
|
* Auto-generated model catalog.
|
|
*
|
|
* Generated by: @cline/llms/scripts/generate-models.ts
|
|
*
|
|
* WARNING: DO NOT EDIT THIS FILE MANUALLY.
|
|
*/
|
|
import type { ModelInfo } from "@cline/shared";
|
|
/**
|
|
* Model list auto-generated for built-in providers
|
|
* listed in @cline/llms/src/providers/provider-keys.ts
|
|
*/
|
|
export const GENERATED_PROVIDER_MODELS: {
|
|
version: number
|
|
providers: Record<string, Record<string, ModelInfo>>
|
|
} = {
|
|
version: ${JSON.stringify(generatedModelsVersion)},
|
|
providers: ${JSON.stringify(sortedProviders, null, 2)}
|
|
}
|
|
`;
|
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
|
|
if (existsSync(outputPath)) {
|
|
const nextProviders = normalizeValue(sortedProviders);
|
|
let existingProviders: unknown | undefined;
|
|
try {
|
|
const existingModule = (await import(
|
|
"../src/catalog/catalog.generated.js"
|
|
)) as {
|
|
GENERATED_PROVIDER_MODELS?: {
|
|
providers?: Record<string, Record<string, ModelInfo>>;
|
|
};
|
|
};
|
|
existingProviders = existingModule.GENERATED_PROVIDER_MODELS?.providers;
|
|
} catch {
|
|
existingProviders = undefined;
|
|
}
|
|
if (
|
|
existingProviders &&
|
|
JSON.stringify(normalizeValue(existingProviders)) ===
|
|
JSON.stringify(nextProviders)
|
|
) {
|
|
const totalModels = Object.values(sortedProviders).reduce(
|
|
(count, models) => count + Object.keys(models).length,
|
|
0,
|
|
);
|
|
console.log(`No changes detected for ${OUTPUT_FILE}`);
|
|
console.log(`Providers: ${Object.keys(sortedProviders).length}`);
|
|
console.log(`Models: ${totalModels}`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
writeFileSync(outputPath, output, "utf8");
|
|
|
|
const totalModels = Object.values(sortedProviders).reduce(
|
|
(count, models) => count + Object.keys(models).length,
|
|
0,
|
|
);
|
|
console.log(`Generated ${OUTPUT_FILE}`);
|
|
console.log(`Providers: ${Object.keys(sortedProviders).length}`);
|
|
console.log(`Models: ${totalModels}`);
|
|
}
|
|
|
|
generate().catch((error) => {
|
|
console.error(error instanceof Error ? error.message : String(error));
|
|
process.exitCode = 1;
|
|
});
|