@assistant-ui/react 0.14.28 → 0.15.0

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 (190) hide show
  1. package/dist/client/ExternalThread.d.ts +11 -1
  2. package/dist/client/ExternalThread.d.ts.map +1 -1
  3. package/dist/client/ExternalThread.js +762 -516
  4. package/dist/client/ExternalThread.js.map +1 -1
  5. package/dist/client/InMemoryThreadList.js +3 -3
  6. package/dist/client/InMemoryThreadList.js.map +1 -1
  7. package/dist/context/index.d.ts +1 -8
  8. package/dist/context/index.js +1 -8
  9. package/dist/index.d.ts +1 -8
  10. package/dist/index.js +1 -8
  11. package/dist/legacy-runtime/cloud/auiV0.d.ts +12 -1
  12. package/dist/legacy-runtime/cloud/auiV0.d.ts.map +1 -1
  13. package/dist/legacy-runtime/cloud/auiV0.js +2 -1
  14. package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
  15. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.d.ts +1 -1
  16. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +7 -6
  17. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js.map +1 -1
  18. package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.d.ts.map +1 -1
  19. package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js +30 -15
  20. package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js.map +1 -1
  21. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  22. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +11 -7
  23. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  24. package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +1 -0
  25. package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js.map +1 -1
  26. package/dist/mcp-apps/McpAppRenderer.js +1 -1
  27. package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
  28. package/dist/model-context/makeAssistantVisible.js +26 -25
  29. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  30. package/dist/primitives/actionBar/ActionBarExportMarkdown.js +3 -3
  31. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  32. package/dist/primitives/actionBar/ActionBarRoot.js +3 -3
  33. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  34. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +7 -6
  35. package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
  36. package/dist/primitives/actionBar/useActionBarFloatStatus.js +10 -11
  37. package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
  38. package/dist/primitives/attachment/AttachmentRemove.js +4 -3
  39. package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
  40. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +4 -3
  41. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
  42. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  43. package/dist/primitives/composer/ComposerAddAttachment.js +11 -5
  44. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  45. package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
  46. package/dist/primitives/composer/ComposerAttachmentDropzone.js +2 -4
  47. package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
  48. package/dist/primitives/composer/ComposerInput.js +18 -16
  49. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  50. package/dist/primitives/composer/ComposerQuote.js +1 -1
  51. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  52. package/dist/primitives/composer/ComposerSend.js +1 -0
  53. package/dist/primitives/composer/ComposerSend.js.map +1 -1
  54. package/dist/primitives/composer/ComposerStopDictation.js +4 -3
  55. package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
  56. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
  57. package/dist/primitives/composer/trigger/triggerSelectionResource.js +3 -3
  58. package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
  59. package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
  60. package/dist/primitives/message/MessagePartsGrouped.js +67 -89
  61. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  62. package/dist/primitives/message/MessageRoot.js +3 -3
  63. package/dist/primitives/message/MessageRoot.js.map +1 -1
  64. package/dist/primitives/queueItem/QueueItemRemove.js +4 -3
  65. package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
  66. package/dist/primitives/queueItem/QueueItemSteer.js +4 -3
  67. package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
  68. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +1 -1
  69. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  70. package/dist/primitives/suggestion/SuggestionTrigger.js +17 -15
  71. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
  72. package/dist/primitives/thread/ThreadScrollToBottom.js +1 -0
  73. package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
  74. package/dist/unstable/useComposerInput.js +2 -2
  75. package/dist/unstable/useComposerInput.js.map +1 -1
  76. package/dist/unstable/useComposerInputHistory.js +6 -6
  77. package/dist/unstable/useComposerInputHistory.js.map +1 -1
  78. package/dist/unstable/useMentionAdapter.js +1 -1
  79. package/dist/unstable/useMentionAdapter.js.map +1 -1
  80. package/dist/utils/hooks/useOnResizeContent.js +1 -0
  81. package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
  82. package/dist/utils/hooks/useSizeHandle.js +1 -0
  83. package/dist/utils/hooks/useSizeHandle.js.map +1 -1
  84. package/dist/utils/smooth/SmoothContext.js +3 -3
  85. package/dist/utils/smooth/SmoothContext.js.map +1 -1
  86. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  87. package/dist/utils/smooth/useSmooth.js +3 -3
  88. package/dist/utils/smooth/useSmooth.js.map +1 -1
  89. package/package.json +9 -9
  90. package/src/client/ExternalThread.ts +345 -56
  91. package/src/client/InMemoryThreadList.ts +3 -3
  92. package/src/context/index.ts +0 -44
  93. package/src/legacy-runtime/cloud/auiV0.ts +14 -0
  94. package/src/legacy-runtime/runtime-cores/assistant-transport/commandQueue.ts +4 -1
  95. package/src/legacy-runtime/runtime-cores/assistant-transport/runManager.ts +37 -10
  96. package/src/legacy-runtime/runtime-cores/assistant-transport/transport-delivery.test.tsx +79 -0
  97. package/src/legacy-runtime/runtime-cores/assistant-transport/transport-parentid.test.tsx +97 -0
  98. package/src/legacy-runtime/runtime-cores/assistant-transport/transport-scheduling.test.ts +113 -2
  99. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransport.spec.md +10 -2
  100. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.test.tsx +185 -0
  101. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.ts +21 -5
  102. package/src/mcp-apps/McpAppRenderer.tsx +1 -1
  103. package/src/model-context/makeAssistantVisible.test.tsx +1 -1
  104. package/src/model-context/makeAssistantVisible.tsx +1 -1
  105. package/src/primitives/actionBar/ActionBarExportMarkdown.tsx +1 -1
  106. package/src/primitives/actionBar/useActionBarFloatStatus.ts +7 -5
  107. package/src/primitives/attachment/AttachmentRemove.ts +1 -1
  108. package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.ts +1 -1
  109. package/src/primitives/composer/ComposerAddAttachment.test.tsx +108 -0
  110. package/src/primitives/composer/ComposerAddAttachment.ts +11 -5
  111. package/src/primitives/composer/ComposerAttachmentDropzone.test.tsx +5 -4
  112. package/src/primitives/composer/ComposerAttachmentDropzone.tsx +4 -3
  113. package/src/primitives/composer/ComposerInput.test.tsx +104 -7
  114. package/src/primitives/composer/ComposerInput.tsx +22 -20
  115. package/src/primitives/composer/ComposerQuote.tsx +1 -1
  116. package/src/primitives/composer/ComposerStopDictation.ts +1 -1
  117. package/src/primitives/composer/trigger/triggerSelectionResource.ts +7 -9
  118. package/src/primitives/message/MessagePartsGrouped.tsx +6 -8
  119. package/src/primitives/message/MessageRoot.tsx +1 -1
  120. package/src/primitives/queueItem/QueueItemRemove.ts +1 -1
  121. package/src/primitives/queueItem/QueueItemSteer.ts +1 -1
  122. package/src/primitives/selectionToolbar/SelectionToolbarQuote.tsx +1 -1
  123. package/src/primitives/suggestion/SuggestionTrigger.ts +9 -9
  124. package/src/tests/DataRenderers.test.tsx +212 -0
  125. package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +1 -11
  126. package/src/tests/RemoteThreadListRuntime.deferredProvider.test.tsx +3 -3
  127. package/src/tests/external-thread-attachments.test.tsx +300 -11
  128. package/src/tests/external-thread-branches.test.tsx +10 -10
  129. package/src/tests/external-thread-parity.test.tsx +230 -0
  130. package/src/tests/generative-ui.test.tsx +1 -46
  131. package/src/tests/local-runtime-queue.test.tsx +29 -34
  132. package/src/tests/messagePartSwitchRace.test.tsx +46 -15
  133. package/src/tests/messagePartTypeMismatch.test.tsx +2 -2
  134. package/src/tests/threadMessageById.test.tsx +0 -7
  135. package/src/unstable/useComposerInput.test.tsx +2 -2
  136. package/src/unstable/useComposerInput.ts +2 -2
  137. package/src/unstable/useComposerInputHistory.test.tsx +3 -3
  138. package/src/unstable/useComposerInputHistory.ts +6 -6
  139. package/src/unstable/useMentionAdapter.ts +1 -1
  140. package/src/utils/smooth/SmoothContext.tsx +1 -1
  141. package/src/utils/smooth/useSmooth.test.tsx +1 -1
  142. package/src/utils/smooth/useSmooth.ts +8 -5
  143. package/dist/context/react/utils/createStateHookForRuntime.d.ts +0 -34
  144. package/dist/context/react/utils/createStateHookForRuntime.d.ts.map +0 -1
  145. package/dist/context/react/utils/createStateHookForRuntime.js +0 -21
  146. package/dist/context/react/utils/createStateHookForRuntime.js.map +0 -1
  147. package/dist/legacy-runtime/hooks/AssistantContext.d.ts +0 -74
  148. package/dist/legacy-runtime/hooks/AssistantContext.d.ts.map +0 -1
  149. package/dist/legacy-runtime/hooks/AssistantContext.js +0 -29
  150. package/dist/legacy-runtime/hooks/AssistantContext.js.map +0 -1
  151. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +0 -1007
  152. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts.map +0 -1
  153. package/dist/legacy-runtime/hooks/AttachmentContext.js +0 -47
  154. package/dist/legacy-runtime/hooks/AttachmentContext.js.map +0 -1
  155. package/dist/legacy-runtime/hooks/ComposerContext.d.ts +0 -141
  156. package/dist/legacy-runtime/hooks/ComposerContext.d.ts.map +0 -1
  157. package/dist/legacy-runtime/hooks/ComposerContext.js +0 -65
  158. package/dist/legacy-runtime/hooks/ComposerContext.js.map +0 -1
  159. package/dist/legacy-runtime/hooks/MessageContext.d.ts +0 -155
  160. package/dist/legacy-runtime/hooks/MessageContext.d.ts.map +0 -1
  161. package/dist/legacy-runtime/hooks/MessageContext.js +0 -68
  162. package/dist/legacy-runtime/hooks/MessageContext.js.map +0 -1
  163. package/dist/legacy-runtime/hooks/MessagePartContext.d.ts +0 -44
  164. package/dist/legacy-runtime/hooks/MessagePartContext.d.ts.map +0 -1
  165. package/dist/legacy-runtime/hooks/MessagePartContext.js +0 -26
  166. package/dist/legacy-runtime/hooks/MessagePartContext.js.map +0 -1
  167. package/dist/legacy-runtime/hooks/ThreadContext.d.ts +0 -139
  168. package/dist/legacy-runtime/hooks/ThreadContext.d.ts.map +0 -1
  169. package/dist/legacy-runtime/hooks/ThreadContext.js +0 -84
  170. package/dist/legacy-runtime/hooks/ThreadContext.js.map +0 -1
  171. package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts +0 -44
  172. package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts.map +0 -1
  173. package/dist/legacy-runtime/hooks/ThreadListItemContext.js +0 -26
  174. package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +0 -1
  175. package/src/context/react/utils/createStateHookForRuntime.ts +0 -82
  176. package/src/legacy-runtime/hooks/AssistantContext.ts +0 -67
  177. package/src/legacy-runtime/hooks/AttachmentContext.ts +0 -99
  178. package/src/legacy-runtime/hooks/ComposerContext.ts +0 -131
  179. package/src/legacy-runtime/hooks/MessageContext.ts +0 -127
  180. package/src/legacy-runtime/hooks/MessagePartContext.ts +0 -32
  181. package/src/legacy-runtime/hooks/ThreadContext.ts +0 -120
  182. package/src/legacy-runtime/hooks/ThreadListItemContext.ts +0 -36
  183. package/src/tests/BaseComposerRuntimeCore.test.ts +0 -621
  184. package/src/tests/BaseSubscribable.test.ts +0 -54
  185. package/src/tests/DataRenderers.test.ts +0 -355
  186. package/src/tests/ExternalStoreThreadRuntimeCore.test.ts +0 -685
  187. package/src/tests/LocalThreadRuntimeCore.test.ts +0 -324
  188. package/src/tests/auiV0Encode.test.ts +0 -188
  189. package/src/tests/external-message-converter.test.ts +0 -346
  190. package/src/tests/shouldContinue.test.ts +0 -122
