@assistant-ui/core 0.2.22 → 0.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/dist/adapters/thread-history.d.ts +8 -0
  2. package/dist/adapters/thread-history.d.ts.map +1 -1
  3. package/dist/internal.d.ts +3 -2
  4. package/dist/internal.js +3 -2
  5. package/dist/model-context/frame/host.d.ts.map +1 -1
  6. package/dist/model-context/frame/host.js +36 -21
  7. package/dist/model-context/frame/host.js.map +1 -1
  8. package/dist/model-context/types.d.ts.map +1 -1
  9. package/dist/model-context/types.js +13 -4
  10. package/dist/model-context/types.js.map +1 -1
  11. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  12. package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -0
  13. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  14. package/dist/react/client/interactable-model-context.js +1 -0
  15. package/dist/react/client/interactable-model-context.js.map +1 -1
  16. package/dist/react/interactables-legacy/useInteractableState.js +1 -0
  17. package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
  18. package/dist/react/model-context/useInteractableState.js +1 -0
  19. package/dist/react/model-context/useInteractableState.js.map +1 -1
  20. package/dist/react/model-context/useInteractableVersions.js +1 -0
  21. package/dist/react/model-context/useInteractableVersions.js.map +1 -1
  22. package/dist/react/model-context/useToolArgsStatus.js +1 -0
  23. package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
  24. package/dist/react/primitive-hooks/useActionBarCopy.js +1 -0
  25. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  26. package/dist/react/primitive-hooks/useActionBarEdit.js +1 -0
  27. package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
  28. package/dist/react/primitive-hooks/useActionBarFeedback.js +1 -0
  29. package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
  30. package/dist/react/primitive-hooks/useActionBarReload.js +1 -0
  31. package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
  32. package/dist/react/primitive-hooks/useActionBarSpeak.js +1 -0
  33. package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
  34. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +1 -0
  35. package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
  36. package/dist/react/primitive-hooks/useBranchPickerNext.js +1 -0
  37. package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
  38. package/dist/react/primitive-hooks/useBranchPickerPrevious.js +1 -0
  39. package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
  40. package/dist/react/primitive-hooks/useComposerAddAttachment.js +1 -0
  41. package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
  42. package/dist/react/primitive-hooks/useComposerCancel.js +1 -0
  43. package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
  44. package/dist/react/primitive-hooks/useComposerDictate.js +1 -0
  45. package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
  46. package/dist/react/primitive-hooks/useComposerSend.js +1 -0
  47. package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
  48. package/dist/react/primitive-hooks/useEditComposerCancel.js +1 -0
  49. package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
  50. package/dist/react/primitive-hooks/useEditComposerSend.js +1 -0
  51. package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
  52. package/dist/react/primitive-hooks/useMessageBranching.js +1 -0
  53. package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
  54. package/dist/react/primitive-hooks/useMessageReload.js +1 -0
  55. package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
  56. package/dist/react/primitive-hooks/useSuggestionTrigger.js +1 -0
  57. package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
  58. package/dist/react/primitive-hooks/useThreadListItemArchive.js +1 -0
  59. package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
  60. package/dist/react/primitive-hooks/useThreadListItemDelete.js +1 -0
  61. package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
  62. package/dist/react/primitive-hooks/useThreadListItemTrigger.js +1 -0
  63. package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
  64. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +1 -0
  65. package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
  66. package/dist/react/primitive-hooks/useThreadListLoadMore.js +1 -0
  67. package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
  68. package/dist/react/primitive-hooks/useThreadListNew.js +1 -0
  69. package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
  70. package/dist/react/providers/TextMessagePartProvider.js +1 -0
  71. package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
  72. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  73. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +6 -4
  74. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  75. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
  76. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
  77. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +11 -1
  78. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  79. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
  80. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  81. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +1 -1
  82. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  83. package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
  84. package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
  85. package/dist/react/runtimes/cloud/auiV0.js +2 -1
  86. package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
  87. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
  88. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
  89. package/dist/react/runtimes/external-message-converter.js +1 -1
  90. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  91. package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
  92. package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
  93. package/dist/react/runtimes/useLocalRuntime.d.ts +0 -1
  94. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  95. package/dist/runtime/api/assistant-runtime.d.ts +1 -1
  96. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  97. package/dist/runtime/api/assistant-runtime.js +1 -1
  98. package/dist/runtime/api/assistant-runtime.js.map +1 -1
  99. package/dist/runtime/api/attachment-runtime.d.ts +1 -1
  100. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  101. package/dist/runtime/api/attachment-runtime.js +1 -1
  102. package/dist/runtime/api/attachment-runtime.js.map +1 -1
  103. package/dist/runtime/api/composer-runtime.d.ts +2 -2
  104. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  105. package/dist/runtime/api/composer-runtime.js +2 -2
  106. package/dist/runtime/api/composer-runtime.js.map +1 -1
  107. package/dist/runtime/api/message-part-runtime.d.ts +4 -4
  108. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  109. package/dist/runtime/api/message-part-runtime.js +3 -3
  110. package/dist/runtime/api/message-part-runtime.js.map +1 -1
  111. package/dist/runtime/api/message-runtime.d.ts +1 -1
  112. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  113. package/dist/runtime/api/message-runtime.js +2 -2
  114. package/dist/runtime/api/message-runtime.js.map +1 -1
  115. package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
  116. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  117. package/dist/runtime/api/thread-list-item-runtime.js +2 -2
  118. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  119. package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
  120. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  121. package/dist/runtime/api/thread-list-runtime.js +1 -1
  122. package/dist/runtime/api/thread-list-runtime.js.map +1 -1
  123. package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
  124. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  125. package/dist/runtime/base/base-thread-runtime-core.js +1 -1
  126. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  127. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
  128. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  129. package/dist/runtime/base/default-edit-composer-runtime-core.js +2 -2
  130. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  131. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
  132. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  133. package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -1
  134. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  135. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  136. package/dist/runtime/utils/message-repository.js +4 -2
  137. package/dist/runtime/utils/message-repository.js.map +1 -1
  138. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
  139. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  140. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
  141. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
  142. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  143. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
  144. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  145. package/dist/runtimes/internal.d.ts +2 -1
  146. package/dist/runtimes/internal.js +2 -1
  147. package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
  148. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  149. package/dist/runtimes/local/local-thread-runtime-core.js +44 -13
  150. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  151. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
  152. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  153. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
  154. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  155. package/dist/store/clients/no-op-composer-client.js +1 -0
  156. package/dist/store/clients/no-op-composer-client.js.map +1 -1
  157. package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
  158. package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
  159. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  160. package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
  161. package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
  162. package/dist/store/scopes/thread.d.ts +1 -0
  163. package/dist/store/scopes/thread.d.ts.map +1 -1
  164. package/dist/subscribable/subscribable.d.ts +3 -3
  165. package/dist/subscribable/subscribable.d.ts.map +1 -1
  166. package/dist/subscribable/subscribable.js +3 -3
  167. package/dist/subscribable/subscribable.js.map +1 -1
  168. package/package.json +7 -7
  169. package/src/adapters/thread-history.ts +8 -0
  170. package/src/internal.ts +1 -1
  171. package/src/model-context/frame/host.test.ts +47 -0
  172. package/src/model-context/frame/host.ts +46 -19
  173. package/src/model-context/types.ts +16 -6
  174. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +15 -5
  175. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +20 -6
  176. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
  177. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +26 -5
  178. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +5 -1
  179. package/src/react/runtimes/cloud/auiV0.ts +14 -0
  180. package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
  181. package/src/react/runtimes/external-message-converter.test.ts +346 -0
  182. package/src/react/runtimes/external-message-converter.ts +1 -1
  183. package/src/react/runtimes/useLocalRuntime.test.tsx +43 -0
  184. package/src/runtime/api/assistant-runtime.ts +4 -1
  185. package/src/runtime/api/attachment-runtime.ts +8 -2
  186. package/src/runtime/api/composer-runtime.ts +9 -5
  187. package/src/runtime/api/message-part-runtime.ts +10 -3
  188. package/src/runtime/api/message-runtime.ts +7 -2
  189. package/src/runtime/api/thread-list-item-runtime.ts +7 -2
  190. package/src/runtime/api/thread-list-runtime.ts +10 -2
  191. package/src/runtime/base/base-thread-runtime-core.ts +5 -1
  192. package/src/runtime/base/default-edit-composer-runtime-core.ts +14 -2
  193. package/src/runtime/base/default-thread-composer-runtime-core.ts +11 -1
  194. package/src/runtime/utils/message-repository.ts +19 -13
  195. package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
  196. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
  197. package/src/runtimes/internal.ts +3 -0
  198. package/src/runtimes/local/local-thread-runtime-core.test.ts +596 -0
  199. package/src/runtimes/local/local-thread-runtime-core.ts +85 -21
  200. package/src/runtimes/local/should-continue.test.ts +122 -0
  201. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +9 -10
  202. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +38 -32
  203. package/src/store/clients/model-context-client.test.ts +21 -1
  204. package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
  205. package/src/store/scopes/thread.ts +1 -0
  206. package/src/subscribable/subscribable.ts +16 -8
  207. package/src/tests/MessageRepository.test.ts +12 -0
  208. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
  209. package/src/tests/auiV0Encode.test.ts +74 -0
  210. package/src/tests/base-composer-runtime-core.test.ts +422 -0
  211. package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
  212. package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
  213. package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
  214. package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
