@assistant-ui/react 0.12.14 → 0.12.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal.d.ts +1 -1
  6. package/dist/internal.d.ts.map +1 -1
  7. package/dist/internal.js +1 -1
  8. package/dist/internal.js.map +1 -1
  9. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.d.ts +1 -4
  10. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  11. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.js +2 -527
  12. package/dist/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  13. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +96 -96
  14. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.d.ts +1 -16
  15. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.d.ts.map +1 -1
  16. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.js +1 -14
  17. package/dist/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.js.map +1 -1
  18. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.d.ts +1 -13
  19. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.d.ts.map +1 -1
  20. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.js +2 -82
  21. package/dist/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.js.map +1 -1
  22. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts +1 -23
  23. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts.map +1 -1
  24. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js +1 -305
  25. package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js.map +1 -1
  26. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts +1 -16
  27. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.d.ts.map +1 -1
  28. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js +1 -48
  29. package/dist/legacy-runtime/runtime-cores/external-store/createMessageConverter.js.map +1 -1
  30. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts +1 -33
  31. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts.map +1 -1
  32. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +1 -295
  33. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js.map +1 -1
  34. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.d.ts +1 -3
  35. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.d.ts.map +1 -1
  36. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.js +1 -17
  37. package/dist/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.js.map +1 -1
  38. package/dist/legacy-runtime/runtime-cores/local/LocalRuntimeOptions.d.ts +1 -1
  39. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts +1 -96
  40. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  41. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.js +1 -110
  42. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.js.map +1 -1
  43. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts +1 -112
  44. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  45. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js +1 -439
  46. package/dist/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  47. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.d.ts +1 -12
  48. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.d.ts.map +1 -1
  49. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.js +1 -102
  50. package/dist/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.js.map +1 -1
  51. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.d.ts +1 -3
  52. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.d.ts.map +1 -1
  53. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.js +1 -46
  54. package/dist/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.js.map +1 -1
  55. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts +6 -0
  56. package/dist/primitives/actionBar/ActionBarInteractionContext.d.ts.map +1 -0
  57. package/dist/primitives/actionBar/ActionBarInteractionContext.js +5 -0
  58. package/dist/primitives/actionBar/ActionBarInteractionContext.js.map +1 -0
  59. package/dist/primitives/actionBar/ActionBarRoot.d.ts.map +1 -1
  60. package/dist/primitives/actionBar/ActionBarRoot.js +18 -4
  61. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  62. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +2 -1
  63. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
  64. package/dist/primitives/actionBar/useActionBarFloatStatus.js +3 -2
  65. package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
  66. package/dist/primitives/actionBarMore/ActionBarMoreRoot.d.ts.map +1 -1
  67. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js +35 -2
  68. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
  69. package/dist/utils/createActionButton.js +1 -1
  70. package/dist/utils/createActionButton.js.map +1 -1
  71. package/dist/utils/json/is-json-equal.d.ts +2 -0
  72. package/dist/utils/json/is-json-equal.d.ts.map +1 -0
  73. package/dist/utils/json/is-json-equal.js +31 -0
  74. package/dist/utils/json/is-json-equal.js.map +1 -0
  75. package/dist/utils/json/is-json.d.ts +1 -0
  76. package/dist/utils/json/is-json.d.ts.map +1 -1
  77. package/dist/utils/json/is-json.js +5 -3
  78. package/dist/utils/json/is-json.js.map +1 -1
  79. package/package.json +8 -8
  80. package/src/index.ts +1 -1
  81. package/src/internal.ts +1 -1
  82. package/src/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.ts +2 -784
  83. package/src/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.tsx +5 -43
  84. package/src/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.ts +2 -100
  85. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.test.ts +225 -2
  86. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +4 -439
  87. package/src/legacy-runtime/runtime-cores/external-store/createMessageConverter.ts +1 -76
  88. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.ts +4 -465
  89. package/src/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.ts +1 -27
  90. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.tsx +1 -178
  91. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.tsx +1 -529
  92. package/src/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.tsx +1 -152
  93. package/src/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.ts +1 -80
  94. package/src/primitives/actionBar/ActionBarInteractionContext.ts +13 -0
  95. package/src/primitives/actionBar/ActionBarRoot.tsx +38 -8
  96. package/src/primitives/actionBar/useActionBarFloatStatus.ts +4 -1
  97. package/src/primitives/actionBarMore/ActionBarMoreRoot.tsx +52 -2
  98. package/src/tests/BaseComposerRuntimeCore.test.ts +2 -3
  99. package/src/tests/external-message-converter.test.ts +80 -0
  100. package/src/utils/createActionButton.tsx +1 -1
  101. package/src/utils/json/is-json-equal.ts +48 -0
  102. package/src/utils/json/is-json.ts +6 -3
