Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/ai-devtools-hook-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@tanstack/ai-client': minor
'@tanstack/ai-devtools-core': minor
'@tanstack/ai-event-client': minor
'@tanstack/ai-preact': patch
'@tanstack/ai-react': patch
'@tanstack/ai-solid': patch
'@tanstack/ai-svelte': patch
'@tanstack/ai-vue': patch
---

Add hook-aware AI devtools registration, run tracking, state snapshots, and tool fixture replay.
19 changes: 19 additions & 0 deletions docs/getting-started/devtools.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,30 @@ keywords:
TanStack Devtools is a unified devtools panel for inspecting and debugging TanStack libraries, including TanStack AI. It provides real-time insights into AI interactions, tool calls, and state changes, making it easier to develop and troubleshoot AI-powered applications.

## Features
- **Hook dashboard** - Discover every active TanStack AI hook on the page, including chat, structured output, image, video, audio, speech, transcription, and summarize hooks.
- **Run timeline** - Inspect user turns, linked runs, stream events, client snapshots, and server-only events by `threadId` and `runId`.
- **Real-time Monitoring** - View live chat messages, tool invocations, and AI responses.
- **Tool Call Inspection** - Inspect input and output of tool calls.
- **Tool Fixture Replay** - Build tool payloads from a tool's standard-schema input, append the result into chat messages, and save fixtures in localStorage for repeated UI iteration.
- **State Visualization** - Visualize chat state and message history.
- **Error Tracking** - Monitor errors and exceptions in AI interactions.

## Hook Dashboard

The AI devtools panel listens for active TanStack AI clients and shows them in the left sidebar. Hooks register when they are created, emit a snapshot immediately, and respond again whenever the devtools panel opens or requests state. This keeps hooks discoverable even when the panel is opened after the app has already rendered.

Each hook entry includes its type, lifecycle, message count, run count, and the latest linked `threadId`. Selecting a hook opens the full timeline for that hook. Chat hooks keep the current turn-based view: a user message wraps every run and event that happened while answering that turn. The details view also includes lightweight client/server state snapshots between runs so you can see exactly what changed.

## Tool Fixtures

When a `useChat` hook receives tools, the devtools panel lists those tools and their schemas. For standard-schema-compatible inputs, the panel renders a small form from the input schema so you can create a tool call payload without hand-writing JSON.

Applying a tool fixture appends the tool call and result into the real chat messages for that hook. Saved fixtures are stored in browser localStorage under the AI devtools namespace so they are available the next time you open the panel.

## Event Sources

Client-visible state is emitted by the headless client. Server-only details, such as middleware and provider stream events that never exist on the client, are emitted from the server counterpart. Events include a source descriptor and stable envelope id so the panel can link related events and avoid displaying duplicates.

## Installation
To use TanStack Devtools with TanStack AI, install the `@tanstack/react-ai-devtools` package:

Expand Down
14 changes: 14 additions & 0 deletions examples/ts-react-chat/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Link } from '@tanstack/react-router'

import { useState } from 'react'
import {
Activity,
Braces,
FileAudio,
FileText,
Expand Down Expand Up @@ -75,6 +76,19 @@ export default function Header() {
Generations
</p>

<Link
to="/generation-hooks"
onClick={() => setIsOpen(false)}
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-800 transition-colors mb-1"
activeProps={{
className:
'flex items-center gap-3 p-3 rounded-lg bg-cyan-600 hover:bg-cyan-700 transition-colors mb-1',
}}
>
<Activity size={20} />
<span className="font-medium">Generation Hooks</span>
</Link>

<Link
to="/generations/image"
onClick={() => setIsOpen(false)}
Expand Down
21 changes: 21 additions & 0 deletions examples/ts-react-chat/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as RealtimeRouteImport } from './routes/realtime'
import { Route as Issue176ToolResultRouteImport } from './routes/issue-176-tool-result'
import { Route as ImageGenRouteImport } from './routes/image-gen'
import { Route as GenerationHooksRouteImport } from './routes/generation-hooks'
import { Route as IndexRouteImport } from './routes/index'
import { Route as GenerationsVideoRouteImport } from './routes/generations.video'
import { Route as GenerationsTranscriptionRouteImport } from './routes/generations.transcription'
Expand Down Expand Up @@ -49,6 +50,11 @@ const ImageGenRoute = ImageGenRouteImport.update({
path: '/image-gen',
getParentRoute: () => rootRouteImport,
} as any)
const GenerationHooksRoute = GenerationHooksRouteImport.update({
id: '/generation-hooks',
path: '/generation-hooks',
getParentRoute: () => rootRouteImport,
} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
Expand Down Expand Up @@ -160,6 +166,7 @@ const ApiGenerateAudioRoute = ApiGenerateAudioRouteImport.update({

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/generation-hooks': typeof GenerationHooksRoute
'/image-gen': typeof ImageGenRoute
'/issue-176-tool-result': typeof Issue176ToolResultRoute
'/realtime': typeof RealtimeRoute
Expand All @@ -186,6 +193,7 @@ export interface FileRoutesByFullPath {
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/generation-hooks': typeof GenerationHooksRoute
'/image-gen': typeof ImageGenRoute
'/issue-176-tool-result': typeof Issue176ToolResultRoute
'/realtime': typeof RealtimeRoute
Expand Down Expand Up @@ -213,6 +221,7 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/generation-hooks': typeof GenerationHooksRoute
'/image-gen': typeof ImageGenRoute
'/issue-176-tool-result': typeof Issue176ToolResultRoute
'/realtime': typeof RealtimeRoute
Expand Down Expand Up @@ -241,6 +250,7 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
| '/generation-hooks'
| '/image-gen'
| '/issue-176-tool-result'
| '/realtime'
Expand All @@ -267,6 +277,7 @@ export interface FileRouteTypes {
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/generation-hooks'
| '/image-gen'
| '/issue-176-tool-result'
| '/realtime'
Expand All @@ -293,6 +304,7 @@ export interface FileRouteTypes {
id:
| '__root__'
| '/'
| '/generation-hooks'
| '/image-gen'
| '/issue-176-tool-result'
| '/realtime'
Expand Down Expand Up @@ -320,6 +332,7 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
GenerationHooksRoute: typeof GenerationHooksRoute
ImageGenRoute: typeof ImageGenRoute
Issue176ToolResultRoute: typeof Issue176ToolResultRoute
RealtimeRoute: typeof RealtimeRoute
Expand Down Expand Up @@ -368,6 +381,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ImageGenRouteImport
parentRoute: typeof rootRouteImport
}
'/generation-hooks': {
id: '/generation-hooks'
path: '/generation-hooks'
fullPath: '/generation-hooks'
preLoaderRoute: typeof GenerationHooksRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
id: '/'
path: '/'
Expand Down Expand Up @@ -520,6 +540,7 @@ declare module '@tanstack/react-router' {

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
GenerationHooksRoute: GenerationHooksRoute,
ImageGenRoute: ImageGenRoute,
Issue176ToolResultRoute: Issue176ToolResultRoute,
RealtimeRoute: RealtimeRoute,
Expand Down
Loading
Loading