@@ -1,208 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { OptimisticState } from "../runtimes/remote-thread-list/optimistic-state";
3
- import {
4
- type RemoteThreadState,
5
- createThreadMappingId,
6
- updateStatusReducer,
7
- getThreadData,
8
- } from "../runtimes/remote-thread-list/remote-thread-state";
9
-
10
- /**
11
- * This test reproduces the crash from issue #3346:
12
- * "Entry not available in the store" when deleting the active thread.
13
- *
14
- * Root cause: optimisticUpdate's `optimistic` callback runs synchronously
15
- * and removes the thread from threadData, but mainThreadId still points to
16
- * the deleted thread. Subscribers that fire during _notifySubscribers() see
17
- * this inconsistent state and crash.
18
- */
19
-
20
- const createThreadState = (
21
- threadId: string,
22
- status: "regular" | "archived" = "regular",
23
- ): RemoteThreadState => {
24
- const mappingId = createThreadMappingId(threadId);
25
- return {
26
- isLoading: false,
27
- isLoadingMore: false,
28
- cursor: undefined,
29
- newThreadId: undefined,
30
- threadIds: status === "regular" ? [threadId] : [],
31
- archivedThreadIds: status === "archived" ? [threadId] : [],
32
- threadIdMap: { [threadId]: mappingId },
33
- threadData: {
34
- [mappingId]: {
35
- id: threadId,
36
- remoteId: threadId,
37
- externalId: undefined,
38
- status,
39
- title: undefined,
40
- initializeTask: Promise.resolve({
41
- remoteId: threadId,
42
- externalId: undefined,
43
- }),
44
- },
45
- },
46
- };
47
- };
48
-
49
- describe("OptimisticState delete crash (#3346)", () => {
50
- it("optimistic callback runs synchronously before execute completes", async () => {
51
- const state = new OptimisticState(createThreadState("thread-1"));
52
- const events: string[] = [];
53
-
54
- state.subscribe(() => {
55
- events.push("subscriber-notified");
56
- });
57
-
58
- const executeStarted = vi.fn();
59
- const executeCompleted = vi.fn();
60
-
61
- const promise = state.optimisticUpdate({
62
- execute: async () => {
63
- executeStarted();
64
- // simulate async work like _ensureThreadIsNotMain
65
- await Promise.resolve();
66
- executeCompleted();
67
- },
68
- optimistic: (s) => {
69
- events.push("optimistic-ran");
70
- return updateStatusReducer(s, "thread-1", "deleted");
71
- },
72
- });
73
-
74
- // After calling optimisticUpdate but before awaiting:
75
- // - optimistic callback has already run (synchronous)
76
- // - execute has started but not completed (async)
77
- expect(events).toEqual(["optimistic-ran", "subscriber-notified"]);
78
- expect(executeStarted).toHaveBeenCalled();
79
- expect(executeCompleted).not.toHaveBeenCalled();
80
-
81
- // Thread data is already gone from the optimistic value
82
- expect(getThreadData(state.value, "thread-1")).toBeUndefined();
83
-
84
- await promise;
85
- });
86
-
87
- it("BUG SCENARIO: subscriber sees deleted thread data while mainThreadId still references it", async () => {
88
- const state = new OptimisticState(createThreadState("thread-1"));
89
-
90
- // Simulate what happens in the real code:
91
- // mainThreadId is external state that _ensureThreadIsNotMain would update
92
- let mainThreadId = "thread-1";
93
- let subscriberSawInconsistentState = false;
94
-
95
- state.subscribe(() => {
96
- // This fires synchronously during optimisticUpdate.
97
- // In the real code, React components would re-render here and try to
98
- // access the main thread's data.
99
- const threadData = getThreadData(state.value, mainThreadId);
100
- if (threadData === undefined && mainThreadId === "thread-1") {
101
- // mainThreadId points to a deleted thread — this is the crash condition
102
- subscriberSawInconsistentState = true;
103
- }
104
- });
105
-
106
- // OLD CODE: _ensureThreadIsNotMain inside execute
107
- // The optimistic callback deletes thread data BEFORE execute can update mainThreadId
108
- const promise = state.optimisticUpdate({
109
- execute: async () => {
110
- // In old code, _ensureThreadIsNotMain was here.
111
- // It would switch mainThreadId, but this runs AFTER optimistic callback
112
- await Promise.resolve();
113
- mainThreadId = "thread-2"; // too late — subscriber already fired
114
- },
115
- optimistic: (s) => {
116
- return updateStatusReducer(s, "thread-1", "deleted");
117
- },
118
- });
119
-
120
- // The subscriber saw inconsistent state — mainThreadId points to deleted thread
121
- expect(subscriberSawInconsistentState).toBe(true);
122
-
123
- await promise;
124
- });
125
-
126
- it("FIX: switching mainThreadId before optimisticUpdate prevents inconsistency", async () => {
127
- const state = new OptimisticState(createThreadState("thread-1"));
128
-
129
- let mainThreadId = "thread-1";
130
- let subscriberSawInconsistentState = false;
131
-
132
- state.subscribe(() => {
133
- const threadData = getThreadData(state.value, mainThreadId);
134
- if (threadData === undefined) {
135
- subscriberSawInconsistentState = true;
136
- }
137
- });
138
-
139
- // FIX: _ensureThreadIsNotMain runs BEFORE optimisticUpdate.
140
- // switchToNewThread() both creates the new thread in state AND updates mainThreadId.
141
- const newThreadId = "thread-2";
142
- const mappingId = createThreadMappingId(newThreadId);
143
- const currentState = state.value;
144
- state.update({
145
- ...currentState,
146
- newThreadId: newThreadId,
147
- threadIdMap: {
148
- ...currentState.threadIdMap,
149
- [newThreadId]: mappingId,
150
- },
151
- threadData: {
152
- ...currentState.threadData,
153
- [mappingId]: {
154
- status: "new" as const,
155
- id: newThreadId,
156
- remoteId: undefined,
157
- externalId: undefined,
158
- title: undefined,
159
- },
160
- },
161
- });
162
- mainThreadId = newThreadId;
163
-
164
- // Reset flag — the state.update above triggered the subscriber
165
- subscriberSawInconsistentState = false;
166
-
167
- const promise = state.optimisticUpdate({
168
- execute: async () => {
169
- // _ensureThreadIsNotMain no longer here
170
- return undefined;
171
- },
172
- optimistic: (s) => {
173
- return updateStatusReducer(s, "thread-1", "deleted");
174
- },
175
- });
176
-
177
- // mainThreadId was already switched to thread-2 which exists in state
178
- // — subscriber sees consistent state, no crash
179
- expect(subscriberSawInconsistentState).toBe(false);
180
-
181
- await promise;
182
- });
183
-
184
- it("archive does NOT remove threadData (no crash even without fix)", async () => {
185
- const state = new OptimisticState(createThreadState("thread-1"));
186
-
187
- let threadDataMissingDuringNotify = false;
188
-
189
- state.subscribe(() => {
190
- const threadData = getThreadData(state.value, "thread-1");
191
- if (threadData === undefined) {
192
- threadDataMissingDuringNotify = true;
193
- }
194
- });
195
-
196
- await state.optimisticUpdate({
197
- execute: async () => undefined,
198
- optimistic: (s) => {
199
- return updateStatusReducer(s, "thread-1", "archived");
200
- },
201
- });
202
-
203
- // Archive keeps threadData — no SKIP_UPDATE, no crash
204
- expect(threadDataMissingDuringNotify).toBe(false);
205
- expect(getThreadData(state.value, "thread-1")).toBeDefined();
206
- expect(getThreadData(state.value, "thread-1")?.status).toBe("archived");
207
- });
208
- });