@assistant-ui/react 0.5.66 → 0.5.67

Sign up to get free protection for your applications and to get access to all the features.
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,