Skip to content

shadcn.io is not affiliated with official shadcn/ui

Components

Free

Confirmation for Vue

A yes or no the agent asks for before a tool runs. For Vue with Ark UI, an outline Item with Deny and Approve Buttons, and no component of its own.

UI library: Ark UI

The agent stops before a tool runs and asks: a bordered row with the question, and Deny and Approve.

Use it for a call the reader should answer for: one that deletes, spends, sends, or can't be undone. A read or a search shouldn't ask, or the reader learns to approve without reading. The question is an Item with two Buttons, so there is no Confirmation component to install in Vue. Put the command or the change in the title, word for word, so the reader approves what will actually run. Once they answer, the row becomes the call's Tool line, in a Trace.

Preview width

Installation

Confirmation is a pattern. The command adds the parts it's built from, Item and Button, and the code to copy is the demo's.

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Confirmation anatomy: item, item media, item content, item actions, button
Item (variant="outline", size="sm")
├── ItemMedia (variant="icon")
├── ItemContent
│   ├── ItemTitle
│   └── ItemDescription
└── ItemActions
    ├── Button (Deny, variant="outline")
    └── Button (Approve)

Usage

<script setup lang="ts">
import { TerminalIcon } from "lucide-vue-next";
import { Button } from "@/components/ui/button";
import {
  Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,
} from "@/components/ui/item";
</script>
export function Confirmation(props: {
  command: string;
  onApprove: () => void;
  onDeny: () => void;
}) {
  return (
    <Item size="sm" variant="outline">
      <ItemMedia variant="icon">
        <TerminalIcon aria-hidden="true" />
      </ItemMedia>
      <ItemContent>
        <ItemTitle>Run {props.command}?</ItemTitle>
        <ItemDescription>The command runs in this project.</ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button onClick={props.onDeny} size="sm" variant="outline">
          Deny
        </Button>
        <Button onClick={props.onApprove} size="sm">
          Approve
        </Button>
      </ItemActions>
    </Item>
  );
}

AI SDK

Set needsApproval on the tool, and the call stops at approval-requested until the reader answers.

app/api/chat/route.ts
const runCommand = tool({
  description: "Run a shell command in the project.",
  inputSchema: z.object({ command: z.string() }),
  needsApproval: true,
  execute: async ({ command }) => run(command),
});

While the part is approval-requested, answer with the approval id. Pass sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses so the chat continues once every approval has an answer.

import { Chat } from "@ai-sdk/vue";
import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";

const chat = new Chat({
  sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
});

chat.addToolApprovalResponse({
  id: part.approval.id,
  approved: true,
});

Approve streams the tool output. Deny streams output-denied. Either way, the part becomes a Tool line.

Migrating from AI SDK Elements

AI SDK Elements is for React. In Vue, start from the demo above: an Item and two Buttons are all there is to Confirmation.

FAQ

What does installing Confirmation add in Vue?

Item and Button, the two parts the question is built from. Confirmation is a pattern, so no confirmation file lands in your ui folder: copy the demo's code into your own component and wire Deny and Approve to your chat. The command uses the shadcn-vue CLI.

Which tool calls should ask first?

The ones the reader would want to stop: deleting files, running a migration, sending a message, spending money. Reads, searches and anything easy to undo should run without asking, so that a question still means something when it appears.

What should the question say?

What will run, in the words that will run it: the command, the address, the amount. Run rm -rf dist? lets the reader judge the call, where Run a command? only asks for trust. The description says where it runs or what it touches, in one line.

What happens after the reader answers?

The row goes away and the call becomes a line in the agent's trace: Running, then Ran when the output comes back, or Denied. Then the agent's turn continues, and its reply says what it did or that it left things alone. A pending question sits outside Trace because it's a prompt for the reader, not a step the agent took.

What if the reader never answers?

The agent's turn stays paused on the question, and nothing runs. If the reader sends another message instead, answer the pending approval as denied first, so the agent never acts on a yes nobody gave. The demo's Reset clears the thread, question and all.

Can the reader answer with the keyboard?

Yes. Deny and Approve are Buttons, so Tab reaches Deny first, then Approve, and Enter or Space presses. Deny comes first so a quick Enter on the first button doesn't run a destructive call.

Is this the same as AI SDK Elements' Confirmation?

It does the same job without a wrapper: Confirmation was an Alert with request, accepted and rejected slots, and here it's an Item with two Buttons, replaced by a Trace line once answered. The Migrating from AI SDK Elements section has a prompt that rebuilds the old file on these parts and keeps its exports.

API Reference

Confirmation has no props of its own. The question is an Item with variant outline and size sm, and its ItemMedia, ItemContent and ItemActions; Deny and Approve are Buttons with size sm. The line it becomes is a Trace line.