হুকস

হুকস আপনাকে এজেন্ট তার রিমোট স্যান্ডবক্সের ভিতরে কোড এক্সিকিউট করার বা ফাইল পরিবর্তন করার ঠিক আগে বা পরে কাস্টম স্ক্রিপ্ট অথবা এক্সটার্নাল HTTP রিকোয়েস্ট চালানোর সুযোগ দেয়। স্বয়ংক্রিয় গার্ডরেল এবং ব্যাকগ্রাউন্ড ওয়ার্কফ্লো দিয়ে এজেন্ট লুপকে প্রসারিত করতে হুকস ব্যবহার করুন, যেমন:

  • উচ্চ-ঝুঁকিপূর্ণ শেল কমান্ড বা সীমাবদ্ধ ফাইল রিড কার্যকর হওয়ার আগে নিরাপত্তা ও অ্যাক্সেস সংক্রান্ত সুরক্ষা ব্যবস্থা প্রয়োগ করা
  • এজেন্ট ফাইল তৈরি বা পরিবর্তন করার ঠিক পরেই ডেটা পাইপলাইন রূপান্তর স্বয়ংক্রিয় করা
  • টুলটি কার্যকর করার পর এন্টারপ্রাইজ অডিট টেলিমেট্রি বাহ্যিক মনিটরিং সিস্টেমে স্ট্রিম করা

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

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 থেকে টুল কলের বিবরণ পড়ে এবং এর সিদ্ধান্তের JSON ( allow বা deny ) stdout এ আউটপুট করে।

