@assistant-ui/react 0.5.66 → 0.5.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -145,7 +145,9 @@ var { useThread, useThreadStore } = createContextStoreHook(
145
145
  useThreadContext,
146
146
  "useThread"
147
147
  );
148
- var { useThreadMessages, useThreadMessagesStore } = createContextStoreHook(useThreadContext, "useThreadMessages");
148
+ var messages = createContextStoreHook(useThreadContext, "useThreadMessages");
149
+ var useThreadMessages = messages.useThreadMessages;
150
+ var useThreadMessagesStore = messages.useThreadMessagesStore;
149
151
  var {
150
152
  useComposer: useThreadComposer,
151
153
  useComposerStore: useThreadComposerStore
@@ -155,61 +157,11 @@ var {
155
157
  useViewportStore: useThreadViewportStore
156
158
  } = createContextStoreHook(useThreadContext, "useViewport");
157
159
 
158
- // src/context/stores/ThreadComposer.ts
159
- import { create as create2 } from "zustand";
160
- var makeThreadComposerStore = (runtime) => {
161
- const focusListeners = /* @__PURE__ */ new Set();
162
- return create2()((_, get) => {
163
- return {
164
- type: "thread",
165
- get value() {
166
- return get().text;
167
- },
168
- setValue(value) {
169
- get().setText(value);
170
- },
171
- ...runtime.getState(),
172
- canCancel: false,
173
- // "TODO",
174
- isEditing: true,
175
- addAttachment: (file) => {
176
- runtime.addAttachment(file);
177
- },
178
- removeAttachment: (attachmentId) => {
179
- runtime.removeAttachment(attachmentId);
180
- },
181
- reset: () => {
182
- runtime.reset();
183
- },
184
- setText: (text) => {
185
- runtime.setText(text);
186
- },
187
- send: () => {
188
- runtime.send();
189
- },
190
- cancel: () => {
191
- runtime.cancel();
192
- },
193
- focus: () => {
194
- for (const listener of focusListeners) {
195
- listener();
196
- }
197
- },
198
- onFocus: (listener) => {
199
- focusListeners.add(listener);
200
- return () => {
201
- focusListeners.delete(listener);
202
- };
203
- }
204
- };
205
- });
206
- };
207
-
208
160
  // src/context/stores/ThreadViewport.tsx
209
- import { create as create3 } from "zustand";
161
+ import { create as create2 } from "zustand";
210
162
  var makeThreadViewportStore = () => {
211
163
  const scrollToBottomListeners = /* @__PURE__ */ new Set();
212
- return create3(() => ({
164
+ return create2(() => ({
213
165
  isAtBottom: true,
214
166
  scrollToBottom: () => {
215
167
  for (const listener of scrollToBottomListeners) {
@@ -231,17 +183,17 @@ var writableStore = (store) => {
231
183
  };
232
184
 
233
185
  // src/context/providers/ThreadRuntimeProvider.tsx
234
- import { create as create4 } from "zustand";
186
+ import { create as create3 } from "zustand";
235
187
  import { jsx, jsxs } from "react/jsx-runtime";
236
188
  var useThreadRuntimeStore2 = (runtime) => {
237
- const [store] = useState(() => create4(() => runtime));
189
+ const [store] = useState(() => create3(() => runtime));
238
190
  useEffect(() => {
239
191
  writableStore(store).setState(runtime, true);
240
192
  }, [runtime, store]);
241
193
  return store;
242
194
  };
243
195
  var useThreadStore2 = (runtime) => {
244
- const [store] = useState(() => create4(() => runtime.getState()));
196
+ const [store] = useState(() => create3(() => runtime.getState()));
245
197
  useEffect(() => {
246
198
  const updateState = () => writableStore(store).setState(runtime.getState(), true);
247
199
  updateState();
@@ -250,7 +202,7 @@ var useThreadStore2 = (runtime) => {
250
202
  return store;
251
203
  };
252
204
  var useThreadMessagesStore2 = (runtime) => {
253
- const [store] = useState(() => create4(() => runtime.messages));
205
+ const [store] = useState(() => create3(() => runtime.messages));
254
206
  useEffect(() => {
255
207
  const updateState = () => writableStore(store).setState(runtime.messages, true);
256
208
  updateState();
@@ -259,9 +211,9 @@ var useThreadMessagesStore2 = (runtime) => {
259
211
  return store;
260
212
  };
261
213
  var useThreadComposerStore2 = (runtime) => {
262
- const [store] = useState(() => makeThreadComposerStore(runtime));
214
+ const [store] = useState(() => create3(() => runtime.getState()));
263
215
  useEffect(() => {
264
- const updateState = () => writableStore(store).setState(runtime.getState());
216
+ const updateState = () => writableStore(store).setState(runtime.getState(), true);
265
217
  updateState();
266
218
  return runtime.subscribe(updateState);
267
219
  }, [runtime, store]);
@@ -293,10 +245,10 @@ var ThreadRuntimeProvider = ({ children, runtime }) => {
293
245
  };
294
246
 
295
247
  // src/context/providers/AssistantRuntimeProvider.tsx
296
- import { create as create5 } from "zustand";
248
+ import { create as create4 } from "zustand";
297
249
  import { jsx as jsx2 } from "react/jsx-runtime";
298
250
  var useAssistantRuntimeStore2 = (runtime) => {
299
- const [store] = useState2(() => create5(() => runtime));
251
+ const [store] = useState2(() => create4(() => runtime));
300
252
  useEffect2(() => {
301
253
  writableStore(store).setState(runtime, true);
302
254
  }, [runtime, store]);
@@ -321,7 +273,7 @@ var AssistantRuntimeProvider = memo(AssistantRuntimeProviderImpl);
321
273
 
322
274
  // src/context/providers/TextContentPartProvider.tsx
323
275
  import { useEffect as useEffect3, useState as useState3 } from "react";
324
- import { create as create6 } from "zustand";
276
+ import { create as create5 } from "zustand";
325
277
 
326
278
  // src/context/react/ContentPartContext.ts
327
279
  import { createContext as createContext3 } from "react";
@@ -332,11 +284,47 @@ var useContentPartContext = createContextHook(
332
284
  ContentPartContext,
333
285
  "a component passed to <MessagePrimitive.Content components={...}>"
334
286
  );
287
+ function useContentPartRuntime(options) {
288
+ const context = useContentPartContext(options);
289
+ if (!context) return null;
290
+ return context.useContentPartRuntime();
291
+ }
335
292
  var { useContentPart, useContentPartStore } = createContextStoreHook(
336
293
  useContentPartContext,
337
294
  "useContentPart"
338
295
  );
339
296
 
297
+ // src/api/ContentPartRuntime.ts
298
+ var ContentPartRuntime = class {
299
+ constructor(contentBinding, messageApi, threadApi) {
300
+ this.contentBinding = contentBinding;
301
+ this.messageApi = messageApi;
302
+ this.threadApi = threadApi;
303
+ }
304
+ getState() {
305
+ return this.contentBinding.getState();
306
+ }
307
+ addToolResult(result) {
308
+ const message = this.messageApi.getState();
309
+ if (!message) throw new Error("Message is not available");
310
+ const state = this.contentBinding.getState();
311
+ if (!state) throw new Error("Content part is not available");
312
+ if (state.type !== "tool-call")
313
+ throw new Error("Tried to add tool result to non-tool content part");
314
+ const toolName = state.toolName;
315
+ const toolCallId = state.toolCallId;
316
+ this.threadApi.getState().addToolResult({
317
+ messageId: message.id,
318
+ toolName,
319
+ toolCallId,
320
+ result
321
+ });
322
+ }
323
+ subscribe(callback) {
324
+ return this.contentBinding.subscribe(callback);
325
+ }
326
+ };
327
+
340
328
  // src/context/providers/TextContentPartProvider.tsx
341
329
  import { jsx as jsx3 } from "react/jsx-runtime";
342
330
  var COMPLETE_STATUS = {
@@ -347,18 +335,22 @@ var RUNNING_STATUS = {
347
335
  };
348
336
  var TextContentPartProvider = ({ children, text, isRunning }) => {
349
337
  const [context] = useState3(() => {
350
- const useContentPart2 = create6(() => ({
338
+ const useContentPartRuntime2 = create5(
339
+ // TODO
340
+ () => new ContentPartRuntime(null, null, null)
341
+ );
342
+ const useContentPart2 = create5(() => ({
351
343
  status: isRunning ? RUNNING_STATUS : COMPLETE_STATUS,
352
- part: { type: "text", text }
344
+ part: { type: "text", text },
345
+ type: "text",
346
+ text
353
347
  }));
354
- return {
355
- useContentPart: useContentPart2
356
- };
348
+ return { useContentPartRuntime: useContentPartRuntime2, useContentPart: useContentPart2 };
357
349
  });
358
350
  useEffect3(() => {
359
351
  const state = context.useContentPart.getState();
360
- const textUpdated = state.part.text !== text;
361
- const targetTextPart = textUpdated ? { type: "text", text } : state.part;
352
+ const textUpdated = state.text !== text;
353
+ const targetTextPart = textUpdated ? { type: "text", text } : state;
362
354
  const targetStatus = isRunning ? RUNNING_STATUS : COMPLETE_STATUS;
363
355
  const statusUpdated = state.status !== targetStatus;
364
356
  if (!textUpdated && !statusUpdated) return;
@@ -401,20 +393,25 @@ var { useEditComposer, useEditComposerStore } = createContextStoreHook(
401
393
  // src/context/react/ComposerContext.ts
402
394
  import { useMemo as useMemo3 } from "react";
403
395
  var useComposerContext = () => {
404
- const { useComposer: useComposer2 } = useThreadContext();
396
+ const { useComposer: useThreadComposer2 } = useThreadContext();
405
397
  const { useEditComposer: useEditComposer2 } = useMessageContext({ optional: true }) ?? {};
406
398
  return useMemo3(
407
399
  () => ({
408
- useComposer: useEditComposer2 ?? useComposer2,
400
+ useComposer: useEditComposer2 ?? useThreadComposer2,
409
401
  type: useEditComposer2 ? "edit" : "new"
410
402
  }),
411
- [useEditComposer2, useComposer2]
403
+ [useEditComposer2, useThreadComposer2]
412
404
  );
413
405
  };
414
406
  var { useComposer, useComposerStore } = createContextStoreHook(
415
407
  useComposerContext,
416
408
  "useComposer"
417
409
  );
410
+ function useComposerRuntime(options) {
411
+ const messageRuntime = useMessageRuntime({ optional: true });
412
+ const threadRuntime = useThreadRuntime(options);
413
+ return messageRuntime ? messageRuntime.composer : threadRuntime?.composer ?? null;
414
+ }
418
415
 
419
416
  // src/hooks/useAppendMessage.tsx
420
417
  import { useCallback } from "react";
@@ -580,12 +577,11 @@ var useActionBarCopy = ({
580
577
  // src/primitive-hooks/actionBar/useActionBarEdit.tsx
581
578
  import { useCallback as useCallback4 } from "react";
582
579
  var useActionBarEdit = () => {
583
- const editComposerStore = useEditComposerStore();
584
- const disabled = useEditComposer((c) => c.isEditing);
580
+ const composerRuntime = useComposerRuntime();
581
+ const disabled = useComposer((c) => c.isEditing);
585
582
  const callback = useCallback4(() => {
586
- const { edit } = editComposerStore.getState();
587
- edit();
588
- }, [editComposerStore]);
583
+ composerRuntime.beginEdit();
584
+ }, [composerRuntime]);
589
585
  if (disabled) return null;
590
586
  return callback;
591
587
  };
@@ -595,7 +591,7 @@ import { useCallback as useCallback5 } from "react";
595
591
  var useActionBarReload = () => {
596
592
  const messageStore = useMessageStore();
597
593
  const threadStore = useThreadStore();
598
- const threadRuntime = useThreadRuntime();
594
+ const messageRuntime = useMessageRuntime();
599
595
  const threadComposerStore = useThreadComposerStore();
600
596
  const threadViewportStore = useThreadViewportStore();
601
597
  const disabled = useCombinedStore(
@@ -603,11 +599,10 @@ var useActionBarReload = () => {
603
599
  (t, m) => t.isRunning || t.isDisabled || m.role !== "assistant"
604
600
  );
605
601
  const callback = useCallback5(() => {
606
- const { parentId } = messageStore.getState();
607
- threadRuntime.startRun(parentId);
602
+ messageRuntime.reload();
608
603
  threadViewportStore.getState().scrollToBottom();
609
604
  threadComposerStore.getState().focus();
610
- }, [threadRuntime, threadComposerStore, threadViewportStore, messageStore]);
605
+ }, [messageRuntime, threadComposerStore, threadViewportStore]);
611
606
  if (disabled) return null;
612
607
  return callback;
613
608
  };
@@ -617,19 +612,18 @@ import { useCallback as useCallback6 } from "react";
617
612
  var useActionBarSpeak = () => {
618
613
  const messageStore = useMessageStore();
619
614
  const editComposerStore = useEditComposerStore();
620
- const threadRuntime = useThreadRuntime();
615
+ const messageRunime = useMessageRuntime();
621
616
  const messageUtilsStore = useMessageUtilsStore();
622
617
  const hasSpeakableContent = useCombinedStore(
623
618
  [messageStore, editComposerStore],
624
- ({ message }, c) => {
619
+ (message, c) => {
625
620
  return !c.isEditing && (message.role !== "assistant" || message.status.type !== "running") && message.content.some((c2) => c2.type === "text" && c2.text.length > 0);
626
621
  }
627
622
  );
628
623
  const callback = useCallback6(async () => {
629
- const { message } = messageStore.getState();
630
- const utt = threadRuntime.speak(message.id);
624
+ const utt = messageRunime.speak();
631
625
  messageUtilsStore.getState().addUtterance(utt);
632
- }, [threadRuntime, messageStore, messageUtilsStore]);
626
+ }, [messageRunime, messageUtilsStore]);
633
627
  if (!hasSpeakableContent) return null;
634
628
  return callback;
635
629
  };
@@ -649,32 +643,28 @@ var useActionBarStopSpeaking = () => {
649
643
  // src/primitive-hooks/actionBar/useActionBarFeedbackPositive.tsx
650
644
  import { useCallback as useCallback8 } from "react";
651
645
  var useActionBarFeedbackPositive = () => {
652
- const threadRuntime = useThreadRuntime();
653
- const messageStore = useMessageStore();
646
+ const messageRuntime = useMessageRuntime();
654
647
  const messageUtilsStore = useMessageUtilsStore();
655
648
  const callback = useCallback8(() => {
656
- threadRuntime.submitFeedback({
657
- messageId: messageStore.getState().id,
649
+ messageRuntime.submitFeedback({
658
650
  type: "positive"
659
651
  });
660
652
  messageUtilsStore.getState().setSubmittedFeedback("positive");
661
- }, [messageStore, messageUtilsStore, threadRuntime]);
653
+ }, [messageUtilsStore, messageRuntime]);
662
654
  return callback;
663
655
  };
664
656
 
665
657
  // src/primitive-hooks/actionBar/useActionBarFeedbackNegative.tsx
666
658
  import { useCallback as useCallback9 } from "react";
667
659
  var useActionBarFeedbackNegative = () => {
668
- const threadRuntime = useThreadRuntime();
669
- const messageStore = useMessageStore();
660
+ const messageRuntime = useMessageRuntime();
670
661
  const messageUtilsStore = useMessageUtilsStore();
671
662
  const callback = useCallback9(() => {
672
- threadRuntime.submitFeedback({
673
- messageId: messageStore.getState().id,
663
+ messageRuntime.submitFeedback({
674
664
  type: "negative"
675
665
  });
676
666
  messageUtilsStore.getState().setSubmittedFeedback("negative");
677
- }, [messageStore, messageUtilsStore, threadRuntime]);
667
+ }, [messageUtilsStore, messageRuntime]);
678
668
  return callback;
679
669
  };
680
670
 
@@ -796,7 +786,7 @@ var useComposerAddAttachment = () => {
796
786
  // src/primitive-hooks/contentPart/useContentPartDisplay.tsx
797
787
  var useContentPartDisplay = () => {
798
788
  const display = useContentPart((c) => {
799
- if (c.part.type !== "ui")
789
+ if (c.type !== "ui")
800
790
  throw new Error(
801
791
  "This component can only be used inside ui content parts."
802
792
  );
@@ -808,7 +798,7 @@ var useContentPartDisplay = () => {
808
798
  // src/primitive-hooks/contentPart/useContentPartImage.tsx
809
799
  var useContentPartImage = () => {
810
800
  const image = useContentPart((c) => {
811
- if (c.part.type !== "image")
801
+ if (c.type !== "image")
812
802
  throw new Error(
813
803
  "ContentPartImage can only be used inside image content parts."
814
804
  );
@@ -820,7 +810,7 @@ var useContentPartImage = () => {
820
810
  // src/primitive-hooks/contentPart/useContentPartText.tsx
821
811
  var useContentPartText = () => {
822
812
  const text = useContentPart((c) => {
823
- if (c.part.type !== "text")
813
+ if (c.type !== "text")
824
814
  throw new Error(
825
815
  "ContentPartText can only be used inside text content parts."
826
816
  );
@@ -858,20 +848,15 @@ var useMessageIf = (props) => {
858
848
 
859
849
  // src/primitive-hooks/thread/useThreadIf.tsx
860
850
  var useThreadIf = (props) => {
861
- const threadStore = useThreadStore();
862
- const threadMessagesStore = useThreadMessagesStore();
863
- return useCombinedStore(
864
- [threadStore, threadMessagesStore],
865
- (thread, messages) => {
866
- if (props.empty === true && messages.length !== 0) return false;
867
- if (props.empty === false && messages.length === 0) return false;
868
- if (props.running === true && !thread.isRunning) return false;
869
- if (props.running === false && thread.isRunning) return false;
870
- if (props.disabled === true && thread.isDisabled) return false;
871
- if (props.disabled === false && thread.isDisabled) return false;
872
- return true;
873
- }
874
- );
851
+ return useThread((thread) => {
852
+ if (props.empty === true && thread.messages.length !== 0) return false;
853
+ if (props.empty === false && thread.messages.length === 0) return false;
854
+ if (props.running === true && !thread.isRunning) return false;
855
+ if (props.running === false && thread.isRunning) return false;
856
+ if (props.disabled === true && thread.isDisabled) return false;
857
+ if (props.disabled === false && thread.isDisabled) return false;
858
+ return true;
859
+ });
875
860
  };
876
861
 
877
862
  // src/primitive-hooks/thread/useThreadEmpty.tsx
@@ -1380,76 +1365,37 @@ var MessagePrimitiveIf = ({
1380
1365
  MessagePrimitiveIf.displayName = "MessagePrimitive.If";
1381
1366
 
1382
1367
  // src/primitives/message/MessageContent.tsx
1383
- import { memo as memo2 } from "react";
1368
+ import { memo as memo2, useMemo as useMemo6 } from "react";
1384
1369
 
1385
- // src/context/providers/ContentPartProvider.tsx
1370
+ // src/context/providers/ContentPartRuntimeProvider.tsx
1386
1371
  import { useEffect as useEffect8, useState as useState5 } from "react";
1387
- import { create as create7 } from "zustand";
1372
+ import { create as create6 } from "zustand";
1388
1373
  import { jsx as jsx17 } from "react/jsx-runtime";
1389
- var COMPLETE_STATUS2 = {
1390
- type: "complete"
1391
- };
1392
- var toContentPartStatus = (message, partIndex, part) => {
1393
- if (message.role !== "assistant") return COMPLETE_STATUS2;
1394
- const isLastPart = partIndex === Math.max(0, message.content.length - 1);
1395
- if (part.type !== "tool-call") {
1396
- if ("reason" in message.status && message.status.reason === "tool-calls" && isLastPart)
1397
- throw new Error(
1398
- "Encountered unexpected requires-action status. This is likely an internal bug in assistant-ui."
1399
- );
1400
- return isLastPart ? message.status : COMPLETE_STATUS2;
1401
- }
1402
- if (!!part.result) {
1403
- return COMPLETE_STATUS2;
1404
- }
1405
- return message.status;
1406
- };
1407
- var EMPTY_CONTENT = Object.freeze({ type: "text", text: "" });
1408
- var getContentPartState = ({ message }, useContentPart2, partIndex) => {
1409
- let part = message.content[partIndex];
1410
- if (!part) {
1411
- if (message.content.length === 0 && partIndex === 0) {
1412
- part = EMPTY_CONTENT;
1413
- } else {
1414
- return null;
1415
- }
1416
- } else if (message.content.length === 1 && part.type === "text" && part.text.length === 0) {
1417
- part = EMPTY_CONTENT;
1418
- }
1419
- const status = toContentPartStatus(message, partIndex, part);
1420
- const currentState = useContentPart2?.getState();
1421
- if (currentState && currentState.part === part && currentState.status === status)
1422
- return null;
1423
- return Object.freeze({ part, status });
1374
+ var useContentPartRuntimeStore = (runtime) => {
1375
+ const [store] = useState5(() => create6(() => runtime));
1376
+ useEffect8(() => {
1377
+ writableStore(store).setState(runtime, true);
1378
+ }, [runtime, store]);
1379
+ return store;
1424
1380
  };
1425
- var useContentPartContext2 = (partIndex) => {
1426
- const messageStore = useMessageStore();
1427
- const [context] = useState5(() => {
1428
- const useContentPart2 = create7(
1429
- () => getContentPartState(messageStore.getState(), void 0, partIndex)
1430
- );
1431
- return { useContentPart: useContentPart2 };
1432
- });
1381
+ var useContentPartStore2 = (runtime) => {
1382
+ const [store] = useState5(() => create6(() => runtime.getState()));
1433
1383
  useEffect8(() => {
1434
- const syncContentPart = (message) => {
1435
- const newState = getContentPartState(
1436
- message,
1437
- context.useContentPart,
1438
- partIndex
1439
- );
1440
- if (!newState) return;
1441
- writableStore(context.useContentPart).setState(newState, true);
1442
- };
1443
- syncContentPart(messageStore.getState());
1444
- return messageStore.subscribe(syncContentPart);
1445
- }, [context, messageStore, partIndex]);
1446
- return context;
1384
+ const updateState = () => writableStore(store).setState(runtime.getState(), true);
1385
+ updateState();
1386
+ return runtime.subscribe(updateState);
1387
+ }, [runtime, store]);
1388
+ return store;
1447
1389
  };
1448
- var ContentPartProvider = ({
1449
- partIndex,
1390
+ var ContentPartRuntimeProvider = ({
1391
+ runtime,
1450
1392
  children
1451
1393
  }) => {
1452
- const context = useContentPartContext2(partIndex);
1394
+ const useContentPartRuntime2 = useContentPartRuntimeStore(runtime);
1395
+ const useContentPart2 = useContentPartStore2(runtime);
1396
+ const [context] = useState5(() => {
1397
+ return { useContentPartRuntime: useContentPartRuntime2, useContentPart: useContentPart2 };
1398
+ });
1453
1399
  return /* @__PURE__ */ jsx17(ContentPartContext.Provider, { value: context, children });
1454
1400
  };
1455
1401
 
@@ -1469,11 +1415,11 @@ import {
1469
1415
  useContext as useContext2,
1470
1416
  useState as useState6
1471
1417
  } from "react";
1472
- import { create as create8 } from "zustand";
1418
+ import { create as create7 } from "zustand";
1473
1419
  import { jsx as jsx18 } from "react/jsx-runtime";
1474
1420
  var SmoothContext = createContext5(null);
1475
1421
  var makeSmoothContext = (initialState) => {
1476
- const useSmoothStatus2 = create8(() => initialState);
1422
+ const useSmoothStatus2 = create7(() => initialState);
1477
1423
  return { useSmoothStatus: useSmoothStatus2 };
1478
1424
  };
1479
1425
  var SmoothContextProvider = ({ children }) => {
@@ -1554,9 +1500,7 @@ var SMOOTH_STATUS = Object.freeze({
1554
1500
  type: "running"
1555
1501
  });
1556
1502
  var useSmooth = (state, smooth = false) => {
1557
- const {
1558
- part: { text }
1559
- } = state;
1503
+ const { text } = state;
1560
1504
  const id = useMessage({
1561
1505
  optional: true,
1562
1506
  selector: (m) => m.id
@@ -1568,17 +1512,17 @@ var useSmooth = (state, smooth = false) => {
1568
1512
  setDisplayedText(text2);
1569
1513
  if (smoothStatusStore) {
1570
1514
  writableStore(smoothStatusStore).setState(
1571
- text2 !== state.part.text ? SMOOTH_STATUS : state.status
1515
+ text2 !== state.text ? SMOOTH_STATUS : state.status
1572
1516
  );
1573
1517
  }
1574
1518
  });
1575
1519
  useEffect9(() => {
1576
1520
  if (smoothStatusStore) {
1577
1521
  writableStore(smoothStatusStore).setState(
1578
- text !== state.part.text ? SMOOTH_STATUS : state.status
1522
+ text !== state.text ? SMOOTH_STATUS : state.status
1579
1523
  );
1580
1524
  }
1581
- }, [smoothStatusStore, text, displayedText, state.status, state.part.text]);
1525
+ }, [smoothStatusStore, text, displayedText, state.status, state.text]);
1582
1526
  const [animatorRef] = useState7(
1583
1527
  new TextStreamAnimator(text, setText)
1584
1528
  );
@@ -1605,6 +1549,8 @@ var useSmooth = (state, smooth = false) => {
1605
1549
  }, [animatorRef]);
1606
1550
  return useMemo5(
1607
1551
  () => smooth ? {
1552
+ type: "text",
1553
+ text: displayedText,
1608
1554
  part: { type: "text", text: displayedText },
1609
1555
  status: text === displayedText ? state.status : SMOOTH_STATUS
1610
1556
  } : state,
@@ -1615,10 +1561,7 @@ var useSmooth = (state, smooth = false) => {
1615
1561
  // src/primitives/contentPart/ContentPartText.tsx
1616
1562
  import { jsx as jsx19 } from "react/jsx-runtime";
1617
1563
  var ContentPartPrimitiveText = forwardRef12(({ smooth = true, component: Component = "span", ...rest }, forwardedRef) => {
1618
- const {
1619
- part: { text },
1620
- status
1621
- } = useSmooth(useContentPartText(), smooth);
1564
+ const { text, status } = useSmooth(useContentPartText(), smooth);
1622
1565
  return /* @__PURE__ */ jsx19(Component, { "data-status": status.type, ...rest, ref: forwardedRef, children: text });
1623
1566
  });
1624
1567
  ContentPartPrimitiveText.displayName = "ContentPartPrimitive.Text";
@@ -1628,18 +1571,14 @@ import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
1628
1571
  import { forwardRef as forwardRef13 } from "react";
1629
1572
  import { jsx as jsx20 } from "react/jsx-runtime";
1630
1573
  var ContentPartPrimitiveImage = forwardRef13((props, forwardedRef) => {
1631
- const {
1632
- part: { image }
1633
- } = useContentPartImage();
1574
+ const { image } = useContentPartImage();
1634
1575
  return /* @__PURE__ */ jsx20(Primitive8.img, { src: image, ...props, ref: forwardedRef });
1635
1576
  });
1636
1577
  ContentPartPrimitiveImage.displayName = "ContentPartPrimitive.Image";
1637
1578
 
1638
1579
  // src/primitives/contentPart/ContentPartDisplay.tsx
1639
1580
  var ContentPartPrimitiveDisplay = () => {
1640
- const {
1641
- part: { display }
1642
- } = useContentPartDisplay();
1581
+ const { display } = useContentPartDisplay();
1643
1582
  return display ?? null;
1644
1583
  };
1645
1584
  ContentPartPrimitiveDisplay.displayName = "ContentPartPrimitive.Display";
@@ -1651,136 +1590,504 @@ var ContentPartPrimitiveInProgress = ({ children }) => {
1651
1590
  };
1652
1591
  ContentPartPrimitiveInProgress.displayName = "ContentPartPrimitive.InProgress";
1653
1592
 
1654
- // src/primitives/message/MessageContent.tsx
1655
- import { jsx as jsx21, jsxs as jsxs2 } from "react/jsx-runtime";
1656
- var ToolUIDisplay = ({
1657
- UI,
1658
- ...props
1659
- }) => {
1660
- const Render = useToolUIs((s) => s.getToolUI(props.part.toolName)) ?? UI;
1661
- if (!Render) return null;
1662
- return /* @__PURE__ */ jsx21(Render, { ...props });
1593
+ // src/api/ComposerRuntime.ts
1594
+ var METHOD_NOT_SUPPORTED = () => {
1595
+ throw new Error("Composer is not available");
1663
1596
  };
1664
- var defaultComponents = {
1665
- Text: () => /* @__PURE__ */ jsxs2("p", { style: { whiteSpace: "pre-line" }, children: [
1666
- /* @__PURE__ */ jsx21(ContentPartPrimitiveText, {}),
1667
- /* @__PURE__ */ jsx21(ContentPartPrimitiveInProgress, { children: /* @__PURE__ */ jsx21("span", { style: { fontFamily: "revert" }, children: " \u25CF" }) })
1668
- ] }),
1669
- Image: () => /* @__PURE__ */ jsx21(ContentPartPrimitiveImage, {}),
1670
- UI: () => /* @__PURE__ */ jsx21(ContentPartPrimitiveDisplay, {})
1597
+ var EMPTY_ARRAY = Object.freeze([]);
1598
+ var getThreadComposerState = (type, runtime, beginEdit, focus, onFocus) => {
1599
+ return Object.freeze({
1600
+ type,
1601
+ isEditing: runtime?.isEditing ?? false,
1602
+ canCancel: runtime?.canCancel ?? false,
1603
+ isEmpty: runtime?.isEmpty ?? true,
1604
+ text: runtime?.text ?? "",
1605
+ attachments: runtime?.attachments ?? EMPTY_ARRAY,
1606
+ attachmentAccept: runtime?.attachmentAccept ?? "*",
1607
+ value: runtime?.text ?? "",
1608
+ setValue: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1609
+ setText: runtime?.setText.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1610
+ edit: beginEdit,
1611
+ send: runtime?.send.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1612
+ cancel: runtime?.cancel.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1613
+ focus: focus ?? METHOD_NOT_SUPPORTED,
1614
+ onFocus: onFocus ?? METHOD_NOT_SUPPORTED,
1615
+ reset: runtime?.reset.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1616
+ addAttachment: runtime?.addAttachment.bind(runtime) ?? METHOD_NOT_SUPPORTED,
1617
+ removeAttachment: runtime?.removeAttachment.bind(runtime) ?? METHOD_NOT_SUPPORTED
1618
+ });
1671
1619
  };
1672
- var MessageContentPartComponent = ({
1673
- components: {
1674
- Text: Text2 = defaultComponents.Text,
1675
- Empty,
1676
- Image: Image2 = defaultComponents.Image,
1677
- UI = defaultComponents.UI,
1678
- tools: { by_name = {}, Fallback: Fallback2 = void 0 } = {}
1679
- } = {}
1680
- }) => {
1681
- const messageStore = useMessageStore();
1682
- const threadRuntime = useThreadRuntime();
1683
- const { part, status } = useContentPart();
1684
- const type = part.type;
1685
- switch (type) {
1686
- case "text":
1687
- if (status.type === "requires-action")
1688
- throw new Error("Encountered unexpected requires-action status");
1689
- if (part === EMPTY_CONTENT && !!Empty) {
1690
- return /* @__PURE__ */ jsx21(Empty, { status });
1691
- }
1692
- return /* @__PURE__ */ jsx21(Text2, { part, status });
1693
- case "image":
1694
- if (status.type === "requires-action")
1695
- throw new Error("Encountered unexpected requires-action status");
1696
- return /* @__PURE__ */ jsx21(Image2, { part, status });
1697
- case "ui":
1698
- if (status.type === "requires-action")
1699
- throw new Error("Encountered unexpected requires-action status");
1700
- return /* @__PURE__ */ jsx21(UI, { part, status });
1701
- case "tool-call": {
1702
- const Tool = by_name[part.toolName] || Fallback2;
1703
- const addResult = (result) => threadRuntime.addToolResult({
1704
- messageId: messageStore.getState().id,
1705
- toolName: part.toolName,
1706
- toolCallId: part.toolCallId,
1707
- result
1708
- });
1709
- return /* @__PURE__ */ jsx21(
1710
- ToolUIDisplay,
1711
- {
1712
- UI: Tool,
1713
- part,
1714
- status,
1715
- addResult
1716
- }
1717
- );
1718
- }
1719
- default:
1720
- const unhandledType = type;
1721
- throw new Error(`Unknown content part type: ${unhandledType}`);
1620
+ var ComposerRuntime = class {
1621
+ constructor(_core, _beginEdit) {
1622
+ this._core = _core;
1623
+ this._beginEdit = _beginEdit;
1722
1624
  }
1723
- };
1724
- var MessageContentPartImpl = ({
1725
- partIndex,
1726
- components
1727
- }) => {
1728
- return /* @__PURE__ */ jsx21(ContentPartProvider, { partIndex, children: /* @__PURE__ */ jsx21(MessageContentPartComponent, { components }) });
1729
- };
1730
- var MessageContentPart = memo2(
1731
- MessageContentPartImpl,
1732
- (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
1733
- );
1734
- var MessagePrimitiveContent = ({
1735
- components
1736
- }) => {
1737
- const contentLength = useMessage((s) => s.content.length) || 1;
1738
- return Array.from({ length: contentLength }, (_, index) => /* @__PURE__ */ jsx21(MessageContentPart, { partIndex: index, components }, index));
1739
- };
1740
- MessagePrimitiveContent.displayName = "MessagePrimitive.Content";
1741
-
1742
- // src/primitives/message/MessageInProgress.tsx
1743
- var MessagePrimitiveInProgress = () => {
1744
- return null;
1745
- };
1746
- MessagePrimitiveInProgress.displayName = "MessagePrimitive.InProgress";
1747
-
1748
- // src/primitives/message/MessageAttachments.tsx
1749
- import { memo as memo3 } from "react";
1750
-
1751
- // src/context/react/AttachmentContext.ts
1752
- import { createContext as createContext6, useContext as useContext3 } from "react";
1753
- var AttachmentContext = createContext6(
1754
- null
1755
- );
1756
- function useAttachmentContext(options) {
1757
- const context = useContext3(AttachmentContext);
1758
- if (!options?.optional && !context)
1759
- throw new Error(
1760
- "This component must be used within a ComposerPrimitive.Attachments or MessagePrimitive.Attachments component."
1761
- );
1762
- return context;
1763
- }
1764
- function useComposerAttachmentContext(options) {
1765
- const context = useAttachmentContext(options);
1766
- if (!context) return null;
1767
- if (context.type !== "composer")
1768
- throw new Error(
1769
- "This component must be used within a ComposerPrimitive.Attachments component."
1770
- );
1771
- return context;
1772
- }
1773
- function useMessageAttachmentContext(options) {
1774
- const context = useAttachmentContext(options);
1775
- if (!context) return null;
1776
- if (context.type !== "message")
1777
- throw new Error(
1778
- "This component must be used within a MessagePrimitive.Attachments component."
1779
- );
1780
- return context;
1781
- }
1782
- var { useAttachment, useAttachmentStore } = createContextStoreHook(
1783
- useAttachmentContext,
1625
+ get type() {
1626
+ return this._beginEdit ? "edit" : "thread";
1627
+ }
1628
+ /**
1629
+ * @deprecated Use `getState().isEditing` instead. This will be removed in 0.6.0.
1630
+ */
1631
+ get isEditing() {
1632
+ return this.getState().isEditing;
1633
+ }
1634
+ /**
1635
+ * @deprecated Use `getState().isEmpty` instead. This will be removed in 0.6.0.
1636
+ */
1637
+ get isEmpty() {
1638
+ return this.getState().isEmpty;
1639
+ }
1640
+ /**
1641
+ * @deprecated Use `getState().canCancel` instead. This will be removed in 0.6.0.
1642
+ */
1643
+ get canCancel() {
1644
+ return this.getState().canCancel;
1645
+ }
1646
+ /**
1647
+ * @deprecated Use `getState().text` instead. This will be removed in 0.6.0.
1648
+ */
1649
+ get text() {
1650
+ return this.getState().text;
1651
+ }
1652
+ /**
1653
+ * @deprecated Use `getState().attachmentAccept` instead. This will be removed in 0.6.0.
1654
+ */
1655
+ get attachmentAccept() {
1656
+ return this.getState().attachmentAccept;
1657
+ }
1658
+ // TODO should this instead return getAttachmentByIndex([idx]) instead?
1659
+ /**
1660
+ * @deprecated Use `getState().attachments` instead. This will be removed in 0.6.0.
1661
+ */
1662
+ get attachments() {
1663
+ return this.getState().attachments;
1664
+ }
1665
+ /**
1666
+ * @deprecated Use `getState().text` instead. This will be removed in 0.6.0.
1667
+ */
1668
+ get value() {
1669
+ return this.text;
1670
+ }
1671
+ getState() {
1672
+ return getThreadComposerState(
1673
+ this.type,
1674
+ this._core.getState(),
1675
+ this._beginEdit?.bind(this) ?? METHOD_NOT_SUPPORTED,
1676
+ this.focus.bind(this),
1677
+ this.onFocus.bind(this)
1678
+ );
1679
+ }
1680
+ setText(text) {
1681
+ const core = this._core.getState();
1682
+ if (!core) throw new Error("Composer is not available");
1683
+ core.setText(text);
1684
+ }
1685
+ setValue(text) {
1686
+ this.setText(text);
1687
+ }
1688
+ addAttachment(file) {
1689
+ const core = this._core.getState();
1690
+ if (!core) throw new Error("Composer is not available");
1691
+ return core.addAttachment(file);
1692
+ }
1693
+ // /**
1694
+ // * @deprecated Use `getAttachmentById(id).removeAttachment` instead. This will be removed in 0.6.0.
1695
+ // */
1696
+ removeAttachment(attachmentId) {
1697
+ const core = this._core.getState();
1698
+ if (!core) throw new Error("Composer is not available");
1699
+ return core.removeAttachment(attachmentId);
1700
+ }
1701
+ /**
1702
+ * @deprecated This method will be removed in 0.6.0. Submit feedback if you need this functionality.
1703
+ */
1704
+ reset() {
1705
+ const core = this._core.getState();
1706
+ if (!core) throw new Error("Composer is not available");
1707
+ core.reset();
1708
+ }
1709
+ send() {
1710
+ const core = this._core.getState();
1711
+ if (!core) throw new Error("Composer is not available");
1712
+ core.send();
1713
+ }
1714
+ cancel() {
1715
+ const core = this._core.getState();
1716
+ if (!core) throw new Error("Composer is not available");
1717
+ core.cancel();
1718
+ }
1719
+ beginEdit() {
1720
+ this._beginEdit?.();
1721
+ }
1722
+ /**
1723
+ * @deprecated Use `beginEdit()` instead. This will be removed in 0.6.0.
1724
+ */
1725
+ edit() {
1726
+ this.beginEdit();
1727
+ }
1728
+ subscribe(callback) {
1729
+ return this._core.subscribe(callback);
1730
+ }
1731
+ _focusListeners = /* @__PURE__ */ new Set();
1732
+ focus() {
1733
+ this._focusListeners.forEach((callback) => callback());
1734
+ }
1735
+ onFocus(callback) {
1736
+ this._focusListeners.add(callback);
1737
+ return () => this._focusListeners.delete(callback);
1738
+ }
1739
+ };
1740
+
1741
+ // src/api/subscribable/BaseSubject.ts
1742
+ var BaseSubject = class {
1743
+ _subscriptions = /* @__PURE__ */ new Set();
1744
+ _connection;
1745
+ get isConnected() {
1746
+ return !!this._connection;
1747
+ }
1748
+ notifySubscribers() {
1749
+ for (const callback of this._subscriptions) callback();
1750
+ }
1751
+ _updateConnection() {
1752
+ if (this._subscriptions.size > 0) {
1753
+ if (this._connection) return;
1754
+ this._connection = this._connect();
1755
+ } else {
1756
+ this._connection?.();
1757
+ this._connection = void 0;
1758
+ }
1759
+ }
1760
+ subscribe(callback) {
1761
+ this._subscriptions.add(callback);
1762
+ this._updateConnection();
1763
+ return () => {
1764
+ this._subscriptions.delete(callback);
1765
+ this._updateConnection();
1766
+ };
1767
+ }
1768
+ };
1769
+
1770
+ // src/api/subscribable/NestedSubscriptionSubject.ts
1771
+ var NestedSubscriptionSubject = class extends BaseSubject {
1772
+ constructor(binding) {
1773
+ super();
1774
+ this.binding = binding;
1775
+ }
1776
+ getState() {
1777
+ return this.binding.getState();
1778
+ }
1779
+ _connect() {
1780
+ const callback = () => {
1781
+ this.notifySubscribers();
1782
+ };
1783
+ let lastState = this.binding.getState();
1784
+ let innerUnsubscribe = lastState?.subscribe(callback);
1785
+ const onRuntimeUpdate = () => {
1786
+ const newState = this.binding.getState();
1787
+ if (newState === lastState) return;
1788
+ lastState = newState;
1789
+ innerUnsubscribe?.();
1790
+ innerUnsubscribe = this.binding.getState()?.subscribe(callback);
1791
+ callback();
1792
+ };
1793
+ const outerUnsubscribe = this.binding.subscribe(onRuntimeUpdate);
1794
+ return () => {
1795
+ outerUnsubscribe?.();
1796
+ innerUnsubscribe?.();
1797
+ };
1798
+ }
1799
+ };
1800
+
1801
+ // src/api/subscribable/shallowEqual.ts
1802
+ function shallowEqual(objA, objB) {
1803
+ if (objA === void 0 && objB === void 0) return true;
1804
+ if (objA === void 0) return false;
1805
+ if (objB === void 0) return false;
1806
+ for (const key of Object.keys(objA)) {
1807
+ const valueA = objA[key];
1808
+ const valueB = objB[key];
1809
+ if (!Object.is(valueA, valueB)) return false;
1810
+ }
1811
+ return true;
1812
+ }
1813
+
1814
+ // src/api/subscribable/ShallowMemoizeSubject.ts
1815
+ var ShallowMemoizeSubject = class extends BaseSubject {
1816
+ constructor(binding) {
1817
+ super();
1818
+ this.binding = binding;
1819
+ const state = binding.getState();
1820
+ if (state === void 0)
1821
+ throw new Error("Entry not available in the store");
1822
+ this._previousState = state;
1823
+ }
1824
+ _previousState;
1825
+ getState = () => {
1826
+ if (!this.isConnected) this._syncState();
1827
+ return this._previousState;
1828
+ };
1829
+ _syncState() {
1830
+ const state = this.binding.getState();
1831
+ if (state === void 0) return false;
1832
+ if (shallowEqual(state, this._previousState)) return false;
1833
+ this._previousState = state;
1834
+ return true;
1835
+ }
1836
+ _connect() {
1837
+ const callback = () => {
1838
+ if (this._syncState()) {
1839
+ this.notifySubscribers();
1840
+ }
1841
+ };
1842
+ return this.binding.subscribe(callback);
1843
+ }
1844
+ };
1845
+
1846
+ // src/api/MessageRuntime.ts
1847
+ var COMPLETE_STATUS2 = {
1848
+ type: "complete"
1849
+ };
1850
+ var toContentPartStatus = (message, partIndex, part) => {
1851
+ if (message.role !== "assistant") return COMPLETE_STATUS2;
1852
+ const isLastPart = partIndex === Math.max(0, message.content.length - 1);
1853
+ if (part.type !== "tool-call") {
1854
+ if ("reason" in message.status && message.status.reason === "tool-calls" && isLastPart)
1855
+ throw new Error(
1856
+ "Encountered unexpected requires-action status. This is likely an internal bug in assistant-ui."
1857
+ );
1858
+ return isLastPart ? message.status : COMPLETE_STATUS2;
1859
+ }
1860
+ if (!!part.result) {
1861
+ return COMPLETE_STATUS2;
1862
+ }
1863
+ return message.status;
1864
+ };
1865
+ var EMPTY_CONTENT = Object.freeze({ type: "text", text: "" });
1866
+ var getContentPartState = (message, partIndex) => {
1867
+ let part = message.content[partIndex];
1868
+ if (!part) {
1869
+ if (message.content.length === 0 && partIndex === 0) {
1870
+ part = EMPTY_CONTENT;
1871
+ } else {
1872
+ return void 0;
1873
+ }
1874
+ } else if (message.content.length === 1 && part.type === "text" && part.text.length === 0) {
1875
+ part = EMPTY_CONTENT;
1876
+ }
1877
+ const status = toContentPartStatus(message, partIndex, part);
1878
+ return Object.freeze({ ...part, part, status });
1879
+ };
1880
+ var MessageRuntime = class {
1881
+ constructor(_core, _threadBinding) {
1882
+ this._core = _core;
1883
+ this._threadBinding = _threadBinding;
1884
+ }
1885
+ composer = new ComposerRuntime(
1886
+ new NestedSubscriptionSubject({
1887
+ getState: () => this._threadBinding.getState().getEditComposer(this._core.getState().id),
1888
+ subscribe: (callback) => this._threadBinding.subscribe(callback)
1889
+ }),
1890
+ () => this._threadBinding.getState().beginEdit(this._core.getState().id)
1891
+ );
1892
+ getState() {
1893
+ return this._core.getState();
1894
+ }
1895
+ // TODO improve type
1896
+ unstable_edit(message) {
1897
+ const state = this._core.getState();
1898
+ if (!state) throw new Error("Message is not available");
1899
+ this._threadBinding.getState().append({
1900
+ ...message,
1901
+ parentId: state.parentId
1902
+ });
1903
+ }
1904
+ reload() {
1905
+ const state = this._core.getState();
1906
+ if (!state) throw new Error("Message is not available");
1907
+ if (state.role !== "assistant")
1908
+ throw new Error("Can only reload assistant messages");
1909
+ this._threadBinding.getState().startRun(state.parentId);
1910
+ }
1911
+ speak() {
1912
+ const state = this._core.getState();
1913
+ if (!state) throw new Error("Message is not available");
1914
+ return this._threadBinding.getState().speak(state.id);
1915
+ }
1916
+ submitFeedback({ type }) {
1917
+ const state = this._core.getState();
1918
+ if (!state) throw new Error("Message is not available");
1919
+ this._threadBinding.getState().submitFeedback({
1920
+ messageId: state.id,
1921
+ type
1922
+ });
1923
+ }
1924
+ switchToBranch({
1925
+ position,
1926
+ branchId
1927
+ }) {
1928
+ const state = this._core.getState();
1929
+ if (!state) throw new Error("Message is not available");
1930
+ if (branchId && position) {
1931
+ throw new Error("May not specify both branchId and position");
1932
+ } else if (!branchId && !position) {
1933
+ throw new Error("Must specify either branchId or position");
1934
+ }
1935
+ const thread = this._threadBinding.getState();
1936
+ const branches = thread.getBranches(state.id);
1937
+ let targetBranch = branchId;
1938
+ if (position === "previous") {
1939
+ targetBranch = branches[state.branchNumber - 2];
1940
+ } else if (position === "next") {
1941
+ targetBranch = branches[state.branchNumber];
1942
+ }
1943
+ if (!targetBranch) throw new Error("Branch not found");
1944
+ this._threadBinding.getState().switchToBranch(targetBranch);
1945
+ }
1946
+ subscribe(callback) {
1947
+ return this._core.subscribe(callback);
1948
+ }
1949
+ unstable_getContentPartByIndex(idx) {
1950
+ if (idx < 0) throw new Error("Message index must be >= 0");
1951
+ return new ContentPartRuntime(
1952
+ new ShallowMemoizeSubject({
1953
+ getState: () => {
1954
+ return getContentPartState(this.getState(), idx);
1955
+ },
1956
+ subscribe: (callback) => this._core.subscribe(callback)
1957
+ }),
1958
+ this._core,
1959
+ this._threadBinding
1960
+ );
1961
+ }
1962
+ };
1963
+
1964
+ // src/primitives/message/MessageContent.tsx
1965
+ import { jsx as jsx21, jsxs as jsxs2 } from "react/jsx-runtime";
1966
+ var ToolUIDisplay = ({
1967
+ UI,
1968
+ ...props
1969
+ }) => {
1970
+ const Render = useToolUIs((s) => s.getToolUI(props.toolName)) ?? UI;
1971
+ if (!Render) return null;
1972
+ return /* @__PURE__ */ jsx21(Render, { ...props });
1973
+ };
1974
+ var defaultComponents = {
1975
+ Text: () => /* @__PURE__ */ jsxs2("p", { style: { whiteSpace: "pre-line" }, children: [
1976
+ /* @__PURE__ */ jsx21(ContentPartPrimitiveText, {}),
1977
+ /* @__PURE__ */ jsx21(ContentPartPrimitiveInProgress, { children: /* @__PURE__ */ jsx21("span", { style: { fontFamily: "revert" }, children: " \u25CF" }) })
1978
+ ] }),
1979
+ Image: () => /* @__PURE__ */ jsx21(ContentPartPrimitiveImage, {}),
1980
+ UI: () => /* @__PURE__ */ jsx21(ContentPartPrimitiveDisplay, {})
1981
+ };
1982
+ var MessageContentPartComponent = ({
1983
+ components: {
1984
+ Text: Text2 = defaultComponents.Text,
1985
+ Empty,
1986
+ Image: Image2 = defaultComponents.Image,
1987
+ UI = defaultComponents.UI,
1988
+ tools: { by_name = {}, Fallback: Fallback2 = void 0 } = {}
1989
+ } = {}
1990
+ }) => {
1991
+ const messageStore = useMessageStore();
1992
+ const threadRuntime = useThreadRuntime();
1993
+ const part = useContentPart();
1994
+ const type = part.type;
1995
+ switch (type) {
1996
+ case "text":
1997
+ if (part.status.type === "requires-action")
1998
+ throw new Error("Encountered unexpected requires-action status");
1999
+ if (part.part === EMPTY_CONTENT && !!Empty) {
2000
+ return /* @__PURE__ */ jsx21(Empty, { status: part.status });
2001
+ }
2002
+ return /* @__PURE__ */ jsx21(Text2, { ...part, part });
2003
+ case "image":
2004
+ if (part.status.type === "requires-action")
2005
+ throw new Error("Encountered unexpected requires-action status");
2006
+ return /* @__PURE__ */ jsx21(Image2, { ...part, part });
2007
+ case "ui":
2008
+ if (part.status.type === "requires-action")
2009
+ throw new Error("Encountered unexpected requires-action status");
2010
+ return /* @__PURE__ */ jsx21(UI, { ...part, part });
2011
+ case "tool-call": {
2012
+ const Tool = by_name[part.toolName] || Fallback2;
2013
+ const addResult = (result) => threadRuntime.addToolResult({
2014
+ messageId: messageStore.getState().id,
2015
+ toolName: part.toolName,
2016
+ toolCallId: part.toolCallId,
2017
+ result
2018
+ });
2019
+ return /* @__PURE__ */ jsx21(ToolUIDisplay, { ...part, part, UI: Tool, addResult });
2020
+ }
2021
+ default:
2022
+ const unhandledType = type;
2023
+ throw new Error(`Unknown content part type: ${unhandledType}`);
2024
+ }
2025
+ };
2026
+ var MessageContentPartImpl = ({
2027
+ partIndex,
2028
+ components
2029
+ }) => {
2030
+ const messageRuntime = useMessageRuntime();
2031
+ const runtime = useMemo6(
2032
+ () => messageRuntime.unstable_getContentPartByIndex(partIndex),
2033
+ [messageRuntime, partIndex]
2034
+ );
2035
+ return /* @__PURE__ */ jsx21(ContentPartRuntimeProvider, { runtime, children: /* @__PURE__ */ jsx21(MessageContentPartComponent, { components }) });
2036
+ };
2037
+ var MessageContentPart = memo2(
2038
+ MessageContentPartImpl,
2039
+ (prev, next) => prev.partIndex === next.partIndex && prev.components?.Text === next.components?.Text && prev.components?.Image === next.components?.Image && prev.components?.UI === next.components?.UI && prev.components?.tools === next.components?.tools
2040
+ );
2041
+ var MessagePrimitiveContent = ({
2042
+ components
2043
+ }) => {
2044
+ const contentLength = useMessage((s) => s.content.length) || 1;
2045
+ return Array.from({ length: contentLength }, (_, index) => /* @__PURE__ */ jsx21(MessageContentPart, { partIndex: index, components }, index));
2046
+ };
2047
+ MessagePrimitiveContent.displayName = "MessagePrimitive.Content";
2048
+
2049
+ // src/primitives/message/MessageInProgress.tsx
2050
+ var MessagePrimitiveInProgress = () => {
2051
+ return null;
2052
+ };
2053
+ MessagePrimitiveInProgress.displayName = "MessagePrimitive.InProgress";
2054
+
2055
+ // src/primitives/message/MessageAttachments.tsx
2056
+ import { memo as memo3 } from "react";
2057
+
2058
+ // src/context/react/AttachmentContext.ts
2059
+ import { createContext as createContext6, useContext as useContext3 } from "react";
2060
+ var AttachmentContext = createContext6(
2061
+ null
2062
+ );
2063
+ function useAttachmentContext(options) {
2064
+ const context = useContext3(AttachmentContext);
2065
+ if (!options?.optional && !context)
2066
+ throw new Error(
2067
+ "This component must be used within a ComposerPrimitive.Attachments or MessagePrimitive.Attachments component."
2068
+ );
2069
+ return context;
2070
+ }
2071
+ function useComposerAttachmentContext(options) {
2072
+ const context = useAttachmentContext(options);
2073
+ if (!context) return null;
2074
+ if (context.type !== "composer")
2075
+ throw new Error(
2076
+ "This component must be used within a ComposerPrimitive.Attachments component."
2077
+ );
2078
+ return context;
2079
+ }
2080
+ function useMessageAttachmentContext(options) {
2081
+ const context = useAttachmentContext(options);
2082
+ if (!context) return null;
2083
+ if (context.type !== "message")
2084
+ throw new Error(
2085
+ "This component must be used within a MessagePrimitive.Attachments component."
2086
+ );
2087
+ return context;
2088
+ }
2089
+ var { useAttachment, useAttachmentStore } = createContextStoreHook(
2090
+ useAttachmentContext,
1784
2091
  "useAttachment"
1785
2092
  );
1786
2093
  var {
@@ -1794,7 +2101,7 @@ var {
1794
2101
 
1795
2102
  // src/context/providers/MessageAttachmentProvider.tsx
1796
2103
  import { useEffect as useEffect10, useState as useState8 } from "react";
1797
- import { create as create9 } from "zustand";
2104
+ import { create as create8 } from "zustand";
1798
2105
  import { jsx as jsx22 } from "react/jsx-runtime";
1799
2106
  var getAttachment = (message, useAttachment2, partIndex) => {
1800
2107
  if (message.role !== "user") return null;
@@ -1809,7 +2116,7 @@ var useMessageAttachmentContext2 = (partIndex) => {
1809
2116
  const messageStore = useMessageStore();
1810
2117
  const [context] = useState8(
1811
2118
  () => {
1812
- const useAttachment2 = create9(
2119
+ const useAttachment2 = create8(
1813
2120
  () => getAttachment(messageStore.getState(), void 0, partIndex)
1814
2121
  );
1815
2122
  return { type: "message", useAttachment: useAttachment2 };
@@ -2040,7 +2347,7 @@ import { memo as memo4 } from "react";
2040
2347
 
2041
2348
  // src/context/providers/ComposerAttachmentProvider.tsx
2042
2349
  import { useEffect as useEffect12, useState as useState9 } from "react";
2043
- import { create as create10 } from "zustand";
2350
+ import { create as create9 } from "zustand";
2044
2351
  import { jsx as jsx27 } from "react/jsx-runtime";
2045
2352
  var getAttachment2 = ({ attachments }, useAttachment2, partIndex) => {
2046
2353
  const attachment = attachments[partIndex];
@@ -2053,7 +2360,7 @@ var useComposerAttachmentContext2 = (partIndex) => {
2053
2360
  const threadComposerStore = useThreadComposerStore();
2054
2361
  const [context] = useState9(
2055
2362
  () => {
2056
- const useAttachment2 = create10(
2363
+ const useAttachment2 = create9(
2057
2364
  () => getAttachment2(threadComposerStore.getState(), void 0, partIndex)
2058
2365
  );
2059
2366
  return { type: "composer", useAttachment: useAttachment2 };
@@ -2306,54 +2613,15 @@ var ThreadPrimitiveViewport = forwardRef18(({ autoScroll, children, ...rest }, f
2306
2613
  ThreadPrimitiveViewport.displayName = "ThreadPrimitive.Viewport";
2307
2614
 
2308
2615
  // src/primitives/thread/ThreadMessages.tsx
2309
- import { memo as memo5, useMemo as useMemo6 } from "react";
2616
+ import { memo as memo5, useMemo as useMemo7 } from "react";
2310
2617
 
2311
2618
  // src/context/providers/MessageRuntimeProvider.tsx
2312
2619
  import { useEffect as useEffect14, useState as useState10 } from "react";
2313
- import { create as create13 } from "zustand";
2314
-
2315
- // src/context/stores/EditComposer.ts
2316
2620
  import { create as create11 } from "zustand";
2317
- var makeEditComposerStore = ({
2318
- onEdit,
2319
- onSend
2320
- }) => create11()((set, get) => ({
2321
- type: "edit",
2322
- get value() {
2323
- return get().text;
2324
- },
2325
- setValue(value) {
2326
- get().setText(value);
2327
- },
2328
- text: "",
2329
- setText: (text) => {
2330
- set({ text, isEmpty: text.trim().length === 0 });
2331
- },
2332
- canCancel: false,
2333
- isEditing: false,
2334
- isEmpty: true,
2335
- edit: () => {
2336
- const text = onEdit();
2337
- set({
2338
- isEditing: true,
2339
- canCancel: true,
2340
- isEmpty: text.trim().length === 0,
2341
- text
2342
- });
2343
- },
2344
- send: () => {
2345
- const text = get().text;
2346
- set({ isEditing: false, canCancel: false });
2347
- onSend(text);
2348
- },
2349
- cancel: () => {
2350
- set({ isEditing: false, canCancel: false });
2351
- }
2352
- }));
2353
2621
 
2354
2622
  // src/context/stores/MessageUtils.ts
2355
- import { create as create12 } from "zustand";
2356
- var makeMessageUtilsStore = () => create12((set) => {
2623
+ import { create as create10 } from "zustand";
2624
+ var makeMessageUtilsStore = () => create10((set) => {
2357
2625
  let utterance = null;
2358
2626
  return {
2359
2627
  isCopied: false,
@@ -2385,14 +2653,14 @@ var makeMessageUtilsStore = () => create12((set) => {
2385
2653
  // src/context/providers/MessageRuntimeProvider.tsx
2386
2654
  import { jsx as jsx31 } from "react/jsx-runtime";
2387
2655
  var useMessageRuntimeStore = (runtime) => {
2388
- const [store] = useState10(() => create13(() => runtime));
2656
+ const [store] = useState10(() => create11(() => runtime));
2389
2657
  useEffect14(() => {
2390
2658
  writableStore(store).setState(runtime, true);
2391
2659
  }, [runtime, store]);
2392
2660
  return store;
2393
2661
  };
2394
2662
  var useMessageStore2 = (runtime) => {
2395
- const [store] = useState10(() => create13(() => runtime.getState()));
2663
+ const [store] = useState10(() => create11(() => runtime.getState()));
2396
2664
  useEffect14(() => {
2397
2665
  const updateState = () => writableStore(store).setState(runtime.getState(), true);
2398
2666
  updateState();
@@ -2405,29 +2673,13 @@ var useMessageUtilsStore2 = () => {
2405
2673
  return store;
2406
2674
  };
2407
2675
  var useEditComposerStore2 = (useMessageRuntime2) => {
2408
- const [store] = useState10(
2409
- () => makeEditComposerStore({
2410
- onEdit: () => {
2411
- const text = getThreadMessageText(
2412
- useMessageRuntime2.getState().getState()
2413
- );
2414
- return text;
2415
- },
2416
- onSend: (text) => {
2417
- const message = useMessageRuntime2.getState().getState();
2418
- const previousText = getThreadMessageText(message);
2419
- if (previousText === text) return;
2420
- const nonTextParts = message.content.filter(
2421
- (part) => part.type !== "text" && part.type !== "ui"
2422
- );
2423
- useMessageRuntime2.getState().edit({
2424
- role: message.role,
2425
- content: [{ type: "text", text }, ...nonTextParts],
2426
- attachments: message.attachments ?? []
2427
- });
2428
- }
2429
- })
2430
- );
2676
+ const runtime = useMessageRuntime2.getState().composer;
2677
+ const [store] = useState10(() => create11(() => runtime.getState()));
2678
+ useEffect14(() => {
2679
+ const updateState = () => writableStore(store).setState(runtime.getState());
2680
+ updateState();
2681
+ return runtime.subscribe(updateState);
2682
+ }, [runtime, store]);
2431
2683
  return store;
2432
2684
  };
2433
2685
  var MessageRuntimeProvider = ({
@@ -2488,7 +2740,7 @@ var ThreadMessageImpl = ({
2488
2740
  components
2489
2741
  }) => {
2490
2742
  const threadRuntime = useThreadRuntime();
2491
- const runtime = useMemo6(
2743
+ const runtime = useMemo7(
2492
2744
  () => threadRuntime.unstable_getMesssageByIndex(messageIndex),
2493
2745
  [threadRuntime, messageIndex]
2494
2746
  );
@@ -2501,7 +2753,7 @@ var ThreadMessage = memo5(
2501
2753
  var ThreadPrimitiveMessagesImpl = ({
2502
2754
  components
2503
2755
  }) => {
2504
- const messagesLength = useThreadMessages((t) => t.length);
2756
+ const messagesLength = useThread((t) => t.messages.length);
2505
2757
  if (messagesLength === 0) return null;
2506
2758
  return Array.from({ length: messagesLength }, (_, index) => /* @__PURE__ */ jsx32(ThreadMessage, { messageIndex: index, components }, index));
2507
2759
  };
@@ -2545,7 +2797,7 @@ var subscribeToMainThread = (runtime, callback) => {
2545
2797
  };
2546
2798
 
2547
2799
  // src/runtimes/local/useLocalRuntime.tsx
2548
- import { useInsertionEffect, useMemo as useMemo7, useState as useState12 } from "react";
2800
+ import { useInsertionEffect, useMemo as useMemo8, useState as useState12 } from "react";
2549
2801
 
2550
2802
  // src/runtimes/core/BaseAssistantRuntimeCore.tsx
2551
2803
  var BaseAssistantRuntimeCore = class {
@@ -2575,7 +2827,7 @@ var internal_exports = {};
2575
2827
  __export(internal_exports, {
2576
2828
  AssistantRuntime: () => AssistantRuntime,
2577
2829
  BaseAssistantRuntimeCore: () => BaseAssistantRuntimeCore,
2578
- BaseThreadComposerRuntimeCore: () => BaseThreadComposerRuntimeCore,
2830
+ DefaultThreadComposerRuntimeCore: () => DefaultThreadComposerRuntimeCore,
2579
2831
  MessageRepository: () => MessageRepository,
2580
2832
  ProxyConfigProvider: () => ProxyConfigProvider,
2581
2833
  ThreadRuntime: () => ThreadRuntime,
@@ -2586,58 +2838,20 @@ __export(internal_exports, {
2586
2838
  withSmoothContextProvider: () => withSmoothContextProvider
2587
2839
  });
2588
2840
 
2589
- // src/runtimes/utils/BaseThreadComposerRuntimeCore.tsx
2590
- var BaseThreadComposerRuntimeCore = class {
2591
- constructor(runtime) {
2592
- this.runtime = runtime;
2593
- this.connect();
2594
- }
2595
- _attachmentAdapter;
2841
+ // src/runtimes/composer/BaseComposerRuntimeCore.tsx
2842
+ var BaseComposerRuntimeCore = class {
2843
+ isEditing = true;
2596
2844
  attachmentAccept = "*";
2597
- get isEmpty() {
2598
- return !this.text.trim() && !this.attachments.length;
2599
- }
2600
- _canCancel = false;
2601
- get canCancel() {
2602
- return this._canCancel;
2603
- }
2604
- connect() {
2605
- return this.runtime.subscribe(() => {
2606
- if (this.canCancel !== this.runtime.capabilities.cancel) {
2607
- this._canCancel = this.runtime.capabilities.cancel;
2608
- this.notifySubscribers();
2609
- }
2610
- });
2611
- }
2612
- setAttachmentAdapter(adapter) {
2613
- this._attachmentAdapter = adapter;
2614
- const accept = adapter?.accept ?? "*";
2615
- if (this.attachmentAccept !== accept) {
2616
- this.attachmentAccept = accept;
2617
- return true;
2618
- }
2619
- return false;
2620
- }
2621
2845
  _attachments = [];
2846
+ set attachments(value) {
2847
+ this._attachments = value;
2848
+ this.notifySubscribers();
2849
+ }
2622
2850
  get attachments() {
2623
2851
  return this._attachments;
2624
2852
  }
2625
- async addAttachment(file) {
2626
- if (!this._attachmentAdapter)
2627
- throw new Error("Attachments are not supported");
2628
- const attachment = await this._attachmentAdapter.add({ file });
2629
- this._attachments = [...this._attachments, attachment];
2630
- this.notifySubscribers();
2631
- }
2632
- async removeAttachment(attachmentId) {
2633
- if (!this._attachmentAdapter)
2634
- throw new Error("Attachments are not supported");
2635
- const index = this._attachments.findIndex((a) => a.id === attachmentId);
2636
- if (index === -1) throw new Error("Attachment not found");
2637
- const attachment = this._attachments[index];
2638
- await this._attachmentAdapter.remove(attachment);
2639
- this._attachments = this._attachments.toSpliced(index, 1);
2640
- this.notifySubscribers();
2853
+ get isEmpty() {
2854
+ return !this.text.trim() && !this.attachments.length;
2641
2855
  }
2642
2856
  _text = "";
2643
2857
  get text() {
@@ -2658,16 +2872,39 @@ var BaseThreadComposerRuntimeCore = class {
2658
2872
  async (a) => await this._attachmentAdapter.send(a)
2659
2873
  )
2660
2874
  ) : [];
2661
- this.runtime.append({
2662
- parentId: this.runtime.messages.at(-1)?.id ?? null,
2875
+ const message = {
2663
2876
  role: "user",
2664
2877
  content: this.text ? [{ type: "text", text: this.text }] : [],
2665
2878
  attachments
2666
- });
2879
+ };
2667
2880
  this.reset();
2881
+ this.handleSend(message);
2668
2882
  }
2669
- async cancel() {
2670
- this.runtime.cancelRun();
2883
+ _attachmentAdapter;
2884
+ setAttachmentAdapter(adapter) {
2885
+ this._attachmentAdapter = adapter;
2886
+ const accept = adapter?.accept ?? "*";
2887
+ if (this.attachmentAccept !== accept) {
2888
+ this.attachmentAccept = accept;
2889
+ this.notifySubscribers();
2890
+ }
2891
+ }
2892
+ async addAttachment(file) {
2893
+ if (!this._attachmentAdapter)
2894
+ throw new Error("Attachments are not supported");
2895
+ const attachment = await this._attachmentAdapter.add({ file });
2896
+ this._attachments = [...this._attachments, attachment];
2897
+ this.notifySubscribers();
2898
+ }
2899
+ async removeAttachment(attachmentId) {
2900
+ if (!this._attachmentAdapter)
2901
+ throw new Error("Attachments are not supported");
2902
+ const index = this._attachments.findIndex((a) => a.id === attachmentId);
2903
+ if (index === -1) throw new Error("Attachment not found");
2904
+ const attachment = this._attachments[index];
2905
+ await this._attachmentAdapter.remove(attachment);
2906
+ this._attachments = this._attachments.toSpliced(index, 1);
2907
+ this.notifySubscribers();
2671
2908
  }
2672
2909
  _subscriptions = /* @__PURE__ */ new Set();
2673
2910
  notifySubscribers() {
@@ -2679,6 +2916,36 @@ var BaseThreadComposerRuntimeCore = class {
2679
2916
  }
2680
2917
  };
2681
2918
 
2919
+ // src/runtimes/composer/DefaultThreadComposerRuntimeCore.tsx
2920
+ var DefaultThreadComposerRuntimeCore = class extends BaseComposerRuntimeCore {
2921
+ constructor(runtime) {
2922
+ super();
2923
+ this.runtime = runtime;
2924
+ this.connect();
2925
+ }
2926
+ _canCancel = false;
2927
+ get canCancel() {
2928
+ return this._canCancel;
2929
+ }
2930
+ connect() {
2931
+ return this.runtime.subscribe(() => {
2932
+ if (this.canCancel !== this.runtime.capabilities.cancel) {
2933
+ this._canCancel = this.runtime.capabilities.cancel;
2934
+ this.notifySubscribers();
2935
+ }
2936
+ });
2937
+ }
2938
+ async handleSend(message) {
2939
+ this.runtime.append({
2940
+ ...message,
2941
+ parentId: this.runtime.messages.at(-1)?.id ?? null
2942
+ });
2943
+ }
2944
+ async cancel() {
2945
+ this.runtime.cancelRun();
2946
+ }
2947
+ };
2948
+
2682
2949
  // src/utils/ProxyConfigProvider.ts
2683
2950
  var ProxyConfigProvider = class {
2684
2951
  _providers = /* @__PURE__ */ new Set();
@@ -2804,11 +3071,11 @@ var MessageRepository = class {
2804
3071
  }
2805
3072
  }
2806
3073
  getMessages() {
2807
- const messages = new Array(this.head?.level ?? 0);
3074
+ const messages2 = new Array(this.head?.level ?? 0);
2808
3075
  for (let current = this.head; current; current = current.prev) {
2809
- messages[current.level] = current.current;
3076
+ messages2[current.level] = current.current;
2810
3077
  }
2811
- return messages;
3078
+ return messages2;
2812
3079
  }
2813
3080
  addOrUpdateMessage(parentId, message) {
2814
3081
  const existingItem = this.messages.get(message.id);
@@ -2934,11 +3201,11 @@ var MessageRepository = class {
2934
3201
  messages: exportItems
2935
3202
  };
2936
3203
  }
2937
- import({ headId, messages }) {
2938
- for (const { message, parentId } of messages) {
3204
+ import({ headId, messages: messages2 }) {
3205
+ for (const { message, parentId } of messages2) {
2939
3206
  this.addOrUpdateMessage(parentId, message);
2940
3207
  }
2941
- this.resetHead(headId ?? messages.at(-1)?.message.id ?? null);
3208
+ this.resetHead(headId ?? messages2.at(-1)?.message.id ?? null);
2942
3209
  }
2943
3210
  };
2944
3211
 
@@ -3005,98 +3272,38 @@ var buttonVariants = cva("aui-button", {
3005
3272
  default: "aui-button-medium",
3006
3273
  icon: "aui-button-icon"
3007
3274
  }
3008
- },
3009
- defaultVariants: {
3010
- variant: "default",
3011
- size: "default"
3012
- }
3013
- });
3014
- var Button = forwardRef20(
3015
- ({ className, variant, size, ...props }, ref) => {
3016
- return /* @__PURE__ */ jsx35(
3017
- Primitive13.button,
3018
- {
3019
- className: buttonVariants({ variant, size, className }),
3020
- ...props,
3021
- ref
3022
- }
3023
- );
3024
- }
3025
- );
3026
- Button.displayName = "Button";
3027
-
3028
- // src/ui/base/tooltip-icon-button.tsx
3029
- import { jsx as jsx36, jsxs as jsxs3 } from "react/jsx-runtime";
3030
- var TooltipIconButton = forwardRef21(({ children, tooltip, side = "bottom", ...rest }, ref) => {
3031
- return /* @__PURE__ */ jsxs3(Tooltip, { children: [
3032
- /* @__PURE__ */ jsx36(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
3033
- children,
3034
- /* @__PURE__ */ jsx36("span", { className: "aui-sr-only", children: tooltip })
3035
- ] }) }),
3036
- /* @__PURE__ */ jsx36(TooltipContent, { side, children: tooltip })
3037
- ] });
3038
- });
3039
- TooltipIconButton.displayName = "TooltipIconButton";
3040
-
3041
- // src/api/subscribable/BaseSubject.ts
3042
- var BaseSubject = class {
3043
- _subscriptions = /* @__PURE__ */ new Set();
3044
- _connection;
3045
- get isConnected() {
3046
- return !!this._connection;
3047
- }
3048
- notifySubscribers() {
3049
- for (const callback of this._subscriptions) callback();
3050
- }
3051
- _updateConnection() {
3052
- if (this._subscriptions.size > 0) {
3053
- if (this._connection) return;
3054
- this._connection = this._connect();
3055
- } else {
3056
- this._connection?.();
3057
- this._connection = void 0;
3058
- }
3059
- }
3060
- subscribe(callback) {
3061
- this._subscriptions.add(callback);
3062
- this._updateConnection();
3063
- return () => {
3064
- this._subscriptions.delete(callback);
3065
- this._updateConnection();
3066
- };
3067
- }
3068
- };
3069
-
3070
- // src/api/subscribable/NestedSubscriptionSubject.ts
3071
- var NestedSubscriptionSubject = class extends BaseSubject {
3072
- constructor(binding) {
3073
- super();
3074
- this.binding = binding;
3075
- }
3076
- getState() {
3077
- return this.binding.getState();
3078
- }
3079
- _connect() {
3080
- const callback = () => {
3081
- this.notifySubscribers();
3082
- };
3083
- let lastState = this.binding.getState();
3084
- let innerUnsubscribe = lastState.subscribe(callback);
3085
- const onRuntimeUpdate = () => {
3086
- const newState = this.binding.getState();
3087
- if (newState === lastState) return;
3088
- lastState = newState;
3089
- innerUnsubscribe?.();
3090
- innerUnsubscribe = this.binding.getState().subscribe(callback);
3091
- callback();
3092
- };
3093
- const outerUnsubscribe = this.binding.subscribe(onRuntimeUpdate);
3094
- return () => {
3095
- outerUnsubscribe?.();
3096
- innerUnsubscribe();
3097
- };
3275
+ },
3276
+ defaultVariants: {
3277
+ variant: "default",
3278
+ size: "default"
3098
3279
  }
3099
- };
3280
+ });
3281
+ var Button = forwardRef20(
3282
+ ({ className, variant, size, ...props }, ref) => {
3283
+ return /* @__PURE__ */ jsx35(
3284
+ Primitive13.button,
3285
+ {
3286
+ className: buttonVariants({ variant, size, className }),
3287
+ ...props,
3288
+ ref
3289
+ }
3290
+ );
3291
+ }
3292
+ );
3293
+ Button.displayName = "Button";
3294
+
3295
+ // src/ui/base/tooltip-icon-button.tsx
3296
+ import { jsx as jsx36, jsxs as jsxs3 } from "react/jsx-runtime";
3297
+ var TooltipIconButton = forwardRef21(({ children, tooltip, side = "bottom", ...rest }, ref) => {
3298
+ return /* @__PURE__ */ jsxs3(Tooltip, { children: [
3299
+ /* @__PURE__ */ jsx36(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(Button, { variant: "ghost", size: "icon", ...rest, ref, children: [
3300
+ children,
3301
+ /* @__PURE__ */ jsx36("span", { className: "aui-sr-only", children: tooltip })
3302
+ ] }) }),
3303
+ /* @__PURE__ */ jsx36(TooltipContent, { side, children: tooltip })
3304
+ ] });
3305
+ });
3306
+ TooltipIconButton.displayName = "TooltipIconButton";
3100
3307
 
3101
3308
  // src/api/AssistantRuntime.ts
3102
3309
  var AssistantRuntime = class {
@@ -3128,49 +3335,8 @@ var AssistantRuntime = class {
3128
3335
  }
3129
3336
  };
3130
3337
 
3131
- // src/api/ContentPartRuntime.ts
3132
- var ContentPartRuntime = class {
3133
- constructor(contentBinding, messageApi, threadApi) {
3134
- this.contentBinding = contentBinding;
3135
- this.messageApi = messageApi;
3136
- this.threadApi = threadApi;
3137
- }
3138
- getState() {
3139
- return this.contentBinding.getState();
3140
- }
3141
- addToolResult(result) {
3142
- const message = this.messageApi.getState();
3143
- if (!message) throw new Error("Message is not available");
3144
- const state = this.contentBinding.getState();
3145
- if (!state) throw new Error("Content part is not available");
3146
- if (state.part.type !== "tool-call")
3147
- throw new Error("Tried to add tool result to non-tool content part");
3148
- const toolName = state.part.toolName;
3149
- const toolCallId = state.part.toolCallId;
3150
- this.threadApi.getState().addToolResult({
3151
- messageId: message.id,
3152
- toolName,
3153
- toolCallId,
3154
- result
3155
- });
3156
- }
3157
- };
3158
-
3159
- // src/api/subscribable/shallowEqual.ts
3160
- function shallowEqual(objA, objB) {
3161
- if (objA === void 0 && objB === void 0) return true;
3162
- if (objA === void 0) return false;
3163
- if (objB === void 0) return false;
3164
- for (const key of Object.keys(objA)) {
3165
- const valueA = objA[key];
3166
- const valueB = objB[key];
3167
- if (!Object.is(valueA, valueB)) return false;
3168
- }
3169
- return true;
3170
- }
3171
-
3172
- // src/api/subscribable/ShallowMemoizeSubject.ts
3173
- var ShallowMemoizeSubject = class extends BaseSubject {
3338
+ // src/api/subscribable/LazyMemoizeSubject.ts
3339
+ var LazyMemoizeSubject = class extends BaseSubject {
3174
3340
  constructor(binding) {
3175
3341
  super();
3176
3342
  this.binding = binding;
@@ -3179,194 +3345,32 @@ var ShallowMemoizeSubject = class extends BaseSubject {
3179
3345
  throw new Error("Entry not available in the store");
3180
3346
  this._previousState = state;
3181
3347
  }
3348
+ _previousStateDirty = true;
3182
3349
  _previousState;
3183
3350
  getState = () => {
3184
- if (!this.isConnected) this._syncState();
3351
+ if (!this.isConnected || this._previousStateDirty) {
3352
+ const newState = this.binding.getState();
3353
+ if (newState !== void 0) {
3354
+ this._previousState = newState;
3355
+ }
3356
+ this._previousStateDirty = false;
3357
+ }
3185
3358
  return this._previousState;
3186
3359
  };
3187
- _syncState() {
3188
- const state = this.binding.getState();
3189
- if (state === void 0) return false;
3190
- if (shallowEqual(state, this._previousState)) return false;
3191
- this._previousState = state;
3192
- return true;
3193
- }
3194
3360
  _connect() {
3195
3361
  const callback = () => {
3196
- if (this._syncState()) {
3197
- this.notifySubscribers();
3198
- }
3362
+ this._previousStateDirty = true;
3363
+ this.notifySubscribers();
3199
3364
  };
3200
3365
  return this.binding.subscribe(callback);
3201
3366
  }
3202
3367
  };
3203
3368
 
3204
- // src/api/MessageRuntime.ts
3205
- var MessageRuntime = class {
3206
- constructor(_core, _threadBinding) {
3207
- this._core = _core;
3208
- this._threadBinding = _threadBinding;
3209
- }
3210
- getState() {
3211
- return this._core.getState();
3212
- }
3213
- // TODO improve type
3214
- edit(message) {
3215
- const state = this._core.getState();
3216
- if (!state) throw new Error("Message is not available");
3217
- this._threadBinding.getState().append({
3218
- ...message,
3219
- parentId: state.parentId
3220
- });
3221
- }
3222
- reload() {
3223
- const state = this._core.getState();
3224
- if (!state) throw new Error("Message is not available");
3225
- this._threadBinding.getState().startRun(state.parentId);
3226
- }
3227
- speak() {
3228
- const state = this._core.getState();
3229
- if (!state) throw new Error("Message is not available");
3230
- this._threadBinding.getState().speak(state.id);
3231
- }
3232
- submitFeedback({ type }) {
3233
- const state = this._core.getState();
3234
- if (!state) throw new Error("Message is not available");
3235
- this._threadBinding.getState().submitFeedback({
3236
- messageId: state.id,
3237
- type
3238
- });
3239
- }
3240
- switchToBranch({
3241
- position,
3242
- branchId
3243
- }) {
3244
- const state = this._core.getState();
3245
- if (!state) throw new Error("Message is not available");
3246
- if (branchId && position) {
3247
- throw new Error("May not specify both branchId and position");
3248
- } else if (!branchId && !position) {
3249
- throw new Error("Must specify either branchId or position");
3250
- }
3251
- const thread = this._threadBinding.getState();
3252
- const branches = thread.getBranches(state.id);
3253
- let targetBranch = branchId;
3254
- if (position === "previous") {
3255
- targetBranch = branches[state.branchNumber - 2];
3256
- } else if (position === "next") {
3257
- targetBranch = branches[state.branchNumber];
3258
- }
3259
- if (!targetBranch) throw new Error("Branch not found");
3260
- this._threadBinding.getState().switchToBranch(targetBranch);
3261
- }
3262
- subscribe(callback) {
3263
- return this._core.subscribe(callback);
3264
- }
3265
- getContentPartByIdx(idx) {
3266
- if (idx < 0) throw new Error("Message index must be >= 0");
3267
- return new ContentPartRuntime(
3268
- new ShallowMemoizeSubject({
3269
- getState: () => {
3270
- const state = this.getState();
3271
- if (!state) return void 0;
3272
- const message = state.message;
3273
- const part = message.content[idx];
3274
- if (!part) return void 0;
3275
- return {
3276
- part,
3277
- status: toContentPartStatus(message, idx, part)
3278
- };
3279
- },
3280
- subscribe: (callback) => this._core.subscribe(callback)
3281
- }),
3282
- this._core,
3283
- this._threadBinding
3284
- );
3285
- }
3286
- };
3287
-
3288
- // src/api/ThreadComposerRuntime.ts
3289
- var getThreadComposerState = (runtime) => {
3290
- return Object.freeze({
3291
- canCancel: runtime.canCancel,
3292
- isEmpty: runtime.isEmpty,
3293
- text: runtime.text,
3294
- attachments: runtime.attachments,
3295
- attachmentAccept: runtime.attachmentAccept
3296
- });
3297
- };
3298
- var ThreadComposerRuntime = class {
3299
- constructor(_core) {
3300
- this._core = _core;
3301
- }
3302
- /**
3303
- * @deprecated Use `getState().isEmpty` instead. This will be removed in 0.6.0.
3304
- */
3305
- get isEmpty() {
3306
- return this._core.getState().isEmpty;
3307
- }
3308
- /**
3309
- * @deprecated Use `getState().canCancel` instead. This will be removed in 0.6.0.
3310
- */
3311
- get canCancel() {
3312
- return this._core.getState().canCancel;
3313
- }
3314
- /**
3315
- * @deprecated Use `getState().text` instead. This will be removed in 0.6.0.
3316
- */
3317
- get text() {
3318
- return this._core.getState().text;
3319
- }
3320
- /**
3321
- * @deprecated Use `getState().attachmentAccept` instead. This will be removed in 0.6.0.
3322
- */
3323
- get attachmentAccept() {
3324
- return this._core.getState().attachmentAccept;
3325
- }
3326
- // TODO should this instead return getAttachmentByIndex([idx]) instead?
3327
- /**
3328
- * @deprecated Use `getState().attachments` instead. This will be removed in 0.6.0.
3329
- */
3330
- get attachments() {
3331
- return this._core.getState().attachments;
3332
- }
3333
- getState() {
3334
- return getThreadComposerState(this._core.getState());
3335
- }
3336
- setText(text) {
3337
- this._core.getState().setText(text);
3338
- }
3339
- addAttachment(file) {
3340
- return this._core.getState().addAttachment(file);
3341
- }
3342
- // /**
3343
- // * @deprecated Use `getAttachmentById(id).removeAttachment` instead. This will be removed in 0.6.0.
3344
- // */
3345
- removeAttachment(attachmentId) {
3346
- return this._core.getState().removeAttachment(attachmentId);
3347
- }
3348
- /**
3349
- * @deprecated This method will be removed in 0.6.0. Submit feedback if you need this functionality.
3350
- */
3351
- reset() {
3352
- this._core.getState().reset();
3353
- }
3354
- send() {
3355
- this._core.getState().send();
3356
- }
3357
- cancel() {
3358
- this._core.getState().cancel();
3359
- }
3360
- subscribe(callback) {
3361
- return this._core.subscribe(callback);
3362
- }
3363
- };
3364
-
3365
3369
  // src/api/ThreadRuntime.ts
3366
- var toAppendMessage = (messages, message) => {
3370
+ var toAppendMessage = (messages2, message) => {
3367
3371
  if (typeof message === "string") {
3368
3372
  return {
3369
- parentId: messages.at(-1)?.id ?? null,
3373
+ parentId: messages2.at(-1)?.id ?? null,
3370
3374
  role: "user",
3371
3375
  content: [{ type: "text", text: message }],
3372
3376
  attachments: []
@@ -3376,7 +3380,7 @@ var toAppendMessage = (messages, message) => {
3376
3380
  return message;
3377
3381
  }
3378
3382
  return {
3379
- parentId: message.parentId ?? messages.at(-1)?.id ?? null,
3383
+ parentId: message.parentId ?? messages2.at(-1)?.id ?? null,
3380
3384
  role: message.role ?? "user",
3381
3385
  content: message.content,
3382
3386
  attachments: message.attachments ?? []
@@ -3389,13 +3393,11 @@ var getThreadState = (runtime) => {
3389
3393
  capabilities: runtime.capabilities,
3390
3394
  isDisabled: runtime.isDisabled,
3391
3395
  isRunning: lastMessage?.role !== "assistant" ? false : lastMessage.status.type === "running",
3396
+ messages: runtime.messages,
3392
3397
  unstable_synchronizer: runtime.unstable_synchronizer
3393
3398
  });
3394
3399
  };
3395
3400
  var ThreadRuntime = class {
3396
- constructor(_threadBinding) {
3397
- this._threadBinding = _threadBinding;
3398
- }
3399
3401
  // public path = "assistant.threads[main]"; // TODO
3400
3402
  /**
3401
3403
  * @deprecated Use `getState().threadId` instead. This will be removed in 0.6.0.
@@ -3421,21 +3423,35 @@ var ThreadRuntime = class {
3421
3423
  get capabilities() {
3422
3424
  return this.getState().capabilities;
3423
3425
  }
3424
- // TODO this should instead return getMessageByIndex([idx])
3426
+ /**
3427
+ * @deprecated Use `getState().messages` instead. This will be removed in 0.6.0.
3428
+ */
3425
3429
  get messages() {
3426
3430
  return this._threadBinding.getState().messages;
3427
3431
  }
3428
3432
  unstable_getCore() {
3429
3433
  return this._threadBinding.getState();
3430
3434
  }
3431
- composer = new ThreadComposerRuntime(
3435
+ _threadBinding;
3436
+ constructor(threadBinding) {
3437
+ const stateBinding = new LazyMemoizeSubject({
3438
+ getState: () => getThreadState(threadBinding.getState()),
3439
+ subscribe: (callback) => threadBinding.subscribe(callback)
3440
+ });
3441
+ this._threadBinding = {
3442
+ getState: () => threadBinding.getState(),
3443
+ getStateState: () => stateBinding.getState(),
3444
+ subscribe: (callback) => threadBinding.subscribe(callback)
3445
+ };
3446
+ }
3447
+ composer = new ComposerRuntime(
3432
3448
  new NestedSubscriptionSubject({
3433
3449
  getState: () => this._threadBinding.getState().composer,
3434
3450
  subscribe: (callback) => this._threadBinding.subscribe(callback)
3435
3451
  })
3436
3452
  );
3437
3453
  getState() {
3438
- return getThreadState(this._threadBinding.getState());
3454
+ return this._threadBinding.getStateState();
3439
3455
  }
3440
3456
  append(message) {
3441
3457
  this._threadBinding.getState().append(
@@ -3484,6 +3500,18 @@ var ThreadRuntime = class {
3484
3500
  submitFeedback(options) {
3485
3501
  return this._threadBinding.getState().submitFeedback(options);
3486
3502
  }
3503
+ /**
3504
+ * @deprecated This is a temporary API. This will be removed in 0.6.0.
3505
+ */
3506
+ getEditComposer(messageId) {
3507
+ return this._threadBinding.getState().getEditComposer(messageId);
3508
+ }
3509
+ /**
3510
+ * @deprecated This is a temporary API. This will be removed in 0.6.0.
3511
+ */
3512
+ beginEdit(messageId) {
3513
+ return this._threadBinding.getState().beginEdit(messageId);
3514
+ }
3487
3515
  export() {
3488
3516
  return this._threadBinding.getState().export();
3489
3517
  }
@@ -3495,15 +3523,15 @@ var ThreadRuntime = class {
3495
3523
  return new MessageRuntime(
3496
3524
  new ShallowMemoizeSubject({
3497
3525
  getState: () => {
3498
- const messages = this.messages;
3499
- const message = messages[idx];
3526
+ const messages2 = this.messages;
3527
+ const message = messages2[idx];
3500
3528
  if (!message) return void 0;
3501
3529
  const branches = this._threadBinding.getState().getBranches(message.id);
3502
3530
  return {
3503
3531
  ...message,
3504
3532
  message,
3505
- isLast: idx === messages.length - 1,
3506
- parentId: messages[idx - 1]?.id ?? null,
3533
+ isLast: idx === messages2.length - 1,
3534
+ parentId: messages2[idx - 1]?.id ?? null,
3507
3535
  branches,
3508
3536
  branchNumber: branches.indexOf(message.id) + 1,
3509
3537
  branchCount: branches.length
@@ -3518,12 +3546,12 @@ var ThreadRuntime = class {
3518
3546
 
3519
3547
  // src/runtimes/edge/converters/fromLanguageModelMessages.ts
3520
3548
  var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
3521
- const messages = [];
3549
+ const messages2 = [];
3522
3550
  for (const lmMessage of lm) {
3523
3551
  const role = lmMessage.role;
3524
3552
  switch (role) {
3525
3553
  case "system": {
3526
- messages.push({
3554
+ messages2.push({
3527
3555
  role: "system",
3528
3556
  content: [
3529
3557
  {
@@ -3535,7 +3563,7 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
3535
3563
  break;
3536
3564
  }
3537
3565
  case "user": {
3538
- messages.push({
3566
+ messages2.push({
3539
3567
  role: "user",
3540
3568
  content: lmMessage.content.map((part) => {
3541
3569
  const type = part.type;
@@ -3578,20 +3606,20 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
3578
3606
  return part;
3579
3607
  });
3580
3608
  if (mergeRoundtrips) {
3581
- const previousMessage = messages[messages.length - 1];
3609
+ const previousMessage = messages2[messages2.length - 1];
3582
3610
  if (previousMessage?.role === "assistant") {
3583
3611
  previousMessage.content.push(...newContent);
3584
3612
  break;
3585
3613
  }
3586
3614
  }
3587
- messages.push({
3615
+ messages2.push({
3588
3616
  role: "assistant",
3589
3617
  content: newContent
3590
3618
  });
3591
3619
  break;
3592
3620
  }
3593
3621
  case "tool": {
3594
- const previousMessage = messages[messages.length - 1];
3622
+ const previousMessage = messages2[messages2.length - 1];
3595
3623
  if (previousMessage?.role !== "assistant")
3596
3624
  throw new Error(
3597
3625
  "A tool message must be preceded by an assistant message."
@@ -3617,7 +3645,7 @@ var fromLanguageModelMessages = (lm, { mergeRoundtrips }) => {
3617
3645
  }
3618
3646
  }
3619
3647
  }
3620
- return messages;
3648
+ return messages2;
3621
3649
  };
3622
3650
 
3623
3651
  // src/runtimes/edge/converters/fromLanguageModelTools.ts
@@ -3775,7 +3803,7 @@ var EdgeChatAdapter = class {
3775
3803
  constructor(options) {
3776
3804
  this.options = options;
3777
3805
  }
3778
- async *run({ messages, abortSignal, config }) {
3806
+ async *run({ messages: messages2, abortSignal, config }) {
3779
3807
  const headers = new Headers(this.options.headers);
3780
3808
  headers.set("Content-Type", "application/json");
3781
3809
  const result = await fetch(this.options.api, {
@@ -3784,7 +3812,7 @@ var EdgeChatAdapter = class {
3784
3812
  credentials: this.options.credentials ?? "same-origin",
3785
3813
  body: JSON.stringify({
3786
3814
  system: config.system,
3787
- messages: toCoreMessages(messages),
3815
+ messages: toCoreMessages(messages2),
3788
3816
  tools: config.tools ? toLanguageModelTools(config.tools) : [],
3789
3817
  ...config.callSettings,
3790
3818
  ...config.config,
@@ -3823,6 +3851,43 @@ var useEdgeRuntime = ({
3823
3851
  // src/runtimes/local/shouldContinue.tsx
3824
3852
  var shouldContinue = (result) => result.status?.type === "requires-action" && result.status.reason === "tool-calls" && result.content.every((c) => c.type !== "tool-call" || !!c.result);
3825
3853
 
3854
+ // src/runtimes/composer/DefaultEditComposerRuntimeCore.tsx
3855
+ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
3856
+ constructor(runtime, endEditCallback, { parentId, message }) {
3857
+ super();
3858
+ this.runtime = runtime;
3859
+ this.endEditCallback = endEditCallback;
3860
+ this._parentId = parentId;
3861
+ this._previousText = getThreadMessageText(message);
3862
+ this.setText(this._previousText);
3863
+ this._nonTextParts = message.content.filter(
3864
+ (part) => part.type !== "text" && part.type !== "ui"
3865
+ );
3866
+ }
3867
+ get canCancel() {
3868
+ return true;
3869
+ }
3870
+ _nonTextParts;
3871
+ _previousText;
3872
+ _parentId;
3873
+ async handleSend(message) {
3874
+ const text = getThreadMessageText(message);
3875
+ if (text !== this._previousText) {
3876
+ this.runtime.append({
3877
+ ...message,
3878
+ content: [...message.content, ...this._nonTextParts],
3879
+ parentId: this._parentId
3880
+ });
3881
+ }
3882
+ this.endEditCallback();
3883
+ this.notifySubscribers();
3884
+ }
3885
+ async cancel() {
3886
+ this.endEditCallback();
3887
+ this.notifySubscribers();
3888
+ }
3889
+ };
3890
+
3826
3891
  // src/runtimes/local/LocalThreadRuntimeCore.tsx
3827
3892
  var LocalThreadRuntimeCore = class {
3828
3893
  constructor(configProvider, adapter, { initialMessages, ...options }) {
@@ -3832,8 +3897,8 @@ var LocalThreadRuntimeCore = class {
3832
3897
  this.options = options;
3833
3898
  if (initialMessages) {
3834
3899
  let parentId = null;
3835
- const messages = fromCoreMessages(initialMessages);
3836
- for (const message of messages) {
3900
+ const messages2 = fromCoreMessages(initialMessages);
3901
+ for (const message of messages2) {
3837
3902
  this.repository.addOrUpdateMessage(parentId, message);
3838
3903
  parentId = message.id;
3839
3904
  }
@@ -3857,7 +3922,7 @@ var LocalThreadRuntimeCore = class {
3857
3922
  get messages() {
3858
3923
  return this.repository.getMessages();
3859
3924
  }
3860
- composer = new BaseThreadComposerRuntimeCore(this);
3925
+ composer = new DefaultThreadComposerRuntimeCore(this);
3861
3926
  getModelConfig() {
3862
3927
  return this.configProvider.getModelConfig();
3863
3928
  }
@@ -3886,6 +3951,23 @@ var LocalThreadRuntimeCore = class {
3886
3951
  }
3887
3952
  if (hasUpdates) this.notifySubscribers();
3888
3953
  }
3954
+ _editComposers = /* @__PURE__ */ new Map();
3955
+ getEditComposer(messageId) {
3956
+ return this._editComposers.get(messageId);
3957
+ }
3958
+ beginEdit(messageId) {
3959
+ if (this._editComposers.has(messageId))
3960
+ throw new Error("Edit already in progress");
3961
+ this._editComposers.set(
3962
+ messageId,
3963
+ new DefaultEditComposerRuntimeCore(
3964
+ this,
3965
+ () => this._editComposers.delete(messageId),
3966
+ this.repository.getMessage(messageId)
3967
+ )
3968
+ );
3969
+ this.notifySubscribers();
3970
+ }
3889
3971
  getBranches(messageId) {
3890
3972
  return this.repository.getBranches(messageId);
3891
3973
  }
@@ -3920,7 +4002,7 @@ var LocalThreadRuntimeCore = class {
3920
4002
  } while (shouldContinue(message));
3921
4003
  }
3922
4004
  async performRoundtrip(parentId, message) {
3923
- const messages = this.repository.getMessages();
4005
+ const messages2 = this.repository.getMessages();
3924
4006
  this.abortController?.abort();
3925
4007
  this.abortController = new AbortController();
3926
4008
  const initialContent = message.content;
@@ -3975,7 +4057,7 @@ var LocalThreadRuntimeCore = class {
3975
4057
  }
3976
4058
  try {
3977
4059
  const promiseOrGenerator = this.adapter.run({
3978
- messages,
4060
+ messages: messages2,
3979
4061
  abortSignal: this.abortController.signal,
3980
4062
  config: this.configProvider.getModelConfig(),
3981
4063
  onUpdate: updateMessage
@@ -4117,10 +4199,10 @@ var LocalRuntimeCore = class extends BaseAssistantRuntimeCore {
4117
4199
  } = {}) {
4118
4200
  this.switchToThread(null);
4119
4201
  if (!initialMessages) return;
4120
- const messages = fromCoreMessages(initialMessages);
4202
+ const messages2 = fromCoreMessages(initialMessages);
4121
4203
  this.thread.import({
4122
- messages: messages.map((m, idx) => ({
4123
- parentId: messages[idx - 1]?.id ?? null,
4204
+ messages: messages2.map((m, idx) => ({
4205
+ parentId: messages2[idx - 1]?.id ?? null,
4124
4206
  message: m
4125
4207
  }))
4126
4208
  });
@@ -4143,11 +4225,11 @@ var useLocalRuntime = (adapter, options = {}) => {
4143
4225
  runtime.thread.adapter = adapter;
4144
4226
  runtime.thread.options = options;
4145
4227
  });
4146
- return useMemo7(() => new LocalRuntime(runtime), [runtime]);
4228
+ return useMemo8(() => new LocalRuntime(runtime), [runtime]);
4147
4229
  };
4148
4230
 
4149
4231
  // src/runtimes/external-store/useExternalStoreRuntime.tsx
4150
- import { useEffect as useEffect15, useMemo as useMemo8, useState as useState13 } from "react";
4232
+ import { useEffect as useEffect15, useMemo as useMemo9, useState as useState13 } from "react";
4151
4233
 
4152
4234
  // src/runtimes/external-store/getExternalStoreMessage.tsx
4153
4235
  var symbolInnerMessage = Symbol("innerMessage");
@@ -4158,8 +4240,8 @@ var getExternalStoreMessage = (message) => {
4158
4240
  // src/runtimes/external-store/ThreadMessageConverter.ts
4159
4241
  var ThreadMessageConverter = class {
4160
4242
  cache = /* @__PURE__ */ new WeakMap();
4161
- convertMessages(messages, converter) {
4162
- return messages.map((m, idx) => {
4243
+ convertMessages(messages2, converter) {
4244
+ return messages2.map((m, idx) => {
4163
4245
  const cached = this.cache.get(m);
4164
4246
  const newMessage = converter(cached, m, idx);
4165
4247
  this.cache.set(m, newMessage);
@@ -4252,8 +4334,8 @@ var fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
4252
4334
  };
4253
4335
 
4254
4336
  // src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx
4255
- var hasUpcomingMessage = (isRunning, messages) => {
4256
- return isRunning && messages[messages.length - 1]?.role !== "assistant";
4337
+ var hasUpcomingMessage = (isRunning, messages2) => {
4338
+ return isRunning && messages2[messages2.length - 1]?.role !== "assistant";
4257
4339
  };
4258
4340
  var ExternalStoreThreadRuntimeCore = class {
4259
4341
  constructor(configProvider, store) {
@@ -4281,7 +4363,24 @@ var ExternalStoreThreadRuntimeCore = class {
4281
4363
  isDisabled;
4282
4364
  converter = new ThreadMessageConverter();
4283
4365
  _store;
4284
- composer = new BaseThreadComposerRuntimeCore(this);
4366
+ composer = new DefaultThreadComposerRuntimeCore(this);
4367
+ _editComposers = /* @__PURE__ */ new Map();
4368
+ getEditComposer(messageId) {
4369
+ return this._editComposers.get(messageId);
4370
+ }
4371
+ beginEdit(messageId) {
4372
+ if (this._editComposers.has(messageId))
4373
+ throw new Error("Edit already in progress");
4374
+ this._editComposers.set(
4375
+ messageId,
4376
+ new DefaultEditComposerRuntimeCore(
4377
+ this,
4378
+ () => this._editComposers.delete(messageId),
4379
+ this.repository.getMessage(messageId)
4380
+ )
4381
+ );
4382
+ this.notifySubscribers();
4383
+ }
4285
4384
  get store() {
4286
4385
  return this._store;
4287
4386
  }
@@ -4312,7 +4411,7 @@ var ExternalStoreThreadRuntimeCore = class {
4312
4411
  return;
4313
4412
  }
4314
4413
  }
4315
- const messages = !store.convertMessage ? store.messages : this.converter.convertMessages(store.messages, (cache, m, idx) => {
4414
+ const messages2 = !store.convertMessage ? store.messages : this.converter.convertMessages(store.messages, (cache, m, idx) => {
4316
4415
  if (!store.convertMessage) return m;
4317
4416
  const isLast = idx === store.messages.length - 1;
4318
4417
  const autoStatus = getAutoStatus(isLast, isRunning);
@@ -4326,18 +4425,18 @@ var ExternalStoreThreadRuntimeCore = class {
4326
4425
  newMessage[symbolInnerMessage] = m;
4327
4426
  return newMessage;
4328
4427
  });
4329
- for (let i = 0; i < messages.length; i++) {
4330
- const message = messages[i];
4331
- const parent = messages[i - 1];
4428
+ for (let i = 0; i < messages2.length; i++) {
4429
+ const message = messages2[i];
4430
+ const parent = messages2[i - 1];
4332
4431
  this.repository.addOrUpdateMessage(parent?.id ?? null, message);
4333
4432
  }
4334
4433
  if (this.assistantOptimisticId) {
4335
4434
  this.repository.deleteMessage(this.assistantOptimisticId);
4336
4435
  this.assistantOptimisticId = null;
4337
4436
  }
4338
- if (hasUpcomingMessage(isRunning, messages)) {
4437
+ if (hasUpcomingMessage(isRunning, messages2)) {
4339
4438
  this.assistantOptimisticId = this.repository.appendOptimisticMessage(
4340
- messages.at(-1)?.id ?? null,
4439
+ messages2.at(-1)?.id ?? null,
4341
4440
  {
4342
4441
  role: "assistant",
4343
4442
  content: []
@@ -4345,7 +4444,7 @@ var ExternalStoreThreadRuntimeCore = class {
4345
4444
  );
4346
4445
  }
4347
4446
  this.repository.resetHead(
4348
- this.assistantOptimisticId ?? messages.at(-1)?.id ?? null
4447
+ this.assistantOptimisticId ?? messages2.at(-1)?.id ?? null
4349
4448
  );
4350
4449
  this.messages = this.repository.getMessages();
4351
4450
  this.notifySubscribers();
@@ -4387,19 +4486,19 @@ var ExternalStoreThreadRuntimeCore = class {
4387
4486
  this.repository.deleteMessage(this.assistantOptimisticId);
4388
4487
  this.assistantOptimisticId = null;
4389
4488
  }
4390
- let messages = this.repository.getMessages();
4391
- const previousMessage = messages[messages.length - 1];
4392
- if (previousMessage?.role === "user" && previousMessage.id === messages.at(-1)?.id) {
4489
+ let messages2 = this.repository.getMessages();
4490
+ const previousMessage = messages2[messages2.length - 1];
4491
+ if (previousMessage?.role === "user" && previousMessage.id === messages2.at(-1)?.id) {
4393
4492
  this.repository.deleteMessage(previousMessage.id);
4394
4493
  if (!this.composer.text.trim()) {
4395
4494
  this.composer.setText(getThreadMessageText(previousMessage));
4396
4495
  }
4397
- messages = this.repository.getMessages();
4496
+ messages2 = this.repository.getMessages();
4398
4497
  } else {
4399
4498
  this.notifySubscribers();
4400
4499
  }
4401
4500
  setTimeout(() => {
4402
- this.updateMessages(messages);
4501
+ this.updateMessages(messages2);
4403
4502
  }, 0);
4404
4503
  }
4405
4504
  addToolResult(options) {
@@ -4423,9 +4522,9 @@ var ExternalStoreThreadRuntimeCore = class {
4423
4522
  this._subscriptions.add(callback);
4424
4523
  return () => this._subscriptions.delete(callback);
4425
4524
  }
4426
- updateMessages = (messages) => {
4525
+ updateMessages = (messages2) => {
4427
4526
  this._store.setMessages?.(
4428
- messages.flatMap(getExternalStoreMessage).filter((m) => m != null)
4527
+ messages2.flatMap(getExternalStoreMessage).filter((m) => m != null)
4429
4528
  );
4430
4529
  };
4431
4530
  import(repository) {
@@ -4487,17 +4586,17 @@ var useExternalStoreRuntime = (store) => {
4487
4586
  useEffect15(() => {
4488
4587
  runtime.thread.store = store;
4489
4588
  });
4490
- return useMemo8(() => new AssistantRuntime(runtime, ThreadRuntime), [runtime]);
4589
+ return useMemo9(() => new AssistantRuntime(runtime, ThreadRuntime), [runtime]);
4491
4590
  };
4492
4591
 
4493
4592
  // src/runtimes/external-store/external-message-converter.tsx
4494
- import { useMemo as useMemo9 } from "react";
4495
- var joinExternalMessages = (messages) => {
4593
+ import { useMemo as useMemo10 } from "react";
4594
+ var joinExternalMessages = (messages2) => {
4496
4595
  const assistantMessage = {
4497
4596
  role: "assistant",
4498
4597
  content: []
4499
4598
  };
4500
- for (const output of messages) {
4599
+ for (const output of messages2) {
4501
4600
  if (output.role === "tool") {
4502
4601
  const toolCallIdx = assistantMessage.content.findIndex(
4503
4602
  (c) => c.type === "tool-call" && c.toolCallId === output.toolCallId
@@ -4574,10 +4673,10 @@ var chunkExternalMessages = (callbackResults) => {
4574
4673
  };
4575
4674
  var useExternalMessageConverter = ({
4576
4675
  callback,
4577
- messages,
4676
+ messages: messages2,
4578
4677
  isRunning
4579
4678
  }) => {
4580
- const state = useMemo9(
4679
+ const state = useMemo10(
4581
4680
  () => ({
4582
4681
  callback,
4583
4682
  callbackCache: /* @__PURE__ */ new WeakMap(),
@@ -4586,9 +4685,9 @@ var useExternalMessageConverter = ({
4586
4685
  }),
4587
4686
  [callback]
4588
4687
  );
4589
- return useMemo9(() => {
4688
+ return useMemo10(() => {
4590
4689
  const callbackResults = [];
4591
- for (const message of messages) {
4690
+ for (const message of messages2) {
4592
4691
  let result = state.callbackCache.get(message);
4593
4692
  if (!result) {
4594
4693
  const output = state.callback(message);
@@ -4626,7 +4725,7 @@ var useExternalMessageConverter = ({
4626
4725
  return newMessage;
4627
4726
  }
4628
4727
  );
4629
- }, [state, messages, isRunning]);
4728
+ }, [state, messages2, isRunning]);
4630
4729
  };
4631
4730
  var shallowArrayEqual = (a, b) => {
4632
4731
  if (a.length !== b.length) return false;
@@ -4644,13 +4743,13 @@ var DangerousInBrowserAdapter = class {
4644
4743
  constructor(options) {
4645
4744
  this.options = options;
4646
4745
  }
4647
- async *run({ messages, abortSignal, config }) {
4746
+ async *run({ messages: messages2, abortSignal, config }) {
4648
4747
  const res = await getEdgeRuntimeStream({
4649
4748
  options: this.options,
4650
4749
  abortSignal,
4651
4750
  requestData: {
4652
4751
  system: config.system,
4653
- messages: toCoreMessages(messages),
4752
+ messages: toCoreMessages(messages2),
4654
4753
  tools: config.tools ? toLanguageModelTools(config.tools) : [],
4655
4754
  ...config.callSettings,
4656
4755
  ...config.config
@@ -5047,7 +5146,7 @@ var assistant_action_bar_default = Object.assign(
5047
5146
  );
5048
5147
 
5049
5148
  // src/ui/assistant-message.tsx
5050
- import { forwardRef as forwardRef24, useMemo as useMemo10 } from "react";
5149
+ import { forwardRef as forwardRef24, useMemo as useMemo11 } from "react";
5051
5150
 
5052
5151
  // src/ui/branch-picker.tsx
5053
5152
  import { forwardRef as forwardRef23 } from "react";
@@ -5175,7 +5274,7 @@ var AssistantMessageContentWrapper = withDefaults("div", {
5175
5274
  });
5176
5275
  var AssistantMessageContent = forwardRef24(({ components: componentsProp, ...rest }, ref) => {
5177
5276
  const { tools, assistantMessage: { components = {} } = {} } = useThreadConfig();
5178
- const toolsComponents = useMemo10(
5277
+ const toolsComponents = useMemo11(
5179
5278
  () => ({
5180
5279
  by_name: !tools ? void 0 : Object.fromEntries(
5181
5280
  tools.map((t) => [
@@ -5866,12 +5965,14 @@ export {
5866
5965
  useComposerCancel,
5867
5966
  useComposerContext,
5868
5967
  useComposerIf,
5968
+ useComposerRuntime,
5869
5969
  useComposerSend,
5870
5970
  useComposerStore,
5871
5971
  useContentPart,
5872
5972
  useContentPartContext,
5873
5973
  useContentPartDisplay,
5874
5974
  useContentPartImage,
5975
+ useContentPartRuntime,
5875
5976
  useContentPartStore,
5876
5977
  useContentPartText,
5877
5978
  useDangerousInBrowserRuntime,