mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-03 01:50:23 +08:00
Compare commits
1 Commits
fix/electr
...
fix/biome-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7d104671a |
@@ -10,7 +10,6 @@ import {
|
|||||||
ResizablePanelGroup,
|
ResizablePanelGroup,
|
||||||
} from "@/components/ui/resizable"
|
} from "@/components/ui/resizable"
|
||||||
import { useDiagram } from "@/contexts/diagram-context"
|
import { useDiagram } from "@/contexts/diagram-context"
|
||||||
import { type DrawioTheme, isDrawioTheme } from "@/lib/drawio-themes"
|
|
||||||
import { i18n, type Locale } from "@/lib/i18n/config"
|
import { i18n, type Locale } from "@/lib/i18n/config"
|
||||||
import { isIndexedDBUsable } from "@/lib/session-storage"
|
import { isIndexedDBUsable } from "@/lib/session-storage"
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ export default function Home() {
|
|||||||
const currentLang = (pathname.split("/")[1] || i18n.defaultLocale) as Locale
|
const currentLang = (pathname.split("/")[1] || i18n.defaultLocale) as Locale
|
||||||
const [isMobile, setIsMobile] = useState(false)
|
const [isMobile, setIsMobile] = useState(false)
|
||||||
const [isChatVisible, setIsChatVisible] = useState(true)
|
const [isChatVisible, setIsChatVisible] = useState(true)
|
||||||
const [drawioUi, setDrawioUi] = useState<DrawioTheme>("kennedy")
|
const [drawioUi, setDrawioUi] = useState<"min" | "sketch">("min")
|
||||||
const [darkMode, setDarkMode] = useState(false)
|
const [darkMode, setDarkMode] = useState(false)
|
||||||
const [isLoaded, setIsLoaded] = useState(false)
|
const [isLoaded, setIsLoaded] = useState(false)
|
||||||
const [isDrawioReady, setIsDrawioReady] = useState(false)
|
const [isDrawioReady, setIsDrawioReady] = useState(false)
|
||||||
@@ -57,7 +56,7 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const savedUi = localStorage.getItem("drawio-theme")
|
const savedUi = localStorage.getItem("drawio-theme")
|
||||||
if (isDrawioTheme(savedUi)) {
|
if (savedUi === "min" || savedUi === "sketch") {
|
||||||
setDrawioUi(savedUi)
|
setDrawioUi(savedUi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,9 +113,10 @@ export default function Home() {
|
|||||||
resetDrawioReady()
|
resetDrawioReady()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDrawioUiChange = (theme: DrawioTheme) => {
|
const handleDrawioUiChange = () => {
|
||||||
localStorage.setItem("drawio-theme", theme)
|
const newUi = drawioUi === "min" ? "sketch" : "min"
|
||||||
setDrawioUi(theme)
|
localStorage.setItem("drawio-theme", newUi)
|
||||||
|
setDrawioUi(newUi)
|
||||||
setIsDrawioReady(false)
|
setIsDrawioReady(false)
|
||||||
resetDrawioReady()
|
resetDrawioReady()
|
||||||
}
|
}
|
||||||
@@ -216,8 +216,7 @@ export default function Home() {
|
|||||||
saveAndExit: false,
|
saveAndExit: false,
|
||||||
noSaveBtn: true,
|
noSaveBtn: true,
|
||||||
noExitBtn: true,
|
noExitBtn: true,
|
||||||
dark:
|
dark: darkMode,
|
||||||
darkMode || drawioUi === "dark",
|
|
||||||
lang: currentLang,
|
lang: currentLang,
|
||||||
// Enable offline mode in Electron to disable external service calls
|
// Enable offline mode in Electron to disable external service calls
|
||||||
...(isElectron && {
|
...(isElectron && {
|
||||||
@@ -265,7 +264,7 @@ export default function Home() {
|
|||||||
isVisible={isChatVisible}
|
isVisible={isChatVisible}
|
||||||
onToggleVisibility={toggleChatPanel}
|
onToggleVisibility={toggleChatPanel}
|
||||||
drawioUi={drawioUi}
|
drawioUi={drawioUi}
|
||||||
onDrawioUiChange={handleDrawioUiChange}
|
onToggleDrawioUi={handleDrawioUiChange}
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
onToggleDarkMode={handleDarkModeChange}
|
onToggleDarkMode={handleDarkModeChange}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import { useSessionManager } from "@/hooks/use-session-manager"
|
|||||||
import { useValidateDiagram } from "@/hooks/use-validate-diagram"
|
import { useValidateDiagram } from "@/hooks/use-validate-diagram"
|
||||||
import { getApiEndpoint } from "@/lib/base-path"
|
import { getApiEndpoint } from "@/lib/base-path"
|
||||||
import { findCachedResponse } from "@/lib/cached-responses"
|
import { findCachedResponse } from "@/lib/cached-responses"
|
||||||
import type { DrawioTheme } from "@/lib/drawio-themes"
|
|
||||||
import { formatMessage } from "@/lib/i18n/utils"
|
import { formatMessage } from "@/lib/i18n/utils"
|
||||||
import { isPdfFile, isTextFile } from "@/lib/pdf-utils"
|
import { isPdfFile, isTextFile } from "@/lib/pdf-utils"
|
||||||
import { sanitizeMessages } from "@/lib/session-storage"
|
import { sanitizeMessages } from "@/lib/session-storage"
|
||||||
@@ -69,8 +68,8 @@ interface ChatMessage {
|
|||||||
interface ChatPanelProps {
|
interface ChatPanelProps {
|
||||||
isVisible: boolean
|
isVisible: boolean
|
||||||
onToggleVisibility: () => void
|
onToggleVisibility: () => void
|
||||||
drawioUi: DrawioTheme
|
drawioUi: "min" | "sketch"
|
||||||
onDrawioUiChange: (theme: DrawioTheme) => void
|
onToggleDrawioUi: () => void
|
||||||
darkMode: boolean
|
darkMode: boolean
|
||||||
onToggleDarkMode: () => void
|
onToggleDarkMode: () => void
|
||||||
isMobile?: boolean
|
isMobile?: boolean
|
||||||
@@ -111,7 +110,7 @@ export default function ChatPanel({
|
|||||||
isVisible,
|
isVisible,
|
||||||
onToggleVisibility,
|
onToggleVisibility,
|
||||||
drawioUi,
|
drawioUi,
|
||||||
onDrawioUiChange,
|
onToggleDrawioUi,
|
||||||
darkMode,
|
darkMode,
|
||||||
onToggleDarkMode,
|
onToggleDarkMode,
|
||||||
isMobile = false,
|
isMobile = false,
|
||||||
@@ -1443,7 +1442,7 @@ export default function ChatPanel({
|
|||||||
open={showSettingsDialog}
|
open={showSettingsDialog}
|
||||||
onOpenChange={setShowSettingsDialog}
|
onOpenChange={setShowSettingsDialog}
|
||||||
drawioUi={drawioUi}
|
drawioUi={drawioUi}
|
||||||
onDrawioUiChange={onDrawioUiChange}
|
onToggleDrawioUi={onToggleDrawioUi}
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
onToggleDarkMode={onToggleDarkMode}
|
onToggleDarkMode={onToggleDarkMode}
|
||||||
minimalStyle={minimalStyle}
|
minimalStyle={minimalStyle}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import { Switch } from "@/components/ui/switch"
|
|||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { useDictionary } from "@/hooks/use-dictionary"
|
import { useDictionary } from "@/hooks/use-dictionary"
|
||||||
import { getApiEndpoint } from "@/lib/base-path"
|
import { getApiEndpoint } from "@/lib/base-path"
|
||||||
import type { DrawioTheme } from "@/lib/drawio-themes"
|
|
||||||
import { i18n, type Locale } from "@/lib/i18n/config"
|
import { i18n, type Locale } from "@/lib/i18n/config"
|
||||||
import { STORAGE_KEYS } from "@/lib/storage"
|
import { STORAGE_KEYS } from "@/lib/storage"
|
||||||
|
|
||||||
@@ -64,8 +63,8 @@ const LANGUAGE_LABELS: Record<Locale, string> = {
|
|||||||
interface SettingsDialogProps {
|
interface SettingsDialogProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
onOpenChange: (open: boolean) => void
|
onOpenChange: (open: boolean) => void
|
||||||
drawioUi: DrawioTheme
|
drawioUi: "min" | "sketch"
|
||||||
onDrawioUiChange: (theme: DrawioTheme) => void
|
onToggleDrawioUi: () => void
|
||||||
darkMode: boolean
|
darkMode: boolean
|
||||||
onToggleDarkMode: () => void
|
onToggleDarkMode: () => void
|
||||||
minimalStyle?: boolean
|
minimalStyle?: boolean
|
||||||
@@ -91,7 +90,7 @@ function SettingsContent({
|
|||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
drawioUi,
|
drawioUi,
|
||||||
onDrawioUiChange,
|
onToggleDrawioUi,
|
||||||
darkMode,
|
darkMode,
|
||||||
onToggleDarkMode,
|
onToggleDarkMode,
|
||||||
minimalStyle = false,
|
minimalStyle = false,
|
||||||
@@ -135,11 +134,8 @@ function SettingsContent({
|
|||||||
const [isApplyingProxy, setIsApplyingProxy] = useState(false)
|
const [isApplyingProxy, setIsApplyingProxy] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Re-fetch config whenever the dialog opens to ensure we always show
|
// Only fetch if not cached in localStorage
|
||||||
// the access code input if the server requires it. This fixes the case
|
if (getStoredAccessCodeRequired() !== null) return
|
||||||
// where a stale localStorage cache (from before ACCESS_CODE_LIST was
|
|
||||||
// configured) would hide the access code input.
|
|
||||||
if (!open) return
|
|
||||||
|
|
||||||
fetch(getApiEndpoint("/api/config"))
|
fetch(getApiEndpoint("/api/config"))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
@@ -155,9 +151,10 @@ function SettingsContent({
|
|||||||
setAccessCodeRequired(required)
|
setAccessCodeRequired(required)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
// Keep existing cached value on error
|
// Don't cache on error - allow retry on next mount
|
||||||
|
setAccessCodeRequired(false)
|
||||||
})
|
})
|
||||||
}, [open])
|
}, [])
|
||||||
|
|
||||||
// Detect current language from pathname
|
// Detect current language from pathname
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -433,40 +430,23 @@ function SettingsContent({
|
|||||||
{/* Draw.io Style */}
|
{/* Draw.io Style */}
|
||||||
<SettingItem
|
<SettingItem
|
||||||
label={dict.settings.drawioStyle}
|
label={dict.settings.drawioStyle}
|
||||||
description={dict.settings.drawioStyleDescription}
|
description={`${dict.settings.drawioStyleDescription} ${
|
||||||
|
drawioUi === "min"
|
||||||
|
? dict.settings.minimal
|
||||||
|
: dict.settings.sketch
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<Select
|
<Button
|
||||||
value={drawioUi}
|
id="drawio-ui"
|
||||||
onValueChange={(v) =>
|
variant="outline"
|
||||||
onDrawioUiChange(v as DrawioTheme)
|
onClick={onToggleDrawioUi}
|
||||||
}
|
className="h-9 w-[120px] rounded-xl border-border-subtle hover:bg-interactive-hover font-normal"
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
{dict.settings.switchTo}{" "}
|
||||||
id="drawio-ui-select"
|
{drawioUi === "min"
|
||||||
aria-label={dict.settings.drawioStyle}
|
? dict.settings.sketch
|
||||||
className="w-[120px] h-9 rounded-xl"
|
: dict.settings.minimal}
|
||||||
>
|
</Button>
|
||||||
<SelectValue />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="kennedy">
|
|
||||||
{dict.settings.themeDefault}
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="atlas">Atlas</SelectItem>
|
|
||||||
<SelectItem value="dark">
|
|
||||||
{dict.settings.themeDark}
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="min">
|
|
||||||
{dict.settings.themeMinimal}
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="sketch">
|
|
||||||
{dict.settings.themeSketch}
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="simple">
|
|
||||||
{dict.settings.themeSimple}
|
|
||||||
</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
{/* Diagram Style */}
|
{/* Diagram Style */}
|
||||||
|
|||||||
@@ -60,13 +60,6 @@ export function createWindow(serverUrl: string): BrowserWindow {
|
|||||||
mainWindow.webContents.openDevTools()
|
mainWindow.webContents.openDevTools()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override the draw.io iframe's beforeunload handler so the window can
|
|
||||||
// close after the user edits text in a shape (fixes #815). Diagrams are
|
|
||||||
// already persisted via autosave, so the prompt is unnecessary.
|
|
||||||
mainWindow.webContents.on("will-prevent-unload", (event) => {
|
|
||||||
event.preventDefault()
|
|
||||||
})
|
|
||||||
|
|
||||||
mainWindow.on("closed", () => {
|
mainWindow.on("closed", () => {
|
||||||
mainWindow = null
|
mainWindow = null
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1262,6 +1262,7 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig {
|
|||||||
case "glm":
|
case "glm":
|
||||||
case "qwen":
|
case "qwen":
|
||||||
case "qiniu":
|
case "qiniu":
|
||||||
|
case "kimi":
|
||||||
case "novita": {
|
case "novita": {
|
||||||
const envVar = PROVIDER_ENV_VARS[provider]
|
const envVar = PROVIDER_ENV_VARS[provider]
|
||||||
if (!envVar) {
|
if (!envVar) {
|
||||||
@@ -1287,23 +1288,6 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "kimi": {
|
|
||||||
const apiKey = resolveApiKey(overrides, "KIMI_API_KEY")
|
|
||||||
const baseURL = resolveBaseURL(
|
|
||||||
overrides?.apiKey,
|
|
||||||
overrides?.baseUrl,
|
|
||||||
resolveBaseUrlEnv(overrides, "KIMI_BASE_URL"),
|
|
||||||
PROVIDER_INFO["kimi"]?.defaultBaseUrl,
|
|
||||||
)
|
|
||||||
// Use createDeepSeek to properly handle reasoning_content for Kimi
|
|
||||||
// thinking models (e.g., kimi-k2.6). Kimi's API uses the same
|
|
||||||
// reasoning_content field as DeepSeek, so this provider correctly
|
|
||||||
// captures and replays reasoning in multi-turn conversations.
|
|
||||||
const customProvider = createDeepSeek({ apiKey, baseURL })
|
|
||||||
model = customProvider(modelId)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway, edgeone, doubao, modelscope, glm, qwen, qiniu, kimi, minimax, novita`,
|
`Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway, edgeone, doubao, modelscope, glm, qwen, qiniu, kimi, minimax, novita`,
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
export const DRAWIO_THEMES = [
|
|
||||||
"kennedy",
|
|
||||||
"atlas",
|
|
||||||
"dark",
|
|
||||||
"min",
|
|
||||||
"sketch",
|
|
||||||
"simple",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export type DrawioTheme = (typeof DRAWIO_THEMES)[number]
|
|
||||||
|
|
||||||
export function isDrawioTheme(value: unknown): value is DrawioTheme {
|
|
||||||
return (
|
|
||||||
typeof value === "string" &&
|
|
||||||
(DRAWIO_THEMES as readonly string[]).includes(value)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -102,12 +102,10 @@
|
|||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"themeDescription": "Dark/Light mode for interface and DrawIO canvas.",
|
"themeDescription": "Dark/Light mode for interface and DrawIO canvas.",
|
||||||
"drawioStyle": "DrawIO Style",
|
"drawioStyle": "DrawIO Style",
|
||||||
"drawioStyleDescription": "Canvas style",
|
"drawioStyleDescription": "Canvas style:",
|
||||||
"themeDefault": "Default",
|
"switchTo": "Switch to",
|
||||||
"themeDark": "Dark",
|
"minimal": "Minimal",
|
||||||
"themeMinimal": "Minimal",
|
"sketch": "Sketch",
|
||||||
"themeSketch": "Sketch",
|
|
||||||
"themeSimple": "Simple",
|
|
||||||
"diagramStyle": "Diagram Style",
|
"diagramStyle": "Diagram Style",
|
||||||
"diagramStyleDescription": "Toggle between minimal and styled diagram output.",
|
"diagramStyleDescription": "Toggle between minimal and styled diagram output.",
|
||||||
"sendShortcut": "Send Shortcut",
|
"sendShortcut": "Send Shortcut",
|
||||||
|
|||||||
@@ -102,12 +102,10 @@
|
|||||||
"theme": "テーマ",
|
"theme": "テーマ",
|
||||||
"themeDescription": "インターフェースと DrawIO キャンバスのダーク/ライトモード。",
|
"themeDescription": "インターフェースと DrawIO キャンバスのダーク/ライトモード。",
|
||||||
"drawioStyle": "DrawIO スタイル",
|
"drawioStyle": "DrawIO スタイル",
|
||||||
"drawioStyleDescription": "キャンバススタイル",
|
"drawioStyleDescription": "キャンバススタイル:",
|
||||||
"themeDefault": "デフォルト",
|
"switchTo": "切り替え",
|
||||||
"themeDark": "ダーク",
|
"minimal": "ミニマル",
|
||||||
"themeMinimal": "ミニマル",
|
"sketch": "スケッチ",
|
||||||
"themeSketch": "スケッチ",
|
|
||||||
"themeSimple": "シンプル",
|
|
||||||
"diagramStyle": "ダイアグラムスタイル",
|
"diagramStyle": "ダイアグラムスタイル",
|
||||||
"diagramStyleDescription": "ミニマルとスタイル付きの出力を切り替えます。",
|
"diagramStyleDescription": "ミニマルとスタイル付きの出力を切り替えます。",
|
||||||
"sendShortcut": "送信ショートカット",
|
"sendShortcut": "送信ショートカット",
|
||||||
|
|||||||
@@ -102,12 +102,10 @@
|
|||||||
"theme": "主題",
|
"theme": "主題",
|
||||||
"themeDescription": "介面和 DrawIO 畫布的深色/淺色模式。",
|
"themeDescription": "介面和 DrawIO 畫布的深色/淺色模式。",
|
||||||
"drawioStyle": "DrawIO 樣式",
|
"drawioStyle": "DrawIO 樣式",
|
||||||
"drawioStyleDescription": "畫布樣式",
|
"drawioStyleDescription": "畫布樣式:",
|
||||||
"themeDefault": "預設",
|
"switchTo": "切換到",
|
||||||
"themeDark": "深色",
|
"minimal": "簡約",
|
||||||
"themeMinimal": "簡約",
|
"sketch": "草圖",
|
||||||
"themeSketch": "草圖",
|
|
||||||
"themeSimple": "簡單",
|
|
||||||
"diagramStyle": "圖表樣式",
|
"diagramStyle": "圖表樣式",
|
||||||
"diagramStyleDescription": "切換簡約與精緻圖表輸出模式。",
|
"diagramStyleDescription": "切換簡約與精緻圖表輸出模式。",
|
||||||
"sendShortcut": "傳送快捷鍵",
|
"sendShortcut": "傳送快捷鍵",
|
||||||
|
|||||||
@@ -102,12 +102,10 @@
|
|||||||
"theme": "主题",
|
"theme": "主题",
|
||||||
"themeDescription": "界面和 DrawIO 画布的深色/浅色模式。",
|
"themeDescription": "界面和 DrawIO 画布的深色/浅色模式。",
|
||||||
"drawioStyle": "DrawIO 样式",
|
"drawioStyle": "DrawIO 样式",
|
||||||
"drawioStyleDescription": "画布样式",
|
"drawioStyleDescription": "画布样式:",
|
||||||
"themeDefault": "默认",
|
"switchTo": "切换到",
|
||||||
"themeDark": "深色",
|
"minimal": "简约",
|
||||||
"themeMinimal": "简约",
|
"sketch": "草图",
|
||||||
"themeSketch": "草图",
|
|
||||||
"themeSimple": "简单",
|
|
||||||
"diagramStyle": "图表样式",
|
"diagramStyle": "图表样式",
|
||||||
"diagramStyleDescription": "切换简约与精致图表输出模式。",
|
"diagramStyleDescription": "切换简约与精致图表输出模式。",
|
||||||
"sendShortcut": "发送快捷键",
|
"sendShortcut": "发送快捷键",
|
||||||
|
|||||||
@@ -35,10 +35,8 @@ test.describe("Iframe Interaction", () => {
|
|||||||
await expect(
|
await expect(
|
||||||
frame
|
frame
|
||||||
.locator('text="Diagram"')
|
.locator('text="Diagram"')
|
||||||
.or(frame.locator('[title*="Diagram"]'))
|
.or(frame.locator('[title*="Diagram"]')),
|
||||||
.filter({ visible: true })
|
).toBeVisible({ timeout: 10000 })
|
||||||
.first(),
|
|
||||||
).toBeVisible({ timeout: 30000 })
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("diagram XML is rendered in iframe after generation", async ({
|
test("diagram XML is rendered in iframe after generation", async ({
|
||||||
|
|||||||
@@ -245,67 +245,6 @@ vi.mock("ollama-ai-provider-v2", () => {
|
|||||||
return { createOllama: mockCreateOllama, ollama: mockOllama }
|
return { createOllama: mockCreateOllama, ollama: mockOllama }
|
||||||
})
|
})
|
||||||
|
|
||||||
vi.mock("@ai-sdk/deepseek", () => {
|
|
||||||
const mockModel = { modelId: "test-model" }
|
|
||||||
const mockProviderFn = vi.fn(() => mockModel)
|
|
||||||
const mockCreateDeepSeek = vi.fn(() => mockProviderFn)
|
|
||||||
const mockDeepseek = vi.fn(() => mockModel)
|
|
||||||
return { createDeepSeek: mockCreateDeepSeek, deepseek: mockDeepseek }
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("Kimi provider uses createDeepSeek for reasoning_content support", () => {
|
|
||||||
let createDeepSeekMock: ReturnType<typeof vi.fn>
|
|
||||||
const savedEnv: Record<string, string | undefined> = {}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
savedEnv.KIMI_API_KEY = process.env.KIMI_API_KEY
|
|
||||||
savedEnv.KIMI_BASE_URL = process.env.KIMI_BASE_URL
|
|
||||||
delete process.env.KIMI_BASE_URL
|
|
||||||
|
|
||||||
const mod = await import("@ai-sdk/deepseek")
|
|
||||||
createDeepSeekMock = mod.createDeepSeek as ReturnType<typeof vi.fn>
|
|
||||||
createDeepSeekMock.mockClear()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
process.env.KIMI_API_KEY = savedEnv.KIMI_API_KEY
|
|
||||||
process.env.KIMI_BASE_URL = savedEnv.KIMI_BASE_URL
|
|
||||||
})
|
|
||||||
|
|
||||||
it("uses createDeepSeek with Kimi default base URL for reasoning_content support", () => {
|
|
||||||
process.env.KIMI_API_KEY = "test-kimi-key"
|
|
||||||
|
|
||||||
getAIModel({
|
|
||||||
provider: "kimi",
|
|
||||||
apiKey: "test-kimi-key",
|
|
||||||
modelId: "moonshot-v1-8k",
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(createDeepSeekMock).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
baseURL: "https://api.moonshot.cn/v1",
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("uses custom base URL when provided for kimi provider", () => {
|
|
||||||
process.env.KIMI_API_KEY = "test-kimi-key"
|
|
||||||
|
|
||||||
getAIModel({
|
|
||||||
provider: "kimi",
|
|
||||||
apiKey: "test-kimi-key",
|
|
||||||
baseUrl: "https://custom-kimi-endpoint.com/v1",
|
|
||||||
modelId: "kimi-k2.6",
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(createDeepSeekMock).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
baseURL: "https://custom-kimi-endpoint.com/v1",
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("Ollama API key security", () => {
|
describe("Ollama API key security", () => {
|
||||||
let createOllamaMock: ReturnType<typeof vi.fn>
|
let createOllamaMock: ReturnType<typeof vi.fn>
|
||||||
const savedEnv: Record<string, string | undefined> = {}
|
const savedEnv: Record<string, string | undefined> = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user