Hooks

Mit Hooks können Sie benutzerdefinierte Skripts oder externe HTTP-Anfragen ausführen, kurz bevor oder nachdem der Agent Code ausführt oder Dateien in seiner Remote-Sandbox ändert. Verwenden Sie Hooks, um den Agent-Loop mit automatisierten Schutzmaßnahmen und Hintergrund-Workflows zu erweitern, z. B.:

  • Sicherheits- und Zugriffsschutzmaßnahmen erzwingen , bevor Shell-Befehle mit hohem Risiko oder eingeschränkte Dateilesevorgänge ausgeführt werden.
  • Datentransformationen in der Datenpipeline automatisieren , direkt nachdem ein Agent Dateien erstellt oder geändert hat.
  • Telemetriedaten für die Unternehmensprüfung streamen , nach der Ausführung des Tools an externe Überwachungssysteme.

Python

import json
from google import genai

client = genai.Client()

hooks_config = {
    "security-gate": {
        "pre_tool_execution": [
            {
                "matcher": "code_execution",
                "hooks": [
                    {
                        "type": "command",
                        "command": "python3 /.agents/hooks-scripts/gate.py",
                        "timeout": 10,
                    }
                ],
            }
        ]
    }
}

gate_script = """#!/usr/bin/env python3
import sys, json
data = json.load(sys.stdin)
cmd = str(data.get("tool_call", {}).get("args", {}))
if "rm -rf" in cmd:
    print(json.dumps({"decision": "deny", "reason": "Destructive command blocked by security gate."}))
else:
    print(json.dumps({"decision": "allow"}))
"""

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Run `rm -rf /tmp/forbidden` using code_execution.",
    tools=[{"type": "code_execution"}],
    environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/hooks.json",
                "content": json.dumps(hooks_config, indent=2),
            },
            {
                "type": "inline",
                "target": ".agents/hooks-scripts/gate.py",
                "content": gate_script,
            },
        ],
    },
)
print(interaction.output_text)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const hooksConfig = {
    "security-gate": {
        pre_tool_execution: [
            {
                matcher: "code_execution",
                hooks: [
                    {
                        type: "command",
                        command: "python3 /.agents/hooks-scripts/gate.py",
                        timeout: 10,
                    },
                ],
            },
        ],
    },
};

const gateScript = `#!/usr/bin/env python3
import sys, json
data = json.load(sys.stdin)
cmd = str(data.get("tool_call", {}).get("args", {}))
if "rm -rf" in cmd:
    print(json.dumps({"decision": "deny", "reason": "Destructive command blocked by security gate."}))
else:
    print(json.dumps({"decision": "allow"}))
`;

const interaction = await client.interactions.create({
    agent: "antigravity-preview-05-2026",
    input: "Run `rm -rf /tmp/forbidden` using code_execution.",
    tools: [{ type: "code_execution" }],
    environment: {
        type: "remote",
        sources: [
            {
                type: "inline",
                target: ".agents/hooks.json",
                content: JSON.stringify(hooksConfig, null, 2),
            },
            {
                type: "inline",
                target: ".agents/hooks-scripts/gate.py",
                content: gateScript,
            },
        ],
    },
});
console.log(interaction.output_text);

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -d '{
      "agent": "antigravity-preview-05-2026",
      "input": [{"type": "text", "text": "Run `rm -rf /tmp/forbidden` using code_execution."}],
      "tools": [{"type": "code_execution"}],
      "environment": {
          "type": "remote",
          "sources": [
              {
                  "type": "inline",
                  "target": ".agents/hooks.json",
                  "content": "{\"security-gate\": {\"pre_tool_execution\": [{\"matcher\": \"code_execution\", \"hooks\": [{\"type\": \"command\", \"command\": \"python3 /.agents/hooks-scripts/gate.py\", \"timeout\": 10}]}]}}"
              },
              {
                  "type": "inline",
                  "target": ".agents/hooks-scripts/gate.py",
                  "content": "#!/usr/bin/env python3\nimport sys, json\ndata = json.load(sys.stdin)\ncmd = str(data.get(\"tool_call\", {}).get(\"args\", {}))\nif \"rm -rf\" in cmd:\n    print(json.dumps({\"decision\": \"deny\", \"reason\": \"Destructive command blocked by security gate.\"}))\nelse:\n    print(json.dumps({\"decision\": \"allow\"}))\n"
              }
          ]
      }
  }'

