Browse Source

Use routable Doubao LLM model ids

The LLM selector exposed display-style Doubao model names that the NewApiWG test gateway cannot route. The UI now stores the gateway model ids returned by /models, while the API route maps legacy saved selector values to those ids so existing workflows do not keep failing.

Constraint: Preserve GPT-4.1 Mini as the NewApiWG default and keep old workflow JSON compatible.

Rejected: Remove Doubao from the LLM selector | the gateway exposes working Doubao chat model ids, so the issue is stale ids rather than product support.

Confidence: high

Scope-risk: narrow

Directive: LLM selector values must be callable provider ids; use labels only for display text.

Tested: Live NewApiWG chat completion with doubao-seed-2-0-lite-260428 and doubao-seed-2-0-pro-260215.

Tested: npm run test:run -- src/lib/__tests__/llmModels.test.ts src/app/api/llm/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/store/utils/__tests__/nodeDefaults.test.ts

Tested: npm run build

Tested: git diff --check
feature/canvas-chatbot-copilot
jiajia 2 months ago
parent
commit
c2bf435d19
  1. 82
      src/app/api/llm/__tests__/route.test.ts
  2. 8
      src/app/api/llm/route.ts
  3. 2
      src/components/__tests__/LLMGenerateNode.test.tsx
  4. 8
      src/lib/__tests__/llmModels.test.ts
  5. 2
      src/lib/chat/tools.ts
  6. 4
      src/lib/llmModels.ts
  7. 2
      src/types/providers.ts

82
src/app/api/llm/__tests__/route.test.ts

