|
|
@@ -45,6 +45,7 @@ const SERVICE_PRESETS_MOCK: Record<string, ServicePresetMock> = {
|
|
|
anthropic: { providerFamily: "anthropic", baseUrl: "https://api.anthropic.com", modelsBaseUrl: "https://api.anthropic.com", knownModels: [] as string[] },
|
|
|
minimax: { providerFamily: "anthropic", baseUrl: "https://api.minimaxi.com/anthropic", modelsBaseUrl: "https://api.minimaxi.com/anthropic", knownModels: [] as string[] },
|
|
|
bailian: { providerFamily: "anthropic", baseUrl: "https://dashscope.aliyuncs.com/apps/anthropic", modelsBaseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", knownModels: [] as string[] },
|
|
|
+ google: { providerFamily: "openai", baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", modelsBaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai", knownModels: [] as string[] },
|
|
|
custom: { providerFamily: "openai", baseUrl: "", knownModels: [] as string[] },
|
|
|
};
|
|
|
const resolveServicePresetMock = vi.fn((service: string) => SERVICE_PRESETS_MOCK[service]);
|
|
|
@@ -93,6 +94,7 @@ const endpointMocks = [
|
|
|
id,
|
|
|
label: id,
|
|
|
group,
|
|
|
+ ...(id === "google" ? { checkModel: "gemini-2.5-flash" } : {}),
|
|
|
models: [
|
|
|
{ id: `${id}-model`, maxOutput: 4096, contextWindowTokens: 32768, enabled: true },
|
|
|
{ id: `${id}-disabled`, maxOutput: 4096, contextWindowTokens: 32768, enabled: false },
|
|
|
@@ -1113,6 +1115,60 @@ describe("createStudioServer daemon lifecycle", () => {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ it("uses the bank endpoint check model before the global default during service probe", async () => {
|
|
|
+ await writeFile(join(root, "inkos.json"), JSON.stringify({
|
|
|
+ ...projectConfig,
|
|
|
+ llm: {
|
|
|
+ services: [
|
|
|
+ { service: "google", apiFormat: "chat", stream: false },
|
|
|
+ ],
|
|
|
+ defaultModel: "MiniMax-M2.7",
|
|
|
+ },
|
|
|
+ }, null, 2), "utf-8");
|
|
|
+
|
|
|
+ const fetchMock = vi.fn().mockResolvedValue({
|
|
|
+ ok: false,
|
|
|
+ status: 404,
|
|
|
+ text: async () => "Not Found",
|
|
|
+ });
|
|
|
+ vi.stubGlobal("fetch", fetchMock as typeof fetch);
|
|
|
+ createLLMClientMock.mockImplementation(((cfg: unknown) => cfg) as any);
|
|
|
+ chatCompletionMock.mockImplementation(async (_client: any, model: string) => {
|
|
|
+ if (model === "gemini-2.5-flash") {
|
|
|
+ return {
|
|
|
+ content: "pong",
|
|
|
+ usage: { promptTokens: 1, completionTokens: 1, totalTokens: 2 },
|
|
|
+ };
|
|
|
+ }
|
|
|
+ throw new Error(`unexpected model: ${model}`);
|
|
|
+ });
|
|
|
+
|
|
|
+ const { createStudioServer } = await import("./server.js");
|
|
|
+ const app = createStudioServer(cloneProjectConfig() as never, root);
|
|
|
+
|
|
|
+ const response = await app.request("http://localhost/api/v1/services/google/test", {
|
|
|
+ method: "POST",
|
|
|
+ headers: { "Content-Type": "application/json" },
|
|
|
+ body: JSON.stringify({
|
|
|
+ apiKey: "google-key",
|
|
|
+ apiFormat: "chat",
|
|
|
+ stream: false,
|
|
|
+ }),
|
|
|
+ });
|
|
|
+
|
|
|
+ expect(response.status).toBe(200);
|
|
|
+ await expect(response.json()).resolves.toMatchObject({
|
|
|
+ ok: true,
|
|
|
+ selectedModel: "gemini-2.5-flash",
|
|
|
+ });
|
|
|
+ expect(chatCompletionMock).toHaveBeenCalledWith(
|
|
|
+ expect.anything(),
|
|
|
+ "gemini-2.5-flash",
|
|
|
+ expect.any(Array),
|
|
|
+ expect.any(Object),
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
it("uses the preset models baseUrl when listing Bailian models", async () => {
|
|
|
await writeFile(join(root, "inkos.json"), JSON.stringify({
|
|
|
...projectConfig,
|