Skip to content

Commit 64217ac

Browse files
committed
feat: continuous thread UI and finalize functionality.
1 parent e3672fe commit 64217ac

File tree

9 files changed

+82
-65
lines changed

9 files changed

+82
-65
lines changed

apps/masterbots.ai/app/u/[slug]/t/[category]/[chatbot]/[threadId]/page.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,22 @@ interface ThreadPageProps {
1010
}
1111
}
1212
export default async function ThreadPage({ params }: ThreadPageProps) {
13-
14-
1513
const thread = await getThread({
1614
threadId: params.threadId,
1715
jwt: ''
1816
})
19-
17+
2018
if(!thread){
2119
return <div>Thread not found</div>
2220
}
2321
const { user, chatbot, messages } = thread
2422

2523
return (
2624
<BrowseChatMessageList
27-
user={user as User | undefined}
28-
chatbot={chatbot}
29-
messages={messages}
30-
isThread
31-
/>
25+
user={user as User | undefined}
26+
chatbot={chatbot}
27+
messages={messages}
28+
isThread
29+
/>
3230
)
3331
}

apps/masterbots.ai/components/routes/browse/browse-chat-message-list.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export function BrowseChatMessageList({
4343
setPairs(prePairs)
4444
} else setPairs([])
4545
}, [messages])
46-
4746
return (
4847
<div>
4948
{pairs.map((pair: MessagePair, key: number) => (

apps/masterbots.ai/components/routes/browse/browse-chat-messages.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { BrowseChatMessageList } from '@/components/routes/browse/browse-chat-me
2121
import { getMessages } from '@/services/hasura'
2222
import { ExternalLink } from '@/components/shared/external-link'
2323
import { toSlug } from 'mb-lib'
24+
import Link from 'next/link'
2425

2526
export type MessagePair = {
2627
userMessage: Message
@@ -38,16 +39,20 @@ export function convertMessage(message: Message) {
3839

3940
export function BrowseChatMessages({
4041
threadId,
42+
parentThreadId,
4143
user,
4244
chatbot
4345
}: {
4446
threadId: string
47+
parentThreadId?: string
4548
user?: User
4649
chatbot?: Chatbot
4750
}) {
4851
const [messages, setMessages] = React.useState<Message[]>([])
52+
const [parentThreadTitle, setParentThreadTitle] = React.useState<string | null>(null)
4953
const { name: categoryName } = chatbot?.categories[0].category || { name: '' }
5054
const { name: chatBotName } = chatbot || { name: '' }
55+
const parentThreadUrl = `/b/${toSlug(chatBotName)}/${parentThreadId}`
5156

5257
// Fetch messages for the specified thread ID
5358
const fetchMessages = async () => {
@@ -57,11 +62,27 @@ export function BrowseChatMessages({
5762
}
5863
}
5964

65+
// Fetch parent thread info
66+
const fetchParentThreadInfo = async () => {
67+
if (parentThreadId) {
68+
const parentThread = await getMessages({ threadId: parentThreadId })
69+
const parentThreadTitle = parentThread[0]?.content
70+
setParentThreadTitle(parentThreadTitle)
71+
}
72+
}
73+
6074
// Effect to fetch messages when the thread ID changes
6175
React.useEffect(() => {
6276
fetchMessages()
6377
}, [threadId])
6478

79+
// Effect to fetch the parent thread info if the parentThreadId exists
80+
React.useEffect(() => {
81+
if (parentThreadId) {
82+
fetchParentThreadInfo()
83+
}
84+
}, [parentThreadId])
85+
6586
return (
6687
<div className="w-full">
6788
{chatbot ? (
@@ -73,6 +94,9 @@ export function BrowseChatMessages({
7394
''
7495
)}
7596
<div className="flex flex-col max-w-screen-lg px-4 mx-auto mt-8 gap-y-4">
97+
{ parentThreadTitle && (
98+
<p>This thread is an extension of the original content from the parent thread titled <Link className="text-muted-foreground hover:text-primary transition-colors underline" href={parentThreadUrl}>"{ parentThreadTitle }"</Link>. To get the full context and explore more, visit the <Link className="text-muted-foreground hover:text-primary transition-colors underline" href={parentThreadUrl}>original post</Link>.</p>
99+
)}
76100
<BrowseChatMessageList
77101
user={user}
78102
chatbot={chatbot}

apps/masterbots.ai/components/routes/browse/browse-thread.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export function BrowseThread({
3434
chatbot={thread?.chatbot}
3535
user={thread?.user || undefined}
3636
threadId={thread.threadId}
37+
parentThreadId={thread?.parentThreadId}
3738
/>
3839
) : (
3940
''

apps/masterbots.ai/components/routes/chat/chat.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function Chat({
7070
setLoadingState,
7171
} = useThread();
7272
const { activeChatbot } = useSidebar();
73-
const { isContinuosThread } = useThreadVisibility()
73+
const { isContinuousThread } = useThreadVisibility()
7474
const containerRef = React.useRef<HTMLDivElement>();
7575
const params = useParams<{ chatbot: string; threadId: string }>();
7676
const chatbot = chatbotProps || activeThread?.chatbot || activeChatbot as Chatbot
@@ -115,9 +115,9 @@ export function Chat({
115115
}
116116
};
117117

118-
const chatSearchMessage = (isNewChat: boolean, isContinuosThread: boolean, allMessages: UiUtilsMessage[] ) => {
118+
const chatSearchMessage = (isNewChat: boolean, isContinuousThread: boolean, allMessages: UiUtilsMessage[] ) => {
119119
const threadTitle = allMessages.filter(m => m.role === 'user')[0]?.content
120-
if (isContinuosThread && allMessages) {
120+
if (isContinuousThread && allMessages) {
121121
return `Create new thread from "${threadTitle}" by making a new question.`
122122
} else if (isNewChat) {
123123
return `Start New Chat with ${chatbot.name}`
@@ -186,15 +186,15 @@ export function Chat({
186186
id={params.threadId || isNewChat ? threadId : activeThread?.threadId}
187187
isLoading={isLoading}
188188
stop={stop}
189-
append={isContinuosThread ? appendAsContinuousThread : appendWithMbContextPrompts}
189+
append={isContinuousThread ? appendAsContinuousThread : appendWithMbContextPrompts}
190190
reload={reload}
191191
messages={allMessages}
192192
input={input}
193193
setInput={setInput}
194194
chatbot={chatbot}
195195
placeholder={
196196
chatbot
197-
? chatSearchMessage(isNewChat, isContinuosThread, allMessages)
197+
? chatSearchMessage(isNewChat, isContinuousThread, allMessages)
198198
: ""
199199
}
200200
showReload={!isNewChat}

apps/masterbots.ai/components/routes/thread/user-thread-panel.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* - Updates the thread list when the active category or chatbot changes
1818
* - Handles loading state and pagination
1919
* - Sets the active thread when a thread is part of que Query Params.
20-
* - Handles the visibility of the continuos thread functionality.
20+
* - Handles the visibility of the continuous thread functionality.
2121
*
2222
* Props:
2323
* - chatbot: Optional string representing the selected chatbot
@@ -36,6 +36,7 @@ import { useThread } from '@/lib/hooks/use-thread'
3636
import { useThreadVisibility } from '@/lib/hooks/use-thread-visibility'
3737
import { getBrowseThreads, getThread, getThreads, getUserBySlug } from '@/services/hasura'
3838
import type { Thread } from 'mb-genql'
39+
import { Session } from 'next-auth/core/types'
3940
import { useSession } from 'next-auth/react'
4041
import { useParams, usePathname, useSearchParams } from 'next/navigation'
4142
import { useEffect, useMemo, useRef, useState } from 'react'
@@ -62,7 +63,7 @@ export default function UserThreadPanel({
6263
const { activeCategory, activeChatbot } = useSidebar()
6364
const { isOpenPopup, activeThread, setActiveThread, setIsOpenPopup } = useThread()
6465
const [loading, setLoading] = useState<boolean>(false)
65-
const { threads: hookThreads, isContinuosThread, setIsContinuosThread } = useThreadVisibility()
66+
const { threads: hookThreads, isContinuousThread, setIsContinuousThread } = useThreadVisibility()
6667
const [searchTerm, setSearchTerm] = useState<string>('')
6768
const searchParams = useSearchParams()
6869
const { slug, threadId } = params;
@@ -171,7 +172,7 @@ export default function UserThreadPanel({
171172
setLoading(false)
172173
}
173174

174-
const getThreadByContinuousThreadId = async () => {
175+
const getThreadByContinuousThreadId = async (continuousThreadId: string, session: Session) => {
175176
const thread = await getThread({
176177
threadId: continuousThreadId,
177178
jwt: session!.user?.hasuraJwt,
@@ -180,7 +181,7 @@ export default function UserThreadPanel({
180181
if (thread) {
181182
setActiveThread(thread)
182183
setThreads([thread])
183-
setIsContinuosThread(true)
184+
setIsContinuousThread(true)
184185
setTotalThreads(1)
185186
setCount(1)
186187
setIsOpenPopup(true)
@@ -189,7 +190,7 @@ export default function UserThreadPanel({
189190

190191
useEffect(() => {
191192
if (continuousThreadId && session) {
192-
getThreadByContinuousThreadId()
193+
getThreadByContinuousThreadId(continuousThreadId, session)
193194
}
194195
}, [continuousThreadId, session]);
195196

@@ -236,7 +237,7 @@ export default function UserThreadPanel({
236237
const showChatbotDetails = !loading && !searchTerm && threads.length === 0
237238
return (
238239
<>
239-
{ !isContinuosThread && (
240+
{ !isContinuousThread && (
240241
<div className="flex justify-between px-4 md:px-10 py-5 lg:max-w-[calc(100%-100px)] 2xl:max-w-full">
241242
<ChatSearchInput setThreads={setThreads} onSearch={setSearchTerm} />
242243
</div>

apps/masterbots.ai/lib/hooks/use-mb-chat.ts

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import { useModel } from '@/lib/hooks/use-model'
88
import { useSidebar } from '@/lib/hooks/use-sidebar'
99
import { useThread } from '@/lib/hooks/use-thread'
10+
import { useThreadVisibility } from '@/lib/hooks/use-thread-visibility'
1011
import { delayFetch } from '@/lib/utils'
1112
import {
1213
createThread,
@@ -59,6 +60,7 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
5960
messagesFromDB: [] as Message[]
6061
})
6162
const { customSonner } = useSonner()
63+
const { isContinuousThread } = useThreadVisibility()
6264
// console.log('[HOOK] webSearch', webSearch)
6365

6466
const params = useParams<{ chatbot: string; threadId: string }>()
@@ -110,15 +112,8 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
110112
model: selectedModel,
111113
clientType,
112114
webSearch
113-
// chatbot:
114-
// activeChatbot && activeChatbot?.categories?.length
115-
// ? {
116-
// chatbotId: activeChatbot?.chatbotId,
117-
// categoryId: activeChatbot?.categories[0].categoryId
118-
// }
119-
// : {},
120115
},
121-
async onResponse(response) {
116+
async onResponse(response: any) {
122117
if (response.status >= 400) {
123118
customSonner({ type: 'error', text: response.statusText })
124119

@@ -131,21 +126,30 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
131126
}
132127
}
133128
},
134-
async onFinish(message) {
129+
async onFinish(message: any) {
130+
let aiChatThreadId;
131+
132+
if (isContinuousThread) {
133+
aiChatThreadId = randomThreadId.current
134+
// aiChatQuestion =
135+
} else if (params.threadId || isNewChat) {
136+
aiChatThreadId = threadId
137+
} else {
138+
aiChatThreadId = activeThread?.threadId
139+
}
140+
135141
await Promise.all([
136142
saveNewMessage({
137143
role: 'user',
138-
threadId:
139-
params.threadId || isNewChat ? threadId : activeThread?.threadId,
144+
threadId: aiChatThreadId,
140145
content: userContentRef.current,
141146
jwt: session!.user?.hasuraJwt
142147
}),
143148
// ? Adding a delay to securely keep the order of messages
144149
delayFetch(),
145150
saveNewMessage({
146151
role: 'assistant',
147-
threadId:
148-
params.threadId || isNewChat ? threadId : activeThread?.threadId,
152+
threadId: aiChatThreadId,
149153
content: message.content,
150154
jwt: session!.user?.hasuraJwt
151155
})
@@ -154,12 +158,12 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
154158
setLoadingState(undefined)
155159
setActiveTool(undefined)
156160
},
157-
onToolCall({ toolCall }) {
161+
onToolCall({ toolCall }: any) {
158162
console.log('Tool call:', toolCall)
159163
customSonner({ type: 'info', text: `Tool call executed: ${toolCall.toolName}` })
160164
setActiveTool(toolCall as AiToolCall)
161165
},
162-
async onError(error) {
166+
async onError(error: any) {
163167
console.error('Error in chat: ', error)
164168

165169
customSonner({ type: 'error', text: 'Failed to send message. Please try again.' })
@@ -333,9 +337,10 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
333337

334338
const appendAsContinuousThread = async (userMessage: AiMessage | CreateMessage) => {
335339
const optimisticUserMessage = { ...userMessage, id: randomThreadId.current }
336-
console.log('session!.user.id', session!.user.id)
340+
const message = followingQuestionsPrompt(userMessage.content, messages.concat(allMessages))
341+
userContentRef.current = userMessage.content
337342

338-
await createThread({
343+
const createdThread = await createThread({
339344
threadId: randomThreadId.current as string,
340345
parentThreadId: activeThread?.threadId,
341346
chatbotId: chatbot ? chatbot?.chatbotId : 0,
@@ -344,29 +349,19 @@ export function useMBChat(config?: MBChatHookConfig): MBChatHookCallback {
344349
isPublic: activeChatbot?.name !== 'BlankBot'
345350
})
346351

347-
const thread = await getThread({
348-
threadId: randomThreadId.current as string,
349-
jwt: session!.user?.hasuraJwt
350-
})
351-
352-
append({
353-
...optimisticUserMessage,
354-
content: followingQuestionsPrompt(userContentRef.current, messages.concat(allMessages))
355-
})
352+
if (createdThread) {
353+
await append({
354+
...optimisticUserMessage,
355+
content: message
356+
})
356357

357-
saveNewMessage({
358-
role: 'user',
359-
threadId: randomThreadId.current,
360-
content: userMessage.content,
361-
jwt: session!.user?.hasuraJwt
362-
})
358+
router.push(`/${chatbot?.name.trim().toLowerCase()}/${randomThreadId.current}`, {
359+
scroll: false
360+
})
363361

364-
updateActiveThread(thread)
362+
router.refresh()
363+
}
365364

366-
router.push(`/${chatbot?.name.trim().toLowerCase()}/${randomThreadId.current}`, {
367-
scroll: false
368-
})
369-
router.refresh()
370365
return null
371366
}
372367

apps/masterbots.ai/lib/hooks/use-thread-visibility.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ interface ThreadVisibilityContextProps {
2626
handleToggleAdminMode: () => void
2727
adminApproveThread: (threadId: string) => void
2828
isAdminMode: boolean
29-
isContinuosThread: boolean,
30-
setIsContinuosThread: React.Dispatch<React.SetStateAction<boolean>>
29+
isContinuousThread: boolean,
30+
setIsContinuousThread: React.Dispatch<React.SetStateAction<boolean>>
3131
}
3232

3333
const ThreadVisibilityContext = React.createContext<
@@ -54,7 +54,7 @@ export function ThreadVisibilityProvider({
5454
const [isPublic, setIsPublic] = useState(false)
5555
const [threads, setThreads] = useState<Thread[]>([])
5656
const [isAdminMode, setIsAdminMode] = React.useState<boolean>(false)
57-
const [isContinuosThread, setIsContinuosThread] = React.useState<boolean>(false)
57+
const [isContinuousThread, setIsContinuousThread] = React.useState<boolean>(false)
5858
const { customSonner } = useSonner()
5959

6060
const session = useSession()
@@ -188,8 +188,8 @@ export function ThreadVisibilityProvider({
188188
handleToggleAdminMode,
189189
adminApproveThread,
190190
isAdminMode,
191-
isContinuosThread,
192-
setIsContinuosThread
191+
isContinuousThread,
192+
setIsContinuousThread
193193
}}
194194
>
195195
{children}

0 commit comments

Comments
 (0)