@assistant-ui/react 0.5.45 → 0.5.47

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  toLanguageModelMessages,
11
11
  toLanguageModelTools,
12
12
  toolResultStream
13
- } from "./chunk-5ZTUOAPH.mjs";
13
+ } from "./chunk-TZO3D3VQ.mjs";
14
14
  import {
15
15
  __export
16
16
  } from "./chunk-BJPOCE4O.mjs";
@@ -125,21 +125,26 @@ var makeComposerStore = (useThreadRuntime) => {
125
125
  setValue(value) {
126
126
  get().setText(value);
127
127
  },
128
+ attachments: runtime.composer.attachments,
129
+ addAttachment: (file) => {
130
+ useThreadRuntime.getState().composer.addAttachment(file);
131
+ },
132
+ removeAttachment: (attachmentId) => {
133
+ useThreadRuntime.getState().composer.removeAttachment(attachmentId);
134
+ },
135
+ reset: () => {
136
+ useThreadRuntime.getState().composer.reset();
137
+ },
128
138
  text: runtime.composer.text,
129
- setText: (value) => {
130
- useThreadRuntime.getState().composer.setText(value);
139
+ setText: (text) => {
140
+ useThreadRuntime.getState().composer.setText(text);
131
141
  },
132
142
  canCancel: runtime.capabilities.cancel,
133
143
  isEditing: true,
144
+ isEmpty: runtime.composer.isEmpty,
134
145
  send: () => {
135
146
  const runtime2 = useThreadRuntime.getState();
136
- const text = runtime2.composer.text;
137
- runtime2.composer.setText("");
138
- runtime2.append({
139
- parentId: runtime2.messages.at(-1)?.id ?? null,
140
- role: "user",
141
- content: [{ type: "text", text }]
142
- });
147
+ runtime2.composer.send();
143
148
  },
144
149
  cancel: () => {
145
150
  useThreadRuntime.getState().cancelRun();
@@ -275,6 +280,7 @@ __export(internal_exports, {
275
280
  BaseAssistantRuntime: () => BaseAssistantRuntime,
276
281
  MessageRepository: () => MessageRepository,
277
282
  ProxyConfigProvider: () => ProxyConfigProvider,
283
+ ThreadRuntimeComposer: () => ThreadRuntimeComposer,
278
284
  TooltipIconButton: () => TooltipIconButton,
279
285
  generateId: () => generateId,
280
286
  useSmooth: () => useSmooth,
@@ -282,6 +288,76 @@ __export(internal_exports, {
282
288
  withSmoothContextProvider: () => withSmoothContextProvider
283
289
  });
284
290
 
291
+ // src/runtimes/utils/ThreadRuntimeComposer.tsx
292
+ var ThreadRuntimeComposer = class {
293
+ constructor(runtime, notifySubscribers) {
294
+ this.runtime = runtime;
295
+ this.notifySubscribers = notifySubscribers;
296
+ }
297
+ _attachmentAdapter;
298
+ attachmentAccept = "*";
299
+ get isEmpty() {
300
+ return !this.text.trim() && !this.attachments.length;
301
+ }
302
+ setAttachmentAdapter(adapter) {
303
+ this._attachmentAdapter = adapter;
304
+ const accept = adapter?.accept ?? "*";
305
+ if (this.attachmentAccept !== accept) {
306
+ this.attachmentAccept = accept;
307
+ return true;
308
+ }
309
+ return false;
310
+ }
311
+ _attachments = [];
312
+ get attachments() {
313
+ return this._attachments;
314
+ }
315
+ async addAttachment(file) {
316
+ if (!this._attachmentAdapter)
317
+ throw new Error("Attachments are not supported");
318
+ const attachment = await this._attachmentAdapter.add({ file });
319
+ this._attachments = [...this._attachments, attachment];
320
+ this.notifySubscribers();
321
+ }
322
+ async removeAttachment(attachmentId) {
323
+ if (!this._attachmentAdapter)
324
+ throw new Error("Attachments are not supported");
325
+ const index = this._attachments.findIndex((a) => a.id === attachmentId);
326
+ if (index === -1) throw new Error("Attachment not found");
327
+ const attachment = this._attachments[index];
328
+ await this._attachmentAdapter.remove(attachment);
329
+ this._attachments = this._attachments.toSpliced(index, 1);
330
+ this.notifySubscribers();
331
+ }
332
+ _text = "";
333
+ get text() {
334
+ return this._text;
335
+ }
336
+ setText(value) {
337
+ this._text = value;
338
+ this.notifySubscribers();
339
+ }
340
+ reset() {
341
+ this._text = "";
342
+ this._attachments = [];
343
+ this.notifySubscribers();
344
+ }
345
+ async send() {
346
+ const attachments = this._attachmentAdapter ? await Promise.all(
347
+ this.attachments.map(
348
+ async (a) => await this._attachmentAdapter.send(a)
349
+ )
350
+ ) : [];
351
+ this.runtime.append({
352
+ parentId: this.runtime.messages.at(-1)?.id ?? null,
353
+ role: "user",
354
+ content: this.text ? [{ type: "text", text: this.text }] : [],
355
+ attachments
356
+ });
357
+ this.reset();
358
+ }
359
+ };
360
+
285
361
  // src/utils/idUtils.tsx
286
362
  import { customAlphabet } from "nanoid/non-secure";
287
363
  var generateId = customAlphabet(
@@ -324,7 +400,8 @@ var fromCoreMessage = (message, {
324
400
  return {
325
401
  ...commonProps,
326
402
  role,
327
- content: message.content
403
+ content: message.content,
404
+ attachments: []
328
405
  };
329
406
  case "system":
330
407
  return {
@@ -1101,31 +1178,37 @@ var LocalThreadRuntime = class {
1101
1178
  reload: true,
1102
1179
  cancel: true,
1103
1180
  unstable_copy: true,
1104
- speak: false
1181
+ speak: false,
1182
+ attachments: false
1105
1183
  };
1106
1184
  threadId;
1107
1185
  isDisabled = false;
1108
1186
  get messages() {
1109
1187
  return this.repository.getMessages();
1110
1188
  }
1111
- composer = {
1112
- text: "",
1113
- setText: (value) => {
1114
- this.composer.text = value;
1115
- this.notifySubscribers();
1116
- }
1117
- };
1189
+ composer = new ThreadRuntimeComposer(
1190
+ this,
1191
+ this.notifySubscribers.bind(this)
1192
+ );
1118
1193
  _options;
1119
1194
  get options() {
1120
1195
  return this._options;
1121
1196
  }
1122
1197
  set options({ initialMessages, ...options }) {
1123
1198
  this._options = options;
1199
+ let hasUpdates = false;
1124
1200
  const canSpeak = options.adapters?.speech !== void 0;
1125
1201
  if (this.capabilities.speak !== canSpeak) {
1126
1202
  this.capabilities.speak = canSpeak;
1127
- this.notifySubscribers();
1203
+ hasUpdates = true;
1128
1204
  }
1205
+ this.composer.setAttachmentAdapter(options.adapters?.attachments);
1206
+ const canAttach = options.adapters?.attachments !== void 0;
1207
+ if (this.capabilities.attachments !== canAttach) {
1208
+ this.capabilities.attachments = canAttach;
1209
+ hasUpdates = true;
1210
+ }
1211
+ if (hasUpdates) this.notifySubscribers();
1129
1212
  }
1130
1213
  getBranches(messageId) {
1131
1214
  return this.repository.getBranches(messageId);
@@ -1144,6 +1227,7 @@ var LocalThreadRuntime = class {
1144
1227
  id: userMessageId,
1145
1228
  role: "user",
1146
1229
  content: message.content,
1230
+ attachments: message.attachments ?? [],
1147
1231
  createdAt: /* @__PURE__ */ new Date()
1148
1232
  };
1149
1233
  this.repository.addOrUpdateMessage(message.parentId, userMessage);
@@ -1406,12 +1490,14 @@ var getAutoStatus = (isLast, isRunning) => isLast && isRunning ? AUTO_STATUS_RUN
1406
1490
 
1407
1491
  // src/runtimes/external-store/ThreadMessageLike.tsx
1408
1492
  var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
1409
- const { role, id, createdAt, status } = like;
1493
+ const { role, id, createdAt, attachments, status } = like;
1410
1494
  const common = {
1411
1495
  id: id ?? fallbackId,
1412
1496
  createdAt: createdAt ?? /* @__PURE__ */ new Date()
1413
1497
  };
1414
1498
  const content = typeof like.content === "string" ? [{ type: "text", text: like.content }] : like.content;
1499
+ if (role !== "user" && attachments)
1500
+ throw new Error("Attachments are only supported for user messages");
1415
1501
  switch (role) {
1416
1502
  case "assistant":
1417
1503
  return {
@@ -1456,7 +1542,8 @@ var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
1456
1542
  throw new Error(`Unknown content part type: ${unhandledType}`);
1457
1543
  }
1458
1544
  }
1459
- })
1545
+ }),
1546
+ attachments: attachments ?? []
1460
1547
  };
1461
1548
  case "system":
1462
1549
  if (content.length !== 1 || content[0].type !== "text")
@@ -1497,7 +1584,8 @@ var ExternalStoreThreadRuntime = class {
1497
1584
  reload: false,
1498
1585
  cancel: false,
1499
1586
  unstable_copy: false,
1500
- speak: false
1587
+ speak: false,
1588
+ attachments: false
1501
1589
  };
1502
1590
  get capabilities() {
1503
1591
  return this._capabilities;
@@ -1507,13 +1595,10 @@ var ExternalStoreThreadRuntime = class {
1507
1595
  isDisabled;
1508
1596
  converter = new ThreadMessageConverter();
1509
1597
  _store;
1510
- composer = {
1511
- text: "",
1512
- setText: (value) => {
1513
- this.composer.text = value;
1514
- this.notifySubscribers();
1515
- }
1516
- };
1598
+ composer = new ThreadRuntimeComposer(
1599
+ this,
1600
+ this.notifySubscribers.bind(this)
1601
+ );
1517
1602
  constructor(store) {
1518
1603
  this.store = store;
1519
1604
  }
@@ -1532,9 +1617,12 @@ var ExternalStoreThreadRuntime = class {
1532
1617
  edit: this._store.onEdit !== void 0,
1533
1618
  reload: this._store.onReload !== void 0,
1534
1619
  cancel: this._store.onCancel !== void 0,
1535
- unstable_copy: this._store.unstable_capabilities?.copy !== null,
1536
- speak: this._store.onSpeak !== void 0
1620
+ speak: this._store.onSpeak !== void 0,
1621
+ unstable_copy: this._store.unstable_capabilities?.copy !== false,
1622
+ // default true
1623
+ attachments: !!this.store.adapters?.attachments
1537
1624
  };
1625
+ this.composer.setAttachmentAdapter(this._store.adapters?.attachments);
1538
1626
  if (oldStore) {
1539
1627
  if (oldStore.convertMessage !== store.convertMessage) {
1540
1628
  this.converter = new ThreadMessageConverter();
@@ -1925,6 +2013,147 @@ var WebSpeechSynthesisAdapter = class {
1925
2013
  }
1926
2014
  };
1927
2015
 
2016
+ // src/runtimes/attachment/SimpleImageAttachmentAdapter.ts
2017
+ var SimpleImageAttachmentAdapter = class {
2018
+ accept = "image/*";
2019
+ async add(state) {
2020
+ return {
2021
+ id: state.file.name,
2022
+ type: "image",
2023
+ name: state.file.name,
2024
+ file: state.file
2025
+ };
2026
+ }
2027
+ async send(attachment) {
2028
+ return {
2029
+ ...attachment,
2030
+ content: [
2031
+ {
2032
+ type: "image",
2033
+ image: await getFileDataURL(attachment.file)
2034
+ }
2035
+ ]
2036
+ };
2037
+ }
2038
+ async remove() {
2039
+ }
2040
+ };
2041
+ var getFileDataURL = (file) => new Promise((resolve, reject) => {
2042
+ const reader = new FileReader();
2043
+ reader.onload = () => resolve(reader.result);
2044
+ reader.onerror = (error) => reject(error);
2045
+ reader.readAsDataURL(file);
2046
+ });
2047
+
2048
+ // src/runtimes/attachment/SimpleTextAttachmentAdapter.ts
2049
+ var SimpleTextAttachmentAdapter = class {
2050
+ accept = "text/plain,text/html,text/markdown,text/csv,text/xml,text/json,text/css";
2051
+ async add(state) {
2052
+ return {
2053
+ id: state.file.name,
2054
+ type: "document",
2055
+ name: state.file.name,
2056
+ file: state.file
2057
+ };
2058
+ }
2059
+ async send(attachment) {
2060
+ return {
2061
+ ...attachment,
2062
+ content: [
2063
+ {
2064
+ type: "text",
2065
+ text: `<attachment name=${attachment.name}>
2066
+ ${await getFileText(attachment.file)}
2067
+ </attachment>`
2068
+ }
2069
+ ]
2070
+ };
2071
+ }
2072
+ async remove() {
2073
+ }
2074
+ };
2075
+ var getFileText = (file) => new Promise((resolve, reject) => {
2076
+ const reader = new FileReader();
2077
+ reader.onload = () => resolve(reader.result);
2078
+ reader.onerror = (error) => reject(error);
2079
+ reader.readAsText(file);
2080
+ });
2081
+
2082
+ // src/runtimes/attachment/CompositeAttachmentAdapter.ts
2083
+ function fileMatchesAccept(file, acceptString) {
2084
+ if (acceptString === "*") {
2085
+ return true;
2086
+ }
2087
+ const allowedTypes = acceptString.split(",").map((type) => type.trim().toLowerCase());
2088
+ const fileExtension = "." + file.name.split(".").pop().toLowerCase();
2089
+ const fileMimeType = file.type.toLowerCase();
2090
+ for (const type of allowedTypes) {
2091
+ if (type.startsWith(".") && type === fileExtension) {
2092
+ return true;
2093
+ }
2094
+ if (type.includes("/") && type === fileMimeType) {
2095
+ return true;
2096
+ }
2097
+ if (type === "image/*" || type === "video/*" || type === "audio/*") {
2098
+ if (type.endsWith("/*")) {
2099
+ const generalType = type.split("/")[0];
2100
+ if (fileMimeType.startsWith(generalType + "/")) {
2101
+ return true;
2102
+ }
2103
+ }
2104
+ }
2105
+ }
2106
+ return false;
2107
+ }
2108
+ var CompositeAttachmentAdapter = class {
2109
+ _adapters;
2110
+ accept;
2111
+ constructor(adapters) {
2112
+ this._adapters = adapters;
2113
+ const wildcardIdx = adapters.findIndex((a) => a.accept === "*");
2114
+ if (wildcardIdx !== -1) {
2115
+ if (wildcardIdx !== adapters.length - 1)
2116
+ throw new Error(
2117
+ "A wildcard adapter (handling all files) can only be specified as the last adapter."
2118
+ );
2119
+ this.accept = "*";
2120
+ } else {
2121
+ this.accept = adapters.map((a) => a.accept).join(",");
2122
+ }
2123
+ }
2124
+ async add(state) {
2125
+ for (const adapter of this._adapters) {
2126
+ if (fileMatchesAccept(state.file, adapter.accept)) {
2127
+ return adapter.add(state);
2128
+ }
2129
+ }
2130
+ throw new Error("No matching adapter found for file");
2131
+ }
2132
+ async send(attachment) {
2133
+ const adapters = this._adapters.slice();
2134
+ for (const adapter of adapters) {
2135
+ if (fileMatchesAccept(attachment.file, adapter.accept)) {
2136
+ return adapter.send(attachment);
2137
+ }
2138
+ }
2139
+ throw new Error("No matching adapter found for attachment");
2140
+ }
2141
+ async remove(attachment) {
2142
+ const adapters = this._adapters.slice();
2143
+ for (const adapter of adapters) {
2144
+ if (fileMatchesAccept(attachment.file, adapter.accept)) {
2145
+ return adapter.remove(attachment);
2146
+ }
2147
+ }
2148
+ throw new Error("No matching adapter found for attachment");
2149
+ }
2150
+ };
2151
+
2152
+ // src/context/ReadonlyStore.ts
2153
+ var writableStore = (store) => {
2154
+ return store;
2155
+ };
2156
+
1928
2157
  // src/context/providers/ThreadProvider.tsx
1929
2158
  import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
1930
2159
  var ThreadProvider = ({
@@ -1954,18 +2183,20 @@ var ThreadProvider = ({
1954
2183
  const state = getThreadStateFromRuntime(thread);
1955
2184
  if (oldState.threadId !== state.threadId || oldState.isDisabled !== state.isDisabled || oldState.isRunning !== state.isRunning || // TODO ensure capabilities is memoized
1956
2185
  oldState.capabilities !== state.capabilities) {
1957
- context.useThread.setState(
1958
- state,
1959
- true
1960
- );
2186
+ writableStore(context.useThread).setState(state, true);
1961
2187
  }
1962
2188
  if (thread.messages !== context.useThreadMessages.getState()) {
1963
- context.useThreadMessages.setState(thread.messages, true);
2189
+ writableStore(context.useThreadMessages).setState(
2190
+ thread.messages,
2191
+ true
2192
+ );
1964
2193
  }
1965
2194
  const composerState = context.useComposer.getState();
1966
- if (thread.composer.text !== composerState.text || state.capabilities.cancel !== composerState.canCancel) {
1967
- context.useComposer.setState({
2195
+ if (thread.composer.isEmpty !== composerState.isEmpty || thread.composer.text !== composerState.text || thread.composer.attachments !== composerState.attachments || state.capabilities.cancel !== composerState.canCancel) {
2196
+ writableStore(context.useComposer).setState({
2197
+ isEmpty: thread.composer.isEmpty,
1968
2198
  text: thread.composer.text,
2199
+ attachments: thread.composer.attachments,
1969
2200
  canCancel: state.capabilities.cancel
1970
2201
  });
1971
2202
  }
@@ -1975,7 +2206,7 @@ var ThreadProvider = ({
1975
2206
  }, [provider, context]);
1976
2207
  useInsertionEffect2(
1977
2208
  () => provider.subscribe(() => {
1978
- context.useThreadRuntime.setState(provider.thread, true);
2209
+ writableStore(context.useThreadRuntime).setState(provider.thread, true);
1979
2210
  }),
1980
2211
  [provider, context]
1981
2212
  );
@@ -2027,7 +2258,7 @@ var AssistantProvider = ({ children, runtime }) => {
2027
2258
  return runtime.registerModelConfigProvider(getModelConfig);
2028
2259
  }, [runtime, getModelConfig]);
2029
2260
  useEffect4(
2030
- () => context.useAssistantRuntime.setState(runtime, true),
2261
+ () => writableStore(context.useAssistantRuntime).setState(runtime, true),
2031
2262
  [runtime, context]
2032
2263
  );
2033
2264
  return /* @__PURE__ */ jsx7(AssistantContext.Provider, { value: context, children: /* @__PURE__ */ jsx7(ThreadProvider, { provider: runtime, children }) });
@@ -2089,13 +2320,15 @@ var toAppendMessage = (useThreadMessages, message) => {
2089
2320
  return {
2090
2321
  parentId: useThreadMessages.getState().at(-1)?.id ?? null,
2091
2322
  role: "user",
2092
- content: [{ type: "text", text: message }]
2323
+ content: [{ type: "text", text: message }],
2324
+ attachments: []
2093
2325
  };
2094
2326
  }
2095
2327
  return {
2096
2328
  parentId: message.parentId ?? useThreadMessages.getState().at(-1)?.id ?? null,
2097
2329
  role: message.role ?? "user",
2098
- content: message.content
2330
+ content: message.content,
2331
+ attachments: message.attachments ?? []
2099
2332
  };
2100
2333
  };
2101
2334
  var useAppendMessage = () => {
@@ -2156,6 +2389,7 @@ var makeAssistantTool = (tool) => {
2156
2389
  useAssistantTool(tool);
2157
2390
  return null;
2158
2391
  };
2392
+ Tool.unstable_tool = tool;
2159
2393
  return Tool;
2160
2394
  };
2161
2395
 
@@ -2177,6 +2411,7 @@ var makeAssistantToolUI = (tool) => {
2177
2411
  useAssistantToolUI(tool);
2178
2412
  return null;
2179
2413
  };
2414
+ ToolUI.unstable_tool = tool;
2180
2415
  return ToolUI;
2181
2416
  };
2182
2417
 
@@ -2398,7 +2633,7 @@ var useComposerSend = () => {
2398
2633
  const { useComposer } = useComposerContext();
2399
2634
  const disabled = useCombinedStore(
2400
2635
  [useThread, useComposer],
2401
- (t, c) => t.isRunning || !c.isEditing || c.text.length === 0
2636
+ (t, c) => t.isRunning || !c.isEditing || c.isEmpty
2402
2637
  );
2403
2638
  const callback = useCallback11(() => {
2404
2639
  const composerState = useComposer.getState();
@@ -2411,6 +2646,30 @@ var useComposerSend = () => {
2411
2646
  return callback;
2412
2647
  };
2413
2648
 
2649
+ // src/primitive-hooks/composer/useComposerAddAttachment.tsx
2650
+ import { useCallback as useCallback12 } from "react";
2651
+ var useComposerAddAttachment = () => {
2652
+ const { useComposer, useThreadRuntime } = useThreadContext();
2653
+ const disabled = useComposer((c) => !c.isEditing);
2654
+ const callback = useCallback12(() => {
2655
+ const { addAttachment } = useComposer.getState();
2656
+ const { attachmentAccept } = useThreadRuntime.getState().composer;
2657
+ const input = document.createElement("input");
2658
+ input.type = "file";
2659
+ if (attachmentAccept !== "*") {
2660
+ input.accept = attachmentAccept;
2661
+ }
2662
+ input.onchange = (e) => {
2663
+ const file = e.target.files?.[0];
2664
+ if (!file) return;
2665
+ addAttachment(file);
2666
+ };
2667
+ input.click();
2668
+ }, [useComposer, useThreadRuntime]);
2669
+ if (disabled) return null;
2670
+ return callback;
2671
+ };
2672
+
2414
2673
  // src/primitive-hooks/contentPart/useContentPartDisplay.tsx
2415
2674
  var useContentPartDisplay = () => {
2416
2675
  const { useContentPart } = useContentPartContext();
@@ -2465,6 +2724,10 @@ var useMessageIf = (props) => {
2465
2724
  if (props.copied === false && isCopied) return false;
2466
2725
  if (props.speaking === true && !isSpeaking) return false;
2467
2726
  if (props.speaking === false && isSpeaking) return false;
2727
+ if (props.hasAttachments === true && (message.role !== "user" || !message.attachments.length))
2728
+ return false;
2729
+ if (props.hasAttachments === false && message.role === "user" && !!message.attachments.length)
2730
+ return false;
2468
2731
  return true;
2469
2732
  }
2470
2733
  );
@@ -2493,11 +2756,11 @@ var useThreadEmpty = () => {
2493
2756
  };
2494
2757
 
2495
2758
  // src/primitive-hooks/thread/useThreadScrollToBottom.tsx
2496
- import { useCallback as useCallback12 } from "react";
2759
+ import { useCallback as useCallback13 } from "react";
2497
2760
  var useThreadScrollToBottom = () => {
2498
2761
  const { useComposer, useViewport } = useThreadContext();
2499
2762
  const isAtBottom = useViewport((s) => s.isAtBottom);
2500
- const handleScrollToBottom = useCallback12(() => {
2763
+ const handleScrollToBottom = useCallback13(() => {
2501
2764
  useViewport.getState().scrollToBottom();
2502
2765
  useComposer.getState().focus();
2503
2766
  }, [useViewport, useComposer]);
@@ -2506,7 +2769,7 @@ var useThreadScrollToBottom = () => {
2506
2769
  };
2507
2770
 
2508
2771
  // src/primitive-hooks/thread/useThreadSuggestion.tsx
2509
- import { useCallback as useCallback13 } from "react";
2772
+ import { useCallback as useCallback14 } from "react";
2510
2773
  var useThreadSuggestion = ({
2511
2774
  prompt,
2512
2775
  autoSend
@@ -2514,7 +2777,7 @@ var useThreadSuggestion = ({
2514
2777
  const { useThread, useComposer } = useThreadContext();
2515
2778
  const append = useAppendMessage();
2516
2779
  const disabled = useThread((t) => t.isDisabled);
2517
- const callback = useCallback13(() => {
2780
+ const callback = useCallback14(() => {
2518
2781
  const thread = useThread.getState();
2519
2782
  const composer = useComposer.getState();
2520
2783
  if (autoSend && !thread.isRunning) {
@@ -2842,6 +3105,7 @@ import { forwardRef as forwardRef14 } from "react";
2842
3105
  // src/primitives/message/index.ts
2843
3106
  var message_exports = {};
2844
3107
  __export(message_exports, {
3108
+ Attachments: () => MessagePrimitiveAttachments,
2845
3109
  Content: () => MessagePrimitiveContent,
2846
3110
  If: () => MessagePrimitiveIf,
2847
3111
  InProgress: () => MessagePrimitiveInProgress,
@@ -2852,14 +3116,14 @@ __export(message_exports, {
2852
3116
  import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
2853
3117
  import {
2854
3118
  forwardRef as forwardRef11,
2855
- useCallback as useCallback15
3119
+ useCallback as useCallback16
2856
3120
  } from "react";
2857
3121
 
2858
3122
  // src/utils/hooks/useManagedRef.ts
2859
- import { useCallback as useCallback14, useRef as useRef3 } from "react";
3123
+ import { useCallback as useCallback15, useRef as useRef3 } from "react";
2860
3124
  var useManagedRef = (callback) => {
2861
3125
  const cleanupRef = useRef3();
2862
- const ref = useCallback14(
3126
+ const ref = useCallback15(
2863
3127
  (el) => {
2864
3128
  if (cleanupRef.current) {
2865
3129
  cleanupRef.current();
@@ -2878,7 +3142,7 @@ import { useComposedRefs } from "@radix-ui/react-compose-refs";
2878
3142
  import { jsx as jsx18 } from "react/jsx-runtime";
2879
3143
  var useIsHoveringRef = () => {
2880
3144
  const { useMessageUtils } = useMessageContext();
2881
- const callbackRef = useCallback15(
3145
+ const callbackRef = useCallback16(
2882
3146
  (el) => {
2883
3147
  const setIsHovering = useMessageUtils.getState().setIsHovering;
2884
3148
  const handleMouseEnter = () => {
@@ -2973,7 +3237,7 @@ var useContentPartContext2 = (partIndex) => {
2973
3237
  partIndex
2974
3238
  );
2975
3239
  if (!newState) return;
2976
- context.useContentPart.setState(newState, true);
3240
+ writableStore(context.useContentPart).setState(newState, true);
2977
3241
  };
2978
3242
  syncContentPart(useMessage.getState());
2979
3243
  return useMessage.subscribe(syncContentPart);
@@ -3033,21 +3297,22 @@ ContentPartPrimitiveInProgress.displayName = "ContentPartPrimitive.InProgress";
3033
3297
 
3034
3298
  // src/primitives/message/MessageContent.tsx
3035
3299
  import { jsx as jsx22, jsxs as jsxs3 } from "react/jsx-runtime";
3300
+ var ToolUIDisplay = ({
3301
+ UI,
3302
+ ...props
3303
+ }) => {
3304
+ const { useToolUIs } = useAssistantContext();
3305
+ const Render = useToolUIs((s) => s.getToolUI(props.part.toolName)) ?? UI;
3306
+ if (!Render) return null;
3307
+ return /* @__PURE__ */ jsx22(Render, { ...props });
3308
+ };
3036
3309
  var defaultComponents = {
3037
3310
  Text: () => /* @__PURE__ */ jsxs3("p", { style: { whiteSpace: "pre-line" }, children: [
3038
3311
  /* @__PURE__ */ jsx22(ContentPartPrimitiveText, {}),
3039
3312
  /* @__PURE__ */ jsx22(ContentPartPrimitiveInProgress, { children: /* @__PURE__ */ jsx22("span", { style: { fontFamily: "revert" }, children: " \u25CF" }) })
3040
3313
  ] }),
3041
3314
  Image: () => /* @__PURE__ */ jsx22(ContentPartPrimitiveImage, {}),
3042
- UI: () => /* @__PURE__ */ jsx22(ContentPartPrimitiveDisplay, {}),
3043
- tools: {
3044
- Fallback: (props) => {
3045
- const { useToolUIs } = useAssistantContext();
3046
- const Render = useToolUIs((s) => s.getToolUI(props.part.toolName));
3047
- if (!Render) return null;
3048
- return /* @__PURE__ */ jsx22(Render, { ...props });
3049
- }
3050
- }
3315
+ UI: () => /* @__PURE__ */ jsx22(ContentPartPrimitiveDisplay, {})
3051
3316
  };
3052
3317
  var MessageContentPartComponent = ({
3053
3318
  components: {
@@ -3055,7 +3320,7 @@ var MessageContentPartComponent = ({
3055
3320
  Text: Text2 = defaultComponents.Text,
3056
3321
  Image: Image2 = defaultComponents.Image,
3057
3322
  UI = defaultComponents.UI,
3058
- tools: { by_name = {}, Fallback: Fallback2 = defaultComponents.tools.Fallback } = {}
3323
+ tools: { by_name = {}, Fallback: Fallback2 = void 0 } = {}
3059
3324
  } = {}
3060
3325
  }) => {
3061
3326
  const { useThreadActions } = useThreadContext();
@@ -3086,7 +3351,15 @@ var MessageContentPartComponent = ({
3086
3351
  toolCallId: part.toolCallId,
3087
3352
  result
3088
3353
  });
3089
- return /* @__PURE__ */ jsx22(Tool, { part, status, addResult });
3354
+ return /* @__PURE__ */ jsx22(
3355
+ ToolUIDisplay,
3356
+ {
3357
+ UI: Tool,
3358
+ part,
3359
+ status,
3360
+ addResult
3361
+ }
3362
+ );
3090
3363
  }
3091
3364
  default:
3092
3365
  const unhandledType = type;
@@ -3108,17 +3381,7 @@ var MessagePrimitiveContent = ({
3108
3381
  }) => {
3109
3382
  const { useMessage } = useMessageContext();
3110
3383
  const contentLength = useMessage((s) => s.message.content.length) || 1;
3111
- return new Array(contentLength).fill(null).map((_, idx) => {
3112
- const partIndex = idx;
3113
- return /* @__PURE__ */ jsx22(
3114
- MessageContentPart,
3115
- {
3116
- partIndex,
3117
- components
3118
- },
3119
- partIndex
3120
- );
3121
- });
3384
+ return Array.from({ length: contentLength }, (_, index) => /* @__PURE__ */ jsx22(MessageContentPart, { partIndex: index, components }, index));
3122
3385
  };
3123
3386
  MessagePrimitiveContent.displayName = "MessagePrimitive.Content";
3124
3387
 
@@ -3128,16 +3391,137 @@ var MessagePrimitiveInProgress = () => {
3128
3391
  };
3129
3392
  MessagePrimitiveInProgress.displayName = "MessagePrimitive.InProgress";
3130
3393
 
3131
- // src/primitives/branchPicker/BranchPickerRoot.tsx
3394
+ // src/primitives/message/MessageAttachments.tsx
3395
+ import { memo as memo3 } from "react";
3396
+
3397
+ // src/context/react/AttachmentContext.ts
3398
+ import { createContext as createContext6, useContext as useContext6 } from "react";
3399
+ var AttachmentContext = createContext6(
3400
+ null
3401
+ );
3402
+ function useAttachmentContext(options) {
3403
+ const context = useContext6(AttachmentContext);
3404
+ if (options?.type === "composer" && context?.type !== "composer")
3405
+ throw new Error(
3406
+ "This component must be used within a ComposerPrimitive.Attachments component."
3407
+ );
3408
+ if (options?.type === "message" && context?.type !== "message")
3409
+ throw new Error(
3410
+ "This component must be used within a MessagePrimitive.Attachments component."
3411
+ );
3412
+ if (!options?.optional && !context)
3413
+ throw new Error(
3414
+ "This component must be used within a ComposerPrimitive.Attachments or MessagePrimitive.Attachments component."
3415
+ );
3416
+ return context;
3417
+ }
3418
+
3419
+ // src/context/providers/MessageAttachmentProvider.tsx
3420
+ import { useEffect as useEffect10, useState as useState11 } from "react";
3421
+ import { create as create13 } from "zustand";
3132
3422
  import { jsx as jsx23 } from "react/jsx-runtime";
3423
+ var getAttachment = ({ message }, useAttachment, partIndex) => {
3424
+ if (message.role !== "user") return null;
3425
+ const attachments = message.attachments;
3426
+ let attachment = attachments[partIndex];
3427
+ if (!attachment) return null;
3428
+ const currentState = useAttachment?.getState();
3429
+ if (currentState && currentState.attachment === attachment) return null;
3430
+ return Object.freeze({ attachment });
3431
+ };
3432
+ var useMessageAttachmentContext = (partIndex) => {
3433
+ const { useMessage } = useMessageContext();
3434
+ const [context] = useState11(
3435
+ () => {
3436
+ const useAttachment = create13(
3437
+ () => getAttachment(useMessage.getState(), void 0, partIndex)
3438
+ );
3439
+ return { type: "message", useAttachment };
3440
+ }
3441
+ );
3442
+ useEffect10(() => {
3443
+ const syncAttachment = (messageState) => {
3444
+ const newState = getAttachment(
3445
+ messageState,
3446
+ context.useAttachment,
3447
+ partIndex
3448
+ );
3449
+ if (!newState) return;
3450
+ writableStore(context.useAttachment).setState(newState, true);
3451
+ };
3452
+ syncAttachment(useMessage.getState());
3453
+ return useMessage.subscribe(syncAttachment);
3454
+ }, [context, useMessage, partIndex]);
3455
+ return context;
3456
+ };
3457
+ var MessageAttachmentProvider = ({
3458
+ attachmentIndex: partIndex,
3459
+ children
3460
+ }) => {
3461
+ const context = useMessageAttachmentContext(partIndex);
3462
+ return /* @__PURE__ */ jsx23(AttachmentContext.Provider, { value: context, children });
3463
+ };
3464
+
3465
+ // src/primitives/message/MessageAttachments.tsx
3466
+ import { jsx as jsx24 } from "react/jsx-runtime";
3467
+ var getComponent = (components, attachment) => {
3468
+ const type = attachment.type;
3469
+ switch (type) {
3470
+ case "image":
3471
+ return components?.Image ?? components?.Attachment;
3472
+ case "document":
3473
+ return components?.Document ?? components?.Attachment;
3474
+ case "file":
3475
+ return components?.File ?? components?.Attachment;
3476
+ default:
3477
+ const _exhaustiveCheck = type;
3478
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
3479
+ }
3480
+ };
3481
+ var AttachmentComponent = ({ components }) => {
3482
+ const { useAttachment } = useAttachmentContext({ type: "message" });
3483
+ const Component = useAttachment(
3484
+ (a) => getComponent(components, a.attachment)
3485
+ );
3486
+ if (!Component) return null;
3487
+ return /* @__PURE__ */ jsx24(Component, {});
3488
+ };
3489
+ var MessageAttachmentImpl = ({ components, attachmentIndex }) => {
3490
+ return /* @__PURE__ */ jsx24(MessageAttachmentProvider, { attachmentIndex, children: /* @__PURE__ */ jsx24(AttachmentComponent, { components }) });
3491
+ };
3492
+ var MessageAttachment = memo3(
3493
+ MessageAttachmentImpl,
3494
+ (prev, next) => prev.attachmentIndex === next.attachmentIndex && prev.components?.Image === next.components?.Image && prev.components?.Document === next.components?.Document && prev.components?.File === next.components?.File && prev.components?.Attachment === next.components?.Attachment
3495
+ );
3496
+ var MessagePrimitiveAttachments = ({ components }) => {
3497
+ const { useMessage } = useMessageContext();
3498
+ const attachmentsCount = useMessage(({ message }) => {
3499
+ if (message.role !== "user") return 0;
3500
+ return message.attachments.length;
3501
+ });
3502
+ return Array.from({ length: attachmentsCount }, (_, index) => /* @__PURE__ */ jsx24(
3503
+ MessageAttachment,
3504
+ {
3505
+ attachmentIndex: index,
3506
+ components
3507
+ },
3508
+ index
3509
+ ));
3510
+ };
3511
+ MessagePrimitiveAttachments.displayName = "MessagePrimitive.Attachments";
3512
+
3513
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
3514
+ import { jsx as jsx25 } from "react/jsx-runtime";
3133
3515
  var BranchPickerPrimitiveRoot = forwardRef14(({ hideWhenSingleBranch, ...rest }, ref) => {
3134
- return /* @__PURE__ */ jsx23(MessagePrimitiveIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx23(Primitive7.div, { ...rest, ref }) });
3516
+ return /* @__PURE__ */ jsx25(MessagePrimitiveIf, { hasBranches: hideWhenSingleBranch ? true : void 0, children: /* @__PURE__ */ jsx25(Primitive7.div, { ...rest, ref }) });
3135
3517
  });
3136
3518
  BranchPickerPrimitiveRoot.displayName = "BranchPickerPrimitive.Root";
3137
3519
 
3138
3520
  // src/primitives/composer/index.ts
3139
3521
  var composer_exports = {};
3140
3522
  __export(composer_exports, {
3523
+ AddAttachment: () => ComposerPrimitiveAddAttachment,
3524
+ Attachments: () => ComposerPrimitiveAttachments,
3141
3525
  Cancel: () => ComposerPrimitiveCancel,
3142
3526
  If: () => ComposerPrimitiveIf,
3143
3527
  Input: () => ComposerPrimitiveInput,
@@ -3151,7 +3535,7 @@ import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
3151
3535
  import {
3152
3536
  forwardRef as forwardRef15
3153
3537
  } from "react";
3154
- import { jsx as jsx24 } from "react/jsx-runtime";
3538
+ import { jsx as jsx26 } from "react/jsx-runtime";
3155
3539
  var ComposerPrimitiveRoot = forwardRef15(({ onSubmit, ...rest }, forwardedRef) => {
3156
3540
  const send = useComposerSend();
3157
3541
  const handleSubmit = (e) => {
@@ -3159,7 +3543,7 @@ var ComposerPrimitiveRoot = forwardRef15(({ onSubmit, ...rest }, forwardedRef) =
3159
3543
  if (!send) return;
3160
3544
  send();
3161
3545
  };
3162
- return /* @__PURE__ */ jsx24(
3546
+ return /* @__PURE__ */ jsx26(
3163
3547
  Primitive8.form,
3164
3548
  {
3165
3549
  ...rest,
@@ -3176,13 +3560,13 @@ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-ref
3176
3560
  import { Slot } from "@radix-ui/react-slot";
3177
3561
  import {
3178
3562
  forwardRef as forwardRef16,
3179
- useCallback as useCallback16,
3180
- useEffect as useEffect10,
3563
+ useCallback as useCallback17,
3564
+ useEffect as useEffect11,
3181
3565
  useRef as useRef4
3182
3566
  } from "react";
3183
3567
  import TextareaAutosize from "react-textarea-autosize";
3184
3568
  import { useEscapeKeydown as useEscapeKeydown2 } from "@radix-ui/react-use-escape-keydown";
3185
- import { jsx as jsx25 } from "react/jsx-runtime";
3569
+ import { jsx as jsx27 } from "react/jsx-runtime";
3186
3570
  var ComposerPrimitiveInput = forwardRef16(
3187
3571
  ({
3188
3572
  autoFocus = false,
@@ -3221,7 +3605,7 @@ var ComposerPrimitiveInput = forwardRef16(
3221
3605
  }
3222
3606
  };
3223
3607
  const autoFocusEnabled = autoFocus && !isDisabled;
3224
- const focus = useCallback16(() => {
3608
+ const focus = useCallback17(() => {
3225
3609
  const textarea = textareaRef.current;
3226
3610
  if (!textarea || !autoFocusEnabled) return;
3227
3611
  textarea.focus({ preventScroll: true });
@@ -3230,13 +3614,13 @@ var ComposerPrimitiveInput = forwardRef16(
3230
3614
  textareaRef.current.value.length
3231
3615
  );
3232
3616
  }, [autoFocusEnabled]);
3233
- useEffect10(() => focus(), [focus]);
3617
+ useEffect11(() => focus(), [focus]);
3234
3618
  useOnComposerFocus(() => {
3235
3619
  if (type === "new") {
3236
3620
  focus();
3237
3621
  }
3238
3622
  });
3239
- return /* @__PURE__ */ jsx25(
3623
+ return /* @__PURE__ */ jsx27(
3240
3624
  Component,
3241
3625
  {
3242
3626
  name: "input",
@@ -3257,23 +3641,10 @@ var ComposerPrimitiveInput = forwardRef16(
3257
3641
  ComposerPrimitiveInput.displayName = "ComposerPrimitive.Input";
3258
3642
 
3259
3643
  // src/primitives/composer/ComposerSend.tsx
3260
- import { forwardRef as forwardRef17 } from "react";
3261
- import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
3262
- import { jsx as jsx26 } from "react/jsx-runtime";
3263
- var ComposerPrimitiveSend = forwardRef17(({ disabled, ...rest }, ref) => {
3264
- const { useComposer } = useComposerContext();
3265
- const hasValue = useComposer((c) => c.isEditing && c.text.length > 0);
3266
- return /* @__PURE__ */ jsx26(
3267
- Primitive9.button,
3268
- {
3269
- type: "submit",
3270
- ...rest,
3271
- ref,
3272
- disabled: disabled || !hasValue
3273
- }
3274
- );
3275
- });
3276
- ComposerPrimitiveSend.displayName = "ComposerPrimitive.Send";
3644
+ var ComposerPrimitiveSend = createActionButton(
3645
+ "ComposerPrimitive.Send",
3646
+ useComposerSend
3647
+ );
3277
3648
 
3278
3649
  // src/primitives/composer/ComposerCancel.tsx
3279
3650
  var ComposerPrimitiveCancel = createActionButton(
@@ -3281,6 +3652,101 @@ var ComposerPrimitiveCancel = createActionButton(
3281
3652
  useComposerCancel
3282
3653
  );
3283
3654
 
3655
+ // src/primitives/composer/ComposerAddAttachment.tsx
3656
+ var ComposerPrimitiveAddAttachment = createActionButton(
3657
+ "ComposerPrimitive.AddAttachment",
3658
+ useComposerAddAttachment
3659
+ );
3660
+
3661
+ // src/primitives/composer/ComposerAttachments.tsx
3662
+ import { memo as memo4 } from "react";
3663
+
3664
+ // src/context/providers/ComposerAttachmentProvider.tsx
3665
+ import { useEffect as useEffect12, useState as useState12 } from "react";
3666
+ import { create as create14 } from "zustand";
3667
+ import { jsx as jsx28 } from "react/jsx-runtime";
3668
+ var getAttachment2 = ({ attachments }, useAttachment, partIndex) => {
3669
+ let attachment = attachments[partIndex];
3670
+ if (!attachment) return null;
3671
+ const currentState = useAttachment?.getState();
3672
+ if (currentState && currentState.attachment === attachment) return null;
3673
+ return Object.freeze({ attachment });
3674
+ };
3675
+ var useComposerAttachmentContext = (partIndex) => {
3676
+ const { useComposer } = useThreadContext();
3677
+ const [context] = useState12(
3678
+ () => {
3679
+ const useAttachment = create14(
3680
+ () => getAttachment2(useComposer.getState(), void 0, partIndex)
3681
+ );
3682
+ return { type: "composer", useAttachment };
3683
+ }
3684
+ );
3685
+ useEffect12(() => {
3686
+ const syncAttachment = (composer) => {
3687
+ const newState = getAttachment2(
3688
+ composer,
3689
+ context.useAttachment,
3690
+ partIndex
3691
+ );
3692
+ if (!newState) return;
3693
+ writableStore(context.useAttachment).setState(newState, true);
3694
+ };
3695
+ syncAttachment(useComposer.getState());
3696
+ return useComposer.subscribe(syncAttachment);
3697
+ }, [context, useComposer, partIndex]);
3698
+ return context;
3699
+ };
3700
+ var ComposerAttachmentProvider = ({ attachmentIndex: partIndex, children }) => {
3701
+ const context = useComposerAttachmentContext(partIndex);
3702
+ return /* @__PURE__ */ jsx28(AttachmentContext.Provider, { value: context, children });
3703
+ };
3704
+
3705
+ // src/primitives/composer/ComposerAttachments.tsx
3706
+ import { jsx as jsx29 } from "react/jsx-runtime";
3707
+ var getComponent2 = (components, attachment) => {
3708
+ const type = attachment.type;
3709
+ switch (type) {
3710
+ case "image":
3711
+ return components?.Image ?? components?.Attachment;
3712
+ case "document":
3713
+ return components?.Document ?? components?.Attachment;
3714
+ case "file":
3715
+ return components?.File ?? components?.Attachment;
3716
+ default:
3717
+ const _exhaustiveCheck = type;
3718
+ throw new Error(`Unknown attachment type: ${_exhaustiveCheck}`);
3719
+ }
3720
+ };
3721
+ var AttachmentComponent2 = ({ components }) => {
3722
+ const { useAttachment } = useAttachmentContext({ type: "composer" });
3723
+ const Component = useAttachment(
3724
+ (a) => getComponent2(components, a.attachment)
3725
+ );
3726
+ if (!Component) return null;
3727
+ return /* @__PURE__ */ jsx29(Component, {});
3728
+ };
3729
+ var ComposerAttachmentImpl = ({ components, attachmentIndex }) => {
3730
+ return /* @__PURE__ */ jsx29(ComposerAttachmentProvider, { attachmentIndex, children: /* @__PURE__ */ jsx29(AttachmentComponent2, { components }) });
3731
+ };
3732
+ var ComposerAttachment = memo4(
3733
+ ComposerAttachmentImpl,
3734
+ (prev, next) => prev.attachmentIndex === next.attachmentIndex && prev.components?.Image === next.components?.Image && prev.components?.Document === next.components?.Document && prev.components?.File === next.components?.File && prev.components?.Attachment === next.components?.Attachment
3735
+ );
3736
+ var ComposerPrimitiveAttachments = ({ components }) => {
3737
+ const { useComposer } = useThreadContext();
3738
+ const attachmentsCount = useComposer((s) => s.attachments.length);
3739
+ return Array.from({ length: attachmentsCount }, (_, index) => /* @__PURE__ */ jsx29(
3740
+ ComposerAttachment,
3741
+ {
3742
+ attachmentIndex: index,
3743
+ components
3744
+ },
3745
+ index
3746
+ ));
3747
+ };
3748
+ ComposerPrimitiveAttachments.displayName = "ComposerPrimitive.Attachments";
3749
+
3284
3750
  // src/primitives/composer/ComposerIf.tsx
3285
3751
  var ComposerPrimitiveIf = ({
3286
3752
  children,
@@ -3313,11 +3779,11 @@ __export(thread_exports, {
3313
3779
  });
3314
3780
 
3315
3781
  // src/primitives/thread/ThreadRoot.tsx
3316
- import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
3317
- import { forwardRef as forwardRef18 } from "react";
3318
- import { jsx as jsx27 } from "react/jsx-runtime";
3319
- var ThreadPrimitiveRoot = forwardRef18((props, ref) => {
3320
- return /* @__PURE__ */ jsx27(Primitive10.div, { ...props, ref });
3782
+ import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
3783
+ import { forwardRef as forwardRef17 } from "react";
3784
+ import { jsx as jsx30 } from "react/jsx-runtime";
3785
+ var ThreadPrimitiveRoot = forwardRef17((props, ref) => {
3786
+ return /* @__PURE__ */ jsx30(Primitive9.div, { ...props, ref });
3321
3787
  });
3322
3788
  ThreadPrimitiveRoot.displayName = "ThreadPrimitive.Root";
3323
3789
 
@@ -3342,8 +3808,8 @@ ThreadPrimitiveIf.displayName = "ThreadPrimitive.If";
3342
3808
 
3343
3809
  // src/primitives/thread/ThreadViewport.tsx
3344
3810
  import { useComposedRefs as useComposedRefs4 } from "@radix-ui/react-compose-refs";
3345
- import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
3346
- import { forwardRef as forwardRef19 } from "react";
3811
+ import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
3812
+ import { forwardRef as forwardRef18 } from "react";
3347
3813
 
3348
3814
  // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
3349
3815
  import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
@@ -3351,10 +3817,10 @@ import { useRef as useRef5 } from "react";
3351
3817
 
3352
3818
  // src/utils/hooks/useOnResizeContent.tsx
3353
3819
  import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
3354
- import { useCallback as useCallback17 } from "react";
3820
+ import { useCallback as useCallback18 } from "react";
3355
3821
  var useOnResizeContent = (callback) => {
3356
3822
  const callbackRef = useCallbackRef3(callback);
3357
- const refCallback = useCallback17(
3823
+ const refCallback = useCallback18(
3358
3824
  (el) => {
3359
3825
  const resizeObserver = new ResizeObserver(() => {
3360
3826
  callbackRef();
@@ -3391,11 +3857,11 @@ var useOnResizeContent = (callback) => {
3391
3857
 
3392
3858
  // src/utils/hooks/useOnScrollToBottom.tsx
3393
3859
  import { useCallbackRef as useCallbackRef4 } from "@radix-ui/react-use-callback-ref";
3394
- import { useEffect as useEffect11 } from "react";
3860
+ import { useEffect as useEffect13 } from "react";
3395
3861
  var useOnScrollToBottom = (callback) => {
3396
3862
  const callbackRef = useCallbackRef4(callback);
3397
3863
  const { useViewport } = useThreadContext();
3398
- useEffect11(() => {
3864
+ useEffect13(() => {
3399
3865
  return useViewport.getState().onScrollToBottom(() => {
3400
3866
  callbackRef();
3401
3867
  });
@@ -3427,9 +3893,7 @@ var useThreadViewportAutoScroll = ({
3427
3893
  isScrollingToBottomRef.current = false;
3428
3894
  }
3429
3895
  if (newIsAtBottom !== isAtBottom) {
3430
- useViewport.setState({
3431
- isAtBottom: newIsAtBottom
3432
- });
3896
+ writableStore(useViewport).setState({ isAtBottom: newIsAtBottom });
3433
3897
  }
3434
3898
  }
3435
3899
  lastScrollTop.current = div.scrollTop;
@@ -3454,29 +3918,29 @@ var useThreadViewportAutoScroll = ({
3454
3918
  };
3455
3919
 
3456
3920
  // src/primitives/thread/ThreadViewport.tsx
3457
- import { jsx as jsx28 } from "react/jsx-runtime";
3458
- var ThreadPrimitiveViewport = forwardRef19(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
3921
+ import { jsx as jsx31 } from "react/jsx-runtime";
3922
+ var ThreadPrimitiveViewport = forwardRef18(({ autoScroll, onScroll, children, ...rest }, forwardedRef) => {
3459
3923
  const autoScrollRef = useThreadViewportAutoScroll({
3460
3924
  autoScroll
3461
3925
  });
3462
3926
  const ref = useComposedRefs4(forwardedRef, autoScrollRef);
3463
- return /* @__PURE__ */ jsx28(Primitive11.div, { ...rest, ref, children });
3927
+ return /* @__PURE__ */ jsx31(Primitive10.div, { ...rest, ref, children });
3464
3928
  });
3465
3929
  ThreadPrimitiveViewport.displayName = "ThreadPrimitive.Viewport";
3466
3930
 
3467
3931
  // src/primitives/thread/ThreadMessages.tsx
3468
- import { memo as memo3 } from "react";
3932
+ import { memo as memo5 } from "react";
3469
3933
 
3470
3934
  // src/context/providers/MessageProvider.tsx
3471
- import { useEffect as useEffect12, useState as useState11 } from "react";
3472
- import { create as create15 } from "zustand";
3935
+ import { useEffect as useEffect14, useState as useState13 } from "react";
3936
+ import { create as create17 } from "zustand";
3473
3937
 
3474
3938
  // src/context/stores/EditComposer.ts
3475
- import { create as create13 } from "zustand";
3939
+ import { create as create15 } from "zustand";
3476
3940
  var makeEditComposerStore = ({
3477
3941
  onEdit,
3478
3942
  onSend
3479
- }) => create13()((set, get) => ({
3943
+ }) => create15()((set, get) => ({
3480
3944
  get value() {
3481
3945
  return get().text;
3482
3946
  },
@@ -3485,13 +3949,19 @@ var makeEditComposerStore = ({
3485
3949
  },
3486
3950
  text: "",
3487
3951
  setText: (text) => {
3488
- set({ text });
3952
+ set({ text, isEmpty: text.trim().length === 0 });
3489
3953
  },
3490
3954
  canCancel: false,
3491
3955
  isEditing: false,
3956
+ isEmpty: true,
3492
3957
  edit: () => {
3493
3958
  const text = onEdit();
3494
- set({ isEditing: true, canCancel: true, text });
3959
+ set({
3960
+ isEditing: true,
3961
+ canCancel: true,
3962
+ isEmpty: text.trim().length === 0,
3963
+ text
3964
+ });
3495
3965
  },
3496
3966
  send: () => {
3497
3967
  const text = get().text;
@@ -3504,8 +3974,8 @@ var makeEditComposerStore = ({
3504
3974
  }));
3505
3975
 
3506
3976
  // src/context/stores/MessageUtils.ts
3507
- import { create as create14 } from "zustand";
3508
- var makeMessageUtilsStore = () => create14((set) => {
3977
+ import { create as create16 } from "zustand";
3978
+ var makeMessageUtilsStore = () => create16((set) => {
3509
3979
  let utterance = null;
3510
3980
  return {
3511
3981
  isCopied: false,
@@ -3531,7 +4001,7 @@ var makeMessageUtilsStore = () => create14((set) => {
3531
4001
  });
3532
4002
 
3533
4003
  // src/context/providers/MessageProvider.tsx
3534
- import { jsx as jsx29 } from "react/jsx-runtime";
4004
+ import { jsx as jsx32 } from "react/jsx-runtime";
3535
4005
  var getIsLast = (messages, message) => {
3536
4006
  return messages[messages.length - 1]?.id === message.id;
3537
4007
  };
@@ -3553,8 +4023,8 @@ var getMessageState = (messages, getBranches, useMessage, messageIndex) => {
3553
4023
  };
3554
4024
  var useMessageContext2 = (messageIndex) => {
3555
4025
  const { useThreadMessages, useThreadActions } = useThreadContext();
3556
- const [context] = useState11(() => {
3557
- const useMessage = create15(
4026
+ const [context] = useState13(() => {
4027
+ const useMessage = create17(
3558
4028
  () => getMessageState(
3559
4029
  useThreadMessages.getState(),
3560
4030
  useThreadActions.getState().getBranches,
@@ -3585,13 +4055,14 @@ var useMessageContext2 = (messageIndex) => {
3585
4055
  useThreadActions.getState().append({
3586
4056
  parentId,
3587
4057
  role: "user",
3588
- content: [{ type: "text", text }, ...nonTextParts]
4058
+ content: [{ type: "text", text }, ...nonTextParts],
4059
+ attachments: message.attachments
3589
4060
  });
3590
4061
  }
3591
4062
  });
3592
4063
  return { useMessage, useMessageUtils, useEditComposer };
3593
4064
  });
3594
- useEffect12(() => {
4065
+ useEffect14(() => {
3595
4066
  const syncMessage = (thread) => {
3596
4067
  const newState = getMessageState(
3597
4068
  thread,
@@ -3600,10 +4071,7 @@ var useMessageContext2 = (messageIndex) => {
3600
4071
  messageIndex
3601
4072
  );
3602
4073
  if (!newState) return;
3603
- context.useMessage.setState(
3604
- newState,
3605
- true
3606
- );
4074
+ writableStore(context.useMessage).setState(newState, true);
3607
4075
  };
3608
4076
  syncMessage(useThreadMessages.getState());
3609
4077
  return useThreadMessages.subscribe(syncMessage);
@@ -3615,11 +4083,11 @@ var MessageProvider = ({
3615
4083
  children
3616
4084
  }) => {
3617
4085
  const context = useMessageContext2(messageIndex);
3618
- return /* @__PURE__ */ jsx29(MessageContext.Provider, { value: context, children });
4086
+ return /* @__PURE__ */ jsx32(MessageContext.Provider, { value: context, children });
3619
4087
  };
3620
4088
 
3621
4089
  // src/primitives/thread/ThreadMessages.tsx
3622
- import { jsx as jsx30, jsxs as jsxs4 } from "react/jsx-runtime";
4090
+ import { jsx as jsx33, jsxs as jsxs4 } from "react/jsx-runtime";
3623
4091
  var DEFAULT_SYSTEM_MESSAGE = () => null;
3624
4092
  var getComponents = (components) => {
3625
4093
  return {
@@ -3636,14 +4104,14 @@ var ThreadMessageImpl = ({
3636
4104
  const { UserMessage: UserMessage2, EditComposer: EditComposer2, AssistantMessage: AssistantMessage2, SystemMessage: SystemMessage2 } = getComponents(components);
3637
4105
  return /* @__PURE__ */ jsxs4(MessageProvider, { messageIndex, children: [
3638
4106
  /* @__PURE__ */ jsxs4(MessagePrimitiveIf, { user: true, children: [
3639
- /* @__PURE__ */ jsx30(ComposerPrimitiveIf, { editing: false, children: /* @__PURE__ */ jsx30(UserMessage2, {}) }),
3640
- /* @__PURE__ */ jsx30(ComposerPrimitiveIf, { editing: true, children: /* @__PURE__ */ jsx30(EditComposer2, {}) })
4107
+ /* @__PURE__ */ jsx33(ComposerPrimitiveIf, { editing: false, children: /* @__PURE__ */ jsx33(UserMessage2, {}) }),
4108
+ /* @__PURE__ */ jsx33(ComposerPrimitiveIf, { editing: true, children: /* @__PURE__ */ jsx33(EditComposer2, {}) })
3641
4109
  ] }),
3642
- /* @__PURE__ */ jsx30(MessagePrimitiveIf, { assistant: true, children: /* @__PURE__ */ jsx30(AssistantMessage2, {}) }),
3643
- /* @__PURE__ */ jsx30(MessagePrimitiveIf, { system: true, children: /* @__PURE__ */ jsx30(SystemMessage2, {}) })
4110
+ /* @__PURE__ */ jsx33(MessagePrimitiveIf, { assistant: true, children: /* @__PURE__ */ jsx33(AssistantMessage2, {}) }),
4111
+ /* @__PURE__ */ jsx33(MessagePrimitiveIf, { system: true, children: /* @__PURE__ */ jsx33(SystemMessage2, {}) })
3644
4112
  ] });
3645
4113
  };
3646
- var ThreadMessage = memo3(
4114
+ var ThreadMessage = memo5(
3647
4115
  ThreadMessageImpl,
3648
4116
  (prev, next) => prev.messageIndex === next.messageIndex && prev.components.Message === next.components.Message && prev.components.UserMessage === next.components.UserMessage && prev.components.EditComposer === next.components.EditComposer && prev.components.AssistantMessage === next.components.AssistantMessage && prev.components.SystemMessage === next.components.SystemMessage
3649
4117
  );
@@ -3653,20 +4121,10 @@ var ThreadPrimitiveMessagesImpl = ({
3653
4121
  const { useThreadMessages } = useThreadContext();
3654
4122
  const messagesLength = useThreadMessages((t) => t.length);
3655
4123
  if (messagesLength === 0) return null;
3656
- return new Array(messagesLength).fill(null).map((_, idx) => {
3657
- const messageIndex = idx;
3658
- return /* @__PURE__ */ jsx30(
3659
- ThreadMessage,
3660
- {
3661
- messageIndex,
3662
- components
3663
- },
3664
- messageIndex
3665
- );
3666
- });
4124
+ return Array.from({ length: messagesLength }, (_, index) => /* @__PURE__ */ jsx33(ThreadMessage, { messageIndex: index, components }, index));
3667
4125
  };
3668
4126
  ThreadPrimitiveMessagesImpl.displayName = "ThreadPrimitive.Messages";
3669
- var ThreadPrimitiveMessages = memo3(
4127
+ var ThreadPrimitiveMessages = memo5(
3670
4128
  ThreadPrimitiveMessagesImpl,
3671
4129
  (prev, next) => prev.components?.Message === next.components?.Message && prev.components?.UserMessage === next.components?.UserMessage && prev.components?.EditComposer === next.components?.EditComposer && prev.components?.AssistantMessage === next.components?.AssistantMessage && prev.components?.SystemMessage === next.components?.SystemMessage
3672
4130
  );
@@ -3686,32 +4144,32 @@ var ThreadPrimitiveSuggestion = createActionButton(
3686
4144
 
3687
4145
  // src/ui/thread-config.tsx
3688
4146
  import {
3689
- createContext as createContext6,
3690
- useContext as useContext6
4147
+ createContext as createContext7,
4148
+ useContext as useContext7
3691
4149
  } from "react";
3692
- import { Fragment as Fragment3, jsx as jsx31 } from "react/jsx-runtime";
3693
- var ThreadConfigContext = createContext6({});
4150
+ import { Fragment as Fragment3, jsx as jsx34 } from "react/jsx-runtime";
4151
+ var ThreadConfigContext = createContext7({});
3694
4152
  var useThreadConfig = () => {
3695
- return useContext6(ThreadConfigContext);
4153
+ return useContext7(ThreadConfigContext);
3696
4154
  };
3697
4155
  var ThreadConfigProvider = ({
3698
4156
  children,
3699
4157
  config
3700
4158
  }) => {
3701
4159
  const assistant = useAssistantContext({ optional: true });
3702
- const configProvider = config && Object.keys(config ?? {}).length > 0 ? /* @__PURE__ */ jsx31(ThreadConfigContext.Provider, { value: config, children }) : /* @__PURE__ */ jsx31(Fragment3, { children });
4160
+ const configProvider = config && Object.keys(config ?? {}).length > 0 ? /* @__PURE__ */ jsx34(ThreadConfigContext.Provider, { value: config, children }) : /* @__PURE__ */ jsx34(Fragment3, { children });
3703
4161
  if (!config?.runtime) return configProvider;
3704
4162
  if (assistant) {
3705
4163
  throw new Error(
3706
4164
  "You provided a runtime to <Thread> while simulataneously using <AssistantRuntimeProvider>. This is not allowed."
3707
4165
  );
3708
4166
  }
3709
- return /* @__PURE__ */ jsx31(AssistantRuntimeProvider, { runtime: config.runtime, children: configProvider });
4167
+ return /* @__PURE__ */ jsx34(AssistantRuntimeProvider, { runtime: config.runtime, children: configProvider });
3710
4168
  };
3711
4169
  ThreadConfigProvider.displayName = "ThreadConfigProvider";
3712
4170
 
3713
4171
  // src/ui/assistant-action-bar.tsx
3714
- import { forwardRef as forwardRef20 } from "react";
4172
+ import { forwardRef as forwardRef19 } from "react";
3715
4173
  import {
3716
4174
  AudioLinesIcon,
3717
4175
  CheckIcon,
@@ -3719,7 +4177,7 @@ import {
3719
4177
  RefreshCwIcon,
3720
4178
  StopCircleIcon
3721
4179
  } from "lucide-react";
3722
- import { Fragment as Fragment4, jsx as jsx32, jsxs as jsxs5 } from "react/jsx-runtime";
4180
+ import { Fragment as Fragment4, jsx as jsx35, jsxs as jsxs5 } from "react/jsx-runtime";
3723
4181
  var useAllowCopy = (ensureCapability = false) => {
3724
4182
  const { assistantMessage: { allowCopy = true } = {} } = useThreadConfig();
3725
4183
  const { useThread } = useThreadContext();
@@ -3750,9 +4208,9 @@ var AssistantActionBar = () => {
3750
4208
  autohide: "not-last",
3751
4209
  autohideFloat: "single-branch",
3752
4210
  children: [
3753
- allowSpeak && /* @__PURE__ */ jsx32(AssistantActionBarSpeechControl, {}),
3754
- allowCopy && /* @__PURE__ */ jsx32(AssistantActionBarCopy, {}),
3755
- allowReload && /* @__PURE__ */ jsx32(AssistantActionBarReload, {})
4211
+ allowSpeak && /* @__PURE__ */ jsx35(AssistantActionBarSpeechControl, {}),
4212
+ allowCopy && /* @__PURE__ */ jsx35(AssistantActionBarCopy, {}),
4213
+ allowReload && /* @__PURE__ */ jsx35(AssistantActionBarReload, {})
3756
4214
  ]
3757
4215
  }
3758
4216
  );
@@ -3762,36 +4220,35 @@ var AssistantActionBarRoot = withDefaults(actionBar_exports.Root, {
3762
4220
  className: "aui-assistant-action-bar-root"
3763
4221
  });
3764
4222
  AssistantActionBarRoot.displayName = "AssistantActionBarRoot";
3765
- var AssistantActionBarCopy = forwardRef20((props, ref) => {
4223
+ var AssistantActionBarCopy = forwardRef19((props, ref) => {
3766
4224
  const {
3767
4225
  strings: {
3768
4226
  assistantMessage: { copy: { tooltip = "Copy" } = {} } = {}
3769
4227
  } = {}
3770
4228
  } = useThreadConfig();
3771
- return /* @__PURE__ */ jsx32(actionBar_exports.Copy, { asChild: true, children: /* @__PURE__ */ jsx32(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
3772
- /* @__PURE__ */ jsx32(message_exports.If, { copied: true, children: /* @__PURE__ */ jsx32(CheckIcon, {}) }),
3773
- /* @__PURE__ */ jsx32(message_exports.If, { copied: false, children: /* @__PURE__ */ jsx32(CopyIcon, {}) })
4229
+ return /* @__PURE__ */ jsx35(actionBar_exports.Copy, { asChild: true, children: /* @__PURE__ */ jsx35(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
4230
+ /* @__PURE__ */ jsx35(message_exports.If, { copied: true, children: /* @__PURE__ */ jsx35(CheckIcon, {}) }),
4231
+ /* @__PURE__ */ jsx35(message_exports.If, { copied: false, children: /* @__PURE__ */ jsx35(CopyIcon, {}) })
3774
4232
  ] }) }) });
3775
4233
  });
3776
4234
  AssistantActionBarCopy.displayName = "AssistantActionBarCopy";
3777
4235
  var AssistantActionBarSpeechControl = () => {
3778
4236
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
3779
- /* @__PURE__ */ jsx32(message_exports.If, { speaking: false, children: /* @__PURE__ */ jsx32(AssistantActionBarSpeak, {}) }),
3780
- /* @__PURE__ */ jsx32(message_exports.If, { speaking: true, children: /* @__PURE__ */ jsx32(AssistantActionBarStopSpeaking, {}) })
4237
+ /* @__PURE__ */ jsx35(message_exports.If, { speaking: false, children: /* @__PURE__ */ jsx35(AssistantActionBarSpeak, {}) }),
4238
+ /* @__PURE__ */ jsx35(message_exports.If, { speaking: true, children: /* @__PURE__ */ jsx35(AssistantActionBarStopSpeaking, {}) })
3781
4239
  ] });
3782
4240
  };
3783
- var AssistantActionBarSpeak = forwardRef20((props, ref) => {
4241
+ var AssistantActionBarSpeak = forwardRef19((props, ref) => {
3784
4242
  const {
3785
4243
  strings: {
3786
4244
  assistantMessage: { speak: { tooltip = "Read aloud" } = {} } = {}
3787
4245
  } = {}
3788
4246
  } = useThreadConfig();
3789
4247
  const allowSpeak = useAllowSpeak();
3790
- if (!allowSpeak) return null;
3791
- return /* @__PURE__ */ jsx32(actionBar_exports.Speak, { asChild: true, children: /* @__PURE__ */ jsx32(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx32(AudioLinesIcon, {}) }) });
4248
+ return /* @__PURE__ */ jsx35(actionBar_exports.Speak, { disabled: !allowSpeak, asChild: true, children: /* @__PURE__ */ jsx35(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx35(AudioLinesIcon, {}) }) });
3792
4249
  });
3793
4250
  AssistantActionBarSpeak.displayName = "AssistantActionBarSpeak";
3794
- var AssistantActionBarStopSpeaking = forwardRef20((props, ref) => {
4251
+ var AssistantActionBarStopSpeaking = forwardRef19((props, ref) => {
3795
4252
  const {
3796
4253
  strings: {
3797
4254
  assistantMessage: {
@@ -3800,19 +4257,17 @@ var AssistantActionBarStopSpeaking = forwardRef20((props, ref) => {
3800
4257
  } = {}
3801
4258
  } = useThreadConfig();
3802
4259
  const allowSpeak = useAllowSpeak();
3803
- if (!allowSpeak) return null;
3804
- return /* @__PURE__ */ jsx32(actionBar_exports.StopSpeaking, { asChild: true, children: /* @__PURE__ */ jsx32(TooltipIconButton, { tooltip: stopTooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx32(StopCircleIcon, {}) }) });
4260
+ return /* @__PURE__ */ jsx35(actionBar_exports.StopSpeaking, { disabled: !allowSpeak, asChild: true, children: /* @__PURE__ */ jsx35(TooltipIconButton, { tooltip: stopTooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx35(StopCircleIcon, {}) }) });
3805
4261
  });
3806
4262
  AssistantActionBarStopSpeaking.displayName = "AssistantActionBarStopSpeaking";
3807
- var AssistantActionBarReload = forwardRef20((props, ref) => {
4263
+ var AssistantActionBarReload = forwardRef19((props, ref) => {
3808
4264
  const {
3809
4265
  strings: {
3810
4266
  assistantMessage: { reload: { tooltip = "Refresh" } = {} } = {}
3811
4267
  } = {}
3812
4268
  } = useThreadConfig();
3813
4269
  const allowReload = useAllowReload();
3814
- if (!allowReload) return null;
3815
- return /* @__PURE__ */ jsx32(actionBar_exports.Reload, { asChild: true, children: /* @__PURE__ */ jsx32(TooltipIconButton, { tooltip, ...props, ref, children: /* @__PURE__ */ jsx32(RefreshCwIcon, {}) }) });
4270
+ return /* @__PURE__ */ jsx35(actionBar_exports.Reload, { disabled: !allowReload, asChild: true, children: /* @__PURE__ */ jsx35(TooltipIconButton, { tooltip, ...props, ref, children: /* @__PURE__ */ jsx35(RefreshCwIcon, {}) }) });
3816
4271
  });
3817
4272
  AssistantActionBarReload.displayName = "AssistantActionBarReload";
3818
4273
  var exports = {
@@ -3829,25 +4284,25 @@ var assistant_action_bar_default = Object.assign(
3829
4284
  );
3830
4285
 
3831
4286
  // src/ui/assistant-message.tsx
3832
- import { forwardRef as forwardRef22 } from "react";
4287
+ import { forwardRef as forwardRef21, useMemo as useMemo5 } from "react";
3833
4288
 
3834
4289
  // src/ui/branch-picker.tsx
3835
- import { forwardRef as forwardRef21 } from "react";
4290
+ import { forwardRef as forwardRef20 } from "react";
3836
4291
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
3837
- import { jsx as jsx33, jsxs as jsxs6 } from "react/jsx-runtime";
3838
- var useAllowBranchPicker = () => {
4292
+ import { jsx as jsx36, jsxs as jsxs6 } from "react/jsx-runtime";
4293
+ var useAllowBranchPicker = (ensureCapability = false) => {
3839
4294
  const { branchPicker: { allowBranchPicker = true } = {} } = useThreadConfig();
3840
4295
  const { useThread } = useThreadContext();
3841
4296
  const branchPickerSupported = useThread((t) => t.capabilities.edit);
3842
- return branchPickerSupported && allowBranchPicker;
4297
+ return allowBranchPicker && (!ensureCapability || branchPickerSupported);
3843
4298
  };
3844
4299
  var BranchPicker = () => {
3845
4300
  const allowBranchPicker = useAllowBranchPicker();
3846
4301
  if (!allowBranchPicker) return null;
3847
4302
  return /* @__PURE__ */ jsxs6(BranchPickerRoot, { hideWhenSingleBranch: true, children: [
3848
- /* @__PURE__ */ jsx33(BranchPickerPrevious2, {}),
3849
- /* @__PURE__ */ jsx33(BranchPickerState, {}),
3850
- /* @__PURE__ */ jsx33(BranchPickerNext, {})
4303
+ /* @__PURE__ */ jsx36(BranchPickerPrevious2, {}),
4304
+ /* @__PURE__ */ jsx36(BranchPickerState, {}),
4305
+ /* @__PURE__ */ jsx36(BranchPickerNext, {})
3851
4306
  ] });
3852
4307
  };
3853
4308
  BranchPicker.displayName = "BranchPicker";
@@ -3855,31 +4310,33 @@ var BranchPickerRoot = withDefaults(branchPicker_exports.Root, {
3855
4310
  className: "aui-branch-picker-root"
3856
4311
  });
3857
4312
  BranchPickerRoot.displayName = "BranchPickerRoot";
3858
- var BranchPickerPrevious2 = forwardRef21((props, ref) => {
4313
+ var BranchPickerPrevious2 = forwardRef20((props, ref) => {
3859
4314
  const {
3860
4315
  strings: {
3861
4316
  branchPicker: { previous: { tooltip = "Previous" } = {} } = {}
3862
4317
  } = {}
3863
4318
  } = useThreadConfig();
3864
- return /* @__PURE__ */ jsx33(branchPicker_exports.Previous, { asChild: true, children: /* @__PURE__ */ jsx33(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx33(ChevronLeftIcon, {}) }) });
4319
+ const allowBranchPicker = useAllowBranchPicker();
4320
+ return /* @__PURE__ */ jsx36(branchPicker_exports.Previous, { disabled: !allowBranchPicker, asChild: true, children: /* @__PURE__ */ jsx36(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx36(ChevronLeftIcon, {}) }) });
3865
4321
  });
3866
4322
  BranchPickerPrevious2.displayName = "BranchPickerPrevious";
3867
4323
  var BranchPickerStateWrapper = withDefaults("span", {
3868
4324
  className: "aui-branch-picker-state"
3869
4325
  });
3870
- var BranchPickerState = forwardRef21((props, ref) => {
4326
+ var BranchPickerState = forwardRef20((props, ref) => {
3871
4327
  return /* @__PURE__ */ jsxs6(BranchPickerStateWrapper, { ...props, ref, children: [
3872
- /* @__PURE__ */ jsx33(branchPicker_exports.Number, {}),
4328
+ /* @__PURE__ */ jsx36(branchPicker_exports.Number, {}),
3873
4329
  " / ",
3874
- /* @__PURE__ */ jsx33(branchPicker_exports.Count, {})
4330
+ /* @__PURE__ */ jsx36(branchPicker_exports.Count, {})
3875
4331
  ] });
3876
4332
  });
3877
4333
  BranchPickerState.displayName = "BranchPickerState";
3878
- var BranchPickerNext = forwardRef21((props, ref) => {
4334
+ var BranchPickerNext = forwardRef20((props, ref) => {
3879
4335
  const {
3880
4336
  strings: { branchPicker: { next: { tooltip = "Next" } = {} } = {} } = {}
3881
4337
  } = useThreadConfig();
3882
- return /* @__PURE__ */ jsx33(branchPicker_exports.Next, { asChild: true, children: /* @__PURE__ */ jsx33(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx33(ChevronRightIcon, {}) }) });
4338
+ const allowBranchPicker = useAllowBranchPicker();
4339
+ return /* @__PURE__ */ jsx36(branchPicker_exports.Next, { disabled: !allowBranchPicker, asChild: true, children: /* @__PURE__ */ jsx36(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx36(ChevronRightIcon, {}) }) });
3883
4340
  });
3884
4341
  BranchPickerNext.displayName = "BranchPickerNext";
3885
4342
  var exports2 = {
@@ -3891,12 +4348,12 @@ var branch_picker_default = Object.assign(BranchPicker, exports2);
3891
4348
 
3892
4349
  // src/ui/base/avatar.tsx
3893
4350
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
3894
- import { jsx as jsx34, jsxs as jsxs7 } from "react/jsx-runtime";
4351
+ import { jsx as jsx37, jsxs as jsxs7 } from "react/jsx-runtime";
3895
4352
  var Avatar = ({ src, alt, fallback }) => {
3896
4353
  if (src == null && fallback == null) return null;
3897
4354
  return /* @__PURE__ */ jsxs7(AvatarRoot, { children: [
3898
- src != null && /* @__PURE__ */ jsx34(AvatarImage, { src, alt }),
3899
- fallback != null && /* @__PURE__ */ jsx34(AvatarFallback, { children: fallback })
4355
+ src != null && /* @__PURE__ */ jsx37(AvatarImage, { src, alt }),
4356
+ fallback != null && /* @__PURE__ */ jsx37(AvatarFallback, { children: fallback })
3900
4357
  ] });
3901
4358
  };
3902
4359
  Avatar.displayName = "Avatar";
@@ -3915,10 +4372,10 @@ AvatarFallback.displayName = "AvatarFallback";
3915
4372
 
3916
4373
  // src/ui/content-part.tsx
3917
4374
  import classNames2 from "classnames";
3918
- import { jsx as jsx35 } from "react/jsx-runtime";
4375
+ import { jsx as jsx38 } from "react/jsx-runtime";
3919
4376
  var Text = () => {
3920
4377
  const status = useSmoothStatus();
3921
- return /* @__PURE__ */ jsx35(
4378
+ return /* @__PURE__ */ jsx38(
3922
4379
  contentPart_exports.Text,
3923
4380
  {
3924
4381
  className: classNames2(
@@ -3933,19 +4390,19 @@ var exports3 = { Text: withSmoothContextProvider(Text) };
3933
4390
  var content_part_default = exports3;
3934
4391
 
3935
4392
  // src/ui/assistant-message.tsx
3936
- import { jsx as jsx36, jsxs as jsxs8 } from "react/jsx-runtime";
4393
+ import { jsx as jsx39, jsxs as jsxs8 } from "react/jsx-runtime";
3937
4394
  var AssistantMessage = () => {
3938
4395
  return /* @__PURE__ */ jsxs8(AssistantMessageRoot, { children: [
3939
- /* @__PURE__ */ jsx36(AssistantMessageAvatar, {}),
3940
- /* @__PURE__ */ jsx36(AssistantMessageContent, {}),
3941
- /* @__PURE__ */ jsx36(branch_picker_default, {}),
3942
- /* @__PURE__ */ jsx36(assistant_action_bar_default, {})
4396
+ /* @__PURE__ */ jsx39(AssistantMessageAvatar, {}),
4397
+ /* @__PURE__ */ jsx39(AssistantMessageContent, {}),
4398
+ /* @__PURE__ */ jsx39(branch_picker_default, {}),
4399
+ /* @__PURE__ */ jsx39(assistant_action_bar_default, {})
3943
4400
  ] });
3944
4401
  };
3945
4402
  AssistantMessage.displayName = "AssistantMessage";
3946
4403
  var AssistantMessageAvatar = () => {
3947
4404
  const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
3948
- return /* @__PURE__ */ jsx36(Avatar, { ...avatar });
4405
+ return /* @__PURE__ */ jsx39(Avatar, { ...avatar });
3949
4406
  };
3950
4407
  var AssistantMessageRoot = withDefaults(message_exports.Root, {
3951
4408
  className: "aui-assistant-message-root"
@@ -3954,14 +4411,28 @@ AssistantMessageRoot.displayName = "AssistantMessageRoot";
3954
4411
  var AssistantMessageContentWrapper = withDefaults("div", {
3955
4412
  className: "aui-assistant-message-content"
3956
4413
  });
3957
- var AssistantMessageContent = forwardRef22(({ components: componentsProp, ...rest }, ref) => {
3958
- const { assistantMessage: { components = {} } = {} } = useThreadConfig();
3959
- return /* @__PURE__ */ jsx36(AssistantMessageContentWrapper, { ...rest, ref, children: /* @__PURE__ */ jsx36(
4414
+ var AssistantMessageContent = forwardRef21(({ components: componentsProp, ...rest }, ref) => {
4415
+ const { tools, assistantMessage: { components = {} } = {} } = useThreadConfig();
4416
+ const toolsComponents = useMemo5(
4417
+ () => ({
4418
+ by_name: !tools ? void 0 : Object.fromEntries(
4419
+ tools.map((t) => [
4420
+ t.unstable_tool.toolName,
4421
+ t.unstable_tool.render
4422
+ ])
4423
+ ),
4424
+ Fallback: components.ToolFallback
4425
+ }),
4426
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4427
+ [...tools ?? [], components.ToolFallback]
4428
+ );
4429
+ return /* @__PURE__ */ jsx39(AssistantMessageContentWrapper, { ...rest, ref, children: /* @__PURE__ */ jsx39(
3960
4430
  message_exports.Content,
3961
4431
  {
3962
4432
  components: {
3963
4433
  ...componentsProp,
3964
- Text: componentsProp?.Text ?? components.Text ?? content_part_default.Text
4434
+ Text: componentsProp?.Text ?? components.Text ?? content_part_default.Text,
4435
+ tools: toolsComponents
3965
4436
  }
3966
4437
  }
3967
4438
  ) });
@@ -3987,12 +4458,12 @@ import { ArrowDownIcon } from "lucide-react";
3987
4458
 
3988
4459
  // src/ui/composer.tsx
3989
4460
  import { forwardRef as forwardRef23 } from "react";
3990
- import { SendHorizontalIcon } from "lucide-react";
4461
+ import { PaperclipIcon, SendHorizontalIcon } from "lucide-react";
3991
4462
 
3992
4463
  // src/ui/base/CircleStopIcon.tsx
3993
- import { jsx as jsx37 } from "react/jsx-runtime";
4464
+ import { jsx as jsx40 } from "react/jsx-runtime";
3994
4465
  var CircleStopIcon = () => {
3995
- return /* @__PURE__ */ jsx37(
4466
+ return /* @__PURE__ */ jsx40(
3996
4467
  "svg",
3997
4468
  {
3998
4469
  xmlns: "http://www.w3.org/2000/svg",
@@ -4000,18 +4471,79 @@ var CircleStopIcon = () => {
4000
4471
  fill: "currentColor",
4001
4472
  width: "16",
4002
4473
  height: "16",
4003
- children: /* @__PURE__ */ jsx37("rect", { width: "10", height: "10", x: "3", y: "3", rx: "2" })
4474
+ children: /* @__PURE__ */ jsx40("rect", { width: "10", height: "10", x: "3", y: "3", rx: "2" })
4004
4475
  }
4005
4476
  );
4006
4477
  };
4007
4478
  CircleStopIcon.displayName = "CircleStopIcon";
4008
4479
 
4480
+ // src/ui/composer-attachment.tsx
4481
+ import { forwardRef as forwardRef22 } from "react";
4482
+ import { CircleXIcon } from "lucide-react";
4483
+ import { jsx as jsx41, jsxs as jsxs9 } from "react/jsx-runtime";
4484
+ var ComposerAttachmentRoot = withDefaults("div", {
4485
+ className: "aui-composer-attachment-root"
4486
+ });
4487
+ ComposerAttachmentRoot.displayName = "ComposerAttachmentRoot";
4488
+ var ComposerAttachment2 = () => {
4489
+ const { useAttachment } = useAttachmentContext({ type: "composer" });
4490
+ const attachment = useAttachment((a) => a.attachment);
4491
+ return /* @__PURE__ */ jsxs9(ComposerAttachmentRoot, { children: [
4492
+ ".",
4493
+ attachment.name.split(".").pop(),
4494
+ /* @__PURE__ */ jsx41(ComposerAttachmentRemove, {})
4495
+ ] });
4496
+ };
4497
+ ComposerAttachment2.displayName = "ComposerAttachment";
4498
+ var ComposerAttachmentRemove = forwardRef22((props, ref) => {
4499
+ const {
4500
+ strings: {
4501
+ composer: { removeAttachment: { tooltip = "Remove file" } = {} } = {}
4502
+ } = {}
4503
+ } = useThreadConfig();
4504
+ const { useComposer } = useThreadContext();
4505
+ const { useAttachment } = useAttachmentContext();
4506
+ const handleRemoveAttachment = () => {
4507
+ useComposer.getState().removeAttachment(useAttachment.getState().attachment.id);
4508
+ };
4509
+ return /* @__PURE__ */ jsx41(
4510
+ TooltipIconButton,
4511
+ {
4512
+ tooltip,
4513
+ className: "aui-composer-attachment-remove",
4514
+ side: "top",
4515
+ ...props,
4516
+ onClick: handleRemoveAttachment,
4517
+ ref,
4518
+ children: props.children ?? /* @__PURE__ */ jsx41(CircleXIcon, {})
4519
+ }
4520
+ );
4521
+ });
4522
+ ComposerAttachmentRemove.displayName = "ComposerAttachmentRemove";
4523
+ var exports5 = {
4524
+ Root: ComposerAttachmentRoot,
4525
+ Remove: ComposerAttachmentRemove
4526
+ };
4527
+ var composer_attachment_default = Object.assign(
4528
+ ComposerAttachment2,
4529
+ exports5
4530
+ );
4531
+
4009
4532
  // src/ui/composer.tsx
4010
- import { Fragment as Fragment5, jsx as jsx38, jsxs as jsxs9 } from "react/jsx-runtime";
4533
+ import { Fragment as Fragment5, jsx as jsx42, jsxs as jsxs10 } from "react/jsx-runtime";
4534
+ var useAllowAttachments = (ensureCapability = false) => {
4535
+ const { composer: { allowAttachments = true } = {} } = useThreadConfig();
4536
+ const { useThread } = useThreadContext();
4537
+ const attachmentsSupported = useThread((t) => t.capabilities.attachments);
4538
+ return allowAttachments && (!ensureCapability || attachmentsSupported);
4539
+ };
4011
4540
  var Composer = () => {
4012
- return /* @__PURE__ */ jsxs9(ComposerRoot, { children: [
4013
- /* @__PURE__ */ jsx38(ComposerInput, { autoFocus: true }),
4014
- /* @__PURE__ */ jsx38(ComposerAction, {})
4541
+ const allowAttachments = useAllowAttachments(true);
4542
+ return /* @__PURE__ */ jsxs10(ComposerRoot, { children: [
4543
+ allowAttachments && /* @__PURE__ */ jsx42(ComposerAttachments, {}),
4544
+ allowAttachments && /* @__PURE__ */ jsx42(ComposerAddAttachment, {}),
4545
+ /* @__PURE__ */ jsx42(ComposerInput, { autoFocus: true }),
4546
+ /* @__PURE__ */ jsx42(ComposerAction, {})
4015
4547
  ] });
4016
4548
  };
4017
4549
  Composer.displayName = "Composer";
@@ -4031,10 +4563,47 @@ var ComposerInput = forwardRef23(
4031
4563
  composer: { input: { placeholder = "Write a message..." } = {} } = {}
4032
4564
  } = {}
4033
4565
  } = useThreadConfig();
4034
- return /* @__PURE__ */ jsx38(ComposerInputStyled, { placeholder, ...props, ref });
4566
+ return /* @__PURE__ */ jsx42(ComposerInputStyled, { placeholder, ...props, ref });
4035
4567
  }
4036
4568
  );
4037
4569
  ComposerInput.displayName = "ComposerInput";
4570
+ var ComposerAttachmentsContainer = withDefaults("div", {
4571
+ className: "aui-composer-attachments"
4572
+ });
4573
+ var ComposerAttachments = ({ components }) => {
4574
+ return /* @__PURE__ */ jsx42(ComposerAttachmentsContainer, { children: /* @__PURE__ */ jsx42(
4575
+ composer_exports.Attachments,
4576
+ {
4577
+ components: {
4578
+ ...components,
4579
+ Attachment: components?.Attachment ?? composer_attachment_default
4580
+ }
4581
+ }
4582
+ ) });
4583
+ };
4584
+ var ComposerAttachButton = withDefaults(TooltipIconButton, {
4585
+ variant: "default",
4586
+ className: "aui-composer-attach"
4587
+ });
4588
+ var ComposerAddAttachment = forwardRef23((props, ref) => {
4589
+ const {
4590
+ strings: {
4591
+ composer: { addAttachment: { tooltip = "Attach file" } = {} } = {}
4592
+ } = {}
4593
+ } = useThreadConfig();
4594
+ const allowAttachments = useAllowAttachments();
4595
+ return /* @__PURE__ */ jsx42(composer_exports.AddAttachment, { disabled: !allowAttachments, asChild: true, children: /* @__PURE__ */ jsx42(
4596
+ ComposerAttachButton,
4597
+ {
4598
+ tooltip,
4599
+ variant: "ghost",
4600
+ ...props,
4601
+ ref,
4602
+ children: props.children ?? /* @__PURE__ */ jsx42(PaperclipIcon, {})
4603
+ }
4604
+ ) });
4605
+ });
4606
+ ComposerAddAttachment.displayName = "ComposerAddAttachment";
4038
4607
  var useAllowCancel = () => {
4039
4608
  const { useThread } = useThreadContext();
4040
4609
  const cancelSupported = useThread((t) => t.capabilities.cancel);
@@ -4042,10 +4611,10 @@ var useAllowCancel = () => {
4042
4611
  };
4043
4612
  var ComposerAction = () => {
4044
4613
  const allowCancel = useAllowCancel();
4045
- if (!allowCancel) return /* @__PURE__ */ jsx38(ComposerSend, {});
4046
- return /* @__PURE__ */ jsxs9(Fragment5, { children: [
4047
- /* @__PURE__ */ jsx38(thread_exports.If, { running: false, children: /* @__PURE__ */ jsx38(ComposerSend, {}) }),
4048
- /* @__PURE__ */ jsx38(thread_exports.If, { running: true, children: /* @__PURE__ */ jsx38(ComposerCancel, {}) })
4614
+ if (!allowCancel) return /* @__PURE__ */ jsx42(ComposerSend, {});
4615
+ return /* @__PURE__ */ jsxs10(Fragment5, { children: [
4616
+ /* @__PURE__ */ jsx42(thread_exports.If, { running: false, children: /* @__PURE__ */ jsx42(ComposerSend, {}) }),
4617
+ /* @__PURE__ */ jsx42(thread_exports.If, { running: true, children: /* @__PURE__ */ jsx42(ComposerCancel, {}) })
4049
4618
  ] });
4050
4619
  };
4051
4620
  ComposerAction.displayName = "ComposerAction";
@@ -4057,7 +4626,7 @@ var ComposerSend = forwardRef23((props, ref) => {
4057
4626
  const {
4058
4627
  strings: { composer: { send: { tooltip = "Send" } = {} } = {} } = {}
4059
4628
  } = useThreadConfig();
4060
- return /* @__PURE__ */ jsx38(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx38(ComposerSendButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx38(SendHorizontalIcon, {}) }) });
4629
+ return /* @__PURE__ */ jsx42(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx42(ComposerSendButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx42(SendHorizontalIcon, {}) }) });
4061
4630
  });
4062
4631
  ComposerSend.displayName = "ComposerSend";
4063
4632
  var ComposerCancelButton = withDefaults(TooltipIconButton, {
@@ -4068,28 +4637,30 @@ var ComposerCancel = forwardRef23((props, ref) => {
4068
4637
  const {
4069
4638
  strings: { composer: { cancel: { tooltip = "Cancel" } = {} } = {} } = {}
4070
4639
  } = useThreadConfig();
4071
- return /* @__PURE__ */ jsx38(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx38(ComposerCancelButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx38(CircleStopIcon, {}) }) });
4640
+ return /* @__PURE__ */ jsx42(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx42(ComposerCancelButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx42(CircleStopIcon, {}) }) });
4072
4641
  });
4073
4642
  ComposerCancel.displayName = "ComposerCancel";
4074
- var exports5 = {
4643
+ var exports6 = {
4075
4644
  Root: ComposerRoot,
4076
4645
  Input: ComposerInput,
4077
4646
  Action: ComposerAction,
4078
4647
  Send: ComposerSend,
4079
- Cancel: ComposerCancel
4648
+ Cancel: ComposerCancel,
4649
+ AddAttachment: ComposerAddAttachment,
4650
+ Attachments: ComposerAttachments
4080
4651
  };
4081
- var composer_default = Object.assign(Composer, exports5);
4652
+ var composer_default = Object.assign(Composer, exports6);
4082
4653
 
4083
4654
  // src/ui/thread-welcome.tsx
4084
4655
  import { forwardRef as forwardRef24 } from "react";
4085
- import { jsx as jsx39, jsxs as jsxs10 } from "react/jsx-runtime";
4656
+ import { jsx as jsx43, jsxs as jsxs11 } from "react/jsx-runtime";
4086
4657
  var ThreadWelcome = () => {
4087
- return /* @__PURE__ */ jsxs10(ThreadWelcomeRoot, { children: [
4088
- /* @__PURE__ */ jsxs10(ThreadWelcomeCenter, { children: [
4089
- /* @__PURE__ */ jsx39(ThreadWelcomeAvatar, {}),
4090
- /* @__PURE__ */ jsx39(ThreadWelcomeMessage, {})
4658
+ return /* @__PURE__ */ jsxs11(ThreadWelcomeRoot, { children: [
4659
+ /* @__PURE__ */ jsxs11(ThreadWelcomeCenter, { children: [
4660
+ /* @__PURE__ */ jsx43(ThreadWelcomeAvatar, {}),
4661
+ /* @__PURE__ */ jsx43(ThreadWelcomeMessage, {})
4091
4662
  ] }),
4092
- /* @__PURE__ */ jsx39(ThreadWelcomeSuggestions, {})
4663
+ /* @__PURE__ */ jsx43(ThreadWelcomeSuggestions, {})
4093
4664
  ] });
4094
4665
  };
4095
4666
  ThreadWelcome.displayName = "ThreadWelcome";
@@ -4101,20 +4672,20 @@ var ThreadWelcomeCenter = withDefaults("div", {
4101
4672
  });
4102
4673
  var ThreadWelcomeRoot = forwardRef24(
4103
4674
  (props, ref) => {
4104
- return /* @__PURE__ */ jsx39(thread_exports.Empty, { children: /* @__PURE__ */ jsx39(ThreadWelcomeRootStyled, { ...props, ref }) });
4675
+ return /* @__PURE__ */ jsx43(thread_exports.Empty, { children: /* @__PURE__ */ jsx43(ThreadWelcomeRootStyled, { ...props, ref }) });
4105
4676
  }
4106
4677
  );
4107
4678
  ThreadWelcomeRoot.displayName = "ThreadWelcomeRoot";
4108
4679
  var ThreadWelcomeAvatar = () => {
4109
4680
  const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
4110
- return /* @__PURE__ */ jsx39(Avatar, { ...avatar });
4681
+ return /* @__PURE__ */ jsx43(Avatar, { ...avatar });
4111
4682
  };
4112
4683
  var ThreadWelcomeMessageStyled = withDefaults("p", {
4113
4684
  className: "aui-thread-welcome-message"
4114
4685
  });
4115
4686
  var ThreadWelcomeMessage = forwardRef24(({ message: messageProp, ...rest }, ref) => {
4116
4687
  const { welcome: { message = "How can I help you today?" } = {} } = useThreadConfig();
4117
- return /* @__PURE__ */ jsx39(ThreadWelcomeMessageStyled, { ...rest, ref, children: messageProp ?? message });
4688
+ return /* @__PURE__ */ jsx43(ThreadWelcomeMessageStyled, { ...rest, ref, children: messageProp ?? message });
4118
4689
  });
4119
4690
  ThreadWelcomeMessage.displayName = "ThreadWelcomeMessage";
4120
4691
  var ThreadWelcomeSuggestionContainer = withDefaults("div", {
@@ -4126,25 +4697,25 @@ var ThreadWelcomeSuggestionStyled = withDefaults(thread_exports.Suggestion, {
4126
4697
  var ThreadWelcomeSuggestion = ({
4127
4698
  suggestion: { text, prompt }
4128
4699
  }) => {
4129
- return /* @__PURE__ */ jsx39(
4700
+ return /* @__PURE__ */ jsx43(
4130
4701
  ThreadWelcomeSuggestionStyled,
4131
4702
  {
4132
4703
  prompt,
4133
4704
  method: "replace",
4134
4705
  autoSend: true,
4135
- children: /* @__PURE__ */ jsx39("span", { className: "aui-thread-welcome-suggestion-text", children: text ?? prompt })
4706
+ children: /* @__PURE__ */ jsx43("span", { className: "aui-thread-welcome-suggestion-text", children: text ?? prompt })
4136
4707
  }
4137
4708
  );
4138
4709
  };
4139
4710
  var ThreadWelcomeSuggestions = () => {
4140
4711
  const { welcome: { suggestions } = {} } = useThreadConfig();
4141
- return /* @__PURE__ */ jsx39(ThreadWelcomeSuggestionContainer, { children: suggestions?.map((suggestion, idx) => {
4712
+ return /* @__PURE__ */ jsx43(ThreadWelcomeSuggestionContainer, { children: suggestions?.map((suggestion, idx) => {
4142
4713
  const key = `${suggestion.prompt}-${idx}`;
4143
- return /* @__PURE__ */ jsx39(ThreadWelcomeSuggestion, { suggestion }, key);
4714
+ return /* @__PURE__ */ jsx43(ThreadWelcomeSuggestion, { suggestion }, key);
4144
4715
  }) });
4145
4716
  };
4146
4717
  ThreadWelcomeSuggestions.displayName = "ThreadWelcomeSuggestions";
4147
- var exports6 = {
4718
+ var exports7 = {
4148
4719
  Root: ThreadWelcomeRoot,
4149
4720
  Center: ThreadWelcomeCenter,
4150
4721
  Avatar: ThreadWelcomeAvatar,
@@ -4152,7 +4723,7 @@ var exports6 = {
4152
4723
  Suggestions: ThreadWelcomeSuggestions,
4153
4724
  Suggestion: ThreadWelcomeSuggestion
4154
4725
  };
4155
- var thread_welcome_default = Object.assign(ThreadWelcome, exports6);
4726
+ var thread_welcome_default = Object.assign(ThreadWelcome, exports7);
4156
4727
 
4157
4728
  // src/ui/user-message.tsx
4158
4729
  import { forwardRef as forwardRef26 } from "react";
@@ -4160,7 +4731,7 @@ import { forwardRef as forwardRef26 } from "react";
4160
4731
  // src/ui/user-action-bar.tsx
4161
4732
  import { forwardRef as forwardRef25 } from "react";
4162
4733
  import { PencilIcon } from "lucide-react";
4163
- import { jsx as jsx40 } from "react/jsx-runtime";
4734
+ import { jsx as jsx44 } from "react/jsx-runtime";
4164
4735
  var useAllowEdit = (ensureCapability = false) => {
4165
4736
  const { userMessage: { allowEdit = true } = {} } = useThreadConfig();
4166
4737
  const { useThread } = useThreadContext();
@@ -4170,7 +4741,7 @@ var useAllowEdit = (ensureCapability = false) => {
4170
4741
  var UserActionBar = () => {
4171
4742
  const allowEdit = useAllowEdit(true);
4172
4743
  if (!allowEdit) return null;
4173
- return /* @__PURE__ */ jsx40(UserActionBarRoot, { hideWhenRunning: true, autohide: "not-last", children: /* @__PURE__ */ jsx40(UserActionBarEdit, {}) });
4744
+ return /* @__PURE__ */ jsx44(UserActionBarRoot, { hideWhenRunning: true, autohide: "not-last", children: /* @__PURE__ */ jsx44(UserActionBarEdit, {}) });
4174
4745
  };
4175
4746
  UserActionBar.displayName = "UserActionBar";
4176
4747
  var UserActionBarRoot = withDefaults(actionBar_exports.Root, {
@@ -4182,23 +4753,46 @@ var UserActionBarEdit = forwardRef25((props, ref) => {
4182
4753
  strings: { userMessage: { edit: { tooltip = "Edit" } = {} } = {} } = {}
4183
4754
  } = useThreadConfig();
4184
4755
  const allowEdit = useAllowEdit();
4185
- if (!allowEdit) return null;
4186
- return /* @__PURE__ */ jsx40(actionBar_exports.Edit, { asChild: true, children: /* @__PURE__ */ jsx40(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx40(PencilIcon, {}) }) });
4756
+ return /* @__PURE__ */ jsx44(actionBar_exports.Edit, { disabled: !allowEdit, asChild: true, children: /* @__PURE__ */ jsx44(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx44(PencilIcon, {}) }) });
4187
4757
  });
4188
4758
  UserActionBarEdit.displayName = "UserActionBarEdit";
4189
- var exports7 = {
4759
+ var exports8 = {
4190
4760
  Root: UserActionBarRoot,
4191
4761
  Edit: UserActionBarEdit
4192
4762
  };
4193
- var user_action_bar_default = Object.assign(UserActionBar, exports7);
4763
+ var user_action_bar_default = Object.assign(UserActionBar, exports8);
4764
+
4765
+ // src/ui/user-message-attachment.tsx
4766
+ import { jsxs as jsxs12 } from "react/jsx-runtime";
4767
+ var UserMessageAttachmentRoot = withDefaults("div", {
4768
+ className: "aui-user-message-attachment-root"
4769
+ });
4770
+ UserMessageAttachmentRoot.displayName = "UserMessageAttachmentRoot";
4771
+ var UserMessageAttachment = () => {
4772
+ const { useAttachment } = useAttachmentContext();
4773
+ const attachment = useAttachment((a) => a.attachment);
4774
+ return /* @__PURE__ */ jsxs12(UserMessageAttachmentRoot, { children: [
4775
+ ".",
4776
+ attachment.name.split(".").pop()
4777
+ ] });
4778
+ };
4779
+ UserMessageAttachment.displayName = "UserMessageAttachment";
4780
+ var exports9 = {
4781
+ Root: UserMessageAttachmentRoot
4782
+ };
4783
+ var user_message_attachment_default = Object.assign(
4784
+ UserMessageAttachment,
4785
+ exports9
4786
+ );
4194
4787
 
4195
4788
  // src/ui/user-message.tsx
4196
- import { jsx as jsx41, jsxs as jsxs11 } from "react/jsx-runtime";
4789
+ import { jsx as jsx45, jsxs as jsxs13 } from "react/jsx-runtime";
4197
4790
  var UserMessage = () => {
4198
- return /* @__PURE__ */ jsxs11(UserMessageRoot, { children: [
4199
- /* @__PURE__ */ jsx41(user_action_bar_default, {}),
4200
- /* @__PURE__ */ jsx41(UserMessageContent, {}),
4201
- /* @__PURE__ */ jsx41(branch_picker_default, {})
4791
+ return /* @__PURE__ */ jsxs13(UserMessageRoot, { children: [
4792
+ /* @__PURE__ */ jsx45(UserMessageAttachments, {}),
4793
+ /* @__PURE__ */ jsx45(user_action_bar_default, {}),
4794
+ /* @__PURE__ */ jsx45(UserMessageContent, {}),
4795
+ /* @__PURE__ */ jsx45(branch_picker_default, {})
4202
4796
  ] });
4203
4797
  };
4204
4798
  UserMessage.displayName = "UserMessage";
@@ -4211,7 +4805,7 @@ var UserMessageContentWrapper = withDefaults("div", {
4211
4805
  });
4212
4806
  var UserMessageContent = forwardRef26(
4213
4807
  ({ components, ...props }, ref) => {
4214
- return /* @__PURE__ */ jsx41(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx41(
4808
+ return /* @__PURE__ */ jsx45(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx45(
4215
4809
  message_exports.Content,
4216
4810
  {
4217
4811
  components: {
@@ -4223,21 +4817,38 @@ var UserMessageContent = forwardRef26(
4223
4817
  }
4224
4818
  );
4225
4819
  UserMessageContent.displayName = "UserMessageContent";
4226
- var exports8 = {
4820
+ var UserMessageAttachmentsContainer = withDefaults("div", {
4821
+ className: "aui-user-message-attachments"
4822
+ });
4823
+ var UserMessageAttachments = ({
4824
+ components
4825
+ }) => {
4826
+ return /* @__PURE__ */ jsx45(message_exports.If, { hasAttachments: true, children: /* @__PURE__ */ jsx45(UserMessageAttachmentsContainer, { children: /* @__PURE__ */ jsx45(
4827
+ message_exports.Attachments,
4828
+ {
4829
+ components: {
4830
+ ...components,
4831
+ Attachment: components?.Attachment ?? user_message_attachment_default
4832
+ }
4833
+ }
4834
+ ) }) });
4835
+ };
4836
+ var exports10 = {
4227
4837
  Root: UserMessageRoot,
4228
- Content: UserMessageContent
4838
+ Content: UserMessageContent,
4839
+ Attachments: UserMessageAttachments
4229
4840
  };
4230
- var user_message_default = Object.assign(UserMessage, exports8);
4841
+ var user_message_default = Object.assign(UserMessage, exports10);
4231
4842
 
4232
4843
  // src/ui/edit-composer.tsx
4233
4844
  import { forwardRef as forwardRef27 } from "react";
4234
- import { jsx as jsx42, jsxs as jsxs12 } from "react/jsx-runtime";
4845
+ import { jsx as jsx46, jsxs as jsxs14 } from "react/jsx-runtime";
4235
4846
  var EditComposer = () => {
4236
- return /* @__PURE__ */ jsxs12(EditComposerRoot, { children: [
4237
- /* @__PURE__ */ jsx42(EditComposerInput, {}),
4238
- /* @__PURE__ */ jsxs12(EditComposerFooter, { children: [
4239
- /* @__PURE__ */ jsx42(EditComposerCancel, {}),
4240
- /* @__PURE__ */ jsx42(EditComposerSend, {})
4847
+ return /* @__PURE__ */ jsxs14(EditComposerRoot, { children: [
4848
+ /* @__PURE__ */ jsx46(EditComposerInput, {}),
4849
+ /* @__PURE__ */ jsxs14(EditComposerFooter, { children: [
4850
+ /* @__PURE__ */ jsx46(EditComposerCancel, {}),
4851
+ /* @__PURE__ */ jsx46(EditComposerSend, {})
4241
4852
  ] })
4242
4853
  ] });
4243
4854
  };
@@ -4261,7 +4872,7 @@ var EditComposerCancel = forwardRef27(
4261
4872
  editComposer: { cancel: { label = "Cancel" } = {} } = {}
4262
4873
  } = {}
4263
4874
  } = useThreadConfig();
4264
- return /* @__PURE__ */ jsx42(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx42(Button, { variant: "ghost", ...props, ref, children: props.children ?? label }) });
4875
+ return /* @__PURE__ */ jsx46(composer_exports.Cancel, { asChild: true, children: /* @__PURE__ */ jsx46(Button, { variant: "ghost", ...props, ref, children: props.children ?? label }) });
4265
4876
  }
4266
4877
  );
4267
4878
  EditComposerCancel.displayName = "EditComposerCancel";
@@ -4270,28 +4881,28 @@ var EditComposerSend = forwardRef27(
4270
4881
  const {
4271
4882
  strings: { editComposer: { send: { label = "Send" } = {} } = {} } = {}
4272
4883
  } = useThreadConfig();
4273
- return /* @__PURE__ */ jsx42(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx42(Button, { ...props, ref, children: props.children ?? label }) });
4884
+ return /* @__PURE__ */ jsx46(composer_exports.Send, { asChild: true, children: /* @__PURE__ */ jsx46(Button, { ...props, ref, children: props.children ?? label }) });
4274
4885
  }
4275
4886
  );
4276
4887
  EditComposerSend.displayName = "EditComposerSend";
4277
- var exports9 = {
4888
+ var exports11 = {
4278
4889
  Root: EditComposerRoot,
4279
4890
  Input: EditComposerInput,
4280
4891
  Footer: EditComposerFooter,
4281
4892
  Cancel: EditComposerCancel,
4282
4893
  Send: EditComposerSend
4283
4894
  };
4284
- var edit_composer_default = Object.assign(EditComposer, exports9);
4895
+ var edit_composer_default = Object.assign(EditComposer, exports11);
4285
4896
 
4286
4897
  // src/ui/thread.tsx
4287
- import { jsx as jsx43, jsxs as jsxs13 } from "react/jsx-runtime";
4898
+ import { jsx as jsx47, jsxs as jsxs15 } from "react/jsx-runtime";
4288
4899
  var Thread = (config) => {
4289
- return /* @__PURE__ */ jsx43(ThreadRoot, { config, children: /* @__PURE__ */ jsxs13(ThreadViewport, { children: [
4290
- /* @__PURE__ */ jsx43(thread_welcome_default, {}),
4291
- /* @__PURE__ */ jsx43(ThreadMessages, {}),
4292
- /* @__PURE__ */ jsxs13(ThreadViewportFooter, { children: [
4293
- /* @__PURE__ */ jsx43(ThreadScrollToBottom, {}),
4294
- /* @__PURE__ */ jsx43(composer_default, {})
4900
+ return /* @__PURE__ */ jsx47(ThreadRoot, { config, children: /* @__PURE__ */ jsxs15(ThreadViewport, { children: [
4901
+ /* @__PURE__ */ jsx47(thread_welcome_default, {}),
4902
+ /* @__PURE__ */ jsx47(ThreadMessages, {}),
4903
+ /* @__PURE__ */ jsxs15(ThreadViewportFooter, { children: [
4904
+ /* @__PURE__ */ jsx47(ThreadScrollToBottom, {}),
4905
+ /* @__PURE__ */ jsx47(composer_default, {})
4295
4906
  ] })
4296
4907
  ] }) });
4297
4908
  };
@@ -4300,7 +4911,7 @@ var ThreadRootStyled = withDefaults(thread_exports.Root, {
4300
4911
  });
4301
4912
  var ThreadRoot = forwardRef28(
4302
4913
  ({ config, ...props }, ref) => {
4303
- return /* @__PURE__ */ jsx43(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx43(ThreadRootStyled, { ...props, ref }) });
4914
+ return /* @__PURE__ */ jsx47(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx47(ThreadRootStyled, { ...props, ref }) });
4304
4915
  }
4305
4916
  );
4306
4917
  ThreadRoot.displayName = "ThreadRoot";
@@ -4314,7 +4925,7 @@ var ThreadViewportFooter = withDefaults("div", {
4314
4925
  ThreadViewportFooter.displayName = "ThreadViewportFooter";
4315
4926
  var SystemMessage = () => null;
4316
4927
  var ThreadMessages = ({ components, ...rest }) => {
4317
- return /* @__PURE__ */ jsx43(
4928
+ return /* @__PURE__ */ jsx47(
4318
4929
  thread_exports.Messages,
4319
4930
  {
4320
4931
  components: {
@@ -4338,33 +4949,33 @@ var ThreadScrollToBottom = forwardRef28((props, ref) => {
4338
4949
  thread: { scrollToBottom: { tooltip = "Scroll to bottom" } = {} } = {}
4339
4950
  } = {}
4340
4951
  } = useThreadConfig();
4341
- return /* @__PURE__ */ jsx43(thread_exports.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx43(ThreadScrollToBottomIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx43(ArrowDownIcon, {}) }) });
4952
+ return /* @__PURE__ */ jsx47(thread_exports.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx47(ThreadScrollToBottomIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsx47(ArrowDownIcon, {}) }) });
4342
4953
  });
4343
4954
  ThreadScrollToBottom.displayName = "ThreadScrollToBottom";
4344
- var exports10 = {
4955
+ var exports12 = {
4345
4956
  Root: ThreadRoot,
4346
4957
  Viewport: ThreadViewport,
4347
4958
  Messages: ThreadMessages,
4348
4959
  ScrollToBottom: ThreadScrollToBottom,
4349
4960
  ViewportFooter: ThreadViewportFooter
4350
4961
  };
4351
- var thread_default = Object.assign(Thread, exports10);
4962
+ var thread_default = Object.assign(Thread, exports12);
4352
4963
 
4353
4964
  // src/ui/assistant-modal.tsx
4354
- import { Fragment as Fragment6, jsx as jsx44, jsxs as jsxs14 } from "react/jsx-runtime";
4965
+ import { Fragment as Fragment6, jsx as jsx48, jsxs as jsxs16 } from "react/jsx-runtime";
4355
4966
  var AssistantModal = (config) => {
4356
- return /* @__PURE__ */ jsxs14(AssistantModalRoot, { config, children: [
4357
- /* @__PURE__ */ jsx44(AssistantModalTrigger, {}),
4358
- /* @__PURE__ */ jsx44(AssistantModalContent, { children: /* @__PURE__ */ jsx44(thread_default, {}) })
4967
+ return /* @__PURE__ */ jsxs16(AssistantModalRoot, { config, children: [
4968
+ /* @__PURE__ */ jsx48(AssistantModalTrigger, {}),
4969
+ /* @__PURE__ */ jsx48(AssistantModalContent, { children: /* @__PURE__ */ jsx48(thread_default, {}) })
4359
4970
  ] });
4360
4971
  };
4361
4972
  AssistantModal.displayName = "AssistantModal";
4362
4973
  var AssistantModalRoot = ({ config, ...props }) => {
4363
- return /* @__PURE__ */ jsx44(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx44(assistantModal_exports.Root, { ...props }) });
4974
+ return /* @__PURE__ */ jsx48(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx48(assistantModal_exports.Root, { ...props }) });
4364
4975
  };
4365
4976
  AssistantModalRoot.displayName = "AssistantModalRoot";
4366
4977
  var AssistantModalTrigger = forwardRef29((props, ref) => {
4367
- return /* @__PURE__ */ jsx44(AssistantModalAnchor, { children: /* @__PURE__ */ jsx44(assistantModal_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx44(AssistantModalButton, { ...props, ref }) }) });
4978
+ return /* @__PURE__ */ jsx48(AssistantModalAnchor, { children: /* @__PURE__ */ jsx48(assistantModal_exports.Trigger, { asChild: true, children: /* @__PURE__ */ jsx48(AssistantModalButton, { ...props, ref }) }) });
4368
4979
  });
4369
4980
  AssistantModalTrigger.displayName = "AssistantModalTrigger";
4370
4981
  var AssistantModalAnchor = withDefaults(assistantModal_exports.Anchor, {
@@ -4389,7 +5000,7 @@ var AssistantModalButton = forwardRef29(({ "data-state": state, ...rest }, ref)
4389
5000
  } = {}
4390
5001
  } = useThreadConfig();
4391
5002
  const tooltip = state === "open" ? openTooltip : closedTooltip;
4392
- return /* @__PURE__ */ jsx44(
5003
+ return /* @__PURE__ */ jsx48(
4393
5004
  ModalButtonStyled,
4394
5005
  {
4395
5006
  side: "left",
@@ -4397,15 +5008,15 @@ var AssistantModalButton = forwardRef29(({ "data-state": state, ...rest }, ref)
4397
5008
  "data-state": state,
4398
5009
  ...rest,
4399
5010
  ref,
4400
- children: rest.children ?? /* @__PURE__ */ jsxs14(Fragment6, { children: [
4401
- /* @__PURE__ */ jsx44(
5011
+ children: rest.children ?? /* @__PURE__ */ jsxs16(Fragment6, { children: [
5012
+ /* @__PURE__ */ jsx48(
4402
5013
  BotIcon,
4403
5014
  {
4404
5015
  "data-state": state,
4405
5016
  className: "aui-modal-button-closed-icon"
4406
5017
  }
4407
5018
  ),
4408
- /* @__PURE__ */ jsx44(
5019
+ /* @__PURE__ */ jsx48(
4409
5020
  ChevronDownIcon,
4410
5021
  {
4411
5022
  "data-state": state,
@@ -4422,14 +5033,14 @@ var AssistantModalContent = withDefaults(assistantModal_exports.Content, {
4422
5033
  sideOffset: 16
4423
5034
  });
4424
5035
  AssistantModalContent.displayName = "AssistantModalContent";
4425
- var exports11 = {
5036
+ var exports13 = {
4426
5037
  Root: AssistantModalRoot,
4427
5038
  Trigger: AssistantModalTrigger,
4428
5039
  Content: AssistantModalContent,
4429
5040
  Button: AssistantModalButton,
4430
5041
  Anchor: AssistantModalAnchor
4431
5042
  };
4432
- var assistant_modal_default = Object.assign(AssistantModal, exports11);
5043
+ var assistant_modal_default = Object.assign(AssistantModal, exports13);
4433
5044
  export {
4434
5045
  actionBar_exports as ActionBarPrimitive,
4435
5046
  assistant_action_bar_default as AssistantActionBar,
@@ -4440,7 +5051,9 @@ export {
4440
5051
  branch_picker_default as BranchPicker,
4441
5052
  branchPicker_exports as BranchPickerPrimitive,
4442
5053
  composer_default as Composer,
5054
+ composer_attachment_default as ComposerAttachment,
4443
5055
  composer_exports as ComposerPrimitive,
5056
+ CompositeAttachmentAdapter,
4444
5057
  content_part_default as ContentPart,
4445
5058
  contentPart_exports as ContentPartPrimitive,
4446
5059
  EdgeChatAdapter,
@@ -4448,12 +5061,15 @@ export {
4448
5061
  ExternalStoreRuntime,
4449
5062
  internal_exports as INTERNAL,
4450
5063
  message_exports as MessagePrimitive,
5064
+ SimpleImageAttachmentAdapter,
5065
+ SimpleTextAttachmentAdapter,
4451
5066
  thread_default as Thread,
4452
5067
  ThreadConfigProvider,
4453
5068
  thread_exports as ThreadPrimitive,
4454
5069
  thread_welcome_default as ThreadWelcome,
4455
5070
  user_action_bar_default as UserActionBar,
4456
5071
  user_message_default as UserMessage,
5072
+ user_message_attachment_default as UserMessageAttachment,
4457
5073
  WebSpeechSynthesisAdapter,
4458
5074
  fromCoreMessage,
4459
5075
  fromCoreMessages,
@@ -4482,6 +5098,7 @@ export {
4482
5098
  useBranchPickerNext,
4483
5099
  useBranchPickerNumber,
4484
5100
  useBranchPickerPrevious,
5101
+ useComposerAddAttachment,
4485
5102
  useComposerCancel,
4486
5103
  useComposerContext,
4487
5104
  useComposerIf,