@timbal-ai/timbal-react 0.2.1 → 0.3.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/index.cjs CHANGED
@@ -30,15 +30,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- ActionBarPrimitive: () => import_react13.ActionBarPrimitive,
33
+ ARTIFACT_AGENT_INSTRUCTIONS: () => ARTIFACT_AGENT_INSTRUCTIONS,
34
+ ARTIFACT_FENCE_LANGUAGES: () => ARTIFACT_FENCE_LANGUAGES,
35
+ ActionBarPrimitive: () => import_react26.ActionBarPrimitive,
36
+ ArtifactCard: () => ArtifactCard,
37
+ ArtifactRegistryProvider: () => ArtifactRegistryProvider,
38
+ ArtifactView: () => ArtifactView,
39
+ AssistantRuntimeProvider: () => import_react26.AssistantRuntimeProvider,
34
40
  AuthGuard: () => AuthGuard,
35
41
  Avatar: () => Avatar,
36
42
  AvatarFallback: () => AvatarFallback,
37
43
  AvatarImage: () => AvatarImage,
38
44
  Button: () => Button,
45
+ ChartArtifactView: () => ChartArtifactView,
46
+ Composer: () => Composer,
39
47
  ComposerAddAttachment: () => ComposerAddAttachment,
40
48
  ComposerAttachments: () => ComposerAttachments,
41
- ComposerPrimitive: () => import_react13.ComposerPrimitive,
49
+ ComposerPrimitive: () => import_react26.ComposerPrimitive,
50
+ DEFAULT_UPLOAD_ACCEPT: () => DEFAULT_UPLOAD_ACCEPT,
42
51
  Dialog: () => Dialog,
43
52
  DialogClose: () => DialogClose,
44
53
  DialogContent: () => DialogContent,
@@ -46,35 +55,72 @@ __export(index_exports, {
46
55
  DialogPortal: () => DialogPortal,
47
56
  DialogTitle: () => DialogTitle,
48
57
  DialogTrigger: () => DialogTrigger,
58
+ HtmlArtifactView: () => HtmlArtifactView,
59
+ JsonArtifactView: () => JsonArtifactView,
49
60
  MarkdownText: () => MarkdownText,
50
- MessagePrimitive: () => import_react13.MessagePrimitive,
61
+ MessagePrimitive: () => import_react26.MessagePrimitive,
62
+ QuestionArtifactView: () => QuestionArtifactView,
51
63
  SessionProvider: () => SessionProvider,
52
64
  Shimmer: () => Shimmer,
65
+ Suggestions: () => Suggestions,
53
66
  SyntaxHighlighter: () => syntax_highlighter_default,
67
+ TableArtifactView: () => TableArtifactView,
54
68
  Thread: () => Thread,
55
- ThreadPrimitive: () => import_react13.ThreadPrimitive,
69
+ ThreadPrimitive: () => import_react26.ThreadPrimitive,
56
70
  TimbalChat: () => TimbalChat,
71
+ TimbalChatShell: () => TimbalChatShell,
57
72
  TimbalRuntimeProvider: () => TimbalRuntimeProvider,
73
+ ToolArtifactFallback: () => ToolArtifactFallback,
58
74
  ToolFallback: () => ToolFallback,
59
75
  Tooltip: () => Tooltip,
60
76
  TooltipContent: () => TooltipContent,
61
77
  TooltipIconButton: () => TooltipIconButton,
62
78
  TooltipProvider: () => TooltipProvider,
63
79
  TooltipTrigger: () => TooltipTrigger,
80
+ UiArtifactView: () => UiArtifactView,
81
+ UiCustomNodeRegistryProvider: () => UiCustomNodeRegistryProvider,
82
+ UiEventProvider: () => UiEventProvider,
83
+ UiNodeView: () => UiNodeView,
64
84
  UserMessageAttachments: () => UserMessageAttachments,
85
+ WorkforceSelector: () => WorkforceSelector,
65
86
  authFetch: () => authFetch,
66
87
  buttonVariants: () => buttonVariants,
67
88
  clearTokens: () => clearTokens,
68
89
  cn: () => cn,
90
+ createDefaultAttachmentAdapter: () => createDefaultAttachmentAdapter,
91
+ createUploadAttachmentAdapter: () => createUploadAttachmentAdapter,
92
+ defaultArtifactRenderers: () => defaultArtifactRenderers,
69
93
  fetchCurrentUser: () => fetchCurrentUser,
94
+ findMarkdownArtifacts: () => findMarkdownArtifacts,
70
95
  getAccessToken: () => getAccessToken,
96
+ getPath: () => getPath,
71
97
  getRefreshToken: () => getRefreshToken,
98
+ isArtifact: () => isArtifact,
99
+ isArtifactFenceLanguage: () => isArtifactFenceLanguage,
100
+ isUiBinding: () => isUiBinding,
101
+ parseArtifactFromToolResult: () => parseArtifactFromToolResult,
102
+ parseSSELine: () => import_timbal_sdk2.parseSSELine,
72
103
  refreshAccessToken: () => refreshAccessToken,
73
- useComposerRuntime: () => import_react13.useComposerRuntime,
74
- useMessageRuntime: () => import_react13.useMessageRuntime,
104
+ resolveAttachmentAdapter: () => resolveAttachmentAdapter,
105
+ resolveBindable: () => resolveBindable,
106
+ setAccessToken: () => setAccessToken,
107
+ setPath: () => setPath,
108
+ setRefreshToken: () => setRefreshToken,
109
+ splitMarkdownByArtifacts: () => splitMarkdownByArtifacts,
110
+ useArtifactRegistry: () => useArtifactRegistry,
111
+ useComposerRuntime: () => import_react26.useComposerRuntime,
112
+ useMessageRuntime: () => import_react26.useMessageRuntime,
113
+ useResolvedSuggestions: () => useResolvedSuggestions,
75
114
  useSession: () => useSession,
76
- useThread: () => import_react13.useThread,
77
- useThreadRuntime: () => import_react13.useThreadRuntime
115
+ useThread: () => import_react26.useThread,
116
+ useThreadRuntime: () => import_react26.useThreadRuntime,
117
+ useTimbalRuntime: () => useTimbalRuntime,
118
+ useTimbalStream: () => useTimbalStream,
119
+ useUiCustomNodeRegistry: () => useUiCustomNodeRegistry,
120
+ useUiDispatch: () => useUiDispatch,
121
+ useUiEventEmitter: () => useUiEventEmitter,
122
+ useUiState: () => useUiState,
123
+ useWorkforces: () => useWorkforces
78
124
  });
79
125
  module.exports = __toCommonJS(index_exports);
80
126
 
@@ -87,7 +133,9 @@ var import_timbal_sdk = require("@timbal-ai/timbal-sdk");
87
133
  var ACCESS_TOKEN_KEY = "timbal_project_access_token";
88
134
  var REFRESH_TOKEN_KEY = "timbal_project_refresh_token";
89
135
  var getAccessToken = () => localStorage.getItem(ACCESS_TOKEN_KEY);
136
+ var setAccessToken = (token) => localStorage.setItem(ACCESS_TOKEN_KEY, token);
90
137
  var getRefreshToken = () => localStorage.getItem(REFRESH_TOKEN_KEY);
138
+ var setRefreshToken = (token) => localStorage.setItem(REFRESH_TOKEN_KEY, token);
91
139
  var clearTokens = () => {
92
140
  localStorage.removeItem(ACCESS_TOKEN_KEY);
93
141
  localStorage.removeItem(REFRESH_TOKEN_KEY);
@@ -162,13 +210,506 @@ var fetchCurrentUser = async () => {
162
210
  }
163
211
  };
164
212
 
213
+ // src/artifacts/types.ts
214
+ function isArtifact(value) {
215
+ return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.type === "string";
216
+ }
217
+
218
+ // src/runtime/reducer.ts
219
+ function createReducerState() {
220
+ return { parts: [], toolIndexById: /* @__PURE__ */ new Map() };
221
+ }
222
+ function reduceSseEvent(state, event) {
223
+ switch (event.type) {
224
+ case "DELTA":
225
+ return reduceDelta(state, event.item);
226
+ case "OUTPUT": {
227
+ const path = event.path;
228
+ const isNested = typeof path === "string" && path.includes(".");
229
+ if (!isNested) {
230
+ const errorMessage = readErrorMessage(event);
231
+ if (errorMessage) {
232
+ state.parts.push({ type: "text", text: `**Error:** ${errorMessage}` });
233
+ return true;
234
+ }
235
+ }
236
+ if (isNested) {
237
+ return reduceNestedOutput(
238
+ state,
239
+ path,
240
+ event.output
241
+ );
242
+ }
243
+ return reduceOutput(
244
+ state,
245
+ event.output
246
+ );
247
+ }
248
+ default:
249
+ return false;
250
+ }
251
+ }
252
+ function reduceDelta(state, item) {
253
+ if (!item) return false;
254
+ if (item.type === "text_delta" && typeof item.text_delta === "string") {
255
+ lastTextPart(state).text += item.text_delta;
256
+ return true;
257
+ }
258
+ if (item.type === "thinking_delta" && typeof item.thinking_delta === "string") {
259
+ lastThinkingPart(state).text += item.thinking_delta;
260
+ return true;
261
+ }
262
+ if (item.type === "tool_use") {
263
+ const toolCallId = item.id || `tool-${crypto.randomUUID()}`;
264
+ const inputStr = stringifyInput(item.input);
265
+ const part = {
266
+ type: "tool-call",
267
+ toolCallId,
268
+ toolName: item.name || "unknown",
269
+ argsText: inputStr,
270
+ status: "running"
271
+ };
272
+ state.parts.push(part);
273
+ state.toolIndexById.set(toolCallId, state.parts.length - 1);
274
+ return true;
275
+ }
276
+ if (item.type === "tool_use_delta") {
277
+ const idx = state.toolIndexById.get(item.id);
278
+ if (idx !== void 0 && typeof item.input_delta === "string") {
279
+ state.parts[idx].argsText += item.input_delta;
280
+ return true;
281
+ }
282
+ }
283
+ return false;
284
+ }
285
+ function reduceNestedOutput(state, path, output) {
286
+ if (!output || typeof output !== "object") return false;
287
+ if (!Array.isArray(output.content) && isArtifact(output)) {
288
+ const toolName = toolNameFromPath(path);
289
+ if (toolName && attachToolResult(state, { toolName, result: output })) {
290
+ return true;
291
+ }
292
+ }
293
+ return reduceOutput(state, output, { toolResultsOnly: true, allowOrphan: false });
294
+ }
295
+ function reduceOutput(state, output, options) {
296
+ if (!output) return false;
297
+ if (typeof output === "string") {
298
+ if (state.parts.length === 0) {
299
+ state.parts.push({ type: "text", text: output });
300
+ return true;
301
+ }
302
+ return false;
303
+ }
304
+ if (Array.isArray(output.content)) {
305
+ let changed = false;
306
+ const blocks = output.content;
307
+ for (const block of blocks) {
308
+ if (block.type === "tool_use") {
309
+ if (!options?.toolResultsOnly && recordToolUse(state, block)) {
310
+ changed = true;
311
+ }
312
+ } else if (block.type === "tool_result") {
313
+ if (recordToolResult(state, block, options)) changed = true;
314
+ } else if (!options?.toolResultsOnly) {
315
+ if (block.type === "text" && typeof block.text === "string" && !lastTextPart(state).text) {
316
+ lastTextPart(state).text = block.text;
317
+ changed = true;
318
+ } else if (block.type === "thinking" && typeof block.thinking === "string" && !lastThinkingPart(state).text) {
319
+ lastThinkingPart(state).text = block.thinking;
320
+ changed = true;
321
+ }
322
+ }
323
+ }
324
+ return changed;
325
+ }
326
+ if (state.parts.length === 0) {
327
+ state.parts.push({ type: "text", text: JSON.stringify(output) });
328
+ return true;
329
+ }
330
+ return false;
331
+ }
332
+ function recordToolUse(state, block) {
333
+ const id = block.id || `tool-${crypto.randomUUID()}`;
334
+ if (state.toolIndexById.has(id)) return false;
335
+ const inputStr = stringifyInput(block.input);
336
+ const part = {
337
+ type: "tool-call",
338
+ toolCallId: id,
339
+ toolName: block.name || "unknown",
340
+ argsText: inputStr,
341
+ status: "running"
342
+ };
343
+ state.parts.push(part);
344
+ state.toolIndexById.set(id, state.parts.length - 1);
345
+ return true;
346
+ }
347
+ function recordToolResult(state, block, options) {
348
+ const allowOrphan = options?.allowOrphan !== false;
349
+ const id = block.id || block.tool_use_id || "";
350
+ const { result, resultText } = parseToolResultContent(block.content);
351
+ const toolName = block.name || void 0;
352
+ if (id) {
353
+ const idx = state.toolIndexById.get(id);
354
+ if (idx !== void 0) {
355
+ const part2 = state.parts[idx];
356
+ part2.result = result;
357
+ if (resultText) part2.resultText = resultText;
358
+ part2.status = "complete";
359
+ return true;
360
+ }
361
+ if (!allowOrphan) return false;
362
+ }
363
+ if (!id && toolName && attachToolResult(state, {
364
+ toolName,
365
+ result,
366
+ resultText
367
+ })) {
368
+ return true;
369
+ }
370
+ if (!id || !allowOrphan) return false;
371
+ const part = {
372
+ type: "tool-call",
373
+ toolCallId: id,
374
+ toolName: toolName || "unknown",
375
+ argsText: "",
376
+ result,
377
+ resultText,
378
+ status: "complete"
379
+ };
380
+ state.parts.push(part);
381
+ state.toolIndexById.set(id, state.parts.length - 1);
382
+ return true;
383
+ }
384
+ function toolNameFromPath(path) {
385
+ const segment = path.split(".").pop();
386
+ return segment && segment !== "agent" && segment !== "llm" ? segment : null;
387
+ }
388
+ function attachToolResult(state, {
389
+ toolCallId,
390
+ toolName,
391
+ result,
392
+ resultText
393
+ }) {
394
+ if (toolCallId) {
395
+ const idx = state.toolIndexById.get(toolCallId);
396
+ if (idx !== void 0) {
397
+ const part = state.parts[idx];
398
+ part.result = result;
399
+ if (resultText) part.resultText = resultText;
400
+ part.status = "complete";
401
+ return true;
402
+ }
403
+ }
404
+ if (toolName) {
405
+ for (let i = state.parts.length - 1; i >= 0; i--) {
406
+ const part = state.parts[i];
407
+ if (part.type === "tool-call" && part.toolName === toolName && part.result === void 0) {
408
+ part.result = result;
409
+ if (resultText) part.resultText = resultText;
410
+ part.status = "complete";
411
+ return true;
412
+ }
413
+ }
414
+ }
415
+ return false;
416
+ }
417
+ function parseToolResultContent(content) {
418
+ if (typeof content === "string") {
419
+ return { result: content, resultText: content };
420
+ }
421
+ if (!Array.isArray(content)) {
422
+ return { result: content };
423
+ }
424
+ const textChunks = [];
425
+ for (const item of content) {
426
+ if (typeof item === "string") {
427
+ textChunks.push(item);
428
+ } else if (item && typeof item === "object") {
429
+ const obj = item;
430
+ if (obj.type === "text" && typeof obj.text === "string") {
431
+ textChunks.push(obj.text);
432
+ } else if (obj.type === "thinking" && typeof obj.thinking === "string") {
433
+ textChunks.push(obj.thinking);
434
+ }
435
+ }
436
+ }
437
+ return {
438
+ result: content,
439
+ resultText: textChunks.length > 0 ? textChunks.join("\n") : void 0
440
+ };
441
+ }
442
+ function readErrorMessage(event) {
443
+ const status = event.status;
444
+ const isErrorStatus = status?.code === "error";
445
+ const error = event.error;
446
+ let type = null;
447
+ let message = null;
448
+ if (isErrorStatus && typeof status?.message === "string" && status.message.length > 0) {
449
+ message = status.message;
450
+ }
451
+ if (!message && typeof error === "string" && error.length > 0) {
452
+ message = error;
453
+ } else if (error && typeof error === "object") {
454
+ const obj = error;
455
+ if (typeof obj.type === "string" && obj.type.length > 0) {
456
+ type = obj.type;
457
+ }
458
+ if (!message && typeof obj.message === "string" && obj.message.length > 0) {
459
+ message = obj.message;
460
+ }
461
+ }
462
+ if (!message && !isErrorStatus) return null;
463
+ if (!message) return "The agent failed to generate a response.";
464
+ const compact = compactError(message);
465
+ return type ? `${type}: ${compact}` : compact;
466
+ }
467
+ var ERROR_MAX_CHARS = 480;
468
+ function compactError(message) {
469
+ const trimmed = message.split(/\n\s*Traceback \(most recent call last\):/u)[0].trim();
470
+ if (trimmed.length <= ERROR_MAX_CHARS) return trimmed;
471
+ return `${trimmed.slice(0, ERROR_MAX_CHARS).trimEnd()}\u2026`;
472
+ }
473
+ function stringifyInput(input) {
474
+ if (input === void 0 || input === null) return "{}";
475
+ return typeof input === "string" ? input : JSON.stringify(input);
476
+ }
477
+ function lastTextPart(state) {
478
+ const last = state.parts[state.parts.length - 1];
479
+ if (last?.type === "text") return last;
480
+ const next = { type: "text", text: "" };
481
+ state.parts.push(next);
482
+ return next;
483
+ }
484
+ function lastThinkingPart(state) {
485
+ const last = state.parts[state.parts.length - 1];
486
+ if (last?.type === "thinking") return last;
487
+ const next = { type: "thinking", text: "" };
488
+ state.parts.push(next);
489
+ return next;
490
+ }
491
+
492
+ // src/runtime/attachments.ts
493
+ async function extractAttachment(attachment) {
494
+ const file = attachment.file;
495
+ let src = null;
496
+ let contentType;
497
+ let name = attachment.name ?? file?.name;
498
+ const content = attachment.content;
499
+ if (content) {
500
+ for (const block of content) {
501
+ if (block.type === "image" && typeof block.image === "string") {
502
+ src = block.image;
503
+ if (typeof block.mimeType === "string") {
504
+ contentType = block.mimeType;
505
+ }
506
+ break;
507
+ }
508
+ if (block.type === "file" && typeof block.data === "string") {
509
+ src = block.data;
510
+ if (typeof block.mimeType === "string") contentType = block.mimeType;
511
+ break;
512
+ }
513
+ }
514
+ }
515
+ if (src === null && file) {
516
+ src = await fileToDataUrl(file);
517
+ if (!contentType) contentType = file.type || void 0;
518
+ if (!name) name = file.name;
519
+ }
520
+ if (!src) return null;
521
+ if (!contentType) contentType = mimeFromDataUrl(src);
522
+ const rawType = String(attachment.type ?? "file");
523
+ const type = rawType === "image" || rawType === "document" ? rawType : "file";
524
+ return {
525
+ id: attachment.id ?? crypto.randomUUID(),
526
+ type,
527
+ ...name !== void 0 ? { name } : {},
528
+ ...contentType !== void 0 ? { contentType } : {},
529
+ dataUrl: src
530
+ };
531
+ }
532
+ function fileToDataUrl(file) {
533
+ return new Promise((resolve, reject) => {
534
+ const reader = new FileReader();
535
+ reader.onload = () => resolve(reader.result);
536
+ reader.onerror = () => reject(reader.error);
537
+ reader.readAsDataURL(file);
538
+ });
539
+ }
540
+ function mimeFromDataUrl(dataUrl) {
541
+ const match = /^data:([^;,]+)[;,]/.exec(dataUrl);
542
+ return match?.[1];
543
+ }
544
+ function buildPromptBody({
545
+ input,
546
+ attachments,
547
+ parentId
548
+ }) {
549
+ const context = { parent_id: parentId };
550
+ const files = attachments ?? [];
551
+ if (files.length === 0) {
552
+ return { prompt: input, context };
553
+ }
554
+ const parts = [];
555
+ if (input) parts.push({ type: "text", text: input });
556
+ for (const attachment of files) {
557
+ parts.push({ type: "file", file: attachment.dataUrl });
558
+ }
559
+ return { prompt: parts, context };
560
+ }
561
+
562
+ // src/runtime/upload-adapter.ts
563
+ var DEFAULT_UPLOAD_ACCEPT = "image/*,application/pdf,text/*,.md,.json,.csv,.tsv,.xlsx,.docx";
564
+ function createDefaultAttachmentAdapter({
565
+ baseUrl = "",
566
+ uploadUrl,
567
+ fetch: fetchFn = authFetch,
568
+ accept = DEFAULT_UPLOAD_ACCEPT
569
+ } = {}) {
570
+ const base = baseUrl.replace(/\/$/, "");
571
+ const resolvedUploadUrl = uploadUrl ?? `${base}/files/upload`;
572
+ return {
573
+ accept,
574
+ async add({ file }) {
575
+ const isImage = file.type.startsWith("image/");
576
+ const pending = {
577
+ id: crypto.randomUUID(),
578
+ type: isImage ? "image" : "file",
579
+ name: file.name,
580
+ contentType: file.type || "application/octet-stream",
581
+ file,
582
+ status: { type: "requires-action", reason: "composer-send" }
583
+ };
584
+ return pending;
585
+ },
586
+ async send(attachment) {
587
+ const fd = new FormData();
588
+ fd.append("file", attachment.file);
589
+ const res = await fetchFn(resolvedUploadUrl, { method: "POST", body: fd });
590
+ if (!res.ok) {
591
+ const detail = await res.text().catch(() => "");
592
+ throw new Error(
593
+ `Attachment upload failed (${res.status}): ${detail || res.statusText}`
594
+ );
595
+ }
596
+ const remoteUrl = await readUploadedUrl(res);
597
+ const mime = attachment.contentType ?? "application/octet-stream";
598
+ const filename = attachment.name;
599
+ const complete = {
600
+ ...attachment,
601
+ status: { type: "complete" },
602
+ content: mime.startsWith("image/") ? [{ type: "image", image: remoteUrl, filename }] : [{ type: "file", data: remoteUrl, mimeType: mime, filename }]
603
+ };
604
+ return complete;
605
+ },
606
+ async remove() {
607
+ }
608
+ };
609
+ }
610
+ var createUploadAttachmentAdapter = createDefaultAttachmentAdapter;
611
+ async function readUploadedUrl(res) {
612
+ const contentType = res.headers.get("content-type") ?? "";
613
+ if (contentType.includes("application/json")) {
614
+ const data = await res.json();
615
+ const candidate = data.url ?? data.signed_url ?? data.id;
616
+ if (typeof candidate === "string" && candidate.length > 0) {
617
+ return candidate;
618
+ }
619
+ throw new Error(
620
+ "Attachment upload response did not include a `url`, `signed_url`, or `id` field."
621
+ );
622
+ }
623
+ const text = (await res.text()).trim();
624
+ if (!text) {
625
+ throw new Error("Attachment upload response was empty.");
626
+ }
627
+ return text;
628
+ }
629
+
630
+ // src/runtime/resolve-attachments.ts
631
+ function isAttachmentAdapter(value) {
632
+ return typeof value === "object" && value !== null && "accept" in value && typeof value.add === "function" && typeof value.send === "function" && typeof value.remove === "function";
633
+ }
634
+ function resolveAttachmentAdapter(attachments, options = {}) {
635
+ const baseUrl = options.baseUrl ?? "/api";
636
+ const legacyUploadUrl = options.uploadUrl;
637
+ const legacyAccept = options.accept;
638
+ if (attachments === null) return void 0;
639
+ const legacyEnables = legacyUploadUrl !== void 0 || legacyAccept !== void 0;
640
+ if (attachments === void 0) {
641
+ if (!legacyEnables) return void 0;
642
+ return createDefaultAttachmentAdapter({
643
+ baseUrl,
644
+ fetch: options.fetch,
645
+ uploadUrl: legacyUploadUrl,
646
+ accept: legacyAccept
647
+ });
648
+ }
649
+ if (attachments === true) {
650
+ return createDefaultAttachmentAdapter({
651
+ baseUrl,
652
+ fetch: options.fetch,
653
+ uploadUrl: legacyUploadUrl,
654
+ accept: legacyAccept
655
+ });
656
+ }
657
+ if (isAttachmentAdapter(attachments)) return attachments;
658
+ const config = attachments;
659
+ return createDefaultAttachmentAdapter({
660
+ baseUrl,
661
+ fetch: options.fetch,
662
+ uploadUrl: config.uploadUrl ?? legacyUploadUrl,
663
+ accept: config.accept ?? legacyAccept
664
+ });
665
+ }
666
+
165
667
  // src/runtime/provider.tsx
