Móc

Các hook cho phép bạn chạy tập lệnh tuỳ chỉnh hoặc yêu cầu HTTP bên ngoài ngay trước hoặc sau khi tác nhân thực thi mã hoặc sửa đổi tệp trong hộp cát từ xa. Sử dụng các hook để mở rộng vòng lặp của tác nhân bằng các quy tắc tự động và quy trình làm việc ở chế độ nền, chẳng hạn như:

  • Thực thi các biện pháp bảo vệ an toàn và quyền truy cập trước khi thực thi các lệnh shell có mức độ rủi ro cao hoặc các thao tác đọc tệp bị hạn chế.
  • Tự động hoá các hoạt động chuyển đổi quy trình dữ liệu ngay sau khi một tác nhân tạo hoặc sửa đổi tệp.
  • Truyền trực tuyến dữ liệu đo từ xa kiểm tra doanh nghiệp đến các hệ thống giám sát bên ngoài sau khi thực thi công cụ.

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

Các sự kiện trong vòng đời được hỗ trợ

Các hook hỗ trợ 2 sự kiện trong hộp cát:

Sự kiện Thời điểm kích hoạt Ý nghĩa
pre_tool_execution Ngay trước khi một công cụ chạy Có thể phê duyệt (allow) hoặc chặn (deny) công cụ này trước khi công cụ thực thi. Khi bị chặn, mô hình sẽ thấy lý do bạn từ chối và điều chỉnh.
post_tool_execution Ngay sau khi một công cụ hoàn tất Chạy các tác vụ tiếp theo như định dạng mã, chạy kiểm thử đơn vị hoặc ghi nhật ký đo từ xa. Không thể chặn hoặc huỷ các thao tác đã hoàn tất.

pre_tool_execution

Kích hoạt ngay trước khi một công cụ thực thi. Tập lệnh của bạn đọc thông tin chi tiết về lệnh gọi công cụ từ stdin và xuất JSON quyết định (allow hoặc deny) sang stdout.

Phần tải đầu vào (stdin):

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

Phản hồi đầu ra (stdout):

Cách phê duyệt lệnh gọi công cụ:

{
  "decision": "allow"
}

Để chặn lệnh gọi công cụ và trả về ý kiến phản hồi cho mô hình:

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

Khi một lệnh từ chối lệnh, lệnh gọi công cụ sẽ bị bỏ qua ngay lập tức. Ngay trong lượt hiện tại, tác nhân sẽ thấy một kết quả lỗi có chứa lý do từ chối của bạn. Sau đó, mô hình có thể tự điều chỉnh bằng cách chọn một lệnh thay thế hoặc giải thích cho người dùng về khối này.

Nếu tập lệnh của bạn xuất ra JSON không xác định, văn bản thuần tuý hoặc bất kỳ nội dung nào khác ngoài {"decision": "deny"}, thì thời gian chạy sẽ coi phản hồi đó là một phản hồi phê duyệt (allow).

post_tool_execution

Kích hoạt ngay sau khi một công cụ hoàn tất. Tập lệnh của bạn sẽ đọc thông tin chi tiết về quá trình thực thi và mọi trạng thái lỗi từ stdin.

Phần tải đầu vào (stdin):

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

Nếu một lệnh shell in lỗi ra lỗi chuẩn (stderr) hoặc một thao tác trên hệ thống tệp không thành công, thì một trường "error" chứa văn bản lỗi sẽ được đưa vào tải trọng. Khi lệnh thành công mà không có lỗi, trường "error" sẽ bị bỏ qua hoàn toàn.

Phản hồi đầu ra (stdout):

{}

Vì các lệnh gọi sau công cụ chỉ chạy cho các tác vụ trong nền như định dạng mã hoặc ghi nhật ký, nên thời gian chạy sẽ bỏ qua mọi giá trị quyết định được trả về trên stdout.

Khám phá cấu hình

Thời gian chạy sẽ tự động phát hiện các định nghĩa về lệnh gọi từ .agents/hooks.json hoặc /.agents/hooks.json trong môi trường hộp cát. Bạn có thể cung cấp hooks.json cùng với các tập lệnh tuỳ chỉnh bằng cách sử dụng bất kỳ nguồn môi trường nào được hỗ trợ:

  • Thư mục gốc của kho lưu trữ: Kho lưu trữ Git chứa .agents/hooks.json cùng với AGENTS.md.
  • Cloud Storage (gcs): Bộ chứa GCS chứa hooks.json được sao chép vào môi trường.
  • Nguồn nội tuyến: Chuỗi JSON thô và nội dung tập lệnh được truyền trong environment.sources khi gọi client.interactions.create.

hooks.json lược đồ

Tệp hooks.json nhóm các định nghĩa về sự kiện (pre_tool_execution hoặc post_tool_execution) theo tên tuỳ chỉnh. Bạn có thể bật hoặc tắt từng nhóm một cách độc lập:

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

Cú pháp và quy tắc của bộ so khớp

Mỗi nhóm quy tắc trong hooks.json xác định thời điểm và cách các trình xử lý kích hoạt bằng cách sử dụng các thuộc tính matcherhooks:

