@assistant-ui/react 0.12.15 → 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 (72) 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 -410
  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 -307
  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/utils/createActionButton.js +1 -1
  56. package/dist/utils/createActionButton.js.map +1 -1
  57. package/package.json +3 -3
  58. package/src/index.ts +1 -1
  59. package/src/internal.ts +1 -1
  60. package/src/legacy-runtime/cloud/AssistantCloudThreadHistoryAdapter.ts +2 -784
  61. package/src/legacy-runtime/runtime-cores/adapters/RuntimeAdapterProvider.tsx +5 -43
  62. package/src/legacy-runtime/runtime-cores/adapters/attachment/CloudFileAttachmentAdapter.ts +2 -100
  63. package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +4 -580
  64. package/src/legacy-runtime/runtime-cores/external-store/createMessageConverter.ts +1 -76
  65. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.ts +4 -483
  66. package/src/legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime.ts +1 -27
  67. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListHookInstanceManager.tsx +1 -178
  68. package/src/legacy-runtime/runtime-cores/remote-thread-list/RemoteThreadListThreadListRuntimeCore.tsx +1 -529
  69. package/src/legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud.tsx +1 -152
  70. package/src/legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime.ts +1 -80
  71. package/src/tests/BaseComposerRuntimeCore.test.ts +2 -3
  72. package/src/utils/createActionButton.tsx +1 -1
