Skip to content
Tier

useAnsweringApprovals

Pro

The guard every chat with permission prompts needs: while an answer is being sent, that request's buttons wait, so Allow can't be pressed twice; and an answer that fails to send leaves the prompt answerable again and says so, instead of an unhandled rejection. respond is the chat's own (useCandorChat, useClaudeAgent, useAgUi).

const { answering, answer, failed } = useAnsweringApprovals(respond)
<PermissionPrompt onAllow={() => answer(a.id, true)} onDeny={() => answer(a.id, false)} busy={answering.has(a.id)} />
{(error ?? failed) && <p role="alert">{error ?? failed}</p>}
Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0 and 2.8.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/use-answering-approvals

Brings in: locale, tokens

Usage

TSX · The example above
"use client"

import * as React from "react"
import { PermissionPrompt } from "@/components/candor/permission-prompt"
import { useAnsweringApprovals } from "@/lib/candor/use-answering-approvals"

const request = { id: "ap-1", tool: "set_flag", title: "The agent wants to turn on new_checkout in production", input: { flag: "new_checkout", environment: "production", on: true } }

export default function Example() {
  const [answered, setAnswered] = React.useState<string>()
  // Stands in for the chat's own respond (useCandorChat, useClaudeAgent): here the first answer fails to send.
  const tries = React.useRef(0)
  const respond = React.useCallback(async (id: string, approved: boolean) => {
    await new Promise((r) => setTimeout(r, 800))
    if (tries.current++ === 0) throw new Error("The network dropped.")
    setAnswered(`${id}: ${approved ? "allowed" : "denied"}`)
  }, [])
  const { answering, answer, failed } = useAnsweringApprovals(respond)
  if (answered) return <p className="text-sm text-muted-foreground">Sent. {answered}</p>
  return (
    <div className="flex max-w-xl flex-col gap-2">
      <PermissionPrompt request={request} onAllow={() => answer(request.id, true)} onDeny={() => answer(request.id, false, "Not now")} busy={answering.has(request.id)} />
      {failed && (
        <p role="alert" className="text-sm text-destructive-text">
          {failed}
        </p>
      )}
    </div>
  )
}

Functions

useAnsweringApprovals(respond: (id: string, approved: boolean, reason?: string) => unknown)

Strings

The fixed words, in English by default. Change any of them under answeringApprovals in <LocaleProvider strings={{ … }}>; the table is exported as answeringApprovalsStrings.

KeyEnglish
failedYour answer wasn’t sent, so the request is still waiting. Answer it again.

Types

AnsweringApprovals
What `useAnsweringApprovals` gives back.
{ /** The ids of the requests whose answer is being sent. Pass `answering.has(id)` as the prompt's `busy`. */ answering: ReadonlySet<string>; /** * Sends one answer through `respond`. While it's being sent, a second answer to the same request is ignored, so a * double press can't answer twice. When it settles the request leaves `answering`, whether it was sent or not. */ answer: (id: string, approved: boolean, reason?: string | undefined) => void; /** * The sentence to show when the last answer failed to send (`respond` threw or its promise rejected), in * LocaleProvider's words; undefined otherwise. The request is still waiting and can be answered again. It clears * when the next answer is sent. */ failed: string | undefined; }