@tanstack/ai-devtools-core 0.3.38 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/Shell/DKCFIT6H.js +12142 -0
  2. package/dist/Shell/SLOX2TPU.js +12119 -0
  3. package/dist/Shell/Z6HLJOVZ.js +10170 -0
  4. package/dist/dev.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/production/Shell/DKCFIT6H.js +12142 -0
  7. package/dist/production/Shell/SLOX2TPU.js +12119 -0
  8. package/dist/production/Shell/Z6HLJOVZ.js +10170 -0
  9. package/dist/production/dev.js +1 -1
  10. package/dist/production/index.js +1 -1
  11. package/dist/production/server.js +1 -1
  12. package/dist/server.js +1 -1
  13. package/package.json +4 -4
  14. package/src/components/Shell.tsx +74 -30
  15. package/src/components/conversation/IterationCard.tsx +261 -12
  16. package/src/components/conversation/IterationTimeline.tsx +66 -16
  17. package/src/components/conversation/index.ts +0 -9
  18. package/src/components/hooks/FixtureNamePopover.tsx +69 -0
  19. package/src/components/hooks/GenerationPanel.tsx +847 -0
  20. package/src/components/hooks/HookDashboard.tsx +292 -0
  21. package/src/components/hooks/HookDetails.tsx +1757 -0
  22. package/src/components/hooks/ToolFixtureForm.tsx +347 -0
  23. package/src/components/hooks/hook-dashboard-model.ts +134 -0
  24. package/src/components/hooks/index.ts +4 -0
  25. package/src/components/hooks/preview-messages.ts +117 -0
  26. package/src/components/hooks/preview-model.ts +195 -0
  27. package/src/components/utils/format.ts +0 -58
  28. package/src/store/ai-context.tsx +1165 -159
  29. package/src/store/ai-store.ts +0 -1
  30. package/src/store/hook-registry.ts +815 -0
  31. package/src/store/message-event-utils.ts +60 -0
  32. package/src/styles/use-styles.ts +1558 -99
  33. package/dist/Shell/MRWZEHAJ.js +0 -6225
  34. package/dist/Shell/RRRNZJ5E.js +0 -7560
  35. package/dist/production/Shell/MRWZEHAJ.js +0 -6225
  36. package/dist/production/Shell/RRRNZJ5E.js +0 -7560
  37. package/src/components/ConversationDetails.tsx +0 -216
  38. package/src/components/ConversationsList.tsx +0 -21
  39. package/src/components/conversation/ActivityEventsTab.tsx +0 -57
  40. package/src/components/conversation/ChunkBadges.tsx +0 -51
  41. package/src/components/conversation/ChunkItem.tsx +0 -273
  42. package/src/components/conversation/ChunksCollapsible.tsx +0 -56
  43. package/src/components/conversation/ChunksTab.tsx +0 -87
  44. package/src/components/conversation/ConversationHeader.tsx +0 -106
  45. package/src/components/conversation/ConversationTabs.tsx +0 -205
  46. package/src/components/conversation/MessageCard.tsx +0 -174
  47. package/src/components/conversation/MessageGroup.tsx +0 -101
  48. package/src/components/conversation/MessagesTab.tsx +0 -30
  49. package/src/components/conversation/SummariesTab.tsx +0 -91
  50. package/src/components/conversation/ToolCallDisplay.tsx +0 -99
  51. package/src/components/list/ConversationRow.tsx +0 -85
  52. package/src/components/list/index.ts +0 -1
