@assistant-ui/core 0.1.16 → 0.2.0

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 (173) hide show
  1. package/dist/index.d.ts +7 -7
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/react/index.d.ts +3 -1
  6. package/dist/react/index.d.ts.map +1 -1
  7. package/dist/react/index.js +2 -0
  8. package/dist/react/index.js.map +1 -1
  9. package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts +5 -0
  10. package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -0
  11. package/dist/react/primitive-hooks/useThreadListLoadMore.js +11 -0
  12. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -0
  13. package/dist/react/primitives/message/MessageGroupedParts.d.ts +104 -0
  14. package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -0
  15. package/dist/react/primitives/message/MessageGroupedParts.js +74 -0
  16. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -0
  17. package/dist/react/primitives/message/MessageParts.d.ts +8 -1
  18. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  19. package/dist/react/primitives/message/MessageParts.js +45 -42
  20. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  21. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +2 -4
  22. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  23. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +4 -3
  24. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  25. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -6
  26. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  27. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +86 -38
  28. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  29. package/dist/react/runtimes/useLocalRuntime.d.ts +1 -1
  30. package/dist/react/utils/groupParts.d.ts +49 -0
  31. package/dist/react/utils/groupParts.d.ts.map +1 -0
  32. package/dist/react/utils/groupParts.js +97 -0
  33. package/dist/react/utils/groupParts.js.map +1 -0
  34. package/dist/runtime/api/assistant-runtime.d.ts +0 -33
  35. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  36. package/dist/runtime/api/assistant-runtime.js +0 -23
  37. package/dist/runtime/api/assistant-runtime.js.map +1 -1
  38. package/dist/runtime/api/bindings.d.ts +1 -3
  39. package/dist/runtime/api/bindings.d.ts.map +1 -1
  40. package/dist/runtime/api/composer-runtime.d.ts +3 -3
  41. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  42. package/dist/runtime/api/composer-runtime.js +1 -1
  43. package/dist/runtime/api/composer-runtime.js.map +1 -1
  44. package/dist/runtime/api/message-runtime.d.ts +1 -6
  45. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  46. package/dist/runtime/api/message-runtime.js.map +1 -1
  47. package/dist/runtime/api/thread-list-item-runtime.d.ts +18 -3
  48. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  49. package/dist/runtime/api/thread-list-item-runtime.js +1 -1
  50. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  51. package/dist/runtime/api/thread-list-runtime.d.ts +4 -0
  52. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  53. package/dist/runtime/api/thread-list-runtime.js +6 -0
  54. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  55. package/dist/runtime/api/thread-runtime.d.ts +6 -29
  56. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  57. package/dist/runtime/api/thread-runtime.js +2 -21
  58. package/dist/runtime/api/thread-runtime.js.map +1 -1
  59. package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -3
  60. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  61. package/dist/runtime/base/base-composer-runtime-core.js +47 -33
  62. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  63. package/dist/runtime/base/base-thread-runtime-core.d.ts +3 -4
  64. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  65. package/dist/runtime/base/base-thread-runtime-core.js +11 -11
  66. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  67. package/dist/runtime/interfaces/composer-runtime-core.d.ts +28 -2
  68. package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
  69. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +3 -0
  70. package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
  71. package/dist/runtime/interfaces/thread-runtime-core.d.ts +35 -4
  72. package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
  73. package/dist/runtime/utils/chat-model-adapter.d.ts +0 -4
  74. package/dist/runtime/utils/chat-model-adapter.d.ts.map +1 -1
  75. package/dist/runtime/utils/external-store-message.d.ts +0 -4
  76. package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
  77. package/dist/runtime/utils/external-store-message.js +0 -7
  78. package/dist/runtime/utils/external-store-message.js.map +1 -1
  79. package/dist/runtimes/assistant-transport/utils.d.ts +0 -9
  80. package/dist/runtimes/assistant-transport/utils.d.ts.map +1 -1
  81. package/dist/runtimes/assistant-transport/utils.js +0 -13
  82. package/dist/runtimes/assistant-transport/utils.js.map +1 -1
  83. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +0 -1
  84. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  85. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +2 -5
  86. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  87. package/dist/runtimes/local/local-thread-runtime-core.d.ts +0 -1
  88. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  89. package/dist/runtimes/local/local-thread-runtime-core.js +2 -6
  90. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  91. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +0 -1
  92. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  93. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +0 -3
  94. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
  95. package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
  96. package/dist/runtimes/remote-thread-list/empty-thread-core.js +0 -3
  97. package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
  98. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +12 -1
  99. package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
  100. package/dist/runtimes/remote-thread-list/remote-thread-state.js +34 -0
  101. package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
  102. package/dist/runtimes/remote-thread-list/types.d.ts +5 -1
  103. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  104. package/dist/store/clients/thread-message-client.d.ts.map +1 -1
  105. package/dist/store/clients/thread-message-client.js +0 -1
  106. package/dist/store/clients/thread-message-client.js.map +1 -1
  107. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  108. package/dist/store/runtime-clients/composer-runtime-client.js +5 -6
  109. package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
  110. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  111. package/dist/store/runtime-clients/thread-list-runtime-client.js +3 -0
  112. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  113. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  114. package/dist/store/runtime-clients/thread-runtime-client.js +0 -1
  115. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  116. package/dist/store/scopes/composer.d.ts +11 -1
  117. package/dist/store/scopes/composer.d.ts.map +1 -1
  118. package/dist/store/scopes/message.d.ts +1 -3
  119. package/dist/store/scopes/message.d.ts.map +1 -1
  120. package/dist/store/scopes/thread-list-item.d.ts +10 -0
  121. package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
  122. package/dist/store/scopes/thread.d.ts +17 -4
  123. package/dist/store/scopes/thread.d.ts.map +1 -1
  124. package/dist/store/scopes/threads.d.ts +3 -0
  125. package/dist/store/scopes/threads.d.ts.map +1 -1
  126. package/dist/subscribable/subscribable.d.ts +4 -4
  127. package/dist/subscribable/subscribable.d.ts.map +1 -1
  128. package/dist/subscribable/subscribable.js +4 -4
  129. package/dist/subscribable/subscribable.js.map +1 -1
  130. package/package.json +25 -13
  131. package/src/index.ts +12 -6
  132. package/src/react/index.ts +3 -0
  133. package/src/react/primitive-hooks/useThreadListLoadMore.ts +15 -0
  134. package/src/react/primitives/message/MessageGroupedParts.tsx +186 -0
  135. package/src/react/primitives/message/MessageParts.tsx +80 -55
  136. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +7 -6
  137. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +96 -43
  138. package/src/react/utils/groupParts.ts +152 -0
  139. package/src/runtime/api/assistant-runtime.ts +0 -62
  140. package/src/runtime/api/bindings.ts +1 -6
  141. package/src/runtime/api/composer-runtime.ts +10 -9
  142. package/src/runtime/api/message-runtime.ts +1 -8
  143. package/src/runtime/api/thread-list-item-runtime.ts +28 -6
  144. package/src/runtime/api/thread-list-runtime.ts +10 -0
  145. package/src/runtime/api/thread-runtime.ts +12 -53
  146. package/src/runtime/base/base-composer-runtime-core.ts +85 -42
  147. package/src/runtime/base/base-thread-runtime-core.ts +21 -13
  148. package/src/runtime/interfaces/composer-runtime-core.ts +39 -7
  149. package/src/runtime/interfaces/thread-list-runtime-core.ts +3 -0
  150. package/src/runtime/interfaces/thread-runtime-core.ts +42 -9
  151. package/src/runtime/utils/chat-model-adapter.ts +0 -5
  152. package/src/runtime/utils/external-store-message.ts +0 -8
  153. package/src/runtimes/assistant-transport/utils.ts +0 -28
  154. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +2 -6
  155. package/src/runtimes/local/local-thread-runtime-core.ts +2 -7
  156. package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +0 -4
  157. package/src/runtimes/remote-thread-list/empty-thread-core.ts +0 -4
  158. package/src/runtimes/remote-thread-list/remote-thread-state.ts +54 -1
  159. package/src/runtimes/remote-thread-list/types.ts +6 -1
  160. package/src/store/clients/thread-message-client.ts +0 -1
  161. package/src/store/runtime-clients/composer-runtime-client.ts +5 -9
  162. package/src/store/runtime-clients/thread-list-runtime-client.ts +3 -0
  163. package/src/store/runtime-clients/thread-runtime-client.ts +0 -1
  164. package/src/store/scopes/composer.ts +11 -0
  165. package/src/store/scopes/message.ts +1 -6
  166. package/src/store/scopes/thread-list-item.ts +10 -0
  167. package/src/store/scopes/thread.ts +17 -5
  168. package/src/store/scopes/threads.ts +3 -0
  169. package/src/subscribable/subscribable.ts +10 -7
  170. package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +448 -0
  171. package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +6 -1
  172. package/src/tests/base-composer-runtime-core-addAttachment.test.ts +63 -0
  173. package/src/tests/groupParts.test.ts +114 -0
