From c2e14c48a00e46403798f91db511c9c7f21ffcae Mon Sep 17 00:00:00 2001 From: gongzhiyong Date: Wed, 8 Apr 2026 17:42:50 +0800 Subject: [PATCH] fix: single gpt-5.4 model selector + SSE buffer edge case fix - Replace Flash/Pro dual model buttons with single "gpt-5.4" label - Backend still receives "flash" as model param (matches schema validation) - Remove unused selectedModel/onSelectedModelChange props from GeminiInput - Fix SSE stream parsing: process remaining buffer data when stream ends without trailing newline (potential cause of "no return" issue) Co-Authored-By: Claude Sonnet 4.6 (1M context) --- frontend/components/gemini/GeminiChat.tsx | 4 +-- frontend/components/gemini/GeminiInput.tsx | 33 ++++------------------ frontend/lib/api.ts | 19 ++++++++++++- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/frontend/components/gemini/GeminiChat.tsx b/frontend/components/gemini/GeminiChat.tsx index 11ae6d3..ffb78bc 100644 --- a/frontend/components/gemini/GeminiChat.tsx +++ b/frontend/components/gemini/GeminiChat.tsx @@ -72,7 +72,7 @@ export function GeminiChat() { const [extensions, setExtensions] = useState(INITIAL_EXTENSIONS); const [ticketSummary, setTicketSummary] = useState(null); const [activeTools, setActiveTools] = useState>(new Set()); - const [selectedModel, setSelectedModel] = useState<"flash" | "pro">("pro"); + const [selectedModel, setSelectedModel] = useState<"flash" | "pro">("flash"); const messagesEndRef = useRef(null); const abortRef = useRef(null); @@ -381,8 +381,6 @@ export function GeminiChat() { isLoading={isLoading} activeTools={activeTools} onActiveToolsChange={setActiveTools} - selectedModel={selectedModel} - onSelectedModelChange={setSelectedModel} /> diff --git a/frontend/components/gemini/GeminiInput.tsx b/frontend/components/gemini/GeminiInput.tsx index 1eabd34..6eb5df5 100644 --- a/frontend/components/gemini/GeminiInput.tsx +++ b/frontend/components/gemini/GeminiInput.tsx @@ -27,8 +27,6 @@ interface GeminiInputProps { isLoading?: boolean; activeTools: Set; onActiveToolsChange: (tools: Set) => void; - selectedModel: "flash" | "pro"; - onSelectedModelChange: (model: "flash" | "pro") => void; } const TOOLS: Tool[] = [ @@ -45,8 +43,6 @@ export function GeminiInput({ isLoading, activeTools, onActiveToolsChange, - selectedModel, - onSelectedModelChange, }: GeminiInputProps) { const textareaRef = useRef(null); const fileInputRef = useRef(null); @@ -204,32 +200,13 @@ export function GeminiInput({ - {/* Bottom row: Model selector */} + {/* Bottom row: Model indicator */}
- - + gpt-5.4 +
{/* Tools panel (collapsible, below input) */} diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts index 9c571fb..cd11fb7 100644 --- a/frontend/lib/api.ts +++ b/frontend/lib/api.ts @@ -114,7 +114,24 @@ export function streamChat( while (true) { const { done, value } = await reader.read(); - if (done) break; + if (done) { + // Process any remaining data in buffer (last line may lack trailing newline) + if (buffer.trim()) { + const trimmed = buffer.trim(); + if (trimmed.startsWith("data: ")) { + const json = trimmed.slice(6); + if (json) { + try { + const event: ChatStreamEvent = JSON.parse(json); + onEvent(event); + } catch { + // skip malformed + } + } + } + } + break; + } buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n");