@assistant-ui/react 0.8.15 → 0.8.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 (70) hide show
  1. package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.js +2 -2
  2. package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.js.map +1 -1
  3. package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.mjs +1 -1
  4. package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.mjs.map +1 -1
  5. package/dist/runtimes/edge/{EdgeChatAdapter.d.ts → EdgeModelAdapter.d.ts} +4 -4
  6. package/dist/runtimes/edge/EdgeModelAdapter.d.ts.map +1 -0
  7. package/dist/runtimes/edge/{EdgeChatAdapter.js → EdgeModelAdapter.js} +8 -8
  8. package/dist/runtimes/edge/EdgeModelAdapter.js.map +1 -0
  9. package/dist/runtimes/edge/{EdgeChatAdapter.mjs → EdgeModelAdapter.mjs} +4 -4
  10. package/dist/runtimes/edge/EdgeModelAdapter.mjs.map +1 -0
  11. package/dist/runtimes/edge/converters/toLanguageModelMessages.d.ts.map +1 -1
  12. package/dist/runtimes/edge/converters/toLanguageModelMessages.js +1 -0
  13. package/dist/runtimes/edge/converters/toLanguageModelMessages.js.map +1 -1
  14. package/dist/runtimes/edge/converters/toLanguageModelMessages.mjs +1 -0
  15. package/dist/runtimes/edge/converters/toLanguageModelMessages.mjs.map +1 -1
  16. package/dist/runtimes/edge/index.d.ts +2 -1
  17. package/dist/runtimes/edge/index.d.ts.map +1 -1
  18. package/dist/runtimes/edge/index.js +5 -2
  19. package/dist/runtimes/edge/index.js.map +1 -1
  20. package/dist/runtimes/edge/index.mjs +4 -2
  21. package/dist/runtimes/edge/index.mjs.map +1 -1
  22. package/dist/runtimes/edge/streams/toolResultStream.d.ts +2 -1
  23. package/dist/runtimes/edge/streams/toolResultStream.d.ts.map +1 -1
  24. package/dist/runtimes/edge/streams/toolResultStream.js +60 -21
  25. package/dist/runtimes/edge/streams/toolResultStream.js.map +1 -1
  26. package/dist/runtimes/edge/streams/toolResultStream.mjs +58 -20
  27. package/dist/runtimes/edge/streams/toolResultStream.mjs.map +1 -1
  28. package/dist/runtimes/edge/useEdgeRuntime.d.ts +2 -2
  29. package/dist/runtimes/edge/useEdgeRuntime.d.ts.map +1 -1
  30. package/dist/runtimes/edge/useEdgeRuntime.js +2 -2
  31. package/dist/runtimes/edge/useEdgeRuntime.js.map +1 -1
  32. package/dist/runtimes/edge/useEdgeRuntime.mjs +2 -2
  33. package/dist/runtimes/edge/useEdgeRuntime.mjs.map +1 -1
  34. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.d.ts.map +1 -1
  35. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js +3 -0
  36. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js.map +1 -1
  37. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs +3 -0
  38. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs.map +1 -1
  39. package/dist/runtimes/utils/MessageRepository.d.ts +112 -0
  40. package/dist/runtimes/utils/MessageRepository.d.ts.map +1 -1
  41. package/dist/runtimes/utils/MessageRepository.js +103 -1
  42. package/dist/runtimes/utils/MessageRepository.js.map +1 -1
  43. package/dist/runtimes/utils/MessageRepository.mjs +103 -1
  44. package/dist/runtimes/utils/MessageRepository.mjs.map +1 -1
  45. package/dist/tests/MessageRepository.test.d.ts +2 -0
  46. package/dist/tests/MessageRepository.test.d.ts.map +1 -0
  47. package/dist/tests/setup.d.ts +2 -0
  48. package/dist/tests/setup.d.ts.map +1 -0
  49. package/dist/tests/setup.js +2656 -0
  50. package/dist/tests/setup.js.map +1 -0
  51. package/dist/tests/setup.mjs +2632 -0
  52. package/dist/tests/setup.mjs.map +1 -0
  53. package/dist/types/AssistantTypes.d.ts +1 -1
  54. package/dist/types/AssistantTypes.d.ts.map +1 -1
  55. package/dist/types/AssistantTypes.js.map +1 -1
  56. package/package.json +10 -4
  57. package/src/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.ts +1 -1
  58. package/src/runtimes/edge/{EdgeChatAdapter.ts → EdgeModelAdapter.ts} +3 -3
  59. package/src/runtimes/edge/converters/toLanguageModelMessages.ts +3 -1
  60. package/src/runtimes/edge/index.ts +3 -1
  61. package/src/runtimes/edge/streams/toolResultStream.ts +76 -27
  62. package/src/runtimes/edge/useEdgeRuntime.ts +3 -3
  63. package/src/runtimes/remote-thread-list/EMPTY_THREAD_CORE.tsx +4 -0
  64. package/src/runtimes/utils/MessageRepository.tsx +142 -1
  65. package/src/tests/MessageRepository.test.ts +690 -0
  66. package/src/tests/setup.ts +11 -0
  67. package/src/types/AssistantTypes.ts +1 -1
  68. package/dist/runtimes/edge/EdgeChatAdapter.d.ts.map +0 -1
  69. package/dist/runtimes/edge/EdgeChatAdapter.js.map +0 -1
  70. package/dist/runtimes/edge/EdgeChatAdapter.mjs.map +0 -1