@@ -4,6 +4,7 @@ import type {
4
4
  ThreadRuntimeCore,
5
5
  SpeechState,
6
6
  VoiceSessionState,
7
+ ThreadRuntimeEventCallback,
7
8
  ThreadRuntimeEventType,
8
9
  StartRunConfig,
9
10
  ResumeRunConfig,
@@ -251,10 +252,6 @@ export type ThreadRuntime = {
251
252
  */
252
253
  append(message: CreateAppendMessage): void;
253
254
 
254
- /**
255
- * @deprecated pass an object with `parentId` instead. This will be removed in 0.12.0.
256
- */
257
- startRun(parentId: string | null): void;
258
255
  /**
259
256
  * Start a new run with the given configuration.
260
257
  * @param config The configuration for starting the run
@@ -267,11 +264,6 @@ export type ThreadRuntime = {
267
264
  **/
268
265
  resumeRun(config: CreateResumeRunConfig): void;
269
266
 
270
- /**
271
- * @deprecated Use `resumeRun` instead.
272
- */
273
- unstable_resumeRun(config: CreateResumeRunConfig): void;
274
-
275
267
  /**
276
268
  * Export the thread state in the external store format.
277
269
  * For AI SDK runtimes, this returns the AI SDK message format.
@@ -288,22 +280,10 @@ export type ThreadRuntime = {
288
280
  */
289
281
  importExternalState(state: any): void;
290
282
 
291
- /**
292
- * Load external state into the thread.
293
- * @deprecated Use importExternalState instead. This method will be removed in 0.12.0.
294
- * @param state The state to load into the thread
295
- */
296
- unstable_loadExternalState(state: any): void;
297
-
298
283
  subscribe(callback: () => void): Unsubscribe;
299
284
  cancelRun(): void;
300
285
  getModelContext(): ModelContext;
301
286
 
302
- /**
303
- * @deprecated This method was renamed to `getModelContext`.
304
- */
305
- getModelConfig(): ModelContext;
306
-
307
287
  export(): ExportedMessageRepository;
308
288
  import(repository: ExportedMessageRepository): void;
309
289
 
@@ -329,7 +309,10 @@ export type ThreadRuntime = {
329
309
  muteVoice(): void;
330
310
  unmuteVoice(): void;
331
311
 
332
- unstable_on(event: ThreadRuntimeEventType, callback: () => void): Unsubscribe;
312
+ unstable_on<E extends ThreadRuntimeEventType>(
313
+ event: E,
314
+ callback: ThreadRuntimeEventCallback<E>,
315
+ ): Unsubscribe;
333
316
  };
334
317
 
335
318
  export class ThreadRuntimeImpl implements ThreadRuntime {
@@ -392,9 +375,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
392
375
  protected __internal_bindMethods() {
393
376
  this.append = this.append.bind(this);
394
377
  this.resumeRun = this.resumeRun.bind(this);
395
- this.unstable_resumeRun = this.unstable_resumeRun.bind(this);
396
- this.unstable_loadExternalState =
397
- this.unstable_loadExternalState.bind(this);
398
378
  this.importExternalState = this.importExternalState.bind(this);
399
379
  this.exportExternalState = this.exportExternalState.bind(this);
400
380
  this.startRun = this.startRun.bind(this);
@@ -414,7 +394,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
414
394
  this.subscribe = this.subscribe.bind(this);
415
395
  this.unstable_on = this.unstable_on.bind(this);
416
396
  this.getModelContext = this.getModelContext.bind(this);
417
- this.getModelConfig = this.getModelConfig.bind(this);
418
397
  this.getState = this.getState.bind(this);
419
398
  }
420
399
 
@@ -440,15 +419,7 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
440
419
  return this._threadBinding.getState().getModelContext();
441
420
  }
442
421
 
443
- public getModelConfig() {
444
- return this.getModelContext();
445
- }
446
-
447
- public startRun(configOrParentId: string | null | CreateStartRunConfig) {
448
- const config =
449
- configOrParentId === null || typeof configOrParentId === "string"
450
- ? { parentId: configOrParentId }
451
- : configOrParentId;
422
+ public startRun(config: CreateStartRunConfig) {
452
423
  return this._threadBinding.getState().startRun(toStartRunConfig(config));
453
424
  }
454
425
 
@@ -456,11 +427,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
456
427
  return this._threadBinding.getState().resumeRun(toResumeRunConfig(config));
457
428
  }
458
429
 
459
- /** @deprecated Use `resumeRun` instead. */
460
- public unstable_resumeRun(config: CreateResumeRunConfig) {
461
- return this.resumeRun(config);
462
- }
463
-
464
430
  public exportExternalState() {
465
431
  return this._threadBinding.getState().exportExternalState();
466
432
  }
@@ -469,10 +435,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
469
435
  this._threadBinding.getState().importExternalState(state);
470
436
  }
471
437
 
472
- public unstable_loadExternalState(state: any) {
473
- this._threadBinding.getState().unstable_loadExternalState(state);
474
- }
475
-
476
438
  public cancelRun() {
477
439
  this._threadBinding.getState().cancelRun();
478
440
  }
@@ -571,7 +533,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
571
533
  const thread = this._threadBinding.getState();
572
534
 
573
535
  const branches = thread.getBranches(message.id);
574
- const submittedFeedback = message.metadata.submittedFeedback;
575
536
 
576
537
  return {
577
538
  ...message,
@@ -586,8 +547,6 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
586
547
 
587
548
  speech:
588
549
  speechState?.messageId === message.id ? speechState : undefined,
589
-
590
- submittedFeedback,
591
550
  } satisfies MessageState;
592
551
  },
