@assistant-ui/core 0.1.12 → 0.1.14
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/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/mention.d.ts +3 -17
- package/dist/adapters/mention.d.ts.map +1 -1
- package/dist/adapters/mention.js.map +1 -1
- package/dist/adapters/trigger.d.ts +28 -0
- package/dist/adapters/trigger.d.ts.map +1 -0
- package/dist/adapters/trigger.js +2 -0
- package/dist/adapters/trigger.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +2 -2
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +2 -2
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +1 -3
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/runtime/api/bindings.d.ts +2 -2
- package/dist/runtime/api/bindings.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +6 -3
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js +4 -2
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +2 -27
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +3 -3
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +2 -2
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +4 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +9 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +2 -2
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +2 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +8 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +2 -2
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +6 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +17 -0
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +2 -2
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/mention.d.ts +3 -14
- package/dist/types/mention.d.ts.map +1 -1
- package/dist/types/trigger.d.ts +15 -0
- package/dist/types/trigger.d.ts.map +1 -0
- package/dist/types/trigger.js +2 -0
- package/dist/types/trigger.js.map +1 -0
- package/package.json +11 -11
- package/src/adapters/index.ts +9 -0
- package/src/adapters/mention.ts +3 -20
- package/src/adapters/trigger.ts +52 -0
- package/src/index.ts +17 -0
- package/src/runtime/api/bindings.ts +2 -1
- package/src/runtime/api/composer-runtime.ts +12 -5
- package/src/runtime/base/base-composer-runtime-core.ts +4 -2
- package/src/runtime/base/default-edit-composer-runtime-core.ts +14 -3
- package/src/runtime/base/default-thread-composer-runtime-core.ts +6 -1
- package/src/runtime/interfaces/composer-runtime-core.ts +11 -1
- package/src/runtime/interfaces/thread-runtime-core.ts +2 -2
- package/src/runtime/utils/message-repository.ts +26 -0
- package/src/store/scopes/composer.ts +5 -2
- package/src/tests/MessageRepository.test.ts +141 -0
- package/src/types/index.ts +5 -0
- package/src/types/mention.ts +5 -16
- package/src/types/trigger.ts +24 -0
package/src/index.ts
CHANGED
|
@@ -50,6 +50,15 @@ export type {
|
|
|
50
50
|
Unstable_DirectiveFormatter,
|
|
51
51
|
} from "./types/mention";
|
|
52
52
|
|
|
53
|
+
export type {
|
|
54
|
+
Unstable_TriggerItem,
|
|
55
|
+
Unstable_TriggerCategory,
|
|
56
|
+
} from "./types/trigger";
|
|
57
|
+
|
|
58
|
+
// === trigger adapter ===
|
|
59
|
+
|
|
60
|
+
export type { Unstable_TriggerAdapter } from "./adapters/trigger";
|
|
61
|
+
|
|
53
62
|
// === model-context ===
|
|
54
63
|
|
|
55
64
|
export type {
|
|
@@ -123,6 +132,12 @@ export type { SuggestionAdapter } from "./adapters/suggestion";
|
|
|
123
132
|
export type { Unstable_MentionAdapter } from "./adapters/mention";
|
|
124
133
|
export { unstable_defaultDirectiveFormatter } from "./adapters/mention";
|
|
125
134
|
|
|
135
|
+
// Slash command adapter
|
|
136
|
+
export type {
|
|
137
|
+
Unstable_SlashCommandAdapter,
|
|
138
|
+
Unstable_SlashCommandItem,
|
|
139
|
+
} from "./adapters/trigger";
|
|
140
|
+
|
|
126
141
|
// Thread history adapters
|
|
127
142
|
export type {
|
|
128
143
|
ThreadHistoryAdapter,
|
|
@@ -150,6 +165,8 @@ export type {
|
|
|
150
165
|
ComposerRuntimeCore,
|
|
151
166
|
ComposerRuntimeEventType,
|
|
152
167
|
DictationState,
|
|
168
|
+
EditComposerRuntimeCore,
|
|
169
|
+
SendOptions,
|
|
153
170
|
ThreadComposerRuntimeCore,
|
|
154
171
|
} from "./runtime/interfaces/composer-runtime-core";
|
|
155
172
|
|
|
@@ -2,6 +2,7 @@ import type { ThreadMessage } from "../../types/message";
|
|
|
2
2
|
import type { SubscribableWithState } from "../../subscribable/subscribable";
|
|
3
3
|
import type {
|
|
4
4
|
ComposerRuntimeCore,
|
|
5
|
+
EditComposerRuntimeCore,
|
|
5
6
|
ThreadComposerRuntimeCore,
|
|
6
7
|
} from "../interfaces/composer-runtime-core";
|
|
7
8
|
import type {
|
|
@@ -21,7 +22,7 @@ export type ThreadComposerRuntimeCoreBinding = SubscribableWithState<
|
|
|
21
22
|
>;
|
|
22
23
|
|
|
23
24
|
export type EditComposerRuntimeCoreBinding = SubscribableWithState<
|
|
24
|
-
|
|
25
|
+
EditComposerRuntimeCore | undefined,
|
|
25
26
|
ComposerRuntimePath & { composerSource: "edit" }
|
|
26
27
|
>;
|
|
27
28
|
|
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
SKIP_UPDATE,
|
|
13
13
|
} from "../../subscribable/subscribable";
|
|
14
14
|
import type {
|
|
15
|
-
ComposerRuntimeCore,
|
|
16
15
|
ComposerRuntimeEventType,
|
|
17
16
|
DictationState,
|
|
17
|
+
EditComposerRuntimeCore,
|
|
18
|
+
SendOptions,
|
|
18
19
|
ThreadComposerRuntimeCore,
|
|
19
20
|
} from "../interfaces/composer-runtime-core";
|
|
20
21
|
import type {
|
|
@@ -68,6 +69,8 @@ export type ThreadComposerState = BaseComposerState & {
|
|
|
68
69
|
|
|
69
70
|
export type EditComposerState = BaseComposerState & {
|
|
70
71
|
readonly type: "edit";
|
|
72
|
+
readonly parentId: string | null;
|
|
73
|
+
readonly sourceId: string | null;
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
export type ComposerState = ThreadComposerState | EditComposerState;
|
|
@@ -97,7 +100,7 @@ const getThreadComposerState = (
|
|
|
97
100
|
};
|
|
98
101
|
|
|
99
102
|
const getEditComposerState = (
|
|
100
|
-
runtime:
|
|
103
|
+
runtime: EditComposerRuntimeCore | undefined,
|
|
101
104
|
): EditComposerState => {
|
|
102
105
|
return Object.freeze({
|
|
103
106
|
type: "edit",
|
|
@@ -114,6 +117,9 @@ const getEditComposerState = (
|
|
|
114
117
|
dictation: runtime?.dictation,
|
|
115
118
|
quote: runtime?.quote,
|
|
116
119
|
|
|
120
|
+
parentId: runtime?.parentId ?? null,
|
|
121
|
+
sourceId: runtime?.sourceId ?? null,
|
|
122
|
+
|
|
117
123
|
value: runtime?.text ?? "",
|
|
118
124
|
});
|
|
119
125
|
};
|
|
@@ -173,8 +179,9 @@ export type ComposerRuntime = {
|
|
|
173
179
|
|
|
174
180
|
/**
|
|
175
181
|
* Send a message. This will send whatever text or attachments are in the composer.
|
|
182
|
+
* @param options Optional send options. Use `{ startRun: true }` to force starting a new run.
|
|
176
183
|
*/
|
|
177
|
-
send(): void;
|
|
184
|
+
send(options?: SendOptions): void;
|
|
178
185
|
|
|
179
186
|
/**
|
|
180
187
|
* Cancel the current run. In edit mode, this will exit edit mode.
|
|
@@ -278,10 +285,10 @@ export abstract class ComposerRuntimeImpl implements ComposerRuntime {
|
|
|
278
285
|
return core.clearAttachments();
|
|
279
286
|
}
|
|
280
287
|
|
|
281
|
-
public send() {
|
|
288
|
+
public send(options?: SendOptions) {
|
|
282
289
|
const core = this._core.getState();
|
|
283
290
|
if (!core) throw new Error("Composer is not available");
|
|
284
|
-
core.send();
|
|
291
|
+
core.send(options);
|
|
285
292
|
}
|
|
286
293
|
|
|
287
294
|
public cancel() {
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
ComposerRuntimeCore,
|
|
18
18
|
ComposerRuntimeEventType,
|
|
19
19
|
DictationState,
|
|
20
|
+
SendOptions,
|
|
20
21
|
} from "../interfaces/composer-runtime-core";
|
|
21
22
|
import type { DictationAdapter } from "../../adapters/speech";
|
|
22
23
|
import { generateId } from "../../utils/id";
|
|
@@ -152,7 +153,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
152
153
|
await task;
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
public async send() {
|
|
156
|
+
public async send(options?: SendOptions) {
|
|
156
157
|
if (this.isEmpty) return;
|
|
157
158
|
|
|
158
159
|
if (this._dictationSession) {
|
|
@@ -187,7 +188,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
187
188
|
metadata: { custom: { ...(quote ? { quote } : {}) } },
|
|
188
189
|
};
|
|
189
190
|
|
|
190
|
-
this.handleSend(message);
|
|
191
|
+
this.handleSend(message, options);
|
|
191
192
|
this._notifyEventSubscribers("send");
|
|
192
193
|
}
|
|
193
194
|
|
|
@@ -197,6 +198,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
197
198
|
|
|
198
199
|
protected abstract handleSend(
|
|
199
200
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
201
|
+
options?: SendOptions,
|
|
200
202
|
): void;
|
|
201
203
|
protected abstract handleCancel(): void;
|
|
202
204
|
|
|
@@ -2,6 +2,7 @@ import type { AppendMessage, ThreadMessage } from "../../types/message";
|
|
|
2
2
|
import { getThreadMessageText } from "../../utils/text";
|
|
3
3
|
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
4
4
|
import type { DictationAdapter } from "../../adapters/speech";
|
|
5
|
+
import type { SendOptions } from "../interfaces/composer-runtime-core";
|
|
5
6
|
import type { ThreadRuntimeCore } from "../interfaces/thread-runtime-core";
|
|
6
7
|
import { BaseComposerRuntimeCore } from "./base-composer-runtime-core";
|
|
7
8
|
|
|
@@ -20,8 +21,8 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
20
21
|
|
|
21
22
|
private _nonTextParts;
|
|
22
23
|
private _previousText;
|
|
23
|
-
private _parentId;
|
|
24
|
-
private _sourceId;
|
|
24
|
+
private _parentId: string | null;
|
|
25
|
+
private _sourceId: string | null;
|
|
25
26
|
constructor(
|
|
26
27
|
private runtime: ThreadRuntimeCore & {
|
|
27
28
|
adapters?:
|
|
@@ -48,16 +49,26 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
48
49
|
this.setRunConfig({ ...runtime.composer.runConfig });
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
public get parentId() {
|
|
53
|
+
return this._parentId;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public get sourceId() {
|
|
57
|
+
return this._sourceId;
|
|
58
|
+
}
|
|
59
|
+
|
|
51
60
|
public async handleSend(
|
|
52
61
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
62
|
+
options?: SendOptions,
|
|
53
63
|
) {
|
|
54
64
|
const text = getThreadMessageText(message as AppendMessage);
|
|
55
|
-
if (text !== this._previousText) {
|
|
65
|
+
if (text !== this._previousText || options?.startRun) {
|
|
56
66
|
this.runtime.append({
|
|
57
67
|
...message,
|
|
58
68
|
content: [...message.content, ...this._nonTextParts] as any,
|
|
59
69
|
parentId: this._parentId,
|
|
60
70
|
sourceId: this._sourceId,
|
|
71
|
+
startRun: options?.startRun,
|
|
61
72
|
});
|
|
62
73
|
}
|
|
63
74
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { AppendMessage } from "../../types/message";
|
|
2
2
|
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
3
3
|
import type { DictationAdapter } from "../../adapters/speech";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
SendOptions,
|
|
6
|
+
ThreadComposerRuntimeCore,
|
|
7
|
+
} from "../interfaces/composer-runtime-core";
|
|
5
8
|
import type { ThreadRuntimeCore } from "../interfaces/thread-runtime-core";
|
|
6
9
|
import { BaseComposerRuntimeCore } from "./base-composer-runtime-core";
|
|
7
10
|
|
|
@@ -47,11 +50,13 @@ export class DefaultThreadComposerRuntimeCore
|
|
|
47
50
|
|
|
48
51
|
public async handleSend(
|
|
49
52
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
53
|
+
options?: SendOptions,
|
|
50
54
|
) {
|
|
51
55
|
this.runtime.append({
|
|
52
56
|
...(message as AppendMessage),
|
|
53
57
|
parentId: this.runtime.messages.at(-1)?.id ?? null,
|
|
54
58
|
sourceId: null,
|
|
59
|
+
startRun: options?.startRun,
|
|
55
60
|
});
|
|
56
61
|
}
|
|
57
62
|
|
|
@@ -16,6 +16,10 @@ export type DictationState = {
|
|
|
16
16
|
readonly inputDisabled?: boolean;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
export type SendOptions = {
|
|
20
|
+
startRun?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
19
23
|
export type ComposerRuntimeCore = Readonly<{
|
|
20
24
|
isEditing: boolean;
|
|
21
25
|
|
|
@@ -43,7 +47,7 @@ export type ComposerRuntimeCore = Readonly<{
|
|
|
43
47
|
reset: () => Promise<void>;
|
|
44
48
|
clearAttachments: () => Promise<void>;
|
|
45
49
|
|
|
46
|
-
send: () => void;
|
|
50
|
+
send: (options?: SendOptions) => void;
|
|
47
51
|
cancel: () => void;
|
|
48
52
|
|
|
49
53
|
dictation: DictationState | undefined;
|
|
@@ -59,3 +63,9 @@ export type ComposerRuntimeCore = Readonly<{
|
|
|
59
63
|
}>;
|
|
60
64
|
|
|
61
65
|
export type ThreadComposerRuntimeCore = ComposerRuntimeCore;
|
|
66
|
+
|
|
67
|
+
export type EditComposerRuntimeCore = ComposerRuntimeCore &
|
|
68
|
+
Readonly<{
|
|
69
|
+
parentId: string | null;
|
|
70
|
+
sourceId: string | null;
|
|
71
|
+
}>;
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
import type { ExportedMessageRepository } from "../utils/message-repository";
|
|
13
13
|
import type { ThreadMessageLike } from "../utils/thread-message-like";
|
|
14
14
|
import type {
|
|
15
|
-
|
|
15
|
+
EditComposerRuntimeCore,
|
|
16
16
|
ThreadComposerRuntimeCore,
|
|
17
17
|
} from "./composer-runtime-core";
|
|
18
18
|
|
|
@@ -120,7 +120,7 @@ export type ThreadRuntimeCore = Readonly<{
|
|
|
120
120
|
getModelContext: () => ModelContext;
|
|
121
121
|
|
|
122
122
|
composer: ThreadComposerRuntimeCore;
|
|
123
|
-
getEditComposer: (messageId: string) =>
|
|
123
|
+
getEditComposer: (messageId: string) => EditComposerRuntimeCore | undefined;
|
|
124
124
|
beginEdit: (messageId: string) => void;
|
|
125
125
|
|
|
126
126
|
speech: SpeechState | undefined;
|
|
@@ -39,6 +39,32 @@ export const ExportedMessageRepository = {
|
|
|
39
39
|
})),
|
|
40
40
|
};
|
|
41
41
|
},
|
|
42
|
+
|
|
43
|
+
fromBranchableArray: (
|
|
44
|
+
items: readonly {
|
|
45
|
+
message: ThreadMessageLike;
|
|
46
|
+
parentId: string | null;
|
|
47
|
+
}[],
|
|
48
|
+
options?: { headId?: string | null },
|
|
49
|
+
): ExportedMessageRepository => {
|
|
50
|
+
const fallbackStatus = getAutoStatus(false, false, false, false, undefined);
|
|
51
|
+
return {
|
|
52
|
+
...(options?.headId !== undefined
|
|
53
|
+
? { headId: options.headId }
|
|
54
|
+
: undefined),
|
|
55
|
+
messages: items.map(({ message, parentId }) => {
|
|
56
|
+
if (!message.id) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"ExportedMessageRepository.fromBranchableArray: Each message must have an 'id' field set.",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
parentId,
|
|
63
|
+
message: fromThreadMessageLike(message, message.id, fallbackStatus),
|
|
64
|
+
};
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
},
|
|
42
68
|
};
|
|
43
69
|
|
|
44
70
|
type RepositoryParent = {
|
|
@@ -3,11 +3,14 @@ import type { MessageRole } from "../../types/message";
|
|
|
3
3
|
import type { QuoteInfo } from "../../types/quote";
|
|
4
4
|
import type { RunConfig } from "../../types/message";
|
|
5
5
|
import type { ComposerRuntime } from "../../runtime/api/composer-runtime";
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
DictationState,
|
|
8
|
+
SendOptions,
|
|
9
|
+
} from "../../runtime/interfaces/composer-runtime-core";
|
|
7
10
|
import type { AttachmentMethods } from "./attachment";
|
|
8
11
|
import type { QueueItemState, QueueItemMethods } from "./queue-item";
|
|
9
12
|
|
|
10
|
-
export type ComposerSendOptions = {
|
|
13
|
+
export type ComposerSendOptions = SendOptions & {
|
|
11
14
|
/**
|
|
12
15
|
* Whether to steer (interrupt the current run and process this message immediately).
|
|
13
16
|
* When false (default), the message is queued and processed in order.
|
|
@@ -457,6 +457,147 @@ describe("MessageRepository", () => {
|
|
|
457
457
|
});
|
|
458
458
|
});
|
|
459
459
|
|
|
460
|
+
describe("ExportedMessageRepository.fromBranchableArray", () => {
|
|
461
|
+
it("should create a branching tree structure", () => {
|
|
462
|
+
const items = [
|
|
463
|
+
{
|
|
464
|
+
message: {
|
|
465
|
+
id: "user-1",
|
|
466
|
+
role: "user" as const,
|
|
467
|
+
content: [{ type: "text" as const, text: "Hello" }],
|
|
468
|
+
},
|
|
469
|
+
parentId: null,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
message: {
|
|
473
|
+
id: "assistant-1",
|
|
474
|
+
role: "assistant" as const,
|
|
475
|
+
content: [{ type: "text" as const, text: "Hi there" }],
|
|
476
|
+
},
|
|
477
|
+
parentId: "user-1",
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
message: {
|
|
481
|
+
id: "assistant-2",
|
|
482
|
+
role: "assistant" as const,
|
|
483
|
+
content: [{ type: "text" as const, text: "Hey!" }],
|
|
484
|
+
},
|
|
485
|
+
parentId: "user-1",
|
|
486
|
+
},
|
|
487
|
+
];
|
|
488
|
+
|
|
489
|
+
const result = ExportedMessageRepository.fromBranchableArray(items);
|
|
490
|
+
|
|
491
|
+
expect(result.messages).toHaveLength(3);
|
|
492
|
+
expect(result.messages[0]!.parentId).toBeNull();
|
|
493
|
+
expect(result.messages[0]!.message.id).toBe("user-1");
|
|
494
|
+
expect(result.messages[1]!.parentId).toBe("user-1");
|
|
495
|
+
expect(result.messages[1]!.message.id).toBe("assistant-1");
|
|
496
|
+
expect(result.messages[2]!.parentId).toBe("user-1");
|
|
497
|
+
expect(result.messages[2]!.message.id).toBe("assistant-2");
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it("should support headId option", () => {
|
|
501
|
+
const items = [
|
|
502
|
+
{
|
|
503
|
+
message: {
|
|
504
|
+
id: "msg-1",
|
|
505
|
+
role: "user" as const,
|
|
506
|
+
content: [{ type: "text" as const, text: "Hello" }],
|
|
507
|
+
},
|
|
508
|
+
parentId: null,
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
message: {
|
|
512
|
+
id: "msg-2a",
|
|
513
|
+
role: "assistant" as const,
|
|
514
|
+
content: [{ type: "text" as const, text: "Branch A" }],
|
|
515
|
+
},
|
|
516
|
+
parentId: "msg-1",
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
message: {
|
|
520
|
+
id: "msg-2b",
|
|
521
|
+
role: "assistant" as const,
|
|
522
|
+
content: [{ type: "text" as const, text: "Branch B" }],
|
|
523
|
+
},
|
|
524
|
+
parentId: "msg-1",
|
|
525
|
+
},
|
|
526
|
+
];
|
|
527
|
+
|
|
528
|
+
const result = ExportedMessageRepository.fromBranchableArray(items, {
|
|
529
|
+
headId: "msg-2b",
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
expect(result.headId).toBe("msg-2b");
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it("should throw if a message has no id", () => {
|
|
536
|
+
const items = [
|
|
537
|
+
{
|
|
538
|
+
message: {
|
|
539
|
+
role: "user" as const,
|
|
540
|
+
content: [{ type: "text" as const, text: "Hello" }],
|
|
541
|
+
},
|
|
542
|
+
parentId: null,
|
|
543
|
+
},
|
|
544
|
+
];
|
|
545
|
+
|
|
546
|
+
expect(() =>
|
|
547
|
+
ExportedMessageRepository.fromBranchableArray(items),
|
|
548
|
+
).toThrow(/Each message must have an 'id' field set/);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it("should handle empty arrays", () => {
|
|
552
|
+
const result = ExportedMessageRepository.fromBranchableArray([]);
|
|
553
|
+
expect(result.messages).toHaveLength(0);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it("should work with MessageRepository.import for branch switching", () => {
|
|
557
|
+
const items = [
|
|
558
|
+
{
|
|
559
|
+
message: {
|
|
560
|
+
id: "user-1",
|
|
561
|
+
role: "user" as const,
|
|
562
|
+
content: [{ type: "text" as const, text: "Hello" }],
|
|
563
|
+
},
|
|
564
|
+
parentId: null,
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
message: {
|
|
568
|
+
id: "assistant-a",
|
|
569
|
+
role: "assistant" as const,
|
|
570
|
+
content: [{ type: "text" as const, text: "Response A" }],
|
|
571
|
+
},
|
|
572
|
+
parentId: "user-1",
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
message: {
|
|
576
|
+
id: "assistant-b",
|
|
577
|
+
role: "assistant" as const,
|
|
578
|
+
content: [{ type: "text" as const, text: "Response B" }],
|
|
579
|
+
},
|
|
580
|
+
parentId: "user-1",
|
|
581
|
+
},
|
|
582
|
+
];
|
|
583
|
+
|
|
584
|
+
const repo = ExportedMessageRepository.fromBranchableArray(items, {
|
|
585
|
+
headId: "assistant-a",
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
repository.import(repo);
|
|
589
|
+
|
|
590
|
+
// Should show branch A
|
|
591
|
+
let messages = repository.getMessages();
|
|
592
|
+
expect(messages.map((m) => m.id)).toEqual(["user-1", "assistant-a"]);
|
|
593
|
+
|
|
594
|
+
// Switch to branch B
|
|
595
|
+
repository.switchToBranch("assistant-b");
|
|
596
|
+
messages = repository.getMessages();
|
|
597
|
+
expect(messages.map((m) => m.id)).toEqual(["user-1", "assistant-b"]);
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
|
|
460
601
|
describe("Complex scenarios", () => {
|
|
461
602
|
it("should maintain tree structure after deletions", () => {
|
|
462
603
|
const root = createTestMessage({ id: "root-id" });
|
package/src/types/index.ts
CHANGED
package/src/types/mention.ts
CHANGED
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Unstable_TriggerItem, Unstable_TriggerCategory } from "./trigger";
|
|
2
2
|
|
|
3
3
|
// =============================================================================
|
|
4
|
-
// Mention Item
|
|
4
|
+
// Mention Item — alias of the generic TriggerItem for backward compatibility
|
|
5
5
|
// =============================================================================
|
|
6
6
|
|
|
7
|
-
export type Unstable_MentionItem =
|
|
8
|
-
readonly id: string;
|
|
9
|
-
readonly type: string;
|
|
10
|
-
readonly label: string;
|
|
11
|
-
readonly icon?: string | undefined;
|
|
12
|
-
readonly description?: string | undefined;
|
|
13
|
-
readonly metadata?: ReadonlyJSONObject | undefined;
|
|
14
|
-
};
|
|
7
|
+
export type Unstable_MentionItem = Unstable_TriggerItem;
|
|
15
8
|
|
|
16
9
|
// =============================================================================
|
|
17
|
-
// Mention Category
|
|
10
|
+
// Mention Category — alias of the generic TriggerCategory
|
|
18
11
|
// =============================================================================
|
|
19
12
|
|
|
20
|
-
export type Unstable_MentionCategory =
|
|
21
|
-
readonly id: string;
|
|
22
|
-
readonly label: string;
|
|
23
|
-
readonly icon?: string | undefined;
|
|
24
|
-
};
|
|
13
|
+
export type Unstable_MentionCategory = Unstable_TriggerCategory;
|
|
25
14
|
|
|
26
15
|
// =============================================================================
|
|
27
16
|
// Directive Segment (parsed representation of mention directives in text)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
2
|
+
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Trigger Item (generic item for any trigger-based popover: @mention, /command)
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
export type Unstable_TriggerItem = {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly type: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly icon?: string | undefined;
|
|
12
|
+
readonly description?: string | undefined;
|
|
13
|
+
readonly metadata?: ReadonlyJSONObject | undefined;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Trigger Category (for hierarchical navigation in trigger popovers)
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
export type Unstable_TriggerCategory = {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly icon?: string | undefined;
|
|
24
|
+
};
|