ইনপুট পেলোড ( 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 সরবরাহ করতে পারেন।

  • রিপোজিটরি মাউন্ট : একটি গিট রিপোজিটরি যেখানে .agents.md AGENTS.md পাশাপাশি .agents/hooks.json রয়েছে।
  • ক্লাউড স্টোরেজ ( gcs ) : একটি জিসিএস বাকেট যা hooks.json ধারণ করে এবং এনভায়রনমেন্টে কপি করা হয়।
  • ইনলাইন সোর্স : client.interactions.create কল করার সময় environment.sources এ পাঠানো কাঁচা JSON স্ট্রিং এবং স্ক্রিপ্টের বিষয়বস্তু।

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

HTTP হুক

HTTP হুকগুলি স্যান্ডবক্স নেটওয়ার্কের ভেতর থেকে সরাসরি একটি বাহ্যিক HTTPS URL-এ POST অনুরোধ হিসেবে ইভেন্ট JSON পাঠায়। টার্গেট সার্ভারটি HTTP প্রতিক্রিয়া বডিতে হুবহু একই JSON ফর্ম্যাট ( {"decision": "allow"} অথবা {"decision": "deny", "reason": "..."} ) ব্যবহার করে তার সিদ্ধান্ত ফেরত দেয়।

মাঠ প্রকার বর্ণনা
type string অবশ্যই "http" হতে হবে।
url string ইভেন্ট পেলোড পোস্ট করার জন্য বাহ্যিক HTTPS এন্ডপয়েন্ট।
headers object অসংবেদনশীল কাস্টম হেডারের জন্য ঐচ্ছিক কী-ভ্যালু পেয়ার (যেমন {"X-Event-Source": "agent-sandbox"} )। প্রমাণীকরণ ক্রেডেনশিয়ালের জন্য, এর পরিবর্তে নেটওয়ার্ক প্রক্সি ব্যবহার করুন।
timeout integer সেকেন্ডে সময়সীমা। ডিফল্ট: 30

বহির্গমন প্রক্সি এবং টোকেন রূপান্তর

যেহেতু HTTP হুকগুলি সরাসরি স্যান্ডবক্স নেটওয়ার্ক নেমস্পেসের ভেতর থেকে কার্যকর হয়, তাই বহির্গামী অনুরোধগুলি স্বচ্ছ ইগ্রেস প্রক্সির মধ্য দিয়ে যায়। এই স্থাপত্যটি আপনাকে ২টি গুরুত্বপূর্ণ নিরাপত্তা সুবিধা প্রদান করে:

  • নেটওয়ার্ক অ্যালাওলিস্টিং: টার্গেট এন্ডপয়েন্টগুলোকে অবশ্যই আপনার এনভায়রনমেন্টের network.allowlist এ স্পষ্টভাবে অনুমতি দিতে হবে। লুপব্যাক ট্র্যাফিক ( 127.0.0.1 বা localhost ) প্রক্সি দ্বারা ব্লক করা হয়; সর্বদা অ্যালাওলিস্টে থাকা এক্সটার্নাল এন্ডপয়েন্টগুলোকে টার্গেট করুন।
  • টোকেন রূপান্তর: আপনার .agents/hooks.json ফাইলের ভিতরে API কী বা সিক্রেট বেয়ারার টোকেন সংরক্ষণ করার বা সেগুলিকে কন্টেইনারে মাউন্ট করার প্রয়োজন নেই। পরিবর্তে, আপনার নেটওয়ার্ক কনফিগারেশনে ( network.allowlist.transform ) টোকেন রূপান্তর নিয়মগুলি কনফিগার করুন। ইগ্রেস প্রক্সি স্বয়ংক্রিয়ভাবে বহির্গামী HTTP হুক ট্র্যাফিককে বাধা দেয় এবং স্যান্ডবক্স ছাড়ার আগে ওয়্যারে আপনার আসল প্রমাণীকরণ হেডারগুলি ইনজেক্ট করে।

রানটাইম কীভাবে সিদ্ধান্ত এবং ব্যর্থতা পরিচালনা করে

  • সিঙ্ক্রোনাস ওয়েটিং: এজেন্ট আপনার হুকগুলো শেষ হওয়ার জন্য থেমে অপেক্ষা করে এবং তারপর কাজ চালিয়ে যায়।
  • টুল এক্সিকিউশন ব্লক করা: যদি আপনার প্রি-টুল হুক {"decision": "deny", "reason": "<your reason>"} রিটার্ন করে, তাহলে রানটাইম সাথে সাথে টুল কলটি বাতিল করে দেয়। মডেলটি তার কনভারসেশন হিস্ট্রিতে আপনার প্রত্যাখ্যানের কারণটি দেখে এবং একটি নিরাপদ বিকল্প বেছে নিয়ে বা ব্যবহারকারীকে ব্লক করার কারণ ব্যাখ্যা করে সেই অনুযায়ী নিজেকে মানিয়ে নেয়।
  • স্ক্রিপ্ট ক্র্যাশ, HTTP ত্রুটি এবং টাইমআউট পরিচালনা: যদি কোনো কমান্ড স্ক্রিপ্ট ক্র্যাশ করে (নন-জিরো এক্সিট স্ট্যাটাস), কোনো HTTP হুক 2xx ছাড়া অন্য কোনো স্ট্যাটাস কোড (যেমন 4xx বা 5xx সার্ভার এরর) রিটার্ন করে, অথবা কোনো অপারেশন টাইমআউট হয়ে যায় বা অচেনা JSON রিটার্ন করে, তাহলে রানটাইম এটিকে একটি অনুমোদন ( allow ) হিসেবে গণ্য করে। টুলের এক্সিকিউশন স্বাভাবিকভাবে চলতে থাকে, ফলে কোনো ত্রুটিপূর্ণ স্ক্রিপ্ট বা নাগালের বাইরে থাকা টেলিমেট্রি সার্ভার আপনার অ্যাপ্লিকেশনকে কখনো ডেডলক করে না।

সাধারণ ব্যবহারের ক্ষেত্রগুলি

ডেটা গোপনীয়তা এবং সম্মতির জন্য বহু-পর্যায়ের পুনরুদ্ধার

যখন কোনো হুক সীমাবদ্ধ রিসোর্স—যেমন ব্যক্তিগত শনাক্তকরণযোগ্য তথ্য (PII) বা গোপনীয় আর্থিক রেকর্ড ধারণকারী ডিরেক্টরি—এর অ্যাক্সেস ব্লক করে, তখন আপনি একই পরিবেশে টার্নটি চালিয়ে যাওয়ার জন্য পরবর্তী কলে previous_interaction_id পাস করতে পারেন। এজেন্ট অস্বীকৃতির ব্যাখ্যাটি পড়ে এবং এর পরিবর্তে অনুমোদিত পাবলিক টেবিলগুলো কোয়েরি করে স্বয়ংক্রিয়ভাবে পুনরুদ্ধার করে।

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

# 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 ) অথেনটিকেশন টোকেন নির্ধারণ করুন। ইগ্রেস প্রক্সি বহির্গামী অনুরোধগুলিতে স্বয়ংক্রিয়ভাবে আপনার আসল বেয়ারার টোকেন যুক্ত করে দেয়।

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

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 ) টুলের জন্য ফায়ার হয় না।
  • নেটওয়ার্ক অ্যালাওলিস্ট: HTTP হুকগুলো কন্টেইনার নেটওয়ার্কের ভেতরে চলে। আপনাকে অবশ্যই আপনার এনভায়রনমেন্টের network.allowlist এ টার্গেট URL-গুলোকে স্পষ্টভাবে অনুমতি দিতে হবে। লুপব্যাক অ্যাড্রেস ( localhost , 127.0.0.1 ) প্রক্সি দ্বারা ব্লক করা হয়।
  • ত্রুটির ক্ষেত্রে স্বয়ংক্রিয় অনুমোদন: যদি কোনো হুক স্ক্রিপ্ট ক্র্যাশ করে (নন-জিরো এক্সিট স্ট্যাটাস), টাইম আউট হয়, বা ব্যর্থ হয়, তাহলে রানটাইম সেই ব্যর্থতা লগ করে এবং টুল কলটিকে চালিয়ে যাওয়ার অনুমতি দেয়। এটি নিশ্চিত করে যে ত্রুটিপূর্ণ লিন্টার স্ক্রিপ্ট বা আটকে থাকা প্রসেস কখনোই আপনার অ্যাপ্লিকেশনগুলোকে ডেডলক করবে না।
  • স্যান্ডবক্স কনফিগারেশন সুরক্ষা: যেহেতু হুকগুলো কন্টেইনার স্যান্ডবক্সের ভিতরে চলে, তাই ফাইলসিস্টেমে লেখার টুল বা শেল কোড চালানোর অনুমতি থাকা এজেন্টরা স্থানীয় .agents/hooks.json অথবা লেখার যোগ্য ওয়ার্কস্পেসের ভেতরের স্ক্রিপ্ট পরিবর্তন করতে পারে। স্বয়ংক্রিয় পলিসি নির্দেশিকা এবং অপারেশনাল সুরক্ষা ব্যবস্থা হিসেবে কন্টেইনার হুক ব্যবহার করুন; যদি অবিশ্বস্ত মডেল চালানোর বিরুদ্ধে কঠোর টেম্পার রেজিস্ট্যান্সের প্রয়োজন হয়, তবে রিড-অনলি রিপোজিটরি থেকে কনফিগারেশন সোর্স মাউন্ট করুন।

