AI Agent Hooks: How to Control Every Chatbot Tool Call

AI agent hooks let you inspect, block, and audit chatbot tool calls. Use this runtime checklist to enforce policy before and after every action.

Cover Image for AI Agent Hooks: How to Control Every Chatbot Tool Call

Google added environment hooks to Gemini API Managed Agents on July 28, 2026. A hook can run before or after an agent uses a tool, giving the runtime a place to block, validate, or audit the call. The timing matters: current agent harnesses can make many model requests and tool calls in one turn, so a policy written only in the prompt has more chances to be ignored, misread, or bypassed.

Start with a six-point hook map. For every chatbot tool, define what runs before it, what runs after it, which facts come from trusted systems, how failure behaves, what gets logged, and who owns the alert. If one of those cells is blank, the tool is not ready for unattended use.

This article turns that map into a practical runtime design. It applies whether your framework calls the interception point a hook, middleware, a guardrail, a policy gate, or a tool wrapper.

Put the Checkpoint Next to the Side Effect

A tool-calling chatbot has at least three decision layers:

  • The model decides what it wants to do. It selects a tool and proposes arguments.
  • The policy layer decides what may happen. It evaluates identity, scope, risk, and current business state.
  • The destination decides what did happen. A CRM, calendar, payment service, or help desk accepts or rejects the operation.

Hooks belong between those layers. A pre-tool hook inspects the proposal before the side effect. A post-tool hook verifies the result before the chatbot tells the user that the job is complete.

Use this minimum map for each tool:

CheckpointRequired jobExample decision
Before tool selectionLimit which tools are visible for this user and channelHide billing tools from an anonymous website visitor
Before executionValidate identity, authorization, arguments, and approvalDeny cancel_order when the order belongs to another account
After executionValidate the business outcome, not only the HTTP statusTreat a 200 response with status: rejected as failure
Before user receiptRequire durable evidence for consequential claimsDo not say “refunded” without a refund ID
On hook failureChoose fail-open or fail-closed behavior by consequenceBlock a refund when the policy service times out
After the runEmit traceable events and route alertsPage an owner after repeated denied account changes

The chatbot tool-permissions checklist defines which capabilities a bot should receive. Hooks enforce those decisions at execution time. They also complement human approval workflows: the hook verifies that a valid approval exists and matches the exact payload being executed.

Keep Trusted Facts Outside the Model

The model may propose an order ID, email address, refund amount, or destination. It should not get to assert the facts that authorize its own proposal.

Build the pre-tool context from server-controlled sources:

  • authenticated user and tenant identifiers;
  • channel and chatbot identity;
  • tool permission and risk classification;
  • fresh account, order, or ticket state;
  • approval ID, approver, expiry, and payload hash;
  • request and action identifiers used for idempotency;
  • data-handling and geographic restrictions.

If the user says, “I am the account owner,” that sentence remains untrusted input. The hook uses the authenticated session. If the model says an order is refundable, the hook checks current policy and order state. If a tool argument contains account_id, the hook replaces or rejects it rather than trusting a model-generated tenant boundary.

This rule prevents a common circular design: the prompt tells the model to obey a policy, then the policy hook asks the same model whether its call obeys the policy. Model-based classifiers can help with fuzzy questions such as detecting suspicious intent. Authorization, amount limits, ownership, and allowed destinations should be deterministic.

Write a Small Hook Contract

A hook becomes maintainable when its input and output are explicit. Avoid giving a script the full transcript, every credential, and an open-ended instruction to “check safety.” Pass the minimum fields needed for one decision.

FieldSourcePurpose
trace_id and action_idRuntimeJoin proposal, attempt, result, and receipt
actorAuth serviceBind the action to a user, tenant, chatbot, and channel
tool and operationTool registrySelect the correct policy without parsing prose
argumentsModel proposalValidate the exact payload before execution
riskTool registryChoose approval and failure behavior
approvalApproval serviceProve who approved which immutable payload and when
decision and reason_codeHookReturn allow, deny, or require-review with an operator-readable reason

Prefer stable reason codes such as tenant_mismatch, approval_expired, or amount_over_limit. The chatbot can translate a safe public explanation for the visitor; operators can aggregate the code without grouping free-form model prose.

Keep hook outcomes narrow. allow, deny, and require_review are easier to reason about than silently rewriting a consequential payload. Normalization is reasonable for low-risk fields such as trimming whitespace or converting a date to an agreed timezone. Changing a refund amount, recipient, account, or product should create a new proposal and, when required, a new approval.

Worked Call: Cancel an Order Without Crossing Accounts

Suppose an authenticated customer asks, “Cancel order 7412. I placed it by mistake.” The model proposes this call:

