Skip to main content

Approve a tool action and finish the conversation

Section ID: Guide/jetf8m1i0k#use-and-approve-tools-in-conversations

Build an assistant that can search for information but waits for a person before sending an email or performing another reviewed action. Use the platform-run approval recipe first: configure the gate, submit a request, show the pending action, send the decision and follow the same run to its result.

If your application executes the action itself, use the separate client-tool recipe. Client tools do not pass through the platform approval queue; your application validates arguments, checks permission and obtains the required confirmation before executing them.

Before you start: choose the tool and its review policy​

Section ID: Guide/jetf8m1i0k#tool-execution-policy

You need an authenticated conversation, a selected server whose tools have been discovered, and the exact names of the tools your assistant can call. Use tool discovery and inspect the server/tool names before writing approval patterns. The example below uses illustrative search and email patterns; adapt them to your discovered names.

For this recipe, allow ordinary lookup calls and require a decision before the chosen sending action. Keep the same conversation and accepted run when listing and deciding on approvals.

Step 1: Add the approval gate to the send​

Section ID: Guide/jetf8m1i0k#worked-example

Add this policy to the user’s normal send request after adapting send_email to the discovered sending tool. This is the policy portion, not a complete message. It allows a 30-second approval wait and a finite overall run budget.

See Send a message to a conversation for the full field contract. This excerpt illustrates the relevant choices; replace identifiers with your own authorized values.

  • conversationKey: text support-chat-001.
  • overrideGenerationConfig.toolPolicy.requireApprovalToolNamePatterns[0]: text send_email.
  • overrideGenerationConfig.toolPolicy.approvalMode: text APPROVAL_MODE_MIXED.
  • overrideGenerationConfig.toolPolicy.approvalTimeoutMs: number 30000.
  • overrideGenerationConfig.toolPolicy.timeouts.overallMs: number 600000.

Request excerpt: Send a message to a conversation · Request fields.

Send the user’s request once and retain its run ID. If the model does not request the gated action, no approval appears; read the actual reply rather than manufacturing a pending decision. Use the send reference for the complete toolPolicy schema.

Step 2: Show the action awaiting a decision​

Section ID: Guide/jetf8m1i0k#checking-pending-approvals

Read the pending calls for the conversation and present the action that needs a decision. Keep its tool-call ID so the decision applies to that call.

Request example: List pending tool approvals. Example identifiers and values are illustrative; substitute authorized values.

Example request headers: X-API-Key: sk_your_key_here; X-On-Behalf-Of: user_123; Content-Type: application/json. Replace the credential and user placeholders with your own authorized values.

Present the pending action for review before asking for a decision. Keep its toolCallId tied to that action; do not reuse a decision for an unrelated later call. An empty pending list means there is no current approval to submit, not that the run completed.

Step 3: Submit the decision and inspect the outcome​

Section ID: Guide/jetf8m1i0k#submitting-approvals

After the user decides, submit the decision for the pending toolCallId. The example approves the call. Continue following the run afterward: an approval decision is not confirmation that the tool or the full task succeeded.

Request example: Approve or reject pending tool calls. Example identifiers and values are illustrative; substitute authorized values.

Example request headers: X-API-Key: sk_your_key_here; X-On-Behalf-Of: user_123; Content-Type: application/json. Replace the credential and user placeholders with your own authorized values.

Continue reading the same run through generation outcomes. Approval authorizes execution of the held call; it does not confirm that execution succeeded. Show a rejected, failed, timed-out or still-unknown tool result accurately.

Finished result: the person reviewed the pending action, the decision referred to that call ID, and the conversation shows its actual result and correlated run outcome. If the decision response is lost, read the pending/call state before deciding again; do not resend the original user message to recover.

Variant: decide which calls wait together​

Section ID: Guide/jetf8m1i0k#approval-patterns

Keep APPROVAL_MODE_MIXED when independent auto-approved lookups may proceed while the sending action waits. Choose APPROVAL_MODE_BLOCK_ALL when the entire batch must wait for every gated decision.

