66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import { ModelProvider, ProviderProbeResult } from "./types.js";
|
|
import { createId, nowIso } from "./ids.js";
|
|
|
|
export function createProvider(
|
|
kind: ModelProvider["kind"],
|
|
name: string,
|
|
baseUrl: string
|
|
): ModelProvider {
|
|
const createdAt = nowIso();
|
|
return {
|
|
id: createId("provider"),
|
|
name: name.trim(),
|
|
kind,
|
|
baseUrl: normalizeBaseUrl(baseUrl),
|
|
enabled: true,
|
|
supportsTools: kind !== "ollama",
|
|
contextWindow: 8192,
|
|
defaults: {},
|
|
createdAt,
|
|
updatedAt: createdAt
|
|
};
|
|
}
|
|
|
|
export function normalizeBaseUrl(baseUrl: string): string {
|
|
return baseUrl.trim().replace(/\/+$/, "");
|
|
}
|
|
|
|
export async function probeOpenAiCompatibleProvider(
|
|
provider: ModelProvider,
|
|
fetchImpl: typeof fetch = fetch
|
|
): Promise<ProviderProbeResult> {
|
|
const url = `${normalizeBaseUrl(provider.baseUrl)}/models`;
|
|
try {
|
|
const response = await fetchImpl(url, {
|
|
headers: provider.apiKey ? { Authorization: `Bearer ${provider.apiKey}` } : undefined
|
|
});
|
|
if (!response.ok) {
|
|
return {
|
|
ok: false,
|
|
providerId: provider.id,
|
|
models: [],
|
|
message: `Provider returned HTTP ${response.status}`
|
|
};
|
|
}
|
|
const body = await response.json() as { data?: Array<{ id?: string }>; models?: string[] };
|
|
const models = Array.isArray(body.data)
|
|
? body.data.map((model) => model.id).filter(Boolean) as string[]
|
|
: Array.isArray(body.models)
|
|
? body.models
|
|
: [];
|
|
return {
|
|
ok: models.length > 0,
|
|
providerId: provider.id,
|
|
models,
|
|
message: models.length > 0 ? "Provider is reachable." : "Provider responded without model ids."
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
ok: false,
|
|
providerId: provider.id,
|
|
models: [],
|
|
message: error instanceof Error ? error.message : "Provider probe failed."
|
|
};
|
|
}
|
|
}
|