Unterstützte Lebenszyklusereignisse

Hooks unterstützen zwei Ereignisse in der Sandbox:

Ereignis Auslöser Funktion
pre_tool_execution Kurz bevor ein Tool ausgeführt wird Kann das Tool genehmigen (allow) oder blockieren (deny), bevor es ausgeführt wird. Wenn es blockiert wird, sieht das Modell den Grund für Ihre Ablehnung und passt sich an.
post_tool_execution Kurz nachdem ein Tool beendet wurde Führt Folgeaufgaben aus, z. B. Code formatieren, Unit-Tests ausführen oder Telemetriedaten protokollieren. Abgeschlossene Aktionen können nicht blockiert oder rückgängig gemacht werden.

pre_tool_execution

Wird kurz vor der Ausführung eines Tools ausgelöst. Ihr Skript liest die Details des Toolaufrufs aus stdin und gibt die JSON-Entscheidung (allow oder deny) an stdout aus.

Eingabe-Payload (stdin):

{
  "tool_call": {
    "name": "code_execution",
    "args": {
      "code": "rm -rf /tmp/forbidden",
      "language": "bash"
    }
  },
  "environment_id": "env_xyz789"
}

Ausgabeantwort (stdout):

So genehmigen Sie den Toolaufruf:

{
  "decision": "allow"
}

So blockieren Sie den Toolaufruf und geben Feedback an das Modell zurück:

{
  "decision": "deny",
  "reason": "Destructive command blocked by security gate."
}

Wenn ein Hook einen Befehl ablehnt, wird der Toolaufruf sofort übersprungen. Der Agent sieht direkt in seiner aktuellen Runde ein Fehlerergebnis mit dem Grund für Ihre Ablehnung. Das Modell kann sich dann selbst korrigieren, indem es einen alternativen Befehl auswählt oder die Blockierung dem Nutzer erklärt.

Wenn Ihr Skript nicht erkannte JSON, Nur-Text oder etwas anderes als {"decision": "deny"} ausgibt, behandelt die Laufzeit die Antwort als Genehmigung (allow).

post_tool_execution

Wird kurz nach Abschluss eines Tools ausgelöst. Ihr Skript liest die Ausführungsdetails und den Fehlerstatus aus stdin.

Eingabe-Payload (stdin):

{
  "tool_call": {
    "name": "code_execution",
    "args": {
      "code": "python3 /workspace/app.py",
      "language": "bash"
    }
  },
  "environment_id": "env_xyz789"
}

Wenn ein Shell-Befehl Fehler an die Standardfehlerausgabe (stderr) ausgibt oder ein Dateisystemvorgang fehlschlägt, wird der Payload ein Feld "error" mit dem Fehlertext hinzugefügt. Wenn der Befehl ohne Fehler ausgeführt wird, wird das "error" Feld vollständig weggelassen.

Ausgabeantwort (stdout):

{}

Da Post-Tool-Hooks ausschließlich für Hintergrundaufgaben wie die Codeformatierung oder das Logging ausgeführt werden, ignoriert die Laufzeit alle Entscheidungswerte, die an stdout zurückgegeben werden.

Konfigurationserkennung