166
668
  var import_jsx_runtime = require("react/jsx-runtime");
167
- var convertMessage = (message) => ({
168
- role: message.role,
169
- content: message.content,
170
- id: message.id
171
- });
669
+ function projectAttachment(attachment) {
670
+ const filename = attachment.name ?? "attachment";
671
+ const mimeType = attachment.contentType ?? "application/octet-stream";
672
+ if (attachment.type === "image") {
673
+ return {
674
+ id: attachment.id,
675
+ type: "image",
676
+ name: filename,
677
+ contentType: mimeType,
678
+ status: { type: "complete" },
679
+ content: [{ type: "image", image: attachment.dataUrl, filename }]
680
+ };
681
+ }
682
+ return {
683
+ id: attachment.id,
684
+ type: attachment.type,
685
+ name: filename,
686
+ contentType: mimeType,
687
+ status: { type: "complete" },
688
+ content: [
689
+ { type: "file", data: attachment.dataUrl, mimeType, filename }
690
+ ]
691
+ };
692
+ }
693
+ var convertMessage = (message) => {
694
+ const content = message.content.map((part) => {
695
+ if (part.type === "text") return { type: "text", text: part.text };
696
+ if (part.type === "thinking") return { type: "reasoning", text: part.text };
697
+ return {
698
+ type: "tool-call",
699
+ toolCallId: part.toolCallId,
700
+ toolName: part.toolName,
701
+ argsText: part.argsText,
702
+ ...part.result !== void 0 ? { result: part.result } : {}
703
+ };
704
+ });
705
+ const attachments = message.attachments && message.attachments.length > 0 ? message.attachments.map(projectAttachment) : void 0;
706
+ return {
707
+ role: message.role,
708
+ content,
709
+ id: message.id,
710
+ ...attachments ? { attachments } : {}
711
+ };
712
+ };
172
713
  function findParentId(messages, beforeIndex) {
173
714
  const slice = beforeIndex !== void 0 ? messages.slice(0, beforeIndex) : messages;
174
715
  for (let i = slice.length - 1; i >= 0; i--) {
@@ -176,18 +717,18 @@ function findParentId(messages, beforeIndex) {
176
717
  }
177
718
  return null;
178
719
  }
179
- function isTopLevelStart(event) {
180
- return event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".");
181
- }
182
720
  function getTextFromMessage(message) {
183
721
  const part = message.content.find((c) => c.type === "text");
184
- return part?.type === "text" ? part.text : null;
722
+ return part?.type === "text" ? part.text : "";
185
723
  }
