Клиент — замороженный объект с семью методами GET, без универсального запроса и тела; денежные поля проверяются на строковый тип (fail-closed). Каталог джойнит /api/models и /v1/models: модальность и рубли из первого, USD и доступность ключу из второго. Инструменты: list_models, pick_model, estimate_cost, get_balance, get_usage, list_api_keys. Точка входа stdio уводит console.log/info в stderr первым импортом. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { joinCatalog, type CatalogItem } from "../src/catalog.js";
|
|
import type { ApiModelsResponse, V1ModelsResponse } from "../src/client.js";
|
|
|
|
export function fixture<T = unknown>(name: string): T {
|
|
return JSON.parse(readFileSync(new URL(`./fixtures/${name}.json`, import.meta.url), "utf8")) as T;
|
|
}
|
|
|
|
export function fixtureCatalog(): CatalogItem[] {
|
|
const api = fixture<ApiModelsResponse>("api-models");
|
|
const v1 = fixture<V1ModelsResponse>("v1-models");
|
|
return joinCatalog(api.data, v1.data, () => undefined);
|
|
}
|
|
|
|
export function byId(items: readonly CatalogItem[], id: string): CatalogItem {
|
|
const it = items.find((m) => m.id === id);
|
|
if (it === undefined) throw new Error(`нет ${id} в фикстуре`);
|
|
return it;
|
|
}
|
|
|
|
/** Синтетическая текстовая модель для граничных случаев сравнения цен. */
|
|
export function synthetic(id: string, prompt: string | null, completion: string | null = prompt): CatalogItem {
|
|
return {
|
|
id,
|
|
name: id,
|
|
description: "",
|
|
vendor: id.split("/")[0] ?? id,
|
|
modality: "text",
|
|
input_modalities: ["text"],
|
|
context_length: 100_000,
|
|
is_free: false,
|
|
price_prompt_rub_1m: prompt,
|
|
price_completion_rub_1m: completion,
|
|
price_image_rub: null,
|
|
price_image_unit: null,
|
|
price_note: null,
|
|
usd: null,
|
|
allowed_for_this_key: true,
|
|
};
|
|
}
|