@copilotkit/react-core 1.56.3 → 1.56.4-canary.1777531098
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/copilotkit-DFaI4j2r.d.mts.map +1 -1
- package/dist/{copilotkit-By2G6-Zx.cjs → copilotkit-DMFu29Kx.cjs} +142 -103
- package/dist/copilotkit-DMFu29Kx.cjs.map +1 -0
- package/dist/copilotkit-Dg4r4Gi_.d.cts.map +1 -1
- package/dist/{copilotkit-PzJlPKcU.mjs → copilotkit-OmIUrWym.mjs} +142 -103
- package/dist/copilotkit-OmIUrWym.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +24 -0
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +144 -105
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +8 -8
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +7 -114
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +26 -6
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +2 -2
- package/src/v2/components/chat/CopilotChatView.tsx +66 -77
- package/src/v2/components/chat/Lightbox.tsx +103 -0
- package/src/v2/components/chat/__tests__/CopilotChat.suggestionsAlways.test.tsx +183 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +193 -57
- package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.tsx +264 -0
- package/src/v2/hooks/use-configure-suggestions.tsx +43 -0
- package/dist/copilotkit-By2G6-Zx.cjs.map +0 -1
- package/dist/copilotkit-PzJlPKcU.mjs.map +0 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
|
3
|
+
import { beforeEach, vi } from "vitest";
|
|
4
|
+
import { useConfigureSuggestions } from "../../../hooks/use-configure-suggestions";
|
|
5
|
+
import { CopilotChat } from "../CopilotChat";
|
|
6
|
+
import { CopilotKitProvider } from "../../../providers/CopilotKitProvider";
|
|
7
|
+
import {
|
|
8
|
+
MockStepwiseAgent,
|
|
9
|
+
runStartedEvent,
|
|
10
|
+
runFinishedEvent,
|
|
11
|
+
textChunkEvent,
|
|
12
|
+
testId,
|
|
13
|
+
} from "../../../__tests__/utils/test-helpers";
|
|
14
|
+
import type { AutoScrollMode } from "../normalize-auto-scroll";
|
|
15
|
+
|
|
16
|
+
// jsdom doesn't implement scrollTo; pin-to-send mode calls it from a rAF
|
|
17
|
+
// callback, so without this stub the cleanup throws an unhandled error.
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
HTMLElement.prototype.scrollTo = vi.fn();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const STATIC_SUGGESTIONS = [
|
|
23
|
+
{ title: "Say hello", message: "Hello there!" },
|
|
24
|
+
{ title: "Get help", message: "Can you help me?" },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const ChatWithStaticAlwaysSuggestions: React.FC<{
|
|
28
|
+
autoScroll?: AutoScrollMode | boolean;
|
|
29
|
+
consumerAgentId?: string;
|
|
30
|
+
}> = ({ autoScroll, consumerAgentId }) => {
|
|
31
|
+
useConfigureSuggestions({
|
|
32
|
+
suggestions: STATIC_SUGGESTIONS,
|
|
33
|
+
available: "always",
|
|
34
|
+
...(consumerAgentId ? { consumerAgentId } : {}),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return <CopilotChat autoScroll={autoScroll} />;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function renderChat({
|
|
41
|
+
agent,
|
|
42
|
+
autoScroll,
|
|
43
|
+
consumerAgentId,
|
|
44
|
+
}: {
|
|
45
|
+
agent: MockStepwiseAgent;
|
|
46
|
+
autoScroll?: AutoScrollMode | boolean;
|
|
47
|
+
consumerAgentId?: string;
|
|
48
|
+
}) {
|
|
49
|
+
return render(
|
|
50
|
+
<CopilotKitProvider agents__unsafe_dev_only={{ default: agent }}>
|
|
51
|
+
<div style={{ height: 400 }}>
|
|
52
|
+
<ChatWithStaticAlwaysSuggestions
|
|
53
|
+
autoScroll={autoScroll}
|
|
54
|
+
consumerAgentId={consumerAgentId}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</CopilotKitProvider>,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("CopilotChat - static suggestions with available:'always'", () => {
|
|
62
|
+
it("should show suggestions on the welcome screen", async () => {
|
|
63
|
+
const agent = new MockStepwiseAgent();
|
|
64
|
+
renderChat({ agent, consumerAgentId: "default" });
|
|
65
|
+
|
|
66
|
+
await waitFor(() => {
|
|
67
|
+
expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await waitFor(() => {
|
|
71
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
72
|
+
expect(screen.getByText("Get help")).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should show suggestions on the welcome screen with global config (no consumerAgentId)", async () => {
|
|
77
|
+
const agent = new MockStepwiseAgent();
|
|
78
|
+
renderChat({ agent });
|
|
79
|
+
|
|
80
|
+
await waitFor(() => {
|
|
81
|
+
expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await waitFor(() => {
|
|
85
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
86
|
+
expect(screen.getByText("Get help")).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should hide suggestions during a run and restore them after", async () => {
|
|
91
|
+
const agent = new MockStepwiseAgent();
|
|
92
|
+
renderChat({ agent, consumerAgentId: "default" });
|
|
93
|
+
|
|
94
|
+
await waitFor(() => {
|
|
95
|
+
expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const input = await screen.findByRole("textbox");
|
|
103
|
+
fireEvent.change(input, { target: { value: "Hi!" } });
|
|
104
|
+
fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
|
|
105
|
+
|
|
106
|
+
await waitFor(() => {
|
|
107
|
+
expect(screen.getByText("Hi!")).toBeDefined();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const messageId = testId("msg");
|
|
111
|
+
agent.emit(runStartedEvent());
|
|
112
|
+
agent.emit(textChunkEvent(messageId, "Hello! How can I help?"));
|
|
113
|
+
|
|
114
|
+
// While the run is in flight, suggestions should be hidden — every run
|
|
115
|
+
// changes the conversation context, so we wait for the end-of-run reload
|
|
116
|
+
// before showing them again.
|
|
117
|
+
await waitFor(() => {
|
|
118
|
+
expect(screen.queryByText("Say hello")).toBeNull();
|
|
119
|
+
expect(screen.queryByText("Get help")).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
agent.emit(runFinishedEvent());
|
|
123
|
+
agent.complete();
|
|
124
|
+
|
|
125
|
+
await waitFor(() => {
|
|
126
|
+
expect(screen.getByText("Hello! How can I help?")).toBeDefined();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// After the run, the static "always" config repopulates them.
|
|
130
|
+
await waitFor(
|
|
131
|
+
() => {
|
|
132
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
133
|
+
expect(screen.getByText("Get help")).toBeDefined();
|
|
134
|
+
},
|
|
135
|
+
{ timeout: 3000 },
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should hide suggestions during a run in pin-to-send mode", async () => {
|
|
140
|
+
const agent = new MockStepwiseAgent();
|
|
141
|
+
renderChat({ agent, autoScroll: "pin-to-send" });
|
|
142
|
+
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(screen.getByTestId("copilot-welcome-screen")).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await waitFor(() => {
|
|
148
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const input = await screen.findByRole("textbox");
|
|
152
|
+
fireEvent.change(input, { target: { value: "Hi!" } });
|
|
153
|
+
fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
|
|
154
|
+
|
|
155
|
+
await waitFor(() => {
|
|
156
|
+
expect(screen.getByText("Hi!")).toBeDefined();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const messageId = testId("msg");
|
|
160
|
+
agent.emit(runStartedEvent());
|
|
161
|
+
agent.emit(textChunkEvent(messageId, "Hello! How can I help?"));
|
|
162
|
+
|
|
163
|
+
await waitFor(() => {
|
|
164
|
+
expect(screen.queryByText("Say hello")).toBeNull();
|
|
165
|
+
expect(screen.queryByText("Get help")).toBeNull();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
agent.emit(runFinishedEvent());
|
|
169
|
+
agent.complete();
|
|
170
|
+
|
|
171
|
+
await waitFor(() => {
|
|
172
|
+
expect(screen.getByText("Hello! How can I help?")).toBeDefined();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await waitFor(
|
|
176
|
+
() => {
|
|
177
|
+
expect(screen.getByText("Say hello")).toBeDefined();
|
|
178
|
+
expect(screen.getByText("Get help")).toBeDefined();
|
|
179
|
+
},
|
|
180
|
+
{ timeout: 3000 },
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { EventType } from "@ag-ui/client";
|
|
4
5
|
import {
|
|
5
6
|
MockReconnectableAgent,
|
|
6
7
|
MockStepwiseAgent,
|
|
@@ -10,34 +11,149 @@ import {
|
|
|
10
11
|
runStartedEvent,
|
|
11
12
|
testId,
|
|
12
13
|
} from "../../../__tests__/utils/test-helpers";
|
|
13
|
-
import { ReactActivityMessageRenderer } from "../../../types";
|
|
14
|
+
import type { ReactActivityMessageRenderer } from "../../../types";
|
|
14
15
|
import {
|
|
15
16
|
CopilotChatConfigurationProvider,
|
|
16
17
|
CopilotKitProvider,
|
|
17
18
|
useCopilotKit,
|
|
18
19
|
} from "../../../providers";
|
|
19
|
-
import { AbstractAgent } from "@ag-ui/client";
|
|
20
|
+
import type { AbstractAgent } from "@ag-ui/client";
|
|
20
21
|
import { IntelligenceAgent } from "@copilotkit/core";
|
|
21
22
|
import { getThreadClone } from "../../../hooks/use-agent";
|
|
22
23
|
import { createA2UIMessageRenderer } from "../../../a2ui/A2UIMessageRenderer";
|
|
23
24
|
import type { Theme } from "@copilotkit/a2ui-renderer";
|
|
24
25
|
import { CopilotChat } from "..";
|
|
25
26
|
|
|
26
|
-
const {
|
|
27
|
+
const {
|
|
28
|
+
mockWebsandboxCreate,
|
|
29
|
+
mockWebsandboxDestroy,
|
|
30
|
+
mockPhoenixSockets,
|
|
31
|
+
MockPhoenixSocket,
|
|
32
|
+
} = vi.hoisted(() => {
|
|
27
33
|
const mockDestroy = vi.fn();
|
|
28
|
-
const mockCreate = vi.fn(() => ({
|
|
34
|
+
const mockCreate = vi.fn((..._args: unknown[]) => ({
|
|
29
35
|
iframe: document.createElement("iframe"),
|
|
30
36
|
promise: Promise.resolve(),
|
|
31
37
|
run: vi.fn().mockResolvedValue(undefined),
|
|
32
38
|
destroy: mockDestroy,
|
|
33
39
|
}));
|
|
40
|
+
const mockSockets: MockPhoenixSocket[] = [];
|
|
41
|
+
|
|
42
|
+
class MockPhoenixPush {
|
|
43
|
+
private callbacks = new Map<string, (response?: unknown) => void>();
|
|
44
|
+
|
|
45
|
+
receive(
|
|
46
|
+
status: string,
|
|
47
|
+
callback: (response?: unknown) => void,
|
|
48
|
+
): MockPhoenixPush {
|
|
49
|
+
this.callbacks.set(status, callback);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
trigger(status: string, response?: unknown): void {
|
|
54
|
+
this.callbacks.get(status)?.(response);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class MockPhoenixChannel {
|
|
59
|
+
public topic: string;
|
|
60
|
+
public params: Record<string, unknown>;
|
|
61
|
+
public left = false;
|
|
62
|
+
|
|
63
|
+
private handlers = new Map<
|
|
64
|
+
string,
|
|
65
|
+
Array<{ ref: number; callback: (payload: unknown) => void }>
|
|
66
|
+
>();
|
|
67
|
+
private joinPush = new MockPhoenixPush();
|
|
68
|
+
private nextRef = 1;
|
|
69
|
+
|
|
70
|
+
constructor(topic: string, params: Record<string, unknown>) {
|
|
71
|
+
this.topic = topic;
|
|
72
|
+
this.params = params;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
on(event: string, callback: (payload: unknown) => void): number {
|
|
76
|
+
if (!this.handlers.has(event)) {
|
|
77
|
+
this.handlers.set(event, []);
|
|
78
|
+
}
|
|
79
|
+
const ref = this.nextRef;
|
|
80
|
+
this.nextRef += 1;
|
|
81
|
+
this.handlers.get(event)?.push({ ref, callback });
|
|
82
|
+
return ref;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
off(event: string, ref?: number): void {
|
|
86
|
+
if (ref === undefined) {
|
|
87
|
+
this.handlers.delete(event);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.handlers.set(
|
|
91
|
+
event,
|
|
92
|
+
(this.handlers.get(event) ?? []).filter(
|
|
93
|
+
(handler) => handler.ref !== ref,
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
join(): MockPhoenixPush {
|
|
99
|
+
return this.joinPush;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
leave(): void {
|
|
103
|
+
this.left = true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
triggerJoin(status: string, response?: unknown): void {
|
|
107
|
+
this.joinPush.trigger(status, response);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
serverPush(event: string, payload: unknown): void {
|
|
111
|
+
for (const { callback } of this.handlers.get(event) ?? []) {
|
|
112
|
+
callback(payload);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class MockPhoenixSocket {
|
|
118
|
+
public channels: MockPhoenixChannel[] = [];
|
|
119
|
+
|
|
120
|
+
constructor(
|
|
121
|
+
public url: string,
|
|
122
|
+
public opts: Record<string, unknown>,
|
|
123
|
+
) {
|
|
124
|
+
mockSockets.push(this);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
connect(): void {}
|
|
128
|
+
|
|
129
|
+
disconnect(): void {}
|
|
130
|
+
|
|
131
|
+
onOpen(): void {}
|
|
132
|
+
|
|
133
|
+
onError(): void {}
|
|
134
|
+
|
|
135
|
+
channel(
|
|
136
|
+
topic: string,
|
|
137
|
+
params: Record<string, unknown>,
|
|
138
|
+
): MockPhoenixChannel {
|
|
139
|
+
const channel = new MockPhoenixChannel(topic, params);
|
|
140
|
+
this.channels.push(channel);
|
|
141
|
+
return channel;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
34
144
|
|
|
35
145
|
return {
|
|
36
146
|
mockWebsandboxCreate: mockCreate,
|
|
37
147
|
mockWebsandboxDestroy: mockDestroy,
|
|
148
|
+
mockPhoenixSockets: mockSockets,
|
|
149
|
+
MockPhoenixSocket,
|
|
38
150
|
};
|
|
39
151
|
});
|
|
40
152
|
|
|
153
|
+
vi.mock("phoenix", () => ({
|
|
154
|
+
Socket: MockPhoenixSocket,
|
|
155
|
+
}));
|
|
156
|
+
|
|
41
157
|
vi.mock("@jetbrains/websandbox", () => ({
|
|
42
158
|
default: {
|
|
43
159
|
create: (...args: unknown[]) => mockWebsandboxCreate(...args),
|
|
@@ -329,66 +445,22 @@ describe("CopilotChat activity message rendering", () => {
|
|
|
329
445
|
});
|
|
330
446
|
});
|
|
331
447
|
|
|
332
|
-
it("restores a completed A2UI surface from
|
|
448
|
+
it("restores a completed A2UI surface from IntelligenceAgent /connect gateway replay", async () => {
|
|
333
449
|
const threadId = testId("intelligence-connect-thread");
|
|
334
450
|
const surfaceId = testId("intelligence-connect-surface");
|
|
335
451
|
const fetchMock = vi.fn().mockResolvedValueOnce(
|
|
336
452
|
jsonResponse({
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
input: {
|
|
345
|
-
messages: [
|
|
346
|
-
{
|
|
347
|
-
id: testId("connect-user-message"),
|
|
348
|
-
role: "user",
|
|
349
|
-
content: "show me the restored ui",
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
},
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
type: "ACTIVITY_SNAPSHOT",
|
|
356
|
-
messageId: testId("connect-a2ui-activity"),
|
|
357
|
-
activityType: "a2ui-surface",
|
|
358
|
-
content: {
|
|
359
|
-
a2ui_operations: [
|
|
360
|
-
{
|
|
361
|
-
version: "v0.9",
|
|
362
|
-
createSurface: {
|
|
363
|
-
surfaceId,
|
|
364
|
-
catalogId:
|
|
365
|
-
"https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
366
|
-
},
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
version: "v0.9",
|
|
370
|
-
updateComponents: {
|
|
371
|
-
surfaceId,
|
|
372
|
-
components: [
|
|
373
|
-
{
|
|
374
|
-
id: "root",
|
|
375
|
-
component: "Text",
|
|
376
|
-
text: "Restored dashboard",
|
|
377
|
-
variant: "body",
|
|
378
|
-
},
|
|
379
|
-
],
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
],
|
|
383
|
-
},
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
type: "RUN_FINISHED",
|
|
387
|
-
},
|
|
388
|
-
],
|
|
453
|
+
threadId,
|
|
454
|
+
runId: null,
|
|
455
|
+
joinToken: "join-token-1",
|
|
456
|
+
realtime: {
|
|
457
|
+
clientUrl: "ws://localhost:4000/client",
|
|
458
|
+
topic: `thread:${threadId}`,
|
|
459
|
+
},
|
|
389
460
|
}),
|
|
390
461
|
);
|
|
391
462
|
vi.stubGlobal("fetch", fetchMock);
|
|
463
|
+
mockPhoenixSockets.length = 0;
|
|
392
464
|
|
|
393
465
|
const agent = new IntelligenceAgent({
|
|
394
466
|
url: "ws://localhost:4000/client",
|
|
@@ -409,6 +481,70 @@ describe("CopilotChat activity message rendering", () => {
|
|
|
409
481
|
await waitFor(() => {
|
|
410
482
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
411
483
|
});
|
|
484
|
+
|
|
485
|
+
await waitFor(() => {
|
|
486
|
+
expect(mockPhoenixSockets).toHaveLength(1);
|
|
487
|
+
expect(mockPhoenixSockets[0]?.channels).toHaveLength(1);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
const channel = mockPhoenixSockets[0]!.channels[0]!;
|
|
491
|
+
expect(channel.topic).toBe(`thread:${threadId}`);
|
|
492
|
+
expect(channel.params).toEqual({
|
|
493
|
+
stream_mode: "connect",
|
|
494
|
+
last_seen_event_id: null,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
channel.triggerJoin("ok");
|
|
498
|
+
channel.serverPush("ag_ui_event", {
|
|
499
|
+
type: EventType.RUN_STARTED,
|
|
500
|
+
threadId,
|
|
501
|
+
run_id: "backend-run-1",
|
|
502
|
+
input: {
|
|
503
|
+
messages: [
|
|
504
|
+
{
|
|
505
|
+
id: testId("connect-user-message"),
|
|
506
|
+
role: "user",
|
|
507
|
+
content: "show me the restored ui",
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
channel.serverPush("ag_ui_event", {
|
|
513
|
+
type: EventType.ACTIVITY_SNAPSHOT,
|
|
514
|
+
messageId: testId("connect-a2ui-activity"),
|
|
515
|
+
activityType: "a2ui-surface",
|
|
516
|
+
content: {
|
|
517
|
+
a2ui_operations: [
|
|
518
|
+
{
|
|
519
|
+
version: "v0.9",
|
|
520
|
+
createSurface: {
|
|
521
|
+
surfaceId,
|
|
522
|
+
catalogId:
|
|
523
|
+
"https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
version: "v0.9",
|
|
528
|
+
updateComponents: {
|
|
529
|
+
surfaceId,
|
|
530
|
+
components: [
|
|
531
|
+
{
|
|
532
|
+
id: "root",
|
|
533
|
+
component: "Text",
|
|
534
|
+
text: "Restored dashboard",
|
|
535
|
+
variant: "body",
|
|
536
|
+
},
|
|
537
|
+
],
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
channel.serverPush("ag_ui_event", {
|
|
544
|
+
type: EventType.RUN_FINISHED,
|
|
545
|
+
});
|
|
546
|
+
channel.serverPush("stream_idle", { latestEventId: "event-3" });
|
|
547
|
+
|
|
412
548
|
await waitFor(() => {
|
|
413
549
|
expect(screen.getByText("show me the restored ui")).toBeDefined();
|
|
414
550
|
});
|