এরপর কী?

,

হুকস আপনাকে এজেন্ট তার রিমোট স্যান্ডবক্সের ভিতরে কোড এক্সিকিউট করার বা ফাইল পরিবর্তন করার ঠিক আগে বা পরে কাস্টম স্ক্রিপ্ট অথবা এক্সটার্নাল HTTP রিকোয়েস্ট চালানোর সুযোগ দেয়। স্বয়ংক্রিয় গার্ডরেল এবং ব্যাকগ্রাউন্ড ওয়ার্কফ্লো দিয়ে এজেন্ট লুপকে প্রসারিত করতে হুকস ব্যবহার করুন, যেমন:

  • উচ্চ-ঝুঁকিপূর্ণ শেল কমান্ড বা সীমাবদ্ধ ফাইল রিড কার্যকর হওয়ার আগে নিরাপত্তা ও অ্যাক্সেস সংক্রান্ত সুরক্ষা ব্যবস্থা প্রয়োগ করা
  • এজেন্ট ফাইল তৈরি বা পরিবর্তন করার ঠিক পরেই ডেটা পাইপলাইন রূপান্তর স্বয়ংক্রিয় করা
  • টুলটি কার্যকর করার পর এন্টারপ্রাইজ অডিট টেলিমেট্রি বাহ্যিক মনিটরিং সিস্টেমে স্ট্রিম করা

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

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 থেকে টুল কলের বিবরণ পড়ে এবং এর সিদ্ধান্তের JSON ( allow বা deny ) stdout এ আউটপুট করে।

