@assistant-ui/react 0.8.14 → 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.
- package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.js +2 -2
- package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.js.map +1 -1
- package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.mjs +1 -1
- package/dist/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.mjs.map +1 -1
- package/dist/runtimes/edge/{EdgeChatAdapter.d.ts → EdgeModelAdapter.d.ts} +4 -4
- package/dist/runtimes/edge/EdgeModelAdapter.d.ts.map +1 -0
- package/dist/runtimes/edge/{EdgeChatAdapter.js → EdgeModelAdapter.js} +8 -8
- package/dist/runtimes/edge/EdgeModelAdapter.js.map +1 -0
- package/dist/runtimes/edge/{EdgeChatAdapter.mjs → EdgeModelAdapter.mjs} +4 -4
- package/dist/runtimes/edge/EdgeModelAdapter.mjs.map +1 -0
- package/dist/runtimes/edge/converters/toLanguageModelMessages.d.ts.map +1 -1
- package/dist/runtimes/edge/converters/toLanguageModelMessages.js +1 -0
- package/dist/runtimes/edge/converters/toLanguageModelMessages.js.map +1 -1
- package/dist/runtimes/edge/converters/toLanguageModelMessages.mjs +1 -0
- package/dist/runtimes/edge/converters/toLanguageModelMessages.mjs.map +1 -1
- package/dist/runtimes/edge/index.d.ts +2 -1
- package/dist/runtimes/edge/index.d.ts.map +1 -1
- package/dist/runtimes/edge/index.js +5 -2
- package/dist/runtimes/edge/index.js.map +1 -1
- package/dist/runtimes/edge/index.mjs +4 -2
- package/dist/runtimes/edge/index.mjs.map +1 -1
- package/dist/runtimes/edge/streams/toolResultStream.d.ts +2 -1
- package/dist/runtimes/edge/streams/toolResultStream.d.ts.map +1 -1
- package/dist/runtimes/edge/streams/toolResultStream.js +60 -21
- package/dist/runtimes/edge/streams/toolResultStream.js.map +1 -1
- package/dist/runtimes/edge/streams/toolResultStream.mjs +58 -20
- package/dist/runtimes/edge/streams/toolResultStream.mjs.map +1 -1
- package/dist/runtimes/edge/useEdgeRuntime.d.ts +2 -2
- package/dist/runtimes/edge/useEdgeRuntime.d.ts.map +1 -1
- package/dist/runtimes/edge/useEdgeRuntime.js +2 -2
- package/dist/runtimes/edge/useEdgeRuntime.js.map +1 -1
- package/dist/runtimes/edge/useEdgeRuntime.mjs +2 -2
- package/dist/runtimes/edge/useEdgeRuntime.mjs.map +1 -1
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js +3 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js.map +1 -1
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs +3 -0
- package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.mjs.map +1 -1
- package/dist/runtimes/utils/MessageRepository.d.ts +112 -0
- package/dist/runtimes/utils/MessageRepository.d.ts.map +1 -1
- package/dist/runtimes/utils/MessageRepository.js +103 -1
- package/dist/runtimes/utils/MessageRepository.js.map +1 -1
- package/dist/runtimes/utils/MessageRepository.mjs +103 -1
- package/dist/runtimes/utils/MessageRepository.mjs.map +1 -1
- package/dist/tests/MessageRepository.test.d.ts +2 -0
- package/dist/tests/MessageRepository.test.d.ts.map +1 -0
- package/dist/tests/setup.d.ts +2 -0
- package/dist/tests/setup.d.ts.map +1 -0
- package/dist/tests/setup.js +2656 -0
- package/dist/tests/setup.js.map +1 -0
- package/dist/tests/setup.mjs +2632 -0
- package/dist/tests/setup.mjs.map +1 -0
- package/dist/types/AssistantTypes.d.ts +1 -1
- package/dist/types/AssistantTypes.d.ts.map +1 -1
- package/dist/types/AssistantTypes.js.map +1 -1
- package/package.json +10 -4
- package/src/runtimes/dangerous-in-browser/DangerousInBrowserAdapter.ts +1 -1
- package/src/runtimes/edge/{EdgeChatAdapter.ts → EdgeModelAdapter.ts} +3 -3
- package/src/runtimes/edge/converters/toLanguageModelMessages.ts +3 -1
- package/src/runtimes/edge/index.ts +3 -1
- package/src/runtimes/edge/streams/toolResultStream.ts +76 -27
- package/src/runtimes/edge/useEdgeRuntime.ts +3 -3
- package/src/runtimes/remote-thread-list/EMPTY_THREAD_CORE.tsx +4 -0
- package/src/runtimes/utils/MessageRepository.tsx +142 -1
- package/src/tests/MessageRepository.test.ts +690 -0
- package/src/tests/setup.ts +11 -0
- package/src/types/AssistantTypes.ts +1 -1
- package/dist/runtimes/edge/EdgeChatAdapter.d.ts.map +0 -1
- package/dist/runtimes/edge/EdgeChatAdapter.js.map +0 -1
- 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
|
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
|
113
|
-
constructor(private options:
|
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 "./
|
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
|
-
|
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
|
-
|
10
|
-
|
11
|
-
if (!tool || !tool.execute) return undefined;
|
15
|
+
const tool = tools?.[toolCall.toolName];
|
16
|
+
if (!tool || !tool.execute) return undefined;
|
12
17
|
|
13
|
-
|
18
|
+
let executeFn = tool.execute;
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
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 {
|
4
|
+
import { EdgeModelAdapterOptions, EdgeModelAdapter } from "./EdgeModelAdapter";
|
5
5
|
import { splitLocalRuntimeOptions } from "../local/LocalRuntimeOptions";
|
6
6
|
|
7
|
-
export type EdgeRuntimeOptions =
|
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
|
14
|
+
new EdgeModelAdapter(otherOptions),
|
15
15
|
localRuntimeOptions,
|
16
16
|
);
|
17
17
|
};
|
@@ -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
|
-
|
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);
|