cjovs's picture
Add Custom LLM Endpoint plugin
df23150 verified
Raw
History Blame Contribute Delete
1.69 kB
import type { ProviderModelEntry } from "../types.js";
function asRecord(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
return value as Record<string, unknown>;
}
export function normalizeBaseUrl(value: string): string {
return value.trim().replace(/\/+$/, "");
}
export function toModelCatalog(rawEntries: unknown[]): ProviderModelEntry[] {
const deduped = new Map<string, ProviderModelEntry>();
for (const rawEntry of rawEntries) {
const record = asRecord(rawEntry);
const id = typeof record?.id === "string" ? record.id.trim() : "";
if (!id || deduped.has(id)) continue;
const label = typeof record?.name === "string" && record.name.trim().length > 0
? record.name.trim()
: id;
deduped.set(id, {
id,
label,
raw: record ?? null,
});
}
return Array.from(deduped.values()).sort((left, right) => left.id.localeCompare(right.id));
}
export async function fetchOpenAiModelCatalog(
fetchImpl: (url: string, init?: RequestInit) => Promise<Response>,
input: { baseUrl: string; apiKey: string },
): Promise<{ baseUrl: string; modelCatalog: ProviderModelEntry[] }> {
const baseUrl = normalizeBaseUrl(input.baseUrl);
const response = await fetchImpl(`${baseUrl}/models`, {
headers: {
Authorization: `Bearer ${input.apiKey}`,
},
});
if (!response.ok) {
throw new Error(`Failed to fetch models (${response.status})`);
}
const body = await response.json() as { data?: unknown[] };
return {
baseUrl,
modelCatalog: toModelCatalog(Array.isArray(body.data) ? body.data : []),
};
}
export { asRecord };