ইনপুট পেলোড ( 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 সরবরাহ করতে পারেন।

  • রিপোজিটরি মাউন্ট : একটি গিট রিপোজিটরি যেখানে .agents.md AGENTS.md পাশাপাশি .agents/hooks.json রয়েছে।
  • ক্লাউড স্টোরেজ ( gcs ) : একটি জিসিএস বাকেট যা hooks.json ধারণ করে এবং এনভায়রনমেন্টে কপি করা হয়।
  • ইনলাইন সোর্স : client.interactions.create কল করার সময় environment.sources এ পাঠানো কাঁচা JSON স্ট্রিং এবং স্ক্রিপ্টের বিষয়বস্তু।

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

HTTP হুক

HTTP হুকগুলি স্যান্ডবক্স নেটওয়ার্কের ভেতর থেকে সরাসরি একটি বাহ্যিক HTTPS URL-এ POST অনুরোধ হিসেবে ইভেন্ট JSON পাঠায়। টার্গেট সার্ভারটি HTTP প্রতিক্রিয়া বডিতে হুবহু একই JSON ফর্ম্যাট ( {"decision": "allow"} অথবা {"decision": "deny", "reason": "..."} ) ব্যবহার করে তার সিদ্ধান্ত ফেরত দেয়।

মাঠ প্রকার বর্ণনা
type string অবশ্যই "http" হতে হবে।
url string ইভেন্ট পেলোড পোস্ট করার জন্য বাহ্যিক HTTPS এন্ডপয়েন্ট।
headers object অসংবেদনশীল কাস্টম হেডারের জন্য ঐচ্ছিক কী-ভ্যালু পেয়ার (যেমন {"X-Event-Source": "agent-sandbox"} )। প্রমাণীকরণ ক্রেডেনশিয়ালের জন্য, এর পরিবর্তে নেটওয়ার্ক প্রক্সি ব্যবহার করুন।
timeout integer সেকেন্ডে সময়সীমা। ডিফল্ট: 30

বহির্গমন প্রক্সি এবং টোকেন রূপান্তর

যেহেতু HTTP হুকগুলি সরাসরি স্যান্ডবক্স নেটওয়ার্ক নেমস্পেসের ভেতর থেকে কার্যকর হয়, তাই বহির্গামী অনুরোধগুলি স্বচ্ছ ইগ্রেস প্রক্সির মধ্য দিয়ে যায়। এই স্থাপত্যটি আপনাকে ২টি গুরুত্বপূর্ণ নিরাপত্তা সুবিধা প্রদান করে:

  • নেটওয়ার্ক অ্যালাওলিস্টিং: টার্গেট এন্ডপয়েন্টগুলোকে অবশ্যই আপনার এনভায়রনমেন্টের network.allowlist এ স্পষ্টভাবে অনুমতি দিতে হবে। লুপব্যাক ট্র্যাফিক ( 127.0.0.1 বা localhost ) প্রক্সি দ্বারা ব্লক করা হয়; সর্বদা অ্যালাওলিস্টে থাকা এক্সটার্নাল এন্ডপয়েন্টগুলোকে টার্গেট করুন।
  • টোকেন রূপান্তর: আপনার .agents/hooks.json ফাইলের ভিতরে API কী বা সিক্রেট বেয়ারার টোকেন সংরক্ষণ করার বা সেগুলিকে কন্টেইনারে মাউন্ট করার প্রয়োজন নেই। পরিবর্তে, আপনার নেটওয়ার্ক কনফিগারেশনে ( network.allowlist.transform ) টোকেন রূপান্তর নিয়মগুলি কনফিগার করুন। ইগ্রেস প্রক্সি স্বয়ংক্রিয়ভাবে বহির্গামী HTTP হুক ট্র্যাফিককে বাধা দেয় এবং স্যান্ডবক্স ছাড়ার আগে ওয়্যারে আপনার আসল প্রমাণীকরণ হেডারগুলি ইনজেক্ট করে।

রানটাইম কীভাবে সিদ্ধান্ত এবং ব্যর্থতা পরিচালনা করে

  • সিঙ্ক্রোনাস ওয়েটিং: এজেন্ট আপনার হুকগুলো শেষ হওয়ার জন্য থেমে অপেক্ষা করে এবং তারপর কাজ চালিয়ে যায়।
  • টুল এক্সিকিউশন ব্লক করা: যদি আপনার প্রি-টুল হুক {"decision": "deny", "reason": "<your reason>"} রিটার্ন করে, তাহলে রানটাইম সাথে সাথে টুল কলটি বাতিল করে দেয়। মডেলটি তার কনভারসেশন হিস্ট্রিতে আপনার প্রত্যাখ্যানের কারণটি দেখে এবং একটি নিরাপদ বিকল্প বেছে নিয়ে বা ব্যবহারকারীকে ব্লক করার কারণ ব্যাখ্যা করে সেই অনুযায়ী নিজেকে মানিয়ে নেয়।
  • স্ক্রিপ্ট ক্র্যাশ, HTTP ত্রুটি এবং টাইমআউট পরিচালনা: যদি কোনো কমান্ড স্ক্রিপ্ট ক্র্যাশ করে (নন-জিরো এক্সিট স্ট্যাটাস), কোনো HTTP হুক 2xx ছাড়া অন্য কোনো স্ট্যাটাস কোড (যেমন 4xx বা 5xx সার্ভার এরর) রিটার্ন করে, অথবা কোনো অপারেশন টাইমআউট হয়ে যায় বা অচেনা JSON রিটার্ন করে, তাহলে রানটাইম এটিকে একটি অনুমোদন ( allow ) হিসেবে গণ্য করে। টুলের এক্সিকিউশন স্বাভাবিকভাবে চলতে থাকে, ফলে কোনো ত্রুটিপূর্ণ স্ক্রিপ্ট বা নাগালের বাইরে থাকা টেলিমেট্রি সার্ভার আপনার অ্যাপ্লিকেশনকে কখনো ডেডলক করে না।

সাধারণ ব্যবহারের ক্ষেত্রগুলি

ডেটা গোপনীয়তা এবং সম্মতির জন্য বহু-পর্যায়ের পুনরুদ্ধার

যখন কোনো হুক সীমাবদ্ধ রিসোর্স—যেমন ব্যক্তিগত শনাক্তকরণযোগ্য তথ্য (PII) বা গোপনীয় আর্থিক রেকর্ড ধারণকারী ডিরেক্টরি—এর অ্যাক্সেস ব্লক করে, তখন আপনি একই পরিবেশে টার্নটি চালিয়ে যাওয়ার জন্য পরবর্তী কলে previous_interaction_id পাস করতে পারেন। এজেন্ট অস্বীকৃতির ব্যাখ্যাটি পড়ে এবং এর পরিবর্তে অনুমোদিত পাবলিক টেবিলগুলো কোয়েরি করে স্বয়ংক্রিয়ভাবে পুনরুদ্ধার করে।

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

# 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 ) অথেনটিকেশন টোকেন নির্ধারণ করুন। ইগ্রেস প্রক্সি বহির্গামী অনুরোধগুলিতে স্বয়ংক্রিয়ভাবে আপনার আসল বেয়ারার টোকেন যুক্ত করে দেয়।

পাইথন

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)