@@ -1,466 +1,5 @@
1
1
  "use client";
2
-
3
- import { useMemo } from "react";
4
- import { ThreadMessageConverter } from "./ThreadMessageConverter";
5
- import {
6
- getExternalStoreMessages,
7
- symbolInnerMessage,
8
- bindExternalStoreMessage,
9
- } from "./getExternalStoreMessage";
10
- import { fromThreadMessageLike, ThreadMessageLike } from "./ThreadMessageLike";
11
- import { getAutoStatus, isAutoStatus } from "./auto-status";
12
- import { ToolExecutionStatus } from "../assistant-transport/useToolInvocations";
13
- import { ReadonlyJSONValue } from "assistant-stream/utils";
14
- import { generateErrorMessageId } from "@assistant-ui/core/internal";
15
- import type {
16
- MessageTiming,
17
- ThreadAssistantMessage,
18
- ThreadMessage,
19
- ToolCallMessagePart,
20
- } from "@assistant-ui/core";
21
-
22
- export namespace useExternalMessageConverter {
23
- export type Message =
24
- | (ThreadMessageLike & {
25
- readonly convertConfig?: {
26
- readonly joinStrategy?: "concat-content" | "none";
27
- };
28
- })
29
- | {
30
- role: "tool";
31
- toolCallId: string;
32
- toolName?: string | undefined;
33
- result: any;
34
- artifact?: any;
35
- isError?: boolean;
36
- messages?: readonly ThreadMessage[];
37
- };
38
-
39
- export type Metadata = {
40
- readonly toolStatuses?: Record<string, ToolExecutionStatus>;
41
- readonly error?: ReadonlyJSONValue;
42
- readonly messageTiming?: Record<string, MessageTiming>;
43
- };
44
-
45
- export type Callback<T> = (
46
- message: T,
47
- metadata: Metadata,
48
- ) => Message | Message[];
49
- }
50
-
51
- type CallbackResult<T> = {
52
- input: T;
53
- outputs: useExternalMessageConverter.Message[];
54
- };
55
-
56
- type ChunkResult<T> = {
57
- inputs: T[];
58
- outputs: useExternalMessageConverter.Message[];
59
- };
60
-
61
- type Mutable<T> = {
62
- -readonly [P in keyof T]: T[P];
63
- };
64
-
65
- const joinExternalMessages = (
66
- messages: readonly useExternalMessageConverter.Message[],
67
- ): ThreadMessageLike => {
68
- const assistantMessage: Mutable<Omit<ThreadMessageLike, "metadata">> & {
69
- content: Exclude<ThreadMessageLike["content"][0], string>[];
70
- metadata?: Mutable<ThreadMessageLike["metadata"]>;
71
- } = {
72
- role: "assistant",
73
- content: [],
74
- };
75
- for (const output of messages) {
76
- if (output.role === "tool") {
77
- const toolCallIdx = assistantMessage.content.findIndex(
78
- (c) => c.type === "tool-call" && c.toolCallId === output.toolCallId,
79
- );
80
- if (toolCallIdx !== -1) {
81
- const toolCall = assistantMessage.content[
82
- toolCallIdx
83
- ]! as ToolCallMessagePart;
84
- if (output.toolName !== undefined) {
85
- if (toolCall.toolName !== output.toolName)
86
- throw new Error(
87
- `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`,
88
- );
89
- }
90
- assistantMessage.content[toolCallIdx] = {
91
- ...toolCall,
92
- ...{
93
- [symbolInnerMessage]: [
94
- ...((toolCall as any)[symbolInnerMessage] ?? []),
95
- output,
96
- ],
97
- },
98
- result: output.result,
99
- artifact: output.artifact,
100
- isError: output.isError,
101
- messages: output.messages,
102
- };
103
- } else {
104
- throw new Error(
105
- `Tool call ${output.toolCallId} ${output.toolName} not found in assistant message`,
106
- );
107
- }
108
- } else {
109
- const role = output.role;
110
- const content = (
111
- typeof output.content === "string"
112
- ? [{ type: "text" as const, text: output.content }]
113
- : output.content
114
- ).map((c) => ({
115
- ...c,
116
- ...{ [symbolInnerMessage]: [output] },
117
- }));
118
- switch (role) {
119
- case "system":
120
- case "user":
121
- return {
122
- ...output,
123
- content,
124
- };
125
- case "assistant":
126
- if (assistantMessage.content.length === 0) {
127
- assistantMessage.id = output.id;
128
- assistantMessage.createdAt ??= output.createdAt;
129
- assistantMessage.status ??= output.status;
130
-
131
- if (output.attachments) {
132
- assistantMessage.attachments = [
133
- ...(assistantMessage.attachments ?? []),
134
- ...output.attachments,
135
- ];
136
- }
137
-
138
- if (output.metadata) {
139
- assistantMessage.metadata ??= {};
140
- if (output.metadata.unstable_state) {
141
- assistantMessage.metadata.unstable_state =
142
- output.metadata.unstable_state;
143
- }
144
- if (output.metadata.unstable_annotations) {
145
- assistantMessage.metadata.unstable_annotations = [
146
- ...(assistantMessage.metadata.unstable_annotations ?? []),
147
- ...output.metadata.unstable_annotations,
148
- ];
149
- }
150
- if (output.metadata.unstable_data) {
151
- assistantMessage.metadata.unstable_data = [
152
- ...(assistantMessage.metadata.unstable_data ?? []),
153
- ...output.metadata.unstable_data,
154
- ];
155
- }
156
- if (output.metadata.steps) {
157
- assistantMessage.metadata.steps = [
158
- ...(assistantMessage.metadata.steps ?? []),
159
- ...output.metadata.steps,
160
- ];
161
- }
162
- if (output.metadata.custom) {
163
- assistantMessage.metadata.custom = {
164
- ...(assistantMessage.metadata.custom ?? {}),
165
- ...output.metadata.custom,
166
- };
167
- }
168
-
169
- if (output.metadata.timing) {
170
- assistantMessage.metadata.timing = output.metadata.timing;
171
- }
172
-
173
- if (output.metadata.submittedFeedback) {
174
- assistantMessage.metadata.submittedFeedback =
175
- output.metadata.submittedFeedback;
176
- }
177
- }
178
- // TODO keep this in sync
179
- }
180
-
181
- // Add content parts, merging reasoning parts with same parentId
182
- for (const part of content) {
183
- if (
184
- part.type === "reasoning" &&
185
- "parentId" in part &&
186
- part.parentId
187
- ) {
188
- const existingIdx = assistantMessage.content.findIndex(
189
- (c) =>
190
- c.type === "reasoning" &&
191
- "parentId" in c &&
192
- c.parentId === part.parentId,
193
- );
194
- if (existingIdx !== -1) {
195
- const existing = assistantMessage.content[
196
- existingIdx
197
- ] as typeof part;
198
- assistantMessage.content[existingIdx] = {
199
- ...existing,
200
- text: `${existing.text}\n\n${part.text}`,
201
- ...{
202
- [symbolInnerMessage]: [
203
- ...((existing as any)[symbolInnerMessage] ?? []),
204
- ...((part as any)[symbolInnerMessage] ?? []),
205
- ],
206
- },
207
- };
208
- continue;
209
- }
210
- }
211
- assistantMessage.content.push(part);
212
- }
213
- break;
214
- default: {
215
- const unsupportedRole: never = role;
216
- throw new Error(`Unknown message role: ${unsupportedRole}`);
217
- }
218
- }
219
- }
220
- }
221
- return assistantMessage;
222
- };
223
-
224
- const chunkExternalMessages = <T>(
225
- callbackResults: CallbackResult<T>[],
226
- joinStrategy?: "concat-content" | "none",
227
- ) => {
228
- const results: ChunkResult<T>[] = [];
229
- let isAssistant = false;
230
- let pendingNone = false; // true if the previous assistant message had joinStrategy "none"
231
- let inputs: T[] = [];
232
- let outputs: useExternalMessageConverter.Message[] = [];
233
-
234
- const flush = () => {
235
- if (outputs.length) {
236
- results.push({
237
- inputs,
238
- outputs,
239
- });
240
- }
241
- inputs = [];
242
- outputs = [];
243
- isAssistant = false;
244
- pendingNone = false;
245
- };
246
-
247
- for (const callbackResult of callbackResults) {
248
- for (const output of callbackResult.outputs) {
249
- if (
250
- (pendingNone && output.role !== "tool") ||
251
- !isAssistant ||
252
- output.role === "user" ||
253
- output.role === "system"
254
- ) {
255
- flush();
256
- }
257
- isAssistant = output.role === "assistant" || output.role === "tool";
258
-
259
- if (inputs.at(-1) !== callbackResult.input) {
260
- inputs.push(callbackResult.input);
261
- }
262
- outputs.push(output);
263
-
264
- if (
265
- output.role === "assistant" &&
266
- (output.convertConfig?.joinStrategy === "none" ||
267
- joinStrategy === "none")
268
- ) {
269
- pendingNone = true;
270
- }
271
- }
272
- }
273
- flush();
274
- return results;
275
- };
276
-
277
- function createErrorAssistantMessage(
278
- error: ReadonlyJSONValue,
279
- ): ThreadAssistantMessage {
280
- const msg: ThreadAssistantMessage = {
281
- id: generateErrorMessageId(),
282
- role: "assistant",
283
- content: [],
284
- status: { type: "incomplete", reason: "error", error },
285
- createdAt: new Date(),
286
- metadata: {
287
- unstable_state: null,
288
- unstable_annotations: [],
289
- unstable_data: [],
290
- custom: {},
291
- steps: [],
292
- },
293
- };
294
- bindExternalStoreMessage(msg, []);
295
- return msg;
296
- }
297
-
298
- export const convertExternalMessages = <T extends WeakKey>(
299
- messages: T[],
300
- callback: useExternalMessageConverter.Callback<T>,
301
- isRunning: boolean,
302
- metadata: useExternalMessageConverter.Metadata,
303
- ) => {
304
- const callbackResults: CallbackResult<T>[] = [];
305
- for (const message of messages) {
306
- const output = callback(message, metadata);
307
- const outputs = Array.isArray(output) ? output : [output];
308
- const result = { input: message, outputs };
309
- callbackResults.push(result);
310
- }
311
-
312
- const chunks = chunkExternalMessages(callbackResults);
313
-
314
- const result = chunks.map((message, idx) => {
315
- const isLast = idx === chunks.length - 1;
316
- const joined = joinExternalMessages(message.outputs);
317
- const hasPendingToolCalls =
318
- typeof joined.content === "object" &&
319
- joined.content.some(
320
- (c) => c.type === "tool-call" && c.result === undefined,
321
- );
322
- const autoStatus = getAutoStatus(
323
- isLast,
324
- isRunning,
325
- hasPendingToolCalls,
326
- hasPendingToolCalls,
327
- isLast ? metadata.error : undefined,
328
- );
329
- const newMessage = fromThreadMessageLike(
330
- joined,
331
- idx.toString(),
332
- autoStatus,
333
- );
334
- bindExternalStoreMessage(newMessage, message.inputs);
335
- return newMessage;
336
- });
337
-
338
- if (metadata.error) {
339
- const lastMessage = result.at(-1);
340
- if (!lastMessage || lastMessage.role !== "assistant") {
341
- result.push(createErrorAssistantMessage(metadata.error));
342
- }
343
- }
344
-
345
- return result;
346
- };
347
-
348
- export const useExternalMessageConverter = <T extends WeakKey>({
349
- callback,
350
- messages,
351
- isRunning,
352
- joinStrategy,
353
- metadata,
354
- }: {
355
- callback: useExternalMessageConverter.Callback<T>;
356
- messages: T[];
357
- isRunning: boolean;
358
- joinStrategy?: "concat-content" | "none" | undefined;
359
- metadata?: useExternalMessageConverter.Metadata | undefined;
360
- }) => {
361
- const state = useMemo(
362
- () => ({
363
- metadata: metadata ?? {},
364
- callback,
365
- callbackCache: new WeakMap<T, CallbackResult<T>>(),
366
- chunkCache: new WeakMap<
367
- useExternalMessageConverter.Message,
368
- ChunkResult<T>
369
- >(),
370
- converterCache: new ThreadMessageConverter(),
371
- }),
372
- [callback, metadata],
373
- );
374
-
375
- return useMemo(() => {
376
- const callbackResults: CallbackResult<T>[] = [];
377
- for (const message of messages) {
378
- let result = state.callbackCache.get(message);
379
- if (!result) {
380
- const output = state.callback(message, state.metadata);
381
- const outputs = Array.isArray(output) ? output : [output];
382
- result = { input: message, outputs };
383
- state.callbackCache.set(message, result);
384
- }
385
- callbackResults.push(result);
386
- }
387
-
388
- const chunks = chunkExternalMessages(callbackResults, joinStrategy).map(
389
- (m) => {
390
- const key = m.outputs[0];
391
- if (!key) return m;
392
-
393
- const cached = state.chunkCache.get(key);
394
- if (cached && shallowArrayEqual(cached.outputs, m.outputs))
395
- return cached;
396
- state.chunkCache.set(key, m);
397
- return m;
398
- },
399
- );
400
-
401
- const threadMessages = state.converterCache.convertMessages(
402
- chunks,
403
- (cache, message, idx) => {
404
- const isLast = idx === chunks.length - 1;
405
-
406
- const joined = joinExternalMessages(message.outputs);
407
- const hasSuspendedToolCalls =
408
- typeof joined.content === "object" &&
409
- joined.content.some(
410
- (c) => c.type === "tool-call" && c.result === undefined,
411
- );
412
- const hasPendingToolCalls =
413
- typeof joined.content === "object" &&
414
- joined.content.some(
415
- (c) => c.type === "tool-call" && c.result === undefined,
416
- );
417
- const autoStatus = getAutoStatus(
418
- isLast,
419
- isRunning,
420
- hasSuspendedToolCalls,
421
- hasPendingToolCalls,
422
- isLast ? state.metadata.error : undefined,
423
- );
424
-
425
- if (
426
- cache &&
427
- (cache.role !== "assistant" ||
428
- !isAutoStatus(cache.status) ||
429
- cache.status === autoStatus)
430
- ) {
431
- const inputs = getExternalStoreMessages<T>(cache);
432
- if (shallowArrayEqual(inputs, message.inputs)) {
433
- return cache;
434
- }
435
- }
436
-
437
- const newMessage = fromThreadMessageLike(
438
- joined,
439
- idx.toString(),
440
- autoStatus,
441
- );
442
- bindExternalStoreMessage(newMessage, message.inputs);
443
- return newMessage;
444
- },
445
- );
446
-
447
- bindExternalStoreMessage(threadMessages, messages);
448
-
449
- if (state.metadata.error) {
450
- const lastMessage = threadMessages.at(-1);
451
- if (!lastMessage || lastMessage.role !== "assistant") {
452
- threadMessages.push(createErrorAssistantMessage(state.metadata.error));
453
- }
454
- }
455
-
456
- return threadMessages;
457
- }, [state, messages, isRunning, joinStrategy]);
458
- };
459
-
460
- const shallowArrayEqual = (a: unknown[], b: unknown[]) => {
461
- if (a.length !== b.length) return false;
462
- for (let i = 0; i < a.length; i++) {
463
- if (a[i] !== b[i]) return false;
464
- }
465
- return true;
466
- };
2
+ export {
3
+ useExternalMessageConverter,
4
+ convertExternalMessages,
5
+ } from "@assistant-ui/core/react";
@@ -1,29 +1,3 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useMemo, useState } from "react";
4
- import { ExternalStoreRuntimeCore } from "./ExternalStoreRuntimeCore";
5
- import { ExternalStoreAdapter } from "./ExternalStoreAdapter";
6
- import {
7
- AssistantRuntime,
8
- AssistantRuntimeImpl,
9
- } from "../../runtime/AssistantRuntime";
10
- import { useRuntimeAdapters } from "../adapters/RuntimeAdapterProvider";
11
-
12
- export const useExternalStoreRuntime = <T>(
13
- store: ExternalStoreAdapter<T>,
14
- ): AssistantRuntime => {
15
- const [runtime] = useState(() => new ExternalStoreRuntimeCore(store));
16
-
17
- useEffect(() => {
18
- runtime.setAdapter(store);
19
- });
20
-
21
- const { modelContext } = useRuntimeAdapters() ?? {};
22
-
23
- useEffect(() => {
24
- if (!modelContext) return undefined;
25
- return runtime.registerModelContextProvider(modelContext);
26
- }, [modelContext, runtime]);
27
-
28
- return useMemo(() => new AssistantRuntimeImpl(runtime), [runtime]);
29
- };
3
+ export { useExternalStoreRuntime } from "@assistant-ui/core/react";
@@ -1,180 +1,3 @@
1
1
  "use client";
