@tanstack/ai-devtools-core 0.3.31 → 0.3.33

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.
@@ -2,7 +2,7 @@ import { constructCoreClass } from '@tanstack/devtools-utils/solid/class';
2
2
 
3
3
  // src/core.ts
4
4
  var [AiDevtoolsCore, AiDevtoolsCoreNoOp] = constructCoreClass(
5
- () => import('./Shell/E5BETLAK.js')
5
+ () => import('./Shell/RRRNZJ5E.js')
6
6
  );
7
7
 
8
8
  export { AiDevtoolsCore };
@@ -2,7 +2,7 @@ import { constructCoreClass } from '@tanstack/devtools-utils/solid/class';
2
2
 
3
3
  // src/core.ts
4
4
  var [AiDevtoolsCore, AiDevtoolsCoreNoOp] = constructCoreClass(
5
- () => import('./Shell/E5BETLAK.js')
5
+ () => import('./Shell/RRRNZJ5E.js')
6
6
  );
7
7
 
8
8
  export { AiDevtoolsCore };
@@ -2,7 +2,7 @@ import { constructCoreClass } from '@tanstack/devtools-utils/solid/class';
2
2
 
3
3
  // src/core.ts
4
4
  var [AiDevtoolsCore, AiDevtoolsCoreNoOp] = constructCoreClass(
5
- () => import('./Shell/KINKIMWF.js')
5
+ () => import('./Shell/MRWZEHAJ.js')
6
6
  );
7
7
 
8
8
  export { AiDevtoolsCore };
package/dist/server.js CHANGED
@@ -2,7 +2,7 @@ import { constructCoreClass } from '@tanstack/devtools-utils/solid/class';
2
2
 
3
3
  // src/core.ts
4
4
  var [AiDevtoolsCore, AiDevtoolsCoreNoOp] = constructCoreClass(
5
- () => import('./Shell/KINKIMWF.js')
5
+ () => import('./Shell/MRWZEHAJ.js')
6
6
  );
7
7
 
8
8
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-devtools-core",
3
- "version": "0.3.31",
3
+ "version": "0.3.33",
4
4
  "description": "Core TanStack AI Devtools",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -72,8 +72,8 @@
72
72
  "@tanstack/devtools-utils": "^0.4.0",
73
73
  "goober": "^2.1.18",
74
74
  "solid-js": "^1.9.10",
