Path: blob/master/src/packages/util/db-schema/llm-utils.test.ts
5808 views
import {1DEFAULT_LLM_PRIORITY,2DEFAULT_MODEL,3getValidLanguageModelName,4isCoreLanguageModel,5isFreeModel,6LANGUAGE_MODEL_SERVICES,7LANGUAGE_MODELS,8LanguageService,9LLM_DESCR,10LLM_COST,11LLMServicesAvailable,12model2vendor,13model2service,14OLLAMA_PREFIX,15SERVICES,16USER_SELECTABLE_LANGUAGE_MODELS,17USER_SELECTABLE_LLMS_BY_VENDOR,18} from "./llm-utils";1920describe("llm", () => {21const is_cocalc_com = true; // otherwise, the test makes no sense2223test("isFreeModel", () => {24expect(isFreeModel("gpt-3", is_cocalc_com)).toBe(true);25expect(isFreeModel("gpt-4", is_cocalc_com)).toBe(false);26// WARNING: if the following breaks, and ollama becomes non-free, then a couple of assumptions are broken as well.27// search for model2service(...) as LanguageService in the codebase!28expect(isFreeModel(`${OLLAMA_PREFIX}-1`, is_cocalc_com)).toBe(true);29});3031test.each(Object.keys(LLM_COST))(32"is valid model names in LLM_COST: '%s'",33(model) => {34expect(LANGUAGE_MODELS.includes(model as any)).toBe(true);35},36);3738test("all user selectable ones are valid", () => {39for (const model of USER_SELECTABLE_LANGUAGE_MODELS) {40expect(LANGUAGE_MODELS.includes(model)).toBe(true);41}42});4344// none of the user selectable models start with any of the vendor prefixes45test.each(USER_SELECTABLE_LANGUAGE_MODELS)(46"model '%s' does not start with any vendor prefix",47(model) => {48for (const prefix of LANGUAGE_MODEL_SERVICES) {49expect(model.startsWith(prefix)).toBe(false);50}51},52);5354test.each(LANGUAGE_MODELS)(55`check that model2vendor('%s') knows the model`,56(model) => {57const vendor = model2vendor(model);58expect(LANGUAGE_MODEL_SERVICES.includes(vendor.name)).toBe(true);59},60);6162test("model2service handles xAI models", () => {63expect(model2service("grok-4-1-fast-non-reasoning-16k")).toBe(64"xai-grok-4-1-fast-non-reasoning-16k",65);66});6768test("model2service handles gpt-5.2 models", () => {69expect(model2service("gpt-5.2-8k")).toBe("openai-gpt-5.2-8k");70});7172test("Gemini 3 Flash description omits preview", () => {73expect(LLM_DESCR["gemini-3-flash-preview-16k"].toLowerCase()).not.toContain(74"preview",75);76});7778test(`check model by vendor`, () => {79for (const vendor in USER_SELECTABLE_LLMS_BY_VENDOR) {80const models = USER_SELECTABLE_LLMS_BY_VENDOR[vendor];81for (const model of models) {82const v = model2vendor(model);83expect(v.name).toBe(vendor);84expect(v.url).toContain("https://");85}86}87});8889test("just checking the price", () => {90expect(1_000_000 * LLM_COST["gpt-4"].prompt_tokens).toBeCloseTo(30);91expect(1_000_000 * LLM_COST["gpt-4"].completion_tokens).toBeCloseTo(60);92expect(1_000_000 * LLM_COST["claude-3-opus"].prompt_tokens).toBeCloseTo(15);93expect(1_000_000 * LLM_COST["claude-3-opus"].completion_tokens).toBeCloseTo(9475,95);96});9798test("priority list is a shuffle of all llm vendors", () => {99// except for "user"100const prio = DEFAULT_LLM_PRIORITY;101const vend = SERVICES;102// test, that those lists have the same elements103expect(prio.length).toBe(vend.length);104for (const v of vend) {105expect(prio.includes(v)).toBe(true);106}107});108109test("getting valid language model", () => {110const selectable_llms = [...USER_SELECTABLE_LANGUAGE_MODELS];111const notAvailable = selectable_llms.pop();112113function getModel(model: LanguageService, disabled?: LanguageService) {114const allEnabled = LANGUAGE_MODEL_SERVICES.reduce((acc, svc) => {115acc[svc] = disabled !== svc;116return acc;117}, {}) as LLMServicesAvailable;118return getValidLanguageModelName({119model,120filter: allEnabled,121ollama: ["phi3"],122custom_openai: ["bar"],123selectable_llms,124});125}126127// meaningless name128expect(getModel("foobar")).toEqual(DEFAULT_MODEL);129expect(getModel("baz-delta99")).toEqual(DEFAULT_MODEL);130// gpt 3.5 is disabled131expect(getModel("gpt-3.5-turbo")).toEqual(DEFAULT_MODEL);132// not available133expect(134typeof notAvailable === "string" && isCoreLanguageModel(notAvailable),135).toBe(true);136if (typeof notAvailable === "string") {137expect(getModel(notAvailable)).toEqual(DEFAULT_MODEL);138}139// not disabled140expect(getModel("mistral-large-latest")).toEqual("mistral-large-latest");141expect(getModel("gpt-4")).toEqual("gpt-4");142expect(getModel(DEFAULT_MODEL)).toEqual(DEFAULT_MODEL);143expect(getModel("magistral-medium-latest")).toEqual(DEFAULT_MODEL);144expect(getModel("mistral-large-latest")).toEqual("mistral-large-latest");145expect(getModel("claude-4-5-haiku-8k")).toEqual("claude-4-5-haiku-8k");146// anthropic service disabled147expect(getModel("claude-4-5-haiku-8k", "anthropic")).toEqual(DEFAULT_MODEL);148// ollama149expect(getModel("ollama-foo")).toEqual(DEFAULT_MODEL);150expect(getModel("ollama-phi3")).toEqual("ollama-phi3");151// openai api152expect(getModel("custom_openai-foo")).toEqual(DEFAULT_MODEL);153expect(getModel("custom_openai-bar")).toEqual("custom_openai-bar");154// user models: there are no further checks155expect(getModel("user-custom_openai-foo")).toEqual(156"user-custom_openai-foo",157);158expect(getModel("user-openai-gpt-3.5-turbo")).toEqual(159"user-openai-gpt-3.5-turbo",160);161// it's ok to use a model if disabled by the admin, since it's their key162expect(getModel("user-anthropic-claude-3-5-haiku-8k", "anthropic")).toEqual(163"user-anthropic-claude-3-5-haiku-8k",164);165// meaningless user service166expect(getModel("user-baz-delta99")).toEqual(DEFAULT_MODEL);167});168});169170171