@tanstack/ai-devtools-core 0.0.1

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/esm/components/ConversationDetails.d.ts +2 -0
  4. package/dist/esm/components/ConversationDetails.js +134 -0
  5. package/dist/esm/components/ConversationDetails.js.map +1 -0
  6. package/dist/esm/components/ConversationsList.d.ts +2 -0
  7. package/dist/esm/components/ConversationsList.js +30 -0
  8. package/dist/esm/components/ConversationsList.js.map +1 -0
  9. package/dist/esm/components/Shell.d.ts +1 -0
  10. package/dist/esm/components/Shell.js +94 -0
  11. package/dist/esm/components/Shell.js.map +1 -0
  12. package/dist/esm/components/conversation/ChunkBadges.d.ts +7 -0
  13. package/dist/esm/components/conversation/ChunkBadges.js +54 -0
  14. package/dist/esm/components/conversation/ChunkBadges.js.map +1 -0
  15. package/dist/esm/components/conversation/ChunkItem.d.ts +9 -0
  16. package/dist/esm/components/conversation/ChunkItem.js +247 -0
  17. package/dist/esm/components/conversation/ChunkItem.js.map +1 -0
  18. package/dist/esm/components/conversation/ChunksCollapsible.d.ts +7 -0
  19. package/dist/esm/components/conversation/ChunksCollapsible.js +77 -0
  20. package/dist/esm/components/conversation/ChunksCollapsible.js.map +1 -0
  21. package/dist/esm/components/conversation/ChunksTab.d.ts +8 -0
  22. package/dist/esm/components/conversation/ChunksTab.js +87 -0
  23. package/dist/esm/components/conversation/ChunksTab.js.map +1 -0
  24. package/dist/esm/components/conversation/ConversationHeader.d.ts +7 -0
  25. package/dist/esm/components/conversation/ConversationHeader.js +187 -0
  26. package/dist/esm/components/conversation/ConversationHeader.js.map +1 -0
  27. package/dist/esm/components/conversation/ConversationTabs.d.ts +10 -0
  28. package/dist/esm/components/conversation/ConversationTabs.js +88 -0
  29. package/dist/esm/components/conversation/ConversationTabs.js.map +1 -0
  30. package/dist/esm/components/conversation/EmbeddingsTab.d.ts +7 -0
  31. package/dist/esm/components/conversation/EmbeddingsTab.js +90 -0
  32. package/dist/esm/components/conversation/EmbeddingsTab.js.map +1 -0
  33. package/dist/esm/components/conversation/MessageCard.d.ts +7 -0
  34. package/dist/esm/components/conversation/MessageCard.js +152 -0
  35. package/dist/esm/components/conversation/MessageCard.js.map +1 -0
  36. package/dist/esm/components/conversation/MessageGroup.d.ts +15 -0
  37. package/dist/esm/components/conversation/MessageGroup.js +119 -0
  38. package/dist/esm/components/conversation/MessageGroup.js.map +1 -0
  39. package/dist/esm/components/conversation/MessagesTab.d.ts +7 -0
  40. package/dist/esm/components/conversation/MessagesTab.js +37 -0
  41. package/dist/esm/components/conversation/MessagesTab.js.map +1 -0
  42. package/dist/esm/components/conversation/SummariesTab.d.ts +7 -0
  43. package/dist/esm/components/conversation/SummariesTab.js +110 -0
  44. package/dist/esm/components/conversation/SummariesTab.js.map +1 -0
  45. package/dist/esm/components/conversation/ToolCallDisplay.d.ts +7 -0
  46. package/dist/esm/components/conversation/ToolCallDisplay.js +123 -0
  47. package/dist/esm/components/conversation/ToolCallDisplay.js.map +1 -0
  48. package/dist/esm/components/conversation/index.d.ts +7 -0
  49. package/dist/esm/components/list/ConversationRow.d.ts +7 -0
  50. package/dist/esm/components/list/ConversationRow.js +122 -0
  51. package/dist/esm/components/list/ConversationRow.js.map +1 -0
  52. package/dist/esm/components/list/index.d.ts +1 -0
  53. package/dist/esm/components/utils/format.d.ts +6 -0
  54. package/dist/esm/components/utils/format.js +68 -0
  55. package/dist/esm/components/utils/format.js.map +1 -0
  56. package/dist/esm/components/utils/index.d.ts +1 -0
  57. package/dist/esm/core.d.ts +18 -0
  58. package/dist/esm/core.js +9 -0
  59. package/dist/esm/core.js.map +1 -0
  60. package/dist/esm/index.d.ts +9 -0
  61. package/dist/esm/index.js +6 -0
  62. package/dist/esm/index.js.map +1 -0
  63. package/dist/esm/production.d.ts +2 -0
  64. package/dist/esm/production.js +5 -0
  65. package/dist/esm/production.js.map +1 -0
  66. package/dist/esm/store/ai-context.d.ts +126 -0
  67. package/dist/esm/store/ai-context.js +1081 -0
  68. package/dist/esm/store/ai-context.js.map +1 -0
  69. package/dist/esm/store/ai-store.d.ts +1 -0
  70. package/dist/esm/styles/tokens.d.ts +298 -0
  71. package/dist/esm/styles/tokens.js +107 -0
  72. package/dist/esm/styles/tokens.js.map +1 -0
  73. package/dist/esm/styles/use-styles.d.ts +226 -0
  74. package/dist/esm/styles/use-styles.js +1538 -0
  75. package/dist/esm/styles/use-styles.js.map +1 -0
  76. package/package.json +61 -0
  77. package/src/components/ConversationDetails.tsx +89 -0
  78. package/src/components/ConversationsList.tsx +21 -0
  79. package/src/components/Shell.tsx +93 -0
  80. package/src/components/conversation/ChunkBadges.tsx +51 -0
  81. package/src/components/conversation/ChunkItem.tsx +273 -0
  82. package/src/components/conversation/ChunksCollapsible.tsx +58 -0
  83. package/src/components/conversation/ChunksTab.tsx +85 -0
  84. package/src/components/conversation/ConversationHeader.tsx +130 -0
  85. package/src/components/conversation/ConversationTabs.tsx +104 -0
  86. package/src/components/conversation/EmbeddingsTab.tsx +80 -0
  87. package/src/components/conversation/MessageCard.tsx +137 -0
  88. package/src/components/conversation/MessageGroup.tsx +101 -0
  89. package/src/components/conversation/MessagesTab.tsx +30 -0
  90. package/src/components/conversation/SummariesTab.tsx +91 -0
  91. package/src/components/conversation/ToolCallDisplay.tsx +99 -0
  92. package/src/components/conversation/index.ts +8 -0
  93. package/src/components/list/ConversationRow.tsx +85 -0
  94. package/src/components/list/index.ts +1 -0
  95. package/src/components/utils/format.ts +61 -0
  96. package/src/components/utils/index.ts +1 -0
  97. package/src/core.tsx +10 -0
  98. package/src/index.ts +8 -0
  99. package/src/production.ts +3 -0
  100. package/src/store/ai-context.tsx +1784 -0
  101. package/src/store/ai-store.ts +2 -0
  102. package/src/styles/tokens.ts +305 -0
  103. package/src/styles/use-styles.ts +1537 -0