75
- "@tanstack/ai": "0.19.1",
76
- "@tanstack/ai-event-client": "0.3.4"
75
+ "@tanstack/ai": "0.20.1",
76
+ "@tanstack/ai-event-client": "0.3.6"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@vitest/coverage-v8": "4.0.14",
@@ -28,10 +28,12 @@ export const ChunksTab: Component<ChunksTabProps> = (props) => {
28
28
 
29
29
  props.chunks.forEach((chunk) => {
30
30
  const key = chunk.messageId || 'no-message-id'
31
- if (!groups.has(key)) {
32
- groups.set(key, [])
31
+ let group = groups.get(key)
32
+ if (!group) {
33
+ group = []
34
+ groups.set(key, group)
33
35
  }
34
- groups.get(key)!.push(chunk)
36
+ group.push(chunk)
35
37
  })
36
38
 
37
39
  return Array.from(groups.entries())
@@ -16,8 +16,9 @@ export const ConversationHeader: Component<ConversationHeaderProps> = (
16
16
 
17
17
  const iterationCount = () => conv().iterationCount ?? conv().iterations.length
18
18
  const totalDuration = () => {
19
- if (!conv().completedAt) return undefined
20
- return conv().completedAt! - conv().startedAt
19
+ const completedAt = conv().completedAt
20
+ if (!completedAt) return undefined
21
+ return completedAt - conv().startedAt
21
22
  }
22
23
 
23
24
  const totalMessages = () => conv().messages.length
@@ -124,8 +124,10 @@ const MiddlewareStep: Component<{
124
124
  return null
125
125
  }
126
126
 
127
- const hasChanges = () =>
128
- ev().configChanges && Object.keys(ev().configChanges!).length > 0
127
+ const hasChanges = () => {
128
+ const changes = ev().configChanges
129
+ return changes && Object.keys(changes).length > 0
130
+ }
129
131
 
130
132
  return (
131
133
  <>
@@ -386,8 +388,9 @@ export const IterationCard: Component<IterationCardProps> = (props) => {
386
388
  const isError = () => iter().finishReason === 'error'
387
389
 
388
390
  const duration = () => {
389
- if (!iter().completedAt) return undefined
390
- return iter().completedAt! - iter().startedAt
391
+ const completedAt = iter().completedAt
392
+ if (!completedAt) return undefined
393
+ return completedAt - iter().startedAt
391
394
  }
392
395
 
393
396
  const label = () => getIterationLabel(iter(), props.index)
@@ -417,8 +420,9 @@ export const IterationCard: Component<IterationCardProps> = (props) => {
417
420
  })
418
421
 
419
422
  const finishLabel = () => {
420
- if (!iter().finishReason) return null
421
- switch (iter().finishReason) {
423
+ const reason = iter().finishReason
424
+ if (!reason) return null
425
+ switch (reason) {
422
426
  case 'stop':
423
427
  return 'completed'
424
428
  case 'tool_calls':
@@ -428,7 +432,7 @@ export const IterationCard: Component<IterationCardProps> = (props) => {
428
432
  case 'length':
429
433
  return 'max length'
430
434
  default:
431
- return iter().finishReason
435
+ return reason
432
436
  }
433
437
  }
434
438
 
@@ -441,9 +445,10 @@ export const IterationCard: Component<IterationCardProps> = (props) => {
441
445
 
442
446
  // Config data from this iteration
443
447
  const configSubtitle = () => {
448
+ const { model, provider } = iter()
444
449
  const parts: Array<string> = []
445
- if (iter().model) parts.push(iter().model!)
446
- if (iter().provider) parts.push(iter().provider!)
450
+ if (model) parts.push(model)
451
+ if (provider) parts.push(provider)
447
452
  return parts.length > 0 ? parts.join(' \u00B7 ') : null
448
453
  }
449
454
 
@@ -610,12 +615,14 @@ export const IterationCard: Component<IterationCardProps> = (props) => {
610
615
  </span>
611
616
  </Show>
612
617
  <Show when={deltaUsage()}>
613
- <span
614
- class={`${s().badge} ${s().badgeUsage}`}
615
- title={`Prompt: ${deltaUsage()!.promptTokens.toLocaleString()} | Completion: ${deltaUsage()!.completionTokens.toLocaleString()}`}
616
- >
617
- 🎯 {deltaUsage()!.totalTokens.toLocaleString()}
618
- </span>
618
+ {(usage) => (
619
+ <span
620
+ class={`${s().badge} ${s().badgeUsage}`}
621
+ title={`Prompt: ${usage().promptTokens.toLocaleString()} | Completion: ${usage().completionTokens.toLocaleString()}`}
622
+ >
623
+ 🎯 {usage().totalTokens.toLocaleString()}
624
+ </span>
625
+ )}
619
626
  </Show>
620
627
  <Show when={isActive()}>
621
628
  <span class={`${s().badge} ${s().badgeDuration}`}>⟳ streaming</span>
@@ -39,8 +39,7 @@ export const IterationTimeline: Component<IterationTimelineProps> = (props) => {
39
39
  (a, b) => a.timestamp - b.timestamp,
40
40
  )
41
41
 
42
- for (let u = 0; u < sortedUsers.length; u++) {
43
- const currentUser = sortedUsers[u]!
42
+ for (const [u, currentUser] of sortedUsers.entries()) {
44
43
  const nextUser = sortedUsers[u + 1]
45
44
 
46
45
  const groupIters = iters.filter((it) => {
@@ -55,9 +54,10 @@ export const IterationTimeline: Component<IterationTimelineProps> = (props) => {
55
54
  }
56
55
 
57
56
  // Catch any iterations before the first user message
58
- if (sortedUsers[0]) {
57
+ const firstUser = sortedUsers[0]
58
+ if (firstUser) {
59
59
  const earlyIters = iters.filter(
60
- (it) => it.startedAt < sortedUsers[0]!.timestamp,
60
+ (it) => it.startedAt < firstUser.timestamp,
61
61
  )
62
62
  if (earlyIters.length > 0) {
63
63
  result.unshift({ userMessage: null, iterations: earlyIters })
@@ -332,12 +332,14 @@ const UserMessageGroupCard: Component<{
332
332
  </span>
333
333
  </Show>
334
334
  <Show when={totalUsage()}>
335
- <span
336
- class={`${s().badge} ${s().badgeUsage}`}
337
- title={`Prompt: ${totalUsage()!.promptTokens.toLocaleString()} | Completion: ${totalUsage()!.completionTokens.toLocaleString()}`}
338
- >
339
- 🎯 {totalUsage()!.totalTokens.toLocaleString()}
340
- </span>
335
+ {(usage) => (
336
+ <span
337
+ class={`${s().badge} ${s().badgeUsage}`}
338
+ title={`Prompt: ${usage().promptTokens.toLocaleString()} | Completion: ${usage().completionTokens.toLocaleString()}`}
339
+ >
340
+ 🎯 {usage().totalTokens.toLocaleString()}
341
+ </span>
342
+ )}
341
343
  </Show>
342
344
  <Show when={isActive()}>
343
345
  <span class={`${s().badge} ${s().badgeDuration}`}>⟳ streaming</span>
@@ -141,20 +141,22 @@ export const MessageCard: Component<MessageCardProps> = (props) => {
141
141
  </Show>
142
142
 
143
143
  <Show
144
- when={msg().role === 'tool' && parseJsonContent() !== null}
144
+ when={msg().role === 'tool' && parseJsonContent()}
145
145
  fallback={
146
146
  <div class={styles().conversationDetails.messageContent}>
147
147
  {msg().content}
148
148
  </div>
149
149
  }
150
150
  >
151
- <div class={styles().conversationDetails.toolJsonContainer}>
152
- <JsonTree value={parseJsonContent()!} />
153
- </div>
151
+ {(parsed) => (
152
+ <div class={styles().conversationDetails.toolJsonContainer}>
153
+ <JsonTree value={parsed()} />
154
+ </div>
155
+ )}
154
156
  </Show>
155
157
 
156
158
  {/* Tool Calls Display */}
157
- <Show when={msg().toolCalls && msg().toolCalls!.length > 0}>
159
+ <Show when={msg().toolCalls?.length}>
158
160
  <div class={styles().conversationDetails.toolCallsContainer}>
159
161
  <For each={msg().toolCalls}>
160
162
  {(tool) => <ToolCallDisplay tool={tool} />}
@@ -163,8 +165,8 @@ export const MessageCard: Component<MessageCardProps> = (props) => {
163
165
  </Show>
164
166
 
165
167
  {/* Chunks Display (for client conversations with server chunks) */}
166
- <Show when={msg().chunks && msg().chunks!.length > 0}>
167
- <ChunksCollapsible chunks={msg().chunks!} />
168
+ <Show when={msg().chunks?.length ? msg().chunks : null}>
169
+ {(chunks) => <ChunksCollapsible chunks={chunks()} />}
168
170
  </Show>
169
171
  </div>
170
172
  </div>
@@ -53,7 +53,7 @@ export const ToolCallDisplay: Component<ToolCallDisplayProps> = (props) => {
53
53
  >
54
54
  {tool().state}
55
55
  </div>
56
- <Show when={tool().duration !== undefined && tool().duration! > 0}>
56
+ <Show when={(tool().duration ?? 0) > 0}>
57
57
  <div class={styles().conversationDetails.durationBadge}>
58
58
  ⏱️ {formatDuration(tool().duration)}
59
59
  </div>
@@ -29,6 +29,8 @@ export const getChunkTypeColor = (type: Chunk['type']): string => {
29
29
  return '#ef4444' // red
30
30
  case 'approval':
31
31
  return '#f59e0b' // orange/amber
32
+ case 'thinking':
33
+ return '#a855f7' // violet
32
34
  default:
33
35
  return '#6b7280' // gray
34
36
  }
@@ -126,8 +126,8 @@ export interface Iteration {
126
126
  provider?: string
127
127
  systemPrompts?: Array<string>
128
128
  toolNames?: Array<string>
129
- options?: Record<string, unknown>
130
- modelOptions?: Record<string, unknown>
129
+ options?: Record<string, unknown> | undefined
130
+ modelOptions?: Record<string, unknown> | undefined
131
131
  finishReason?: string
132
132
  usage?: TokenUsage
133
133
  middlewareEvents: Array<MiddlewareEvent>
@@ -166,8 +166,8 @@ export interface Conversation {
166
166
  iterations: Array<Iteration>
167
167
  iterationCount?: number
168
168
  toolNames?: Array<string>
169
- options?: Record<string, unknown>
170
- modelOptions?: Record<string, unknown>
169
+ options?: Record<string, unknown> | undefined
170
+ modelOptions?: Record<string, unknown> | undefined
171
171
  systemPrompts?: Array<string>
172
172
  /** Flags for which operation types this conversation has */
173
173
  hasChat?: boolean
@@ -328,13 +328,11 @@ export const AIProvider: ParentComponent = (props) => {
328
328
  }
329
329
 
330
330
  function queueChunk(conversationId: string, chunk: Chunk): void {
331
- if (!pendingConversationChunks.has(conversationId)) {
332
- pendingConversationChunks.set(conversationId, {
333
- chunks: [],
334
- newChunkCount: 0,
335
- })
331
+ let pending = pendingConversationChunks.get(conversationId)
332
+ if (!pending) {
333
+ pending = { chunks: [], newChunkCount: 0 }
334
+ pendingConversationChunks.set(conversationId, pending)
336
335
  }
337
- const pending = pendingConversationChunks.get(conversationId)!
338
336
 
339
337
  // Pre-merge in pending buffer to reduce array operations during flush
340
338
  const lastPending = pending.chunks[pending.chunks.length - 1]
@@ -361,14 +359,16 @@ export const AIProvider: ParentComponent = (props) => {
361
359
  messageIndex: number,
362
360
  chunk: Chunk,
363
361
  ): void {
364
- if (!pendingMessageChunks.has(conversationId)) {
365
- pendingMessageChunks.set(conversationId, new Map())
362
+ let messageMap = pendingMessageChunks.get(conversationId)
363
+ if (!messageMap) {
364
+ messageMap = new Map()
365
+ pendingMessageChunks.set(conversationId, messageMap)
366
366
  }
367
- const messageMap = pendingMessageChunks.get(conversationId)!
368
- if (!messageMap.has(messageIndex)) {
369
- messageMap.set(messageIndex, { chunks: [], newChunkCount: 0 })
367
+ let pending = messageMap.get(messageIndex)
368
+ if (!pending) {
369
+ pending = { chunks: [], newChunkCount: 0 }
370
+ messageMap.set(messageIndex, pending)
370
371
  }
371
- const pending = messageMap.get(messageIndex)!
372
372
 
373
373
  // Pre-merge in pending buffer
374
374
  const lastPending = pending.chunks[pending.chunks.length - 1]
@@ -605,7 +605,7 @@ export const AIProvider: ParentComponent = (props) => {
605
605
  'conversations',
606
606
  conversationId,
607
607
  key as keyof Conversation,
608
- value as Conversation[keyof Conversation],
608
+ value,
609
609
  )
610
610
  }
611
611
  }
@@ -624,7 +624,7 @@ export const AIProvider: ParentComponent = (props) => {
624
624
  'messages',
625
625
  messageIndex,
626
626
  key as keyof Message,
627
- value as Message[keyof Message],
627
+ value,
628
628
  )
629
629
  }
630
630
  }
@@ -816,14 +816,12 @@ export const AIProvider: ParentComponent = (props) => {
816
816
  content: part.content,
817
817
  }
818
818
  }
819
- // Handle multimodal parts (image, audio, video, document)
819
+ // Handle multimodal parts (image, audio, video)
820
820
  // These have a source property instead of content
821
821
  if (
822
822
  part.type === 'image' ||
823
823
  part.type === 'audio' ||
824
- part.type === 'video' ||
825
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
826
- part.type === 'document'
824
+ part.type === 'video'
827
825
  ) {
828
826
  return {
829
827
  type: part.type,