feat(coding-agent): add model catalog refresh flag
This commit is contained in:
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
|
||||
import { delimiter, join } from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { ENV_AGENT_DIR, PACKAGE_NAME, VERSION } from "../src/config.ts";
|
||||
import { ModelRuntime } from "../src/core/model-runtime.ts";
|
||||
import type { ResolvedPaths } from "../src/core/package-manager.ts";
|
||||
import { InMemorySettingsStorage, SettingsManager } from "../src/core/settings-manager.ts";
|
||||
import { ProjectTrustStore } from "../src/core/trust-manager.ts";
|
||||
@@ -371,6 +372,42 @@ describe("package commands", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("refreshes only model catalogs with update --models", async () => {
|
||||
const refresh = vi.fn(async () => ({ aborted: false, errors: new Map<string, Error>() }));
|
||||
const create = vi.spyOn(ModelRuntime, "create").mockResolvedValue({ refresh } as unknown as ModelRuntime);
|
||||
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
await expect(runPackageCommandDirectly(["update", "--models"])).resolves.toBeUndefined();
|
||||
|
||||
expect(create).toHaveBeenCalledWith({
|
||||
authPath: join(agentDir, "auth.json"),
|
||||
modelsPath: join(agentDir, "models.json"),
|
||||
allowModelNetwork: false,
|
||||
});
|
||||
expect(refresh).toHaveBeenCalledWith({
|
||||
allowNetwork: true,
|
||||
force: true,
|
||||
signal: expect.any(AbortSignal),
|
||||
});
|
||||
expect(logSpy.mock.calls.map(([message]) => String(message)).join("\n")).toContain("Model catalogs refreshed");
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(process.exitCode).toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects update --models combined with another update target", async () => {
|
||||
const create = vi.spyOn(ModelRuntime, "create");
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
await expect(runPackageCommandDirectly(["update", "--models", "--self"])).resolves.toBeUndefined();
|
||||
|
||||
expect(create).not.toHaveBeenCalled();
|
||||
expect(errorSpy.mock.calls.map(([message]) => String(message)).join("\n")).toContain(
|
||||
"--models cannot be combined with --self",
|
||||
);
|
||||
expect(process.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("cycles project package overrides in config local mode", async () => {
|
||||
const storage = new InMemorySettingsStorage();
|
||||
storage.withLock("global", () => JSON.stringify({ packages: ["npm:pi-tools"] }));
|
||||
|
||||
@@ -21,12 +21,13 @@ function model(id: string): Model<"openai-completions"> {
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
describe("remote catalog provider", () => {
|
||||
it("parses keyed catalogs, sends version headers, and observes the refresh TTL", async () => {
|
||||
const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
||||
new Response(JSON.stringify({ dynamic: model("dynamic") }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
it("parses keyed catalogs, sends version headers, observes the refresh TTL, and supports forced refreshes", async () => {
|
||||
const fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(
|
||||
async () =>
|
||||
new Response(JSON.stringify({ dynamic: model("dynamic") }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
);
|
||||
const provider = withRemoteCatalog(
|
||||
createProvider({
|
||||
@@ -62,10 +63,20 @@ describe("remote catalog provider", () => {
|
||||
},
|
||||
allowNetwork: true,
|
||||
});
|
||||
await provider.refreshModels?.({
|
||||
credential: { type: "api_key" },
|
||||
store: {
|
||||
read: () => store.read(provider.id),
|
||||
write: (entry) => store.write(provider.id, entry),
|
||||
delete: () => store.delete(provider.id),
|
||||
},
|
||||
allowNetwork: true,
|
||||
force: true,
|
||||
});
|
||||
|
||||
expect(provider.getModels().map((entry) => entry.id)).toEqual(["static", "dynamic"]);
|
||||
expect((await store.read(provider.id))?.models.map((entry) => entry.id)).toEqual(["dynamic"]);
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
||||
expect(fetchSpy.mock.calls[0]?.[1]?.headers).toMatchObject({
|
||||
"User-Agent": expect.stringContaining(`pi/${VERSION}`),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user