@tangle-network/sandbox-ui 0.113.6 → 0.114.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.
Files changed (106) hide show
  1. package/dist/WorkflowGraph-B-NsdYz_.js +1961 -0
  2. package/dist/assets.d.ts +214 -206
  3. package/dist/assets.js +1057 -908
  4. package/dist/auth-CWe17Hly.js +37 -0
  5. package/dist/auth.d.ts +2 -30
  6. package/dist/auth.js +2 -15
  7. package/dist/chat-BOvFAe6p.js +903 -0
  8. package/dist/chat.d.ts +2 -230
  9. package/dist/chat.js +2 -34
  10. package/dist/connectors.d.ts +52 -49
  11. package/dist/connectors.js +595 -643
  12. package/dist/dashboard-CZ3VgNPR.js +4969 -0
  13. package/dist/dashboard.d.ts +4 -1297
  14. package/dist/dashboard.js +4 -152
  15. package/dist/editor.d.ts +2 -1
  16. package/dist/editor.js +2 -31
  17. package/dist/files.d.ts +2 -6
  18. package/dist/files.js +2 -33
  19. package/dist/globals.css +63 -3
  20. package/dist/hooks.d.ts +146 -148
  21. package/dist/hooks.js +222 -55
  22. package/dist/index-CKRaj1pM.d.ts +776 -0
  23. package/dist/index-CXX5IpH2.d.ts +2 -0
  24. package/dist/index-DPePq7c8.d.ts +1340 -0
  25. package/dist/index-DiyLLZuJ.d.ts +230 -0
  26. package/dist/index-DvmZLMT1.d.ts +30 -0
  27. package/dist/index-I8ZLVtHd.d.ts +330 -0
  28. package/dist/index-PRM636Ex.d.ts +86 -0
  29. package/dist/index.d.ts +21 -33
  30. package/dist/index.js +21 -701
  31. package/dist/info-panel-C9cqDzOL.js +594 -0
  32. package/dist/integrations.d.ts +133 -139
  33. package/dist/integrations.js +491 -673
  34. package/dist/markdown.d.ts +2 -1
  35. package/dist/markdown.js +2 -13
  36. package/dist/model-I-NIxeM-.js +1250 -0
  37. package/dist/model-brand-B9A4H9pJ.d.ts +98 -0
  38. package/dist/model-brand-hMyDTUqB.js +624 -0
  39. package/dist/motion-DkyBRJb9.js +37 -0
  40. package/dist/openui.d.ts +2 -1
  41. package/dist/openui.js +2 -7
  42. package/dist/pages.d.ts +307 -300
  43. package/dist/pages.js +4404 -4181
  44. package/dist/primitives-Dh1vG6J3.js +113 -0
  45. package/dist/primitives.d.ts +2 -74
  46. package/dist/primitives.js +2 -204
  47. package/dist/provider-logo-DjqmConF.js +311 -0
  48. package/dist/run.d.ts +2 -1
  49. package/dist/run.js +2 -23
  50. package/dist/sdk-hooks.d.ts +3 -4
  51. package/dist/sdk-hooks.js +3 -31
  52. package/dist/sidecar-DgH_vQ6m.d.ts +9 -0
  53. package/dist/stores.d.ts +14 -15
  54. package/dist/stores.js +13 -81
  55. package/dist/styles.css +63 -3
  56. package/dist/template-card-L-4gmjx2.d.ts +90 -0
  57. package/dist/terminal-CN9ZgHRt.js +197 -0
  58. package/dist/terminal.d.ts +60 -60
  59. package/dist/terminal.js +2 -10
  60. package/dist/tokens.css +51 -0
  61. package/dist/types.d.ts +4 -11
  62. package/dist/types.js +0 -1
  63. package/dist/use-pty-session-C8cE0adT.js +669 -0
  64. package/dist/use-sidecar-auth-CCTJcrq7.d.ts +145 -0
  65. package/dist/use-sidecar-auth-DkdcufOz.js +742 -0
  66. package/dist/utils-DzWbktWG.js +2 -0
  67. package/dist/utils.d.ts +2 -1
  68. package/dist/utils.js +2 -37
  69. package/dist/workbench-BCaCKl-J.js +8347 -0
  70. package/dist/workbench.d.ts +2 -310
  71. package/dist/workbench.js +2 -44
  72. package/dist/workflows.d.ts +341 -339
  73. package/dist/workflows.js +74 -109
  74. package/dist/workspace-B6AtI6ld.js +2510 -0
  75. package/dist/workspace.d.ts +2 -761
  76. package/dist/workspace.js +2 -51
  77. package/package.json +46 -40
  78. package/dist/WorkflowGraph-2QOORYIR.js +0 -1722
  79. package/dist/chunk-2BUPSB7O.js +0 -0
  80. package/dist/chunk-3KBNPQQF.js +0 -2697
  81. package/dist/chunk-3LIXVEEE.js +0 -279
  82. package/dist/chunk-72UF2H5H.js +0 -707
  83. package/dist/chunk-AI25G5MX.js +0 -944
  84. package/dist/chunk-ANSC5AFC.js +0 -314
  85. package/dist/chunk-AZ3AWMTM.js +0 -8
  86. package/dist/chunk-BGVEHENC.js +0 -10
  87. package/dist/chunk-CZ7CSFO4.js +0 -39
  88. package/dist/chunk-DYXXYGS4.js +0 -4700
  89. package/dist/chunk-EI44GEQ5.js +0 -6
  90. package/dist/chunk-IACRDXER.js +0 -219
  91. package/dist/chunk-IOB2PW5Z.js +0 -55
  92. package/dist/chunk-M4K7ZGR2.js +0 -24
  93. package/dist/chunk-MYZAW4RX.js +0 -665
  94. package/dist/chunk-OMUIPJQZ.js +0 -555
  95. package/dist/chunk-RQZRXKMR.js +0 -398
  96. package/dist/chunk-SOKKTB7W.js +0 -230
  97. package/dist/chunk-TADGS4Q7.js +0 -1010
  98. package/dist/chunk-UCQNOUN3.js +0 -7964
  99. package/dist/chunk-ULPLRBMF.js +0 -34
  100. package/dist/chunk-WID73FPH.js +0 -89
  101. package/dist/chunk-X3YXP7FG.js +0 -38
  102. package/dist/logo-DiAjq759.d.ts +0 -15
  103. package/dist/model-brand-BNnaUKKZ.d.ts +0 -99
  104. package/dist/ports-list-CDIvTNnX.d.ts +0 -17
  105. package/dist/sdk-hooks-Djkjq4cp.d.ts +0 -145
  106. package/dist/template-card-Bn-Bw5xC.d.ts +0 -87
