@tanstack/ai-devtools-core 0.3.37 → 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.
- package/dist/Shell/DKCFIT6H.js +12142 -0
- package/dist/Shell/SLOX2TPU.js +12119 -0
- package/dist/Shell/Z6HLJOVZ.js +10170 -0
- package/dist/dev.js +1 -1
- package/dist/index.js +1 -1
- package/dist/production/Shell/DKCFIT6H.js +12142 -0
- package/dist/production/Shell/SLOX2TPU.js +12119 -0
- package/dist/production/Shell/Z6HLJOVZ.js +10170 -0
- package/dist/production/dev.js +1 -1
- package/dist/production/index.js +1 -1
- package/dist/production/server.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +4 -4
- package/src/components/Shell.tsx +74 -30
- package/src/components/conversation/IterationCard.tsx +261 -12
- package/src/components/conversation/IterationTimeline.tsx +66 -16
- package/src/components/conversation/index.ts +0 -9
- package/src/components/hooks/FixtureNamePopover.tsx +69 -0
- package/src/components/hooks/GenerationPanel.tsx +847 -0
- package/src/components/hooks/HookDashboard.tsx +292 -0
- package/src/components/hooks/HookDetails.tsx +1757 -0
- package/src/components/hooks/ToolFixtureForm.tsx +347 -0
- package/src/components/hooks/hook-dashboard-model.ts +134 -0
- package/src/components/hooks/index.ts +4 -0
- package/src/components/hooks/preview-messages.ts +117 -0
- package/src/components/hooks/preview-model.ts +195 -0
- package/src/components/utils/format.ts +0 -58
- package/src/store/ai-context.tsx +1165 -159
- package/src/store/ai-store.ts +0 -1
- package/src/store/hook-registry.ts +815 -0
- package/src/store/message-event-utils.ts +60 -0
- package/src/styles/use-styles.ts +1558 -99
- package/dist/Shell/MRWZEHAJ.js +0 -6225
- package/dist/Shell/RRRNZJ5E.js +0 -7560
- package/dist/production/Shell/MRWZEHAJ.js +0 -6225
- package/dist/production/Shell/RRRNZJ5E.js +0 -7560
- package/src/components/ConversationDetails.tsx +0 -216
- package/src/components/ConversationsList.tsx +0 -21
- package/src/components/conversation/ActivityEventsTab.tsx +0 -57
- package/src/components/conversation/ChunkBadges.tsx +0 -51
- package/src/components/conversation/ChunkItem.tsx +0 -273
- package/src/components/conversation/ChunksCollapsible.tsx +0 -56
- package/src/components/conversation/ChunksTab.tsx +0 -87
- package/src/components/conversation/ConversationHeader.tsx +0 -106
- package/src/components/conversation/ConversationTabs.tsx +0 -205
- package/src/components/conversation/MessageCard.tsx +0 -174
- package/src/components/conversation/MessageGroup.tsx +0 -101
- package/src/components/conversation/MessagesTab.tsx +0 -30
- package/src/components/conversation/SummariesTab.tsx +0 -91
- package/src/components/conversation/ToolCallDisplay.tsx +0 -99
- package/src/components/list/ConversationRow.tsx +0 -85
- package/src/components/list/index.ts +0 -1
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { For, Index, Show, createMemo, createSignal } from 'solid-js'
|
|
2
2
|
import { JsonTree } from '@tanstack/devtools-ui'
|
|
3
3
|
import { useStyles } from '../../styles/use-styles'
|
|
4
|
+
import {
|
|
5
|
+
createHoverTarget,
|
|
6
|
+
getHoverDataAttributes,
|
|
7
|
+
isMessageHighlighted,
|
|
8
|
+
} from '../hooks/preview-model'
|
|
4
9
|
import { formatDuration } from '../utils'
|
|
5
10
|
import { IterationCard } from './IterationCard'
|
|
11
|
+
import type { HoverTarget } from '../hooks/preview-model'
|
|
6
12
|
import type { Iteration, Message } from '../../store/ai-store'
|
|
7
13
|
import type { Component } from 'solid-js'
|
|
8
14
|
|
|
@@ -15,6 +21,8 @@ interface UserMessageGroup {
|
|
|
15
21
|
interface IterationTimelineProps {
|
|
16
22
|
iterations: Array<Iteration>
|
|
17
23
|
messages: Array<Message>
|
|
24
|
+
hoverTarget?: HoverTarget | null
|
|
25
|
+
onHoverTarget?: (target: HoverTarget | null) => void
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
export const IterationTimeline: Component<IterationTimelineProps> = (props) => {
|
|
@@ -79,6 +87,8 @@ export const IterationTimeline: Component<IterationTimelineProps> = (props) => {
|
|
|
79
87
|
<UserMessageGroupCard
|
|
80
88
|
group={group()}
|
|
81
89
|
allMessages={props.messages}
|
|
90
|
+
hoverTarget={props.hoverTarget ?? null}
|
|
91
|
+
onHoverTarget={props.onHoverTarget}
|
|
82
92
|
/>
|
|
83
93
|
)}
|
|
84
94
|
</Index>
|
|
@@ -127,6 +137,8 @@ export const SystemPromptItem: Component<{ prompt: string; index: number }> = (
|
|
|
127
137
|
const UserMessageGroupCard: Component<{
|
|
128
138
|
group: UserMessageGroup
|
|
129
139
|
allMessages: Array<Message>
|
|
140
|
+
hoverTarget: HoverTarget | null
|
|
141
|
+
onHoverTarget?: (target: HoverTarget | null) => void
|
|
130
142
|
}> = (props) => {
|
|
131
143
|
const styles = useStyles()
|
|
132
144
|
const s = () => styles().iterationTimeline
|
|
@@ -135,6 +147,7 @@ const UserMessageGroupCard: Component<{
|
|
|
135
147
|
|
|
136
148
|
const group = () => props.group
|
|
137
149
|
const userMsg = () => group().userMessage
|
|
150
|
+
const userMessageId = () => userMsg()?.id
|
|
138
151
|
const iters = () => group().iterations
|
|
139
152
|
|
|
140
153
|
const totalDuration = createMemo(() => {
|
|
@@ -170,42 +183,42 @@ const UserMessageGroupCard: Component<{
|
|
|
170
183
|
return count
|
|
171
184
|
})
|
|
172
185
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
186
|
+
// Iterations store CUMULATIVE usage per request, so keep the MAX totalTokens
|
|
187
|
+
// reading per requestId. Comparing on totalTokens directly (not prompt +
|
|
188
|
+
// completion) is necessary because some providers — Anthropic, OpenAI o-series
|
|
189
|
+
// — bundle reasoning tokens into totalTokens that are not summed into
|
|
190
|
+
// prompt + completion, and a later reading with fewer reasoning tokens would
|
|
191
|
+
// otherwise overwrite a larger earlier one.
|
|
179
192
|
const totalUsage = createMemo(() => {
|
|
180
193
|
const maxByRequest = new Map<
|
|
181
194
|
string,
|
|
182
|
-
{ prompt: number; completion: number }
|
|
195
|
+
{ prompt: number; completion: number; total: number }
|
|
183
196
|
>()
|
|
184
197
|
for (const it of iters()) {
|
|
185
198
|
if (!it.usage) continue
|
|
186
199
|
const key = it.requestId || '__default__'
|
|
187
200
|
const existing = maxByRequest.get(key)
|
|
188
|
-
if (
|
|
189
|
-
!existing ||
|
|
190
|
-
it.usage.totalTokens > existing.prompt + existing.completion
|
|
191
|
-
) {
|
|
201
|
+
if (!existing || it.usage.totalTokens > existing.total) {
|
|
192
202
|
maxByRequest.set(key, {
|
|
193
203
|
prompt: it.usage.promptTokens,
|
|
194
204
|
completion: it.usage.completionTokens,
|
|
205
|
+
total: it.usage.totalTokens,
|
|
195
206
|
})
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
209
|
let prompt = 0
|
|
199
210
|
let completion = 0
|
|
211
|
+
let total = 0
|
|
200
212
|
for (const v of maxByRequest.values()) {
|
|
201
213
|
prompt += v.prompt
|
|
202
214
|
completion += v.completion
|
|
215
|
+
total += v.total
|
|
203
216
|
}
|
|
204
|
-
if (
|
|
217
|
+
if (total === 0) return undefined
|
|
205
218
|
return {
|
|
206
219
|
promptTokens: prompt,
|
|
207
220
|
completionTokens: completion,
|
|
208
|
-
totalTokens:
|
|
221
|
+
totalTokens: total,
|
|
209
222
|
}
|
|
210
223
|
})
|
|
211
224
|
|
|
@@ -228,6 +241,29 @@ const UserMessageGroupCard: Component<{
|
|
|
228
241
|
return text.length > 120 ? text.slice(0, 120) + '...' : text
|
|
229
242
|
}
|
|
230
243
|
|
|
244
|
+
const handleUserMouseEnter = () => {
|
|
245
|
+
const messageId = userMessageId()
|
|
246
|
+
if (messageId) {
|
|
247
|
+
props.onHoverTarget?.(
|
|
248
|
+
createHoverTarget({
|
|
249
|
+
messageIds: [messageId],
|
|
250
|
+
origin: 'timeline',
|
|
251
|
+
}),
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const handleUserMouseLeave = () => {
|
|
257
|
+
props.onHoverTarget?.(null)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const isUserMessageHighlighted = () => {
|
|
261
|
+
const messageId = userMessageId()
|
|
262
|
+
return messageId
|
|
263
|
+
? isMessageHighlighted(messageId, props.hoverTarget)
|
|
264
|
+
: false
|
|
265
|
+
}
|
|
266
|
+
|
|
231
267
|
// Config from the first iteration of this group
|
|
232
268
|
const firstIter = createMemo(() => iters()[0])
|
|
233
269
|
|
|
@@ -262,9 +298,21 @@ const UserMessageGroupCard: Component<{
|
|
|
262
298
|
toolNames().length > 0 || systemPrompts().length > 0 || hasModelOptions()
|
|
263
299
|
|
|
264
300
|
return (
|
|
265
|
-
<div
|
|
301
|
+
<div
|
|
302
|
+
{...getHoverDataAttributes({
|
|
303
|
+
messageIds: userMessageId() ? [userMessageId() ?? ''] : [],
|
|
304
|
+
})}
|
|
305
|
+
class={`${s().card} ${groupAccentClass()} ${
|
|
306
|
+
isUserMessageHighlighted() ? s().cardHighlighted : ''
|
|
307
|
+
}`}
|
|
308
|
+
>
|
|
266
309
|
{/* User message header */}
|
|
267
|
-
<div
|
|
310
|
+
<div
|
|
311
|
+
class={s().cardHeader}
|
|
312
|
+
onClick={() => setIsOpen(!isOpen())}
|
|
313
|
+
onMouseEnter={handleUserMouseEnter}
|
|
314
|
+
onMouseLeave={handleUserMouseLeave}
|
|
315
|
+
>
|
|
268
316
|
<div class={s().userBubble}>U</div>
|
|
269
317
|
<div class={s().cardHeaderContent}>
|
|
270
318
|
<span class={s().cardHeaderLabel}>{userContent()}</span>
|
|
@@ -390,7 +438,7 @@ const UserMessageGroupCard: Component<{
|
|
|
390
438
|
<span class={s().configPanelLabel}>Model Options</span>
|
|
391
439
|
<div class={s().configJsonTreeContainer}>
|
|
392
440
|
<JsonTree
|
|
393
|
-
value={modelOptions()
|
|
441
|
+
value={modelOptions()}
|
|
394
442
|
defaultExpansionDepth={2}
|
|
395
443
|
copyable
|
|
396
444
|
/>
|
|
@@ -415,6 +463,8 @@ const UserMessageGroupCard: Component<{
|
|
|
415
463
|
messages={props.allMessages}
|
|
416
464
|
index={index()}
|
|
417
465
|
isLast={index() === iters().length - 1}
|
|
466
|
+
hoverTarget={props.hoverTarget}
|
|
467
|
+
onHoverTarget={props.onHoverTarget}
|
|
418
468
|
/>
|
|
419
469
|
)}
|
|
420
470
|
</For>
|
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
export { ConversationHeader } from './ConversationHeader'
|
|
2
|
-
export { ConversationTabs } from './ConversationTabs'
|
|
3
|
-
export type { TabType } from './ConversationTabs'
|
|
4
|
-
|
|
5
|
-
export { MessagesTab } from './MessagesTab'
|
|
6
|
-
export { ChunksTab } from './ChunksTab'
|
|
7
|
-
export { SummariesTab } from './SummariesTab'
|
|
8
|
-
export { ActivityEventsTab } from './ActivityEventsTab'
|
|
9
|
-
|
|
10
1
|
export { IterationTimeline } from './IterationTimeline'
|
|
11
2
|
export { IterationCard } from './IterationCard'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createEffect, createSignal } from 'solid-js'
|
|
2
|
+
import { useStyles } from '../../styles/use-styles'
|
|
3
|
+
import type { Component } from 'solid-js'
|
|
4
|
+
|
|
5
|
+
interface FixtureNamePopoverProps {
|
|
6
|
+
defaultName: string
|
|
7
|
+
onCancel: () => void
|
|
8
|
+
onSave: (name: string) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const FixtureNamePopover: Component<FixtureNamePopoverProps> = (
|
|
12
|
+
props,
|
|
13
|
+
) => {
|
|
14
|
+
const styles = useStyles()
|
|
15
|
+
const [name, setName] = createSignal(props.defaultName)
|
|
16
|
+
let input: HTMLInputElement | undefined
|
|
17
|
+
|
|
18
|
+
createEffect(() => {
|
|
19
|
+
setName(props.defaultName)
|
|
20
|
+
queueMicrotask(() => input?.focus())
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const handleSave = () => {
|
|
24
|
+
const trimmedName = name().trim()
|
|
25
|
+
if (!trimmedName) return
|
|
26
|
+
props.onSave(trimmedName)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<form
|
|
31
|
+
class={styles().hookDetails.fixturePopover}
|
|
32
|
+
data-testid="ai-devtools-fixture-save-popover"
|
|
33
|
+
onSubmit={(event) => {
|
|
34
|
+
event.preventDefault()
|
|
35
|
+
handleSave()
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<label class={styles().hookDetails.fixtureField}>
|
|
39
|
+
<span class={styles().hookDetails.fixtureLabel}>Fixture name</span>
|
|
40
|
+
<input
|
|
41
|
+
ref={(element) => {
|
|
42
|
+
input = element
|
|
43
|
+
}}
|
|
44
|
+
class={styles().hookDetails.fixtureInput}
|
|
45
|
+
data-testid="ai-devtools-fixture-name-input"
|
|
46
|
+
value={name()}
|
|
47
|
+
onInput={(event) => setName(event.currentTarget.value)}
|
|
48
|
+
/>
|
|
49
|
+
</label>
|
|
50
|
+
<div class={styles().hookDetails.fixtureActions}>
|
|
51
|
+
<button
|
|
52
|
+
class={styles().hookDetails.fixtureButton}
|
|
53
|
+
data-testid="ai-devtools-fixture-save-confirm"
|
|
54
|
+
type="submit"
|
|
55
|
+
>
|
|
56
|
+
Save
|
|
57
|
+
</button>
|
|
58
|
+
<button
|
|
59
|
+
class={`${styles().hookDetails.fixtureButton} ${styles().hookDetails.fixtureButtonSecondary}`}
|
|
60
|
+
data-testid="ai-devtools-fixture-save-cancel"
|
|
61
|
+
type="button"
|
|
62
|
+
onClick={props.onCancel}
|
|
63
|
+
>
|
|
64
|
+
Cancel
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
</form>
|
|
68
|
+
)
|
|
69
|
+
}
|