@@ -37,7 +37,7 @@ export function asAsyncIterable<T>(
37
37
 
38
38
  type HeadersValue = Record<string, string> | Headers;
39
39
 
40
- export type EdgeChatAdapterOptions = {
40
+ export type EdgeModelAdapterOptions = {
41
41
  api: string;
42
42
 
43
43
  // experimental_prepareRequestBody?: (options: {
@@ -109,8 +109,8 @@ const toAISDKTools = (tools: Record<string, Tool<any, any>>) => {
109
109
  );
110
110
  };
111
111
 
112
- export class EdgeChatAdapter implements ChatModelAdapter {
113
- constructor(private options: EdgeChatAdapterOptions) {}
112
+ export class EdgeModelAdapter implements ChatModelAdapter {
113
+ constructor(private options: EdgeModelAdapterOptions) {}
114
114
 
115
115
  async *run({
116
116
  messages,
@@ -11,6 +11,7 @@ import {
11
11
  ThreadMessage,
12
12
  TextContentPart,
13
13
  CoreToolCallContentPart,
14
+ ToolCallContentPart,
14
15
  } from "../../../types/AssistantTypes";
15
16
 
16
17
  const assistantMessageSplitter = () => {
@@ -46,7 +47,7 @@ const assistantMessageSplitter = () => {
46
47
 
47
48
  assistantMessage.content.push(part);
48
49
  },
49
- addToolCallPart: (part: CoreToolCallContentPart) => {
50
+ addToolCallPart: (part: CoreToolCallContentPart | ToolCallContentPart) => {
50
51
  assistantMessage.content.push({
51
52
  type: "tool-call",
52
53
  toolCallId: part.toolCallId,
@@ -58,6 +59,7 @@ const assistantMessageSplitter = () => {
58
59
  type: "tool-result",
59
60
  toolCallId: part.toolCallId,
60
61
  toolName: part.toolName,
62
+ ...("artifact" in part ? { artifact: part.artifact } : {}),
61
63
  result:
62
64
  part.result === undefined
63
65
  ? "Error: tool is has no configured code to run"
@@ -1,5 +1,7 @@
1
1
  export * from "./converters";
2
2
 
3
3
  export { useEdgeRuntime, type EdgeRuntimeOptions } from "./useEdgeRuntime";
4
- export { EdgeChatAdapter } from "./EdgeChatAdapter";
4
+ export { EdgeModelAdapter as EdgeChatAdapter } from "./EdgeModelAdapter";
5
5
  export type { EdgeRuntimeRequestOptions } from "./EdgeRuntimeRequestOptions";
6
+
7
+ export { unstable_runPendingTools } from "./streams/toolResultStream";
@@ -1,39 +1,88 @@
1
1
  import { Tool } from "../../../model-context/ModelContextTypes";
2
2
  import { z } from "zod";
3
- import { ToolExecutionStream } from "assistant-stream";
3
+ import { AssistantMessage, ToolExecutionStream } from "assistant-stream";
4
+ import { ToolResponse } from "assistant-stream/core/effects/ToolResponse";
4
5
 
5
- export function toolResultStream(
6
+ function getToolResponse(
6
7
  tools: Record<string, Tool<any, any>> | undefined,
7
8
  abortSignal: AbortSignal,
9
+ toolCall: {
10
+ toolCallId: string;
11
+ toolName: string;
12
+ args: unknown;
13
+ },
8
14
  ) {
9
- return new ToolExecutionStream(({ toolCallId, toolName, args }) => {
10
- const tool = tools?.[toolName];
11
- if (!tool || !tool.execute) return undefined;
15
+ const tool = tools?.[toolCall.toolName];
16
+ if (!tool || !tool.execute) return undefined;
12
17
 
13
- let executeFn = tool.execute;
18
+ let executeFn = tool.execute;
14
19
 
15
- if (tool.parameters instanceof z.ZodType) {
16
- const result = tool.parameters.safeParse(args);
17
- if (!result.success) {
18
- executeFn =
19
- tool.experimental_onSchemaValidationError ??
20
- (() => {
21
- throw (
22
- "Function parameter validation failed. " +
23
- JSON.stringify(result.error.issues)
24
- );
25
- });
26
- }
20
+ if (tool.parameters instanceof z.ZodType) {
21
+ const result = tool.parameters.safeParse(toolCall.args);
22
+ if (!result.success) {
23
+ executeFn =
24
+ tool.experimental_onSchemaValidationError ??
25
+ (() => {
26
+ throw new Error(
27
+ `Function parameter validation failed. ${JSON.stringify(result.error.issues)}`,
28
+ );
29
+ });
27
30
  }
31
+ }
28
32
 
29
- const getResult = async () => {
30
- const result = await executeFn(args, {
31
- toolCallId,
32
- abortSignal,
33
- });
34
- return result === undefined ? "<no result>" : result;
35
- };
33
+ const getResult = async () => {
34
+ const result = await executeFn(toolCall.args, {
35
+ toolCallId: toolCall.toolCallId,
36
+ abortSignal,
37
+ });
38
+ if (result instanceof ToolResponse) return result;
39
+ return new ToolResponse({
40
+ result: result === undefined ? "<no result>" : result,
41
+ });
42
+ };
43
+
44
+ return getResult();
45
+ }
36
46
 
37
- return getResult();
38
- });
47
+ export async function unstable_runPendingTools(
48
+ message: AssistantMessage,
49
+ tools: Record<string, Tool<any, any>> | undefined,
50
+ abortSignal: AbortSignal,
51
+ ) {
52
+ // TODO parallel tool calling
53
+ for (const part of message.parts) {
54
+ if (part.type === "tool-call") {
55
+ const promiseOrUndefined = getToolResponse(tools, abortSignal, part);
56
+ if (promiseOrUndefined) {
57
+ const result = await promiseOrUndefined;
58
+ const updatedParts = message.parts.map((p) => {
59
+ if (p.type === "tool-call" && p.toolCallId === part.toolCallId) {
60
+ return {
61
+ ...p,
62
+ state: "result" as const,
63
+ artifact: result.artifact,
64
+ result: result.result,
65
+ isError: result.isError,
66
+ };
67
+ }
68
+ return p;
69
+ });
70
+ message = {
71
+ ...message,
72
+ parts: updatedParts,
73
+ content: updatedParts,
74
+ };
75
+ }
76
+ }
77
+ }
78
+ return message;
79
+ }
80
+
81
+ export function toolResultStream(
82
+ tools: Record<string, Tool<any, any>> | undefined,
83
+ abortSignal: AbortSignal,
84
+ ) {
85
+ return new ToolExecutionStream((toolCall) =>
86
+ getToolResponse(tools, abortSignal, toolCall),
87
+ );
39
88
  }
@@ -1,17 +1,17 @@
1
1
  "use client";
2
2
 
3
3
  import { LocalRuntimeOptions, useLocalRuntime } from "..";
4
- import { EdgeChatAdapterOptions, EdgeChatAdapter } from "./EdgeChatAdapter";
4
+ import { EdgeModelAdapterOptions, EdgeModelAdapter } from "./EdgeModelAdapter";
5
5
  import { splitLocalRuntimeOptions } from "../local/LocalRuntimeOptions";
6
6
 
7
- export type EdgeRuntimeOptions = EdgeChatAdapterOptions & LocalRuntimeOptions;
7
+ export type EdgeRuntimeOptions = EdgeModelAdapterOptions & LocalRuntimeOptions;
8
8
 
9
9
  export const useEdgeRuntime = (options: EdgeRuntimeOptions) => {
10
10
  const { localRuntimeOptions, otherOptions } =
11
11
  splitLocalRuntimeOptions(options);
12
12
 
13
13
  return useLocalRuntime(
14
- new EdgeChatAdapter(otherOptions),
14
+ new EdgeModelAdapter(otherOptions),
15
15
  localRuntimeOptions,
16
16
  );
17
17
  };
@@ -24,6 +24,10 @@ export const EMPTY_THREAD_CORE: ThreadRuntimeCore = {
24
24
  throw EMPTY_THREAD_ERROR;
25
25
  },
26
26
 
27
+ resumeRun() {
28
+ throw EMPTY_THREAD_ERROR;
29
+ },
30
+
27
31
  cancelRun() {
28
32
  throw EMPTY_THREAD_ERROR;
29
33
  },
@@ -5,31 +5,62 @@ import { ThreadMessageLike } from "../external-store";
5
5
  import { getAutoStatus } from "../external-store/auto-status";
6
6
  import { fromThreadMessageLike } from "../external-store/ThreadMessageLike";
7
7
 
8
+ /**
9
+ * Represents a parent node in the repository tree structure.
10
+ */
8
11
  type RepositoryParent = {
12
+ /** IDs of child messages */
9
13
  children: string[];
14
+ /** Reference to the next message in the active branch */
10
15
  next: RepositoryMessage | null;
11
16
  };
12
17
 
18
+ /**
19
+ * Represents a message node in the repository tree structure.
20
+ */
13
21
  type RepositoryMessage = RepositoryParent & {
22
+ /** Reference to the parent message */
14
23
  prev: RepositoryMessage | null;
24
+ /** The actual message data */
15
25
  current: ThreadMessage;
26
+ /** The depth level in the tree (0 for root messages) */
16
27
  level: number;
17
28
  };
18
29
 
30
+ /**
31
+ * Represents a message item that can be exported from the repository.
32
+ */
19
33
  export type ExportedMessageRepositoryItem = {
34
+ /** The message data */
20
35
  message: ThreadMessage;
36
+ /** ID of the parent message, or null for root messages */
21
37
  parentId: string | null;
22
38
  };
23
39
 
40
+ /**
41
+ * Represents the entire repository state for export/import.
42
+ */
24
43
  export type ExportedMessageRepository = {
44
+ /** ID of the head message, or null/undefined if no head */
25
45
  headId?: string | null;
46
+ /** Array of all messages with their parent references */
26
47
  messages: Array<{
27
48
  message: ThreadMessage;
28
49
  parentId: string | null;
29
50
  }>;
30
51
  };
31
52
 
53
+ /**
54
+ * Utility functions for working with exported message repositories.
55
+ */
32
56
  export const ExportedMessageRepository = {
57
+ /**
58
+ * Converts an array of messages to an ExportedMessageRepository format.
59
+ * Creates parent-child relationships based on the order of messages in the array.
60
+ *
61
+ * @param messages - Array of message-like objects to convert
62
+ * @returns ExportedMessageRepository with parent-child relationships established
63
+ */
33
64
  fromArray: (
34
65
  messages: readonly ThreadMessageLike[],
35
66
  ): ExportedMessageRepository => {
@@ -46,6 +77,12 @@ export const ExportedMessageRepository = {
46
77
  },
47
78
  };
48
79
 
80
+ /**
81
+ * Recursively finds the head (leaf) message in a branch.
82
+ *
83
+ * @param message - The starting message or parent node
84
+ * @returns The leaf message of the branch, or null if not found
85
+ */
49
86
  const findHead = (
50
87
  message: RepositoryMessage | RepositoryParent,
51
88
  ): RepositoryMessage | null => {
@@ -54,11 +91,20 @@ const findHead = (
54
91
  return null;
55
92
  };
56
93
 
94
+ /**
95
+ * A utility class for caching computed values and invalidating the cache when needed.
96
+ */
57
97
  class CachedValue<T> {
58
98
  private _value: T | null = null;
59
99
 
100
+ /**
101
+ * @param func - The function that computes the cached value
102
+ */
60
103
  constructor(private func: () => T) {}
61
104
 
105
+ /**
106
+ * Gets the cached value, computing it if necessary.
107
+ */
62
108
  get value() {
63
109
  if (this._value === null) {
64
110
  this._value = this.func();
@@ -66,19 +112,40 @@ class CachedValue<T> {
66
112
  return this._value;
67
113
  }
68
114
 
115
+ /**
116
+ * Invalidates the cache, forcing recomputation on next access.
117
+ */
69
118
  dirty() {
70
119
  this._value = null;
71
120
  }
72
121
  }
73
122
 
123
+ /**
124
+ * A repository that manages a tree of messages with branching capabilities.
125
+ * Supports operations like adding, updating, and deleting messages, as well as
126
+ * managing multiple conversation branches.
127
+ */
74
128
  export class MessageRepository {
75
- private messages = new Map<string, RepositoryMessage>(); // message_id -> item
129
+ /** Map of message IDs to repository message objects */
130
+ private messages = new Map<string, RepositoryMessage>();
131
+ /** Reference to the current head (most recent) message in the active branch */
76
132
  private head: RepositoryMessage | null = null;
133
+ /** Root node of the tree structure */
77
134
  private root: RepositoryParent = {
78
135
  children: [],
79
136
  next: null,
80
137
  };
81
138
 
139
+ /**
140
+ * Performs link/unlink operations between messages in the tree.
141
+ *
142
+ * @param newParent - The new parent message, or null
143
+ * @param child - The child message to operate on
144
+ * @param operation - The type of operation to perform:
145
+ * - "cut": Remove the child from its current parent
146
+ * - "link": Add the child to a new parent
147
+ * - "relink": Both cut and link operations
148
+ */
82
149
  private performOp(
83
150
  newParent: RepositoryMessage | null,
84
151
  child: RepositoryMessage,
@@ -139,6 +206,7 @@ export class MessageRepository {
139
206
  }
140
207
  }
141
208
 
209
+ /** Cached array of messages in the current active branch, from root to head */
142
210
  private _messages = new CachedValue<readonly ThreadMessage[]>(() => {
143
211
  const messages = new Array<ThreadMessage>(this.head?.level ?? 0);
144
212
  for (let current = this.head; current; current = current.prev) {
@@ -147,14 +215,31 @@ export class MessageRepository {
147
215
  return messages;
148
216
  });
149
217
 
218
+ /**
219
+ * Gets the ID of the current head message.
220
+ * @returns The ID of the head message, or null if no messages exist
221
+ */
150
222
  get headId() {
151
223
  return this.head?.current.id ?? null;
152
224
  }
153
225
 
226
+ /**
227
+ * Gets all messages in the current active branch, from root to head.
228
+ * @returns Array of messages in the current branch
229
+ */
154
230
  getMessages() {
155
231
  return this._messages.value;
156
232
  }
157
233
 
234
+ /**
235
+ * Adds a new message or updates an existing one in the repository.
236
+ * If the message ID already exists, the message is updated and potentially relinked to a new parent.
237
+ * If the message is new, it's added as a child of the specified parent.
238
+ *
239
+ * @param parentId - ID of the parent message, or null for root messages
240
+ * @param message - The message to add or update
241
+ * @throws Error if the parent message is not found
242
+ */
158
243
  addOrUpdateMessage(parentId: string | null, message: ThreadMessage) {
159
244
  const existingItem = this.messages.get(message.id);
160
245
  const prev = parentId ? this.messages.get(parentId) : null;
@@ -190,6 +275,13 @@ export class MessageRepository {
190
275
  this._messages.dirty();
191
276
  }
192
277
 
278
+ /**
279
+ * Gets a message and its parent ID by message ID.
280
+ *
281
+ * @param messageId - ID of the message to retrieve
282
+ * @returns Object containing the message and its parent ID
283
+ * @throws Error if the message is not found
284
+ */
193
285
  getMessage(messageId: string) {
194
286
  const message = this.messages.get(messageId);
195
287
  if (!message)
@@ -203,6 +295,14 @@ export class MessageRepository {
203
295
  };
204
296
  }
205
297
 
298
+ /**
299
+ * Adds an optimistic message to the repository.
300
+ * An optimistic message is a temporary placeholder that will be replaced by a real message later.
301
+ *
302
+ * @param parentId - ID of the parent message, or null for root messages
303
+ * @param message - The core message to convert to an optimistic message
304
+ * @returns The generated optimistic ID
305
+ */
206
306
  appendOptimisticMessage(parentId: string | null, message: CoreMessage) {
207
307
  let optimisticId: string;
208
308
  do {
@@ -220,6 +320,15 @@ export class MessageRepository {
220
320
  return optimisticId;
221
321
  }
222
322
 
323
+ /**
324
+ * Deletes a message from the repository and relinks its children.
325
+ *
326
+ * @param messageId - ID of the message to delete
327
+ * @param replacementId - Optional ID of the message to become the new parent of the children,
328
+ * undefined means use the deleted message's parent,
329
+ * null means use the root
330
+ * @throws Error if the message or replacement is not found
331
+ */
223
332
  deleteMessage(messageId: string, replacementId?: string | null | undefined) {
224
333
  const message = this.messages.get(messageId);
225
334
 
@@ -258,6 +367,13 @@ export class MessageRepository {
258
367
  this._messages.dirty();
259
368
  }
260
369
 
370
+ /**
371
+ * Gets all branch IDs (sibling messages) at the level of a specified message.
372
+ *
373
+ * @param messageId - ID of the message to find branches for
374
+ * @returns Array of message IDs representing branches
375
+ * @throws Error if the message is not found
376
+ */
261
377
  getBranches(messageId: string) {
262
378
  const message = this.messages.get(messageId);
263
379
  if (!message)
@@ -269,6 +385,12 @@ export class MessageRepository {
269
385
  return children;
270
386
  }
271
387
 
388
+ /**
389
+ * Switches the active branch to the one containing the specified message.
390
+ *
391
+ * @param messageId - ID of the message in the branch to switch to
392
+ * @throws Error if the branch is not found
393
+ */
272
394
  switchToBranch(messageId: string) {
273
395
  const message = this.messages.get(messageId);
274
396
  if (!message)
@@ -284,6 +406,12 @@ export class MessageRepository {
284
406
  this._messages.dirty();
285
407
  }
286
408
 
409
+ /**
410
+ * Resets the head to a specific message or null.
411
+ *
412
+ * @param messageId - ID of the message to set as head, or null to clear the head
413
+ * @throws Error if the message is not found
414
+ */
287
415
  resetHead(messageId: string | null) {
288
416
  if (messageId === null) {
289
417
  this.head = null;
@@ -311,6 +439,9 @@ export class MessageRepository {
311
439
  this._messages.dirty();
312
440
  }
313
441
 
442
+ /**
443
+ * Clears all messages from the repository.
444
+ */
314
445
  clear(): void {
315
446
  this.messages.clear();
316
447
  this.head = null;
@@ -321,6 +452,11 @@ export class MessageRepository {
321
452
  this._messages.dirty();
322
453
  }
323
454
 
455
+ /**
456
+ * Exports the repository state for persistence.
457
+ *
458
+ * @returns Exportable repository state
459
+ */
324
460
  export(): ExportedMessageRepository {
325
461
  const exportItems: ExportedMessageRepository["messages"] = [];
326
462
 
@@ -339,6 +475,11 @@ export class MessageRepository {
339
475
  };
340
476
  }
341
477
 
478
+ /**
479
+ * Imports repository state from an exported repository.
480
+ *
481
+ * @param repository - The exported repository state to import
482
+ */
342
483
  import({ headId, messages }: ExportedMessageRepository) {
343
484
  for (const { message, parentId } of messages) {
344
485
  this.addOrUpdateMessage(parentId, message);