Confirmations

Confirmations

A tool that books, sends, pays or cancels should run only after the caller has said yes to exactly what will happen. Give it confirm: the question read back to the caller, built from the validated input, in the agent’s language.

Only for such actions. To repeat a name or a number back so the caller can correct it, say it in the reply: a confirm tool makes the caller’s next turn the answer to its question, so a caller who simply goes on with the next detail leaves the tool waiting and unconfirmed.

<Tool
  schema={bookSchema}
  name="book_meeting"
  description="Book the chosen slot."
  confirm={(input) => `${input.start} for ${input.email}, is that right?`}
  onSubmit={async (input) => ({ ok: true, message: `Booked for ${input.start}.` })}
/>
  1. The model calls book_meeting, and onSubmit does not run. The input is validated as for any call, the caller hears the confirm question word for word, and the turn ends there. The model’s tool result says that nothing has happened yet.
  2. The caller’s next words are checked against that question with one short call on the agent’s own LLM, which answers yes, no or unclear:
    • Yes: onSubmit runs and the model answers from its result. The transcript records the call with the words that confirmed it.
    • No, or a changed detail: nothing runs, and the model is told so. It handles the correction; calling the tool again reads the new details back.
    • Unclear, or the check failed: nothing runs, the question stays open, and the model asks once more.
  3. While the question is open, the model’s context shows Waiting for the caller to confirm: "…". Calling the tool again replaces the open question; holding another confirm tool does too, and the model is told that the replaced action will not run.

The model cannot run a confirm tool itself: only the caller’s yes on a later turn does, in preview chat, local voice, hosted calls and tests alike.

  • Only words that arrived after the caller heard the question answer it: in chat and tests as soon as it is said, on a call once it played to its end. Input already waiting, and the framework’s silence follow-up, do not; a turn the caller cancels before the question is said asks nothing.
  • On a call, a caller who speaks before the question played to its end has not been asked: their words drop it, and the model is told to call the tool again so the whole question is said.
  • A yes runs the tool from the skill that asked. If that skill no longer owns the tool’s name, nothing runs and the model is told.
  • A step that asks never hangs up: an end_call in the same step is refused, and its goodbye is not said.
  • Rewinding, or reopening a stored conversation, to just after the question keeps it open. Rewinding anywhere else drops it.
  • A confirmed action is not replayed when a conversation is reopened or rewound; the preview names it as not replayed.
  • Limit: when the model writes two or more sentences before the call in the same step, all but the last are said before the question. The tool’s description already tells the model not to claim success, and nothing runs without the yes.

When you write one:

  • Name what the caller must check (date, time, email, amount), so that a plain yes means “do exactly this”.
  • The question is said word for word. Build it only from the input the tool sends, never from a free-text field the model fills, such as a summary, so the yes approves exactly what runs. A phone number, IBAN or plate the tool sends belongs in its read-back.
  • Throw ToolInputError in confirm to send the model back for better input, for example a slot that cannot be booked.
  • Do not also ask for the confirmation in your prompt. The model is told that calling the tool asks the caller.
  • If onSubmit fails after the yes ({ ok: false } or a thrown error), the model learns it like any failed tool call.
  • confirm works on both onSubmit variants (schema, or <Field> children), inline or in defineTool.

Next steps

  • Testing: keep the confirmation as a scenario.