@@ -0,0 +1,1081 @@
1
+ import { createComponent } from "solid-js/web";
2
+ import { onMount, onCleanup, createContext, useContext, batch } from "solid-js";
3
+ import { createStore, produce } from "solid-js/store";
4
+ import { aiEventClient } from "@tanstack/ai/event-client";
5
+ const AIContext = createContext();
6
+ function useAIStore() {
7
+ const context = useContext(AIContext);
8
+ if (!context) {
9
+ throw new Error("useAIStore must be used within an AIProvider");
10
+ }
11
+ return context;
12
+ }
13
+ const AIProvider = (props) => {
14
+ const [state, setState] = createStore({
15
+ conversations: {},
16
+ activeConversationId: null
17
+ });
18
+ const streamToConversation = /* @__PURE__ */ new Map();
19
+ const requestToConversation = /* @__PURE__ */ new Map();
20
+ const pendingConversationChunks = /* @__PURE__ */ new Map();
21
+ const pendingMessageChunks = /* @__PURE__ */ new Map();
22
+ let batchScheduled = false;
23
+ function scheduleBatchFlush() {
24
+ if (batchScheduled) return;
25
+ batchScheduled = true;
26
+ queueMicrotask(flushPendingChunks);
27
+ }
28
+ function isMergeableChunkType(type) {
29
+ return type === "content" || type === "thinking";
30
+ }
31
+ function mergeChunks(existing, pending) {
32
+ for (const chunk of pending) {
33
+ const lastChunk = existing[existing.length - 1];
34
+ if (lastChunk && lastChunk.type === chunk.type && isMergeableChunkType(chunk.type) && lastChunk.messageId === chunk.messageId) {
35
+ lastChunk.content = chunk.content || lastChunk.content;
36
+ lastChunk.delta = chunk.delta;
37
+ lastChunk.chunkCount += chunk.chunkCount;
38
+ } else {
39
+ existing.push(chunk);
40
+ }
41
+ }
42
+ }
43
+ function flushPendingChunks() {
44
+ batchScheduled = false;
45
+ batch(() => {
46
+ for (const [conversationId, {
47
+ chunks,
48
+ newChunkCount
49
+ }] of pendingConversationChunks) {
50
+ const conv = state.conversations[conversationId];
51
+ if (conv) {
52
+ setState("conversations", conversationId, "chunks", produce((arr) => {
53
+ mergeChunks(arr, chunks);
54
+ }));
55
+ }
56
+ }
57
+ pendingConversationChunks.clear();
58
+ for (const [conversationId, messageMap] of pendingMessageChunks) {
59
+ const conv = state.conversations[conversationId];
60
+ if (!conv) continue;
61
+ for (const [messageIndex, {
62
+ chunks,
63
+ newChunkCount
64
+ }] of messageMap) {
65
+ const message = conv.messages[messageIndex];
66
+ if (message) {
67
+ setState("conversations", conversationId, "messages", messageIndex, "chunks", produce((arr) => {
68
+ if (!arr) {
69
+ return chunks;
70
+ }
71
+ mergeChunks(arr, chunks);
72
+ return arr;
73
+ }));
74
+ const currentTotal = message.totalChunkCount || 0;
75
+ setState("conversations", conversationId, "messages", messageIndex, "totalChunkCount", currentTotal + newChunkCount);
76
+ }
77
+ }
78
+ }
79
+ pendingMessageChunks.clear();
80
+ });
81
+ }
82
+ function queueChunk(conversationId, chunk) {
83
+ if (!pendingConversationChunks.has(conversationId)) {
84
+ pendingConversationChunks.set(conversationId, {
85
+ chunks: [],
86
+ newChunkCount: 0
87
+ });
88
+ }
89
+ const pending = pendingConversationChunks.get(conversationId);
90
+ const lastPending = pending.chunks[pending.chunks.length - 1];
91
+ if (lastPending && lastPending.type === chunk.type && isMergeableChunkType(chunk.type) && lastPending.messageId === chunk.messageId) {
92
+ lastPending.content = chunk.content || lastPending.content;
93
+ lastPending.delta = chunk.delta;
94
+ lastPending.chunkCount += chunk.chunkCount;
95
+ } else {
96
+ pending.chunks.push(chunk);
97
+ }
98
+ pending.newChunkCount += chunk.chunkCount;
99
+ scheduleBatchFlush();
100
+ }
101
+ function queueMessageChunk(conversationId, messageIndex, chunk) {
102
+ if (!pendingMessageChunks.has(conversationId)) {
103
+ pendingMessageChunks.set(conversationId, /* @__PURE__ */ new Map());
104
+ }
105
+ const messageMap = pendingMessageChunks.get(conversationId);
106
+ if (!messageMap.has(messageIndex)) {
107
+ messageMap.set(messageIndex, {
108
+ chunks: [],
109
+ newChunkCount: 0
110
+ });
111
+ }
112
+ const pending = messageMap.get(messageIndex);
113
+ const lastPending = pending.chunks[pending.chunks.length - 1];
114
+ if (lastPending && lastPending.type === chunk.type && isMergeableChunkType(chunk.type) && lastPending.messageId === chunk.messageId) {
115
+ lastPending.content = chunk.content || lastPending.content;
116
+ lastPending.delta = chunk.delta;
117
+ lastPending.chunkCount += chunk.chunkCount;
118
+ } else {
119
+ pending.chunks.push(chunk);
120
+ }
121
+ pending.newChunkCount += chunk.chunkCount;
122
+ scheduleBatchFlush();
123
+ }
124
+ function getOrCreateConversation(id, type, label) {
125
+ if (!state.conversations[id]) {
126
+ setState("conversations", id, {
127
+ id,
128
+ type,
129
+ label,
130
+ messages: [],
131
+ chunks: [],
132
+ status: "active",
133
+ startedAt: Date.now()
134
+ });
135
+ if (!state.activeConversationId) {
136
+ setState("activeConversationId", id);
137
+ }
138
+ }
139
+ }
140
+ function addMessage(conversationId, message) {
141
+ const conv = state.conversations[conversationId];
142
+ if (!conv) return;
143
+ setState("conversations", conversationId, "messages", conv.messages.length, message);
144
+ }
145
+ function addChunkToMessage(conversationId, chunk) {
146
+ const conv = state.conversations[conversationId];
147
+ if (!conv) return;
148
+ if (chunk.messageId) {
149
+ const messageIndex = conv.messages.findIndex((msg) => msg.id === chunk.messageId);
150
+ if (messageIndex !== -1) {
151
+ queueMessageChunk(conversationId, messageIndex, chunk);
152
+ return;
153
+ } else {
154
+ const newMessage = {
155
+ id: chunk.messageId,
156
+ role: "assistant",
157
+ content: "",
158
+ timestamp: chunk.timestamp,
159
+ model: conv.model,
160
+ chunks: [chunk]
161
+ };
162
+ setState("conversations", conversationId, "messages", conv.messages.length, newMessage);
163
+ return;
164
+ }
165
+ }
166
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
167
+ const message = conv.messages[i];
168
+ if (message && message.role === "assistant") {
169
+ queueMessageChunk(conversationId, i, chunk);
170
+ return;
171
+ }
172
+ }
173
+ }
174
+ function updateMessageUsage(conversationId, messageId, cumulativeUsage) {
175
+ const conv = state.conversations[conversationId];
176
+ if (!conv) return;
177
+ let previousPromptTokens = 0;
178
+ let previousCompletionTokens = 0;
179
+ let targetMessageIndex = -1;
180
+ if (messageId) {
181
+ targetMessageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
182
+ } else {
183
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
184
+ if (conv.messages[i]?.role === "assistant") {
185
+ targetMessageIndex = i;
186
+ break;
187
+ }
188
+ }
189
+ }
190
+ if (targetMessageIndex === -1) return;
191
+ for (let i = 0; i < targetMessageIndex; i++) {
192
+ const msg = conv.messages[i];
193
+ if (msg?.role === "assistant" && msg.usage) {
194
+ previousPromptTokens += msg.usage.promptTokens;
195
+ previousCompletionTokens += msg.usage.completionTokens;
196
+ }
197
+ }
198
+ const deltaUsage = {
199
+ promptTokens: Math.max(0, cumulativeUsage.promptTokens - previousPromptTokens),
200
+ completionTokens: Math.max(0, cumulativeUsage.completionTokens - previousCompletionTokens),
201
+ totalTokens: 0
202
+ };
203
+ deltaUsage.totalTokens = deltaUsage.promptTokens + deltaUsage.completionTokens;
204
+ setState("conversations", conversationId, "messages", targetMessageIndex, "usage", deltaUsage);
205
+ }
206
+ function clearAllConversations() {
207
+ setState("conversations", {});
208
+ setState("activeConversationId", null);
209
+ streamToConversation.clear();
210
+ requestToConversation.clear();
211
+ pendingConversationChunks.clear();
212
+ pendingMessageChunks.clear();
213
+ }
214
+ function selectConversation(id) {
215
+ setState("activeConversationId", id);
216
+ }
217
+ function updateConversation(conversationId, updates) {
218
+ if (!state.conversations[conversationId]) return;
219
+ for (const [key, value] of Object.entries(updates)) {
220
+ setState("conversations", conversationId, key, value);
221
+ }
222
+ }
223
+ function updateMessage(conversationId, messageIndex, updates) {
224
+ const conv = state.conversations[conversationId];
225
+ if (!conv || !conv.messages[messageIndex]) return;
226
+ for (const [key, value] of Object.entries(updates)) {
227
+ setState("conversations", conversationId, "messages", messageIndex, key, value);
228
+ }
229
+ }
230
+ function updateToolCall(conversationId, messageIndex, toolCallIndex, updates) {
231
+ const conv = state.conversations[conversationId];
232
+ if (!conv?.messages[messageIndex]?.toolCalls?.[toolCallIndex]) return;
233
+ setState("conversations", conversationId, "messages", messageIndex, "toolCalls", toolCallIndex, produce((tc) => Object.assign(tc, updates)));
234
+ }
235
+ function setToolCalls(conversationId, messageIndex, toolCalls) {
236
+ if (!state.conversations[conversationId]?.messages[messageIndex]) return;
237
+ setState("conversations", conversationId, "messages", messageIndex, "toolCalls", toolCalls);
238
+ }
239
+ function addChunk(conversationId, chunk) {
240
+ if (!state.conversations[conversationId]) return;
241
+ queueChunk(conversationId, chunk);
242
+ }
243
+ function ensureMessageForChunk(conversationId, messageId, timestamp) {
244
+ if (!messageId) return;
245
+ const conv = state.conversations[conversationId];
246
+ if (!conv || conv.type === "client") return;
247
+ const existingMessage = conv.messages.find((m) => m.id === messageId);
248
+ if (existingMessage) return;
249
+ addMessage(conversationId, {
250
+ id: messageId,
251
+ role: "assistant",
252
+ content: "",
253
+ timestamp,
254
+ source: "server"
255
+ });
256
+ }
257
+ onMount(() => {
258
+ const cleanupFns = [];
259
+ cleanupFns.push(aiEventClient.on("client:created", (e) => {
260
+ const clientId = e.payload.clientId;
261
+ getOrCreateConversation(clientId, "client", `Client Chat (${clientId.substring(0, 8)})`);
262
+ updateConversation(clientId, {
263
+ model: void 0,
264
+ provider: "Client"
265
+ });
266
+ }, {
267
+ withEventTarget: false
268
+ }));
269
+ cleanupFns.push(aiEventClient.on("client:message-sent", (e) => {
270
+ const clientId = e.payload.clientId;
271
+ if (!state.conversations[clientId]) {
272
+ getOrCreateConversation(clientId, "client", `Client Chat (${clientId.substring(0, 8)})`);
273
+ }
274
+ addMessage(clientId, {
275
+ id: e.payload.messageId,
276
+ role: "user",
277
+ content: e.payload.content,
278
+ timestamp: e.payload.timestamp,
279
+ source: "client"
280
+ });
281
+ updateConversation(clientId, {
282
+ status: "active"
283
+ });
284
+ }, {
285
+ withEventTarget: false
286
+ }));
287
+ cleanupFns.push(aiEventClient.on("client:message-appended", (e) => {
288
+ const clientId = e.payload.clientId;
289
+ const role = e.payload.role;
290
+ if (role === "user") return;
291
+ if (!state.conversations[clientId]) return;
292
+ if (role === "assistant") {
293
+ addMessage(clientId, {
294
+ id: e.payload.messageId,
295
+ role: "assistant",
296
+ content: e.payload.contentPreview,
297
+ timestamp: e.payload.timestamp,
298
+ source: "client"
299
+ });
300
+ } else if (role === "tool") {
301
+ addMessage(clientId, {
302
+ id: e.payload.messageId,
303
+ role: "tool",
304
+ content: e.payload.contentPreview,
305
+ timestamp: e.payload.timestamp,
306
+ source: "client"
307
+ });
308
+ }
309
+ }, {
310
+ withEventTarget: false
311
+ }));
312
+ cleanupFns.push(aiEventClient.on("client:loading-changed", (e) => {
313
+ const clientId = e.payload.clientId;
314
+ if (state.conversations[clientId]) {
315
+ updateConversation(clientId, {
316
+ status: e.payload.isLoading ? "active" : "completed"
317
+ });
318
+ }
319
+ }, {
320
+ withEventTarget: false
321
+ }));
322
+ cleanupFns.push(aiEventClient.on("client:stopped", (e) => {
323
+ const clientId = e.payload.clientId;
324
+ if (state.conversations[clientId]) {
325
+ updateConversation(clientId, {
326
+ status: "completed",
327
+ completedAt: e.payload.timestamp
328
+ });
329
+ }
330
+ }, {
331
+ withEventTarget: false
332
+ }));
333
+ cleanupFns.push(aiEventClient.on("client:messages-cleared", (e) => {
334
+ const clientId = e.payload.clientId;
335
+ if (state.conversations[clientId]) {
336
+ updateConversation(clientId, {
337
+ messages: [],
338
+ chunks: [],
339
+ usage: void 0
340
+ });
341
+ }
342
+ }, {
343
+ withEventTarget: false
344
+ }));
345
+ cleanupFns.push(aiEventClient.on("client:reloaded", (e) => {
346
+ const clientId = e.payload.clientId;
347
+ const conv = state.conversations[clientId];
348
+ if (conv) {
349
+ updateConversation(clientId, {
350
+ messages: conv.messages.slice(0, e.payload.fromMessageIndex),
351
+ status: "active"
352
+ });
353
+ }
354
+ }, {
355
+ withEventTarget: false
356
+ }));
357
+ cleanupFns.push(aiEventClient.on("client:error-changed", (e) => {
358
+ const clientId = e.payload.clientId;
359
+ if (state.conversations[clientId] && e.payload.error) {
360
+ updateConversation(clientId, {
361
+ status: "error"
362
+ });
363
+ }
364
+ }, {
365
+ withEventTarget: false
366
+ }));
367
+ cleanupFns.push(aiEventClient.on("client:assistant-message-updated", (e) => {
368
+ const clientId = e.payload.clientId;
369
+ const messageId = e.payload.messageId;
370
+ const content = e.payload.content;
371
+ if (!state.conversations[clientId]) return;
372
+ const conv = state.conversations[clientId];
373
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
374
+ if (messageIndex >= 0) {
375
+ updateMessage(clientId, messageIndex, {
376
+ content,
377
+ model: conv.model
378
+ });
379
+ }
380
+ }, {
381
+ withEventTarget: false
382
+ }));
383
+ cleanupFns.push(aiEventClient.on("client:tool-call-updated", (e) => {
384
+ const {
385
+ clientId,
386
+ messageId,
387
+ toolCallId,
388
+ toolName,
389
+ state: toolCallState,
390
+ arguments: args
391
+ } = e.payload;
392
+ if (!state.conversations[clientId]) return;
393
+ const conv = state.conversations[clientId];
394
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
395
+ if (messageIndex === -1) return;
396
+ const message = conv.messages[messageIndex];
397
+ if (!message) return;
398
+ const toolCalls = message.toolCalls || [];
399
+ const existingToolIndex = toolCalls.findIndex((t) => t.id === toolCallId);
400
+ const toolCall = {
401
+ id: toolCallId,
402
+ name: toolName,
403
+ arguments: JSON.stringify(args, null, 2),
404
+ state: toolCallState
405
+ };
406
+ if (existingToolIndex >= 0) {
407
+ updateToolCall(clientId, messageIndex, existingToolIndex, toolCall);
408
+ } else {
409
+ setToolCalls(clientId, messageIndex, [...toolCalls, toolCall]);
410
+ }
411
+ }, {
412
+ withEventTarget: false
413
+ }));
414
+ cleanupFns.push(aiEventClient.on("client:approval-requested", (e) => {
415
+ const {
416
+ clientId,
417
+ messageId,
418
+ toolCallId,
419
+ approvalId
420
+ } = e.payload;
421
+ if (!state.conversations[clientId]) return;
422
+ const conv = state.conversations[clientId];
423
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
424
+ if (messageIndex === -1) return;
425
+ const message = conv.messages[messageIndex];
426
+ if (!message?.toolCalls) return;
427
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
428
+ if (toolCallIndex === -1) return;
429
+ updateToolCall(clientId, messageIndex, toolCallIndex, {
430
+ approvalRequired: true,
431
+ approvalId,
432
+ state: "approval-requested"
433
+ });
434
+ }, {
435
+ withEventTarget: false
436
+ }));
437
+ cleanupFns.push(aiEventClient.on("tool:result-added", (e) => {
438
+ const {
439
+ clientId,
440
+ toolCallId,
441
+ toolName,
442
+ output,
443
+ state: resultState,
444
+ timestamp
445
+ } = e.payload;
446
+ if (!state.conversations[clientId]) return;
447
+ const conv = state.conversations[clientId];
448
+ for (let messageIndex = conv.messages.length - 1; messageIndex >= 0; messageIndex--) {
449
+ const message = conv.messages[messageIndex];
450
+ if (!message?.toolCalls) continue;
451
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
452
+ if (toolCallIndex >= 0) {
453
+ updateToolCall(clientId, messageIndex, toolCallIndex, {
454
+ result: output,
455
+ state: resultState === "output-error" ? "error" : "complete"
456
+ });
457
+ const chunk = {
458
+ id: `chunk-tool-result-${toolCallId}-${Date.now()}`,
459
+ type: "tool_result",
460
+ messageId: message.id,
461
+ toolCallId,
462
+ toolName,
463
+ result: output,
464
+ timestamp,
465
+ chunkCount: 1
466
+ };
467
+ addChunkToMessage(clientId, chunk);
468
+ return;
469
+ }
470
+ }
471
+ }, {
472
+ withEventTarget: false
473
+ }));
474
+ cleanupFns.push(aiEventClient.on("tool:approval-responded", (e) => {
475
+ const {
476
+ clientId,
477
+ toolCallId,
478
+ approved
479
+ } = e.payload;
480
+ if (!state.conversations[clientId]) return;
481
+ const conv = state.conversations[clientId];
482
+ for (let messageIndex = conv.messages.length - 1; messageIndex >= 0; messageIndex--) {
483
+ const message = conv.messages[messageIndex];
484
+ if (!message?.toolCalls) continue;
485
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
486
+ if (toolCallIndex >= 0) {
487
+ updateToolCall(clientId, messageIndex, toolCallIndex, {
488
+ state: approved ? "approved" : "denied",
489
+ approvalRequired: false
490
+ });
491
+ return;
492
+ }
493
+ }
494
+ }, {
495
+ withEventTarget: false
496
+ }));
497
+ cleanupFns.push(aiEventClient.on("stream:chunk:content", (e) => {
498
+ const streamId = e.payload.streamId;
499
+ const conversationId = streamToConversation.get(streamId);
500
+ if (!conversationId) return;
501
+ const chunk = {
502
+ id: `chunk-${Date.now()}-${Math.random()}`,
503
+ type: "content",
504
+ messageId: e.payload.messageId,
505
+ content: e.payload.content,
506
+ delta: e.payload.delta,
507
+ timestamp: e.payload.timestamp,
508
+ chunkCount: 1
509
+ };
510
+ const conv = state.conversations[conversationId];
511
+ if (conv?.type === "client") {
512
+ addChunkToMessage(conversationId, chunk);
513
+ } else {
514
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
515
+ addChunk(conversationId, chunk);
516
+ }
517
+ }, {
518
+ withEventTarget: false
519
+ }));
520
+ cleanupFns.push(aiEventClient.on("stream:chunk:tool-call", (e) => {
521
+ const streamId = e.payload.streamId;
522
+ const conversationId = streamToConversation.get(streamId);
523
+ if (!conversationId) return;
524
+ const chunk = {
525
+ id: `chunk-${Date.now()}-${Math.random()}`,
526
+ type: "tool_call",
527
+ messageId: e.payload.messageId,
528
+ toolCallId: e.payload.toolCallId,
529
+ toolName: e.payload.toolName,
530
+ arguments: e.payload.arguments,
531
+ timestamp: e.payload.timestamp,
532
+ chunkCount: 1
533
+ };
534
+ const conv = state.conversations[conversationId];
535
+ if (conv?.type === "client") {
536
+ addChunkToMessage(conversationId, chunk);
537
+ } else {
538
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
539
+ addChunk(conversationId, chunk);
540
+ }
541
+ }, {
542
+ withEventTarget: false
543
+ }));
544
+ cleanupFns.push(aiEventClient.on("stream:chunk:tool-result", (e) => {
545
+ const streamId = e.payload.streamId;
546
+ const conversationId = streamToConversation.get(streamId);
547
+ if (!conversationId) return;
548
+ const chunk = {
549
+ id: `chunk-${Date.now()}-${Math.random()}`,
550
+ type: "tool_result",
551
+ messageId: e.payload.messageId,
552
+ toolCallId: e.payload.toolCallId,
553
+ content: e.payload.result,
554
+ timestamp: e.payload.timestamp,
555
+ chunkCount: 1
556
+ };
557
+ const conv = state.conversations[conversationId];
558
+ if (conv?.type === "client") {
559
+ addChunkToMessage(conversationId, chunk);
560
+ } else {
561
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
562
+ addChunk(conversationId, chunk);
563
+ }
564
+ if (conv && e.payload.toolCallId) {
565
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
566
+ const message = conv.messages[i];
567
+ if (!message?.toolCalls) continue;
568
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === e.payload.toolCallId);
569
+ if (toolCallIndex >= 0) {
570
+ updateToolCall(conversationId, i, toolCallIndex, {
571
+ result: e.payload.result,
572
+ state: "complete"
573
+ });
574
+ break;
575
+ }
576
+ }
577
+ }
578
+ }, {
579
+ withEventTarget: false
580
+ }));
581
+ cleanupFns.push(aiEventClient.on("stream:chunk:thinking", (e) => {
582
+ const streamId = e.payload.streamId;
583
+ const conversationId = streamToConversation.get(streamId);
584
+ if (!conversationId) return;
585
+ const chunk = {
586
+ id: `chunk-${Date.now()}-${Math.random()}`,
587
+ type: "thinking",
588
+ messageId: e.payload.messageId,
589
+ content: e.payload.content,
590
+ delta: e.payload.delta,
591
+ timestamp: e.payload.timestamp,
592
+ chunkCount: 1
593
+ };
594
+ const conv = state.conversations[conversationId];
595
+ if (conv?.type === "client") {
596
+ addChunkToMessage(conversationId, chunk);
597
+ if (e.payload.messageId) {
598
+ const messageIndex = conv.messages.findIndex((msg) => msg.id === e.payload.messageId);
599
+ if (messageIndex !== -1) {
600
+ updateMessage(conversationId, messageIndex, {
601
+ thinkingContent: e.payload.content
602
+ });
603
+ }
604
+ }
605
+ } else {
606
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
607
+ addChunk(conversationId, chunk);
608
+ }
609
+ }, {
610
+ withEventTarget: false
611
+ }));
612
+ cleanupFns.push(aiEventClient.on("stream:chunk:done", (e) => {
613
+ const streamId = e.payload.streamId;
614
+ const conversationId = streamToConversation.get(streamId);
615
+ if (!conversationId) return;
616
+ const chunk = {
617
+ id: `chunk-${Date.now()}-${Math.random()}`,
618
+ type: "done",
619
+ messageId: e.payload.messageId,
620
+ finishReason: e.payload.finishReason || void 0,
621
+ timestamp: e.payload.timestamp,
622
+ chunkCount: 1
623
+ };
624
+ if (e.payload.usage) {
625
+ updateConversation(conversationId, {
626
+ usage: e.payload.usage
627
+ });
628
+ updateMessageUsage(conversationId, e.payload.messageId, e.payload.usage);
629
+ }
630
+ const conv = state.conversations[conversationId];
631
+ if (conv?.type === "client") {
632
+ addChunkToMessage(conversationId, chunk);
633
+ } else {
634
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
635
+ addChunk(conversationId, chunk);
636
+ }
637
+ updateConversation(conversationId, {
638
+ status: "completed",
639
+ completedAt: e.payload.timestamp
640
+ });
641
+ }, {
642
+ withEventTarget: false
643
+ }));
644
+ cleanupFns.push(aiEventClient.on("stream:chunk:error", (e) => {
645
+ const streamId = e.payload.streamId;
646
+ const conversationId = streamToConversation.get(streamId);
647
+ if (!conversationId) return;
648
+ const chunk = {
649
+ id: `chunk-${Date.now()}-${Math.random()}`,
650
+ type: "error",
651
+ messageId: e.payload.messageId,
652
+ error: e.payload.error,
653
+ timestamp: e.payload.timestamp,
654
+ chunkCount: 1
655
+ };
656
+ const conv = state.conversations[conversationId];
657
+ if (conv?.type === "client") {
658
+ addChunkToMessage(conversationId, chunk);
659
+ } else {
660
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
661
+ addChunk(conversationId, chunk);
662
+ }
663
+ updateConversation(conversationId, {
664
+ status: "error",
665
+ completedAt: e.payload.timestamp
666
+ });
667
+ }, {
668
+ withEventTarget: false
669
+ }));
670
+ cleanupFns.push(aiEventClient.on("stream:ended", (e) => {
671
+ const streamId = e.payload.streamId;
672
+ const conversationId = streamToConversation.get(streamId);
673
+ if (!conversationId) return;
674
+ updateConversation(conversationId, {
675
+ status: "completed",
676
+ completedAt: e.payload.timestamp
677
+ });
678
+ }, {
679
+ withEventTarget: false
680
+ }));
681
+ cleanupFns.push(aiEventClient.on("stream:approval-requested", (e) => {
682
+ const {
683
+ streamId,
684
+ messageId,
685
+ toolCallId,
686
+ toolName,
687
+ input,
688
+ approvalId,
689
+ timestamp
690
+ } = e.payload;
691
+ const conversationId = streamToConversation.get(streamId);
692
+ if (!conversationId) return;
693
+ const conv = state.conversations[conversationId];
694
+ if (!conv) return;
695
+ const chunk = {
696
+ id: `chunk-${Date.now()}-${Math.random()}`,
697
+ type: "approval",
698
+ messageId,
699
+ toolCallId,
700
+ toolName,
701
+ approvalId,
702
+ input,
703
+ timestamp,
704
+ chunkCount: 1
705
+ };
706
+ if (conv.type === "client") {
707
+ addChunkToMessage(conversationId, chunk);
708
+ } else {
709
+ addChunk(conversationId, chunk);
710
+ }
711
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
712
+ const message = conv.messages[i];
713
+ if (!message) continue;
714
+ if (message.role === "assistant" && message.toolCalls) {
715
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
716
+ if (toolCallIndex >= 0) {
717
+ updateToolCall(conversationId, i, toolCallIndex, {
718
+ approvalRequired: true,
719
+ approvalId,
720
+ state: "approval-requested"
721
+ });
722
+ return;
723
+ }
724
+ }
725
+ }
726
+ }, {
727
+ withEventTarget: false
728
+ }));
729
+ cleanupFns.push(aiEventClient.on("processor:text-updated", (e) => {
730
+ const streamId = e.payload.streamId;
731
+ let conversationId = streamToConversation.get(streamId);
732
+ if (!conversationId) {
733
+ const activeClients = Object.values(state.conversations).filter((c) => c.type === "client" && c.status === "active").sort((a, b) => b.startedAt - a.startedAt);
734
+ if (activeClients.length > 0 && activeClients[0]) {
735
+ conversationId = activeClients[0].id;
736
+ streamToConversation.set(streamId, conversationId);
737
+ }
738
+ }
739
+ if (!conversationId) return;
740
+ const conv = state.conversations[conversationId];
741
+ if (!conv) return;
742
+ const lastMessage = conv.messages[conv.messages.length - 1];
743
+ if (lastMessage && lastMessage.role === "assistant") {
744
+ updateMessage(conversationId, conv.messages.length - 1, {
745
+ content: e.payload.content
746
+ });
747
+ }
748
+ }, {
749
+ withEventTarget: false
750
+ }));
751
+ cleanupFns.push(aiEventClient.on("processor:tool-call-state-changed", (e) => {
752
+ const streamId = e.payload.streamId;
753
+ const conversationId = streamToConversation.get(streamId);
754
+ if (!conversationId || !state.conversations[conversationId]) return;
755
+ const conv = state.conversations[conversationId];
756
+ const lastMessage = conv.messages[conv.messages.length - 1];
757
+ if (lastMessage && lastMessage.role === "assistant") {
758
+ const toolCalls = lastMessage.toolCalls || [];
759
+ const existingToolIndex = toolCalls.findIndex((t) => t.id === e.payload.toolCallId);
760
+ const toolCall = {
761
+ id: e.payload.toolCallId,
762
+ name: e.payload.toolName,
763
+ arguments: JSON.stringify(e.payload.arguments, null, 2),
764
+ state: e.payload.state
765
+ };
766
+ if (existingToolIndex >= 0) {
767
+ updateToolCall(conversationId, conv.messages.length - 1, existingToolIndex, toolCall);
768
+ } else {
769
+ setToolCalls(conversationId, conv.messages.length - 1, [...toolCalls, toolCall]);
770
+ }
771
+ }
772
+ }, {
773
+ withEventTarget: false
774
+ }));
775
+ cleanupFns.push(aiEventClient.on("processor:tool-result-state-changed", (e) => {
776
+ const streamId = e.payload.streamId;
777
+ const conversationId = streamToConversation.get(streamId);
778
+ if (!conversationId || !state.conversations[conversationId]) return;
779
+ const conv = state.conversations[conversationId];
780
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
781
+ const message = conv.messages[i];
782
+ if (!message?.toolCalls) continue;
783
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === e.payload.toolCallId);
784
+ if (toolCallIndex >= 0) {
785
+ updateToolCall(conversationId, i, toolCallIndex, {
786
+ result: e.payload.content,
787
+ state: e.payload.error ? "error" : e.payload.state
788
+ });
789
+ return;
790
+ }
791
+ }
792
+ }, {
793
+ withEventTarget: false
794
+ }));
795
+ cleanupFns.push(aiEventClient.on("chat:started", (e) => {
796
+ const streamId = e.payload.streamId;
797
+ const model = e.payload.model;
798
+ e.payload.provider;
799
+ const clientId = e.payload.clientId;
800
+ if (clientId && state.conversations[clientId]) {
801
+ streamToConversation.set(streamId, clientId);
802
+ updateConversation(clientId, {
803
+ status: "active",
804
+ ...e.payload
805
+ });
806
+ return;
807
+ }
808
+ const activeClient = Object.values(state.conversations).find((c) => c.type === "client" && c.status === "active" && !c.model);
809
+ if (activeClient) {
810
+ streamToConversation.set(streamId, activeClient.id);
811
+ updateConversation(activeClient.id, {
812
+ ...e.payload
813
+ });
814
+ } else {
815
+ const existingServerConv = Object.values(state.conversations).find((c) => c.type === "server" && c.model === model);
816
+ if (existingServerConv) {
817
+ streamToConversation.set(streamId, existingServerConv.id);
818
+ updateConversation(existingServerConv.id, {
819
+ status: "active",
820
+ ...e.payload
821
+ });
822
+ } else {
823
+ const serverId = `server-${model}`;
824
+ getOrCreateConversation(serverId, "server", `${model} Server`);
825
+ streamToConversation.set(streamId, serverId);
826
+ updateConversation(serverId, {
827
+ ...e.payload
828
+ });
829
+ }
830
+ }
831
+ }, {
832
+ withEventTarget: false
833
+ }));
834
+ cleanupFns.push(aiEventClient.on("chat:completed", (e) => {
835
+ const {
836
+ requestId,
837
+ usage
838
+ } = e.payload;
839
+ const conversationId = requestToConversation.get(requestId);
840
+ if (conversationId && state.conversations[conversationId]) {
841
+ const updates = {
842
+ status: "completed",
843
+ completedAt: e.payload.timestamp
844
+ };
845
+ if (usage) {
846
+ updates.usage = usage;
847
+ }
848
+ updateConversation(conversationId, updates);
849
+ if (usage) {
850
+ updateMessageUsage(conversationId, e.payload.messageId, usage);
851
+ }
852
+ }
853
+ }, {
854
+ withEventTarget: false
855
+ }));
856
+ cleanupFns.push(aiEventClient.on("chat:iteration", (e) => {
857
+ const {
858
+ requestId,
859
+ iterationNumber
860
+ } = e.payload;
861
+ const conversationId = requestToConversation.get(requestId);
862
+ if (conversationId && state.conversations[conversationId]) {
863
+ updateConversation(conversationId, {
864
+ iterationCount: iterationNumber
865
+ });
866
+ }
867
+ }, {
868
+ withEventTarget: false
869
+ }));
870
+ cleanupFns.push(aiEventClient.on("usage:tokens", (e) => {
871
+ const {
872
+ requestId,
873
+ usage,
874
+ messageId
875
+ } = e.payload;
876
+ const conversationId = requestToConversation.get(requestId);
877
+ if (conversationId && state.conversations[conversationId]) {
878
+ updateConversation(conversationId, {
879
+ usage
880
+ });
881
+ updateMessageUsage(conversationId, messageId, usage);
882
+ }
883
+ }, {
884
+ withEventTarget: false
885
+ }));
886
+ cleanupFns.push(aiEventClient.on("tool:call-completed", (e) => {
887
+ const {
888
+ streamId,
889
+ toolCallId,
890
+ toolName,
891
+ result,
892
+ duration,
893
+ messageId,
894
+ timestamp
895
+ } = e.payload;
896
+ const conversationId = streamToConversation.get(streamId);
897
+ if (!conversationId || !state.conversations[conversationId]) return;
898
+ const conv = state.conversations[conversationId];
899
+ const chunk = {
900
+ id: `chunk-tool-result-${toolCallId}-${Date.now()}`,
901
+ type: "tool_result",
902
+ messageId,
903
+ toolCallId,
904
+ toolName,
905
+ result,
906
+ duration,
907
+ timestamp,
908
+ chunkCount: 1
909
+ };
910
+ if (conv.type === "client" && messageId) {
911
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
912
+ if (messageIndex !== -1) {
913
+ queueMessageChunk(conversationId, messageIndex, chunk);
914
+ } else {
915
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
916
+ if (conv.messages[i]?.role === "assistant") {
917
+ queueMessageChunk(conversationId, i, chunk);
918
+ break;
919
+ }
920
+ }
921
+ }
922
+ } else {
923
+ addChunk(conversationId, chunk);
924
+ }
925
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
926
+ const message = conv.messages[i];
927
+ if (!message?.toolCalls) continue;
928
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
929
+ if (toolCallIndex >= 0) {
930
+ updateToolCall(conversationId, i, toolCallIndex, {
931
+ duration,
932
+ result
933
+ });
934
+ return;
935
+ }
936
+ }
937
+ }, {
938
+ withEventTarget: false
939
+ }));
940
+ cleanupFns.push(aiEventClient.on("embedding:started", (e) => {
941
+ const {
942
+ requestId,
943
+ model,
944
+ inputCount,
945
+ timestamp,
946
+ clientId
947
+ } = e.payload;
948
+ let conversationId = clientId;
949
+ if (!conversationId || !state.conversations[conversationId]) {
950
+ const activeClients = Object.values(state.conversations).filter((c) => c.type === "client" && c.status === "active").sort((a, b) => b.startedAt - a.startedAt);
951
+ if (activeClients.length > 0 && activeClients[0]) {
952
+ conversationId = activeClients[0].id;
953
+ } else {
954
+ conversationId = `embedding-${requestId}`;
955
+ getOrCreateConversation(conversationId, "server", `Embedding (${model})`);
956
+ updateConversation(conversationId, {
957
+ model
958
+ });
959
+ }
960
+ }
961
+ requestToConversation.set(requestId, conversationId);
962
+ const embeddingOp = {
963
+ id: requestId,
964
+ model,
965
+ inputCount,
966
+ duration: 0,
967
+ timestamp,
968
+ status: "started"
969
+ };
970
+ const conv = state.conversations[conversationId];
971
+ if (conv) {
972
+ const embeddings = conv.embeddings || [];
973
+ setState("conversations", conversationId, "embeddings", [...embeddings, embeddingOp]);
974
+ setState("conversations", conversationId, "hasEmbedding", true);
975
+ }
976
+ }, {
977
+ withEventTarget: false
978
+ }));
979
+ cleanupFns.push(aiEventClient.on("embedding:completed", (e) => {
980
+ const {
981
+ requestId,
982
+ duration
983
+ } = e.payload;
984
+ const conversationId = requestToConversation.get(requestId);
985
+ if (!conversationId || !state.conversations[conversationId]) return;
986
+ const conv = state.conversations[conversationId];
987
+ if (!conv.embeddings) return;
988
+ const embeddingIndex = conv.embeddings.findIndex((op) => op.id === requestId);
989
+ if (embeddingIndex >= 0) {
990
+ setState("conversations", conversationId, "embeddings", embeddingIndex, produce((op) => {
991
+ op.duration = duration;
992
+ op.status = "completed";
993
+ }));
994
+ }
995
+ }, {
996
+ withEventTarget: false
997
+ }));
998
+ cleanupFns.push(aiEventClient.on("summarize:started", (e) => {
999
+ const {
1000
+ requestId,
1001
+ model,
1002
+ inputLength,
1003
+ timestamp,
1004
+ clientId
1005
+ } = e.payload;
1006
+ let conversationId = clientId;
1007
+ if (!conversationId || !state.conversations[conversationId]) {
1008
+ const activeClients = Object.values(state.conversations).filter((c) => c.type === "client" && c.status === "active").sort((a, b) => b.startedAt - a.startedAt);
1009
+ if (activeClients.length > 0 && activeClients[0]) {
1010
+ conversationId = activeClients[0].id;
1011
+ } else {
1012
+ conversationId = `summarize-${requestId}`;
1013
+ getOrCreateConversation(conversationId, "server", `Summarize (${model})`);
1014
+ updateConversation(conversationId, {
1015
+ model
1016
+ });
1017
+ }
1018
+ }
1019
+ requestToConversation.set(requestId, conversationId);
1020
+ const summarizeOp = {
1021
+ id: requestId,
1022
+ model,
1023
+ inputLength,
1024
+ timestamp,
1025
+ status: "started"
1026
+ };
1027
+ const conv = state.conversations[conversationId];
1028
+ if (conv) {
1029
+ const summaries = conv.summaries || [];
1030
+ setState("conversations", conversationId, "summaries", [...summaries, summarizeOp]);
1031
+ setState("conversations", conversationId, "hasSummarize", true);
1032
+ }
1033
+ }, {
1034
+ withEventTarget: false
1035
+ }));
1036
+ cleanupFns.push(aiEventClient.on("summarize:completed", (e) => {
1037
+ const {
1038
+ requestId,
1039
+ outputLength,
1040
+ duration
1041
+ } = e.payload;
1042
+ const conversationId = requestToConversation.get(requestId);
1043
+ if (!conversationId || !state.conversations[conversationId]) return;
1044
+ const conv = state.conversations[conversationId];
1045
+ if (!conv.summaries) return;
1046
+ const summaryIndex = conv.summaries.findIndex((op) => op.id === requestId);
1047
+ if (summaryIndex >= 0) {
1048
+ setState("conversations", conversationId, "summaries", summaryIndex, produce((op) => {
1049
+ op.duration = duration;
1050
+ op.outputLength = outputLength;
1051
+ op.status = "completed";
1052
+ }));
1053
+ }
1054
+ }, {
1055
+ withEventTarget: false
1056
+ }));
1057
+ onCleanup(() => {
1058
+ for (const cleanup of cleanupFns) {
1059
+ cleanup();
1060
+ }
1061
+ streamToConversation.clear();
1062
+ requestToConversation.clear();
1063
+ });
1064
+ });
1065
+ const contextValue = {
1066
+ state,
1067
+ clearAllConversations,
1068
+ selectConversation
1069
+ };
1070
+ return createComponent(AIContext.Provider, {
1071
+ value: contextValue,
1072
+ get children() {
1073
+ return props.children;
1074
+ }
1075
+ });
1076
+ };
1077
+ export {
1078
+ AIProvider,
1079
+ useAIStore
1080
+ };
1081
+ //# sourceMappingURL=ai-context.js.map