feat: Ollama models command, with load/pull/delete and unload (#16)
This commit was merged in pull request #16.
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { __resetLocalStorage, __setPreferenceValues } from "../__mocks__/@vicinae/api";
|
||||
import { DEFAULT_HOST, DEFAULT_MAX_TOOL_ROUNDS, DEFAULT_MODEL } from "../lib/constants";
|
||||
import {
|
||||
clearModelSelection,
|
||||
describeAutoDelete,
|
||||
describeMaxToolRounds,
|
||||
describeResumeTimeout,
|
||||
resolveAutoDelete,
|
||||
resolveMaxToolRounds,
|
||||
resolvePreferences,
|
||||
loadPreferences,
|
||||
readModelSelection,
|
||||
resolveResumeTimeout,
|
||||
selectModel,
|
||||
} from "../lib/preferences";
|
||||
|
||||
const MINUTE = 60_000;
|
||||
@@ -203,3 +208,91 @@ describe("describeMaxToolRounds", () => {
|
||||
expect(describeMaxToolRounds(1)).toBe("1 round per answer");
|
||||
});
|
||||
});
|
||||
|
||||
describe("the model selection", () => {
|
||||
beforeEach(() => {
|
||||
__resetLocalStorage();
|
||||
__setPreferenceValues({ apiKey: "k", model: "from-preference:1b" });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
__setPreferenceValues({});
|
||||
});
|
||||
|
||||
it("uses the preference when nothing has been picked", async () => {
|
||||
const resolved = await loadPreferences();
|
||||
|
||||
expect(resolved.model).toBe("from-preference:1b");
|
||||
expect(resolved.modelSource).toBe("preference");
|
||||
expect(resolved.preferenceModel).toBe("from-preference:1b");
|
||||
});
|
||||
|
||||
it("prefers a picked model over the preference, and says so", async () => {
|
||||
// The whole reason this exists: an extension cannot write its own
|
||||
// preferences, so the pick has to live somewhere else and win.
|
||||
await selectModel("picked:9b");
|
||||
|
||||
const resolved = await loadPreferences();
|
||||
|
||||
expect(resolved.model).toBe("picked:9b");
|
||||
expect(resolved.modelSource).toBe("selection");
|
||||
// Both values are carried, so a screen can answer "what would a reset give
|
||||
// me back".
|
||||
expect(resolved.preferenceModel).toBe("from-preference:1b");
|
||||
});
|
||||
|
||||
it("round-trips a pick through storage", async () => {
|
||||
await selectModel("first:1b");
|
||||
await expect(readModelSelection()).resolves.toBe("first:1b");
|
||||
|
||||
await selectModel("second:2b");
|
||||
await expect(readModelSelection()).resolves.toBe("second:2b");
|
||||
});
|
||||
|
||||
it("hands the model back to the preference when the selection is cleared", async () => {
|
||||
await selectModel("picked:9b");
|
||||
await clearModelSelection();
|
||||
|
||||
const resolved = await loadPreferences();
|
||||
|
||||
expect(resolved.model).toBe("from-preference:1b");
|
||||
expect(resolved.modelSource).toBe("preference");
|
||||
});
|
||||
|
||||
it("ignores a stored selection that is empty or whitespace", async () => {
|
||||
// A blank value is not a model name, and treating it as one would leave the
|
||||
// chat asking for "" on every turn.
|
||||
await selectModel(" ");
|
||||
|
||||
await expect(readModelSelection()).resolves.toBeUndefined();
|
||||
await expect(loadPreferences()).resolves.toMatchObject({ model: "from-preference:1b" });
|
||||
});
|
||||
|
||||
it("trims a stored selection", async () => {
|
||||
await selectModel(" spaced:1b ");
|
||||
|
||||
await expect(readModelSelection()).resolves.toBe("spaced:1b");
|
||||
});
|
||||
|
||||
it("falls back to the preference when storage cannot be read", async () => {
|
||||
const { LocalStorage } = await import("../__mocks__/@vicinae/api");
|
||||
const original = LocalStorage.getItem;
|
||||
LocalStorage.getItem = async () => {
|
||||
throw new Error("storage is unavailable");
|
||||
};
|
||||
|
||||
try {
|
||||
await expect(loadPreferences()).resolves.toMatchObject({ model: "from-preference:1b" });
|
||||
} finally {
|
||||
LocalStorage.getItem = original;
|
||||
}
|
||||
});
|
||||
|
||||
it("leaves the model source as the preference when resolving without storage", () => {
|
||||
expect(resolvePreferences({ model: "plain:1b" })).toMatchObject({
|
||||
model: "plain:1b",
|
||||
modelSource: "preference",
|
||||
preferenceModel: "plain:1b",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user