@assistant-ui/react 0.5.46 → 0.5.48

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;
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;
1128
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 = () => {
@@ -2400,7 +2633,7 @@ var useComposerSend = () => {
2400
2633
  const { useComposer } = useComposerContext();
2401
2634
  const disabled = useCombinedStore(
2402
2635
  [useThread, useComposer],
2403
- (t, c) => t.isRunning || !c.isEditing || c.text.length === 0
2636
+ (t, c) => t.isRunning || !c.isEditing || c.isEmpty
2404
2637
  );
2405
2638
  const callback = useCallback11(() => {
2406
2639
  const composerState = useComposer.getState();
@@ -2413,6 +2646,30 @@ var useComposerSend = () => {
2413
2646
  return callback;
2414
2647
  };
2415
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
+
2416
2673
  // src/primitive-hooks/contentPart/useContentPartDisplay.tsx
2417
2674
  var useContentPartDisplay = () => {
2418
2675
  const { useContentPart } = useContentPartContext();
@@ -2467,6 +2724,10 @@ var useMessageIf = (props) => {
2467
2724
  if (props.copied === false && isCopied) return false;
2468
2725
  if (props.speaking === true && !isSpeaking) return false;
2469
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;
2470
2731
  return true;
2471
2732
  }
2472
2733
  );
@@ -2495,11 +2756,11 @@ var useThreadEmpty = () => {
2495
2756
  };
2496
2757
 
2497
2758
  // src/primitive-hooks/thread/useThreadScrollToBottom.tsx
2498
- import { useCallback as useCallback12 } from "react";
2759
+ import { useCallback as useCallback13 } from "react";
2499
2760
  var useThreadScrollToBottom = () => {
2500
2761
  const { useComposer, useViewport } = useThreadContext();
2501
2762
  const isAtBottom = useViewport((s) => s.isAtBottom);
2502
- const handleScrollToBottom = useCallback12(() => {
2763
+ const handleScrollToBottom = useCallback13(() => {
2503
2764
  useViewport.getState().scrollToBottom();
2504
2765
  useComposer.getState().focus();
2505
2766
  }, [useViewport, useComposer]);
@@ -2508,7 +2769,7 @@ var useThreadScrollToBottom = () => {
2508
2769
  };
2509
2770
 
2510
2771
  // src/primitive-hooks/thread/useThreadSuggestion.tsx
2511
- import { useCallback as useCallback13 } from "react";
2772
+ import { useCallback as useCallback14 } from "react";
2512
2773
  var useThreadSuggestion = ({
2513
2774
  prompt,
2514
2775
  autoSend
@@ -2516,7 +2777,7 @@ var useThreadSuggestion = ({
2516
2777
  const { useThread, useComposer } = useThreadContext();
2517
2778
  const append = useAppendMessage();
2518
2779
  const disabled = useThread((t) => t.isDisabled);
2519
- const callback = useCallback13(() => {
2780
+ const callback = useCallback14(() => {
2520
2781
  const thread = useThread.getState();
2521
2782
  const composer = useComposer.getState();
2522
2783
  if (autoSend && !thread.isRunning) {
@@ -2844,6 +3105,7 @@ import { forwardRef as forwardRef14 } from "react";
2844
3105
  // src/primitives/message/index.ts
2845
3106
  var message_exports = {};
2846
3107
  __export(message_exports, {
3108
+ Attachments: () => MessagePrimitiveAttachments,
2847
3109
  Content: () => MessagePrimitiveContent,
2848
3110
  If: () => MessagePrimitiveIf,
2849
3111
  InProgress: () => MessagePrimitiveInProgress,
@@ -2854,14 +3116,14 @@ __export(message_exports, {
2854
3116
  import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
2855
3117
  import {
2856
3118
  forwardRef as forwardRef11,
2857
- useCallback as useCallback15
3119
+ useCallback as useCallback16
2858
3120
  } from "react";
2859
3121
 
2860
3122
  // src/utils/hooks/useManagedRef.ts
2861
- import { useCallback as useCallback14, useRef as useRef3 } from "react";
3123
+ import { useCallback as useCallback15, useRef as useRef3 } from "react";
2862
3124
  var useManagedRef = (callback) => {
2863
3125
  const cleanupRef = useRef3();
2864
- const ref = useCallback14(
3126
+ const ref = useCallback15(
2865
3127
  (el) => {
2866
3128
  if (cleanupRef.current) {
2867
3129
  cleanupRef.current();
@@ -2880,7 +3142,7 @@ import { useComposedRefs } from "@radix-ui/react-compose-refs";
2880
3142
  import { jsx as jsx18 } from "react/jsx-runtime";
2881
3143
  var useIsHoveringRef = () => {
2882
3144
  const { useMessageUtils } = useMessageContext();
2883
- const callbackRef = useCallback15(
3145
+ const callbackRef = useCallback16(
2884
3146
  (el) => {
2885
3147
  const setIsHovering = useMessageUtils.getState().setIsHovering;
2886
3148
  const handleMouseEnter = () => {
@@ -2975,7 +3237,7 @@ var useContentPartContext2 = (partIndex) => {
2975
3237
  partIndex
2976
3238
  );
2977
3239
  if (!newState) return;
2978
- context.useContentPart.setState(newState, true);
3240
+ writableStore(context.useContentPart).setState(newState, true);
2979
3241
  };
2980
3242
  syncContentPart(useMessage.getState());
2981
3243
  return useMessage.subscribe(syncContentPart);
@@ -3119,17 +3381,7 @@ var MessagePrimitiveContent = ({
3119
3381
  }) => {
3120
3382
  const { useMessage } = useMessageContext();
3121
3383
  const contentLength = useMessage((s) => s.message.content.length) || 1;
3122
- return new Array(contentLength).fill(null).map((_, idx) => {
3123
- const partIndex = idx;
3124
- return /* @__PURE__ */ jsx22(
3125
- MessageContentPart,
3126
- {
3127
- partIndex,
3128
- components
3129
- },
3130
- partIndex
3131
- );
3132
- });
3384
+ return Array.from({ length: contentLength }, (_, index) => /* @__PURE__ */ jsx22(MessageContentPart, { partIndex: index, components }, index));
3133
3385
  };
3134
3386
  MessagePrimitiveContent.displayName = "MessagePrimitive.Content";
3135
3387
 
@@ -3139,16 +3391,137 @@ var MessagePrimitiveInProgress = () => {
3139
3391
  };
3140
3392
  MessagePrimitiveInProgress.displayName = "MessagePrimitive.InProgress";
3141
3393
 
3142
- // 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";
3143
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";
3144
3515
  var BranchPickerPrimitiveRoot = forwardRef14(({ hideWhenSingleBranch, ...rest }, ref) => {
3145
- 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 }) });
3146
3517
  });
3147
3518
  BranchPickerPrimitiveRoot.displayName = "BranchPickerPrimitive.Root";
3148
3519
 
3149
3520
  // src/primitives/composer/index.ts
3150
3521
  var composer_exports = {};
3151
3522
  __export(composer_exports, {
3523
+ AddAttachment: () => ComposerPrimitiveAddAttachment,
3524
+ Attachments: () => ComposerPrimitiveAttachments,
3152
3525
  Cancel: () => ComposerPrimitiveCancel,
3153
3526
  If: () => ComposerPrimitiveIf,
3154
3527
  Input: () => ComposerPrimitiveInput,
@@ -3162,7 +3535,7 @@ import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
3162
3535
  import {
3163
3536
  forwardRef as forwardRef15
3164
3537
  } from "react";
3165
- import { jsx as jsx24 } from "react/jsx-runtime";
3538
+ import { jsx as jsx26 } from "react/jsx-runtime";
3166
3539
  var ComposerPrimitiveRoot = forwardRef15(({ onSubmit, ...rest }, forwardedRef) => {
3167
3540
  const send = useComposerSend();
3168
3541
  const handleSubmit = (e) => {
@@ -3170,7 +3543,7 @@ var ComposerPrimitiveRoot = forwardRef15(({ onSubmit, ...rest }, forwardedRef) =
3170
3543
  if (!send) return;
3171
3544
  send();
3172
3545
  };
3173
- return /* @__PURE__ */ jsx24(
3546
+ return /* @__PURE__ */ jsx26(
3174
3547
  Primitive8.form,
3175
3548
  {
3176
3549
  ...rest,
@@ -3187,13 +3560,13 @@ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-ref
3187
3560
  import { Slot } from "@radix-ui/react-slot";
3188
3561
  import {
3189
3562
  forwardRef as forwardRef16,
3190
- useCallback as useCallback16,
3191
- useEffect as useEffect10,
3563
+ useCallback as useCallback17,
3564
+ useEffect as useEffect11,
3192
3565
  useRef as useRef4
3193
3566
  } from "react";
3194
3567
  import TextareaAutosize from "react-textarea-autosize";
3195
3568
  import { useEscapeKeydown as useEscapeKeydown2 } from "@radix-ui/react-use-escape-keydown";
3196
- import { jsx as jsx25 } from "react/jsx-runtime";
3569
+ import { jsx as jsx27 } from "react/jsx-runtime";
3197
3570
  var ComposerPrimitiveInput = forwardRef16(
3198
3571
  ({
3199
3572
  autoFocus = false,
@@ -3232,7 +3605,7 @@ var ComposerPrimitiveInput = forwardRef16(
3232
3605
  }
3233
3606
  };
3234
3607
  const autoFocusEnabled = autoFocus && !isDisabled;
3235
- const focus = useCallback16(() => {
3608
+ const focus = useCallback17(() => {
3236
3609
  const textarea = textareaRef.current;
3237
3610
  if (!textarea || !autoFocusEnabled) return;
3238
3611
  textarea.focus({ preventScroll: true });
@@ -3241,13 +3614,13 @@ var ComposerPrimitiveInput = forwardRef16(
3241
3614
  textareaRef.current.value.length
3242
3615
  );
3243
3616
  }, [autoFocusEnabled]);
3244
- useEffect10(() => focus(), [focus]);
3617
+ useEffect11(() => focus(), [focus]);
3245
3618
  useOnComposerFocus(() => {
3246
3619
  if (type === "new") {
3247
3620
  focus();
3248
3621
  }
3249
3622
  });
3250
- return /* @__PURE__ */ jsx25(
3623
+ return /* @__PURE__ */ jsx27(
3251
3624
  Component,
3252
3625
  {
3253
3626
  name: "input",
@@ -3268,23 +3641,10 @@ var ComposerPrimitiveInput = forwardRef16(
3268
3641
  ComposerPrimitiveInput.displayName = "ComposerPrimitive.Input";
3269
3642
 
3270
3643
  // src/primitives/composer/ComposerSend.tsx
3271
- import { forwardRef as forwardRef17 } from "react";
3272
- import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
3273
- import { jsx as jsx26 } from "react/jsx-runtime";
3274
- var ComposerPrimitiveSend = forwardRef17(({ disabled, ...rest }, ref) => {
3275
- const { useComposer } = useComposerContext();
3276
- const hasValue = useComposer((c) => c.isEditing && c.text.length > 0);
3277
- return /* @__PURE__ */ jsx26(
3278
- Primitive9.button,
3279
- {
3280
- type: "submit",
3281
- ...rest,
3282
- ref,
3283
- disabled: disabled || !hasValue
3284
- }
3285
- );
3286
- });
3287
- ComposerPrimitiveSend.displayName = "ComposerPrimitive.Send";
3644
+ var ComposerPrimitiveSend = createActionButton(
3645
+ "ComposerPrimitive.Send",
3646
+ useComposerSend
3647
+ );
3288
3648
 
3289
3649
  // src/primitives/composer/ComposerCancel.tsx
3290
3650
  var ComposerPrimitiveCancel = createActionButton(
@@ -3292,6 +3652,101 @@ var ComposerPrimitiveCancel = createActionButton(
3292
3652
  useComposerCancel
3293
3653
  );
3294
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
+
3295
3750
  // src/primitives/composer/ComposerIf.tsx
3296
3751
  var ComposerPrimitiveIf = ({
3297
3752
  children,
@@ -3324,11 +3779,11 @@ __export(thread_exports, {
3324
3779
  });
3325
3780
 
3326
3781
  // src/primitives/thread/ThreadRoot.tsx
3327
- import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
3328
- import { forwardRef as forwardRef18 } from "react";
3329
- import { jsx as jsx27 } from "react/jsx-runtime";
3330
- var ThreadPrimitiveRoot = forwardRef18((props, ref) => {
3331
- 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 });
3332
3787
  });
3333
3788
  ThreadPrimitiveRoot.displayName = "ThreadPrimitive.Root";
3334
3789
 
@@ -3353,8 +3808,8 @@ ThreadPrimitiveIf.displayName = "ThreadPrimitive.If";
3353
3808
 
3354
3809
  // src/primitives/thread/ThreadViewport.tsx
3355
3810
  import { useComposedRefs as useComposedRefs4 } from "@radix-ui/react-compose-refs";
3356
- import { Primitive as Primitive11 } from "@radix-ui/react-primitive";
3357
- import { forwardRef as forwardRef19 } from "react";
3811
+ import { Primitive as Primitive10 } from "@radix-ui/react-primitive";
3812
+ import { forwardRef as forwardRef18 } from "react";
3358
3813
 
3359
3814
  // src/primitive-hooks/thread/useThreadViewportAutoScroll.tsx
3360
3815
  import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
@@ -3362,10 +3817,10 @@ import { useRef as useRef5 } from "react";
3362
3817
 
3363
3818
  // src/utils/hooks/useOnResizeContent.tsx
3364
3819
  import { useCallbackRef as useCallbackRef3 } from "@radix-ui/react-use-callback-ref";
3365
- import { useCallback as useCallback17 } from "react";
3820
+ import { useCallback as useCallback18 } from "react";
3366
3821
  var useOnResizeContent = (callback) => {
3367
3822
  const callbackRef = useCallbackRef3(callback);
3368
- const refCallback = useCallback17(
3823
+ const refCallback = useCallback18(
3369
3824
  (el) => {
3370
3825
  const resizeObserver = new ResizeObserver(() => {
3371
3826
  callbackRef();
@@ -3402,11 +3857,11 @@ var useOnResizeContent = (callback) => {
3402
3857
 
3403
3858
  // src/utils/hooks/useOnScrollToBottom.tsx
3404
3859
  import { useCallbackRef as useCallbackRef4 } from "@radix-ui/react-use-callback-ref";
3405
- import { useEffect as useEffect11 } from "react";
3860
+ import { useEffect as useEffect13 } from "react";
3406
3861
  var useOnScrollToBottom = (callback) => {
3407
3862
  const callbackRef = useCallbackRef4(callback);
3408
3863
  const { useViewport } = useThreadContext();
3409
- useEffect11(() => {
3864
+ useEffect13(() => {
3410
3865
  return useViewport.getState().onScrollToBottom(() => {
3411
3866
  callbackRef();
3412
3867
  });
@@ -3438,9 +3893,7 @@ var useThreadViewportAutoScroll = ({
3438
3893
  isScrollingToBottomRef.current = false;
3439
3894
  }
3440
3895
  if (newIsAtBottom !== isAtBottom) {
3441
- useViewport.setState({
3442
- isAtBottom: newIsAtBottom
3443
- });
3896
+ writableStore(useViewport).setState({ isAtBottom: newIsAtBottom });
3444
3897
  }
3445
3898
  }
3446
3899
  lastScrollTop.current = div.scrollTop;
@@ -3465,29 +3918,29 @@ var useThreadViewportAutoScroll = ({
3465
3918
  };
3466
3919
 
3467
3920
  // src/primitives/thread/ThreadViewport.tsx
3468
- import { jsx as jsx28 } from "react/jsx-runtime";
3469
- 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) => {
3470
3923
  const autoScrollRef = useThreadViewportAutoScroll({
3471
3924
  autoScroll
3472
3925
  });
3473
3926
  const ref = useComposedRefs4(forwardedRef, autoScrollRef);
3474
- return /* @__PURE__ */ jsx28(Primitive11.div, { ...rest, ref, children });
3927
+ return /* @__PURE__ */ jsx31(Primitive10.div, { ...rest, ref, children });
3475
3928
  });
3476
3929
  ThreadPrimitiveViewport.displayName = "ThreadPrimitive.Viewport";
3477
3930
 
3478
3931
  // src/primitives/thread/ThreadMessages.tsx
3479
- import { memo as memo3 } from "react";
3932
+ import { memo as memo5 } from "react";
3480
3933
 
3481
3934
  // src/context/providers/MessageProvider.tsx
3482
- import { useEffect as useEffect12, useState as useState11 } from "react";
3483
- import { create as create15 } from "zustand";
3935
+ import { useEffect as useEffect14, useState as useState13 } from "react";
3936
+ import { create as create17 } from "zustand";
3484
3937
 
3485
3938
  // src/context/stores/EditComposer.ts
3486
- import { create as create13 } from "zustand";
3939
+ import { create as create15 } from "zustand";
3487
3940
  var makeEditComposerStore = ({
3488
3941
  onEdit,
3489
3942
  onSend
3490
- }) => create13()((set, get) => ({
3943
+ }) => create15()((set, get) => ({
3491
3944
  get value() {
3492
3945
  return get().text;
3493
3946
  },
@@ -3496,13 +3949,19 @@ var makeEditComposerStore = ({
3496
3949
  },
3497
3950
  text: "",
3498
3951
  setText: (text) => {
3499
- set({ text });
3952
+ set({ text, isEmpty: text.trim().length === 0 });
3500
3953
  },
3501
3954
  canCancel: false,
3502
3955
  isEditing: false,
3956
+ isEmpty: true,
3503
3957
  edit: () => {
3504
3958
  const text = onEdit();
3505
- set({ isEditing: true, canCancel: true, text });
3959
+ set({
3960
+ isEditing: true,
3961
+ canCancel: true,
3962
+ isEmpty: text.trim().length === 0,
3963
+ text
3964
+ });
3506
3965
  },
3507
3966
  send: () => {
3508
3967
  const text = get().text;
@@ -3515,8 +3974,8 @@ var makeEditComposerStore = ({
3515
3974
  }));
3516
3975
 
3517
3976
  // src/context/stores/MessageUtils.ts
3518
- import { create as create14 } from "zustand";
3519
- var makeMessageUtilsStore = () => create14((set) => {
3977
+ import { create as create16 } from "zustand";
3978
+ var makeMessageUtilsStore = () => create16((set) => {
3520
3979
  let utterance = null;
3521
3980
  return {
3522
3981
  isCopied: false,
@@ -3542,7 +4001,7 @@ var makeMessageUtilsStore = () => create14((set) => {
3542
4001
  });
3543
4002
 
3544
4003
  // src/context/providers/MessageProvider.tsx
3545
- import { jsx as jsx29 } from "react/jsx-runtime";
4004
+ import { jsx as jsx32 } from "react/jsx-runtime";
3546
4005
  var getIsLast = (messages, message) => {
3547
4006
  return messages[messages.length - 1]?.id === message.id;
3548
4007
  };
@@ -3564,8 +4023,8 @@ var getMessageState = (messages, getBranches, useMessage, messageIndex) => {
3564
4023
  };
3565
4024
  var useMessageContext2 = (messageIndex) => {
3566
4025
  const { useThreadMessages, useThreadActions } = useThreadContext();
3567
- const [context] = useState11(() => {
3568
- const useMessage = create15(
4026
+ const [context] = useState13(() => {
4027
+ const useMessage = create17(
3569
4028
  () => getMessageState(
3570
4029
  useThreadMessages.getState(),
3571
4030
  useThreadActions.getState().getBranches,
@@ -3596,13 +4055,14 @@ var useMessageContext2 = (messageIndex) => {
3596
4055
  useThreadActions.getState().append({
3597
4056
  parentId,
3598
4057
  role: "user",
3599
- content: [{ type: "text", text }, ...nonTextParts]
4058
+ content: [{ type: "text", text }, ...nonTextParts],
4059
+ attachments: message.attachments
3600
4060
  });
3601
4061
  }
3602
4062
  });
3603
4063
  return { useMessage, useMessageUtils, useEditComposer };
3604
4064
  });
3605
- useEffect12(() => {
4065
+ useEffect14(() => {
3606
4066
  const syncMessage = (thread) => {
3607
4067
  const newState = getMessageState(
3608
4068
  thread,
@@ -3611,10 +4071,7 @@ var useMessageContext2 = (messageIndex) => {
3611
4071
  messageIndex
3612
4072
  );
3613
4073
  if (!newState) return;
3614
- context.useMessage.setState(
3615
- newState,
3616
- true
3617
- );
4074
+ writableStore(context.useMessage).setState(newState, true);
3618
4075
  };
3619
4076
  syncMessage(useThreadMessages.getState());
3620
4077
  return useThreadMessages.subscribe(syncMessage);
@@ -3626,11 +4083,11 @@ var MessageProvider = ({
3626
4083
  children
3627
4084
  }) => {
3628
4085
  const context = useMessageContext2(messageIndex);
3629
- return /* @__PURE__ */ jsx29(MessageContext.Provider, { value: context, children });
4086
+ return /* @__PURE__ */ jsx32(MessageContext.Provider, { value: context, children });
3630
4087
  };
3631
4088
 
3632
4089
  // src/primitives/thread/ThreadMessages.tsx
3633
- import { jsx as jsx30, jsxs as jsxs4 } from "react/jsx-runtime";
4090
+ import { jsx as jsx33, jsxs as jsxs4 } from "react/jsx-runtime";
3634
4091
  var DEFAULT_SYSTEM_MESSAGE = () => null;
3635
4092
  var getComponents = (components) => {
3636
4093
  return {
@@ -3647,14 +4104,14 @@ var ThreadMessageImpl = ({
3647
4104
  const { UserMessage: UserMessage2, EditComposer: EditComposer2, AssistantMessage: AssistantMessage2, SystemMessage: SystemMessage2 } = getComponents(components);
3648
4105
  return /* @__PURE__ */ jsxs4(MessageProvider, { messageIndex, children: [
3649
4106
  /* @__PURE__ */ jsxs4(MessagePrimitiveIf, { user: true, children: [
3650
- /* @__PURE__ */ jsx30(ComposerPrimitiveIf, { editing: false, children: /* @__PURE__ */ jsx30(UserMessage2, {}) }),
3651
- /* @__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, {}) })
3652
4109
  ] }),
3653
- /* @__PURE__ */ jsx30(MessagePrimitiveIf, { assistant: true, children: /* @__PURE__ */ jsx30(AssistantMessage2, {}) }),
3654
- /* @__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, {}) })
3655
4112
  ] });
3656
4113
  };
3657
- var ThreadMessage = memo3(
4114
+ var ThreadMessage = memo5(
3658
4115
  ThreadMessageImpl,
3659
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
3660
4117
  );
@@ -3664,20 +4121,10 @@ var ThreadPrimitiveMessagesImpl = ({
3664
4121
  const { useThreadMessages } = useThreadContext();
3665
4122
  const messagesLength = useThreadMessages((t) => t.length);
3666
4123
  if (messagesLength === 0) return null;
3667
- return new Array(messagesLength).fill(null).map((_, idx) => {
3668
- const messageIndex = idx;
3669
- return /* @__PURE__ */ jsx30(
3670
- ThreadMessage,
3671
- {
3672
- messageIndex,
3673
- components
3674
- },
3675
- messageIndex
3676
- );
3677
- });
4124
+ return Array.from({ length: messagesLength }, (_, index) => /* @__PURE__ */ jsx33(ThreadMessage, { messageIndex: index, components }, index));
3678
4125
  };
3679
4126
  ThreadPrimitiveMessagesImpl.displayName = "ThreadPrimitive.Messages";
3680
- var ThreadPrimitiveMessages = memo3(
4127
+ var ThreadPrimitiveMessages = memo5(
3681
4128
  ThreadPrimitiveMessagesImpl,
3682
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
3683
4130
  );
@@ -3697,32 +4144,32 @@ var ThreadPrimitiveSuggestion = createActionButton(
3697
4144
 
3698
4145
  // src/ui/thread-config.tsx
3699
4146
  import {
3700
- createContext as createContext6,
3701
- useContext as useContext6
4147
+ createContext as createContext7,
4148
+ useContext as useContext7
3702
4149
  } from "react";
3703
- import { Fragment as Fragment3, jsx as jsx31 } from "react/jsx-runtime";
3704
- var ThreadConfigContext = createContext6({});
4150
+ import { Fragment as Fragment3, jsx as jsx34 } from "react/jsx-runtime";
4151
+ var ThreadConfigContext = createContext7({});
3705
4152
  var useThreadConfig = () => {
3706
- return useContext6(ThreadConfigContext);
4153
+ return useContext7(ThreadConfigContext);
3707
4154
  };
3708
4155
  var ThreadConfigProvider = ({
3709
4156
  children,
3710
4157
  config
3711
4158
  }) => {
3712
4159
  const assistant = useAssistantContext({ optional: true });
3713
- 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 });
3714
4161
  if (!config?.runtime) return configProvider;
3715
4162
  if (assistant) {
3716
4163
  throw new Error(
3717
4164
  "You provided a runtime to <Thread> while simulataneously using <AssistantRuntimeProvider>. This is not allowed."
3718
4165
  );
3719
4166
  }
3720
- return /* @__PURE__ */ jsx31(AssistantRuntimeProvider, { runtime: config.runtime, children: configProvider });
4167
+ return /* @__PURE__ */ jsx34(AssistantRuntimeProvider, { runtime: config.runtime, children: configProvider });
3721
4168
  };
3722
4169
  ThreadConfigProvider.displayName = "ThreadConfigProvider";
3723
4170
 
3724
4171
  // src/ui/assistant-action-bar.tsx
3725
- import { forwardRef as forwardRef20 } from "react";
4172
+ import { forwardRef as forwardRef19 } from "react";
3726
4173
  import {
3727
4174
  AudioLinesIcon,
3728
4175
  CheckIcon,
@@ -3730,7 +4177,7 @@ import {
3730
4177
  RefreshCwIcon,
3731
4178
  StopCircleIcon
3732
4179
  } from "lucide-react";
3733
- 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";
3734
4181
  var useAllowCopy = (ensureCapability = false) => {
3735
4182
  const { assistantMessage: { allowCopy = true } = {} } = useThreadConfig();
3736
4183
  const { useThread } = useThreadContext();
@@ -3761,9 +4208,9 @@ var AssistantActionBar = () => {
3761
4208
  autohide: "not-last",
3762
4209
  autohideFloat: "single-branch",
3763
4210
  children: [
3764
- allowSpeak && /* @__PURE__ */ jsx32(AssistantActionBarSpeechControl, {}),
3765
- allowCopy && /* @__PURE__ */ jsx32(AssistantActionBarCopy, {}),
3766
- allowReload && /* @__PURE__ */ jsx32(AssistantActionBarReload, {})
4211
+ allowSpeak && /* @__PURE__ */ jsx35(AssistantActionBarSpeechControl, {}),
4212
+ allowCopy && /* @__PURE__ */ jsx35(AssistantActionBarCopy, {}),
4213
+ allowReload && /* @__PURE__ */ jsx35(AssistantActionBarReload, {})
3767
4214
  ]
3768
4215
  }
3769
4216
  );
@@ -3773,36 +4220,35 @@ var AssistantActionBarRoot = withDefaults(actionBar_exports.Root, {
3773
4220
  className: "aui-assistant-action-bar-root"
3774
4221
  });
3775
4222
  AssistantActionBarRoot.displayName = "AssistantActionBarRoot";
3776
- var AssistantActionBarCopy = forwardRef20((props, ref) => {
4223
+ var AssistantActionBarCopy = forwardRef19((props, ref) => {
3777
4224
  const {
3778
4225
  strings: {
3779
4226
  assistantMessage: { copy: { tooltip = "Copy" } = {} } = {}
3780
4227
  } = {}
3781
4228
  } = useThreadConfig();
3782
- return /* @__PURE__ */ jsx32(actionBar_exports.Copy, { asChild: true, children: /* @__PURE__ */ jsx32(TooltipIconButton, { tooltip, ...props, ref, children: props.children ?? /* @__PURE__ */ jsxs5(Fragment4, { children: [
3783
- /* @__PURE__ */ jsx32(message_exports.If, { copied: true, children: /* @__PURE__ */ jsx32(CheckIcon, {}) }),
3784
- /* @__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, {}) })
3785
4232
  ] }) }) });
3786
4233
  });
3787
4234
  AssistantActionBarCopy.displayName = "AssistantActionBarCopy";
3788
4235
  var AssistantActionBarSpeechControl = () => {
3789
4236
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
3790
- /* @__PURE__ */ jsx32(message_exports.If, { speaking: false, children: /* @__PURE__ */ jsx32(AssistantActionBarSpeak, {}) }),
3791
- /* @__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, {}) })
3792
4239
  ] });
3793
4240
  };
3794
- var AssistantActionBarSpeak = forwardRef20((props, ref) => {
4241
+ var AssistantActionBarSpeak = forwardRef19((props, ref) => {
3795
4242
  const {
3796
4243
  strings: {
3797
4244
  assistantMessage: { speak: { tooltip = "Read aloud" } = {} } = {}
3798
4245
  } = {}
3799
4246
  } = useThreadConfig();
3800
4247
  const allowSpeak = useAllowSpeak();
3801
- if (!allowSpeak) return null;
3802
- 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, {}) }) });
3803
4249
  });
3804
4250
  AssistantActionBarSpeak.displayName = "AssistantActionBarSpeak";
3805
- var AssistantActionBarStopSpeaking = forwardRef20((props, ref) => {
4251
+ var AssistantActionBarStopSpeaking = forwardRef19((props, ref) => {
3806
4252
  const {
3807
4253
  strings: {
3808
4254
  assistantMessage: {
@@ -3811,19 +4257,17 @@ var AssistantActionBarStopSpeaking = forwardRef20((props, ref) => {
3811
4257
  } = {}
3812
4258
  } = useThreadConfig();
3813
4259
  const allowSpeak = useAllowSpeak();
3814
- if (!allowSpeak) return null;
3815
- 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, {}) }) });
3816
4261
  });
3817
4262
  AssistantActionBarStopSpeaking.displayName = "AssistantActionBarStopSpeaking";
3818
- var AssistantActionBarReload = forwardRef20((props, ref) => {
4263
+ var AssistantActionBarReload = forwardRef19((props, ref) => {
3819
4264
  const {
3820
4265
  strings: {
3821
4266
  assistantMessage: { reload: { tooltip = "Refresh" } = {} } = {}
3822
4267
  } = {}
3823
4268
  } = useThreadConfig();
3824
4269
  const allowReload = useAllowReload();
3825
- if (!allowReload) return null;
3826
- 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, {}) }) });
3827
4271
  });
3828
4272
  AssistantActionBarReload.displayName = "AssistantActionBarReload";
3829
4273
  var exports = {
@@ -3840,25 +4284,25 @@ var assistant_action_bar_default = Object.assign(
3840
4284
  );
3841
4285
 
3842
4286
  // src/ui/assistant-message.tsx
3843
- import { forwardRef as forwardRef22 } from "react";
4287
+ import { forwardRef as forwardRef21, useMemo as useMemo5 } from "react";
3844
4288
 
3845
4289
  // src/ui/branch-picker.tsx
3846
- import { forwardRef as forwardRef21 } from "react";
4290
+ import { forwardRef as forwardRef20 } from "react";
3847
4291
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
3848
- import { jsx as jsx33, jsxs as jsxs6 } from "react/jsx-runtime";
3849
- var useAllowBranchPicker = () => {
4292
+ import { jsx as jsx36, jsxs as jsxs6 } from "react/jsx-runtime";
4293
+ var useAllowBranchPicker = (ensureCapability = false) => {
3850
4294
  const { branchPicker: { allowBranchPicker = true } = {} } = useThreadConfig();
3851
4295
  const { useThread } = useThreadContext();
3852
4296
  const branchPickerSupported = useThread((t) => t.capabilities.edit);
3853
- return branchPickerSupported && allowBranchPicker;
4297
+ return allowBranchPicker && (!ensureCapability || branchPickerSupported);
3854
4298
  };
3855
4299
  var BranchPicker = () => {
3856
4300
  const allowBranchPicker = useAllowBranchPicker();
3857
4301
  if (!allowBranchPicker) return null;
3858
4302
  return /* @__PURE__ */ jsxs6(BranchPickerRoot, { hideWhenSingleBranch: true, children: [
3859
- /* @__PURE__ */ jsx33(BranchPickerPrevious2, {}),
3860
- /* @__PURE__ */ jsx33(BranchPickerState, {}),
3861
- /* @__PURE__ */ jsx33(BranchPickerNext, {})
4303
+ /* @__PURE__ */ jsx36(BranchPickerPrevious2, {}),
4304
+ /* @__PURE__ */ jsx36(BranchPickerState, {}),
4305
+ /* @__PURE__ */ jsx36(BranchPickerNext, {})
3862
4306
  ] });
3863
4307
  };
3864
4308
  BranchPicker.displayName = "BranchPicker";
@@ -3866,31 +4310,33 @@ var BranchPickerRoot = withDefaults(branchPicker_exports.Root, {
3866
4310
  className: "aui-branch-picker-root"
3867
4311
  });
3868
4312
  BranchPickerRoot.displayName = "BranchPickerRoot";
3869
- var BranchPickerPrevious2 = forwardRef21((props, ref) => {
4313
+ var BranchPickerPrevious2 = forwardRef20((props, ref) => {
3870
4314
  const {
3871
4315
  strings: {
3872
4316
  branchPicker: { previous: { tooltip = "Previous" } = {} } = {}
3873
4317
  } = {}
3874
4318
  } = useThreadConfig();
3875
- 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, {}) }) });
3876
4321
  });
3877
4322
  BranchPickerPrevious2.displayName = "BranchPickerPrevious";
3878
4323
  var BranchPickerStateWrapper = withDefaults("span", {
3879
4324
  className: "aui-branch-picker-state"
3880
4325
  });
3881
- var BranchPickerState = forwardRef21((props, ref) => {
4326
+ var BranchPickerState = forwardRef20((props, ref) => {
3882
4327
  return /* @__PURE__ */ jsxs6(BranchPickerStateWrapper, { ...props, ref, children: [
3883
- /* @__PURE__ */ jsx33(branchPicker_exports.Number, {}),
4328
+ /* @__PURE__ */ jsx36(branchPicker_exports.Number, {}),
3884
4329
  " / ",
3885
- /* @__PURE__ */ jsx33(branchPicker_exports.Count, {})
4330
+ /* @__PURE__ */ jsx36(branchPicker_exports.Count, {})
3886
4331
  ] });
3887
4332
  });
3888
4333
  BranchPickerState.displayName = "BranchPickerState";
3889
- var BranchPickerNext = forwardRef21((props, ref) => {
4334
+ var BranchPickerNext = forwardRef20((props, ref) => {
3890
4335
  const {
3891
4336
  strings: { branchPicker: { next: { tooltip = "Next" } = {} } = {} } = {}
3892
4337
  } = useThreadConfig();
3893
- 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, {}) }) });
3894
4340
  });
3895
4341
  BranchPickerNext.displayName = "BranchPickerNext";
3896
4342
  var exports2 = {
@@ -3902,12 +4348,12 @@ var branch_picker_default = Object.assign(BranchPicker, exports2);
3902
4348
 
3903
4349
  // src/ui/base/avatar.tsx
3904
4350
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
3905
- import { jsx as jsx34, jsxs as jsxs7 } from "react/jsx-runtime";
4351
+ import { jsx as jsx37, jsxs as jsxs7 } from "react/jsx-runtime";
3906
4352
  var Avatar = ({ src, alt, fallback }) => {
3907
4353
  if (src == null && fallback == null) return null;
3908
4354
  return /* @__PURE__ */ jsxs7(AvatarRoot, { children: [
3909
- src != null && /* @__PURE__ */ jsx34(AvatarImage, { src, alt }),
3910
- fallback != null && /* @__PURE__ */ jsx34(AvatarFallback, { children: fallback })
4355
+ src != null && /* @__PURE__ */ jsx37(AvatarImage, { src, alt }),
4356
+ fallback != null && /* @__PURE__ */ jsx37(AvatarFallback, { children: fallback })
3911
4357
  ] });
3912
4358
  };
3913
4359
  Avatar.displayName = "Avatar";
@@ -3926,10 +4372,10 @@ AvatarFallback.displayName = "AvatarFallback";
3926
4372
 
3927
4373
  // src/ui/content-part.tsx
3928
4374
  import classNames2 from "classnames";
3929
- import { jsx as jsx35 } from "react/jsx-runtime";
4375
+ import { jsx as jsx38 } from "react/jsx-runtime";
3930
4376
  var Text = () => {
3931
4377
  const status = useSmoothStatus();
3932
- return /* @__PURE__ */ jsx35(
4378
+ return /* @__PURE__ */ jsx38(
3933
4379
  contentPart_exports.Text,
3934
4380
  {
3935
4381
  className: classNames2(
@@ -3944,19 +4390,19 @@ var exports3 = { Text: withSmoothContextProvider(Text) };
3944
4390
  var content_part_default = exports3;
3945
4391
 
3946
4392
  // src/ui/assistant-message.tsx
3947
- import { jsx as jsx36, jsxs as jsxs8 } from "react/jsx-runtime";
4393
+ import { jsx as jsx39, jsxs as jsxs8 } from "react/jsx-runtime";
3948
4394
  var AssistantMessage = () => {
3949
4395
  return /* @__PURE__ */ jsxs8(AssistantMessageRoot, { children: [
3950
- /* @__PURE__ */ jsx36(AssistantMessageAvatar, {}),
3951
- /* @__PURE__ */ jsx36(AssistantMessageContent, {}),
3952
- /* @__PURE__ */ jsx36(branch_picker_default, {}),
3953
- /* @__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, {})
3954
4400
  ] });
3955
4401
  };
3956
4402
  AssistantMessage.displayName = "AssistantMessage";
3957
4403
  var AssistantMessageAvatar = () => {
3958
4404
  const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
3959
- return /* @__PURE__ */ jsx36(Avatar, { ...avatar });
4405
+ return /* @__PURE__ */ jsx39(Avatar, { ...avatar });
3960
4406
  };
3961
4407
  var AssistantMessageRoot = withDefaults(message_exports.Root, {
3962
4408
  className: "aui-assistant-message-root"
@@ -3965,23 +4411,28 @@ AssistantMessageRoot.displayName = "AssistantMessageRoot";
3965
4411
  var AssistantMessageContentWrapper = withDefaults("div", {
3966
4412
  className: "aui-assistant-message-content"
3967
4413
  });
3968
- var AssistantMessageContent = forwardRef22(({ components: componentsProp, ...rest }, ref) => {
4414
+ var AssistantMessageContent = forwardRef21(({ components: componentsProp, ...rest }, ref) => {
3969
4415
  const { tools, assistantMessage: { components = {} } = {} } = useThreadConfig();
3970
- return /* @__PURE__ */ jsx36(AssistantMessageContentWrapper, { ...rest, ref, children: /* @__PURE__ */ jsx36(
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(
3971
4430
  message_exports.Content,
3972
4431
  {
3973
4432
  components: {
3974
4433
  ...componentsProp,
3975
4434
  Text: componentsProp?.Text ?? components.Text ?? content_part_default.Text,
3976
- tools: {
3977
- by_name: !tools ? void 0 : Object.fromEntries(
3978
- tools.map((t) => [
3979
- t.unstable_tool.toolName,
3980
- t.unstable_tool.render
3981
- ])
3982
- ),
3983
- Fallback: components.ToolFallback
3984
- }
4435
+ tools: toolsComponents
3985
4436
  }
3986
4437
  }
3987
4438
  ) });
@@ -4007,12 +4458,12 @@ import { ArrowDownIcon } from "lucide-react";
4007
4458
 
4008
4459
  // src/ui/composer.tsx
4009
4460
  import { forwardRef as forwardRef23 } from "react";
4010
- import { SendHorizontalIcon } from "lucide-react";
4461
+ import { PaperclipIcon, SendHorizontalIcon } from "lucide-react";
4011
4462
 
4012
4463
  // src/ui/base/CircleStopIcon.tsx
4013
- import { jsx as jsx37 } from "react/jsx-runtime";
4464
+ import { jsx as jsx40 } from "react/jsx-runtime";
4014
4465
  var CircleStopIcon = () => {
4015
- return /* @__PURE__ */ jsx37(
4466
+ return /* @__PURE__ */ jsx40(
4016
4467
  "svg",
4017
4468
  {
4018
4469
  xmlns: "http://www.w3.org/2000/svg",
@@ -4020,18 +4471,79 @@ var CircleStopIcon = () => {
4020
4471
  fill: "currentColor",
4021
4472
  width: "16",
4022
4473
  height: "16",
4023
- 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" })
4024
4475
  }
4025
4476
  );
4026
4477
  };
4027
4478
  CircleStopIcon.displayName = "CircleStopIcon";
4028
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
+
4029
4532
  // src/ui/composer.tsx
4030
- 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
+ };
4031
4540
  var Composer = () => {
4032
- return /* @__PURE__ */ jsxs9(ComposerRoot, { children: [
4033
- /* @__PURE__ */ jsx38(ComposerInput, { autoFocus: true }),
4034
- /* @__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, {})
4035
4547
  ] });
4036
4548
  };
4037
4549
  Composer.displayName = "Composer";
@@ -4051,10 +4563,47 @@ var ComposerInput = forwardRef23(
4051
4563
  composer: { input: { placeholder = "Write a message..." } = {} } = {}
4052
4564
  } = {}
4053
4565
  } = useThreadConfig();
4054
- return /* @__PURE__ */ jsx38(ComposerInputStyled, { placeholder, ...props, ref });
4566
+ return /* @__PURE__ */ jsx42(ComposerInputStyled, { placeholder, ...props, ref });
4055
4567
  }
4056
4568
  );
4057
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";
4058
4607
  var useAllowCancel = () => {
4059
4608
  const { useThread } = useThreadContext();
4060
4609
  const cancelSupported = useThread((t) => t.capabilities.cancel);
@@ -4062,10 +4611,10 @@ var useAllowCancel = () => {
4062
4611
  };
4063
4612
  var ComposerAction = () => {
4064
4613
  const allowCancel = useAllowCancel();
4065
- if (!allowCancel) return /* @__PURE__ */ jsx38(ComposerSend, {});
4066
- return /* @__PURE__ */ jsxs9(Fragment5, { children: [
4067
- /* @__PURE__ */ jsx38(thread_exports.If, { running: false, children: /* @__PURE__ */ jsx38(ComposerSend, {}) }),
4068
- /* @__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, {}) })
4069
4618
  ] });
4070
4619
  };
4071
4620
  ComposerAction.displayName = "ComposerAction";
@@ -4077,7 +4626,7 @@ var ComposerSend = forwardRef23((props, ref) => {
4077
4626
  const {
4078
4627
  strings: { composer: { send: { tooltip = "Send" } = {} } = {} } = {}
4079
4628
  } = useThreadConfig();
4080
- 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, {}) }) });
4081
4630
  });
4082
4631
  ComposerSend.displayName = "ComposerSend";
4083
4632
  var ComposerCancelButton = withDefaults(TooltipIconButton, {
@@ -4088,28 +4637,30 @@ var ComposerCancel = forwardRef23((props, ref) => {
4088
4637
  const {
4089
4638
  strings: { composer: { cancel: { tooltip = "Cancel" } = {} } = {} } = {}
4090
4639
  } = useThreadConfig();
4091
- 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, {}) }) });
4092
4641
  });
4093
4642
  ComposerCancel.displayName = "ComposerCancel";
4094
- var exports5 = {
4643
+ var exports6 = {
4095
4644
  Root: ComposerRoot,
4096
4645
  Input: ComposerInput,
4097
4646
  Action: ComposerAction,
4098
4647
  Send: ComposerSend,
4099
- Cancel: ComposerCancel
4648
+ Cancel: ComposerCancel,
4649
+ AddAttachment: ComposerAddAttachment,
4650
+ Attachments: ComposerAttachments
4100
4651
  };
4101
- var composer_default = Object.assign(Composer, exports5);
4652
+ var composer_default = Object.assign(Composer, exports6);
4102
4653
 
4103
4654
  // src/ui/thread-welcome.tsx
4104
4655
  import { forwardRef as forwardRef24 } from "react";
4105
- import { jsx as jsx39, jsxs as jsxs10 } from "react/jsx-runtime";
4656
+ import { jsx as jsx43, jsxs as jsxs11 } from "react/jsx-runtime";
4106
4657
  var ThreadWelcome = () => {
4107
- return /* @__PURE__ */ jsxs10(ThreadWelcomeRoot, { children: [
4108
- /* @__PURE__ */ jsxs10(ThreadWelcomeCenter, { children: [
4109
- /* @__PURE__ */ jsx39(ThreadWelcomeAvatar, {}),
4110
- /* @__PURE__ */ jsx39(ThreadWelcomeMessage, {})
4658
+ return /* @__PURE__ */ jsxs11(ThreadWelcomeRoot, { children: [
4659
+ /* @__PURE__ */ jsxs11(ThreadWelcomeCenter, { children: [
4660
+ /* @__PURE__ */ jsx43(ThreadWelcomeAvatar, {}),
4661
+ /* @__PURE__ */ jsx43(ThreadWelcomeMessage, {})
4111
4662
  ] }),
4112
- /* @__PURE__ */ jsx39(ThreadWelcomeSuggestions, {})
4663
+ /* @__PURE__ */ jsx43(ThreadWelcomeSuggestions, {})
4113
4664
  ] });
4114
4665
  };
4115
4666
  ThreadWelcome.displayName = "ThreadWelcome";
@@ -4121,20 +4672,20 @@ var ThreadWelcomeCenter = withDefaults("div", {
4121
4672
  });
4122
4673
  var ThreadWelcomeRoot = forwardRef24(
4123
4674
  (props, ref) => {
4124
- 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 }) });
4125
4676
  }
4126
4677
  );
4127
4678
  ThreadWelcomeRoot.displayName = "ThreadWelcomeRoot";
4128
4679
  var ThreadWelcomeAvatar = () => {
4129
4680
  const { assistantAvatar: avatar = { fallback: "A" } } = useThreadConfig();
4130
- return /* @__PURE__ */ jsx39(Avatar, { ...avatar });
4681
+ return /* @__PURE__ */ jsx43(Avatar, { ...avatar });
4131
4682
  };
4132
4683
  var ThreadWelcomeMessageStyled = withDefaults("p", {
4133
4684
  className: "aui-thread-welcome-message"
4134
4685
  });
4135
4686
  var ThreadWelcomeMessage = forwardRef24(({ message: messageProp, ...rest }, ref) => {
4136
4687
  const { welcome: { message = "How can I help you today?" } = {} } = useThreadConfig();
4137
- return /* @__PURE__ */ jsx39(ThreadWelcomeMessageStyled, { ...rest, ref, children: messageProp ?? message });
4688
+ return /* @__PURE__ */ jsx43(ThreadWelcomeMessageStyled, { ...rest, ref, children: messageProp ?? message });
4138
4689
  });
4139
4690
  ThreadWelcomeMessage.displayName = "ThreadWelcomeMessage";
4140
4691
  var ThreadWelcomeSuggestionContainer = withDefaults("div", {
@@ -4146,25 +4697,25 @@ var ThreadWelcomeSuggestionStyled = withDefaults(thread_exports.Suggestion, {
4146
4697
  var ThreadWelcomeSuggestion = ({
4147
4698
  suggestion: { text, prompt }
4148
4699
  }) => {
4149
- return /* @__PURE__ */ jsx39(
4700
+ return /* @__PURE__ */ jsx43(
4150
4701
  ThreadWelcomeSuggestionStyled,
4151
4702
  {
4152
4703
  prompt,
4153
4704
  method: "replace",
4154
4705
  autoSend: true,
4155
- 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 })
4156
4707
  }
4157
4708
  );
4158
4709
  };
4159
4710
  var ThreadWelcomeSuggestions = () => {
4160
4711
  const { welcome: { suggestions } = {} } = useThreadConfig();
4161
- return /* @__PURE__ */ jsx39(ThreadWelcomeSuggestionContainer, { children: suggestions?.map((suggestion, idx) => {
4712
+ return /* @__PURE__ */ jsx43(ThreadWelcomeSuggestionContainer, { children: suggestions?.map((suggestion, idx) => {
4162
4713
  const key = `${suggestion.prompt}-${idx}`;
4163
- return /* @__PURE__ */ jsx39(ThreadWelcomeSuggestion, { suggestion }, key);
4714
+ return /* @__PURE__ */ jsx43(ThreadWelcomeSuggestion, { suggestion }, key);
4164
4715
  }) });
4165
4716
  };
4166
4717
  ThreadWelcomeSuggestions.displayName = "ThreadWelcomeSuggestions";
4167
- var exports6 = {
4718
+ var exports7 = {
4168
4719
  Root: ThreadWelcomeRoot,
4169
4720
  Center: ThreadWelcomeCenter,
4170
4721
  Avatar: ThreadWelcomeAvatar,
@@ -4172,7 +4723,7 @@ var exports6 = {
4172
4723
  Suggestions: ThreadWelcomeSuggestions,
4173
4724
  Suggestion: ThreadWelcomeSuggestion
4174
4725
  };
4175
- var thread_welcome_default = Object.assign(ThreadWelcome, exports6);
4726
+ var thread_welcome_default = Object.assign(ThreadWelcome, exports7);
4176
4727
 
4177
4728
  // src/ui/user-message.tsx
4178
4729
  import { forwardRef as forwardRef26 } from "react";
@@ -4180,7 +4731,7 @@ import { forwardRef as forwardRef26 } from "react";
4180
4731
  // src/ui/user-action-bar.tsx
4181
4732
  import { forwardRef as forwardRef25 } from "react";
4182
4733
  import { PencilIcon } from "lucide-react";
4183
- import { jsx as jsx40 } from "react/jsx-runtime";
4734
+ import { jsx as jsx44 } from "react/jsx-runtime";
4184
4735
  var useAllowEdit = (ensureCapability = false) => {
4185
4736
  const { userMessage: { allowEdit = true } = {} } = useThreadConfig();
4186
4737
  const { useThread } = useThreadContext();
@@ -4190,7 +4741,7 @@ var useAllowEdit = (ensureCapability = false) => {
4190
4741
  var UserActionBar = () => {
4191
4742
  const allowEdit = useAllowEdit(true);
4192
4743
  if (!allowEdit) return null;
4193
- 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, {}) });
4194
4745
  };
4195
4746
  UserActionBar.displayName = "UserActionBar";
4196
4747
  var UserActionBarRoot = withDefaults(actionBar_exports.Root, {
@@ -4202,23 +4753,46 @@ var UserActionBarEdit = forwardRef25((props, ref) => {
4202
4753
  strings: { userMessage: { edit: { tooltip = "Edit" } = {} } = {} } = {}
4203
4754
  } = useThreadConfig();
4204
4755
  const allowEdit = useAllowEdit();
4205
- if (!allowEdit) return null;
4206
- 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, {}) }) });
4207
4757
  });
4208
4758
  UserActionBarEdit.displayName = "UserActionBarEdit";
4209
- var exports7 = {
4759
+ var exports8 = {
4210
4760
  Root: UserActionBarRoot,
4211
4761
  Edit: UserActionBarEdit
4212
4762
  };
4213
- 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
+ );
4214
4787
 
4215
4788
  // src/ui/user-message.tsx
4216
- import { jsx as jsx41, jsxs as jsxs11 } from "react/jsx-runtime";
4789
+ import { jsx as jsx45, jsxs as jsxs13 } from "react/jsx-runtime";
4217
4790
  var UserMessage = () => {
4218
- return /* @__PURE__ */ jsxs11(UserMessageRoot, { children: [
4219
- /* @__PURE__ */ jsx41(user_action_bar_default, {}),
4220
- /* @__PURE__ */ jsx41(UserMessageContent, {}),
4221
- /* @__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, {})
4222
4796
  ] });
4223
4797
  };
4224
4798
  UserMessage.displayName = "UserMessage";
@@ -4231,7 +4805,7 @@ var UserMessageContentWrapper = withDefaults("div", {
4231
4805
  });
4232
4806
  var UserMessageContent = forwardRef26(
4233
4807
  ({ components, ...props }, ref) => {
4234
- return /* @__PURE__ */ jsx41(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx41(
4808
+ return /* @__PURE__ */ jsx45(UserMessageContentWrapper, { ...props, ref, children: /* @__PURE__ */ jsx45(
4235
4809
  message_exports.Content,
4236
4810
  {
4237
4811
  components: {
@@ -4243,21 +4817,38 @@ var UserMessageContent = forwardRef26(
4243
4817
  }
4244
4818
  );
4245
4819
  UserMessageContent.displayName = "UserMessageContent";
4246
- 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 = {
4247
4837
  Root: UserMessageRoot,
4248
- Content: UserMessageContent
4838
+ Content: UserMessageContent,
4839
+ Attachments: UserMessageAttachments
4249
4840
  };
4250
- var user_message_default = Object.assign(UserMessage, exports8);
4841
+ var user_message_default = Object.assign(UserMessage, exports10);
4251
4842
 
4252
4843
  // src/ui/edit-composer.tsx
4253
4844
  import { forwardRef as forwardRef27 } from "react";
4254
- import { jsx as jsx42, jsxs as jsxs12 } from "react/jsx-runtime";
4845
+ import { jsx as jsx46, jsxs as jsxs14 } from "react/jsx-runtime";
4255
4846
  var EditComposer = () => {
4256
- return /* @__PURE__ */ jsxs12(EditComposerRoot, { children: [
4257
- /* @__PURE__ */ jsx42(EditComposerInput, {}),
4258
- /* @__PURE__ */ jsxs12(EditComposerFooter, { children: [
4259
- /* @__PURE__ */ jsx42(EditComposerCancel, {}),
4260
- /* @__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, {})
4261
4852
  ] })
4262
4853
  ] });
4263
4854
  };
@@ -4281,7 +4872,7 @@ var EditComposerCancel = forwardRef27(
4281
4872
  editComposer: { cancel: { label = "Cancel" } = {} } = {}
4282
4873
  } = {}
4283
4874
  } = useThreadConfig();
4284
- 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 }) });
4285
4876
  }
4286
4877
  );
4287
4878
  EditComposerCancel.displayName = "EditComposerCancel";
@@ -4290,28 +4881,28 @@ var EditComposerSend = forwardRef27(
4290
4881
  const {
4291
4882
  strings: { editComposer: { send: { label = "Send" } = {} } = {} } = {}
4292
4883
  } = useThreadConfig();
4293
- 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 }) });
4294
4885
  }
4295
4886
  );
4296
4887
  EditComposerSend.displayName = "EditComposerSend";
4297
- var exports9 = {
4888
+ var exports11 = {
4298
4889
  Root: EditComposerRoot,
4299
4890
  Input: EditComposerInput,
4300
4891
  Footer: EditComposerFooter,
4301
4892
  Cancel: EditComposerCancel,
4302
4893
  Send: EditComposerSend
4303
4894
  };
4304
- var edit_composer_default = Object.assign(EditComposer, exports9);
4895
+ var edit_composer_default = Object.assign(EditComposer, exports11);
4305
4896
 
4306
4897
  // src/ui/thread.tsx
4307
- import { jsx as jsx43, jsxs as jsxs13 } from "react/jsx-runtime";
4898
+ import { jsx as jsx47, jsxs as jsxs15 } from "react/jsx-runtime";
4308
4899
  var Thread = (config) => {
4309
- return /* @__PURE__ */ jsx43(ThreadRoot, { config, children: /* @__PURE__ */ jsxs13(ThreadViewport, { children: [
4310
- /* @__PURE__ */ jsx43(thread_welcome_default, {}),
4311
- /* @__PURE__ */ jsx43(ThreadMessages, {}),
4312
- /* @__PURE__ */ jsxs13(ThreadViewportFooter, { children: [
4313
- /* @__PURE__ */ jsx43(ThreadScrollToBottom, {}),
4314
- /* @__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, {})
4315
4906
  ] })
4316
4907
  ] }) });
4317
4908
  };
@@ -4320,7 +4911,7 @@ var ThreadRootStyled = withDefaults(thread_exports.Root, {
4320
4911
  });
4321
4912
  var ThreadRoot = forwardRef28(
4322
4913
  ({ config, ...props }, ref) => {
4323
- return /* @__PURE__ */ jsx43(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx43(ThreadRootStyled, { ...props, ref }) });
4914
+ return /* @__PURE__ */ jsx47(ThreadConfigProvider, { config, children: /* @__PURE__ */ jsx47(ThreadRootStyled, { ...props, ref }) });
4324
4915
  }
4325
4916
  );
4326
4917
  ThreadRoot.displayName = "ThreadRoot";
@@ -4334,7 +4925,7 @@ var ThreadViewportFooter = withDefaults("div", {
4334
4925
  ThreadViewportFooter.displayName = "ThreadViewportFooter";
4335
4926
  var SystemMessage = () => null;
4336
4927
  var ThreadMessages = ({ components, ...rest }) => {
4337
- return /* @__PURE__ */ jsx43(
4928
+ return /* @__PURE__ */ jsx47(
4338
4929
  thread_exports.Messages,
4339
4930
  {
4340
4931
  components: {
@@ -4358,33 +4949,33 @@ var ThreadScrollToBottom = forwardRef28((props, ref) => {
4358
4949
  thread: { scrollToBottom: { tooltip = "Scroll to bottom" } = {} } = {}
4359
4950
  } = {}
4360
4951
  } = useThreadConfig();
4361
- 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, {}) }) });
4362
4953
  });
4363
4954
  ThreadScrollToBottom.displayName = "ThreadScrollToBottom";
4364
- var exports10 = {
4955
+ var exports12 = {
4365
4956
  Root: ThreadRoot,
4366
4957
  Viewport: ThreadViewport,
4367
4958
  Messages: ThreadMessages,
4368
4959
  ScrollToBottom: ThreadScrollToBottom,
4369
4960
  ViewportFooter: ThreadViewportFooter
4370
4961
  };
4371
- var thread_default = Object.assign(Thread, exports10);
4962
+ var thread_default = Object.assign(Thread, exports12);
4372
4963
 
4373
4964
  // src/ui/assistant-modal.tsx
4374
- 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";
4375
4966
  var AssistantModal = (config) => {
4376
- return /* @__PURE__ */ jsxs14(AssistantModalRoot, { config, children: [
4377
- /* @__PURE__ */ jsx44(AssistantModalTrigger, {}),
4378
- /* @__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, {}) })
4379
4970
  ] });
4380
4971
  };
4381
4972
  AssistantModal.displayName = "AssistantModal";
4382
4973
  var AssistantModalRoot = ({ config, ...props }) => {
4383
- 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 }) });
4384
4975
  };
4385
4976
  AssistantModalRoot.displayName = "AssistantModalRoot";
4386
4977
  var AssistantModalTrigger = forwardRef29((props, ref) => {
4387
- 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 }) }) });
4388
4979
  });
4389
4980
  AssistantModalTrigger.displayName = "AssistantModalTrigger";
4390
4981
  var AssistantModalAnchor = withDefaults(assistantModal_exports.Anchor, {
@@ -4409,7 +5000,7 @@ var AssistantModalButton = forwardRef29(({ "data-state": state, ...rest }, ref)
4409
5000
  } = {}
4410
5001
  } = useThreadConfig();
4411
5002
  const tooltip = state === "open" ? openTooltip : closedTooltip;
4412
- return /* @__PURE__ */ jsx44(
5003
+ return /* @__PURE__ */ jsx48(
4413
5004
  ModalButtonStyled,
4414
5005
  {
4415
5006
  side: "left",
@@ -4417,15 +5008,15 @@ var AssistantModalButton = forwardRef29(({ "data-state": state, ...rest }, ref)
4417
5008
  "data-state": state,
4418
5009
  ...rest,
4419
5010
  ref,
4420
- children: rest.children ?? /* @__PURE__ */ jsxs14(Fragment6, { children: [
4421
- /* @__PURE__ */ jsx44(
5011
+ children: rest.children ?? /* @__PURE__ */ jsxs16(Fragment6, { children: [
5012
+ /* @__PURE__ */ jsx48(
4422
5013
  BotIcon,
4423
5014
  {
4424
5015
  "data-state": state,
4425
5016
  className: "aui-modal-button-closed-icon"
4426
5017
  }
4427
5018
  ),
4428
- /* @__PURE__ */ jsx44(
5019
+ /* @__PURE__ */ jsx48(
4429
5020
  ChevronDownIcon,
4430
5021
  {
4431
5022
  "data-state": state,
@@ -4442,14 +5033,14 @@ var AssistantModalContent = withDefaults(assistantModal_exports.Content, {
4442
5033
  sideOffset: 16
4443
5034
  });
4444
5035
  AssistantModalContent.displayName = "AssistantModalContent";
4445
- var exports11 = {
5036
+ var exports13 = {
4446
5037
  Root: AssistantModalRoot,
4447
5038
  Trigger: AssistantModalTrigger,
4448
5039
  Content: AssistantModalContent,
4449
5040
  Button: AssistantModalButton,
4450
5041
  Anchor: AssistantModalAnchor
4451
5042
  };
4452
- var assistant_modal_default = Object.assign(AssistantModal, exports11);
5043
+ var assistant_modal_default = Object.assign(AssistantModal, exports13);
4453
5044
  export {
4454
5045
  actionBar_exports as ActionBarPrimitive,
4455
5046
  assistant_action_bar_default as AssistantActionBar,
@@ -4460,7 +5051,9 @@ export {
4460
5051
  branch_picker_default as BranchPicker,
4461
5052
  branchPicker_exports as BranchPickerPrimitive,
4462
5053
  composer_default as Composer,
5054
+ composer_attachment_default as ComposerAttachment,
4463
5055
  composer_exports as ComposerPrimitive,
5056
+ CompositeAttachmentAdapter,
4464
5057
  content_part_default as ContentPart,
4465
5058
  contentPart_exports as ContentPartPrimitive,
4466
5059
  EdgeChatAdapter,
@@ -4468,12 +5061,15 @@ export {
4468
5061
  ExternalStoreRuntime,
4469
5062
  internal_exports as INTERNAL,
4470
5063
  message_exports as MessagePrimitive,
5064
+ SimpleImageAttachmentAdapter,
5065
+ SimpleTextAttachmentAdapter,
4471
5066
  thread_default as Thread,
4472
5067
  ThreadConfigProvider,
4473
5068
  thread_exports as ThreadPrimitive,
4474
5069
  thread_welcome_default as ThreadWelcome,
4475
5070
  user_action_bar_default as UserActionBar,
4476
5071
  user_message_default as UserMessage,
5072
+ user_message_attachment_default as UserMessageAttachment,
4477
5073
  WebSpeechSynthesisAdapter,
4478
5074
  fromCoreMessage,
4479
5075
  fromCoreMessages,
@@ -4502,6 +5098,7 @@ export {
4502
5098
  useBranchPickerNext,
4503
5099
  useBranchPickerNumber,
4504
5100
  useBranchPickerPrevious,
5101
+ useComposerAddAttachment,
4505
5102
  useComposerCancel,
4506
5103
  useComposerContext,
4507
5104
  useComposerIf,