186
- function TimbalRuntimeProvider({
724
+ function getAttachmentsFromMessage(message) {
725
+ return message.attachments?.length ? message.attachments : void 0;
726
+ }
727
+ function useTimbalStream({
187
728
  workforceId,
188
- children,
189
729
  baseUrl = "/api",
190
- fetch: fetchFn
730
+ fetch: fetchFn,
731
+ debug = false
191
732
  }) {
192
733
  const [messages, setMessages] = (0, import_react.useState)([]);
193
734
  const [isRunning, setIsRunning] = (0, import_react.useState)(false);
@@ -197,40 +738,41 @@ function TimbalRuntimeProvider({
197
738
  (0, import_react.useEffect)(() => {
198
739
  fetchFnRef.current = fetchFn ?? authFetch;
199
740
  }, [fetchFn]);
741
+ const debugRef = (0, import_react.useRef)(debug);
742
+ (0, import_react.useEffect)(() => {
743
+ debugRef.current = debug;
744
+ }, [debug]);
200
745
  (0, import_react.useEffect)(() => {
201
746
  messagesRef.current = messages;
202
747
  }, [messages]);
203
748
  const streamAssistantResponse = (0, import_react.useCallback)(
204
- async (input, userId, assistantId, parentId, signal) => {
205
- const parts = [];
206
- const toolIndexById = /* @__PURE__ */ new Map();
207
- const lastTextPart = () => {
208
- const last = parts[parts.length - 1];
209
- if (last?.type === "text") return last;
210
- const next = { type: "text", text: "" };
211
- parts.push(next);
212
- return next;
213
- };
749
+ async (input, attachments, userId, assistantId, parentId, signal) => {
750
+ const state = createReducerState();
214
751
  const flush = () => {
215
752
  setMessages(
216
- (prev) => prev.map((m) => m.id === assistantId ? { ...m, content: [...parts] } : m)
753
+ (prev) => prev.map(
754
+ (m) => m.id === assistantId ? { ...m, content: [...state.parts] } : m
755
+ )
217
756
  );
218
757
  };
219
758
  const stampRunId = (runId) => {
220
759
  setMessages(
221
- (prev) => prev.map((m) => m.id === userId || m.id === assistantId ? { ...m, runId } : m)
760
+ (prev) => prev.map(
761
+ (m) => m.id === userId || m.id === assistantId ? { ...m, runId } : m
762
+ )
222
763
  );
223
764
  };
224
765
  try {
225
- const res = await fetchFnRef.current(`${baseUrl}/workforce/${workforceId}/stream`, {
226
- method: "POST",
227
- headers: { "Content-Type": "application/json" },
228
- body: JSON.stringify({
229
- prompt: input,
230
- context: { parent_id: parentId }
231
- }),
232
- signal
233
- });
766
+ const body = buildPromptBody({ input, attachments, parentId });
767
+ const res = await fetchFnRef.current(
768
+ `${baseUrl}/workforce/${workforceId}/stream`,
769
+ {
770
+ method: "POST",
771
+ headers: { "Content-Type": "application/json" },
772
+ body: JSON.stringify(body),
773
+ signal
774
+ }
775
+ );
234
776
  if (!res.ok || !res.body) throw new Error(`Request failed: ${res.status}`);
235
777
  const reader = res.body.getReader();
236
778
  const decoder = new TextDecoder();
@@ -245,84 +787,34 @@ function TimbalRuntimeProvider({
245
787
  for (const line of lines) {
246
788
  const event = (0, import_timbal_sdk.parseSSELine)(line);
247
789
  if (!event) continue;
248
- if (!capturedRunId && isTopLevelStart(event)) {
249
- capturedRunId = event.run_id;
250
- stampRunId(capturedRunId);
790
+ if (debugRef.current) {
791
+ console.debug("[timbal]", event.type, event);
251
792
  }
252
- switch (event.type) {
253
- case "DELTA": {
254
- const item = event.item;
255
- if (!item) break;
256
- if (item.type === "text_delta" && typeof item.text_delta === "string") {
257
- lastTextPart().text += item.text_delta;
258
- flush();
259
- } else if (item.type === "tool_use") {
260
- const toolCallId = item.id || `tool-${crypto.randomUUID()}`;
261
- const inputStr = typeof item.input === "string" ? item.input : JSON.stringify(item.input ?? {});
262
- parts.push({
263
- type: "tool-call",
264
- toolCallId,
265
- toolName: item.name || "unknown",
266
- argsText: inputStr
267
- });
268
- toolIndexById.set(toolCallId, parts.length - 1);
269
- flush();
270
- } else if (item.type === "tool_use_delta") {
271
- const idx = toolIndexById.get(item.id);
272
- if (idx !== void 0 && typeof item.input_delta === "string") {
273
- parts[idx].argsText += item.input_delta;
274
- flush();
275
- }
276
- }
277
- break;
278
- }
279
- case "OUTPUT": {
280
- const output = event.output;
281
- if (!output) break;
282
- if (typeof output === "object" && Array.isArray(output.content)) {
283
- for (const block of output.content) {
284
- if (block.type === "tool_use") {
285
- const id = block.id || `tool-${crypto.randomUUID()}`;
286
- const idx = toolIndexById.get(id);
287
- if (idx !== void 0) {
288
- parts[idx].result = "Tool executed";
289
- } else {
290
- const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input ?? {});
291
- parts.push({
292
- type: "tool-call",
293
- toolCallId: id,
294
- toolName: block.name || "unknown",
295
- argsText: inputStr,
296
- result: "Tool executed"
297
- });
298
- toolIndexById.set(id, parts.length - 1);
299
- }
300
- } else if (block.type === "text" && typeof block.text === "string" && !lastTextPart().text) {
301
- lastTextPart().text = block.text;
302
- }
303
- }
304
- flush();
305
- } else if (parts.length === 0) {
306
- const text = typeof output === "string" ? output : JSON.stringify(output);
307
- parts.push({ type: "text", text });
308
- flush();
309
- }
310
- break;
793
+ if (!capturedRunId) {
794
+ const runId = readTopLevelStartRunId(event);
795
+ if (runId) {
796
+ capturedRunId = runId;
797
+ stampRunId(runId);
311
798
  }
312
799
  }
800
+ const changed = reduceSseEvent(state, event);
801
+ if (changed) flush();
313
802
  }
314
803
  }
315
804
  if (buffer.trim()) {
316
805
  const event = (0, import_timbal_sdk.parseSSELine)(buffer);
317
- if (event?.type === "OUTPUT" && parts.length === 0 && event.output) {
318
- const text = typeof event.output === "string" ? event.output : JSON.stringify(event.output);
319
- parts.push({ type: "text", text });
320
- flush();
806
+ if (event) {
807
+ if (debugRef.current) {
808
+ console.debug("[timbal]", event.type, event);
809
+ }
810
+ if (reduceSseEvent(state, event)) flush();
321
811
  }
322
812
  }
323
813
  } catch (err) {
324
814
  if (err.name !== "AbortError") {
325
- if (parts.length === 0) parts.push({ type: "text", text: "Something went wrong." });
815
+ if (state.parts.length === 0) {
816
+ state.parts.push({ type: "text", text: "Something went wrong." });
817
+ }
326
818
  flush();
327
819
  }
328
820
  } finally {
@@ -332,44 +824,46 @@ function TimbalRuntimeProvider({
332
824
  },
333
825
  [workforceId, baseUrl]
334
826
  );
335
- const onNew = (0, import_react.useCallback)(
336
- async (message) => {
337
- const textPart = message.content.find((c) => c.type === "text");
338
- if (!textPart || textPart.type !== "text") return;
339
- const input = textPart.text;
827
+ const send = (0, import_react.useCallback)(
828
+ async (input, options) => {
340
829
  const userId = crypto.randomUUID();
341
830
  const assistantId = crypto.randomUUID();
342
- let base = messagesRef.current;
343
- if (message.parentId !== null) {
344
- const parentIdx = base.findIndex((m) => m.id === message.parentId);
345
- if (parentIdx >= 0) {
346
- base = base.slice(0, parentIdx + 1);
347
- }
348
- }
349
- const parentId = findParentId(base);
831
+ const base = messagesRef.current;
832
+ const parentId = options?.parentId !== void 0 ? options.parentId : findParentId(base);
833
+ const userMessage = {
834
+ id: userId,
835
+ role: "user",
836
+ content: input ? [{ type: "text", text: input }] : [],
837
+ ...options?.attachments && options.attachments.length > 0 ? { attachments: options.attachments } : {}
838
+ };
350
839
  setMessages([
351
840
  ...base,
352
- { id: userId, role: "user", content: [{ type: "text", text: input }] }
353
- ]);
354
- setIsRunning(true);
355
- setMessages((prev) => [
356
- ...prev,
841
+ userMessage,
357
842
  { id: assistantId, role: "assistant", content: [] }
358
843
  ]);
844
+ setIsRunning(true);
359
845
  const controller = new AbortController();
360
846
  abortRef.current = controller;
361
- await streamAssistantResponse(input, userId, assistantId, parentId, controller.signal);
847
+ await streamAssistantResponse(
848
+ input,
849
+ options?.attachments,
850
+ userId,
851
+ assistantId,
852
+ parentId,
853
+ controller.signal
854
+ );
362
855
  },
363
856
  [streamAssistantResponse]
364
857
  );
365
- const onReload = (0, import_react.useCallback)(
858
+ const reload = (0, import_react.useCallback)(
366
859
  async (messageId) => {
367
860
  const current = messagesRef.current;
368
861
  const idx = messageId ? current.findIndex((m) => m.id === messageId) : current.length - 2;
369
862
  const userMessage = idx >= 0 ? current[idx] : null;
370
863
  if (!userMessage || userMessage.role !== "user") return;
371
864
  const input = getTextFromMessage(userMessage);
372
- if (!input) return;
865
+ const messageAttachments = getAttachmentsFromMessage(userMessage);
866
+ if (!input && !messageAttachments?.length) return;
373
867
  const assistantId = crypto.randomUUID();
374
868
  const parentId = findParentId(current, idx);
375
869
  setMessages((prev) => [
@@ -379,24 +873,114 @@ function TimbalRuntimeProvider({
379
873
  setIsRunning(true);
380
874
  const controller = new AbortController();
381
875
  abortRef.current = controller;
382
- await streamAssistantResponse(input, userMessage.id, assistantId, parentId, controller.signal);
876
+ await streamAssistantResponse(
877
+ input,
878
+ messageAttachments,
879
+ userMessage.id,
880
+ assistantId,
881
+ parentId,
882
+ controller.signal
883
+ );
383
884
  },
384
885
  [streamAssistantResponse]
385
886
  );
386
- const onCancel = (0, import_react.useCallback)(async () => {
887
+ const cancel = (0, import_react.useCallback)(() => {
888
+ abortRef.current?.abort();
889
+ }, []);
890
+ const clear = (0, import_react.useCallback)(() => {
387
891
  abortRef.current?.abort();
892
+ setMessages([]);
388
893
  }, []);
894
+ return (0, import_react.useMemo)(
895
+ () => ({ messages, isRunning, send, reload, cancel, clear }),
896
+ [messages, isRunning, send, reload, cancel, clear]
897
+ );
898
+ }
899
+ function readTopLevelStartRunId(event) {
900
+ if (event.type === "START" && typeof event.run_id === "string" && typeof event.path === "string" && !event.path.includes(".")) {
901
+ return event.run_id;
902
+ }
903
+ return null;
904
+ }
905
+ var TimbalStreamContext = (0, import_react.createContext)(null);
906
+ function useTimbalRuntime() {
907
+ const ctx = (0, import_react.useContext)(TimbalStreamContext);
908
+ if (!ctx) {
909
+ throw new Error(
910
+ "useTimbalRuntime must be used inside a <TimbalRuntimeProvider>."
911
+ );
912
+ }
913
+ return ctx;
914
+ }
915
+ function TimbalRuntimeProvider({
916
+ workforceId,
917
+ children,
918
+ baseUrl = "/api",
919
+ fetch: fetchFn,
920
+ attachments,
921
+ attachmentsUploadUrl,
922
+ attachmentsAccept,
923
+ debug
924
+ }) {
925
+ const stream = useTimbalStream({
926
+ workforceId,
927
+ baseUrl,
928
+ fetch: fetchFn,
929
+ debug
930
+ });
931
+ const attachmentAdapter = (0, import_react.useMemo)(
932
+ () => resolveAttachmentAdapter(attachments, {
933
+ baseUrl,
934
+ fetch: fetchFn,
935
+ uploadUrl: attachmentsUploadUrl,
936
+ accept: attachmentsAccept
937
+ }),
938
+ [attachments, attachmentsUploadUrl, attachmentsAccept, baseUrl, fetchFn]
939
+ );
940
+ const onNew = (0, import_react.useCallback)(
941
+ async (message) => {
942
+ const textPart = message.content.find((c) => c.type === "text");
943
+ const input = textPart && textPart.type === "text" ? textPart.text : "";
944
+ const auiAttachments = message.attachments;
945
+ const attachments2 = auiAttachments ? (await Promise.all(auiAttachments.map(extractAttachment))).filter((a) => a !== null) : [];
946
+ if (!input && attachments2.length === 0) return;
947
+ const parentId = message.parentId !== null && message.parentId !== void 0 ? findParentIdFromAuiParent(stream.messages, message.parentId) : void 0;
948
+ await stream.send(input, {
949
+ attachments: attachments2.length > 0 ? attachments2 : void 0,
950
+ ...parentId !== void 0 ? { parentId } : {}
951
+ });
952
+ },
953
+ [stream]
954
+ );
955
+ const onReload = (0, import_react.useCallback)(
956
+ async (messageId) => {
957
+ await stream.reload(messageId);
958
+ },
959
+ [stream]
960
+ );
961
+ const onCancel = (0, import_react.useCallback)(async () => {
962
+ stream.cancel();
963
+ }, [stream]);
389
964
  const runtime = (0, import_react2.useExternalStoreRuntime)({
390
- isRunning,
391
- messages,
965
+ isRunning: stream.isRunning,
966
+ messages: stream.messages,
392
967
  convertMessage,
393
968
  onNew,
394
969
  onEdit: onNew,
395
970
  onReload,
396
- onCancel
971
+ onCancel,
972
+ ...attachmentAdapter ? { adapters: { attachments: attachmentAdapter } } : {}
397
973
  });
398
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children });
974
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TimbalStreamContext.Provider, { value: stream, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.AssistantRuntimeProvider, { runtime, children }) });
399
975
  }
976
+ function findParentIdFromAuiParent(messages, auiParentId) {
977
+ const idx = messages.findIndex((m) => m.id === auiParentId);
978
+ if (idx < 0) return null;
979
+ return findParentId(messages.slice(0, idx + 1));
980
+ }
981
+
982
+ // src/index.ts
983
+ var import_timbal_sdk2 = require("@timbal-ai/timbal-sdk");
400
984
 
401
985
  // src/components/attachment.tsx
402
986
  var import_react4 = require("react");
@@ -850,72 +1434,1111 @@ var import_react_markdown = require("@assistant-ui/react-markdown");
850
1434
  var import_remark_gfm = __toESM(require("remark-gfm"), 1);
851
1435
  var import_remark_math = __toESM(require("remark-math"), 1);
852
1436
  var import_rehype_katex = __toESM(require("rehype-katex"), 1);
853
- var import_react7 = require("react");
854
- var import_lucide_react3 = require("lucide-react");
1437
+ var import_react16 = require("react");
1438
+ var import_lucide_react4 = require("lucide-react");
855
1439
 
856
1440
  // src/components/syntax-highlighter.tsx
857
- var import_react6 = require("react");
1441
+ var import_react15 = require("react");
858
1442
  var import_core = require("shiki/core");
859
1443
  var import_javascript = require("shiki/engine/javascript");
860
- var import_javascript2 = __toESM(require("shiki/langs/javascript.mjs"), 1);
861
- var import_typescript = __toESM(require("shiki/langs/typescript.mjs"), 1);
862
- var import_python = __toESM(require("shiki/langs/python.mjs"), 1);
863
- var import_html = __toESM(require("shiki/langs/html.mjs"), 1);
864
- var import_css = __toESM(require("shiki/langs/css.mjs"), 1);
865
- var import_json = __toESM(require("shiki/langs/json.mjs"), 1);
866
- var import_bash = __toESM(require("shiki/langs/bash.mjs"), 1);
867
- var import_markdown = __toESM(require("shiki/langs/markdown.mjs"), 1);
868
- var import_jsx = __toESM(require("shiki/langs/jsx.mjs"), 1);
869
- var import_tsx = __toESM(require("shiki/langs/tsx.mjs"), 1);
870
- var import_sql = __toESM(require("shiki/langs/sql.mjs"), 1);
871
- var import_yaml = __toESM(require("shiki/langs/yaml.mjs"), 1);
872
- var import_rust = __toESM(require("shiki/langs/rust.mjs"), 1);
873
- var import_go = __toESM(require("shiki/langs/go.mjs"), 1);
874
- var import_java = __toESM(require("shiki/langs/java.mjs"), 1);
875
- var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
876
- var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
877
- var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
878
- var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
1444
+
1445
+ // src/artifacts/registry.tsx
1446
+ var import_react14 = require("react");
1447
+
1448
+ // src/artifacts/chart-artifact.tsx
1449
+ var import_react6 = require("react");
1450
+
1451
+ // src/artifacts/artifact-card.tsx
879
1452
  var import_jsx_runtime8 = require("react/jsx-runtime");
880
- var SHIKI_THEME_DARK = "vitesse-dark";
881
- var SHIKI_THEME_LIGHT = "vitesse-light";
882
- var highlighterPromise = null;
883
- function getHighlighter() {
884
- if (!highlighterPromise) {
885
- highlighterPromise = (0, import_core.createHighlighterCore)({
886
- themes: [import_vitesse_dark.default, import_vitesse_light.default],
887
- langs: [
888
- import_javascript2.default,
889
- import_typescript.default,
890
- import_python.default,
891
- import_html.default,
892
- import_css.default,
893
- import_json.default,
894
- import_bash.default,
895
- import_markdown.default,
896
- import_jsx.default,
897
- import_tsx.default,
898
- import_sql.default,
899
- import_yaml.default,
900
- import_rust.default,
901
- import_go.default,
902
- import_java.default,
903
- import_c.default,
904
- import_cpp.default
905
- ],
906
- engine: (0, import_javascript.createJavaScriptRegexEngine)()
907
- });
908
- }
909
- return highlighterPromise;
910
- }
911
- getHighlighter();
912
- var ShikiSyntaxHighlighter = ({
913
- components: { Pre, Code: Code2 },
914
- language,
915
- code
1453
+ var ArtifactCard = ({ title, kind, className, bodyClassName, toolbar, children }) => {
1454
+ const hasHeader = Boolean(title || toolbar);
1455
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1456
+ "div",
1457
+ {
1458
+ className: cn(
1459
+ "aui-artifact-root my-3 overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm",
1460
+ className
1461
+ ),
1462
+ "data-artifact-kind": kind,
1463
+ children: [
1464
+ hasHeader && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "aui-artifact-header flex items-center gap-2 border-b border-border/40 bg-muted/30 px-3 py-1.5", children: [
1465
+ title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "aui-artifact-title flex-1 truncate text-xs font-semibold text-foreground/80", children: title }),
1466
+ !title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "flex-1" }),
1467
+ toolbar
1468
+ ] }),
1469
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: cn("aui-artifact-body", bodyClassName), children })
1470
+ ]
1471
+ }
1472
+ );
1473
+ };
1474
+
1475
+ // src/artifacts/chart-artifact.tsx
1476
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1477
+ var ChartArtifactView = ({
1478
+ artifact
916
1479
  }) => {
917
- const [html, setHtml] = (0, import_react6.useState)(null);
918
- (0, import_react6.useEffect)(() => {
1480
+ const { type: _t, chartType = "bar", data = [] } = artifact;
1481
+ const xKey = artifact.xKey ?? inferXKey(data);
1482
+ const dataKeys = (0, import_react6.useMemo)(() => {
1483
+ if (Array.isArray(artifact.dataKey)) return artifact.dataKey;
1484
+ if (typeof artifact.dataKey === "string") return [artifact.dataKey];
1485
+ return inferDataKeys(data, xKey);
1486
+ }, [artifact.dataKey, data, xKey]);
1487
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ArtifactCard, { title: artifact.title, kind: "chart", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "aui-artifact-chart p-3", children: [
1488
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1489
+ ChartSvg,
1490
+ {
1491
+ chartType,
1492
+ data,
1493
+ xKey,
1494
+ dataKeys,
1495
+ unit: artifact.unit
1496
+ }
1497
+ ),
1498
+ dataKeys.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Legend, { dataKeys })
1499
+ ] }) });
1500
+ };
1501
+ var COLORS = [
1502
+ "var(--primary, #6366f1)",
1503
+ "#22c55e",
1504
+ "#f59e0b",
1505
+ "#ef4444",
1506
+ "#06b6d4",
1507
+ "#a855f7"
1508
+ ];
1509
+ var W = 600;
1510
+ var H = 240;
1511
+ var PAD = { top: 12, right: 16, bottom: 28, left: 36 };
1512
+ var ChartSvg = ({ chartType, data, xKey, dataKeys, unit }) => {
1513
+ if (data.length === 0 || dataKeys.length === 0) {
1514
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EmptyState, {});
1515
+ }
1516
+ if (chartType === "pie") {
1517
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PieChart, { data, xKey, dataKey: dataKeys[0] });
1518
+ }
1519
+ const innerW = W - PAD.left - PAD.right;
1520
+ const innerH = H - PAD.top - PAD.bottom;
1521
+ const all = dataKeys.flatMap((k) => data.map((d) => toNum(d[k])));
1522
+ const maxV = Math.max(0, ...all);
1523
+ const minV = Math.min(0, ...all);
1524
+ const range = maxV - minV || 1;
1525
+ const yScale = (v) => PAD.top + innerH - (v - minV) / range * innerH;
1526
+ const xCount = data.length;
1527
+ const xStep = xCount > 1 ? innerW / (xCount - 1) : innerW;
1528
+ const xPos = (i) => chartType === "bar" ? PAD.left + innerW * (i + 0.5) / xCount : PAD.left + i * xStep;
1529
+ const ticks = niceTicks(minV, maxV);
1530
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1531
+ "svg",
1532
+ {
1533
+ viewBox: `0 0 ${W} ${H}`,
1534
+ className: "aui-artifact-chart-svg w-full",
1535
+ role: "img",
1536
+ "aria-label": "Chart",
1537
+ children: [
1538
+ ticks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
1539
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1540
+ "line",
1541
+ {
1542
+ x1: PAD.left,
1543
+ x2: W - PAD.right,
1544
+ y1: yScale(t),
1545
+ y2: yScale(t),
1546
+ stroke: "currentColor",
1547
+ strokeOpacity: 0.08
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1551
+ "text",
1552
+ {
1553
+ x: PAD.left - 6,
1554
+ y: yScale(t),
1555
+ textAnchor: "end",
1556
+ dominantBaseline: "middle",
1557
+ className: "fill-muted-foreground text-[10px]",
1558
+ children: formatTick(t, unit)
1559
+ }
1560
+ )
1561
+ ] }, i)),
1562
+ data.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1563
+ "text",
1564
+ {
1565
+ x: xPos(i),
1566
+ y: H - PAD.bottom + 14,
1567
+ textAnchor: "middle",
1568
+ className: "fill-muted-foreground text-[10px]",
1569
+ children: String(d[xKey] ?? i)
1570
+ },
1571
+ i
1572
+ )),
1573
+ chartType === "bar" && renderBars({ data, dataKeys, xCount, xPos, yScale, minV, innerW }),
1574
+ chartType === "line" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1575
+ Polyline,
1576
+ {
1577
+ data,
1578
+ dataKey: k,
1579
+ xPos,
1580
+ yScale,
1581
+ color: COLORS[ki % COLORS.length]
1582
+ },
1583
+ k
1584
+ )),
1585
+ chartType === "area" && dataKeys.map((k, ki) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1586
+ Area,
1587
+ {
1588
+ data,
1589
+ dataKey: k,
1590
+ xPos,
1591
+ yScale,
1592
+ baseY: yScale(Math.max(0, minV)),
1593
+ color: COLORS[ki % COLORS.length]
1594
+ },
1595
+ k
1596
+ ))
1597
+ ]
1598
+ }
1599
+ );
1600
+ };
1601
+ function renderBars(args) {
1602
+ const { data, dataKeys, xCount, xPos, yScale, minV, innerW } = args;
1603
+ const groupWidth = innerW / xCount * 0.7;
1604
+ const barWidth = groupWidth / dataKeys.length;
1605
+ const baseY = yScale(Math.max(0, minV));
1606
+ return dataKeys.flatMap(
1607
+ (k, ki) => data.map((d, i) => {
1608
+ const v = toNum(d[k]);
1609
+ const y = yScale(v);
1610
+ const x = xPos(i) - groupWidth / 2 + ki * barWidth;
1611
+ const top = Math.min(y, baseY);
1612
+ const height = Math.abs(y - baseY);
1613
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1614
+ "rect",
1615
+ {
1616
+ x,
1617
+ y: top,
1618
+ width: Math.max(1, barWidth - 2),
1619
+ height: Math.max(1, height),
1620
+ rx: 2,
1621
+ fill: COLORS[ki % COLORS.length]
1622
+ },
1623
+ `${k}-${i}`
1624
+ );
1625
+ })
1626
+ );
1627
+ }
1628
+ var Polyline = ({ data, dataKey, xPos, yScale, color }) => {
1629
+ const points = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
1630
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1631
+ "polyline",
1632
+ {
1633
+ points,
1634
+ fill: "none",
1635
+ stroke: color,
1636
+ strokeWidth: 2,
1637
+ strokeLinejoin: "round",
1638
+ strokeLinecap: "round"
1639
+ }
1640
+ );
1641
+ };
1642
+ var Area = ({ data, dataKey, xPos, yScale, baseY, color }) => {
1643
+ if (data.length === 0) return null;
1644
+ const top = data.map((d, i) => `${xPos(i)},${yScale(toNum(d[dataKey]))}`).join(" ");
1645
+ const path = `M ${xPos(0)},${baseY} L ${top} L ${xPos(data.length - 1)},${baseY} Z`;
1646
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1647
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, fillOpacity: 0.18 }),
1648
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Polyline, { data, dataKey, xPos, yScale, color })
1649
+ ] });
1650
+ };
1651
+ var PieChart = ({ data, xKey, dataKey }) => {
1652
+ const cx = W / 2;
1653
+ const cy = H / 2;
1654
+ const r = Math.min(W, H) / 2 - 16;
1655
+ const total = data.reduce((sum, d) => sum + toNum(d[dataKey]), 0) || 1;
1656
+ let acc = 0;
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1658
+ "svg",
1659
+ {
1660
+ viewBox: `0 0 ${W} ${H}`,
1661
+ className: "aui-artifact-chart-svg w-full",
1662
+ role: "img",
1663
+ "aria-label": "Pie chart",
1664
+ children: data.map((d, i) => {
1665
+ const value = toNum(d[dataKey]);
1666
+ const start = acc / total * Math.PI * 2;
1667
+ acc += value;
1668
+ const end = acc / total * Math.PI * 2;
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1670
+ PieSlice,
1671
+ {
1672
+ cx,
1673
+ cy,
1674
+ r,
1675
+ start,
1676
+ end,
1677
+ color: COLORS[i % COLORS.length],
1678
+ label: String(d[xKey] ?? i)
1679
+ },
1680
+ i
1681
+ );
1682
+ })
1683
+ }
1684
+ );
1685
+ };
1686
+ var PieSlice = ({ cx, cy, r, start, end, color, label }) => {
1687
+ const x1 = cx + Math.sin(start) * r;
1688
+ const y1 = cy - Math.cos(start) * r;
1689
+ const x2 = cx + Math.sin(end) * r;
1690
+ const y2 = cy - Math.cos(end) * r;
1691
+ const large = end - start > Math.PI ? 1 : 0;
1692
+ const path = `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`;
1693
+ const mid = (start + end) / 2;
1694
+ const lx = cx + Math.sin(mid) * (r * 0.65);
1695
+ const ly = cy - Math.cos(mid) * (r * 0.65);
1696
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("g", { children: [
1697
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: path, fill: color, stroke: "var(--background, #fff)", strokeWidth: 1 }),
1698
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1699
+ "text",
1700
+ {
1701
+ x: lx,
1702
+ y: ly,
1703
+ textAnchor: "middle",
1704
+ dominantBaseline: "middle",
1705
+ className: "fill-white text-[10px] font-semibold",
1706
+ children: label
1707
+ }
1708
+ )
1709
+ ] });
1710
+ };
1711
+ var Legend = ({ dataKeys }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "aui-artifact-chart-legend mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: dataKeys.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1713
+ "span",
1714
+ {
1715
+ className: "inline-block size-2 rounded-sm",
1716
+ style: { background: COLORS[i % COLORS.length] },
1717
+ "aria-hidden": true
1718
+ }
1719
+ ),
1720
+ k
1721
+ ] }, k)) });
1722
+ var EmptyState = () => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "aui-artifact-chart-empty flex h-32 items-center justify-center text-xs text-muted-foreground", children: "No data" });
1723
+ function inferXKey(data) {
1724
+ if (data.length === 0) return "x";
1725
+ for (const k of Object.keys(data[0])) {
1726
+ if (typeof data[0][k] !== "number") return k;
1727
+ }
1728
+ return Object.keys(data[0])[0] ?? "x";
1729
+ }
1730
+ function inferDataKeys(data, xKey) {
1731
+ if (data.length === 0) return [];
1732
+ return Object.keys(data[0]).filter(
1733
+ (k) => k !== xKey && typeof data[0][k] === "number"
1734
+ );
1735
+ }
1736
+ function toNum(value) {
1737
+ const n = typeof value === "number" ? value : Number(value);
1738
+ return Number.isFinite(n) ? n : 0;
1739
+ }
1740
+ function niceTicks(min, max, count = 4) {
1741
+ if (max === min) return [min];
1742
+ const range = max - min;
1743
+ const step = niceStep(range / count);
1744
+ const start = Math.floor(min / step) * step;
1745
+ const out = [];
1746
+ for (let v = start; v <= max + step / 2; v += step) {
1747
+ out.push(round(v));
1748
+ }
1749
+ return out;
1750
+ }
1751
+ function niceStep(raw) {
1752
+ const exp = Math.floor(Math.log10(Math.abs(raw))) || 0;
1753
+ const base = Math.pow(10, exp);
1754
+ const norm = raw / base;
1755
+ let nice = 1;
1756
+ if (norm >= 5) nice = 5;
1757
+ else if (norm >= 2) nice = 2;
1758
+ return nice * base;
1759
+ }
1760
+ function round(v) {
1761
+ return Math.round(v * 1e6) / 1e6;
1762
+ }
1763
+ function formatTick(v, unit) {
1764
+ const s = Math.abs(v) >= 1e3 ? `${(v / 1e3).toFixed(1)}k` : String(round(v));
1765
+ return unit ? `${s}${unit}` : s;
1766
+ }
1767
+
1768
+ // src/artifacts/question-artifact.tsx
1769
+ var import_react7 = require("react");
1770
+ var import_react8 = require("@assistant-ui/react");
1771
+ var import_lucide_react3 = require("lucide-react");
1772
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1773
+ var QuestionArtifactView = ({
1774
+ artifact
1775
+ }) => {
1776
+ const runtime = (0, import_react8.useThreadRuntime)();
1777
+ const [selected, setSelected] = (0, import_react7.useState)([]);
1778
+ const [submitted, setSubmitted] = (0, import_react7.useState)(null);
1779
+ const isMulti = artifact.multi === true;
1780
+ const send = (labels) => {
1781
+ if (labels.length === 0) return;
1782
+ const text = labels.join(", ");
1783
+ setSubmitted(text);
1784
+ runtime.append({ role: "user", content: [{ type: "text", text }] });
1785
+ };
1786
+ const onPick = (option) => {
1787
+ if (submitted) return;
1788
+ if (!isMulti) {
1789
+ send([option.label]);
1790
+ return;
1791
+ }
1792
+ setSelected(
1793
+ (prev) => prev.includes(option.id) ? prev.filter((id) => id !== option.id) : [...prev, option.id]
1794
+ );
1795
+ };
1796
+ const onConfirm = () => {
1797
+ const labels = artifact.options.filter((o) => selected.includes(o.id)).map((o) => o.label);
1798
+ send(labels);
1799
+ };
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArtifactCard, { kind: "question", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question p-3", children: [
1801
+ artifact.prompt && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "aui-artifact-question-prompt mb-2 text-sm text-foreground/85", children: artifact.prompt }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "aui-artifact-question-options flex flex-col gap-1.5", children: artifact.options.map((option) => {
1803
+ const isSelected = isMulti && selected.includes(option.id);
1804
+ const isDisabled = Boolean(submitted);
1805
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1806
+ "button",
1807
+ {
1808
+ type: "button",
1809
+ disabled: isDisabled,
1810
+ onClick: () => onPick(option),
1811
+ className: cn(
1812
+ "aui-artifact-question-option flex items-center gap-2 rounded-lg border px-3 py-2 text-left text-sm transition-colors",
1813
+ "border-border/60 hover:border-primary/40 hover:bg-muted/40",
1814
+ isSelected && "border-primary/60 bg-primary/5",
1815
+ isDisabled && "cursor-not-allowed opacity-60 hover:border-border/60 hover:bg-transparent"
1816
+ ),
1817
+ children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1819
+ "span",
1820
+ {
1821
+ className: cn(
1822
+ "flex size-4 shrink-0 items-center justify-center rounded-full border",
1823
+ isSelected ? "border-primary bg-primary text-primary-foreground" : "border-border"
1824
+ ),
1825
+ "aria-hidden": true,
1826
+ children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.CheckIcon, { className: "size-3" })
1827
+ }
1828
+ ),
1829
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "aui-artifact-question-option-text flex-1", children: [
1830
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium text-foreground/90", children: option.label }),
1831
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs text-muted-foreground", children: option.description })
1832
+ ] })
1833
+ ]
1834
+ },
1835
+ option.id
1836
+ );
1837
+ }) }),
1838
+ isMulti && !submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1839
+ Button,
1840
+ {
1841
+ type: "button",
1842
+ size: "sm",
1843
+ disabled: selected.length === 0,
1844
+ onClick: onConfirm,
1845
+ children: "Confirm"
1846
+ }
1847
+ ) }),
1848
+ submitted && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "aui-artifact-question-submitted mt-2 text-xs text-muted-foreground", children: [
1849
+ "Sent: ",
1850
+ submitted
1851
+ ] })
1852
+ ] }) });
1853
+ };
1854
+
1855
+ // src/artifacts/html-artifact.tsx
1856
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1857
+ var HtmlArtifactView = ({ artifact }) => {
1858
+ const sandboxed = artifact.sandboxed !== false;
1859
+ const sandbox = sandboxed ? "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-pointer-lock" : void 0;
1860
+ const height = artifact.height ?? "320px";
1861
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ArtifactCard, { title: artifact.title, kind: "html", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1862
+ "iframe",
1863
+ {
1864
+ title: artifact.title ?? "HTML artifact",
1865
+ srcDoc: artifact.content,
1866
+ sandbox,
1867
+ className: "aui-artifact-html w-full border-0 bg-background",
1868
+ style: { height }
1869
+ }
1870
+ ) });
1871
+ };
1872
+
1873
+ // src/artifacts/json-artifact.tsx
1874
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1875
+ var JsonArtifactView = ({
1876
+ artifact
1877
+ }) => {
1878
+ const data = "data" in artifact ? artifact.data : artifact;
1879
+ const title = artifact.title;
1880
+ let body;
1881
+ try {
1882
+ body = JSON.stringify(data, null, 2);
1883
+ } catch {
1884
+ body = String(data);
1885
+ }
1886
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ArtifactCard, { title, kind: "json", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { className: "aui-artifact-json m-0 max-h-[420px] overflow-auto p-3 font-mono text-[12px] leading-relaxed text-foreground/85", children: body }) });
1887
+ };
1888
+
1889
+ // src/artifacts/table-artifact.tsx
1890
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1891
+ var TableArtifactView = ({ artifact }) => {
1892
+ const rows = artifact.rows ?? [];
1893
+ const columns = artifact.columns ?? deriveColumns(rows);
1894
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ArtifactCard, { title: artifact.title, kind: "table", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "aui-artifact-table-wrap overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "aui-artifact-table w-full border-collapse text-sm", children: [
1895
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { className: "border-b border-border/40 bg-muted/20", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1896
+ "th",
1897
+ {
1898
+ className: "px-3 py-2 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground",
1899
+ children: col.label ?? col.key
1900
+ },
1901
+ col.key
1902
+ )) }) }),
1903
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1904
+ "tr",
1905
+ {
1906
+ className: "border-b border-border/30 transition-colors last:border-b-0 hover:bg-muted/20",
1907
+ children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1908
+ "td",
1909
+ {
1910
+ className: "px-3 py-2 align-top text-foreground/85",
1911
+ children: formatCell(row[col.key])
1912
+ },
1913
+ col.key
1914
+ ))
1915
+ },
1916
+ i
1917
+ )) })
1918
+ ] }) }) });
1919
+ };
1920
+ function deriveColumns(rows) {
1921
+ const seen = /* @__PURE__ */ new Set();
1922
+ const cols = [];
1923
+ for (const row of rows) {
1924
+ for (const key of Object.keys(row)) {
1925
+ if (!seen.has(key)) {
1926
+ seen.add(key);
1927
+ cols.push({ key });
1928
+ }
1929
+ }
1930
+ }
1931
+ return cols;
1932
+ }
1933
+ function formatCell(value) {
1934
+ if (value === null || value === void 0) return "";
1935
+ if (typeof value === "object") return JSON.stringify(value);
1936
+ return String(value);
1937
+ }
1938
+
1939
+ // src/artifacts/ui/ui-artifact.tsx
1940
+ var import_react13 = require("react");
1941
+
1942
+ // src/artifacts/ui/types.ts
1943
+ function isUiBinding(value) {
1944
+ return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.$bind === "string";
1945
+ }
1946
+
1947
+ // src/artifacts/ui/state.ts
1948
+ function uiStateReducer(state, action) {
1949
+ switch (action.type) {
1950
+ case "set":
1951
+ return setPath(state, action.path, action.value);
1952
+ case "toggle": {
1953
+ const current = getPath(state, action.path);
1954
+ return setPath(state, action.path, !current);
1955
+ }
1956
+ case "replace":
1957
+ return action.state;
1958
+ }
1959
+ }
1960
+ function getPath(state, path) {
1961
+ if (!path) return void 0;
1962
+ const parts = path.split(".");
1963
+ let cursor = state;
1964
+ for (const part of parts) {
1965
+ if (typeof cursor !== "object" || cursor === null) return void 0;
1966
+ cursor = cursor[part];
1967
+ }
1968
+ return cursor;
1969
+ }
1970
+ function setPath(state, path, value) {
1971
+ if (!path) return state;
1972
+ const parts = path.split(".");
1973
+ const next = { ...state };
1974
+ let cursor = next;
1975
+ for (let i = 0; i < parts.length - 1; i++) {
1976
+ const key = parts[i];
1977
+ const child = cursor[key];
1978
+ const cloned = typeof child === "object" && child !== null && !Array.isArray(child) ? { ...child } : {};
1979
+ cursor[key] = cloned;
1980
+ cursor = cloned;
1981
+ }
1982
+ cursor[parts[parts.length - 1]] = value;
1983
+ return next;
1984
+ }
1985
+ function resolveBindable(value, state) {
1986
+ if (isUiBinding(value)) {
1987
+ return getPath(state, value.$bind);
1988
+ }
1989
+ return value;
1990
+ }
1991
+
1992
+ // src/artifacts/ui/registry.tsx
1993
+ var import_react9 = require("react");
1994
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1995
+ var UiStateContext = (0, import_react9.createContext)({});
1996
+ var UiDispatchContext = (0, import_react9.createContext)(() => {
1997
+ });
1998
+ var UiStateProvider = ({ state, dispatch, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiStateContext.Provider, { value: state, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiDispatchContext.Provider, { value: dispatch, children }) });
1999
+ function useUiState() {
2000
+ return (0, import_react9.useContext)(UiStateContext);
2001
+ }
2002
+ function useUiDispatch() {
2003
+ return (0, import_react9.useContext)(UiDispatchContext);
2004
+ }
2005
+ var UiEventContext = (0, import_react9.createContext)(
2006
+ null
2007
+ );
2008
+ var UiEventProvider = ({ onEvent, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiEventContext.Provider, { value: onEvent, children });
2009
+ function useUiEventEmitter() {
2010
+ return (0, import_react9.useContext)(UiEventContext);
2011
+ }
2012
+ var UiCustomNodeRegistryContext = (0, import_react9.createContext)({});
2013
+ var UiCustomNodeRegistryProvider = ({ renderers, children }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UiCustomNodeRegistryContext.Provider, { value: renderers, children });
2014
+ function useUiCustomNodeRegistry() {
2015
+ return (0, import_react9.useContext)(UiCustomNodeRegistryContext);
2016
+ }
2017
+
2018
+ // src/artifacts/ui/nodes.tsx
2019
+ var import_react10 = require("react");
2020
+ var import_react11 = require("motion/react");
2021
+ var import_react12 = require("@assistant-ui/react");
2022
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2023
+ var UiNodeView = ({ node }) => {
2024
+ switch (node.kind) {
2025
+ case "box":
2026
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BoxNode, { node });
2027
+ case "text":
2028
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TextNode, { node });
2029
+ case "heading":
2030
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(HeadingNode, { node });
2031
+ case "badge":
2032
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BadgeNode, { node });
2033
+ case "button":
2034
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ButtonNode, { node });
2035
+ case "toggle":
2036
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ToggleNode, { node });
2037
+ case "slider":
2038
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SliderNode, { node });
2039
+ case "tooltip":
2040
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipNode, { node });
2041
+ case "draggable":
2042
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DraggableNode, { node });
2043
+ case "custom":
2044
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CustomNode, { node });
2045
+ default:
2046
+ return null;
2047
+ }
2048
+ };
2049
+ function useActionRunner() {
2050
+ const state = useUiState();
2051
+ const dispatch = useUiDispatch();
2052
+ const runtime = (0, import_react12.useThreadRuntime)();
2053
+ const emit = useUiEventEmitter();
2054
+ return (0, import_react10.useCallback)(
2055
+ (actions) => {
2056
+ if (!actions) return;
2057
+ const list = Array.isArray(actions) ? actions : [actions];
2058
+ for (const action of list) {
2059
+ switch (action.kind) {
2060
+ case "message": {
2061
+ const text = resolveBindable(action.text, state);
2062
+ if (typeof text === "string" && text.length > 0) {
2063
+ runtime?.append({
2064
+ role: "user",
2065
+ content: [{ type: "text", text }]
2066
+ });
2067
+ }
2068
+ break;
2069
+ }
2070
+ case "set": {
2071
+ const value = resolveBindable(action.value, state);
2072
+ dispatch({ type: "set", path: action.path, value });
2073
+ break;
2074
+ }
2075
+ case "toggle": {
2076
+ dispatch({ type: "toggle", path: action.path });
2077
+ break;
2078
+ }
2079
+ case "emit": {
2080
+ emit?.({ name: action.name, payload: action.payload });
2081
+ break;
2082
+ }
2083
+ }
2084
+ }
2085
+ },
2086
+ [state, dispatch, runtime, emit]
2087
+ );
2088
+ }
2089
+ var ALIGN_CLS = {
2090
+ start: "items-start",
2091
+ center: "items-center",
2092
+ end: "items-end",
2093
+ stretch: "items-stretch"
2094
+ };
2095
+ var JUSTIFY_CLS = {
2096
+ start: "justify-start",
2097
+ center: "justify-center",
2098
+ end: "justify-end",
2099
+ between: "justify-between",
2100
+ around: "justify-around"
2101
+ };
2102
+ var BoxNode = ({ node }) => {
2103
+ const dir = node.direction ?? "col";
2104
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2105
+ "div",
2106
+ {
2107
+ className: cn(
2108
+ "aui-ui-box flex",
2109
+ dir === "col" ? "flex-col" : "flex-row",
2110
+ node.wrap && "flex-wrap",
2111
+ node.align && ALIGN_CLS[node.align],
2112
+ node.justify && JUSTIFY_CLS[node.justify],
2113
+ node.className
2114
+ ),
2115
+ style: {
2116
+ gap: node.gap !== void 0 ? `${node.gap * 0.25}rem` : void 0,
2117
+ padding: node.padding !== void 0 ? `${node.padding * 0.25}rem` : void 0
2118
+ },
2119
+ children: node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i))
2120
+ }
2121
+ );
2122
+ };
2123
+ var TEXT_SIZE = {
2124
+ xs: "text-xs",
2125
+ sm: "text-sm",
2126
+ base: "text-base",
2127
+ lg: "text-lg"
2128
+ };
2129
+ var TEXT_WEIGHT = {
2130
+ normal: "font-normal",
2131
+ medium: "font-medium",
2132
+ semibold: "font-semibold",
2133
+ bold: "font-bold"
2134
+ };
2135
+ var TextNode = ({ node }) => {
2136
+ const state = useUiState();
2137
+ const value = resolveBindable(node.value, state);
2138
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2139
+ "span",
2140
+ {
2141
+ className: cn(
2142
+ "aui-ui-text",
2143
+ node.muted && "text-muted-foreground",
2144
+ node.size && TEXT_SIZE[node.size],
2145
+ node.weight && TEXT_WEIGHT[node.weight],
2146
+ node.className
2147
+ ),
2148
+ children: value === void 0 || value === null ? "" : String(value)
2149
+ }
2150
+ );
2151
+ };
2152
+ var HEADING_CLS = {
2153
+ 1: "text-2xl",
2154
+ 2: "text-xl",
2155
+ 3: "text-lg",
2156
+ 4: "text-base"
2157
+ };
2158
+ var HeadingNode = ({ node }) => {
2159
+ const state = useUiState();
2160
+ const value = String(resolveBindable(node.value, state) ?? "");
2161
+ const level = node.level ?? 2;
2162
+ const cls = cn(
2163
+ "aui-ui-heading font-semibold text-foreground",
2164
+ HEADING_CLS[level],
2165
+ node.className
2166
+ );
2167
+ switch (level) {
2168
+ case 1:
2169
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h1", { className: cls, children: value });
2170
+ case 2:
2171
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: cls, children: value });
2172
+ case 3:
2173
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: cls, children: value });
2174
+ case 4:
2175
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h4", { className: cls, children: value });
2176
+ }
2177
+ };
2178
+ var BADGE_TONE = {
2179
+ default: "bg-muted text-foreground",
2180
+ primary: "bg-primary/10 text-primary",
2181
+ success: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
2182
+ warn: "bg-amber-500/10 text-amber-600 dark:text-amber-400",
2183
+ danger: "bg-destructive/10 text-destructive"
2184
+ };
2185
+ var BadgeNode = ({ node }) => {
2186
+ const state = useUiState();
2187
+ const value = String(resolveBindable(node.value, state) ?? "");
2188
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2189
+ "span",
2190
+ {
2191
+ className: cn(
2192
+ "aui-ui-badge inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
2193
+ BADGE_TONE[node.tone ?? "default"],
2194
+ node.className
2195
+ ),
2196
+ children: value
2197
+ }
2198
+ );
2199
+ };
2200
+ var ButtonNode = ({ node }) => {
2201
+ const state = useUiState();
2202
+ const run = useActionRunner();
2203
+ const label = String(resolveBindable(node.label, state) ?? "");
2204
+ const disabled = node.disabled !== void 0 ? Boolean(resolveBindable(node.disabled, state)) : false;
2205
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2206
+ Button,
2207
+ {
2208
+ variant: node.variant ?? "default",
2209
+ size: node.size ?? "default",
2210
+ disabled,
2211
+ className: node.className,
2212
+ onClick: () => run(node.onClick),
2213
+ children: label
2214
+ }
2215
+ );
2216
+ };
2217
+ var ToggleNode = ({ node }) => {
2218
+ const state = useUiState();
2219
+ const dispatch = useUiDispatch();
2220
+ const run = useActionRunner();
2221
+ const value = Boolean(getPath(state, node.binding));
2222
+ const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
2223
+ const onToggle = () => {
2224
+ dispatch({ type: "toggle", path: node.binding });
2225
+ run(node.onChange);
2226
+ };
2227
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2228
+ "label",
2229
+ {
2230
+ className: cn(
2231
+ "aui-ui-toggle inline-flex cursor-pointer items-center gap-2 text-sm select-none",
2232
+ node.className
2233
+ ),
2234
+ children: [
2235
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2236
+ "button",
2237
+ {
2238
+ type: "button",
2239
+ role: "switch",
2240
+ "aria-checked": value,
2241
+ onClick: onToggle,
2242
+ className: cn(
2243
+ "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border transition-colors",
2244
+ value ? "border-primary bg-primary" : "border-border bg-muted hover:bg-muted/80"
2245
+ ),
2246
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2247
+ "span",
2248
+ {
2249
+ className: cn(
2250
+ "inline-block size-4 transform rounded-full bg-background shadow transition-transform",
2251
+ value ? "translate-x-4" : "translate-x-0.5"
2252
+ ),
2253
+ "aria-hidden": true
2254
+ }
2255
+ )
2256
+ }
2257
+ ),
2258
+ label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-foreground/85", children: label })
2259
+ ]
2260
+ }
2261
+ );
2262
+ };
2263
+ var SliderNode = ({ node }) => {
2264
+ const state = useUiState();
2265
+ const dispatch = useUiDispatch();
2266
+ const run = useActionRunner();
2267
+ const min = node.min ?? 0;
2268
+ const max = node.max ?? 100;
2269
+ const step = node.step ?? 1;
2270
+ const raw = getPath(state, node.binding);
2271
+ const value = typeof raw === "number" ? raw : min;
2272
+ const showValue = node.showValue ?? true;
2273
+ const label = node.label ? String(resolveBindable(node.label, state) ?? "") : null;
2274
+ const onChange = (e) => {
2275
+ const next = Number(e.target.value);
2276
+ dispatch({ type: "set", path: node.binding, value: next });
2277
+ };
2278
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("aui-ui-slider flex flex-col gap-1", node.className), children: [
2279
+ (label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
2280
+ label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
2281
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: value })
2282
+ ] }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2284
+ "input",
2285
+ {
2286
+ type: "range",
2287
+ min,
2288
+ max,
2289
+ step,
2290
+ value,
2291
+ onChange,
2292
+ onMouseUp: () => run(node.onChange),
2293
+ onKeyUp: (e) => {
2294
+ if (e.key === "Enter" || e.key === " ") run(node.onChange);
2295
+ },
2296
+ onTouchEnd: () => run(node.onChange),
2297
+ className: "aui-ui-slider-input h-1.5 w-full cursor-pointer appearance-none rounded-full bg-muted accent-primary"
2298
+ }
2299
+ )
2300
+ ] });
2301
+ };
2302
+ var TooltipNode = ({ node }) => {
2303
+ const state = useUiState();
2304
+ const content = String(resolveBindable(node.content, state) ?? "");
2305
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tooltip, { children: [
2306
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: cn("aui-ui-tooltip-trigger inline-flex", node.className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child }) }) }),
2307
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContent, { side: node.side ?? "top", children: content })
2308
+ ] }) });
2309
+ };
2310
+ var DraggableNode = ({ node }) => {
2311
+ const run = useActionRunner();
2312
+ const snapBack = node.snapBack ?? true;
2313
+ const axis = node.axis ?? "both";
2314
+ const dragProp = axis === "both" ? true : axis;
2315
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2316
+ import_react11.motion.div,
2317
+ {
2318
+ drag: dragProp,
2319
+ dragMomentum: false,
2320
+ dragSnapToOrigin: snapBack,
2321
+ whileDrag: { scale: 1.02, cursor: "grabbing" },
2322
+ onDragEnd: () => run(node.onDragEnd),
2323
+ className: cn(
2324
+ "aui-ui-draggable inline-block cursor-grab touch-none",
2325
+ node.className
2326
+ ),
2327
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: node.child })
2328
+ }
2329
+ );
2330
+ };
2331
+ var CustomNode = ({ node }) => {
2332
+ const state = useUiState();
2333
+ const registry = useUiCustomNodeRegistry();
2334
+ const Renderer = registry[node.name];
2335
+ if (!Renderer) return null;
2336
+ const resolvedProps = resolveProps(node.props ?? {}, state);
2337
+ const children = node.children?.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UiNodeView, { node: child }, child.id ?? i));
2338
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Renderer, { props: resolvedProps, children });
2339
+ };
2340
+ function resolveProps(props, state) {
2341
+ const out = {};
2342
+ for (const [k, v] of Object.entries(props)) {
2343
+ out[k] = resolveBindable(v, state);
2344
+ }
2345
+ return out;
2346
+ }
2347
+
2348
+ // src/artifacts/ui/ui-artifact.tsx
2349
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2350
+ var UiArtifactView = ({ artifact }) => {
2351
+ const [state, dispatch] = (0, import_react13.useReducer)(
2352
+ uiStateReducer,
2353
+ artifact.initialState ?? {}
2354
+ );
2355
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ArtifactCard, { title: artifact.title, kind: "ui", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiStateProvider, { state, dispatch, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "aui-ui-root p-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UiNodeView, { node: artifact.root }) }) }) });
2356
+ };
2357
+
2358
+ // src/artifacts/registry.tsx
2359
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2360
+ var defaultArtifactRenderers = {
2361
+ chart: ChartArtifactView,
2362
+ question: QuestionArtifactView,
2363
+ html: HtmlArtifactView,
2364
+ json: JsonArtifactView,
2365
+ table: TableArtifactView,
2366
+ ui: UiArtifactView
2367
+ };
2368
+ var ArtifactRegistryContext = (0, import_react14.createContext)(
2369
+ defaultArtifactRenderers
2370
+ );
2371
+ var ArtifactRegistryProvider = ({ renderers, override, children }) => {
2372
+ const merged = (0, import_react14.useMemo)(() => {
2373
+ if (!renderers) return defaultArtifactRenderers;
2374
+ if (override) return renderers;
2375
+ return { ...defaultArtifactRenderers, ...renderers };
2376
+ }, [renderers, override]);
2377
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ArtifactRegistryContext.Provider, { value: merged, children });
2378
+ };
2379
+ function useArtifactRegistry() {
2380
+ return (0, import_react14.useContext)(ArtifactRegistryContext);
2381
+ }
2382
+ var ArtifactView = ({ artifact }) => {
2383
+ const registry = useArtifactRegistry();
2384
+ const Renderer = registry[artifact.type] ?? registry.json;
2385
+ if (!Renderer) return null;
2386
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Renderer, { artifact });
2387
+ };
2388
+
2389
+ // src/artifacts/parse.ts
2390
+ var ARTIFACT_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
2391
+ "timbal-artifact",
2392
+ "timbal"
2393
+ ]);
2394
+ function isArtifactFenceLanguage(language) {
2395
+ return typeof language === "string" && ARTIFACT_FENCE_LANGUAGES.has(language);
2396
+ }
2397
+ function tryParseStructuredText(text) {
2398
+ const trimmed = text.trim();
2399
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
2400
+ try {
2401
+ return JSON.parse(trimmed);
2402
+ } catch {
2403
+ }
2404
+ try {
2405
+ const asJson = trimmed.replace(/\bTrue\b/g, "true").replace(/\bFalse\b/g, "false").replace(/\bNone\b/g, "null").replace(/'/g, '"');
2406
+ return JSON.parse(asJson);
2407
+ } catch {
2408
+ return null;
2409
+ }
2410
+ }
2411
+ function parseArtifactFromToolResult(result) {
2412
+ if (result === void 0 || result === null) return null;
2413
+ if (typeof result === "string") {
2414
+ const parsed = tryParseStructuredText(result);
2415
+ if (parsed === null) return null;
2416
+ return parseArtifactFromToolResult(parsed);
2417
+ }
2418
+ if (Array.isArray(result)) {
2419
+ for (const item of result) {
2420
+ if (typeof item === "object" && item !== null && "text" in item) {
2421
+ const text = item.text;
2422
+ if (typeof text === "string") {
2423
+ const fromText = parseArtifactFromToolResult(text);
2424
+ if (fromText) return fromText;
2425
+ }
2426
+ }
2427
+ }
2428
+ return null;
2429
+ }
2430
+ if (typeof result === "object") {
2431
+ const obj = result;
2432
+ if (obj.type === "text" && typeof obj.text === "string") {
2433
+ return parseArtifactFromToolResult(obj.text);
2434
+ }
2435
+ if (obj.type === "thinking" && typeof obj.thinking === "string") {
2436
+ return parseArtifactFromToolResult(obj.thinking);
2437
+ }
2438
+ }
2439
+ return isArtifact(result) ? result : null;
2440
+ }
2441
+ var FENCE_RE = /```(?:timbal-artifact|timbal)\s*\n([\s\S]*?)\n```/g;
2442
+ function findMarkdownArtifacts(markdown) {
2443
+ const matches = [];
2444
+ FENCE_RE.lastIndex = 0;
2445
+ let m;
2446
+ while ((m = FENCE_RE.exec(markdown)) !== null) {
2447
+ const raw = m[0];
2448
+ const body = m[1];
2449
+ try {
2450
+ const parsed = JSON.parse(body);
2451
+ if (isArtifact(parsed)) {
2452
+ matches.push({
2453
+ artifact: parsed,
2454
+ raw,
2455
+ start: m.index,
2456
+ end: m.index + raw.length
2457
+ });
2458
+ }
2459
+ } catch {
2460
+ }
2461
+ }
2462
+ return matches;
2463
+ }
2464
+ function splitMarkdownByArtifacts(markdown) {
2465
+ const matches = findMarkdownArtifacts(markdown);
2466
+ if (matches.length === 0) return [{ kind: "text", text: markdown }];
2467
+ const segments = [];
2468
+ let cursor = 0;
2469
+ for (const match of matches) {
2470
+ if (match.start > cursor) {
2471
+ segments.push({ kind: "text", text: markdown.slice(cursor, match.start) });
2472
+ }
2473
+ segments.push({ kind: "artifact", artifact: match.artifact });
2474
+ cursor = match.end;
2475
+ }
2476
+ if (cursor < markdown.length) {
2477
+ segments.push({ kind: "text", text: markdown.slice(cursor) });
2478
+ }
2479
+ return segments;
2480
+ }
2481
+
2482
+ // src/components/syntax-highlighter.tsx
2483
+ var import_javascript2 = __toESM(require("shiki/langs/javascript.mjs"), 1);
2484
+ var import_typescript = __toESM(require("shiki/langs/typescript.mjs"), 1);
2485
+ var import_python = __toESM(require("shiki/langs/python.mjs"), 1);
2486
+ var import_html = __toESM(require("shiki/langs/html.mjs"), 1);
2487
+ var import_css = __toESM(require("shiki/langs/css.mjs"), 1);
2488
+ var import_json = __toESM(require("shiki/langs/json.mjs"), 1);
2489
+ var import_bash = __toESM(require("shiki/langs/bash.mjs"), 1);
2490
+ var import_markdown = __toESM(require("shiki/langs/markdown.mjs"), 1);
2491
+ var import_jsx = __toESM(require("shiki/langs/jsx.mjs"), 1);
2492
+ var import_tsx = __toESM(require("shiki/langs/tsx.mjs"), 1);
2493
+ var import_sql = __toESM(require("shiki/langs/sql.mjs"), 1);
2494
+ var import_yaml = __toESM(require("shiki/langs/yaml.mjs"), 1);
2495
+ var import_rust = __toESM(require("shiki/langs/rust.mjs"), 1);
2496
+ var import_go = __toESM(require("shiki/langs/go.mjs"), 1);
2497
+ var import_java = __toESM(require("shiki/langs/java.mjs"), 1);
2498
+ var import_c = __toESM(require("shiki/langs/c.mjs"), 1);
2499
+ var import_cpp = __toESM(require("shiki/langs/cpp.mjs"), 1);
2500
+ var import_vitesse_dark = __toESM(require("shiki/themes/vitesse-dark.mjs"), 1);
2501
+ var import_vitesse_light = __toESM(require("shiki/themes/vitesse-light.mjs"), 1);
2502
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2503
+ var SHIKI_THEME_DARK = "vitesse-dark";
2504
+ var SHIKI_THEME_LIGHT = "vitesse-light";
2505
+ var highlighterPromise = null;
2506
+ function getHighlighter() {
2507
+ if (!highlighterPromise) {
2508
+ highlighterPromise = (0, import_core.createHighlighterCore)({
2509
+ themes: [import_vitesse_dark.default, import_vitesse_light.default],
2510
+ langs: [
2511
+ import_javascript2.default,
2512
+ import_typescript.default,
2513
+ import_python.default,
2514
+ import_html.default,
2515
+ import_css.default,
2516
+ import_json.default,
2517
+ import_bash.default,
2518
+ import_markdown.default,
2519
+ import_jsx.default,
2520
+ import_tsx.default,
2521
+ import_sql.default,
2522
+ import_yaml.default,
2523
+ import_rust.default,
2524
+ import_go.default,
2525
+ import_java.default,
2526
+ import_c.default,
2527
+ import_cpp.default
2528
+ ],
2529
+ engine: (0, import_javascript.createJavaScriptRegexEngine)()
2530
+ });
2531
+ }
2532
+ return highlighterPromise;
2533
+ }
2534
+ getHighlighter();
2535
+ var ShikiSyntaxHighlighter = ({
2536
+ components: { Pre, Code: Code2 },
2537
+ language,
2538
+ code
2539
+ }) => {
2540
+ const [html, setHtml] = (0, import_react15.useState)(null);
2541
+ (0, import_react15.useEffect)(() => {
919
2542
  let cancelled = false;
920
2543
  (async () => {
921
2544
  try {
@@ -941,8 +2564,17 @@ var ShikiSyntaxHighlighter = ({
941
2564
  cancelled = true;
942
2565
  };
943
2566
  }, [code, language]);
2567
+ if (isArtifactFenceLanguage(language)) {
2568
+ try {
2569
+ const parsed = JSON.parse(code);
2570
+ if (isArtifact(parsed)) {
2571
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ArtifactView, { artifact: parsed });
2572
+ }
2573
+ } catch {
2574
+ }
2575
+ }
944
2576
  if (html) {
945
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2577
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
946
2578
  "div",
947
2579
  {
948
2580
  className: "shiki-wrapper [&>pre]:!m-0 [&>pre]:!rounded-t-none [&>pre]:!rounded-b-lg [&>pre]:!border [&>pre]:!border-t-0 [&>pre]:!border-border/50 [&>pre]:!p-3 [&>pre]:!text-xs [&>pre]:!leading-relaxed [&>pre]:overflow-x-auto",
@@ -950,14 +2582,14 @@ var ShikiSyntaxHighlighter = ({
950
2582
  }
951
2583
  );
952
2584
  }
953
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Code2, { children: code }) });
2585
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pre, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Code2, { children: code }) });
954
2586
  };