Die Laufzeit erkennt Hook-Definitionen automatisch aus .agents/hooks.json oder /.agents/hooks.json in der Sandbox-Umgebung. Sie können hooks.json zusammen mit Ihren benutzerdefinierten Skripts über eine beliebige unterstützte Umgebungsquelle bereitstellen:

  • Repository-Mount: Ein Git-Repository mit .agents/hooks.json neben AGENTS.md.
  • Cloud Storage (gcs): Ein GCS-Bucket mit hooks.json, das in die Umgebung kopiert wurde.
  • Inline-Quellen: Roher JSON-String und Skriptinhalte, die beim Aufrufen von client.interactions.create in environment.sources übergeben werden.

hooks.json-Schema

In einer hooks.json-Datei werden Ereignisdefinitionen (pre_tool_execution oder post_tool_execution) unter benutzerdefinierten Namen gruppiert. Sie können jede Gruppe unabhängig aktivieren oder deaktivieren:

{
  "security-gate": {
    "enabled": true,
    "pre_tool_execution": [
      {
        "matcher": "code_execution",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /.agents/hooks-scripts/gate.py",
            "timeout": 10
          }
        ]
      }
    ]
  },
  "auto-format": {
    "post_tool_execution": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /.agents/hooks-scripts/auto_lint.py",
            "timeout": 15
          }
        ]
      }
    ]
  }
}

Syntax und Regeln für Matcher

Jede Regelgruppe in hooks.json definiert mit den Eigenschaften matcher und hooks, wann und wie Handler ausgelöst werden:

Feld Typ Beschreibung
enabled boolean Optional. Legen Sie false fest, um die Gruppe zu deaktivieren (true ist die Standardeinstellung).
matcher string Regulärer Ausdruck, der mit den Namen der Zieltools im Container übereinstimmt.
hooks array Geordnete Liste von Handler-Definitionen (command oder http). Handler werden sequenziell in der Reihenfolge der Deklaration ausgeführt.

So funktioniert die Auswertung regulärer Ausdrücke

Wenn der Agent ein Tool in der Sandbox aufruft, wertet die Laufzeit den Containernamen des Tools anhand Ihres matcher-Musters mit regulären RE2-Ausdrücken aus. Wenn der reguläre Ausdruck mit dem Toolnamen übereinstimmt, werden alle Handler im hooks-Array in der Reihenfolge ausgeführt. Wenn mehrere Regelgruppen mit demselben Tool übereinstimmen, werden alle entsprechenden Handler-Arrays ausgeführt.

Sie können jeden integrierten Containertoolnamen verwenden: Codeausführung (code_execution) oder Dateisystemvorgänge (read_file, write_file, list_files und delete_file).

Häufig verwendete Matcher-Ausdrücke

  • "code_execution": Exakte Stringübereinstimmung für Shell-Befehle und Skriptausführungen.
  • "write_file": Exakte Übereinstimmung für die Erstellung von Dateisystemdateien und Festplattenschreibvorgänge.
  • "read_file|write_file": Die Trennung durch einen senkrechten Strich ermöglicht die Übereinstimmung mit mehreren bestimmten Toolnamen in einer einzigen Regel.
  • ".*_file": Regulärer Ausdruck mit Platzhalter, der mit jedem Tool übereinstimmt, das mit _file endet (z. B. read_file, write_file oder delete_file). Für reguläre RE2-Ausdrücke ist .* erforderlich. Einfache Shell-Globs wie *_file sind keine gültige Syntax für reguläre Ausdrücke und führen zu keiner Übereinstimmung.
  • ".*" oder "*" oder "": Catch-all-Muster, das jeden einzelnen Toolaufruf im Container abfängt.

Handler-Typen

Befehls-Hooks

Befehls-Hooks führen einen Shell-Befehl oder ein Skript in der Sandbox aus. Das Skript empfängt das Ereignis-JSON über stdin und gibt das Entscheidungs-JSON über stdout aus.

Feld Typ Beschreibung
type string Muss "command" sein.
command string Befehlszeile, die in der Sandbox ausgeführt werden soll (z. B. python3 /.agents/hooks-scripts/gate.py).
timeout integer Zeitlimit in Sekunden. Standard: 30.

HTTP-Hooks

