@stigmer/react 3.12.7 → 3.12.9

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 (196) hide show
  1. package/README.md +1 -3
  2. package/composer/ComposerToolbar.d.ts +1 -19
  3. package/composer/ComposerToolbar.d.ts.map +1 -1
  4. package/composer/ComposerToolbar.js +2 -7
  5. package/composer/ComposerToolbar.js.map +1 -1
  6. package/composer/SessionComposer.d.ts +0 -10
  7. package/composer/SessionComposer.d.ts.map +1 -1
  8. package/composer/SessionComposer.js +2 -2
  9. package/composer/SessionComposer.js.map +1 -1
  10. package/composer/index.d.ts +0 -1
  11. package/composer/index.d.ts.map +1 -1
  12. package/composer/index.js.map +1 -1
  13. package/conversation/ConversationTimelineView.d.ts +15 -1
  14. package/conversation/ConversationTimelineView.d.ts.map +1 -1
  15. package/conversation/ConversationTimelineView.js +3 -2
  16. package/conversation/ConversationTimelineView.js.map +1 -1
  17. package/conversation/ConversationsWorkbench.d.ts +14 -1
  18. package/conversation/ConversationsWorkbench.d.ts.map +1 -1
  19. package/conversation/ConversationsWorkbench.js +11 -2
  20. package/conversation/ConversationsWorkbench.js.map +1 -1
  21. package/execution/MessageThread.d.ts +33 -2
  22. package/execution/MessageThread.d.ts.map +1 -1
  23. package/execution/MessageThread.js +44 -6
  24. package/execution/MessageThread.js.map +1 -1
  25. package/execution/RecalledMemoriesCard.d.ts +47 -0
  26. package/execution/RecalledMemoriesCard.d.ts.map +1 -0
  27. package/execution/RecalledMemoriesCard.js +58 -0
  28. package/execution/RecalledMemoriesCard.js.map +1 -0
  29. package/execution/ResultView.d.ts.map +1 -1
  30. package/execution/ResultView.js +6 -0
  31. package/execution/ResultView.js.map +1 -1
  32. package/execution/ToolCallItem.d.ts.map +1 -1
  33. package/execution/ToolCallItem.js +13 -2
  34. package/execution/ToolCallItem.js.map +1 -1
  35. package/execution/index.d.ts +2 -0
  36. package/execution/index.d.ts.map +1 -1
  37. package/execution/index.js +1 -0
  38. package/execution/index.js.map +1 -1
  39. package/execution/tool-categories.d.ts +1 -1
  40. package/execution/tool-categories.d.ts.map +1 -1
  41. package/execution/tool-categories.js +6 -0
  42. package/execution/tool-categories.js.map +1 -1
  43. package/identity-account/AccountPreferencesPanel.d.ts +2 -1
  44. package/identity-account/AccountPreferencesPanel.d.ts.map +1 -1
  45. package/identity-account/AccountPreferencesPanel.js +41 -3
  46. package/identity-account/AccountPreferencesPanel.js.map +1 -1
  47. package/identity-account/useAccountExecutionDefaults.d.ts +7 -0
  48. package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -1
  49. package/identity-account/useAccountExecutionDefaults.js +5 -2
  50. package/identity-account/useAccountExecutionDefaults.js.map +1 -1
  51. package/index.d.ts +6 -6
  52. package/index.d.ts.map +1 -1
  53. package/index.js +2 -2
  54. package/index.js.map +1 -1
  55. package/internal/MemoryEnabledRow.d.ts +37 -0
  56. package/internal/MemoryEnabledRow.d.ts.map +1 -0
  57. package/internal/MemoryEnabledRow.js +25 -0
  58. package/internal/MemoryEnabledRow.js.map +1 -0
  59. package/internal/VirtualizedThread.d.ts +3 -1
  60. package/internal/VirtualizedThread.d.ts.map +1 -1
  61. package/internal/VirtualizedThread.js +3 -1
  62. package/internal/VirtualizedThread.js.map +1 -1
  63. package/internal/useAutoScroll.d.ts +18 -0
  64. package/internal/useAutoScroll.d.ts.map +1 -1
  65. package/internal/useAutoScroll.js +50 -0
  66. package/internal/useAutoScroll.js.map +1 -1
  67. package/memory/MemoryProposalCard.d.ts +35 -0
  68. package/memory/MemoryProposalCard.d.ts.map +1 -0
  69. package/memory/MemoryProposalCard.js +73 -0
  70. package/memory/MemoryProposalCard.js.map +1 -0
  71. package/memory/index.d.ts +2 -0
  72. package/memory/index.d.ts.map +1 -1
  73. package/memory/index.js +2 -0
  74. package/memory/index.js.map +1 -1
  75. package/memory/useMemory.d.ts +39 -0
  76. package/memory/useMemory.d.ts.map +1 -0
  77. package/memory/useMemory.js +43 -0
  78. package/memory/useMemory.js.map +1 -0
  79. package/organization/OrgPreferencesPanel.d.ts.map +1 -1
  80. package/organization/OrgPreferencesPanel.js +36 -4
  81. package/organization/OrgPreferencesPanel.js.map +1 -1
  82. package/package.json +4 -4
  83. package/session/AutoApproveIndicator.d.ts +18 -0
  84. package/session/AutoApproveIndicator.d.ts.map +1 -0
  85. package/session/AutoApproveIndicator.js +23 -0
  86. package/session/AutoApproveIndicator.js.map +1 -0
  87. package/session/NewSessionViewer.d.ts.map +1 -1
  88. package/session/NewSessionViewer.js +10 -9
  89. package/session/NewSessionViewer.js.map +1 -1
  90. package/session/SessionViewer.d.ts +21 -9
  91. package/session/SessionViewer.d.ts.map +1 -1
  92. package/session/SessionViewer.js +31 -21
  93. package/session/SessionViewer.js.map +1 -1
  94. package/session/facets/SetupTab.d.ts +43 -6
  95. package/session/facets/SetupTab.d.ts.map +1 -1
  96. package/session/facets/SetupTab.js +32 -36
  97. package/session/facets/SetupTab.js.map +1 -1
  98. package/session/facets/UsageTab.d.ts +2 -1
  99. package/session/facets/UsageTab.d.ts.map +1 -1
  100. package/session/facets/UsageTab.js +11 -5
  101. package/session/facets/UsageTab.js.map +1 -1
  102. package/session/facets/index.d.ts +1 -1
  103. package/session/facets/index.d.ts.map +1 -1
  104. package/session/facets/primitives.d.ts +58 -0
  105. package/session/facets/primitives.d.ts.map +1 -0
  106. package/session/facets/primitives.js +59 -0
  107. package/session/facets/primitives.js.map +1 -0
  108. package/session/index.d.ts +1 -1
  109. package/session/index.d.ts.map +1 -1
  110. package/session/index.js.map +1 -1
  111. package/session/useNewSessionFlow.d.ts +9 -4
  112. package/session/useNewSessionFlow.d.ts.map +1 -1
  113. package/session/useNewSessionFlow.js +20 -9
  114. package/session/useNewSessionFlow.js.map +1 -1
  115. package/session/useSessionPageFlow.d.ts +28 -10
  116. package/session/useSessionPageFlow.d.ts.map +1 -1
  117. package/session/useSessionPageFlow.js +16 -10
  118. package/session/useSessionPageFlow.js.map +1 -1
  119. package/settings/MemorySection.d.ts.map +1 -1
  120. package/settings/MemorySection.js +1 -1
  121. package/settings/MemorySection.js.map +1 -1
  122. package/src/attachment/__tests__/prepare-image.test.ts +12 -6
  123. package/src/composer/ComposerToolbar.tsx +0 -57
  124. package/src/composer/SessionComposer.tsx +1 -13
  125. package/src/composer/index.ts +0 -1
  126. package/src/conversation/ConversationTimelineView.tsx +17 -1
  127. package/src/conversation/ConversationsWorkbench.tsx +25 -0
  128. package/src/conversation/__tests__/ConversationTimelineView.layout.test.tsx +37 -1
  129. package/src/execution/MessageThread.tsx +75 -3
  130. package/src/execution/RecalledMemoriesCard.tsx +164 -0
  131. package/src/execution/ResultView.tsx +6 -0
  132. package/src/execution/ToolCallItem.tsx +18 -1
  133. package/src/execution/__tests__/RecalledMemoriesCard.test.tsx +123 -0
  134. package/src/execution/__tests__/message-thread-recalled-memories.test.tsx +216 -0
  135. package/src/execution/__tests__/message-thread-scroll-on-send.test.tsx +141 -0
  136. package/src/execution/__tests__/message-thread-slots.test.tsx +36 -0
  137. package/src/execution/index.ts +2 -0
  138. package/src/execution/tool-categories.ts +7 -0
  139. package/src/identity-account/AccountPreferencesPanel.tsx +89 -2
  140. package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +112 -0
  141. package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +34 -1
  142. package/src/identity-account/useAccountExecutionDefaults.ts +12 -2
  143. package/src/index.ts +8 -1
  144. package/src/internal/MemoryEnabledRow.tsx +92 -0
  145. package/src/internal/VirtualizedThread.tsx +5 -0
  146. package/src/internal/__tests__/useAutoScroll.layout.test.tsx +105 -4
  147. package/src/internal/__tests__/useAutoScroll.test.tsx +41 -1
  148. package/src/internal/useAutoScroll.ts +54 -0
  149. package/src/memory/MemoryProposalCard.tsx +181 -0
  150. package/src/memory/__tests__/MemoryProposalCard.test.tsx +236 -0
  151. package/src/memory/__tests__/memoryHooks.test.tsx +63 -0
  152. package/src/memory/index.ts +5 -0
  153. package/src/memory/useMemory.ts +80 -0
  154. package/src/organization/OrgPreferencesPanel.tsx +52 -3
  155. package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +65 -0
  156. package/src/session/AutoApproveIndicator.tsx +45 -0
  157. package/src/session/NewSessionViewer.tsx +18 -15
  158. package/src/session/SessionViewer.tsx +70 -32
  159. package/src/session/__tests__/NewSessionViewer.test.tsx +32 -0
  160. package/src/session/__tests__/SessionViewer-autoApprove.test.tsx +244 -0
  161. package/src/session/__tests__/SessionViewer-transcriptExport.test.tsx +60 -22
  162. package/src/session/__tests__/useNewSessionFlow.test.tsx +56 -0
  163. package/src/session/__tests__/useSessionPageFlow.autoApprove.test.tsx +87 -0
  164. package/src/session/facets/SetupTab.tsx +193 -157
  165. package/src/session/facets/UsageTab.tsx +38 -38
  166. package/src/session/facets/index.ts +1 -0
  167. package/src/session/facets/primitives.tsx +169 -0
  168. package/src/session/index.ts +1 -0
  169. package/src/session/useNewSessionFlow.ts +30 -15
  170. package/src/session/useSessionPageFlow.ts +44 -20
  171. package/src/settings/MemorySection.tsx +4 -2
  172. package/src/switch/Switch.tsx +4 -0
  173. package/src/workflow/__tests__/WorkflowExecutionViewer.approvals.test.tsx +26 -7
  174. package/src/workflow/__tests__/task-presentation.test.ts +49 -12
  175. package/src/workflow/__tests__/useWorkflowCanvas.dirty.test.tsx +7 -2
  176. package/src/workflow/__tests__/useWorkflowCanvas.drag.test.tsx +7 -2
  177. package/src/workflow/__tests__/workflow-thread-scroll-on-send.test.tsx +145 -0
  178. package/src/workflow/thread/WorkflowTaskThread.tsx +59 -32
  179. package/src/workflow/thread/task-presentation.ts +52 -7
  180. package/src/workspace/WorkspaceSurface.tsx +26 -3
  181. package/styles.css +1 -1
  182. package/switch/Switch.d.ts +3 -1
  183. package/switch/Switch.d.ts.map +1 -1
  184. package/switch/Switch.js +2 -2
  185. package/switch/Switch.js.map +1 -1
  186. package/workflow/thread/WorkflowTaskThread.d.ts +13 -0
  187. package/workflow/thread/WorkflowTaskThread.d.ts.map +1 -1
  188. package/workflow/thread/WorkflowTaskThread.js +33 -25
  189. package/workflow/thread/WorkflowTaskThread.js.map +1 -1
  190. package/workflow/thread/task-presentation.d.ts.map +1 -1
  191. package/workflow/thread/task-presentation.js +50 -7
  192. package/workflow/thread/task-presentation.js.map +1 -1
  193. package/workspace/WorkspaceSurface.js +11 -2
  194. package/workspace/WorkspaceSurface.js.map +1 -1
  195. package/src/composer/__tests__/ComposerToolbar-autoApprove.test.tsx +0 -80
  196. package/src/session/__tests__/SessionViewer-autoApproveToggle.test.tsx +0 -178