955
2587
  var syntax_highlighter_default = ShikiSyntaxHighlighter;
956
2588
 
957
2589
  // src/components/markdown-text.tsx
958
- var import_jsx_runtime9 = require("react/jsx-runtime");
2590
+ var import_jsx_runtime19 = require("react/jsx-runtime");
959
2591
  var MarkdownTextImpl = () => {
960
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2592
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
961
2593
  import_react_markdown.MarkdownTextPrimitive,
962
2594
  {
963
2595
  remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
@@ -970,27 +2602,28 @@ var MarkdownTextImpl = () => {
970
2602
  }
971
2603
  );
972
2604
  };
973
- var MarkdownText = (0, import_react7.memo)(MarkdownTextImpl);
2605
+ var MarkdownText = (0, import_react16.memo)(MarkdownTextImpl);
974
2606
  var CodeHeader = ({ language, code }) => {
975
2607
  const { isCopied, copyToClipboard } = useCopyToClipboard();
2608
+ if (isArtifactFenceLanguage(language)) return null;
976
2609
  const onCopy = () => {
977
2610
  if (!code || isCopied) return;
978
2611
  copyToClipboard(code);
979
2612
  };
980
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-zinc-100 px-4 py-2 dark:bg-zinc-800/80", children: [
981
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
982
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
2613
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "aui-code-header flex items-center justify-between rounded-t-lg border border-b-0 border-border/50 bg-zinc-100 px-4 py-2 dark:bg-zinc-800/80", children: [
2614
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase", children: [
2615
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40" }),
983
2616
  language
984
2617
  ] }),
