@workerdeck/ui 0.6.0 → 0.9.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workerdeck/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Styled agent-control component library for WorkerDeck: session panel, transcript with streaming, tool-call cards, permission prompts, session list, composer. Tailwind v4 + Base UI + cva. Pairs with the headless @workerdeck/react layer.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"streamdown": "^2.5.0",
|
|
28
28
|
"tailwind-merge": "^3.6.0",
|
|
29
29
|
"use-stick-to-bottom": "^1.1.6",
|
|
30
|
-
"@workerdeck/
|
|
31
|
-
"@workerdeck/
|
|
32
|
-
"@workerdeck/react": "0.
|
|
30
|
+
"@workerdeck/client": "0.9.0",
|
|
31
|
+
"@workerdeck/protocol": "0.9.0",
|
|
32
|
+
"@workerdeck/react": "0.9.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -90,6 +90,7 @@ export function SessionPanel({ client, sessionId, header, className }: SessionPa
|
|
|
90
90
|
<Transcript
|
|
91
91
|
state={state}
|
|
92
92
|
fileUrl={sessionId ? (path) => client.sessionFileUrl(sessionId, path) : undefined}
|
|
93
|
+
attachmentUrl={sessionId ? (id) => client.attachmentUrl(sessionId, id) : undefined}
|
|
93
94
|
/>
|
|
94
95
|
{state.pendingApprovals.length > 0 ? (
|
|
95
96
|
<div className='px-3 pb-2'>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MessageAttachment } from '@workerdeck/protocol'
|
|
1
2
|
import type { TranscriptItem, TranscriptState } from '@workerdeck/react'
|
|
2
3
|
import { cn } from '../../lib/utils.ts'
|
|
3
4
|
import { formatCost, formatDuration } from '../../lib/format.ts'
|
|
@@ -40,15 +41,21 @@ function NoticeRow({ item }: { item: Extract<TranscriptItem, { kind: 'notice' }>
|
|
|
40
41
|
function TranscriptItemView({
|
|
41
42
|
item,
|
|
42
43
|
fileUrl,
|
|
44
|
+
attachmentUrl,
|
|
43
45
|
}: {
|
|
44
46
|
item: TranscriptItem
|
|
45
47
|
fileUrl?: (path: string) => string
|
|
48
|
+
attachmentUrl?: (attachmentId: string) => string
|
|
46
49
|
}) {
|
|
47
50
|
switch (item.kind) {
|
|
48
51
|
case 'user':
|
|
49
52
|
return (
|
|
50
53
|
<Message from='user'>
|
|
51
|
-
|
|
54
|
+
{item.attachments?.length ? (
|
|
55
|
+
<SentAttachments attachments={item.attachments} attachmentUrl={attachmentUrl} />
|
|
56
|
+
) : null}
|
|
57
|
+
{/* A photo can be the whole message — an empty bubble under it says nothing. */}
|
|
58
|
+
{item.text ? <MessageContent>{item.text}</MessageContent> : null}
|
|
52
59
|
</Message>
|
|
53
60
|
)
|
|
54
61
|
case 'assistant_text':
|
|
@@ -85,15 +92,51 @@ function showLoader(state: TranscriptState): boolean {
|
|
|
85
92
|
return last.kind !== 'turn_result' || state.status === 'running'
|
|
86
93
|
}
|
|
87
94
|
|
|
95
|
+
/** Files sent with a message: thumbnails for images, named chips for the rest.
|
|
96
|
+
* References only — the bytes are fetched from the gateway. */
|
|
97
|
+
function SentAttachments({
|
|
98
|
+
attachments,
|
|
99
|
+
attachmentUrl,
|
|
100
|
+
}: {
|
|
101
|
+
attachments: MessageAttachment[]
|
|
102
|
+
attachmentUrl?: (attachmentId: string) => string
|
|
103
|
+
}) {
|
|
104
|
+
return (
|
|
105
|
+
<div className='mb-1 flex flex-wrap justify-end gap-1.5'>
|
|
106
|
+
{attachments.map((attachment) => {
|
|
107
|
+
const href = attachmentUrl?.(attachment.id)
|
|
108
|
+
return attachment.mediaType.startsWith('image/') && href ? (
|
|
109
|
+
<img
|
|
110
|
+
key={attachment.id}
|
|
111
|
+
src={href}
|
|
112
|
+
alt={attachment.name}
|
|
113
|
+
className='size-20 rounded-md border border-border object-cover'
|
|
114
|
+
/>
|
|
115
|
+
) : (
|
|
116
|
+
<span
|
|
117
|
+
key={attachment.id}
|
|
118
|
+
className='rounded-full border border-border bg-surface px-2.5 py-1 text-body-xs text-fg-3'>
|
|
119
|
+
{attachment.name}
|
|
120
|
+
</span>
|
|
121
|
+
)
|
|
122
|
+
})}
|
|
123
|
+
</div>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
88
127
|
export interface TranscriptProps {
|
|
89
128
|
state: TranscriptState
|
|
90
129
|
/** Builds the download URL for a delivered file (see FileCard). Typically
|
|
91
130
|
* `(path) => client.sessionFileUrl(sessionId, path)`. */
|
|
92
131
|
fileUrl?: (path: string) => string
|
|
132
|
+
/** Builds the URL for an uploaded attachment. Typically
|
|
133
|
+
* `(id) => client.attachmentUrl(sessionId, id)`. Same-origin and
|
|
134
|
+
* cookie-authenticated, which is what lets an `<img src>` render one. */
|
|
135
|
+
attachmentUrl?: (attachmentId: string) => string
|
|
93
136
|
className?: string
|
|
94
137
|
}
|
|
95
138
|
|
|
96
|
-
export function Transcript({ state, fileUrl, className }: TranscriptProps) {
|
|
139
|
+
export function Transcript({ state, fileUrl, attachmentUrl, className }: TranscriptProps) {
|
|
97
140
|
return (
|
|
98
141
|
<Conversation className={className}>
|
|
99
142
|
<ConversationContent>
|
|
@@ -101,7 +144,12 @@ export function Transcript({ state, fileUrl, className }: TranscriptProps) {
|
|
|
101
144
|
<div className='py-12 text-center text-body-sm text-fg-4'>No messages yet.</div>
|
|
102
145
|
) : (
|
|
103
146
|
state.items.map((item) => (
|
|
104
|
-
<TranscriptItemView
|
|
147
|
+
<TranscriptItemView
|
|
148
|
+
key={`${item.kind}:${item.id}`}
|
|
149
|
+
item={item}
|
|
150
|
+
fileUrl={fileUrl}
|
|
151
|
+
attachmentUrl={attachmentUrl}
|
|
152
|
+
/>
|
|
105
153
|
))
|
|
106
154
|
)}
|
|
107
155
|
{showLoader(state) ? (
|