@@ -2,6 +2,7 @@ import cx from 'classnames'
2
2
import * as Eff from 'effect'
3
3
import * as React from 'react'
4
4
import * as M from '@material-ui/core'
5
+ import * as Icons from '@material-ui/icons'
5
6
6
7
import JsonDisplay from 'components/JsonDisplay'
7
8
import Markdown from 'components/Markdown'
@@ -14,15 +15,15 @@ import Input from './Input'
14
15
15
16
const BG = {
16
17
intense : M . colors . indigo [ 900 ] ,
17
- bright : M . colors . indigo [ 500 ] ,
18
- faint : M . colors . common . white ,
18
+ normal : M . colors . common . white ,
19
+ faint : M . colors . grey [ 600 ] ,
19
20
}
20
21
21
22
const useMessageContainerStyles = M . makeStyles ( ( t ) => ( {
22
23
align_left : { } ,
23
24
align_right : { } ,
24
25
color_intense : { } ,
25
- color_bright : { } ,
26
+ color_normal : { } ,
26
27
color_faint : { } ,
27
28
messageContainer : {
28
29
display : 'flex' ,
@@ -46,13 +47,17 @@ const useMessageContainerStyles = M.makeStyles((t) => ({
46
47
background : BG . intense ,
47
48
color : M . fade ( t . palette . common . white , 0.8 ) ,
48
49
} ,
49
- '$color_bright &' : {
50
- background : BG . bright ,
51
- color : t . palette . common . white ,
50
+ '$color_normal &' : {
51
+ background : BG . normal ,
52
+ color : t . palette . text . primary ,
52
53
} ,
53
54
'$color_faint &' : {
54
55
background : BG . faint ,
55
- color : t . palette . text . primary ,
56
+ color : t . palette . getContrastText ( BG . faint ) ,
57
+ opacity : 0.5 ,
58
+ '&:hover' : {
59
+ opacity : 1 ,
60
+ } ,
56
61
} ,
57
62
'$align_right &' : {
58
63
borderBottomRightRadius : 0 ,
@@ -83,15 +88,15 @@ const useMessageContainerStyles = M.makeStyles((t) => ({
83
88
} ) )
84
89
85
90
interface MessageContainerProps {
86
- color ?: 'intense' | 'bright ' | 'faint'
91
+ color ?: 'intense' | 'normal ' | 'faint'
87
92
align ?: 'left' | 'right'
88
93
children : React . ReactNode
89
94
actions ?: React . ReactNode
90
95
timestamp ?: Date
91
96
}
92
97
93
98
function MessageContainer ( {
94
- color = 'faint ' ,
99
+ color = 'normal ' ,
95
100
align = 'left' ,
96
101
children,
97
102
actions,
@@ -131,6 +136,32 @@ const useMessageActionStyles = M.makeStyles({
131
136
} ,
132
137
} )
133
138
139
+ const useToolMessageStyles = M . makeStyles ( ( t ) => ( {
140
+ header : {
141
+ display : 'flex' ,
142
+ alignItems : 'center' ,
143
+ cursor : 'pointer' ,
144
+ userSelect : 'none' ,
145
+ '&:hover' : {
146
+ opacity : 0.8 ,
147
+ } ,
148
+ } ,
149
+ icon : {
150
+ fontSize : '1rem' ,
151
+ color : 'inherit' ,
152
+ } ,
153
+ toolName : {
154
+ marginLeft : t . spacing ( 1 ) ,
155
+ marginRight : t . spacing ( 1 ) ,
156
+ } ,
157
+ spinner : {
158
+ color : 'inherit' ,
159
+ } ,
160
+ details : {
161
+ marginTop : t . spacing ( 1 ) ,
162
+ } ,
163
+ } ) )
164
+
134
165
interface MessageActionProps {
135
166
children : React . ReactNode
136
167
className ?: string
@@ -154,6 +185,42 @@ interface ConversationStateProps {
154
185
state : Model . Conversation . State [ '_tag' ]
155
186
}
156
187
188
+ interface ToolMessageProps {
189
+ name : string
190
+ status ?: 'success' | 'error' | 'running'
191
+ details : Record < string , any >
192
+ timestamp : Date
193
+ actions ?: React . ReactNode
194
+ }
195
+
196
+ function ToolMessage ( { name, status, details, timestamp, actions } : ToolMessageProps ) {
197
+ const classes = useToolMessageStyles ( )
198
+ const [ expanded , setExpanded ] = React . useState ( false )
199
+
200
+ const toggleExpanded = React . useCallback ( ( ) => {
201
+ setExpanded ( ( prev ) => ! prev )
202
+ } , [ ] )
203
+
204
+ return (
205
+ < MessageContainer color = "faint" timestamp = { timestamp } actions = { actions } >
206
+ < div className = { classes . header } onClick = { toggleExpanded } >
207
+ < Icons . Build className = { classes . icon } />
208
+ < span className = { classes . toolName } > { name } </ span >
209
+ { status === 'success' && < Icons . CheckCircleOutline className = { classes . icon } /> }
210
+ { status === 'error' && < Icons . ErrorOutline className = { classes . icon } /> }
211
+ { status === 'running' && (
212
+ < M . CircularProgress size = { 14 } thickness = { 4 } className = { classes . spinner } />
213
+ ) }
214
+ </ div >
215
+ < M . Collapse in = { expanded } >
216
+ < div className = { classes . details } >
217
+ < JsonDisplay defaultExpanded = { 2 } name = "details" value = { details } />
218
+ </ div >
219
+ </ M . Collapse >
220
+ </ MessageContainer >
221
+ )
222
+ }
223
+
157
224
type MessageEventProps = ConversationDispatchProps &
158
225
ConversationStateProps &
159
226
ReturnType < typeof Model . Conversation . Event . Message >
@@ -174,7 +241,7 @@ function MessageEvent({
174
241
175
242
return (
176
243
< MessageContainer
177
- color = { role === 'user' ? 'intense' : 'faint ' }
244
+ color = { role === 'user' ? 'intense' : 'normal ' }
178
245
align = { role === 'user' ? 'right' : 'left' }
179
246
actions = { discard && < MessageAction onClick = { discard } > discard</ MessageAction > }
180
247
timestamp = { timestamp }
@@ -212,18 +279,13 @@ function ToolUseEvent({
212
279
[ toolUseId , input , result ] ,
213
280
)
214
281
return (
215
- < MessageContainer
216
- color = "bright"
282
+ < ToolMessage
283
+ name = { name }
284
+ status = { result . status }
285
+ details = { details }
217
286
timestamp = { timestamp }
218
287
actions = { discard && < MessageAction onClick = { discard } > discard</ MessageAction > }
219
- >
220
- < span >
221
- Tool Use: < b > { name } </ b > ({ result . status } )
222
- </ span >
223
- < M . Box py = { 0.5 } >
224
- < JsonDisplay name = "details" value = { details } />
225
- </ M . Box >
226
- </ MessageContainer >
288
+ />
227
289
)
228
290
}
229
291
@@ -246,18 +308,13 @@ function ToolUseState({ timestamp, dispatch, calls }: ToolUseStateProps) {
246
308
const names = Eff . Record . collect ( calls , ( _k , v ) => v . name )
247
309
248
310
return (
249
- < MessageContainer
250
- color = "bright"
311
+ < ToolMessage
312
+ name = { names . join ( ', ' ) }
313
+ status = "running"
314
+ details = { details }
251
315
timestamp = { timestamp }
252
316
actions = { < MessageAction onClick = { abort } > abort</ MessageAction > }
253
- >
254
- < span >
255
- Tool Use: < b > { names . join ( ', ' ) } </ b >
256
- </ span >
257
- < M . Box py = { 0.5 } >
258
- < JsonDisplay name = "details" value = { details } />
259
- </ M . Box >
260
- </ MessageContainer >
317
+ />
261
318
)
262
319
}
263
320
0 commit comments