593
552
  subscribe: (callback) => this._threadBinding.subscribe(callback),
@@ -601,18 +560,18 @@ export class ThreadRuntimeImpl implements ThreadRuntime {
601
560
  EventSubscriptionSubject<ThreadRuntimeEventType>
602
561
  >();
603
562
 
604
- public unstable_on(
605
- event: ThreadRuntimeEventType,
606
- callback: () => void,
563
+ public unstable_on<E extends ThreadRuntimeEventType>(
564
+ event: E,
565
+ callback: ThreadRuntimeEventCallback<E>,
607
566
  ): Unsubscribe {
608
567
  let subject = this._eventSubscriptionSubjects.get(event);
609
568
  if (!subject) {
610
- subject = new EventSubscriptionSubject({
611
- event: event,
569
+ subject = new EventSubscriptionSubject<ThreadRuntimeEventType>({
570
+ event,
612
571
  binding: this._threadBinding,
613
572
  });
614
573
  this._eventSubscriptionSubjects.set(event, subject);
615
574
  }
616
- return subject.subscribe(callback);
575
+ return subject.subscribe(callback as (payload?: unknown) => void);
617
576
  }
618
577
  }
@@ -14,7 +14,10 @@ import {
14
14
  fileMatchesAccept,
15
15
  } from "../../adapters/attachment";
16
16
  import type {
17
+ AttachmentAddErrorReason,
17
18
  ComposerRuntimeCore,
19
+ ComposerRuntimeEventCallback,
20
+ ComposerRuntimeEventPayload,
18
21
  ComposerRuntimeEventType,
19
22
  DictationState,
20
23
  SendOptions,
@@ -189,7 +192,7 @@ export abstract class BaseComposerRuntimeCore
189
192
  };
190
193
 
191
194
  this.handleSend(message, options);
192
- this._notifyEventSubscribers("send");
195
+ this._notifyEventSubscribers("send", {});
193
196
  }
194
197
 
195
198
  public cancel() {
@@ -215,14 +218,15 @@ export abstract class BaseComposerRuntimeCore
215
218
  adapter.accept,
216
219
  )
217
220
  ) {
218
- try {
219
- this._notifyEventSubscribers("attachmentAddError");
220
- } catch {
221
- // prevent subscriber errors from masking the original error
222
- }
223
- throw new Error(
224
- `File type ${fileOrAttachment.contentType || "unknown"} is not accepted. Accepted types: ${adapter.accept}`,
221
+ const message = `File type ${fileOrAttachment.contentType || "unknown"} is not accepted. Accepted types: ${adapter.accept}`;
222
+ const err = new Error(message);
223
+ this._safeEmitAttachmentAddError(
224
+ "not-accepted",
225
+ message,
226
+ undefined,
227
+ err,
225
228
  );
229
+ throw err;
226
230
  }
227
231
 
228
232
  const a: CompleteAttachment = {
@@ -235,7 +239,7 @@ export abstract class BaseComposerRuntimeCore
235
239
  };
236
240
  this._attachments = [...this._attachments, a];
237
241
  this._notifySubscribers();
238
- this._notifyEventSubscribers("attachmentAdd");
242
+ this._notifyEventSubscribers("attachmentAdd", {});
239
243
  return;
240
244
  }
241
245
 
@@ -256,22 +260,28 @@ export abstract class BaseComposerRuntimeCore
256
260
  this._notifySubscribers();
257
261
  };