985
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2618
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
986
2619
  TooltipIconButton,
987
2620
  {
988
2621
  tooltip: isCopied ? "Copied!" : "Copy",
989
2622
  onClick: onCopy,
990
2623
  className: "transition-colors hover:text-foreground",
991
2624
  children: [
992
- !isCopied && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.CopyIcon, { className: "h-3.5 w-3.5" }),
993
- isCopied && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
2625
+ !isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CopyIcon, { className: "h-3.5 w-3.5" }),
2626
+ isCopied && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.CheckIcon, { className: "h-3.5 w-3.5 text-emerald-500" })
994
2627
  ]
995
2628
  }
996
2629
  )
@@ -999,7 +2632,7 @@ var CodeHeader = ({ language, code }) => {
999
2632
  var useCopyToClipboard = ({
1000
2633
  copiedDuration = 3e3
1001
2634
  } = {}) => {
1002
- const [isCopied, setIsCopied] = (0, import_react7.useState)(false);
2635
+ const [isCopied, setIsCopied] = (0, import_react16.useState)(false);
1003
2636
  const copyToClipboard = (value) => {
1004
2637
  if (!value) return;
1005
2638
  navigator.clipboard.writeText(value).then(() => {
@@ -1010,7 +2643,7 @@ var useCopyToClipboard = ({
1010
2643
  return { isCopied, copyToClipboard };
1011
2644
  };
1012
2645
  var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownComponents)({
1013
- h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2646
+ h1: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1014
2647
  "h1",
1015
2648
  {
1016
2649
  className: cn(
@@ -1020,7 +2653,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1020
2653
  ...props
1021
2654
  }
1022
2655
  ),
1023
- h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2656
+ h2: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1024
2657
  "h2",
1025
2658
  {
1026
2659
  className: cn(
@@ -1030,7 +2663,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1030
2663
  ...props
1031
2664
  }
1032
2665
  ),
1033
- h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2666
+ h3: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1034
2667
  "h3",
1035
2668
  {
1036
2669
  className: cn(
@@ -1040,7 +2673,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1040
2673
  ...props
1041
2674
  }
1042
2675
  ),
1043
- h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2676
+ h4: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1044
2677
  "h4",
1045
2678
  {
1046
2679
  className: cn(
@@ -1050,7 +2683,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1050
2683
  ...props
1051
2684
  }
1052
2685
  ),
1053
- h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2686
+ h5: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1054
2687
  "h5",
1055
2688
  {
1056
2689
  className: cn(
@@ -1060,7 +2693,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1060
2693
  ...props
1061
2694
  }
1062
2695
  ),
1063
- h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2696
+ h6: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1064
2697
  "h6",
1065
2698
  {
1066
2699
  className: cn(
@@ -1070,7 +2703,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1070
2703
  ...props
1071
2704
  }
1072
2705
  ),
1073
- p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2706
+ p: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1074
2707
  "p",
1075
2708
  {
1076
2709
  className: cn(
@@ -1080,7 +2713,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1080
2713
  ...props
1081
2714
  }
1082
2715
  ),
1083
- a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2716
+ a: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1084
2717
  "a",
1085
2718
  {
1086
2719
  className: cn(
@@ -1092,7 +2725,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1092
2725
  ...props
1093
2726
  }
1094
2727
  ),
1095
- blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2728
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1096
2729
  "blockquote",
1097
2730
  {
1098
2731
  className: cn(
@@ -1102,7 +2735,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1102
2735
  ...props
1103
2736
  }
1104
2737
  ),
1105
- ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2738
+ ul: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1106
2739
  "ul",
1107
2740
  {
1108
2741
  className: cn(
@@ -1112,7 +2745,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1112
2745
  ...props
1113
2746
  }
1114
2747
  ),
1115
- ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2748
+ ol: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1116
2749
  "ol",
1117
2750
  {
1118
2751
  className: cn(
@@ -1122,7 +2755,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1122
2755
  ...props
1123
2756
  }
1124
2757
  ),
1125
- hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2758
+ hr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1126
2759
  "hr",
1127
2760
  {
1128
2761
  className: cn(
@@ -1132,14 +2765,14 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1132
2765
  ...props
1133
2766
  }
1134
2767
  ),
1135
- table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2768
+ table: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "my-4 w-full overflow-x-auto rounded-lg border border-border/50", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1136
2769
  "table",
1137
2770
  {
1138
2771
  className: cn("aui-md-table w-full border-collapse text-sm", className),
1139
2772
  ...props
1140
2773
  }
1141
2774
  ) }),
1142
- th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2775
+ th: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1143
2776
  "th",
1144
2777
  {
1145
2778
  className: cn(
@@ -1149,7 +2782,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1149
2782
  ...props
1150
2783
  }
1151
2784
  ),
1152
- td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2785
+ td: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1153
2786
  "td",
1154
2787
  {
1155
2788
  className: cn(
@@ -1159,7 +2792,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1159
2792
  ...props
1160
2793
  }
1161
2794
  ),
1162
- tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2795
+ tr: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1163
2796
  "tr",
1164
2797
  {
1165
2798
  className: cn(
@@ -1169,8 +2802,8 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1169
2802
  ...props
1170
2803
  }
1171
2804
  ),
1172
- li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
1173
- sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2805
+ li: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("li", { className: cn("aui-md-li leading-[1.7]", className), ...props }),
2806
+ sup: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1174
2807
  "sup",
1175
2808
  {
1176
2809
  className: cn(
@@ -1180,7 +2813,7 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1180
2813
  ...props
1181
2814
  }
1182
2815
  ),
1183
- pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2816
+ pre: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1184
2817
  "pre",
1185
2818
  {
1186
2819
  className: cn(
@@ -1192,97 +2825,364 @@ var defaultComponents = (0, import_react_markdown.unstable_memoizeMarkdownCompon
1192
2825
  ),
1193
2826
  code: function Code({ className, ...props }) {
1194
2827
  const isCodeBlock = (0, import_react_markdown.useIsMarkdownCodeBlock)();
1195
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2828
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1196
2829
  "code",
1197
2830
  {
1198
- className: cn(
1199
- !isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90 dark:bg-muted/40",
1200
- className
1201
- ),
1202
- ...props
2831
+ className: cn(
2832
+ !isCodeBlock && "aui-md-inline-code rounded-[5px] border border-border/60 bg-muted/60 px-[0.4em] py-[0.15em] font-mono text-[0.85em] font-medium text-foreground/90 dark:bg-muted/40",
2833
+ className
2834
+ ),
2835
+ ...props
2836
+ }
2837
+ );
2838
+ },
2839
+ strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
2840
+ em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("em", { className: cn("italic", className), ...props }),
2841
+ CodeHeader
2842
+ });
2843
+
2844
+ // src/components/tool-fallback.tsx
2845
+ var import_react19 = require("react");
2846
+ var import_lucide_react5 = require("lucide-react");
2847
+
2848
+ // src/ui/shimmer.tsx
2849
+ var import_react17 = require("motion/react");
2850
+ var import_react18 = require("react");
2851
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2852
+ var ShimmerComponent = ({
2853
+ children,
2854
+ as: Component = "p",
2855
+ className,
2856
+ duration = 2,
2857
+ spread = 2
2858
+ }) => {
2859
+ const MotionComponent = import_react17.motion.create(
2860
+ Component
2861
+ );
2862
+ const dynamicSpread = (0, import_react18.useMemo)(
2863
+ () => (children?.length ?? 0) * spread,
2864
+ [children, spread]
2865
+ );
2866
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2867
+ MotionComponent,
2868
+ {
2869
+ animate: { backgroundPosition: "0% center" },
2870
+ className: cn(
2871
+ "relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",
2872
+ "[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
2873
+ className
2874
+ ),
2875
+ initial: { backgroundPosition: "100% center" },
2876
+ style: {
2877
+ "--spread": `${dynamicSpread}px`,
2878
+ backgroundImage: "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"
2879
+ },
2880
+ transition: {
2881
+ repeat: Number.POSITIVE_INFINITY,
2882
+ duration,
2883
+ ease: "linear"
2884
+ },
2885
+ children
2886
+ }
2887
+ );
2888
+ };
2889
+ var Shimmer = (0, import_react18.memo)(ShimmerComponent);
2890
+
2891
+ // src/components/tool-fallback.tsx
2892
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2893
+ var ToolFallbackImpl = ({
2894
+ toolName,
2895
+ argsText,
2896
+ result,
2897
+ status
2898
+ }) => {
2899
+ const isRunning = status?.type === "running";
2900
+ const isError = status?.type === "incomplete" && status.reason !== "cancelled";
2901
+ if (isRunning) {
2902
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-running flex items-center gap-2 py-1 text-sm text-muted-foreground", children: [
2903
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-4" }),
2904
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Shimmer, { as: "span", duration: 1.8, spread: 2.5, children: `Using tool: ${toolName}` })
2905
+ ] });
2906
+ }
2907
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2908
+ ToolPanel,
2909
+ {
2910
+ toolName,
2911
+ argsText,
2912
+ result,
2913
+ isError
2914
+ }
2915
+ );
2916
+ };
2917
+ var ToolPanel = ({ toolName, argsText, result, isError }) => {
2918
+ const [open, setOpen] = (0, import_react19.useState)(false);
2919
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2920
+ "div",
2921
+ {
2922
+ className: cn(
2923
+ "aui-tool-fallback-root my-2 overflow-hidden rounded-lg border border-border/60 bg-muted/30 text-sm",
2924
+ isError && "border-destructive/50 bg-destructive/5"
2925
+ ),
2926
+ children: [
2927
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2928
+ "button",
2929
+ {
2930
+ type: "button",
2931
+ onClick: () => setOpen((v) => !v),
2932
+ className: "aui-tool-fallback-header flex w-full items-center gap-2 px-3 py-2 text-left text-muted-foreground transition-colors hover:bg-muted/50",
2933
+ "aria-expanded": open,
2934
+ children: [
2935
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.WrenchIcon, { className: "size-3.5" }),
2936
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-name flex-1 truncate font-mono text-xs font-medium text-foreground/80", children: toolName }),
2937
+ isError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "aui-tool-fallback-status text-xs font-medium text-destructive", children: "error" }),
2938
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2939
+ import_lucide_react5.ChevronDownIcon,
2940
+ {
2941
+ className: cn(
2942
+ "size-3.5 shrink-0 transition-transform",
2943
+ open && "rotate-180"
2944
+ )
2945
+ }
2946
+ )
2947
+ ]
2948
+ }
2949
+ ),
2950
+ open && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-body grid gap-2 border-t border-border/40 bg-background/50 px-3 py-2.5 text-xs", children: [
2951
+ argsText && argsText !== "{}" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Input", value: argsText }),
2952
+ result !== void 0 && result !== null && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Section, { label: "Output", value: formatResult(result) })
2953
+ ] })
2954
+ ]
2955
+ }
2956
+ );
2957
+ };
2958
+ var Section = ({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "aui-tool-fallback-section", children: [
2959
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "aui-tool-fallback-section-label mb-0.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
2960
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pre", { className: "aui-tool-fallback-section-value overflow-x-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-relaxed text-foreground/85", children: value })
2961
+ ] });
2962
+ function formatResult(result) {
2963
+ if (typeof result === "string") return result;
2964
+ try {
2965
+ return JSON.stringify(result, null, 2);
2966
+ } catch {
2967
+ return String(result);
2968
+ }
2969
+ }
2970
+ var ToolFallback = (0, import_react19.memo)(
2971
+ ToolFallbackImpl
2972
+ );
2973
+ ToolFallback.displayName = "ToolFallback";
2974
+
2975
+ // src/artifacts/tool-artifact.tsx
2976
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2977
+ var ToolArtifactFallback = (props) => {
2978
+ const registry = useArtifactRegistry();
2979
+ const isRunning = props.status?.type === "running";
2980
+ if (!isRunning) {
2981
+ const artifact = parseArtifactFromToolResult(props.result);
2982
+ if (artifact) {
2983
+ const Renderer = registry[artifact.type];
2984
+ if (Renderer) {
2985
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Renderer, { artifact });
2986
+ }
2987
+ }
2988
+ }
2989
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolFallback, { ...props });
2990
+ };
2991
+
2992
+ // src/components/composer.tsx
2993
+ var import_react20 = require("@assistant-ui/react");
2994
+ var import_lucide_react6 = require("lucide-react");
2995
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2996
+ var Composer = ({
2997
+ placeholder = "Send a message...",
2998
+ showAttachments = true,
2999
+ toolbar,
3000
+ sendTooltip = "Send message",
3001
+ noAutoFocus,
3002
+ className
3003
+ }) => {
3004
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3005
+ import_react20.ComposerPrimitive.Root,
3006
+ {
3007
+ className: cn(
3008
+ "aui-composer-root relative mt-3 flex w-full flex-col",
3009
+ className
3010
+ ),
3011
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3012
+ import_react20.ComposerPrimitive.AttachmentDropzone,
3013
+ {
3014
+ className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50",
3015
+ children: [
3016
+ showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAttachments, {}),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerInput, { placeholder, autoFocus: !noAutoFocus }),
3018
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3019
+ ComposerToolbar,
3020
+ {
3021
+ showAttachments,
3022
+ toolbar,
3023
+ sendTooltip
3024
+ }
3025
+ )
3026
+ ]
3027
+ }
3028
+ )
3029
+ }
3030
+ );
3031
+ };
3032
+ var ComposerInput = ({
3033
+ placeholder,
3034
+ autoFocus
3035
+ }) => {
3036
+ const composer = (0, import_react20.useComposerRuntime)();
3037
+ const onKeyDown = (e) => {
3038
+ if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
3039
+ e.preventDefault();
3040
+ composer.send();
3041
+ }
3042
+ };
3043
+ const onInput = (e) => {
3044
+ const el = e.currentTarget;
3045
+ el.style.height = "auto";
3046
+ el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
3047
+ };
3048
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3049
+ import_react20.ComposerPrimitive.Input,
3050
+ {
3051
+ placeholder,
3052
+ className: "aui-composer-input mb-1 max-h-60 min-h-12 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
3053
+ rows: 1,
3054
+ autoFocus,
3055
+ "aria-label": "Message input",
3056
+ onKeyDown,
3057
+ onInput
3058
+ }
3059
+ );
3060
+ };
3061
+ var ComposerToolbar = ({ showAttachments, toolbar, sendTooltip }) => {
3062
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center gap-1", children: [
3063
+ showAttachments && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerAddAttachment, {}),
3064
+ toolbar,
3065
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1" }),
3066
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ComposerSendOrCancel, { sendTooltip })
3067
+ ] });
3068
+ };
3069
+ var ComposerSendOrCancel = ({ sendTooltip }) => {
3070
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
3071
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3072
+ TooltipIconButton,
3073
+ {
3074
+ tooltip: sendTooltip,
3075
+ side: "bottom",
3076
+ type: "submit",
3077
+ variant: "default",
3078
+ size: "icon",
3079
+ className: "aui-composer-send size-8 rounded-full",
3080
+ "aria-label": "Send message",
3081
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
1203
3082
  }
1204
- );
1205
- },
1206
- strong: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { className: cn("font-semibold text-foreground", className), ...props }),
1207
- em: ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("em", { className: cn("italic", className), ...props }),
1208
- CodeHeader
1209
- });
1210
-
1211
- // src/components/tool-fallback.tsx
1212
- var import_react10 = require("react");
1213
- var import_lucide_react4 = require("lucide-react");
3083
+ ) }) }),
3084
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react20.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3085
+ Button,
3086
+ {
3087
+ type: "button",
3088
+ variant: "default",
3089
+ size: "icon",
3090
+ className: "aui-composer-cancel size-8 rounded-full",
3091
+ "aria-label": "Stop generating",
3092
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react6.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
3093
+ }
3094
+ ) }) })
3095
+ ] });
3096
+ };
1214
3097
 