@@ -1,324 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { LocalThreadRuntimeCore } from "../legacy-runtime/runtime-cores/local/LocalThreadRuntimeCore";
3
- import type { ChatModelAdapter } from "../legacy-runtime/runtime-cores/local/ChatModelAdapter";
4
- import type { LocalRuntimeOptionsBase } from "../legacy-runtime/runtime-cores/local/LocalRuntimeOptions";
5
- import type { ModelContextProvider } from "@assistant-ui/core";
6
- import type { AppendMessage } from "@assistant-ui/core";
7
-
8
- const createMockContextProvider = (): ModelContextProvider => ({
9
- getModelContext: () => ({}),
10
- });
11
-
12
- const createOptions = (
13
- adapter: ChatModelAdapter,
14
- overrides: Partial<LocalRuntimeOptionsBase> = {},
15
- ): LocalRuntimeOptionsBase => ({
16
- adapters: { chatModel: adapter },
17
- ...overrides,
18
- });
19
-
20
- const createUserAppendMessage = (
21
- text: string,
22
- overrides: Partial<AppendMessage> = {},
23
- ): AppendMessage => ({
24
- role: "user",
25
- content: [{ type: "text", text }],
26
- attachments: [],
27
- metadata: { custom: {} },
28
- parentId: null,
29
- sourceId: null,
30
- runConfig: undefined,
31
- createdAt: new Date(),
32
- ...overrides,
33
- });
34
-
35
- describe("LocalThreadRuntimeCore", () => {
36
- let contextProvider: ModelContextProvider;
37
-
38
- beforeEach(() => {
39
- contextProvider = createMockContextProvider();
40
- });
41
-
42
- it("appends a user message and runs the chat model", async () => {
43
- const adapter: ChatModelAdapter = {
44
- run: vi.fn().mockResolvedValue({
45
- content: [{ type: "text", text: "Hello!" }],
46
- status: { type: "complete", reason: "stop" },
47
- }),
48
- };
49
- const core = new LocalThreadRuntimeCore(
50
- contextProvider,
51
- createOptions(adapter),
52
- );
53
-
54
- await core.append(createUserAppendMessage("Hi"));
55
-
56
- const messages = core.messages;
57
- expect(messages).toHaveLength(2);
58
- expect(messages[0]!.role).toBe("user");
59
- expect(messages[1]!.role).toBe("assistant");
60
- expect(messages[1]!.content).toEqual(
61
- expect.arrayContaining([
62
- expect.objectContaining({ type: "text", text: "Hello!" }),
63
- ]),
64
- );
65
- expect(messages[1]!.status).toEqual({ type: "complete", reason: "stop" });
66
- expect(adapter.run).toHaveBeenCalledOnce();
67
- });
68
-
69
- it("streams assistant response via async generator", async () => {
70
- const adapter: ChatModelAdapter = {
71
- run: vi.fn().mockImplementation(async function* () {
72
- yield {
73
- content: [{ type: "text" as const, text: "Hel" }],
74
- };
75
- yield {
76
- content: [{ type: "text" as const, text: "Hello world" }],
77
- status: { type: "complete" as const, reason: "stop" as const },
78
- };
79
- }),
80
- };
81
- const core = new LocalThreadRuntimeCore(
82
- contextProvider,
83
- createOptions(adapter),
84
- );
85
-
86
- await core.append(createUserAppendMessage("Stream test"));
87
-
88
- const messages = core.messages;
89
- expect(messages).toHaveLength(2);
90
- const assistant = messages[1]!;
91
- expect(assistant.role).toBe("assistant");
92
- expect(assistant.content).toEqual(
93
- expect.arrayContaining([
94
- expect.objectContaining({ type: "text", text: "Hello world" }),
95
- ]),
96
- );
97
- expect(assistant.status).toEqual({ type: "complete", reason: "stop" });
98
- });
99
-
100
- it("cancels a running response", async () => {
101
- const adapter: ChatModelAdapter = {
102
- run: vi.fn().mockImplementation(async function* ({ abortSignal }) {
103
- yield {
104
- content: [{ type: "text" as const, text: "partial" }],
105
- };
106
- // Wait until the abort signal fires
107
- await new Promise<void>((_resolve, reject) => {
108
- if (abortSignal.aborted) {
109
- reject(abortSignal.reason);
110
- return;
111
- }
112
- abortSignal.addEventListener(
113
- "abort",
114
- () => reject(abortSignal.reason),
115
- { once: true },
116
- );
117
- });
118
- }),
119
- };
120
- const core = new LocalThreadRuntimeCore(
121
- contextProvider,
122
- createOptions(adapter),
123
- );
124
-
125
- // Start append but don't await (it will hang until cancelled)
126
- const appendPromise = core.append(createUserAppendMessage("Cancel me"));
127
-
128
- // Give the generator time to yield first chunk
129
- await new Promise((r) => setTimeout(r, 50));
130
-
131
- core.cancelRun();
132
- await appendPromise;
133
-
134
- const messages = core.messages;
135
- expect(messages).toHaveLength(2);
136
- const assistant = messages[1]!;
137
- expect(assistant.status).toBeDefined();
138
- expect(assistant.status!.type).toBe("incomplete");
139
- if (assistant.status!.type === "incomplete") {
140
- expect(assistant.status!.reason).toBe("cancelled");
141
- }
142
- });
143
-
144
- it("handles adapter errors gracefully", async () => {
145
- const adapter: ChatModelAdapter = {
146
- run: vi.fn().mockRejectedValue(new Error("Model unavailable")),
147
- };
148
- const core = new LocalThreadRuntimeCore(
149
- contextProvider,
150
- createOptions(adapter),
151
- );
152
-
153
- await expect(
154
- core.append(createUserAppendMessage("Error test")),
155
- ).rejects.toThrow("Model unavailable");
156
-
157
- const messages = core.messages;
158
- expect(messages).toHaveLength(2);
159
- const assistant = messages[1]!;
160
- expect(assistant.status).toBeDefined();
161
- expect(assistant.status!.type).toBe("incomplete");
162
- if (assistant.status!.type === "incomplete") {
163
- expect(assistant.status!.reason).toBe("error");
164
- expect(assistant.status!.error).toEqual({
165
- code: "unknown",
166
- message: "Model unavailable",
167
- });
168
- }
169
- });
170
-
171
- it("continues tool execution loop", async () => {
172
- let callCount = 0;
173
- const adapter: ChatModelAdapter = {
174
- run: vi.fn().mockImplementation(() => {
175
- callCount++;
176
- if (callCount === 1) {
177
- return Promise.resolve({
178
- content: [
179
- {
180
- type: "tool-call",
181
- toolCallId: "tc1",
182
- toolName: "myTool",
183
- args: { input: "test" },
184
- argsText: '{"input":"test"}',
185
- },
186
- ],
187
- status: { type: "requires-action", reason: "tool-calls" },
188
- });
189
- }
190
- return Promise.resolve({
191
- content: [{ type: "text", text: "Done with tool" }],
192
- status: { type: "complete", reason: "stop" },
193
- });
194
- }),
195
- };
196
- const core = new LocalThreadRuntimeCore(
197
- contextProvider,
198
- createOptions(adapter),
199
- );
200
-
201
- await core.append(createUserAppendMessage("Use a tool"));
202
-
203
- // The assistant message should have a tool-call with no result yet
204
- // and status requires-action. Now add the tool result.
205
- const assistantMsg = core.messages[1]!;
206
- expect(assistantMsg.role).toBe("assistant");
207
-
208
- core.addToolResult({
209
- messageId: assistantMsg.id,
210
- toolName: "myTool",
211
- toolCallId: "tc1",
212
- result: "tool output",
213
- isError: false,
214
- });
215
-
216
- // Wait for the second roundtrip to complete
217
- await new Promise((r) => setTimeout(r, 100));
218
-
219
- expect(adapter.run).toHaveBeenCalledTimes(2);
220
-
221
- const finalMessages = core.messages;
222
- const finalAssistant = finalMessages[1]!;
223
- // Content should include both the tool-call from round 1 and text from round 2
224
- expect(finalAssistant.content.some((c) => c.type === "tool-call")).toBe(
225
- true,
226
- );
227
- expect(
228
- finalAssistant.content.some(
229
- (c) => c.type === "text" && c.text === "Done with tool",
230
- ),
231
- ).toBe(true);
232
- });
233
-
234
- it("stops at maxSteps", async () => {
235
- const adapter: ChatModelAdapter = {
236
- run: vi.fn().mockResolvedValue({
237
- content: [
238
- {
239
- type: "tool-call",
240
- toolCallId: "tc1",
241
- toolName: "myTool",
242
- args: {},
243
- argsText: "{}",
244
- },
245
- ],
246
- status: { type: "requires-action", reason: "tool-calls" },
247
- metadata: {
248
- steps: [{ usage: { promptTokens: 10, completionTokens: 5 } }],
249
- },
250
- }),
251
- };
252
- const core = new LocalThreadRuntimeCore(
253
- contextProvider,
254
- createOptions(adapter, { maxSteps: 1 }),
255
- );
256
-
257
- await core.append(createUserAppendMessage("Tool call"));
258
-
259
- // Add tool result - this should NOT trigger another roundtrip because maxSteps=1
260
- const assistantMsg = core.messages[1]!;
261
- core.addToolResult({
262
- messageId: assistantMsg.id,
263
- toolName: "myTool",
264
- toolCallId: "tc1",
265
- result: "result",
266
- isError: false,
267
- });
268
-
269
- // Wait a bit to ensure no additional roundtrip happened
270
- await new Promise((r) => setTimeout(r, 100));
271
-
272
- // Should have been called only once (the initial run)
273
- expect(adapter.run).toHaveBeenCalledTimes(1);
274
-
275
- const finalAssistant = core.messages[1]!;
276
- expect(finalAssistant.status).toBeDefined();
277
- expect(finalAssistant.status!.type).toBe("incomplete");
278
- if (finalAssistant.status!.type === "incomplete") {
279
- expect(finalAssistant.status!.reason).toBe("tool-calls");
280
- }
281
- });
282
-
283
- it("capabilities update from options", () => {
284
- const adapter: ChatModelAdapter = {
285
- run: vi.fn().mockResolvedValue({ content: [] }),
286
- };
287
- const core = new LocalThreadRuntimeCore(
288
- contextProvider,
289
- createOptions(adapter),
290
- );
291
-
292
- // Default capabilities
293
- expect(core.capabilities.speech).toBe(false);
294
- expect(core.capabilities.dictation).toBe(false);
295
- expect(core.capabilities.attachments).toBe(false);
296
- expect(core.capabilities.feedback).toBe(false);
297
-
298
- // Update with adapters
299
- core.__internal_setOptions({
300
- adapters: {
301
- chatModel: adapter,
302
- speech: {} as any,
303
- dictation: {} as any,
304
- attachments: {} as any,
305
- feedback: {} as any,
306
- },
307
- });
308
-
309
- expect(core.capabilities.speech).toBe(true);
310
- expect(core.capabilities.dictation).toBe(true);
311
- expect(core.capabilities.attachments).toBe(true);
312
- expect(core.capabilities.feedback).toBe(true);
313
-
314
- // Update back to no adapters
315
- core.__internal_setOptions({
316
- adapters: { chatModel: adapter },
317
- });
318
-
319
- expect(core.capabilities.speech).toBe(false);
320
- expect(core.capabilities.dictation).toBe(false);
321
- expect(core.capabilities.attachments).toBe(false);
322
- expect(core.capabilities.feedback).toBe(false);
323
- });
324
- });
@@ -1,188 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { auiV0Decode, auiV0Encode } from "../legacy-runtime/cloud/auiV0";
3
-
4
- describe("auiV0Encode", () => {
5
- it("preserves document source parts in the legacy cloud encoder", () => {
6
- const encoded = auiV0Encode({
7
- id: "m1",
8
- createdAt: new Date("2026-03-15T00:00:00.000Z"),
9
- role: "assistant",
10
- status: { type: "complete", reason: "stop" },
11
- metadata: {
12
- unstable_state: null,
13
- unstable_annotations: [],
14
- unstable_data: [],
15
- steps: [],
16
- custom: {},
17
- },
18
- content: [
19
- {
20
- type: "source",
21
- sourceType: "document",
22
- id: "doc_123",
23
- title: "proposal.pdf",
24
- mediaType: "application/pdf",
25
- filename: "proposal.pdf",
26
- providerMetadata: {
27
- openai: {
28
- type: "file_citation",
29
- fileId: "file_123",
30
- index: 0,
31
- },
32
- },
33
- },
34
- ],
35
- });
36
-
37
- expect(encoded.content).toEqual([
38
- {
39
- type: "source",
40
- sourceType: "document",
41
- id: "doc_123",
42
- title: "proposal.pdf",
43
- mediaType: "application/pdf",
44
- filename: "proposal.pdf",
45
- providerMetadata: {
46
- openai: {
47
- type: "file_citation",
48
- fileId: "file_123",
49
- index: 0,
50
- },
51
- },
52
- },
53
- ]);
54
- });
55
-
56
- it("preserves user attachments in the legacy cloud encoder", () => {
57
- const encoded = auiV0Encode({
58
- id: "m1",
59
- createdAt: new Date("2026-03-15T00:00:00.000Z"),
60
- role: "user",
61
- metadata: { custom: {} },
62
- content: [{ type: "text", text: "please review this" }],
63
- attachments: [
64
- {
65
- id: "att-1",
66
- type: "document",
67
- name: "proposal.pdf",
68
- contentType: "application/pdf",
69
- status: { type: "complete" },
70
- content: [
71
- {
72
- type: "file",
73
- data: "data:application/pdf;base64,JVBERi0xLjQ=",
74
- mimeType: "application/pdf",
75
- filename: "proposal.pdf",
76
- },
77
- ],
78
- },
79
- ],
80
- });
81
-
82
- expect(encoded.attachments).toEqual([
83
- {
84
- id: "att-1",
85
- type: "document",
86
- name: "proposal.pdf",
87
- contentType: "application/pdf",
88
- status: { type: "complete" },
89
- content: [
90
- {
91
- type: "file",
92
- data: "data:application/pdf;base64,JVBERi0xLjQ=",
93
- mimeType: "application/pdf",
94
- filename: "proposal.pdf",
95
- },
96
- ],
97
- },
98
- ]);
99
- });
100
-
101
- it("omits missing attachment contentType in the legacy cloud encoder", () => {
102
- const encoded = auiV0Encode({
103
- id: "m1",
104
- createdAt: new Date("2026-03-15T00:00:00.000Z"),
105
- role: "user",
106
- metadata: { custom: {} },
107
- content: [{ type: "text", text: "please review this" }],
108
- attachments: [
109
- {
110
- id: "att-1",
111
- type: "document",
112
- name: "notes.txt",
113
- status: { type: "complete" },
114
- content: [{ type: "text", text: "notes" }],
115
- },
116
- ],
117
- });
118
-
119
- expect(encoded.attachments).toEqual([
120
- {
121
- id: "att-1",
122
- type: "document",
123
- name: "notes.txt",
124
- status: { type: "complete" },
125
- content: [{ type: "text", text: "notes" }],
126
- },
127
- ]);
128
- });
129
- });
130
-
131
- describe("auiV0Decode", () => {
132
- it("restores user attachments from legacy cloud history", () => {
133
- const content = auiV0Encode({
134
- id: "local",
135
- createdAt: new Date("2026-03-15T00:00:00.000Z"),
136
- role: "user",
137
- metadata: { custom: {} },
138
- content: [{ type: "text", text: "please review this" }],
139
- attachments: [
140
- {
141
- id: "att-1",
142
- type: "document",
143
- name: "proposal.pdf",
144
- contentType: "application/pdf",
145
- status: { type: "complete" },
146
- content: [
147
- {
148
- type: "file",
149
- data: "data:application/pdf;base64,JVBERi0xLjQ=",
150
- mimeType: "application/pdf",
151
- filename: "proposal.pdf",
152
- },
153
- ],
154
- },
155
- ],
156
- });
157
-
158
- const decoded = auiV0Decode({
159
- id: "cloud",
160
- parent_id: null,
161
- height: 0,
162
- created_at: new Date("2026-03-15T00:00:00.000Z"),
163
- updated_at: new Date("2026-03-15T00:00:00.000Z"),
164
- format: "aui/v0",
165
- content: content as never,
166
- });
167
-
168
- expect(decoded.message.role).toBe("user");
169
- if (decoded.message.role !== "user") throw new Error("expected user");
170
- expect(decoded.message.attachments).toEqual([
171
- {
172
- id: "att-1",
173
- type: "document",
174
- name: "proposal.pdf",
175
- contentType: "application/pdf",
176
- status: { type: "complete" },
177
- content: [
178
- {
179
- type: "file",
180
- data: "data:application/pdf;base64,JVBERi0xLjQ=",
181
- mimeType: "application/pdf",
182
- filename: "proposal.pdf",
183
- },
184
- ],
185
- },
186
- ]);
187
- });
188
- });