@ -313,6 +313,88 @@ describe("/api/llm route", () => {
}); });
}); });
describe("NewApiWG provider", () => {
beforeEach(() => {
global.fetch = mockFetch;
});
it("should use current Doubao Seed model ids for NewApiWG", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: () =>
Promise.resolve({
choices: [{ message: { content: "Doubao response text" } }],
}),
});
const request = createMockPostRequest(
{
prompt: "Test prompt",
provider: "newapiwg",
model: "doubao-seed-2-0-lite-260428",
temperature: 0.7,
maxTokens: 1024,
},
{
"X-NewApiWG-Key": "test-newapiwg-key",
"X-NewApiWG-Base-URL": "https://newapi.example/v1",
}
);
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(200);
expect(data.success).toBe(true);
expect(data.text).toBe("Doubao response text");
expect(mockFetch).toHaveBeenCalledWith(
"https://newapi.example/v1/chat/completions",
expect.objectContaining({
body: JSON.stringify({
model: "doubao-seed-2-0-lite-260428",
messages: [{ role: "user", content: "Test prompt" }],
temperature: 0.7,
max_tokens: 1024,
}),
})
);
});
it("should map legacy Doubao selector values to available gateway model ids", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: () =>
Promise.resolve({
choices: [{ message: { content: "Legacy Doubao response text" } }],
}),
});
const request = createMockPostRequest(
{
prompt: "Test prompt",
provider: "newapiwg",
model: "Doubao-Seed-2.0-lite",
},
{
"X-NewApiWG-Key": "test-newapiwg-key",
"X-NewApiWG-Base-URL": "https://newapi.example/v1",
}
);
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(200);
expect(data.success).toBe(true);
expect(mockFetch).toHaveBeenCalledWith(
"https://newapi.example/v1/chat/completions",
expect.objectContaining({
body: expect.stringContaining('"model":"doubao-seed-2-0-lite-260428"'),
})
);
});
});
describe("OpenAI provider", () => { describe("OpenAI provider", () => {
beforeEach(() => { beforeEach(() => {
global.fetch = mockFetch; global.fetch = mockFetch;

8
src/app/api/llm/route.ts

@ -30,6 +30,11 @@ const ANTHROPIC_MODEL_MAP: Record<string, string> = {
"claude-opus-4.6": "claude-opus-4-6", "claude-opus-4.6": "claude-opus-4-6",
}; };
const NEWAPIWG_LLM_MODEL_ALIASES: Record<string, string> = {
"Doubao-Seed-2.0-lite": "doubao-seed-2-0-lite-260428",
"Doubao-Seed-2.0-pro": "doubao-seed-2-0-pro-260215",
};
type GoogleContentPart = type GoogleContentPart =
| { inlineData: { mimeType: string; data: string } } | { inlineData: { mimeType: string; data: string } }
| { fileData: { mimeType: string; fileUri: string } } | { fileData: { mimeType: string; fileUri: string } }
@ -246,6 +251,7 @@ async function generateWithNewApiWG(
} }
const content = buildChatContent(prompt, images, videos); const content = buildChatContent(prompt, images, videos);
const modelId = NEWAPIWG_LLM_MODEL_ALIASES[model] ?? model;
const startTime = Date.now(); const startTime = Date.now();
const response = await fetch(`${normalizeNewApiWGBaseUrl(userBaseUrl)}/chat/completions`, { const response = await fetch(`${normalizeNewApiWGBaseUrl(userBaseUrl)}/chat/completions`, {
@ -255,7 +261,7 @@ async function generateWithNewApiWG(
"Authorization": `Bearer ${apiKey}`, "Authorization": `Bearer ${apiKey}`,
}, },
body: JSON.stringify({ body: JSON.stringify({
model, model: modelId,
messages: [{ role: "user", content }], messages: [{ role: "user", content }],
temperature, temperature,
max_tokens: maxTokens, max_tokens: maxTokens,

2
src/components/__tests__/LLMGenerateNode.test.tsx

@ -54,7 +54,7 @@ describe("LLMGenerateNode", () => {
inputVideos: [], inputVideos: [],
outputText: null, outputText: null,
provider: "newapiwg", provider: "newapiwg",
model: "Doubao-Seed-2.0-lite", model: "doubao-seed-2-0-lite-260428",
temperature: 1.0, temperature: 1.0,
maxTokens: 2048, maxTokens: 2048,
status: "idle", status: "idle",

8
src/lib/__tests__/llmModels.test.ts

@ -12,12 +12,12 @@ describe("LLM model options", () => {
label: "GPT-4.1 Mini", label: "GPT-4.1 Mini",
}); });
expect(LLM_MODELS.newapiwg).toContainEqual({ expect(LLM_MODELS.newapiwg).toContainEqual({
value: "Doubao-Seed-2.0-lite", value: "doubao-seed-2-0-lite-260428",
label: "Doubao-Seed-2.0-lite", label: "Doubao Seed 2.0 Lite",
}); });
expect(LLM_MODELS.newapiwg).toContainEqual({ expect(LLM_MODELS.newapiwg).toContainEqual({
value: "Doubao-Seed-2.0-pro", value: "doubao-seed-2-0-pro-260215",
label: "Doubao-Seed-2.0-pro", label: "Doubao Seed 2.0 Pro",
}); });
}); });
}); });

2
src/lib/chat/tools.ts

@ -59,7 +59,7 @@ AI video generation. Takes image + text inputs, outputs video. Only available wi
### LLM Text Generation ### LLM Text Generation
AI text generation for expanding prompts or analyzing images. AI text generation for expanding prompts or analyzing images.
- **Provider dropdown**: NewApiWG, Google, OpenAI, or Anthropic - **Provider dropdown**: NewApiWG, Google, OpenAI, or Anthropic
- **Model dropdown**: GPT-4.1 Mini (NewApiWG default), Doubao-Seed-2.0-lite/pro (NewApiWG options) / Gemini 3 Flash, Gemini 2.5 Flash, Gemini 3.0 Pro (Google) / GPT-4.1 Mini, GPT-4.1 Nano (OpenAI) - **Model dropdown**: GPT-4.1 Mini (NewApiWG default), Doubao Seed 2.0 Lite/Pro (NewApiWG options) / Gemini 3 Flash, Gemini 2.5 Flash, Gemini 3.0 Pro (Google) / GPT-4.1 Mini, GPT-4.1 Nano (OpenAI)
- **Parameters** (collapsible): Temperature slider (0-2), Max Tokens slider (256-16384) - **Parameters** (collapsible): Temperature slider (0-2), Max Tokens slider (256-16384)
- Takes **text** input (required), optional **image** input - Takes **text** input (required), optional **image** input

4
src/lib/llmModels.ts

@ -17,8 +17,8 @@ export const LLM_PROVIDERS: { value: LLMProvider; label: string }[] = [
export const LLM_MODELS: Record<LLMProvider, LLMModelOption[]> = { export const LLM_MODELS: Record<LLMProvider, LLMModelOption[]> = {
newapiwg: [ newapiwg: [
{ value: "gpt-4.1-mini", label: "GPT-4.1 Mini" }, { value: "gpt-4.1-mini", label: "GPT-4.1 Mini" },
{ value: "Doubao-Seed-2.0-lite", label: "Doubao-Seed-2.0-lite" }, { value: "doubao-seed-2-0-lite-260428", label: "Doubao Seed 2.0 Lite" },
{ value: "Doubao-Seed-2.0-pro", label: "Doubao-Seed-2.0-pro" }, { value: "doubao-seed-2-0-pro-260215", label: "Doubao Seed 2.0 Pro" },
], ],
google: [ google: [
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash" }, { value: "gemini-3-flash-preview", label: "Gemini 3 Flash" },

2
src/types/providers.ts

@ -47,6 +47,8 @@ export type LLMModelType =
| "gemini-3-flash-preview" | "gemini-3-flash-preview"
| "gemini-3-pro-preview" | "gemini-3-pro-preview"
| "gemini-3.1-pro-preview" | "gemini-3.1-pro-preview"
| "doubao-seed-2-0-lite-260428"
| "doubao-seed-2-0-pro-260215"
| "Doubao-Seed-2.0-lite" | "Doubao-Seed-2.0-lite"
| "Doubao-Seed-2.0-pro" | "Doubao-Seed-2.0-pro"
| "gpt-4.1-mini" | "gpt-4.1-mini"

Loading…
Cancel
Save