@assistant-ui/eve 0.0.23 → 0.0.25

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.
Files changed (37) hide show
  1. package/dist/convertEveMessages.d.ts +40 -51
  2. package/dist/convertEveMessages.d.ts.map +1 -1
  3. package/dist/convertEveMessages.js +151 -122
  4. package/dist/convertEveMessages.js.map +1 -1
  5. package/dist/deriveCreatedAt.d.ts +9 -9
  6. package/dist/deriveCreatedAt.d.ts.map +1 -1
  7. package/dist/deriveCreatedAt.js +25 -34
  8. package/dist/deriveCreatedAt.js.map +1 -1
  9. package/dist/eveCloudSessions.js +1 -2
  10. package/dist/eveExtras.d.ts +4 -2
  11. package/dist/eveExtras.d.ts.map +1 -1
  12. package/dist/eveExtras.js +1 -2
  13. package/dist/eveExtras.js.map +1 -1
  14. package/dist/hooks.d.ts +4 -3
  15. package/dist/hooks.d.ts.map +1 -1
  16. package/dist/hooks.js +5 -5
  17. package/dist/hooks.js.map +1 -1
  18. package/dist/sdkIdentity.js +2 -3
  19. package/dist/useEveAgentRuntime.d.ts +3 -5
  20. package/dist/useEveAgentRuntime.d.ts.map +1 -1
  21. package/dist/useEveAgentRuntime.js +34 -23
  22. package/dist/useEveAgentRuntime.js.map +1 -1
  23. package/package.json +10 -10
  24. package/src/convertEveMessages.test.ts +940 -775
  25. package/src/convertEveMessages.ts +290 -233
  26. package/src/deriveCreatedAt.test.ts +90 -88
  27. package/src/deriveCreatedAt.ts +32 -36
  28. package/src/eveExtras.ts +4 -4
  29. package/src/hooks.ts +4 -3
  30. package/src/testUtils.ts +189 -8
  31. package/src/useEveAgentRuntime.cloud.test.tsx +105 -136
  32. package/src/useEveAgentRuntime.eveResume.test.tsx +22 -104
  33. package/src/useEveAgentRuntime.fast-refresh.test.tsx +195 -37
  34. package/src/useEveAgentRuntime.interruptedTurn.test.tsx +86 -40
  35. package/src/useEveAgentRuntime.refetch.test.tsx +19 -58
  36. package/src/useEveAgentRuntime.test.tsx +372 -291
  37. package/src/useEveAgentRuntime.ts +100 -113
@@ -3,10 +3,12 @@
3
3
  import { act, render, renderHook, waitFor } from "@testing-library/react";
4
4
  import { AssistantRuntimeProvider } from "@assistant-ui/core/react";
5
5
  import type { AssistantRuntime } from "@assistant-ui/core";
6
- import type { AssistantCloud } from "assistant-cloud";
6
+ import { AssistantCloud } from "assistant-cloud";
7
7
  import type { ClientSessionState } from "eve/client";
8
- import type { EveMessageData, UseEveAgentOptions } from "eve/react";
9
- import { Component, StrictMode, useState, type ReactNode } from "react";
8
+ import { emptySessionView } from "eve/events";
9
+ import type { EveMessage, UseEveAgentOptions } from "eve/react";
10
+ import type { Delivery } from "eve/sessions";
11
+ import { StrictMode, useState } from "react";
10
12
  import { afterEach, describe, expect, it, vi, type Mock } from "vitest";
11
13
 
