Skip to content

Commit d6bc9e3

Browse files
committed
Refactor AI provider model creation and configuration
- Removed individual provider creation logic in favor of a unified `createLanguageModel` function that handles multiple provider types. - Introduced support for custom API formats (OpenAI and Anthropic) in provider configurations. - Updated the AIProviderDialog component to allow users to select the API format for compatible providers. - Removed the deprecated thinking mode utility functions and integrated thinking options directly into provider configurations. - Enhanced error handling and connection testing for providers. - Updated storage functions to handle sidepanel thinking mode state more robustly. - Removed unused Qwen compatibility functions and streamlined provider handling.
1 parent a91c90c commit d6bc9e3

16 files changed

Lines changed: 357 additions & 1117 deletions

app/extension/src/__tests__/openAICompatibleStream.test.ts

Lines changed: 0 additions & 55 deletions
This file was deleted.

app/extension/src/__tests__/providers.test.ts

Lines changed: 22 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,10 @@ import {
22
getOpenAICompatibleBaseUrl,
33
getOllamaBaseUrl,
44
getOllamaOpenAIBaseUrl,
5-
isDashScopeCompatibleBaseUrl,
6-
usesRawOpenAICompatibleStream,
75
} from "../ai/openAICompatibleProviders";
6+
import { getEffectiveApiFormat } from "../ai/types";
87

98
describe("providers helpers", () => {
10-
it("detects DashScope-compatible endpoints", () => {
11-
expect(
12-
isDashScopeCompatibleBaseUrl(
13-
"https://dashscope.aliyuncs.com/compatible-mode/v1"
14-
)
15-
).toBe(true);
16-
expect(
17-
isDashScopeCompatibleBaseUrl(
18-
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
19-
)
20-
).toBe(true);
21-
expect(isDashScopeCompatibleBaseUrl("https://api.openai.com/v1")).toBe(
22-
false
23-
);
24-
});
25-
26-
it("uses raw OpenAI-compatible streaming only for providers that need it", () => {
27-
expect(
28-
usesRawOpenAICompatibleStream({
29-
type: "qwen",
30-
enabled: true,
31-
apiKey: "test",
32-
baseUrl: "",
33-
enabledModels: ["qwen3-max"],
34-
updatedAt: Date.now(),
35-
})
36-
).toBe(true);
37-
38-
expect(
39-
usesRawOpenAICompatibleStream({
40-
type: "openai",
41-
enabled: true,
42-
apiKey: "test",
43-
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
44-
enabledModels: ["qwen3-max"],
45-
updatedAt: Date.now(),
46-
})
47-
).toBe(true);
48-
49-
expect(
50-
usesRawOpenAICompatibleStream({
51-
type: "openai",
52-
enabled: true,
53-
apiKey: "test",
54-
baseUrl: "https://api.openai.com/v1",
55-
enabledModels: ["gpt-4.1"],
56-
updatedAt: Date.now(),
57-
})
58-
).toBe(false);
59-
60-
expect(
61-
usesRawOpenAICompatibleStream({
62-
type: "google",
63-
enabled: true,
64-
apiKey: "test",
65-
baseUrl: "",
66-
enabledModels: ["gemini-2.5-flash"],
67-
updatedAt: Date.now(),
68-
})
69-
).toBe(false);
70-
});
71-
729
it("returns configured or default OpenAI-compatible base url", () => {
7310
expect(
7411
getOpenAICompatibleBaseUrl({
@@ -106,4 +43,25 @@ describe("providers helpers", () => {
10643
"http://localhost:11434/v1"
10744
);
10845
});
46+
47+
it("falls back to the provider native format when no override is given", () => {
48+
expect(getEffectiveApiFormat({ type: "qwen" })).toBe("openai");
49+
expect(getEffectiveApiFormat({ type: "anthropic" })).toBe("anthropic");
50+
});
51+
52+
it("honours the user-selected api format for flexible providers", () => {
53+
expect(
54+
getEffectiveApiFormat({ type: "qwen", apiFormat: "anthropic" })
55+
).toBe("anthropic");
56+
expect(
57+
getEffectiveApiFormat({ type: "zhipu", apiFormat: "anthropic" })
58+
).toBe("anthropic");
59+
});
60+
61+
it("ignores an api format override on providers that do not allow it", () => {
62+
// openai has a fixed native format; the override should be ignored.
63+
expect(
64+
getEffectiveApiFormat({ type: "openai", apiFormat: "anthropic" })
65+
).toBe("openai");
66+
});
10967
});

app/extension/src/__tests__/qwenCompatibility.test.ts

Lines changed: 0 additions & 109 deletions
This file was deleted.

app/extension/src/__tests__/thinkingMode.test.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,21 @@
1-
import { AIProviderConfig, ProviderType, PROVIDER_REGISTRY } from "./types";
1+
import { AIProviderConfig, PROVIDER_REGISTRY } from "./types";
22

3-
const ALWAYS_RAW_OPENAI_COMPATIBLE_PROVIDERS = new Set<ProviderType>([
4-
"qwen",
5-
"zhipu",
6-
"minimax",
7-
]);
8-
9-
export function isDashScopeCompatibleBaseUrl(baseUrl?: string): boolean {
10-
const normalizedBaseUrl = baseUrl?.toLowerCase() || "";
3+
function trimTrailingSlash(url: string): string {
4+
return url.replace(/\/+$/, "");
5+
}
116

7+
export function getProviderBaseUrl(config: AIProviderConfig): string | undefined {
128
return (
13-
normalizedBaseUrl.includes("dashscope.aliyuncs.com/compatible-mode") ||
14-
normalizedBaseUrl.includes("dashscope-intl.aliyuncs.com/compatible-mode")
9+
config.baseUrl ||
10+
PROVIDER_REGISTRY[config.type]?.defaultBaseUrl ||
11+
undefined
1512
);
1613
}
1714

18-
export function usesRawOpenAICompatibleStream(
19-
config: AIProviderConfig
20-
): boolean {
21-
if (ALWAYS_RAW_OPENAI_COMPATIBLE_PROVIDERS.has(config.type)) {
22-
return true;
23-
}
24-
25-
if (config.type === "openai") {
26-
return isDashScopeCompatibleBaseUrl(getOpenAICompatibleBaseUrl(config));
27-
}
28-
29-
return false;
30-
}
31-
32-
export function getOpenAICompatibleBaseUrl(
33-
config: AIProviderConfig
34-
): string | undefined {
35-
return config.baseUrl || PROVIDER_REGISTRY[config.type]?.defaultBaseUrl || undefined;
36-
}
37-
38-
function trimTrailingSlash(url: string): string {
39-
return url.replace(/\/+$/, "");
40-
}
15+
/**
16+
* @deprecated use {@link getProviderBaseUrl}. Kept for call sites still being migrated.
17+
*/
18+
export const getOpenAICompatibleBaseUrl = getProviderBaseUrl;
4119

4220
export function getOllamaBaseUrl(baseUrl?: string): string {
4321
const normalizedBaseUrl = trimTrailingSlash(
@@ -50,7 +28,5 @@ export function getOllamaBaseUrl(baseUrl?: string): string {
5028
}
5129

5230
export function getOllamaOpenAIBaseUrl(baseUrl?: string): string {
53-
const normalizedBaseUrl = getOllamaBaseUrl(baseUrl);
54-
55-
return `${normalizedBaseUrl}/v1`;
31+
return `${getOllamaBaseUrl(baseUrl)}/v1`;
5632
}

0 commit comments

Comments
 (0)