HTTP-Hooks senden das Ereignis-JSON als POST-Anfrage direkt aus dem Sandbox-Netzwerk an eine externe HTTPS-URL. Der Zielserver gibt seine Entscheidung im HTTP-Antworttext im genau gleichen JSON-Format zurück ({"decision": "allow"} oder {"decision": "deny", "reason": "..."}).

Feld Typ Beschreibung
type string Muss "http" sein.
url string Externer HTTPS-Endpunkt, an den die Ereignis-Payload gesendet werden soll.
headers object Optionale Schlüssel/Wert-Paare für nicht vertrauliche benutzerdefinierte Header (z. B. {"X-Event-Source": "agent-sandbox"}). Verwenden Sie stattdessen den Netzwerkproxy für Authentifizierungsdaten.
timeout integer Zeitlimit in Sekunden. Standard: 30.

Egress-Proxy und Tokentransformation

Da HTTP-Hooks direkt aus dem Netzwerk-Namespace der Sandbox ausgeführt werden, werden ausgehende Anfragen über den transparenten Egress-Proxy geleitet. Diese Architektur bietet Ihnen zwei entscheidende Sicherheitsvorteile:

  • Netzwerk-Allowlisting: Zielendpunkte müssen in der network.allowlist Ihrer Umgebung explizit zugelassen werden. Loopback-Traffic (127.0.0.1 oder localhost) wird vom Proxy blockiert. Verwenden Sie immer zugelassene externe Endpunkte.
  • Tokentransformation: Sie müssen keine API-Schlüssel oder geheimen Bearertokens in .agents/hooks.json speichern oder in den Container einbinden. Konfigurieren Sie stattdessen Regeln für die Tokentransformation in Ihrer Netzwerkkonfiguration (network.allowlist.transform). Der Egress-Proxy fängt ausgehenden HTTP-Hook-Traffic automatisch ab und fügt Ihre echten Authentifizierungsheader ein, bevor er die Sandbox verlässt.

So verarbeitet die Laufzeit Entscheidungen und Fehler

  • Synchrone Wartezeit: Der Agent pausiert und wartet, bis Ihre Hooks abgeschlossen sind, bevor er fortfährt.
  • Toolausführung blockieren: Wenn Ihr Pre-Tool-Hook {"decision": "deny", "reason": "<your reason>"} zurückgibt, bricht die Laufzeit den Toolaufruf sofort ab. Der Grund für Ihre Ablehnung wird im Unterhaltungsverlauf des Modells angezeigt. Das Modell passt sich an, indem es eine sichere Alternative auswählt oder die Blockierung dem Nutzer erklärt.
  • Skriptabstürze, HTTP-Fehler und Zeitüberschreitungen verarbeiten: Wenn ein Befehlsskript abstürzt (Exit-Status ungleich null), ein HTTP-Hook einen Statuscode ungleich 2xx zurückgibt (z. B. ein 4xx- oder 5xx-Serverfehler) oder ein Vorgang eine Zeitüberschreitung verursacht oder nicht erkannte JSON zurückgibt, behandelt die Laufzeit dies als Genehmigung (allow). Die Toolausführung wird normal fortgesetzt, sodass ein fehlerhaftes Skript oder ein nicht erreichbarer Telemetrieserver Ihre Anwendung niemals blockieren kann.

Häufige Anwendungsfälle

Wiederherstellung in mehreren Runden für Datenschutz und Compliance

Wenn ein Hook den Zugriff auf eingeschränkte Ressourcen blockiert, z. B. auf Verzeichnisse mit personenbezogenen Daten oder vertraulichen Finanzdaten, können Sie previous_interaction_id im nächsten Aufruf übergeben, um die Runde in derselben Umgebung fortzusetzen. Der Agent liest die Erklärung für die Ablehnung und stellt automatisch eine Verbindung wieder her, indem er stattdessen genehmigte öffentliche Tabellen abfragt.

Python

import json
from google import genai

