@tanstack/ai-devtools-core 0.3.6 → 0.3.8

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 (86) hide show
  1. package/dist/Shell/GHXECDJV.js +5056 -0
  2. package/dist/Shell/MUFU35SY.js +4242 -0
  3. package/dist/dev.js +11 -0
  4. package/dist/{esm/index.d.ts → index.d.ts} +7 -5
  5. package/dist/index.js +11 -0
  6. package/dist/production/Shell/GHXECDJV.js +5056 -0
  7. package/dist/production/Shell/MUFU35SY.js +4242 -0
  8. package/dist/production/dev.js +8 -0
  9. package/dist/production/index.d.ts +12 -0
  10. package/dist/production/index.js +8 -0
  11. package/dist/production/server.js +8 -0
  12. package/dist/server.js +11 -0
  13. package/package.json +45 -11
  14. package/src/{core.tsx → core.ts} +4 -5
  15. package/dist/esm/components/ConversationDetails.d.ts +0 -2
  16. package/dist/esm/components/ConversationDetails.js +0 -192
  17. package/dist/esm/components/ConversationDetails.js.map +0 -1
  18. package/dist/esm/components/ConversationsList.d.ts +0 -2
  19. package/dist/esm/components/ConversationsList.js +0 -30
  20. package/dist/esm/components/ConversationsList.js.map +0 -1
  21. package/dist/esm/components/Shell.d.ts +0 -1
  22. package/dist/esm/components/Shell.js +0 -94
  23. package/dist/esm/components/Shell.js.map +0 -1
  24. package/dist/esm/components/conversation/ActivityEventsTab.d.ts +0 -8
  25. package/dist/esm/components/conversation/ActivityEventsTab.js +0 -72
  26. package/dist/esm/components/conversation/ActivityEventsTab.js.map +0 -1
  27. package/dist/esm/components/conversation/ChunkBadges.d.ts +0 -7
  28. package/dist/esm/components/conversation/ChunkBadges.js +0 -54
  29. package/dist/esm/components/conversation/ChunkBadges.js.map +0 -1
  30. package/dist/esm/components/conversation/ChunkItem.d.ts +0 -9
  31. package/dist/esm/components/conversation/ChunkItem.js +0 -247
  32. package/dist/esm/components/conversation/ChunkItem.js.map +0 -1
  33. package/dist/esm/components/conversation/ChunksCollapsible.d.ts +0 -7
  34. package/dist/esm/components/conversation/ChunksCollapsible.js +0 -77
  35. package/dist/esm/components/conversation/ChunksCollapsible.js.map +0 -1
  36. package/dist/esm/components/conversation/ChunksTab.d.ts +0 -8
  37. package/dist/esm/components/conversation/ChunksTab.js +0 -87
  38. package/dist/esm/components/conversation/ChunksTab.js.map +0 -1
  39. package/dist/esm/components/conversation/ConversationHeader.d.ts +0 -7
  40. package/dist/esm/components/conversation/ConversationHeader.js +0 -230
  41. package/dist/esm/components/conversation/ConversationHeader.js.map +0 -1
  42. package/dist/esm/components/conversation/ConversationTabs.d.ts +0 -10
  43. package/dist/esm/components/conversation/ConversationTabs.js +0 -176
  44. package/dist/esm/components/conversation/ConversationTabs.js.map +0 -1
  45. package/dist/esm/components/conversation/MessageCard.d.ts +0 -7
  46. package/dist/esm/components/conversation/MessageCard.js +0 -207
  47. package/dist/esm/components/conversation/MessageCard.js.map +0 -1
  48. package/dist/esm/components/conversation/MessageGroup.d.ts +0 -15
  49. package/dist/esm/components/conversation/MessageGroup.js +0 -119
  50. package/dist/esm/components/conversation/MessageGroup.js.map +0 -1
  51. package/dist/esm/components/conversation/MessagesTab.d.ts +0 -7
  52. package/dist/esm/components/conversation/MessagesTab.js +0 -37
  53. package/dist/esm/components/conversation/MessagesTab.js.map +0 -1
  54. package/dist/esm/components/conversation/SummariesTab.d.ts +0 -7
  55. package/dist/esm/components/conversation/SummariesTab.js +0 -110
  56. package/dist/esm/components/conversation/SummariesTab.js.map +0 -1
  57. package/dist/esm/components/conversation/ToolCallDisplay.d.ts +0 -7
  58. package/dist/esm/components/conversation/ToolCallDisplay.js +0 -123
  59. package/dist/esm/components/conversation/ToolCallDisplay.js.map +0 -1
  60. package/dist/esm/components/conversation/index.d.ts +0 -7
  61. package/dist/esm/components/list/ConversationRow.d.ts +0 -7
  62. package/dist/esm/components/list/ConversationRow.js +0 -122
  63. package/dist/esm/components/list/ConversationRow.js.map +0 -1
  64. package/dist/esm/components/list/index.d.ts +0 -1
  65. package/dist/esm/components/utils/format.d.ts +0 -6
  66. package/dist/esm/components/utils/format.js +0 -68
  67. package/dist/esm/components/utils/format.js.map +0 -1
  68. package/dist/esm/components/utils/index.d.ts +0 -1
  69. package/dist/esm/core.d.ts +0 -22
  70. package/dist/esm/core.js +0 -9
  71. package/dist/esm/core.js.map +0 -1
  72. package/dist/esm/index.js +0 -6
  73. package/dist/esm/index.js.map +0 -1
  74. package/dist/esm/production.d.ts +0 -2
  75. package/dist/esm/production.js +0 -5
  76. package/dist/esm/production.js.map +0 -1
  77. package/dist/esm/store/ai-context.d.ts +0 -135
  78. package/dist/esm/store/ai-context.js +0 -1238
  79. package/dist/esm/store/ai-context.js.map +0 -1
  80. package/dist/esm/store/ai-store.d.ts +0 -1
  81. package/dist/esm/styles/tokens.d.ts +0 -298
  82. package/dist/esm/styles/tokens.js +0 -107
  83. package/dist/esm/styles/tokens.js.map +0 -1
  84. package/dist/esm/styles/use-styles.d.ts +0 -233
  85. package/dist/esm/styles/use-styles.js +0 -1602
  86. package/dist/esm/styles/use-styles.js.map +0 -1
