Skip to content

Update version and fix samples for 0.8.5 release #731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 16, 2025
Merged
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ With Gemini 2.0, we took the chance to create a single unified SDK for all devel

The full migration guide from the old SDK to new SDK is available in the [Gemini API docs](https://ai.google.dev/gemini-api/docs/migrate).

We won't be adding anything to this SDK or making any further changes. The Gemini API docs are fully updated to show examples of the new Google Gen AI SDK. We know how disruptive an SDK change can be and don't take this change lightly, but our goal is to create an extremely simple and clear path for developers to build with our models so it felt necessary to make this change.
The Gemini API docs are fully updated to show examples of the new Google Gen AI SDK. We know how disruptive an SDK change can be and don't take this change lightly, but our goal is to create an extremely simple and clear path for developers to build with our models so it felt necessary to make this change.

Thank you for building with Gemini and [let us know](https://discuss.ai.google.dev/c/gemini-api/4) if you need any help!

**Please be advised that this repository is now considered legacy.** For the latest features, performance improvements, and active development, we strongly recommend migrating to the official **[Google Generative AI SDK for Python](https://github.com/googleapis/python-genai)**.

**Support Plan for this Repository:**

* **Limited Maintenance:** Development is now restricted to **critical bug fixes only**. No new features will be added.
* **Purpose:** This limited support aims to provide stability for users while they transition to the new SDK.
* **End-of-Life Date:** All support for this repository (including bug fixes) will permanently end on **August 31st, 2025**.

We encourage all users to begin planning their migration to the [Google Generative AI SDK](https://github.com/googleapis/python-genai) to ensure continued access to the latest capabilities and support.

<!--
[START update]
# With Gemini 2 we're launching a new SDK. See the following doc for details.
Expand Down
4 changes: 2 additions & 2 deletions google/generativeai/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,12 @@ def configure(
"Invalid configuration: Please set either `api_key` or `client_options['api_key']`, but not both."
)
else:
if api_key is None:
if not api_key:
# If no key is provided explicitly, attempt to load one from the
# environment.
api_key = os.getenv("GEMINI_API_KEY")

if api_key is None:
if not api_key:
# If the GEMINI_API_KEY doesn't exist, attempt to load the
# GOOGLE_API_KEY from the environment.
api_key = os.getenv("GOOGLE_API_KEY")
Expand Down
195 changes: 154 additions & 41 deletions google/generativeai/responder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import pydantic

from google.generativeai import protos
from google.generativeai.types import content_types

Type = protos.Type

Expand Down Expand Up @@ -89,52 +90,36 @@ def _generate_schema(
"""
if descriptions is None:
descriptions = {}
if required is None:
required = []
defaults = dict(inspect.signature(f).parameters)
fields_dict = {
name: (
# 1. We infer the argument type here: use Any rather than None so
# it will not try to auto-infer the type based on the default value.
(param.annotation if param.annotation != inspect.Parameter.empty else Any),
pydantic.Field(
# 2. We do not support default values for now.
# default=(
# param.default if param.default != inspect.Parameter.empty
# else None
# ),
# 3. We support user-provided descriptions.
description=descriptions.get(name, None),
),
)
for name, param in defaults.items()
# We do not support *args or **kwargs
if param.kind
in (

fields_dict = {}
for name, param in defaults.items():
if param.kind in (
inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY,
inspect.Parameter.POSITIONAL_ONLY,
)
}
parameters = pydantic.create_model(f.__name__, **fields_dict).model_json_schema()
# Postprocessing
# 4. Suppress unnecessary title generation:
# * https://github.com/pydantic/pydantic/issues/1051
# * http://cl/586221780
parameters.pop("title", None)
for name, function_arg in parameters.get("properties", {}).items():
function_arg.pop("title", None)
annotation = defaults[name].annotation
# 5. Nullable fields:
# * https://github.com/pydantic/pydantic/issues/1270
# * https://stackoverflow.com/a/58841311
# * https://github.com/pydantic/pydantic/discussions/4872
if typing.get_origin(annotation) is typing.Union and type(None) in typing.get_args(
annotation
):
function_arg["nullable"] = True
# We do not support default values for now.
# default=(
# param.default if param.default != inspect.Parameter.empty
# else None
# ),
field = pydantic.Field(
# We support user-provided descriptions.
description=descriptions.get(name, None)
)

# 1. We infer the argument type here: use Any rather than None so
# it will not try to auto-infer the type based on the default value.
if param.annotation != inspect.Parameter.empty:
fields_dict[name] = param.annotation, field
else:
fields_dict[name] = Any, field

parameters = _build_schema(f.__name__, fields_dict)

# 6. Annotate required fields.
if required:
if required is not None:
# We use the user-provided "required" fields if specified.
parameters["required"] = required
else:
Expand All @@ -152,10 +137,138 @@ def _generate_schema(
)
)
]
schema = dict(name=f.__name__, description=f.__doc__, parameters=parameters)
schema = dict(name=f.__name__, description=f.__doc__)
if parameters["properties"]:
schema["parameters"] = parameters

return schema


def _build_schema(fname, fields_dict):
parameters = pydantic.create_model(fname, **fields_dict).model_json_schema()
defs = parameters.pop("$defs", {})
# flatten the defs
for name, value in defs.items():
unpack_defs(value, defs)
unpack_defs(parameters, defs)

# 5. Nullable fields:
# * https://github.com/pydantic/pydantic/issues/1270
# * https://stackoverflow.com/a/58841311
# * https://github.com/pydantic/pydantic/discussions/4872
convert_to_nullable(parameters)
add_object_type(parameters)
# Postprocessing
# 4. Suppress unnecessary title generation:
# * https://github.com/pydantic/pydantic/issues/1051
# * http://cl/586221780
strip_titles(parameters)
strip_additional_properties(parameters)
return parameters


def unpack_defs(schema, defs):
properties = schema.get("properties", None)
if properties is None:
return

for name, value in properties.items():
ref_key = value.get("$ref", None)
if ref_key is not None:
ref = defs[ref_key.split("defs/")[-1]]
unpack_defs(ref, defs)
properties[name] = ref
continue

anyof = value.get("anyOf", None)
if anyof is not None:
for i, atype in enumerate(anyof):
ref_key = atype.get("$ref", None)
if ref_key is not None:
ref = defs[ref_key.split("defs/")[-1]]
unpack_defs(ref, defs)
anyof[i] = ref
continue

items = value.get("items", None)
if items is not None:
ref_key = items.get("$ref", None)
if ref_key is not None:
ref = defs[ref_key.split("defs/")[-1]]
unpack_defs(ref, defs)
value["items"] = ref
continue


def strip_titles(schema):
title = schema.pop("title", None)

properties = schema.get("properties", None)
if properties is not None:
for name, value in properties.items():
strip_titles(value)

items = schema.get("items", None)
if items is not None:
strip_titles(items)


def strip_additional_properties(schema):
schema.pop("additionalProperties", None)

properties = schema.get("properties", None)
if properties is not None:
for name, value in properties.items():
strip_additional_properties(value)

items = schema.get("items", None)
if items is not None:
strip_additional_properties(items)


def add_object_type(schema):
properties = schema.get("properties", None)
if properties is not None:
schema.pop("required", None)
schema["type"] = "object"
for name, value in properties.items():
add_object_type(value)

items = schema.get("items", None)
if items is not None:
add_object_type(items)


def convert_to_nullable(schema):
anyof = schema.pop("anyOf", None)
if anyof is not None:
if len(anyof) != 2:
raise ValueError(
"Invalid input: Type Unions are not supported, except for `Optional` types. "
"Please provide an `Optional` type or a non-Union type."
)
a, b = anyof
if a == {"type": "null"}:
schema.update(b)
elif b == {"type": "null"}:
schema.update(a)
else:
raise ValueError(
"Invalid input: Type Unions are not supported, except for `Optional` types. "
"Please provide an `Optional` type or a non-Union type."
)
schema["nullable"] = True

properties = schema.get("properties", None)
if properties is not None:
for name, value in properties.items():
convert_to_nullable(value)

items = schema.get("items", None)
if items is not None:
convert_to_nullable(items)


def _rename_schema_fields(schema: dict[str, Any]):
if schema is None:
return schema
Expand Down
14 changes: 14 additions & 0 deletions google/generativeai/types/content_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ def _build_schema(fname, fields_dict):
# * https://github.com/pydantic/pydantic/issues/1051
# * http://cl/586221780
strip_titles(parameters)
strip_additional_properties(parameters)
return parameters


Expand Down Expand Up @@ -484,6 +485,19 @@ def strip_titles(schema):
strip_titles(items)


def strip_additional_properties(schema):
schema.pop("additionalProperties", None)

properties = schema.get("properties", None)
if properties is not None:
for name, value in properties.items():
strip_additional_properties(value)

items = schema.get("items", None)
if items is not None:
strip_additional_properties(items)


def add_object_type(schema):
properties = schema.get("properties", None)
if properties is not None:
Expand Down
2 changes: 1 addition & 1 deletion google/generativeai/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
# limitations under the License.
from __future__ import annotations

__version__ = "0.8.4"
__version__ = "0.8.5"
Loading
Loading