client = genai.Client()

hooks_config = {
    "privacy-gate": {
        "pre_tool_execution": [
            {
                "matcher": "read_file",
                "hooks": [
                    {
                        "type": "command",
                        "command": "python3 /.agents/hooks-scripts/check_privacy.py",
                        "timeout": 5,
                    }
                ],
            }
        ]
    }
}

check_privacy_script = """#!/usr/bin/env python3
import sys, json
data = json.load(sys.stdin)
path = str(data.get("tool_call", {}).get("args", {}).get("path", ""))

if "/private/" in path:
    resp = {
        "decision": "deny",
        "reason": "Access to confidential `/private/` records is blocked by PII compliance policy. Query approved `/public/` summary tables instead."
    }
else:
    resp = {"decision": "allow"}

print(json.dumps(resp))
"""

# Step 1: Agent attempts to read confidential PII records and is intercepted
int_1 = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Use your filesystem tool to read `/workspace/private/employees.json` and summarize the employee details.",
    environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/hooks.json",
                "content": json.dumps(hooks_config, indent=2),
            },
            {
                "type": "inline",
                "target": ".agents/hooks-scripts/check_privacy.py",
                "content": check_privacy_script,
            },
            {
                "type": "inline",
                "target": "workspace/private/employees.json",
                "content": '{"employees": [{"id": 1, "salary": 150000, "ssn": "000-00-0000"}]}',
            },
            {
                "type": "inline",
                "target": "workspace/public/summary.json",
                "content": '{"department": "Engineering", "team_size": 42, "status": "active"}',
            },
        ],
    },
)
print(int_1.output_text)

# Step 2: Continue in the same environment using previous_interaction_id; agent recovers with public tables
int_2 = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Understood. Please read the approved `/workspace/public/summary.json` file instead and provide the summary.",
    environment=int_1.environment_id,
    previous_interaction_id=int_1.id,
)
print(int_2.output_text)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const hooksConfig = {
    "privacy-gate": {
        pre_tool_execution: [
            {
                matcher: "read_file",
                hooks: [
                    {
                        type: "command",
                        command: "python3 /.agents/hooks-scripts/check_privacy.py",
                        timeout: 5,
                    },
                ],
            },
        ],
    },
};

const checkPrivacyScript = `#!/usr/bin/env python3
import sys, json
data = json.load(sys.stdin)
path = str(data.get("tool_call", {}).get("args", {}).get("path", ""))

if "/private/" in path:
    resp = {
        "decision": "deny",
        "reason": "Access to confidential \`/private/\` records is blocked by PII compliance policy. Query approved \`/public/\` summary tables instead."
    }
else:
    resp = {"decision": "allow"}

print(json.dumps(resp))
`;

const int1 = await client.interactions.create({
    agent: "antigravity-preview-05-2026",
    input: "Use your filesystem tool to read `/workspace/private/employees.json` and summarize the employee details.",
    environment: {
        type: "remote",
        sources: [
            {
                type: "inline",
                "target": ".agents/hooks.json",
                content: JSON.stringify(hooksConfig, null, 2),
            },
            {
                type: "inline",
                "target": ".agents/hooks-scripts/check_privacy.py",
                content: checkPrivacyScript,
            },
            {
                type: "inline",
                "target": "workspace/private/employees.json",
                content: '{"employees": [{"id": 1, "salary": 150000, "ssn": "000-00-0000"}]}',
            },
            {
                type: "inline",
                "target": "workspace/public/summary.json",
                content: '{"department": "Engineering", "team_size": 42, "status": "active"}',
            },
        ],
    },
});
console.log(int1.output_text);

const int2 = await client.interactions.create({
    agent: "antigravity-preview-05-2026",
    input: "Understood. Please read the approved `/workspace/public/summary.json` file instead and provide the summary.",
    environment: int1.environment_id,
    previous_interaction_id: int1.id,
});
console.log(int2.output_text);

REST