12
14
  const { mockUseEveAgent } = vi.hoisted(() => ({
@@ -19,26 +21,29 @@ vi.mock("eve/react", async (importOriginal) => ({
19
21
  }));
20
22
 
21
23
  import { useEveReset } from "./hooks";
24
+ import { createEveDelivery } from "./testUtils";
22
25
  import {
23
26
  useEveAgentRuntime,
24
27
  type UseEveAgentRuntimeOptions,
25
28
  } from "./useEveAgentRuntime";
26
29
 
27
- type AgentOptions = UseEveAgentOptions<EveMessageData>;
30
+ type AgentOptions = UseEveAgentOptions;
28
31
 
29
- type FakeSnapshot = { data: EveMessageData; status: string };
32
+ type FakeSnapshot = {
33
+ messages: readonly EveMessage[];
34
+ status: "idle" | "busy" | "resuming";
35
+ };
30
36
 
31
37
  type FakeAgent = {
32
38
  readonly initialOptions: AgentOptions;
33
39
  options: AgentOptions;
34
40
  update: (next: Partial<FakeSnapshot>) => void;
35
- readonly send: Mock<() => Promise<void>>;
36
- readonly reset: Mock<() => void>;
41
+ readonly send: Mock<() => Promise<Delivery>>;
42
+ readonly newSession: Mock<() => void>;
37
43
  readonly resume: Mock<() => Promise<void>>;
38
44
  };
39
45
 
40
46
  const agents: FakeAgent[] = [];
41
- let withResume = true;
42
47
 
43
48
  const createdSession = (sessionId: string): ClientSessionState => ({
44
49
  sessionId,
@@ -53,30 +58,31 @@ mockUseEveAgent.mockImplementation(function useFakeEveAgent(
53
58
  initialOptions: options,
54
59
  options,
55
60
  update: () => {},
56
- send: vi.fn(async () => {}),
57
- reset: vi.fn(),
61
+ send: vi.fn(async () => createEveDelivery()),
62
+ newSession: vi.fn(),
58
63
  resume: vi.fn(async () => {}),
59
64
  };
60
65
  agents.push(created);
61
66
  return created;
62
67
  });
63
68
  const [snapshot, setSnapshot] = useState<FakeSnapshot>({
64
- data: { messages: [] },
65
- status: "ready",
69
+ messages: [],
70
+ status: "idle",
66
71
  });
67
72
  agent.options = options;
68
73
  agent.update = (next) => setSnapshot((current) => ({ ...current, ...next }));
69
74
  return {
70
- data: snapshot.data,
75
+ messages: snapshot.messages,
76
+ view: emptySessionView(),
71
77
  error: undefined,
72
78
  events: [],
73
79
  session: agent.initialOptions.initialSession,
74
80
  status: snapshot.status,
75
81
  send: agent.send,
76
- respond: vi.fn(async () => {}),
77
- cancel: vi.fn(async () => ({ status: "no_active_turn" })),
78
- reset: agent.reset,
79
- ...(withResume ? { resume: agent.resume } : {}),
82
+ respond: vi.fn(async () => createEveDelivery()),
83
+ cancel: vi.fn(async () => createEveDelivery()),
84
+ newSession: agent.newSession,
85
+ resume: agent.resume,
80
86
  };
81
87
  });
82
88
 
@@ -87,47 +93,50 @@ const makeCloud = (
87
93
  telemetry: { enabled: boolean } = { enabled: false },
88
94
  ) => {
89
95
  let created = 0;
90
- return {
91
- threads: {
92
- list: vi.fn(async ({ is_archived }: { is_archived?: boolean } = {}) => ({
93
- threads: is_archived
94
- ? []
95
- : rows.map((row) => ({
96
- ...row,
97
- title: row.id,
98
- is_archived: false,
99
- last_message_at: new Date(0),
100
- metadata: null,
101
- })),
102
- })),
103
- create: vi.fn(async () => ({ thread_id: `cloud-${++created}` })),
104
- update: vi.fn(async () => {}),
105
- delete: vi.fn(async () => {}),
106
- get: vi.fn(),
107
- messages: {
108
- list: vi.fn(async () => ({ messages: [] })),
109
- create: vi.fn(async () => ({ message_id: "cloud-message" })),
110
- update: vi.fn(async () => {}),
111
- },
112
- },
113
- events: { track: vi.fn() },
96
+ const cloud = new AssistantCloud({
97
+ baseUrl: "http://localhost",
98
+ apiKey: "test-key",
99
+ userId: "test-user",
100
+ workspaceId: "test-workspace",
114
101
  telemetry,
115
- runs: {
116
- report: vi.fn(async () => {}),
117
- stream: vi.fn(
118
- async () =>
119
- new ReadableStream({
120
- start(controller) {
121
- controller.close();
122
- },
123
- }),
124
- ),
125
- },
126
- registerSdk: vi.fn(),
127
- } as unknown as AssistantCloud & {
128
- threads: { create: Mock; list: Mock; messages: { create: Mock } };
129
- registerSdk: Mock;
130
- };
102
+ });
103
+ const list = vi
104
+ .spyOn(cloud.threads, "list")
105
+ .mockImplementation(async ({ is_archived } = {}) => ({
106
+ threads: is_archived
107
+ ? []
108
+ : rows.map((row) => ({
109
+ ...row,
110
+ title: row.id,
111
+ is_archived: false,
112
+ last_message_at: new Date(0),
113
+ created_at: new Date(0),
114
+ updated_at: new Date(0),
115
+ project_id: "test-project",
116
+ workspace_id: "test-workspace",
117
+ metadata: null,
118
+ })),
119
+ }));
120
+ const create = vi
121
+ .spyOn(cloud.threads, "create")
122
+ .mockImplementation(async () => ({
123
+ thread_id: `cloud-${++created}`,
124
+ }));
125
+ vi.spyOn(cloud.threads, "update").mockResolvedValue(undefined);
126
+ vi.spyOn(cloud.threads, "delete").mockResolvedValue(undefined);
127
+ vi.spyOn(cloud.threads.messages, "list").mockResolvedValue({ messages: [] });
128
+ const messagesCreate = vi
129
+ .spyOn(cloud.threads.messages, "create")
130
+ .mockResolvedValue({ message_id: "cloud-message" });
131
+ vi.spyOn(cloud.threads.messages, "update").mockResolvedValue(undefined);
132
+ vi.spyOn(cloud.events, "track").mockImplementation(() => {});
133
+ vi.spyOn(cloud.runs, "report").mockResolvedValue({ run_id: "test-run" });
134
+ const registerSdk = vi
135
+ .spyOn(cloud, "registerSdk")
136
+ .mockImplementation(() => {});
137
+ return Object.assign(cloud, {
138
+ mocks: { list, create, messagesCreate, registerSdk },
139
+ });
131
140
  };
132
141
 
133
142
  const settle = () =>
@@ -187,7 +196,6 @@ const lastAgent = () => {
187
196
 
188
197
  afterEach(() => {
189
198
  agents.length = 0;
190
- withResume = true;
191
199
  });
192
200
 
193
201
  describe("useEveAgentRuntime with cloud", () => {
@@ -203,7 +211,7 @@ describe("useEveAgentRuntime with cloud", () => {
203
211
  const agent = lastAgent();
204
212
  expect(agent.initialOptions.initialSession).toBeUndefined();
205
213
  expect(agent.initialOptions.resume).toBeUndefined();
206
- expect(cloud.registerSdk).toHaveBeenCalledWith({
214
+ expect(cloud.mocks.registerSdk).toHaveBeenCalledWith({
207
215
  name: "@assistant-ui/eve",
208
216
  version: expect.any(String),
209
217
  });
@@ -211,10 +219,10 @@ describe("useEveAgentRuntime with cloud", () => {
211
219
  let acceptTurn!: () => void;
212
220
  agent.send.mockImplementation(
213
221
  () =>
214
- new Promise<void>((resolve) => {
222
+ new Promise<Delivery>((resolve) => {
215
223
  acceptTurn = () => {
216
224
  agent.options.onSessionChange?.(createdSession("session-1"));
217
- resolve();
225
+ resolve(createEveDelivery());
218
226
  };
219
227
  }),
220
228
  );
@@ -222,11 +230,11 @@ describe("useEveAgentRuntime with cloud", () => {
222
230
  await settle();
223
231
 
224
232
  expect(agent.send).toHaveBeenCalledOnce();
225
- expect(cloud.threads.create).not.toHaveBeenCalled();
233
+ expect(cloud.mocks.create).not.toHaveBeenCalled();
226
234
 
227
235
  await act(async () => acceptTurn());
228
236
  await waitFor(() =>
229
- expect(cloud.threads.create).toHaveBeenCalledExactlyOnceWith({
237
+ expect(cloud.mocks.create).toHaveBeenCalledExactlyOnceWith({
230
238
  last_message_at: expect.any(Date),
231
239
  external_id: "session-1",
232
240
  upsert: true,
@@ -249,20 +257,22 @@ describe("useEveAgentRuntime with cloud", () => {
249
257
 
250
258
  agent.send.mockImplementationOnce(async () => {
251
259
  agent.options.onSessionChange?.(undefined);
260
+ return createEveDelivery();
252
261
  });
253
262
  act(() => app.runtime().thread.append("hi"));
254
263
  await settle();
255
264
 
256
- expect(cloud.threads.create).not.toHaveBeenCalled();
265
+ expect(cloud.mocks.create).not.toHaveBeenCalled();
257
266
  expect(app.runtime().threads.mainItem.getState().status).toBe("new");
258
267
 
259
268
  agent.send.mockImplementationOnce(async () => {
260
269
  agent.options.onSessionChange?.(createdSession("session-2"));
270
+ return createEveDelivery();
261
271
  });
262
272
  act(() => app.runtime().thread.append("again"));
263
273
 
264
274
  await waitFor(() =>
265
- expect(cloud.threads.create).toHaveBeenCalledExactlyOnceWith({
275
+ expect(cloud.mocks.create).toHaveBeenCalledExactlyOnceWith({
266
276
  last_message_at: expect.any(Date),
267
277
  external_id: "session-2",
268
278
  upsert: true,
@@ -286,7 +296,7 @@ describe("useEveAgentRuntime with cloud", () => {
286
296
  await settle();
287
297
 
288
298
  expect(agent.send).not.toHaveBeenCalled();
289
- expect(cloud.threads.create).not.toHaveBeenCalled();
299
+ expect(cloud.mocks.create).not.toHaveBeenCalled();
290
300
  expect(app.runtime().threads.mainItem.getState().status).toBe("new");
291
301
  const switched = await act(() =>
292
302
  Promise.race([
@@ -303,11 +313,12 @@ describe("useEveAgentRuntime with cloud", () => {
303
313
  if (!staged) throw new Error("the staged message is missing");
304
314
  agent.send.mockImplementationOnce(async () => {
305
315
  agent.options.onSessionChange?.(createdSession("session-3"));
316
+ return createEveDelivery();
306
317
  });
307
318
  await act(() => app.runtime().thread.startRun({ parentId: staged.id }));
308
319
 
309
320
  await waitFor(() =>
310
- expect(cloud.threads.create).toHaveBeenCalledExactlyOnceWith({
321
+ expect(cloud.mocks.create).toHaveBeenCalledExactlyOnceWith({
311
322
  last_message_at: expect.any(Date),
312
323
  external_id: "session-3",
313
324
  upsert: true,
@@ -317,22 +328,23 @@ describe("useEveAgentRuntime with cloud", () => {
317
328
 
318
329
  it("retries a lost save with the same session and upsert, so the cloud answers the thread it already stored", async () => {
319
330
  const cloud = makeCloud();
320
- cloud.threads.create.mockRejectedValueOnce(new Error("response lost"));
331
+ cloud.mocks.create.mockRejectedValueOnce(new Error("response lost"));
321
332
  const app = setup({ cloud });
322
333
  await settle();
323
334
  const agent = lastAgent();
324
335
  agent.send.mockImplementation(async () => {
325
336
  agent.options.onSessionChange?.(createdSession("session-1"));
337
+ return createEveDelivery();
326
338
  });
327
339
 
328
340
  act(() => app.runtime().thread.append("hi"));
329
- await waitFor(() => expect(cloud.threads.create).toHaveBeenCalledOnce());
341
+ await waitFor(() => expect(cloud.mocks.create).toHaveBeenCalledOnce());
330
342
  await settle();
331
343
  expect(app.runtime().threads.mainItem.getState().status).toBe("new");
332
344
 
333
345
  act(() => app.runtime().thread.append("again"));
334
- await waitFor(() => expect(cloud.threads.create).toHaveBeenCalledTimes(2));
335
- for (const [body] of cloud.threads.create.mock.calls) {
346
+ await waitFor(() => expect(cloud.mocks.create).toHaveBeenCalledTimes(2));
347
+ for (const [body] of cloud.mocks.create.mock.calls) {
336
348
  expect(body).toEqual({
337
349
  last_message_at: expect.any(Date),
338
350
  external_id: "session-1",
@@ -402,6 +414,7 @@ describe("useEveAgentRuntime with cloud", () => {
402
414
  const agent = lastAgent();
403
415
  agent.send.mockImplementationOnce(async () => {
404
416
  agent.options.onSessionChange?.(createdSession("session-1"));
417
+ return createEveDelivery();
405
418
  });
406
419
  act(() => app.runtime().thread.append("hi"));
407
420
  await waitFor(() =>
@@ -414,7 +427,7 @@ describe("useEveAgentRuntime with cloud", () => {
414
427
  act(() => app.reset());
415
428
  await settle();
416
429
 
417
- expect(agent.reset).not.toHaveBeenCalled();
430
+ expect(agent.newSession).not.toHaveBeenCalled();
418
431
  expect(app.runtime().threads.mainItem.getState()).toMatchObject({
419
432
  status: "new",
420
433
  });
@@ -431,38 +444,37 @@ describe("useEveAgentRuntime with cloud", () => {
431
444
  const agent = lastAgent();
432
445
  agent.send.mockImplementationOnce(async () => {
433
446
  agent.options.onSessionChange?.(createdSession("session-1"));
447
+ return createEveDelivery();
434
448
  });
435
449
  act(() => app.runtime().thread.append("hi"));
436
- await waitFor(() => expect(cloud.threads.create).toHaveBeenCalledOnce());
450
+ await waitFor(() => expect(cloud.mocks.create).toHaveBeenCalledOnce());
437
451
 
438
- act(() => agent.update({ status: "streaming" }));
452
+ act(() => agent.update({ status: "busy" }));
439
453
  act(() =>
440
454
  agent.update({
441
- status: "ready",
442
- data: {
443
- messages: [
444
- {
445
- id: "turn_1:user",
446
- role: "user",
447
- parts: [{ type: "text", text: "hi" }],
448
- metadata: { turnId: "turn_1" },
449
- },
450
- {
451
- id: "turn_1:assistant",
452
- role: "assistant",
453
- parts: [{ type: "text", text: "hello" }],
454
- metadata: { turnId: "turn_1" },
455
- },
456
- ],
457
- } as never,
455
+ status: "idle",
456
+ messages: [
457
+ {
458
+ id: "turn_1:user",
459
+ role: "user",
460
+ parts: [{ type: "text", text: "hi" }],
461
+ metadata: { turnId: "turn_1" },
462
+ },
463
+ {
464
+ id: "turn_1:assistant",
465
+ role: "assistant",
466
+ parts: [{ type: "text", text: "hello" }],
467
+ metadata: { turnId: "turn_1" },
468
+ },
469
+ ],
458
470
  }),
459
471
  );
460
472
  await settle();
461
473
 
462
474
  await waitFor(() =>
463
- expect(cloud.threads.messages.create).toHaveBeenCalledTimes(2),
475
+ expect(cloud.mocks.messagesCreate).toHaveBeenCalledTimes(2),
464
476
  );
465
- expect(cloud.threads.messages.create.mock.calls).toMatchObject([
477
+ expect(cloud.mocks.messagesCreate.mock.calls).toMatchObject([
466
478
  ["cloud-1", { format: "aui/v0", external_id: "turn_1:user" }],
467
479
  [
468
480
  "cloud-1",
@@ -474,49 +486,6 @@ describe("useEveAgentRuntime with cloud", () => {
474
486
  ],
475
487
  ]);
476
488
  });
477
-
478
- it("requires an eve that can resume a session", async () => {
479
- withResume = false;
480
- const errors: unknown[] = [];
481
- class Boundary extends Component<{ children: ReactNode }> {
482
- override state = { failed: false };
483
- static getDerivedStateFromError() {
484
- return { failed: true };
485
- }
486
- override componentDidCatch(error: unknown) {
487
- errors.push(error);
488
- }
489
- override render() {
490
- return this.state.failed ? null : this.props.children;
491
- }
492
- }
493
- const cloud = makeCloud();
494
- const App = () => {
495
- const runtime = useEveAgentRuntime({ cloud });
496
- return (
497
- <AssistantRuntimeProvider runtime={runtime}>
498
- {null}
499
- </AssistantRuntimeProvider>
500
- );
501
- };
502
- const consoleError = vi
503
- .spyOn(console, "error")
504
- .mockImplementation(() => {});
505
-
506
- render(
507
- <Boundary>
508
- <App />
509
- </Boundary>,
510
- );
511
- await settle();
512
-
513
- expect(errors).toContainEqual(
514
- expect.objectContaining({
515
- message: expect.stringContaining("eve 0.44.1 or later"),
516
- }),
517
- );
518
- consoleError.mockRestore();
519
- });
520
489
  });
521
490
 
522
491
  describe("useEveAgentRuntime switching cloud after mount", () => {
@@ -2,111 +2,29 @@
2
2
 
3
3
  import { act, renderHook, waitFor } from "@testing-library/react";
4
4
  import { afterEach, describe, expect, it, vi } from "vitest";
5
- import type { MessageStreamEvent } from "eve/client";
6
-
7
- import { createEveSessionFixture } from "./testUtils";
5
+ import {
6
+ createCompletedTurnEvents,
7
+ createEveSessionFixture,
8
+ } from "./testUtils";
8
9
  import { useEveAgentRuntime } from "./useEveAgentRuntime";
9
10
 
10
- const TURN = "turn_resumed";
11
-
12
11
  const USER_AT = "2026-01-02T10:00:01.000Z";
13
12
  const ASSISTANT_AT = "2026-01-02T10:02:00.000Z";
14
-
15
- const resumedEvents = [
16
- {
17
- type: "turn.started",
18
- data: { sequence: 1, turnId: TURN },
19
- meta: { at: "2026-01-02T10:00:00.000Z", id: "evt_001" },
20
- },
21
- {
22
- type: "message.received",
23
- data: { message: "hi", sequence: 2, turnId: TURN },
24
- meta: { at: USER_AT, id: "evt_101" },
25
- },
26
- {
27
- type: "step.started",
28
- data: { modelId: "test-model", sequence: 3, stepIndex: 0, turnId: TURN },
29
- meta: { at: ASSISTANT_AT, id: "evt_102" },
30
- },
31
- {
32
- type: "message.completed",
33
- data: {
34
- finishReason: "stop",
35
- message: "hello",
36
- sequence: 5,
37
- stepIndex: 0,
38
- turnId: TURN,
39
- },
40
- meta: { at: "2026-01-02T10:02:06.000Z", id: "evt_003" },
41
- },
42
- {
43
- type: "turn.completed",
44
- data: { sequence: 6, turnId: TURN },
45
- meta: { at: "2026-01-02T10:02:07.000Z", id: "evt_004" },
46
- },
47
- ] as const satisfies readonly MessageStreamEvent[];
48
-
49
- const NEXT_TURN = "turn_next";
50
-
51
- const nextTurnEvents = [
52
- {
53
- type: "turn.started",
54
- data: { sequence: 7, turnId: NEXT_TURN },
55
- meta: { at: "2026-01-02T10:03:00.000Z", id: "evt_201" },
56
- },
57
- {
58
- type: "message.received",
59
- data: { message: "follow up", sequence: 8, turnId: NEXT_TURN },
60
- meta: {
61
- at: "2026-01-02T10:03:01.000Z",
62
- id: "evt_202",
63
- deliveryIds: ["delivery_1"],
64
- },
65
- },
66
- {
67
- type: "step.started",
68
- data: {
69
- modelId: "test-model",
70
- sequence: 9,
71
- stepIndex: 0,
72
- turnId: NEXT_TURN,
73
- },
74
- meta: { at: "2026-01-02T10:03:02.000Z", id: "evt_203" },
75
- },
76
- {
77
- type: "message.completed",
78
- data: {
79
- finishReason: "stop",
80
- message: "noted",
81
- sequence: 10,
82
- stepIndex: 0,
83
- turnId: NEXT_TURN,
84
- },
85
- meta: { at: "2026-01-02T10:03:03.000Z", id: "evt_204" },
86
- },
87
- {
88
- type: "turn.completed",
89
- data: { sequence: 11, turnId: NEXT_TURN },
90
- meta: { at: "2026-01-02T10:03:04.000Z", id: "evt_205" },
91
- },
92
- {
93
- type: "session.waiting",
94
- data: { continuationToken: "session_resumed", wait: "next-user-message" },
95
- meta: { at: "2026-01-02T10:03:05.000Z", id: "evt_206" },
96
- },
97
- ] as const satisfies readonly MessageStreamEvent[];
98
-
99
- const parkedEvents = [
100
- ...resumedEvents,
101
- {
102
- type: "session.waiting",
103
- data: { continuationToken: "session_resumed", wait: "next-user-message" },
104
- meta: { at: "2026-01-02T10:02:08.000Z", id: "evt_005" },
105
- },
106
- ] as const satisfies readonly MessageStreamEvent[];
107
-
108
- const copyEvents = (events: readonly MessageStreamEvent[]) =>
109
- JSON.parse(JSON.stringify(events)) as readonly MessageStreamEvent[];
13
+ const resumedEvents = createCompletedTurnEvents({
14
+ turnId: "turn_resumed",
15
+ text: "hi",
16
+ reply: "hello",
17
+ userAt: USER_AT,
18
+ assistantAt: ASSISTANT_AT,
19
+ });
20
+ const nextTurnEvents = createCompletedTurnEvents({
21
+ turnId: "turn_next",
22
+ text: "follow up",
23
+ reply: "next answer",
24
+ startLine: resumedEvents.length,
25
+ follows: "turn_resumed",
26
+ deliveryId: "delivery_1",
27
+ });
110
28
 
111
29
  afterEach(() => vi.unstubAllGlobals());
112
30
 
@@ -128,8 +46,8 @@ describe("useEveAgentRuntime against a resumed eve session", () => {
128
46
 
129
47
  it("reports the replay as loading and holds a send typed during it until the replay ends", async () => {
130
48
  const { fetch, push, session } = createEveSessionFixture({
131
- tailIndex: parkedEvents.length - 1,
132
- onSend: () => setTimeout(() => push(copyEvents(nextTurnEvents)), 0),
49
+ tailIndex: resumedEvents.length - 1,
50
+ onSend: () => setTimeout(() => push(nextTurnEvents), 0),
133
51
  });
134
52
 
135
53
  const { result } = renderHook(() =>
@@ -146,7 +64,7 @@ describe("useEveAgentRuntime against a resumed eve session", () => {
146
64
  expect(fetch).toHaveBeenCalledOnce();
147
65
 
148
66
  await act(async () => {
149
- push(copyEvents(parkedEvents));
67
+ push(resumedEvents);
150
68
  });
151
69
 
152
70
  await waitFor(() =>