জাভাস্ক্রিপ্ট

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);

বিশ্রাম

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 ) টুলের জন্য ফায়ার হয় না।
  • নেটওয়ার্ক অ্যালাওলিস্ট: HTTP হুকগুলো কন্টেইনার নেটওয়ার্কের ভেতরে চলে। আপনাকে অবশ্যই আপনার এনভায়রনমেন্টের network.allowlist এ টার্গেট URL-গুলোকে স্পষ্টভাবে অনুমতি দিতে হবে। লুপব্যাক অ্যাড্রেস ( localhost , 127.0.0.1 ) প্রক্সি দ্বারা ব্লক করা হয়।
  • ত্রুটির ক্ষেত্রে স্বয়ংক্রিয় অনুমোদন: যদি কোনো হুক স্ক্রিপ্ট ক্র্যাশ করে (নন-জিরো এক্সিট স্ট্যাটাস), টাইম আউট হয়, বা ব্যর্থ হয়, তাহলে রানটাইম সেই ব্যর্থতা লগ করে এবং টুল কলটিকে চালিয়ে যাওয়ার অনুমতি দেয়। এটি নিশ্চিত করে যে ত্রুটিপূর্ণ লিন্টার স্ক্রিপ্ট বা আটকে থাকা প্রসেস কখনোই আপনার অ্যাপ্লিকেশনগুলোকে ডেডলক করবে না।
  • স্যান্ডবক্স কনফিগারেশন সুরক্ষা: যেহেতু হুকগুলো কন্টেইনার স্যান্ডবক্সের ভিতরে চলে, তাই ফাইলসিস্টেমে লেখার টুল বা শেল কোড চালানোর অনুমতি থাকা এজেন্টরা স্থানীয় .agents/hooks.json অথবা লেখার যোগ্য ওয়ার্কস্পেসের ভেতরের স্ক্রিপ্ট পরিবর্তন করতে পারে। স্বয়ংক্রিয় পলিসি নির্দেশিকা এবং অপারেশনাল সুরক্ষা ব্যবস্থা হিসেবে কন্টেইনার হুক ব্যবহার করুন; যদি অবিশ্বস্ত মডেল চালানোর বিরুদ্ধে কঠোর টেম্পার রেজিস্ট্যান্সের প্রয়োজন হয়, তবে রিড-অনলি রিপোজিটরি থেকে কনফিগারেশন সোর্স মাউন্ট করুন।

এরপর কী?