@@ -1,484 +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 mergeInnerMessages = (existing: object, incoming: object) => ({
66
- [symbolInnerMessage]: [
67
- ...((existing as any)[symbolInnerMessage] ?? []),
68
- ...((incoming as any)[symbolInnerMessage] ?? []),
69
- ],
70
- });
71
-
72
- const joinExternalMessages = (
73
- messages: readonly useExternalMessageConverter.Message[],
74
- ): ThreadMessageLike => {
75
- const assistantMessage: Mutable<Omit<ThreadMessageLike, "metadata">> & {
76
- content: Exclude<ThreadMessageLike["content"][0], string>[];
77
- metadata?: Mutable<ThreadMessageLike["metadata"]>;
78
- } = {
79
- role: "assistant",
80
- content: [],
81
- };
82
- for (const output of messages) {
83
- if (output.role === "tool") {
84
- const toolCallIdx = assistantMessage.content.findIndex(
85
- (c) => c.type === "tool-call" && c.toolCallId === output.toolCallId,
86
- );
87
- // Ignore orphaned tool results so one bad tool message does not
88
- // prevent rendering the rest of the conversation.
89
- if (toolCallIdx !== -1) {
90
- const toolCall = assistantMessage.content[
91
- toolCallIdx
92
- ]! as ToolCallMessagePart;
93
- if (output.toolName !== undefined) {
94
- if (toolCall.toolName !== output.toolName)
95
- throw new Error(
96
- `Tool call name ${output.toolCallId} ${output.toolName} does not match existing tool call ${toolCall.toolName}`,
97
- );
98
- }
99
- assistantMessage.content[toolCallIdx] = {
100
- ...toolCall,
101
- ...{
102
- [symbolInnerMessage]: [
103
- ...((toolCall as any)[symbolInnerMessage] ?? []),
104
- output,
105
- ],
106
- },
107
- result: output.result,
108
- artifact: output.artifact,
109
- isError: output.isError,
110
- messages: output.messages,
111
- };
112
- }
113
- } else {
114
- const role = output.role;
115
- const content = (
116
- typeof output.content === "string"
117
- ? [{ type: "text" as const, text: output.content }]
118
- : output.content
119
- ).map((c) => ({
120
- ...c,
121
- ...{ [symbolInnerMessage]: [output] },
122
- }));
123
- switch (role) {
124
- case "system":
125
- case "user":
126
- return {
127
- ...output,
128
- content,
129
- };
130
- case "assistant":
131
- if (assistantMessage.content.length === 0) {
132
- assistantMessage.id = output.id;
133
- assistantMessage.createdAt ??= output.createdAt;
134
- assistantMessage.status ??= output.status;
135
-
136
- if (output.attachments) {
137
- assistantMessage.attachments = [
138
- ...(assistantMessage.attachments ?? []),
139
- ...output.attachments,
140
- ];
141
- }
142
-
143
- if (output.metadata) {
144
- assistantMessage.metadata ??= {};
145
- if (output.metadata.unstable_state) {
146
- assistantMessage.metadata.unstable_state =
147
- output.metadata.unstable_state;
148
- }
149
- if (output.metadata.unstable_annotations) {
150
- assistantMessage.metadata.unstable_annotations = [
151
- ...(assistantMessage.metadata.unstable_annotations ?? []),
152
- ...output.metadata.unstable_annotations,
153
- ];
154
- }
155
- if (output.metadata.unstable_data) {
156
- assistantMessage.metadata.unstable_data = [
157
- ...(assistantMessage.metadata.unstable_data ?? []),
158
- ...output.metadata.unstable_data,
159
- ];
160
- }
161
- if (output.metadata.steps) {
162
- assistantMessage.metadata.steps = [
163
- ...(assistantMessage.metadata.steps ?? []),
164
- ...output.metadata.steps,
165
- ];
166
- }
167
- if (output.metadata.custom) {
168
- assistantMessage.metadata.custom = {
169
- ...(assistantMessage.metadata.custom ?? {}),
170
- ...output.metadata.custom,
171
- };
172
- }
173
-
174
- if (output.metadata.timing) {
175
- assistantMessage.metadata.timing = output.metadata.timing;
176
- }
177
-
178
- if (output.metadata.submittedFeedback) {
179
- assistantMessage.metadata.submittedFeedback =
180
- output.metadata.submittedFeedback;
181
- }
182
- }
183
- // TODO keep this in sync
184
- }
185
-
186
- // Add content parts, merging reasoning parts with same parentId
187
- for (const part of content) {
188
- if (part.type === "tool-call") {
189
- const existingIdx = assistantMessage.content.findIndex(
190
- (c) =>
191
- c.type === "tool-call" && c.toolCallId === part.toolCallId,
192
- );
193
- if (existingIdx !== -1) {
194
- const existing = assistantMessage.content[
195
- existingIdx
196
- ] as typeof part;
197
- assistantMessage.content[existingIdx] = {
198
- ...existing,
199
- ...part,
200
- ...mergeInnerMessages(existing, part),
201
- };
202
- continue;
203
- }
204
- }
205
-
206
- if (
207
- part.type === "reasoning" &&
208
- "parentId" in part &&
209
- part.parentId
210
- ) {
211
- const existingIdx = assistantMessage.content.findIndex(
212
- (c) =>
213
- c.type === "reasoning" &&
214
- "parentId" in c &&
215
- c.parentId === part.parentId,
216
- );
217
- if (existingIdx !== -1) {
218
- const existing = assistantMessage.content[
219
- existingIdx
220
- ] as typeof part;
221
- assistantMessage.content[existingIdx] = {
222
- ...existing,
223
- text: `${existing.text}\n\n${part.text}`,
224
- ...mergeInnerMessages(existing, part),
225
- };
226
- continue;
227
- }
228
- }
229
- assistantMessage.content.push(part);
230
- }
231
- break;
232
- default: {
233
- const unsupportedRole: never = role;
234
- throw new Error(`Unknown message role: ${unsupportedRole}`);
235
- }
236
- }
237
- }
238
- }
239
- return assistantMessage;
240
- };
241
-
242
- const chunkExternalMessages = <T>(
243
- callbackResults: CallbackResult<T>[],
244
- joinStrategy?: "concat-content" | "none",
245
- ) => {
246
- const results: ChunkResult<T>[] = [];
247
- let isAssistant = false;
248
- let pendingNone = false; // true if the previous assistant message had joinStrategy "none"
249
- let inputs: T[] = [];
250
- let outputs: useExternalMessageConverter.Message[] = [];
251
-
252
- const flush = () => {
253
- if (outputs.length) {
254
- results.push({
255
- inputs,
256
- outputs,
257
- });
258
- }
259
- inputs = [];
260
- outputs = [];
261
- isAssistant = false;
262
- pendingNone = false;
263
- };
264
-
265
- for (const callbackResult of callbackResults) {
266
- for (const output of callbackResult.outputs) {
267
- if (
268
- (pendingNone && output.role !== "tool") ||
269
- !isAssistant ||
270
- output.role === "user" ||
271
- output.role === "system"
272
- ) {
273
- flush();
274
- }
275
- isAssistant = output.role === "assistant" || output.role === "tool";
276
-
277
- if (inputs.at(-1) !== callbackResult.input) {
278
- inputs.push(callbackResult.input);
279
- }
280
- outputs.push(output);
281
-
282
- if (
283
- output.role === "assistant" &&
284
- (output.convertConfig?.joinStrategy === "none" ||
285
- joinStrategy === "none")
286
- ) {
287
- pendingNone = true;
288
- }
289
- }
290
- }
291
- flush();
292
- return results;
293
- };
294
-
295
- function createErrorAssistantMessage(
296
- error: ReadonlyJSONValue,
297
- ): ThreadAssistantMessage {
298
- const msg: ThreadAssistantMessage = {
299
- id: generateErrorMessageId(),
300
- role: "assistant",
301
- content: [],
302
- status: { type: "incomplete", reason: "error", error },
303
- createdAt: new Date(),
304
- metadata: {
305
- unstable_state: null,
306
- unstable_annotations: [],
307
- unstable_data: [],
308
- custom: {},
309
- steps: [],
310
- },
311
- };
312
- bindExternalStoreMessage(msg, []);
313
- return msg;
314
- }
315
-
316
- export const convertExternalMessages = <T extends WeakKey>(
317
- messages: T[],
318
- callback: useExternalMessageConverter.Callback<T>,
319
- isRunning: boolean,
320
- metadata: useExternalMessageConverter.Metadata,
321
- ) => {
322
- const callbackResults: CallbackResult<T>[] = [];
323
- for (const message of messages) {
324
- const output = callback(message, metadata);
325
- const outputs = Array.isArray(output) ? output : [output];
326
- const result = { input: message, outputs };
327
- callbackResults.push(result);
328
- }
329
-
330
- const chunks = chunkExternalMessages(callbackResults);
331
-
332
- const result = chunks.map((message, idx) => {
333
- const isLast = idx === chunks.length - 1;
334
- const joined = joinExternalMessages(message.outputs);
335
- const hasPendingToolCalls =
336
- typeof joined.content === "object" &&
337
- joined.content.some(
338
- (c) => c.type === "tool-call" && c.result === undefined,
339
- );
340
- const autoStatus = getAutoStatus(
341
- isLast,
342
- isRunning,
343
- hasPendingToolCalls,
344
- hasPendingToolCalls,
345
- isLast ? metadata.error : undefined,
346
- );
347
- const newMessage = fromThreadMessageLike(
348
- joined,
349
- idx.toString(),
350
- autoStatus,
351
- );
352
- bindExternalStoreMessage(newMessage, message.inputs);
353
- return newMessage;
354
- });
355
-
356
- if (metadata.error) {
357
- const lastMessage = result.at(-1);
358
- if (!lastMessage || lastMessage.role !== "assistant") {
359
- result.push(createErrorAssistantMessage(metadata.error));
360
- }
361
- }
362
-
363
- return result;
364
- };
365
-
366
- export const useExternalMessageConverter = <T extends WeakKey>({
367
- callback,
368
- messages,
369
- isRunning,
370
- joinStrategy,
371
- metadata,
372
- }: {
373
- callback: useExternalMessageConverter.Callback<T>;
374
- messages: T[];
375
- isRunning: boolean;
376
- joinStrategy?: "concat-content" | "none" | undefined;
377
- metadata?: useExternalMessageConverter.Metadata | undefined;
378
- }) => {
379
- const state = useMemo(
380
- () => ({
381
- metadata: metadata ?? {},
382
- callback,
383
- callbackCache: new WeakMap<T, CallbackResult<T>>(),
384
- chunkCache: new WeakMap<
385
- useExternalMessageConverter.Message,
386
- ChunkResult<T>
387
- >(),
388
- converterCache: new ThreadMessageConverter(),
389
- }),
390
- [callback, metadata],
391
- );
392
-
393
- return useMemo(() => {
394
- const callbackResults: CallbackResult<T>[] = [];
395
- for (const message of messages) {
396
- let result = state.callbackCache.get(message);
397
- if (!result) {
398
- const output = state.callback(message, state.metadata);
399
- const outputs = Array.isArray(output) ? output : [output];
400
- result = { input: message, outputs };
401
- state.callbackCache.set(message, result);
402
- }
403
- callbackResults.push(result);
404
- }
405
-
406
- const chunks = chunkExternalMessages(callbackResults, joinStrategy).map(
407
- (m) => {
408
- const key = m.outputs[0];
409
- if (!key) return m;
410
-
411
- const cached = state.chunkCache.get(key);
412
- if (cached && shallowArrayEqual(cached.outputs, m.outputs))
413
- return cached;
414
- state.chunkCache.set(key, m);
415
- return m;
416
- },
417
- );
418
-
419
- const threadMessages = state.converterCache.convertMessages(
420
- chunks,
421
- (cache, message, idx) => {
422
- const isLast = idx === chunks.length - 1;
423
-
424
- const joined = joinExternalMessages(message.outputs);
425
- const hasSuspendedToolCalls =
426
- typeof joined.content === "object" &&
427
- joined.content.some(
428
- (c) => c.type === "tool-call" && c.result === undefined,
429
- );
430
- const hasPendingToolCalls =
431
- typeof joined.content === "object" &&
432
- joined.content.some(
433
- (c) => c.type === "tool-call" && c.result === undefined,
434
- );
435
- const autoStatus = getAutoStatus(
436
- isLast,
437
- isRunning,
438
- hasSuspendedToolCalls,
439
- hasPendingToolCalls,
440
- isLast ? state.metadata.error : undefined,
441
- );
442
-
443
- if (
444
- cache &&
445
- (cache.role !== "assistant" ||
446
- !isAutoStatus(cache.status) ||
447
- cache.status === autoStatus)
448
- ) {
449
- const inputs = getExternalStoreMessages<T>(cache);
450
- if (shallowArrayEqual(inputs, message.inputs)) {
451
- return cache;
452
- }
453
- }
454
-
455
- const newMessage = fromThreadMessageLike(
456
- joined,
457
- idx.toString(),
458
- autoStatus,
459
- );
460
- bindExternalStoreMessage(newMessage, message.inputs);
461
- return newMessage;
462
- },
463
- );
464
-
465
- bindExternalStoreMessage(threadMessages, messages);
466
-
467
- if (state.metadata.error) {
468
- const lastMessage = threadMessages.at(-1);
469
- if (!lastMessage || lastMessage.role !== "assistant") {
470
- threadMessages.push(createErrorAssistantMessage(state.metadata.error));
471
- }
472
- }
473
-
474
- return threadMessages;
475
- }, [state, messages, isRunning, joinStrategy]);
476
- };
477
-
478
- const shallowArrayEqual = (a: unknown[], b: unknown[]) => {
479
- if (a.length !== b.length) return false;
480
- for (let i = 0; i < a.length; i++) {
481
- if (a[i] !== b[i]) return false;
482
- }
483
- return true;
484
- };
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";