1215
- // src/ui/shimmer.tsx
1216
- var import_react8 = require("motion/react");
1217
- var import_react9 = require("react");
1218
- var import_jsx_runtime10 = require("react/jsx-runtime");
1219
- var ShimmerComponent = ({
1220
- children,
1221
- as: Component = "p",
1222
- className,
1223
- duration = 2,
1224
- spread = 2
3098
+ // src/components/suggestions.tsx
3099
+ var import_react21 = require("react");
3100
+ var import_react22 = require("@assistant-ui/react");
3101
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3102
+ var Suggestions = ({
3103
+ suggestions,
3104
+ layout = "grid",
3105
+ className
1225
3106
  }) => {
1226
- const MotionComponent = import_react8.motion.create(
1227
- Component
1228
- );
1229
- const dynamicSpread = (0, import_react9.useMemo)(
1230
- () => (children?.length ?? 0) * spread,
1231
- [children, spread]
1232
- );
1233
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1234
- MotionComponent,
3107
+ const items = useResolvedSuggestions(suggestions);
3108
+ if (!items || items.length === 0) return null;
3109
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3110
+ "div",
1235
3111
  {
1236
- animate: { backgroundPosition: "0% center" },
1237
3112
  className: cn(
1238
- "relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",
1239
- "[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
3113
+ "aui-thread-suggestions w-full pb-4",
3114
+ layout === "grid" ? "grid gap-2 @md:grid-cols-2" : "flex gap-2 overflow-x-auto pb-1 [&::-webkit-scrollbar]:hidden",
1240
3115
  className
1241
3116
  ),
1242
- initial: { backgroundPosition: "100% center" },
1243
- style: {
1244
- "--spread": `${dynamicSpread}px`,
1245
- backgroundImage: "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))"
1246
- },
1247
- transition: {
1248
- repeat: Number.POSITIVE_INFINITY,
1249
- duration,
1250
- ease: "linear"
1251
- },
1252
- children
3117
+ children: items.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SuggestionChip, { suggestion: s, compact: layout === "row" }, s.title + i))
1253
3118
  }
1254
3119
  );
1255
3120
  };
1256
- var Shimmer = (0, import_react9.memo)(ShimmerComponent);
1257
-
1258
- // src/components/tool-fallback.tsx
1259
- var import_jsx_runtime11 = require("react/jsx-runtime");
1260
- var ToolFallbackImpl = ({
1261
- toolName,
1262
- status
3121
+ var SuggestionChip = ({
3122
+ suggestion,
3123
+ compact
1263
3124
  }) => {
1264
- if (status?.type !== "running") return null;
1265
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2 py-1 text-sm text-muted-foreground", children: [
1266
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react4.WrenchIcon, { className: "size-4" }),
1267
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Shimmer, { as: "span", duration: 1.8, spread: 2.5, children: `Using tool: ${toolName}` })
1268
- ] });
3125
+ const runtime = (0, import_react22.useThreadRuntime)();
3126
+ const onClick = () => {
3127
+ const text = suggestion.prompt ?? suggestion.title;
3128
+ runtime.append({ role: "user", content: [{ type: "text", text }] });
3129
+ };
3130
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "aui-thread-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3131
+ Button,
3132
+ {
3133
+ variant: "ghost",
3134
+ onClick,
3135
+ className: cn(
3136
+ "aui-thread-suggestion h-auto rounded-2xl border text-left text-sm transition-colors hover:bg-muted",
3137
+ compact ? "shrink-0 flex-row items-center gap-2 whitespace-nowrap px-3 py-2" : "w-full flex-wrap items-start justify-start gap-1 px-4 py-3 @md:flex-col"
3138
+ ),
3139
+ children: [
3140
+ suggestion.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-icon shrink-0 text-muted-foreground", children: suggestion.icon }),
3141
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-1 font-medium", children: suggestion.title }),
3142
+ suggestion.description && !compact && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "aui-thread-suggestion-text-2 text-muted-foreground", children: suggestion.description })
3143
+ ]
3144
+ }
3145
+ ) });
1269
3146
  };
1270
- var ToolFallback = (0, import_react10.memo)(
1271
- ToolFallbackImpl
1272
- );
1273
- ToolFallback.displayName = "ToolFallback";
3147
+ function useResolvedSuggestions(source) {
3148
+ const [resolved, setResolved] = (0, import_react21.useState)(
3149
+ () => Array.isArray(source) ? source : void 0
3150
+ );
3151
+ (0, import_react21.useEffect)(() => {
3152
+ if (!source) {
3153
+ setResolved(void 0);
3154
+ return;
3155
+ }
3156
+ if (Array.isArray(source)) {
3157
+ setResolved(source);
3158
+ return;
3159
+ }
3160
+ let cancelled = false;
3161
+ Promise.resolve().then(() => source()).then((value) => {
3162
+ if (!cancelled) setResolved(value);
3163
+ }).catch(() => {
3164
+ if (!cancelled) setResolved([]);
3165
+ });
3166
+ return () => {
3167
+ cancelled = true;
3168
+ };
3169
+ }, [source]);
3170
+ return (0, import_react21.useMemo)(() => resolved, [resolved]);
3171
+ }
1274
3172
 
1275
3173
  // src/components/thread.tsx