# Step 1: Attempt to access restricted PII directory (blocked by hook)
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -d '{
      "agent": "antigravity-preview-05-2026",
      "input": [{"type": "text", "text": "Use your filesystem tool to read /workspace/private/employees.json and summarize the employee details."}],
      "environment": {
          "type": "remote",
          "sources": [
              {
                  "type": "inline",
                  "target": ".agents/hooks.json",
                  "content": "{\"privacy-gate\": {\"pre_tool_execution\": [{\"matcher\": \"read_file\", \"hooks\": [{\"type\": \"command\", \"command\": \"python3 /.agents/hooks-scripts/check_privacy.py\", \"timeout\": 5}]}]}}"
              },
              {
                  "type": "inline",
                  "target": ".agents/hooks-scripts/check_privacy.py",
                  "content": "#!/usr/bin/env python3\nimport sys, json\ndata = json.load(sys.stdin)\npath = str(data.get(\"tool_call\", {}).get(\"args\", {}).get(\"path\", \"\"))\nif \"/private/\" in path:\n    resp = {\"decision\": \"deny\", \"reason\": \"Access to confidential `/private/` records is blocked by PII compliance policy. Query approved `/public/` summary tables instead.\"}\nelse:\n    resp = {\"decision\": \"allow\"}\nprint(json.dumps(resp))\n"
              },
              {
                  "type": "inline",
                  "target": "workspace/private/employees.json",
                  "content": "{\"employees\": [{\"id\": 1, \"salary\": 150000, \"ssn\": \"000-00-0000\"}]}"
              },
              {
                  "type": "inline",
                  "target": "workspace/public/summary.json",
                  "content": "{\"department\": \"Engineering\", \"team_size\": 42, \"status\": \"active\"}"
              }
          ]
      }
  }'

# Step 2: Continue in the same environment using $ENV_ID and $INTERACTION_ID from the previous response
# curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
#   -H "Content-Type: application/json" \
#   -H "x-goog-api-key: $GEMINI_API_KEY" \
#   -d '{
#       "agent": "antigravity-preview-05-2026",
#       "input": [{"type": "text", "text": "Understood. Please read the approved /workspace/public/summary.json file instead and provide the summary."}],
#       "environment": "'"$ENV_ID"'",
#       "previous_interaction_id": "'"$INTERACTION_ID"'"
#   }'

Externe Audit-Logs und Telemetrie

Senden Sie in Echtzeit Auditereignisse aus der Sandbox an einen externen Überwachungsserver, wenn Dateien gelesen oder geändert werden.

  • Mehrere Tools abgleichen: Da Matcher reguläre Ausdrücke verwenden, können Sie mehrere Tools in einer einzigen Regel kombinieren, indem Sie senkrechte Striche (read_file|write_file) oder Platzhalter (.*_file) verwenden.
  • Geheimnisse aus der Konfiguration entfernen: Definieren Sie Authentifizierungstokens in der Netzwerkkonfiguration Ihrer Umgebung (network.allowlist.transform). Der Egress-Proxy fügt ausgehenden Anfragen automatisch Ihre echten Bearertokens hinzu.

Python

import json
from google import genai

client = genai.Client()

# Define hook without secrets; the egress proxy injects headers dynamically
hooks_config = {
    "audit-logging": {
        "post_tool_execution": [
            {
                "matcher": "read_file|write_file",
                "hooks": [
                    {
                        "type": "http",
                        "url": "https://telemetry.example.com/api/v1/agent-events",
                        "timeout": 10,
                    }
                ],
            }
        ]
    }
}

interaction = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Use your filesystem tool to create `/workspace/audit.log` containing 'event 1', then immediately read it back using your filesystem read tool.",
    environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/hooks.json",
                "content": json.dumps(hooks_config, indent=2),
            }
        ],
        "network": {
            "allowlist": [
                {
                    "domain": "telemetry.example.com",
                    "transform": {
                        "Authorization": "Bearer telemetry_secret_token_123",
                    },
                },
                {"domain": "*"},
            ]
        },
    },
)
print(interaction.output_text)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

