agentic-ui-kit 0.3.0 → 0.5.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/README.md +6 -0
- package/dist/core.js +11 -4
- package/dist/index.js +492 -195
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +3 -1
- package/dist/types/core/src/index.d.ts +1 -0
- package/dist/types/core/src/replaces.d.ts +15 -0
- package/dist/types/core/src/types.d.ts +2 -0
- package/dist/types/core/src/ui-markup.d.ts +6 -0
- package/dist/types/core/src/ui-tree.d.ts +6 -0
- package/dist/types/core/src/visualize.d.ts +7 -1
- package/dist/types/react/src/components/composer.d.ts +7 -1
- package/dist/types/react/src/components/effort-slider.d.ts +24 -0
- package/dist/types/react/src/components/message-list.d.ts +6 -2
- package/dist/types/react/src/components/messages.d.ts +22 -2
- package/dist/types/react/src/components/replacements.d.ts +29 -0
- package/dist/types/react/src/index.d.ts +11 -1
- package/dist/types/react/src/primitives/button.d.ts +10 -1
- package/dist/types/react/src/primitives/code-block.d.ts +3 -1
- package/dist/types/react/src/primitives/copy-button.d.ts +5 -0
- package/dist/types/react/src/primitives/icons.d.ts +7 -0
- package/dist/types/react/src/primitives/labels.d.ts +7 -0
- package/dist/types/react/src/primitives/menu.d.ts +3 -1
- package/dist/types/react/src/primitives/segmented-control.d.ts +22 -0
- package/dist/types/react/src/views/chat-view.d.ts +15 -3
- package/dist/types/react/src/views/sidebar.d.ts +3 -1
- package/dist/{ui-markup-6xbP-myu.js → ui-markup-CG9Lednh.js} +33 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { C as toBlocks, E as awaitingToolCalls, N as salvageJson, T as applyEvent, _ as replacedId, d as isStateRef, f as matchesSchema, g as uiActionSchema, i as parseUiMarkup, j as settleToolCall, w as activityTokens, x as readEventStream } from "./ui-markup-CG9Lednh.js";
|
|
3
3
|
import { clsx } from "clsx";
|
|
4
|
-
import { Autocomplete, Button as Button$1, Dialog, Disclosure as Disclosure$1, DisclosurePanel, Focusable, Header, Heading, Input, Keyboard, Link, Menu as Menu$1, MenuItem as MenuItem$1, MenuSection as MenuSection$1, MenuTrigger, MenuTrigger as MenuTrigger$1, Modal as Modal$1, ModalOverlay, Popover as Popover$1, SearchField, Separator, SubmenuTrigger, Text, Tooltip as Tooltip$1, TooltipTrigger, useFilter } from "react-aria-components";
|
|
4
|
+
import { Autocomplete, Button as Button$1, Dialog, DialogTrigger, Disclosure as Disclosure$1, DisclosurePanel, Focusable, Header, Heading, Input, Keyboard, Link, Menu as Menu$1, MenuItem as MenuItem$1, MenuSection as MenuSection$1, MenuTrigger, MenuTrigger as MenuTrigger$1, Modal as Modal$1, ModalOverlay, Popover as Popover$1, SearchField, Separator, SubmenuTrigger, Text, ToggleButton, ToggleButtonGroup, Tooltip as Tooltip$1, TooltipTrigger, useFilter } from "react-aria-components";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Component, Fragment as Fragment$1, createContext, createElement, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
7
|
import { AlertTriangle, ArrowDown, ArrowUp, Check, ChevronDown, ChevronRight, ChevronsUpDown, Copy, FileText, Folder, FolderOpen, FolderPlus, Globe, Info, MoreHorizontal, PanelLeft, Pencil, Pin, PinOff, Plus, RefreshCw, Share, ShieldQuestion, Square, ThumbsDown, ThumbsUp, Trash2, Volume2, X } from "lucide-react";
|
|
7
|
-
import { Component, Fragment as Fragment$1, createContext, createElement, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
8
8
|
import { UNSAFE_PortalProvider } from "react-aria";
|
|
9
9
|
import { createMathPlugin } from "@streamdown/math";
|
|
10
10
|
import { Streamdown, defaultRehypePlugins } from "streamdown";
|
|
@@ -27,25 +27,34 @@ const variants = {
|
|
|
27
27
|
/** Plain text button, highlights on hover. Sidebar rows, header buttons. */
|
|
28
28
|
ghost: "text-chat-fg data-hovered:bg-chat-hover data-pressed:bg-chat-selected",
|
|
29
29
|
/** Filled with the surface color, e.g. the selected Chat/Cowork toggle. */
|
|
30
|
-
subtle: "bg-chat-surface text-chat-fg data-hovered:bg-chat-hover data-pressed:bg-chat-selected",
|
|
31
|
-
/**
|
|
32
|
-
|
|
30
|
+
subtle: "bg-chat-surface font-medium text-chat-fg data-hovered:bg-chat-hover data-pressed:bg-chat-selected",
|
|
31
|
+
/** A thin border, no fill: secondary actions next to a primary one, e.g. Cancel or Share. */
|
|
32
|
+
outline: "border border-chat-border-strong font-medium text-chat-fg data-hovered:bg-chat-hover data-pressed:bg-chat-selected",
|
|
33
|
+
/** The send button and the one main action of a dialog. */
|
|
34
|
+
primary: "bg-chat-accent font-medium text-chat-accent-fg data-hovered:brightness-110 data-pressed:brightness-95",
|
|
35
|
+
/**
|
|
36
|
+
* Destructive confirmations, e.g. Delete chat. Fill --chat-danger-bg (default: --chat-danger, darkened so it
|
|
37
|
+
* doesn't read as the accent), text --chat-danger-fg (default white).
|
|
38
|
+
*/
|
|
39
|
+
danger: "bg-[var(--chat-danger-bg,color-mix(in_srgb,var(--chat-danger)_70%,black))] font-medium text-[var(--chat-danger-fg,#fff)] data-hovered:brightness-110 data-pressed:brightness-95"
|
|
33
40
|
};
|
|
34
41
|
const sizes = {
|
|
35
42
|
sm: "h-7 gap-1.5 px-2 text-(length:--chat-ui-font-size) leading-5 [@media(pointer:coarse)]:h-9",
|
|
36
|
-
md: "h-8 gap-2 px-2.5 text-(length:--chat-ui-font-size) leading-5 [@media(pointer:coarse)]:h-10"
|
|
43
|
+
md: "h-8 gap-2 px-2.5 text-(length:--chat-ui-font-size) leading-5 [@media(pointer:coarse)]:h-10",
|
|
44
|
+
/** Dialog and empty-state actions. */
|
|
45
|
+
lg: "h-9 gap-2 px-3.5 text-(length:--chat-ui-font-size) leading-5 [@media(pointer:coarse)]:h-11"
|
|
37
46
|
};
|
|
38
47
|
function Button({ variant = "ghost", size = "md", className, ...props }) {
|
|
39
48
|
return /* @__PURE__ */ jsx(Button$1, {
|
|
40
49
|
...props,
|
|
41
|
-
className: clsx("inline-flex cursor-pointer items-center rounded-chat-sm font-chat-sans whitespace-nowrap transition-colors select-none", "data-disabled:cursor-default data-disabled:opacity-40", focusRing, variants[variant], sizes[size], className)
|
|
50
|
+
className: clsx("inline-flex cursor-pointer items-center rounded-chat-sm font-chat-sans whitespace-nowrap transition-colors select-none [&_svg]:size-4 [&_svg]:shrink-0", "data-disabled:cursor-default data-disabled:opacity-40", focusRing, variants[variant], sizes[size], className)
|
|
42
51
|
});
|
|
43
52
|
}
|
|
44
53
|
function IconButton({ label, variant = "ghost", size = "md", tooltip = true, className, ...props }) {
|
|
45
54
|
const button = /* @__PURE__ */ jsx(Button$1, {
|
|
46
55
|
...props,
|
|
47
56
|
"aria-label": label,
|
|
48
|
-
className: clsx("inline-flex shrink-0 cursor-pointer items-center justify-center rounded-chat-sm
|
|
57
|
+
className: clsx("inline-flex shrink-0 cursor-pointer items-center justify-center rounded-chat-sm transition-colors select-none", "data-disabled:cursor-default data-disabled:opacity-40 [&_svg]:size-4", focusRing, variants[variant], variant === "ghost" && "text-chat-muted data-hovered:text-chat-fg", size === "sm" ? "size-7 [@media(pointer:coarse)]:size-9" : "size-8 [@media(pointer:coarse)]:size-10", className)
|
|
49
58
|
});
|
|
50
59
|
return tooltip ? /* @__PURE__ */ jsx(Tooltip, {
|
|
51
60
|
content: label,
|
|
@@ -142,6 +151,176 @@ function IconSlot({ children, className }) {
|
|
|
142
151
|
children
|
|
143
152
|
});
|
|
144
153
|
}
|
|
154
|
+
// src/primitives/labels.tsx
|
|
155
|
+
const plural = (count, one, many) => count === 1 ? one : many(count);
|
|
156
|
+
/** The English strings. */
|
|
157
|
+
const defaultLabels = {
|
|
158
|
+
thinking: "Thinking…",
|
|
159
|
+
thought: "Thought",
|
|
160
|
+
thoughtFor: (duration) => `Thought for ${duration}`,
|
|
161
|
+
waitingForYou: " · waiting for you",
|
|
162
|
+
usedTool: (name) => `used ${name}`,
|
|
163
|
+
joinSummaries: (phrases) => {
|
|
164
|
+
const text = phrases.join(", ");
|
|
165
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
166
|
+
},
|
|
167
|
+
duration: (seconds) => seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`,
|
|
168
|
+
ranCommandLabel: "Ran a command",
|
|
169
|
+
ranCommands: (count) => plural(count, "ran a command", (n) => `ran ${n} commands`),
|
|
170
|
+
searchedWebLabel: "Searched the web",
|
|
171
|
+
readPageLabel: "Read page",
|
|
172
|
+
readPages: (count) => plural(count, "read a page", (n) => `read ${n} pages`),
|
|
173
|
+
searchedWeb: (count) => plural(count, "searched the web", (n) => `searched the web ${n} times`),
|
|
174
|
+
recalledMemoryLabel: "Recalled memory",
|
|
175
|
+
recalledMemory: () => "recalled memory",
|
|
176
|
+
output: "Output",
|
|
177
|
+
noOutput: "(no output)",
|
|
178
|
+
noResults: "No results",
|
|
179
|
+
reasoningHidden: "The model's reasoning is not shown.",
|
|
180
|
+
allowTool: (name) => `Allow ${name}?`,
|
|
181
|
+
allowAction: (label) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
182
|
+
"Allow ",
|
|
183
|
+
label,
|
|
184
|
+
"?"
|
|
185
|
+
] }),
|
|
186
|
+
allow: "Allow",
|
|
187
|
+
deny: "Deny",
|
|
188
|
+
sidebar: "Sidebar",
|
|
189
|
+
closeSidebar: "Close sidebar",
|
|
190
|
+
openSidebar: "Open sidebar",
|
|
191
|
+
expandSidebar: "Expand sidebar",
|
|
192
|
+
collapseSidebar: "Collapse sidebar",
|
|
193
|
+
context: "Context",
|
|
194
|
+
contextUsed: "Context used",
|
|
195
|
+
percentUsed: (percent) => `${percent}% used`,
|
|
196
|
+
freeSpace: "Free space",
|
|
197
|
+
tokenCount: (count) => `${count} tokens`,
|
|
198
|
+
replyPlaceholder: "Reply…",
|
|
199
|
+
replyDirectly: "Or reply directly…",
|
|
200
|
+
message: "Message",
|
|
201
|
+
stop: "Stop",
|
|
202
|
+
send: "Send",
|
|
203
|
+
addFiles: "Add files and more",
|
|
204
|
+
attachments: "Attachments",
|
|
205
|
+
editPastedText: "Edit pasted text",
|
|
206
|
+
viewPastedText: "View pasted text",
|
|
207
|
+
removeAttachment: (name) => `Remove ${name}`,
|
|
208
|
+
pastedText: "Pasted text",
|
|
209
|
+
pasted: "Pasted",
|
|
210
|
+
failed: "Failed",
|
|
211
|
+
file: "File",
|
|
212
|
+
uploadFailed: "Upload failed",
|
|
213
|
+
cancel: "Cancel",
|
|
214
|
+
close: "Close",
|
|
215
|
+
save: "Save",
|
|
216
|
+
chats: "Chats",
|
|
217
|
+
running: "Running",
|
|
218
|
+
unread: "Unread",
|
|
219
|
+
moreOptionsFor: (title) => `More options for ${title}`,
|
|
220
|
+
new: "New",
|
|
221
|
+
viewAll: "View all",
|
|
222
|
+
chatActions: "Chat actions",
|
|
223
|
+
pin: "Pin",
|
|
224
|
+
unpin: "Unpin",
|
|
225
|
+
rename: "Rename",
|
|
226
|
+
addToProject: "Add to project",
|
|
227
|
+
searchProjects: "Search or create a project",
|
|
228
|
+
projects: "Projects",
|
|
229
|
+
newProject: "New project",
|
|
230
|
+
shareChat: "Share chat",
|
|
231
|
+
delete: "Delete",
|
|
232
|
+
justNow: "just now",
|
|
233
|
+
copy: "Copy",
|
|
234
|
+
copied: "Copied",
|
|
235
|
+
retry: "Retry",
|
|
236
|
+
edit: "Edit",
|
|
237
|
+
readAloud: "Read aloud",
|
|
238
|
+
goodResponse: "Good response",
|
|
239
|
+
badResponse: "Bad response",
|
|
240
|
+
somethingWentWrong: "Something went wrong.",
|
|
241
|
+
conversation: "Conversation",
|
|
242
|
+
scrollToBottom: "Scroll to bottom",
|
|
243
|
+
showMore: "Show more",
|
|
244
|
+
showLess: "Show less",
|
|
245
|
+
model: "Model",
|
|
246
|
+
modelButton: (label) => `Model: ${label}`,
|
|
247
|
+
effort: "Effort",
|
|
248
|
+
effortNote: "Higher effort means more thorough responses, but takes longer and uses your limits faster.",
|
|
249
|
+
recommended: "Recommended",
|
|
250
|
+
effortFaster: "Faster",
|
|
251
|
+
effortSmarter: "Smarter",
|
|
252
|
+
moreModels: "More models",
|
|
253
|
+
widget: "Widget",
|
|
254
|
+
visualUpdated: "Updated below ↓",
|
|
255
|
+
visualUpdating: "Updating…",
|
|
256
|
+
drawingWidget: "Drawing"
|
|
257
|
+
};
|
|
258
|
+
const LabelsContext = createContext(defaultLabels);
|
|
259
|
+
/** Merges `labels` over the labels of the enclosing provider (or the defaults). */
|
|
260
|
+
function LabelsProvider({ labels, children }) {
|
|
261
|
+
const parent = useLabels();
|
|
262
|
+
const merged = useMemo(() => labels ? {
|
|
263
|
+
...parent,
|
|
264
|
+
...labels
|
|
265
|
+
} : parent, [parent, labels]);
|
|
266
|
+
return /* @__PURE__ */ jsx(LabelsContext.Provider, {
|
|
267
|
+
value: merged,
|
|
268
|
+
children
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/** The active UI strings: the enclosing `ChatTheme`'s `labels` over the English defaults. */
|
|
272
|
+
function useLabels() {
|
|
273
|
+
return useContext(LabelsContext);
|
|
274
|
+
}
|
|
275
|
+
// src/primitives/copy-button.tsx
|
|
276
|
+
/** Copies `text`; shows a check for a moment after. */
|
|
277
|
+
function CopyButton({ text, className }) {
|
|
278
|
+
const icons = useIcons();
|
|
279
|
+
const labels = useLabels();
|
|
280
|
+
const [copied, setCopied] = useState(false);
|
|
281
|
+
return /* @__PURE__ */ jsx(IconButton, {
|
|
282
|
+
label: copied ? labels.copied : labels.copy,
|
|
283
|
+
size: "sm",
|
|
284
|
+
...className && { className },
|
|
285
|
+
onPress: () => {
|
|
286
|
+
navigator.clipboard?.writeText(text);
|
|
287
|
+
setCopied(true);
|
|
288
|
+
setTimeout(() => setCopied(false), 1500);
|
|
289
|
+
},
|
|
290
|
+
children: copied ? icons.copied : icons.copy
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
// src/primitives/segmented-control.tsx
|
|
294
|
+
/**
|
|
295
|
+
* One of a few options, side by side on a track, like claude.ai's Chat / Cowork switch. Themed with
|
|
296
|
+
* `--chat-segment-track` (default: a shade darker than the surface it sits on) and `--chat-segment-selected`
|
|
297
|
+
* (default `--chat-raised`).
|
|
298
|
+
*/
|
|
299
|
+
function SegmentedControl({ label, options, value, onChange, className }) {
|
|
300
|
+
return /* @__PURE__ */ jsx(ToggleButtonGroup, {
|
|
301
|
+
"aria-label": label,
|
|
302
|
+
selectionMode: "single",
|
|
303
|
+
disallowEmptySelection: true,
|
|
304
|
+
selectedKeys: [value],
|
|
305
|
+
onSelectionChange: (keys) => {
|
|
306
|
+
const next = [...keys][0];
|
|
307
|
+
if (next !== void 0) onChange(next);
|
|
308
|
+
},
|
|
309
|
+
className: clsx("inline-flex shrink-0 items-center gap-0.5 rounded-chat-md p-0.5", "bg-[var(--chat-segment-track,color-mix(in_srgb,var(--chat-bg)_55%,transparent))]", className),
|
|
310
|
+
children: options.map((o) => {
|
|
311
|
+
const button = /* @__PURE__ */ jsxs(ToggleButton, {
|
|
312
|
+
id: o.id,
|
|
313
|
+
...o.iconOnly && { "aria-label": o.label },
|
|
314
|
+
className: clsx("inline-flex h-6 cursor-pointer items-center justify-center gap-1.5 rounded-[calc(var(--chat-radius-md)-2px)] font-chat-sans text-(length:--chat-ui-font-size) leading-5 text-chat-muted outline-none transition-colors select-none [&_svg]:size-4", o.iconOnly ? "w-7" : "px-2", "data-hovered:text-chat-fg data-focus-visible:ring-2 data-focus-visible:ring-chat-focus", "data-selected:bg-[var(--chat-segment-selected,var(--chat-raised))] data-selected:text-chat-fg data-selected:shadow-[inset_0_0_0_1px_var(--chat-border-strong)]"),
|
|
315
|
+
children: [o.icon, !o.iconOnly && o.label]
|
|
316
|
+
}, o.id);
|
|
317
|
+
return o.iconOnly ? /* @__PURE__ */ jsx(Tooltip, {
|
|
318
|
+
content: o.label,
|
|
319
|
+
children: button
|
|
320
|
+
}, o.id) : button;
|
|
321
|
+
})
|
|
322
|
+
});
|
|
323
|
+
}
|
|
145
324
|
// src/primitives/disclosure.tsx
|
|
146
325
|
/** A row that expands to show more, like "Recalled memory ▸". */
|
|
147
326
|
function Disclosure({ summary, children, className, summaryClassName, panelClassName, indicator = "caret", trailing, ...props }) {
|
|
@@ -212,7 +391,7 @@ function Menu({ className, ...props }) {
|
|
|
212
391
|
className: clsx("max-h-[inherit] min-w-52 overflow-auto p-1.5 outline-none", className)
|
|
213
392
|
});
|
|
214
393
|
}
|
|
215
|
-
function MenuItem({ children, icon, description, detail, shortcut, tone = "default", className, ...props }) {
|
|
394
|
+
function MenuItem({ children, icon, description, descriptionPlacement = "below", detail, shortcut, tone = "default", className, ...props }) {
|
|
216
395
|
const icons = useIcons();
|
|
217
396
|
const textValue = props.textValue ?? (typeof children === "string" ? children : void 0);
|
|
218
397
|
return /* @__PURE__ */ jsx(MenuItem$1, {
|
|
@@ -225,14 +404,14 @@ function MenuItem({ children, icon, description, detail, shortcut, tone = "defau
|
|
|
225
404
|
children: icon
|
|
226
405
|
}),
|
|
227
406
|
/* @__PURE__ */ jsxs("span", {
|
|
228
|
-
className: "flex min-w-0 flex-1 flex-col",
|
|
407
|
+
className: clsx("flex min-w-0 flex-1", descriptionPlacement === "beside" ? "items-baseline gap-2" : "flex-col"),
|
|
229
408
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
230
409
|
slot: "label",
|
|
231
|
-
className: "truncate",
|
|
410
|
+
className: clsx("truncate", descriptionPlacement === "beside" && "shrink-0"),
|
|
232
411
|
children
|
|
233
412
|
}), description && /* @__PURE__ */ jsx(Text, {
|
|
234
413
|
slot: "description",
|
|
235
|
-
className: "text-(length:--chat-ui-font-size
|
|
414
|
+
className: clsx("text-chat-muted", descriptionPlacement === "beside" ? "truncate text-(length:--chat-ui-font-size) leading-5" : "text-(length:--chat-ui-font-size-sm) leading-4"),
|
|
236
415
|
children: description
|
|
237
416
|
})]
|
|
238
417
|
}),
|
|
@@ -519,7 +698,7 @@ function useHighlight(code, language) {
|
|
|
519
698
|
}
|
|
520
699
|
// src/primitives/code-block.tsx
|
|
521
700
|
/** Monospace code with Shiki highlighting, scrolling past a fixed height. */
|
|
522
|
-
function CodeBlock({ code, language, label = language, variant = "plain", className }) {
|
|
701
|
+
function CodeBlock({ code, language, label = language, variant = "plain", copy = variant === "boxed", className }) {
|
|
523
702
|
const result = useHighlight(code, language);
|
|
524
703
|
const lines = result?.lines;
|
|
525
704
|
const themeBackground = useCodeThemes().background === "theme" && variant === "boxed" && !!result;
|
|
@@ -531,9 +710,12 @@ function CodeBlock({ code, language, label = language, variant = "plain", classN
|
|
|
531
710
|
"data-chat-code-bg": themeBackground ? "theme" : void 0,
|
|
532
711
|
style: themeBackground ? result.vars : void 0,
|
|
533
712
|
className: clsx(variant === "boxed" && "my-4 rounded-chat-md border border-chat-code-border bg-chat-code-bg px-4 py-3.5", className),
|
|
534
|
-
children: [label && /* @__PURE__ */
|
|
535
|
-
className: "
|
|
536
|
-
children:
|
|
713
|
+
children: [(label || copy) && /* @__PURE__ */ jsxs("div", {
|
|
714
|
+
className: clsx("flex items-center gap-2 font-chat-sans text-(length:--chat-ui-font-size-sm) leading-4 text-chat-subtle", copy ? "-mt-1.5 -mr-2 mb-1.5" : "mb-3"),
|
|
715
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
716
|
+
className: "min-w-0 flex-1 truncate",
|
|
717
|
+
children: label
|
|
718
|
+
}), copy && /* @__PURE__ */ jsx(CopyButton, { text: code })]
|
|
537
719
|
}), /* @__PURE__ */ jsx("pre", {
|
|
538
720
|
className: clsx("overflow-auto font-chat-mono text-(length:--chat-code-font-size) leading-[1.75] whitespace-pre text-chat-fg", variant === "plain" && "max-h-56", "[scrollbar-color:var(--chat-border-strong)_transparent] [scrollbar-width:thin]"),
|
|
539
721
|
children: /* @__PURE__ */ jsxs("code", { children: [highlighted ? highlighted.map((line, i) => /* @__PURE__ */ jsxs(Fragment$1, { children: [i > 0 && "\n", line.map((token, j) => /* @__PURE__ */ jsx("span", {
|
|
@@ -544,123 +726,6 @@ function CodeBlock({ code, language, label = language, variant = "plain", classN
|
|
|
544
726
|
})]
|
|
545
727
|
});
|
|
546
728
|
}
|
|
547
|
-
// src/primitives/labels.tsx
|
|
548
|
-
const plural = (count, one, many) => count === 1 ? one : many(count);
|
|
549
|
-
/** The English strings. */
|
|
550
|
-
const defaultLabels = {
|
|
551
|
-
thinking: "Thinking…",
|
|
552
|
-
thought: "Thought",
|
|
553
|
-
thoughtFor: (duration) => `Thought for ${duration}`,
|
|
554
|
-
waitingForYou: " · waiting for you",
|
|
555
|
-
usedTool: (name) => `used ${name}`,
|
|
556
|
-
joinSummaries: (phrases) => {
|
|
557
|
-
const text = phrases.join(", ");
|
|
558
|
-
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
559
|
-
},
|
|
560
|
-
duration: (seconds) => seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`,
|
|
561
|
-
ranCommandLabel: "Ran a command",
|
|
562
|
-
ranCommands: (count) => plural(count, "ran a command", (n) => `ran ${n} commands`),
|
|
563
|
-
searchedWebLabel: "Searched the web",
|
|
564
|
-
readPageLabel: "Read page",
|
|
565
|
-
readPages: (count) => plural(count, "read a page", (n) => `read ${n} pages`),
|
|
566
|
-
searchedWeb: (count) => plural(count, "searched the web", (n) => `searched the web ${n} times`),
|
|
567
|
-
recalledMemoryLabel: "Recalled memory",
|
|
568
|
-
recalledMemory: () => "recalled memory",
|
|
569
|
-
output: "Output",
|
|
570
|
-
noOutput: "(no output)",
|
|
571
|
-
noResults: "No results",
|
|
572
|
-
reasoningHidden: "The model's reasoning is not shown.",
|
|
573
|
-
allowTool: (name) => `Allow ${name}?`,
|
|
574
|
-
allowAction: (label) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
575
|
-
"Allow ",
|
|
576
|
-
label,
|
|
577
|
-
"?"
|
|
578
|
-
] }),
|
|
579
|
-
allow: "Allow",
|
|
580
|
-
deny: "Deny",
|
|
581
|
-
sidebar: "Sidebar",
|
|
582
|
-
closeSidebar: "Close sidebar",
|
|
583
|
-
openSidebar: "Open sidebar",
|
|
584
|
-
expandSidebar: "Expand sidebar",
|
|
585
|
-
collapseSidebar: "Collapse sidebar",
|
|
586
|
-
context: "Context",
|
|
587
|
-
contextUsed: "Context used",
|
|
588
|
-
percentUsed: (percent) => `${percent}% used`,
|
|
589
|
-
freeSpace: "Free space",
|
|
590
|
-
tokenCount: (count) => `${count} tokens`,
|
|
591
|
-
replyPlaceholder: "Reply…",
|
|
592
|
-
replyDirectly: "Or reply directly…",
|
|
593
|
-
message: "Message",
|
|
594
|
-
stop: "Stop",
|
|
595
|
-
send: "Send",
|
|
596
|
-
addFiles: "Add files and more",
|
|
597
|
-
attachments: "Attachments",
|
|
598
|
-
editPastedText: "Edit pasted text",
|
|
599
|
-
viewPastedText: "View pasted text",
|
|
600
|
-
removeAttachment: (name) => `Remove ${name}`,
|
|
601
|
-
pastedText: "Pasted text",
|
|
602
|
-
pasted: "Pasted",
|
|
603
|
-
failed: "Failed",
|
|
604
|
-
file: "File",
|
|
605
|
-
uploadFailed: "Upload failed",
|
|
606
|
-
cancel: "Cancel",
|
|
607
|
-
close: "Close",
|
|
608
|
-
save: "Save",
|
|
609
|
-
chats: "Chats",
|
|
610
|
-
running: "Running",
|
|
611
|
-
unread: "Unread",
|
|
612
|
-
moreOptionsFor: (title) => `More options for ${title}`,
|
|
613
|
-
new: "New",
|
|
614
|
-
viewAll: "View all",
|
|
615
|
-
chatActions: "Chat actions",
|
|
616
|
-
pin: "Pin",
|
|
617
|
-
unpin: "Unpin",
|
|
618
|
-
rename: "Rename",
|
|
619
|
-
addToProject: "Add to project",
|
|
620
|
-
searchProjects: "Search or create a project",
|
|
621
|
-
projects: "Projects",
|
|
622
|
-
newProject: "New project",
|
|
623
|
-
shareChat: "Share chat",
|
|
624
|
-
delete: "Delete",
|
|
625
|
-
justNow: "just now",
|
|
626
|
-
copy: "Copy",
|
|
627
|
-
copied: "Copied",
|
|
628
|
-
retry: "Retry",
|
|
629
|
-
edit: "Edit",
|
|
630
|
-
readAloud: "Read aloud",
|
|
631
|
-
goodResponse: "Good response",
|
|
632
|
-
badResponse: "Bad response",
|
|
633
|
-
somethingWentWrong: "Something went wrong.",
|
|
634
|
-
conversation: "Conversation",
|
|
635
|
-
scrollToBottom: "Scroll to bottom",
|
|
636
|
-
showMore: "Show more",
|
|
637
|
-
showLess: "Show less",
|
|
638
|
-
model: "Model",
|
|
639
|
-
modelButton: (label) => `Model: ${label}`,
|
|
640
|
-
effort: "Effort",
|
|
641
|
-
effortNote: "Higher effort means more thorough responses, but takes longer and uses your limits faster.",
|
|
642
|
-
recommended: "Recommended",
|
|
643
|
-
moreModels: "More models",
|
|
644
|
-
widget: "Widget",
|
|
645
|
-
drawingWidget: "Drawing"
|
|
646
|
-
};
|
|
647
|
-
const LabelsContext = createContext(defaultLabels);
|
|
648
|
-
/** Merges `labels` over the labels of the enclosing provider (or the defaults). */
|
|
649
|
-
function LabelsProvider({ labels, children }) {
|
|
650
|
-
const parent = useLabels();
|
|
651
|
-
const merged = useMemo(() => labels ? {
|
|
652
|
-
...parent,
|
|
653
|
-
...labels
|
|
654
|
-
} : parent, [parent, labels]);
|
|
655
|
-
return /* @__PURE__ */ jsx(LabelsContext.Provider, {
|
|
656
|
-
value: merged,
|
|
657
|
-
children
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
/** The active UI strings: the enclosing `ChatTheme`'s `labels` over the English defaults. */
|
|
661
|
-
function useLabels() {
|
|
662
|
-
return useContext(LabelsContext);
|
|
663
|
-
}
|
|
664
729
|
// src/primitives/chat-theme.tsx
|
|
665
730
|
/**
|
|
666
731
|
* Applies a chat theme to part of a page. Menus, tooltips and dialogs opened inside render into this
|
|
@@ -1207,6 +1272,87 @@ const SidebarContext = createContext({
|
|
|
1207
1272
|
dismiss: () => {}
|
|
1208
1273
|
});
|
|
1209
1274
|
const useSidebar = () => useContext(SidebarContext);
|
|
1275
|
+
// src/components/replacements.tsx
|
|
1276
|
+
/**
|
|
1277
|
+
* In-place updates of drawn visuals: a tool call whose input has `replaces: <id>` takes the place of that
|
|
1278
|
+
* earlier call. In the same reply the newest finished call is drawn where the first one was, and the old one
|
|
1279
|
+
* stays (dimmed) until the new one's input is complete. A call replaced from a later reply folds into a link.
|
|
1280
|
+
*/
|
|
1281
|
+
/** Ready to take the old one's place: its input is complete and it didn't fail. */
|
|
1282
|
+
const isReady = (p) => p.status !== "streaming" && p.status !== "input" && p.status !== "error";
|
|
1283
|
+
const callsOf = (m) => m.parts.filter((p) => p.type === "tool_call");
|
|
1284
|
+
const replaces = (p) => replacedId(p.input ?? p.partialInput);
|
|
1285
|
+
/** One reply's chains: each call's first call (where the chain is drawn) and each first call's chain, in order. */
|
|
1286
|
+
function chainsOf(message) {
|
|
1287
|
+
const first = /* @__PURE__ */ new Map();
|
|
1288
|
+
const chains = /* @__PURE__ */ new Map();
|
|
1289
|
+
for (const call of callsOf(message)) {
|
|
1290
|
+
const r = replaces(call);
|
|
1291
|
+
const root = r !== void 0 && first.has(r) ? first.get(r) : call.id;
|
|
1292
|
+
first.set(call.id, root);
|
|
1293
|
+
chains.set(root, [...chains.get(root) ?? [], call]);
|
|
1294
|
+
}
|
|
1295
|
+
return {
|
|
1296
|
+
first,
|
|
1297
|
+
chains
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
/** Calls replaced by a finished call in a later reply: replaced id → the newest such call. */
|
|
1301
|
+
function laterReplacements(messages) {
|
|
1302
|
+
const later = /* @__PURE__ */ new Map();
|
|
1303
|
+
for (const m of messages) {
|
|
1304
|
+
if (m.role !== "assistant") continue;
|
|
1305
|
+
const own = new Set(callsOf(m).map((c) => c.id));
|
|
1306
|
+
for (const call of callsOf(m)) {
|
|
1307
|
+
const r = replaces(call);
|
|
1308
|
+
if (r !== void 0 && !own.has(r) && isReady(call)) later.set(r, call);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
return later;
|
|
1312
|
+
}
|
|
1313
|
+
const LaterContext = createContext(/* @__PURE__ */ new Map());
|
|
1314
|
+
function LaterReplacements({ value, children }) {
|
|
1315
|
+
return /* @__PURE__ */ jsx(LaterContext.Provider, {
|
|
1316
|
+
value,
|
|
1317
|
+
children
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
/** The call in a later reply that replaces any call of this chain, if there is one. */
|
|
1321
|
+
function useLaterReplacement(chain) {
|
|
1322
|
+
const later = useContext(LaterContext);
|
|
1323
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
1324
|
+
const by = later.get(chain[i].id);
|
|
1325
|
+
if (by) return by;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
/** The DOM id of a drawn tool call, for the "Updated below" link. */
|
|
1329
|
+
const toolAnchor = (id) => `chat-tool-${id}`;
|
|
1330
|
+
/** Draws a chain: the newest finished call (dimmed while a newer one streams), or a link to its later update. */
|
|
1331
|
+
function ToolChain({ chain, draw }) {
|
|
1332
|
+
const labels = useLabels();
|
|
1333
|
+
const later = useLaterReplacement(chain);
|
|
1334
|
+
const shown = chain.findLast(isReady) ?? chain[0];
|
|
1335
|
+
const updating = chain.indexOf(shown) < chain.length - 1 && chain.at(-1).status !== "error";
|
|
1336
|
+
if (later) return /* @__PURE__ */ jsx(Button, {
|
|
1337
|
+
variant: "ghost",
|
|
1338
|
+
size: "sm",
|
|
1339
|
+
className: "self-start text-chat-muted data-hovered:text-chat-fg",
|
|
1340
|
+
onPress: () => document.getElementById(toolAnchor(later.id))?.scrollIntoView({
|
|
1341
|
+
behavior: "smooth",
|
|
1342
|
+
block: "center"
|
|
1343
|
+
}),
|
|
1344
|
+
children: labels.visualUpdated
|
|
1345
|
+
});
|
|
1346
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1347
|
+
id: toolAnchor(chain[0].id),
|
|
1348
|
+
"aria-busy": updating || void 0,
|
|
1349
|
+
className: updating ? "opacity-60 transition-opacity" : "transition-opacity",
|
|
1350
|
+
children: [/* @__PURE__ */ jsx("div", { children: draw(shown) }, shown.id), updating && /* @__PURE__ */ jsx("p", {
|
|
1351
|
+
className: "chat-shimmer mt-1 font-chat-sans text-(length:--chat-ui-font-size-sm) text-chat-muted",
|
|
1352
|
+
children: labels.visualUpdating
|
|
1353
|
+
})]
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1210
1356
|
// src/components/widget-frame.tsx
|
|
1211
1357
|
const WidgetHostContext = createContext({});
|
|
1212
1358
|
/** Sets what widgets below may do. ChatView and ChatTranscript set it from their `widgets` prop. */
|
|
@@ -1322,6 +1468,8 @@ const BOOT = `(() => {
|
|
|
1322
1468
|
new ResizeObserver(() => {
|
|
1323
1469
|
const h = Math.ceil(root.getBoundingClientRect().height);
|
|
1324
1470
|
if (h !== last) { last = h; post("ui/notifications/size-changed", { height: h }); }
|
|
1471
|
+
// The frame grows to fit, a moment behind; only content past the cap gets a scrollbar.
|
|
1472
|
+
document.documentElement.style.overflowY = h > ${WIDGET_MAX_HEIGHT} ? "auto" : "hidden";
|
|
1325
1473
|
}).observe(root);
|
|
1326
1474
|
const seen = new Set();
|
|
1327
1475
|
const report = (text) => { if (!seen.has(text) && seen.size < 10) { seen.add(text); post("notifications/message", { level: "error", logger: "widget", data: text }); } };
|
|
@@ -1334,6 +1482,7 @@ function fragmentDoc(csp, theme) {
|
|
|
1334
1482
|
<meta http-equiv="Content-Security-Policy" content="${csp}">
|
|
1335
1483
|
<style>
|
|
1336
1484
|
:root { ${Object.entries(theme.vars).map(([k, v]) => `${k}: ${v};`).join(" ")} color-scheme: ${theme.scheme}; }
|
|
1485
|
+
html { overflow: hidden; }
|
|
1337
1486
|
html, body { margin: 0; background: transparent; color: var(--chat-fg); font-family: var(--chat-font-sans);
|
|
1338
1487
|
font-size: var(--chat-ui-font-size); line-height: 1.5; }
|
|
1339
1488
|
#widget { display: flow-root; }
|
|
@@ -2348,10 +2497,14 @@ function ActivityGroup({ parts, defaultExpanded = false, className }) {
|
|
|
2348
2497
|
}) : /* @__PURE__ */ jsx(Disclosure, {
|
|
2349
2498
|
isExpanded: expanded,
|
|
2350
2499
|
onExpandedChange: setExpanded,
|
|
2351
|
-
summary: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2352
|
-
live,
|
|
2353
|
-
|
|
2354
|
-
|
|
2500
|
+
summary: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2501
|
+
/* @__PURE__ */ jsx(Lead, { live }),
|
|
2502
|
+
/* @__PURE__ */ jsx(Live, {
|
|
2503
|
+
live,
|
|
2504
|
+
children: activityHeading(parts, views, labels)
|
|
2505
|
+
}),
|
|
2506
|
+
after
|
|
2507
|
+
] }),
|
|
2355
2508
|
summaryClassName: "text-(length:--chat-activity-font-size)",
|
|
2356
2509
|
panelClassName: "pt-3",
|
|
2357
2510
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -2361,6 +2514,17 @@ function ActivityGroup({ parts, defaultExpanded = false, className }) {
|
|
|
2361
2514
|
})
|
|
2362
2515
|
});
|
|
2363
2516
|
}
|
|
2517
|
+
/** The host's mark left of the summary (`icons.activity` while working, `icons.activityDone` after), if set. */
|
|
2518
|
+
function Lead({ live }) {
|
|
2519
|
+
const icons = useIcons();
|
|
2520
|
+
const icon = live ? icons.activity : icons.activityDone;
|
|
2521
|
+
if (!icon) return null;
|
|
2522
|
+
return /* @__PURE__ */ jsx("span", {
|
|
2523
|
+
"aria-hidden": true,
|
|
2524
|
+
className: "chat-activity-icon mr-1.5 inline-flex size-[1.15em] shrink-0 items-center self-center [&_svg]:size-full",
|
|
2525
|
+
children: icon
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2364
2528
|
const SHIMMER_MS = 2e3;
|
|
2365
2529
|
/**
|
|
2366
2530
|
* Sweeps a highlight across a label while its step is running. The animation starts at the phase of a
|
|
@@ -2385,10 +2549,14 @@ function SingleStep({ part, live, after, expanded, onExpandedChange }) {
|
|
|
2385
2549
|
return /* @__PURE__ */ jsx(Disclosure, {
|
|
2386
2550
|
isExpanded: expanded,
|
|
2387
2551
|
onExpandedChange,
|
|
2388
|
-
summary: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2389
|
-
live,
|
|
2390
|
-
|
|
2391
|
-
|
|
2552
|
+
summary: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2553
|
+
/* @__PURE__ */ jsx(Lead, { live }),
|
|
2554
|
+
/* @__PURE__ */ jsx(Live, {
|
|
2555
|
+
live,
|
|
2556
|
+
children: summary
|
|
2557
|
+
}),
|
|
2558
|
+
after
|
|
2559
|
+
] }),
|
|
2392
2560
|
summaryClassName: "text-(length:--chat-activity-font-size)",
|
|
2393
2561
|
panelClassName: "pt-3",
|
|
2394
2562
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -2689,24 +2857,9 @@ function formatRelativeTime(iso, now = Date.now(), labels = defaultLabels) {
|
|
|
2689
2857
|
function messageText(message) {
|
|
2690
2858
|
return message.parts.map((p) => p.type === "text" ? p.text : p.type === "custom" ? p.text ?? "" : "").filter(Boolean).join("\n\n");
|
|
2691
2859
|
}
|
|
2692
|
-
function CopyButton({ text }) {
|
|
2693
|
-
const icons = useIcons();
|
|
2694
|
-
const labels = useLabels();
|
|
2695
|
-
const [copied, setCopied] = useState(false);
|
|
2696
|
-
return /* @__PURE__ */ jsx(IconButton, {
|
|
2697
|
-
label: copied ? labels.copied : labels.copy,
|
|
2698
|
-
size: "sm",
|
|
2699
|
-
onPress: () => {
|
|
2700
|
-
navigator.clipboard?.writeText(text);
|
|
2701
|
-
setCopied(true);
|
|
2702
|
-
setTimeout(() => setCopied(false), 1500);
|
|
2703
|
-
},
|
|
2704
|
-
children: copied ? icons.copied : icons.copy
|
|
2705
|
-
});
|
|
2706
|
-
}
|
|
2707
2860
|
const timeClass = "px-1 font-chat-sans text-(length:--chat-ui-font-size-sm) leading-4 text-chat-subtle";
|
|
2708
2861
|
/** The user's turn: a bubble on the right, with time, retry, edit and copy under it on hover. */
|
|
2709
|
-
function UserMessage({ message, onRetry, onEdit, actions, className }) {
|
|
2862
|
+
function UserMessage({ message, onRetry, onEdit, actions, copy = true, time = true, className }) {
|
|
2710
2863
|
const icons = useIcons();
|
|
2711
2864
|
const labels = useLabels();
|
|
2712
2865
|
const text = messageText(message);
|
|
@@ -2732,7 +2885,7 @@ function UserMessage({ message, onRetry, onEdit, actions, className }) {
|
|
|
2732
2885
|
/* @__PURE__ */ jsxs("div", {
|
|
2733
2886
|
className: "mt-1 flex items-center gap-0.5 opacity-0 transition-opacity group-hover/message:opacity-100 group-focus-within/message:opacity-100 [@media(hover:none)]:opacity-100",
|
|
2734
2887
|
children: [
|
|
2735
|
-
/* @__PURE__ */ jsx("span", {
|
|
2888
|
+
time && /* @__PURE__ */ jsx("span", {
|
|
2736
2889
|
className: timeClass,
|
|
2737
2890
|
children: formatRelativeTime(message.createdAt, void 0, labels)
|
|
2738
2891
|
}),
|
|
@@ -2748,7 +2901,7 @@ function UserMessage({ message, onRetry, onEdit, actions, className }) {
|
|
|
2748
2901
|
onPress: onEdit,
|
|
2749
2902
|
children: icons.edit
|
|
2750
2903
|
}),
|
|
2751
|
-
/* @__PURE__ */ jsx(CopyButton, { text }),
|
|
2904
|
+
copy && /* @__PURE__ */ jsx(CopyButton, { text }),
|
|
2752
2905
|
actions
|
|
2753
2906
|
]
|
|
2754
2907
|
})
|
|
@@ -2792,12 +2945,13 @@ function UserBubble({ text }) {
|
|
|
2792
2945
|
* The assistant's turn: activity groups (each with its own token count), markdown, and other parts in
|
|
2793
2946
|
* order. When done, copy / read aloud / feedback / retry and the time sit under it.
|
|
2794
2947
|
*/
|
|
2795
|
-
function AssistantMessage({ message, onRetry, onFeedback, onReadAloud, renderPart, actions, className }) {
|
|
2948
|
+
function AssistantMessage({ message, onRetry, onFeedback, onReadAloud, renderPart, actions, copy = true, time = true, className }) {
|
|
2796
2949
|
const icons = useIcons();
|
|
2797
2950
|
const labels = useLabels();
|
|
2798
2951
|
const streaming = message.status === "streaming";
|
|
2799
2952
|
const views = useToolViews();
|
|
2800
2953
|
const blocks = toBlocks(message.parts, (part) => views[part.name]?.Block !== void 0);
|
|
2954
|
+
const { first, chains } = chainsOf(message);
|
|
2801
2955
|
return /* @__PURE__ */ jsxs("div", {
|
|
2802
2956
|
className: clsx("group/message flex flex-col gap-4", className),
|
|
2803
2957
|
children: [
|
|
@@ -2812,8 +2966,14 @@ function AssistantMessage({ message, onRetry, onFeedback, onReadAloud, renderPar
|
|
|
2812
2966
|
})] }, block.id);
|
|
2813
2967
|
}
|
|
2814
2968
|
if (block.kind === "tool") {
|
|
2815
|
-
|
|
2816
|
-
return /* @__PURE__ */ jsx(
|
|
2969
|
+
if (first.get(block.part.id) !== block.part.id) return null;
|
|
2970
|
+
return /* @__PURE__ */ jsx(ToolChain, {
|
|
2971
|
+
chain: chains.get(block.part.id) ?? [block.part],
|
|
2972
|
+
draw: (part) => {
|
|
2973
|
+
const ToolBlock = (views[part.name] ?? views[block.part.name]).Block;
|
|
2974
|
+
return /* @__PURE__ */ jsx(ToolBlock, { part });
|
|
2975
|
+
}
|
|
2976
|
+
}, block.id);
|
|
2817
2977
|
}
|
|
2818
2978
|
const part = block.part;
|
|
2819
2979
|
if (part.type === "text") return /* @__PURE__ */ jsx(Markdown, {
|
|
@@ -2834,7 +2994,7 @@ function AssistantMessage({ message, onRetry, onFeedback, onReadAloud, renderPar
|
|
|
2834
2994
|
streaming ? /* @__PURE__ */ jsx("div", { className: "h-7" }) : /* @__PURE__ */ jsxs("div", {
|
|
2835
2995
|
className: "-ml-1.5 flex h-7 items-center gap-0.5",
|
|
2836
2996
|
children: [
|
|
2837
|
-
/* @__PURE__ */ jsx(CopyButton, { text: messageText(message) }),
|
|
2997
|
+
copy && /* @__PURE__ */ jsx(CopyButton, { text: messageText(message) }),
|
|
2838
2998
|
onReadAloud && /* @__PURE__ */ jsx(IconButton, {
|
|
2839
2999
|
label: labels.readAloud,
|
|
2840
3000
|
size: "sm",
|
|
@@ -2859,7 +3019,7 @@ function AssistantMessage({ message, onRetry, onFeedback, onReadAloud, renderPar
|
|
|
2859
3019
|
children: icons.retry
|
|
2860
3020
|
}),
|
|
2861
3021
|
actions,
|
|
2862
|
-
/* @__PURE__ */ jsx("span", {
|
|
3022
|
+
time && /* @__PURE__ */ jsx("span", {
|
|
2863
3023
|
className: timeClass,
|
|
2864
3024
|
children: formatRelativeTime(message.createdAt, void 0, labels)
|
|
2865
3025
|
})
|
|
@@ -3143,18 +3303,18 @@ function Composer({ onSubmit, onStop, busy = false, value, onChange, placeholder
|
|
|
3143
3303
|
label: labels.stop,
|
|
3144
3304
|
variant: "primary",
|
|
3145
3305
|
onPress: onStop,
|
|
3146
|
-
className: "rounded-chat-md [&_svg]:size-3.5 [&_svg]:fill-current",
|
|
3306
|
+
className: "rounded-[var(--chat-send-radius,var(--chat-radius-md))]! [&_svg]:size-3.5 [&_svg]:fill-current",
|
|
3147
3307
|
children: icons.stop
|
|
3148
3308
|
}) : /* @__PURE__ */ jsx(IconButton, {
|
|
3149
3309
|
label: labels.send,
|
|
3150
3310
|
variant: "primary",
|
|
3151
3311
|
onPress: submit,
|
|
3152
3312
|
isDisabled: !canSend,
|
|
3153
|
-
className: "rounded-chat-md",
|
|
3313
|
+
className: "rounded-[var(--chat-send-radius,var(--chat-radius-md))]!",
|
|
3154
3314
|
children: icons.send
|
|
3155
3315
|
});
|
|
3156
3316
|
return /* @__PURE__ */ jsxs("div", {
|
|
3157
|
-
className: clsx("flex flex-col rounded-[1.25rem] border border-chat-border bg-chat-surface font-chat-sans shadow-chat-popover", "focus-within:border-chat-border-strong", dragging && "border-chat-accent! border-dashed", compact ? "gap-1 p-2" : "gap-2 p-3", className),
|
|
3317
|
+
className: clsx("flex flex-col rounded-[var(--chat-composer-radius,1.25rem)] border border-chat-border bg-chat-surface font-chat-sans shadow-chat-popover", "focus-within:border-chat-border-strong", dragging && "border-chat-accent! border-dashed", compact ? "gap-1 p-2" : "gap-2 p-3", className),
|
|
3158
3318
|
...dropProps,
|
|
3159
3319
|
onPointerDown: (e) => {
|
|
3160
3320
|
if (e.target === e.currentTarget) {
|
|
@@ -3198,17 +3358,128 @@ function Composer({ onSubmit, onStop, busy = false, value, onChange, placeholder
|
|
|
3198
3358
|
});
|
|
3199
3359
|
}
|
|
3200
3360
|
/** The `+` button that opens the attach menu above the composer. */
|
|
3201
|
-
function AttachButton({ children, label }) {
|
|
3361
|
+
function AttachButton({ children, label, icon, className, menuClassName }) {
|
|
3202
3362
|
const icons = useIcons();
|
|
3203
3363
|
const labels = useLabels();
|
|
3204
3364
|
return /* @__PURE__ */ jsxs(MenuTrigger, { children: [/* @__PURE__ */ jsx(IconButton, {
|
|
3205
3365
|
label: label ?? labels.addFiles,
|
|
3206
|
-
|
|
3366
|
+
...className && { className },
|
|
3367
|
+
children: icon ?? icons.attach
|
|
3207
3368
|
}), /* @__PURE__ */ jsx(Popover, {
|
|
3208
3369
|
placement: "top start",
|
|
3370
|
+
...menuClassName && { className: menuClassName },
|
|
3209
3371
|
children
|
|
3210
3372
|
})] });
|
|
3211
3373
|
}
|
|
3374
|
+
// src/components/effort-slider.tsx
|
|
3375
|
+
/**
|
|
3376
|
+
* Effort as a slider with one stop per level, lowest (faster) on the left: title and the current level on
|
|
3377
|
+
* top, the level's description under them, "Faster" and "Smarter" under the track. Arrow keys move a stop.
|
|
3378
|
+
*/
|
|
3379
|
+
function EffortSlider({ efforts, value, onChange, label, className }) {
|
|
3380
|
+
const labels = useLabels();
|
|
3381
|
+
const id = useId();
|
|
3382
|
+
const index = Math.max(0, efforts.findIndex((e) => e.id === value));
|
|
3383
|
+
const current = efforts[index];
|
|
3384
|
+
const last = Math.max(1, efforts.length - 1);
|
|
3385
|
+
const at = (i) => `${i / last * 100}%`;
|
|
3386
|
+
if (!current) return null;
|
|
3387
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3388
|
+
className: clsx("flex w-full flex-col gap-1 font-chat-sans", className),
|
|
3389
|
+
children: [
|
|
3390
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3391
|
+
className: "flex items-center gap-2",
|
|
3392
|
+
children: [
|
|
3393
|
+
/* @__PURE__ */ jsx("label", {
|
|
3394
|
+
htmlFor: id,
|
|
3395
|
+
className: "flex-1 text-(length:--chat-ui-font-size) font-medium text-chat-fg",
|
|
3396
|
+
children: label ?? labels.effort
|
|
3397
|
+
}),
|
|
3398
|
+
current.recommended && /* @__PURE__ */ jsx(Badge, { children: labels.recommended }),
|
|
3399
|
+
current.warning && /* @__PURE__ */ jsx(Badge, {
|
|
3400
|
+
tone: "warning",
|
|
3401
|
+
children: current.warning
|
|
3402
|
+
}),
|
|
3403
|
+
/* @__PURE__ */ jsx("output", {
|
|
3404
|
+
htmlFor: id,
|
|
3405
|
+
className: "text-(length:--chat-ui-font-size) text-chat-fg",
|
|
3406
|
+
children: current.label
|
|
3407
|
+
})
|
|
3408
|
+
]
|
|
3409
|
+
}),
|
|
3410
|
+
current.description && /* @__PURE__ */ jsx("p", {
|
|
3411
|
+
className: "text-(length:--chat-ui-font-size-sm) leading-4 text-chat-muted",
|
|
3412
|
+
children: current.description
|
|
3413
|
+
}),
|
|
3414
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3415
|
+
className: "relative mx-2 mt-2 h-6",
|
|
3416
|
+
children: [
|
|
3417
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-1/2 right-0 left-0 h-1 -translate-y-1/2 rounded-full bg-chat-border-strong" }),
|
|
3418
|
+
/* @__PURE__ */ jsx("div", {
|
|
3419
|
+
className: "absolute top-1/2 left-0 h-1 -translate-y-1/2 rounded-full bg-chat-accent",
|
|
3420
|
+
style: { width: at(index) }
|
|
3421
|
+
}),
|
|
3422
|
+
efforts.map((e, i) => /* @__PURE__ */ jsx("span", {
|
|
3423
|
+
"aria-hidden": true,
|
|
3424
|
+
className: clsx("absolute top-1/2 size-1.5 -translate-1/2 rounded-full", i <= index ? "bg-chat-accent-fg/70" : "bg-chat-subtle"),
|
|
3425
|
+
style: { left: at(i) }
|
|
3426
|
+
}, e.id)),
|
|
3427
|
+
/* @__PURE__ */ jsx("span", {
|
|
3428
|
+
"aria-hidden": true,
|
|
3429
|
+
className: "pointer-events-none absolute top-1/2 size-4 -translate-1/2 rounded-full border-2 border-chat-accent bg-chat-fg shadow-sm peer-focus-visible:ring-2",
|
|
3430
|
+
style: { left: at(index) }
|
|
3431
|
+
}),
|
|
3432
|
+
/* @__PURE__ */ jsx("input", {
|
|
3433
|
+
id,
|
|
3434
|
+
type: "range",
|
|
3435
|
+
min: 0,
|
|
3436
|
+
max: efforts.length - 1,
|
|
3437
|
+
step: 1,
|
|
3438
|
+
value: index,
|
|
3439
|
+
"aria-valuetext": current.label,
|
|
3440
|
+
onChange: (e) => {
|
|
3441
|
+
const next = efforts[Number(e.target.value)];
|
|
3442
|
+
if (next && next.id !== value) onChange(next.id);
|
|
3443
|
+
},
|
|
3444
|
+
onKeyDown: (e) => {
|
|
3445
|
+
const step = e.key === "ArrowRight" || e.key === "ArrowUp" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowDown" ? -1 : 0;
|
|
3446
|
+
const next = step ? efforts[index + step] : void 0;
|
|
3447
|
+
if (next) {
|
|
3448
|
+
e.preventDefault();
|
|
3449
|
+
onChange(next.id);
|
|
3450
|
+
}
|
|
3451
|
+
},
|
|
3452
|
+
className: "absolute -inset-x-2 inset-y-0 w-[calc(100%+1rem)] cursor-pointer rounded-full opacity-0 focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-chat-focus [&::-webkit-slider-thumb]:opacity-0"
|
|
3453
|
+
})
|
|
3454
|
+
]
|
|
3455
|
+
}),
|
|
3456
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3457
|
+
className: "flex justify-between text-(length:--chat-ui-font-size-sm) leading-4 text-chat-subtle",
|
|
3458
|
+
children: [/* @__PURE__ */ jsx("span", { children: labels.effortFaster }), /* @__PURE__ */ jsx("span", { children: labels.effortSmarter })]
|
|
3459
|
+
})
|
|
3460
|
+
]
|
|
3461
|
+
});
|
|
3462
|
+
}
|
|
3463
|
+
/** A composer pill ("◎ Medium") that opens the effort slider above it, like chatgpt.com's Think button. */
|
|
3464
|
+
function EffortButton({ icon, children, className, ...slider }) {
|
|
3465
|
+
const current = slider.efforts.find((e) => e.id === slider.value) ?? slider.efforts[0];
|
|
3466
|
+
const labels = useLabels();
|
|
3467
|
+
return /* @__PURE__ */ jsxs(DialogTrigger, { children: [/* @__PURE__ */ jsxs(Button, {
|
|
3468
|
+
variant: "ghost",
|
|
3469
|
+
size: "sm",
|
|
3470
|
+
className: clsx("text-chat-muted data-hovered:text-chat-fg", className),
|
|
3471
|
+
"aria-label": `${labels.effort}: ${current?.label ?? ""}`,
|
|
3472
|
+
children: [icon, children ?? current?.label]
|
|
3473
|
+
}), /* @__PURE__ */ jsx(Popover, {
|
|
3474
|
+
placement: "top end",
|
|
3475
|
+
className: "w-72 p-3",
|
|
3476
|
+
children: /* @__PURE__ */ jsx(Dialog, {
|
|
3477
|
+
"aria-label": labels.effort,
|
|
3478
|
+
className: "outline-none",
|
|
3479
|
+
children: /* @__PURE__ */ jsx(EffortSlider, { ...slider })
|
|
3480
|
+
})
|
|
3481
|
+
})] });
|
|
3482
|
+
}
|
|
3212
3483
|
// src/components/model-picker.tsx
|
|
3213
3484
|
/** "Opus 5.5 High ⌄": the models, an Effort submenu for models that have levels, and More models. */
|
|
3214
3485
|
function ModelPicker({ models, model, onModelChange, effort, onEffortChange, effortNote, footnote, className }) {
|
|
@@ -3323,12 +3594,13 @@ const STICK_SLOP = 48;
|
|
|
3323
3594
|
* The scrolling conversation. It follows a streaming reply while the reader is at the bottom and leaves
|
|
3324
3595
|
* them alone once they scroll up, with a button to jump back. Sending a message always jumps down.
|
|
3325
3596
|
*/
|
|
3326
|
-
function MessageList({ messages, onRetry, onEdit, onFeedback, renderPart, header, footer, start = "bottom", className }) {
|
|
3597
|
+
function MessageList({ messages, onRetry, onEdit, onFeedback, onReadAloud, actions, renderPart, header, footer, start = "bottom", className }) {
|
|
3327
3598
|
const icons = useIcons();
|
|
3328
3599
|
const scroller = useRef(null);
|
|
3329
3600
|
const content = useRef(null);
|
|
3330
3601
|
const stuck = useRef(start === "bottom");
|
|
3331
3602
|
const labels = useLabels();
|
|
3603
|
+
const later = useMemo(() => laterReplacements(messages), [messages]);
|
|
3332
3604
|
const [atBottom, setAtBottom] = useState(true);
|
|
3333
3605
|
const toBottom = useCallback((behavior = "auto") => {
|
|
3334
3606
|
const el = scroller.current;
|
|
@@ -3378,15 +3650,25 @@ function MessageList({ messages, onRetry, onEdit, onFeedback, renderPart, header
|
|
|
3378
3650
|
role: "log",
|
|
3379
3651
|
"aria-label": labels.conversation,
|
|
3380
3652
|
className: "mx-auto flex w-full max-w-[calc(var(--chat-content-width)+2*var(--chat-gutter,var(--chat-content-padding)))] flex-1 flex-col gap-6 px-[var(--chat-gutter,var(--chat-content-padding))] pt-6 pb-4",
|
|
3381
|
-
children: [header,
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3653
|
+
children: [header, /* @__PURE__ */ jsx(LaterReplacements, {
|
|
3654
|
+
value: later,
|
|
3655
|
+
children: messages.map((m) => m.role === "user" ? /* @__PURE__ */ jsx(UserMessage, {
|
|
3656
|
+
message: m,
|
|
3657
|
+
...onEdit && { onEdit: () => onEdit(m.id) },
|
|
3658
|
+
...actions?.extra && { actions: actions.extra(m) },
|
|
3659
|
+
...actions?.copy === false && { copy: false },
|
|
3660
|
+
...actions?.time === false && { time: false }
|
|
3661
|
+
}, m.id) : /* @__PURE__ */ jsx(AssistantMessage, {
|
|
3662
|
+
message: m,
|
|
3663
|
+
...onRetry && { onRetry: () => onRetry(m.id) },
|
|
3664
|
+
...onFeedback && { onFeedback: (f) => onFeedback(m.id, f) },
|
|
3665
|
+
...onReadAloud && { onReadAloud: () => onReadAloud(m.id) },
|
|
3666
|
+
...actions?.extra && { actions: actions.extra(m) },
|
|
3667
|
+
...actions?.copy === false && { copy: false },
|
|
3668
|
+
...actions?.time === false && { time: false },
|
|
3669
|
+
...renderPart && { renderPart }
|
|
3670
|
+
}, m.id))
|
|
3671
|
+
})]
|
|
3390
3672
|
}), footer && /* @__PURE__ */ jsx("div", {
|
|
3391
3673
|
className: "sticky bottom-0",
|
|
3392
3674
|
children: footer
|
|
@@ -3683,7 +3965,7 @@ const densityVars = {
|
|
|
3683
3965
|
}
|
|
3684
3966
|
};
|
|
3685
3967
|
/** A whole chat: header, the conversation, the docked composer. An empty chat shows `emptyState`. */
|
|
3686
|
-
function ChatView({ messages, busy = false, onSend, onStop, approvals, onApprove, onRetry, onEdit, onFeedback, renderPart, widgets, header, composer, emptyState, disclaimer, density = "full", contentWidth, contentPadding, className }) {
|
|
3968
|
+
function ChatView({ messages, busy = false, onSend, onStop, approvals, onApprove, onRetry, onEdit, onFeedback, onReadAloud, messageActions, renderPart, widgets, header, composer, emptyState, disclaimer, renderComposer, density = "full", contentWidth, contentPadding, className }) {
|
|
3687
3969
|
const style = {
|
|
3688
3970
|
...densityVars[density],
|
|
3689
3971
|
...contentWidth && { "--chat-content-width": contentWidth },
|
|
@@ -3698,14 +3980,17 @@ function ChatView({ messages, busy = false, onSend, onStop, approvals, onApprove
|
|
|
3698
3980
|
const [body, short] = useShortPane();
|
|
3699
3981
|
const labels = useLabels();
|
|
3700
3982
|
const pending = onApprove && approvals?.[0];
|
|
3701
|
-
const box = (variant) =>
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3983
|
+
const box = (variant) => {
|
|
3984
|
+
const element = /* @__PURE__ */ jsx(Composer, {
|
|
3985
|
+
variant: density === "inline" || short && !empty ? "compact" : variant,
|
|
3986
|
+
busy,
|
|
3987
|
+
onSubmit: onSend,
|
|
3988
|
+
...onStop && { onStop },
|
|
3989
|
+
...composer,
|
|
3990
|
+
...pending && { placeholder: labels.replyDirectly }
|
|
3991
|
+
});
|
|
3992
|
+
return renderComposer ? renderComposer(element, variant === "centered" ? "empty" : "docked") : element;
|
|
3993
|
+
};
|
|
3709
3994
|
return /* @__PURE__ */ jsxs("div", {
|
|
3710
3995
|
"data-chat-density": density,
|
|
3711
3996
|
style,
|
|
@@ -3726,6 +4011,8 @@ function ChatView({ messages, busy = false, onSend, onStop, approvals, onApprove
|
|
|
3726
4011
|
...onRetry && { onRetry },
|
|
3727
4012
|
...onEdit && { onEdit },
|
|
3728
4013
|
...onFeedback && { onFeedback },
|
|
4014
|
+
...onReadAloud && { onReadAloud },
|
|
4015
|
+
...messageActions && { actions: messageActions },
|
|
3729
4016
|
...renderPart && { renderPart },
|
|
3730
4017
|
footer: /* @__PURE__ */ jsx("div", {
|
|
3731
4018
|
className: clsx("bg-linear-to-t from-chat-bg from-70% to-transparent px-(--chat-gutter)", short ? "pt-2" : "pt-4"),
|
|
@@ -3771,7 +4058,7 @@ function EmptyState({ greeting, icon, children, footer }) {
|
|
|
3771
4058
|
/* @__PURE__ */ jsxs("h1", {
|
|
3772
4059
|
className: "chat-empty-greeting flex items-center justify-center gap-3 text-center font-chat-serif text-[clamp(1.5rem,6cqw,2.5rem)] font-normal text-chat-fg",
|
|
3773
4060
|
children: [icon && /* @__PURE__ */ jsx("span", {
|
|
3774
|
-
className: "flex shrink-0 text-chat-accent [&_svg]:size-[1em]",
|
|
4061
|
+
className: "flex shrink-0 text-[var(--chat-empty-icon,var(--chat-accent))] [&_svg]:size-[1em]",
|
|
3775
4062
|
children: icon
|
|
3776
4063
|
}), greeting]
|
|
3777
4064
|
}),
|
|
@@ -3892,17 +4179,27 @@ function SidebarToggle({ drawerOnly = false, className }) {
|
|
|
3892
4179
|
}
|
|
3893
4180
|
// src/views/sidebar.tsx
|
|
3894
4181
|
/** The claude.ai sidebar frame. Collapses to an icon rail inside `AppShell`; a drawer on phones. */
|
|
3895
|
-
function Sidebar({ brand, headerActions, nav, children, footer, className }) {
|
|
4182
|
+
function Sidebar({ brand, brandIcon, headerActions, nav, children, footer, className }) {
|
|
3896
4183
|
const { collapsed } = useSidebar();
|
|
3897
4184
|
return /* @__PURE__ */ jsxs("div", {
|
|
3898
4185
|
className: clsx("flex h-full flex-col font-chat-sans", collapsed ? "w-13" : "w-full", className),
|
|
3899
4186
|
children: [
|
|
4187
|
+
collapsed && brandIcon && /* @__PURE__ */ jsx("div", {
|
|
4188
|
+
className: "flex h-12 shrink-0 items-center justify-center [&_svg]:size-5",
|
|
4189
|
+
children: brandIcon
|
|
4190
|
+
}),
|
|
3900
4191
|
/* @__PURE__ */ jsxs("div", {
|
|
3901
4192
|
className: clsx("flex h-12 shrink-0 items-center gap-1 px-2", collapsed && "justify-center"),
|
|
3902
4193
|
children: [
|
|
3903
|
-
!collapsed && /* @__PURE__ */
|
|
3904
|
-
className: "min-w-0 flex-1
|
|
3905
|
-
children:
|
|
4194
|
+
!collapsed && /* @__PURE__ */ jsxs("div", {
|
|
4195
|
+
className: "flex min-w-0 flex-1 items-center gap-2 px-1.5 font-chat-serif text-lg text-chat-fg",
|
|
4196
|
+
children: [brandIcon && /* @__PURE__ */ jsx("span", {
|
|
4197
|
+
className: "flex shrink-0 [&_svg]:size-5",
|
|
4198
|
+
children: brandIcon
|
|
4199
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
4200
|
+
className: "min-w-0 truncate",
|
|
4201
|
+
children: brand
|
|
4202
|
+
})]
|
|
3906
4203
|
}),
|
|
3907
4204
|
!collapsed && headerActions,
|
|
3908
4205
|
/* @__PURE__ */ jsx(SidebarToggle, {})
|
|
@@ -4002,4 +4299,4 @@ function SidebarUser({ name, detail, avatarUrl, menu }) {
|
|
|
4002
4299
|
children: menu
|
|
4003
4300
|
})] });
|
|
4004
4301
|
}
|
|
4005
|
-
export { ActivityGroup, AgentProvider, AgentRegistry, AppShell, ApprovalCard, AssistantMessage, AttachButton, AttachmentCard, AttachmentRow, Badge, Button, Caret, ChatHeader, ChatList, ChatNotice, ChatTheme, ChatTitleMenu, ChatTranscript, ChatView, CodeBlock, Composer, ContextMenu, ContextPanel, DRAWER_QUERY, Disclosure, Drawer, EmptyState, IconButton, Markdown, MarkdownLinksProvider, Menu, MenuItem, MenuNote, MenuSearch, MenuSection, MenuSeparator, MenuTrigger, MessageList, Modal, ModelPicker, Panel, PastedTextDialog, Popover, Sidebar, SidebarItem, SidebarToggle, SidebarUser, SubmenuTrigger, TokenCounter, ToolViewsProvider, Tooltip, UiComponentsProvider, UiMarkupBlock, UiTree, UserMessage, WIDGET_MAX_HEIGHT, WidgetFrame, WidgetHostProvider, WidgetPartView, activityHeading, activityLabel, commandTool, defaultIcons, defaultLabels, defaultToolViews, formatDuration, formatRelativeTime, formatTokens, htmlComponent, intersectAllow, memoryTool, messageText, openInNewTab, readTreeInput, readVisualizeInput, sseTransport, uiMarkupToolView, uiTreeToolView, useAgentContext, useAgentRegistry, useAgentSnapshot, useAgentTool, useAttachments, useChat, useChatTool, useCountUp, useIcons, useLabels, useMediaQuery, useSidebar, useSmoothText, useToolView, useToolViews, useUiAction, useUiMarkupLanguage, useUiState, useWidgetHost, userMessage, webFetchTool, webSearchTool, widgetCsp, widgetToolView };
|
|
4302
|
+
export { ActivityGroup, AgentProvider, AgentRegistry, AppShell, ApprovalCard, AssistantMessage, AttachButton, AttachmentCard, AttachmentRow, Badge, Button, Caret, ChatHeader, ChatList, ChatNotice, ChatTheme, ChatTitleMenu, ChatTranscript, ChatView, CodeBlock, Composer, ContextMenu, ContextPanel, CopyButton, DRAWER_QUERY, Disclosure, Drawer, EffortButton, EffortSlider, EmptyState, IconButton, Markdown, MarkdownLinksProvider, Menu, MenuItem, MenuNote, MenuSearch, MenuSection, MenuSeparator, MenuTrigger, MessageList, Modal, ModelPicker, Panel, PastedTextDialog, Popover, SegmentedControl, Sidebar, SidebarItem, SidebarToggle, SidebarUser, SubmenuTrigger, TokenCounter, ToolViewsProvider, Tooltip, UiComponentsProvider, UiMarkupBlock, UiTree, UserMessage, WIDGET_MAX_HEIGHT, WidgetFrame, WidgetHostProvider, WidgetPartView, activityHeading, activityLabel, commandTool, defaultIcons, defaultLabels, defaultToolViews, formatDuration, formatRelativeTime, formatTokens, htmlComponent, intersectAllow, memoryTool, messageText, openInNewTab, readTreeInput, readVisualizeInput, sseTransport, uiMarkupToolView, uiTreeToolView, useAgentContext, useAgentRegistry, useAgentSnapshot, useAgentTool, useAttachments, useChat, useChatTool, useCountUp, useIcons, useLabels, useMediaQuery, useSidebar, useSmoothText, useToolView, useToolViews, useUiAction, useUiMarkupLanguage, useUiState, useWidgetHost, userMessage, webFetchTool, webSearchTool, widgetCsp, widgetToolView };
|