Current limit: tool-policy retries are not applied​

Section ID: Guide/jetf8m1i0k#retries

Tool-policy retry settings are accepted and stored, but current execution does not apply their patterns, error filters or backoff. Setting them does not cause a failed lookup to retry.

Inspect the failed call and show its actual outcome. Initiate another lookup only when it can safely be repeated. Reconcile an uncertain external write before any new attempt; a stored retry policy does not establish that repetition is safe.

Variant: bound the assistant’s supporting lookups​

Section ID: Guide/jetf8m1i0k#parallel-calls-and-budgets

Set a finite lookup budget for the task. Allow parallel calls only when those lookups are independent.

Inspect whether the reply contains the needed evidence. Show partial work as partial; reaching a budget limit does not establish that every requested lookup completed.

Recover when the run or review deadline expires​

Section ID: Guide/jetf8m1i0k#run-time-budget

Choose a finite duration for the task and show a timeout or unfinished result honestly. Inspect any external action separately before retrying it.

Approval and client-tool deadlines bound those individual waits; they are separate from the overall run budget and from a provider spending limit.

Current limit: stop-on-failure rules are not enforced​

Section ID: Guide/jetf8m1i0k#stop-on-failure-rules

Configured stop-on-failure rules are stored but do not currently stop a run after a tool error. Do not depend on this setting to prevent later model or tool steps.

If a later application action depends on the failed action succeeding, check the original outcome in your application before allowing that action. Inspect the tool and run outcomes separately; neither a failure nor a stopped run undoes an external effect that already occurred.

Client tools executed by your application​

Section ID: Guide/jetf8m1i0k#client-side-tools

For a tool that opens a page or performs another application action, follow the client-tool recipe. This page focuses on approval policy; approving a call and executing it in your app are separate actions.

Set the client answer window​

Section ID: Guide/jetf8m1i0k#client-tools

Choose a finite answer window long enough to validate and perform the requested action. Retain the returned deadline and use it during recovery; after expiry, inspect the terminal outcome instead of submitting a late success. Approval does not prove the application action ran.

Client-tool flow​

Section ID: Guide/jetf8m1i0k#the-loop

Synchronous client tool handoff shows the handoff. The tool recipe carries the full request and result examples.

Receive the pending call​

Section ID: Guide/jetf8m1i0k#turn-1--the-model-asks

Retain the pending call’s ID, name, arguments and deadline. Follow receiving a complete call before executing anything.

Validate and return the outcome​

Section ID: Guide/jetf8m1i0k#turn-2--you-answer

Validate untrusted arguments and authorize the requested action in your application. Return the result for the same pending call only after inspecting what happened; see executing and answering the call.

Recover the original call​

Section ID: Guide/jetf8m1i0k#if-the-connection-drops

Recover the pending call and inspect its status before sending another result or repeating the business action. Follow client-tool recovery. Do not resend the original user message to recover a lost response.

Client tools from a worker​

Section ID: Guide/jetf8m1i0k#client-side-tools-async

A worker can use the asynchronous send path and recover pending calls without keeping the send request open. Follow the worker and recovery path and Asynchronous client tool handoff.

Discover a pending call​

Section ID: Guide/jetf8m1i0k#knowing-a-call-is-waiting

Use the enabled event-delivery surface or poll for pending client tools, then read the call before acting. A notification alone is not an authorization decision or proof that execution is still permitted. The recovery recipe explains the same-call checks.

Choose synchronous or asynchronous handoff​

Section ID: Guide/jetf8m1i0k#which-style-to-use

Keep the request open when the caller can wait for the model’s handoff. Use asynchronous send and recovery for a worker that cannot hold that connection. Both paths must reconcile the original call and its deadline before acting.

Inspect terminal outcomes​

Section ID: Guide/jetf8m1i0k#two-rules-for-clients

A reply that asks for a client tool is an intermediate handoff. After returning the result, inspect the continuing run and its terminal outcome. A failed, cancelled or timed-out call is not a successful application action.

Document ID: Guide/jetf8m1i0k