@@ -0,0 +1,292 @@
1
+ import { For, Show, createMemo } from 'solid-js'
2
+ import { useAIStore } from '../../store/ai-context'
3
+ import { useStyles } from '../../styles/use-styles'
4
+ import { getHookUnseenEventCount } from '../../store/hook-registry'
5
+ import {
6
+ getHookDisplayName,
7
+ groupHooksByCategory,
8
+ isHookRunning,
9
+ visibleHooks,
10
+ } from './hook-dashboard-model'
11
+ import type { HookRecord } from '../../store/hook-registry'
12
+ import type { Component } from 'solid-js'
13
+
14
+ export const HookDashboard: Component = () => {
15
+ const { state, selectHook, selectConversation, clearHooks } = useAIStore()
16
+ const styles = useStyles()
17
+
18
+ const hooks = createMemo(() =>
19
+ visibleHooks(Object.values(state.hooks.hooks)).sort(
20
+ (a, b) => a.registeredAt - b.registeredAt,
21
+ ),
22
+ )
23
+ const hookGroups = createMemo(() => groupHooksByCategory(hooks()))
24
+
25
+ const activeCount = createMemo(() => hooks().length)
26
+ const toolCount = createMemo(() =>
27
+ hooks().reduce((count, hook) => count + hook.tools.length, 0),
28
+ )
29
+ const messageCount = createMemo(() =>
30
+ Object.values(state.conversations).reduce(
31
+ (count, conversation) => count + conversation.messages.length,
32
+ 0,
33
+ ),
34
+ )
35
+ const runCount = createMemo(() => Object.keys(state.hooks.runs).length)
36
+ const totalTokens = createMemo(() =>
37
+ Object.values(state.conversations).reduce(
38
+ (count, conversation) => count + (conversation.usage?.totalTokens ?? 0),
39
+ 0,
40
+ ),
41
+ )
42
+ const runningCount = createMemo(
43
+ () =>
44
+ Object.values(state.hooks.runs).filter(
45
+ (run) => run.status === 'started' || run.status === 'updated',
46
+ ).length,
47
+ )
48
+ const unseenUpdateCount = createMemo(() =>
49
+ hooks().reduce(
50
+ (count, hook) => count + getHookUnseenEventCount(state.hooks, hook.id),
51
+ 0,
52
+ ),
53
+ )
54
+
55
+ const handleSelect = (hook: HookRecord) => {
56
+ selectHook(hook.id)
57
+ if (state.conversations[hook.id]) {
58
+ selectConversation(hook.id)
59
+ }
60
+ }
61
+
62
+ return (
63
+ <div
64
+ class={styles().hookDashboard.container}
65
+ data-testid="ai-devtools-hook-sidebar"
66
+ >
67
+ <div class={styles().hookDashboard.summary}>
68
+ <div
69
+ class={styles().hookDashboard.summaryItem}
70
+ data-testid="ai-devtools-sidebar-active-hooks"
71
+ >
72
+ <span class={styles().hookDashboard.summaryValue}>
73
+ {activeCount()}
74
+ </span>
75
+ <span class={styles().hookDashboard.summaryLabel}>active</span>
76
+ </div>
77
+ <div
78
+ class={styles().hookDashboard.summaryItem}
79
+ data-testid="ai-devtools-sidebar-tools"
80
+ >
81
+ <span class={styles().hookDashboard.summaryValue}>{toolCount()}</span>
82
+ <span class={styles().hookDashboard.summaryLabel}>tools</span>
83
+ </div>
84
+ <div
85
+ class={styles().hookDashboard.summaryItem}
86
+ data-testid="ai-devtools-sidebar-runs"
87
+ >
88
+ <span class={styles().hookDashboard.summaryValue}>{runCount()}</span>
89
+ <span class={styles().hookDashboard.summaryLabel}>runs</span>
90
+ </div>
91
+ <div
92
+ class={styles().hookDashboard.summaryItem}
93
+ data-testid="ai-devtools-sidebar-messages"
94
+ >
95
+ <span class={styles().hookDashboard.summaryValue}>
96
+ {messageCount()}
97
+ </span>
98
+ <span class={styles().hookDashboard.summaryLabel}>messages</span>
99
+ </div>
100
+ <div
101
+ class={styles().hookDashboard.summaryItem}
102
+ data-testid="ai-devtools-sidebar-tokens"
103
+ >
104
+ <span class={styles().hookDashboard.summaryValue}>
105
+ {totalTokens()}
106
+ </span>
107
+ <span class={styles().hookDashboard.summaryLabel}>tokens</span>
108
+ </div>
109
+ <div
110
+ class={styles().hookDashboard.summaryItem}
111
+ data-testid="ai-devtools-sidebar-running-hooks"
112
+ >
113
+ <span class={styles().hookDashboard.summaryValue}>
114
+ {runningCount()}
115
+ </span>
116
+ <span class={styles().hookDashboard.summaryLabel}>running</span>
117
+ </div>
118
+ <div class={styles().hookDashboard.summaryItem}>
119
+ <span class={styles().hookDashboard.summaryValue}>
120
+ {unseenUpdateCount()}
121
+ </span>
122
+ <span class={styles().hookDashboard.summaryLabel}>updates</span>
123
+ </div>
124
+ <button
125
+ class={styles().hookDashboard.clearButton}
126
+ type="button"
127
+ onClick={clearHooks}
128
+ disabled={hooks().length === 0}
129
+ >
130
+ Clear
131
+ </button>
132
+ </div>
133
+
134
+ <Show
135
+ when={hooks().length > 0}
136
+ fallback={
137
+ <div class={styles().hookDashboard.empty}>
138
+ No AI hooks registered yet.
139
+ </div>
140
+ }
141
+ >
142
+ <div class={styles().hookDashboard.list}>
143
+ <button
144
+ type="button"
145
+ data-testid="ai-devtools-dashboard-row"
146
+ class={`${styles().hookDashboard.row} ${
147
+ state.hooks.activeHookId === null
148
+ ? styles().hookDashboard.rowSelected
149
+ : ''
150
+ }`}
151
+ onClick={() => selectHook(null)}
152
+ >
153
+ <div class={styles().hookDashboard.rowMain}>
154
+ <div class={styles().hookDashboard.rowTitleLine}>
155
+ <span class={styles().hookDashboard.rowTitle}>Dashboard</span>
156
+ </div>
157
+ <span class={styles().hookDashboard.rowId}>All hooks</span>
158
+ </div>
159
+ <div class={styles().hookDashboard.rowMeta}>
160
+ <span class={styles().hookDashboard.countBadge}>
161
+ {hookGroups().length} categories
162
+ </span>
163
+ <span class={styles().hookDashboard.countBadge}>
164
+ {hooks().length} hooks
165
+ </span>
166
+ </div>
167
+ </button>
168
+ <For each={hookGroups()}>
169
+ {(group) => (
170
+ <section
171
+ class={styles().hookDashboard.categorySection}
172
+ data-testid="ai-devtools-hook-category"
173
+ data-category={group.id}
174
+ >
175
+ <div class={styles().hookDashboard.categoryHeader}>
176
+ <span class={styles().hookDashboard.categoryLabel}>
177
+ {group.label}
178
+ </span>
179
+ <span class={styles().hookDashboard.categoryCount}>
180
+ {group.hooks.length}
181
+ </span>
182
+ </div>
183
+ <div class={styles().hookDashboard.categoryRows}>
184
+ <For each={group.hooks}>
185
+ {(hook) => {
186
+ const isSelected = createMemo(
187
+ () => state.hooks.activeHookId === hook.id,
188
+ )
189
+ const unseenCount = createMemo(() =>
190
+ getHookUnseenEventCount(state.hooks, hook.id),
191
+ )
192
+ const running = createMemo(() =>
193
+ isHookRunning(hook, state.hooks.runs),
194
+ )
195
+ const hasUnseenUpdates = createMemo(
196
+ () => unseenCount() > 0 && !isSelected(),
197
+ )
198
+ const hasBackgroundActivity = createMemo(
199
+ () => running() && !isSelected(),
200
+ )
201
+
202
+ return (
203
+ <button
204
+ type="button"
205
+ data-testid="ai-devtools-hook-row"
206
+ data-hook-id={hook.id}
207
+ data-hook-name={hook.hookName}
208
+ data-display-name={getHookDisplayName(hook)}
209
+ class={`${styles().hookDashboard.row} ${
210
+ isSelected()
211
+ ? styles().hookDashboard.rowSelected
212
+ : ''
213
+ } ${
214
+ hasBackgroundActivity()
215
+ ? styles().hookDashboard.rowLive
216
+ : ''
217
+ } ${
218
+ hasUnseenUpdates()
219
+ ? styles().hookDashboard.rowUpdating
220
+ : ''
221
+ }`}
222
+ onClick={() => handleSelect(hook)}
223
+ >
224
+ <div class={styles().hookDashboard.rowMain}>
225
+ <div class={styles().hookDashboard.rowTitleLine}>
226
+ <span
227
+ class={styles().hookDashboard.rowTitle}
228
+ data-testid="ai-devtools-hook-display-name"
229
+ >
230
+ {getHookDisplayName(hook)}
231
+ </span>
232
+ <Show when={hasBackgroundActivity()}>
233
+ <span
234
+ class={styles().hookDashboard.liveIndicator}
235
+ aria-label="Hook is receiving updates"
236
+ />
237
+ </Show>
238
+ <Show when={hasUnseenUpdates()}>
239
+ <span
240
+ class={styles().hookDashboard.updateBadge}
241
+ >
242
+ {unseenCount()} new
243
+ </span>
244
+ </Show>
245
+ </div>
246
+ <span class={styles().hookDashboard.rowId}>
247
+ <Show when={hook.displayName} fallback={hook.id}>
248
+ {hook.hookName} - {hook.id}
249
+ </Show>
250
+ </span>
251
+ </div>
252
+ <div class={styles().hookDashboard.rowMeta}>
253
+ <span
254
+ class={`${styles().hookDashboard.lifecycleBadge} ${
255
+ hook.lifecycle === 'streaming'
256
+ ? styles().hookDashboard.lifecycleStreaming
257
+ : hook.lifecycle === 'errored'
258
+ ? styles().hookDashboard.lifecycleErrored
259
+ : ''
260
+ }`}
261
+ >
262
+ {hook.lifecycle}
263
+ </span>
264
+ <Show when={hook.outputKind}>
265
+ <span class={styles().hookDashboard.kindBadge}>
266
+ {hook.outputKind}
267
+ </span>
268
+ </Show>
269
+ <Show when={hook.tools.length > 0}>
270
+ <span class={styles().hookDashboard.countBadge}>
271
+ {hook.tools.length} tools
272
+ </span>
273
+ </Show>
274
+ <Show when={hook.runIds.length > 0}>
275
+ <span class={styles().hookDashboard.countBadge}>
276
+ {hook.runIds.length} runs
277
+ </span>
278
+ </Show>
279
+ </div>
280
+ </button>
281
+ )
282
+ }}
283
+ </For>
284
+ </div>
285
+ </section>
286
+ )}
287
+ </For>
288
+ </div>
289
+ </Show>
290
+ </div>
291
+ )
292
+ }