返回 DeepSeek-Reasonix
provider-endpoint.test.ts
根目录 / desktop / frontend / src / __tests__ / provider-endpoint.test.ts
1 import {
2 providerBaseURLForSave,
3 providerRequestURLForFormatChange,
4 providerBaseURLFromRequestURL,
5 providerEndpointMismatchDetail,
6 providerRequestURLForCatalogFormatChange,
7 providerRequestURLFromConfig,
8 } from "../lib/providerEndpoint";
9 let failed = 0;
10 function eq(actual: unknown, expected: unknown, label: string) {
11 if (actual === expected) {
12 process.stdout.write(` PASS ${label}\n`);
13 return;
14 }
15 process.stdout.write(` FAIL ${label}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}\n`);
16 failed += 1;
17 }
18 console.log("\nprovider endpoint");
19
20 eq(providerRequestURLFromConfig("openai", "https://proxy.example.com/v1", ""), "https://proxy.example.com/v1/chat/completions", "legacy OpenAI base URLs expose their effective request URL");
21 eq(providerRequestURLFromConfig("anthropic", "https://proxy.example.com/v1", ""), "https://proxy.example.com/v1/messages", "legacy Anthropic base URLs expose their effective request URL");
22 eq(providerRequestURLFromConfig("responses", "https://proxy.example.com/v1", ""), "https://proxy.example.com/v1/responses", "legacy Responses base URLs expose their effective request URL");
23 eq(providerRequestURLFromConfig("openai", "https://proxy.example.com/v1", "", "https://legacy.example.com/chat/completions/"), "https://legacy.example.com/chat/completions", "legacy OpenAI chat URLs preserve historical trailing-slash normalization");
24 eq(providerRequestURLFromConfig("anthropic", "https://proxy.example.com/v1", "", "https://stale.example.com/chat/completions"), "https://proxy.example.com/v1/messages", "legacy Anthropic chat URLs remain ignored");
25 eq(providerRequestURLFromConfig("openai", "", "https://proxy.example.com/custom/chat/?token=1", "https://legacy.example.com/chat/completions"), "https://proxy.example.com/custom/chat/?token=1", "explicit request URLs remain unchanged and take priority");
26 eq(providerBaseURLFromRequestURL("openai", "https://proxy.example.com/v1/chat/completions?token=1"), "https://proxy.example.com/v1", "request URLs derive a query-free base URL for model discovery");
27
28 eq(providerBaseURLForSave({ kind: "openai", baseUrl: "https://api.deepseek.com/v1", chatUrl: "https://gateway.example/custom/chat/completions" }, "openai", "https://gateway.example/custom/chat/completions"), "https://api.deepseek.com/v1", "unchanged legacy providers preserve their independent base URL");
29 eq(providerBaseURLForSave({ kind: "anthropic", baseUrl: "https://models.example/v1/", requestUrl: "https://gateway.example/custom/messages?token=1" }, "anthropic", "https://gateway.example/custom/messages?token=1"), "https://models.example/v1/", "unchanged explicit request URLs preserve their independent base URL exactly");
30 eq(providerBaseURLForSave({ kind: "openai", baseUrl: "https://models.example/v1", requestUrl: "https://gateway.example/old/chat/completions" }, "openai", "https://gateway.example/new/chat/completions"), "https://gateway.example/new", "changing the request URL derives a new base URL");
31 eq(providerBaseURLForSave({ kind: "openai", baseUrl: "https://models.example/v1", requestUrl: "https://gateway.example/v1/chat/completions" }, "anthropic", "https://gateway.example/v1/chat/completions"), "https://gateway.example/v1/chat/completions", "changing protocol derives a new base URL under the new protocol");
32 eq(providerBaseURLForSave(undefined, "responses", "https://gateway.example/v1/responses"), "https://gateway.example/v1", "new providers derive their base URL from the exact request URL");
33
34 eq(providerRequestURLForFormatChange("openai", "responses", "https://gateway.example/v1/chat/completions"), "https://gateway.example/v1/responses", "explicit format switch changes a standard suffix");
35 eq(providerRequestURLForFormatChange("anthropic", "openai", "https://gateway.example/v1/messages"), "https://gateway.example/v1/chat/completions", "Anthropic v1 is preserved when switching to chat");
36 eq(providerRequestURLForFormatChange("openai", "responses", "https://gateway.example/custom?token=x"), "https://gateway.example/custom?token=x", "custom request paths and query values remain untouched");
37 eq(providerRequestURLForFormatChange("openai", "responses", "https://gateway.example/v1/chat/completions?version=1"), "https://gateway.example/v1/chat/completions?version=1", "query-bearing exact overrides are never rewritten");
38
39 const deepSeekCatalog = {
40 brandId: "deepseek", brandLabel: "DeepSeek", region: "global", product: "api", format: "anthropic", baseUrl: "https://api.deepseek.com/anthropic",
41 protocols: {
42 openai: { baseUrl: "https://api.deepseek.com/v1", source: "fixture", checkedOn: "2026-09-08" },
43 responses: { baseUrl: "https://api.deepseek.com", source: "fixture", checkedOn: "2026-09-08" },
44 anthropic: { baseUrl: "https://api.deepseek.com/anthropic", source: "fixture", checkedOn: "2026-09-08" },
45 },
46 };
47 const mimoCatalog = {
48 ...deepSeekCatalog,
49 brandId: "mimo",
50 protocols: {
51 ...deepSeekCatalog.protocols,
52 openai: { ...deepSeekCatalog.protocols.openai, baseUrl: "https://api.xiaomimimo.com/v1" },
53 responses: { ...deepSeekCatalog.protocols.responses, baseUrl: "https://api.xiaomimimo.com/v1" },
54 },
55 };
56 eq(providerRequestURLForCatalogFormatChange("anthropic", "openai", "https://api.deepseek.com/anthropic/v1/messages", deepSeekCatalog), "https://api.deepseek.com/v1/chat/completions", "official Anthropic route switches to the registered Chat route");
57 eq(providerRequestURLForCatalogFormatChange("anthropic", "responses", "https://api.deepseek.com/anthropic/v1/messages", deepSeekCatalog), "https://api.deepseek.com/responses", "official Anthropic route switches to the registered Responses route");
58 eq(providerRequestURLForCatalogFormatChange("anthropic", "openai", "https://gateway.example/custom/v1/messages", deepSeekCatalog), "https://gateway.example/custom/v1/messages", "custom gateway remains byte-for-byte unchanged");
59 eq(providerRequestURLForCatalogFormatChange("anthropic", "openai", "https://api.deepseek.com/anthropic/v1/messages?token=x", deepSeekCatalog), "https://api.deepseek.com/anthropic/v1/messages?token=x", "query-bearing official host override stays untouched");
60 eq(providerEndpointMismatchDetail("openai", "https://api.deepseek.com/anthropic/v1/chat/completions", deepSeekCatalog).mismatch, true, "mixed DeepSeek path is blocked");
61 eq(providerEndpointMismatchDetail("openai", "https://api.deepseek.com/anthropic/v1/chat/completions", deepSeekCatalog).recommendedUrl, "https://api.deepseek.com/v1/chat/completions", "mixed DeepSeek path recommends the catalog route");
62 eq(providerEndpointMismatchDetail("openai", "https://api.deepseek.com/chat/completions", deepSeekCatalog).mismatch, false, "working DeepSeek root alias remains valid");
63 eq(providerEndpointMismatchDetail("openai", "https://api.xiaomimimo.com/v1/chat/completions", mimoCatalog).mismatch, false, "shared Chat and Responses base remains valid");
64 eq(providerEndpointMismatchDetail("openai", "https://gateway.example/anthropic/v1/chat/completions", deepSeekCatalog).mismatch, false, "custom host is not catalog-rewritten");
65 eq(providerEndpointMismatchDetail("openai", "https://api.deepseek.com/anthropic/custom/chat/completions", deepSeekCatalog).mismatch, false, "unknown custom path on the official host stays user-owned");
66
67 if (failed > 0) process.exit(1);
68
68 lines TYPESCRIPT