1276
- var import_react11 = require("@assistant-ui/react");
1277
- var import_lucide_react5 = require("lucide-react");
1278
- var import_jsx_runtime12 = require("react/jsx-runtime");
3174
+ var import_react23 = require("@assistant-ui/react");
3175
+ var import_lucide_react7 = require("lucide-react");
3176
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1279
3177
  var Thread = ({
1280
3178
  className,
1281
3179
  maxWidth = "44rem",
1282
3180
  welcome,
1283
3181
  suggestions,
1284
3182
  composerPlaceholder = "Send a message...",
1285
- components
3183
+ components,
3184
+ artifacts,
3185
+ onArtifactEvent
1286
3186
  }) => {
1287
3187
  const WelcomeSlot = components?.Welcome ?? ThreadWelcome;
1288
3188
  const ComposerSlot = components?.Composer ?? Composer;
@@ -1290,59 +3190,79 @@ var Thread = ({
1290
3190
  const AssistantMessageSlot = components?.AssistantMessage ?? AssistantMessage;
1291
3191
  const EditComposerSlot = components?.EditComposer ?? EditComposer;
1292
3192
  const ScrollToBottomSlot = components?.ScrollToBottom ?? ThreadScrollToBottom;
1293
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1294
- import_react11.ThreadPrimitive.Root,
3193
+ const SuggestionsSlot = components?.Suggestions ?? Suggestions;
3194
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3195
+ ArtifactRegistryProvider,
1295
3196
  {
1296
- className: cn(
1297
- "aui-root aui-thread-root @container flex h-full flex-col bg-background",
1298
- className
1299
- ),
1300
- style: { ["--thread-max-width"]: maxWidth },
1301
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1302
- import_react11.ThreadPrimitive.Viewport,
3197
+ renderers: artifacts?.renderers,
3198
+ override: artifacts?.override,
3199
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UiEventProvider, { onEvent: onArtifactEvent ?? (() => {
3200
+ }), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3201
+ import_react23.ThreadPrimitive.Root,
1303
3202
  {
1304
- turnAnchor: "bottom",
1305
- className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
1306
- children: [
1307
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WelcomeSlot, { config: welcome, suggestions }),
1308
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1309
- import_react11.ThreadPrimitive.Messages,
1310
- {
1311
- components: {
1312
- UserMessage: UserMessageSlot,
1313
- EditComposer: EditComposerSlot,
1314
- AssistantMessage: AssistantMessageSlot
1315
- }
1316
- }
1317
- ),
1318
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
1319
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollToBottomSlot, {}),
1320
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
1321
- ] })
1322
- ]
3203
+ className: cn(
3204
+ "aui-root aui-thread-root @container flex h-full flex-col bg-background",
3205
+ className
3206
+ ),
3207
+ style: { ["--thread-max-width"]: maxWidth },
3208
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3209
+ import_react23.ThreadPrimitive.Viewport,
3210
+ {
3211
+ turnAnchor: "bottom",
3212
+ className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll px-4 pt-4",
3213
+ children: [
3214
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3215
+ WelcomeSlot,
3216
+ {
3217
+ config: welcome,
3218
+ suggestions,
3219
+ Suggestions: SuggestionsSlot
3220
+ }
3221
+ ),
3222
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3223
+ import_react23.ThreadPrimitive.Messages,
3224
+ {
3225
+ components: {
3226
+ UserMessage: UserMessageSlot,
3227
+ EditComposer: EditComposerSlot,
3228
+ AssistantMessage: AssistantMessageSlot
3229
+ }
3230
+ }
3231
+ ),
3232
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4 md:pb-6", children: [
3233
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScrollToBottomSlot, {}),
3234
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ComposerSlot, { placeholder: composerPlaceholder })
3235
+ ] })
3236
+ ]
3237
+ }
3238
+ )
1323
3239
  }
1324
- )
3240
+ ) })
1325
3241
  }
1326
3242
  );
1327
3243
  };
1328
3244
  var ThreadScrollToBottom = () => {
1329
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3245
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1330
3246
  TooltipIconButton,
1331
3247
  {
1332
3248
  tooltip: "Scroll to bottom",
1333
3249
  variant: "outline",
1334
3250
  className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent",
1335
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ArrowDownIcon, {})
3251
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.ArrowDownIcon, {})
1336
3252
  }
1337
3253
  ) });
1338
3254
  };
1339
- var ThreadWelcome = ({ config, suggestions }) => {
1340
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
1341
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
1342
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
1343
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
1344
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "animate-ai-pulse-ring absolute inset-0" }),
1345
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3255
+ var ThreadWelcome = ({
3256
+ config,
3257
+ suggestions,
3258
+ Suggestions: SuggestionsSlot = Suggestions
3259
+ }) => {
3260
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.thread.isEmpty, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col", children: [
3261
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-thread-welcome-message flex size-full flex-col items-center justify-center px-4 text-center", children: [
3262
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "fade-in animate-in fill-mode-both relative mb-6 flex size-14 items-center justify-center duration-300", children: [
3263
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-ring-glow absolute inset-0 rounded-2xl bg-gradient-to-br from-primary/15 to-primary/5 ring-1 ring-primary/15" }),
3264
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "animate-ai-pulse-ring absolute inset-0" }),
3265
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1346
3266
  "svg",
1347
3267
  {
1348
3268
  xmlns: "http://www.w3.org/2000/svg",
@@ -1353,139 +3273,74 @@ var ThreadWelcome = ({ config, suggestions }) => {
1353
3273
  strokeLinecap: "round",
1354
3274
  strokeLinejoin: "round",
1355
3275
  className: "animate-ai-breathe relative size-7 text-primary/75",
1356
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" })
3276
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" })
1357
3277
  }
1358
3278
  )
1359
3279
  ] }),
1360
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
1361
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
3280
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both font-semibold text-2xl duration-200", children: config?.heading ?? "How can I help you today?" }),
3281
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground mt-2 delay-75 duration-200", children: config?.subheading ?? "Send a message to start a conversation." })
1362
3282
  ] }) }),
1363
- suggestions && suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestions, { suggestions })
1364
- ] }) });
1365
- };
1366
- var ThreadSuggestions = ({ suggestions }) => {
1367
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestions grid w-full @md:grid-cols-2 gap-2 pb-4", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ThreadSuggestionItem, { title: s.title, description: s.description }, i)) });
1368
- };
1369
- var ThreadSuggestionItem = ({ title, description }) => {
1370
- const runtime = (0, import_react11.useThreadRuntime)();
1371
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1372
- Button,
1373
- {
1374
- variant: "ghost",
1375
- className: "aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border px-4 py-3 text-left text-sm transition-colors hover:bg-muted",
1376
- onClick: () => runtime.append({
1377
- role: "user",
1378
- content: [{ type: "text", text: title }]
1379
- }),
1380
- children: [
1381
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-1 font-medium", children: title }),
1382
- description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "aui-thread-welcome-suggestion-text-2 text-muted-foreground", children: description })
1383
- ]
1384
- }
1385
- ) });
1386
- };
1387
- var Composer = ({ placeholder }) => {
1388
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Root, { className: "aui-composer-root relative mt-3 flex w-full flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ComposerPrimitive.AttachmentDropzone, { className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [
1389
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAttachments, {}),
1390
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1391
- import_react11.ComposerPrimitive.Input,
1392
- {
1393
- placeholder: placeholder ?? "Send a message...",
1394
- className: "aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0",
1395
- rows: 1,
1396
- autoFocus: true,
1397
- "aria-label": "Message input"
1398
- }
1399
- ),
1400
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ComposerAction, {})
3283
+ suggestions && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SuggestionsSlot, { suggestions })
1401
3284
  ] }) });
1402
3285
  };
1403
- var ComposerAction = () => {
1404
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-end", children: [
1405
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => !s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1406
- TooltipIconButton,
1407
- {
1408
- tooltip: "Send message",
1409
- side: "bottom",
1410
- type: "submit",
1411
- variant: "default",
1412
- size: "icon",
1413
- className: "aui-composer-send size-8 rounded-full",
1414
- "aria-label": "Send message",
1415
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
1416
- }
1417
- ) }) }),
1418
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => s.thread.isRunning, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1419
- Button,
1420
- {
1421
- type: "button",
1422
- variant: "default",
1423
- size: "icon",
1424
- className: "aui-composer-cancel size-8 rounded-full",
1425
- "aria-label": "Stop generating",
1426
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
1427
- }
1428
- ) }) })
1429
- ] });
1430
- };
1431
3286
  var MessageError = () => {
1432
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
3287
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Error, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
1433
3288
  };
1434
3289
  var AssistantMessage = () => {
1435
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1436
- import_react11.MessagePrimitive.Root,
3290
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3291
+ import_react23.MessagePrimitive.Root,
1437
3292
  {
1438
3293
  className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
1439
3294
  "data-role": "assistant",
1440
3295
  children: [
1441
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1443
- import_react11.MessagePrimitive.Parts,
3296
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
3297
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3298
+ import_react23.MessagePrimitive.Parts,
1444
3299
  {
1445
3300
  components: {
1446
3301
  Text: MarkdownText,
1447
- tools: { Fallback: ToolFallback }
3302
+ tools: { Fallback: ToolArtifactFallback }
1448
3303
  }
1449
3304
  }
1450
3305
  ),
1451
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageError, {})
3306
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MessageError, {})
1452
3307
  ] }),
1453
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssistantActionBar, {}) })
3308
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AssistantActionBar, {}) })
1454
3309
  ]
1455
3310
  }
1456
3311
  );
1457
3312
  };
1458
3313
  var AssistantActionBar = () => {
1459
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1460
- import_react11.ActionBarPrimitive.Root,
3314
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3315
+ import_react23.ActionBarPrimitive.Root,
1461
3316
  {
1462
3317
  hideWhenRunning: true,
1463
3318
  autohide: "not-last",
1464
3319
  autohideFloat: "single-branch",
1465
3320
  className: "aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm",
1466
3321
  children: [
1467
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(TooltipIconButton, { tooltip: "Copy", children: [
1468
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.CheckIcon, {}) }),
1469
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.CopyIcon, {}) })
3322
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(TooltipIconButton, { tooltip: "Copy", children: [
3323
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CheckIcon, {}) }),
3324
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.AuiIf, { condition: (s) => !s.message.isCopied, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.CopyIcon, {}) })
1470
3325
  ] }) }),
1471
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipIconButton, { tooltip: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.RefreshCwIcon, {}) }) }),
1472
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ActionBarMorePrimitive.Root, { children: [
1473
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3326
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Refresh", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.RefreshCwIcon, {}) }) }),
3327
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Root, { children: [
3328
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarMorePrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1474
3329
  TooltipIconButton,
1475
3330
  {
1476
3331
  tooltip: "More",
1477
3332
  className: "data-[state=open]:bg-accent",
1478
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.MoreHorizontalIcon, {})
3333
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.MoreHorizontalIcon, {})
1479
3334
  }
1480
3335
  ) }),
1481
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1482
- import_react11.ActionBarMorePrimitive.Content,
3336
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3337
+ import_react23.ActionBarMorePrimitive.Content,
1483
3338
  {
1484
3339
  side: "bottom",
1485
3340
  align: "start",
1486
3341
  className: "aui-action-bar-more-content z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
1487
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", children: [
1488
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.DownloadIcon, { className: "size-4" }),
3342
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ActionBarMorePrimitive.Item, { className: "aui-action-bar-more-item flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", children: [
3343
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.DownloadIcon, { className: "size-4" }),
1489
3344
  "Export as Markdown"
1490
3345
  ] }) })
1491
3346
  }
@@ -1496,68 +3351,382 @@ var AssistantActionBar = () => {
1496
3351
  );
1497
3352
  };
1498
3353
  var UserMessage = () => {
1499
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1500
- import_react11.MessagePrimitive.Root,
3354
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3355
+ import_react23.MessagePrimitive.Root,
1501
3356
  {
1502
3357
  className: "aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2",
1503
3358
  "data-role": "user",
1504
3359
  children: [
1505
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UserMessageAttachments, {}),
1506
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [
1507
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.MessagePrimitive.Parts, {}) }),
1508
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UserActionBar, {}) })
3360
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserMessageAttachments, {}),
3361
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [
3362
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Parts, {}) }),
3363
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(UserActionBar, {}) })
1509
3364
  ] })
1510
3365
  ]
1511
3366
  }
1512
3367
  );
1513
3368
  };
1514
3369
  var UserActionBar = () => {
1515
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1516
- import_react11.ActionBarPrimitive.Root,
3370
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3371
+ import_react23.ActionBarPrimitive.Root,
1517
3372
  {
1518
3373
  hideWhenRunning: true,
1519
3374
  autohide: "not-last",
1520
3375
  className: "aui-user-action-bar-root flex flex-col items-end",
1521
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit p-4", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.PencilIcon, {}) }) })
3376
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit p-4", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react7.PencilIcon, {}) }) })
1522
3377
  }
1523
3378
  );
1524
3379
  };
1525
3380
  var EditComposer = () => {
1526
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react11.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
1527
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1528
- import_react11.ComposerPrimitive.Input,
3381
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react23.ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
3382
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3383
+ import_react23.ComposerPrimitive.Input,
1529
3384
  {
1530
3385
  className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
1531
3386
  autoFocus: true
1532
3387
  }
1533
3388
  ),
1534
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
1535
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
1536
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react11.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { size: "sm", children: "Update" }) })
3389
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
3390
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
3391
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react23.ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Button, { size: "sm", children: "Update" }) })
1537
3392
  ] })
1538
3393
  ] }) });
1539
3394
  };
1540
3395
 
1541
3396
  // src/components/chat.tsx
1542
- var import_jsx_runtime13 = require("react/jsx-runtime");
3397
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1543
3398
  function TimbalChat({
1544
3399
  workforceId,
1545
3400
  baseUrl,
1546
3401
  fetch: fetch2,
3402
+ attachments,
3403
+ attachmentsUploadUrl,
3404
+ attachmentsAccept,
3405
+ debug,
1547
3406
  ...threadProps
1548
3407
  }) {
1549
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TimbalRuntimeProvider, { workforceId, baseUrl, fetch: fetch2, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Thread, { ...threadProps }) });
3408
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3409
+ TimbalRuntimeProvider,
3410
+ {
3411
+ workforceId,
3412
+ baseUrl,
3413
+ fetch: fetch2,
3414
+ attachments,
3415
+ attachmentsUploadUrl,
3416
+ attachmentsAccept,
3417
+ debug,
3418
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Thread, { ...threadProps })
3419
+ }
3420
+ );
3421
+ }
3422
+
3423
+ // src/artifacts/agent-instructions.ts
3424
+ var ARTIFACT_AGENT_INSTRUCTIONS = `
3425
+ ## Rich artifacts (Timbal chat UI)
3426
+
3427
+ When you need charts, tables, choice widgets, or interactive controls, return a **JSON artifact object** instead of plain prose. The chat UI renders these automatically.
3428
+
3429
+ ### Delivery channels (either works)
3430
+
3431
+ 1. **Tool result (preferred)** \u2014 return a single JSON object (or a JSON string) from a tool. The object must include a string \`type\` field.
3432
+ 2. **Inline markdown fence** \u2014 embed the same JSON inside a fenced block:
3433
+
3434
+ \`\`\`timbal-artifact
3435
+ {"type":"chart","data":[{"month":"Jan","sales":120}]}
3436
+ \`\`\`
3437
+
3438
+ The alias \`\`\`timbal\`\`\` is also accepted.
3439
+
3440
+ ### Built-in artifact types
3441
+
3442
+ | \`type\` | Use for |
3443
+ |---|---|
3444
+ | \`chart\` | Bar, line, area, or pie charts. Fields: \`data\`, optional \`chartType\`, \`xKey\`, \`dataKey\`, \`title\`, \`unit\`. |
3445
+ | \`table\` | Tabular data. Fields: \`rows\`, optional \`columns\`, \`title\`. |
3446
+ | \`question\` | In-thread multiple choice. Fields: \`options: [{ id, label, description? }]\`, optional \`prompt\`, \`multi\`. User replies are sent back as a normal user message. |
3447
+ | \`html\` | Custom HTML/CSS/JS in an iframe. Fields: \`content\` (HTML document or fragment), optional \`title\`, \`height\`, \`sandboxed\` (default \`true\`; set \`false\` for unrestricted scripts/CDN). |
3448
+ | \`json\` | Fallback structured view. Fields: \`data\`, optional \`title\`. |
3449
+ | \`ui\` | **Interactive UI** composed from a fixed node palette (hover, click, drag). See below. |
3450
+
3451
+ ### When to use \`type: "html"\`
3452
+
3453
+ Use \`html\` when the user wants a **rich visual or interactive page** that does not fit the \`ui\` palette \u2014 e.g. styled layouts, SVG graphics, CSS animations, canvas, small games, calculators, or multi-section mockups. Pass a full HTML document or a body fragment in \`content\`.
3454
+
3455
+ - Inline \`<style>\`, \`<script>\`, SVG, and canvas are supported.
3456
+ - Default \`sandboxed: true\` runs in an isolated iframe with scripts enabled.
3457
+ - Set \`sandboxed: false\` only for trusted content that needs external CDN scripts/styles or full DOM freedom.
3458
+ - Prefer \`ui\` when controls should send chat messages or host events; prefer \`html\` for self-contained mini-apps and visual demos.
3459
+
3460
+ ### When to use \`type: "ui"\`
3461
+
3462
+ Use a \`ui\` artifact when the user should **hover, click, drag, or adjust controls** in-thread and those actions should integrate with the chat runtime (messages, \`onArtifactEvent\`). For standalone visual/interactive HTML, use \`html\` instead.
3463
+
3464
+ Each \`ui\` artifact has:
3465
+
3466
+ - \`initialState\` \u2014 optional object seeding local state (per widget instance).
3467
+ - \`root\` \u2014 a single node tree (see node kinds below).
3468
+ - optional \`title\` \u2014 card heading.
3469
+
3470
+ **Bindings:** anywhere a primitive is accepted, you may use \`{ "$bind": "dotted.path" }\` to read from \`initialState\` / local state (e.g. \`{ "$bind": "qty" }\`).
3471
+
3472
+ **Actions:** nodes may attach \`onClick\`, \`onChange\`, or \`onDragEnd\` with one action or an array:
3473
+
3474
+ | Action | Shape | Effect |
3475
+ |---|---|---|
3476
+ | User message | \`{ "kind": "message", "text": "..." }\` or \`{ "kind": "message", "text": { "$bind": "path" } }\` | Sends text as the next user message. |
3477
+ | Set state | \`{ "kind": "set", "path": "foo", "value": 1 }\` | Writes local widget state. |
3478
+ | Toggle boolean | \`{ "kind": "toggle", "path": "enabled" }\` | Flips a boolean at \`path\`. |
3479
+ | Host event | \`{ "kind": "emit", "name": "event-name", "payload": { ... } }\` | Bubbles to the host app (\`onArtifactEvent\` on \`<Thread>\`). |
3480
+
3481
+ ### \`ui\` node palette (\`root.kind\`)
3482
+
3483
+ | \`kind\` | Purpose | Key fields |
3484
+ |---|---|---|
3485
+ | \`box\` | Layout container | \`children\`, \`direction\` (\`row\`/\`col\`), \`gap\`, \`padding\`, \`align\`, \`justify\`, \`wrap\` |
3486
+ | \`text\` | Body text | \`value\`, optional \`muted\`, \`size\`, \`weight\` |
3487
+ | \`heading\` | Heading | \`value\`, optional \`level\` (1\u20134) |
3488
+ | \`badge\` | Pill label | \`value\`, optional \`tone\` (\`default\`, \`primary\`, \`success\`, \`warn\`, \`danger\`) |
3489
+ | \`button\` | Clickable button | \`label\`, optional \`variant\`, \`size\`, \`disabled\`, \`onClick\` |
3490
+ | \`toggle\` | Boolean switch | \`binding\` (state path), optional \`label\`, \`onChange\` |
3491
+ | \`slider\` | Numeric range | \`binding\`, optional \`min\`, \`max\`, \`step\`, \`label\`, \`showValue\`, \`onChange\` |
3492
+ | \`tooltip\` | Hover tooltip | \`content\`, \`child\` (single node), optional \`side\` |
3493
+ | \`draggable\` | Drag gesture | \`child\`, optional \`axis\` (\`x\`/\`y\`/\`both\`), \`snapBack\`, \`onDragEnd\` |
3494
+ | \`custom\` | Host-registered widget | \`name\`, optional \`props\`, \`children\` \u2014 only if the app registered that name |
3495
+
3496
+ ### Example \`ui\` artifact
3497
+
3498
+ \`\`\`json
3499
+ {
3500
+ "type": "ui",
3501
+ "title": "Configure plan",
3502
+ "initialState": { "qty": 1, "premium": false },
3503
+ "root": {
3504
+ "kind": "box",
3505
+ "direction": "col",
3506
+ "gap": 3,
3507
+ "children": [
3508
+ { "kind": "heading", "value": "Choose quantity", "level": 3 },
3509
+ {
3510
+ "kind": "tooltip",
3511
+ "content": "Drag to adjust quantity",
3512
+ "child": {
3513
+ "kind": "slider",
3514
+ "binding": "qty",
3515
+ "min": 1,
3516
+ "max": 50,
3517
+ "label": "Quantity",
3518
+ "onChange": { "kind": "emit", "name": "qty-changed" }
3519
+ }
3520
+ },
3521
+ { "kind": "toggle", "binding": "premium", "label": "Premium support" },
3522
+ {
3523
+ "kind": "button",
3524
+ "label": "Confirm",
3525
+ "onClick": { "kind": "message", "text": { "$bind": "qty" } }
3526
+ }
3527
+ ]
3528
+ }
1550
3529
  }
3530
+ \`\`\`
3531
+
3532
+ ### Rules
3533
+
3534
+ - Always set \`type\` to a built-in value above unless the app documented a custom type.
3535
+ - Prefer \`ui\` over \`html\` when actions must bubble to the host chat (\`message\`, \`emit\`).
3536
+ - Prefer \`question\` for simple A/B/C choices; use \`ui\` when you need sliders, toggles, drag, or multi-control layouts.
3537
+ - Keep \`data\` arrays reasonably small (charts/tables).
3538
+
3539
+ ### After calling an artifact tool (critical)
3540
+
3541
+ When you call a tool that returns an artifact (\`make_chart\`, \`ask_question\`, \`show_table\`, \`show_html\`, \`make_ui_demo\`, etc.):
3542
+
3543
+ 1. **Do not** paste, quote, paraphrase as JSON, or fence the tool return value in your assistant message. The chat UI already renders it from the tool result.
3544
+ 2. **Do not** emit a matching \`\`\`timbal-artifact\`\`\` block for the same payload \u2014 pick **one** channel (tool result only).
3545
+ 3. Your follow-up text should be **empty**, or at most **one short sentence** (e.g. "Pick an option above." / "Try the controls."). Never include \`type\`, \`options\`, \`data\`, or dict/JSON syntax.
3546
+ 4. Treat the widget as visible to the user; refer to it as "above" / "the chart" / "the choices" \u2014 never reproduce its contents.
3547
+ `.trim();
1551
3548
 