258
262
 
259
- let lastAttachment: PendingAttachment | undefined;
260
- try {
261
- const adapter = this.getAttachmentAdapter();
262
- if (!adapter) throw new Error("Attachments are not supported");
263
+ const adapter = this.getAttachmentAdapter();
264
+ if (!adapter) {
265
+ const message = "Attachments are not supported";
266
+ const err = new Error(message);
267
+ this._safeEmitAttachmentAddError("no-adapter", message, undefined, err);
268
+ throw err;
269
+ }
263
270
 
264
- if (
265
- !fileMatchesAccept(
266
- { name: fileOrAttachment.name, type: fileOrAttachment.type },
267
- adapter.accept,
268
- )
269
- ) {
270
- throw new Error(
271
- `File type ${fileOrAttachment.type || "unknown"} is not accepted. Accepted types: ${adapter.accept}`,
272
- );
273
- }
271
+ if (
272
+ !fileMatchesAccept(
273
+ { name: fileOrAttachment.name, type: fileOrAttachment.type },
274
+ adapter.accept,
275
+ )
276
+ ) {
277
+ const message = `File type ${fileOrAttachment.type || "unknown"} is not accepted. Accepted types: ${adapter.accept}`;
278
+ const err = new Error(message);
279
+ this._safeEmitAttachmentAddError("not-accepted", message, undefined, err);
280
+ throw err;
281
+ }
274
282
 
283
+ let lastAttachment: PendingAttachment | undefined;
284
+ try {
275
285
  const promiseOrGenerator = adapter.add({ file: fileOrAttachment });
276
286
  if (Symbol.asyncIterator in promiseOrGenerator) {
277
287
  for await (const r of promiseOrGenerator) {
@@ -289,20 +299,48 @@ export abstract class BaseComposerRuntimeCore
289
299
  status: { type: "incomplete", reason: "error" },
290
300
  });
291
301
  }
292
- try {
293
- this._notifyEventSubscribers("attachmentAddError");
294
- } catch {
295
- // prevent subscriber errors from masking the original error
296
- }
302
+ this._safeEmitAttachmentAddError(
303
+ "adapter-error",
304
+ e instanceof Error ? e.message : String(e),
305
+ lastAttachment?.id,
306
+ e instanceof Error ? e : undefined,
307
+ );
297
308
  throw e;
298
309
  }
