
tool-ui
by ataschz
AI-powered travel assistant built with Mastra, TanStack Start, and AI SDK. Features agent networks, real-time streaming, and dynamic UI for tool calls and reasoning.
SKILL.md
name: tool-ui description: | Add custom UI components for Mastra tools that render in chat streaming and history. Uses ToolUIRegistry pattern with type-safe component mapping.
Use when: creating tool UI cards, adding dynamic tool rendering, or debugging why a tool component isn't showing in chat. user-invocable: true
Tool UI Skill
Status: Production Ready
Last Updated: 2026-01-21
Dependencies: @/components/chat/renderers
Quick Start
To add a custom UI for a new tool:
/add-tool-ui my-tool-name
Or follow the manual steps below.
Step 1: Create the Component
Create a new card component in src/components/ai-elements/:
// src/components/ai-elements/my-tool-card.tsx
'use client';
import type { ComponentProps } from 'react';
import { cn } from '@/lib/utils';
export interface MyToolData {
// Match your tool's outputSchema
result: string;
value: number;
}
interface MyToolCardProps extends ComponentProps<'div'> {
data: MyToolData;
}
export function MyToolCard({ data, className, ...props }: MyToolCardProps) {
return (
<div className={cn('not-prose mb-4 w-full rounded-md border p-4', className)} {...props}>
<span className="font-medium">{data.result}</span>
<span className="text-muted-foreground">{data.value}</span>
</div>
);
}
// Type guard - REQUIRED for registry
export function isMyToolData(data: unknown): data is MyToolData {
if (!data || typeof data !== 'object') return false;
const d = data as Record<string, unknown>;
return typeof d.result === 'string' && typeof d.value === 'number';
}
Critical: The type guard function is required for the registry to validate output data.
Step 2: Register in the Registry
Add registration to src/components/chat/renderers/index.ts:
// At the imports section
import { MyToolCard, isMyToolData } from '@/components/ai-elements/my-tool-card';
// After the existing toolUIRegistry.register() calls
toolUIRegistry.register({
toolIds: ['my-tool-id'], // Must match tool's `id` in Mastra
Component: MyToolCard,
isValidOutput: isMyToolData,
});
Note: toolIds is an array - some tools have different IDs in different contexts
(e.g., ['get-weather', 'weatherTool']).
Step 3: Done
The component now automatically renders in:
- ✅ Streaming via
network-renderer.tsx - ✅ History via
dynamic-tool-renderer.tsx
Registry API
interface ToolUIRegistration<TOutput = unknown> {
toolIds: string[]; // Tool ID(s)
Component: FC<{ data: TOutput }>; // React component
isValidOutput: (output: unknown) => output is TOutput; // Type guard
}
// Register
toolUIRegistry.register(registration);
// Check if tool has custom UI
toolUIRegistry.hasCustomUI('tool-id'); // boolean
// Get component for output
toolUIRegistry.getComponent('tool-id', output);
// Returns: { Component, data } | null
How It Works
flowchart TD
subgraph Registry["ToolUIRegistry"]
Map["Map<toolId, Registration>"]
end
subgraph Streaming["Streaming Context"]
NR["network-renderer.tsx"]
Extract["extractToolUIFromNetwork()"]
NR --> Extract --> Map
end
subgraph History["History Context"]
DTR["dynamic-tool-renderer.tsx"]
Lookup["getComponent()"]
DTR --> Lookup --> Map
end
Map --> Component["Your Component"]
Troubleshooting
Component not rendering during streaming
- Check the tool ID matches exactly what Mastra uses
- Verify the tool is in an agent that uses
networkRoute() - Check
toolResultsstructure in network steps
Component not rendering in history
- Check
toolNameinchildMessagesmatches registered ID - Verify
isValidOutputreturns true for the data - Check console for validation errors
Finding the correct tool ID
Look at your Mastra tool definition:
// src/mastra/tools/my-tool.ts
export const myTool = createTool({
id: 'my-tool-id', // <-- This is the ID to register
// ...
});
Example: WeatherCard
Reference implementation at:
- Component:
src/components/ai-elements/weather-card.tsx - Tool:
src/mastra/tools/weather-tool.ts - Registration:
src/components/chat/renderers/index.ts
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


