Ok _much_ better timing and just me understanding this stuff
This commit is contained in:
parent
cd8df15e94
commit
f460842bbc
2 changed files with 39 additions and 61 deletions
|
|
@ -29,9 +29,8 @@ const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message }) => {
|
|||
|
||||
// Format duration nicely
|
||||
const formatDuration = (seconds: number) => {
|
||||
if (seconds < 1) {
|
||||
return `${Math.round(seconds * 1000)}ms`
|
||||
}
|
||||
if (seconds < 0.001) return `< 1ms`
|
||||
if (seconds < 1) return `${Math.round(seconds * 1000)}ms`
|
||||
return `${seconds.toFixed(1)}s`
|
||||
}
|
||||
|
||||
|
|
@ -39,8 +38,8 @@ const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message }) => {
|
|||
<div className={`flex justify-start`}>
|
||||
<div className={`text-zinc-900 w-full`}>
|
||||
<div
|
||||
className={`text-xs/5 text-zinc-600 border opacity-80 hover:opacity-100 border-zinc-200 rounded-lg p-3 bg-zinc-50 cursor-pointer hover:bg-zinc-100 ${
|
||||
isExpanded ? 'border-zinc-300 opacity-100' : ''
|
||||
className={`text-xs/5 text-zinc-600 border border-zinc-200 rounded-lg p-3 bg-zinc-50 cursor-pointer hover:bg-zinc-100 ${
|
||||
isExpanded ? 'border-zinc-300' : ''
|
||||
}`}
|
||||
onClick={toggleExpanded}
|
||||
>
|
||||
|
|
@ -61,7 +60,11 @@ const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message }) => {
|
|||
// Collapsed view: show timing summary
|
||||
<div className="flex-1">
|
||||
<span className="text-zinc-500">
|
||||
{message.isReasoningStreaming ? 'Thinking...' : duration ? `Thought for ${formatDuration(duration)}` : 'Thought process'}
|
||||
{message.isReasoningStreaming
|
||||
? 'Thinking...'
|
||||
: typeof duration === 'number'
|
||||
? `Thought for ${formatDuration(duration)}`
|
||||
: 'Thought process'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
import { useState, useRef } from 'react'
|
||||
import { streamText, tool, jsonSchema } from 'ai'
|
||||
import { useRef, useState } from 'react'
|
||||
import { CoreMessage, jsonSchema, streamText, tool } from 'ai'
|
||||
import { createGroq } from '@ai-sdk/groq'
|
||||
import { createAnthropic } from '@ai-sdk/anthropic'
|
||||
import { type Message, type Conversation, type UserMessage, type AssistantMessage, type SystemMessage } from '../types'
|
||||
import { type AssistantMessage, type Conversation, type Message, type SystemMessage, type UserMessage } from '../types'
|
||||
import { type Model } from '../types/models'
|
||||
import { getApiKey } from '../utils/apiKeys'
|
||||
import { type Tool } from 'use-mcp/react'
|
||||
import { useConversationUpdater } from './useConversationUpdater'
|
||||
|
||||
// Debug logging for message operations
|
||||
const debugMessages = (...args: any[]) => {
|
||||
if (typeof window !== 'undefined' && localStorage.getItem('USE_MCP_DEBUG') === 'true') {
|
||||
console.log('[Messages]', ...args)
|
||||
}
|
||||
}
|
||||
|
||||
// Type guard for messages with content
|
||||
const hasContent = (message: Message): message is UserMessage | AssistantMessage | SystemMessage => {
|
||||
return 'content' in message
|
||||
|
|
@ -41,10 +34,10 @@ export const useStreamResponse = ({
|
|||
const [streamStarted, setStreamStarted] = useState(false)
|
||||
const [controller, setController] = useState(new AbortController())
|
||||
const aiResponseRef = useRef<string>('')
|
||||
|
||||
|
||||
const { updateConversation } = useConversationUpdater({
|
||||
conversationId,
|
||||
setConversations
|
||||
setConversations,
|
||||
})
|
||||
|
||||
// Convert MCP tools to the format expected by the 'ai' package
|
||||
|
|
@ -140,18 +133,20 @@ export const useStreamResponse = ({
|
|||
// Convert MCP tools to AI package format
|
||||
const aiTools = convertMcpToolsToAiTools(mcpTools)
|
||||
|
||||
console.log({ messages })
|
||||
const messagesToSend: CoreMessage[] = messages
|
||||
.filter((msg) => ['user', 'assistant', 'system'].includes(msg.role) && hasContent(msg))
|
||||
.map((msg) => {
|
||||
const contentMsg = msg as UserMessage | AssistantMessage | SystemMessage
|
||||
return {
|
||||
role: contentMsg.role,
|
||||
content: contentMsg.content,
|
||||
}
|
||||
})
|
||||
// Prepare stream options
|
||||
const streamOptions = {
|
||||
model: modelInstance,
|
||||
messages: messages
|
||||
.filter((msg) => ['user', 'assistant', 'system'].includes(msg.role) && hasContent(msg))
|
||||
.map((msg) => {
|
||||
const contentMsg = msg as UserMessage | AssistantMessage | SystemMessage
|
||||
return {
|
||||
role: contentMsg.role,
|
||||
content: contentMsg.content,
|
||||
}
|
||||
}),
|
||||
messages: messagesToSend,
|
||||
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
||||
maxSteps: 5, // Allow up to 5 steps for tool calling
|
||||
abortSignal: controller.signal,
|
||||
|
|
@ -161,10 +156,11 @@ export const useStreamResponse = ({
|
|||
|
||||
// Use fullStream to get all events including tool calls, results, and text
|
||||
for await (const event of result.fullStream) {
|
||||
console.log({ 'result.fullStream.event': event })
|
||||
const eventTime = Date.now()
|
||||
// console.log({ 'result.fullStream.event': event })
|
||||
updateConversation((conv) => {
|
||||
const lastMessage = conv.messages?.at(-1)
|
||||
console.log({ setConversations: event, conv: JSON.parse(JSON.stringify(conv)) })
|
||||
// console.log({ setConversations: event, conv: JSON.parse(JSON.stringify(conv)) })
|
||||
let updatedMessage: Message | undefined
|
||||
let newMessage: Message | undefined
|
||||
try {
|
||||
|
|
@ -177,7 +173,7 @@ export const useStreamResponse = ({
|
|||
}
|
||||
} else {
|
||||
// We need a new reasoning block!
|
||||
const currentReasoningStartTime = Date.now()
|
||||
const currentReasoningStartTime = eventTime
|
||||
|
||||
// Create a new assistant message for reasoning (even if we already have one)
|
||||
// This handles multiple reasoning sessions in the same conversation turn
|
||||
|
|
@ -194,9 +190,15 @@ export const useStreamResponse = ({
|
|||
if (lastMessage?.role === 'assistant' && lastMessage.type === 'reasoning') {
|
||||
updatedMessage = {
|
||||
...lastMessage,
|
||||
reasoningEndTime: Date.now(),
|
||||
reasoningEndTime: eventTime,
|
||||
isReasoningStreaming: false,
|
||||
}
|
||||
|
||||
// Try hacking the tool call loop to include reasoning blocks
|
||||
messagesToSend.push({
|
||||
role: 'assistant',
|
||||
content: `<think>${lastMessage.content}</think>`,
|
||||
})
|
||||
}
|
||||
|
||||
if (event.type === 'tool-call') {
|
||||
|
|
@ -243,7 +245,7 @@ export const useStreamResponse = ({
|
|||
} catch (e) {
|
||||
console.error('Error in full stream processing:', e)
|
||||
}
|
||||
|
||||
|
||||
if (updatedMessage || newMessage) {
|
||||
const messages = [...conv.messages]
|
||||
|
||||
|
|
@ -255,39 +257,13 @@ export const useStreamResponse = ({
|
|||
messages.push(newMessage)
|
||||
}
|
||||
|
||||
console.log({ updatedMessage, newMessage })
|
||||
// console.log({ updatedMessage, newMessage })
|
||||
return { ...conv, messages }
|
||||
}
|
||||
|
||||
|
||||
return conv
|
||||
})
|
||||
}
|
||||
|
||||
// Show final conversation state
|
||||
updateConversation((conv) => {
|
||||
debugMessages('Final conversation state:', JSON.stringify(conv.messages))
|
||||
return conv
|
||||
})
|
||||
//
|
||||
// // Final cleanup - ensure reasoning streaming is stopped
|
||||
// if (assistantMessageCreated && currentReasoningStartTime) {
|
||||
// if (!currentReasoningEndTime) {
|
||||
// currentReasoningEndTime = Date.now()
|
||||
// }
|
||||
//
|
||||
// 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.isReasoningStreaming = false
|
||||
// assistantMessage.reasoningEndTime = currentReasoningEndTime
|
||||
// }
|
||||
// }
|
||||
// return updated
|
||||
// })
|
||||
// }
|
||||
} catch (error: unknown) {
|
||||
if (controller.signal.aborted) {
|
||||
} else {
|
||||
|
|
@ -296,7 +272,6 @@ export const useStreamResponse = ({
|
|||
} finally {
|
||||
setStreamStarted(false)
|
||||
setController(new AbortController())
|
||||
debugMessages('Stream response function completed')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue