Only updating one conversation at a time
This commit is contained in:
parent
b07b0a73e1
commit
cd8df15e94
3 changed files with 70 additions and 45 deletions
|
|
@ -12,6 +12,7 @@ import ModelSelectionModal from './ModelSelectionModal'
|
|||
import McpServerModal from './McpServerModal'
|
||||
import { useAutoscroll } from '../hooks/useAutoscroll'
|
||||
import { useStreamResponse } from '../hooks/useStreamResponse'
|
||||
import { useConversationUpdater } from '../hooks/useConversationUpdater'
|
||||
import { setApiKey } from '../utils/apiKeys'
|
||||
import { hasApiKey } from '../utils/apiKeys'
|
||||
import ApiKeyModal from './ApiKeyModal'
|
||||
|
|
@ -88,6 +89,11 @@ const ConversationThread: React.FC<ConversationThreadProps> = ({
|
|||
}
|
||||
}
|
||||
|
||||
const { updateConversation } = useConversationUpdater({
|
||||
conversationId,
|
||||
setConversations
|
||||
})
|
||||
|
||||
const { isLoading, setIsLoading, streamStarted, controller, streamResponse, aiResponseRef } = useStreamResponse({
|
||||
conversationId,
|
||||
setConversations,
|
||||
|
|
@ -133,14 +139,10 @@ const ConversationThread: React.FC<ConversationThreadProps> = ({
|
|||
setInput('')
|
||||
setIsLoading(true)
|
||||
|
||||
setConversations((prev) => {
|
||||
const updated = [...prev]
|
||||
const conv = updated.find((c) => c.id === conversationId)
|
||||
if (conv && conv.messages?.[conv.messages.length - 1] !== userMessage) {
|
||||
conv.messages.push(userMessage)
|
||||
}
|
||||
return updated
|
||||
})
|
||||
updateConversation((conv) => ({
|
||||
...conv,
|
||||
messages: [...conv.messages, userMessage]
|
||||
}))
|
||||
|
||||
await streamResponse([...currentConversation.messages, userMessage])
|
||||
|
||||
|
|
|
|||
27
examples/chat-ui/src/hooks/useConversationUpdater.ts
Normal file
27
examples/chat-ui/src/hooks/useConversationUpdater.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { type Conversation } from '../types'
|
||||
|
||||
interface UseConversationUpdaterProps {
|
||||
conversationId?: number
|
||||
setConversations: React.Dispatch<React.SetStateAction<Conversation[]>>
|
||||
}
|
||||
|
||||
export const useConversationUpdater = ({ conversationId, setConversations }: UseConversationUpdaterProps) => {
|
||||
|
||||
const updateConversation = (updater: (conversation: Conversation) => Conversation) => {
|
||||
setConversations((prev) => {
|
||||
const conversation = prev.find((c) => c.id === conversationId)
|
||||
if (!conversation) {
|
||||
console.error(`Missing conversation for ID ${conversationId}`)
|
||||
return prev
|
||||
}
|
||||
|
||||
const updatedConversation = updater(conversation)
|
||||
|
||||
return prev.map((c) =>
|
||||
c.id === conversationId ? updatedConversation : c
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return { updateConversation }
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { type Message, type Conversation, type UserMessage, type AssistantMessag
|
|||
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[]) => {
|
||||
|
|
@ -40,6 +41,11 @@ export const useStreamResponse = ({
|
|||
const [streamStarted, setStreamStarted] = useState(false)
|
||||
const [controller, setController] = useState(new AbortController())
|
||||
const aiResponseRef = useRef<string>('')
|
||||
|
||||
const { updateConversation } = useConversationUpdater({
|
||||
conversationId,
|
||||
setConversations
|
||||
})
|
||||
|
||||
// Convert MCP tools to the format expected by the 'ai' package
|
||||
const convertMcpToolsToAiTools = (mcpTools: Tool[]) => {
|
||||
|
|
@ -71,17 +77,17 @@ export const useStreamResponse = ({
|
|||
}
|
||||
|
||||
// Check if a model supports reasoning
|
||||
const supportsReasoning = (model: Model) => {
|
||||
const reasoningModels = [
|
||||
'qwen/qwen3-32b',
|
||||
'qwen-qwq-32b',
|
||||
'deepseek-r1-distill-llama-70b',
|
||||
'claude-4-opus-20250514',
|
||||
'claude-4-sonnet-20250514',
|
||||
'claude-3-7-sonnet-20250219',
|
||||
]
|
||||
return reasoningModels.includes(model.modelId)
|
||||
}
|
||||
// const supportsReasoning = (model: Model) => {
|
||||
// const reasoningModels = [
|
||||
// 'qwen/qwen3-32b',
|
||||
// 'qwen-qwq-32b',
|
||||
// 'deepseek-r1-distill-llama-70b',
|
||||
// 'claude-4-opus-20250514',
|
||||
// 'claude-4-sonnet-20250514',
|
||||
// 'claude-3-7-sonnet-20250219',
|
||||
// ]
|
||||
// return reasoningModels.includes(model.modelId)
|
||||
// }
|
||||
|
||||
const getModelInstance = (model: Model, apiKey: string) => {
|
||||
let baseModel
|
||||
|
|
@ -156,12 +162,7 @@ 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 })
|
||||
setConversations((prev) => {
|
||||
const conv = prev.find((c) => c.id === conversationId)
|
||||
if (!conv) {
|
||||
console.error(`Missing conversation for ID ${conversationId}! Ignoring ${JSON.stringify(event)}`)
|
||||
return prev
|
||||
}
|
||||
updateConversation((conv) => {
|
||||
const lastMessage = conv.messages?.at(-1)
|
||||
console.log({ setConversations: event, conv: JSON.parse(JSON.stringify(conv)) })
|
||||
let updatedMessage: Message | undefined
|
||||
|
|
@ -242,35 +243,30 @@ export const useStreamResponse = ({
|
|||
} catch (e) {
|
||||
console.error('Error in full stream processing:', e)
|
||||
}
|
||||
let updated = prev
|
||||
|
||||
if (updatedMessage || newMessage) {
|
||||
updated = prev.map((c) => {
|
||||
if (c.id !== conversationId) return c
|
||||
const messages = [...c.messages]
|
||||
const messages = [...conv.messages]
|
||||
|
||||
if (updatedMessage) {
|
||||
messages.splice(-1, 1, updatedMessage)
|
||||
}
|
||||
if (updatedMessage) {
|
||||
messages.splice(-1, 1, updatedMessage)
|
||||
}
|
||||
|
||||
if (newMessage) {
|
||||
messages.push(newMessage)
|
||||
}
|
||||
if (newMessage) {
|
||||
messages.push(newMessage)
|
||||
}
|
||||
|
||||
return { ...c, messages }
|
||||
})
|
||||
console.log({ updatedMessage, newMessage })
|
||||
return { ...conv, messages }
|
||||
}
|
||||
console.log({ updatedMessage, newMessage })
|
||||
return updated
|
||||
|
||||
return conv
|
||||
})
|
||||
}
|
||||
|
||||
// Show final conversation state
|
||||
setConversations((prev) => {
|
||||
const conv = prev.find((c) => c.id === conversationId)
|
||||
if (conv) {
|
||||
debugMessages('Final conversation state:', JSON.stringify(conv.messages))
|
||||
}
|
||||
return prev
|
||||
updateConversation((conv) => {
|
||||
debugMessages('Final conversation state:', JSON.stringify(conv.messages))
|
||||
return conv
|
||||
})
|
||||
//
|
||||
// // Final cleanup - ensure reasoning streaming is stopped
|
||||
|
|
|
|||
Loading…
Reference in a new issue