1552
3549
  // src/index.ts
1553
- var import_react13 = require("@assistant-ui/react");
3550
+ var import_react26 = require("@assistant-ui/react");
3551
+
3552
+ // src/hooks/use-workforces.ts
3553
+ var import_react24 = require("react");
3554
+ function useWorkforces(options = {}) {
3555
+ const { baseUrl = "/api", fetch: fetchFn, pickInitial } = options;
3556
+ const [workforces, setWorkforces] = (0, import_react24.useState)([]);
3557
+ const [selectedId, setSelectedId] = (0, import_react24.useState)("");
3558
+ const [isLoading, setIsLoading] = (0, import_react24.useState)(true);
3559
+ const [error, setError] = (0, import_react24.useState)(null);
3560
+ const fetchFnRef = (0, import_react24.useRef)(fetchFn ?? authFetch);
3561
+ (0, import_react24.useEffect)(() => {
3562
+ fetchFnRef.current = fetchFn ?? authFetch;
3563
+ }, [fetchFn]);
3564
+ const pickInitialRef = (0, import_react24.useRef)(pickInitial);
3565
+ (0, import_react24.useEffect)(() => {
3566
+ pickInitialRef.current = pickInitial;
3567
+ }, [pickInitial]);
3568
+ const load = (0, import_react24.useMemo)(() => {
3569
+ return async () => {
3570
+ setIsLoading(true);
3571
+ setError(null);
3572
+ try {
3573
+ const res = await fetchFnRef.current(`${baseUrl}/workforce`);
3574
+ if (!res.ok) throw new Error(`Failed to load workforces (${res.status})`);
3575
+ const data = await res.json();
3576
+ setWorkforces(data);
3577
+ setSelectedId((current) => {
3578
+ if (current && data.some((w) => idOf(w) === current)) return current;
3579
+ const initial = pickInitialRef.current?.(data) ?? data.find((w) => w.type === "agent") ?? data[0];
3580
+ return initial ? idOf(initial) : "";
3581
+ });
3582
+ } catch (err) {
3583
+ setError(err instanceof Error ? err : new Error(String(err)));
3584
+ } finally {
3585
+ setIsLoading(false);
3586
+ }
3587
+ };
3588
+ }, [baseUrl]);
3589
+ (0, import_react24.useEffect)(() => {
3590
+ load();
3591
+ }, [load]);
3592
+ const selected = (0, import_react24.useMemo)(
3593
+ () => workforces.find((w) => idOf(w) === selectedId),
3594
+ [workforces, selectedId]
3595
+ );
3596
+ return {
3597
+ workforces,
3598
+ selectedId,
3599
+ setSelectedId,
3600
+ selected,
3601
+ isLoading,
3602
+ error,
3603
+ refresh: load
3604
+ };
3605
+ }
3606
+ function idOf(item) {
3607
+ return item.id ?? item.uid ?? item.name ?? "";
3608
+ }
3609
+
3610
+ // src/components/workforce-selector.tsx
3611
+ var import_lucide_react8 = require("lucide-react");
3612
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3613
+ var WorkforceSelector = ({
3614
+ workforces,
3615
+ value,
3616
+ onChange,
3617
+ hideWhenSingle = true,
3618
+ className,
3619
+ placeholder = "Select agent"
3620
+ }) => {
3621
+ if (workforces.length === 0) return null;
3622
+ if (hideWhenSingle && workforces.length === 1) return null;
3623
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("aui-workforce-selector relative inline-flex items-center", className), children: [
3624
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3625
+ "select",
3626
+ {
3627
+ className: "aui-workforce-selector-input h-7 cursor-pointer appearance-none rounded-md border-none bg-transparent pr-5 pl-1.5 text-xs font-medium text-muted-foreground shadow-none outline-none ring-0 transition-colors hover:text-foreground focus:ring-0",
3628
+ value,
3629
+ onChange: (e) => onChange(e.target.value),
3630
+ "aria-label": placeholder,
3631
+ children: [
3632
+ !value && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: "", children: placeholder }),
3633
+ workforces.map((w) => {
3634
+ const id = idOf2(w);
3635
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: id, children: w.name ?? id }, id);
3636
+ })
3637
+ ]
3638
+ }
3639
+ ),
3640
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react8.ChevronDownIcon, { className: "aui-workforce-selector-icon pointer-events-none absolute right-1 size-3 text-muted-foreground" })
3641
+ ] });
3642
+ };
3643
+ function idOf2(item) {
3644
+ return item.id ?? item.uid ?? item.name ?? "";
3645
+ }
3646
+
3647
+ // src/components/chat-shell.tsx
3648
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3649
+ var TimbalChatShell = ({
3650
+ workforceId,
3651
+ brand,
3652
+ headerActions,
3653
+ hideWorkforceSelector,
3654
+ className,
3655
+ headerClassName,
3656
+ baseUrl,
3657
+ fetch: fetch2,
3658
+ ...chatProps
3659
+ }) => {
3660
+ const {
3661
+ workforces,
3662
+ selectedId,
3663
+ setSelectedId
3664
+ } = useWorkforces({ baseUrl, fetch: fetch2 });
3665
+ const effectiveId = workforceId ?? selectedId;
3666
+ const showSelector = !hideWorkforceSelector && !workforceId && workforces.length > 0;
3667
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3668
+ "div",
3669
+ {
3670
+ className: cn(
3671
+ "aui-chat-shell flex h-screen flex-col overflow-hidden",
3672
+ className
3673
+ ),
3674
+ children: [
3675
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
3676
+ "header",
3677
+ {
3678
+ className: cn(
3679
+ "aui-chat-shell-header flex shrink-0 items-center justify-between border-b border-border/50 bg-background/90 px-5 py-2 backdrop-blur-md",
3680
+ headerClassName
3681
+ ),
3682
+ children: [
3683
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center", children: [
3684
+ brand,
3685
+ showSelector && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
3686
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "mx-3.5 h-3.5 w-px bg-border" }),
3687
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3688
+ WorkforceSelector,
3689
+ {
3690
+ workforces,
3691
+ value: selectedId,
3692
+ onChange: setSelectedId
3693
+ }
3694
+ )
3695
+ ] })
3696
+ ] }),
3697
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex items-center gap-0.5", children: headerActions })
3698
+ ]
3699
+ }
3700
+ ),
3701
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
3702
+ TimbalChat,
3703
+ {
3704
+ workforceId: effectiveId,
3705
+ baseUrl,
3706
+ fetch: fetch2,
3707
+ className: "min-h-0 flex-1",
3708
+ ...chatProps
3709
+ },
3710
+ effectiveId
3711
+ )
3712
+ ]
3713
+ }
3714
+ );
3715
+ };
1554
3716
 
1555
3717
  // src/auth/provider.tsx
1556
- var import_react12 = require("react");
1557
- var import_jsx_runtime14 = require("react/jsx-runtime");
1558
- var SessionContext = (0, import_react12.createContext)(void 0);
3718
+ var import_react25 = require("react");
3719
+ var import_jsx_runtime29 = require("react/jsx-runtime");
3720
+ function isInsideIframe() {
3721
+ try {
3722
+ return typeof window !== "undefined" && window.self !== window.top;
3723
+ } catch {
3724
+ return true;
3725
+ }
3726
+ }
3727
+ var SessionContext = (0, import_react25.createContext)(void 0);
1559
3728
  var useSession = () => {
1560
- const context = (0, import_react12.useContext)(SessionContext);
3729
+ const context = (0, import_react25.useContext)(SessionContext);
1561
3730
  if (context === void 0) {
1562
3731
  throw new Error("useSession must be used within a SessionProvider");
1563
3732
  }
@@ -1567,9 +3736,10 @@ var SessionProvider = ({
1567
3736
  children,
1568
3737
  enabled = true
1569
3738
  }) => {
1570
- const [user, setUser] = (0, import_react12.useState)(null);
1571
- const [loading, setLoading] = (0, import_react12.useState)(enabled);
1572
- (0, import_react12.useEffect)(() => {
3739
+ const [user, setUser] = (0, import_react25.useState)(null);
3740
+ const [loading, setLoading] = (0, import_react25.useState)(enabled);
3741
+ const [embedded] = (0, import_react25.useState)(isInsideIframe);
3742
+ (0, import_react25.useEffect)(() => {
1573
3743
  if (!enabled) {
1574
3744
  setLoading(false);
1575
3745
  return;
@@ -1601,14 +3771,36 @@ var SessionProvider = ({
1601
3771
  if (ignore) return;
1602
3772
  clearTokens();
1603
3773
  }
1604
- setLoading(false);
3774
+ if (!ignore && !embedded) {
3775
+ setLoading(false);
3776
+ }
1605
3777
  };
1606
3778
  restoreSession();
3779
+ let messageCleanup;
3780
+ if (embedded) {
3781
+ const handleMessage = async (event) => {
3782
+ if (ignore) return;
3783
+ if (event.data?.type !== "timbal:auth" || !event.data.token) return;
3784
+ setAccessToken(event.data.token);
3785
+ if (event.data.refreshToken) {
3786
+ setRefreshToken(event.data.refreshToken);
3787
+ }
3788
+ const u = await fetchCurrentUser();
3789
+ if (!ignore) {
3790
+ setUser(u);
3791
+ setLoading(false);
3792
+ }
3793
+ };
3794
+ window.addEventListener("message", handleMessage);
3795
+ window.parent.postMessage({ type: "timbal:request-session" }, "*");
3796
+ messageCleanup = () => window.removeEventListener("message", handleMessage);
3797
+ }
1607
3798
  return () => {
1608
3799
  ignore = true;
3800
+ messageCleanup?.();
1609
3801
  };
1610
- }, [enabled]);
1611
- const logout = (0, import_react12.useCallback)(() => {
3802
+ }, [enabled, embedded]);
3803
+ const logout = (0, import_react25.useCallback)(() => {
1612
3804
  clearTokens();
1613
3805
  setUser(null);
1614
3806
  const returnTo = encodeURIComponent(
@@ -1618,13 +3810,14 @@ var SessionProvider = ({
1618
3810
  () => window.location.href = `/api/auth/login?return_to=${returnTo}`
1619
3811
  );
1620
3812
  }, []);
1621
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3813
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1622
3814
  SessionContext.Provider,
1623
3815
  {
1624
3816
  value: {
1625
3817
  user,
1626
3818
  loading,
1627
3819
  isAuthenticated: !!user,
3820
+ isEmbedded: embedded,
1628
3821
  logout
1629
3822
  },
1630
3823
  children
@@ -1633,21 +3826,21 @@ var SessionProvider = ({
1633
3826
  };
1634
3827
 
1635
3828
  // src/auth/guard.tsx
1636
- var import_lucide_react6 = require("lucide-react");
1637
- var import_jsx_runtime15 = require("react/jsx-runtime");
3829
+ var import_lucide_react9 = require("lucide-react");
3830
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1638
3831
  var AuthGuard = ({
1639
3832
  children,
1640
3833
  requireAuth = false,
1641
3834
  enabled = true
1642
3835
  }) => {
1643
- const { isAuthenticated, loading } = useSession();
3836
+ const { isAuthenticated, loading, isEmbedded } = useSession();
1644
3837
  if (!enabled) {
1645
3838
  return children;
1646
3839
  }
1647
3840
  if (loading) {
1648
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Loader2, { className: "w-8 h-8 animate-spin" }) });
3841
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react9.Loader2, { className: "w-8 h-8 animate-spin" }) });
1649
3842
  }
1650
- if (requireAuth && !isAuthenticated) {
3843
+ if (requireAuth && !isAuthenticated && !isEmbedded) {
1651
3844
  const returnTo = encodeURIComponent(
1652
3845
  window.location.pathname + window.location.search
1653
3846
  );
@@ -1658,15 +3851,24 @@ var AuthGuard = ({
1658
3851
  };
1659
3852
  // Annotate the CommonJS export names for ESM import in node:
1660
3853
  0 && (module.exports = {
3854
+ ARTIFACT_AGENT_INSTRUCTIONS,
3855
+ ARTIFACT_FENCE_LANGUAGES,
1661
3856
  ActionBarPrimitive,
3857
+ ArtifactCard,
3858
+ ArtifactRegistryProvider,
3859
+ ArtifactView,
3860
+ AssistantRuntimeProvider,
1662
3861
  AuthGuard,
1663
3862
  Avatar,
1664
3863
  AvatarFallback,
1665
3864
  AvatarImage,
1666
3865
  Button,
3866
+ ChartArtifactView,
3867
+ Composer,
1667
3868
  ComposerAddAttachment,
1668
3869
  ComposerAttachments,
1669
3870
  ComposerPrimitive,
3871
+ DEFAULT_UPLOAD_ACCEPT,
1670
3872
  Dialog,
1671
3873
  DialogClose,
1672
3874
  DialogContent,
@@ -1674,33 +3876,70 @@ var AuthGuard = ({
1674
3876
  DialogPortal,
1675
3877
  DialogTitle,
1676
3878
  DialogTrigger,
3879
+ HtmlArtifactView,
3880
+ JsonArtifactView,
1677
3881
  MarkdownText,
1678
3882
  MessagePrimitive,
3883
+ QuestionArtifactView,
1679
3884
  SessionProvider,
1680
3885
  Shimmer,
3886
+ Suggestions,
1681
3887
  SyntaxHighlighter,
3888
+ TableArtifactView,
1682
3889
  Thread,
1683
3890
  ThreadPrimitive,
1684
3891
  TimbalChat,
3892
+ TimbalChatShell,
1685
3893
  TimbalRuntimeProvider,
3894
+ ToolArtifactFallback,
1686
3895
  ToolFallback,
1687
3896
  Tooltip,
1688
3897
  TooltipContent,
1689
3898
  TooltipIconButton,
1690
3899
  TooltipProvider,
1691
3900
  TooltipTrigger,
3901
+ UiArtifactView,
3902
+ UiCustomNodeRegistryProvider,
3903
+ UiEventProvider,
3904
+ UiNodeView,
1692
3905
  UserMessageAttachments,
3906
+ WorkforceSelector,
1693
3907
  authFetch,
1694
3908
  buttonVariants,
1695
3909
  clearTokens,
1696
3910
  cn,
3911
+ createDefaultAttachmentAdapter,
3912
+ createUploadAttachmentAdapter,
3913
+ defaultArtifactRenderers,
1697
3914
  fetchCurrentUser,
3915
+ findMarkdownArtifacts,
1698
3916
  getAccessToken,
3917
+ getPath,
1699
3918
  getRefreshToken,
3919
+ isArtifact,
3920
+ isArtifactFenceLanguage,
3921
+ isUiBinding,
3922
+ parseArtifactFromToolResult,
3923
+ parseSSELine,
1700
3924
  refreshAccessToken,
3925
+ resolveAttachmentAdapter,
3926
+ resolveBindable,
3927
+ setAccessToken,
3928
+ setPath,
3929
+ setRefreshToken,
3930
+ splitMarkdownByArtifacts,
3931
+ useArtifactRegistry,
1701
3932
  useComposerRuntime,
1702
3933
  useMessageRuntime,
3934
+ useResolvedSuggestions,
1703
3935
  useSession,
1704
3936
  useThread,
1705
- useThreadRuntime
3937
+ useThreadRuntime,
3938
+ useTimbalRuntime,
3939
+ useTimbalStream,
3940
+ useUiCustomNodeRegistry,
3941
+ useUiDispatch,
3942
+ useUiEventEmitter,
3943
+ useUiState,
3944
+ useWorkforces
1706
3945
  });