Trường Loại Mô tả
enabled boolean Không bắt buộc. Đặt thành false để tắt nhóm (true theo mặc định).
matcher string Mẫu biểu thức chính quy so khớp tên công cụ mục tiêu bên trong vùng chứa.
hooks array Danh sách có thứ tự gồm các định nghĩa về trình xử lý (command hoặc http). Các trình xử lý chạy tuần tự theo thứ tự khai báo.

Cách hoạt động của quy trình đánh giá biểu thức chính quy

Khi tác nhân gọi một công cụ bên trong hộp cát, thời gian chạy sẽ đánh giá tên vùng chứa của công cụ dựa trên mẫu matcher bằng cách sử dụng các biểu thức chính quy RE2 tiêu chuẩn. Nếu biểu thức chính quy khớp với tên công cụ, tất cả trình xử lý trong mảng hooks sẽ thực thi theo thứ tự. Nếu nhiều nhóm quy tắc khớp với cùng một công cụ, thì tất cả các mảng trình xử lý tương ứng sẽ chạy.

Bạn có thể nhắm đến bất kỳ tên công cụ vùng chứa tích hợp nào: thực thi mã (code_execution) hoặc các thao tác trên hệ thống tệp (read_file, write_file, list_filesdelete_file).

Các biểu thức trình khớp thường dùng

  • "code_execution": So khớp chuỗi chính xác cho các lệnh shell và quá trình thực thi tập lệnh.
  • "write_file": So khớp chính xác cho hoạt động tạo tệp hệ thống tệp và ghi vào đĩa.
  • "read_file|write_file": Phân tách bằng dấu sổ dọc để so khớp nhiều tên công cụ cụ thể trong một quy tắc duy nhất.
  • ".*_file": Biểu thức chính quy có ký tự đại diện khớp với mọi công cụ có đuôi là _file (chẳng hạn như read_file, write_file hoặc delete_file). Biểu thức chính quy RE2 tiêu chuẩn yêu cầu .*; các ký tự đại diện đơn giản của shell như *_file là cú pháp biểu thức chính quy không hợp lệ và sẽ không khớp.
  • ".*" hoặc "*" hoặc "": Mẫu chung chặn mọi lệnh gọi công cụ trong vùng chứa.

Các loại trình xử lý

Lệnh hook

Lệnh hook thực thi một lệnh hoặc tập lệnh shell bên trong hộp cát. Tập lệnh nhận JSON sự kiện trên stdin và xuất JSON quyết định trên stdout.

Trường Loại Mô tả
type string Phải là "command".
command string Dòng lệnh để chạy trong hộp cát (ví dụ: python3 /.agents/hooks-scripts/gate.py).
timeout integer Thời gian chờ tính bằng giây. Mặc định: 30.

Các lệnh gọi HTTP

Các lệnh gọi HTTP sẽ gửi JSON sự kiện dưới dạng yêu cầu POST đến một URL HTTPS bên ngoài ngay từ bên trong mạng hộp cát. Máy chủ mục tiêu trả về quyết định của mình trong nội dung phản hồi HTTP bằng chính xác định dạng JSON ({"decision": "allow"} hoặc {"decision": "deny", "reason": "..."}).

Trường Loại Mô tả
type string Phải là "http".
url string Điểm cuối HTTPS bên ngoài để gửi tải trọng sự kiện đến.
headers object Cặp khoá-giá trị không bắt buộc cho các tiêu đề tuỳ chỉnh không nhạy cảm (chẳng hạn như {"X-Event-Source": "agent-sandbox"}). Đối với thông tin xác thực, hãy sử dụng proxy mạng.
timeout integer Thời gian chờ tính bằng giây. Mặc định: 30.

Uỷ quyền chuyển dữ liệu ra ngoài và chuyển đổi mã thông báo

Vì các lệnh gọi HTTP thực thi trực tiếp từ bên trong không gian tên mạng hộp cát, nên các yêu cầu đi ra sẽ đi qua proxy truyền tải minh bạch. Cấu trúc này mang lại cho bạn 2 lợi thế quan trọng về bảo mật:

  • Thêm mạng vào danh sách cho phép: Bạn phải cho phép rõ ràng các điểm cuối mục tiêu trong network.allowlist của môi trường. Lưu lượng truy cập vòng lặp (127.0.0.1 hoặc localhost) sẽ bị chặn bởi proxy; luôn nhắm đến các điểm cuối bên ngoài nằm trong danh sách cho phép.
  • Chuyển đổi mã thông báo: Bạn không cần lưu trữ khoá API hoặc mã thông báo bí mật của người mang trong .agents/hooks.json hoặc gắn chúng vào vùng chứa. Thay vào đó, hãy định cấu hình các quy tắc chuyển đổi mã thông báo trong cấu hình mạng (network.allowlist.transform). Proxy truyền dữ liệu ra sẽ tự động chặn lưu lượng truy cập hook HTTP đi ra và chèn tiêu đề xác thực thực của bạn vào đường truyền trước khi rời khỏi hộp cát.

