@assistant-ui/react 0.14.28 → 0.14.29
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/client/ExternalThread.d.ts +11 -1
- package/dist/client/ExternalThread.d.ts.map +1 -1
- package/dist/client/ExternalThread.js +758 -513
- package/dist/client/ExternalThread.js.map +1 -1
- package/dist/legacy-runtime/cloud/auiV0.d.ts +12 -1
- package/dist/legacy-runtime/cloud/auiV0.d.ts.map +1 -1
- package/dist/legacy-runtime/cloud/auiV0.js +2 -1
- package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.d.ts +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +7 -6
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js +30 -15
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +8 -4
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +1 -0
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarRoot.js +3 -3
- package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
- package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +7 -6
- package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
- package/dist/primitives/actionBar/useActionBarFloatStatus.js +10 -11
- package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
- package/dist/primitives/attachment/AttachmentRemove.js +1 -0
- package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +1 -0
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.js +8 -2
- package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.js +1 -3
- package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +6 -4
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/ComposerSend.js +1 -0
- package/dist/primitives/composer/ComposerSend.js.map +1 -1
- package/dist/primitives/composer/ComposerStopDictation.js +1 -0
- package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
- package/dist/primitives/queueItem/QueueItemRemove.js +1 -0
- package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
- package/dist/primitives/queueItem/QueueItemSteer.js +1 -0
- package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
- package/dist/primitives/suggestion/SuggestionTrigger.js +1 -0
- package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
- package/dist/primitives/thread/ThreadScrollToBottom.js +1 -0
- package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
- package/dist/utils/hooks/useOnResizeContent.js +1 -0
- package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
- package/dist/utils/hooks/useSizeHandle.js +1 -0
- package/dist/utils/hooks/useSizeHandle.js.map +1 -1
- package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +2 -2
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/package.json +9 -9
- package/src/client/ExternalThread.ts +340 -53
- package/src/legacy-runtime/cloud/auiV0.ts +14 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/commandQueue.ts +4 -1
- package/src/legacy-runtime/runtime-cores/assistant-transport/runManager.ts +37 -10
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-delivery.test.tsx +79 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-parentid.test.tsx +97 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-scheduling.test.ts +113 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransport.spec.md +10 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.test.tsx +189 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.ts +20 -4
- package/src/primitives/actionBar/useActionBarFloatStatus.ts +7 -5
- package/src/primitives/composer/ComposerAddAttachment.test.tsx +108 -0
- package/src/primitives/composer/ComposerAddAttachment.ts +10 -4
- package/src/primitives/composer/ComposerAttachmentDropzone.test.tsx +3 -2
- package/src/primitives/composer/ComposerAttachmentDropzone.tsx +3 -2
- package/src/primitives/composer/ComposerInput.test.tsx +98 -1
- package/src/primitives/composer/ComposerInput.tsx +10 -8
- package/src/tests/DataRenderers.test.tsx +212 -0
- package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +1 -11
- package/src/tests/external-thread-attachments.test.tsx +292 -1
- package/src/tests/external-thread-parity.test.tsx +232 -0
- package/src/tests/generative-ui.test.tsx +1 -46
- package/src/tests/messagePartSwitchRace.test.tsx +25 -11
- package/src/tests/messagePartTypeMismatch.test.tsx +2 -2
- package/src/tests/threadMessageById.test.tsx +0 -7
- package/src/utils/smooth/useSmooth.ts +7 -4
- package/src/tests/BaseComposerRuntimeCore.test.ts +0 -621
- package/src/tests/BaseSubscribable.test.ts +0 -54
- package/src/tests/DataRenderers.test.ts +0 -355
- package/src/tests/ExternalStoreThreadRuntimeCore.test.ts +0 -685
- package/src/tests/LocalThreadRuntimeCore.test.ts +0 -324
- package/src/tests/auiV0Encode.test.ts +0 -188
- package/src/tests/external-message-converter.test.ts +0 -346
- package/src/tests/shouldContinue.test.ts +0 -122
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import { LocalThreadRuntimeCore } from "../legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore";
|
|
3
|
-
import type { ChatModelAdapter } from "../legacy-runtime/runtime-cores/local/ChatModelAdapter";
|
|
4
|
-
import type { LocalRuntimeOptionsBase } from "../legacy-runtime/runtime-cores/local/LocalRuntimeOptions";
|
|
5
|
-
import type { ModelContextProvider } from "@assistant-ui/core";
|
|
6
|
-
import type { AppendMessage } from "@assistant-ui/core";
|
|
7
|
-
|
|
8
|
-
const createMockContextProvider = (): ModelContextProvider => ({
|
|
9
|
-
getModelContext: () => ({}),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const createOptions = (
|
|
13
|
-
adapter: ChatModelAdapter,
|
|
14
|
-
overrides: Partial<LocalRuntimeOptionsBase> = {},
|
|
15
|
-
): LocalRuntimeOptionsBase => ({
|
|
16
|
-
adapters: { chatModel: adapter },
|
|
17
|
-
...overrides,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const createUserAppendMessage = (
|
|
21
|
-
text: string,
|
|
22
|
-
overrides: Partial<AppendMessage> = {},
|
|
23
|
-
): AppendMessage => ({
|
|
24
|
-
role: "user",
|
|
25
|
-
content: [{ type: "text", text }],
|
|
26
|
-
attachments: [],
|
|
27
|
-
metadata: { custom: {} },
|
|
28
|
-
parentId: null,
|
|
29
|
-
sourceId: null,
|
|
30
|
-
runConfig: undefined,
|
|
31
|
-
createdAt: new Date(),
|
|
32
|
-
...overrides,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe("LocalThreadRuntimeCore", () => {
|
|
36
|
-
let contextProvider: ModelContextProvider;
|
|
37
|
-
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
contextProvider = createMockContextProvider();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("appends a user message and runs the chat model", async () => {
|
|
43
|
-
const adapter: ChatModelAdapter = {
|
|
44
|
-
run: vi.fn().mockResolvedValue({
|
|
45
|
-
content: [{ type: "text", text: "Hello!" }],
|
|
46
|
-
status: { type: "complete", reason: "stop" },
|
|
47
|
-
}),
|
|
48
|
-
};
|
|
49
|
-
const core = new LocalThreadRuntimeCore(
|
|
50
|
-
contextProvider,
|
|
51
|
-
createOptions(adapter),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
await core.append(createUserAppendMessage("Hi"));
|
|
55
|
-
|
|
56
|
-
const messages = core.messages;
|
|
57
|
-
expect(messages).toHaveLength(2);
|
|
58
|
-
expect(messages[0]!.role).toBe("user");
|
|
59
|
-
expect(messages[1]!.role).toBe("assistant");
|
|
60
|
-
expect(messages[1]!.content).toEqual(
|
|
61
|
-
expect.arrayContaining([
|
|
62
|
-
expect.objectContaining({ type: "text", text: "Hello!" }),
|
|
63
|
-
]),
|
|
64
|
-
);
|
|
65
|
-
expect(messages[1]!.status).toEqual({ type: "complete", reason: "stop" });
|
|
66
|
-
expect(adapter.run).toHaveBeenCalledOnce();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("streams assistant response via async generator", async () => {
|
|
70
|
-
const adapter: ChatModelAdapter = {
|
|
71
|
-
run: vi.fn().mockImplementation(async function* () {
|
|
72
|
-
yield {
|
|
73
|
-
content: [{ type: "text" as const, text: "Hel" }],
|
|
74
|
-
};
|
|
75
|
-
yield {
|
|
76
|
-
content: [{ type: "text" as const, text: "Hello world" }],
|
|
77
|
-
status: { type: "complete" as const, reason: "stop" as const },
|
|
78
|
-
};
|
|
79
|
-
}),
|
|
80
|
-
};
|
|
81
|
-
const core = new LocalThreadRuntimeCore(
|
|
82
|
-
contextProvider,
|
|
83
|
-
createOptions(adapter),
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
await core.append(createUserAppendMessage("Stream test"));
|
|
87
|
-
|
|
88
|
-
const messages = core.messages;
|
|
89
|
-
expect(messages).toHaveLength(2);
|
|
90
|
-
const assistant = messages[1]!;
|
|
91
|
-
expect(assistant.role).toBe("assistant");
|
|
92
|
-
expect(assistant.content).toEqual(
|
|
93
|
-
expect.arrayContaining([
|
|
94
|
-
expect.objectContaining({ type: "text", text: "Hello world" }),
|
|
95
|
-
]),
|
|
96
|
-
);
|
|
97
|
-
expect(assistant.status).toEqual({ type: "complete", reason: "stop" });
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("cancels a running response", async () => {
|
|
101
|
-
const adapter: ChatModelAdapter = {
|
|
102
|
-
run: vi.fn().mockImplementation(async function* ({ abortSignal }) {
|
|
103
|
-
yield {
|
|
104
|
-
content: [{ type: "text" as const, text: "partial" }],
|
|
105
|
-
};
|
|
106
|
-
// Wait until the abort signal fires
|
|
107
|
-
await new Promise<void>((_resolve, reject) => {
|
|
108
|
-
if (abortSignal.aborted) {
|
|
109
|
-
reject(abortSignal.reason);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
abortSignal.addEventListener(
|
|
113
|
-
"abort",
|
|
114
|
-
() => reject(abortSignal.reason),
|
|
115
|
-
{ once: true },
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
}),
|
|
119
|
-
};
|
|
120
|
-
const core = new LocalThreadRuntimeCore(
|
|
121
|
-
contextProvider,
|
|
122
|
-
createOptions(adapter),
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// Start append but don't await (it will hang until cancelled)
|
|
126
|
-
const appendPromise = core.append(createUserAppendMessage("Cancel me"));
|
|
127
|
-
|
|
128
|
-
// Give the generator time to yield first chunk
|
|
129
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
130
|
-
|
|
131
|
-
core.cancelRun();
|
|
132
|
-
await appendPromise;
|
|
133
|
-
|
|
134
|
-
const messages = core.messages;
|
|
135
|
-
expect(messages).toHaveLength(2);
|
|
136
|
-
const assistant = messages[1]!;
|
|
137
|
-
expect(assistant.status).toBeDefined();
|
|
138
|
-
expect(assistant.status!.type).toBe("incomplete");
|
|
139
|
-
if (assistant.status!.type === "incomplete") {
|
|
140
|
-
expect(assistant.status!.reason).toBe("cancelled");
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("handles adapter errors gracefully", async () => {
|
|
145
|
-
const adapter: ChatModelAdapter = {
|
|
146
|
-
run: vi.fn().mockRejectedValue(new Error("Model unavailable")),
|
|
147
|
-
};
|
|
148
|
-
const core = new LocalThreadRuntimeCore(
|
|
149
|
-
contextProvider,
|
|
150
|
-
createOptions(adapter),
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
await expect(
|
|
154
|
-
core.append(createUserAppendMessage("Error test")),
|
|
155
|
-
).rejects.toThrow("Model unavailable");
|
|
156
|
-
|
|
157
|
-
const messages = core.messages;
|
|
158
|
-
expect(messages).toHaveLength(2);
|
|
159
|
-
const assistant = messages[1]!;
|
|
160
|
-
expect(assistant.status).toBeDefined();
|
|
161
|
-
expect(assistant.status!.type).toBe("incomplete");
|
|
162
|
-
if (assistant.status!.type === "incomplete") {
|
|
163
|
-
expect(assistant.status!.reason).toBe("error");
|
|
164
|
-
expect(assistant.status!.error).toEqual({
|
|
165
|
-
code: "unknown",
|
|
166
|
-
message: "Model unavailable",
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("continues tool execution loop", async () => {
|
|
172
|
-
let callCount = 0;
|
|
173
|
-
const adapter: ChatModelAdapter = {
|
|
174
|
-
run: vi.fn().mockImplementation(() => {
|
|
175
|
-
callCount++;
|
|
176
|
-
if (callCount === 1) {
|
|
177
|
-
return Promise.resolve({
|
|
178
|
-
content: [
|
|
179
|
-
{
|
|
180
|
-
type: "tool-call",
|
|
181
|
-
toolCallId: "tc1",
|
|
182
|
-
toolName: "myTool",
|
|
183
|
-
args: { input: "test" },
|
|
184
|
-
argsText: '{"input":"test"}',
|
|
185
|
-
},
|
|
186
|
-
],
|
|
187
|
-
status: { type: "requires-action", reason: "tool-calls" },
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
return Promise.resolve({
|
|
191
|
-
content: [{ type: "text", text: "Done with tool" }],
|
|
192
|
-
status: { type: "complete", reason: "stop" },
|
|
193
|
-
});
|
|
194
|
-
}),
|
|
195
|
-
};
|
|
196
|
-
const core = new LocalThreadRuntimeCore(
|
|
197
|
-
contextProvider,
|
|
198
|
-
createOptions(adapter),
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
await core.append(createUserAppendMessage("Use a tool"));
|
|
202
|
-
|
|
203
|
-
// The assistant message should have a tool-call with no result yet
|
|
204
|
-
// and status requires-action. Now add the tool result.
|
|
205
|
-
const assistantMsg = core.messages[1]!;
|
|
206
|
-
expect(assistantMsg.role).toBe("assistant");
|
|
207
|
-
|
|
208
|
-
core.addToolResult({
|
|
209
|
-
messageId: assistantMsg.id,
|
|
210
|
-
toolName: "myTool",
|
|
211
|
-
toolCallId: "tc1",
|
|
212
|
-
result: "tool output",
|
|
213
|
-
isError: false,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
// Wait for the second roundtrip to complete
|
|
217
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
218
|
-
|
|
219
|
-
expect(adapter.run).toHaveBeenCalledTimes(2);
|
|
220
|
-
|
|
221
|
-
const finalMessages = core.messages;
|
|
222
|
-
const finalAssistant = finalMessages[1]!;
|
|
223
|
-
// Content should include both the tool-call from round 1 and text from round 2
|
|
224
|
-
expect(finalAssistant.content.some((c) => c.type === "tool-call")).toBe(
|
|
225
|
-
true,
|
|
226
|
-
);
|
|
227
|
-
expect(
|
|
228
|
-
finalAssistant.content.some(
|
|
229
|
-
(c) => c.type === "text" && c.text === "Done with tool",
|
|
230
|
-
),
|
|
231
|
-
).toBe(true);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it("stops at maxSteps", async () => {
|
|
235
|
-
const adapter: ChatModelAdapter = {
|
|
236
|
-
run: vi.fn().mockResolvedValue({
|
|
237
|
-
content: [
|
|
238
|
-
{
|
|
239
|
-
type: "tool-call",
|
|
240
|
-
toolCallId: "tc1",
|
|
241
|
-
toolName: "myTool",
|
|
242
|
-
args: {},
|
|
243
|
-
argsText: "{}",
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
status: { type: "requires-action", reason: "tool-calls" },
|
|
247
|
-
metadata: {
|
|
248
|
-
steps: [{ usage: { promptTokens: 10, completionTokens: 5 } }],
|
|
249
|
-
},
|
|
250
|
-
}),
|
|
251
|
-
};
|
|
252
|
-
const core = new LocalThreadRuntimeCore(
|
|
253
|
-
contextProvider,
|
|
254
|
-
createOptions(adapter, { maxSteps: 1 }),
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
await core.append(createUserAppendMessage("Tool call"));
|
|
258
|
-
|
|
259
|
-
// Add tool result - this should NOT trigger another roundtrip because maxSteps=1
|
|
260
|
-
const assistantMsg = core.messages[1]!;
|
|
261
|
-
core.addToolResult({
|
|
262
|
-
messageId: assistantMsg.id,
|
|
263
|
-
toolName: "myTool",
|
|
264
|
-
toolCallId: "tc1",
|
|
265
|
-
result: "result",
|
|
266
|
-
isError: false,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Wait a bit to ensure no additional roundtrip happened
|
|
270
|
-
await new Promise((r) => setTimeout(r, 100));
|
|
271
|
-
|
|
272
|
-
// Should have been called only once (the initial run)
|
|
273
|
-
expect(adapter.run).toHaveBeenCalledTimes(1);
|
|
274
|
-
|
|
275
|
-
const finalAssistant = core.messages[1]!;
|
|
276
|
-
expect(finalAssistant.status).toBeDefined();
|
|
277
|
-
expect(finalAssistant.status!.type).toBe("incomplete");
|
|
278
|
-
if (finalAssistant.status!.type === "incomplete") {
|
|
279
|
-
expect(finalAssistant.status!.reason).toBe("tool-calls");
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it("capabilities update from options", () => {
|
|
284
|
-
const adapter: ChatModelAdapter = {
|
|
285
|
-
run: vi.fn().mockResolvedValue({ content: [] }),
|
|
286
|
-
};
|
|
287
|
-
const core = new LocalThreadRuntimeCore(
|
|
288
|
-
contextProvider,
|
|
289
|
-
createOptions(adapter),
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Default capabilities
|
|
293
|
-
expect(core.capabilities.speech).toBe(false);
|
|
294
|
-
expect(core.capabilities.dictation).toBe(false);
|
|
295
|
-
expect(core.capabilities.attachments).toBe(false);
|
|
296
|
-
expect(core.capabilities.feedback).toBe(false);
|
|
297
|
-
|
|
298
|
-
// Update with adapters
|
|
299
|
-
core.__internal_setOptions({
|
|
300
|
-
adapters: {
|
|
301
|
-
chatModel: adapter,
|
|
302
|
-
speech: {} as any,
|
|
303
|
-
dictation: {} as any,
|
|
304
|
-
attachments: {} as any,
|
|
305
|
-
feedback: {} as any,
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
expect(core.capabilities.speech).toBe(true);
|
|
310
|
-
expect(core.capabilities.dictation).toBe(true);
|
|
311
|
-
expect(core.capabilities.attachments).toBe(true);
|
|
312
|
-
expect(core.capabilities.feedback).toBe(true);
|
|
313
|
-
|
|
314
|
-
// Update back to no adapters
|
|
315
|
-
core.__internal_setOptions({
|
|
316
|
-
adapters: { chatModel: adapter },
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
expect(core.capabilities.speech).toBe(false);
|
|
320
|
-
expect(core.capabilities.dictation).toBe(false);
|
|
321
|
-
expect(core.capabilities.attachments).toBe(false);
|
|
322
|
-
expect(core.capabilities.feedback).toBe(false);
|
|
323
|
-
});
|
|
324
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { auiV0Decode, auiV0Encode } from "../legacy-runtime/cloud/auiV0";
|
|
3
|
-
|
|
4
|
-
describe("auiV0Encode", () => {
|
|
5
|
-
it("preserves document source parts in the legacy cloud encoder", () => {
|
|
6
|
-
const encoded = auiV0Encode({
|
|
7
|
-
id: "m1",
|
|
8
|
-
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
9
|
-
role: "assistant",
|
|
10
|
-
status: { type: "complete", reason: "stop" },
|
|
11
|
-
metadata: {
|
|
12
|
-
unstable_state: null,
|
|
13
|
-
unstable_annotations: [],
|
|
14
|
-
unstable_data: [],
|
|
15
|
-
steps: [],
|
|
16
|
-
custom: {},
|
|
17
|
-
},
|
|
18
|
-
content: [
|
|
19
|
-
{
|
|
20
|
-
type: "source",
|
|
21
|
-
sourceType: "document",
|
|
22
|
-
id: "doc_123",
|
|
23
|
-
title: "proposal.pdf",
|
|
24
|
-
mediaType: "application/pdf",
|
|
25
|
-
filename: "proposal.pdf",
|
|
26
|
-
providerMetadata: {
|
|
27
|
-
openai: {
|
|
28
|
-
type: "file_citation",
|
|
29
|
-
fileId: "file_123",
|
|
30
|
-
index: 0,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(encoded.content).toEqual([
|
|
38
|
-
{
|
|
39
|
-
type: "source",
|
|
40
|
-
sourceType: "document",
|
|
41
|
-
id: "doc_123",
|
|
42
|
-
title: "proposal.pdf",
|
|
43
|
-
mediaType: "application/pdf",
|
|
44
|
-
filename: "proposal.pdf",
|
|
45
|
-
providerMetadata: {
|
|
46
|
-
openai: {
|
|
47
|
-
type: "file_citation",
|
|
48
|
-
fileId: "file_123",
|
|
49
|
-
index: 0,
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
]);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("preserves user attachments in the legacy cloud encoder", () => {
|
|
57
|
-
const encoded = auiV0Encode({
|
|
58
|
-
id: "m1",
|
|
59
|
-
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
60
|
-
role: "user",
|
|
61
|
-
metadata: { custom: {} },
|
|
62
|
-
content: [{ type: "text", text: "please review this" }],
|
|
63
|
-
attachments: [
|
|
64
|
-
{
|
|
65
|
-
id: "att-1",
|
|
66
|
-
type: "document",
|
|
67
|
-
name: "proposal.pdf",
|
|
68
|
-
contentType: "application/pdf",
|
|
69
|
-
status: { type: "complete" },
|
|
70
|
-
content: [
|
|
71
|
-
{
|
|
72
|
-
type: "file",
|
|
73
|
-
data: "data:application/pdf;base64,JVBERi0xLjQ=",
|
|
74
|
-
mimeType: "application/pdf",
|
|
75
|
-
filename: "proposal.pdf",
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
expect(encoded.attachments).toEqual([
|
|
83
|
-
{
|
|
84
|
-
id: "att-1",
|
|
85
|
-
type: "document",
|
|
86
|
-
name: "proposal.pdf",
|
|
87
|
-
contentType: "application/pdf",
|
|
88
|
-
status: { type: "complete" },
|
|
89
|
-
content: [
|
|
90
|
-
{
|
|
91
|
-
type: "file",
|
|
92
|
-
data: "data:application/pdf;base64,JVBERi0xLjQ=",
|
|
93
|
-
mimeType: "application/pdf",
|
|
94
|
-
filename: "proposal.pdf",
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it("omits missing attachment contentType in the legacy cloud encoder", () => {
|
|
102
|
-
const encoded = auiV0Encode({
|
|
103
|
-
id: "m1",
|
|
104
|
-
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
105
|
-
role: "user",
|
|
106
|
-
metadata: { custom: {} },
|
|
107
|
-
content: [{ type: "text", text: "please review this" }],
|
|
108
|
-
attachments: [
|
|
109
|
-
{
|
|
110
|
-
id: "att-1",
|
|
111
|
-
type: "document",
|
|
112
|
-
name: "notes.txt",
|
|
113
|
-
status: { type: "complete" },
|
|
114
|
-
content: [{ type: "text", text: "notes" }],
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
expect(encoded.attachments).toEqual([
|
|
120
|
-
{
|
|
121
|
-
id: "att-1",
|
|
122
|
-
type: "document",
|
|
123
|
-
name: "notes.txt",
|
|
124
|
-
status: { type: "complete" },
|
|
125
|
-
content: [{ type: "text", text: "notes" }],
|
|
126
|
-
},
|
|
127
|
-
]);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("auiV0Decode", () => {
|
|
132
|
-
it("restores user attachments from legacy cloud history", () => {
|
|
133
|
-
const content = auiV0Encode({
|
|
134
|
-
id: "local",
|
|
135
|
-
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
136
|
-
role: "user",
|
|
137
|
-
metadata: { custom: {} },
|
|
138
|
-
content: [{ type: "text", text: "please review this" }],
|
|
139
|
-
attachments: [
|
|
140
|
-
{
|
|
141
|
-
id: "att-1",
|
|
142
|
-
type: "document",
|
|
143
|
-
name: "proposal.pdf",
|
|
144
|
-
contentType: "application/pdf",
|
|
145
|
-
status: { type: "complete" },
|
|
146
|
-
content: [
|
|
147
|
-
{
|
|
148
|
-
type: "file",
|
|
149
|
-
data: "data:application/pdf;base64,JVBERi0xLjQ=",
|
|
150
|
-
mimeType: "application/pdf",
|
|
151
|
-
filename: "proposal.pdf",
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const decoded = auiV0Decode({
|
|
159
|
-
id: "cloud",
|
|
160
|
-
parent_id: null,
|
|
161
|
-
height: 0,
|
|
162
|
-
created_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
163
|
-
updated_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
164
|
-
format: "aui/v0",
|
|
165
|
-
content: content as never,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
expect(decoded.message.role).toBe("user");
|
|
169
|
-
if (decoded.message.role !== "user") throw new Error("expected user");
|
|
170
|
-
expect(decoded.message.attachments).toEqual([
|
|
171
|
-
{
|
|
172
|
-
id: "att-1",
|
|
173
|
-
type: "document",
|
|
174
|
-
name: "proposal.pdf",
|
|
175
|
-
contentType: "application/pdf",
|
|
176
|
-
status: { type: "complete" },
|
|
177
|
-
content: [
|
|
178
|
-
{
|
|
179
|
-
type: "file",
|
|
180
|
-
data: "data:application/pdf;base64,JVBERi0xLjQ=",
|
|
181
|
-
mimeType: "application/pdf",
|
|
182
|
-
filename: "proposal.pdf",
|
|
183
|
-
},
|
|
184
|
-
],
|
|
185
|
-
},
|
|
186
|
-
]);
|
|
187
|
-
});
|
|
188
|
-
});
|