@tanstack/ai-devtools-core 0.3.38 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) 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/env.d.ts +5 -0
  29. package/src/store/ai-context.tsx +1165 -159
  30. package/src/store/ai-store.ts +0 -1
  31. package/src/store/hook-registry.ts +815 -0
  32. package/src/store/message-event-utils.ts +60 -0
  33. package/src/styles/use-styles.ts +1558 -99
  34. package/dist/Shell/MRWZEHAJ.js +0 -6225
  35. package/dist/Shell/RRRNZJ5E.js +0 -7560
  36. package/dist/production/Shell/MRWZEHAJ.js +0 -6225
  37. package/dist/production/Shell/RRRNZJ5E.js +0 -7560
  38. package/src/components/ConversationDetails.tsx +0 -216
  39. package/src/components/ConversationsList.tsx +0 -21
  40. package/src/components/conversation/ActivityEventsTab.tsx +0 -57
  41. package/src/components/conversation/ChunkBadges.tsx +0 -51
  42. package/src/components/conversation/ChunkItem.tsx +0 -273
  43. package/src/components/conversation/ChunksCollapsible.tsx +0 -56
  44. package/src/components/conversation/ChunksTab.tsx +0 -87
  45. package/src/components/conversation/ConversationHeader.tsx +0 -106
  46. package/src/components/conversation/ConversationTabs.tsx +0 -205
  47. package/src/components/conversation/MessageCard.tsx +0 -174
  48. package/src/components/conversation/MessageGroup.tsx +0 -101
  49. package/src/components/conversation/MessagesTab.tsx +0 -30
  50. package/src/components/conversation/SummariesTab.tsx +0 -91
  51. package/src/components/conversation/ToolCallDisplay.tsx +0 -99
  52. package/src/components/list/ConversationRow.tsx +0 -85
  53. 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
+ }