@@ -1,11 +1,12 @@
1
- // SessionViewer's built-in transcript export (stigmer/stigmer#814): the
2
- // control ships ON by default in the header corner wherever a conversation
3
- // is viewed, its transcript is one click away (the owner-ratified DD-011
4
- // divergence recorded on SessionViewerProps.transcriptExport) — composes
5
- // with host headerActions, and disappears on explicit opt-out.
1
+ // SessionViewer's built-in transcript export (stigmer/stigmer#814, placement
2
+ // reworked with #816): export lives in the Config facet's Transcript section
3
+ // for viewers with the session panel, and the header TranscriptExportMenu
4
+ // remains ONLY as the panel-less fallback (guests, panel="none") — so
5
+ // wherever a conversation is viewed, its transcript stays reachable, without
6
+ // a floating header button on surfaces that have a proper home for it.
6
7
 
7
8
  import { describe, it, expect, vi, afterEach } from "vitest";
8
- import { render, screen, cleanup } from "@testing-library/react";
9
+ import { render, screen, cleanup, fireEvent } from "@testing-library/react";
9
10
 
10
11
  vi.mock("../../composer", async (importOriginal) => {
11
12
  const actual = await importOriginal<typeof import("../../composer")>();
@@ -20,9 +21,10 @@ vi.mock("../../execution/MessageThread", () => ({
20
21
  vi.mock("../../execution/FileReviewDock", () => ({
21
22
  FileReviewDock: () => <div data-testid="file-review-dock-probe" />,
22
23
  }));
23
- vi.mock("../facets/SetupTab", () => ({
24
- SetupTab: () => <div data-testid="setup-probe" />,
25
- }));
24
+
25
+ // SetupTab renders for real: the facet's Transcript section is asserted
26
+ // through its actual DOM (the "Copy transcript" action row), reached by
27
+ // opening the panel and selecting the Config rail view.
26
28
 
27
29
  const stubWorkspace = {
28
30
  entries: [],
@@ -107,45 +109,81 @@ vi.mock("../../hooks", () => ({
107
109
 
108
110
  import { SessionViewer } from "../SessionViewer";
109
111
 
110
- afterEach(cleanup);
112
+ afterEach(() => {
113
+ cleanup();
114
+ vi.clearAllMocks();
115
+ });
111
116
 
112
- function exportTrigger(): HTMLElement | null {
117
+ function headerExportTrigger(): HTMLElement | null {
113
118
  return screen.queryByRole("button", { name: "Export transcript" });
114
119
  }
115
120
 
116
- describe("SessionViewer transcript export wiring", () => {
117
- it("renders the export control by default", () => {
118
- render(<SessionViewer sessionId="ses_1" org="acme" />);
119
- expect(exportTrigger()).not.toBeNull();
121
+ /** Selects the panel's Config facet (the rail's radio). */
122
+ function openConfigFacet() {
123
+ fireEvent.click(screen.getByRole("radio", { name: "Config" }));
124
+ }
125
+
126
+ function facetCopyAction(): HTMLElement | null {
127
+ return screen.queryByRole("button", { name: "Copy transcript" });
128
+ }
129
+
130
+ describe("SessionViewer transcript export placement", () => {
131
+ it("panel-enabled viewers export from the Config facet, not the header", () => {
132
+ render(<SessionViewer sessionId="ses_1" org="acme" defaultPanelOpen />);
133
+ expect(headerExportTrigger()).toBeNull();
134
+ openConfigFacet();
135
+ expect(facetCopyAction()).not.toBeNull();
136
+ });
137
+
138
+ it("observers keep facet export — a bulk copy of what they already see", () => {
139
+ render(
140
+ <SessionViewer
141
+ sessionId="ses_1"
142
+ org="acme"
143
+ audience="observer"
144
+ defaultPanelOpen
145
+ />,
146
+ );
147
+ openConfigFacet();
148
+ expect(facetCopyAction()).not.toBeNull();
149
+ });
150
+
151
+ it("panel=\"none\" hosts fall back to the header menu", () => {
152
+ render(<SessionViewer sessionId="ses_1" org="acme" panel="none" />);
153
+ expect(headerExportTrigger()).not.toBeNull();
120
154
  });
121
155
 
122
- it("keeps the export control for the read-only observer audience a bulk copy of what the observer already sees", () => {
123
- render(<SessionViewer sessionId="ses_1" org="acme" audience="observer" />);
124
- expect(exportTrigger()).not.toBeNull();
156
+ it("guests fall back to the header menu (no panel to reach the facet)", () => {
157
+ render(<SessionViewer sessionId="ses_1" org="acme" audience="guest" />);
158
+ expect(headerExportTrigger()).not.toBeNull();
125
159
  });
126
160
 
127
- it("composes with host headerActions rather than replacing them", () => {
161
+ it("the header fallback composes with host headerActions", () => {
128
162
  render(
129
163
  <SessionViewer
130
164
  sessionId="ses_1"
131
165
  org="acme"
166
+ panel="none"
132
167
  headerActions={<button>Share</button>}
133
168
  />,
134
169
  );
135
170
  expect(screen.getByRole("button", { name: "Share" })).toBeTruthy();
136
- expect(exportTrigger()).not.toBeNull();
171
+ expect(headerExportTrigger()).not.toBeNull();
137
172
  });
138
173
 
139
- it("disappears on explicit opt-out, leaving host actions intact", () => {
174
+ it("explicit opt-out removes BOTH surfaces, leaving host actions intact", () => {
140
175
  render(
141
176
  <SessionViewer
142
177
  sessionId="ses_1"
143
178
  org="acme"
144
179
  transcriptExport={false}
180
+ defaultPanelOpen
145
181
  headerActions={<button>Share</button>}
146
182
  />,
147
183
  );
148
- expect(exportTrigger()).toBeNull();
184
+ expect(headerExportTrigger()).toBeNull();
185
+ openConfigFacet();
186
+ expect(facetCopyAction()).toBeNull();
149
187
  expect(screen.getByRole("button", { name: "Share" })).toBeTruthy();
150
188
  });
151
189
  });
@@ -464,6 +464,62 @@ describe("useNewSessionFlow", () => {
464
464
  expect(execInput.autoApproveAll).toBeUndefined();
465
465
  });
466
466
 
467
+ it("arms from the account's default_auto_approve preference", async () => {
468
+ const opts = {
469
+ ...defaultOptions(),
470
+ accountDefaults: { autoApprove: true },
471
+ };
472
+ const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
473
+
474
+ expect(result.current.autoApproveAll).toBe(true);
475
+
476
+ await act(async () => {
477
+ await result.current.submit("Hello");
478
+ });
479
+
480
+ const execInput = mockCreateExecution.mock.calls[0][0];
481
+ expect(execInput.autoApproveAll).toBe(true);
482
+ });
483
+
484
+ it("a LATE-arriving account preference still arms (derived, not initialized)", () => {
485
+ // whoAmI resolves after mount — the seed must be part of the
486
+ // derivation so it cannot be missed by a useState initializer.
487
+ const initialProps: { accountDefaults?: { autoApprove?: boolean } } = {};
488
+ const { result, rerender } = renderHook(
489
+ ({ accountDefaults }: typeof initialProps) =>
490
+ useNewSessionFlow({ ...defaultOptions(), accountDefaults }),
491
+ { wrapper: createWrapper(), initialProps },
492
+ );
493
+ expect(result.current.autoApproveAll).toBe(false);
494
+
495
+ rerender({ accountDefaults: { autoApprove: true } });
496
+ expect(result.current.autoApproveAll).toBe(true);
497
+ });
498
+
499
+ it("a late arrival never overrides the user's explicit OFF", () => {
500
+ const initialProps: { accountDefaults?: { autoApprove?: boolean } } = {};
501
+ const { result, rerender } = renderHook(
502
+ ({ accountDefaults }: typeof initialProps) =>
503
+ useNewSessionFlow({ ...defaultOptions(), accountDefaults }),
504
+ { wrapper: createWrapper(), initialProps },
505
+ );
506
+ act(() => result.current.setAutoApproveAll(false));
507
+
508
+ rerender({ accountDefaults: { autoApprove: true } });
509
+ expect(result.current.autoApproveAll).toBe(false);
510
+ });
511
+
512
+ it("guests never inherit the account auto-approve preference", () => {
513
+ const opts = {
514
+ ...defaultOptions(),
515
+ audience: "guest" as const,
516
+ accountDefaults: { autoApprove: true },
517
+ };
518
+ const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
519
+
520
+ expect(result.current.autoApproveAll).toBe(false);
521
+ });
522
+
467
523
  it("passes cursor harness in the sessionSpec after switching", async () => {
468
524
  const opts = defaultOptions();
469
525
  const { result } = renderHook(() => useNewSessionFlow(opts), { wrapper: createWrapper() });
@@ -231,6 +231,93 @@ describe("useSessionPageFlow — host-set approval default (#302)", () => {
231
231
  });
232
232
  });
233
233
 
234
+ describe("useSessionPageFlow — account preference seed (default_auto_approve)", () => {
235
+ beforeEach(() => {
236
+ mockSubmitApproval.mockResolvedValue(undefined);
237
+ });
238
+ afterEach(() => {
239
+ vi.clearAllMocks();
240
+ });
241
+
242
+ it("arms autoApproveAll from the account preference", () => {
243
+ const { result } = renderHook(() =>
244
+ useSessionPageFlow({ ...OPTS, accountDefaults: { autoApprove: true } }),
245
+ );
246
+ expect(result.current.autoApproveAll).toBe(true);
247
+ });
248
+
249
+ it("a LATE-arriving preference still applies (whoAmI resolves async)", () => {
250
+ // The preference is part of the derivation, not a mount-time
251
+ // initializer — a value arriving after mount must not be missed.
252
+ const initialProps: { accountDefaults?: { autoApprove?: boolean } } = {};
253
+ const { result, rerender } = renderHook(
254
+ ({ accountDefaults }: typeof initialProps) =>
255
+ useSessionPageFlow({ ...OPTS, accountDefaults }),
256
+ { initialProps },
257
+ );
258
+ expect(result.current.autoApproveAll).toBe(false);
259
+
260
+ rerender({ accountDefaults: { autoApprove: true } });
261
+ expect(result.current.autoApproveAll).toBe(true);
262
+ });
263
+
264
+ it("a late arrival never overrides an explicit in-session OFF", () => {
265
+ const initialProps: { accountDefaults?: { autoApprove?: boolean } } = {};
266
+ const { result, rerender } = renderHook(
267
+ ({ accountDefaults }: typeof initialProps) =>
268
+ useSessionPageFlow({ ...OPTS, accountDefaults }),
269
+ { initialProps },
270
+ );
271
+ act(() => {
272
+ result.current.setAutoApproveAll(false);
273
+ });
274
+
275
+ rerender({ accountDefaults: { autoApprove: true } });
276
+ expect(result.current.autoApproveAll).toBe(false);
277
+ });
278
+
279
+ it("the user's Turn off beats the preference for this session only", async () => {
280
+ const { result } = renderHook(() =>
281
+ useSessionPageFlow({ ...OPTS, accountDefaults: { autoApprove: true } }),
282
+ );
283
+
284
+ act(() => {
285
+ result.current.setAutoApproveAll(false);
286
+ });
287
+ expect(result.current.autoApproveAll).toBe(false);
288
+
289
+ await act(async () => {
290
+ await result.current.handleSubmit("after turn off");
291
+ });
292
+ const followUpOpts = mockSendFollowUp.mock.calls.at(-1)?.[1];
293
+ expect(followUpOpts.autoApproveAll).toBeUndefined();
294
+ });
295
+
296
+ it("carries the preference-armed state into follow-ups", async () => {
297
+ const { result } = renderHook(() =>
298
+ useSessionPageFlow({ ...OPTS, accountDefaults: { autoApprove: true } }),
299
+ );
300
+
301
+ await act(async () => {
302
+ await result.current.handleSubmit("first message");
303
+ });
304
+
305
+ const followUpOpts = mockSendFollowUp.mock.calls[0][1];
306
+ expect(followUpOpts.autoApproveAll).toBe(true);
307
+ });
308
+
309
+ it("guests never inherit the account preference", () => {
310
+ const { result } = renderHook(() =>
311
+ useSessionPageFlow({
312
+ ...OPTS,
313
+ audience: "guest",
314
+ accountDefaults: { autoApprove: true },
315
+ }),
316
+ );
317
+ expect(result.current.autoApproveAll).toBe(false);
318
+ });
319
+ });
320
+
234
321
  describe("useSessionPageFlow — arming derived from the in-flight run (#816)", () => {
235
322
  afterEach(() => {
236
323
  mockConv.activeStreamExecution = null;