97e91a83f3
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
from instructor.v2.providers.gemini.utils import update_genai_kwargs
|
|
|
|
|
|
def test_update_genai_kwargs_safety_settings_excludes_image_categories():
|
|
"""IMAGE_* harm categories must never be sent to the standard Gemini API.
|
|
|
|
They are only supported by Vertex AI and cause 400 INVALID_ARGUMENT errors
|
|
on the standard Gemini API.
|
|
See: https://github.com/567-labs/instructor/issues/2146
|
|
"""
|
|
from google.genai import types
|
|
|
|
kwargs = {
|
|
"contents": [
|
|
types.Content(
|
|
role="user",
|
|
parts=[types.Part.from_bytes(data=b"123", mime_type="image/png")],
|
|
)
|
|
]
|
|
}
|
|
base_config = {}
|
|
|
|
result = update_genai_kwargs(kwargs, base_config)
|
|
|
|
assert "safety_settings" in result
|
|
assert isinstance(result["safety_settings"], list)
|
|
# No IMAGE_* categories should be present
|
|
for setting in result["safety_settings"]:
|
|
assert not setting["category"].name.startswith("HARM_CATEGORY_IMAGE_"), (
|
|
f"IMAGE_ category {setting['category'].name} must not be sent to the "
|
|
"standard Gemini API"
|
|
)
|
|
|
|
|
|
def test_update_genai_kwargs_text_only_categories_for_image_content():
|
|
"""Even with image content, only text harm categories should be used."""
|
|
from google.genai import types
|
|
from google.genai.types import HarmBlockThreshold, HarmCategory
|
|
|
|
custom_safety = {
|
|
HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
|
|
}
|
|
|
|
kwargs = {
|
|
"contents": [
|
|
types.Content(
|
|
role="user",
|
|
parts=[types.Part.from_bytes(data=b"123", mime_type="image/png")],
|
|
)
|
|
],
|
|
"safety_settings": custom_safety,
|
|
}
|
|
base_config = {}
|
|
|
|
result = update_genai_kwargs(kwargs, base_config)
|
|
|
|
# Custom threshold should be preserved for text category
|
|
found_hate_speech = False
|
|
for setting in result["safety_settings"]:
|
|
assert not setting["category"].name.startswith("HARM_CATEGORY_IMAGE_")
|
|
if setting["category"] == HarmCategory.HARM_CATEGORY_HATE_SPEECH:
|
|
assert setting["threshold"] == HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
|
|
found_hate_speech = True
|
|
assert found_hate_speech, "HARM_CATEGORY_HATE_SPEECH should be in safety_settings"
|
|
|
|
|
|
def test_handle_genai_tools_autodetect_images_excludes_image_categories():
|
|
"""Autodetected image content should NOT use IMAGE_* harm categories."""
|
|
from pydantic import BaseModel
|
|
|
|
from instructor.v2.providers.gemini.utils import handle_genai_tools
|
|
|
|
class SimpleModel(BaseModel):
|
|
text: str
|
|
|
|
data_uri = (
|
|
"data:image/png;base64,"
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO6q0S8AAAAASUVORK5CYII="
|
|
)
|
|
|
|
kwargs = {
|
|
"messages": [
|
|
{
|
|
"role": "user",
|
|
"content": ["What is in this image?", data_uri],
|
|
}
|
|
]
|
|
}
|
|
|
|
_, out = handle_genai_tools(SimpleModel, kwargs, autodetect_images=True)
|
|
|
|
assert "config" in out
|
|
assert out["config"].safety_settings is not None
|
|
# No IMAGE_* categories should be present
|
|
assert not any(
|
|
s.category.name.startswith("HARM_CATEGORY_IMAGE_")
|
|
for s in out["config"].safety_settings
|
|
), "IMAGE_ categories must not be sent to the standard Gemini API"
|