Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new

Confirmation

A confirmation request that presents a tool action and records a clear decision.

Interactive preview

The shared preview uses React Base. The source below uses Reka UI. Each example runs with local data.

Installation

Complete project setup with vue/reka, then install these components:

pnpm exec frontfriend download item button icon message bubble -f vue --primitive reka

The example never runs a command. Each request accepts one decision; Reset creates another request. Keep the request ID when you connect the decision to a tool approval response. Do not run the tool before approval.

Usage

Complete example

<script setup lang="ts">
import { ref } from "vue";
import { nextTick } from "vue";
import { Message } from "@/components/ui/message";
import { MessageContent } from "@/components/ui/message";
import { Bubble } from "@/components/ui/bubble";
import { BubbleContent } from "@/components/ui/bubble";
import { Item } from "@/components/ui/item";
import { ItemMedia } from "@/components/ui/item";
import { Icon } from "@/components/ui/icon";
import { ItemContent } from "@/components/ui/item";
import { ItemTitle } from "@/components/ui/item";
import { ItemDescription } from "@/components/ui/item";
import { ItemActions } from "@/components/ui/item";
import { Button } from "@/components/ui/button";

const args = {
  "command": "pnpm build",
};
const decision = ref("pending");
const resultRef = ref<HTMLParagraphElement | null>(null);
async function decide(value: "approved" | "denied") {
  decision.value = value;
  await nextTick();
  resultRef.value?.focus();
}
</script>

<template>
  <div
    style="
      width: 100%;
      max-width: 560px;
      min-width: 0;
      margin-inline: auto;
      display: flex;
      flex-direction: column;
      gap: 16px;
      padding-block: 16px;
      font-size: var(--text-sm);
      line-height: 1.5;
    "
  >
    <Message align="end"
      ><MessageContent
        ><Bubble align="end" variant="muted"
          ><BubbleContent
            >Run the build before I ship this change.</BubbleContent
          ></Bubble
        ></MessageContent
      ></Message
    ><Item v-if="decision === 'pending'" variant="outline" size="sm"
      ><ItemMedia variant="icon"><Icon name="Terminal" /></ItemMedia
      ><ItemContent
        ><ItemTitle>Run {{ args.command }}?</ItemTitle
        ><ItemDescription
          >The command runs in this project.</ItemDescription
        ></ItemContent
      ><ItemActions
        ><Button size="sm" variant="outline" @click="decide('denied')"
          >Deny</Button
        ><Button size="sm" @click="decide('approved')"
          >Approve</Button
        ></ItemActions
      ></Item
    ><Message v-if="decision !== 'pending'"
      ><MessageContent
        ><p ref="resultRef" tabindex="-1">
          {{
            decision === "approved"
              ? "Build approved. Ready to run " + args.command + "."
              : "Build cancelled. No command was run."
          }}
        </p></MessageContent
      ></Message
    >
    <div>
      <Button size="sm" variant="ghost" @click="decision = 'pending'"
        >Reset</Button
      >
    </div>
  </div>
</template>

Components and API

This composition has no separate component API. Use the APIs for its installed components.

ComponentTarget reference
item Reka UI API
button Reka UI API
icon Reka UI API
message Reka UI API
bubble Reka UI API