From d9c4ad2c9507d987bec37a263fe61c3891a5ffb0 Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Sun, 1 Mar 2026 22:55:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=87=E6=8D=A2=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E5=90=8E=E6=A8=A1=E5=9E=8B=E9=80=89=E6=8B=A9=E4=B8=8D=E4=BF=9D?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两个问题: 1. 用户选择模型只写 localStorage,不写 DB。切换聊天回来后从 DB 读到空值,模型回退到默认值 2. ChatView 的 useState 只用初始值,后续 modelName prop 异步更新 不会同步到 currentModel state 修复: - handleProviderModelChange 选择模型时立即 PATCH 到 DB - PATCH /api/chat/sessions/:id 新增 model + provider_id 字段支持 - ChatView 添加 useEffect 同步 modelName/providerId prop 变化 Co-Authored-By: Claude Opus 4.6 --- src/app/api/chat/sessions/[id]/route.ts | 8 +++++++- src/components/chat/ChatView.tsx | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/app/api/chat/sessions/[id]/route.ts b/src/app/api/chat/sessions/[id]/route.ts index 5729cd7..91d760b 100644 --- a/src/app/api/chat/sessions/[id]/route.ts +++ b/src/app/api/chat/sessions/[id]/route.ts @@ -1,5 +1,5 @@ import { NextRequest } from 'next/server'; -import { deleteSession, getSession, updateSessionWorkingDirectory, updateSessionTitle, updateSessionMode, clearSessionMessages } from '@/lib/db'; +import { deleteSession, getSession, updateSessionWorkingDirectory, updateSessionTitle, updateSessionMode, updateSessionModel, updateSessionProviderId, clearSessionMessages } from '@/lib/db'; export async function GET( _request: NextRequest, @@ -40,6 +40,12 @@ export async function PATCH( if (body.mode) { updateSessionMode(id, body.mode); } + if (body.model !== undefined) { + updateSessionModel(id, body.model); + } + if (body.provider_id !== undefined) { + updateSessionProviderId(id, body.provider_id); + } if (body.clear_messages) { clearSessionMessages(id); } diff --git a/src/components/chat/ChatView.tsx b/src/components/chat/ChatView.tsx index 24084b0..bfa197f 100644 --- a/src/components/chat/ChatView.tsx +++ b/src/components/chat/ChatView.tsx @@ -35,6 +35,14 @@ export function ChatView({ sessionId, initialMessages = [], initialHasMore = fal const [currentModel, setCurrentModel] = useState(modelName || (typeof window !== 'undefined' ? localStorage.getItem('codepilot:last-model') : null) || 'sonnet'); const [currentProviderId, setCurrentProviderId] = useState(providerId || (typeof window !== 'undefined' ? localStorage.getItem('codepilot:last-provider-id') : null) || ''); + // Sync model/provider when session data loads (props update after async fetch) + useEffect(() => { + if (modelName) setCurrentModel(modelName); + }, [modelName]); + useEffect(() => { + if (providerId) setCurrentProviderId(providerId); + }, [providerId]); + // Stream snapshot from the manager — drives all streaming UI const [streamSnapshot, setStreamSnapshot] = useState( () => getSnapshot(sessionId) @@ -79,7 +87,13 @@ export function ChatView({ sessionId, initialMessages = [], initialHasMore = fal const handleProviderModelChange = useCallback((newProviderId: string, model: string) => { setCurrentProviderId(newProviderId); setCurrentModel(model); - }, []); + // Persist immediately so switching chats preserves the selection + fetch(`/api/chat/sessions/${sessionId}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ model, provider_id: newProviderId }), + }).catch(() => {}); + }, [sessionId]); // Subscribe to stream-session-manager for this session. // On unmount we only unsubscribe — we do NOT abort the stream.