@assistant-ui/eve 0.0.24 → 0.0.26

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 +146 -117
  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 +925 -729
  25. package/src/convertEveMessages.ts +282 -227
  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
@@ -1,6 +1,11 @@
1
1
  // @vitest-environment jsdom
2
2
 
3
- import { act, render, renderHook, waitFor } from "@testing-library/react";
3
+ import {
4
+ act,
5
+ render,
6
+ renderHook,
7
+ waitFor as waitForAssertion,
8
+ } from "@testing-library/react";
4
9
  import {
5
10
  startTransition,
6
11
  Suspense,
@@ -18,12 +23,24 @@ vi.mock("eve/react", async (importOriginal) => ({
18
23
  useEveAgent: mockUseEveAgent,
19
24
  }));
20
25
 
21
- import type { MessageStreamEvent } from "eve/client";
22
- import type { EveMessageData } from "eve/react";
26
+ import type { SessionEvent, SessionStreamEvent } from "eve/client";
27
+ import { activeTurn, emptySessionView, foldEvents, idle } from "eve/events";
28
+ import type { EveMessage } from "eve/react";
29
+ import {
30
+ createEveDelivery,
31
+ createEveDeliveryAfter,
32
+ createEveEvents,
33
+ } from "./testUtils";
34
+
23
35
  import { useEveAgentRuntime } from "./useEveAgentRuntime";
24
36
  import { eveExtras } from "./eveExtras";
25
37
 
26
- const stuckStreamingData: EveMessageData = {
38
+ type MessageFixture = { messages: readonly EveMessage[] };
39
+
40
+ const waitFor = (assertion: () => void) =>
41
+ waitForAssertion(assertion, { interval: 10 });
42
+
43
+ const stuckStreamingData: MessageFixture = {
27
44
  messages: [
28
45
  { id: "u1", role: "user", parts: [{ type: "text", text: "hi" }] },
29
46
  {
@@ -35,18 +52,34 @@ const stuckStreamingData: EveMessageData = {
35
52
  ],
36
53
  };
37
54
 
38
- const createAgent = (overrides: Record<string, unknown>) => ({
39
- data: stuckStreamingData,
40
- error: undefined,
41
- events: [],
42
- session: undefined,
43
- status: "ready",
44
- send: vi.fn(),
45
- respond: vi.fn(),
46
- stop: vi.fn(),
47
- reset: vi.fn(),
48
- ...overrides,
49
- });
55
+ const createAgent = (overrides: Record<string, unknown>) => {
56
+ const { send, respond, ...other } = overrides;
57
+ const invoke = (handler: unknown, args: unknown[]) => {
58
+ if (typeof handler !== "function")
59
+ return Promise.resolve(createEveDelivery());
60
+ try {
61
+ return Promise.resolve(
62
+ createEveDeliveryAfter(Promise.resolve(handler(...args))),
63
+ );
64
+ } catch (error) {
65
+ return Promise.reject(error);
66
+ }
67
+ };
68
+ return {
69
+ messages: stuckStreamingData.messages,
70
+ view: emptySessionView(),
71
+ error: undefined,
72
+ events: [],
73
+ session: undefined,
74
+ status: "idle",
75
+ cancel: vi.fn(async () => createEveDelivery()),
76
+ newSession: vi.fn(),
77
+ resume: vi.fn(async () => {}),
78
+ ...other,
79
+ send: vi.fn((...args: unknown[]) => invoke(send, args)),
80
+ respond: vi.fn((...args: unknown[]) => invoke(respond, args)),
81
+ };
82
+ };
50
83
 
51
84
  afterEach(() => {
52
85
  vi.restoreAllMocks();
@@ -68,7 +101,7 @@ describe("useEveAgentRuntime status forwarding", () => {
68
101
  if (failureMode === "throws") throw callbackError;
69
102
  return Promise.reject(callbackError);
70
103
  });
71
- const agent = createAgent({ data: { messages: [] } });
104
+ const agent = createAgent({ messages: [] });
72
105
  let capturedOptions: Record<
73
106
  string,
74
107
  ((value: unknown) => void) | undefined
@@ -87,7 +120,7 @@ describe("useEveAgentRuntime status forwarding", () => {
87
120
 
88
121
  const value =
89
122
  callbackName === "onFinish"
90
- ? { status: "ready" }
123
+ ? { status: "idle" }
91
124
  : callbackName === "onError"
92
125
  ? new Error("run failed")
93
126
  : {};
@@ -104,7 +137,7 @@ describe("useEveAgentRuntime status forwarding", () => {
104
137
 
105
138
  it("maps the session error onto the interrupted assistant message", () => {
106
139
  mockUseEveAgent.mockReturnValue(
107
- createAgent({ status: "error", error: new Error("boom") }) as never,
140
+ createAgent({ status: "idle", error: new Error("boom") }) as never,
108
141
  );
109
142
 
110
143
  const { result } = renderHook(() => useEveAgentRuntime());
@@ -117,7 +150,7 @@ describe("useEveAgentRuntime status forwarding", () => {
117
150
  });
118
151
 
119
152
  it("settles an aborted turn to cancelled once the agent is idle", () => {
120
- mockUseEveAgent.mockReturnValue(createAgent({ status: "ready" }) as never);
153
+ mockUseEveAgent.mockReturnValue(createAgent({ status: "idle" }) as never);
121
154
 
122
155
  const { result } = renderHook(() => useEveAgentRuntime());
123
156
 
@@ -128,7 +161,7 @@ describe("useEveAgentRuntime status forwarding", () => {
128
161
  });
129
162
 
130
163
  it("recomputes statuses when only the session error changes", () => {
131
- const idle = createAgent({ status: "ready" });
164
+ const idle = createAgent({ status: "idle" });
132
165
  mockUseEveAgent.mockReturnValue(idle as never);
133
166
 
134
167
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
@@ -140,7 +173,7 @@ describe("useEveAgentRuntime status forwarding", () => {
140
173
 
141
174
  mockUseEveAgent.mockReturnValue({
142
175
  ...idle,
143
- status: "error",
176
+ status: "idle",
144
177
  error: new Error("boom"),
145
178
  } as never);
146
179
  rerender();
@@ -154,7 +187,7 @@ describe("useEveAgentRuntime status forwarding", () => {
154
187
 
155
188
  it("forwards runConfig to eve as one-turn client context when sending", async () => {
156
189
  const agent = createAgent({
157
- data: { messages: [] } satisfies EveMessageData,
190
+ messages: [],
158
191
  });
159
192
  mockUseEveAgent.mockReturnValue(agent as never);
160
193
 
@@ -177,7 +210,7 @@ describe("useEveAgentRuntime status forwarding", () => {
177
210
 
178
211
  it("omits clientContext when no runConfig is provided", async () => {
179
212
  const agent = createAgent({
180
- data: { messages: [] } satisfies EveMessageData,
213
+ messages: [],
181
214
  });
182
215
  mockUseEveAgent.mockReturnValue(agent as never);
183
216
 
@@ -197,7 +230,7 @@ describe("useEveAgentRuntime status forwarding", () => {
197
230
 
198
231
  it("omits clientContext when runConfig.custom is empty", async () => {
199
232
  const agent = createAgent({
200
- data: { messages: [] } satisfies EveMessageData,
233
+ messages: [],
201
234
  });
202
235
  mockUseEveAgent.mockReturnValue(agent as never);
203
236
 
@@ -218,7 +251,7 @@ describe("useEveAgentRuntime status forwarding", () => {
218
251
 
219
252
  it("prefers the reload-time runConfig over the staged one", async () => {
220
253
  const agent = createAgent({
221
- data: { messages: [] } satisfies EveMessageData,
254
+ messages: [],
222
255
  });
223
256
  mockUseEveAgent.mockReturnValue(agent as never);
224
257
 
@@ -254,7 +287,7 @@ describe("useEveAgentRuntime status forwarding", () => {
254
287
 
255
288
  it("falls back to the staged runConfig when reload passes none", async () => {
256
289
  const agent = createAgent({
257
- data: { messages: [] } satisfies EveMessageData,
290
+ messages: [],
258
291
  });
259
292
  mockUseEveAgent.mockReturnValue(agent as never);
260
293
 
@@ -291,7 +324,7 @@ describe("useEveAgentRuntime status forwarding", () => {
291
324
  // the adapter and cannot clear the staged context.
292
325
  it("cannot clear the staged runConfig with an explicit empty reload config", async () => {
293
326
  const agent = createAgent({
294
- data: { messages: [] } satisfies EveMessageData,
327
+ messages: [],
295
328
  });
296
329
  mockUseEveAgent.mockReturnValue(agent as never);
297
330
 
@@ -323,9 +356,7 @@ describe("useEveAgentRuntime status forwarding", () => {
323
356
  });
324
357
 
325
358
  it("keeps the last assistant message running while streaming", () => {
326
- mockUseEveAgent.mockReturnValue(
327
- createAgent({ status: "streaming" }) as never,
328
- );
359
+ mockUseEveAgent.mockReturnValue(createAgent({ status: "busy" }) as never);
329
360
 
330
361
  const { result } = renderHook(() => useEveAgentRuntime());
331
362
 
@@ -336,7 +367,7 @@ describe("useEveAgentRuntime status forwarding", () => {
336
367
  });
337
368
 
338
369
  describe("useEveAgentRuntime tool approval responses", () => {
339
- const textRequestData: EveMessageData = {
370
+ const textRequestData: MessageFixture = {
340
371
  messages: [
341
372
  { id: "u1", role: "user", parts: [{ type: "text", text: "hi" }] },
342
373
  {
@@ -344,22 +375,23 @@ describe("useEveAgentRuntime tool approval responses", () => {
344
375
  role: "assistant",
345
376
  parts: [
346
377
  {
347
- type: "dynamic-tool",
348
- state: "approval-requested",
349
- toolCallId: "call_1",
350
- toolName: "ask_question",
378
+ type: "tool",
379
+ state: "approval",
380
+ callId: "call_1",
381
+ stepIndex: 0,
382
+ kind: "tool",
383
+ name: "ask_question",
384
+ label: "ask_question",
351
385
  input: {},
352
- approval: { id: "req_1" },
353
- toolMetadata: {
354
- eve: {
355
- kind: "tool-call",
356
- name: "ask_question",
357
- inputRequest: {
358
- requestId: "req_1",
359
- prompt: "What should the subject line be?",
360
- kind: "question",
361
- display: "text",
362
- },
386
+ interaction: {
387
+ interactionId: "req_1",
388
+ turnId: "t1",
389
+ stepIndex: 0,
390
+ status: "open",
391
+ request: {
392
+ prompt: "What should the subject line be?",
393
+ kind: "question",
394
+ display: "text",
363
395
  },
364
396
  },
365
397
  },
@@ -371,11 +403,6 @@ describe("useEveAgentRuntime tool approval responses", () => {
371
403
  const flushMicrotasks = () =>
372
404
  new Promise((resolve) => setTimeout(resolve, 0));
373
405
 
374
- const processEvents = process as unknown as {
375
- on(event: "unhandledRejection", listener: (reason: unknown) => void): void;
376
- off(event: "unhandledRejection", listener: (reason: unknown) => void): void;
377
- };
378
-
379
406
  const respondToTextRequest = (
380
407
  result: { current: ReturnType<typeof useEveAgentRuntime> },
381
408
  response: { approved: boolean; reason?: string; optionId?: string },
@@ -386,14 +413,85 @@ describe("useEveAgentRuntime tool approval responses", () => {
386
413
  .respondToToolApproval(response);
387
414
 
388
415
  it("keeps an unanswered free-form request pending through the default controls", async () => {
416
+ const pausedEvents: readonly SessionEvent[] = [
417
+ { type: "session.started", data: {} },
418
+ { type: "delivery.admitted", data: { deliveryId: "d1" } },
419
+ {
420
+ type: "turn.started",
421
+ data: {
422
+ turnId: "t1",
423
+ cause: { deliveryId: "d1" },
424
+ follows: null,
425
+ },
426
+ },
427
+ {
428
+ type: "delivery.consumed",
429
+ data: {
430
+ deliveryId: "d1",
431
+ turnId: "t1",
432
+ parts: [{ kind: "text", text: "hi" }],
433
+ },
434
+ },
435
+ {
436
+ type: "interaction.opened",
437
+ data: {
438
+ interactionId: "req_1",
439
+ subject: { turnId: "t1" },
440
+ request: {
441
+ kind: "question",
442
+ prompt: "What should the subject line be?",
443
+ display: "text",
444
+ },
445
+ },
446
+ },
447
+ {
448
+ type: "turn.paused",
449
+ data: { turnId: "t1", awaiting: [{ interactionId: "req_1" }] },
450
+ },
451
+ {
452
+ type: "delivery.settled",
453
+ data: {
454
+ deliveryId: "d1",
455
+ turnId: "t1",
456
+ outcome: "awaiting-input",
457
+ },
458
+ },
459
+ ];
460
+ const view = foldEvents(
461
+ emptySessionView(),
462
+ createEveEvents(
463
+ pausedEvents.map((event) => ({
464
+ at: "2026-01-02T10:00:00.000Z",
465
+ event,
466
+ })),
467
+ ),
468
+ );
469
+ expect(activeTurn(view)?.turnId).toBe("t1");
470
+ expect(idle(view)).toBe(true);
389
471
  const rejections: unknown[] = [];
390
472
  const onUnhandledRejection = (reason: unknown) => rejections.push(reason);
473
+ const processEvents = process as {
474
+ env: typeof process.env;
475
+ on(
476
+ event: "unhandledRejection",
477
+ listener: (reason: unknown) => void,
478
+ ): void;
479
+ off(
480
+ event: "unhandledRejection",
481
+ listener: (reason: unknown) => void,
482
+ ): void;
483
+ };
391
484
  processEvents.on("unhandledRejection", onUnhandledRejection);
392
- const agent = createAgent({ data: textRequestData });
485
+ const agent = createAgent({ messages: textRequestData.messages, view });
393
486
  mockUseEveAgent.mockReturnValue(agent as never);
394
487
 
395
488
  try {
396
489
  const { result } = renderHook(() => useEveAgentRuntime());
490
+ expect(result.current.thread.getState().isRunning).toBe(false);
491
+ expect(result.current.thread.getState().messages.at(-1)?.status).toEqual({
492
+ type: "requires-action",
493
+ reason: "tool-calls",
494
+ });
397
495
 
398
496
  await expect(
399
497
  respondToTextRequest(result, { approved: true }),
@@ -410,89 +508,53 @@ describe("useEveAgentRuntime tool approval responses", () => {
410
508
  }
411
509
  });
412
510
 
413
- const bareApprovalData = (toolMetadata?: {
414
- eve: { kind: "tool-call"; name: string };
415
- }): EveMessageData => ({
416
- messages: [
417
- { id: "u1", role: "user", parts: [{ type: "text", text: "hi" }] },
418
- {
419
- id: "a1",
420
- role: "assistant",
421
- parts: [
422
- {
423
- type: "dynamic-tool",
424
- state: "approval-requested",
425
- toolCallId: "call_1",
426
- toolName: "delete_file",
427
- input: {},
428
- approval: { id: "req_1" },
429
- ...(toolMetadata && { toolMetadata }),
430
- },
431
- ],
432
- },
433
- ],
434
- });
435
-
436
- it.each([
437
- ["no eve tool metadata at all", undefined],
438
- [
439
- "eve metadata carrying no input request",
440
- { eve: { kind: "tool-call", name: "delete_file" } },
441
- ],
442
- ])(
443
- "still answers an ordinary approval when the part has %s",
444
- async (_label, toolMetadata) => {
445
- const agent = createAgent({
446
- data: bareApprovalData(toolMetadata as never),
447
- });
448
- mockUseEveAgent.mockReturnValue(agent as never);
511
+ it("submits a free-form answer as text without an option id", async () => {
512
+ const agent = createAgent({ messages: textRequestData.messages });
513
+ mockUseEveAgent.mockReturnValue(agent as never);
449
514
 
450
- const { result } = renderHook(() => useEveAgentRuntime());
451
- expect(() =>
452
- respondToTextRequest(result, { approved: true }),
453
- ).not.toThrow();
515
+ const { result } = renderHook(() => useEveAgentRuntime());
516
+ respondToTextRequest(result, {
517
+ approved: true,
518
+ reason: "Quarterly results",
519
+ });
454
520
 
455
- await flushMicrotasks();
521
+ await flushMicrotasks();
456
522
 
457
- expect(agent.respond).toHaveBeenCalledWith([
458
- { requestId: "req_1", optionId: "approve" },
459
- ]);
460
- },
461
- );
523
+ expect(agent.respond).toHaveBeenCalledWith([
524
+ { interactionId: "req_1", text: "Quarterly results" },
525
+ ]);
526
+ });
462
527
 
463
- it("maps a refusal on a request the data does not carry", async () => {
464
- const agent = createAgent({ data: bareApprovalData(undefined) });
528
+ it("submits an approval using the interaction's option id", async () => {
529
+ const agent = createAgent({ messages: approvalData.messages });
465
530
  mockUseEveAgent.mockReturnValue(agent as never);
466
531
 
467
532
  const { result } = renderHook(() => useEveAgentRuntime());
468
- respondToTextRequest(result, { approved: false, reason: "not safe" });
533
+ respondToTextRequest(result, { approved: true });
469
534
 
470
535
  await flushMicrotasks();
471
536
 
472
537
  expect(agent.respond).toHaveBeenCalledWith([
473
- { requestId: "req_1", optionId: "cancel", text: "not safe" },
538
+ { interactionId: "req_1", optionId: "approve" },
474
539
  ]);
475
540
  });
476
541
 
477
- it("submits a free-form answer as text without an option id", async () => {
478
- const agent = createAgent({ data: textRequestData });
542
+ it("maps a refusal to eve's deny option", async () => {
543
+ const agent = createAgent({ messages: approvalData.messages });
479
544
  mockUseEveAgent.mockReturnValue(agent as never);
480
545
 
481
546
  const { result } = renderHook(() => useEveAgentRuntime());
482
- respondToTextRequest(result, {
483
- approved: true,
484
- reason: "Quarterly results",
485
- });
547
+ respondToTextRequest(result, { approved: false, reason: "not safe" });
486
548
 
487
549
  await flushMicrotasks();
488
550
 
489
551
  expect(agent.respond).toHaveBeenCalledWith([
490
- { requestId: "req_1", text: "Quarterly results" },
552
+ { interactionId: "req_1", optionId: "deny", text: "not safe" },
491
553
  ]);
492
554
  });
493
555
  });
494
556
 
495
- const settledData: EveMessageData = {
557
+ const settledData: MessageFixture = {
496
558
  messages: [
497
559
  { id: "u1", role: "user", parts: [{ type: "text", text: "earlier" }] },
498
560
  {
@@ -503,7 +565,7 @@ const settledData: EveMessageData = {
503
565
  ],
504
566
  };
505
567
 
506
- const executingToolData: EveMessageData = {
568
+ const executingToolData: MessageFixture = {
507
569
  messages: [
508
570
  { id: "u1", role: "user", parts: [{ type: "text", text: "run it" }] },
509
571
  {
@@ -511,10 +573,13 @@ const executingToolData: EveMessageData = {
511
573
  role: "assistant",
512
574
  parts: [
513
575
  {
514
- type: "dynamic-tool",
515
- state: "input-available",
516
- toolCallId: "call_slow",
517
- toolName: "slow_tool",
576
+ type: "tool",
577
+ state: "running",
578
+ callId: "call_slow",
579
+ stepIndex: 0,
580
+ kind: "tool",
581
+ name: "slow_tool",
582
+ label: "slow_tool",
518
583
  input: {},
519
584
  },
520
585
  ],
@@ -522,7 +587,7 @@ const executingToolData: EveMessageData = {
522
587
  ],
523
588
  };
524
589
 
525
- const twoExecutingToolsData: EveMessageData = {
590
+ const twoExecutingToolsData: MessageFixture = {
526
591
  messages: [
527
592
  { id: "u1", role: "user", parts: [{ type: "text", text: "run them" }] },
528
593
  {
@@ -530,17 +595,23 @@ const twoExecutingToolsData: EveMessageData = {
530
595
  role: "assistant",
531
596
  parts: [
532
597
  {
533
- type: "dynamic-tool",
534
- state: "input-available",
535
- toolCallId: "call_slow_a",
536
- toolName: "slow_tool",
598
+ type: "tool",
599
+ state: "running",
600
+ callId: "call_slow_a",
601
+ stepIndex: 0,
602
+ kind: "tool",
603
+ name: "slow_tool",
604
+ label: "slow_tool",
537
605
  input: {},
538
606
  },
539
607
  {
540
- type: "dynamic-tool",
541
- state: "input-available",
542
- toolCallId: "call_slow_b",
543
- toolName: "slow_tool",
608
+ type: "tool",
609
+ state: "running",
610
+ callId: "call_slow_b",
611
+ stepIndex: 0,
612
+ kind: "tool",
613
+ name: "slow_tool",
614
+ label: "slow_tool",
544
615
  input: {},
545
616
  },
546
617
  ],
@@ -572,7 +643,7 @@ const stageMessage = async (
572
643
 
573
644
  describe("useEveAgentRuntime staged messages", () => {
574
645
  it("stages a user message without submitting when startRun is false", async () => {
575
- const agent = createAgent({ data: settledData });
646
+ const agent = createAgent({ messages: settledData.messages });
576
647
  mockUseEveAgent.mockReturnValue(agent as never);
577
648
  const { result } = renderHook(() => useEveAgentRuntime());
578
649
 
@@ -589,7 +660,7 @@ describe("useEveAgentRuntime staged messages", () => {
589
660
  });
590
661
 
591
662
  it("renders new turns and refloats staged drafts after a normal send", async () => {
592
- const agent = createAgent({ data: settledData });
663
+ const agent = createAgent({ messages: settledData.messages });
593
664
  mockUseEveAgent.mockReturnValue(agent as never);
594
665
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
595
666
 
@@ -605,21 +676,19 @@ describe("useEveAgentRuntime staged messages", () => {
605
676
 
606
677
  mockUseEveAgent.mockReturnValue(
607
678
  createAgent({
608
- data: {
609
- messages: [
610
- ...settledData.messages,
611
- {
612
- id: "u2",
613
- role: "user",
614
- parts: [{ type: "text", text: "hello" }],
615
- },
616
- {
617
- id: "a2",
618
- role: "assistant",
619
- parts: [{ type: "text", text: "hi there" }],
620
- },
621
- ],
622
- },
679
+ messages: [
680
+ ...settledData.messages,
681
+ {
682
+ id: "u2",
683
+ role: "user",
684
+ parts: [{ type: "text", text: "hello" }],
685
+ },
686
+ {
687
+ id: "a2",
688
+ role: "assistant",
689
+ parts: [{ type: "text", text: "hi there" }],
690
+ },
691
+ ],
623
692
  send: agent.send,
624
693
  }) as never,
625
694
  );
@@ -637,7 +706,7 @@ describe("useEveAgentRuntime staged messages", () => {
637
706
  });
638
707
 
639
708
  it("keeps both drafts when two appends stage in the same batch", async () => {
640
- const agent = createAgent({ data: settledData });
709
+ const agent = createAgent({ messages: settledData.messages });
641
710
  mockUseEveAgent.mockReturnValue(agent as never);
642
711
  const { result } = renderHook(() => useEveAgentRuntime());
643
712
 
@@ -672,7 +741,7 @@ describe("useEveAgentRuntime staged messages", () => {
672
741
  new Error("eve session is already processing a turn."),
673
742
  )
674
743
  .mockResolvedValue(undefined);
675
- const agent = createAgent({ data: settledData, send });
744
+ const agent = createAgent({ messages: settledData.messages, send });
676
745
  mockUseEveAgent.mockReturnValue(agent as never);
677
746
  const { result } = renderHook(() => useEveAgentRuntime());
678
747
 
@@ -717,7 +786,7 @@ describe("useEveAgentRuntime staged messages", () => {
717
786
  });
718
787
 
719
788
  it("applies the reload runConfig only to the message being reloaded", async () => {
720
- const agent = createAgent({ data: settledData });
789
+ const agent = createAgent({ messages: settledData.messages });
721
790
  mockUseEveAgent.mockReturnValue(agent as never);
722
791
  const { result } = renderHook(() => useEveAgentRuntime());
723
792
 
@@ -755,7 +824,7 @@ describe("useEveAgentRuntime staged messages", () => {
755
824
  });
756
825
 
757
826
  it("keeps later staged messages visible after promoting one staged parent", async () => {
758
- const agent = createAgent({ data: settledData });
827
+ const agent = createAgent({ messages: settledData.messages });
759
828
  mockUseEveAgent.mockReturnValue(agent as never);
760
829
  const { result } = renderHook(() => useEveAgentRuntime());
761
830
 
@@ -793,7 +862,7 @@ describe("useEveAgentRuntime staged messages", () => {
793
862
  }),
794
863
  )
795
864
  .mockResolvedValue(undefined);
796
- const agent = createAgent({ data: settledData, send });
865
+ const agent = createAgent({ messages: settledData.messages, send });
797
866
  mockUseEveAgent.mockReturnValue(agent as never);
798
867
  const { result } = renderHook(() => useEveAgentRuntime());
799
868
 
@@ -835,14 +904,14 @@ describe("useEveAgentRuntime staged messages", () => {
835
904
  });
836
905
 
837
906
  it("keeps staged drafts when the session collapses to empty", async () => {
838
- const agent = createAgent({ data: settledData });
907
+ const agent = createAgent({ messages: settledData.messages });
839
908
  mockUseEveAgent.mockReturnValue(agent as never);
840
909
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
841
910
 
842
911
  await stageMessage(result.current, "staged draft");
843
912
 
844
913
  mockUseEveAgent.mockReturnValue(
845
- createAgent({ data: { messages: [] }, send: agent.send }) as never,
914
+ createAgent({ messages: [], send: agent.send }) as never,
846
915
  );
847
916
  rerender();
848
917
 
@@ -852,17 +921,9 @@ describe("useEveAgentRuntime staged messages", () => {
852
921
  });
853
922
 
854
923
  it("stops promoting once a promoted turn parks with an error status", async () => {
855
- let capturedOptions: {
856
- onFinish?: (snapshot: { status: string }) => void;
857
- } = {};
858
- const send = vi.fn().mockImplementation(async () => {
859
- capturedOptions.onFinish?.({ status: "error" });
860
- });
861
- const agent = createAgent({ data: settledData, send });
862
- mockUseEveAgent.mockImplementation((options) => {
863
- capturedOptions = options as typeof capturedOptions;
864
- return agent as never;
865
- });
924
+ const send = vi.fn().mockResolvedValue(createEveDelivery("failed"));
925
+ const agent = createAgent({ messages: settledData.messages, send });
926
+ mockUseEveAgent.mockReturnValue(agent as never);
866
927
  const { result } = renderHook(() => useEveAgentRuntime());
867
928
 
868
929
  await stageMessage(result.current, "first staged");
@@ -899,7 +960,7 @@ describe("useEveAgentRuntime staged messages", () => {
899
960
  }),
900
961
  )
901
962
  .mockResolvedValue(undefined);
902
- const agent = createAgent({ data: settledData, send });
963
+ const agent = createAgent({ messages: settledData.messages, send });
903
964
  mockUseEveAgent.mockReturnValue(agent as never);
904
965
  const { result } = renderHook(() => useEveAgentRuntime());
905
966
 
@@ -934,7 +995,7 @@ describe("useEveAgentRuntime staged messages", () => {
934
995
  });
935
996
 
936
997
  it("still rejects reloading a non-staged message", async () => {
937
- const agent = createAgent({ data: settledData });
998
+ const agent = createAgent({ messages: settledData.messages });
938
999
  mockUseEveAgent.mockReturnValue(agent as never);
939
1000
  const { result } = renderHook(() => useEveAgentRuntime());
940
1001
 
@@ -959,7 +1020,7 @@ describe("useEveAgentRuntime extras wiring", () => {
959
1020
  const events = [{ type: "session.started" }];
960
1021
  const session = { sessionId: "s1" };
961
1022
  mockUseEveAgent.mockReturnValue(
962
- createAgent({ status: "error", error, events, session }) as never,
1023
+ createAgent({ status: "idle", error, events, session }) as never,
963
1024
  );
964
1025
 
965
1026
  const { result } = renderHook(() => useEveAgentRuntime());
@@ -970,7 +1031,7 @@ describe("useEveAgentRuntime extras wiring", () => {
970
1031
  });
971
1032
 
972
1033
  it("discards staged inputs when reset is invoked", async () => {
973
- const agent = createAgent({ data: settledData });
1034
+ const agent = createAgent({ messages: settledData.messages });
974
1035
  mockUseEveAgent.mockReturnValue(agent as never);
975
1036
  const { result } = renderHook(() => useEveAgentRuntime());
976
1037
 
@@ -998,11 +1059,11 @@ describe("useEveAgentRuntime extras wiring", () => {
998
1059
  ),
999
1060
  ).rejects.toThrow("Runtime does not support reloading messages.");
1000
1061
  expect(agent.send).not.toHaveBeenCalled();
1001
- expect(agent.reset).toHaveBeenCalledTimes(1);
1062
+ expect(agent.newSession).toHaveBeenCalledTimes(1);
1002
1063
  });
1003
1064
 
1004
1065
  it("clears executing tool state when reset is invoked", async () => {
1005
- const agent = createAgent({ data: settledData });
1066
+ const agent = createAgent({ messages: settledData.messages });
1006
1067
  mockUseEveAgent.mockReturnValue(agent as never);
1007
1068
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
1008
1069
 
@@ -1022,7 +1083,10 @@ describe("useEveAgentRuntime extras wiring", () => {
1022
1083
  // The tracker treats its first snapshot as historical, so the tool call
1023
1084
  // has to arrive on a later one to actually execute.
1024
1085
  mockUseEveAgent.mockReturnValue(
1025
- createAgent({ data: executingToolData, reset: agent.reset }) as never,
1086
+ createAgent({
1087
+ messages: executingToolData.messages,
1088
+ newSession: agent.newSession,
1089
+ }) as never,
1026
1090
  );
1027
1091
  rerender();
1028
1092
 
@@ -1037,7 +1101,7 @@ describe("useEveAgentRuntime extras wiring", () => {
1037
1101
  await waitFor(() => {
1038
1102
  expect(result.current.thread.getState().isRunning).toBe(false);
1039
1103
  });
1040
- expect(agent.reset).toHaveBeenCalledTimes(1);
1104
+ expect(agent.newSession).toHaveBeenCalledTimes(1);
1041
1105
  });
1042
1106
 
1043
1107
  it("drops a send queued behind an active turn when reset is invoked", async () => {
@@ -1051,7 +1115,7 @@ describe("useEveAgentRuntime extras wiring", () => {
1051
1115
  }),
1052
1116
  )
1053
1117
  .mockResolvedValue(undefined);
1054
- const agent = createAgent({ data: settledData, send });
1118
+ const agent = createAgent({ messages: settledData.messages, send });
1055
1119
  mockUseEveAgent.mockReturnValue(agent as never);
1056
1120
  const { result } = renderHook(() => useEveAgentRuntime());
1057
1121
 
@@ -1104,7 +1168,7 @@ describe("useEveAgentRuntime extras wiring", () => {
1104
1168
  }),
1105
1169
  )
1106
1170
  .mockResolvedValue(undefined);
1107
- const agent = createAgent({ data: settledData, send });
1171
+ const agent = createAgent({ messages: settledData.messages, send });
1108
1172
  mockUseEveAgent.mockReturnValue(agent as never);
1109
1173
  const { result } = renderHook(() => useEveAgentRuntime());
1110
1174
 
@@ -1140,7 +1204,7 @@ describe("useEveAgentRuntime extras wiring", () => {
1140
1204
  });
1141
1205
 
1142
1206
  expect(send).toHaveBeenCalledTimes(1);
1143
- expect(agent.stop).toHaveBeenCalledTimes(1);
1207
+ expect(agent.cancel).toHaveBeenCalledTimes(1);
1144
1208
  await waitFor(() => {
1145
1209
  expect(getText(result.current)).toEqual([
1146
1210
  "earlier",
@@ -1153,10 +1217,13 @@ describe("useEveAgentRuntime extras wiring", () => {
1153
1217
  it("aborts client tool executions when reset is invoked", async () => {
1154
1218
  const agentReset = vi.fn(() => {
1155
1219
  mockUseEveAgent.mockReturnValue(
1156
- createAgent({ data: { messages: [] }, reset: agentReset }) as never,
1220
+ createAgent({ messages: [], newSession: agentReset }) as never,
1157
1221
  );
1158
1222
  });
1159
- const agent = createAgent({ data: settledData, reset: agentReset });
1223
+ const agent = createAgent({
1224
+ messages: settledData.messages,
1225
+ newSession: agentReset,
1226
+ });
1160
1227
  mockUseEveAgent.mockReturnValue(agent as never);
1161
1228
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
1162
1229
 
@@ -1183,7 +1250,10 @@ describe("useEveAgentRuntime extras wiring", () => {
1183
1250
  });
1184
1251
 
1185
1252
  mockUseEveAgent.mockReturnValue(
1186
- createAgent({ data: twoExecutingToolsData, reset: agentReset }) as never,
1253
+ createAgent({
1254
+ messages: twoExecutingToolsData.messages,
1255
+ newSession: agentReset,
1256
+ }) as never,
1187
1257
  );
1188
1258
  rerender();
1189
1259
 
@@ -1205,10 +1275,13 @@ describe("useEveAgentRuntime extras wiring", () => {
1205
1275
  it("rejects a pending human-input request when reset is invoked", async () => {
1206
1276
  const agentReset = vi.fn(() => {
1207
1277
  mockUseEveAgent.mockReturnValue(
1208
- createAgent({ data: { messages: [] }, reset: agentReset }) as never,
1278
+ createAgent({ messages: [], newSession: agentReset }) as never,
1209
1279
  );
1210
1280
  });
1211
- const agent = createAgent({ data: settledData, reset: agentReset });
1281
+ const agent = createAgent({
1282
+ messages: settledData.messages,
1283
+ newSession: agentReset,
1284
+ });
1212
1285
  mockUseEveAgent.mockReturnValue(agent as never);
1213
1286
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
1214
1287
 
@@ -1239,7 +1312,10 @@ describe("useEveAgentRuntime extras wiring", () => {
1239
1312
  });
1240
1313
 
1241
1314
  mockUseEveAgent.mockReturnValue(
1242
- createAgent({ data: twoExecutingToolsData, reset: agentReset }) as never,
1315
+ createAgent({
1316
+ messages: twoExecutingToolsData.messages,
1317
+ newSession: agentReset,
1318
+ }) as never,
1243
1319
  );
1244
1320
  rerender();
1245
1321
 
@@ -1264,10 +1340,13 @@ describe("useEveAgentRuntime extras wiring", () => {
1264
1340
  const releases: Record<string, () => void> = {};
1265
1341
  const agentReset = vi.fn(() => {
1266
1342
  mockUseEveAgent.mockReturnValue(
1267
- createAgent({ data: { messages: [] }, reset: agentReset }) as never,
1343
+ createAgent({ messages: [], newSession: agentReset }) as never,
1268
1344
  );
1269
1345
  });
1270
- const agent = createAgent({ data: settledData, reset: agentReset });
1346
+ const agent = createAgent({
1347
+ messages: settledData.messages,
1348
+ newSession: agentReset,
1349
+ });
1271
1350
  mockUseEveAgent.mockReturnValue(agent as never);
1272
1351
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
1273
1352
 
@@ -1290,8 +1369,8 @@ describe("useEveAgentRuntime extras wiring", () => {
1290
1369
 
1291
1370
  mockUseEveAgent.mockReturnValue(
1292
1371
  createAgent({
1293
- data: twoExecutingToolsData,
1294
- reset: agentReset,
1372
+ messages: twoExecutingToolsData.messages,
1373
+ newSession: agentReset,
1295
1374
  }) as never,
1296
1375
  );
1297
1376
  rerender();
@@ -1321,21 +1400,24 @@ describe("useEveAgentRuntime extras wiring", () => {
1321
1400
  });
1322
1401
 
1323
1402
  it("promotes every staged draft after reset when the discarded run failed", async () => {
1324
- const send = vi.fn().mockResolvedValue(undefined);
1325
- const agent = createAgent({ data: settledData, send });
1326
- let capturedOptions: { onFinish?: (snapshot: unknown) => void } = {};
1327
- mockUseEveAgent.mockImplementation((options) => {
1328
- capturedOptions = options as typeof capturedOptions;
1329
- return agent as never;
1330
- });
1403
+ const send = vi
1404
+ .fn()
1405
+ .mockResolvedValueOnce(createEveDelivery("failed"))
1406
+ .mockResolvedValue(createEveDelivery());
1407
+ const agent = createAgent({ messages: settledData.messages, send });
1408
+ mockUseEveAgent.mockReturnValue(agent as never);
1331
1409
  const { result } = renderHook(() => useEveAgentRuntime());
1332
1410
 
1333
- act(() => {
1334
- capturedOptions.onFinish?.({ status: "error" });
1411
+ await stageMessage(result.current, "discarded draft");
1412
+ const discardedId = result.current.thread.getState().messages[2]!.id;
1413
+ await act(async () => {
1414
+ await result.current.thread.startRun({ parentId: discardedId });
1335
1415
  });
1416
+ expect(send).toHaveBeenCalledTimes(1);
1336
1417
  act(() => {
1337
1418
  eveExtras.tryGet(result.current.thread.getState().extras)!.reset();
1338
1419
  });
1420
+ send.mockClear();
1339
1421
 
1340
1422
  await stageMessage(result.current, "first staged");
1341
1423
  await stageMessage(result.current, "second staged");
@@ -1355,7 +1437,7 @@ describe("useEveAgentRuntime extras wiring", () => {
1355
1437
  });
1356
1438
  });
1357
1439
 
1358
- const approvalData: EveMessageData = {
1440
+ const approvalData: MessageFixture = {
1359
1441
  messages: [
1360
1442
  { id: "u1", role: "user", parts: [{ type: "text", text: "send it" }] },
1361
1443
  {
@@ -1363,26 +1445,27 @@ const approvalData: EveMessageData = {
1363
1445
  role: "assistant",
1364
1446
  parts: [
1365
1447
  {
1366
- type: "dynamic-tool",
1367
- state: "approval-requested",
1368
- toolCallId: "call_1",
1369
- toolName: "send_email",
1448
+ type: "tool",
1449
+ state: "approval",
1450
+ callId: "call_1",
1451
+ stepIndex: 0,
1452
+ kind: "tool",
1453
+ name: "send_email",
1454
+ label: "send_email",
1370
1455
  input: { to: "dev@example.com" },
1371
- approval: { id: "req_1" },
1372
- toolMetadata: {
1373
- eve: {
1374
- kind: "tool-call",
1375
- name: "send_email",
1376
- inputRequest: {
1377
- requestId: "req_1",
1378
- kind: "tool-approval",
1379
- prompt: "Send the email?",
1380
- display: "confirmation",
1381
- options: [
1382
- { id: "approve", label: "Approve" },
1383
- { id: "cancel", label: "Cancel" },
1384
- ],
1385
- },
1456
+ interaction: {
1457
+ interactionId: "req_1",
1458
+ turnId: "t1",
1459
+ stepIndex: 0,
1460
+ status: "open",
1461
+ request: {
1462
+ kind: "approval",
1463
+ prompt: "Send the email?",
1464
+ display: "confirmation",
1465
+ options: [
1466
+ { id: "approve", label: "Approve" },
1467
+ { id: "deny", label: "Deny" },
1468
+ ],
1386
1469
  },
1387
1470
  },
1388
1471
  },
@@ -1401,7 +1484,11 @@ describe("useEveAgentRuntime concurrent sends", () => {
1401
1484
  }),
1402
1485
  );
1403
1486
  const respond = vi.fn().mockResolvedValue(undefined);
1404
- const agent = createAgent({ data: approvalData, send, respond });
1487
+ const agent = createAgent({
1488
+ messages: approvalData.messages,
1489
+ send,
1490
+ respond,
1491
+ });
1405
1492
  mockUseEveAgent.mockReturnValue(agent as never);
1406
1493
  const { result } = renderHook(() => useEveAgentRuntime());
1407
1494
 
@@ -1426,7 +1513,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1426
1513
  });
1427
1514
  await waitFor(() => expect(respond).toHaveBeenCalledTimes(1));
1428
1515
  expect(respond).toHaveBeenCalledWith([
1429
- { requestId: "req_1", optionId: "approve" },
1516
+ { interactionId: "req_1", optionId: "approve" },
1430
1517
  ]);
1431
1518
  });
1432
1519
 
@@ -1441,7 +1528,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1441
1528
  }),
1442
1529
  )
1443
1530
  .mockResolvedValue(undefined);
1444
- const agent = createAgent({ data: settledData, send });
1531
+ const agent = createAgent({ messages: settledData.messages, send });
1445
1532
  mockUseEveAgent.mockReturnValue(agent as never);
1446
1533
  const { result } = renderHook(() => useEveAgentRuntime());
1447
1534
 
@@ -1480,7 +1567,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1480
1567
  }),
1481
1568
  )
1482
1569
  .mockResolvedValue(undefined);
1483
- const agent = createAgent({ data: settledData, send });
1570
+ const agent = createAgent({ messages: settledData.messages, send });
1484
1571
  mockUseEveAgent.mockReturnValue(agent as never);
1485
1572
  const { result } = renderHook(() => useEveAgentRuntime());
1486
1573
 
@@ -1501,7 +1588,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1501
1588
  act(() => {
1502
1589
  result.current.thread.cancelRun();
1503
1590
  });
1504
- expect(agent.stop).toHaveBeenCalledTimes(1);
1591
+ expect(agent.cancel).toHaveBeenCalledTimes(1);
1505
1592
 
1506
1593
  await act(async () => {
1507
1594
  resolveFirstSend();
@@ -1520,7 +1607,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1520
1607
  }),
1521
1608
  )
1522
1609
  .mockResolvedValue(undefined);
1523
- const agent = createAgent({ data: settledData, send });
1610
+ const agent = createAgent({ messages: settledData.messages, send });
1524
1611
  mockUseEveAgent.mockReturnValue(agent as never);
1525
1612
  const { result } = renderHook(() => useEveAgentRuntime());
1526
1613
 
@@ -1566,13 +1653,11 @@ describe("useEveAgentRuntime concurrent sends", () => {
1566
1653
  // Before the turn streams, the dispatched message is the thread's trailing
1567
1654
  // user leaf. Eve owns that message and cannot remove it on cancel.
1568
1655
  const agent = createAgent({
1569
- data: {
1570
- messages: [
1571
- ...settledData.messages,
1572
- { id: "u2", role: "user", parts: [{ type: "text", text: "first" }] },
1573
- ],
1574
- } satisfies EveMessageData,
1575
- status: "submitted",
1656
+ messages: [
1657
+ ...settledData.messages,
1658
+ { id: "u2", role: "user", parts: [{ type: "text", text: "first" }] },
1659
+ ],
1660
+ status: "idle",
1576
1661
  send,
1577
1662
  });
1578
1663
  mockUseEveAgent.mockReturnValue(agent as never);
@@ -1612,7 +1697,11 @@ describe("useEveAgentRuntime concurrent sends", () => {
1612
1697
  }),
1613
1698
  );
1614
1699
  const respond = vi.fn().mockResolvedValue(undefined);
1615
- const agent = createAgent({ data: approvalData, send, respond });
1700
+ const agent = createAgent({
1701
+ messages: approvalData.messages,
1702
+ send,
1703
+ respond,
1704
+ });
1616
1705
  mockUseEveAgent.mockReturnValue(agent as never);
1617
1706
  const { result } = renderHook(() => useEveAgentRuntime());
1618
1707
  const before = getText(result.current);
@@ -1655,7 +1744,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1655
1744
  }),
1656
1745
  )
1657
1746
  .mockResolvedValue(undefined);
1658
- const agent = createAgent({ data: settledData, send });
1747
+ const agent = createAgent({ messages: settledData.messages, send });
1659
1748
  mockUseEveAgent.mockReturnValue(agent as never);
1660
1749
  const { result, unmount } = renderHook(() => useEveAgentRuntime());
1661
1750
 
@@ -1685,7 +1774,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1685
1774
  let capturedOptions: {
1686
1775
  onFinish?: (snapshot: { status: string }) => void;
1687
1776
  } = {};
1688
- const agent = createAgent({ data: settledData });
1777
+ const agent = createAgent({ messages: settledData.messages });
1689
1778
  mockUseEveAgent.mockImplementation((options) => {
1690
1779
  capturedOptions = options as typeof capturedOptions;
1691
1780
  return agent as never;
@@ -1693,9 +1782,9 @@ describe("useEveAgentRuntime concurrent sends", () => {
1693
1782
  const onFinish = vi.fn();
1694
1783
  renderHook(() => useEveAgentRuntime({ onFinish }));
1695
1784
 
1696
- capturedOptions.onFinish?.({ status: "ready" });
1785
+ capturedOptions.onFinish?.({ status: "idle" });
1697
1786
 
1698
- expect(onFinish).toHaveBeenCalledWith({ status: "ready" });
1787
+ expect(onFinish).toHaveBeenCalledWith({ status: "idle" });
1699
1788
  });
1700
1789
 
1701
1790
  it("orders a send issued mid-promotion after the in-flight staged draft", async () => {
@@ -1709,7 +1798,7 @@ describe("useEveAgentRuntime concurrent sends", () => {
1709
1798
  }),
1710
1799
  )
1711
1800
  .mockResolvedValue(undefined);
1712
- const agent = createAgent({ data: settledData, send });
1801
+ const agent = createAgent({ messages: settledData.messages, send });
1713
1802
  mockUseEveAgent.mockReturnValue(agent as never);
1714
1803
  const { result } = renderHook(() => useEveAgentRuntime());
1715
1804
 
@@ -1748,9 +1837,9 @@ describe("useEveAgentRuntime concurrent sends", () => {
1748
1837
  });
1749
1838
 
1750
1839
  describe("useEveAgentRuntime cancel binding", () => {
1751
- it("cancels through the eve 0.38+ cancel binding when the agent provides it", async () => {
1840
+ it("cancels through the eve cancel binding", async () => {
1752
1841
  const cancel = vi.fn().mockResolvedValue({ status: "cancelled" });
1753
- const agent = createAgent({ status: "streaming", cancel });
1842
+ const agent = createAgent({ status: "busy", cancel });
1754
1843
  mockUseEveAgent.mockReturnValue(agent as never);
1755
1844
  const { result } = renderHook(() => useEveAgentRuntime());
1756
1845
 
@@ -1759,19 +1848,6 @@ describe("useEveAgentRuntime cancel binding", () => {
1759
1848
  });
1760
1849
 
1761
1850
  expect(cancel).toHaveBeenCalledTimes(1);
1762
- expect(agent.stop).not.toHaveBeenCalled();
1763
- });
1764
-
1765
- it("falls back to the pre-0.38 stop binding when cancel is absent", async () => {
1766
- const agent = createAgent({ status: "streaming" });
1767
- mockUseEveAgent.mockReturnValue(agent as never);
1768
- const { result } = renderHook(() => useEveAgentRuntime());
1769
-
1770
- await act(async () => {
1771
- result.current.thread.cancelRun();
1772
- });
1773
-
1774
- expect(agent.stop).toHaveBeenCalledTimes(1);
1775
1851
  });
1776
1852
 
1777
1853
  it("drops a queued send when the durable cancel settles late", async () => {
@@ -1792,7 +1868,7 @@ describe("useEveAgentRuntime cancel binding", () => {
1792
1868
  resolveCancel = () => resolve({ status: "cancelled" });
1793
1869
  }),
1794
1870
  );
1795
- const agent = createAgent({ data: settledData, send, cancel });
1871
+ const agent = createAgent({ messages: settledData.messages, send, cancel });
1796
1872
  mockUseEveAgent.mockReturnValue(agent as never);
1797
1873
  const { result } = renderHook(() => useEveAgentRuntime());
1798
1874
 
@@ -1830,28 +1906,24 @@ describe("useEveAgentRuntime thread refetch", () => {
1830
1906
  const resumeA = vi.fn().mockResolvedValue(undefined);
1831
1907
  const resumeB = vi.fn().mockResolvedValue(undefined);
1832
1908
  const agentA = createAgent({
1833
- data: {
1834
- messages: [
1835
- {
1836
- id: "workspace-a",
1837
- role: "user",
1838
- parts: [{ type: "text", text: "workspace A" }],
1839
- },
1840
- ],
1841
- },
1909
+ messages: [
1910
+ {
1911
+ id: "workspace-a",
1912
+ role: "user",
1913
+ parts: [{ type: "text", text: "workspace A" }],
1914
+ },
1915
+ ],
1842
1916
  session,
1843
1917
  resume: resumeA,
1844
1918
  });
1845
1919
  const agentB = createAgent({
1846
- data: {
1847
- messages: [
1848
- {
1849
- id: "workspace-b",
1850
- role: "user",
1851
- parts: [{ type: "text", text: "workspace B" }],
1852
- },
1853
- ],
1854
- },
1920
+ messages: [
1921
+ {
1922
+ id: "workspace-b",
1923
+ role: "user",
1924
+ parts: [{ type: "text", text: "workspace B" }],
1925
+ },
1926
+ ],
1855
1927
  session,
1856
1928
  resume: resumeB,
1857
1929
  });
@@ -2139,19 +2211,6 @@ describe("useEveAgentRuntime thread refetch", () => {
2139
2211
  await waitFor(() => expect(settled).toBe(true));
2140
2212
  expect(resume).not.toHaveBeenCalled();
2141
2213
  });
2142
-
2143
- it("leaves the capability absent when the installed eve has no resume", async () => {
2144
- const agent = createAgent({ session });
2145
- mockUseEveAgent.mockReturnValue(agent as never);
2146
- const { result } = renderHook(() => useEveAgentRuntime());
2147
-
2148
- expect(result.current.thread.getState().capabilities.refetchThread).toBe(
2149
- false,
2150
- );
2151
- await act(async () => {
2152
- await result.current.threads.reloadMainThread();
2153
- });
2154
- });
2155
2214
  });
2156
2215
 
2157
2216
  describe("useEveAgentRuntime createdAt derivation", () => {
@@ -2162,22 +2221,34 @@ describe("useEveAgentRuntime createdAt derivation", () => {
2162
2221
  const turnEvents = [
2163
2222
  {
2164
2223
  type: "turn.started",
2165
- data: { sequence: 1, turnId: TURN },
2166
- meta: { at: "2026-01-02T10:00:00.000Z", id: "evt_1" },
2224
+ data: {
2225
+ turnId: TURN,
2226
+ cause: { deliveryId: "delivery_1" },
2227
+ follows: null,
2228
+ },
2229
+ meta: {
2230
+ at: "2026-01-02T10:00:00.000Z",
2231
+ position: { line: 0, index: 0 },
2232
+ },
2167
2233
  },
2168
2234
  {
2169
- type: "message.received",
2170
- data: { message: "hi", sequence: 2, turnId: TURN },
2171
- meta: { at: USER_AT, id: "evt_2" },
2235
+ type: "delivery.consumed",
2236
+ data: {
2237
+ deliveryId: "delivery_1",
2238
+ turnId: TURN,
2239
+ parts: [{ kind: "text", text: "hi" }],
2240
+ },
2241
+ meta: { at: USER_AT, position: { line: 1, index: 0 } },
2172
2242
  },
2173
2243
  {
2174
- type: "step.started",
2175
- data: { modelId: "m", sequence: 3, stepIndex: 0, turnId: TURN },
2176
- meta: { at: ASSISTANT_AT, id: "evt_3" },
2244
+ type: "model.requested",
2245
+ data: { runId: "run_1", owner: { turnId: TURN } },
2246
+ scope: { turnId: TURN },
2247
+ meta: { at: ASSISTANT_AT, position: { line: 2, index: 0 } },
2177
2248
  },
2178
- ] satisfies readonly MessageStreamEvent[];
2249
+ ] satisfies readonly SessionStreamEvent[];
2179
2250
 
2180
- const turnData: EveMessageData = {
2251
+ const turnData: MessageFixture = {
2181
2252
  messages: [
2182
2253
  {
2183
2254
  id: `${TURN}:user`,
@@ -2196,7 +2267,7 @@ describe("useEveAgentRuntime createdAt derivation", () => {
2196
2267
 
2197
2268
  it("stamps a message with the wall clock when no event covers its turn, and keeps that stamp across renders", () => {
2198
2269
  const before = Date.now();
2199
- const agent = createAgent({ data: turnData, events: [] });
2270
+ const agent = createAgent({ messages: turnData.messages, events: [] });
2200
2271
  mockUseEveAgent.mockReturnValue(agent as never);
2201
2272
 
2202
2273
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
@@ -2206,7 +2277,7 @@ describe("useEveAgentRuntime createdAt derivation", () => {
2206
2277
 
2207
2278
  mockUseEveAgent.mockReturnValue({
2208
2279
  ...agent,
2209
- data: { messages: [...turnData.messages] },
2280
+ messages: [...turnData.messages],
2210
2281
  } as never);
2211
2282
  rerender();
2212
2283
 
@@ -2216,7 +2287,10 @@ describe("useEveAgentRuntime createdAt derivation", () => {
2216
2287
  });
2217
2288
 
2218
2289
  it("keeps the message list identity when appended events stamp no message", () => {
2219
- const agent = createAgent({ data: turnData, events: turnEvents });
2290
+ const agent = createAgent({
2291
+ messages: turnData.messages,
2292
+ events: turnEvents,
2293
+ });
2220
2294
  mockUseEveAgent.mockReturnValue(agent as never);
2221
2295
 
2222
2296
  const { result, rerender } = renderHook(() => useEveAgentRuntime());
@@ -2228,8 +2302,15 @@ describe("useEveAgentRuntime createdAt derivation", () => {
2228
2302
  ...turnEvents,
2229
2303
  {
2230
2304
  type: "turn.started",
2231
- data: { sequence: 4, turnId: "turn_next" },
2232
- meta: { at: "2026-01-02T10:05:00.000Z", id: "evt_4" },
2305
+ data: {
2306
+ turnId: "turn_next",
2307
+ cause: { deliveryId: "delivery_2" },
2308
+ follows: TURN,
2309
+ },
2310
+ meta: {
2311
+ at: "2026-01-02T10:05:00.000Z",
2312
+ position: { line: 3, index: 0 },
2313
+ },
2233
2314
  },
2234
2315
  ],
2235
2316
  } as never);