// Define hook without secrets; the egress proxy injects headers dynamically
const hooksConfig = {
    "audit-logging": {
        post_tool_execution: [
            {
                matcher: "read_file|write_file",
                hooks: [
                    {
                        type: "http",
                        url: "https://telemetry.example.com/api/v1/agent-events",
                        timeout: 10,
                    },
                ],
            },
        ],
    },
};

const interaction = await client.interactions.create({
    agent: "antigravity-preview-05-2026",
    input: "Use your filesystem tool to create `/workspace/audit.log` containing 'event 1', then immediately read it back using your filesystem read tool.",
    environment: {
        type: "remote",
        sources: [
            {
                type: "inline",
                target: ".agents/hooks.json",
                content: JSON.stringify(hooksConfig, null, 2),
            },
        ],
        network: {
            allowlist: [
                {
                    domain: "telemetry.example.com",
                    transform: {
                        Authorization: "Bearer telemetry_secret_token_123",
                    },
                },
                { domain: "*" },
            ],
        },
    },
});
console.log(interaction.output_text);

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "Content-Type: application/json" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -d '{
      "agent": "antigravity-preview-05-2026",
      "input": [{"type": "text", "text": "Use your filesystem tool to create /workspace/audit.log containing event 1, then immediately read it back using your filesystem read tool."}],
      "environment": {
          "type": "remote",
          "sources": [
              {
                  "type": "inline",
                  "target": ".agents/hooks.json",
                  "content": "{\"audit-logging\": {\"post_tool_execution\": [{\"matcher\": \"read_file|write_file\", \"hooks\": [{\"type\": \"http\", \"url\": \"https://telemetry.example.com/api/v1/agent-events\", \"timeout\": 10}]}]}}"
              }
          ],
          "network": {
              "allowlist": [
                  {
                      "domain": "telemetry.example.com",
                      "transform": {
                          "Authorization": "Bearer telemetry_secret_token_123"
                      }
                  },
                  {"domain": "*"}
              ]
          }
      }
  }'

Beschränkungen

  • Toolbereich der Sandbox: Hooks fangen integrierte Tools in der Sandbox ab: Code-Ausführung (code_execution) und Dateisystemvorgänge (read_file, write_file, list_files und delete_file). Sie werden nicht für benutzerdefinierte Funktionsaufrufe (function) oder externe Model Context Protocol-Tools (mcp_server) ausgelöst, die außerhalb des Containers verarbeitet werden.
  • Netzwerk-Allowlists: HTTP-Hooks werden im Containernetzwerk ausgeführt. Sie müssen Ziel-URLs in der network.allowlist Ihrer Umgebung explizit zulassen. Loopback-Adressen (localhost, 127.0.0.1) werden vom Proxy blockiert.
  • Automatische Genehmigung bei Fehlern: Wenn ein Hook-Skript abstürzt (Exit-Status ungleich null), eine Zeitüberschreitung verursacht oder fehlschlägt, protokolliert die Laufzeit den Fehler und lässt den Toolaufruf fortfahren. So wird verhindert, dass fehlerhafte Linter-Skripts oder hängende Prozesse Ihre Anwendungen blockieren.
  • Schutz der Sandbox-Konfiguration: Da Hooks in der Container-Sandbox ausgeführt werden, können Agents mit Dateisystem-Schreibtools oder Berechtigungen zur Ausführung von Shell-Code die lokale Datei .agents/hooks.json oder Skripts in beschreibbaren Arbeitsbereichen ändern. Verwenden Sie Container-Hooks als automatisierte Richtlinien und operative Schutzmaßnahmen. Wenn ein strenger Manipulationsschutz gegen nicht vertrauenswürdige Modellausführungen erforderlich ist, binden Sie Konfigurationsquellen aus schreibgeschützten Repositories ein.

Nächste Schritte