299
310
 
300
311
  const hasError =
301
312
  lastAttachment?.status.type === "incomplete" &&
302
313
  lastAttachment.status.reason === "error";
303
- this._notifyEventSubscribers(
304
- hasError ? "attachmentAddError" : "attachmentAdd",
305
- );
314
+ if (hasError) {
315
+ this._safeEmitAttachmentAddError(
316
+ "adapter-error",
317
+ "Attachment upload did not complete successfully.",
318
+ lastAttachment?.id,
319
+ );
320
+ } else {
321
+ this._notifyEventSubscribers("attachmentAdd", {});
322
+ }
323
+ }
324
+
325
+ private _safeEmitAttachmentAddError(
326
+ reason: AttachmentAddErrorReason,
327
+ message: string,
328
+ attachmentId?: string,
329
+ error?: Error,
330
+ ) {
331
+ try {
332
+ this._notifyEventSubscribers("attachmentAddError", {
333
+ reason,
334
+ message,
335
+ ...(attachmentId !== undefined && { attachmentId }),
336
+ ...(error !== undefined && { error }),
337
+ });
338
+ } catch (subscriberError) {
339
+ console.error(
340
+ "[assistant-ui] attachmentAddError subscriber threw:",
341
+ subscriberError,
342
+ );
343
+ }
306
344
  }
307
345
 
