Building an Agent
Multi-step tool use, human approval, and agent UI with createAgentHandler.
createAgentHandler
Server utility wrapping streamText with tools, stopWhen: stepCountIs(n), and optional needsApproval per tool. Tool parameters use Zod schemas — install with pnpm add zod.
import { createAgentHandler } from 'ai-elements-nuxt/server'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
export default createAgentHandler({
model: openai('gpt-4o'),
maxSteps: 10,
tools: {
getWeather: {
description: 'Get weather for a city',
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => ({ temp: 72, city }),
},
deleteFile: {
description: 'Delete a file',
parameters: z.object({ path: z.string() }),
requireConfirmation: true, // pauses for human approval
execute: async ({ path }) => ({ deleted: path }),
},
},
})Client: useAiAgent + useAiTools
useAiAgent extends useAiChat with steps, plan, tasks, and a human-in-the-loop approval flow. useAiTools wires per-tool metadata and exposes pendingApprovals — already typed as AiToolCall[], ready for AiToolApproval.
const agent = useAiAgent({ api: '/api/chat' })
const tools = useAiTools([
{ name: 'getWeather', icon: '🌤' },
{ name: 'deleteFile', requireConfirmation: true },
], agent)
const { aiMessages, steps, handleSubmit, input } = agentUI: wiring tool approval
Use tools.pendingApprovals (from useAiTools) to drive AiToolApproval — it already carries the right AiToolCall shape including approvalId. Pass tools.approveTool / tools.denyTool directly — no manual ID extraction needed.
<AiToolApproval
v-if="tools.pendingApprovals.value[0]"
:tool-call="tools.pendingApprovals.value[0]"
@approve="tools.approveTool"
@deny="tools.denyTool"
/>
<!-- Step timeline: AiAgent (also available as AiAgentSteps)
renders the steps[] array from useAiAgent -->
<AiAgent :steps="steps" title="Agent run" />
<AiMessage v-for="(msg, i) in aiMessages" :key="i" v-bind="msg" />
<form @submit="handleSubmit">
<AiPromptInput v-model="input" />
</form>Naming note:<AiAgent> is a step-timeline display component — it renders the steps array from useAiAgent. It is also registered as <AiAgentSteps> if you prefer the more descriptive name. The composable useAiAgent manages the full execution state (streaming, tools, plan).
Other UI components
AiTool— per-tool lifecycle states (streaming args → result)AiPlan/AiTask— manual plan/task state viaagent.setPlan/agent.setTasks
See the Agent playground for a working mock UI.