@assistant-ui/react-a2a 0.2.21 → 0.2.23
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/A2AClient.d.ts +8 -5
- package/dist/A2AClient.d.ts.map +1 -1
- package/dist/A2AClient.js +85 -24
- package/dist/A2AClient.js.map +1 -1
- package/dist/A2AThreadRuntimeCore.d.ts +15 -4
- package/dist/A2AThreadRuntimeCore.d.ts.map +1 -1
- package/dist/A2AThreadRuntimeCore.js +162 -45
- package/dist/A2AThreadRuntimeCore.js.map +1 -1
- package/dist/a2aExtras.d.ts +0 -1
- package/dist/a2aExtras.d.ts.map +1 -1
- package/dist/conversions.d.ts +6 -4
- package/dist/conversions.d.ts.map +1 -1
- package/dist/conversions.js +32 -3
- package/dist/conversions.js.map +1 -1
- package/dist/hooks.d.ts +0 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/types.d.ts +27 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/useA2ARuntime.d.ts +0 -1
- package/dist/useA2ARuntime.d.ts.map +1 -1
- package/dist/useA2ARuntime.js +30 -18
- package/dist/useA2ARuntime.js.map +1 -1
- package/package.json +11 -6
- package/src/A2AClient.test.ts +321 -4
- package/src/A2AClient.ts +158 -49
- package/src/A2AThreadRuntimeCore.test.ts +458 -0
- package/src/A2AThreadRuntimeCore.ts +215 -57
- package/src/conversions.test.ts +109 -2
- package/src/conversions.ts +46 -4
- package/src/useA2ARuntime.test.tsx +142 -0
- package/src/useA2ARuntime.ts +55 -36
|
@@ -40,6 +40,57 @@ function createUserAppendMessage(text: string): AppendMessage {
|
|
|
40
40
|
} as unknown as AppendMessage;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function createHistoryMessage(
|
|
44
|
+
id: string,
|
|
45
|
+
role: "user" | "assistant",
|
|
46
|
+
text: string,
|
|
47
|
+
): ThreadMessage {
|
|
48
|
+
return {
|
|
49
|
+
id,
|
|
50
|
+
role,
|
|
51
|
+
createdAt: new Date(),
|
|
52
|
+
content: [{ type: "text", text }],
|
|
53
|
+
status: { type: "complete", reason: "stop" },
|
|
54
|
+
...(role === "assistant"
|
|
55
|
+
? {
|
|
56
|
+
metadata: {
|
|
57
|
+
unstable_state: null,
|
|
58
|
+
unstable_annotations: [],
|
|
59
|
+
unstable_data: [],
|
|
60
|
+
steps: [],
|
|
61
|
+
custom: {},
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
: {}),
|
|
65
|
+
} as ThreadMessage;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createBranchedHistory() {
|
|
69
|
+
const user = createHistoryMessage("user", "user", "Question");
|
|
70
|
+
const firstAssistant = createHistoryMessage(
|
|
71
|
+
"assistant-a",
|
|
72
|
+
"assistant",
|
|
73
|
+
"First answer",
|
|
74
|
+
);
|
|
75
|
+
const secondAssistant = createHistoryMessage(
|
|
76
|
+
"assistant-b",
|
|
77
|
+
"assistant",
|
|
78
|
+
"Second answer",
|
|
79
|
+
);
|
|
80
|
+
const history = {
|
|
81
|
+
load: vi.fn().mockResolvedValue({
|
|
82
|
+
headId: secondAssistant.id,
|
|
83
|
+
messages: [
|
|
84
|
+
{ parentId: null, message: user },
|
|
85
|
+
{ parentId: user.id, message: firstAssistant },
|
|
86
|
+
{ parentId: user.id, message: secondAssistant },
|
|
87
|
+
],
|
|
88
|
+
}),
|
|
89
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
90
|
+
};
|
|
91
|
+
return { user, firstAssistant, secondAssistant, history };
|
|
92
|
+
}
|
|
93
|
+
|
|
43
94
|
function statusUpdateEvent(state: string, text?: string): A2AStreamEvent {
|
|
44
95
|
return {
|
|
45
96
|
type: "statusUpdate",
|
|
@@ -119,6 +170,203 @@ describe("A2AThreadRuntimeCore", () => {
|
|
|
119
170
|
});
|
|
120
171
|
});
|
|
121
172
|
|
|
173
|
+
describe("history loading", () => {
|
|
174
|
+
it("preserves sibling branches and selects the persisted head", async () => {
|
|
175
|
+
const { user, firstAssistant, secondAssistant, history } =
|
|
176
|
+
createBranchedHistory();
|
|
177
|
+
const core = createCore({}, { history });
|
|
178
|
+
|
|
179
|
+
await core.__internal_load();
|
|
180
|
+
|
|
181
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
182
|
+
user.id,
|
|
183
|
+
secondAssistant.id,
|
|
184
|
+
]);
|
|
185
|
+
expect(
|
|
186
|
+
core.getMessageRepository().messages.map(({ message, parentId }) => ({
|
|
187
|
+
id: message.id,
|
|
188
|
+
parentId,
|
|
189
|
+
})),
|
|
190
|
+
).toEqual([
|
|
191
|
+
{ id: user.id, parentId: null },
|
|
192
|
+
{ id: firstAssistant.id, parentId: user.id },
|
|
193
|
+
{ id: secondAssistant.id, parentId: user.id },
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("falls back to linear history when stored parents are invalid", async () => {
|
|
198
|
+
const user = createHistoryMessage("user", "user", "Question");
|
|
199
|
+
const assistant = createHistoryMessage(
|
|
200
|
+
"assistant",
|
|
201
|
+
"assistant",
|
|
202
|
+
"Answer",
|
|
203
|
+
);
|
|
204
|
+
const history = {
|
|
205
|
+
load: vi.fn().mockResolvedValue({
|
|
206
|
+
headId: assistant.id,
|
|
207
|
+
messages: [
|
|
208
|
+
{ parentId: "missing", message: user },
|
|
209
|
+
{ parentId: user.id, message: assistant },
|
|
210
|
+
],
|
|
211
|
+
}),
|
|
212
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
213
|
+
};
|
|
214
|
+
const core = createCore({}, { history });
|
|
215
|
+
|
|
216
|
+
await expect(core.__internal_load()).resolves.toBeUndefined();
|
|
217
|
+
|
|
218
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
219
|
+
user.id,
|
|
220
|
+
assistant.id,
|
|
221
|
+
]);
|
|
222
|
+
expect(
|
|
223
|
+
core.getMessageRepository().messages.map(({ message, parentId }) => ({
|
|
224
|
+
id: message.id,
|
|
225
|
+
parentId,
|
|
226
|
+
})),
|
|
227
|
+
).toEqual([
|
|
228
|
+
{ id: user.id, parentId: null },
|
|
229
|
+
{ id: assistant.id, parentId: user.id },
|
|
230
|
+
]);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("falls back to linear history when stored ids are duplicated", async () => {
|
|
234
|
+
const first = createHistoryMessage("duplicate", "user", "First");
|
|
235
|
+
const replacement = createHistoryMessage(
|
|
236
|
+
"duplicate",
|
|
237
|
+
"assistant",
|
|
238
|
+
"Replacement",
|
|
239
|
+
);
|
|
240
|
+
const tail = createHistoryMessage("tail", "user", "Tail");
|
|
241
|
+
const history = {
|
|
242
|
+
load: vi.fn().mockResolvedValue({
|
|
243
|
+
headId: tail.id,
|
|
244
|
+
messages: [
|
|
245
|
+
{ parentId: null, message: first },
|
|
246
|
+
{ parentId: null, message: replacement },
|
|
247
|
+
{ parentId: replacement.id, message: tail },
|
|
248
|
+
],
|
|
249
|
+
}),
|
|
250
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
251
|
+
};
|
|
252
|
+
const core = createCore({}, { history });
|
|
253
|
+
|
|
254
|
+
await expect(core.__internal_load()).resolves.toBeUndefined();
|
|
255
|
+
|
|
256
|
+
const repository = core.getMessageRepository();
|
|
257
|
+
expect(
|
|
258
|
+
repository.messages.map(({ message, parentId }) => ({
|
|
259
|
+
id: message.id,
|
|
260
|
+
parentId,
|
|
261
|
+
})),
|
|
262
|
+
).toEqual([
|
|
263
|
+
{ id: replacement.id, parentId: null },
|
|
264
|
+
{ id: tail.id, parentId: replacement.id },
|
|
265
|
+
]);
|
|
266
|
+
expect(repository.messages[0]!.message.content).toEqual(
|
|
267
|
+
replacement.content,
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("falls back to linear history when stored parents form a cycle", async () => {
|
|
272
|
+
const first = createHistoryMessage("first", "user", "First");
|
|
273
|
+
const second = createHistoryMessage("second", "assistant", "Second");
|
|
274
|
+
const history = {
|
|
275
|
+
load: vi.fn().mockResolvedValue({
|
|
276
|
+
headId: second.id,
|
|
277
|
+
messages: [
|
|
278
|
+
{ parentId: second.id, message: first },
|
|
279
|
+
{ parentId: first.id, message: second },
|
|
280
|
+
],
|
|
281
|
+
}),
|
|
282
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
283
|
+
};
|
|
284
|
+
const core = createCore({}, { history });
|
|
285
|
+
|
|
286
|
+
await expect(core.__internal_load()).resolves.toBeUndefined();
|
|
287
|
+
|
|
288
|
+
expect(
|
|
289
|
+
core.getMessageRepository().messages.map(({ message, parentId }) => ({
|
|
290
|
+
id: message.id,
|
|
291
|
+
parentId,
|
|
292
|
+
})),
|
|
293
|
+
).toEqual([
|
|
294
|
+
{ id: first.id, parentId: null },
|
|
295
|
+
{ id: second.id, parentId: first.id },
|
|
296
|
+
]);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("keeps hidden siblings when the visible branch changes", async () => {
|
|
300
|
+
const { user, firstAssistant, secondAssistant, history } =
|
|
301
|
+
createBranchedHistory();
|
|
302
|
+
const core = createCore({}, { history });
|
|
303
|
+
|
|
304
|
+
await core.__internal_load();
|
|
305
|
+
core.applyExternalMessages([user, firstAssistant]);
|
|
306
|
+
|
|
307
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
308
|
+
user.id,
|
|
309
|
+
firstAssistant.id,
|
|
310
|
+
]);
|
|
311
|
+
expect(core.getMessageRepository().headId).toBe(firstAssistant.id);
|
|
312
|
+
expect(
|
|
313
|
+
core.getMessageRepository().messages.map(({ message }) => message.id),
|
|
314
|
+
).toEqual([user.id, firstAssistant.id, secondAssistant.id]);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("replaces stored branches when external messages change parentage", async () => {
|
|
318
|
+
const { secondAssistant, history } = createBranchedHistory();
|
|
319
|
+
const core = createCore({}, { history });
|
|
320
|
+
|
|
321
|
+
await core.__internal_load();
|
|
322
|
+
core.applyExternalMessages([secondAssistant]);
|
|
323
|
+
|
|
324
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
325
|
+
secondAssistant.id,
|
|
326
|
+
]);
|
|
327
|
+
expect(
|
|
328
|
+
core.getMessageRepository().messages.map(({ message, parentId }) => ({
|
|
329
|
+
id: message.id,
|
|
330
|
+
parentId,
|
|
331
|
+
})),
|
|
332
|
+
).toEqual([{ id: secondAssistant.id, parentId: null }]);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("adds regenerated responses without dropping loaded siblings", async () => {
|
|
336
|
+
const { user, firstAssistant, secondAssistant, history } =
|
|
337
|
+
createBranchedHistory();
|
|
338
|
+
const core = createCore(
|
|
339
|
+
{
|
|
340
|
+
streamMessage: vi.fn().mockImplementation(async function* () {
|
|
341
|
+
yield statusUpdateEvent("completed", "Regenerated answer");
|
|
342
|
+
}),
|
|
343
|
+
},
|
|
344
|
+
{ history },
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
await core.__internal_load();
|
|
348
|
+
await core.reload(user.id);
|
|
349
|
+
|
|
350
|
+
const visibleMessages = core.getMessages();
|
|
351
|
+
const regenerated = visibleMessages[1]!;
|
|
352
|
+
expect(visibleMessages.map((message) => message.id)).toEqual([
|
|
353
|
+
user.id,
|
|
354
|
+
regenerated.id,
|
|
355
|
+
]);
|
|
356
|
+
expect(regenerated.content).toEqual([
|
|
357
|
+
{ type: "text", text: "Regenerated answer" },
|
|
358
|
+
]);
|
|
359
|
+
expect(
|
|
360
|
+
core.getMessageRepository().messages.map(({ message }) => message.id),
|
|
361
|
+
).toEqual([
|
|
362
|
+
user.id,
|
|
363
|
+
firstAssistant.id,
|
|
364
|
+
secondAssistant.id,
|
|
365
|
+
regenerated.id,
|
|
366
|
+
]);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
122
370
|
// --- Edit & Reload ---
|
|
123
371
|
|
|
124
372
|
describe("edit", () => {
|
|
@@ -136,6 +384,80 @@ describe("A2AThreadRuntimeCore", () => {
|
|
|
136
384
|
expect(messages[0]!.role).toBe("user");
|
|
137
385
|
expect(messages[1]!.role).toBe("assistant");
|
|
138
386
|
});
|
|
387
|
+
|
|
388
|
+
it("keeps the replaced message subtree as a sibling branch", async () => {
|
|
389
|
+
const root = createHistoryMessage("root", "user", "First question");
|
|
390
|
+
const parent = createHistoryMessage(
|
|
391
|
+
"parent",
|
|
392
|
+
"assistant",
|
|
393
|
+
"First answer",
|
|
394
|
+
);
|
|
395
|
+
const source = createHistoryMessage(
|
|
396
|
+
"source",
|
|
397
|
+
"user",
|
|
398
|
+
"Original follow-up",
|
|
399
|
+
);
|
|
400
|
+
const child = createHistoryMessage(
|
|
401
|
+
"child",
|
|
402
|
+
"assistant",
|
|
403
|
+
"Original response",
|
|
404
|
+
);
|
|
405
|
+
const sibling = createHistoryMessage(
|
|
406
|
+
"sibling",
|
|
407
|
+
"user",
|
|
408
|
+
"Alternate follow-up",
|
|
409
|
+
);
|
|
410
|
+
const history = {
|
|
411
|
+
load: vi.fn().mockResolvedValue({
|
|
412
|
+
headId: child.id,
|
|
413
|
+
messages: [
|
|
414
|
+
{ parentId: null, message: root },
|
|
415
|
+
{ parentId: root.id, message: parent },
|
|
416
|
+
{ parentId: parent.id, message: source },
|
|
417
|
+
{ parentId: source.id, message: child },
|
|
418
|
+
{ parentId: parent.id, message: sibling },
|
|
419
|
+
],
|
|
420
|
+
}),
|
|
421
|
+
append: vi.fn().mockResolvedValue(undefined),
|
|
422
|
+
};
|
|
423
|
+
const core = createCore({}, { history });
|
|
424
|
+
|
|
425
|
+
await core.__internal_load();
|
|
426
|
+
await core.edit({
|
|
427
|
+
...createUserAppendMessage("Edited follow-up"),
|
|
428
|
+
parentId: parent.id,
|
|
429
|
+
sourceId: source.id,
|
|
430
|
+
startRun: false,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
const edited = core.getMessages().at(-1)!;
|
|
434
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
435
|
+
root.id,
|
|
436
|
+
parent.id,
|
|
437
|
+
edited.id,
|
|
438
|
+
]);
|
|
439
|
+
expect(
|
|
440
|
+
core.getMessageRepository().messages.map(({ message, parentId }) => ({
|
|
441
|
+
id: message.id,
|
|
442
|
+
parentId,
|
|
443
|
+
})),
|
|
444
|
+
).toEqual([
|
|
445
|
+
{ id: root.id, parentId: null },
|
|
446
|
+
{ id: parent.id, parentId: root.id },
|
|
447
|
+
{ id: source.id, parentId: parent.id },
|
|
448
|
+
{ id: child.id, parentId: source.id },
|
|
449
|
+
{ id: sibling.id, parentId: parent.id },
|
|
450
|
+
{ id: edited.id, parentId: parent.id },
|
|
451
|
+
]);
|
|
452
|
+
|
|
453
|
+
core.applyExternalMessages([root, parent, source, child]);
|
|
454
|
+
expect(core.getMessages().map((message) => message.id)).toEqual([
|
|
455
|
+
root.id,
|
|
456
|
+
parent.id,
|
|
457
|
+
source.id,
|
|
458
|
+
child.id,
|
|
459
|
+
]);
|
|
460
|
+
});
|
|
139
461
|
});
|
|
140
462
|
|
|
141
463
|
describe("reload", () => {
|
|
@@ -690,3 +1012,139 @@ describe("A2AThreadRuntimeCore", () => {
|
|
|
690
1012
|
});
|
|
691
1013
|
});
|
|
692
1014
|
});
|
|
1015
|
+
|
|
1016
|
+
describe("outbound message conversion", () => {
|
|
1017
|
+
function createCoreWithStream() {
|
|
1018
|
+
const streamMessage = vi.fn().mockImplementation(async function* () {});
|
|
1019
|
+
const core = new A2AThreadRuntimeCore({
|
|
1020
|
+
client: createMockClient({ streamMessage }),
|
|
1021
|
+
notifyUpdate: vi.fn() as unknown as () => void,
|
|
1022
|
+
});
|
|
1023
|
+
return { core, streamMessage };
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
it("forwards attachment content to the wire with the attachment MIME type", async () => {
|
|
1027
|
+
const { core, streamMessage } = createCoreWithStream();
|
|
1028
|
+
|
|
1029
|
+
await core.append({
|
|
1030
|
+
parentId: null,
|
|
1031
|
+
role: "user",
|
|
1032
|
+
content: [{ type: "text", text: "See attached" }],
|
|
1033
|
+
attachments: [
|
|
1034
|
+
{
|
|
1035
|
+
id: "att-1",
|
|
1036
|
+
type: "document",
|
|
1037
|
+
name: "doc.pdf",
|
|
1038
|
+
contentType: "application/pdf",
|
|
1039
|
+
status: { type: "complete" },
|
|
1040
|
+
content: [
|
|
1041
|
+
{
|
|
1042
|
+
type: "file",
|
|
1043
|
+
data: "https://files.com/doc.pdf",
|
|
1044
|
+
mimeType: "",
|
|
1045
|
+
filename: "doc.pdf",
|
|
1046
|
+
},
|
|
1047
|
+
],
|
|
1048
|
+
},
|
|
1049
|
+
],
|
|
1050
|
+
} as unknown as AppendMessage);
|
|
1051
|
+
|
|
1052
|
+
const sent = streamMessage.mock.calls[0]![0] as A2AMessage;
|
|
1053
|
+
expect(sent.parts).toEqual([
|
|
1054
|
+
{ text: "See attached" },
|
|
1055
|
+
{
|
|
1056
|
+
url: "https://files.com/doc.pdf",
|
|
1057
|
+
mediaType: "application/pdf",
|
|
1058
|
+
filename: "doc.pdf",
|
|
1059
|
+
},
|
|
1060
|
+
]);
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
it("forwards file parts in message content to the wire", async () => {
|
|
1064
|
+
const { core, streamMessage } = createCoreWithStream();
|
|
1065
|
+
|
|
1066
|
+
await core.append({
|
|
1067
|
+
parentId: null,
|
|
1068
|
+
role: "user",
|
|
1069
|
+
content: [
|
|
1070
|
+
{
|
|
1071
|
+
type: "file",
|
|
1072
|
+
data: "data:text/csv;base64,ZmlsZQ==",
|
|
1073
|
+
mimeType: "text/csv",
|
|
1074
|
+
},
|
|
1075
|
+
],
|
|
1076
|
+
} as unknown as AppendMessage);
|
|
1077
|
+
|
|
1078
|
+
const sent = streamMessage.mock.calls[0]![0] as A2AMessage;
|
|
1079
|
+
expect(sent.parts).toEqual([{ raw: "ZmlsZQ==", mediaType: "text/csv" }]);
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
it("does not throw for user messages missing attachments at runtime", async () => {
|
|
1083
|
+
const { core, streamMessage } = createCoreWithStream();
|
|
1084
|
+
const message = {
|
|
1085
|
+
id: "u1",
|
|
1086
|
+
role: "user",
|
|
1087
|
+
createdAt: new Date(),
|
|
1088
|
+
content: [{ type: "text", text: "Loaded" }],
|
|
1089
|
+
status: { type: "complete", reason: "stop" },
|
|
1090
|
+
} as unknown as ThreadMessage;
|
|
1091
|
+
|
|
1092
|
+
core.applyExternalMessages([message]);
|
|
1093
|
+
await core.reload("u1");
|
|
1094
|
+
|
|
1095
|
+
const sent = streamMessage.mock.calls[0]![0] as A2AMessage;
|
|
1096
|
+
expect(sent.parts).toEqual([{ text: "Loaded" }]);
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
it("forwards data URL image attachments as raw bytes", async () => {
|
|
1100
|
+
const { core, streamMessage } = createCoreWithStream();
|
|
1101
|
+
|
|
1102
|
+
await core.append({
|
|
1103
|
+
parentId: null,
|
|
1104
|
+
role: "user",
|
|
1105
|
+
content: [{ type: "text", text: "See image" }],
|
|
1106
|
+
attachments: [
|
|
1107
|
+
{
|
|
1108
|
+
id: "att-2",
|
|
1109
|
+
type: "image",
|
|
1110
|
+
name: "a.png",
|
|
1111
|
+
contentType: "image/png",
|
|
1112
|
+
status: { type: "complete" },
|
|
1113
|
+
content: [{ type: "image", image: "data:image/png;base64,aGVsbG8=" }],
|
|
1114
|
+
},
|
|
1115
|
+
],
|
|
1116
|
+
} as unknown as AppendMessage);
|
|
1117
|
+
|
|
1118
|
+
const sent = streamMessage.mock.calls[0]![0] as A2AMessage;
|
|
1119
|
+
expect(sent.parts).toEqual([
|
|
1120
|
+
{ text: "See image" },
|
|
1121
|
+
{ raw: "aGVsbG8=", mediaType: "image/png" },
|
|
1122
|
+
]);
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
it("does not throw for attachments missing content at runtime", async () => {
|
|
1126
|
+
const { core, streamMessage } = createCoreWithStream();
|
|
1127
|
+
const message = {
|
|
1128
|
+
id: "u2",
|
|
1129
|
+
role: "user",
|
|
1130
|
+
createdAt: new Date(),
|
|
1131
|
+
content: [{ type: "text", text: "Loaded" }],
|
|
1132
|
+
attachments: [
|
|
1133
|
+
{
|
|
1134
|
+
id: "att-3",
|
|
1135
|
+
type: "file",
|
|
1136
|
+
name: "x.txt",
|
|
1137
|
+
contentType: "text/plain",
|
|
1138
|
+
status: { type: "complete" },
|
|
1139
|
+
},
|
|
1140
|
+
],
|
|
1141
|
+
status: { type: "complete", reason: "stop" },
|
|
1142
|
+
} as unknown as ThreadMessage;
|
|
1143
|
+
|
|
1144
|
+
core.applyExternalMessages([message]);
|
|
1145
|
+
await core.reload("u2");
|
|
1146
|
+
|
|
1147
|
+
const sent = streamMessage.mock.calls[0]![0] as A2AMessage;
|
|
1148
|
+
expect(sent.parts).toEqual([{ text: "Loaded" }]);
|
|
1149
|
+
});
|
|
1150
|
+
});
|