@pikku/assistant-ui 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/pikku-agent-chat.d.ts +6 -0
- package/dist/cjs/pikku-agent-chat.js +228 -124
- package/dist/cjs/use-pikku-agent-runtime.d.ts +40 -6
- package/dist/cjs/use-pikku-agent-runtime.js +589 -63
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/pikku-agent-chat.d.ts +6 -0
- package/dist/esm/pikku-agent-chat.js +238 -125
- package/dist/esm/use-pikku-agent-runtime.d.ts +40 -6
- package/dist/esm/use-pikku-agent-runtime.js +541 -61
- package/package.json +2 -2
- package/src/index.ts +16 -2
- package/src/pikku-agent-chat.tsx +368 -169
- package/src/use-pikku-agent-runtime.ts +763 -79
package/src/pikku-agent-chat.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { useState, type FunctionComponent } from 'react'
|
|
1
|
+
import { createContext, useContext, useState, useMemo, type FunctionComponent } from 'react'
|
|
2
|
+
import Markdown from 'react-markdown'
|
|
2
3
|
import {
|
|
3
4
|
AssistantRuntimeProvider,
|
|
4
5
|
ThreadPrimitive,
|
|
@@ -7,20 +8,103 @@ import {
|
|
|
7
8
|
} from '@assistant-ui/react'
|
|
8
9
|
import {
|
|
9
10
|
usePikkuAgentRuntime,
|
|
11
|
+
PikkuApprovalContext,
|
|
12
|
+
usePikkuApproval,
|
|
13
|
+
resolvePikkuToolStatus,
|
|
14
|
+
type PikkuToolStatus,
|
|
10
15
|
type PikkuAgentRuntimeOptions,
|
|
11
16
|
} from './use-pikku-agent-runtime.js'
|
|
12
17
|
|
|
13
18
|
export interface PikkuAgentChatProps extends PikkuAgentRuntimeOptions {
|
|
14
19
|
emptyMessage?: string
|
|
20
|
+
/** Hide tool calls from the chat display.
|
|
21
|
+
* - `true`: hide all non-approval tool calls
|
|
22
|
+
* - `string[]`: hide tool calls matching these names
|
|
23
|
+
*/
|
|
24
|
+
hideToolCalls?: boolean | string[]
|
|
25
|
+
dark?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ChatColors {
|
|
29
|
+
bg: string
|
|
30
|
+
userBubble: string
|
|
31
|
+
assistantBubble: string
|
|
32
|
+
text: string
|
|
33
|
+
textMuted: string
|
|
34
|
+
border: string
|
|
35
|
+
codeBg: string
|
|
36
|
+
inputBg: string
|
|
37
|
+
sendBg: string
|
|
38
|
+
sendColor: string
|
|
39
|
+
approvalBg: string
|
|
40
|
+
approvalBorder: string
|
|
41
|
+
successBg: string
|
|
42
|
+
successColor: string
|
|
43
|
+
errorBg: string
|
|
44
|
+
errorColor: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const lightColors: ChatColors = {
|
|
48
|
+
bg: '#ffffff',
|
|
49
|
+
userBubble: '#e3f2fd',
|
|
50
|
+
assistantBubble: '#f5f5f5',
|
|
51
|
+
text: '#1a1a1a',
|
|
52
|
+
textMuted: '#888',
|
|
53
|
+
border: '#ddd',
|
|
54
|
+
codeBg: '#f5f5f5',
|
|
55
|
+
inputBg: 'transparent',
|
|
56
|
+
sendBg: '#1976d2',
|
|
57
|
+
sendColor: '#fff',
|
|
58
|
+
approvalBg: '#fef9e7',
|
|
59
|
+
approvalBorder: '#e9a211',
|
|
60
|
+
successBg: '#e8f5e9',
|
|
61
|
+
successColor: '#2e7d32',
|
|
62
|
+
errorBg: '#ffebee',
|
|
63
|
+
errorColor: '#c62828',
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const darkColors: ChatColors = {
|
|
67
|
+
bg: 'transparent',
|
|
68
|
+
userBubble: 'rgba(0, 230, 138, 0.1)',
|
|
69
|
+
assistantBubble: '#1e1e2e',
|
|
70
|
+
text: '#e0e0e8',
|
|
71
|
+
textMuted: '#8888a0',
|
|
72
|
+
border: '#2a2a3e',
|
|
73
|
+
codeBg: '#0e0e16',
|
|
74
|
+
inputBg: 'transparent',
|
|
75
|
+
sendBg: '#00cc7a',
|
|
76
|
+
sendColor: '#0a0a0f',
|
|
77
|
+
approvalBg: 'rgba(233, 162, 17, 0.1)',
|
|
78
|
+
approvalBorder: '#e9a211',
|
|
79
|
+
successBg: 'rgba(0, 230, 138, 0.1)',
|
|
80
|
+
successColor: '#00e68a',
|
|
81
|
+
errorBg: 'rgba(220, 38, 38, 0.1)',
|
|
82
|
+
errorColor: '#f87171',
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ColorsContext = createContext<ChatColors>(lightColors)
|
|
86
|
+
const HideToolCallsContext = createContext<boolean | string[] | undefined>(undefined)
|
|
87
|
+
|
|
88
|
+
function shouldHideToolCall(
|
|
89
|
+
hideToolCalls: boolean | string[] | undefined,
|
|
90
|
+
toolName: string
|
|
91
|
+
): boolean {
|
|
92
|
+
if (!hideToolCalls) return false
|
|
93
|
+
if (hideToolCalls === true) return true
|
|
94
|
+
return hideToolCalls.includes(toolName)
|
|
15
95
|
}
|
|
16
96
|
|
|
17
97
|
const ToolCallDisplay: FunctionComponent<{
|
|
98
|
+
toolCallId: string
|
|
18
99
|
toolName: string
|
|
19
100
|
args: Record<string, unknown>
|
|
20
101
|
result?: unknown
|
|
21
|
-
status:
|
|
102
|
+
status: PikkuToolStatus
|
|
22
103
|
addResult?: (result: unknown) => void
|
|
23
|
-
}> = ({ toolName, args, result, status, addResult }) => {
|
|
104
|
+
}> = ({ toolCallId, toolName, args, result, status, addResult }) => {
|
|
105
|
+
const colors = useContext(ColorsContext)
|
|
106
|
+
const hideToolCalls = useContext(HideToolCallsContext)
|
|
107
|
+
const { handleApproval } = usePikkuApproval()
|
|
24
108
|
const [expanded, setExpanded] = useState(false)
|
|
25
109
|
const isApproval = status.type === 'requires-action'
|
|
26
110
|
const approvalReason = (args as any)?.__approvalReason
|
|
@@ -30,15 +114,25 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
30
114
|
null
|
|
31
115
|
)
|
|
32
116
|
|
|
117
|
+
// Hide responded approval tool calls
|
|
118
|
+
if (isApproval && responded && shouldHideToolCall(hideToolCalls, toolName)) {
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Hide non-approval tool calls
|
|
123
|
+
if (!isApproval && shouldHideToolCall(hideToolCalls, toolName)) {
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
33
127
|
if (isApproval && !responded) {
|
|
34
128
|
return (
|
|
35
129
|
<div
|
|
36
130
|
style={{
|
|
37
|
-
border:
|
|
131
|
+
border: `1px solid ${colors.approvalBorder}`,
|
|
38
132
|
borderRadius: 6,
|
|
39
133
|
padding: 12,
|
|
40
134
|
margin: '4px 0',
|
|
41
|
-
backgroundColor:
|
|
135
|
+
backgroundColor: colors.approvalBg,
|
|
42
136
|
}}
|
|
43
137
|
>
|
|
44
138
|
<div
|
|
@@ -49,24 +143,26 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
49
143
|
marginBottom: 8,
|
|
50
144
|
fontWeight: 600,
|
|
51
145
|
fontSize: 13,
|
|
146
|
+
color: colors.text,
|
|
52
147
|
}}
|
|
53
148
|
>
|
|
54
149
|
Approval required
|
|
55
150
|
</div>
|
|
56
151
|
{approvalReason && (
|
|
57
|
-
<div style={{ fontSize: 13, marginBottom: 4 }}>{approvalReason}</div>
|
|
152
|
+
<div style={{ fontSize: 13, marginBottom: 4, color: colors.text }}>{approvalReason}</div>
|
|
58
153
|
)}
|
|
59
|
-
<div style={{ fontSize: 12, color:
|
|
154
|
+
<div style={{ fontSize: 12, color: colors.textMuted, marginBottom: 4 }}>
|
|
60
155
|
The agent wants to call <code>{toolName}</code>
|
|
61
156
|
</div>
|
|
62
157
|
<pre
|
|
63
158
|
style={{
|
|
64
159
|
fontSize: 11,
|
|
65
|
-
background:
|
|
160
|
+
background: colors.codeBg,
|
|
66
161
|
padding: 8,
|
|
67
162
|
borderRadius: 4,
|
|
68
163
|
overflow: 'auto',
|
|
69
164
|
marginBottom: 8,
|
|
165
|
+
color: colors.text,
|
|
70
166
|
}}
|
|
71
167
|
>
|
|
72
168
|
{JSON.stringify(displayArgs, null, 2)}
|
|
@@ -75,15 +171,16 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
75
171
|
<button
|
|
76
172
|
onClick={() => {
|
|
77
173
|
setResponded('approved')
|
|
174
|
+
handleApproval(toolCallId, true)
|
|
78
175
|
addResult?.({ approved: true })
|
|
79
176
|
}}
|
|
80
177
|
style={{
|
|
81
178
|
padding: '4px 12px',
|
|
82
179
|
fontSize: 12,
|
|
83
|
-
border:
|
|
180
|
+
border: `1px solid ${colors.successColor}`,
|
|
84
181
|
borderRadius: 4,
|
|
85
|
-
background:
|
|
86
|
-
color:
|
|
182
|
+
background: colors.successBg,
|
|
183
|
+
color: colors.successColor,
|
|
87
184
|
cursor: 'pointer',
|
|
88
185
|
}}
|
|
89
186
|
>
|
|
@@ -92,15 +189,16 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
92
189
|
<button
|
|
93
190
|
onClick={() => {
|
|
94
191
|
setResponded('denied')
|
|
192
|
+
handleApproval(toolCallId, false)
|
|
95
193
|
addResult?.({ approved: false })
|
|
96
194
|
}}
|
|
97
195
|
style={{
|
|
98
196
|
padding: '4px 12px',
|
|
99
197
|
fontSize: 12,
|
|
100
|
-
border:
|
|
198
|
+
border: `1px solid ${colors.errorColor}`,
|
|
101
199
|
borderRadius: 4,
|
|
102
|
-
background:
|
|
103
|
-
color:
|
|
200
|
+
background: colors.errorBg,
|
|
201
|
+
color: colors.errorColor,
|
|
104
202
|
cursor: 'pointer',
|
|
105
203
|
}}
|
|
106
204
|
>
|
|
@@ -115,7 +213,7 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
115
213
|
return (
|
|
116
214
|
<div
|
|
117
215
|
style={{
|
|
118
|
-
border:
|
|
216
|
+
border: `1px solid ${colors.border}`,
|
|
119
217
|
borderRadius: 6,
|
|
120
218
|
padding: 8,
|
|
121
219
|
margin: '4px 0',
|
|
@@ -123,6 +221,7 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
123
221
|
alignItems: 'center',
|
|
124
222
|
gap: 8,
|
|
125
223
|
fontSize: 13,
|
|
224
|
+
color: colors.text,
|
|
126
225
|
}}
|
|
127
226
|
>
|
|
128
227
|
<span style={{ fontWeight: 500 }}>{toolName}</span>
|
|
@@ -131,8 +230,8 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
131
230
|
fontSize: 11,
|
|
132
231
|
padding: '2px 6px',
|
|
133
232
|
borderRadius: 3,
|
|
134
|
-
background: responded === 'approved' ?
|
|
135
|
-
color: responded === 'approved' ?
|
|
233
|
+
background: responded === 'approved' ? colors.successBg : colors.errorBg,
|
|
234
|
+
color: responded === 'approved' ? colors.successColor : colors.errorColor,
|
|
136
235
|
}}
|
|
137
236
|
>
|
|
138
237
|
{responded}
|
|
@@ -144,7 +243,7 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
144
243
|
return (
|
|
145
244
|
<div
|
|
146
245
|
style={{
|
|
147
|
-
border:
|
|
246
|
+
border: `1px solid ${colors.border}`,
|
|
148
247
|
borderRadius: 6,
|
|
149
248
|
padding: 8,
|
|
150
249
|
margin: '4px 0',
|
|
@@ -162,6 +261,7 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
162
261
|
width: '100%',
|
|
163
262
|
padding: 0,
|
|
164
263
|
fontSize: 13,
|
|
264
|
+
color: colors.text,
|
|
165
265
|
}}
|
|
166
266
|
>
|
|
167
267
|
<span>{expanded ? '\u25BC' : '\u25B6'}</span>
|
|
@@ -169,16 +269,42 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
169
269
|
{toolName}
|
|
170
270
|
</span>
|
|
171
271
|
{status.type === 'running' && (
|
|
172
|
-
<span style={{ fontSize: 11, color:
|
|
272
|
+
<span style={{ fontSize: 11, color: colors.textMuted }}>running...</span>
|
|
273
|
+
)}
|
|
274
|
+
{status.type === 'error' && (
|
|
275
|
+
<span
|
|
276
|
+
style={{
|
|
277
|
+
fontSize: 11,
|
|
278
|
+
padding: '1px 5px',
|
|
279
|
+
borderRadius: 3,
|
|
280
|
+
background: colors.errorBg,
|
|
281
|
+
color: colors.errorColor,
|
|
282
|
+
}}
|
|
283
|
+
>
|
|
284
|
+
error
|
|
285
|
+
</span>
|
|
286
|
+
)}
|
|
287
|
+
{status.type === 'denied' && (
|
|
288
|
+
<span
|
|
289
|
+
style={{
|
|
290
|
+
fontSize: 11,
|
|
291
|
+
padding: '1px 5px',
|
|
292
|
+
borderRadius: 3,
|
|
293
|
+
background: colors.errorBg,
|
|
294
|
+
color: colors.errorColor,
|
|
295
|
+
}}
|
|
296
|
+
>
|
|
297
|
+
denied
|
|
298
|
+
</span>
|
|
173
299
|
)}
|
|
174
|
-
{status.type === '
|
|
300
|
+
{status.type === 'completed' && (
|
|
175
301
|
<span
|
|
176
302
|
style={{
|
|
177
303
|
fontSize: 11,
|
|
178
304
|
padding: '1px 5px',
|
|
179
305
|
borderRadius: 3,
|
|
180
|
-
background:
|
|
181
|
-
color:
|
|
306
|
+
background: colors.successBg,
|
|
307
|
+
color: colors.successColor,
|
|
182
308
|
}}
|
|
183
309
|
>
|
|
184
310
|
done
|
|
@@ -187,16 +313,17 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
187
313
|
</button>
|
|
188
314
|
{expanded && (
|
|
189
315
|
<div style={{ marginTop: 8 }}>
|
|
190
|
-
<div style={{ fontSize: 12, color:
|
|
316
|
+
<div style={{ fontSize: 12, color: colors.textMuted, marginBottom: 2 }}>
|
|
191
317
|
Arguments:
|
|
192
318
|
</div>
|
|
193
319
|
<pre
|
|
194
320
|
style={{
|
|
195
321
|
fontSize: 11,
|
|
196
|
-
background:
|
|
322
|
+
background: colors.codeBg,
|
|
197
323
|
padding: 8,
|
|
198
324
|
borderRadius: 4,
|
|
199
325
|
overflow: 'auto',
|
|
326
|
+
color: colors.text,
|
|
200
327
|
}}
|
|
201
328
|
>
|
|
202
329
|
{JSON.stringify(displayArgs, null, 2)}
|
|
@@ -204,17 +331,18 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
204
331
|
{result !== undefined && (
|
|
205
332
|
<>
|
|
206
333
|
<div
|
|
207
|
-
style={{ fontSize: 12, color:
|
|
334
|
+
style={{ fontSize: 12, color: colors.textMuted, marginTop: 8, marginBottom: 2 }}
|
|
208
335
|
>
|
|
209
336
|
Result:
|
|
210
337
|
</div>
|
|
211
338
|
<pre
|
|
212
339
|
style={{
|
|
213
340
|
fontSize: 11,
|
|
214
|
-
background:
|
|
341
|
+
background: colors.codeBg,
|
|
215
342
|
padding: 8,
|
|
216
343
|
borderRadius: 4,
|
|
217
344
|
overflow: 'auto',
|
|
345
|
+
color: colors.text,
|
|
218
346
|
}}
|
|
219
347
|
>
|
|
220
348
|
{typeof result === 'string'
|
|
@@ -229,169 +357,237 @@ const ToolCallDisplay: FunctionComponent<{
|
|
|
229
357
|
)
|
|
230
358
|
}
|
|
231
359
|
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
</
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
360
|
+
const MarkdownText: FunctionComponent<{ text: string; colors: ChatColors }> = ({ text, colors }) => {
|
|
361
|
+
const components = useMemo(() => ({
|
|
362
|
+
p: ({ children }: any) => (
|
|
363
|
+
<p style={{ margin: '0 0 8px', fontSize: 14, lineHeight: 1.6, color: colors.text }}>{children}</p>
|
|
364
|
+
),
|
|
365
|
+
strong: ({ children }: any) => (
|
|
366
|
+
<strong style={{ fontWeight: 600, color: colors.text }}>{children}</strong>
|
|
367
|
+
),
|
|
368
|
+
em: ({ children }: any) => (
|
|
369
|
+
<em style={{ color: colors.text }}>{children}</em>
|
|
370
|
+
),
|
|
371
|
+
ul: ({ children }: any) => (
|
|
372
|
+
<ul style={{ margin: '4px 0 8px', paddingLeft: 20, fontSize: 14, color: colors.text }}>{children}</ul>
|
|
373
|
+
),
|
|
374
|
+
ol: ({ children }: any) => (
|
|
375
|
+
<ol style={{ margin: '4px 0 8px', paddingLeft: 20, fontSize: 14, color: colors.text }}>{children}</ol>
|
|
376
|
+
),
|
|
377
|
+
li: ({ children }: any) => (
|
|
378
|
+
<li style={{ marginBottom: 2, lineHeight: 1.6 }}>{children}</li>
|
|
379
|
+
),
|
|
380
|
+
code: ({ children, className }: any) => {
|
|
381
|
+
const isBlock = className?.startsWith('language-')
|
|
382
|
+
if (isBlock) {
|
|
383
|
+
return (
|
|
384
|
+
<pre style={{ background: colors.codeBg, padding: 10, borderRadius: 4, overflow: 'auto', margin: '4px 0 8px', fontSize: 12 }}>
|
|
385
|
+
<code style={{ color: colors.text }}>{children}</code>
|
|
386
|
+
</pre>
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
return (
|
|
390
|
+
<code style={{ background: colors.codeBg, padding: '1px 4px', borderRadius: 3, fontSize: 13, color: colors.text }}>
|
|
391
|
+
{children}
|
|
392
|
+
</code>
|
|
393
|
+
)
|
|
394
|
+
},
|
|
395
|
+
pre: ({ children }: any) => <>{children}</>,
|
|
396
|
+
h1: ({ children }: any) => <h3 style={{ margin: '8px 0 4px', fontSize: 16, fontWeight: 600, color: colors.text }}>{children}</h3>,
|
|
397
|
+
h2: ({ children }: any) => <h4 style={{ margin: '8px 0 4px', fontSize: 15, fontWeight: 600, color: colors.text }}>{children}</h4>,
|
|
398
|
+
h3: ({ children }: any) => <h5 style={{ margin: '8px 0 4px', fontSize: 14, fontWeight: 600, color: colors.text }}>{children}</h5>,
|
|
399
|
+
a: ({ href, children }: any) => (
|
|
400
|
+
<a href={href} target="_blank" rel="noopener noreferrer" style={{ color: colors.textMuted, textDecoration: 'underline' }}>{children}</a>
|
|
401
|
+
),
|
|
402
|
+
}), [colors])
|
|
403
|
+
|
|
404
|
+
return <Markdown components={components}>{text}</Markdown>
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const UserMessage: FunctionComponent = () => {
|
|
408
|
+
const colors = useContext(ColorsContext)
|
|
409
|
+
return (
|
|
410
|
+
<div
|
|
411
|
+
style={{
|
|
412
|
+
display: 'flex',
|
|
413
|
+
justifyContent: 'flex-end',
|
|
414
|
+
width: '100%',
|
|
415
|
+
}}
|
|
416
|
+
>
|
|
417
|
+
<div style={{ maxWidth: '80%' }}>
|
|
418
|
+
<div
|
|
419
|
+
style={{
|
|
420
|
+
fontSize: 12,
|
|
421
|
+
color: colors.textMuted,
|
|
422
|
+
marginBottom: 4,
|
|
423
|
+
textAlign: 'right',
|
|
265
424
|
}}
|
|
266
|
-
|
|
425
|
+
>
|
|
426
|
+
You
|
|
427
|
+
</div>
|
|
428
|
+
<div
|
|
429
|
+
style={{
|
|
430
|
+
padding: 12,
|
|
431
|
+
borderRadius: 12,
|
|
432
|
+
backgroundColor: colors.userBubble,
|
|
433
|
+
}}
|
|
434
|
+
>
|
|
435
|
+
<MessagePrimitive.Content
|
|
436
|
+
components={{
|
|
437
|
+
Text: ({ text }) => (
|
|
438
|
+
<span style={{ fontSize: 14, whiteSpace: 'pre-wrap', color: colors.text }}>
|
|
439
|
+
{text}
|
|
440
|
+
</span>
|
|
441
|
+
),
|
|
442
|
+
}}
|
|
443
|
+
/>
|
|
444
|
+
</div>
|
|
267
445
|
</div>
|
|
268
446
|
</div>
|
|
269
|
-
|
|
270
|
-
|
|
447
|
+
)
|
|
448
|
+
}
|
|
271
449
|
|
|
272
|
-
const AssistantMessage: FunctionComponent = () =>
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
<MessagePrimitive.Content
|
|
292
|
-
components={{
|
|
293
|
-
Text: ({ text }) => (
|
|
294
|
-
<span style={{ fontSize: 14, whiteSpace: 'pre-wrap' }}>
|
|
295
|
-
{text}
|
|
296
|
-
</span>
|
|
297
|
-
),
|
|
298
|
-
tools: {
|
|
299
|
-
Fallback: (props) => (
|
|
300
|
-
<ToolCallDisplay
|
|
301
|
-
toolName={props.toolName}
|
|
302
|
-
args={props.args as Record<string, unknown>}
|
|
303
|
-
result={props.result}
|
|
304
|
-
status={props.status}
|
|
305
|
-
addResult={props.addResult}
|
|
306
|
-
/>
|
|
307
|
-
),
|
|
308
|
-
},
|
|
450
|
+
const AssistantMessage: FunctionComponent = () => {
|
|
451
|
+
const colors = useContext(ColorsContext)
|
|
452
|
+
return (
|
|
453
|
+
<div
|
|
454
|
+
style={{
|
|
455
|
+
display: 'flex',
|
|
456
|
+
justifyContent: 'flex-start',
|
|
457
|
+
width: '100%',
|
|
458
|
+
}}
|
|
459
|
+
>
|
|
460
|
+
<div style={{ maxWidth: '80%' }}>
|
|
461
|
+
<div style={{ fontSize: 12, color: colors.textMuted, marginBottom: 4 }}>
|
|
462
|
+
Assistant
|
|
463
|
+
</div>
|
|
464
|
+
<div
|
|
465
|
+
style={{
|
|
466
|
+
padding: 12,
|
|
467
|
+
borderRadius: 12,
|
|
468
|
+
backgroundColor: colors.assistantBubble,
|
|
309
469
|
}}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
470
|
+
>
|
|
471
|
+
<MessagePrimitive.Content
|
|
472
|
+
components={{
|
|
473
|
+
Text: ({ text }) => (
|
|
474
|
+
<MarkdownText text={text} colors={colors} />
|
|
475
|
+
),
|
|
476
|
+
tools: {
|
|
477
|
+
Fallback: (props) => (
|
|
478
|
+
<ToolCallDisplay
|
|
479
|
+
toolCallId={props.toolCallId}
|
|
480
|
+
toolName={props.toolName}
|
|
481
|
+
args={props.args as Record<string, unknown>}
|
|
482
|
+
result={props.result}
|
|
483
|
+
status={resolvePikkuToolStatus(props.status, props.result)}
|
|
484
|
+
addResult={props.addResult}
|
|
485
|
+
/>
|
|
486
|
+
),
|
|
487
|
+
},
|
|
488
|
+
}}
|
|
489
|
+
/>
|
|
490
|
+
<MessagePrimitive.If last>
|
|
491
|
+
<ThreadPrimitive.If running>
|
|
492
|
+
<div
|
|
493
|
+
style={{
|
|
494
|
+
display: 'flex',
|
|
495
|
+
alignItems: 'center',
|
|
496
|
+
gap: 6,
|
|
497
|
+
marginTop: 8,
|
|
498
|
+
fontSize: 13,
|
|
499
|
+
color: colors.textMuted,
|
|
500
|
+
}}
|
|
501
|
+
>
|
|
502
|
+
Thinking...
|
|
503
|
+
</div>
|
|
504
|
+
</ThreadPrimitive.If>
|
|
505
|
+
</MessagePrimitive.If>
|
|
506
|
+
</div>
|
|
327
507
|
</div>
|
|
328
508
|
</div>
|
|
329
|
-
|
|
330
|
-
|
|
509
|
+
)
|
|
510
|
+
}
|
|
331
511
|
|
|
332
|
-
const PikkuComposer: FunctionComponent
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
display: 'flex',
|
|
341
|
-
alignItems: 'flex-end',
|
|
342
|
-
padding: '6px 12px',
|
|
343
|
-
gap: 8,
|
|
344
|
-
}}
|
|
345
|
-
>
|
|
346
|
-
<ComposerPrimitive.Input
|
|
347
|
-
placeholder="Message..."
|
|
348
|
-
rows={2}
|
|
349
|
-
style={{
|
|
350
|
-
flex: 1,
|
|
351
|
-
border: 'none',
|
|
352
|
-
outline: 'none',
|
|
353
|
-
resize: 'none',
|
|
354
|
-
fontSize: 14,
|
|
355
|
-
fontFamily: 'inherit',
|
|
356
|
-
padding: '4px 0',
|
|
357
|
-
background: 'transparent',
|
|
358
|
-
}}
|
|
359
|
-
/>
|
|
360
|
-
<ComposerPrimitive.Send
|
|
512
|
+
const PikkuComposer: FunctionComponent<{ disabled?: boolean }> = ({
|
|
513
|
+
disabled,
|
|
514
|
+
}) => {
|
|
515
|
+
const colors = useContext(ColorsContext)
|
|
516
|
+
return (
|
|
517
|
+
<div style={{ padding: '8px 0 16px' }}>
|
|
518
|
+
<ComposerPrimitive.Root>
|
|
519
|
+
<div
|
|
361
520
|
style={{
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
border: 'none',
|
|
366
|
-
background: '#1976d2',
|
|
367
|
-
color: '#fff',
|
|
368
|
-
cursor: 'pointer',
|
|
521
|
+
border: `1px solid ${colors.border}`,
|
|
522
|
+
borderRadius: 12,
|
|
523
|
+
overflow: 'hidden',
|
|
369
524
|
display: 'flex',
|
|
370
|
-
alignItems: '
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
fontSize: 14,
|
|
525
|
+
alignItems: 'flex-end',
|
|
526
|
+
padding: '6px 12px',
|
|
527
|
+
gap: 8,
|
|
528
|
+
...(disabled ? { opacity: 0.5, pointerEvents: 'none' as const } : {}),
|
|
375
529
|
}}
|
|
376
530
|
>
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
531
|
+
<ComposerPrimitive.Input
|
|
532
|
+
placeholder={disabled ? 'Respond to approval request above...' : 'Message...'}
|
|
533
|
+
rows={2}
|
|
534
|
+
disabled={disabled}
|
|
535
|
+
style={{
|
|
536
|
+
flex: 1,
|
|
537
|
+
border: 'none',
|
|
538
|
+
outline: 'none',
|
|
539
|
+
resize: 'none',
|
|
540
|
+
fontSize: 14,
|
|
541
|
+
fontFamily: 'inherit',
|
|
542
|
+
padding: '4px 0',
|
|
543
|
+
background: colors.inputBg,
|
|
544
|
+
color: colors.text,
|
|
545
|
+
}}
|
|
546
|
+
/>
|
|
547
|
+
<ComposerPrimitive.Send
|
|
548
|
+
disabled={disabled}
|
|
549
|
+
style={{
|
|
550
|
+
width: 28,
|
|
551
|
+
height: 28,
|
|
552
|
+
borderRadius: '50%',
|
|
553
|
+
border: 'none',
|
|
554
|
+
background: disabled ? colors.textMuted : colors.sendBg,
|
|
555
|
+
color: colors.sendColor,
|
|
556
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
557
|
+
display: 'flex',
|
|
558
|
+
alignItems: 'center',
|
|
559
|
+
justifyContent: 'center',
|
|
560
|
+
flexShrink: 0,
|
|
561
|
+
marginBottom: 2,
|
|
562
|
+
fontSize: 14,
|
|
563
|
+
}}
|
|
564
|
+
>
|
|
565
|
+
▶
|
|
566
|
+
</ComposerPrimitive.Send>
|
|
567
|
+
</div>
|
|
568
|
+
</ComposerPrimitive.Root>
|
|
569
|
+
</div>
|
|
570
|
+
)
|
|
571
|
+
}
|
|
383
572
|
|
|
384
573
|
export function PikkuAgentChat(props: PikkuAgentChatProps) {
|
|
385
|
-
const { emptyMessage, ...runtimeOptions } = props
|
|
386
|
-
const runtime =
|
|
574
|
+
const { emptyMessage, hideToolCalls, dark, ...runtimeOptions } = props
|
|
575
|
+
const { runtime, isAwaitingApproval, pendingApprovals, handleApproval } =
|
|
576
|
+
usePikkuAgentRuntime(runtimeOptions)
|
|
577
|
+
|
|
578
|
+
const colors = dark ? darkColors : lightColors
|
|
387
579
|
|
|
388
580
|
return (
|
|
581
|
+
<ColorsContext.Provider value={colors}>
|
|
582
|
+
<PikkuApprovalContext.Provider value={{ pendingApprovals, handleApproval }}>
|
|
583
|
+
<HideToolCallsContext.Provider value={hideToolCalls}>
|
|
389
584
|
<AssistantRuntimeProvider runtime={runtime}>
|
|
390
585
|
<div
|
|
391
586
|
style={{
|
|
392
587
|
height: '100%',
|
|
393
588
|
display: 'flex',
|
|
394
589
|
flexDirection: 'column',
|
|
590
|
+
background: colors.bg,
|
|
395
591
|
}}
|
|
396
592
|
>
|
|
397
593
|
<ThreadPrimitive.Root
|
|
@@ -426,7 +622,7 @@ export function PikkuAgentChat(props: PikkuAgentChatProps) {
|
|
|
426
622
|
alignItems: 'center',
|
|
427
623
|
justifyContent: 'center',
|
|
428
624
|
minHeight: 300,
|
|
429
|
-
color:
|
|
625
|
+
color: colors.textMuted,
|
|
430
626
|
textAlign: 'center',
|
|
431
627
|
fontSize: 14,
|
|
432
628
|
}}
|
|
@@ -446,10 +642,13 @@ export function PikkuAgentChat(props: PikkuAgentChatProps) {
|
|
|
446
642
|
</div>
|
|
447
643
|
</ThreadPrimitive.Viewport>
|
|
448
644
|
<div style={{ maxWidth: 768, margin: '0 auto', width: '100%', padding: '0 16px' }}>
|
|
449
|
-
<PikkuComposer />
|
|
645
|
+
<PikkuComposer disabled={isAwaitingApproval} />
|
|
450
646
|
</div>
|
|
451
647
|
</ThreadPrimitive.Root>
|
|
452
648
|
</div>
|
|
453
649
|
</AssistantRuntimeProvider>
|
|
650
|
+
</HideToolCallsContext.Provider>
|
|
651
|
+
</PikkuApprovalContext.Provider>
|
|
652
|
+
</ColorsContext.Provider>
|
|
454
653
|
)
|
|
455
654
|
}
|