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
|
// Format duration nicely
|
||||||
const formatDuration = (seconds: number) => {
|
const formatDuration = (seconds: number) => {
|
||||||
if (seconds < 1) {
|
if (seconds < 0.001) return `< 1ms`
|
||||||
return `${Math.round(seconds * 1000)}ms`
|
if (seconds < 1) return `${Math.round(seconds * 1000)}ms`
|
||||||
}
|
|
||||||
return `${seconds.toFixed(1)}s`
|
return `${seconds.toFixed(1)}s`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,8 +38,8 @@ const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message }) => {
|
||||||
<div className={`flex justify-start`}>
|
<div className={`flex justify-start`}>
|
||||||
<div className={`text-zinc-900 w-full`}>
|
<div className={`text-zinc-900 w-full`}>
|
||||||
<div
|
<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 ${
|
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 opacity-100' : ''
|
isExpanded ? 'border-zinc-300' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={toggleExpanded}
|
onClick={toggleExpanded}
|
||||||
>
|
>
|
||||||
|
|
@ -61,7 +60,11 @@ const ReasoningMessage: React.FC<ReasoningMessageProps> = ({ message }) => {
|
||||||
// Collapsed view: show timing summary
|
// Collapsed view: show timing summary
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<span className="text-zinc-500">
|
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,13 @@
|
||||||
import { useState, useRef } from 'react'
|
import { useRef, useState } from 'react'
|
||||||
import { streamText, tool, jsonSchema } from 'ai'
|
import { CoreMessage, jsonSchema, streamText, tool } from 'ai'
|
||||||
import { createGroq } from '@ai-sdk/groq'
|
import { createGroq } from '@ai-sdk/groq'
|
||||||
import { createAnthropic } from '@ai-sdk/anthropic'
|
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 { type Model } from '../types/models'
|
||||||
import { getApiKey } from '../utils/apiKeys'
|
import { getApiKey } from '../utils/apiKeys'
|
||||||
import { type Tool } from 'use-mcp/react'
|
import { type Tool } from 'use-mcp/react'
|
||||||
import { useConversationUpdater } from './useConversationUpdater'
|
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
|
// Type guard for messages with content
|
||||||
const hasContent = (message: Message): message is UserMessage | AssistantMessage | SystemMessage => {
|
const hasContent = (message: Message): message is UserMessage | AssistantMessage | SystemMessage => {
|
||||||
return 'content' in message
|
return 'content' in message
|
||||||
|
|
@ -44,7 +37,7 @@ export const useStreamResponse = ({
|
||||||
|
|
||||||
const { updateConversation } = useConversationUpdater({
|
const { updateConversation } = useConversationUpdater({
|
||||||
conversationId,
|
conversationId,
|
||||||
setConversations
|
setConversations,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Convert MCP tools to the format expected by the 'ai' package
|
// 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
|
// Convert MCP tools to AI package format
|
||||||
const aiTools = convertMcpToolsToAiTools(mcpTools)
|
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
|
// Prepare stream options
|
||||||
const streamOptions = {
|
const streamOptions = {
|
||||||
model: modelInstance,
|
model: modelInstance,
|
||||||
messages: messages
|
messages: messagesToSend,
|
||||||
.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,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
||||||
maxSteps: 5, // Allow up to 5 steps for tool calling
|
maxSteps: 5, // Allow up to 5 steps for tool calling
|
||||||
abortSignal: controller.signal,
|
abortSignal: controller.signal,
|
||||||
|
|
@ -161,10 +156,11 @@ export const useStreamResponse = ({
|
||||||
|
|
||||||
// Use fullStream to get all events including tool calls, results, and text
|
// Use fullStream to get all events including tool calls, results, and text
|
||||||
for await (const event of result.fullStream) {
|
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) => {
|
updateConversation((conv) => {
|
||||||
const lastMessage = conv.messages?.at(-1)
|
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 updatedMessage: Message | undefined
|
||||||
let newMessage: Message | undefined
|
let newMessage: Message | undefined
|
||||||
try {
|
try {
|
||||||
|
|
@ -177,7 +173,7 @@ export const useStreamResponse = ({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We need a new reasoning block!
|
// 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)
|
// Create a new assistant message for reasoning (even if we already have one)
|
||||||
// This handles multiple reasoning sessions in the same conversation turn
|
// This handles multiple reasoning sessions in the same conversation turn
|
||||||
|
|
@ -194,9 +190,15 @@ export const useStreamResponse = ({
|
||||||
if (lastMessage?.role === 'assistant' && lastMessage.type === 'reasoning') {
|
if (lastMessage?.role === 'assistant' && lastMessage.type === 'reasoning') {
|
||||||
updatedMessage = {
|
updatedMessage = {
|
||||||
...lastMessage,
|
...lastMessage,
|
||||||
reasoningEndTime: Date.now(),
|
reasoningEndTime: eventTime,
|
||||||
isReasoningStreaming: false,
|
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') {
|
if (event.type === 'tool-call') {
|
||||||
|
|
@ -255,39 +257,13 @@ export const useStreamResponse = ({
|
||||||
messages.push(newMessage)
|
messages.push(newMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log({ updatedMessage, newMessage })
|
// console.log({ updatedMessage, newMessage })
|
||||||
return { ...conv, messages }
|
return { ...conv, messages }
|
||||||
}
|
}
|
||||||
|
|
||||||
return conv
|
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) {
|
} catch (error: unknown) {
|
||||||
if (controller.signal.aborted) {
|
if (controller.signal.aborted) {
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -296,7 +272,6 @@ export const useStreamResponse = ({
|
||||||
} finally {
|
} finally {
|
||||||
setStreamStarted(false)
|
setStreamStarted(false)
|
||||||
setController(new AbortController())
|
setController(new AbortController())
|
||||||
debugMessages('Stream response function completed')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue