Hooks

हुक की मदद से, कस्टम स्क्रिप्ट या बाहरी एचटीटीपी अनुरोधों को एजेंट के कोड चलाने या उसके रिमोट सैंडबॉक्स में मौजूद फ़ाइलों में बदलाव करने से ठीक पहले या बाद में चलाया जा सकता है. ऑटोमेटेड गार्डरेल और बैकग्राउंड वर्कफ़्लो के साथ एजेंट लूप को बढ़ाने के लिए, हुक का इस्तेमाल करें. जैसे:

  • ज़्यादा जोखिम वाले शेल कमांड या पाबंदी वाली फ़ाइलें पढ़ने से पहले, सुरक्षा और ऐक्सेस गार्डरेल लागू करना.
  • किसी एजेंट के फ़ाइलें बनाने या उनमें बदलाव करने के ठीक बाद, डेटा पाइपलाइन के बदलावों को ऑटोमेट करना.
  • टूल के चलने के बाद, एंटरप्राइज़ ऑडिट टेलीमेट्री को बाहरी मॉनिटरिंग सिस्टम पर स्ट्रीम करना.

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"
              }
          ]
      }
  }'

काम करने वाले लाइफ़साइकल इवेंट

हुक, सैंडबॉक्स में दो इवेंट के साथ काम करते हैं:

इवेंट यह कब ट्रिगर होता है यह क्या करता है
pre_tool_execution किसी टूल के चलने से ठीक पहले टूल के चलने से पहले, उसे अनुमति (allow) दी जा सकती है या ब्लॉक (deny) किया जा सकता है. ब्लॉक करने पर, मॉडल को अस्वीकार करने की वजह दिखती है और वह उसके हिसाब से काम करता है.
post_tool_execution किसी टूल के खत्म होने के ठीक बाद फ़ॉलो-अप टास्क चलाता है. जैसे, कोड को फ़ॉर्मैट करना, यूनिट टेस्ट चलाना या टेलीमेट्री लॉग करना. पूरे हो चुके ऐक्शन को ब्लॉक या अनडू नहीं किया जा सकता.

pre_tool_execution

यह किसी टूल के चलने से ठीक पहले ट्रिगर होता है. आपकी स्क्रिप्ट, stdin से टूल कॉल की जानकारी पढ़ती है और stdout पर अपना फ़ैसला JSON (allow या deny) के तौर पर दिखाती है.

इनपुट पेलोड (stdin):

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

आउटपुट रिस्पॉन्स (stdout):

टूल कॉल को अनुमति देने के लिए:

{
  "decision": "allow"
}

टूल कॉल को ब्लॉक करने और मॉडल को फ़ीडबैक देने के लिए:

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

जब कोई हुक किसी कमांड को अस्वीकार करता है, तो टूल कॉल तुरंत स्किप हो जाता है. एजेंट को, मौजूदा टर्न में ही गड़बड़ी का नतीजा दिखता है. इसमें, अस्वीकार करने की वजह शामिल होती है. इसके बाद, मॉडल किसी दूसरी कमांड को चुनकर या उपयोगकर्ता को ब्लॉक करने की वजह बताकर, खुद को ठीक कर सकता है.

अगर आपकी स्क्रिप्ट, JSON के तौर पर ऐसी वैल्यू दिखाती है जिसे पहचाना नहीं जा सकता, सादा टेक्स्ट दिखाती है या {"decision": "deny"} के अलावा कोई और वैल्यू दिखाती है, तो रनटाइम, रिस्पॉन्स को अनुमति (allow) के तौर पर लेता है.

post_tool_execution

यह किसी टूल के खत्म होने के ठीक बाद ट्रिगर होता है. आपकी स्क्रिप्ट, stdin से चलने की जानकारी और गड़बड़ी की स्थिति पढ़ती है.

इनपुट पेलोड (stdin):

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

अगर कोई शेल कमांड, स्टैंडर्ड एरर (stderr) पर गड़बड़ियां दिखाता है या फ़ाइल सिस्टम का कोई ऑपरेशन फ़ेल हो जाता है, तो पेलोड में "error" फ़ील्ड शामिल किया जाता है. इसमें, गड़बड़ी का टेक्स्ट शामिल होता है. जब कमांड बिना किसी गड़बड़ी के पूरी हो जाती है, तो "error" फ़ील्ड पूरी तरह से हटा दिया जाता है.

आउटपुट रिस्पॉन्स (stdout):

{}

पोस्ट-टूल हुक, सिर्फ़ बैकग्राउंड टास्क के लिए चलते हैं. जैसे, कोड को फ़ॉर्मैट करना या लॉग करना. इसलिए, रनटाइम, stdout पर दिखाई गई किसी भी फ़ैसले की वैल्यू को अनदेखा करता है.

कॉन्फ़िगरेशन की खोज

रनटाइम, सैंडबॉक्स एनवायरमेंट में मौजूद .agents/hooks.json या /.agents/hooks.json से, हुक की परिभाषाओं का पता अपने-आप लगाता है. आपके पास, काम करने वाले किसी भी एनवायरमेंट सोर्स का इस्तेमाल करके, अपनी कस्टम स्क्रिप्ट के साथ hooks.json देने का विकल्प है:

  • डेटा स्टोर करने की जगह को माउंट करना: इसमें, Git डेटा स्टोर करने की जगह शामिल है. इसमें .agents/hooks.json के साथ AGENTS.md मौजूद है.
  • Cloud Storage (gcs): इसमें, GCS बकेट शामिल है. इसमें, एनवायरमेंट में कॉपी की गई hooks.json मौजूद है.
  • इनलाइन सोर्स: इसमें, रॉ JSON स्ट्रिंग और स्क्रिप्ट का कॉन्टेंट शामिल है. इसे environment.sources को कॉल करते समय, client.interactions.create में पास किया जाता है.

hooks.json स्कीमा

hooks.json फ़ाइल, कस्टम नामों के तहत इवेंट की परिभाषाओं (pre_tool_execution या post_tool_execution) को ग्रुप करती है. आपके पास हर ग्रुप को अलग-अलग चालू या बंद करने का विकल्प है:

{
  "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
          }
        ]
      }
    ]
  }
}

मैचर का सिंटैक्स और नियम

hooks.json में मौजूद हर नियम ग्रुप, matcher और hooks प्रॉपर्टी का इस्तेमाल करके यह तय करता है कि हैंडलर कब और कैसे ट्रिगर होते हैं:

फ़ील्ड टाइप ब्यौरा
enabled boolean ज़रूरी नहीं. ग्रुप को बंद करने के लिए, false पर सेट करें. यह डिफ़ॉल्ट रूप से true पर सेट होता है.
matcher string कंटेनर में मौजूद टारगेट टूल के नामों से मेल खाने वाला रेगुलर एक्सप्रेशन पैटर्न.
hooks array हैंडलर की परिभाषाओं (command या http) की क्रम से लगाई गई सूची. हैंडलर, एलान के क्रम में चलते हैं.

रेगुलर एक्सप्रेशन का आकलन कैसे काम करता है

जब एजेंट, सैंडबॉक्स में किसी टूल को शुरू करता है, तो रनटाइम, स्टैंडर्ड RE2 रेगुलर एक्सप्रेशन का इस्तेमाल करके, आपके matcher पैटर्न के हिसाब से टूल के कंटेनर के नाम का आकलन करता है. अगर रेगुलर एक्सप्रेशन, टूल के नाम से मेल खाता है, तो hooks कलेक्शन में मौजूद सभी हैंडलर क्रम से चलते हैं. अगर एक से ज़्यादा नियम ग्रुप, एक ही टूल से मेल खाते हैं, तो उससे जुड़े सभी हैंडलर कलेक्शन चलते हैं.

आपके पास, पहले से मौजूद किसी भी कंटेनर टूल के नाम को टारगेट करने का विकल्प है: कोड एक्ज़ीक्यूशन (code_execution) या फ़ाइल सिस्टम के ऑपरेशन (read_file, write_file, list_files, और delete_file).

मैचर के सामान्य एक्सप्रेशन

  • "code_execution": शेल कमांड और स्क्रिप्ट के चलने के लिए, स्ट्रिंग का सटीक मिलान.
  • "write_file": फ़ाइल सिस्टम में फ़ाइल बनाने और डिस्क पर लिखने के लिए, सटीक मिलान.
  • "read_file|write_file": पाइप से अलग करने पर, एक ही नियम में कई खास टूल के नाम मेल खाते हैं.
  • ".*_file": रेगुलर एक्सप्रेशन वाइल्डकार्ड, _file पर खत्म होने वाले किसी भी टूल से मेल खाता है. जैसे, read_file, write_file या delete_file. स्टैंडर्ड RE2 रेगुलर एक्सप्रेशन के लिए .* की ज़रूरत होती है. वहीं, *_file जैसे सामान्य शेल ग्लोब, रेगुलर एक्सप्रेशन के अमान्य सिंटैक्स होते हैं और इनसे मिलान नहीं हो पाएगा.
  • ".*" या "*" या "": कैच-ऑल पैटर्न, कंटेनर में मौजूद हर टूल कॉल को इंटरसेप्ट करता है.

हैंडलर के टाइप

कमांड हुक

कमांड हुक, सैंडबॉक्स में शेल कमांड या स्क्रिप्ट चलाते हैं. स्क्रिप्ट को stdin पर इवेंट JSON मिलता है और वह stdout पर अपना फ़ैसला JSON के तौर पर दिखाती है.

फ़ील्ड टाइप ब्यौरा
type string यह "command" होना चाहिए.
command string सैंडबॉक्स में चलाने के लिए कमांड लाइन. उदाहरण के लिए, python3 /.agents/hooks-scripts/gate.py.
timeout integer सेकंड में टाइम आउट. डिफ़ॉल्ट: 30.

एचटीटीपी हुक

एचटीटीपी हुक, इवेंट JSON को सैंडबॉक्स नेटवर्क से सीधे किसी बाहरी एचटीटीपीएस यूआरएल पर POST अनुरोध के तौर पर भेजते हैं. टारगेट सर्वर, एचटीटीपी रिस्पॉन्स बॉडी में अपना फ़ैसला, JSON के ठीक उसी फ़ॉर्मैट ({"decision": "allow"} या {"decision": "deny", "reason": "..."}) में दिखाता है.

फ़ील्ड टाइप ब्यौरा
type string यह "http" होना चाहिए.
url string इवेंट पेलोड को पोस्ट करने के लिए, बाहरी एचटीटीपीएस एंडपॉइंट.
headers object संवेदनशील नहीं होने वाले कस्टम हेडर के लिए, ज़रूरी नहीं है कि इसमें कुंजी-वैल्यू पेयर शामिल हों. जैसे, {"X-Event-Source": "agent-sandbox"}. पुष्टि करने के क्रेडेंशियल के लिए, इसके बजाय नेटवर्क प्रॉक्सी का इस्तेमाल करें.
timeout integer सेकंड में टाइम आउट. डिफ़ॉल्ट: 30.

इग्रेस प्रॉक्सी और टोकन में बदलाव

एचटीटीपी हुक, सैंडबॉक्स नेटवर्क नेमस्पेस से सीधे चलते हैं. इसलिए, आउटगोइंग अनुरोध, ट्रांसपैरंट इग्रेस प्रॉक्सी से होकर गुज़रते हैं. इस आर्किटेक्चर से, आपको सुरक्षा से जुड़े दो अहम फ़ायदे मिलते हैं:

  • नेटवर्क की अनुमति वाली सूची: टारगेट एंडपॉइंट को आपके एनवायरमेंट के network.allowlist में साफ़ तौर पर अनुमति दी जानी चाहिए. लूपबैक ट्रैफ़िक (127.0.0.1 या localhost) को प्रॉक्सी ब्लॉक कर देती है. इसलिए, हमेशा अनुमति वाली सूची में शामिल बाहरी एंडपॉइंट को टारगेट करें.
  • टोकन में बदलाव: आपको .agents/hooks.json में एपीआई कुंजियां या सीक्रेट बियरर टोकन सेव करने या उन्हें कंटेनर में माउंट करने की ज़रूरत नहीं है. इसके बजाय, अपने नेटवर्क कॉन्फ़िगरेशन (network.allowlist.transform) में टोकन में बदलाव करने के नियम कॉन्फ़िगर करें. इग्रेस प्रॉक्सी, आउटगोइंग एचटीटीपी हुक ट्रैफ़िक को अपने-आप इंटरसेप्ट करती है और सैंडबॉक्स से बाहर निकलने से पहले, वायर पर आपके असली पुष्टि करने वाले हेडर को इंजेक्ट करती है.

रनटाइम, फ़ैसलों और गड़बड़ियों को कैसे हैंडल करता है

  • सिंक्रोनस इंतज़ार: एजेंट, आपके हुक के खत्म होने तक रुकता है और उसके बाद ही आगे बढ़ता है.
  • टूल के चलने को ब्लॉक करना: अगर आपका प्री-टूल हुक, {"decision": "deny", "reason": "<your reason>"} दिखाता है, तो रनटाइम तुरंत टूल कॉल को रद्द कर देता है. मॉडल को, बातचीत के इतिहास में अस्वीकार करने की वजह दिखती है. इसके बाद, वह सुरक्षित विकल्प चुनकर या उपयोगकर्ता को ब्लॉक करने की वजह बताकर, उसके हिसाब से काम करता है.
  • स्क्रिप्ट क्रैश होने, एचटीटीपी गड़बड़ियों, और टाइम आउट को हैंडल करना: अगर कोई कमांड स्क्रिप्ट क्रैश हो जाती है (नॉन-ज़ीरो एक्ज़िट स्टेटस), कोई एचटीटीपी हुक, नॉन-2xx स्टेटस कोड (जैसे, 4xx या 5xx सर्वर की गड़बड़ी) दिखाता है या कोई ऑपरेशन टाइम आउट हो जाता है या JSON के तौर पर ऐसी वैल्यू दिखाता है जिसे पहचाना नहीं जा सकता, तो रनटाइम इसे अनुमति (allow) के तौर पर लेता है. टूल का चलना सामान्य तरीके से जारी रहता है. इसलिए, खराब स्क्रिप्ट या टेलीमेट्री सर्वर के काम न करने की वजह से, आपका ऐप्लिकेशन कभी भी डेडलॉक नहीं होता.

इस्तेमाल के सामान्य उदाहरण

डेटा की निजता और अनुपालन के लिए, मल्टी-टर्न रिकवरी

जब कोई हुक, पाबंदी वाले रिसॉर्स के ऐक्सेस को ब्लॉक करता है, तो उसी एनवायरमेंट में टर्न जारी रखने के लिए, अगले कॉल पर previous_interaction_id पास किया जा सकता है. पाबंदी वाले रिसॉर्स में, व्यक्तिगत पहचान से जुड़ी जानकारी (पीआईआई) या गोपनीय वित्तीय रिकॉर्ड वाले डायरेक्ट्री शामिल हो सकती हैं. एजेंट, अस्वीकार करने की वजह पढ़ता है और अनुमति वाली सार्वजनिक टेबल के लिए क्वेरी करके, अपने-आप रिकवर हो जाता है.

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"'"
#   }'

बाहरी ऑडिट लॉगिंग और टेलीमेट्री

जब भी फ़ाइलें पढ़ी या उनमें बदलाव किया जाता है, तब सैंडबॉक्स से रीयल-टाइम ऑडिट इवेंट को किसी बाहरी मॉनिटरिंग सर्वर पर भेजें.

  • एक से ज़्यादा टूल से मिलान करना: मैचर, स्टैंडर्ड रेगुलर एक्सप्रेशन का इस्तेमाल करते हैं. इसलिए, पाइप (read_file|write_file) या वाइल्डकार्ड (.*_file) का इस्तेमाल करके, एक ही नियम में एक से ज़्यादा टूल को जोड़ा जा सकता है.
  • अपने कॉन्फ़िगरेशन में सीक्रेट न रखें: अपने एनवायरमेंट के नेटवर्क कॉन्फ़िगरेशन (network.allowlist.transform) में पुष्टि करने वाले टोकन तय करें. इग्रेस प्रॉक्सी, आउटगोइंग अनुरोधों पर आपके असली बियरर टोकन को अपने-आप इंजेक्ट करती है.

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": "*"}
              ]
          }
      }
  }'

सीमाएं

  • सैंडबॉक्स टूल का दायरा: हुक, सैंडबॉक्स में पहले से मौजूद टूल को इंटरसेप्ट करते हैं: कोड का चलना (code_execution) और फ़ाइल सिस्टम के ऑपरेशन (read_file, write_file, list_files, और delete_file). ये कस्टम फ़ंक्शन को कॉल करने (function) या कंटेनर के बाहर हैंडल किए जाने वाले बाहरी मॉडल कॉन्टेक्स्ट प्रोटोकॉल (mcp_server) टूल के लिए ट्रिगर नहीं होते.
  • नेटवर्क की अनुमति वाली सूची: एचटीटीपी हुक, कंटेनर नेटवर्क में चलते हैं. आपको अपने एनवायरमेंट के network.allowlist में टारगेट यूआरएल को साफ़ तौर पर अनुमति देनी होगी. लूपबैक पतों (localhost, 127.0.0.1) को प्रॉक्सी ब्लॉक कर देती है.
  • गड़बड़ियों पर अपने-आप अनुमति मिलना: अगर कोई हुक स्क्रिप्ट क्रैश हो जाती है (नॉन-ज़ीरो एक्ज़िट स्टेटस), टाइम आउट हो जाती है या फ़ेल हो जाती है, तो रनटाइम, गड़बड़ी को लॉग करता है और टूल कॉल को जारी रखने की अनुमति देता है. इससे यह पक्का होता है कि लिंटर स्क्रिप्ट के खराब होने या प्रोसेस के रुकने की वजह से, आपके ऐप्लिकेशन कभी भी डेडलॉक नहीं होते.
  • सैंडबॉक्स कॉन्फ़िगरेशन की सुरक्षा: हुक, कंटेनर सैंडबॉक्स में चलते हैं. इसलिए, फ़ाइल सिस्टम में लिखने वाले टूल या शेल कोड एक्ज़ीक्यूशन की अनुमतियों वाले एजेंट, स्थानीय .agents/hooks.json या लिखने की अनुमति वाले वर्कस्पेस में मौजूद स्क्रिप्ट में बदलाव कर सकते हैं. कंटेनर हुक का इस्तेमाल, ऑटोमेटेड नीति के दिशा-निर्देश और ऑपरेशनल गार्डरेल के तौर पर करें. अगर भरोसेमंद नहीं माने जाने वाले मॉडल के चलने के दौरान, छेड़छाड़ से बचने के लिए सख्त सुरक्षा की ज़रूरत है, तो सिर्फ़ पढ़ने की अनुमति वाले डेटा स्टोर करने की जगहों से कॉन्फ़िगरेशन सोर्स को माउंट करें.

आगे क्या करना है