promptCompare
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v162View latest version
A collapsible task list component for displaying AI workflow progress, with status indicators and optional descriptions.
The Task component provides a structured way to display task lists or workflow
progress with collapsible details, status indicators, and progress tracking. It
consists of a main Task container with TaskTrigger for the clickable header
and TaskContent for the collapsible content area.
See scripts/task.tsx for this example.
npx ai-elements@latest add task
Build a mock async programming agent using
experimental_generateObject.
Add the following component to your frontend:
"use client";
import { experimental_useObject as useObject } from "@ai-sdk/react";
import {
Task,
TaskContent,
TaskItem,
TaskItemFile,
TaskTrigger,
} from "@/components/ai-elements/task";
import { Button } from "@/components/ui/button";
import { tasksSchema } from "@/app/api/task/route";
import {
SiCss,
SiHtml5,
SiJavascript,
SiJson,
SiMarkdown,
SiReact,
SiTypescript,
} from "@icons-pack/react-simple-icons";
const iconMap = {
react: { component: SiReact, color: "#149ECA" },
typescript: { component: SiTypescript, color: "#3178C6" },
javascript: { component: SiJavascript, color: "#F7DF1E" },
css: { component: SiCss, color: "#1572B6" },
html: { component: SiHtml5, color: "#E34F26" },
json: { component: SiJson, color: "#000000" },
markdown: { component: SiMarkdown, color: "#000000" },
};
const TaskDemo = () => {
const { object, submit, isLoading } = useObject({
api: "/api/agent",
schema: tasksSchema,
});
const handleSubmit = (taskType: string) => {
submit({ prompt: taskType });
};
const renderTaskItem = (item: any, index: number) => {
if (item?.type === "file" && item.file) {
const iconInfo = iconMap[item.file.icon as keyof typeof iconMap];
if (iconInfo) {
const IconComponent = iconInfo.component;
return (
<span className="inline-flex items-center gap-1" key={index}>
{item.text}
<TaskItemFile>
<IconComponent
color={item.file.color || iconInfo.color}
className="size-4"
/>
<span>{item.file.name}</span>
</TaskItemFile>
</span>
);
}
}
return item?.text || "";
};
return (
<div className="max-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px]">
<div className="flex flex-col h-full">
<div className="flex gap-2 mb-6 flex-wrap">
<Button
onClick={() => handleSubmit("React component development")}
disabled={isLoading}
variant="outline"
>
React Development
</Button>
</div>
<div className="flex-1 overflow-auto space-y-4">
{isLoading && !object && (
<div className="text-muted-foreground">Generating tasks...</div>
)}
{object?.tasks?.map((task: any, taskIndex: number) => (
<Task key={taskIndex} defaultOpen={taskIndex === 0}>
<TaskTrigger title={task.title || "Loading..."} />
<TaskContent>
{task.items?.map((item: any, itemIndex: number) => (
<TaskItem key={itemIndex}>
{renderTaskItem(item, itemIndex)}
</TaskItem>
))}
</TaskContent>
</Task>
))}
</div>
</div>
</div>
);
};
export default TaskDemo;
Add the following route to your backend:
import { streamObject } from "ai";
import { z } from "zod";
export const taskItemSchema = z.object({
type: z.enum(["text", "file"]),
text: z.string(),
file: z
.object({
name: z.string(),
icon: z.string(),
color: z.string().optional(),
})
.optional(),
});
export const taskSchema = z.object({
title: z.string(),
items: z.array(taskItemSchema),
status: z.enum(["pending", "in_progress", "completed"]),
});
export const tasksSchema = z.object({
tasks: z.array(taskSchema),
});
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export async function POST(req: Request) {
const { prompt } = await req.json();
const result = streamObject({
model: "openai/gpt-4o",
schema: tasksSchema,
prompt:
`You are an AI assistant that generates realistic development task workflows. Generate a set of tasks that would occur during ${prompt}.
Each task should have:
- A descriptive title
- Multiple task items showing the progression
- Some items should be plain text, others should reference files
- Use realistic file names and appropriate file types
- Status should progress from pending to in_progress to completed
For file items, use these icon types: 'react', 'typescript', 'javascript', 'css', 'html', 'json', 'markdown'
Generate 3-4 tasks total, with 4-6 items each.`,
});
return result.toTextStreamResponse();
}
- Visual icons for pending, in-progress, completed, and error states
- Expandable content for task descriptions and additional information
- Built-in progress counter showing completed vs total tasks
- Optional progressive reveal of tasks with customizable timing
- Support for custom content within task items
- Full type safety with proper TypeScript definitions
- Keyboard navigation and screen reader support
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | true | Whether the task is open by default. |
...props | React.ComponentProps<typeof Collapsible> | - | Any other props are spread to the root Collapsible component. |
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Required | The title of the task that will be displayed in the trigger. |
...props | React.ComponentProps<typeof CollapsibleTrigger> | - | Any other props are spread to the CollapsibleTrigger component. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | React.ComponentProps<typeof CollapsibleContent> | - | Any other props are spread to the CollapsibleContent component. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | React.ComponentProps< | - | Any other props are spread to the underlying div. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | React.ComponentProps< | - | Any other props are spread to the underlying div. |