308
346
  async removeAttachment(attachmentId: string) {
@@ -471,28 +509,33 @@ export abstract class BaseComposerRuntimeCore
471
509
 
472
510
  private _eventSubscribers = new Map<
473
511
  ComposerRuntimeEventType,
474
- Set<() => void>
512
+ Set<(payload?: unknown) => void>
475
513
  >();
476
514
 
477
- protected _notifyEventSubscribers(event: ComposerRuntimeEventType) {
515
+ protected _notifyEventSubscribers<E extends ComposerRuntimeEventType>(
516
+ event: E,
517
+ payload: ComposerRuntimeEventPayload[E],
518
+ ) {
478
519
  const subscribers = this._eventSubscribers.get(event);
479
520
  if (!subscribers) return;
480
521
 
481
- for (const callback of subscribers) callback();
522
+ for (const callback of subscribers) callback(payload);
482
523
  }
483
524
 
484
- public unstable_on(event: ComposerRuntimeEventType, callback: () => void) {
485
- const subscribers = this._eventSubscribers.get(event);
525
+ public unstable_on<E extends ComposerRuntimeEventType>(
526
+ event: E,
527
+ callback: ComposerRuntimeEventCallback<E>,
528
+ ) {
529
+ const wrapped = callback as (payload?: unknown) => void;
530
+ let subscribers = this._eventSubscribers.get(event);
486
531
  if (!subscribers) {
487
- this._eventSubscribers.set(event, new Set([callback]));
488
- } else {
489
- subscribers.add(callback);
532
+ subscribers = new Set();
533
+ this._eventSubscribers.set(event, subscribers);
490
534
  }
535
+ subscribers.add(wrapped);
491
536
 
492
537
  return () => {
493
- const subscribers = this._eventSubscribers.get(event);
494
- if (!subscribers) return;
495
- subscribers.delete(callback);
538
+ this._eventSubscribers.get(event)?.delete(wrapped);
496
539
  };
497
540
  }
498
541
  }
@@ -21,6 +21,8 @@ import type {
21
21
  SpeechState,
22
22
  VoiceSessionState,
23
23
  RuntimeCapabilities,
24
+ ThreadRuntimeEventCallback,
25
+ ThreadRuntimeEventPayload,
24
26
  ThreadRuntimeEventType,
25
27
  StartRunConfig,
26
28
  ResumeRunConfig,
@@ -59,7 +61,6 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
59
61
  public abstract cancelRun(): void;
60
62
  public abstract exportExternalState(): any;
61
63
  public abstract importExternalState(state: any): void;
62
- public abstract unstable_loadExternalState(state: any): void;
63
64
 
64
65
  protected _voiceMessages: ThreadMessage[] = [];
65
66
  protected _voiceGeneration = 0;
@@ -168,11 +169,14 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
168
169
  for (const callback of this._subscriptions) callback();
169
170
  }
170
171
 
171
- public _notifyEventSubscribers(event: ThreadRuntimeEventType) {
172
+ public _notifyEventSubscribers<E extends ThreadRuntimeEventType>(
173
+ event: E,
174
+ payload: ThreadRuntimeEventPayload[E],
175
+ ) {
172
176
  const subscribers = this._eventSubscribers.get(event);
173
177
  if (!subscribers) return;
174
178
 
175
- for (const callback of subscribers) callback();
179
+ for (const callback of subscribers) callback(payload);
176
180
  }
177
181
 
178
182
  public subscribe(callback: () => void): Unsubscribe {
@@ -432,7 +436,7 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
432
436
  protected ensureInitialized() {
433
437
  if (!this._isInitialized) {
434
438
  this._isInitialized = true;
435
- this._notifyEventSubscribers("initialize");
439
+ this._notifyEventSubscribers("initialize", {});
436
440
  }
437
441
  }
438
442
 
@@ -453,24 +457,28 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
453
457
 
454
458
  private _eventSubscribers = new Map<
455
459
  ThreadRuntimeEventType,
456
- Set<() => void>
460
+ Set<(payload?: unknown) => void>
457
461
  >();
458
462
 
459
- public unstable_on(event: ThreadRuntimeEventType, callback: () => void) {
463
+ public unstable_on<E extends ThreadRuntimeEventType>(
464
+ event: E,
465
+ callback: ThreadRuntimeEventCallback<E>,
466
+ ) {
467
+ const wrapped = callback as (payload?: unknown) => void;
460
468
  if (event === "modelContextUpdate") {
461
- return this._contextProvider.subscribe?.(callback) ?? (() => {});
469
+ // provider.subscribe is `() => void`; pump the typed empty payload to the user callback.
470
+ return this._contextProvider.subscribe?.(() => wrapped({})) ?? (() => {});
462
471
  }
463
472
 
464
- const subscribers = this._eventSubscribers.get(event);
473
+ let subscribers = this._eventSubscribers.get(event);
465
474
  if (!subscribers) {
466
- this._eventSubscribers.set(event, new Set([callback]));
467
- } else {
468
- subscribers.add(callback);
475
+ subscribers = new Set();
476
+ this._eventSubscribers.set(event, subscribers);
469
477
  }
478
+ subscribers.add(wrapped);
470
479
 
471
480
  return () => {
472
- const subscribers = this._eventSubscribers.get(event)!;
473
- subscribers.delete(callback);
481
+ this._eventSubscribers.get(event)?.delete(wrapped);
474
482
  };
475
483
  }
476
484
  }
@@ -5,10 +5,37 @@ import type { Unsubscribe } from "../../types/unsubscribe";
5
5
  import type { RunConfig } from "../../types/message";
6
6
  import type { DictationAdapter } from "../../adapters/speech";
7
7
 
8
- export type ComposerRuntimeEventType =
9
- | "send"
10
- | "attachmentAdd"
11
- | "attachmentAddError";
8
+ export type AttachmentAddErrorReason =
9
+ | "no-adapter"
10
+ | "not-accepted"
11
+ | "adapter-error";
12
+
13
+ export type AttachmentAddErrorEvent = {
14
+ readonly reason: AttachmentAddErrorReason;
15
+ readonly message: string;
16
+ readonly attachmentId?: string;
17
+ readonly error?: Error;
18
+ };
19
+
20
+ export type ComposerRuntimeEventPayload = {
21
+ /**
22
+ * @deprecated State-derivable. Observe `state.text` clearing via
23
+ * `subscribe` + `getState` instead. Kept for backward compatibility.
24
+ */
25
+ send: Record<string, never>;
26
+ /**
27
+ * @deprecated State-derivable. Observe `state.attachments` via `subscribe` +
28
+ * `getState` instead. Kept for backward compatibility.
29
+ */
30
+ attachmentAdd: Record<string, never>;
31
+ attachmentAddError: AttachmentAddErrorEvent;
32
+ };
33
+
34
+ export type ComposerRuntimeEventType = keyof ComposerRuntimeEventPayload;
35
+
36
+ export type ComposerRuntimeEventCallback<E extends ComposerRuntimeEventType> = (
37
+ payload: ComposerRuntimeEventPayload[E],
38
+ ) => void;
12
39
 
13
40
  export type DictationState = {
14
41
  readonly status: DictationAdapter.Status;
@@ -56,9 +83,14 @@ export type ComposerRuntimeCore = Readonly<{
56
83
 
57
84
  subscribe: (callback: () => void) => Unsubscribe;
58
85
 
59
- unstable_on: (
60
- event: ComposerRuntimeEventType,
61
- callback: () => void,
86
+ /**
87
+ * @deprecated This API is still under active development and might change without notice.
88
+ * For state-derivable transitions, prefer `subscribe` + `getState`. This channel is the
89
+ * escape hatch for transient occurrences not represented in state.
90
+ */
91
+ unstable_on: <E extends ComposerRuntimeEventType>(
92
+ event: E,
93
+ callback: ComposerRuntimeEventCallback<E>,
62
94
  ) => Unsubscribe;
63
95
  }>;
64
96
 
@@ -17,6 +17,8 @@ export type ThreadListItemCoreState = {
17
17
 
18
18
  export type ThreadListRuntimeCore = {
19
19
  readonly isLoading: boolean;
20
+ readonly isLoadingMore?: boolean;
21
+ readonly hasMore?: boolean;
20
22
  mainThreadId: string;
21
23
  newThreadId: string | undefined;
22
24
 
@@ -35,6 +37,7 @@ export type ThreadListRuntimeCore = {
35
37
 
36
38
  getLoadThreadsPromise(): Promise<void>;
37
39
  reload?(): Promise<void>;
40
+ loadMore?(): Promise<void>;
38
41
 
39
42
  detach(threadId: string): Promise<void>;
40
43
  rename(threadId: string, newTitle: string): Promise<void>;
@@ -69,11 +69,41 @@ export type SubmittedFeedback = {
69
69
  readonly type: "negative" | "positive";
70
70
  };
71
71
 
72
- export type ThreadRuntimeEventType =
73
- | "runStart"
74
- | "runEnd"
75
- | "initialize"
76
- | "modelContextUpdate";
72
+ export type ThreadRuntimeEventPayload = {
73
+ /**
74
+ * @deprecated State-derivable. Observe `state.isRunning` flipping to `true`
75
+ * via `subscribe` + `getState` instead. Note: this event fires at the
76
+ * transition point and may run before the next subscriber notification.
77
+ * Kept for backward compatibility.
78
+ */
79
+ runStart: Record<string, never>;
80
+ /**
81
+ * @deprecated State-derivable. Observe `state.isRunning` flipping to `false`
82
+ * via `subscribe` + `getState` instead. Note: this event fires at the
83
+ * transition point and may run before the next subscriber notification.
84
+ * Kept for backward compatibility.
85
+ */
86
+ runEnd: Record<string, never>;
87
+ /**
88
+ * @deprecated State-derivable. This event fires at the initialization
89
+ * transition immediately BEFORE the first message is added, so reading state
90
+ * inside the handler still sees an empty thread; observe `state.messages`
91
+ * becoming non-empty via a regular `subscribe` callback instead. Kept for
92
+ * backward compatibility.
93
+ */
94
+ initialize: Record<string, never>;
95
+ /**
96
+ * Truly transient. The model context lives in a provider, not in thread
97
+ * state, so this event has no state-derivable equivalent.
98
+ */
99
+ modelContextUpdate: Record<string, never>;
100
+ };
101
+
102
+ export type ThreadRuntimeEventType = keyof ThreadRuntimeEventPayload;
103
+
104
+ export type ThreadRuntimeEventCallback<E extends ThreadRuntimeEventType> = (
105
+ payload: ThreadRuntimeEventPayload[E],
106
+ ) => void;
77
107
 
78
108
  export type StartRunConfig = {
79
109
  parentId: string | null;
@@ -155,10 +185,13 @@ export type ThreadRuntimeCore = Readonly<{
155
185
 
156
186
  reset(initialMessages?: readonly ThreadMessageLike[]): void;
157
187
 
158
- unstable_on(event: ThreadRuntimeEventType, callback: () => void): Unsubscribe;
159
-
160
188
  /**
161
- * @deprecated Use importExternalState instead. This method will be removed in 0.12.0.
189
+ * @deprecated This API is still under active development and might change without notice.
190
+ * For state-derivable transitions, prefer `subscribe` + `getState`. This channel is the
191
+ * escape hatch for transient occurrences not represented in state.
162
192
  */
163
- unstable_loadExternalState: (state: any) => void;
193
+ unstable_on<E extends ThreadRuntimeEventType>(
194
+ event: E,
195
+ callback: ThreadRuntimeEventCallback<E>,
196
+ ): Unsubscribe;
164
197
  }>;
@@ -50,11 +50,6 @@ export type ChatModelRunOptions = {
50
50
  readonly abortSignal: AbortSignal;
51
51
  readonly context: ModelContext;
52
52
 
53
- /**
54
- * @deprecated This field was renamed to `context`.
55
- */
56
- readonly config: ModelContext;
57
-
58
53
  readonly unstable_assistantMessageId?: string | undefined;
59
54
  readonly unstable_threadId?: string | undefined;
60
55
  readonly unstable_parentId?: string | null | undefined;
@@ -8,14 +8,6 @@ type WithInnerMessages<T> = {
8
8
  [symbolInnerMessages]?: T[];
9
9
  };
10
10
 
11
- /**
12
- * @deprecated Use `getExternalStoreMessages` (plural) instead. This function will be removed in 0.12.0.
13
- */
14
- export const getExternalStoreMessage = <T>(input: ThreadMessage) => {
15
- const withInnerMessages = input as WithInnerMessages<T>;
16
- return withInnerMessages[symbolInnerMessage];
17
- };
18
-
19
11
  const EMPTY_ARRAY: never[] = [];
20
12
 
21
13
  /**
@@ -1,31 +1,3 @@
1
- import {
2
- type Tool,
3
- toToolsJSONSchema,
4
- type ToolJSONSchema,
5
- } from "assistant-stream";
6
-
7
- /**
8
- * @deprecated Use `toToolsJSONSchema` from `assistant-stream` instead.
9
- */
10
- export function toAISDKTools(
11
- tools: Record<string, Tool>,
12
- ): Record<string, ToolJSONSchema> {
13
- return toToolsJSONSchema(tools, { filter: () => true });
14
- }
15
-
16
- /**
17
- * @deprecated Use `toToolsJSONSchema` from `assistant-stream` instead, which includes filtering by default.
18
- */
19
- export function getEnabledTools(
20
- tools: Record<string, Tool>,
21
- ): Record<string, Tool> {
22
- return Object.fromEntries(
23
- Object.entries(tools).filter(
24
- ([, tool]) => !tool.disabled && tool.type !== "backend",
25
- ),
26
- );
27
- }
28
-
29
1
  export async function createRequestHeaders(
30
2
  headersValue:
31
3
  | Record<string, string>
@@ -236,9 +236,9 @@ export class ExternalStoreThreadRuntimeCore
236
236
 
237
237
  if ((oldStore?.isRunning ?? false) !== (store.isRunning ?? false)) {
238
238
  if (store.isRunning) {
239
- this._notifyEventSubscribers("runStart");
239
+ this._notifyEventSubscribers("runStart", {});
240
240
  } else {
241
- this._notifyEventSubscribers("runEnd");
241
+ this._notifyEventSubscribers("runEnd", {});
242
242
  }
243
243
  }
244
244
 
@@ -316,10 +316,6 @@ export class ExternalStoreThreadRuntimeCore
316
316
  this._store.onLoadExternalState(state);
317
317
  }
318
318
 
319
- public unstable_loadExternalState(state: any): void {
320
- this.importExternalState(state);
321
- }
322
-
323
319
  public cancelRun(): void {
324
320
  if (!this._store.onCancel)
325
321
  throw new Error("Runtime does not support cancelling runs.");