@@ -6,7 +6,6 @@ import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
6
6
import rehypeKatex from 'rehype-katex'
7
7
import remarkGfm from 'remark-gfm'
8
8
import remarkMath from 'remark-math'
9
- import type { FileSearchCompletedData } from '../../../shared/types'
10
9
import type { ActivityPeriod , Message } from '../../types'
11
10
import { ConversationSplash } from './general/ConversationSplash'
12
11
import { LoadingMessage } from './general/LoadingMessage'
@@ -18,7 +17,9 @@ import { t } from 'i18next'
18
17
import FormatQuoteIcon from '@mui/icons-material/FormatQuote'
19
18
import useLocalStorageState from '../../hooks/useLocalStorageState'
20
19
import { BlueButton } from './general/Buttons'
21
- import { ToolCallStatusEvent } from '../../../shared/chat'
20
+ import type { ToolCallResultEvent , ToolCallStatusEvent } from '../../../shared/chat'
21
+ import { ChatToolResult } from '../../../shared/tools'
22
+ import { useMemo } from 'react'
22
23
23
24
const UserMessage = ( { content, attachements } : { content : string ; attachements ?: string } ) => (
24
25
< Box
@@ -55,18 +56,67 @@ const UserMessage = ({ content, attachements }: { content: string; attachements?
55
56
</ Box >
56
57
)
57
58
59
+ const ToolResult = ( { toolResult, handleToolResult } : { toolResult : ToolCallResultEvent ; handleToolResult : ( toolResult : ToolCallResultEvent ) => void } ) => {
60
+ const sources = useMemo ( ( ) => Array . from ( new Set < string > ( toolResult . result . files . map ( ( file ) => file . fileName ) ) . values ( ) ) . join ( ', ' ) , [ ] )
61
+ return (
62
+ < Box
63
+ data-testId = "file-search-sources"
64
+ sx = { {
65
+ display : 'flex' ,
66
+ alignItems : { xs : 'flex-start' , sm : 'center' } ,
67
+ gap : 2 ,
68
+ fontStyle : 'italic' ,
69
+ maxWidth : 'fit-content' ,
70
+ opacity : '0.85' ,
71
+ mt : 3 ,
72
+ cursor : 'pointer' ,
73
+ padding : '0.6rem' ,
74
+ borderRadius : '0.6rem' ,
75
+ } }
76
+ onClick = { ( ) => {
77
+ handleToolResult ( toolResult )
78
+ } }
79
+ >
80
+ < FormatQuoteIcon sx = { { fontSize : '2rem' } } />
81
+ < Box sx = { { minWidth : 0 , mt : { xs : 0.5 , md : 0 } } } >
82
+ < Box
83
+ sx = { {
84
+ display : 'flex' ,
85
+ flexDirection : 'column' ,
86
+ } }
87
+ >
88
+ < Typography
89
+ variant = "body2"
90
+ sx = { {
91
+ mr : 2 ,
92
+ wordBreak : 'break-all' ,
93
+ textOverflow : 'ellipsis' ,
94
+ overflow : 'hidden' ,
95
+ whiteSpace : 'nowrap' ,
96
+ } }
97
+ >
98
+ { `${ t ( 'chat:displaySources' ) } : ` }
99
+
100
+ < em > { sources } </ em >
101
+ </ Typography >
102
+ </ Box >
103
+ </ Box >
104
+ </ Box >
105
+ )
106
+ }
107
+
58
108
const AssistantMessage = ( {
59
109
content,
60
110
error,
61
- fileSearchResult ,
62
- setActiveFileSearchResult ,
63
- setShowFileSearchResults ,
111
+ toolResults ,
112
+ setActiveToolResult ,
113
+ setShowToolResults ,
64
114
} : {
65
115
content : string
66
116
error ?: string
67
- fileSearchResult ?: FileSearchCompletedData
68
- setActiveFileSearchResult : ( data : FileSearchCompletedData ) => void
69
- setShowFileSearchResults : ( show : boolean ) => void
117
+ toolResults ?: Record < string , ToolCallResultEvent >
118
+ setActiveToolResult : ( data : ToolCallResultEvent ) => void
119
+ setShowToolResults : ( show : boolean ) => void
70
120
} ) => {
71
121
const processedContent = preprocessMath ( content )
72
122
const katexOptions = {
@@ -109,9 +159,10 @@ const AssistantMessage = ({
109
159
}
110
160
let codeCount = 0
111
161
112
- const handleFileSearchResult = ( fileSearchResult : FileSearchCompletedData ) => {
113
- setActiveFileSearchResult ( fileSearchResult )
114
- setShowFileSearchResults ( true )
162
+ const handleToolResult = ( toolResult : ToolCallResultEvent ) => {
163
+ console . log ( toolResult )
164
+ setActiveToolResult ( toolResult )
165
+ setShowToolResults ( true )
115
166
}
116
167
117
168
return (
@@ -215,53 +266,9 @@ const AssistantMessage = ({
215
266
< Typography variant = "body1" fontStyle = "italic" color = "#cc0000" > { `\n\n ${ error } ` } </ Typography >
216
267
</ Box >
217
268
) }
218
- { fileSearchResult ?. status === 'completed' && (
219
- < >
220
- < Box
221
- data-testId = "file-search-sources"
222
- sx = { {
223
- display : 'flex' ,
224
- alignItems : { xs : 'flex-start' , sm : 'center' } ,
225
- gap : 2 ,
226
- fontStyle : 'italic' ,
227
- maxWidth : 'fit-content' ,
228
- opacity : '0.85' ,
229
- mt : 3 ,
230
- cursor : 'pointer' ,
231
- padding : '0.6rem' ,
232
- borderRadius : '0.6rem' ,
233
- } }
234
- onClick = { ( ) => {
235
- handleFileSearchResult ( fileSearchResult )
236
- } }
237
- >
238
- < FormatQuoteIcon sx = { { fontSize : '2rem' } } />
239
- < Box sx = { { minWidth : 0 , mt : { xs : 0.5 , md : 0 } } } >
240
- < Box
241
- sx = { {
242
- display : 'flex' ,
243
- flexDirection : 'column' ,
244
- } }
245
- >
246
- < Typography
247
- variant = "body2"
248
- sx = { {
249
- mr : 2 ,
250
- wordBreak : 'break-all' ,
251
- textOverflow : 'ellipsis' ,
252
- overflow : 'hidden' ,
253
- whiteSpace : 'nowrap' ,
254
- } }
255
- >
256
- { `${ t ( 'chat:displaySources' ) } : ` }
257
-
258
- < em > { fileSearchResult ?. searchedFileNames . join ( '\r\n' ) } </ em >
259
- </ Typography >
260
- </ Box >
261
- </ Box >
262
- </ Box >
263
- </ >
264
- ) }
269
+ { Object . values ( toolResults ?? { } ) . map ( ( toolResult ) => (
270
+ < ToolResult key = { toolResult . callId } toolResult = { toolResult } handleToolResult = { handleToolResult } />
271
+ ) ) }
265
272
</ Box >
266
273
)
267
274
}
@@ -270,14 +277,14 @@ const MessageItem = ({
270
277
message,
271
278
isLastAssistantNode,
272
279
expandedNodeHeight,
273
- setActiveFileSearchResult ,
274
- setShowFileSearchResults ,
280
+ setActiveToolResult ,
281
+ setShowToolResults ,
275
282
} : {
276
283
message : Message
277
284
isLastAssistantNode : boolean
278
285
expandedNodeHeight : number
279
- setActiveFileSearchResult : ( data : FileSearchCompletedData ) => void
280
- setShowFileSearchResults : ( show : boolean ) => void
286
+ setActiveToolResult : ( data : ToolCallResultEvent ) => void
287
+ setShowToolResults : ( show : boolean ) => void
281
288
} ) => {
282
289
if ( message . role === 'assistant' ) {
283
290
return (
@@ -292,9 +299,9 @@ const MessageItem = ({
292
299
< AssistantMessage
293
300
content = { message . content }
294
301
error = { message . error }
295
- fileSearchResult = { message . fileSearchResult }
296
- setActiveFileSearchResult = { setActiveFileSearchResult }
297
- setShowFileSearchResults = { setShowFileSearchResults }
302
+ toolResults = { message . toolCalls }
303
+ setActiveToolResult = { setActiveToolResult }
304
+ setShowToolResults = { setShowToolResults }
298
305
/>
299
306
</ Box >
300
307
)
@@ -316,8 +323,8 @@ export const Conversation = ({
316
323
completion,
317
324
toolCalls,
318
325
isStreaming,
319
- setActiveFileSearchResult ,
320
- setShowFileSearchResults ,
326
+ setActiveToolResult ,
327
+ setShowToolResults ,
321
328
} : {
322
329
courseName ?: string
323
330
courseDate ?: ActivityPeriod
@@ -327,8 +334,8 @@ export const Conversation = ({
327
334
completion : string
328
335
toolCalls : { [ callId : string ] : ToolCallStatusEvent }
329
336
isStreaming : boolean
330
- setActiveFileSearchResult : ( data : FileSearchCompletedData ) => void
331
- setShowFileSearchResults : ( show : boolean ) => void
337
+ setActiveToolResult : ( data : ToolCallResultEvent ) => void
338
+ setShowToolResults : ( show : boolean ) => void
332
339
} ) => {
333
340
const [ reminderSeen , setReminderSeen ] = useLocalStorageState < boolean > ( 'reminderSeen' , false )
334
341
@@ -355,8 +362,8 @@ export const Conversation = ({
355
362
message = { message }
356
363
isLastAssistantNode = { isLastAssistantNode }
357
364
expandedNodeHeight = { expandedNodeHeight }
358
- setActiveFileSearchResult = { setActiveFileSearchResult }
359
- setShowFileSearchResults = { setShowFileSearchResults }
365
+ setActiveToolResult = { setActiveToolResult }
366
+ setShowToolResults = { setShowToolResults }
360
367
/>
361
368
)
362
369
} ) }
@@ -368,11 +375,11 @@ export const Conversation = ({
368
375
message = { { role : 'assistant' , content : completion } }
369
376
isLastAssistantNode = { true }
370
377
expandedNodeHeight = { expandedNodeHeight }
371
- setActiveFileSearchResult = { setActiveFileSearchResult }
372
- setShowFileSearchResults = { setShowFileSearchResults }
378
+ setActiveToolResult = { setActiveToolResult }
379
+ setShowToolResults = { setShowToolResults }
373
380
/>
374
381
) : (
375
- < LoadingMessage expandedNodeHeight = { expandedNodeHeight } isFileSearching = { Object . values ( toolCalls ) . some ( ( call ) => ! ! call . result ) } />
382
+ < LoadingMessage expandedNodeHeight = { expandedNodeHeight } toolCalls = { toolCalls } />
376
383
) ) }
377
384
</ Box >
378
385
{ ! reminderSeen && ! isStreaming && messages . length > 15 && (
0 commit comments