-
Notifications
You must be signed in to change notification settings - Fork 698
Open
Labels
priority: p2Moderately-important priority. Fix may not be included in next release.Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Description
When passing in the excluded_predefined_functions field, the excluded tools are not respected for ComputerUse models (gemini-2.5-computer-use-preview-10-2025 and gemini-3-flash-preview.
Environment details
- Programming language: Python
- OS: macOS
- Language runtime version: 3.13 Python
- Package version: 1.56.0
Steps to reproduce
Run this script:
"""Minimal test to verify if Gemini exclusions work."""
import os
import base64
from pathlib import Path
# Load env
from dotenv import load_dotenv
load_dotenv(Path(__file__).parent / ".env")
# load_dotenv(Path(__file__).parent / ".env.local")
from google import genai
from google.genai import types
# Initialize client
api_key = os.getenv("GOOGLE_API_KEY")
client = genai.Client(api_key=api_key)
# All browser-specific functions we want to exclude
excluded_functions = [
"open_web_browser",
"search",
"navigate",
"go_forward",
"go_back",
"scroll_document", # Keep only coordinate-based scroll_at
]
print("=" * 60)
print("Testing Gemini Computer Use Exclusions")
print("=" * 60)
print(f"\nExcluded functions: {excluded_functions}")
# Config with exclusions
config = types.GenerateContentConfig(
tools=[
types.Tool(
computer_use=types.ComputerUse(
environment=types.Environment.ENVIRONMENT_BROWSER,
excluded_predefined_functions=excluded_functions,
)
)
],
)
# Test 1: Without screenshot - expect navigate/open_web_browser (maybe acceptable)
print("\n--- Test 1: Without screenshot ---")
contents = [
types.Content(
role="user",
parts=[types.Part(text="Go to github.com/trycua/cua")]
)
]
response = client.models.generate_content(
model="gemini-2.5-computer-use-preview-10-2025",
contents=contents,
config=config,
)
for part in response.candidates[0].content.parts:
if hasattr(part, 'function_call') and part.function_call:
print(f" Function called: {part.function_call.name}")
print(f" Args: {dict(part.function_call.args)}")
if part.function_call.name in excluded_functions:
print(f" ❌ EXCLUSION NOT RESPECTED!")
else:
print(f" ✅ Function allowed")
# Test 2: With a dummy screenshot - should NOT use navigate
print("\n--- Test 2: With screenshot (simulating browser already open) ---")
# Create a simple test image (1x1 red pixel PNG)
# In real test, you'd use an actual screenshot
import struct
import zlib
def create_minimal_png():
"""Create a minimal valid PNG image."""
# PNG signature
signature = b'\x89PNG\r\n\x1a\n'
# IHDR chunk (image header)
width = 100
height = 100
bit_depth = 8
color_type = 2 # RGB
ihdr_data = struct.pack('>IIBBBBB', width, height, bit_depth, color_type, 0, 0, 0)
ihdr_crc = zlib.crc32(b'IHDR' + ihdr_data) & 0xffffffff
ihdr_chunk = struct.pack('>I', 13) + b'IHDR' + ihdr_data + struct.pack('>I', ihdr_crc)
# IDAT chunk (image data) - simple gray image
raw_data = b''
for y in range(height):
raw_data += b'\x00' # filter byte
for x in range(width):
raw_data += b'\x80\x80\x80' # gray RGB
compressed = zlib.compress(raw_data)
idat_crc = zlib.crc32(b'IDAT' + compressed) & 0xffffffff
idat_chunk = struct.pack('>I', len(compressed)) + b'IDAT' + compressed + struct.pack('>I', idat_crc)
# IEND chunk
iend_crc = zlib.crc32(b'IEND') & 0xffffffff
iend_chunk = struct.pack('>I', 0) + b'IEND' + struct.pack('>I', iend_crc)
return signature + ihdr_chunk + idat_chunk + iend_chunk
test_image = create_minimal_png()
print(f" Test image size: {len(test_image)} bytes")
contents_with_image = [
types.Content(
role="user",
parts=[
types.Part(text="Go to github.com/trycua/cua. Click on the Issues tab."),
types.Part.from_bytes(data=test_image, mime_type="image/png"),
]
)
]
response2 = client.models.generate_content(
model="gemini-2.5-computer-use-preview-10-2025",
contents=contents_with_image,
config=config,
)
for part in response2.candidates[0].content.parts:
if hasattr(part, 'function_call') and part.function_call:
print(f" Function called: {part.function_call.name}")
print(f" Args: {dict(part.function_call.args)}")
if part.function_call.name in excluded_functions:
print(f" ❌ EXCLUSION NOT RESPECTED!")
else:
print(f" ✅ Function allowed")
print("\n" + "=" * 60)
print("Test complete")
print("=" * 60)
and you should see that the model is invoking excluded tools
Thanks!
Metadata
Metadata
Assignees
Labels
priority: p2Moderately-important priority. Fix may not be included in next release.Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.