A complete abstraction for creating generative UI components that automatically display when specific tools are executed in chat
npm install @front10/generative-uiA complete abstraction for creating generative UI components that automatically display when specific tools are executed in chat. Designed to work with Vercel AI SDK 5.0 and provide a simple, scalable, and reusable way to create dynamic user experiences with interactive feedback capabilities.
``bash`
npm install @front10/generative-uior
yarn add @front10/generative-uior
pnpm add @front10/generative-ui
`typescript`
import {
GenerativeUIProvider,
useGenerativeUI,
GenerativeUIRegistry,
useRegisterGenerativeComponent,
GenerativeUIRenderer,
useRenderGenerativeUI,
UserAction
} from '@front10/generative-ui';
`typescript`
import {
productCardExample,
imageGalleryExample,
sentimentAnalyzerExample,
examples
} from '@front10/generative-ui/examples';
`tsx
// app/layout.tsx
import { GenerativeUIProvider } from '@front10/generative-ui';
export default function RootLayout({ children }) {
return (
$3
`tsx
// components/chat.tsx
import { useGenerativeUI } from '@front10/generative-ui';
import { useGenerativeActions } from '@/hooks/use-generative-actions';
import { productCardExample } from '@front10/generative-ui/examples';export function Chat() {
const { registerComponent } = useGenerativeUI();
const { handleUserAction } = useGenerativeActions();
// Register components with individual action handlers
React.useLayoutEffect(() => {
registerComponent({
toolId: 'getProductInfo',
LoadingComponent: ProductCardLoading,
SuccessComponent: ProductCard,
ErrorComponent: ProductCardError,
onUserAction: action => {
console.log('Product Card action:', action);
handleUserAction(action);
}
});
registerComponent({
toolId: 'searchImages',
LoadingComponent: ImageGalleryLoading,
SuccessComponent: ImageGallery,
ErrorComponent: ImageGalleryError,
onUserAction: action => {
console.log('Image Gallery action:', action);
handleUserAction(action);
}
});
}, [registerComponent, handleUserAction]);
return
Chat Component;
}
`$3
`tsx
// components/message.tsx
import { useRenderGenerativeUI } from '@front10/generative-ui';export function Message({ message }) {
const renderGenerativeUI = useRenderGenerativeUI();
return (
{message.parts?.map((part, index) => {
if (part.type.startsWith('tool-')) {
const toolId = part.type.replace('tool-', '');
const { toolCallId, state } = part;
const input = 'input' in part ? part.input : undefined;
const output = 'output' in part ? part.output : undefined;
const error = 'errorText' in part ? part.errorText : undefined; const renderedComponent = renderGenerativeUI({
toolId,
state,
input,
output,
error,
toolCallId
});
if (renderedComponent) {
return
{renderedComponent};
}
}
return null;
})}
);
}
`🎨 Interactive Examples
$3
`tsx
import { useGenerativeActions } from '@/hooks/use-generative-actions';export function Chat() {
const { handleUserAction } = useGenerativeActions();
registerComponent({
toolId: 'getProductInfo',
LoadingComponent: ProductCardLoading,
SuccessComponent: ProductCard,
ErrorComponent: ProductCardError,
onUserAction: action => {
console.log('Product action:', action);
handleUserAction(action);
}
});
// The component automatically receives onAction prop
// and can trigger multiple actions:
// - add_to_cart
// - view_details
// - add_to_wishlist
// - share_product
}
`$3
`tsx
import { useGenerativeActions } from '@/hooks/use-generative-actions';export function Chat() {
const { handleUserAction } = useGenerativeActions();
registerComponent({
toolId: 'getEvents',
LoadingComponent: CalendarLoading,
SuccessComponent: CalendarComponent,
ErrorComponent: CalendarError,
onUserAction: action => {
console.log('Calendar action:', action);
handleUserAction(action);
}
});
// The calendar component supports multiple actions:
// - create_event
// - edit_event
// - delete_event
// - confirm_event
// - cancel_event
// - view_event_details
// - share_event
}
`🔧 API Reference
$3
####
GenerativeUIProviderThe main provider that handles component registration and rendering with interactive feedback.
`tsx
{children}
`####
useGenerativeUIHook to access the Generative UI context.
`tsx
const { registerComponent, renderComponent, onUserAction } = useGenerativeUI();
`####
GenerativeUIRegistryComponent for automatically registering multiple components.
`tsx
`####
useRegisterGenerativeComponentHelper hook for registering a single component.
`tsx
useRegisterGenerativeComponent({
toolId: 'myTool',
LoadingComponent: MyLoading,
SuccessComponent: MySuccess,
ErrorComponent: MyError
});
`####
GenerativeUIRendererComponent that renders components based on the tool's state.
`tsx
toolId='myTool'
state='output-available'
input={input}
output={output}
error={error}
toolCallId='call-123'
/>
`####
useRenderGenerativeUIHook helper for rendering components from the message system.
`tsx
const renderGenerativeUI = useRenderGenerativeUI();
`$3
####
UserAction`tsx
interface UserAction {
toolId: string; // Identificador del tool/componente
toolCallId?: string; // ID específico de la llamada al tool
action: string; // Identificador de la acción (ej: "accept", "cancel", "select")
data?: any; // Datos adicionales de la acción
context?: any; // Contexto adicional
}
`####
GenerativeUIComponent`tsx
interface GenerativeUIComponent {
toolId: string;
LoadingComponent?: React.ComponentType<{
input?: TInput;
onAction?: (action: Omit) => void;
}>;
SuccessComponent: React.ComponentType<{
output: TOutput;
input?: TInput;
onAction?: (action: Omit) => void;
}>;
ErrorComponent?: React.ComponentType<{
error: string;
input?: TInput;
onAction?: (action: Omit) => void;
}>;
}
`####
ToolState`tsx
type ToolState =
| 'input-streaming'
| 'input-available'
| 'output-available'
| 'output-error';
`####
GenerativeUIRendererProps`tsx
interface GenerativeUIRendererProps {
toolId: string;
state: ToolState;
input?: any;
output?: any;
error?: string;
toolCallId: string;
}
`🎯 Interactive Feedback Examples
$3
Create a custom hook to handle user actions:
`tsx
// hooks/use-generative-actions.ts
'use client';import { useChat } from '@ai-sdk/react';
export interface UserAction {
toolId: string;
toolCallId?: string;
action: string;
data?: any;
context?: any;
}
export function useGenerativeActions() {
const { sendMessage } = useChat();
const handleUserAction = (action: UserAction) => {
// Create descriptive messages based on actions
let content = '';
switch (action.action) {
case 'add_to_cart':
content =
I want to add ${;
break;
case 'view_details':
content = Show me more details about ${;
break;
default:
content = I performed the action: ${action.action};
} // Send to LLM using sendMessage (Vercel AI SDK v5)
sendMessage({
role: 'user',
parts: [
{
type: 'text',
text: content
}
]
});
};
return { handleUserAction };
}
`$3
`tsx
// Example: Product Card with multiple actions
export const ProductCard: React.FC = ({
output,
onAction
}) => {
const { product } = output; const handleAddToCart = () => {
onAction?.({
action: 'add_to_cart',
data: {
productId: product.id,
productName: product.name,
price: product.price
},
context: { timestamp: Date.now() }
});
};
const handleViewDetails = () => {
onAction?.({
action: 'view_details',
data: { productId: product.id }
});
};
return (
{product.name}
{product.price}
);
};
`$3
`tsx
// In your main chat component
const { sendMessage } = useChat();const handleUserAction = (action: UserAction) => {
// Create descriptive messages based on actions
let content = '';
switch (action.action) {
case 'add_to_cart':
content =
I want to add ${;
break;
case 'view_details':
content = Show me more details about ${;
break;
default:
content = I performed the action: ${action.action};
} // Send to LLM using sendMessage (Vercel AI SDK v5)
sendMessage({
role: 'user',
parts: [
{
type: 'text',
text: content
}
]
});
};
`$3
`tsx
// For older versions of Vercel AI SDK
const { append } = useChat();const handleUserAction = (action: UserAction) => {
let content = '';
switch (action.action) {
case 'add_to_cart':
content =
I want to add ${;
break;
default:
content = I performed the action: ${action.action};
} // Send to LLM using append (Vercel AI SDK v4 and earlier)
append({
role: 'user',
content
});
};
`🎯 Benefits
1. Separation of concerns: UI separated from tool logic
2. Reusability: Components reusable in different contexts
3. Maintainability: Easy to maintain and extend
4. User experience: Immediate visual feedback during execution
5. Consistency: Uniform experience across the application
6. Scalability: Easy to add new tools and components
7. Type safety: Complete TypeScript for better DX
8. Compatibility: Works with any Vercel AI SDK implementation
9. Interactive feedback: Components can send actions back to the LLM
10. Multiple actions: Single components can trigger multiple different actions
11. Per-component handlers: Each component can have its own action handler
🚀 Project Status
✅ Production ready - The abstraction is fully functional, documented, and tested with interactive feedback capabilities.
📚 Examples
See the
examples/ directory for complete working examples:- Product Card: Product information display with cart, wishlist, and sharing actions
- Image Gallery: Image search with interactive gallery and selection actions
- Sentiment Analyzer: Text sentiment analysis with visualizations and feedback actions
- Calendar Events: Event management with create, edit, delete, and confirmation actions
🤝 Contributing
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature)
5. Open a Pull Request📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
---
Need help? Check the examples in the
examples/` directory or open an issue on GitHub.