Cách thời gian chạy xử lý các quyết định và lỗi

  • Chờ đồng bộ: Tác nhân tạm dừng và đợi các lệnh gọi của bạn hoàn tất rồi mới tiếp tục.
  • Chặn quá trình thực thi công cụ: Nếu lệnh gọi trước công cụ trả về {"decision": "deny", "reason": "<your reason>"}, thì thời gian chạy sẽ huỷ ngay lệnh gọi công cụ. Mô hình sẽ thấy lý do bạn từ chối trong nhật ký trò chuyện và điều chỉnh bằng cách chọn một lựa chọn thay thế an toàn hoặc giải thích cho người dùng về việc chặn.
  • Xử lý sự cố tập lệnh, lỗi HTTP và hết thời gian chờ: Nếu tập lệnh lệnh gặp sự cố (trạng thái thoát khác 0), một lệnh gọi HTTP trả về mã trạng thái không phải 2xx (chẳng hạn như lỗi máy chủ 4xx hoặc 5xx) hoặc một thao tác hết thời gian chờ hoặc trả về JSON không xác định, thì thời gian chạy sẽ coi đó là một lượt phê duyệt (allow). Quá trình thực thi công cụ vẫn diễn ra bình thường, vì vậy, một tập lệnh bị hỏng hoặc máy chủ đo từ xa không thể truy cập sẽ không bao giờ khiến ứng dụng của bạn bị bế tắc.

Các trường hợp sử dụng phổ biến

Khả năng khôi phục nhiều lượt cho quyền riêng tư đối với dữ liệu và việc tuân thủ

Khi một lệnh gọi chặn quyền truy cập vào các tài nguyên bị hạn chế (chẳng hạn như các thư mục chứa Thông tin nhận dạng cá nhân (PII) hoặc hồ sơ tài chính bí mật), bạn có thể truyền previous_interaction_id trong lệnh gọi tiếp theo để tiếp tục lượt trong cùng một môi trường. Tác nhân sẽ đọc nội dung giải thích về việc từ chối và tự động khôi phục bằng cách truy vấn các bảng công khai đã được phê duyệt.

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

Ghi nhật ký kiểm tra và đo từ xa bên ngoài

Gửi các sự kiện kiểm tra theo thời gian thực từ bên trong hộp cát đến một máy chủ giám sát bên ngoài bất cứ khi nào tệp được đọc hoặc sửa đổi.

  • So khớp nhiều công cụ: Vì các công cụ so khớp sử dụng biểu thức chính quy tiêu chuẩn, nên bạn có thể kết hợp nhiều công cụ trong một quy tắc bằng cách sử dụng dấu gạch dọc (read_file|write_file) hoặc ký tự đại diện (.*_file).
  • Không đưa các khoá bí mật vào cấu hình: Xác định mã thông báo xác thực trong cấu hình mạng (network.allowlist.transform) của môi trường. Proxy truyền dữ liệu đi sẽ tự động chèn mã thông báo thực tế của bạn vào các yêu cầu gửi đi.

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

Các điểm hạn chế

  • Phạm vi của công cụ hộp cát: Các lệnh gọi chặn các công cụ tích hợp sẵn bên trong hộp cát: thực thi mã (code_execution) và các thao tác trên hệ thống tệp (read_file, write_file, list_filesdelete_file). Các lệnh gọi này không kích hoạt cho lệnh gọi hàm tuỳ chỉnh (function) hoặc các công cụ Giao thức ngữ cảnh mô hình (mcp_server) bên ngoài được xử lý bên ngoài vùng chứa.
  • Danh sách cho phép mạng: Các lệnh gọi HTTP chạy trong mạng vùng chứa. Bạn phải cho phép rõ ràng các URL mục tiêu trong network.allowlist của môi trường. Địa chỉ Loopback (localhost, 127.0.0.1) bị chặn bởi proxy.
  • Tự động phê duyệt khi có lỗi: Nếu tập lệnh hook gặp sự cố (trạng thái thoát khác 0), hết thời gian chờ hoặc không thành công, thì thời gian chạy sẽ ghi nhật ký lỗi và cho phép lệnh gọi công cụ tiếp tục. Điều này đảm bảo các tập lệnh linter bị hỏng hoặc các quy trình treo không bao giờ làm ứng dụng của bạn bị tắc nghẽn.
  • Bảo vệ cấu hình hộp cát: Vì các lệnh gọi thực thi bên trong hộp cát vùng chứa, nên các tác nhân có công cụ ghi hệ thống tệp hoặc quyền thực thi mã shell có thể sửa đổi .agents/hooks.json cục bộ hoặc tập lệnh trong không gian làm việc có thể ghi. Sử dụng các lệnh gọi vùng chứa làm hướng dẫn tự động về chính sách và biện pháp bảo vệ hoạt động; nếu cần có khả năng chống giả mạo nghiêm ngặt đối với các hoạt động thực thi mô hình không đáng tin cậy, hãy gắn các nguồn cấu hình từ kho lưu trữ chỉ đọc.

Bước tiếp theo