fix: Add detailed debugging and use result.text for cleaned content

- Add debug logging to track aiResponse vs result.text content
- Use result.text from extractReasoningMiddleware for final content
- This should provide the properly cleaned text without thinking tags
- Comment out unused sidebar and edit functionality to fix TS errors

The result.text should contain content that has been automatically
cleaned by the extractReasoningMiddleware, while result.reasoning
contains the extracted thinking content.
This commit is contained in:
Glen Maddern 2025-06-24 17:40:53 +10:00
commit 6c7422f832
3 changed files with 64 additions and 54 deletions

View file

@ -1,6 +1,4 @@
import React, { useState, useEffect } from "react";
import ChatSidebar from "./ChatSidebar.tsx";
import ChatNavbar from "./ChatNavbar.tsx";
import ConversationThread from "./ConversationThread.tsx";
import { storeName } from "../consts.ts";
import { type Conversation } from "../types";
@ -18,7 +16,7 @@ const ChatApp: React.FC<ChatAppProps> = () => {
const [conversationId, setConversationId] = useState<number | undefined>(
undefined
);
const [sidebarVisible, setSidebarVisible] = useState<boolean>(true);
const [selectedModel, setSelectedModel] = useState<Model>(getSelectedModel());
const [apiKeyUpdateTrigger, setApiKeyUpdateTrigger] = useState<number>(0);
const [mcpTools, setMcpTools] = useState<Tool[]>([]);
@ -43,8 +41,8 @@ const ChatApp: React.FC<ChatAppProps> = () => {
// Initialize sidebar visibility based on screen size
useEffect(() => {
const isMobile = window.matchMedia("(max-width: 768px)").matches;
setSidebarVisible(!isMobile);
// const isMobile = window.matchMedia("(max-width: 768px)").matches;
// setSidebarVisible(!isMobile);
}, []);
const getConversations = async () => {
@ -72,21 +70,21 @@ const ChatApp: React.FC<ChatAppProps> = () => {
}
};
const editConversationTitle = async (id: number, newTitle: string) => {
const conversation = (await db!.get(storeName, id)) as Conversation;
conversation.title = newTitle;
await db!.put(storeName, conversation);
setConversations((prev) =>
prev.map((conv) => (conv.id === id ? { ...conv, title: newTitle } : conv))
);
};
// const editConversationTitle = async (id: number, newTitle: string) => {
// const conversation = (await db!.get(storeName, id)) as Conversation;
// conversation.title = newTitle;
// await db!.put(storeName, conversation);
// setConversations((prev) =>
// prev.map((conv) => (conv.id === id ? { ...conv, title: newTitle } : conv))
// );
// };
const startNewConversation = async () => {
//create unique id for new conversation
setConversationId(Date.now() + Math.floor(Math.random() * 1000));
if (window.matchMedia("(max-width: 768px)").matches) {
setSidebarVisible(false);
}
// if (window.matchMedia("(max-width: 768px)").matches) {
// setSidebarVisible(false);
// }
};
// delete conversations with no messages
@ -109,28 +107,28 @@ const ChatApp: React.FC<ChatAppProps> = () => {
>
<div className="flex flex-row flex-grow flex-1 min-h-screen relative">
{/* Sidebar and Navbar components hidden but kept in codebase */}
{false && (
<>
<ChatSidebar
sidebarVisible={sidebarVisible}
setSidebarVisible={setSidebarVisible}
conversations={conversations}
conversationId={conversationId}
setConversationId={setConversationId}
deleteConversation={deleteConversation}
editConversationTitle={editConversationTitle}
startNewConversation={startNewConversation}
selectedModel={selectedModel}
onModelChange={handleModelChange}
apiKeyUpdateTrigger={apiKeyUpdateTrigger}
onMcpToolsUpdate={setMcpTools}
/>
<ChatNavbar
sidebarVisible={sidebarVisible}
setSidebarVisible={setSidebarVisible}
/>
</>
)}
{/*{false && (*/}
{/* <>*/}
{/* <ChatSidebar*/}
{/* sidebarVisible={sidebarVisible}*/}
{/* setSidebarVisible={setSidebarVisible}*/}
{/* conversations={conversations}*/}
{/* conversationId={conversationId}*/}
{/* setConversationId={setConversationId}*/}
{/* deleteConversation={deleteConversation}*/}
{/* editConversationTitle={editConversationTitle}*/}
{/* startNewConversation={startNewConversation}*/}
{/* selectedModel={selectedModel}*/}
{/* onModelChange={handleModelChange}*/}
{/* apiKeyUpdateTrigger={apiKeyUpdateTrigger}*/}
{/* onMcpToolsUpdate={setMcpTools}*/}
{/* />*/}
{/* <ChatNavbar*/}
{/* sidebarVisible={sidebarVisible}*/}
{/* setSidebarVisible={setSidebarVisible}*/}
{/* />*/}
{/* </>*/}
{/*)}*/}
<div className="flex flex-col flex-grow h-full w-full">
<ConversationThread
conversations={conversations}

View file

@ -25,7 +25,7 @@ const ReasoningBlock: React.FC<ReasoningBlockProps> = ({ reasoning }) => {
return (
<div className="mb-3">
<div
className={`text-sm text-zinc-600 border border-zinc-200 rounded-lg p-3 bg-zinc-50 cursor-pointer hover:bg-zinc-100 transition-colors ${shouldTruncate && !isExpanded ? "line-clamp-1" : ""
className={`text-xs text-zinc-600 border border-zinc-200 rounded-lg p-3 *bg-zinc-50 cursor-pointer hover:bg-zinc-50 transition-colors ${shouldTruncate && !isExpanded ? "line-clamp-1" : ""
}`}
onClick={toggleExpanded}
>
@ -34,17 +34,17 @@ const ReasoningBlock: React.FC<ReasoningBlockProps> = ({ reasoning }) => {
<div className={`${shouldTruncate && !isExpanded ? "truncate" : "whitespace-pre-wrap"}`}>
{displayText}
</div>
{shouldTruncate && (
<button
className="text-zinc-400 hover:text-zinc-600 text-xs ml-auto flex-shrink-0"
onClick={(e) => {
e.stopPropagation();
toggleExpanded();
}}
>
{isExpanded ? "↑" : "↓"}
</button>
)}
{/*{shouldTruncate && (*/}
{/* <button*/}
{/* className="text-zinc-400 hover:text-zinc-600 text-xs ml-auto flex-shrink-0"*/}
{/* onClick={(e) => {*/}
{/* e.stopPropagation();*/}
{/* toggleExpanded();*/}
{/* }}*/}
{/* >*/}
{/* {isExpanded ? "↑" : "↓"}*/}
{/* </button>*/}
{/*)}*/}
</div>
</div>
</div>

View file

@ -312,19 +312,31 @@ export const useStreamResponse = ({
}
debugLog(`[useStreamResponse] Finished processing full stream. Final response length: ${aiResponse.length}`)
debugLog(`[useStreamResponse] Final aiResponse content:`, JSON.stringify(aiResponse))
// Extract reasoning from the result after streaming completes
const finalReasoning = await result.reasoning
if (finalReasoning && assistantMessageCreated) {
debugLog(`[useStreamResponse] Extracted reasoning:`, finalReasoning)
const finalText = await result.text
debugLog(`[useStreamResponse] Final result.text:`, JSON.stringify(finalText))
if (assistantMessageCreated) {
setConversations((prev) => {
const updated = [...prev]
const conv = updated.find((c) => c.id === conversationId)
if (conv && assistantMessageIndex >= 0) {
const assistantMessage = conv.messages[assistantMessageIndex]
if (assistantMessage && hasContent(assistantMessage) && assistantMessage.role === 'assistant') {
assistantMessage.reasoning = finalReasoning
debugLog(`[useStreamResponse] Added reasoning to assistant message at index ${assistantMessageIndex}`)
// Use the final cleaned text from the result instead of our tracked aiResponse
if (finalText && supportsReasoning(selectedModel)) {
assistantMessage.content = finalText
debugLog(`[useStreamResponse] Updated content with cleaned result.text`)
}
if (finalReasoning) {
assistantMessage.reasoning = finalReasoning
debugLog(`[useStreamResponse] Added reasoning to assistant message at index ${assistantMessageIndex}`)
}
debugLog(`[useStreamResponse] Final message content:`, JSON.stringify(assistantMessage.content))
}
}
return updated