From 9465a88fdd39e9158679fb7dacf9f545e992a419 Mon Sep 17 00:00:00 2001 From: LynPtl Date: Sun, 15 Feb 2026 02:03:49 +1100 Subject: [PATCH 1/4] fix(ai): change default provider to intern and fix error handling --- app/components/DocsAssistant.tsx | 20 +++++++++++++++++--- app/hooks/useAssistantSettings.tsx | 8 ++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/app/components/DocsAssistant.tsx b/app/components/DocsAssistant.tsx index 60e2af6..b8df594 100644 --- a/app/components/DocsAssistant.tsx +++ b/app/components/DocsAssistant.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useRef } from "react"; import { AssistantRuntimeProvider } from "@assistant-ui/react"; import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk"; @@ -34,11 +34,20 @@ export function DocsAssistant({ pageContext }: DocsAssistantProps) { function DocsAssistantInner({ pageContext }: DocsAssistantProps) { const { provider, openaiApiKey, geminiApiKey } = useAssistantSettings(); + // Use useRef to keep the latest settings, avoiding closure capturing old values + const settingsRef = useRef({ provider, openaiApiKey, geminiApiKey }); + + useEffect(() => { + settingsRef.current = { provider, openaiApiKey, geminiApiKey }; + }, [provider, openaiApiKey, geminiApiKey]); + const transport = useMemo( () => new DefaultChatTransport({ api: "/api/chat", body: () => { + const { provider, openaiApiKey, geminiApiKey } = settingsRef.current; + const apiKey = provider === "openai" ? openaiApiKey @@ -49,13 +58,13 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) { return { pageContext, provider, apiKey }; }, }), - [geminiApiKey, openaiApiKey, pageContext, provider], + [pageContext], // Remove provider and key dependencies to prevent transport recreation ); const chat = useChat({ transport, onFinish: () => { - // 当对话结束时(流式传输完成),记录一次查询行为 + // Track AI query when chat finishes (streaming completes) if (window.umami) { window.umami.track("ai_assistant_query"); } @@ -68,6 +77,11 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) { clearError: clearChatError, } = chat; + // Clear previous error when Provider changes + useEffect(() => { + clearChatError(); + }, [provider, clearChatError]); + useEffect(() => { if (chatStatus === "submitted" || chatStatus === "streaming") { clearChatError(); diff --git a/app/hooks/useAssistantSettings.tsx b/app/hooks/useAssistantSettings.tsx index da78c48..c82ab8e 100644 --- a/app/hooks/useAssistantSettings.tsx +++ b/app/hooks/useAssistantSettings.tsx @@ -16,7 +16,7 @@ interface AssistantSettingsState { provider: Provider; openaiApiKey: string; geminiApiKey: string; - saveToLocalStorage: boolean; // 是否将API Key保存到localStorage + saveToLocalStorage: boolean; // Whether to save API keys to localStorage } interface AssistantSettingsContextValue extends AssistantSettingsState { @@ -30,7 +30,7 @@ interface AssistantSettingsContextValue extends AssistantSettingsState { const SETTINGS_KEY = "assistant-settings-storage"; const defaultSettings: AssistantSettingsState = { - provider: "openai", + provider: "intern", openaiApiKey: "", geminiApiKey: "", saveToLocalStorage: false, @@ -56,7 +56,7 @@ const parseStoredSettings = (raw: string | null): AssistantSettingsState => { : parsed.provider === "intern" ? "intern" : "openai", - // 只有在saveToLocalStorage为true时才使用存储的key + // Use only stored key if saveToLocalStorage is true openaiApiKey: saveToLocalStorage && typeof parsed.openaiApiKey === "string" ? parsed.openaiApiKey @@ -100,7 +100,7 @@ export const AssistantSettingsProvider = ({ } try { - // 根据saveToLocalStorage决定是否保存API key + // Decide whether to save API keys based on saveToLocalStorage const dataToSave = settings.saveToLocalStorage ? settings : { From a30465a32dee62a3b0cb239ffff66a6b0e8589af Mon Sep 17 00:00:00 2001 From: LynPtl Date: Sun, 15 Feb 2026 02:29:22 +1100 Subject: [PATCH 2/4] fix(ci): fix lint error in DocsAssistant by removing useRef --- app/components/DocsAssistant.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/app/components/DocsAssistant.tsx b/app/components/DocsAssistant.tsx index b8df594..0849751 100644 --- a/app/components/DocsAssistant.tsx +++ b/app/components/DocsAssistant.tsx @@ -34,20 +34,11 @@ export function DocsAssistant({ pageContext }: DocsAssistantProps) { function DocsAssistantInner({ pageContext }: DocsAssistantProps) { const { provider, openaiApiKey, geminiApiKey } = useAssistantSettings(); - // Use useRef to keep the latest settings, avoiding closure capturing old values - const settingsRef = useRef({ provider, openaiApiKey, geminiApiKey }); - - useEffect(() => { - settingsRef.current = { provider, openaiApiKey, geminiApiKey }; - }, [provider, openaiApiKey, geminiApiKey]); - const transport = useMemo( () => new DefaultChatTransport({ api: "/api/chat", body: () => { - const { provider, openaiApiKey, geminiApiKey } = settingsRef.current; - const apiKey = provider === "openai" ? openaiApiKey @@ -58,7 +49,7 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) { return { pageContext, provider, apiKey }; }, }), - [pageContext], // Remove provider and key dependencies to prevent transport recreation + [pageContext, provider, openaiApiKey, geminiApiKey], ); const chat = useChat({ From 609f15bc96f2611b6cbd23d5d35c59b5b127f4f5 Mon Sep 17 00:00:00 2001 From: LynPtl Date: Mon, 16 Feb 2026 18:55:55 +1100 Subject: [PATCH 3/4] fix(docs-assistant): include provider/key in useChat id to force reset --- app/components/DocsAssistant.tsx | 28 +++++++++++++++++----------- app/hooks/useAssistantSettings.tsx | 4 +++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/components/DocsAssistant.tsx b/app/components/DocsAssistant.tsx index 0849751..580992d 100644 --- a/app/components/DocsAssistant.tsx +++ b/app/components/DocsAssistant.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useEffect, useMemo, useRef } from "react"; +import { useCallback, useEffect, useMemo } from "react"; import { AssistantRuntimeProvider } from "@assistant-ui/react"; import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk"; @@ -34,27 +34,31 @@ export function DocsAssistant({ pageContext }: DocsAssistantProps) { function DocsAssistantInner({ pageContext }: DocsAssistantProps) { const { provider, openaiApiKey, geminiApiKey } = useAssistantSettings(); + const apiKey = + provider === "openai" + ? openaiApiKey + : provider === "gemini" + ? geminiApiKey + : ""; + const transport = useMemo( () => new DefaultChatTransport({ api: "/api/chat", - body: () => { - const apiKey = - provider === "openai" - ? openaiApiKey - : provider === "gemini" - ? geminiApiKey - : ""; // intern provider doesn't need API key - - return { pageContext, provider, apiKey }; + body: { + pageContext, + provider, + apiKey, }, }), - [pageContext, provider, openaiApiKey, geminiApiKey], + [pageContext, provider, apiKey], ); const chat = useChat({ + id: `assistant-${provider}-${apiKey}`, // Force chat reset when provider OR key changes transport, onFinish: () => { + // 当对话结束时(流式传输完成),记录一次查询行为 // Track AI query when chat finishes (streaming completes) if (window.umami) { window.umami.track("ai_assistant_query"); @@ -180,6 +184,7 @@ function deriveAssistantError( let showSettingsCTA = false; // For intern provider, don't show settings CTA for API key related errors + // 对于书生,不要显示 API 密钥相关的错误 if ( provider !== "intern" && (statusCode === 400 || @@ -249,6 +254,7 @@ function extractErrorFromResponseBody(body: string): string | undefined { } } catch { // Ignore JSON parsing issues and fall back to the raw body text. + // 忽略 JSON 解析问题,回退到原始正文文本。 } return trimmed; diff --git a/app/hooks/useAssistantSettings.tsx b/app/hooks/useAssistantSettings.tsx index c82ab8e..cdd3524 100644 --- a/app/hooks/useAssistantSettings.tsx +++ b/app/hooks/useAssistantSettings.tsx @@ -16,7 +16,7 @@ interface AssistantSettingsState { provider: Provider; openaiApiKey: string; geminiApiKey: string; - saveToLocalStorage: boolean; // Whether to save API keys to localStorage + saveToLocalStorage: boolean; // 是否将API Key保存到localStorage } interface AssistantSettingsContextValue extends AssistantSettingsState { @@ -57,6 +57,7 @@ const parseStoredSettings = (raw: string | null): AssistantSettingsState => { ? "intern" : "openai", // Use only stored key if saveToLocalStorage is true + // 只有在saveToLocalStorage为true时才使用存储的key openaiApiKey: saveToLocalStorage && typeof parsed.openaiApiKey === "string" ? parsed.openaiApiKey @@ -101,6 +102,7 @@ export const AssistantSettingsProvider = ({ try { // Decide whether to save API keys based on saveToLocalStorage + // 根据saveToLocalStorage决定是否保存API key const dataToSave = settings.saveToLocalStorage ? settings : { From 697485b8b1fef4f2c8a20de2d21dba0be1caffe6 Mon Sep 17 00:00:00 2001 From: LynPtl Date: Mon, 16 Feb 2026 19:02:39 +1100 Subject: [PATCH 4/4] docs: add missing Chinese comments --- app/components/DocsAssistant.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/DocsAssistant.tsx b/app/components/DocsAssistant.tsx index 580992d..139f98a 100644 --- a/app/components/DocsAssistant.tsx +++ b/app/components/DocsAssistant.tsx @@ -56,6 +56,7 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) { const chat = useChat({ id: `assistant-${provider}-${apiKey}`, // Force chat reset when provider OR key changes + // 当 Provider 或 Key 更改时强制重置聊天 transport, onFinish: () => { // 当对话结束时(流式传输完成),记录一次查询行为 @@ -73,6 +74,7 @@ function DocsAssistantInner({ pageContext }: DocsAssistantProps) { } = chat; // Clear previous error when Provider changes + // 当 Provider 更改时清除之前的错误 useEffect(() => { clearChatError(); }, [provider, clearChatError]);