Refresh persisted custom-provider model lists from saved endpoints and expose manual refresh controls. - Add dashboard API helpers and routes to refresh one or all custom-provider model lists while preserving concurrent settings edits. - Start background model refresh from serve, dashboard, and daemon startup paths after the server begins listening. - Add Settings UI refresh actions, row-level status messaging, styles, docs, and regression coverage for refresh behavior. Files changed: .changeset/fn-7263-custom-provider-model-refresh.md | 7 + docs/dashboard-guide.md | 6 +- docs/settings-reference.md | 2 +- packages/cli/src/commands/__tests__/daemon.test.ts | 59 +++++ .../cli/src/commands/__tests__/dashboard.test.ts | 51 ++++ packages/cli/src/commands/__tests__/serve.test.ts | 59 ++++- packages/cli/src/commands/daemon.ts | 39 +++- packages/cli/src/commands/dashboard.ts | 10 + packages/cli/src/commands/serve.ts | 11 +- .../app/__tests__/api-custom-providers.test.ts | 43 ++++ packages/dashboard/app/api/legacy.ts | 11 + .../app/components/CustomProvidersSection.css | 41 +++- .../app/components/CustomProvidersSection.tsx | 68 +++++- .../__tests__/CustomProvidersSection.test.tsx | 227 ++++++++++++++++++ packages/dashboard/src/index.ts | 6 + .../__tests__/custom-provider-routes.test.ts | 255 ++++++++++++++++++++ .../src/routes/__tests__/custom-providers.test.ts | 12 + .../src/routes/register-custom-provider-routes.ts | 259 ++++++++++++++++----- 18 files changed, 1101 insertions(+), 65 deletions(-) Fusion-Task-Id: FN-7263 Fusion-Task-Lineage: 60ee0637-ac85-409f-a376-c01f4bc8e8c5 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { refreshProviderModels } from "../api";
|
|
import { clearAuthToken } from "../auth";
|
|
|
|
function mockFetchResponse(body: unknown): Promise<Response> {
|
|
return Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: { get: () => "application/json" },
|
|
json: () => Promise.resolve(body),
|
|
text: () => Promise.resolve(JSON.stringify(body)),
|
|
} as unknown as Response);
|
|
}
|
|
|
|
describe("custom provider API wrappers", () => {
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
afterEach(() => {
|
|
globalThis.fetch = originalFetch;
|
|
clearAuthToken();
|
|
});
|
|
|
|
it("posts to the per-provider model refresh endpoint", async () => {
|
|
const response = {
|
|
provider: {
|
|
id: "provider/id",
|
|
name: "Provider",
|
|
apiType: "openai-compatible",
|
|
baseUrl: "https://api.example.com/v1",
|
|
models: [{ id: "fresh-model", name: "Fresh model" }],
|
|
},
|
|
modelsRefreshed: 1,
|
|
};
|
|
globalThis.fetch = vi.fn().mockReturnValue(mockFetchResponse(response));
|
|
|
|
await expect(refreshProviderModels("provider/id")).resolves.toEqual(response);
|
|
expect(globalThis.fetch).toHaveBeenCalledWith(
|
|
"/api/custom-providers/provider%2Fid/refresh-models",
|
|
expect.objectContaining({ method: "POST" }),
|
|
);
|
|
});
|
|
});
|