mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-01 17:10:24 +08:00
feat: add AIHubMix provider (#865)
* feat: add AIHubMix provider * feat: load AIHubMix models dynamically * feat: polish AIHubMix model setup * feat: send AIHubMix app code * docs: remove redundant AIHubMix recommendation --------- Co-authored-by: LL <13697272357@163.com>
This commit is contained in:
@@ -1,10 +1,36 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
||||
import {
|
||||
getAIModel,
|
||||
isAihubmixStandardBaseURL,
|
||||
resolveBaseURL,
|
||||
supportsImageInput,
|
||||
supportsPromptCaching,
|
||||
} from "@/lib/ai-providers"
|
||||
import { extractAihubmixModelIds } from "@/lib/aihubmix-models"
|
||||
|
||||
describe("extractAihubmixModelIds", () => {
|
||||
it("extracts unique chat model IDs from the AIHubMix model list payload", () => {
|
||||
const models = extractAihubmixModelIds({
|
||||
data: [
|
||||
{ model_id: "claude-sonnet-4-5-20250929", types: "llm" },
|
||||
{ model_id: "gpt-5.1", types: "llm" },
|
||||
{ model_id: "gpt-5.1", types: "llm" },
|
||||
{ model_id: "gpt-image-2", types: "image_generation,llm" },
|
||||
{ model_id: "cohere-rerank-v4.0", types: "rerank" },
|
||||
{ model_id: "", types: "llm" },
|
||||
{ types: "llm" },
|
||||
],
|
||||
})
|
||||
|
||||
expect(models).toEqual(["claude-sonnet-4-5-20250929", "gpt-5.1"])
|
||||
})
|
||||
|
||||
it("returns an empty list for malformed payloads", () => {
|
||||
expect(extractAihubmixModelIds({ data: null })).toEqual([])
|
||||
expect(extractAihubmixModelIds({})).toEqual([])
|
||||
expect(extractAihubmixModelIds(null)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("resolveBaseURL", () => {
|
||||
const SERVER_BASE_URL = "https://server-proxy.example.com"
|
||||
@@ -256,6 +282,70 @@ vi.mock("@ai-sdk/deepseek", () => {
|
||||
return { createDeepSeek: mockCreateDeepSeek, deepseek: mockDeepseek }
|
||||
})
|
||||
|
||||
vi.mock("@aihubmix/ai-sdk-provider", () => {
|
||||
const mockModel = { modelId: "test-model" }
|
||||
const mockProviderFn = vi.fn(() => mockModel)
|
||||
const mockCreateAihubmix = vi.fn(() => mockProviderFn)
|
||||
const mockAihubmix = vi.fn(() => mockModel)
|
||||
return { aihubmix: mockAihubmix, createAihubmix: mockCreateAihubmix }
|
||||
})
|
||||
|
||||
describe("AIHubMix provider", () => {
|
||||
let createAihubmixMock: ReturnType<typeof vi.fn>
|
||||
const savedEnv: Record<string, string | undefined> = {}
|
||||
|
||||
beforeEach(async () => {
|
||||
savedEnv.AIHUBMIX_API_KEY = process.env.AIHUBMIX_API_KEY
|
||||
savedEnv.AIHUBMIX_BASE_URL = process.env.AIHUBMIX_BASE_URL
|
||||
delete process.env.AIHUBMIX_BASE_URL
|
||||
|
||||
const mod = await import("@aihubmix/ai-sdk-provider")
|
||||
createAihubmixMock = mod.createAihubmix as ReturnType<typeof vi.fn>
|
||||
createAihubmixMock.mockClear()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.env.AIHUBMIX_API_KEY = savedEnv.AIHUBMIX_API_KEY
|
||||
process.env.AIHUBMIX_BASE_URL = savedEnv.AIHUBMIX_BASE_URL
|
||||
})
|
||||
|
||||
it("uses AIHUBMIX_API_KEY for server configured AIHubMix", () => {
|
||||
process.env.AIHUBMIX_API_KEY = "server-aihubmix-key"
|
||||
|
||||
getAIModel({
|
||||
provider: "aihubmix",
|
||||
modelId: "claude-sonnet-4-5-20250929",
|
||||
})
|
||||
|
||||
expect(createAihubmixMock).toHaveBeenCalledWith({
|
||||
apiKey: "server-aihubmix-key",
|
||||
appCode: "MSBS9675",
|
||||
})
|
||||
})
|
||||
|
||||
it("uses client BYOK API key for AIHubMix", () => {
|
||||
getAIModel({
|
||||
provider: "aihubmix",
|
||||
apiKey: "client-aihubmix-key",
|
||||
modelId: "gpt-5.1",
|
||||
})
|
||||
|
||||
expect(createAihubmixMock).toHaveBeenCalledWith({
|
||||
apiKey: "client-aihubmix-key",
|
||||
appCode: "MSBS9675",
|
||||
})
|
||||
})
|
||||
|
||||
it("recognizes AIHubMix standard endpoints", () => {
|
||||
expect(isAihubmixStandardBaseURL(undefined)).toBe(true)
|
||||
expect(isAihubmixStandardBaseURL("https://aihubmix.com")).toBe(true)
|
||||
expect(isAihubmixStandardBaseURL("https://aihubmix.com/v1/")).toBe(true)
|
||||
expect(isAihubmixStandardBaseURL("https://proxy.example.com/v1")).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Kimi provider uses createDeepSeek for reasoning_content support", () => {
|
||||
let createDeepSeekMock: ReturnType<typeof vi.fn>
|
||||
const savedEnv: Record<string, string | undefined> = {}
|
||||
|
||||
Reference in New Issue
Block a user