@@ -1,1010 +0,0 @@
1
- import {
2
- cn
3
- } from "./chunk-EI44GEQ5.js";
4
-
5
- // src/chat/index.ts
6
- import {
7
- AgentTimeline,
8
- ChatContainer,
9
- ChatMessage as ChatMessage2,
10
- MessageList,
11
- ThinkingIndicator,
12
- UserMessage
13
- } from "@tangle-network/ui/chat";
14
-
15
- // src/chat/reasoning-level-picker.tsx
16
- import {
17
- reasoningLadder
18
- } from "@tangle-network/agent-interface";
19
- import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
20
- import { Brain, ChevronDown, Sparkles } from "lucide-react";
21
- import { focusRing } from "@tangle-network/ui/utils";
22
- import { jsx, jsxs } from "react/jsx-runtime";
23
- var REASONING_LADDER = reasoningLadder;
24
- function ReasoningGlyph({ level }) {
25
- if (level === "auto") {
26
- return /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 text-muted-foreground" });
27
- }
28
- const BARS = 4;
29
- const rank = REASONING_LADDER.indexOf(level) + 1;
30
- const filled = Math.max(1, Math.ceil(rank / REASONING_LADDER.length * BARS));
31
- return /* @__PURE__ */ jsx(
32
- "span",
33
- {
34
- "aria-hidden": true,
35
- className: "inline-flex h-3.5 items-end gap-px",
36
- style: { width: 16 },
37
- children: Array.from({ length: BARS }).map((_, i) => /* @__PURE__ */ jsx(
38
- "span",
39
- {
40
- className: cn(
41
- "w-1 rounded-[1px]",
42
- i < filled ? "bg-foreground" : "bg-border"
43
- ),
44
- style: { height: `${35 + i * 22}%` }
45
- },
46
- i
47
- ))
48
- }
49
- );
50
- }
51
- var DEFAULT_REASONING_LEVEL_OPTIONS = [
52
- { value: "auto", label: "Auto", description: "Let the agent pick the right depth." },
53
- { value: "none", label: "None", description: "No extended thinking \u2014 fastest, cheapest." },
54
- { value: "minimal", label: "Minimal", description: "Thinking on, lowest budget." },
55
- { value: "low", label: "Low", description: "Fast, direct answers." },
56
- { value: "medium", label: "Medium", description: "Inspect context before acting." },
57
- { value: "high", label: "High", description: "Deeper planning and edge-case checks." },
58
- { value: "xhigh", label: "Extra High", description: "Extended reasoning for the hardest problems." },
59
- { value: "ultracode", label: "Ultracode", description: "Maximum extended thinking." }
60
- ];
61
- var HARNESS_REASONING_OPTIONS = {
62
- "kimi-code": [
63
- { value: "auto", label: "Auto", description: "Use Kimi's default." },
64
- { value: "none", label: "No thinking", description: "Kimi answers directly \u2014 thinking off." },
65
- { value: "high", label: "Thinking", description: "Kimi reasons before answering." }
66
- ]
67
- };
68
- function ReasoningLevelPicker({
69
- value,
70
- onChange,
71
- disabled,
72
- className,
73
- triggerClassName,
74
- options = DEFAULT_REASONING_LEVEL_OPTIONS,
75
- available,
76
- side,
77
- avoidCollisions
78
- }) {
79
- const shown = available ? options.filter((o) => o.value === "auto" || available.includes(o.value)) : options;
80
- const selected = shown.find((option) => option.value === value);
81
- const label = selected?.label ?? "Auto";
82
- return /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
83
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
84
- "button",
85
- {
86
- type: "button",
87
- disabled,
88
- className: cn(
89
- "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5",
90
- "text-xs font-medium text-foreground shadow-sm transition-colors",
91
- "hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
92
- focusRing,
93
- "data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
94
- "disabled:cursor-not-allowed disabled:opacity-50",
95
- className,
96
- triggerClassName
97
- ),
98
- "aria-label": "Reasoning level",
99
- children: [
100
- /* @__PURE__ */ jsx(Brain, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
101
- /* @__PURE__ */ jsx("span", { children: label }),
102
- /* @__PURE__ */ jsx(ChevronDown, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground" })
103
- ]
104
- }
105
- ) }),
106
- /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
107
- DropdownMenu.Content,
108
- {
109
- side,
110
- align: "start",
111
- avoidCollisions,
112
- collisionPadding: 24,
113
- sideOffset: 6,
114
- className: cn(
115
- // Cap to the viewport space on the open side and scroll, so the menu
116
- // pinned downward (floating composer) never runs off the bottom edge.
117
- "z-50 w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-1",
118
- "shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
119
- "data-[state=open]:animate-in data-[state=closed]:animate-out",
120
- "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
121
- "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
122
- ),
123
- children: shown.map((option) => /* @__PURE__ */ jsxs(
124
- DropdownMenu.Item,
125
- {
126
- onSelect: () => onChange(option.value),
127
- className: cn(
128
- "flex cursor-pointer items-start gap-2.5 rounded-md px-2.5 py-2 outline-none",
129
- "transition-colors hover:bg-accent/40 focus:bg-accent/40",
130
- option.value === value && "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]"
131
- ),
132
- children: [
133
- /* @__PURE__ */ jsx("span", { className: "mt-0.5 flex w-3.5 shrink-0 justify-center", children: /* @__PURE__ */ jsx(ReasoningGlyph, { level: option.value }) }),
134
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
135
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: option.label }),
136
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: option.description })
137
- ] })
138
- ]
139
- },
140
- option.value
141
- ))
142
- }
143
- ) })
144
- ] });
145
- }
146
-
147
- // src/chat/agent-profile-picker.tsx
148
- import { Bot, Check, ChevronDown as ChevronDown2, Pencil, Plus as Plus2, Trash2 } from "lucide-react";
149
- import * as React4 from "react";
150
-
151
- // src/lib/use-click-outside.ts
152
- import * as React from "react";
153
- function useClickOutside(onOutside, extras) {
154
- const ref = React.useRef(null);
155
- const extrasRef = React.useRef(extras);
156
- extrasRef.current = extras;
157
- React.useEffect(() => {
158
- function handler(event) {
159
- const target = event.target;
160
- if (!ref.current || ref.current.contains(target)) return;
161
- if (extrasRef.current?.some((extra) => extra.current?.contains(target))) return;
162
- onOutside();
163
- }
164
- document.addEventListener("mousedown", handler);
165
- return () => document.removeEventListener("mousedown", handler);
166
- }, [onOutside]);
167
- return ref;
168
- }
169
-
170
- // src/chat/anchored-popover.tsx
171
- import * as React2 from "react";
172
- import { createPortal } from "react-dom";
173
- import { jsx as jsx2 } from "react/jsx-runtime";
174
- var AnchoredPopover = React2.forwardRef(
175
- function AnchoredPopover2({ anchorRef, side, children, className, style, ...rest }, forwardedRef) {
176
- const innerRef = React2.useRef(null);
177
- const setRefs = (node) => {
178
- innerRef.current = node;
179
- if (typeof forwardedRef === "function") forwardedRef(node);
180
- else if (forwardedRef) forwardedRef.current = node;
181
- };
182
- const [position, setPosition] = React2.useState(null);
183
- const place = React2.useCallback(() => {
184
- const anchor = anchorRef.current;
185
- if (!anchor) return;
186
- const rect = anchor.getBoundingClientRect();
187
- const width = innerRef.current?.offsetWidth ?? 0;
188
- const margin = 8;
189
- const left = Math.max(
190
- margin,
191
- Math.min(rect.left, window.innerWidth - width - margin)
192
- );
193
- setPosition(
194
- side === "top" ? { left, bottom: window.innerHeight - rect.top + margin } : { left, top: rect.bottom + margin }
195
- );
196
- }, [anchorRef, side]);
197
- React2.useLayoutEffect(() => {
198
- place();
199
- window.addEventListener("resize", place);
200
- window.addEventListener("scroll", place, true);
201
- return () => {
202
- window.removeEventListener("resize", place);
203
- window.removeEventListener("scroll", place, true);
204
- };
205
- }, [place]);
206
- return createPortal(
207
- /* @__PURE__ */ jsx2(
208
- "div",
209
- {
210
- ...rest,
211
- ref: setRefs,
212
- className: cn("fixed z-50", className),
213
- style: {
214
- ...style,
215
- pointerEvents: "auto",
216
- ...position ?? { visibility: "hidden", left: 0, top: 0 }
217
- },
218
- children
219
- }
220
- ),
221
- document.body
222
- );
223
- }
224
- );
225
-
226
- // src/chat/informative-lock.tsx
227
- import { Lock, Plus } from "lucide-react";
228
- import * as React3 from "react";
229
- import { focusRing as focusRing2 } from "@tangle-network/ui/utils";
230
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
231
- function InformativeLock({
232
- children,
233
- ariaLabel,
234
- lockTitle,
235
- lockBody,
236
- newChatLabel,
237
- onNewChat,
238
- className,
239
- triggerClassName,
240
- popoverClassName,
241
- side = "top"
242
- }) {
243
- const [open, setOpen] = React3.useState(false);
244
- const closeTimer = React3.useRef(null);
245
- const popoverRef = React3.useRef(null);
246
- const ref = useClickOutside(() => setOpen(false), [popoverRef]);
247
- const cancelClose = React3.useCallback(() => {
248
- if (closeTimer.current) {
249
- clearTimeout(closeTimer.current);
250
- closeTimer.current = null;
251
- }
252
- }, []);
253
- const scheduleClose = React3.useCallback(() => {
254
- cancelClose();
255
- closeTimer.current = setTimeout(() => setOpen(false), 150);
256
- }, [cancelClose]);
257
- React3.useEffect(() => cancelClose, [cancelClose]);
258
- return /* @__PURE__ */ jsxs2(
259
- "div",
260
- {
261
- ref,
262
- className: cn("relative inline-flex", className),
263
- onMouseEnter: () => {
264
- cancelClose();
265
- setOpen(true);
266
- },
267
- onMouseLeave: scheduleClose,
268
- onKeyDown: (event) => {
269
- if (event.key === "Escape") setOpen(false);
270
- },
271
- children: [
272
- /* @__PURE__ */ jsx3(
273
- "button",
274
- {
275
- type: "button",
276
- onClick: () => setOpen(true),
277
- "data-state": open ? "open" : "closed",
278
- "aria-label": ariaLabel,
279
- "aria-haspopup": "dialog",
280
- "aria-expanded": open,
281
- className: cn(
282
- "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5 opacity-60",
283
- "text-xs font-medium text-foreground shadow-sm transition-colors",
284
- "hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
285
- focusRing2,
286
- "data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
287
- triggerClassName
288
- ),
289
- children
290
- }
291
- ),
292
- open && /* @__PURE__ */ jsxs2(
293
- AnchoredPopover,
294
- {
295
- ref: popoverRef,
296
- anchorRef: ref,
297
- side,
298
- role: "dialog",
299
- onMouseEnter: () => {
300
- cancelClose();
301
- setOpen(true);
302
- },
303
- onMouseLeave: scheduleClose,
304
- className: cn(
305
- "w-72 rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-3",
306
- "shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
307
- popoverClassName
308
- ),
309
- children: [
310
- /* @__PURE__ */ jsxs2("p", { className: "flex items-start gap-2 text-sm font-medium text-foreground", children: [
311
- /* @__PURE__ */ jsx3(Lock, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
312
- /* @__PURE__ */ jsx3("span", { children: lockTitle })
313
- ] }),
314
- /* @__PURE__ */ jsx3("p", { className: "mt-1.5 text-xs text-muted-foreground", children: lockBody }),
315
- /* @__PURE__ */ jsxs2(
316
- "button",
317
- {
318
- type: "button",
319
- onClick: () => {
320
- setOpen(false);
321
- onNewChat();
322
- },
323
- className: cn(
324
- "mt-3 flex w-full items-center justify-center gap-1.5 rounded-md px-2.5 py-2 text-sm font-medium text-foreground",
325
- "bg-primary/10 ring-1 ring-inset ring-primary/25 transition-colors",
326
- "hover:bg-primary/15",
327
- focusRing2
328
- ),
329
- children: [
330
- /* @__PURE__ */ jsx3(Plus, { className: "h-4 w-4" }),
331
- newChatLabel
332
- ]
333
- }
334
- )
335
- ]
336
- }
337
- )
338
- ]
339
- }
340
- );
341
- }
342
-
343
- // src/chat/agent-profile-picker.tsx
344
- import { focusField, focusRing as focusRing3 } from "@tangle-network/ui/utils";
345
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
346
- function profileSubtitle(profile) {
347
- if (profile.description) return profile.description;
348
- const count = profile.capabilities?.length ?? 0;
349
- return `${count} ${count === 1 ? "tool group" : "tool groups"}`;
350
- }
351
- function AgentProfilePicker({
352
- value,
353
- onChange,
354
- profiles,
355
- capabilities,
356
- onCreate,
357
- onUpdate,
358
- onDelete,
359
- disabled,
360
- locked,
361
- lockReason,
362
- onNewChat,
363
- className,
364
- triggerClassName,
365
- popoverClassName,
366
- side = "top"
367
- }) {
368
- const [open, setOpen] = React4.useState(false);
369
- const [composing, setComposing] = React4.useState(
370
- null
371
- );
372
- const popoverRef = React4.useRef(null);
373
- const ref = useClickOutside(() => {
374
- setOpen(false);
375
- setComposing(null);
376
- }, [popoverRef]);
377
- const canAuthor = Boolean(capabilities && (onCreate || onUpdate));
378
- const builtins = profiles.filter((profile) => profile.builtin);
379
- const custom = profiles.filter((profile) => !profile.builtin);
380
- const selected = profiles.find((profile) => profile.id === value);
381
- const selectedName = selected?.name ?? value;
382
- React4.useEffect(() => {
383
- if (!locked) return;
384
- setOpen(false);
385
- setComposing(null);
386
- }, [locked]);
387
- function select(id) {
388
- onChange(id);
389
- setOpen(false);
390
- }
391
- async function save(draft) {
392
- if (draft.id) await onUpdate?.(draft.id, draft);
393
- else await onCreate?.(draft);
394
- setComposing(null);
395
- }
396
- if (locked && onNewChat) {
397
- return /* @__PURE__ */ jsxs3(
398
- InformativeLock,
399
- {
400
- ariaLabel: "Agent profile (locked)",
401
- lockTitle: `Profile fixed to ${selectedName} for this conversation.`,
402
- lockBody: "Conversations stay on one profile.",
403
- newChatLabel: "New chat to switch profile",
404
- onNewChat,
405
- className,
406
- triggerClassName,
407
- popoverClassName,
408
- side,
409
- children: [
410
- /* @__PURE__ */ jsx4(Bot, { className: "h-3.5 w-3.5 text-muted-foreground" }),
411
- /* @__PURE__ */ jsx4("span", { className: "max-w-[140px] truncate", children: selectedName })
412
- ]
413
- }
414
- );
415
- }
416
- return /* @__PURE__ */ jsxs3("div", { ref, className: cn("relative inline-flex", className), children: [
417
- /* @__PURE__ */ jsxs3(
418
- "button",
419
- {
420
- type: "button",
421
- disabled: disabled || locked,
422
- title: locked ? lockReason : void 0,
423
- onClick: () => setOpen((v) => !v),
424
- className: cn(
425
- "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5",
426
- "text-xs font-medium text-foreground shadow-sm transition-colors",
427
- "hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
428
- focusRing3,
429
- "data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high",
430
- "disabled:cursor-not-allowed disabled:opacity-60",
431
- triggerClassName
432
- ),
433
- "data-state": open ? "open" : "closed",
434
- "aria-label": "Agent profile",
435
- children: [
436
- /* @__PURE__ */ jsx4(Bot, { className: "h-3.5 w-3.5 text-muted-foreground" }),
437
- /* @__PURE__ */ jsx4("span", { className: "max-w-[140px] truncate", children: selectedName }),
438
- !locked && /* @__PURE__ */ jsx4(ChevronDown2, { className: "ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground" })
439
- ]
440
- }
441
- ),
442
- open && !locked && /* @__PURE__ */ jsx4(
443
- AnchoredPopover,
444
- {
445
- ref: popoverRef,
446
- anchorRef: ref,
447
- side,
448
- className: cn(
449
- "w-[min(320px,calc(100vw-2rem))] overflow-hidden rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-1",
450
- "shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
451
- popoverClassName
452
- ),
453
- "data-testid": "agent-profile-popover",
454
- children: composing ? /* @__PURE__ */ jsx4(
455
- ProfileForm,
456
- {
457
- capabilities: capabilities ?? [],
458
- initial: composing === "new" ? void 0 : composing,
459
- onCancel: () => setComposing(null),
460
- onSave: save
461
- }
462
- ) : /* @__PURE__ */ jsxs3("div", { className: "max-h-[min(60vh,420px)] overflow-y-auto", children: [
463
- /* @__PURE__ */ jsx4(SectionHeader, { children: "Modes" }),
464
- builtins.map((profile) => /* @__PURE__ */ jsx4(
465
- ProfileRow,
466
- {
467
- active: profile.id === value,
468
- title: profile.name,
469
- subtitle: profileSubtitle(profile),
470
- onSelect: () => select(profile.id)
471
- },
472
- profile.id
473
- )),
474
- custom.length > 0 && /* @__PURE__ */ jsx4(SectionHeader, { children: "Your agents" }),
475
- custom.map((profile) => /* @__PURE__ */ jsx4(
476
- ProfileRow,
477
- {
478
- active: profile.id === value,
479
- title: profile.name,
480
- subtitle: profileSubtitle(profile),
481
- onSelect: () => select(profile.id),
482
- onEdit: canAuthor ? () => setComposing(profile) : void 0,
483
- onDelete: onDelete ? () => void onDelete(profile.id) : void 0
484
- },
485
- profile.id
486
- )),
487
- canAuthor && /* @__PURE__ */ jsxs3(
488
- "button",
489
- {
490
- type: "button",
491
- onClick: () => setComposing("new"),
492
- className: "mt-1 flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-left text-sm text-[var(--accent-text)] transition-colors hover:bg-accent/40",
493
- children: [
494
- /* @__PURE__ */ jsx4(Plus2, { className: "h-4 w-4" }),
495
- " New agent\u2026"
496
- ]
497
- }
498
- )
499
- ] })
500
- }
501
- )
502
- ] });
503
- }
504
- function SectionHeader({ children }) {
505
- return /* @__PURE__ */ jsx4("div", { className: "px-2.5 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70", children });
506
- }
507
- function ProfileRow({
508
- active,
509
- title,
510
- subtitle,
511
- onSelect,
512
- onEdit,
513
- onDelete
514
- }) {
515
- return /* @__PURE__ */ jsxs3(
516
- "div",
517
- {
518
- className: cn(
519
- "group flex items-center gap-2 rounded-md px-2.5 py-2 text-sm transition-colors",
520
- active ? "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]" : "hover:bg-accent/40"
521
- ),
522
- children: [
523
- /* @__PURE__ */ jsxs3(
524
- "button",
525
- {
526
- type: "button",
527
- onClick: onSelect,
528
- className: "flex min-w-0 flex-1 items-center gap-2 text-left",
529
- children: [
530
- /* @__PURE__ */ jsx4("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: active && /* @__PURE__ */ jsx4(Check, { className: "h-3.5 w-3.5" }) }),
531
- /* @__PURE__ */ jsxs3("span", { className: "min-w-0", children: [
532
- /* @__PURE__ */ jsx4("span", { className: "block truncate font-medium", children: title }),
533
- /* @__PURE__ */ jsx4("span", { className: "block truncate text-xs text-muted-foreground", children: subtitle })
534
- ] })
535
- ]
536
- }
537
- ),
538
- (onEdit || onDelete) && /* @__PURE__ */ jsxs3("span", { className: "flex shrink-0 items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100", children: [
539
- onEdit && /* @__PURE__ */ jsx4(
540
- "button",
541
- {
542
- type: "button",
543
- onClick: onEdit,
544
- title: "Edit",
545
- className: "rounded p-1 text-muted-foreground hover:text-foreground",
546
- children: /* @__PURE__ */ jsx4(Pencil, { className: "h-3 w-3" })
547
- }
548
- ),
549
- onDelete && /* @__PURE__ */ jsx4(
550
- "button",
551
- {
552
- type: "button",
553
- onClick: onDelete,
554
- title: "Delete",
555
- className: "rounded p-1 text-muted-foreground hover:text-[var(--status-error,#ff4d6d)]",
556
- children: /* @__PURE__ */ jsx4(Trash2, { className: "h-3 w-3" })
557
- }
558
- )
559
- ] })
560
- ]
561
- }
562
- );
563
- }
564
- function ProfileForm({
565
- capabilities,
566
- initial,
567
- onCancel,
568
- onSave
569
- }) {
570
- const [name, setName] = React4.useState(initial?.name ?? "");
571
- const [caps, setCaps] = React4.useState(
572
- initial?.capabilities ? [...initial.capabilities] : capabilities.map((c) => c.id)
573
- );
574
- const [instructions, setInstructions] = React4.useState(initial?.instructions ?? "");
575
- const toggle = (id) => setCaps(
576
- (prev) => prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id]
577
- );
578
- return /* @__PURE__ */ jsxs3("div", { className: "space-y-3 p-2.5", children: [
579
- /* @__PURE__ */ jsx4(
580
- "input",
581
- {
582
- autoFocus: true,
583
- value: name,
584
- onChange: (event) => setName(event.target.value),
585
- placeholder: "Agent name (e.g. Tax Reviewer)",
586
- className: `w-full rounded-lg border bg-surface-container px-3 py-2 text-sm ${focusField}`
587
- }
588
- ),
589
- capabilities.length > 0 && /* @__PURE__ */ jsxs3("div", { children: [
590
- /* @__PURE__ */ jsx4("p", { className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/70", children: "Tools" }),
591
- /* @__PURE__ */ jsx4("div", { className: "space-y-0.5", children: capabilities.map((cap) => /* @__PURE__ */ jsxs3(
592
- "label",
593
- {
594
- className: "flex cursor-pointer items-start gap-2 rounded-md px-2 py-1.5 hover:bg-accent/40",
595
- children: [
596
- /* @__PURE__ */ jsx4(
597
- "input",
598
- {
599
- type: "checkbox",
600
- checked: caps.includes(cap.id),
601
- onChange: () => toggle(cap.id),
602
- className: "mt-0.5"
603
- }
604
- ),
605
- /* @__PURE__ */ jsxs3("span", { className: "min-w-0", children: [
606
- /* @__PURE__ */ jsx4("span", { className: "block text-sm font-medium", children: cap.label }),
607
- cap.description && /* @__PURE__ */ jsx4("span", { className: "block text-xs text-muted-foreground", children: cap.description })
608
- ] })
609
- ]
610
- },
611
- cap.id
612
- )) })
613
- ] }),
614
- /* @__PURE__ */ jsx4(
615
- "textarea",
616
- {
617
- value: instructions,
618
- onChange: (event) => setInstructions(event.target.value),
619
- rows: 2,
620
- placeholder: "Instructions (optional) \u2014 how this agent should behave",
621
- className: `w-full resize-none rounded-lg border bg-surface-container px-3 py-2 text-sm ${focusField}`
622
- }
623
- ),
624
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
625
- /* @__PURE__ */ jsx4(
626
- "button",
627
- {
628
- type: "button",
629
- onClick: onCancel,
630
- className: "rounded-lg px-3 py-1.5 text-sm text-muted-foreground hover:bg-accent/40",
631
- children: "Cancel"
632
- }
633
- ),
634
- /* @__PURE__ */ jsx4(
635
- "button",
636
- {
637
- type: "button",
638
- disabled: !name.trim(),
639
- onClick: () => onSave({
640
- id: initial?.id,
641
- name: name.trim(),
642
- capabilities: caps,
643
- instructions: instructions.trim()
644
- }),
645
- className: "rounded-lg bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40",
646
- children: "Save agent"
647
- }
648
- )
649
- ] })
650
- ] });
651
- }
652
-
653
- // src/chat/harness-model-compat.ts
654
- import { modelProvider, snapHarnessToModel } from "@tangle-network/agent-interface";
655
-
656
- // src/chat/artifact-agent-dock.tsx
657
- import * as React5 from "react";
658
- import { Sparkles as Sparkles2, Send, Square, X } from "lucide-react";
659
- import { ChatMessage } from "@tangle-network/ui/chat";
660
- import { focusField as focusField2 } from "@tangle-network/ui/utils";
661
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
662
- function defaultScopeLabel(scope) {
663
- if (scope.label) return scope.label;
664
- switch (scope.kind) {
665
- case "vault-file":
666
- return scope.key.split("/").pop() ?? scope.key;
667
- case "sequence":
668
- return `Sequence ${scope.key.slice(0, 8)}`;
669
- case "content":
670
- return `Content ${scope.key.slice(0, 8)}`;
671
- case "image":
672
- return `Image ${scope.key.slice(0, 8)}`;
673
- case "video":
674
- return `Video ${scope.key.slice(0, 8)}`;
675
- case "project":
676
- return "Project chat";
677
- case "workspace":
678
- return "Workspace chat";
679
- default:
680
- return scope.key;
681
- }
682
- }
683
- function normalizeRole(role) {
684
- return role === "assistant" || role === "system" ? role : "user";
685
- }
686
- function createDockMessageId() {
687
- const c = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
688
- if (c && typeof c.randomUUID === "function") return c.randomUUID();
689
- if (c && typeof c.getRandomValues === "function") {
690
- const b = c.getRandomValues(new Uint8Array(16));
691
- b[6] = b[6] & 15 | 64;
692
- b[8] = b[8] & 63 | 128;
693
- const h = Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
694
- return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
695
- }
696
- throw new Error("crypto.getRandomValues is required for message ids");
697
- }
698
- function ArtifactAgentDock({
699
- scope,
700
- open,
701
- onOpenChange,
702
- transport,
703
- defaultPrompt,
704
- onError,
705
- className
706
- }) {
707
- const [threadId, setThreadId] = React5.useState(null);
708
- const [messages, setMessages] = React5.useState([]);
709
- const [composer, setComposer] = React5.useState(defaultPrompt ?? "");
710
- const [streamContent, setStreamContent] = React5.useState("");
711
- const [sending, setSending] = React5.useState(false);
712
- const [loading, setLoading] = React5.useState(false);
713
- const abortRef = React5.useRef(null);
714
- const scrollRef = React5.useRef(null);
715
- const scopeTokenRef = React5.useRef(0);
716
- const reportError = React5.useCallback(
717
- (message) => {
718
- if (onError) onError(message);
719
- else if (typeof console !== "undefined") console.error("[ArtifactAgentDock]", message);
720
- },
721
- [onError]
722
- );
723
- React5.useEffect(() => {
724
- if (!open) return;
725
- scopeTokenRef.current += 1;
726
- abortRef.current?.abort();
727
- abortRef.current = null;
728
- let cancelled = false;
729
- async function bootstrap() {
730
- setLoading(true);
731
- try {
732
- const { id } = await transport.ensureThread(scope);
733
- if (cancelled) return;
734
- setThreadId(id);
735
- if (transport.loadMessages) {
736
- const prior = await transport.loadMessages(id);
737
- if (cancelled) return;
738
- setMessages(
739
- prior.map((m) => ({
740
- ...m,
741
- role: normalizeRole(m.role),
742
- createdAt: m.createdAt instanceof Date ? m.createdAt : m.createdAt ? new Date(m.createdAt) : void 0
743
- }))
744
- );
745
- } else {
746
- setMessages([]);
747
- }
748
- } catch (err) {
749
- reportError(err instanceof Error ? err.message : "Failed to open artifact chat");
750
- } finally {
751
- if (!cancelled) setLoading(false);
752
- }
753
- }
754
- void bootstrap();
755
- return () => {
756
- cancelled = true;
757
- };
758
- }, [open, scope.kind, scope.key, transport, reportError]);
759
- React5.useEffect(() => {
760
- if (!scrollRef.current) return;
761
- scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
762
- }, [messages.length, streamContent]);
763
- const send = React5.useCallback(async () => {
764
- const text = composer.trim();
765
- if (!text || !threadId || sending) return;
766
- const token = scopeTokenRef.current;
767
- const userMsg = {
768
- id: createDockMessageId(),
769
- role: "user",
770
- content: text,
771
- createdAt: /* @__PURE__ */ new Date()
772
- };
773
- setMessages((prev) => [...prev, userMsg]);
774
- setComposer("");
775
- setSending(true);
776
- setStreamContent("");
777
- const controller = new AbortController();
778
- abortRef.current = controller;
779
- let assistantContent = "";
780
- let streamFailed = false;
781
- try {
782
- for await (const event of transport.sendStream({ threadId, content: text, signal: controller.signal })) {
783
- if (scopeTokenRef.current !== token) return;
784
- if (event.type === "delta") {
785
- assistantContent += event.text;
786
- setStreamContent(assistantContent);
787
- } else if (event.type === "error") {
788
- streamFailed = true;
789
- reportError(event.message);
790
- }
791
- }
792
- if (scopeTokenRef.current !== token) return;
793
- if (assistantContent && !streamFailed) {
794
- setMessages((prev) => [
795
- ...prev,
796
- {
797
- id: createDockMessageId(),
798
- role: "assistant",
799
- content: assistantContent,
800
- createdAt: /* @__PURE__ */ new Date()
801
- }
802
- ]);
803
- }
804
- setStreamContent("");
805
- } catch (err) {
806
- if (err?.name === "AbortError") return;
807
- if (scopeTokenRef.current === token) reportError(err instanceof Error ? err.message : "Send failed");
808
- } finally {
809
- if (scopeTokenRef.current === token) setSending(false);
810
- if (abortRef.current === controller) abortRef.current = null;
811
- }
812
- }, [composer, threadId, sending, transport, reportError]);
813
- const cancel = React5.useCallback(() => {
814
- if (threadId && transport.cancel) {
815
- try {
816
- void Promise.resolve(transport.cancel({ threadId })).catch(() => {
817
- });
818
- } catch {
819
- }
820
- }
821
- abortRef.current?.abort();
822
- setSending(false);
823
- setStreamContent("");
824
- }, [threadId, transport]);
825
- if (!open) return null;
826
- const heading = defaultScopeLabel(scope);
827
- return /* @__PURE__ */ jsxs4(
828
- "aside",
829
- {
830
- className: cn(
831
- "flex h-full w-[420px] min-w-[360px] max-w-[480px] flex-col border-l border-[var(--md3-outline-variant)] bg-surface-container shadow-[var(--shadow-dropdown)]",
832
- className
833
- ),
834
- "aria-label": `Agent chat about ${heading}`,
835
- children: [
836
- /* @__PURE__ */ jsxs4("header", { className: "flex items-center justify-between border-b border-[var(--md3-outline-variant)] bg-surface-container-low px-4 py-3", children: [
837
- /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-center gap-2", children: [
838
- /* @__PURE__ */ jsx5(Sparkles2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
839
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
840
- /* @__PURE__ */ jsx5("div", { className: "text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: "Discussing" }),
841
- /* @__PURE__ */ jsx5("div", { className: "truncate text-sm font-semibold text-foreground", children: heading })
842
- ] })
843
- ] }),
844
- /* @__PURE__ */ jsx5(
845
- "button",
846
- {
847
- type: "button",
848
- onClick: () => onOpenChange(false),
849
- "aria-label": "Close artifact chat",
850
- className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
851
- children: /* @__PURE__ */ jsx5(X, { className: "h-4 w-4" })
852
- }
853
- )
854
- ] }),
855
- /* @__PURE__ */ jsx5("div", { ref: scrollRef, className: "flex-1 overflow-y-auto px-3 py-4", children: loading ? /* @__PURE__ */ jsx5("div", { className: "px-3 py-8 text-center text-xs text-muted-foreground", children: "Loading conversation\u2026" }) : messages.length === 0 && !streamContent ? /* @__PURE__ */ jsxs4("div", { className: "px-3 py-12 text-center", children: [
856
- /* @__PURE__ */ jsx5(Sparkles2, { className: "mx-auto mb-3 h-5 w-5 text-muted-foreground/40" }),
857
- /* @__PURE__ */ jsxs4("p", { className: "text-sm text-foreground", children: [
858
- "Ask the agent about this ",
859
- scope.kind === "vault-file" ? "document" : scope.kind,
860
- "."
861
- ] }),
862
- /* @__PURE__ */ jsx5("p", { className: "mt-1 text-xs text-muted-foreground", children: "It can read the current contents and propose edits, rewrites, or follow-ups." })
863
- ] }) : /* @__PURE__ */ jsxs4("div", { className: "space-y-3", children: [
864
- messages.map((m) => /* @__PURE__ */ jsx5(ChatMessage, { role: m.role, content: m.content, timestamp: m.createdAt }, m.id)),
865
- streamContent && /* @__PURE__ */ jsx5(ChatMessage, { role: "assistant", content: streamContent, isStreaming: true })
866
- ] }) }),
867
- /* @__PURE__ */ jsx5(
868
- "form",
869
- {
870
- className: "border-t border-[var(--md3-outline-variant)] bg-surface-container-low p-3",
871
- onSubmit: (e) => {
872
- e.preventDefault();
873
- void send();
874
- },
875
- children: /* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2", children: [
876
- /* @__PURE__ */ jsx5(
877
- "textarea",
878
- {
879
- value: composer,
880
- onChange: (e) => setComposer(e.target.value),
881
- onKeyDown: (e) => {
882
- if (e.key === "Enter" && !e.shiftKey && !sending) {
883
- e.preventDefault();
884
- void send();
885
- }
886
- },
887
- placeholder: `Ask about ${heading}\u2026`,
888
- rows: 2,
889
- disabled: !threadId,
890
- className: `min-h-[44px] flex-1 resize-none rounded-[20px] border bg-surface-dim px-3.5 py-2 text-sm text-foreground placeholder:text-muted-foreground disabled:opacity-50 ${focusField2}`
891
- }
892
- ),
893
- sending ? /* @__PURE__ */ jsx5(
894
- "button",
895
- {
896
- type: "button",
897
- onClick: cancel,
898
- "aria-label": "Cancel",
899
- className: "inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
900
- children: /* @__PURE__ */ jsx5(Square, { className: "h-4 w-4" })
901
- }
902
- ) : /* @__PURE__ */ jsx5(
903
- "button",
904
- {
905
- type: "submit",
906
- disabled: !composer.trim() || !threadId,
907
- "aria-label": "Send",
908
- className: "inline-flex h-9 w-9 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50",
909
- children: /* @__PURE__ */ jsx5(Send, { className: "h-4 w-4" })
910
- }
911
- )
912
- ] })
913
- }
914
- )
915
- ]
916
- }
917
- );
918
- }
919
- function createFetchTransport(opts) {
920
- const threadsUrl = opts.threadsUrl ?? "/api/threads";
921
- const chatUrl = opts.chatUrl ?? "/api/chat";
922
- const f = opts.fetchImpl ?? ((...args) => fetch(...args));
923
- const workspaceId = opts.workspaceId;
924
- return {
925
- async ensureThread(scope) {
926
- const url = threadsUrl.includes("?") ? `${threadsUrl}&workspaceId=${encodeURIComponent(workspaceId)}` : `${threadsUrl}?workspaceId=${encodeURIComponent(workspaceId)}`;
927
- const res = await f(url, {
928
- method: "POST",
929
- headers: { "Content-Type": "application/json" },
930
- body: JSON.stringify({ workspaceId, scope, ensureScoped: true })
931
- });
932
- if (!res.ok) throw new Error(`Thread ensure failed (${res.status})`);
933
- const data = await res.json();
934
- const id = data.thread?.id ?? data.id;
935
- if (!id) throw new Error("Malformed ensure response");
936
- return { id };
937
- },
938
- async loadMessages(threadId) {
939
- const res = await f(`${threadsUrl}/${encodeURIComponent(threadId)}/messages`);
940
- if (!res.ok) return [];
941
- const data = await res.json();
942
- return (data.messages ?? []).map((m) => ({
943
- id: m.id,
944
- role: normalizeRole(m.role),
945
- content: m.content,
946
- createdAt: new Date(m.createdAt)
947
- }));
948
- },
949
- sendStream({ threadId, content, signal }) {
950
- return (async function* () {
951
- const res = await f(chatUrl, {
952
- method: "POST",
953
- headers: { "Content-Type": "application/json" },
954
- body: JSON.stringify({ workspaceId, threadId, content }),
955
- signal
956
- });
957
- if (!res.ok || !res.body) {
958
- const text = await res.text().catch(() => "");
959
- yield { type: "error", message: text || `Send failed (${res.status})` };
960
- return;
961
- }
962
- const reader = res.body.getReader();
963
- const decoder = new TextDecoder();
964
- let buffer = "";
965
- while (true) {
966
- const { done, value } = await reader.read();
967
- if (done) break;
968
- buffer += decoder.decode(value, { stream: true });
969
- const lines = buffer.split("\n");
970
- buffer = lines.pop() ?? "";
971
- for (const line of lines) {
972
- if (!line.trim()) continue;
973
- try {
974
- const event = JSON.parse(line);
975
- if (event.type === "message.part.updated" && event.data) {
976
- const delta = event.data.delta;
977
- const part = event.data.part;
978
- const isText = !part || typeof part !== "object" || part.type === void 0 || part.type === "text";
979
- if (isText && typeof delta === "string" && delta.length > 0) {
980
- yield { type: "delta", text: delta };
981
- }
982
- } else if (event.type === "error" && event.data) {
983
- const message = typeof event.data.message === "string" ? event.data.message : "Stream error";
984
- yield { type: "error", message };
985
- }
986
- } catch {
987
- }
988
- }
989
- }
990
- })();
991
- }
992
- };
993
- }
994
-
995
- export {
996
- DEFAULT_REASONING_LEVEL_OPTIONS,
997
- HARNESS_REASONING_OPTIONS,
998
- ReasoningLevelPicker,
999
- AgentProfilePicker,
1000
- modelProvider,
1001
- snapHarnessToModel,
1002
- ArtifactAgentDock,
1003
- createFetchTransport,
1004
- AgentTimeline,
1005
- ChatContainer,
1006
- ChatMessage2 as ChatMessage,
1007
- MessageList,
1008
- ThinkingIndicator,
1009
- UserMessage
1010
- };