2
2
 
3
- import {
4
- FC,
5
- useCallback,
6
- useRef,
7
- useEffect,
8
- memo,
9
- PropsWithChildren,
10
- ComponentType,
11
- useMemo,
12
- } from "react";
13
- import { UseBoundStore, StoreApi, create } from "zustand";
14
- import { useAui } from "@assistant-ui/store";
15
- import { ThreadListItemRuntimeProvider } from "../../../context/providers";
16
- import {
17
- ThreadListRuntimeCore,
18
- ThreadRuntimeCore,
19
- ThreadRuntimeImpl,
20
- } from "../../../internal";
21
- import { BaseSubscribable } from "@assistant-ui/core/internal";
22
- import { AssistantRuntime } from "../../runtime";
23
- import { ThreadListRuntimeImpl } from "../../runtime/ThreadListRuntime";
24
-
25
- type RemoteThreadListHook = () => AssistantRuntime;
26
-
27
- type RemoteThreadListHookInstance = {
28
- runtime?: ThreadRuntimeCore;
29
- };
30
- export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
31
- private useRuntimeHook: UseBoundStore<
32
- StoreApi<{ useRuntime: RemoteThreadListHook }>
33
- >;
34
- private instances = new Map<string, RemoteThreadListHookInstance>();
35
- private useAliveThreadsKeysChanged = create(() => ({}));
36
- private parent: ThreadListRuntimeCore;
37
-
38
- constructor(
39
- runtimeHook: RemoteThreadListHook,
40
- parent: ThreadListRuntimeCore,
41
- ) {
42
- super();
43
- this.parent = parent;
44
- this.useRuntimeHook = create(() => ({ useRuntime: runtimeHook }));
45
- }
46
-
47
- public startThreadRuntime(threadId: string) {
48
- if (!this.instances.has(threadId)) {
49
- this.instances.set(threadId, {});
50
- this.useAliveThreadsKeysChanged.setState({}, true);
51
- }
52
-
53
- return new Promise<ThreadRuntimeCore>((resolve, reject) => {
54
- const callback = () => {
55
- const instance = this.instances.get(threadId);
56
- if (!instance) {
57
- dispose();
58
- reject(new Error("Thread was deleted before runtime was started"));
59
- } else if (!instance.runtime) {
60
- return; // misc update
61
- } else {
62
- dispose();
63
- resolve(instance.runtime);
64
- }
65
- };
66
- const dispose = this.subscribe(callback);
67
- callback();
68
- });
69
- }
70
-
71
- public getThreadRuntimeCore(threadId: string) {
72
- const instance = this.instances.get(threadId);
73
- if (!instance) return undefined;
74
- return instance.runtime;
75
- }
76
-
77
- public stopThreadRuntime(threadId: string) {
78
- this.instances.delete(threadId);
79
- this.useAliveThreadsKeysChanged.setState({}, true);
80
- }
81
-
82
- public setRuntimeHook(newRuntimeHook: RemoteThreadListHook) {
83
- const prevRuntimeHook = this.useRuntimeHook.getState().useRuntime;
84
- if (prevRuntimeHook !== newRuntimeHook) {
85
- this.useRuntimeHook.setState({ useRuntime: newRuntimeHook }, true);
86
- }
87
- }
88
-
89
- private _InnerActiveThreadProvider: FC<{
90
- threadId: string;
91
- }> = ({ threadId }) => {
92
- const { useRuntime } = this.useRuntimeHook();
93
- const runtime = useRuntime();
94
-
95
- const threadBinding = (runtime.thread as ThreadRuntimeImpl)
96
- .__internal_threadBinding;
97
-
98
- const updateRuntime = useCallback(() => {
99
- const aliveThread = this.instances.get(threadId);
100
- if (!aliveThread)
101
- throw new Error("Thread not found. This is a bug in assistant-ui.");
102
-
103
- aliveThread.runtime = threadBinding.getState();
104
- this._notifySubscribers();
105
- }, [threadId, threadBinding]);
106
-
107
- const isMounted = useRef(false);
108
- if (!isMounted.current) {
109
- updateRuntime();
110
- }
111
-
112
- useEffect(() => {
113
- isMounted.current = true;
114
- updateRuntime();
115
- return threadBinding.outerSubscribe(updateRuntime);
116
- }, [threadBinding, updateRuntime]);
117
-
118
- const aui = useAui();
119
- const initPromiseRef = useRef<Promise<unknown> | undefined>(undefined);
120
-
121
- useEffect(() => {
122
- const runtimeCore = threadBinding.getState();
123
- const setGetInitializePromise = (runtimeCore as Record<string, unknown>)[
124
- "__internal_setGetInitializePromise"
125
- ];
126
- if (typeof setGetInitializePromise === "function") {
127
- setGetInitializePromise.call(runtimeCore, () => initPromiseRef.current);
128
- }
129
- }, [threadBinding]);
130
-
131
- useEffect(() => {
132
- return runtime.threads.main.unstable_on("initialize", () => {
133
- const state = aui.threadListItem().getState();
134
- if (state.status === "new") {
135
- initPromiseRef.current = aui.threadListItem().initialize();
136
-
137
- const dispose = runtime.thread.unstable_on("runEnd", () => {
138
- dispose();
139
-
140
- aui.threadListItem().generateTitle();
141
- });
142
- }
143
- });
144
- }, [runtime, aui]);
145
-
146
- return null;
147
- };
148
-
149
- private _OuterActiveThreadProvider: FC<{
150
- threadId: string;
151
- provider: ComponentType<PropsWithChildren>;
152
- }> = memo(({ threadId, provider: Provider }) => {
153
- const runtime = useMemo(
154
- () => new ThreadListRuntimeImpl(this.parent).getItemById(threadId),
155
- [threadId],
156
- );
157
-
158
- return (
159
- <ThreadListItemRuntimeProvider runtime={runtime}>
160
- <Provider>
161
- <this._InnerActiveThreadProvider threadId={threadId} />
162
- </Provider>
163
- </ThreadListItemRuntimeProvider>
164
- );
165
- });
166
-
167
- public __internal_RenderThreadRuntimes: FC<{
168
- provider: ComponentType<PropsWithChildren>;
169
- }> = ({ provider }) => {
170
- this.useAliveThreadsKeysChanged(); // trigger re-render on alive threads change
171
-
172
- return Array.from(this.instances.keys()).map((threadId) => (
173
- <this._OuterActiveThreadProvider
174
- key={threadId}
175
- threadId={threadId}
176
- provider={provider}
177
- />
178
- ));
179
- };
180
- }
3
+ export { RemoteThreadListHookInstanceManager } from "@assistant-ui/core/react";