@mcp-b/react-components 0.2.2 → 0.4.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/dist/{CodeBlock-BrCoypnc.js → CodeBlock-C2Xjxu9M.js} +1 -1
- package/dist/FileTree-D0c9Yj9U.js +310 -0
- package/dist/attachment-preview-ChtC3HiU.js +25 -0
- package/dist/components/Activity.js +1 -1
- package/dist/components/AgentChat.d.ts +56 -9
- package/dist/components/AgentChat.js +146 -47
- package/dist/components/AgentConnection.js +3 -3
- package/dist/components/Artifact.js +1 -1
- package/dist/components/BrowserLiveView.d.ts +47 -0
- package/dist/components/BrowserLiveView.js +135 -0
- package/dist/components/BrowserReplay.d.ts +40 -0
- package/dist/components/BrowserReplay.js +187 -0
- package/dist/components/ChainOfThought.d.ts +1 -1
- package/dist/components/ChainOfThought.js +1 -1
- package/dist/components/CodeBlock.js +1 -1
- package/dist/components/Commit.js +1 -1
- package/dist/components/Context.d.ts +28 -27
- package/dist/components/Context.js +48 -47
- package/dist/components/ContextMenu.js +1 -1
- package/dist/components/Conversation.js +1 -1
- package/dist/components/Dialog.js +1 -1
- package/dist/components/EnvironmentVariables.js +1 -1
- package/dist/components/FileTree.js +1 -309
- package/dist/components/Menubar.js +1 -1
- package/dist/components/Message.d.ts +17 -2
- package/dist/components/Message.js +36 -2
- package/dist/components/ModelSelector.js +1 -1
- package/dist/components/NavigationMenu.js +1 -1
- package/dist/components/PricingPage.js +2 -2
- package/dist/components/PromptInput.d.ts +143 -10
- package/dist/components/PromptInput.js +318 -5
- package/dist/components/Queue.js +1 -1
- package/dist/components/Reasoning.js +1 -1
- package/dist/components/Select.js +1 -1
- package/dist/components/Sources.js +1 -1
- package/dist/components/Stepper.js +1 -1
- package/dist/components/Suggestion.d.ts +43 -0
- package/dist/components/Suggestion.js +39 -0
- package/dist/components/Task.js +1 -1
- package/dist/components/Terminal.js +2 -2
- package/dist/components/TestResults.js +1 -1
- package/dist/components/ThinkChat.d.ts +207 -0
- package/dist/components/ThinkChat.js +798 -0
- package/dist/components/Tool.d.ts +32 -28
- package/dist/components/Tool.js +29 -16
- package/dist/components/WebPreview.js +1 -1
- package/dist/components/WorkspaceExplorer.d.ts +102 -0
- package/dist/components/WorkspaceExplorer.js +352 -0
- package/dist/components/icons.d.ts +2 -2
- package/dist/components/icons.js +2 -2
- package/dist/{copy-button-DAPlB8Z0.js → copy-button-Dd6DEhOm.js} +1 -1
- package/dist/{icons-Bf7JMKk-.js → icons-DQC4Zw5R.js} +5 -1
- package/dist/{icons-BklFyZbx.d.ts → icons-ctdVxng0.d.ts} +2 -1
- package/dist/styles/agent-chat.css +19 -0
- package/dist/styles/attachment-preview.css +21 -0
- package/dist/styles/context.css +9 -17
- package/dist/styles/index.css +2 -0
- package/dist/styles/message.css +48 -0
- package/dist/styles/prompt-input.css +321 -0
- package/dist/styles/suggestions.css +21 -0
- package/package.json +26 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as cx } from "./class-names-9UtZwb0J.js";
|
|
2
2
|
import { Select, SelectContent, SelectItem, SelectList, SelectTrigger, SelectValue } from "./components/Select.js";
|
|
3
|
-
import { t as CopyButton } from "./copy-button-
|
|
3
|
+
import { t as CopyButton } from "./copy-button-Dd6DEhOm.js";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { createHighlighter } from "shiki";
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { t as cx } from "./class-names-9UtZwb0J.js";
|
|
2
|
+
import { _ as FolderOpenIcon, g as FolderIcon, h as FileIcon, l as ChevronRightIcon } from "./icons-DQC4Zw5R.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/_internal/use-file-tree-nav.ts
|
|
6
|
+
const FileTreeContext = React.createContext(null);
|
|
7
|
+
function useFileTreeContext() {
|
|
8
|
+
const ctx = React.useContext(FileTreeContext);
|
|
9
|
+
if (!ctx) throw new Error("FileTree subcomponents must be used inside <FileTree>.");
|
|
10
|
+
return ctx;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Builds a FileTreeContextValue that tracks registered nodes and dispatches
|
|
14
|
+
* keyboard navigation per the WAI-ARIA Tree Pattern.
|
|
15
|
+
*
|
|
16
|
+
* Call `register` from every FileTreeFolder/FileTreeFile during render. The
|
|
17
|
+
* hook resets its internal list on each render pass so removed nodes don't
|
|
18
|
+
* leave stale entries.
|
|
19
|
+
*/
|
|
20
|
+
function useFileTreeNav({ expanded, selectedPath, onSelect, onExpandedChange }) {
|
|
21
|
+
const [focusedPath, setFocusedPath] = React.useState(null);
|
|
22
|
+
const nodesRef = React.useRef([]);
|
|
23
|
+
nodesRef.current = [];
|
|
24
|
+
const register = React.useCallback((path, kind, parentExpanded) => {
|
|
25
|
+
nodesRef.current.push({
|
|
26
|
+
path,
|
|
27
|
+
kind,
|
|
28
|
+
visible: parentExpanded
|
|
29
|
+
});
|
|
30
|
+
}, []);
|
|
31
|
+
const visibleNodes = () => nodesRef.current.filter((n) => n.visible);
|
|
32
|
+
const moveFocus = React.useCallback((direction, from) => {
|
|
33
|
+
const visible = visibleNodes();
|
|
34
|
+
const idx = visible.findIndex((n) => n.path === from);
|
|
35
|
+
if (idx < 0) return;
|
|
36
|
+
const next = visible[Math.max(0, Math.min(visible.length - 1, idx + direction))];
|
|
37
|
+
if (next) setFocusedPath(next.path);
|
|
38
|
+
}, []);
|
|
39
|
+
const focusFirstVisibleNode = React.useCallback(() => {
|
|
40
|
+
const first = visibleNodes()[0];
|
|
41
|
+
if (first) setFocusedPath(first.path);
|
|
42
|
+
}, []);
|
|
43
|
+
const focusLastVisibleNode = React.useCallback(() => {
|
|
44
|
+
const visible = visibleNodes();
|
|
45
|
+
const last = visible[visible.length - 1];
|
|
46
|
+
if (last) setFocusedPath(last.path);
|
|
47
|
+
}, []);
|
|
48
|
+
const setFolderExpanded = React.useCallback((path, nextExpanded) => {
|
|
49
|
+
const next = new Set(expanded);
|
|
50
|
+
if (nextExpanded) next.add(path);
|
|
51
|
+
else next.delete(path);
|
|
52
|
+
onExpandedChange(next);
|
|
53
|
+
}, [expanded, onExpandedChange]);
|
|
54
|
+
const toggleFolderExpanded = React.useCallback((path) => {
|
|
55
|
+
setFolderExpanded(path, !expanded.has(path));
|
|
56
|
+
}, [expanded, setFolderExpanded]);
|
|
57
|
+
const keyHandlers = React.useMemo(() => ({
|
|
58
|
+
ArrowDown(path) {
|
|
59
|
+
moveFocus(1, path);
|
|
60
|
+
},
|
|
61
|
+
ArrowUp(path) {
|
|
62
|
+
moveFocus(-1, path);
|
|
63
|
+
},
|
|
64
|
+
ArrowRight(path, kind) {
|
|
65
|
+
if (!(kind === "folder")) return;
|
|
66
|
+
if (expanded.has(path)) moveFocus(1, path);
|
|
67
|
+
else setFolderExpanded(path, true);
|
|
68
|
+
},
|
|
69
|
+
ArrowLeft(path, kind) {
|
|
70
|
+
if (kind === "folder" && expanded.has(path)) setFolderExpanded(path, false);
|
|
71
|
+
},
|
|
72
|
+
Enter(path, kind) {
|
|
73
|
+
if (kind === "folder") {
|
|
74
|
+
onSelect(path);
|
|
75
|
+
toggleFolderExpanded(path);
|
|
76
|
+
} else onSelect(path);
|
|
77
|
+
},
|
|
78
|
+
" "(path, kind) {
|
|
79
|
+
if (kind === "folder") {
|
|
80
|
+
onSelect(path);
|
|
81
|
+
toggleFolderExpanded(path);
|
|
82
|
+
} else onSelect(path);
|
|
83
|
+
},
|
|
84
|
+
Home() {
|
|
85
|
+
focusFirstVisibleNode();
|
|
86
|
+
},
|
|
87
|
+
End() {
|
|
88
|
+
focusLastVisibleNode();
|
|
89
|
+
}
|
|
90
|
+
}), [
|
|
91
|
+
expanded,
|
|
92
|
+
focusFirstVisibleNode,
|
|
93
|
+
focusLastVisibleNode,
|
|
94
|
+
moveFocus,
|
|
95
|
+
onSelect,
|
|
96
|
+
setFolderExpanded,
|
|
97
|
+
toggleFolderExpanded
|
|
98
|
+
]);
|
|
99
|
+
const handleKeyDown = React.useCallback((event, path, kind) => {
|
|
100
|
+
const keyHandler = keyHandlers[event.key];
|
|
101
|
+
if (!keyHandler) return;
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
keyHandler(path, kind);
|
|
104
|
+
}, [keyHandlers]);
|
|
105
|
+
return {
|
|
106
|
+
focusedPath,
|
|
107
|
+
selectedPath,
|
|
108
|
+
expanded,
|
|
109
|
+
onFocus: React.useCallback((path) => {
|
|
110
|
+
setFocusedPath(path);
|
|
111
|
+
}, []),
|
|
112
|
+
onSelect,
|
|
113
|
+
onExpandedChange: React.useCallback((path, next) => {
|
|
114
|
+
setFolderExpanded(path, next);
|
|
115
|
+
}, [setFolderExpanded]),
|
|
116
|
+
register,
|
|
117
|
+
handleKeyDown
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/components/FileTree.tsx
|
|
122
|
+
/**
|
|
123
|
+
* A keyboard-accessible hierarchical file browser. Compose with
|
|
124
|
+
* FileTreeFolder and FileTreeFile children.
|
|
125
|
+
*
|
|
126
|
+
* Keyboard: ↑/↓ move focus, →/← expand/collapse folders, Enter/Space
|
|
127
|
+
* selects files and selects/toggles folders, Home/End jump to first/last node.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```tsx
|
|
131
|
+
* <FileTree defaultExpanded={new Set(["src"])}>
|
|
132
|
+
* <FileTreeFolder path="src" name="src">
|
|
133
|
+
* <FileTreeFile path="src/index.ts" name="index.ts" />
|
|
134
|
+
* <FileTreeFolder path="src/lib" name="lib">
|
|
135
|
+
* <FileTreeFile path="src/lib/utils.ts" name="utils.ts" />
|
|
136
|
+
* </FileTreeFolder>
|
|
137
|
+
* </FileTreeFolder>
|
|
138
|
+
* </FileTree>
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
function FileTree({ className, "aria-label": ariaLabel = "File tree", expanded, defaultExpanded, selectedPath = null, onSelect, onExpandedChange, children, ref, ...props }) {
|
|
142
|
+
const [internalExpanded, setInternalExpanded] = React.useState(() => defaultExpanded ?? /* @__PURE__ */ new Set());
|
|
143
|
+
const isControlled = expanded !== void 0;
|
|
144
|
+
const currentExpanded = isControlled ? expanded : internalExpanded;
|
|
145
|
+
const handleExpandedChange = React.useCallback((next) => {
|
|
146
|
+
if (!isControlled) setInternalExpanded(next);
|
|
147
|
+
onExpandedChange?.(next);
|
|
148
|
+
}, [isControlled, onExpandedChange]);
|
|
149
|
+
const ctx = useFileTreeNav({
|
|
150
|
+
expanded: currentExpanded,
|
|
151
|
+
selectedPath,
|
|
152
|
+
onSelect: React.useCallback((path) => {
|
|
153
|
+
onSelect?.(path);
|
|
154
|
+
}, [onSelect]),
|
|
155
|
+
onExpandedChange: handleExpandedChange
|
|
156
|
+
});
|
|
157
|
+
return /* @__PURE__ */ jsx(FileTreeContext.Provider, {
|
|
158
|
+
value: ctx,
|
|
159
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
160
|
+
ref,
|
|
161
|
+
className: cx("file-tree", className),
|
|
162
|
+
...props,
|
|
163
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
164
|
+
className: "file-tree__list",
|
|
165
|
+
role: "tree",
|
|
166
|
+
"aria-label": ariaLabel,
|
|
167
|
+
tabIndex: 0,
|
|
168
|
+
children
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function renderNestedFileTreeChild(child, level) {
|
|
174
|
+
if (React.isValidElement(child) && (child.type === FileTreeFolder || child.type === FileTreeFile)) return React.cloneElement(child, { level: level + 1 });
|
|
175
|
+
return child;
|
|
176
|
+
}
|
|
177
|
+
function dataFlag(enabled) {
|
|
178
|
+
return enabled ? "" : void 0;
|
|
179
|
+
}
|
|
180
|
+
function getFileTreeNodeTabIndex(focusedPath, path, level) {
|
|
181
|
+
return focusedPath === path || !focusedPath && level === 0 ? 0 : -1;
|
|
182
|
+
}
|
|
183
|
+
function getFileTreeNodeIndent(level, offset) {
|
|
184
|
+
return `${level * 1.125 + offset}rem`;
|
|
185
|
+
}
|
|
186
|
+
function FileTreeFolder({ className, path, name, level = 0, children, ref, ...props }) {
|
|
187
|
+
const { expanded, focusedPath, selectedPath, onFocus, onSelect, register, handleKeyDown, onExpandedChange } = useFileTreeContext();
|
|
188
|
+
const isExpanded = expanded.has(path);
|
|
189
|
+
const isFocused = focusedPath === path;
|
|
190
|
+
const isSelected = selectedPath === path;
|
|
191
|
+
register(path, "folder", true);
|
|
192
|
+
const toggle = React.useCallback(() => {
|
|
193
|
+
onExpandedChange(path, !isExpanded);
|
|
194
|
+
}, [
|
|
195
|
+
isExpanded,
|
|
196
|
+
onExpandedChange,
|
|
197
|
+
path
|
|
198
|
+
]);
|
|
199
|
+
const handleClick = React.useCallback(() => {
|
|
200
|
+
onSelect(path);
|
|
201
|
+
toggle();
|
|
202
|
+
}, [
|
|
203
|
+
onSelect,
|
|
204
|
+
path,
|
|
205
|
+
toggle
|
|
206
|
+
]);
|
|
207
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
208
|
+
ref,
|
|
209
|
+
role: "treeitem",
|
|
210
|
+
"aria-expanded": isExpanded,
|
|
211
|
+
"aria-selected": isSelected,
|
|
212
|
+
className: cx("file-tree__folder", className),
|
|
213
|
+
...props,
|
|
214
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
215
|
+
type: "button",
|
|
216
|
+
className: "file-tree__node file-tree__node--folder",
|
|
217
|
+
"data-focused": dataFlag(isFocused),
|
|
218
|
+
"data-selected": dataFlag(isSelected),
|
|
219
|
+
tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
|
|
220
|
+
onClick: handleClick,
|
|
221
|
+
onFocus: () => onFocus(path),
|
|
222
|
+
onKeyDown: (e) => handleKeyDown(e, path, "folder"),
|
|
223
|
+
style: { paddingInlineStart: getFileTreeNodeIndent(level, .5) },
|
|
224
|
+
children: [
|
|
225
|
+
/* @__PURE__ */ jsx("span", {
|
|
226
|
+
className: cx("file-tree__chevron", isExpanded && "file-tree__chevron--expanded"),
|
|
227
|
+
"aria-hidden": "true",
|
|
228
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ jsx("span", {
|
|
231
|
+
className: "file-tree__icon",
|
|
232
|
+
"aria-hidden": "true",
|
|
233
|
+
children: isExpanded ? /* @__PURE__ */ jsx(FolderOpenIcon, {}) : /* @__PURE__ */ jsx(FolderIcon, {})
|
|
234
|
+
}),
|
|
235
|
+
/* @__PURE__ */ jsx("span", {
|
|
236
|
+
className: "file-tree__name",
|
|
237
|
+
children: name
|
|
238
|
+
})
|
|
239
|
+
]
|
|
240
|
+
}), isExpanded ? /* @__PURE__ */ jsx("ul", {
|
|
241
|
+
className: "file-tree__list",
|
|
242
|
+
role: "group",
|
|
243
|
+
children: React.Children.map(children, (child) => renderNestedFileTreeChild(child, level))
|
|
244
|
+
}) : null]
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function FileTreeFile({ className, path, name, icon, level = 0, ref, ...props }) {
|
|
248
|
+
const { selectedPath, focusedPath, onFocus, onSelect, register, handleKeyDown } = useFileTreeContext();
|
|
249
|
+
const isSelected = selectedPath === path;
|
|
250
|
+
const isFocused = focusedPath === path;
|
|
251
|
+
register(path, "file", true);
|
|
252
|
+
return /* @__PURE__ */ jsx("li", {
|
|
253
|
+
ref,
|
|
254
|
+
role: "treeitem",
|
|
255
|
+
"aria-selected": isSelected,
|
|
256
|
+
className: cx("file-tree__file", className),
|
|
257
|
+
...props,
|
|
258
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
259
|
+
type: "button",
|
|
260
|
+
className: "file-tree__node file-tree__node--file",
|
|
261
|
+
"data-selected": dataFlag(isSelected),
|
|
262
|
+
"data-focused": dataFlag(isFocused),
|
|
263
|
+
tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
|
|
264
|
+
onClick: () => onSelect(path),
|
|
265
|
+
onFocus: () => onFocus(path),
|
|
266
|
+
onKeyDown: (e) => handleKeyDown(e, path, "file"),
|
|
267
|
+
style: { paddingInlineStart: getFileTreeNodeIndent(level, 1.5) },
|
|
268
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
269
|
+
className: "file-tree__icon",
|
|
270
|
+
"aria-hidden": "true",
|
|
271
|
+
children: icon ?? /* @__PURE__ */ jsx(FileIcon, {})
|
|
272
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
273
|
+
className: "file-tree__name",
|
|
274
|
+
children: name
|
|
275
|
+
})]
|
|
276
|
+
})
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function FileTreeIcon({ className, children, ref, ...props }) {
|
|
280
|
+
return /* @__PURE__ */ jsx("span", {
|
|
281
|
+
ref,
|
|
282
|
+
className: cx("file-tree__icon", className),
|
|
283
|
+
"aria-hidden": "true",
|
|
284
|
+
...props,
|
|
285
|
+
children
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function FileTreeName({ className, children, ref, ...props }) {
|
|
289
|
+
return /* @__PURE__ */ jsx("span", {
|
|
290
|
+
ref,
|
|
291
|
+
className: cx("file-tree__name", className),
|
|
292
|
+
...props,
|
|
293
|
+
children
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function FileTreeActions({ className, children, onClick, ref, ...props }) {
|
|
297
|
+
const handleClick = React.useCallback((e) => {
|
|
298
|
+
e.stopPropagation();
|
|
299
|
+
onClick?.(e);
|
|
300
|
+
}, [onClick]);
|
|
301
|
+
return /* @__PURE__ */ jsx("div", {
|
|
302
|
+
ref,
|
|
303
|
+
className: cx("file-tree__actions", className),
|
|
304
|
+
onClick: handleClick,
|
|
305
|
+
...props,
|
|
306
|
+
children
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
310
|
+
export { FileTreeIcon as a, FileTreeFolder as i, FileTreeActions as n, FileTreeName as o, FileTreeFile as r, FileTree as t };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Dialog, DialogContent, DialogTrigger } from "./components/Dialog.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/_internal/attachment-preview.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Click-to-zoom for image attachments: `children` is the thumbnail and
|
|
7
|
+
* becomes the dialog trigger; the dialog shows the image full size. Shared by
|
|
8
|
+
* the composer chips and message-side attachments.
|
|
9
|
+
*/
|
|
10
|
+
function AttachmentPreview({ url, filename, children }) {
|
|
11
|
+
return /* @__PURE__ */ jsxs(Dialog, { children: [/* @__PURE__ */ jsx(DialogTrigger, { render: children }), /* @__PURE__ */ jsxs(DialogContent, {
|
|
12
|
+
className: "attachment-preview",
|
|
13
|
+
"aria-label": filename ?? "Attachment preview",
|
|
14
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
15
|
+
className: "attachment-preview__image",
|
|
16
|
+
src: url,
|
|
17
|
+
alt: filename ?? "Attachment"
|
|
18
|
+
}), filename ? /* @__PURE__ */ jsx("div", {
|
|
19
|
+
className: "attachment-preview__name",
|
|
20
|
+
children: filename
|
|
21
|
+
}) : null]
|
|
22
|
+
})] });
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { AttachmentPreview as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger } from "./Collapsible.js";
|
|
2
2
|
import { t as cx } from "../class-names-9UtZwb0J.js";
|
|
3
|
-
import { l as ChevronRightIcon } from "../icons-
|
|
3
|
+
import { l as ChevronRightIcon } from "../icons-DQC4Zw5R.js";
|
|
4
4
|
import "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/Activity.tsx
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { PromptInputMessage, PromptInputStatus } from "./PromptInput.js";
|
|
1
|
+
import { ExecutionApprovals, PromptInputMessage, PromptInputStatus } from "./PromptInput.js";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { ChatAddToolApproveResponseFunction, UIMessage } from "ai";
|
|
4
4
|
|
|
5
5
|
//#region src/components/AgentChat.d.ts
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
interface AgentChatRenderPartContext<MessageT extends AgentChatMessage = AgentChatMessage> {
|
|
6
|
+
type AgentChatPart<MessageT extends UIMessage = UIMessage> = MessageT["parts"][number];
|
|
7
|
+
interface AgentChatRenderPartContext<MessageT extends UIMessage = UIMessage> {
|
|
9
8
|
message: MessageT;
|
|
10
9
|
part: AgentChatPart<MessageT>;
|
|
11
10
|
partIndex: number;
|
|
12
11
|
defaultRender: () => React.ReactNode;
|
|
13
12
|
}
|
|
14
|
-
interface AgentChatRenderMessageContext<MessageT extends
|
|
13
|
+
interface AgentChatRenderMessageContext<MessageT extends UIMessage = UIMessage> {
|
|
15
14
|
message: MessageT;
|
|
16
15
|
messageIndex: number;
|
|
17
16
|
}
|
|
18
|
-
interface AgentChatProps<MessageT extends
|
|
17
|
+
interface AgentChatProps<MessageT extends UIMessage = UIMessage> {
|
|
19
18
|
className?: string;
|
|
20
19
|
/** AI SDK `UIMessage`s to render, oldest first. */
|
|
21
20
|
messages: readonly MessageT[];
|
|
@@ -31,6 +30,44 @@ interface AgentChatProps<MessageT extends AgentChatMessage = AgentChatMessage> {
|
|
|
31
30
|
emptyState?: React.ReactNode;
|
|
32
31
|
/** Extra controls rendered in the composer toolbar. */
|
|
33
32
|
composerTools?: React.ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* Prompt suggestions shown as a chip row above the composer; clicking one
|
|
35
|
+
* submits it as the message text. Strings double as React keys — keep them
|
|
36
|
+
* unique.
|
|
37
|
+
*/
|
|
38
|
+
suggestions?: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Transient status rendered between the transcript and the composer —
|
|
41
|
+
* e.g. a "Reconnecting…" pill. `ThinkChat.Messages` fills this from the
|
|
42
|
+
* hook's `isRecovering`/`connectionError` automatically.
|
|
43
|
+
*/
|
|
44
|
+
notice?: React.ReactNode;
|
|
45
|
+
/**
|
|
46
|
+
* When set, the last assistant message gets a Retry action that calls this
|
|
47
|
+
* with its message id — pass to the AI SDK's `regenerate({ messageId })`.
|
|
48
|
+
*/
|
|
49
|
+
onRegenerate?: (messageId: string) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Pass `addToolApprovalResponse` from `useAgentChat`/`useChat` directly.
|
|
52
|
+
* When set and a tool call awaits approval, the composer becomes the
|
|
53
|
+
* confirmation.
|
|
54
|
+
*/
|
|
55
|
+
onApprovalResponse?: ChatAddToolApproveResponseFunction;
|
|
56
|
+
/**
|
|
57
|
+
* When set, paused codemode executions surface in the same composer
|
|
58
|
+
* confirmation as tool approvals. See {@link ExecutionApprovals}.
|
|
59
|
+
*/
|
|
60
|
+
executionApprovals?: ExecutionApprovals;
|
|
61
|
+
/**
|
|
62
|
+
* When set, a Context ring in the composer footer shows how much of the
|
|
63
|
+
* model's window the conversation occupies. Used tokens come from the
|
|
64
|
+
* newest message carrying `metadata.usage` (the AI SDK `messageMetadata`
|
|
65
|
+
* convention; Think merges it into message metadata as turns finish).
|
|
66
|
+
*/
|
|
67
|
+
contextWindow?: {
|
|
68
|
+
maxTokens: number;
|
|
69
|
+
modelId?: string;
|
|
70
|
+
};
|
|
34
71
|
/** Override rendering per part; return `undefined` to fall back to the default part UI. */
|
|
35
72
|
renderPart?: (context: AgentChatRenderPartContext<MessageT>) => React.ReactNode | undefined;
|
|
36
73
|
/** Rendered after each message's parts — for actions, citations, and the like. */
|
|
@@ -40,8 +77,12 @@ interface AgentChatProps<MessageT extends AgentChatMessage = AgentChatMessage> {
|
|
|
40
77
|
* A complete agent chat surface: auto-scrolling conversation of AI SDK
|
|
41
78
|
* `UIMessage`s (text, reasoning, and tool parts rendered by default) plus a
|
|
42
79
|
* prompt composer. Customize per-part rendering with `renderPart`.
|
|
80
|
+
*
|
|
81
|
+
* This is the presentational layer under `ThinkChat` — props in, no
|
|
82
|
+
* transport. Use it directly with plain AI SDK `useChat` or a read-only
|
|
83
|
+
* transcript; if you have a Cloudflare Think agent, use `ThinkChat` instead.
|
|
43
84
|
*/
|
|
44
|
-
declare function AgentChat<MessageT extends
|
|
85
|
+
declare function AgentChat<MessageT extends UIMessage = UIMessage>({
|
|
45
86
|
className,
|
|
46
87
|
messages,
|
|
47
88
|
status,
|
|
@@ -51,6 +92,12 @@ declare function AgentChat<MessageT extends AgentChatMessage = AgentChatMessage>
|
|
|
51
92
|
disabled,
|
|
52
93
|
emptyState,
|
|
53
94
|
composerTools,
|
|
95
|
+
suggestions,
|
|
96
|
+
notice,
|
|
97
|
+
onRegenerate,
|
|
98
|
+
onApprovalResponse,
|
|
99
|
+
executionApprovals,
|
|
100
|
+
contextWindow,
|
|
54
101
|
renderPart,
|
|
55
102
|
renderMessageAfter,
|
|
56
103
|
ref
|
|
@@ -58,4 +105,4 @@ declare function AgentChat<MessageT extends AgentChatMessage = AgentChatMessage>
|
|
|
58
105
|
ref?: React.Ref<HTMLDivElement>;
|
|
59
106
|
}): React.JSX.Element;
|
|
60
107
|
//#endregion
|
|
61
|
-
export { AgentChat,
|
|
108
|
+
export { AgentChat, AgentChatPart, AgentChatProps, AgentChatRenderMessageContext, AgentChatRenderPartContext };
|