{
  "tool": "cancel_order",
  "arguments": {
    "order_id": "7412",
    "customer_id": "cus_999",
    "reason": "ordered_by_mistake"
  }
}

The user actually owns cus_184. The model may have copied cus_999 from retrieved text, an earlier tool result, or malicious page content. The pre-tool hook does not try to infer intent. It compares trusted identity and fresh order ownership, then returns:

{
  "decision": "deny",
  "reason_code": "tenant_mismatch",
  "public_message": "I couldn't verify that order for this account.",
  "audit": {
    "trace_id": "tr_82ac",
    "action_id": "act_cancel_7412",
    "actor_customer_id": "cus_184",
    "requested_customer_id": "cus_999"
  }
}

No cancellation request reaches the commerce API. The runtime records the denial, excludes private order details from the user-facing message, and sends the model only enough context to recover safely: ask the customer to choose an order visible in their authenticated account or hand the case to support.

Now take the valid path. The hook confirms that order 7412 belongs to cus_184, is still cancellable, and has explicit user confirmation. The tool returns 200 OK, but the body says {"status":"pending","request_id":"can_603"}. The post-tool hook must prevent the chatbot from saying “Your order is canceled.” The correct receipt is: “Cancellation request can_603 is pending.” A later webhook or status check can confirm the final effect.

That distinction—proposal, permission, and confirmed effect—is also the foundation of a useful AI agent audit trail. Hooks create the decision evidence; the audit record preserves it.

Choose Failure Behavior by Consequence

Hooks add a dependency to the execution path. The policy service can time out, a validation script can crash, or an audit sink can become unavailable. “Block everything” sounds safe until a low-risk support bot becomes unusable. “Let it through” sounds resilient until a failed check authorizes a refund.

Set failure behavior per checkpoint and tool risk:

SituationLow-risk readReversible writeHigh-impact write
Pre-hook timeoutAllow only if authorization is enforced downstreamPause or retry brieflyFail closed and require review
Post-hook timeoutReturn sourced data with a degraded-state markerReport outcome as unknown; reconcileReport outcome as unknown; alert immediately
Audit sink unavailableBuffer a minimal event with bounded retriesQueue execution only if evidence can be recoveredDo not execute without the required evidence trail
Destination timeoutRetry safe readsCheck status before retrying with the same idempotency keyReconcile before any second attempt

Document the customer message for each state. “Something went wrong” hides whether nothing happened or the outcome is unknown. Those are operationally different. For an unknown result, tell the customer that the request is being checked and avoid inviting a duplicate action.

Latency needs the same deliberate budget. Fast deterministic checks can run synchronously. Slower fraud or content analysis may run in parallel before a high-risk action, or after low-risk content when reversal is possible. Record hook duration by tool and reason code; a safety control that regularly times out will either break the workflow or be bypassed under pressure.

Test the Hook, Not Only the Conversation

Chat transcripts can look correct while a hook is broken. Add tests at the tool boundary with fixed identity, policy, proposal, and destination fixtures.

At minimum, replay these cases:

  1. The model supplies another tenant's identifier.
  2. A valid approval expires one second before execution.
  3. The payload changes after approval.
  4. The same action is delivered twice by a queue.
  5. The destination commits the action and then times out.
  6. A tool returns HTTP success with a rejected business result.
  7. The pre-hook service is unavailable.
  8. The post-hook cannot write its audit event.
  9. A low-risk tool name carries high-risk arguments.
  10. An indirect prompt injection asks the agent to disable or evade the hook.

For each test, assert the side effect count, public message, reason code, trace fields, retry behavior, and alert destination. A refusal in the transcript is insufficient if the tool was called first.

Hook code itself belongs inside the security boundary. Restrict who can edit it, review configuration changes, pin deployed versions, and prevent the agent's toolset from modifying its own policies. If a retrieved document can tell the agent to rewrite hooks.json, the checkpoint is only decorative. Use the severity and containment ideas in the prompt-injection triage guide when a bypass attempt reaches a tool boundary.

Make Every Action Earn Its Receipt

Tool-calling chatbots need a control point that executes even when the model is confident, rushed, or wrong. A small pre-tool contract can enforce identity, authorization, approval, and payload rules. A post-tool contract can separate an accepted request from a completed business effect. Together, they turn a prompt-level promise into a runtime guarantee you can test.

Inventory the tools, add the six hook-map fields, and begin with the action whose mistake would be hardest to reverse. When that path produces a trustworthy decision and receipt under failure, expand the pattern to the next tool.

Build your chatbot for free →

No credit card required.

Comece gratuitamenteNão é necessário cartão de crédito