@@ -0,0 +1,4242 @@
1
+ import { createComponent, ssr, ssrAttribute, escape, ssrStyleProperty } from 'solid-js/web';
2
+ import { createContext, createSignal, onMount, onCleanup, createEffect, For, Show, useContext, batch } from 'solid-js';
3
+ import { MainPanel, Header, HeaderLogo, useTheme, JsonTree } from '@tanstack/devtools-ui';
4
+ import * as goober from 'goober';
5
+ import { createStore, produce } from 'solid-js/store';
6
+ import { aiEventClient } from '@tanstack/ai/event-client';
7
+
8
+ // src/components/Shell.tsx
9
+
10
+ // src/styles/tokens.ts
11
+ var tokens = {
12
+ colors: {
13
+ inherit: "inherit",
14
+ current: "currentColor",
15
+ transparent: "transparent",
16
+ black: "#000000",
17
+ white: "#ffffff",
18
+ neutral: {
19
+ 50: "#f9fafb",
20
+ 100: "#f2f4f7",
21
+ 200: "#eaecf0",
22
+ 300: "#d0d5dd",
23
+ 400: "#98a2b3",
24
+ 500: "#667085",
25
+ 600: "#475467",
26
+ 700: "#344054",
27
+ 800: "#1d2939",
28
+ 900: "#101828"
29
+ },
30
+ darkGray: {
31
+ 50: "#525c7a",
32
+ 100: "#49536e",
33
+ 200: "#414962",
34
+ 300: "#394056",
35
+ 400: "#313749",
36
+ 500: "#292e3d",
37
+ 600: "#212530",
38
+ 700: "#191c24",
39
+ 800: "#111318",
40
+ 900: "#0b0d10"
41
+ },
42
+ gray: {
43
+ 50: "#f9fafb",
44
+ 100: "#f2f4f7",
45
+ 200: "#eaecf0",
46
+ 300: "#d0d5dd",
47
+ 400: "#98a2b3",
48
+ 500: "#667085",
49
+ 600: "#475467",
50
+ 700: "#344054",
51
+ 800: "#1d2939",
52
+ 900: "#101828"
53
+ },
54
+ blue: {
55
+ 25: "#F5FAFF",
56
+ 50: "#EFF8FF",
57
+ 100: "#D1E9FF",
58
+ 200: "#B2DDFF",
59
+ 300: "#84CAFF",
60
+ 400: "#53B1FD",
61
+ 500: "#2E90FA",
62
+ 600: "#1570EF",
63
+ 700: "#175CD3",
64
+ 800: "#1849A9",
65
+ 900: "#194185"
66
+ },
67
+ green: {
68
+ 25: "#F6FEF9",
69
+ 50: "#ECFDF3",
70
+ 100: "#D1FADF",
71
+ 200: "#A6F4C5",
72
+ 300: "#6CE9A6",
73
+ 400: "#32D583",
74
+ 500: "#12B76A",
75
+ 600: "#039855",
76
+ 700: "#027A48",
77
+ 800: "#05603A",
78
+ 900: "#054F31"
79
+ },
80
+ red: {
81
+ 50: "#fef2f2",
82
+ 100: "#fee2e2",
83
+ 200: "#fecaca",
84
+ 300: "#fca5a5",
85
+ 400: "#f87171",
86
+ 500: "#ef4444",
87
+ 600: "#dc2626",
88
+ 700: "#b91c1c",
89
+ 800: "#991b1b",
90
+ 900: "#7f1d1d",
91
+ 950: "#450a0a"
92
+ },
93
+ yellow: {
94
+ 25: "#FFFCF5",
95
+ 50: "#FFFAEB",
96
+ 100: "#FEF0C7",
97
+ 200: "#FEDF89",
98
+ 300: "#FEC84B",
99
+ 400: "#FDB022",
100
+ 500: "#F79009",
101
+ 600: "#DC6803",
102
+ 700: "#B54708",
103
+ 800: "#93370D",
104
+ 900: "#7A2E0E"
105
+ },
106
+ purple: {
107
+ 25: "#FAFAFF",
108
+ 50: "#F4F3FF",
109
+ 100: "#EBE9FE",
110
+ 200: "#D9D6FE",
111
+ 300: "#BDB4FE",
112
+ 400: "#9B8AFB",
113
+ 500: "#7A5AF8",
114
+ 600: "#6938EF",
115
+ 700: "#5925DC",
116
+ 800: "#4A1FB8",
117
+ 900: "#3E1C96"
118
+ },
119
+ teal: {
120
+ 25: "#F6FEFC",
121
+ 50: "#F0FDF9",
122
+ 100: "#CCFBEF",
123
+ 200: "#99F6E0",
124
+ 300: "#5FE9D0",
125
+ 400: "#2ED3B7",
126
+ 500: "#15B79E",
127
+ 600: "#0E9384",
128
+ 700: "#107569",
129
+ 800: "#125D56",
130
+ 900: "#134E48"
131
+ },
132
+ pink: {
133
+ 25: "#fdf2f8",
134
+ 50: "#fce7f3",
135
+ 100: "#fbcfe8",
136
+ 200: "#f9a8d4",
137
+ 300: "#f472b6",
138
+ 400: "#ec4899",
139
+ 500: "#db2777",
140
+ 600: "#be185d",
141
+ 700: "#9d174d",
142
+ 800: "#831843",
143
+ 900: "#500724"
144
+ },
145
+ cyan: {
146
+ 25: "#ecfeff",
147
+ 50: "#cffafe",
148
+ 100: "#a5f3fc",
149
+ 200: "#67e8f9",
150
+ 300: "#22d3ee",
151
+ 400: "#06b6d4",
152
+ 500: "#0891b2",
153
+ 600: "#0e7490",
154
+ 700: "#155e75",
155
+ 800: "#164e63",
156
+ 900: "#083344"
157
+ }
158
+ },
159
+ alpha: {
160
+ 100: "ff",
161
+ 90: "e5",
162
+ 80: "cc",
163
+ 70: "b3",
164
+ 60: "99",
165
+ 50: "80",
166
+ 40: "66",
167
+ 30: "4d",
168
+ 20: "33",
169
+ 10: "1a",
170
+ 0: "00"
171
+ },
172
+ font: {
173
+ size: {
174
+ "2xs": "calc(var(--tsrd-font-size) * 0.625)",
175
+ xs: "calc(var(--tsrd-font-size) * 0.75)",
176
+ sm: "calc(var(--tsrd-font-size) * 0.875)",
177
+ md: "var(--tsrd-font-size)",
178
+ lg: "calc(var(--tsrd-font-size) * 1.125)",
179
+ xl: "calc(var(--tsrd-font-size) * 1.25)",
180
+ "2xl": "calc(var(--tsrd-font-size) * 1.5)",
181
+ "3xl": "calc(var(--tsrd-font-size) * 1.875)",
182
+ "4xl": "calc(var(--tsrd-font-size) * 2.25)",
183
+ "5xl": "calc(var(--tsrd-font-size) * 3)",
184
+ "6xl": "calc(var(--tsrd-font-size) * 3.75)",
185
+ "7xl": "calc(var(--tsrd-font-size) * 4.5)",
186
+ "8xl": "calc(var(--tsrd-font-size) * 6)",
187
+ "9xl": "calc(var(--tsrd-font-size) * 8)"
188
+ },
189
+ lineHeight: {
190
+ "3xs": "calc(var(--tsrd-font-size) * 0.75)",
191
+ "2xs": "calc(var(--tsrd-font-size) * 0.875)",
192
+ xs: "calc(var(--tsrd-font-size) * 1)",
193
+ sm: "calc(var(--tsrd-font-size) * 1.25)",
194
+ md: "calc(var(--tsrd-font-size) * 1.5)",
195
+ lg: "calc(var(--tsrd-font-size) * 1.75)",
196
+ xl: "calc(var(--tsrd-font-size) * 2)",
197
+ "2xl": "calc(var(--tsrd-font-size) * 2.25)",
198
+ "3xl": "calc(var(--tsrd-font-size) * 2.5)",
199
+ "4xl": "calc(var(--tsrd-font-size) * 2.75)",
200
+ "5xl": "calc(var(--tsrd-font-size) * 3)",
201
+ "6xl": "calc(var(--tsrd-font-size) * 3.25)",
202
+ "7xl": "calc(var(--tsrd-font-size) * 3.5)",
203
+ "8xl": "calc(var(--tsrd-font-size) * 3.75)",
204
+ "9xl": "calc(var(--tsrd-font-size) * 4)"
205
+ },
206
+ weight: {
207
+ thin: "100",
208
+ extralight: "200",
209
+ light: "300",
210
+ normal: "400",
211
+ medium: "500",
212
+ semibold: "600",
213
+ bold: "700",
214
+ extrabold: "800",
215
+ black: "900"
216
+ },
217
+ fontFamily: {
218
+ sans: "ui-sans-serif, Inter, system-ui, sans-serif, sans-serif",
219
+ mono: `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace`
220
+ }
221
+ },
222
+ breakpoints: {
223
+ xs: "320px",
224
+ sm: "640px",
225
+ md: "768px",
226
+ lg: "1024px",
227
+ xl: "1280px",
228
+ "2xl": "1536px"
229
+ },
230
+ border: {
231
+ radius: {
232
+ none: "0px",
233
+ xs: "calc(var(--tsrd-font-size) * 0.125)",
234
+ sm: "calc(var(--tsrd-font-size) * 0.25)",
235
+ md: "calc(var(--tsrd-font-size) * 0.375)",
236
+ lg: "calc(var(--tsrd-font-size) * 0.5)",
237
+ xl: "calc(var(--tsrd-font-size) * 0.75)",
238
+ "2xl": "calc(var(--tsrd-font-size) * 1)",
239
+ "3xl": "calc(var(--tsrd-font-size) * 1.5)",
240
+ full: "9999px"
241
+ }
242
+ },
243
+ size: {
244
+ 0: "0px",
245
+ 0.25: "calc(var(--tsrd-font-size) * 0.0625)",
246
+ 0.5: "calc(var(--tsrd-font-size) * 0.125)",
247
+ 1: "calc(var(--tsrd-font-size) * 0.25)",
248
+ 1.5: "calc(var(--tsrd-font-size) * 0.375)",
249
+ 2: "calc(var(--tsrd-font-size) * 0.5)",
250
+ 2.5: "calc(var(--tsrd-font-size) * 0.625)",
251
+ 3: "calc(var(--tsrd-font-size) * 0.75)",
252
+ 3.5: "calc(var(--tsrd-font-size) * 0.875)",
253
+ 4: "calc(var(--tsrd-font-size) * 1)",
254
+ 4.5: "calc(var(--tsrd-font-size) * 1.125)",
255
+ 5: "calc(var(--tsrd-font-size) * 1.25)",
256
+ 5.5: "calc(var(--tsrd-font-size) * 1.375)",
257
+ 6: "calc(var(--tsrd-font-size) * 1.5)",
258
+ 6.5: "calc(var(--tsrd-font-size) * 1.625)",
259
+ 7: "calc(var(--tsrd-font-size) * 1.75)",
260
+ 8: "calc(var(--tsrd-font-size) * 2)",
261
+ 9: "calc(var(--tsrd-font-size) * 2.25)",
262
+ 10: "calc(var(--tsrd-font-size) * 2.5)",
263
+ 11: "calc(var(--tsrd-font-size) * 2.75)",
264
+ 12: "calc(var(--tsrd-font-size) * 3)",
265
+ 14: "calc(var(--tsrd-font-size) * 3.5)",
266
+ 16: "calc(var(--tsrd-font-size) * 4)",
267
+ 20: "calc(var(--tsrd-font-size) * 5)",
268
+ 24: "calc(var(--tsrd-font-size) * 6)",
269
+ 28: "calc(var(--tsrd-font-size) * 7)",
270
+ 32: "calc(var(--tsrd-font-size) * 8)",
271
+ 36: "calc(var(--tsrd-font-size) * 9)",
272
+ 40: "calc(var(--tsrd-font-size) * 10)",
273
+ 44: "calc(var(--tsrd-font-size) * 11)",
274
+ 48: "calc(var(--tsrd-font-size) * 12)",
275
+ 52: "calc(var(--tsrd-font-size) * 13)",
276
+ 56: "calc(var(--tsrd-font-size) * 14)",
277
+ 60: "calc(var(--tsrd-font-size) * 15)",
278
+ 64: "calc(var(--tsrd-font-size) * 16)",
279
+ 72: "calc(var(--tsrd-font-size) * 18)",
280
+ 80: "calc(var(--tsrd-font-size) * 20)",
281
+ 96: "calc(var(--tsrd-font-size) * 24)"
282
+ },
283
+ shadow: {
284
+ xs: (_ = "rgb(0 0 0 / 0.1)") => `0 1px 2px 0 rgb(0 0 0 / 0.05)`,
285
+ sm: (color = "rgb(0 0 0 / 0.1)") => `0 1px 3px 0 ${color}, 0 1px 2px -1px ${color}`,
286
+ md: (color = "rgb(0 0 0 / 0.1)") => `0 4px 6px -1px ${color}, 0 2px 4px -2px ${color}`,
287
+ lg: (color = "rgb(0 0 0 / 0.1)") => `0 10px 15px -3px ${color}, 0 4px 6px -4px ${color}`,
288
+ xl: (color = "rgb(0 0 0 / 0.1)") => `0 20px 25px -5px ${color}, 0 8px 10px -6px ${color}`,
289
+ "2xl": (color = "rgb(0 0 0 / 0.25)") => `0 25px 50px -12px ${color}`,
290
+ inner: (color = "rgb(0 0 0 / 0.05)") => `inset 0 2px 4px 0 ${color}`,
291
+ none: () => `none`
292
+ },
293
+ zIndices: {
294
+ hide: -1,
295
+ auto: "auto",
296
+ base: 0,
297
+ docked: 10,
298
+ dropdown: 1e3,
299
+ sticky: 1100,
300
+ banner: 1200,
301
+ overlay: 1300,
302
+ modal: 1400,
303
+ popover: 1500,
304
+ skipLink: 1600,
305
+ toast: 1700,
306
+ tooltip: 1800
307
+ }
308
+ };
309
+
310
+ // src/styles/use-styles.ts
311
+ var stylesFactory = (theme) => {
312
+ const { colors, font, size, alpha, border } = tokens;
313
+ const { fontFamily, size: fontSize } = font;
314
+ const css2 = goober.css;
315
+ const t = (light, dark) => theme === "light" ? light : dark;
316
+ return {
317
+ mainContainer: css2`
318
+ display: flex;
319
+ flex: 1;
320
+ min-height: 80%;
321
+ overflow: hidden;
322
+ padding: ${size[2]};
323
+ `,
324
+ dragHandle: css2`
325
+ width: 8px;
326
+ background: ${t(colors.gray[300], colors.darkGray[600])};
327
+ cursor: col-resize;
328
+ position: relative;
329
+ transition: all 0.2s ease;
330
+ user-select: none;
331
+ pointer-events: all;
332
+ margin: 0 ${size[1]};
333
+ border-radius: 2px;
334
+
335
+ &:hover {
336
+ background: ${t(colors.blue[600], colors.blue[500])};
337
+ margin: 0 ${size[1]};
338
+ }
339
+
340
+ &.dragging {
341
+ background: ${t(colors.blue[700], colors.blue[600])};
342
+ margin: 0 ${size[1]};
343
+ }
344
+
345
+ &::after {
346
+ content: '';
347
+ position: absolute;
348
+ top: 50%;
349
+ left: 50%;
350
+ transform: translate(-50%, -50%);
351
+ width: 2px;
352
+ height: 20px;
353
+ background: ${t(colors.gray[400], colors.darkGray[400])};
354
+ border-radius: 1px;
355
+ pointer-events: none;
356
+ }
357
+
358
+ &:hover::after,
359
+ &.dragging::after {
360
+ background: ${t(colors.blue[500], colors.blue[300])};
361
+ }
362
+ `,
363
+ leftPanel: css2`
364
+ background: ${t(colors.gray[100], colors.darkGray[800])};
365
+ border-radius: ${border.radius.lg};
366
+ border: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
367
+ display: flex;
368
+ flex-direction: column;
369
+ overflow: hidden;
370
+ min-height: 0;
371
+ flex-shrink: 0;
372
+ `,
373
+ rightPanel: css2`
374
+ background: ${t(colors.gray[100], colors.darkGray[800])};
375
+ border-radius: ${border.radius.lg};
376
+ border: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
377
+ display: flex;
378
+ flex-direction: column;
379
+ overflow: hidden;
380
+ min-height: 0;
381
+ flex: 1;
382
+ `,
383
+ panelHeader: css2`
384
+ font-size: ${fontSize.md};
385
+ font-weight: ${font.weight.bold};
386
+ color: ${t(colors.blue[700], colors.blue[400])};
387
+ padding: ${size[2]};
388
+ border-bottom: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
389
+ background: ${t(colors.gray[100], colors.darkGray[800])};
390
+ flex-shrink: 0;
391
+ `,
392
+ utilList: css2`
393
+ flex: 1;
394
+ overflow-y: auto;
395
+ padding: ${size[1]};
396
+ min-height: 0;
397
+ `,
398
+ utilGroup: css2`
399
+ margin-bottom: ${size[2]};
400
+ `,
401
+ utilGroupHeader: css2`
402
+ font-size: ${fontSize.xs};
403
+ font-weight: ${font.weight.semibold};
404
+ color: ${t(colors.gray[600], colors.gray[400])};
405
+ text-transform: uppercase;
406
+ letter-spacing: 0.05em;
407
+ margin-bottom: ${size[1]};
408
+ padding: ${size[1]} ${size[2]};
409
+ background: ${t(colors.gray[200], colors.darkGray[700])};
410
+ border-radius: ${border.radius.md};
411
+ `,
412
+ utilRow: css2`
413
+ display: flex;
414
+ justify-content: space-between;
415
+ align-items: center;
416
+ padding: ${size[2]};
417
+ margin-bottom: ${size[1]};
418
+ background: ${t(colors.gray[200], colors.darkGray[700])};
419
+ border-radius: ${border.radius.md};
420
+ cursor: pointer;
421
+ transition: all 0.2s ease;
422
+ border: 1px solid transparent;
423
+
424
+ &:hover {
425
+ background: ${t(colors.gray[300], colors.darkGray[600])};
426
+ border-color: ${t(colors.gray[400], colors.darkGray[500])};
427
+ }
428
+ `,
429
+ utilRowSelected: css2`
430
+ background: ${t(colors.blue[100], colors.blue[900] + alpha[20])};
431
+ border-color: ${t(colors.blue[600], colors.blue[500])};
432
+ box-shadow: 0 0 0 1px
433
+ ${t(colors.blue[600] + alpha[30], colors.blue[500] + alpha[30])};
434
+ `,
435
+ utilKey: css2`
436
+ font-family: ${fontFamily.mono};
437
+ font-size: ${fontSize.xs};
438
+ color: ${t(colors.gray[900], colors.gray[100])};
439
+ flex: 1;
440
+ overflow: hidden;
441
+ text-overflow: ellipsis;
442
+ white-space: nowrap;
443
+ `,
444
+ utilStatus: css2`
445
+ font-size: ${fontSize.xs};
446
+ color: ${t(colors.gray[600], colors.gray[400])};
447
+ text-transform: uppercase;
448
+ letter-spacing: 0.05em;
449
+ padding: ${size[1]} ${size[1]};
450
+ background: ${t(colors.gray[300], colors.darkGray[600])};
451
+ border-radius: ${border.radius.sm};
452
+ margin-left: ${size[1]};
453
+ `,
454
+ stateDetails: css2`
455
+ flex: 1;
456
+ overflow-y: auto;
457
+ padding: ${size[2]};
458
+ min-height: 0;
459
+ `,
460
+ stateHeader: css2`
461
+ margin-bottom: ${size[2]};
462
+ padding-bottom: ${size[2]};
463
+ border-bottom: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
464
+ `,
465
+ stateTitle: css2`
466
+ font-size: ${fontSize.md};
467
+ font-weight: ${font.weight.bold};
468
+ color: ${t(colors.blue[700], colors.blue[400])};
469
+ margin-bottom: ${size[1]};
470
+ `,
471
+ stateKey: css2`
472
+ font-family: ${fontFamily.mono};
473
+ font-size: ${fontSize.xs};
474
+ color: ${t(colors.gray[600], colors.gray[400])};
475
+ word-break: break-all;
476
+ `,
477
+ stateContent: css2`
478
+ background: ${t(colors.gray[100], colors.darkGray[700])};
479
+ border-radius: ${border.radius.md};
480
+ padding: ${size[2]};
481
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
482
+ `,
483
+ detailsGrid: css2`
484
+ display: grid;
485
+ grid-template-columns: 1fr;
486
+ gap: ${size[2]};
487
+ align-items: start;
488
+ `,
489
+ detailSection: css2`
490
+ background: ${t(colors.white, colors.darkGray[700])};
491
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
492
+ border-radius: ${border.radius.md};
493
+ padding: ${size[2]};
494
+ `,
495
+ detailSectionHeader: css2`
496
+ font-size: ${fontSize.sm};
497
+ font-weight: ${font.weight.bold};
498
+ color: ${t(colors.gray[800], colors.gray[200])};
499
+ margin-bottom: ${size[1]};
500
+ text-transform: uppercase;
501
+ letter-spacing: 0.04em;
502
+ `,
503
+ actionsRow: css2`
504
+ display: flex;
505
+ flex-wrap: wrap;
506
+ gap: ${size[2]};
507
+ `,
508
+ actionButton: css2`
509
+ display: inline-flex;
510
+ align-items: center;
511
+ gap: ${size[1]};
512
+ padding: ${size[1]} ${size[2]};
513
+ border-radius: ${border.radius.md};
514
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[500])};
515
+ background: ${t(colors.gray[200], colors.darkGray[600])};
516
+ color: ${t(colors.gray[900], colors.gray[100])};
517
+ font-size: ${fontSize.xs};
518
+ cursor: pointer;
519
+ user-select: none;
520
+ transition:
521
+ background 0.15s,
522
+ border-color 0.15s;
523
+ &:hover {
524
+ background: ${t(colors.gray[300], colors.darkGray[500])};
525
+ border-color: ${t(colors.gray[400], colors.darkGray[400])};
526
+ }
527
+ &:disabled {
528
+ opacity: 0.5;
529
+ cursor: not-allowed;
530
+ &:hover {
531
+ background: ${t(colors.gray[200], colors.darkGray[600])};
532
+ border-color: ${t(colors.gray[300], colors.darkGray[500])};
533
+ }
534
+ }
535
+ `,
536
+ actionDotBlue: css2`
537
+ width: 6px;
538
+ height: 6px;
539
+ border-radius: 9999px;
540
+ background: ${colors.blue[400]};
541
+ `,
542
+ actionDotGreen: css2`
543
+ width: 6px;
544
+ height: 6px;
545
+ border-radius: 9999px;
546
+ background: ${colors.green[400]};
547
+ `,
548
+ actionDotRed: css2`
549
+ width: 6px;
550
+ height: 6px;
551
+ border-radius: 9999px;
552
+ background: ${colors.red[400]};
553
+ `,
554
+ actionDotYellow: css2`
555
+ width: 6px;
556
+ height: 6px;
557
+ border-radius: 9999px;
558
+ background: ${colors.yellow[400]};
559
+ `,
560
+ actionDotOrange: css2`
561
+ width: 6px;
562
+ height: 6px;
563
+ border-radius: 9999px;
564
+ background: ${colors.pink[400]};
565
+ `,
566
+ actionDotPurple: css2`
567
+ width: 6px;
568
+ height: 6px;
569
+ border-radius: 9999px;
570
+ background: ${colors.purple[400]};
571
+ `,
572
+ infoGrid: css2`
573
+ display: grid;
574
+ grid-template-columns: auto 1fr;
575
+ gap: ${size[1]};
576
+ row-gap: ${size[1]};
577
+ align-items: center;
578
+ `,
579
+ infoLabel: css2`
580
+ color: ${t(colors.gray[600], colors.gray[400])};
581
+ font-size: ${fontSize.xs};
582
+ text-transform: uppercase;
583
+ letter-spacing: 0.05em;
584
+ `,
585
+ infoValueMono: css2`
586
+ font-family: ${fontFamily.mono};
587
+ font-size: ${fontSize.xs};
588
+ color: ${t(colors.gray[900], colors.gray[100])};
589
+ word-break: break-all;
590
+ `,
591
+ noSelection: css2`
592
+ flex: 1;
593
+ display: flex;
594
+ align-items: center;
595
+ justify-content: center;
596
+ color: ${t(colors.gray[500], colors.gray[500])};
597
+ font-style: italic;
598
+ text-align: center;
599
+ padding: ${size[4]};
600
+ `,
601
+ // Keep existing styles for backward compatibility
602
+ sectionContainer: css2`
603
+ display: flex;
604
+ flex-wrap: wrap;
605
+ gap: ${size[4]};
606
+ `,
607
+ section: css2`
608
+ background: ${t(colors.gray[100], colors.darkGray[800])};
609
+ border-radius: ${border.radius.lg};
610
+ box-shadow: ${tokens.shadow.md(
611
+ t(colors.gray[400] + alpha[80], colors.black + alpha[80])
612
+ )};
613
+ padding: ${size[4]};
614
+ margin-bottom: ${size[4]};
615
+ border: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
616
+ min-width: 0;
617
+ max-width: 33%;
618
+ max-height: fit-content;
619
+ `,
620
+ sectionHeader: css2`
621
+ font-size: ${fontSize.lg};
622
+ font-weight: ${font.weight.bold};
623
+ margin-bottom: ${size[2]};
624
+ color: ${t(colors.blue[600], colors.blue[400])};
625
+ letter-spacing: 0.01em;
626
+ display: flex;
627
+ align-items: center;
628
+ gap: ${size[2]};
629
+ `,
630
+ sectionEmpty: css2`
631
+ color: ${t(colors.gray[500], colors.gray[500])};
632
+ font-size: ${fontSize.sm};
633
+ font-style: italic;
634
+ margin: ${size[2]} 0;
635
+ `,
636
+ instanceList: css2`
637
+ display: flex;
638
+ flex-direction: column;
639
+ gap: ${size[2]};
640
+ background: ${t(colors.gray[200], colors.darkGray[700])};
641
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
642
+ `,
643
+ instanceCard: css2`
644
+ background: ${t(colors.gray[200], colors.darkGray[700])};
645
+ border-radius: ${border.radius.md};
646
+ padding: ${size[3]};
647
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
648
+ font-size: ${fontSize.sm};
649
+ color: ${t(colors.gray[900], colors.gray[100])};
650
+ font-family: ${fontFamily.mono};
651
+ overflow-x: auto;
652
+ transition:
653
+ box-shadow 0.3s,
654
+ background 0.3s;
655
+ `,
656
+ // Shell component styles
657
+ shell: {
658
+ sectionHeader: css2`
659
+ padding: ${size[3]} ${size[4]};
660
+ font-size: ${fontSize.sm};
661
+ font-weight: ${font.weight.semibold};
662
+ color: ${t(colors.gray[100], colors.gray[200])};
663
+ text-transform: uppercase;
664
+ letter-spacing: 0.5px;
665
+ text-align: center;
666
+ background: ${t(colors.gray[700], colors.darkGray[600])};
667
+ border-bottom: 1px solid ${t(colors.gray[600], colors.darkGray[500])};
668
+ `,
669
+ filterContainer: css2`
670
+ display: flex;
671
+ flex-direction: column;
672
+ gap: ${size[2]};
673
+ padding: ${size[3]};
674
+ border-bottom: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
675
+ `,
676
+ filterButtonsRow: css2`
677
+ display: flex;
678
+ gap: ${size[1.5]};
679
+ flex-wrap: wrap;
680
+ `,
681
+ filterButton: css2`
682
+ display: inline-flex;
683
+ align-items: center;
684
+ gap: ${size[1]};
685
+ padding: ${size[1]} ${size[2]};
686
+ border-radius: ${border.radius.md};
687
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[500])};
688
+ background: ${t(colors.gray[200], colors.darkGray[600])};
689
+ color: ${t(colors.gray[900], colors.gray[100])};
690
+ font-size: ${fontSize.xs};
691
+ cursor: pointer;
692
+ user-select: none;
693
+ transition:
694
+ background 0.15s,
695
+ border-color 0.15s;
696
+ &:hover {
697
+ background: ${t(colors.gray[300], colors.darkGray[500])};
698
+ border-color: ${t(colors.gray[400], colors.darkGray[400])};
699
+ }
700
+ `,
701
+ filterButtonActive: css2`
702
+ background: ${colors.pink[400]};
703
+ color: ${colors.white};
704
+ border-color: ${colors.pink[400]};
705
+ &:hover {
706
+ background: ${colors.pink[500]};
707
+ border-color: ${colors.pink[500]};
708
+ }
709
+ `,
710
+ actionsRow: css2`
711
+ display: flex;
712
+ gap: ${size[1.5]};
713
+ `,
714
+ clearAllButton: css2`
715
+ flex: 1;
716
+ font-size: ${fontSize.xs};
717
+ `
718
+ },
719
+ // ConversationsList component styles
720
+ conversationsList: {
721
+ rowMain: css2`
722
+ display: flex;
723
+ flex-direction: column;
724
+ gap: 4px;
725
+ flex: 1;
726
+ min-width: 0;
727
+ `,
728
+ rowTop: css2`
729
+ display: flex;
730
+ align-items: center;
731
+ justify-content: space-between;
732
+ gap: ${size[2]};
733
+ `,
734
+ rowRight: css2`
735
+ display: flex;
736
+ align-items: center;
737
+ gap: ${size[1]};
738
+ flex-shrink: 0;
739
+ `,
740
+ rowContent: css2`
741
+ display: flex;
742
+ align-items: center;
743
+ gap: ${size[2]};
744
+ flex: 1;
745
+ `,
746
+ rowInfo: css2`
747
+ display: flex;
748
+ align-items: center;
749
+ gap: ${size[1]};
750
+ min-width: 0;
751
+ flex: 1;
752
+ `,
753
+ typeDot: css2`
754
+ width: 8px;
755
+ height: 8px;
756
+ border-radius: 50%;
757
+ `,
758
+ label: css2`
759
+ font-weight: ${font.weight.semibold};
760
+ `,
761
+ toolCallsBadge: css2`
762
+ display: flex;
763
+ align-items: center;
764
+ gap: 3px;
765
+ padding: 2px 6px;
766
+ border-radius: ${border.radius.sm};
767
+ background: oklch(0.35 0.1 280);
768
+ color: oklch(0.8 0.12 280);
769
+ font-size: ${fontSize.xs};
770
+ font-weight: ${font.weight.semibold};
771
+ `,
772
+ statusDot: css2`
773
+ width: 6px;
774
+ height: 6px;
775
+ border-radius: 50%;
776
+ margin-left: auto;
777
+ `,
778
+ stats: css2`
779
+ display: flex;
780
+ align-items: center;
781
+ gap: ${size[2]};
782
+ font-size: 10px;
783
+ opacity: 0.7;
784
+ flex-wrap: wrap;
785
+ `,
786
+ statItem: css2`
787
+ display: flex;
788
+ align-items: center;
789
+ gap: 2px;
790
+ white-space: nowrap;
791
+ `,
792
+ tokensBadge: css2`
793
+ display: flex;
794
+ align-items: center;
795
+ gap: 2px;
796
+ padding: 1px 5px;
797
+ border-radius: ${border.radius.sm};
798
+ background: oklch(0.35 0.08 220);
799
+ color: oklch(0.75 0.12 220);
800
+ font-size: 10px;
801
+ font-weight: ${font.weight.semibold};
802
+ white-space: nowrap;
803
+ `,
804
+ loadingIndicator: css2`
805
+ font-size: 12px;
806
+ color: oklch(0.7 0.17 142);
807
+ animation: spin 1s linear infinite;
808
+ @keyframes spin {
809
+ from {
810
+ transform: rotate(0deg);
811
+ }
812
+ to {
813
+ transform: rotate(360deg);
814
+ }
815
+ }
816
+ `
817
+ },
818
+ // ConversationDetails component styles
819
+ conversationDetails: {
820
+ emptyState: css2`
821
+ display: flex;
822
+ align-items: center;
823
+ justify-content: center;
824
+ height: 100%;
825
+ color: ${t(colors.gray[500], colors.gray[500])};
826
+ font-size: ${fontSize.sm};
827
+ `,
828
+ container: css2`
829
+ display: flex;
830
+ flex-direction: column;
831
+ height: 100%;
832
+ `,
833
+ headerContent: css2`
834
+ display: flex;
835
+ flex-direction: column;
836
+ gap: ${size[1]};
837
+ `,
838
+ headerRow: css2`
839
+ display: flex;
840
+ align-items: center;
841
+ gap: ${size[3]};
842
+ `,
843
+ headerLabel: css2`
844
+ font-weight: ${font.weight.semibold};
845
+ font-size: ${fontSize.sm};
846
+ `,
847
+ statusBadge: css2`
848
+ font-size: ${fontSize.xs};
849
+ padding: 2px ${size[2]};
850
+ border-radius: ${border.radius.sm};
851
+ `,
852
+ statusActive: css2`
853
+ background: ${colors.blue[500]}20;
854
+ color: ${colors.blue[500]};
855
+ `,
856
+ statusCompleted: css2`
857
+ background: ${colors.green[500]}20;
858
+ color: ${colors.green[500]};
859
+ `,
860
+ statusError: css2`
861
+ background: ${colors.red[500]}20;
862
+ color: ${colors.red[500]};
863
+ `,
864
+ metaInfo: css2`
865
+ font-size: ${fontSize.xs};
866
+ color: ${t(colors.gray[600], colors.gray[400])};
867
+ `,
868
+ usageInfo: css2`
869
+ font-size: ${fontSize.xs};
870
+ color: ${t(colors.gray[600], colors.gray[400])};
871
+ display: flex;
872
+ align-items: center;
873
+ gap: ${size[2]};
874
+ `,
875
+ usageLabel: css2`
876
+ font-weight: ${font.weight.semibold};
877
+ color: ${colors.blue[500]};
878
+ `,
879
+ usageBold: css2`
880
+ font-weight: ${font.weight.semibold};
881
+ `,
882
+ toolsRow: css2`
883
+ display: flex;
884
+ align-items: flex-start;
885
+ gap: ${size[2]};
886
+ margin-top: ${size[2]};
887
+ `,
888
+ toolsLabel: css2`
889
+ font-size: ${fontSize.sm};
890
+ flex-shrink: 0;
891
+ `,
892
+ optionsRow: css2`
893
+ display: flex;
894
+ align-items: flex-start;
895
+ gap: ${size[2]};
896
+ margin-top: ${size[1]};
897
+ `,
898
+ optionsLabel: css2`
899
+ font-size: ${fontSize.xs};
900
+ color: ${t(colors.gray[600], colors.gray[400])};
901
+ flex-shrink: 0;
902
+ white-space: nowrap;
903
+ `,
904
+ optionsCompact: css2`
905
+ display: flex;
906
+ flex-wrap: wrap;
907
+ gap: 4px;
908
+ `,
909
+ optionBadge: css2`
910
+ display: inline-flex;
911
+ align-items: center;
912
+ padding: 1px 6px;
913
+ background: ${t(colors.gray[200], colors.darkGray[700])};
914
+ color: ${t(colors.gray[700], colors.gray[300])};
915
+ border-radius: ${border.radius.sm};
916
+ font-size: 10px;
917
+ font-family: ${fontFamily.mono};
918
+ max-width: 200px;
919
+ overflow: hidden;
920
+ text-overflow: ellipsis;
921
+ white-space: nowrap;
922
+ `,
923
+ toggleButton: css2`
924
+ background: transparent;
925
+ border: 1px solid ${t(colors.gray[300], colors.darkGray[600])};
926
+ color: ${t(colors.gray[600], colors.gray[400])};
927
+ padding: ${size[1]} ${size[2]};
928
+ border-radius: ${border.radius.sm};
929
+ font-size: ${fontSize.xs};
930
+ cursor: pointer;
931
+ transition: all 0.15s ease;
932
+ margin-top: ${size[2]};
933
+ &:hover {
934
+ background: ${t(colors.gray[100], colors.darkGray[700])};
935
+ color: ${t(colors.gray[700], colors.gray[300])};
936
+ }
937
+ `,
938
+ extendedInfo: css2`
939
+ margin-top: ${size[3]};
940
+ padding: ${size[3]};
941
+ background: ${t(colors.gray[50], colors.darkGray[800])};
942
+ border-radius: ${border.radius.md};
943
+ border: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
944
+ `,
945
+ infoSection: css2`
946
+ margin-bottom: ${size[3]};
947
+ &:last-child {
948
+ margin-bottom: 0;
949
+ }
950
+ `,
951
+ infoLabel: css2`
952
+ font-weight: ${font.weight.semibold};
953
+ font-size: ${fontSize.xs};
954
+ color: ${t(colors.gray[700], colors.gray[300])};
955
+ display: block;
956
+ margin-bottom: ${size[1]};
957
+ `,
958
+ toolsList: css2`
959
+ display: flex;
960
+ flex-wrap: wrap;
961
+ gap: ${size[1]};
962
+ `,
963
+ toolBadge: css2`
964
+ display: inline-flex;
965
+ align-items: center;
966
+ padding: 2px ${size[2]};
967
+ background: ${colors.purple[500]}20;
968
+ color: ${colors.purple[400]};
969
+ border-radius: ${border.radius.sm};
970
+ font-size: ${fontSize.xs};
971
+ font-family: ${fontFamily.mono};
972
+ `,
973
+ jsonPreview: css2`
974
+ margin: 0;
975
+ padding: ${size[2]};
976
+ background: ${t(colors.gray[100], colors.darkGray[900])};
977
+ border-radius: ${border.radius.sm};
978
+ font-size: ${fontSize.xs};
979
+ font-family: ${fontFamily.mono};
980
+ overflow-x: auto;
981
+ max-height: 200px;
982
+ overflow-y: auto;
983
+ color: ${t(colors.gray[700], colors.gray[300])};
984
+ white-space: pre-wrap;
985
+ word-break: break-word;
986
+ `,
987
+ collapsibleSection: css2`
988
+ margin-top: ${size[2]};
989
+ border: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
990
+ border-radius: ${border.radius.md};
991
+ overflow: hidden;
992
+ `,
993
+ collapsibleSummary: css2`
994
+ cursor: pointer;
995
+ padding: ${size[2]} ${size[3]};
996
+ background: ${t(colors.gray[100], colors.darkGray[800])};
997
+ font-size: ${fontSize.xs};
998
+ font-weight: ${font.weight.medium};
999
+ color: ${t(colors.gray[700], colors.gray[300])};
1000
+ user-select: none;
1001
+ &:hover {
1002
+ background: ${t(colors.gray[200], colors.darkGray[700])};
1003
+ }
1004
+ `,
1005
+ collapsibleContent: css2`
1006
+ padding: ${size[3]};
1007
+ background: ${t(colors.gray[50], colors.darkGray[900])};
1008
+ font-size: ${fontSize.xs};
1009
+ max-height: 300px;
1010
+ overflow-y: auto;
1011
+ `,
1012
+ systemPromptItem: css2`
1013
+ display: flex;
1014
+ gap: ${size[2]};
1015
+ padding: ${size[2]};
1016
+ margin-bottom: ${size[2]};
1017
+ background: ${t(colors.gray[100], colors.darkGray[800])};
1018
+ border-radius: ${border.radius.sm};
1019
+ &:last-child {
1020
+ margin-bottom: 0;
1021
+ }
1022
+ `,
1023
+ systemPromptIndex: css2`
1024
+ font-weight: ${font.weight.semibold};
1025
+ color: ${colors.purple[400]};
1026
+ font-size: 10px;
1027
+ flex-shrink: 0;
1028
+ `,
1029
+ systemPromptText: css2`
1030
+ color: ${t(colors.gray[700], colors.gray[300])};
1031
+ white-space: pre-wrap;
1032
+ word-break: break-word;
1033
+ line-height: 1.4;
1034
+ `,
1035
+ tabsContainer: css2`
1036
+ display: flex;
1037
+ gap: ${size[2]};
1038
+ padding: ${size[3]};
1039
+ border-bottom: 1px solid ${t(colors.gray[200], colors.darkGray[700])};
1040
+ `,
1041
+ tabButtonActive: css2`
1042
+ background: ${colors.pink[400]};
1043
+ color: ${colors.white};
1044
+ border-color: ${colors.pink[400]};
1045
+ `,
1046
+ tabButtonPulse: css2`
1047
+ position: relative;
1048
+ animation: activityPulse 1.4s ease-in-out infinite;
1049
+ @keyframes activityPulse {
1050
+ 0% {
1051
+ box-shadow: 0 0 0 0 ${colors.pink[400]}55;
1052
+ }
1053
+ 70% {
1054
+ box-shadow: 0 0 0 8px ${colors.pink[400]}00;
1055
+ }
1056
+ 100% {
1057
+ box-shadow: 0 0 0 0 ${colors.pink[400]}00;
1058
+ }
1059
+ }
1060
+ `,
1061
+ contentArea: css2`
1062
+ flex: 1;
1063
+ overflow: auto;
1064
+ padding: ${size[3]};
1065
+ padding-bottom: ${size[6]};
1066
+ `,
1067
+ emptyMessages: css2`
1068
+ padding: ${size[6]};
1069
+ color: ${t(colors.gray[500], colors.gray[500])};
1070
+ font-size: ${fontSize.sm};
1071
+ text-align: center;
1072
+ `,
1073
+ messagesList: css2`
1074
+ display: flex;
1075
+ flex-direction: column;
1076
+ gap: ${size[3]};
1077
+ `,
1078
+ messageCard: css2`
1079
+ border-radius: ${border.radius.lg};
1080
+ overflow: hidden;
1081
+ `,
1082
+ messageCardUser: css2`
1083
+ padding: ${size[3]};
1084
+ border: 1.5px solid oklch(0.45 0.12 260);
1085
+ `,
1086
+ messageCardAssistant: css2`
1087
+ padding: ${size[4]};
1088
+ border: 1.5px solid oklch(0.45 0.12 142);
1089
+ `,
1090
+ messageCardClient: css2`
1091
+ border: 2px solid oklch(0.45 0.15 142);
1092
+ `,
1093
+ messageCardServer: css2`
1094
+ border: 2px solid oklch(0.45 0.12 45);
1095
+ `,
1096
+ messageHeader: css2`
1097
+ display: flex;
1098
+ align-items: center;
1099
+ gap: 10px;
1100
+ margin-bottom: ${size[3]};
1101
+ `,
1102
+ avatarUser: css2`
1103
+ width: 28px;
1104
+ height: 28px;
1105
+ border-radius: 50%;
1106
+ background: oklch(0.5 0.2 260);
1107
+ display: flex;
1108
+ align-items: center;
1109
+ justify-content: center;
1110
+ font-weight: ${font.weight.bold};
1111
+ font-size: ${fontSize.sm};
1112
+ color: ${colors.white};
1113
+ flex-shrink: 0;
1114
+ `,
1115
+ avatarAssistant: css2`
1116
+ width: 28px;
1117
+ height: 28px;
1118
+ border-radius: 50%;
1119
+ background: oklch(0.5 0.2 142);
1120
+ display: flex;
1121
+ align-items: center;
1122
+ justify-content: center;
1123
+ font-weight: ${font.weight.bold};
1124
+ font-size: ${fontSize.sm};
1125
+ color: ${colors.white};
1126
+ flex-shrink: 0;
1127
+ `,
1128
+ avatarClient: css2`
1129
+ width: 28px;
1130
+ height: 28px;
1131
+ border-radius: 50%;
1132
+ background: oklch(0.5 0.22 142);
1133
+ display: flex;
1134
+ align-items: center;
1135
+ justify-content: center;
1136
+ font-weight: ${font.weight.bold};
1137
+ font-size: ${fontSize.sm};
1138
+ color: ${colors.white};
1139
+ flex-shrink: 0;
1140
+ `,
1141
+ avatarServer: css2`
1142
+ width: 28px;
1143
+ height: 28px;
1144
+ border-radius: 50%;
1145
+ background: oklch(0.55 0.18 45);
1146
+ display: flex;
1147
+ align-items: center;
1148
+ justify-content: center;
1149
+ font-weight: ${font.weight.bold};
1150
+ font-size: ${fontSize.sm};
1151
+ color: ${colors.white};
1152
+ flex-shrink: 0;
1153
+ `,
1154
+ roleLabel: css2`
1155
+ flex: 1;
1156
+ `,
1157
+ roleLabelUser: css2`
1158
+ font-weight: ${font.weight.semibold};
1159
+ font-size: ${fontSize.sm};
1160
+ color: oklch(0.7 0.15 260);
1161
+ text-transform: capitalize;
1162
+ `,
1163
+ roleLabelAssistant: css2`
1164
+ font-weight: ${font.weight.semibold};
1165
+ font-size: ${fontSize.sm};
1166
+ color: oklch(0.7 0.15 142);
1167
+ text-transform: capitalize;
1168
+ `,
1169
+ roleLabelClient: css2`
1170
+ font-weight: ${font.weight.semibold};
1171
+ font-size: ${fontSize.sm};
1172
+ color: oklch(0.75 0.18 142);
1173
+ text-transform: capitalize;
1174
+ `,
1175
+ roleLabelServer: css2`
1176
+ font-weight: ${font.weight.semibold};
1177
+ font-size: ${fontSize.sm};
1178
+ color: oklch(0.75 0.15 45);
1179
+ text-transform: capitalize;
1180
+ `,
1181
+ sourceBanner: css2`
1182
+ display: flex;
1183
+ align-items: center;
1184
+ gap: 8px;
1185
+ padding: 6px 12px;
1186
+ font-size: 10px;
1187
+ font-weight: ${font.weight.medium};
1188
+ text-transform: uppercase;
1189
+ letter-spacing: 0.5px;
1190
+ `,
1191
+ sourceBannerClient: css2`
1192
+ background: oklch(0.25 0.04 142);
1193
+ color: oklch(0.7 0.08 142);
1194
+ `,
1195
+ sourceBannerServer: css2`
1196
+ background: oklch(0.25 0.04 45);
1197
+ color: oklch(0.7 0.06 45);
1198
+ `,
1199
+ sourceBannerIcon: css2`
1200
+ font-size: 14px;
1201
+ `,
1202
+ sourceBannerText: css2`
1203
+ flex: 1;
1204
+ `,
1205
+ messageCardContent: css2`
1206
+ padding: ${size[4]};
1207
+ padding-top: ${size[3]};
1208
+ `,
1209
+ sourceBadge: css2`
1210
+ font-size: 10px;
1211
+ padding: 2px 6px;
1212
+ border-radius: 4px;
1213
+ font-family: ${fontFamily.mono};
1214
+ font-weight: ${font.weight.medium};
1215
+ `,
1216
+ sourceBadgeClient: css2`
1217
+ background: oklch(0.25 0.08 260);
1218
+ color: oklch(0.75 0.12 260);
1219
+ `,
1220
+ sourceBadgeServer: css2`
1221
+ background: oklch(0.25 0.08 45);
1222
+ color: oklch(0.75 0.12 45);
1223
+ `,
1224
+ timestamp: css2`
1225
+ font-size: 10px;
1226
+ color: oklch(0.6 0.05 260);
1227
+ font-family: ${fontFamily.mono};
1228
+ `,
1229
+ messageUsage: css2`
1230
+ display: flex;
1231
+ align-items: center;
1232
+ gap: 4px;
1233
+ font-size: 10px;
1234
+ font-family: ${fontFamily.mono};
1235
+ color: oklch(0.65 0.12 142);
1236
+ margin-left: auto;
1237
+ padding: 2px 6px;
1238
+ background: oklch(0.2 0.03 142);
1239
+ border-radius: 4px;
1240
+ `,
1241
+ messageUsageIcon: css2`
1242
+ font-size: 10px;
1243
+ `,
1244
+ thinkingDetails: css2`
1245
+ margin-bottom: ${size[2]};
1246
+ border: 1px solid oklch(0.35 0.1 280);
1247
+ border-radius: 6px;
1248
+ background: oklch(0.18 0.02 280);
1249
+ overflow: hidden;
1250
+ `,
1251
+ thinkingSummary: css2`
1252
+ padding: ${size[2]};
1253
+ cursor: pointer;
1254
+ font-size: ${fontSize.sm};
1255
+ color: oklch(0.75 0.1 280);
1256
+ font-weight: ${font.weight.semibold};
1257
+ &:hover {
1258
+ background: oklch(0.22 0.03 280);
1259
+ }
1260
+ `,
1261
+ thinkingContent: css2`
1262
+ padding: ${size[2]};
1263
+ font-size: ${fontSize.xs};
1264
+ line-height: 1.5;
1265
+ white-space: pre-wrap;
1266
+ word-break: break-word;
1267
+ color: oklch(0.7 0.05 280);
1268
+ font-family: ${fontFamily.mono};
1269
+ border-top: 1px solid oklch(0.3 0.05 280);
1270
+ max-height: 300px;
1271
+ overflow-y: auto;
1272
+ `,
1273
+ messageContent: css2`
1274
+ font-size: ${fontSize.sm};
1275
+ line-height: 1.6;
1276
+ white-space: pre-wrap;
1277
+ word-break: break-word;
1278
+ color: oklch(0.85 0.02 260);
1279
+ font-family:
1280
+ system-ui,
1281
+ -apple-system,
1282
+ sans-serif;
1283
+ `,
1284
+ toolCallsContainer: css2`
1285
+ margin-top: ${size[3]};
1286
+ display: flex;
1287
+ flex-direction: column;
1288
+ gap: 8px;
1289
+ `,
1290
+ toolCall: css2`
1291
+ border-radius: 8px;
1292
+ font-size: ${fontSize.xs};
1293
+ overflow: hidden;
1294
+ `,
1295
+ toolCallNormal: css2`
1296
+ background: oklch(0.22 0.02 260);
1297
+ border: 1px solid oklch(0.3 0.05 280);
1298
+ `,
1299
+ toolCallApproval: css2`
1300
+ background: oklch(0.22 0.08 60);
1301
+ border: 1px solid oklch(0.4 0.12 60);
1302
+ `,
1303
+ toolCallHeader: css2`
1304
+ display: flex;
1305
+ align-items: center;
1306
+ gap: 6px;
1307
+ padding: 10px 12px;
1308
+ cursor: pointer;
1309
+ list-style: none;
1310
+ &::-webkit-details-marker {
1311
+ display: none;
1312
+ }
1313
+ &::before {
1314
+ content: '▶';
1315
+ font-size: 10px;
1316
+ color: oklch(0.6 0.1 280);
1317
+ transition: transform 0.2s ease;
1318
+ }
1319
+ details[open] > &::before {
1320
+ transform: rotate(90deg);
1321
+ }
1322
+ &:hover {
1323
+ background: oklch(0.25 0.04 280);
1324
+ }
1325
+ `,
1326
+ toolCallContent: css2`
1327
+ padding: ${size[2]} ${size[3]} ${size[3]};
1328
+ border-top: 1px solid oklch(0.3 0.05 280);
1329
+ `,
1330
+ toolCallName: css2`
1331
+ font-weight: ${font.weight.semibold};
1332
+ `,
1333
+ toolCallNameNormal: css2`
1334
+ color: oklch(0.75 0.15 280);
1335
+ `,
1336
+ toolCallNameApproval: css2`
1337
+ color: oklch(0.75 0.15 60);
1338
+ `,
1339
+ toolStateBadge: css2`
1340
+ font-size: 10px;
1341
+ padding: 2px 6px;
1342
+ border-radius: 3px;
1343
+ `,
1344
+ toolStateBadgeNormal: css2`
1345
+ background: oklch(0.35 0.1 280);
1346
+ color: oklch(0.8 0.1 280);
1347
+ `,
1348
+ toolStateBadgeApproval: css2`
1349
+ background: oklch(0.35 0.12 60);
1350
+ color: oklch(0.85 0.1 60);
1351
+ `,
1352
+ approvalRequiredBadge: css2`
1353
+ font-size: 10px;
1354
+ padding: 2px 6px;
1355
+ border-radius: 3px;
1356
+ background: oklch(0.45 0.15 30);
1357
+ color: oklch(0.95 0.05 60);
1358
+ font-weight: ${font.weight.semibold};
1359
+ `,
1360
+ toolArguments: css2`
1361
+ font-family: ${fontFamily.mono};
1362
+ font-size: ${fontSize.xs};
1363
+ color: oklch(0.7 0.05 260);
1364
+ white-space: pre-wrap;
1365
+ word-break: break-all;
1366
+ `,
1367
+ toolSection: css2`
1368
+ margin-top: ${size[2]};
1369
+ border-top: 1px solid oklch(0.28 0.03 260);
1370
+ padding-top: ${size[2]};
1371
+ `,
1372
+ toolSectionLabel: css2`
1373
+ font-size: 10px;
1374
+ font-weight: ${font.weight.semibold};
1375
+ color: oklch(0.6 0.08 260);
1376
+ text-transform: uppercase;
1377
+ letter-spacing: 0.05em;
1378
+ margin-bottom: ${size[1]};
1379
+ `,
1380
+ toolJsonContainer: css2`
1381
+ font-family: ${fontFamily.mono};
1382
+ font-size: ${fontSize.xs};
1383
+ color: oklch(0.8 0.05 260);
1384
+ background: oklch(0.18 0.02 260);
1385
+ border-radius: 4px;
1386
+ padding: ${size[4]};
1387
+ padding-left: ${size[8]};
1388
+ `,
1389
+ chunksDetails: css2`
1390
+ margin-top: ${size[3]};
1391
+ `,
1392
+ chunksSummary: css2`
1393
+ cursor: pointer;
1394
+ font-size: ${fontSize.xs};
1395
+ font-weight: ${font.weight.semibold};
1396
+ color: oklch(0.65 0.08 260);
1397
+ padding: ${size[2]};
1398
+ background: oklch(0.2 0.02 260);
1399
+ border-radius: 6px;
1400
+ border: 1px solid oklch(0.28 0.03 260);
1401
+ user-select: none;
1402
+ list-style: none;
1403
+ &::-webkit-details-marker {
1404
+ display: none;
1405
+ }
1406
+ &::marker {
1407
+ display: none;
1408
+ }
1409
+ details[open] > & .chunks-arrow {
1410
+ transform: rotate(90deg);
1411
+ }
1412
+ `,
1413
+ chunksSummaryRow: css2`
1414
+ display: flex;
1415
+ align-items: center;
1416
+ gap: ${size[1]};
1417
+ `,
1418
+ chunksSummaryArrow: css2`
1419
+ font-size: 8px;
1420
+ transition: transform 0.15s ease;
1421
+ color: oklch(0.5 0.05 260);
1422
+ details[open] > summary > div > & {
1423
+ transform: rotate(90deg);
1424
+ }
1425
+ `,
1426
+ chunksSummaryTitle: css2`
1427
+ margin-right: ${size[1]};
1428
+ `,
1429
+ chunksSummaryContent: css2`
1430
+ display: flex;
1431
+ flex-direction: column;
1432
+ gap: 6px;
1433
+ `,
1434
+ chunksSummaryHeader: css2`
1435
+ display: flex;
1436
+ align-items: center;
1437
+ gap: ${size[2]};
1438
+ `,
1439
+ chunkBadge: css2`
1440
+ padding: 2px 6px;
1441
+ border-radius: 3px;
1442
+ font-size: 9px;
1443
+ `,
1444
+ chunkBadgeTool: css2`
1445
+ background: oklch(0.3 0.1 280);
1446
+ color: oklch(0.75 0.12 280);
1447
+ `,
1448
+ chunkBadgeError: css2`
1449
+ background: oklch(0.3 0.15 25);
1450
+ color: oklch(0.75 0.2 25);
1451
+ `,
1452
+ chunkBadgeSuccess: css2`
1453
+ background: oklch(0.3 0.1 142);
1454
+ color: oklch(0.75 0.15 142);
1455
+ `,
1456
+ chunkBadgeApproval: css2`
1457
+ background: oklch(0.3 0.15 50);
1458
+ color: oklch(0.75 0.2 50);
1459
+ `,
1460
+ chunkBadgeCount: css2`
1461
+ background: oklch(0.3 0.08 260);
1462
+ color: oklch(0.75 0.1 260);
1463
+ font-weight: ${font.weight.semibold};
1464
+ `,
1465
+ contentPreview: css2`
1466
+ font-family: ${fontFamily.mono};
1467
+ font-size: 10px;
1468
+ color: oklch(0.75 0.05 260);
1469
+ white-space: pre-wrap;
1470
+ word-break: break-word;
1471
+ max-width: 100%;
1472
+ font-weight: ${font.weight.normal};
1473
+ margin-top: 2px;
1474
+ `,
1475
+ chunksContainer: css2`
1476
+ margin-top: ${size[2]};
1477
+ padding: ${size[2]};
1478
+ background: oklch(0.18 0.02 260);
1479
+ border-radius: 6px;
1480
+ border: 1px solid oklch(0.25 0.03 260);
1481
+ `,
1482
+ chunksList: css2`
1483
+ display: flex;
1484
+ flex-direction: column;
1485
+ gap: ${size[1]};
1486
+ `,
1487
+ chunkItem: css2`
1488
+ padding: 6px ${size[2]};
1489
+ border-radius: ${border.radius.sm};
1490
+ background: oklch(0.22 0.02 260);
1491
+ border: 1px solid oklch(0.28 0.03 260);
1492
+ font-size: 10px;
1493
+ `,
1494
+ chunkItemLarge: css2`
1495
+ padding: ${size[2]} 10px;
1496
+ border-radius: 6px;
1497
+ background: oklch(0.22 0.02 260);
1498
+ border: 1px solid oklch(0.28 0.03 260);
1499
+ font-size: ${fontSize.xs};
1500
+ `,
1501
+ chunkHeader: css2`
1502
+ display: flex;
1503
+ align-items: center;
1504
+ gap: 6px;
1505
+ margin-bottom: ${size[1]};
1506
+ `,
1507
+ chunkHeaderLarge: css2`
1508
+ display: flex;
1509
+ align-items: center;
1510
+ gap: ${size[2]};
1511
+ margin-bottom: 6px;
1512
+ `,
1513
+ chunkNumber: css2`
1514
+ font-size: 9px;
1515
+ font-weight: ${font.weight.semibold};
1516
+ color: oklch(0.6 0.05 260);
1517
+ min-width: 24px;
1518
+ `,
1519
+ chunkNumberLarge: css2`
1520
+ font-size: 10px;
1521
+ font-weight: ${font.weight.semibold};
1522
+ color: oklch(0.6 0.05 260);
1523
+ min-width: 32px;
1524
+ `,
1525
+ chunkTypeBadge: css2`
1526
+ display: flex;
1527
+ align-items: center;
1528
+ gap: 3px;
1529
+ `,
1530
+ chunkTypeBadgeLarge: css2`
1531
+ display: flex;
1532
+ align-items: center;
1533
+ gap: ${size[1]};
1534
+ `,
1535
+ chunkTypeDot: css2`
1536
+ width: 5px;
1537
+ height: 5px;
1538
+ border-radius: 50%;
1539
+ `,
1540
+ chunkTypeDotLarge: css2`
1541
+ width: 6px;
1542
+ height: 6px;
1543
+ border-radius: 50%;
1544
+ `,
1545
+ chunkTypeLabel: css2`
1546
+ font-weight: ${font.weight.semibold};
1547
+ color: oklch(0.7 0.08 260);
1548
+ `,
1549
+ chunkTypeLabelLarge: css2`
1550
+ font-weight: ${font.weight.semibold};
1551
+ color: oklch(0.75 0.08 260);
1552
+ `,
1553
+ chunkToolBadge: css2`
1554
+ padding: 1px ${size[1]};
1555
+ border-radius: 3px;
1556
+ background: oklch(0.3 0.1 280);
1557
+ color: oklch(0.75 0.12 280);
1558
+ font-size: 9px;
1559
+ font-weight: ${font.weight.semibold};
1560
+ `,
1561
+ chunkToolBadgeLarge: css2`
1562
+ padding: 2px 6px;
1563
+ border-radius: 3px;
1564
+ background: oklch(0.3 0.1 280);
1565
+ color: oklch(0.75 0.12 280);
1566
+ font-size: 10px;
1567
+ font-weight: ${font.weight.semibold};
1568
+ `,
1569
+ chunkTimestamp: css2`
1570
+ margin-left: auto;
1571
+ color: ${t(colors.gray[500], colors.gray[500])};
1572
+ font-size: 9px;
1573
+ `,
1574
+ chunkTimestampLarge: css2`
1575
+ margin-left: auto;
1576
+ color: ${t(colors.gray[500], colors.gray[500])};
1577
+ font-size: 10px;
1578
+ `,
1579
+ rawJsonButton: css2`
1580
+ padding: 1px ${size[1]};
1581
+ border-radius: 2px;
1582
+ border: 1px solid oklch(0.32 0.05 260);
1583
+ color: oklch(0.7 0.08 260);
1584
+ font-size: 8px;
1585
+ cursor: pointer;
1586
+ font-family: ${fontFamily.mono};
1587
+ font-weight: ${font.weight.semibold};
1588
+ `,
1589
+ rawJsonButtonInactive: css2`
1590
+ background: oklch(0.28 0.03 260);
1591
+ `,
1592
+ rawJsonButtonActive: css2`
1593
+ background: oklch(0.35 0.1 260);
1594
+ `,
1595
+ rawJsonButtonLarge: css2`
1596
+ padding: 2px 6px;
1597
+ border-radius: 3px;
1598
+ border: 1px solid oklch(0.32 0.05 260);
1599
+ color: oklch(0.7 0.08 260);
1600
+ font-size: 10px;
1601
+ cursor: pointer;
1602
+ font-family: ${fontFamily.mono};
1603
+ font-weight: ${font.weight.semibold};
1604
+ `,
1605
+ chunkContent: css2`
1606
+ font-family: ${fontFamily.mono};
1607
+ white-space: pre-wrap;
1608
+ word-break: break-word;
1609
+ padding: ${size[1]} 6px;
1610
+ background: oklch(0.2 0.01 260);
1611
+ border-radius: 3px;
1612
+ color: oklch(0.8 0.05 260);
1613
+ font-size: 10px;
1614
+ `,
1615
+ chunkContentLarge: css2`
1616
+ font-family: ${fontFamily.mono};
1617
+ white-space: pre-wrap;
1618
+ word-break: break-word;
1619
+ padding: 6px ${size[2]};
1620
+ background: oklch(0.2 0.01 260);
1621
+ border-radius: ${border.radius.sm};
1622
+ color: oklch(0.8 0.05 260);
1623
+ font-size: ${fontSize.xs};
1624
+ `,
1625
+ chunkError: css2`
1626
+ color: oklch(0.65 0.2 25);
1627
+ font-family: ${fontFamily.mono};
1628
+ padding: ${size[1]} 6px;
1629
+ background: oklch(0.2 0.05 25);
1630
+ border-radius: 3px;
1631
+ `,
1632
+ chunkErrorLarge: css2`
1633
+ color: oklch(0.65 0.2 25);
1634
+ font-family: ${fontFamily.mono};
1635
+ padding: 6px ${size[2]};
1636
+ background: oklch(0.2 0.05 25);
1637
+ border-radius: ${border.radius.sm};
1638
+ `,
1639
+ chunkFinish: css2`
1640
+ color: oklch(0.7 0.12 142);
1641
+ padding: ${size[1]} 6px;
1642
+ background: oklch(0.2 0.03 142);
1643
+ border-radius: 3px;
1644
+ font-weight: ${font.weight.semibold};
1645
+ `,
1646
+ chunkFinishLarge: css2`
1647
+ color: oklch(0.7 0.12 142);
1648
+ padding: 6px ${size[2]};
1649
+ background: oklch(0.2 0.03 142);
1650
+ border-radius: ${border.radius.sm};
1651
+ font-weight: ${font.weight.semibold};
1652
+ `,
1653
+ chunkApproval: css2`
1654
+ padding: 6px ${size[2]};
1655
+ background: oklch(0.25 0.12 50);
1656
+ border-radius: ${border.radius.sm};
1657
+ border: 1px solid oklch(0.35 0.15 50);
1658
+ `,
1659
+ chunkApprovalLarge: css2`
1660
+ padding: ${size[2]};
1661
+ background: oklch(0.25 0.12 50);
1662
+ border-radius: 6px;
1663
+ border: 1px solid oklch(0.35 0.15 50);
1664
+ `,
1665
+ chunkApprovalTitle: css2`
1666
+ color: oklch(0.75 0.15 50);
1667
+ font-weight: ${font.weight.semibold};
1668
+ margin-bottom: ${size[1]};
1669
+ font-size: 10px;
1670
+ `,
1671
+ chunkApprovalTitleLarge: css2`
1672
+ color: oklch(0.75 0.15 50);
1673
+ font-weight: ${font.weight.semibold};
1674
+ margin-bottom: 6px;
1675
+ font-size: ${fontSize.xs};
1676
+ `,
1677
+ chunkApprovalInput: css2`
1678
+ font-family: ${fontFamily.mono};
1679
+ font-size: 9px;
1680
+ color: oklch(0.7 0.08 50);
1681
+ white-space: pre-wrap;
1682
+ word-break: break-word;
1683
+ `,
1684
+ chunkApprovalInputLarge: css2`
1685
+ font-family: ${fontFamily.mono};
1686
+ font-size: 10px;
1687
+ color: oklch(0.7 0.08 50);
1688
+ white-space: pre-wrap;
1689
+ word-break: break-word;
1690
+ `,
1691
+ chunkToolCall: css2`
1692
+ padding: ${size[2]} ${size[3]};
1693
+ background: oklch(0.22 0.08 280);
1694
+ border-radius: ${border.radius.sm};
1695
+ border: 1px solid oklch(0.32 0.1 280);
1696
+ margin-top: ${size[1]};
1697
+ `,
1698
+ chunkToolCallHeader: css2`
1699
+ display: flex;
1700
+ align-items: center;
1701
+ justify-content: space-between;
1702
+ margin-bottom: ${size[2]};
1703
+ `,
1704
+ chunkToolCallTitle: css2`
1705
+ color: oklch(0.75 0.12 280);
1706
+ font-weight: ${font.weight.semibold};
1707
+ font-size: 10px;
1708
+ `,
1709
+ chunkToolResult: css2`
1710
+ padding: ${size[2]} ${size[3]};
1711
+ background: oklch(0.22 0.08 160);
1712
+ border-radius: ${border.radius.sm};
1713
+ border: 1px solid oklch(0.32 0.1 160);
1714
+ margin-top: ${size[1]};
1715
+ `,
1716
+ chunkToolResultHeader: css2`
1717
+ display: flex;
1718
+ align-items: center;
1719
+ justify-content: space-between;
1720
+ margin-bottom: ${size[2]};
1721
+ `,
1722
+ chunkToolResultTitle: css2`
1723
+ color: oklch(0.75 0.12 160);
1724
+ font-weight: ${font.weight.semibold};
1725
+ font-size: 10px;
1726
+ `,
1727
+ rawJson: css2`
1728
+ font-family: ${fontFamily.mono};
1729
+ white-space: pre-wrap;
1730
+ word-break: break-word;
1731
+ padding: 6px;
1732
+ background: oklch(0.16 0.01 260);
1733
+ border-radius: 3px;
1734
+ color: oklch(0.75 0.08 260);
1735
+ font-size: 9px;
1736
+ max-height: 200px;
1737
+ overflow-y: auto;
1738
+ `,
1739
+ rawJsonLarge: css2`
1740
+ font-family: ${fontFamily.mono};
1741
+ white-space: pre-wrap;
1742
+ word-break: break-word;
1743
+ padding: ${size[2]};
1744
+ background: oklch(0.16 0.01 260);
1745
+ border-radius: ${border.radius.sm};
1746
+ color: oklch(0.75 0.08 260);
1747
+ font-size: 10px;
1748
+ max-height: 300px;
1749
+ overflow-y: auto;
1750
+ `,
1751
+ noChunks: css2`
1752
+ padding: ${size[3]};
1753
+ color: ${t(colors.gray[500], colors.gray[500])};
1754
+ font-size: ${fontSize.xs};
1755
+ `,
1756
+ streamContainer: css2`
1757
+ padding: ${size[3]};
1758
+ background: oklch(0.18 0.02 260);
1759
+ border-radius: ${border.radius.lg};
1760
+ border: 1px solid oklch(0.25 0.03 260);
1761
+ `,
1762
+ streamHeader: css2`
1763
+ margin-bottom: ${size[3]};
1764
+ padding-bottom: ${size[2]};
1765
+ border-bottom: 1px solid oklch(0.25 0.03 260);
1766
+ `,
1767
+ streamHeaderRow: css2`
1768
+ display: flex;
1769
+ align-items: center;
1770
+ gap: ${size[2]};
1771
+ margin-bottom: ${size[1]};
1772
+ `,
1773
+ streamTitle: css2`
1774
+ font-weight: ${font.weight.semibold};
1775
+ font-size: ${fontSize.sm};
1776
+ color: oklch(0.8 0.05 260);
1777
+ `,
1778
+ streamSubtitle: css2`
1779
+ font-size: ${fontSize.xs};
1780
+ color: ${t(colors.gray[500], colors.gray[500])};
1781
+ `,
1782
+ messageGroups: css2`
1783
+ display: flex;
1784
+ flex-direction: column;
1785
+ gap: ${size[2]};
1786
+ `,
1787
+ messageGroupDetails: css2`
1788
+ margin-bottom: ${size[1]};
1789
+ `,
1790
+ messageGroupSummary: css2`
1791
+ cursor: pointer;
1792
+ font-size: ${fontSize.xs};
1793
+ font-weight: ${font.weight.semibold};
1794
+ color: oklch(0.65 0.08 260);
1795
+ padding: 10px;
1796
+ background: oklch(0.2 0.02 260);
1797
+ border-radius: 6px;
1798
+ border: 1px solid oklch(0.28 0.03 260);
1799
+ user-select: none;
1800
+ `,
1801
+ messageGroupContent: css2`
1802
+ display: flex;
1803
+ flex-direction: column;
1804
+ gap: 6px;
1805
+ `,
1806
+ messageGroupHeader: css2`
1807
+ display: flex;
1808
+ align-items: center;
1809
+ gap: ${size[2]};
1810
+ `,
1811
+ messageId: css2`
1812
+ font-family: ${fontFamily.mono};
1813
+ font-size: 9px;
1814
+ color: oklch(0.6 0.05 260);
1815
+ font-weight: ${font.weight.normal};
1816
+ `,
1817
+ // Embedding and Summarize operation styles
1818
+ operationCard: css2`
1819
+ padding: ${size[4]};
1820
+ border-radius: ${border.radius.lg};
1821
+ background: linear-gradient(
1822
+ 135deg,
1823
+ oklch(0.25 0.04 200) 0%,
1824
+ oklch(0.22 0.03 200) 100%
1825
+ );
1826
+ border: 1.5px solid oklch(0.5 0.15 200);
1827
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
1828
+ `,
1829
+ operationHeader: css2`
1830
+ display: flex;
1831
+ align-items: center;
1832
+ gap: ${size[2]};
1833
+ margin-bottom: ${size[3]};
1834
+ `,
1835
+ operationIcon: css2`
1836
+ font-size: ${fontSize.lg};
1837
+ `,
1838
+ operationTitle: css2`
1839
+ font-weight: ${font.weight.semibold};
1840
+ font-size: ${fontSize.sm};
1841
+ color: oklch(0.85 0.1 200);
1842
+ flex: 1;
1843
+ `,
1844
+ operationStatus: css2`
1845
+ font-size: ${fontSize.xs};
1846
+ padding: 2px ${size[2]};
1847
+ border-radius: ${border.radius.sm};
1848
+ `,
1849
+ operationStatusCompleted: css2`
1850
+ background: ${colors.green[500]}20;
1851
+ color: ${colors.green[400]};
1852
+ `,
1853
+ operationStatusPending: css2`
1854
+ background: ${colors.yellow[500]}20;
1855
+ color: ${colors.yellow[400]};
1856
+ `,
1857
+ durationBadge: css2`
1858
+ font-size: ${fontSize.xs};
1859
+ padding: 2px ${size[2]};
1860
+ border-radius: ${border.radius.sm};
1861
+ background: oklch(0.3 0.1 280);
1862
+ color: oklch(0.8 0.1 280);
1863
+ font-family: ${fontFamily.mono};
1864
+ `,
1865
+ operationDetails: css2`
1866
+ display: flex;
1867
+ flex-direction: column;
1868
+ gap: ${size[2]};
1869
+ `,
1870
+ operationDetail: css2`
1871
+ display: flex;
1872
+ align-items: center;
1873
+ gap: ${size[2]};
1874
+ font-size: ${fontSize.xs};
1875
+ `,
1876
+ operationLabel: css2`
1877
+ color: oklch(0.65 0.08 200);
1878
+ font-weight: ${font.weight.semibold};
1879
+ min-width: 70px;
1880
+ `,
1881
+ operationValue: css2`
1882
+ color: oklch(0.8 0.05 200);
1883
+ font-family: ${fontFamily.mono};
1884
+ `,
1885
+ // Iteration badge
1886
+ iterationBadge: css2`
1887
+ font-size: ${fontSize.xs};
1888
+ padding: 2px ${size[2]};
1889
+ border-radius: ${border.radius.sm};
1890
+ background: ${colors.purple[500]}20;
1891
+ color: ${colors.purple[400]};
1892
+ font-weight: ${font.weight.semibold};
1893
+ `
1894
+ }
1895
+ };
1896
+ };
1897
+ function useStyles() {
1898
+ const { theme } = useTheme();
1899
+ const [styles, setStyles] = createSignal(stylesFactory(theme()));
1900
+ createEffect(() => {
1901
+ setStyles(stylesFactory(theme()));
1902
+ });
1903
+ return styles;
1904
+ }
1905
+ var AIContext = createContext();
1906
+ function useAIStore() {
1907
+ const context = useContext(AIContext);
1908
+ if (!context) {
1909
+ throw new Error("useAIStore must be used within an AIProvider");
1910
+ }
1911
+ return context;
1912
+ }
1913
+ var AIProvider = (props) => {
1914
+ const [state, setState] = createStore({
1915
+ conversations: {},
1916
+ activeConversationId: null
1917
+ });
1918
+ const streamToConversation = /* @__PURE__ */ new Map();
1919
+ const requestToConversation = /* @__PURE__ */ new Map();
1920
+ const pendingConversationChunks = /* @__PURE__ */ new Map();
1921
+ const pendingMessageChunks = /* @__PURE__ */ new Map();
1922
+ let batchScheduled = false;
1923
+ function scheduleBatchFlush() {
1924
+ if (batchScheduled) return;
1925
+ batchScheduled = true;
1926
+ queueMicrotask(flushPendingChunks);
1927
+ }
1928
+ function isMergeableChunkType(type) {
1929
+ return type === "content" || type === "thinking";
1930
+ }
1931
+ function mergeChunks(existing, pending) {
1932
+ for (const chunk of pending) {
1933
+ const lastChunk = existing[existing.length - 1];
1934
+ if (lastChunk && lastChunk.type === chunk.type && isMergeableChunkType(chunk.type) && lastChunk.messageId === chunk.messageId) {
1935
+ lastChunk.content = chunk.content || lastChunk.content;
1936
+ lastChunk.delta = chunk.delta;
1937
+ lastChunk.chunkCount += chunk.chunkCount;
1938
+ } else {
1939
+ existing.push(chunk);
1940
+ }
1941
+ }
1942
+ }
1943
+ function flushPendingChunks() {
1944
+ batchScheduled = false;
1945
+ batch(() => {
1946
+ for (const [conversationId, {
1947
+ chunks,
1948
+ newChunkCount
1949
+ }] of pendingConversationChunks) {
1950
+ const conv = state.conversations[conversationId];
1951
+ if (conv) {
1952
+ setState("conversations", conversationId, "chunks", produce((arr) => {
1953
+ mergeChunks(arr, chunks);
1954
+ }));
1955
+ }
1956
+ }
1957
+ pendingConversationChunks.clear();
1958
+ for (const [conversationId, messageMap] of pendingMessageChunks) {
1959
+ const conv = state.conversations[conversationId];
1960
+ if (!conv) continue;
1961
+ for (const [messageIndex, {
1962
+ chunks,
1963
+ newChunkCount
1964
+ }] of messageMap) {
1965
+ const message = conv.messages[messageIndex];
1966
+ if (message) {
1967
+ setState("conversations", conversationId, "messages", messageIndex, "chunks", produce((arr) => {
1968
+ if (!arr) {
1969
+ return chunks;
1970
+ }
1971
+ mergeChunks(arr, chunks);
1972
+ return arr;
1973
+ }));
1974
+ const currentTotal = message.totalChunkCount || 0;
1975
+ setState("conversations", conversationId, "messages", messageIndex, "totalChunkCount", currentTotal + newChunkCount);
1976
+ }
1977
+ }
1978
+ }
1979
+ pendingMessageChunks.clear();
1980
+ });
1981
+ }
1982
+ function queueChunk(conversationId, chunk) {
1983
+ if (!pendingConversationChunks.has(conversationId)) {
1984
+ pendingConversationChunks.set(conversationId, {
1985
+ chunks: [],
1986
+ newChunkCount: 0
1987
+ });
1988
+ }
1989
+ const pending = pendingConversationChunks.get(conversationId);
1990
+ const lastPending = pending.chunks[pending.chunks.length - 1];
1991
+ if (lastPending && lastPending.type === chunk.type && isMergeableChunkType(chunk.type) && lastPending.messageId === chunk.messageId) {
1992
+ lastPending.content = chunk.content || lastPending.content;
1993
+ lastPending.delta = chunk.delta;
1994
+ lastPending.chunkCount += chunk.chunkCount;
1995
+ } else {
1996
+ pending.chunks.push(chunk);
1997
+ }
1998
+ pending.newChunkCount += chunk.chunkCount;
1999
+ scheduleBatchFlush();
2000
+ }
2001
+ function queueMessageChunk(conversationId, messageIndex, chunk) {
2002
+ if (!pendingMessageChunks.has(conversationId)) {
2003
+ pendingMessageChunks.set(conversationId, /* @__PURE__ */ new Map());
2004
+ }
2005
+ const messageMap = pendingMessageChunks.get(conversationId);
2006
+ if (!messageMap.has(messageIndex)) {
2007
+ messageMap.set(messageIndex, {
2008
+ chunks: [],
2009
+ newChunkCount: 0
2010
+ });
2011
+ }
2012
+ const pending = messageMap.get(messageIndex);
2013
+ const lastPending = pending.chunks[pending.chunks.length - 1];
2014
+ if (lastPending && lastPending.type === chunk.type && isMergeableChunkType(chunk.type) && lastPending.messageId === chunk.messageId) {
2015
+ lastPending.content = chunk.content || lastPending.content;
2016
+ lastPending.delta = chunk.delta;
2017
+ lastPending.chunkCount += chunk.chunkCount;
2018
+ } else {
2019
+ pending.chunks.push(chunk);
2020
+ }
2021
+ pending.newChunkCount += chunk.chunkCount;
2022
+ scheduleBatchFlush();
2023
+ }
2024
+ function getOrCreateConversation(id, type, label) {
2025
+ if (!state.conversations[id]) {
2026
+ setState("conversations", id, {
2027
+ id,
2028
+ type,
2029
+ label,
2030
+ messages: [],
2031
+ chunks: [],
2032
+ imageEvents: [],
2033
+ speechEvents: [],
2034
+ transcriptionEvents: [],
2035
+ videoEvents: [],
2036
+ status: "active",
2037
+ startedAt: Date.now()
2038
+ });
2039
+ if (!state.activeConversationId) {
2040
+ setState("activeConversationId", id);
2041
+ }
2042
+ }
2043
+ }
2044
+ function addMessage(conversationId, message) {
2045
+ const conv = state.conversations[conversationId];
2046
+ if (!conv) return;
2047
+ setState("conversations", conversationId, "messages", conv.messages.length, message);
2048
+ }
2049
+ function addChunkToMessage(conversationId, chunk) {
2050
+ const conv = state.conversations[conversationId];
2051
+ if (!conv) return;
2052
+ if (chunk.messageId) {
2053
+ const messageIndex = conv.messages.findIndex((msg) => msg.id === chunk.messageId);
2054
+ if (messageIndex !== -1) {
2055
+ queueMessageChunk(conversationId, messageIndex, chunk);
2056
+ return;
2057
+ } else {
2058
+ const newMessage = {
2059
+ id: chunk.messageId,
2060
+ role: "assistant",
2061
+ content: "",
2062
+ timestamp: chunk.timestamp,
2063
+ model: conv.model,
2064
+ chunks: [chunk]
2065
+ };
2066
+ setState("conversations", conversationId, "messages", conv.messages.length, newMessage);
2067
+ return;
2068
+ }
2069
+ }
2070
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2071
+ const message = conv.messages[i];
2072
+ if (message && message.role === "assistant") {
2073
+ queueMessageChunk(conversationId, i, chunk);
2074
+ return;
2075
+ }
2076
+ }
2077
+ addChunk(conversationId, chunk);
2078
+ }
2079
+ function updateMessageUsage(conversationId, messageId, cumulativeUsage) {
2080
+ const conv = state.conversations[conversationId];
2081
+ if (!conv) return;
2082
+ let previousPromptTokens = 0;
2083
+ let previousCompletionTokens = 0;
2084
+ let targetMessageIndex = -1;
2085
+ if (messageId) {
2086
+ targetMessageIndex = conv.messages.findIndex((msg) => msg.id === messageId);
2087
+ } else {
2088
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2089
+ if (conv.messages[i]?.role === "assistant") {
2090
+ targetMessageIndex = i;
2091
+ break;
2092
+ }
2093
+ }
2094
+ }
2095
+ if (targetMessageIndex === -1) return;
2096
+ for (let i = 0; i < targetMessageIndex; i++) {
2097
+ const msg = conv.messages[i];
2098
+ if (msg?.role === "assistant" && msg.usage) {
2099
+ previousPromptTokens += msg.usage.promptTokens;
2100
+ previousCompletionTokens += msg.usage.completionTokens;
2101
+ }
2102
+ }
2103
+ const deltaUsage = {
2104
+ promptTokens: Math.max(0, cumulativeUsage.promptTokens - previousPromptTokens),
2105
+ completionTokens: Math.max(0, cumulativeUsage.completionTokens - previousCompletionTokens),
2106
+ totalTokens: 0
2107
+ };
2108
+ deltaUsage.totalTokens = deltaUsage.promptTokens + deltaUsage.completionTokens;
2109
+ setState("conversations", conversationId, "messages", targetMessageIndex, "usage", deltaUsage);
2110
+ }
2111
+ function clearAllConversations() {
2112
+ setState("conversations", {});
2113
+ setState("activeConversationId", null);
2114
+ streamToConversation.clear();
2115
+ requestToConversation.clear();
2116
+ pendingConversationChunks.clear();
2117
+ pendingMessageChunks.clear();
2118
+ }
2119
+ function selectConversation(id) {
2120
+ setState("activeConversationId", id);
2121
+ }
2122
+ function updateConversation(conversationId, updates) {
2123
+ if (!state.conversations[conversationId]) return;
2124
+ for (const [key, value] of Object.entries(updates)) {
2125
+ setState("conversations", conversationId, key, value);
2126
+ }
2127
+ }
2128
+ function updateMessage(conversationId, messageIndex, updates) {
2129
+ const conv = state.conversations[conversationId];
2130
+ if (!conv || !conv.messages[messageIndex]) return;
2131
+ for (const [key, value] of Object.entries(updates)) {
2132
+ setState("conversations", conversationId, "messages", messageIndex, key, value);
2133
+ }
2134
+ }
2135
+ function updateToolCall(conversationId, messageIndex, toolCallIndex, updates) {
2136
+ const conv = state.conversations[conversationId];
2137
+ if (!conv?.messages[messageIndex]?.toolCalls?.[toolCallIndex]) return;
2138
+ setState("conversations", conversationId, "messages", messageIndex, "toolCalls", toolCallIndex, produce((tc) => Object.assign(tc, updates)));
2139
+ }
2140
+ function setToolCalls(conversationId, messageIndex, toolCalls) {
2141
+ if (!state.conversations[conversationId]?.messages[messageIndex]) return;
2142
+ setState("conversations", conversationId, "messages", messageIndex, "toolCalls", toolCalls);
2143
+ }
2144
+ function addChunk(conversationId, chunk) {
2145
+ if (!state.conversations[conversationId]) return;
2146
+ queueChunk(conversationId, chunk);
2147
+ }
2148
+ function addActivityEvent(conversationId, activity, event) {
2149
+ if (!state.conversations[conversationId]) return;
2150
+ setState("conversations", conversationId, activity, produce((events) => {
2151
+ if (!events) return [event];
2152
+ events.push(event);
2153
+ return events;
2154
+ }));
2155
+ const activityFlagMap = {
2156
+ imageEvents: "hasImage",
2157
+ speechEvents: "hasSpeech",
2158
+ transcriptionEvents: "hasTranscription",
2159
+ videoEvents: "hasVideo"
2160
+ };
2161
+ setState("conversations", conversationId, activityFlagMap[activity], true);
2162
+ }
2163
+ function ensureMessageForChunk(conversationId, messageId, timestamp) {
2164
+ if (!messageId) return;
2165
+ const conv = state.conversations[conversationId];
2166
+ if (!conv || conv.type === "client") return;
2167
+ const existingMessage = conv.messages.find((m) => m.id === messageId);
2168
+ if (existingMessage) return;
2169
+ addMessage(conversationId, {
2170
+ id: messageId,
2171
+ role: "assistant",
2172
+ content: "",
2173
+ timestamp,
2174
+ source: "server"
2175
+ });
2176
+ }
2177
+ onMount(() => {
2178
+ const cleanupFns = [];
2179
+ cleanupFns.push(aiEventClient.on("client:created", (e) => {
2180
+ const clientId = e.payload.clientId;
2181
+ getOrCreateConversation(clientId, "client", `Client Chat (${clientId.substring(0, 8)})`);
2182
+ updateConversation(clientId, {
2183
+ model: void 0,
2184
+ provider: "Client"
2185
+ });
2186
+ }));
2187
+ cleanupFns.push(aiEventClient.on("text:message:created", (e) => {
2188
+ const {
2189
+ clientId,
2190
+ streamId,
2191
+ messageId,
2192
+ role,
2193
+ content,
2194
+ timestamp
2195
+ } = e.payload;
2196
+ const conversationId = clientId || (streamId ? streamToConversation.get(streamId) : void 0);
2197
+ if (!conversationId) return;
2198
+ if (role === "tool" || role === "system") return;
2199
+ if (!state.conversations[conversationId]) {
2200
+ getOrCreateConversation(conversationId, clientId ? "client" : "server", clientId ? `Client Chat (${conversationId.substring(0, 8)})` : `Server Chat (${conversationId.substring(0, 8)})`);
2201
+ }
2202
+ const conv = state.conversations[conversationId];
2203
+ if (!conv) return;
2204
+ const existingIndex = conv.messages.findIndex((message) => message.id === messageId);
2205
+ const parts = e.payload.parts?.map((part) => {
2206
+ if (part.type === "text") {
2207
+ return {
2208
+ type: "text",
2209
+ content: part.content
2210
+ };
2211
+ }
2212
+ if (part.type === "tool-call") {
2213
+ return {
2214
+ type: "tool-call",
2215
+ toolCallId: part.id,
2216
+ toolName: part.name,
2217
+ arguments: part.arguments,
2218
+ state: part.state,
2219
+ output: part.output,
2220
+ content: part.approval ? JSON.stringify(part.approval) : void 0
2221
+ };
2222
+ }
2223
+ if (part.type === "tool-result") {
2224
+ return {
2225
+ type: "tool-result",
2226
+ toolCallId: part.toolCallId,
2227
+ content: part.content,
2228
+ state: part.state,
2229
+ error: part.error
2230
+ };
2231
+ }
2232
+ if (part.type === "thinking") {
2233
+ return {
2234
+ type: "thinking",
2235
+ content: part.content
2236
+ };
2237
+ }
2238
+ if (part.type === "image" || part.type === "audio" || part.type === "video" || // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2239
+ part.type === "document") {
2240
+ return {
2241
+ type: part.type,
2242
+ source: part.source,
2243
+ metadata: part.metadata
2244
+ };
2245
+ }
2246
+ return null;
2247
+ }).filter((part) => part !== null);
2248
+ const toolCalls = e.payload.toolCalls?.map((toolCall) => ({
2249
+ id: toolCall.id,
2250
+ name: toolCall.function.name,
2251
+ arguments: toolCall.function.arguments,
2252
+ state: "input-complete"
2253
+ }));
2254
+ const source = e.payload.source ?? (clientId ? "client" : "server");
2255
+ if (role === "user" && conv.type === "client" && source === "server") {
2256
+ return;
2257
+ }
2258
+ if (role === "assistant" && source === "client" && !content && (!toolCalls || toolCalls.length === 0)) {
2259
+ return;
2260
+ }
2261
+ const messagePayload = {
2262
+ id: messageId,
2263
+ role,
2264
+ content,
2265
+ timestamp,
2266
+ parts,
2267
+ toolCalls,
2268
+ source
2269
+ };
2270
+ if (existingIndex >= 0) {
2271
+ updateMessage(conversationId, existingIndex, messagePayload);
2272
+ } else {
2273
+ addMessage(conversationId, messagePayload);
2274
+ }
2275
+ updateConversation(conversationId, {
2276
+ status: "active",
2277
+ hasChat: true
2278
+ });
2279
+ }));
2280
+ cleanupFns.push(aiEventClient.on("text:message:user", (e) => {
2281
+ const {
2282
+ clientId,
2283
+ streamId,
2284
+ messageId,
2285
+ content,
2286
+ timestamp
2287
+ } = e.payload;
2288
+ const conversationId = clientId || (streamId ? streamToConversation.get(streamId) : void 0);
2289
+ if (!conversationId) return;
2290
+ const conv = state.conversations[conversationId];
2291
+ if (!conv) return;
2292
+ const existingIndex = conv.messages.findIndex((message) => message.id === messageId);
2293
+ if (existingIndex >= 0) return;
2294
+ const source = e.payload.source ?? (clientId ? "client" : "server");
2295
+ if (conv.type === "client" && source === "server") {
2296
+ return;
2297
+ }
2298
+ addMessage(conversationId, {
2299
+ id: messageId,
2300
+ role: "user",
2301
+ content,
2302
+ timestamp,
2303
+ source
2304
+ });
2305
+ }));
2306
+ cleanupFns.push(aiEventClient.on("client:loading:changed", (e) => {
2307
+ const clientId = e.payload.clientId;
2308
+ if (state.conversations[clientId]) {
2309
+ updateConversation(clientId, {
2310
+ status: e.payload.isLoading ? "active" : "completed"
2311
+ });
2312
+ }
2313
+ }));
2314
+ cleanupFns.push(aiEventClient.on("client:stopped", (e) => {
2315
+ const clientId = e.payload.clientId;
2316
+ if (state.conversations[clientId]) {
2317
+ updateConversation(clientId, {
2318
+ status: "completed",
2319
+ completedAt: e.payload.timestamp
2320
+ });
2321
+ }
2322
+ }));
2323
+ cleanupFns.push(aiEventClient.on("client:messages:cleared", (e) => {
2324
+ const clientId = e.payload.clientId;
2325
+ if (state.conversations[clientId]) {
2326
+ updateConversation(clientId, {
2327
+ messages: [],
2328
+ chunks: [],
2329
+ usage: void 0
2330
+ });
2331
+ }
2332
+ }));
2333
+ cleanupFns.push(aiEventClient.on("client:reloaded", (e) => {
2334
+ const clientId = e.payload.clientId;
2335
+ const conv = state.conversations[clientId];
2336
+ if (conv) {
2337
+ updateConversation(clientId, {
2338
+ messages: conv.messages.slice(0, e.payload.fromMessageIndex),
2339
+ status: "active"
2340
+ });
2341
+ }
2342
+ }));
2343
+ cleanupFns.push(aiEventClient.on("client:error:changed", (e) => {
2344
+ const clientId = e.payload.clientId;
2345
+ if (state.conversations[clientId] && e.payload.error) {
2346
+ updateConversation(clientId, {
2347
+ status: "error"
2348
+ });
2349
+ }
2350
+ }));
2351
+ cleanupFns.push(aiEventClient.on("tools:result:added", (e) => {
2352
+ const {
2353
+ clientId,
2354
+ toolCallId,
2355
+ toolName,
2356
+ output,
2357
+ state: resultState,
2358
+ timestamp
2359
+ } = e.payload;
2360
+ if (!clientId) return;
2361
+ if (!state.conversations[clientId]) return;
2362
+ const conv = state.conversations[clientId];
2363
+ const chunk = {
2364
+ id: `chunk-tool-result-${toolCallId}-${Date.now()}`,
2365
+ type: "tool_result",
2366
+ toolCallId,
2367
+ toolName,
2368
+ result: output,
2369
+ timestamp,
2370
+ chunkCount: 1,
2371
+ isClientTool: true
2372
+ };
2373
+ for (let messageIndex = conv.messages.length - 1; messageIndex >= 0; messageIndex--) {
2374
+ const message = conv.messages[messageIndex];
2375
+ if (!message?.toolCalls) continue;
2376
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
2377
+ if (toolCallIndex >= 0) {
2378
+ updateToolCall(clientId, messageIndex, toolCallIndex, {
2379
+ result: output,
2380
+ state: resultState === "output-error" ? "error" : "complete"
2381
+ });
2382
+ chunk.messageId = message.id;
2383
+ addChunkToMessage(clientId, chunk);
2384
+ return;
2385
+ }
2386
+ }
2387
+ addChunkToMessage(clientId, chunk);
2388
+ }));
2389
+ cleanupFns.push(aiEventClient.on("tools:approval:responded", (e) => {
2390
+ const {
2391
+ clientId,
2392
+ toolCallId,
2393
+ approved
2394
+ } = e.payload;
2395
+ if (!clientId) return;
2396
+ if (!state.conversations[clientId]) return;
2397
+ const conv = state.conversations[clientId];
2398
+ for (let messageIndex = conv.messages.length - 1; messageIndex >= 0; messageIndex--) {
2399
+ const message = conv.messages[messageIndex];
2400
+ if (!message?.toolCalls) continue;
2401
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
2402
+ if (toolCallIndex >= 0) {
2403
+ updateToolCall(clientId, messageIndex, toolCallIndex, {
2404
+ state: approved ? "approved" : "denied",
2405
+ approvalRequired: false
2406
+ });
2407
+ return;
2408
+ }
2409
+ }
2410
+ }));
2411
+ cleanupFns.push(aiEventClient.on("tools:call:updated", (e) => {
2412
+ const {
2413
+ clientId,
2414
+ streamId,
2415
+ messageId,
2416
+ toolCallId,
2417
+ toolName,
2418
+ state: toolCallState,
2419
+ arguments: args
2420
+ } = e.payload;
2421
+ const conversationId = clientId || (streamId ? streamToConversation.get(streamId) : void 0);
2422
+ if (!conversationId || !state.conversations[conversationId]) return;
2423
+ const conv = state.conversations[conversationId];
2424
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
2425
+ if (messageIndex === -1) return;
2426
+ const message = conv.messages[messageIndex];
2427
+ if (!message) return;
2428
+ const toolCalls = message.toolCalls || [];
2429
+ const existingToolIndex = toolCalls.findIndex((t) => t.id === toolCallId);
2430
+ const toolCall = {
2431
+ id: toolCallId,
2432
+ name: toolName,
2433
+ arguments: args,
2434
+ state: toolCallState
2435
+ };
2436
+ if (existingToolIndex >= 0) {
2437
+ updateToolCall(conversationId, messageIndex, existingToolIndex, toolCall);
2438
+ } else {
2439
+ setToolCalls(conversationId, messageIndex, [...toolCalls, toolCall]);
2440
+ }
2441
+ }));
2442
+ cleanupFns.push(aiEventClient.on("tools:input:available", (e) => {
2443
+ const {
2444
+ streamId,
2445
+ messageId,
2446
+ toolCallId,
2447
+ toolName,
2448
+ input,
2449
+ timestamp,
2450
+ clientId
2451
+ } = e.payload;
2452
+ const conversationId = clientId || (streamId ? streamToConversation.get(streamId) : void 0);
2453
+ if (!conversationId) return;
2454
+ const chunk = {
2455
+ id: `chunk-${Date.now()}-${Math.random()}`,
2456
+ type: "tool_call",
2457
+ messageId,
2458
+ toolCallId,
2459
+ toolName,
2460
+ arguments: JSON.stringify(input),
2461
+ timestamp,
2462
+ chunkCount: 1
2463
+ };
2464
+ const conv = state.conversations[conversationId];
2465
+ if (conv?.type === "client") {
2466
+ addChunkToMessage(conversationId, chunk);
2467
+ } else {
2468
+ addChunk(conversationId, chunk);
2469
+ }
2470
+ }));
2471
+ cleanupFns.push(aiEventClient.on("tools:call:completed", (e) => {
2472
+ const {
2473
+ streamId,
2474
+ toolCallId,
2475
+ toolName,
2476
+ result,
2477
+ duration,
2478
+ messageId,
2479
+ timestamp,
2480
+ clientId
2481
+ } = e.payload;
2482
+ const conversationId = clientId || (streamId ? streamToConversation.get(streamId) : void 0);
2483
+ if (!conversationId || !state.conversations[conversationId]) return;
2484
+ const conv = state.conversations[conversationId];
2485
+ const chunk = {
2486
+ id: `chunk-tool-result-${toolCallId}-${Date.now()}`,
2487
+ type: "tool_result",
2488
+ messageId,
2489
+ toolCallId,
2490
+ toolName,
2491
+ result,
2492
+ duration,
2493
+ timestamp,
2494
+ chunkCount: 1
2495
+ };
2496
+ if (conv.type === "client" && messageId) {
2497
+ const messageIndex = conv.messages.findIndex((m) => m.id === messageId);
2498
+ if (messageIndex !== -1) {
2499
+ queueMessageChunk(conversationId, messageIndex, chunk);
2500
+ } else {
2501
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2502
+ if (conv.messages[i]?.role === "assistant") {
2503
+ queueMessageChunk(conversationId, i, chunk);
2504
+ break;
2505
+ }
2506
+ }
2507
+ }
2508
+ } else {
2509
+ addChunk(conversationId, chunk);
2510
+ }
2511
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2512
+ const message = conv.messages[i];
2513
+ if (!message?.toolCalls) continue;
2514
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
2515
+ if (toolCallIndex >= 0) {
2516
+ updateToolCall(conversationId, i, toolCallIndex, {
2517
+ duration,
2518
+ result
2519
+ });
2520
+ return;
2521
+ }
2522
+ }
2523
+ }));
2524
+ cleanupFns.push(aiEventClient.on("text:chunk:content", (e) => {
2525
+ const streamId = e.payload.streamId;
2526
+ const conversationId = streamToConversation.get(streamId);
2527
+ if (!conversationId) return;
2528
+ const chunk = {
2529
+ id: `chunk-${Date.now()}-${Math.random()}`,
2530
+ type: "content",
2531
+ messageId: e.payload.messageId,
2532
+ content: e.payload.content,
2533
+ delta: e.payload.delta,
2534
+ timestamp: e.payload.timestamp,
2535
+ chunkCount: 1
2536
+ };
2537
+ const conv = state.conversations[conversationId];
2538
+ if (conv?.type === "client") {
2539
+ addChunkToMessage(conversationId, chunk);
2540
+ } else {
2541
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2542
+ addChunk(conversationId, chunk);
2543
+ }
2544
+ if (e.payload.messageId) {
2545
+ const messageIndex = conv?.messages.findIndex((msg) => msg.id === e.payload.messageId);
2546
+ if (messageIndex !== void 0 && messageIndex >= 0) {
2547
+ updateMessage(conversationId, messageIndex, {
2548
+ content: e.payload.content
2549
+ });
2550
+ }
2551
+ }
2552
+ }));
2553
+ cleanupFns.push(aiEventClient.on("text:chunk:tool-call", (e) => {
2554
+ const streamId = e.payload.streamId;
2555
+ const conversationId = streamToConversation.get(streamId);
2556
+ if (!conversationId) return;
2557
+ const chunk = {
2558
+ id: `chunk-${Date.now()}-${Math.random()}`,
2559
+ type: "tool_call",
2560
+ messageId: e.payload.messageId,
2561
+ toolCallId: e.payload.toolCallId,
2562
+ toolName: e.payload.toolName,
2563
+ arguments: e.payload.arguments,
2564
+ timestamp: e.payload.timestamp,
2565
+ chunkCount: 1
2566
+ };
2567
+ const conv = state.conversations[conversationId];
2568
+ if (conv?.type === "client") {
2569
+ addChunkToMessage(conversationId, chunk);
2570
+ } else {
2571
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2572
+ addChunk(conversationId, chunk);
2573
+ }
2574
+ if (e.payload.messageId) {
2575
+ const messageIndex = conv?.messages.findIndex((msg) => msg.id === e.payload.messageId);
2576
+ if (messageIndex !== void 0 && messageIndex >= 0) {
2577
+ const message = conv?.messages[messageIndex];
2578
+ if (!message) return;
2579
+ const toolCalls = message.toolCalls || [];
2580
+ const existingToolIndex = toolCalls.findIndex((t) => t.id === e.payload.toolCallId);
2581
+ const toolCall = {
2582
+ id: e.payload.toolCallId,
2583
+ name: e.payload.toolName,
2584
+ arguments: e.payload.arguments,
2585
+ state: "input-streaming"
2586
+ };
2587
+ if (existingToolIndex >= 0) {
2588
+ updateToolCall(conversationId, messageIndex, existingToolIndex, toolCall);
2589
+ } else {
2590
+ setToolCalls(conversationId, messageIndex, [...toolCalls, toolCall]);
2591
+ }
2592
+ }
2593
+ }
2594
+ }));
2595
+ cleanupFns.push(aiEventClient.on("text:chunk:tool-result", (e) => {
2596
+ const streamId = e.payload.streamId;
2597
+ const conversationId = streamToConversation.get(streamId);
2598
+ if (!conversationId) return;
2599
+ const chunk = {
2600
+ id: `chunk-${Date.now()}-${Math.random()}`,
2601
+ type: "tool_result",
2602
+ messageId: e.payload.messageId,
2603
+ toolCallId: e.payload.toolCallId,
2604
+ result: e.payload.result,
2605
+ timestamp: e.payload.timestamp,
2606
+ chunkCount: 1
2607
+ };
2608
+ const conv = state.conversations[conversationId];
2609
+ if (conv?.type === "client") {
2610
+ addChunkToMessage(conversationId, chunk);
2611
+ } else {
2612
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2613
+ addChunk(conversationId, chunk);
2614
+ }
2615
+ if (conv && e.payload.toolCallId) {
2616
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2617
+ const message = conv.messages[i];
2618
+ if (!message?.toolCalls) continue;
2619
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === e.payload.toolCallId);
2620
+ if (toolCallIndex >= 0) {
2621
+ updateToolCall(conversationId, i, toolCallIndex, {
2622
+ result: e.payload.result,
2623
+ state: "complete"
2624
+ });
2625
+ break;
2626
+ }
2627
+ }
2628
+ }
2629
+ }));
2630
+ cleanupFns.push(aiEventClient.on("text:chunk:thinking", (e) => {
2631
+ const streamId = e.payload.streamId;
2632
+ const conversationId = streamToConversation.get(streamId);
2633
+ if (!conversationId) return;
2634
+ const chunk = {
2635
+ id: `chunk-${Date.now()}-${Math.random()}`,
2636
+ type: "thinking",
2637
+ messageId: e.payload.messageId,
2638
+ content: e.payload.content,
2639
+ delta: e.payload.delta,
2640
+ timestamp: e.payload.timestamp,
2641
+ chunkCount: 1
2642
+ };
2643
+ const conv = state.conversations[conversationId];
2644
+ if (conv?.type === "client") {
2645
+ addChunkToMessage(conversationId, chunk);
2646
+ if (e.payload.messageId) {
2647
+ const messageIndex = conv.messages.findIndex((msg) => msg.id === e.payload.messageId);
2648
+ if (messageIndex !== -1) {
2649
+ updateMessage(conversationId, messageIndex, {
2650
+ thinkingContent: e.payload.content
2651
+ });
2652
+ }
2653
+ }
2654
+ } else {
2655
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2656
+ addChunk(conversationId, chunk);
2657
+ }
2658
+ }));
2659
+ cleanupFns.push(aiEventClient.on("text:chunk:done", (e) => {
2660
+ const streamId = e.payload.streamId;
2661
+ const conversationId = streamToConversation.get(streamId);
2662
+ if (!conversationId) return;
2663
+ const chunk = {
2664
+ id: `chunk-${Date.now()}-${Math.random()}`,
2665
+ type: "done",
2666
+ messageId: e.payload.messageId,
2667
+ finishReason: e.payload.finishReason || void 0,
2668
+ timestamp: e.payload.timestamp,
2669
+ chunkCount: 1
2670
+ };
2671
+ if (e.payload.usage) {
2672
+ updateConversation(conversationId, {
2673
+ usage: e.payload.usage
2674
+ });
2675
+ updateMessageUsage(conversationId, e.payload.messageId, e.payload.usage);
2676
+ }
2677
+ const conv = state.conversations[conversationId];
2678
+ if (conv?.type === "client") {
2679
+ addChunkToMessage(conversationId, chunk);
2680
+ } else {
2681
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2682
+ addChunk(conversationId, chunk);
2683
+ }
2684
+ updateConversation(conversationId, {
2685
+ status: "completed",
2686
+ completedAt: e.payload.timestamp
2687
+ });
2688
+ }));
2689
+ cleanupFns.push(aiEventClient.on("text:chunk:error", (e) => {
2690
+ const streamId = e.payload.streamId;
2691
+ const conversationId = streamToConversation.get(streamId);
2692
+ if (!conversationId) return;
2693
+ const chunk = {
2694
+ id: `chunk-${Date.now()}-${Math.random()}`,
2695
+ type: "error",
2696
+ messageId: e.payload.messageId,
2697
+ error: e.payload.error,
2698
+ timestamp: e.payload.timestamp,
2699
+ chunkCount: 1
2700
+ };
2701
+ const conv = state.conversations[conversationId];
2702
+ if (conv?.type === "client") {
2703
+ addChunkToMessage(conversationId, chunk);
2704
+ } else {
2705
+ ensureMessageForChunk(conversationId, e.payload.messageId, e.payload.timestamp);
2706
+ addChunk(conversationId, chunk);
2707
+ }
2708
+ updateConversation(conversationId, {
2709
+ status: "error",
2710
+ completedAt: e.payload.timestamp
2711
+ });
2712
+ }));
2713
+ cleanupFns.push(aiEventClient.on("tools:approval:requested", (e) => {
2714
+ const {
2715
+ streamId,
2716
+ messageId,
2717
+ toolCallId,
2718
+ toolName,
2719
+ input,
2720
+ approvalId,
2721
+ timestamp,
2722
+ clientId
2723
+ } = e.payload;
2724
+ const conversationId = clientId || streamToConversation.get(streamId) || "";
2725
+ if (!conversationId) return;
2726
+ const conv = state.conversations[conversationId];
2727
+ if (!conv) return;
2728
+ const chunk = {
2729
+ id: `chunk-${Date.now()}-${Math.random()}`,
2730
+ type: "approval",
2731
+ messageId,
2732
+ toolCallId,
2733
+ toolName,
2734
+ approvalId,
2735
+ input,
2736
+ timestamp,
2737
+ chunkCount: 1
2738
+ };
2739
+ if (conv.type === "client") {
2740
+ addChunkToMessage(conversationId, chunk);
2741
+ } else {
2742
+ addChunk(conversationId, chunk);
2743
+ }
2744
+ for (let i = conv.messages.length - 1; i >= 0; i--) {
2745
+ const message = conv.messages[i];
2746
+ if (!message) continue;
2747
+ if (message.role === "assistant" && message.toolCalls) {
2748
+ const toolCallIndex = message.toolCalls.findIndex((t) => t.id === toolCallId);
2749
+ if (toolCallIndex >= 0) {
2750
+ updateToolCall(conversationId, i, toolCallIndex, {
2751
+ approvalRequired: true,
2752
+ approvalId,
2753
+ state: "approval-requested"
2754
+ });
2755
+ return;
2756
+ }
2757
+ }
2758
+ }
2759
+ }));
2760
+ cleanupFns.push(aiEventClient.on("text:request:started", (e) => {
2761
+ const streamId = e.payload.streamId;
2762
+ const model = e.payload.model;
2763
+ e.payload.provider;
2764
+ const clientId = e.payload.clientId;
2765
+ if (clientId && state.conversations[clientId]) {
2766
+ streamToConversation.set(streamId, clientId);
2767
+ requestToConversation.set(e.payload.requestId, clientId);
2768
+ updateConversation(clientId, {
2769
+ status: "active",
2770
+ ...e.payload,
2771
+ systemPrompts: e.payload.systemPrompts,
2772
+ hasChat: true
2773
+ });
2774
+ return;
2775
+ }
2776
+ const activeClient = Object.values(state.conversations).find((c) => c.type === "client" && c.status === "active" && !c.model);
2777
+ if (activeClient) {
2778
+ streamToConversation.set(streamId, activeClient.id);
2779
+ requestToConversation.set(e.payload.requestId, activeClient.id);
2780
+ updateConversation(activeClient.id, {
2781
+ ...e.payload,
2782
+ systemPrompts: e.payload.systemPrompts,
2783
+ hasChat: true
2784
+ });
2785
+ } else {
2786
+ const existingServerConv = Object.values(state.conversations).find((c) => c.type === "server" && c.model === model);
2787
+ if (existingServerConv) {
2788
+ streamToConversation.set(streamId, existingServerConv.id);
2789
+ requestToConversation.set(e.payload.requestId, existingServerConv.id);
2790
+ updateConversation(existingServerConv.id, {
2791
+ status: "active",
2792
+ ...e.payload,
2793
+ systemPrompts: e.payload.systemPrompts,
2794
+ hasChat: true
2795
+ });
2796
+ } else {
2797
+ const serverId = `server-${model}`;
2798
+ getOrCreateConversation(serverId, "server", `${model} Server`);
2799
+ streamToConversation.set(streamId, serverId);
2800
+ requestToConversation.set(e.payload.requestId, serverId);
2801
+ updateConversation(serverId, {
2802
+ ...e.payload,
2803
+ systemPrompts: e.payload.systemPrompts,
2804
+ hasChat: true
2805
+ });
2806
+ }
2807
+ }
2808
+ }));
2809
+ cleanupFns.push(aiEventClient.on("text:request:completed", (e) => {
2810
+ const {
2811
+ requestId,
2812
+ usage
2813
+ } = e.payload;
2814
+ const conversationId = requestToConversation.get(requestId);
2815
+ if (conversationId && state.conversations[conversationId]) {
2816
+ const updates = {
2817
+ status: "completed",
2818
+ completedAt: e.payload.timestamp
2819
+ };
2820
+ if (usage) {
2821
+ updates.usage = usage;
2822
+ }
2823
+ updateConversation(conversationId, updates);
2824
+ if (usage) {
2825
+ updateMessageUsage(conversationId, e.payload.messageId, usage);
2826
+ }
2827
+ }
2828
+ }));
2829
+ cleanupFns.push(aiEventClient.on("text:usage", (e) => {
2830
+ const {
2831
+ requestId,
2832
+ usage,
2833
+ messageId
2834
+ } = e.payload;
2835
+ const conversationId = requestToConversation.get(requestId);
2836
+ if (conversationId && state.conversations[conversationId]) {
2837
+ updateConversation(conversationId, {
2838
+ usage
2839
+ });
2840
+ updateMessageUsage(conversationId, messageId, usage);
2841
+ }
2842
+ }));
2843
+ cleanupFns.push(aiEventClient.on("summarize:request:started", (e) => {
2844
+ const {
2845
+ requestId,
2846
+ model,
2847
+ inputLength,
2848
+ timestamp,
2849
+ clientId
2850
+ } = e.payload;
2851
+ let conversationId = clientId;
2852
+ if (!conversationId || !state.conversations[conversationId]) {
2853
+ const activeClients = Object.values(state.conversations).filter((c) => c.type === "client" && c.status === "active").sort((a, b) => b.startedAt - a.startedAt);
2854
+ if (activeClients.length > 0 && activeClients[0]) {
2855
+ conversationId = activeClients[0].id;
2856
+ } else {
2857
+ conversationId = `summarize-${requestId}`;
2858
+ getOrCreateConversation(conversationId, "server", `Summarize (${model})`);
2859
+ updateConversation(conversationId, {
2860
+ model
2861
+ });
2862
+ }
2863
+ }
2864
+ requestToConversation.set(requestId, conversationId);
2865
+ const summarizeOp = {
2866
+ id: requestId,
2867
+ model,
2868
+ inputLength,
2869
+ timestamp,
2870
+ status: "started"
2871
+ };
2872
+ const conv = state.conversations[conversationId];
2873
+ if (conv) {
2874
+ const summaries = conv.summaries || [];
2875
+ setState("conversations", conversationId, "summaries", [...summaries, summarizeOp]);
2876
+ setState("conversations", conversationId, "hasSummarize", true);
2877
+ }
2878
+ }));
2879
+ cleanupFns.push(aiEventClient.on("summarize:request:completed", (e) => {
2880
+ const {
2881
+ requestId,
2882
+ outputLength,
2883
+ duration
2884
+ } = e.payload;
2885
+ const conversationId = requestToConversation.get(requestId);
2886
+ if (!conversationId || !state.conversations[conversationId]) return;
2887
+ const conv = state.conversations[conversationId];
2888
+ if (!conv.summaries) return;
2889
+ const summaryIndex = conv.summaries.findIndex((op) => op.id === requestId);
2890
+ if (summaryIndex >= 0) {
2891
+ setState("conversations", conversationId, "summaries", summaryIndex, produce((op) => {
2892
+ op.duration = duration;
2893
+ op.outputLength = outputLength;
2894
+ op.status = "completed";
2895
+ }));
2896
+ }
2897
+ }));
2898
+ cleanupFns.push(aiEventClient.on("image:request:started", (e) => {
2899
+ const {
2900
+ requestId,
2901
+ clientId,
2902
+ timestamp
2903
+ } = e.payload;
2904
+ let conversationId = clientId;
2905
+ if (!conversationId || !state.conversations[conversationId]) {
2906
+ conversationId = `image-${requestId}`;
2907
+ getOrCreateConversation(conversationId, "server", `Image (${requestId.substring(0, 8)})`);
2908
+ }
2909
+ addActivityEvent(conversationId, "imageEvents", {
2910
+ id: requestId,
2911
+ name: "image:request:started",
2912
+ timestamp,
2913
+ payload: e.payload
2914
+ });
2915
+ }));
2916
+ cleanupFns.push(aiEventClient.on("image:request:completed", (e) => {
2917
+ const {
2918
+ requestId,
2919
+ clientId,
2920
+ timestamp
2921
+ } = e.payload;
2922
+ let conversationId = clientId;
2923
+ if (!conversationId || !state.conversations[conversationId]) {
2924
+ conversationId = `image-${requestId}`;
2925
+ getOrCreateConversation(conversationId, "server", `Image (${requestId.substring(0, 8)})`);
2926
+ }
2927
+ addActivityEvent(conversationId, "imageEvents", {
2928
+ id: requestId,
2929
+ name: "image:request:completed",
2930
+ timestamp,
2931
+ payload: e.payload
2932
+ });
2933
+ }));
2934
+ cleanupFns.push(aiEventClient.on("image:usage", (e) => {
2935
+ const {
2936
+ requestId,
2937
+ clientId,
2938
+ timestamp
2939
+ } = e.payload;
2940
+ let conversationId = clientId;
2941
+ if (!conversationId || !state.conversations[conversationId]) {
2942
+ conversationId = `image-${requestId}`;
2943
+ getOrCreateConversation(conversationId, "server", `Image (${requestId.substring(0, 8)})`);
2944
+ }
2945
+ addActivityEvent(conversationId, "imageEvents", {
2946
+ id: requestId,
2947
+ name: "image:usage",
2948
+ timestamp,
2949
+ payload: e.payload
2950
+ });
2951
+ }));
2952
+ cleanupFns.push(aiEventClient.on("speech:request:started", (e) => {
2953
+ const {
2954
+ requestId,
2955
+ clientId,
2956
+ timestamp
2957
+ } = e.payload;
2958
+ let conversationId = clientId;
2959
+ if (!conversationId || !state.conversations[conversationId]) {
2960
+ conversationId = `speech-${requestId}`;
2961
+ getOrCreateConversation(conversationId, "server", `Speech (${requestId.substring(0, 8)})`);
2962
+ }
2963
+ addActivityEvent(conversationId, "speechEvents", {
2964
+ id: requestId,
2965
+ name: "speech:request:started",
2966
+ timestamp,
2967
+ payload: e.payload
2968
+ });
2969
+ }));
2970
+ cleanupFns.push(aiEventClient.on("speech:request:completed", (e) => {
2971
+ const {
2972
+ requestId,
2973
+ clientId,
2974
+ timestamp
2975
+ } = e.payload;
2976
+ let conversationId = clientId;
2977
+ if (!conversationId || !state.conversations[conversationId]) {
2978
+ conversationId = `speech-${requestId}`;
2979
+ getOrCreateConversation(conversationId, "server", `Speech (${requestId.substring(0, 8)})`);
2980
+ }
2981
+ addActivityEvent(conversationId, "speechEvents", {
2982
+ id: requestId,
2983
+ name: "speech:request:completed",
2984
+ timestamp,
2985
+ payload: e.payload
2986
+ });
2987
+ }));
2988
+ cleanupFns.push(aiEventClient.on("speech:usage", (e) => {
2989
+ const {
2990
+ requestId,
2991
+ clientId,
2992
+ timestamp
2993
+ } = e.payload;
2994
+ let conversationId = clientId;
2995
+ if (!conversationId || !state.conversations[conversationId]) {
2996
+ conversationId = `speech-${requestId}`;
2997
+ getOrCreateConversation(conversationId, "server", `Speech (${requestId.substring(0, 8)})`);
2998
+ }
2999
+ addActivityEvent(conversationId, "speechEvents", {
3000
+ id: requestId,
3001
+ name: "speech:usage",
3002
+ timestamp,
3003
+ payload: e.payload
3004
+ });
3005
+ }));
3006
+ cleanupFns.push(aiEventClient.on("transcription:request:started", (e) => {
3007
+ const {
3008
+ requestId,
3009
+ clientId,
3010
+ timestamp
3011
+ } = e.payload;
3012
+ let conversationId = clientId;
3013
+ if (!conversationId || !state.conversations[conversationId]) {
3014
+ conversationId = `transcription-${requestId}`;
3015
+ getOrCreateConversation(conversationId, "server", `Transcription (${requestId.substring(0, 8)})`);
3016
+ }
3017
+ addActivityEvent(conversationId, "transcriptionEvents", {
3018
+ id: requestId,
3019
+ name: "transcription:request:started",
3020
+ timestamp,
3021
+ payload: e.payload
3022
+ });
3023
+ }));
3024
+ cleanupFns.push(aiEventClient.on("transcription:request:completed", (e) => {
3025
+ const {
3026
+ requestId,
3027
+ clientId,
3028
+ timestamp
3029
+ } = e.payload;
3030
+ let conversationId = clientId;
3031
+ if (!conversationId || !state.conversations[conversationId]) {
3032
+ conversationId = `transcription-${requestId}`;
3033
+ getOrCreateConversation(conversationId, "server", `Transcription (${requestId.substring(0, 8)})`);
3034
+ }
3035
+ addActivityEvent(conversationId, "transcriptionEvents", {
3036
+ id: requestId,
3037
+ name: "transcription:request:completed",
3038
+ timestamp,
3039
+ payload: e.payload
3040
+ });
3041
+ }));
3042
+ cleanupFns.push(aiEventClient.on("transcription:usage", (e) => {
3043
+ const {
3044
+ requestId,
3045
+ clientId,
3046
+ timestamp
3047
+ } = e.payload;
3048
+ let conversationId = clientId;
3049
+ if (!conversationId || !state.conversations[conversationId]) {
3050
+ conversationId = `transcription-${requestId}`;
3051
+ getOrCreateConversation(conversationId, "server", `Transcription (${requestId.substring(0, 8)})`);
3052
+ }
3053
+ addActivityEvent(conversationId, "transcriptionEvents", {
3054
+ id: requestId,
3055
+ name: "transcription:usage",
3056
+ timestamp,
3057
+ payload: e.payload
3058
+ });
3059
+ }));
3060
+ cleanupFns.push(aiEventClient.on("video:request:started", (e) => {
3061
+ const {
3062
+ requestId,
3063
+ clientId,
3064
+ timestamp
3065
+ } = e.payload;
3066
+ let conversationId = clientId;
3067
+ if (!conversationId || !state.conversations[conversationId]) {
3068
+ conversationId = `video-${requestId}`;
3069
+ getOrCreateConversation(conversationId, "server", `Video (${requestId.substring(0, 8)})`);
3070
+ }
3071
+ addActivityEvent(conversationId, "videoEvents", {
3072
+ id: requestId,
3073
+ name: "video:request:started",
3074
+ timestamp,
3075
+ payload: e.payload
3076
+ });
3077
+ }));
3078
+ cleanupFns.push(aiEventClient.on("video:request:completed", (e) => {
3079
+ const {
3080
+ requestId,
3081
+ clientId,
3082
+ timestamp
3083
+ } = e.payload;
3084
+ let conversationId = clientId;
3085
+ if (!conversationId || !state.conversations[conversationId]) {
3086
+ conversationId = `video-${requestId}`;
3087
+ getOrCreateConversation(conversationId, "server", `Video (${requestId.substring(0, 8)})`);
3088
+ }
3089
+ addActivityEvent(conversationId, "videoEvents", {
3090
+ id: requestId,
3091
+ name: "video:request:completed",
3092
+ timestamp,
3093
+ payload: e.payload
3094
+ });
3095
+ }));
3096
+ cleanupFns.push(aiEventClient.on("video:usage", (e) => {
3097
+ const {
3098
+ requestId,
3099
+ clientId,
3100
+ timestamp
3101
+ } = e.payload;
3102
+ let conversationId = clientId;
3103
+ if (!conversationId || !state.conversations[conversationId]) {
3104
+ conversationId = `video-${requestId}`;
3105
+ getOrCreateConversation(conversationId, "server", `Video (${requestId.substring(0, 8)})`);
3106
+ }
3107
+ addActivityEvent(conversationId, "videoEvents", {
3108
+ id: requestId,
3109
+ name: "video:usage",
3110
+ timestamp,
3111
+ payload: e.payload
3112
+ });
3113
+ }));
3114
+ onCleanup(() => {
3115
+ for (const cleanup of cleanupFns) {
3116
+ cleanup();
3117
+ }
3118
+ streamToConversation.clear();
3119
+ requestToConversation.clear();
3120
+ });
3121
+ });
3122
+ const contextValue = {
3123
+ state,
3124
+ clearAllConversations,
3125
+ selectConversation
3126
+ };
3127
+ return createComponent(AIContext.Provider, {
3128
+ value: contextValue,
3129
+ get children() {
3130
+ return props.children;
3131
+ }
3132
+ });
3133
+ };
3134
+
3135
+ // src/components/utils/format.ts
3136
+ var formatTimestamp = (timestamp) => {
3137
+ const date = new Date(timestamp);
3138
+ return date.toLocaleTimeString() + "." + date.getMilliseconds().toString().padStart(3, "0");
3139
+ };
3140
+ var formatDuration = (ms) => {
3141
+ if (!ms) return "-";
3142
+ if (ms < 1e3) return `${ms}ms`;
3143
+ return `${(ms / 1e3).toFixed(2)}s`;
3144
+ };
3145
+ var getChunkTypeColor = (type) => {
3146
+ switch (type) {
3147
+ case "content":
3148
+ return "#10b981";
3149
+ // green
3150
+ case "tool_call":
3151
+ return "#8b5cf6";
3152
+ // purple
3153
+ case "tool_result":
3154
+ return "#3b82f6";
3155
+ // blue
3156
+ case "done":
3157
+ return "#6b7280";
3158
+ // gray
3159
+ case "error":
3160
+ return "#ef4444";
3161
+ // red
3162
+ case "approval":
3163
+ return "#f59e0b";
3164
+ // orange/amber
3165
+ default:
3166
+ return "#6b7280";
3167
+ }
3168
+ };
3169
+ var getStatusColor = (status) => {
3170
+ switch (status) {
3171
+ case "active":
3172
+ return "oklch(0.7 0.17 142)";
3173
+ // green
3174
+ case "completed":
3175
+ return "oklch(0.65 0.1 260)";
3176
+ // blue
3177
+ case "error":
3178
+ return "oklch(0.65 0.2 25)";
3179
+ // red
3180
+ default:
3181
+ return "oklch(0.6 0.05 200)";
3182
+ }
3183
+ };
3184
+ var getTypeColor = (type) => {
3185
+ switch (type) {
3186
+ case "client":
3187
+ return "oklch(0.68 0.16 330)";
3188
+ // pink
3189
+ case "server":
3190
+ return "oklch(0.68 0.15 280)";
3191
+ // purple
3192
+ default:
3193
+ return "oklch(0.6 0.05 200)";
3194
+ }
3195
+ };
3196
+
3197
+ // src/components/list/ConversationRow.tsx
3198
+ var _tmpl$ = ["<div", ' title="', '">\u{1F527} ', "</div>"];
3199
+ var _tmpl$2 = ["<div", ">\u27F3</div>"];
3200
+ var _tmpl$3 = ["<div", ' title="', '">\u{1F3AF} ', "</div>"];
3201
+ var _tmpl$4 = ['<div class="', '"><div', "><div", "><div", "><div", ' style="', '"></div><div', ">", "</div>", "</div><div", ">", "<div", ' style="', '"></div></div></div><div', "><div", ">\u{1F4AC} ", "</div><div", ">\u{1F4E6} ", "</div>", "</div></div></div>"];
3202
+ var ConversationRow = (props) => {
3203
+ const {
3204
+ state,
3205
+ selectConversation
3206
+ } = useAIStore();
3207
+ const styles = useStyles();
3208
+ const conv = () => props.conversation;
3209
+ const hasToolCalls = () => {
3210
+ return conv().messages.some((msg) => msg.toolCalls && msg.toolCalls.length > 0);
3211
+ };
3212
+ const countToolCalls = () => {
3213
+ return conv().messages.reduce((total, msg) => {
3214
+ return total + (msg.toolCalls?.length || 0);
3215
+ }, 0);
3216
+ };
3217
+ const totalRawChunks = () => {
3218
+ return conv().chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
3219
+ };
3220
+ return ssr(_tmpl$4, `${escape(styles().utilRow, true)} ${state.activeConversationId === conv().id ? escape(styles().utilRowSelected, true) : ""}`, ssrAttribute("class", escape(styles().conversationsList.rowMain, true), false), ssrAttribute("class", escape(styles().conversationsList.rowTop, true), false), ssrAttribute("class", escape(styles().conversationsList.rowInfo, true), false), ssrAttribute("class", escape(styles().conversationsList.typeDot, true), false), ssrStyleProperty("background:", escape(getTypeColor(conv().type), true)), ssrAttribute("class", escape(styles().conversationsList.label, true), false), escape(conv().label), escape(createComponent(Show, {
3221
+ get when() {
3222
+ return hasToolCalls();
3223
+ },
3224
+ get children() {
3225
+ return ssr(_tmpl$, ssrAttribute("class", escape(styles().conversationsList.toolCallsBadge, true), false), `${escape(countToolCalls(), true)} tool call${countToolCalls() !== 1 ? "s" : ""}`, escape(countToolCalls()));
3226
+ }
3227
+ })), ssrAttribute("class", escape(styles().conversationsList.rowRight, true), false), escape(createComponent(Show, {
3228
+ get when() {
3229
+ return conv().status === "active";
3230
+ },
3231
+ get children() {
3232
+ return ssr(_tmpl$2, ssrAttribute("class", escape(styles().conversationsList.loadingIndicator, true), false));
3233
+ }
3234
+ })), ssrAttribute("class", escape(styles().conversationsList.statusDot, true), false), ssrStyleProperty("background:", escape(getStatusColor(conv().status), true)), ssrAttribute("class", escape(styles().conversationsList.stats, true), false), ssrAttribute("class", escape(styles().conversationsList.statItem, true), false), escape(conv().messages.length), ssrAttribute("class", escape(styles().conversationsList.statItem, true), false), escape(totalRawChunks()), escape(createComponent(Show, {
3235
+ get when() {
3236
+ return conv().usage;
3237
+ },
3238
+ get children() {
3239
+ return ssr(_tmpl$3, ssrAttribute("class", escape(styles().conversationsList.tokensBadge, true), false), `Prompt: ${escape(conv().usage?.promptTokens, true) || 0} | Completion: ${escape(conv().usage?.completionTokens, true) || 0}`, escape(conv().usage?.totalTokens.toLocaleString()) || 0);
3240
+ }
3241
+ })));
3242
+ };
3243
+
3244
+ // src/components/ConversationsList.tsx
3245
+ var _tmpl$5 = ["<div", ">", "</div>"];
3246
+ var ConversationsList = () => {
3247
+ const {
3248
+ state
3249
+ } = useAIStore();
3250
+ const styles = useStyles();
3251
+ const conversations = () => Object.values(state.conversations);
3252
+ return ssr(_tmpl$5, ssrAttribute("class", escape(styles().utilList, true), false), escape(createComponent(For, {
3253
+ get each() {
3254
+ return conversations();
3255
+ },
3256
+ children: (conv) => createComponent(ConversationRow, {
3257
+ conversation: conv
3258
+ })
3259
+ })));
3260
+ };
3261
+ var _tmpl$6 = ["<div", ">\u{1F504} ", " iterations</div>"];
3262
+ var _tmpl$22 = ["<div", "><span", ">\u{1F527}</span><div", ">", "</div></div>"];
3263
+ var _tmpl$32 = ["<div", "><span", ">\u2699\uFE0F Options:</span><div", ">", "</div></div>"];
3264
+ var _tmpl$42 = ["<div", "><span", ">\u{1F3AF} Tokens:</span><span>Prompt: ", "</span><span>\u2022</span><span>Completion: ", "</span><span>\u2022</span><span", ">Total: ", "</span></div>"];
3265
+ var _tmpl$52 = ["<details", "><summary", ">\u{1F9EA} Model options</summary><div", ">", "</div></details>"];
3266
+ var _tmpl$62 = ["<details", "><summary", ">\u{1F9E9} System prompts (", ")</summary><div", ">", "</div></details>"];
3267
+ var _tmpl$7 = ["<div", "><div", "><div", "><div", ">", '</div><div class="', '">', "</div>", "</div><div", ">", "", "", "</div>", "", "", "", "", "</div></div>"];
3268
+ var _tmpl$8 = ["<span", ">", "</span>"];
3269
+ var _tmpl$9 = ["<span", ">", ": ", "</span>"];
3270
+ var _tmpl$0 = ["<div", "><div", ">#", "</div><div", ">", "</div></div>"];
3271
+ var ConversationHeader = (props) => {
3272
+ const styles = useStyles();
3273
+ const conv = () => props.conversation;
3274
+ const toolNames = () => conv().toolNames ?? [];
3275
+ const options = () => conv().options;
3276
+ const modelOptions = () => conv().modelOptions;
3277
+ const iterationCount = () => conv().iterationCount;
3278
+ const systemPrompts = () => conv().systemPrompts ?? [];
3279
+ return ssr(_tmpl$7, ssrAttribute("class", escape(styles().panelHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.headerContent, true), false), ssrAttribute("class", escape(styles().conversationDetails.headerRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.headerLabel, true), false), escape(conv().label), `${escape(styles().conversationDetails.statusBadge, true)} ${conv().status === "active" ? escape(styles().conversationDetails.statusActive, true) : conv().status === "completed" ? escape(styles().conversationDetails.statusCompleted, true) : escape(styles().conversationDetails.statusError, true)}`, escape(conv().status), escape(createComponent(Show, {
3280
+ get when() {
3281
+ return iterationCount() !== void 0 && iterationCount() > 1;
3282
+ },
3283
+ get children() {
3284
+ return ssr(_tmpl$6, ssrAttribute("class", escape(styles().conversationDetails.iterationBadge, true), false), escape(iterationCount()));
3285
+ }
3286
+ })), ssrAttribute("class", escape(styles().conversationDetails.metaInfo, true), false), conv().model && `Model: ${escape(conv().model)}`, conv().provider && ` \u2022 Provider: ${escape(conv().provider)}`, conv().completedAt && ` \u2022 Duration: ${escape(formatDuration(conv().completedAt - conv().startedAt))}`, escape(createComponent(Show, {
3287
+ get when() {
3288
+ return toolNames().length > 0;
3289
+ },
3290
+ get children() {
3291
+ return ssr(_tmpl$22, ssrAttribute("class", escape(styles().conversationDetails.toolsRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolsLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolsList, true), false), escape(createComponent(For, {
3292
+ get each() {
3293
+ return toolNames();
3294
+ },
3295
+ children: (toolName) => ssr(_tmpl$8, ssrAttribute("class", escape(styles().conversationDetails.toolBadge, true), false), escape(toolName))
3296
+ })));
3297
+ }
3298
+ })), escape(createComponent(Show, {
3299
+ get when() {
3300
+ return options() && Object.keys(options()).length > 0;
3301
+ },
3302
+ get children() {
3303
+ return ssr(_tmpl$32, ssrAttribute("class", escape(styles().conversationDetails.optionsRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.optionsLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.optionsCompact, true), false), escape(createComponent(For, {
3304
+ get each() {
3305
+ return Object.entries(options());
3306
+ },
3307
+ children: ([key, value]) => ssr(_tmpl$9, ssrAttribute("class", escape(styles().conversationDetails.optionBadge, true), false), escape(key), typeof value === "object" ? escape(JSON.stringify(value)) : escape(String(value)))
3308
+ })));
3309
+ }
3310
+ })), escape(createComponent(Show, {
3311
+ get when() {
3312
+ return conv().usage;
3313
+ },
3314
+ get children() {
3315
+ return ssr(_tmpl$42, ssrAttribute("class", escape(styles().conversationDetails.usageInfo, true), false), ssrAttribute("class", escape(styles().conversationDetails.usageLabel, true), false), escape(conv().usage?.promptTokens.toLocaleString()) || 0, escape(conv().usage?.completionTokens.toLocaleString()) || 0, ssrAttribute("class", escape(styles().conversationDetails.usageBold, true), false), escape(conv().usage?.totalTokens.toLocaleString()) || 0);
3316
+ }
3317
+ })), escape(createComponent(Show, {
3318
+ get when() {
3319
+ return modelOptions() && Object.keys(modelOptions()).length > 0;
3320
+ },
3321
+ get children() {
3322
+ return ssr(_tmpl$52, ssrAttribute("class", escape(styles().conversationDetails.collapsibleSection, true), false), ssrAttribute("class", escape(styles().conversationDetails.collapsibleSummary, true), false), ssrAttribute("class", escape(styles().conversationDetails.collapsibleContent, true), false), escape(createComponent(JsonTree, {
3323
+ get value() {
3324
+ return modelOptions();
3325
+ },
3326
+ defaultExpansionDepth: 2
3327
+ })));
3328
+ }
3329
+ })), escape(createComponent(Show, {
3330
+ get when() {
3331
+ return systemPrompts().length > 0;
3332
+ },
3333
+ get children() {
3334
+ return ssr(_tmpl$62, ssrAttribute("class", escape(styles().conversationDetails.collapsibleSection, true), false), ssrAttribute("class", escape(styles().conversationDetails.collapsibleSummary, true), false), escape(systemPrompts().length), ssrAttribute("class", escape(styles().conversationDetails.collapsibleContent, true), false), escape(createComponent(For, {
3335
+ get each() {
3336
+ return systemPrompts();
3337
+ },
3338
+ children: (prompt, index) => ssr(_tmpl$0, ssrAttribute("class", escape(styles().conversationDetails.systemPromptItem, true), false), ssrAttribute("class", escape(styles().conversationDetails.systemPromptIndex, true), false), escape(index()) + 1, ssrAttribute("class", escape(styles().conversationDetails.systemPromptText, true), false), escape(prompt))
3339
+ })));
3340
+ }
3341
+ })));
3342
+ };
3343
+ var _tmpl$10 = ['<button class="', '">\u{1F4AC} Messages (', ")</button>"];
3344
+ var _tmpl$23 = ['<button class="', '">\u{1F4E6} Chunks (', ")</button>"];
3345
+ var _tmpl$33 = ['<button class="', '">\u{1F4DD} Summaries (', ")</button>"];
3346
+ var _tmpl$43 = ['<button class="', '">\u{1F5BC}\uFE0F Image (', ")</button>"];
3347
+ var _tmpl$53 = ['<button class="', '">\u{1F50A} Speech (', ")</button>"];
3348
+ var _tmpl$63 = ['<button class="', '">\u{1F4DD} Transcription (', ")</button>"];
3349
+ var _tmpl$72 = ['<button class="', '">\u{1F3AC} Video (', ")</button>"];
3350
+ var _tmpl$82 = ["<div", ">", "", "", "", "", "", "", "</div>"];
3351
+ var ConversationTabs = (props) => {
3352
+ const styles = useStyles();
3353
+ const conv = () => props.conversation;
3354
+ const totalRawChunks = () => conv().chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
3355
+ const summariesCount = () => conv().summaries?.length ?? 0;
3356
+ const imageCount = () => conv().imageEvents?.length ?? 0;
3357
+ const speechCount = () => conv().speechEvents?.length ?? 0;
3358
+ const transcriptionCount = () => conv().transcriptionEvents?.length ?? 0;
3359
+ const videoCount = () => conv().videoEvents?.length ?? 0;
3360
+ const [imagePulse, setImagePulse] = createSignal(false);
3361
+ const [speechPulse, setSpeechPulse] = createSignal(false);
3362
+ const [transcriptionPulse, setTranscriptionPulse] = createSignal(false);
3363
+ const [videoPulse, setVideoPulse] = createSignal(false);
3364
+ const triggerPulse = (setter) => {
3365
+ setter(true);
3366
+ setTimeout(() => setter(false), 2e3);
3367
+ };
3368
+ let previousImageCount = 0;
3369
+ let previousSpeechCount = 0;
3370
+ let previousTranscriptionCount = 0;
3371
+ let previousVideoCount = 0;
3372
+ createEffect(() => {
3373
+ const count = imageCount();
3374
+ if (count > 0 && previousImageCount === 0) {
3375
+ triggerPulse(setImagePulse);
3376
+ }
3377
+ previousImageCount = count;
3378
+ });
3379
+ createEffect(() => {
3380
+ const count = speechCount();
3381
+ if (count > 0 && previousSpeechCount === 0) {
3382
+ triggerPulse(setSpeechPulse);
3383
+ }
3384
+ previousSpeechCount = count;
3385
+ });
3386
+ createEffect(() => {
3387
+ const count = transcriptionCount();
3388
+ if (count > 0 && previousTranscriptionCount === 0) {
3389
+ triggerPulse(setTranscriptionPulse);
3390
+ }
3391
+ previousTranscriptionCount = count;
3392
+ });
3393
+ createEffect(() => {
3394
+ const count = videoCount();
3395
+ if (count > 0 && previousVideoCount === 0) {
3396
+ triggerPulse(setVideoPulse);
3397
+ }
3398
+ previousVideoCount = count;
3399
+ });
3400
+ const hasMessages = () => conv().type === "client" && conv().messages.length > 0;
3401
+ const hasChunks = () => conv().chunks.length > 0 || conv().type === "server";
3402
+ const hasSummaries = () => conv().hasSummarize || summariesCount() > 0;
3403
+ const hasImage = () => conv().hasImage || imageCount() > 0;
3404
+ const hasSpeech = () => conv().hasSpeech || speechCount() > 0;
3405
+ const hasTranscription = () => conv().hasTranscription || transcriptionCount() > 0;
3406
+ const hasVideo = () => conv().hasVideo || videoCount() > 0;
3407
+ const visibleTabCount = () => {
3408
+ let count = 0;
3409
+ if (hasMessages()) count++;
3410
+ if (hasChunks() && conv().type === "server") count++;
3411
+ if (hasSummaries()) count++;
3412
+ if (hasImage()) count++;
3413
+ if (hasSpeech()) count++;
3414
+ if (hasTranscription()) count++;
3415
+ if (hasVideo()) count++;
3416
+ return count;
3417
+ };
3418
+ if (visibleTabCount() <= 1) {
3419
+ return null;
3420
+ }
3421
+ return ssr(_tmpl$82, ssrAttribute("class", escape(styles().conversationDetails.tabsContainer, true), false), escape(createComponent(Show, {
3422
+ get when() {
3423
+ return hasMessages();
3424
+ },
3425
+ get children() {
3426
+ return ssr(_tmpl$10, `${escape(styles().actionButton, true)} ${props.activeTab === "messages" ? escape(styles().conversationDetails.tabButtonActive, true) : ""}`, escape(conv().messages.length));
3427
+ }
3428
+ })), escape(createComponent(Show, {
3429
+ get when() {
3430
+ return hasChunks() && conv().type === "server";
3431
+ },
3432
+ get children() {
3433
+ return ssr(_tmpl$23, `${escape(styles().actionButton, true)} ${props.activeTab === "chunks" ? escape(styles().conversationDetails.tabButtonActive, true) : ""}`, escape(totalRawChunks()));
3434
+ }
3435
+ })), escape(createComponent(Show, {
3436
+ get when() {
3437
+ return hasSummaries();
3438
+ },
3439
+ get children() {
3440
+ return ssr(_tmpl$33, `${escape(styles().actionButton, true)} ${props.activeTab === "summaries" ? escape(styles().conversationDetails.tabButtonActive, true) : ""}`, escape(summariesCount()));
3441
+ }
3442
+ })), escape(createComponent(Show, {
3443
+ get when() {
3444
+ return hasImage();
3445
+ },
3446
+ get children() {
3447
+ return ssr(_tmpl$43, `${escape(styles().actionButton, true)} ${props.activeTab === "image" ? escape(styles().conversationDetails.tabButtonActive, true) : ""} ${imagePulse() ? escape(styles().conversationDetails.tabButtonPulse, true) : ""}`, escape(imageCount()));
3448
+ }
3449
+ })), escape(createComponent(Show, {
3450
+ get when() {
3451
+ return hasSpeech();
3452
+ },
3453
+ get children() {
3454
+ return ssr(_tmpl$53, `${escape(styles().actionButton, true)} ${props.activeTab === "speech" ? escape(styles().conversationDetails.tabButtonActive, true) : ""} ${speechPulse() ? escape(styles().conversationDetails.tabButtonPulse, true) : ""}`, escape(speechCount()));
3455
+ }
3456
+ })), escape(createComponent(Show, {
3457
+ get when() {
3458
+ return hasTranscription();
3459
+ },
3460
+ get children() {
3461
+ return ssr(_tmpl$63, `${escape(styles().actionButton, true)} ${props.activeTab === "transcription" ? escape(styles().conversationDetails.tabButtonActive, true) : ""} ${transcriptionPulse() ? escape(styles().conversationDetails.tabButtonPulse, true) : ""}`, escape(transcriptionCount()));
3462
+ }
3463
+ })), escape(createComponent(Show, {
3464
+ get when() {
3465
+ return hasVideo();
3466
+ },
3467
+ get children() {
3468
+ return ssr(_tmpl$72, `${escape(styles().actionButton, true)} ${props.activeTab === "video" ? escape(styles().conversationDetails.tabButtonActive, true) : ""} ${videoPulse() ? escape(styles().conversationDetails.tabButtonPulse, true) : ""}`, escape(videoCount()));
3469
+ }
3470
+ })));
3471
+ };
3472
+ var _tmpl$11 = ["<div", ">\u23F1\uFE0F ", "</div>"];
3473
+ var _tmpl$24 = ["<div", ">APPROVAL REQUIRED</div>"];
3474
+ var _tmpl$34 = ["<div", "><div", ">Arguments</div><div", ">", "</div></div>"];
3475
+ var _tmpl$44 = ["<div", "><div", ">Result</div><div", ">", "</div></div>"];
3476
+ var _tmpl$54 = ['<details class="', '"><summary', '><div class="', '">', " ", '</div><div class="', '">', "</div>", "", "</summary><div", ">", "", "</div></details>"];
3477
+ var ToolCallDisplay = (props) => {
3478
+ const styles = useStyles();
3479
+ const tool = () => props.tool;
3480
+ const parsedArguments = () => {
3481
+ const args = tool().arguments;
3482
+ if (typeof args === "string") {
3483
+ try {
3484
+ return JSON.parse(args);
3485
+ } catch {
3486
+ return args;
3487
+ }
3488
+ }
3489
+ return args;
3490
+ };
3491
+ return ssr(_tmpl$54, `${escape(styles().conversationDetails.toolCall, true)} ${tool().approvalRequired ? escape(styles().conversationDetails.toolCallApproval, true) : escape(styles().conversationDetails.toolCallNormal, true)}`, ssrAttribute("class", escape(styles().conversationDetails.toolCallHeader, true), false), `${escape(styles().conversationDetails.toolCallName, true)} ${tool().approvalRequired ? escape(styles().conversationDetails.toolCallNameApproval, true) : escape(styles().conversationDetails.toolCallNameNormal, true)}`, tool().approvalRequired ? "\u26A0\uFE0F" : "\u{1F527}", escape(tool().name), `${escape(styles().conversationDetails.toolStateBadge, true)} ${tool().approvalRequired ? escape(styles().conversationDetails.toolStateBadgeApproval, true) : escape(styles().conversationDetails.toolStateBadgeNormal, true)}`, escape(tool().state), escape(createComponent(Show, {
3492
+ get when() {
3493
+ return tool().duration !== void 0 && tool().duration > 0;
3494
+ },
3495
+ get children() {
3496
+ return ssr(_tmpl$11, ssrAttribute("class", escape(styles().conversationDetails.durationBadge, true), false), escape(formatDuration(tool().duration)));
3497
+ }
3498
+ })), escape(createComponent(Show, {
3499
+ get when() {
3500
+ return tool().approvalRequired;
3501
+ },
3502
+ get children() {
3503
+ return ssr(_tmpl$24, ssrAttribute("class", escape(styles().conversationDetails.approvalRequiredBadge, true), false));
3504
+ }
3505
+ })), ssrAttribute("class", escape(styles().conversationDetails.toolCallContent, true), false), escape(createComponent(Show, {
3506
+ get when() {
3507
+ return tool().arguments;
3508
+ },
3509
+ get children() {
3510
+ return ssr(_tmpl$34, ssrAttribute("class", escape(styles().conversationDetails.toolSection, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolSectionLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolJsonContainer, true), false), escape(createComponent(JsonTree, {
3511
+ get value() {
3512
+ return parsedArguments();
3513
+ },
3514
+ defaultExpansionDepth: 2,
3515
+ copyable: true
3516
+ })));
3517
+ }
3518
+ })), escape(createComponent(Show, {
3519
+ get when() {
3520
+ return tool().result !== void 0;
3521
+ },
3522
+ get children() {
3523
+ return ssr(_tmpl$44, ssrAttribute("class", escape(styles().conversationDetails.toolSection, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolSectionLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolJsonContainer, true), false), escape(createComponent(JsonTree, {
3524
+ get value() {
3525
+ return tool().result;
3526
+ },
3527
+ defaultExpansionDepth: 2,
3528
+ copyable: true
3529
+ })));
3530
+ }
3531
+ })));
3532
+ };
3533
+ var _tmpl$12 = ['<span style="', '">(', " chunks)</span>"];
3534
+ var _tmpl$25 = ["<div", ">\u{1F527} ", "</div>"];
3535
+ var _tmpl$35 = ["<div", ">", "</div>"];
3536
+ var _tmpl$45 = ["<div", ">\u274C ", "</div>"];
3537
+ var _tmpl$55 = ["<div", ">\u2713 ", "</div>"];
3538
+ var _tmpl$64 = ["<div", ">Input: ", "</div>"];
3539
+ var _tmpl$73 = ["<div", "><div", ">\u26A0\uFE0F Approval Required</div>", "</div>"];
3540
+ var _tmpl$83 = ["<div", "><div", "><span", ">\u{1F4E4} Tool Arguments</span></div><div", ">", "</div></div>"];
3541
+ var _tmpl$92 = ["<span", ">\u23F1\uFE0F ", "</span>"];
3542
+ var _tmpl$02 = ["<div", "><div", "><span", ">\u2713 Tool Result</span>", "</div><div", ">", "</div></div>"];
3543
+ var _tmpl$1 = ["<div", "><div", "><div", ">#", "", "</div><div", "><div", ' style="', '"></div><div', ">", "</div></div>", "<div", ">", '</div><button class="', '"', ">{}</button></div>", "", "</div>"];
3544
+ var ChunkItem = (props) => {
3545
+ const styles = useStyles();
3546
+ const [showRaw, setShowRaw] = createSignal(false);
3547
+ const isLarge = () => props.variant === "large";
3548
+ const chunkCount = () => props.chunk.chunkCount || 1;
3549
+ const parseToolArguments = () => {
3550
+ try {
3551
+ return JSON.parse(props.chunk.arguments || "{}");
3552
+ } catch {
3553
+ return {
3554
+ raw: props.chunk.arguments
3555
+ };
3556
+ }
3557
+ };
3558
+ const parseToolResult = () => {
3559
+ try {
3560
+ if (typeof props.chunk.result === "string") {
3561
+ return JSON.parse(props.chunk.result);
3562
+ }
3563
+ return props.chunk.result;
3564
+ } catch {
3565
+ return {
3566
+ raw: props.chunk.result
3567
+ };
3568
+ }
3569
+ };
3570
+ return ssr(_tmpl$1, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkItemLarge, true) : escape(styles().conversationDetails.chunkItem, true), false), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkHeaderLarge, true) : escape(styles().conversationDetails.chunkHeader, true), false), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkNumberLarge, true) : escape(styles().conversationDetails.chunkNumber, true), false), escape(props.index) + 1, escape(createComponent(Show, {
3571
+ get when() {
3572
+ return chunkCount() > 1;
3573
+ },
3574
+ get children() {
3575
+ return ssr(_tmpl$12, ssrStyleProperty("margin-left:", "4px") + ssrStyleProperty(";opacity:", 0.7), escape(chunkCount()));
3576
+ }
3577
+ })), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkTypeBadgeLarge, true) : escape(styles().conversationDetails.chunkTypeBadge, true), false), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkTypeDotLarge, true) : escape(styles().conversationDetails.chunkTypeDot, true), false), ssrStyleProperty("background:", escape(getChunkTypeColor(props.chunk.type), true)), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkTypeLabelLarge, true) : escape(styles().conversationDetails.chunkTypeLabel, true), false), escape(props.chunk.type), escape(createComponent(Show, {
3578
+ get when() {
3579
+ return props.chunk.toolName;
3580
+ },
3581
+ get children() {
3582
+ return ssr(_tmpl$25, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkToolBadgeLarge, true) : escape(styles().conversationDetails.chunkToolBadge, true), false), escape(props.chunk.toolName));
3583
+ }
3584
+ })), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkTimestampLarge, true) : escape(styles().conversationDetails.chunkTimestamp, true), false), escape(formatTimestamp(props.chunk.timestamp)), `${isLarge() ? escape(styles().conversationDetails.rawJsonButtonLarge, true) : escape(styles().conversationDetails.rawJsonButton, true)} ${showRaw() ? escape(styles().conversationDetails.rawJsonButtonActive, true) : escape(styles().conversationDetails.rawJsonButtonInactive, true)}`, ssrAttribute("title", showRaw() ? "Show formatted" : "Show raw JSON", false), escape(createComponent(Show, {
3585
+ get when() {
3586
+ return !showRaw();
3587
+ },
3588
+ get children() {
3589
+ return [createComponent(Show, {
3590
+ get when() {
3591
+ return props.chunk.content || props.chunk.delta;
3592
+ },
3593
+ get children() {
3594
+ return ssr(_tmpl$35, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkContentLarge, true) : escape(styles().conversationDetails.chunkContent, true), false), escape(props.chunk.content));
3595
+ }
3596
+ }), createComponent(Show, {
3597
+ get when() {
3598
+ return props.chunk.error;
3599
+ },
3600
+ get children() {
3601
+ return ssr(_tmpl$45, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkErrorLarge, true) : escape(styles().conversationDetails.chunkError, true), false), escape(props.chunk.error));
3602
+ }
3603
+ }), createComponent(Show, {
3604
+ get when() {
3605
+ return props.chunk.finishReason;
3606
+ },
3607
+ get children() {
3608
+ return ssr(_tmpl$55, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkFinishLarge, true) : escape(styles().conversationDetails.chunkFinish, true), false), isLarge() ? `Finish: ${escape(props.chunk.finishReason)}` : escape(props.chunk.finishReason));
3609
+ }
3610
+ }), createComponent(Show, {
3611
+ get when() {
3612
+ return props.chunk.type === "approval";
3613
+ },
3614
+ get children() {
3615
+ return ssr(_tmpl$73, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkApprovalLarge, true) : escape(styles().conversationDetails.chunkApproval, true), false), ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkApprovalTitleLarge, true) : escape(styles().conversationDetails.chunkApprovalTitle, true), false), escape(createComponent(Show, {
3616
+ get when() {
3617
+ return props.chunk.input;
3618
+ },
3619
+ get children() {
3620
+ return ssr(_tmpl$64, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.chunkApprovalInputLarge, true) : escape(styles().conversationDetails.chunkApprovalInput, true), false), escape(JSON.stringify(props.chunk.input, null, 2)));
3621
+ }
3622
+ })));
3623
+ }
3624
+ }), createComponent(Show, {
3625
+ get when() {
3626
+ return props.chunk.type === "tool_call" && props.chunk.arguments;
3627
+ },
3628
+ get children() {
3629
+ return ssr(_tmpl$83, ssrAttribute("class", escape(styles().conversationDetails.chunkToolCall, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunkToolCallHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunkToolCallTitle, true), false), ssrAttribute("class", escape(styles().conversationDetails.toolJsonContainer, true), false), escape(createComponent(JsonTree, {
3630
+ get value() {
3631
+ return parseToolArguments();
3632
+ },
3633
+ defaultExpansionDepth: 2,
3634
+ copyable: true
3635
+ })));
3636
+ }
3637
+ }), createComponent(Show, {
3638
+ get when() {
3639
+ return props.chunk.type === "tool_result" && props.chunk.result !== void 0;
3640
+ },
3641
+ get children() {
3642
+ return ssr(_tmpl$02, ssrAttribute("class", escape(styles().conversationDetails.chunkToolResult, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunkToolResultHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunkToolResultTitle, true), false), escape(createComponent(Show, {
3643
+ get when() {
3644
+ return props.chunk.duration !== void 0 && props.chunk.duration > 0;
3645
+ },
3646
+ get children() {
3647
+ return ssr(_tmpl$92, ssrAttribute("class", escape(styles().conversationDetails.durationBadge, true), false), escape(formatDuration(props.chunk.duration)));
3648
+ }
3649
+ })), ssrAttribute("class", escape(styles().conversationDetails.toolJsonContainer, true), false), escape(createComponent(JsonTree, {
3650
+ get value() {
3651
+ return parseToolResult();
3652
+ },
3653
+ defaultExpansionDepth: 2,
3654
+ copyable: true
3655
+ })));
3656
+ }
3657
+ })];
3658
+ }
3659
+ })), escape(createComponent(Show, {
3660
+ get when() {
3661
+ return showRaw();
3662
+ },
3663
+ get children() {
3664
+ return ssr(_tmpl$35, ssrAttribute("class", isLarge() ? escape(styles().conversationDetails.rawJsonLarge, true) : escape(styles().conversationDetails.rawJson, true), false), escape(JSON.stringify(props.chunk, null, 2)));
3665
+ }
3666
+ })));
3667
+ };
3668
+ var _tmpl$13 = ['<span class="', '">\u{1F527} Tool Calls</span>'];
3669
+ var _tmpl$26 = ['<span class="', '">\u274C Error</span>'];
3670
+ var _tmpl$36 = ['<span class="', '">\u26A0\uFE0F Approval</span>'];
3671
+ var _tmpl$46 = ['<span class="', '">\u2713 ', "</span>"];
3672
+ var ChunkBadges = (props) => {
3673
+ const styles = useStyles();
3674
+ const hasToolCalls = () => props.chunks.some((c) => c.type === "tool_call");
3675
+ const hasErrors = () => props.chunks.some((c) => c.type === "error");
3676
+ const hasApproval = () => props.chunks.some((c) => c.type === "approval");
3677
+ const finishReason = () => props.chunks.find((c) => c.type === "done")?.finishReason;
3678
+ return [createComponent(Show, {
3679
+ get when() {
3680
+ return hasToolCalls();
3681
+ },
3682
+ get children() {
3683
+ return ssr(_tmpl$13, `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeTool, true)}`);
3684
+ }
3685
+ }), createComponent(Show, {
3686
+ get when() {
3687
+ return hasErrors();
3688
+ },
3689
+ get children() {
3690
+ return ssr(_tmpl$26, `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeError, true)}`);
3691
+ }
3692
+ }), createComponent(Show, {
3693
+ get when() {
3694
+ return hasApproval();
3695
+ },
3696
+ get children() {
3697
+ return ssr(_tmpl$36, `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeApproval, true)}`);
3698
+ }
3699
+ }), createComponent(Show, {
3700
+ get when() {
3701
+ return finishReason();
3702
+ },
3703
+ get children() {
3704
+ return ssr(_tmpl$46, `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeSuccess, true)}`, escape(finishReason()));
3705
+ }
3706
+ })];
3707
+ };
3708
+
3709
+ // src/components/conversation/ChunksCollapsible.tsx
3710
+ var _tmpl$14 = ["<div", ">", "</div>"];
3711
+ var _tmpl$27 = ["<details", "><summary", "><div", "><span", ">\u25B6</span><span", ">\u{1F4E6} ", " chunks</span>", "</div>", "</summary><div", "><div", ">", "</div></div></details>"];
3712
+ var ChunksCollapsible = (props) => {
3713
+ const styles = useStyles();
3714
+ const accumulatedContent = () => props.chunks.filter((c) => c.type === "content" && (c.content || c.delta)).map((c) => c.delta || c.content).join("");
3715
+ const totalRawChunks = () => props.chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
3716
+ return ssr(_tmpl$27, ssrAttribute("class", escape(styles().conversationDetails.chunksDetails, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksSummary, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksSummaryRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksSummaryArrow, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksSummaryTitle, true), false), escape(totalRawChunks()), escape(createComponent(ChunkBadges, {
3717
+ get chunks() {
3718
+ return props.chunks;
3719
+ }
3720
+ })), escape(createComponent(Show, {
3721
+ get when() {
3722
+ return accumulatedContent();
3723
+ },
3724
+ get children() {
3725
+ return ssr(_tmpl$14, ssrAttribute("class", escape(styles().conversationDetails.contentPreview, true), false) + ssrAttribute("title", escape(accumulatedContent(), true), false), escape(accumulatedContent()));
3726
+ }
3727
+ })), ssrAttribute("class", escape(styles().conversationDetails.chunksContainer, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksList, true), false), escape(createComponent(For, {
3728
+ get each() {
3729
+ return props.chunks;
3730
+ },
3731
+ children: (chunk, index) => createComponent(ChunkItem, {
3732
+ chunk,
3733
+ get index() {
3734
+ return index();
3735
+ },
3736
+ variant: "small"
3737
+ })
3738
+ })));
3739
+ };
3740
+
3741
+ // src/components/conversation/MessageCard.tsx
3742
+ var _tmpl$15 = ['<div class="', '"><span', ">", "</span><span", ">", "</span></div>"];
3743
+ var _tmpl$28 = ["<div", "><span", ">\u{1F3AF}</span><span>", " in</span><span>\u2022</span><span>", " out</span></div>"];
3744
+ var _tmpl$37 = ["<div", "><span", ">\u23F1\uFE0F</span><span>", "</span></div>"];
3745
+ var _tmpl$47 = ["<details", "><summary", ">\u{1F4AD} Thinking...</summary><div", ">", "</div></details>"];
3746
+ var _tmpl$56 = ["<div", ">", "</div>"];
3747
+ var _tmpl$65 = ["<div", ">", "<div", "><div", "><div", ">", "</div><div", "><div", ">", "</div></div><div", ">", "</div>", "", "</div>", "", "", "", "</div></div>"];
3748
+ var MessageCard = (props) => {
3749
+ const styles = useStyles();
3750
+ const msg = () => props.message;
3751
+ const isClientMessage = () => msg().source === "client";
3752
+ const getCardClass = () => {
3753
+ const base = styles().conversationDetails.messageCard;
3754
+ if (msg().role === "user") {
3755
+ return `${base} ${styles().conversationDetails.messageCardUser}`;
3756
+ }
3757
+ if (isClientMessage()) {
3758
+ return `${base} ${styles().conversationDetails.messageCardClient}`;
3759
+ }
3760
+ return `${base} ${styles().conversationDetails.messageCardServer}`;
3761
+ };
3762
+ const parseJsonContent = () => {
3763
+ const content = msg().content;
3764
+ if (typeof content !== "string") return null;
3765
+ const trimmed = content.trim();
3766
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
3767
+ try {
3768
+ return JSON.parse(trimmed);
3769
+ } catch {
3770
+ return null;
3771
+ }
3772
+ };
3773
+ const toolDuration = () => {
3774
+ const durations = msg().toolCalls?.map((tool) => tool.duration || 0).filter((duration) => duration > 0);
3775
+ if (!durations || durations.length === 0) return 0;
3776
+ return durations.reduce((total, duration) => total + duration, 0);
3777
+ };
3778
+ return ssr(_tmpl$65, ssrAttribute("class", escape(getCardClass(), true), false), escape(createComponent(Show, {
3779
+ get when() {
3780
+ return msg().role === "assistant";
3781
+ },
3782
+ get children() {
3783
+ return ssr(_tmpl$15, `${escape(styles().conversationDetails.sourceBanner, true)} ${isClientMessage() ? escape(styles().conversationDetails.sourceBannerClient, true) : escape(styles().conversationDetails.sourceBannerServer, true)}`, ssrAttribute("class", escape(styles().conversationDetails.sourceBannerIcon, true), false), isClientMessage() ? "\u{1F4F1}" : "\u2601\uFE0F", ssrAttribute("class", escape(styles().conversationDetails.sourceBannerText, true), false), isClientMessage() ? "Client Message" : "Server Message");
3784
+ }
3785
+ })), ssrAttribute("class", msg().role === "user" ? "" : escape(styles().conversationDetails.messageCardContent, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageHeader, true), false), ssrAttribute("class", msg().role === "user" ? escape(styles().conversationDetails.avatarUser, true) : isClientMessage() ? escape(styles().conversationDetails.avatarClient, true) : escape(styles().conversationDetails.avatarServer, true), false), msg().role === "user" ? "U" : msg().role === "tool" ? "\u{1F527}" : "\u{1F916}", ssrAttribute("class", escape(styles().conversationDetails.roleLabel, true), false), ssrAttribute("class", msg().role === "user" ? escape(styles().conversationDetails.roleLabelUser, true) : isClientMessage() ? escape(styles().conversationDetails.roleLabelClient, true) : escape(styles().conversationDetails.roleLabelServer, true), false), escape(msg().role), ssrAttribute("class", escape(styles().conversationDetails.timestamp, true), false), escape(formatTimestamp(msg().timestamp)), escape(createComponent(Show, {
3786
+ get when() {
3787
+ return msg().usage;
3788
+ },
3789
+ get children() {
3790
+ return ssr(_tmpl$28, ssrAttribute("class", escape(styles().conversationDetails.messageUsage, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageUsageIcon, true), false), escape(msg().usage?.promptTokens.toLocaleString()), escape(msg().usage?.completionTokens.toLocaleString()));
3791
+ }
3792
+ })), escape(createComponent(Show, {
3793
+ get when() {
3794
+ return toolDuration() > 0;
3795
+ },
3796
+ get children() {
3797
+ return ssr(_tmpl$37, ssrAttribute("class", escape(styles().conversationDetails.messageUsage, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageUsageIcon, true), false), escape(formatDuration(toolDuration())));
3798
+ }
3799
+ })), escape(createComponent(Show, {
3800
+ get when() {
3801
+ return msg().thinkingContent;
3802
+ },
3803
+ get children() {
3804
+ return ssr(_tmpl$47, ssrAttribute("class", escape(styles().conversationDetails.thinkingDetails, true), false), ssrAttribute("class", escape(styles().conversationDetails.thinkingSummary, true), false), ssrAttribute("class", escape(styles().conversationDetails.thinkingContent, true), false), escape(msg().thinkingContent));
3805
+ }
3806
+ })), escape(createComponent(Show, {
3807
+ get when() {
3808
+ return msg().role === "tool" && parseJsonContent() !== null;
3809
+ },
3810
+ get fallback() {
3811
+ return ssr(_tmpl$56, ssrAttribute("class", escape(styles().conversationDetails.messageContent, true), false), escape(msg().content));
3812
+ },
3813
+ get children() {
3814
+ return ssr(_tmpl$56, ssrAttribute("class", escape(styles().conversationDetails.toolJsonContainer, true), false), escape(createComponent(JsonTree, {
3815
+ get value() {
3816
+ return parseJsonContent();
3817
+ }
3818
+ })));
3819
+ }
3820
+ })), escape(createComponent(Show, {
3821
+ get when() {
3822
+ return msg().toolCalls && msg().toolCalls.length > 0;
3823
+ },
3824
+ get children() {
3825
+ return ssr(_tmpl$56, ssrAttribute("class", escape(styles().conversationDetails.toolCallsContainer, true), false), escape(createComponent(For, {
3826
+ get each() {
3827
+ return msg().toolCalls;
3828
+ },
3829
+ children: (tool) => createComponent(ToolCallDisplay, {
3830
+ tool
3831
+ })
3832
+ })));
3833
+ }
3834
+ })), escape(createComponent(Show, {
3835
+ get when() {
3836
+ return msg().chunks && msg().chunks.length > 0;
3837
+ },
3838
+ get children() {
3839
+ return createComponent(ChunksCollapsible, {
3840
+ get chunks() {
3841
+ return msg().chunks;
3842
+ }
3843
+ });
3844
+ }
3845
+ })));
3846
+ };
3847
+
3848
+ // src/components/conversation/MessagesTab.tsx
3849
+ var _tmpl$16 = ["<div", ">", "</div>"];
3850
+ var _tmpl$29 = ["<div", ">No messages yet. Start a conversation to see messages here.</div>"];
3851
+ var MessagesTab = (props) => {
3852
+ const styles = useStyles();
3853
+ return createComponent(Show, {
3854
+ get when() {
3855
+ return props.messages.length > 0;
3856
+ },
3857
+ get fallback() {
3858
+ return ssr(_tmpl$29, ssrAttribute("class", escape(styles().conversationDetails.emptyMessages, true), false));
3859
+ },
3860
+ get children() {
3861
+ return ssr(_tmpl$16, ssrAttribute("class", escape(styles().conversationDetails.messagesList, true), false), escape(createComponent(For, {
3862
+ get each() {
3863
+ return props.messages;
3864
+ },
3865
+ children: (msg) => createComponent(MessageCard, {
3866
+ message: msg
3867
+ })
3868
+ })));
3869
+ }
3870
+ });
3871
+ };
3872
+ var _tmpl$17 = ['<span style="', '">(', " entries)</span>"];
3873
+ var _tmpl$210 = ["<div", "><span", ">\u{1F3AF}</span><span>", " in</span><span>\u2022</span><span>", " out</span></div>"];
3874
+ var _tmpl$38 = ["<div", ">", "</div>"];
3875
+ var _tmpl$48 = ["<details", "><summary", "><div", "><div", "><span>Message #", '</span><div class="', '">\u{1F4E6} ', " chunks", "</div>", "", "</div><div", ">ID: ", "</div>", "</div></summary><div", "><div", ">", "</div></div></details>"];
3876
+ var MessageGroup = (props) => {
3877
+ const styles = useStyles();
3878
+ const accumulatedContent = () => props.chunks.filter((c) => c.type === "content" && (c.content || c.delta)).map((c) => c.content).join("");
3879
+ const totalRawChunks = () => props.chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
3880
+ const consolidatedEntries = () => props.chunks.length;
3881
+ return ssr(_tmpl$48, ssrAttribute("class", escape(styles().conversationDetails.messageGroupDetails, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageGroupSummary, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageGroupContent, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageGroupHeader, true), false), escape(props.groupIndex) + 1, `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeCount, true)}`, escape(totalRawChunks()), escape(createComponent(Show, {
3882
+ get when() {
3883
+ return consolidatedEntries() !== totalRawChunks();
3884
+ },
3885
+ get children() {
3886
+ return ssr(_tmpl$17, ssrStyleProperty("opacity:", 0.7) + ssrStyleProperty(";margin-left:", "4px"), escape(consolidatedEntries()));
3887
+ }
3888
+ })), escape(createComponent(ChunkBadges, {
3889
+ get chunks() {
3890
+ return props.chunks;
3891
+ }
3892
+ })), escape(createComponent(Show, {
3893
+ get when() {
3894
+ return props.usage;
3895
+ },
3896
+ get children() {
3897
+ return ssr(_tmpl$210, ssrAttribute("class", escape(styles().conversationDetails.messageUsage, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageUsageIcon, true), false), escape(props.usage?.promptTokens.toLocaleString()), escape(props.usage?.completionTokens.toLocaleString()));
3898
+ }
3899
+ })), ssrAttribute("class", escape(styles().conversationDetails.messageId, true), false) + ssrAttribute("title", escape(props.messageId, true), false), escape(props.messageId), escape(createComponent(Show, {
3900
+ get when() {
3901
+ return accumulatedContent();
3902
+ },
3903
+ get children() {
3904
+ return ssr(_tmpl$38, ssrAttribute("class", escape(styles().conversationDetails.contentPreview, true), false) + ssrAttribute("title", escape(accumulatedContent(), true), false), escape(accumulatedContent()));
3905
+ }
3906
+ })), ssrAttribute("class", escape(styles().conversationDetails.chunksContainer, true), false), ssrAttribute("class", escape(styles().conversationDetails.chunksList, true), false), escape(createComponent(For, {
3907
+ get each() {
3908
+ return props.chunks;
3909
+ },
3910
+ children: (chunk, chunkIndex) => createComponent(ChunkItem, {
3911
+ chunk,
3912
+ get index() {
3913
+ return chunkIndex();
3914
+ },
3915
+ variant: "large"
3916
+ })
3917
+ })));
3918
+ };
3919
+
3920
+ // src/components/conversation/ChunksTab.tsx
3921
+ var _tmpl$18 = ["<div", "><div", "><div", "><div", '>Stream Responses</div><div class="', '">', " chunks \xB7 ", " messages</div></div><div", ">Grouped by message ID</div></div><div", ">", "</div></div>"];
3922
+ var _tmpl$211 = ["<div", ">No chunks yet</div>"];
3923
+ var ChunksTab = (props) => {
3924
+ const styles = useStyles();
3925
+ const usageByMessageId = () => {
3926
+ const map = /* @__PURE__ */ new Map();
3927
+ props.messages?.forEach((msg) => {
3928
+ if (msg.usage) {
3929
+ map.set(msg.id, msg.usage);
3930
+ }
3931
+ });
3932
+ return map;
3933
+ };
3934
+ const groupedChunks = () => {
3935
+ const groups = /* @__PURE__ */ new Map();
3936
+ props.chunks.forEach((chunk) => {
3937
+ const key = chunk.messageId || "no-message-id";
3938
+ if (!groups.has(key)) {
3939
+ groups.set(key, []);
3940
+ }
3941
+ groups.get(key).push(chunk);
3942
+ });
3943
+ return Array.from(groups.entries());
3944
+ };
3945
+ const totalRawChunks = () => props.chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
3946
+ return createComponent(Show, {
3947
+ get when() {
3948
+ return props.chunks.length > 0;
3949
+ },
3950
+ get fallback() {
3951
+ return ssr(_tmpl$211, ssrAttribute("class", escape(styles().conversationDetails.noChunks, true), false));
3952
+ },
3953
+ get children() {
3954
+ return ssr(_tmpl$18, ssrAttribute("class", escape(styles().conversationDetails.streamContainer, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamHeaderRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamTitle, true), false), `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeCount, true)}`, escape(totalRawChunks()), escape(groupedChunks().length), ssrAttribute("class", escape(styles().conversationDetails.streamSubtitle, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageGroups, true), false), escape(createComponent(For, {
3955
+ get each() {
3956
+ return groupedChunks();
3957
+ },
3958
+ children: ([messageId, chunks], groupIndex) => createComponent(MessageGroup, {
3959
+ messageId,
3960
+ chunks,
3961
+ get groupIndex() {
3962
+ return groupIndex();
3963
+ },
3964
+ get usage() {
3965
+ return usageByMessageId().get(messageId);
3966
+ }
3967
+ })
3968
+ })));
3969
+ }
3970
+ });
3971
+ };
3972
+ var _tmpl$19 = ["<div", ">", "</div>"];
3973
+ var _tmpl$212 = ["<div", ">No summarize operations yet</div>"];
3974
+ var _tmpl$39 = ["<div", ">\u23F1\uFE0F ", "</div>"];
3975
+ var _tmpl$49 = ["<div", "><span", ">Output:</span><span", ">", " chars</span></div>"];
3976
+ var _tmpl$57 = ["<div", "><div", "><div", ">\u{1F4DD}</div><div", '>Summarize</div><div class="', '">', "</div>", "</div><div", "><div", "><span", ">Model:</span><span", ">", "</span></div><div", "><span", ">Input:</span><span", ">", " chars</span></div>", "<div", "><span", ">Started:</span><span", ">", "</span></div></div></div>"];
3977
+ var SummariesTab = (props) => {
3978
+ const styles = useStyles();
3979
+ return createComponent(Show, {
3980
+ get when() {
3981
+ return props.summaries.length > 0;
3982
+ },
3983
+ get fallback() {
3984
+ return ssr(_tmpl$212, ssrAttribute("class", escape(styles().conversationDetails.emptyMessages, true), false));
3985
+ },
3986
+ get children() {
3987
+ return ssr(_tmpl$19, ssrAttribute("class", escape(styles().conversationDetails.messagesList, true), false), escape(createComponent(For, {
3988
+ get each() {
3989
+ return props.summaries;
3990
+ },
3991
+ children: (summary) => ssr(_tmpl$57, ssrAttribute("class", escape(styles().conversationDetails.operationCard, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationIcon, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationTitle, true), false), `${escape(styles().conversationDetails.operationStatus, true)} ${summary.status === "completed" ? escape(styles().conversationDetails.operationStatusCompleted, true) : escape(styles().conversationDetails.operationStatusPending, true)}`, escape(summary.status), escape(createComponent(Show, {
3992
+ get when() {
3993
+ return summary.duration !== void 0 && summary.duration > 0;
3994
+ },
3995
+ get children() {
3996
+ return ssr(_tmpl$39, ssrAttribute("class", escape(styles().conversationDetails.durationBadge, true), false), escape(formatDuration(summary.duration)));
3997
+ }
3998
+ })), ssrAttribute("class", escape(styles().conversationDetails.operationDetails, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationDetail, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationValue, true), false), escape(summary.model), ssrAttribute("class", escape(styles().conversationDetails.operationDetail, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationValue, true), false), escape(summary.inputLength.toLocaleString()), escape(createComponent(Show, {
3999
+ get when() {
4000
+ return summary.outputLength !== void 0;
4001
+ },
4002
+ get children() {
4003
+ return ssr(_tmpl$49, ssrAttribute("class", escape(styles().conversationDetails.operationDetail, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationValue, true), false), escape(summary.outputLength?.toLocaleString()));
4004
+ }
4005
+ })), ssrAttribute("class", escape(styles().conversationDetails.operationDetail, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationLabel, true), false), ssrAttribute("class", escape(styles().conversationDetails.operationValue, true), false), escape(new Date(summary.timestamp).toLocaleTimeString()))
4006
+ })));
4007
+ }
4008
+ });
4009
+ };
4010
+ var _tmpl$20 = ["<div", "><div", "><div", "><div", ">", '</div><div class="', '">', " events</div></div><div", ">Activity event log</div></div><div", ">", "</div></div>"];
4011
+ var _tmpl$213 = ["<div", ">No events yet</div>"];
4012
+ var _tmpl$310 = ["<div", "><div", ">", " \xB7 ", "</div><pre", ">", "</pre></div>"];
4013
+ var ActivityEventsTab = (props) => {
4014
+ const styles = useStyles();
4015
+ const formattedTimestamp = (timestamp) => new Date(timestamp).toLocaleTimeString();
4016
+ return createComponent(Show, {
4017
+ get when() {
4018
+ return props.events.length > 0;
4019
+ },
4020
+ get fallback() {
4021
+ return ssr(_tmpl$213, ssrAttribute("class", escape(styles().conversationDetails.noChunks, true), false));
4022
+ },
4023
+ get children() {
4024
+ return ssr(_tmpl$20, ssrAttribute("class", escape(styles().conversationDetails.streamContainer, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamHeader, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamHeaderRow, true), false), ssrAttribute("class", escape(styles().conversationDetails.streamTitle, true), false), escape(props.title), `${escape(styles().conversationDetails.chunkBadge, true)} ${escape(styles().conversationDetails.chunkBadgeCount, true)}`, escape(props.events.length), ssrAttribute("class", escape(styles().conversationDetails.streamSubtitle, true), false), ssrAttribute("class", escape(styles().conversationDetails.messageGroups, true), false), escape(createComponent(For, {
4025
+ get each() {
4026
+ return props.events;
4027
+ },
4028
+ children: (event) => ssr(_tmpl$310, ssrAttribute("class", escape(styles().detailSection, true), false), ssrAttribute("class", escape(styles().detailSectionHeader, true), false), escape(event.name), escape(formattedTimestamp(event.timestamp)), ssrAttribute("class", escape(styles().conversationDetails.jsonPreview, true), false), escape(JSON.stringify(event.payload, null, 2)))
4029
+ })));
4030
+ }
4031
+ });
4032
+ };
4033
+
4034
+ // src/components/ConversationDetails.tsx
4035
+ var _tmpl$21 = ["<div", ">Select a conversation to view details</div>"];
4036
+ var _tmpl$214 = ["<div", ">", "", "<div", ">", "", "", "", "", "", "", "</div></div>"];
4037
+ var ConversationDetails = () => {
4038
+ const {
4039
+ state
4040
+ } = useAIStore();
4041
+ const styles = useStyles();
4042
+ const [activeTab, setActiveTab] = createSignal("messages");
4043
+ const activeConversation = () => {
4044
+ if (!state.activeConversationId) return void 0;
4045
+ return state.conversations[state.activeConversationId];
4046
+ };
4047
+ createEffect(() => {
4048
+ const conv = activeConversation();
4049
+ if (conv) {
4050
+ if (conv.type === "server") {
4051
+ if (conv.chunks.length > 0) {
4052
+ setActiveTab("chunks");
4053
+ } else if (conv.hasSummarize || conv.summaries && conv.summaries.length > 0) {
4054
+ setActiveTab("summaries");
4055
+ } else if (conv.hasImage || conv.imageEvents && conv.imageEvents.length > 0) {
4056
+ setActiveTab("image");
4057
+ } else if (conv.hasSpeech || conv.speechEvents && conv.speechEvents.length > 0) {
4058
+ setActiveTab("speech");
4059
+ } else if (conv.hasTranscription || conv.transcriptionEvents && conv.transcriptionEvents.length > 0) {
4060
+ setActiveTab("transcription");
4061
+ } else if (conv.hasVideo || conv.videoEvents && conv.videoEvents.length > 0) {
4062
+ setActiveTab("video");
4063
+ } else {
4064
+ setActiveTab("chunks");
4065
+ }
4066
+ } else {
4067
+ if (conv.messages.length > 0) {
4068
+ setActiveTab("messages");
4069
+ } else if (conv.hasImage || conv.imageEvents && conv.imageEvents.length > 0) {
4070
+ setActiveTab("image");
4071
+ } else if (conv.hasSpeech || conv.speechEvents && conv.speechEvents.length > 0) {
4072
+ setActiveTab("speech");
4073
+ } else if (conv.hasTranscription || conv.transcriptionEvents && conv.transcriptionEvents.length > 0) {
4074
+ setActiveTab("transcription");
4075
+ } else if (conv.hasVideo || conv.videoEvents && conv.videoEvents.length > 0) {
4076
+ setActiveTab("video");
4077
+ } else {
4078
+ setActiveTab("messages");
4079
+ }
4080
+ }
4081
+ }
4082
+ });
4083
+ return createComponent(Show, {
4084
+ get when() {
4085
+ return activeConversation();
4086
+ },
4087
+ get fallback() {
4088
+ return ssr(_tmpl$21, ssrAttribute("class", escape(styles().conversationDetails.emptyState, true), false));
4089
+ },
4090
+ children: (conv) => ssr(_tmpl$214, ssrAttribute("class", escape(styles().conversationDetails.container, true), false), escape(createComponent(ConversationHeader, {
4091
+ get conversation() {
4092
+ return conv();
4093
+ }
4094
+ })), escape(createComponent(ConversationTabs, {
4095
+ get conversation() {
4096
+ return conv();
4097
+ },
4098
+ get activeTab() {
4099
+ return activeTab();
4100
+ },
4101
+ onTabChange: setActiveTab
4102
+ })), ssrAttribute("class", escape(styles().conversationDetails.contentArea, true), false), escape(createComponent(Show, {
4103
+ get when() {
4104
+ return activeTab() === "messages";
4105
+ },
4106
+ get children() {
4107
+ return createComponent(MessagesTab, {
4108
+ get messages() {
4109
+ return conv().messages;
4110
+ }
4111
+ });
4112
+ }
4113
+ })), escape(createComponent(Show, {
4114
+ get when() {
4115
+ return activeTab() === "chunks";
4116
+ },
4117
+ get children() {
4118
+ return createComponent(ChunksTab, {
4119
+ get chunks() {
4120
+ return conv().chunks;
4121
+ },
4122
+ get messages() {
4123
+ return conv().messages;
4124
+ }
4125
+ });
4126
+ }
4127
+ })), escape(createComponent(Show, {
4128
+ get when() {
4129
+ return activeTab() === "summaries";
4130
+ },
4131
+ get children() {
4132
+ return createComponent(SummariesTab, {
4133
+ get summaries() {
4134
+ return conv().summaries ?? [];
4135
+ }
4136
+ });
4137
+ }
4138
+ })), escape(createComponent(Show, {
4139
+ get when() {
4140
+ return activeTab() === "image";
4141
+ },
4142
+ get children() {
4143
+ return createComponent(ActivityEventsTab, {
4144
+ title: "Image Activity",
4145
+ get events() {
4146
+ return conv().imageEvents ?? [];
4147
+ }
4148
+ });
4149
+ }
4150
+ })), escape(createComponent(Show, {
4151
+ get when() {
4152
+ return activeTab() === "speech";
4153
+ },
4154
+ get children() {
4155
+ return createComponent(ActivityEventsTab, {
4156
+ title: "Speech Activity",
4157
+ get events() {
4158
+ return conv().speechEvents ?? [];
4159
+ }
4160
+ });
4161
+ }
4162
+ })), escape(createComponent(Show, {
4163
+ get when() {
4164
+ return activeTab() === "transcription";
4165
+ },
4166
+ get children() {
4167
+ return createComponent(ActivityEventsTab, {
4168
+ title: "Transcription Activity",
4169
+ get events() {
4170
+ return conv().transcriptionEvents ?? [];
4171
+ }
4172
+ });
4173
+ }
4174
+ })), escape(createComponent(Show, {
4175
+ get when() {
4176
+ return activeTab() === "video";
4177
+ },
4178
+ get children() {
4179
+ return createComponent(ActivityEventsTab, {
4180
+ title: "Video Activity",
4181
+ get events() {
4182
+ return conv().videoEvents ?? [];
4183
+ }
4184
+ });
4185
+ }
4186
+ })))
4187
+ });
4188
+ };
4189
+
4190
+ // src/components/Shell.tsx
4191
+ var _tmpl$30 = ["<div", "><div", ' style="', '"><div', ">Active Conversations</div>", '</div><div class="', '"></div><div', ' style="', '">', "</div></div>"];
4192
+ function Devtools() {
4193
+ return createComponent(AIProvider, {
4194
+ get children() {
4195
+ return createComponent(DevtoolsContent, {});
4196
+ }
4197
+ });
4198
+ }
4199
+ function DevtoolsContent() {
4200
+ const styles = useStyles();
4201
+ const [leftPanelWidth, setLeftPanelWidth] = createSignal(300);
4202
+ const [isDragging, setIsDragging] = createSignal(false);
4203
+ let dragStartX = 0;
4204
+ let dragStartWidth = 0;
4205
+ const handleMouseMove = (e) => {
4206
+ if (!isDragging()) return;
4207
+ e.preventDefault();
4208
+ const deltaX = e.clientX - dragStartX;
4209
+ const newWidth = Math.max(150, Math.min(800, dragStartWidth + deltaX));
4210
+ setLeftPanelWidth(newWidth);
4211
+ };
4212
+ const handleMouseUp = () => {
4213
+ setIsDragging(false);
4214
+ document.body.style.cursor = "";
4215
+ document.body.style.userSelect = "";
4216
+ };
4217
+ onMount(() => {
4218
+ document.addEventListener("mousemove", handleMouseMove);
4219
+ document.addEventListener("mouseup", handleMouseUp);
4220
+ });
4221
+ onCleanup(() => {
4222
+ document.removeEventListener("mousemove", handleMouseMove);
4223
+ document.removeEventListener("mouseup", handleMouseUp);
4224
+ });
4225
+ return createComponent(MainPanel, {
4226
+ get children() {
4227
+ return [createComponent(Header, {
4228
+ get children() {
4229
+ return createComponent(HeaderLogo, {
4230
+ flavor: {
4231
+ light: "#ec4899",
4232
+ dark: "#ec4899"
4233
+ },
4234
+ children: "TanStack AI"
4235
+ });
4236
+ }
4237
+ }), ssr(_tmpl$30, ssrAttribute("class", escape(styles().mainContainer, true), false), ssrAttribute("class", escape(styles().leftPanel, true), false), ssrStyleProperty("width:", `${escape(leftPanelWidth(), true)}px`) + ssrStyleProperty(";min-width:", "150px") + ssrStyleProperty(";max-width:", "800px"), ssrAttribute("class", escape(styles().shell.sectionHeader, true), false), escape(createComponent(ConversationsList, {})), `${escape(styles().dragHandle, true)} ${isDragging() ? "dragging" : ""}`, ssrAttribute("class", escape(styles().rightPanel, true), false), ssrStyleProperty("flex:", 1), escape(createComponent(ConversationDetails, {})))];
4238
+ }
4239
+ });
4240
+ }
4241
+
4242
+ export { Devtools as default };