Skip to content

Commit 6bba6e1

Browse files
committed
Simplify chat model provider support
1 parent ec9662c commit 6bba6e1

13 files changed

Lines changed: 106 additions & 59 deletions

File tree

apps/tui/src/config/config-client.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,7 @@ const DatasourceSchemaResponseSchema = z.object({
146146
// ==================== Model Profile Schemas ====================
147147

148148
const ModelProfileSchema = CommonFieldsSchema.extend({
149-
provider: z.enum([
150-
"openai-compatible",
151-
"bailian",
152-
"deepseek",
153-
"openai",
154-
"anthropic",
155-
"google",
156-
]),
149+
provider: z.string().default("openai-compatible"),
157150
baseUrl: z.string().optional(),
158151
modelName: z.string(),
159152
secretRef: z.string().optional(),

apps/tui/src/state/data-task-state.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,16 +572,24 @@ function dbTypeOptions(): Array<{ value: string; label: string }> {
572572
: [...DB_TYPE_OPTIONS];
573573
}
574574

575-
/** Aligns with dataFoundry `LLM_PROVIDER` env and Mastra router provider ids. */
575+
/** Chat models use one OpenAI-compatible provider path; vendor choice lives in baseUrl/modelName. */
576576
export const LLM_PROVIDER_OPTIONS = [
577577
{ value: "openai-compatible", label: "OpenAI 兼容 (LLM_PROVIDER=openai-compatible)" },
578-
{ value: "bailian", label: "百炼 DashScope (bailian)" },
579-
{ value: "deepseek", label: "DeepSeek (deepseek)" },
580-
{ value: "openai", label: "OpenAI (openai)" },
581-
{ value: "anthropic", label: "Anthropic (anthropic)" },
582-
{ value: "google", label: "Google Gemini (google)" },
583578
] as const;
584579

580+
function normalizeLlmProvider(provider?: string): string {
581+
const normalized = provider?.trim().toLowerCase().replaceAll("_", "-") ?? "";
582+
if (
583+
normalized === "bailian"
584+
|| normalized === "deepseek"
585+
|| normalized === "openai"
586+
|| normalized === "openai-compatible"
587+
) {
588+
return "openai-compatible";
589+
}
590+
return normalized || "openai-compatible";
591+
}
592+
585593
export function normalizeLlmSettings(
586594
settings?: Record<string, string>,
587595
): {
@@ -591,7 +599,7 @@ export function normalizeLlmSettings(
591599
modelName: string;
592600
} {
593601
return {
594-
provider: settings?.provider ?? "openai-compatible",
602+
provider: normalizeLlmProvider(settings?.provider),
595603
baseUrl: settings?.baseUrl ?? settings?.base_url ?? "",
596604
apiKey: settings?.apiKey ?? settings?.api_key ?? "",
597605
modelName:
@@ -836,7 +844,7 @@ export const WORKSPACE_CONFIG_FIELDS: Record<
836844
inputType: "select",
837845
options: [...LLM_PROVIDER_OPTIONS],
838846
helpText:
839-
"对应服务端 LLM_PROVIDER。openai-compatible / bailian 使用 OpenAI 兼容 /chat/completions;其他值走 Mastra model router(provider/model)。",
847+
"对应服务端 LLM_PROVIDER。所有 chat 模型都通过 OpenAI 兼容 /chat/completions 调用。",
840848
required: true,
841849
readOnly: (item) => !!item.builtin,
842850
fullWidth: true,

apps/web/src/app/data-tasks/__tests__/config-api-adapter.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
itemToCreateBody,
55
itemToPatchBody,
66
mcpServerDtoToItem,
7+
modelProfileDtoToItem,
78
workspaceConfigDtoToStore,
89
} from "../../../lib/config-api/adapter";
910
import {
@@ -162,6 +163,33 @@ describe("config api adapter", () => {
162163
expect(body.reasoningModel).toBe(true);
163164
});
164165

166+
it("normalizes legacy llm providers to openai-compatible", () => {
167+
const item = modelProfileDtoToItem({
168+
id: "deepseek",
169+
name: "DeepSeek",
170+
provider: "deepseek",
171+
modelName: "deepseek-chat",
172+
});
173+
const createBody = itemToCreateBody("llm", {
174+
id: "qwen",
175+
name: "Qwen",
176+
description: "",
177+
enabled: true,
178+
settings: { provider: "openai_compatible", modelName: "qwen-plus" },
179+
});
180+
const patchBody = itemToPatchBody("llm", {
181+
id: "qwen",
182+
name: "Qwen",
183+
description: "",
184+
enabled: true,
185+
settings: { provider: "bailian" },
186+
});
187+
188+
expect(item.settings?.provider).toBe("openai-compatible");
189+
expect(createBody.provider).toBe("openai-compatible");
190+
expect(patchBody.provider).toBe("openai-compatible");
191+
});
192+
165193
it("maps workspace config dto to store buckets", () => {
166194
const store = workspaceConfigDtoToStore({
167195
datasources: [],

apps/web/src/app/data-tasks/__tests__/dashscope-prompt-compat.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
describe("dashscope prompt compat", () => {
99
it("enables compat for openai-compatible providers", () => {
1010
expect(shouldApplyDashScopePromptCompat("openai-compatible")).toBe(true);
11-
expect(shouldApplyDashScopePromptCompat("mastra-router")).toBe(false);
11+
expect(shouldApplyDashScopePromptCompat("unsupported-provider")).toBe(false);
1212
});
1313

1414
it("adds placeholder text to assistant messages that only contain tool calls", () => {

apps/web/src/app/data-tasks/data-task-state.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,16 +1058,24 @@ export const MCP_AUTH_TYPE_OPTIONS = [
10581058
{ value: "custom-header", label: "Custom header (pending backend)" },
10591059
] as const;
10601060

1061-
/** Aligns with dataFoundry `LLM_PROVIDER` env and Mastra router provider ids. */
1061+
/** Chat models use one OpenAI-compatible provider path; vendor choice lives in baseUrl/modelName. */
10621062
export const LLM_PROVIDER_OPTIONS = [
10631063
{ value: "openai-compatible", label: "OpenAI compatible (LLM_PROVIDER=openai-compatible)" },
1064-
{ value: "bailian", label: "Bailian DashScope (bailian)" },
1065-
{ value: "deepseek", label: "DeepSeek (deepseek)" },
1066-
{ value: "openai", label: "OpenAI (openai)" },
1067-
{ value: "anthropic", label: "Anthropic (anthropic)" },
1068-
{ value: "google", label: "Google Gemini (google)" },
10691064
] as const;
10701065

1066+
function normalizeLlmProvider(provider?: string): string {
1067+
const normalized = provider?.trim().toLowerCase().replaceAll("_", "-") ?? "";
1068+
if (
1069+
normalized === "bailian"
1070+
|| normalized === "deepseek"
1071+
|| normalized === "openai"
1072+
|| normalized === "openai-compatible"
1073+
) {
1074+
return "openai-compatible";
1075+
}
1076+
return normalized || "openai-compatible";
1077+
}
1078+
10711079
export function normalizeLlmSettings(
10721080
settings?: Record<string, string>,
10731081
): {
@@ -1077,7 +1085,7 @@ export function normalizeLlmSettings(
10771085
modelName: string;
10781086
} {
10791087
return {
1080-
provider: settings?.provider ?? "openai-compatible",
1088+
provider: normalizeLlmProvider(settings?.provider),
10811089
baseUrl: settings?.baseUrl ?? settings?.base_url ?? "",
10821090
apiKey: settings?.apiKey ?? settings?.api_key ?? "",
10831091
modelName:
@@ -1668,7 +1676,7 @@ export const WORKSPACE_CONFIG_FIELDS: Record<
16681676
inputType: "select",
16691677
options: [...LLM_PROVIDER_OPTIONS],
16701678
helpText:
1671-
"openai-compatible / bailian use the OpenAI-compatible path. anthropic/google await integration validation.",
1679+
"All chat models use the OpenAI-compatible /chat/completions path.",
16721680
required: true,
16731681
fullWidth: true,
16741682
},

apps/web/src/lib/config-api/adapter.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ function pickString(record: Record<string, unknown>, ...keys: string[]): string
2727
return "";
2828
}
2929

30+
function normalizeLlmProvider(provider?: string): string {
31+
const normalized = provider?.trim().toLowerCase().replaceAll("_", "-") ?? "";
32+
if (
33+
normalized === "bailian"
34+
|| normalized === "deepseek"
35+
|| normalized === "openai"
36+
|| normalized === "openai-compatible"
37+
) {
38+
return "openai-compatible";
39+
}
40+
return normalized || "openai-compatible";
41+
}
42+
3043
function pickBooleanString(record: Record<string, unknown>, key: string): string {
3144
const value = record[key];
3245
if (typeof value === "boolean") return value ? "true" : "false";
@@ -194,7 +207,7 @@ export function modelProfileDtoToItem(dto: ModelProfileDto): WorkspaceConfigItem
194207
revision: dto.revision,
195208
status: mapConnectionStatus(dto.connectionStatus),
196209
settings: {
197-
provider: dto.provider ?? "openai-compatible",
210+
provider: normalizeLlmProvider(dto.provider),
198211
baseUrl: dto.baseUrl ?? "",
199212
modelName: dto.modelName ?? "",
200213
apiKey: "",
@@ -468,7 +481,7 @@ export function itemToCreateBody(
468481
]);
469482
return {
470483
...base,
471-
provider: settings.provider ?? "openai-compatible",
484+
provider: normalizeLlmProvider(settings.provider),
472485
modelName: settings.modelName?.trim() ?? "",
473486
baseUrl: settings.baseUrl?.trim() ?? "",
474487
...(parseNumber(settings.timeoutMs) !== undefined
@@ -646,7 +659,7 @@ export function itemToPatchBody(
646659
appendMcpStdioFields(body, settings);
647660
break;
648661
case "llm":
649-
if (settings.provider?.trim()) body.provider = settings.provider.trim();
662+
body.provider = normalizeLlmProvider(settings.provider);
650663
if (settings.modelName?.trim()) body.modelName = settings.modelName.trim();
651664
if (settings.baseUrl?.trim()) body.baseUrl = settings.baseUrl.trim();
652665
if (settings.fallbackProfileId?.trim()) {

packages/contracts/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,12 @@ export type EnvConfig = {
307307
export const ENV_VARIABLE_SPECS: EnvVariableSpec[] = [
308308
{ name: "API_HOST", required: false, default_value: "127.0.0.1", description: "Agent runtime bind host." },
309309
{ name: "API_PORT", required: false, default_value: "8787", description: "Agent runtime bind port." },
310-
{ name: "LLM_PROVIDER", required: false, default_value: "bailian", description: "Chat model provider." },
310+
{
311+
name: "LLM_PROVIDER",
312+
required: false,
313+
default_value: "openai-compatible",
314+
description: "Chat model provider. Only OpenAI-compatible chat completions are supported."
315+
},
311316
{ name: "LLM_MODEL", required: false, default_value: "qwen-plus", description: "Chat model name." },
312317
{ name: "LLM_BASE_URL", required: true, description: "OpenAI-compatible chat completions base URL." },
313318
{
@@ -348,7 +353,7 @@ export const createEnvConfig = (env: Record<string, string | undefined>): EnvCon
348353
port: Number.parseInt(env.API_PORT ?? "8787", 10)
349354
},
350355
llm: {
351-
provider: env.LLM_PROVIDER ?? "bailian",
356+
provider: env.LLM_PROVIDER ?? "openai-compatible",
352357
model: env.LLM_MODEL ?? "qwen-plus",
353358
base_url: env.LLM_BASE_URL ?? "https://dashscope.aliyuncs.com/compatible-mode/v1",
354359
...(env.LLM_API_KEY ? { api_key: env.LLM_API_KEY } : {})

packages/providers/src/index.ts

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ export type EmbeddingProviderConfig = {
1818
};
1919

2020
export type ModelProvider =
21-
| {
22-
kind: "mastra-router";
23-
model_name: string;
24-
model: unknown;
25-
}
2621
| {
2722
kind: "openai-compatible";
2823
model_name: string;
@@ -45,7 +40,10 @@ export const createModelProvider = (env: Record<string, string | undefined>): Mo
4540

4641
/** Create one model provider from a persisted model-profile configuration. */
4742
export const createModelProviderFromConfig = (config: ChatProviderConfig): ModelProvider => {
48-
const providerName = config.provider.toLowerCase();
43+
const providerName = normalizeChatProviderName(config.provider);
44+
if (!providerName) {
45+
throw new Error(`PROVIDER_UNSUPPORTED:${config.provider}`);
46+
}
4947

5048
if (!config.api_key) {
5149
return {
@@ -54,20 +52,6 @@ export const createModelProviderFromConfig = (config: ChatProviderConfig): Model
5452
};
5553
}
5654

57-
if (!isOpenAiCompatibleProvider(providerName)) {
58-
const modelId = normalizeMastraRouterModelId(providerName, config.model);
59-
60-
return {
61-
kind: "mastra-router",
62-
model_name: modelId,
63-
model: {
64-
id: modelId,
65-
url: config.base_url,
66-
apiKey: config.api_key
67-
}
68-
};
69-
}
70-
7155
const provider = createOpenAI({
7256
apiKey: config.api_key,
7357
baseURL: config.base_url
@@ -80,8 +64,16 @@ export const createModelProviderFromConfig = (config: ChatProviderConfig): Model
8064
};
8165
};
8266

83-
const normalizeMastraRouterModelId = (provider: string, model: string): string =>
84-
model.includes("/") ? model : `${provider}/${model}`;
67+
const normalizeChatProviderName = (provider: string): "openai-compatible" | undefined => {
68+
const normalized = provider.trim().toLowerCase().replaceAll("_", "-");
69+
if (
70+
normalized === "openai-compatible"
71+
|| normalized === "bailian"
72+
|| normalized === "deepseek"
73+
|| normalized === "openai"
74+
) {
75+
return "openai-compatible";
76+
}
8577

86-
const isOpenAiCompatibleProvider = (provider: string): boolean =>
87-
provider === "openai-compatible" || provider === "openai_compatible" || provider === "bailian";
78+
return undefined;
79+
};

scripts/smoke-context-compilation.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ const configuredAgent = await createDataFoundry({
10711071
dataGateway: {},
10721072
emitter: { emit: () => undefined },
10731073
modelProvider: {
1074-
kind: "mastra-router",
1074+
kind: "openai-compatible",
10751075
model_name: "context-smoke/model",
10761076
model: { id: "context-smoke/model", url: "http://127.0.0.1:1", apiKey: "unused" }
10771077
},

scripts/smoke-long-term-memory.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ try {
133133
longTermMemory: { records: memories },
134134
messages: [{ id: "agent-user", role: "user", content: "继续分析 GMV 和退款率" }],
135135
modelProvider: {
136-
kind: "mastra-router",
136+
kind: "openai-compatible",
137137
model_name: "long-term-memory-smoke/model",
138138
model: { id: "long-term-memory-smoke/model", url: "http://127.0.0.1:1", apiKey: "unused" }
139139
},

0 commit comments

Comments
 (0)