2025-11-19 · Authensor

How to Add Safety Controls to Google Gemini Agents

SafeClaw by Authensor intercepts every Gemini functionCall part before your application executes it, enforcing deny-by-default policies defined in YAML. Google's Gemini API supports tool use through functionDeclarations, and SafeClaw sits between the model's function call response and your execution layer, evaluating each call against your policy in sub-millisecond time.

How Gemini Tool Calling Works

Gemini's API uses functionDeclarations in the tools parameter. When the model decides to use a tool, it returns a functionCall part containing the function name and an args object. Your application executes the function and returns a functionResponse part. Gemini also supports function_calling_config to control whether the model can call functions automatically — but this is a model-side hint, not a security boundary. SafeClaw provides the actual enforcement layer.

Gemini Response → functionCall part → [SafeClaw Policy Check] → Execute or Deny

Quick Start

npx @authensor/safeclaw

This creates a safeclaw.yaml policy file. SafeClaw maps Gemini's functionCall.name directly to policy tool names.

Step 1: Define Gemini-Specific Policies

# safeclaw.yaml
version: 1
default: deny

policies:
- name: "gemini-search-tools"
description: "Allow controlled search operations"
actions:
- tool: "google_search"
effect: allow
- tool: "code_execution"
effect: allow
constraints:
language: "python"
timeout_ms: 5000

- name: "gemini-data-access"
description: "Control data retrieval functions"
actions:
- tool: "fetch_document"
effect: allow
constraints:
source: "internal_docs"
- tool: "query_database"
effect: allow
constraints:
operation: "SELECT"
- tool: "modify_database"
effect: deny

- name: "gemini-file-policy"
description: "Restrict file system access"
actions:
- tool: "write_file"
effect: allow
constraints:
path_pattern: "output/**"
- tool: "delete_file"
effect: deny

Step 2: Integrate with the Gemini SDK

import { GoogleGenerativeAI } from "@google/generative-ai";
import { SafeClaw } from "@authensor/safeclaw";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const safeclaw = new SafeClaw("./safeclaw.yaml");

const model = genAI.getGenerativeModel({
model: "gemini-2.0-flash",
tools: [
{
functionDeclarations: [
{
name: "query_database",
description: "Execute a database query",
parameters: {
type: "OBJECT",
properties: { sql: { type: "STRING" } },
},
},
],
},
],
});

const chat = model.startChat();
const result = await chat.sendMessage("Show me recent signups");

const response = result.response;
const calls = response.functionCalls();

if (calls) {
for (const call of calls) {
const decision = safeclaw.evaluate(call.name, call.args);

if (decision.allowed) {
const toolResult = await executeTool(call.name, call.args);
await chat.sendMessage([
{ functionResponse: { name: call.name, response: toolResult } },
]);
} else {
await chat.sendMessage([
{
functionResponse: {
name: call.name,
response: { error: Blocked by policy: ${decision.reason} },
},
},
]);
}
}
}

Step 3: Handle Gemini's Grounding and Code Execution

Gemini offers built-in tools like Google Search grounding and code execution. SafeClaw can gate these as well:

policies:
  - name: "gemini-builtin-tools"
    actions:
      - tool: "google_search_retrieval"
        effect: allow
      - tool: "code_execution"
        effect: allow
        constraints:
          sandbox: true

This ensures that even Gemini's native capabilities go through your policy layer.

Step 4: Multi-Turn Function Call Loops

Gemini agents often chain multiple function calls across turns. SafeClaw evaluates each turn independently and maintains the hash-chained audit log across the entire conversation:

let response = await chat.sendMessage(userQuery);

while (response.response.functionCalls()?.length > 0) {
const functionResponses = [];
for (const call of response.response.functionCalls()) {
const decision = safeclaw.evaluate(call.name, call.args);
functionResponses.push({
functionResponse: {
name: call.name,
response: decision.allowed
? await executeTool(call.name, call.args)
: { error: decision.reason },
},
});
}
response = await chat.sendMessage(functionResponses);
}

Why SafeClaw

Related Pages

Try SafeClaw

Action-level gating for AI agents. Set it up in your browser in 60 seconds.

$ npx @authensor/safeclaw