Skip to content

Commit f5ac4ed

Browse files
authored
Update version and fix samples for 0.8.5 release (#731)
* Update version and fix samples for 0.8.5 release Change-Id: Ie0b0f883cbe5c8e5427c1d59c1b96bea0dd62fde * Fix samples for 0.8.5 release Change-Id: I48f3389565d68bc10f1608980298e6f1e384fc37 * format Change-Id: Ibfe397dc19d055867bb8c0e87f9ba107867e4289 * Fix shawoding caused by an empty GEMINI_API_KEY Change-Id: I1df220253baf1b2171891ba380a0a3dde8e09a8b * fix failing tests Change-Id: I0fdfc084e8c5e88bab8257eef22065ec5a6189ea * fix tests broken by pydantic 2.11 Change-Id: Ie697e2f43b2608cadebfd14d806f3898b064cc3b * format Change-Id: I51110cf338bd61d8cf40b3e73ece12b34c951d0c * sync readme with google-gemini/deprecated-generative-ai-js#462 Change-Id: I6bc43a471b5558f373f6c514a9dc56a49dd9e677 * JS -> Python Change-Id: Ib7aee25dfa0d94fc3c4abd55c28a36211126e883 * patch responder instead of deleting. Change-Id: I8f010a0ff5e45009ce9114d6bfc025e5774c2004
1 parent e179614 commit f5ac4ed

File tree

9 files changed

+238
-317
lines changed

9 files changed

+238
-317
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,20 @@ With Gemini 2.0, we took the chance to create a single unified SDK for all devel
44

55
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).
66

7-
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.
7+
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.
88

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

11+
**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)**.
12+
13+
**Support Plan for this Repository:**
14+
15+
* **Limited Maintenance:** Development is now restricted to **critical bug fixes only**. No new features will be added.
16+
* **Purpose:** This limited support aims to provide stability for users while they transition to the new SDK.
17+
* **End-of-Life Date:** All support for this repository (including bug fixes) will permanently end on **August 31st, 2025**.
18+
19+
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.
20+
1121
<!--
1222
[START update]
1323
# With Gemini 2 we're launching a new SDK. See the following doc for details.

google/generativeai/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,12 @@ def configure(
185185
"Invalid configuration: Please set either `api_key` or `client_options['api_key']`, but not both."
186186
)
187187
else:
188-
if api_key is None:
188+
if not api_key:
189189
# If no key is provided explicitly, attempt to load one from the
190190
# environment.
191191
api_key = os.getenv("GEMINI_API_KEY")
192192

193-
if api_key is None:
193+
if not api_key:
194194
# If the GEMINI_API_KEY doesn't exist, attempt to load the
195195
# GOOGLE_API_KEY from the environment.
196196
api_key = os.getenv("GOOGLE_API_KEY")

google/generativeai/responder.py

Lines changed: 154 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import pydantic
2424

2525
from google.generativeai import protos
26+
from google.generativeai.types import content_types
2627

2728
Type = protos.Type
2829

@@ -89,52 +90,36 @@ def _generate_schema(
8990
"""
9091
if descriptions is None:
9192
descriptions = {}
92-
if required is None:
93-
required = []
9493
defaults = dict(inspect.signature(f).parameters)
95-
fields_dict = {
96-
name: (
97-
# 1. We infer the argument type here: use Any rather than None so
98-
# it will not try to auto-infer the type based on the default value.
99-
(param.annotation if param.annotation != inspect.Parameter.empty else Any),
100-
pydantic.Field(
101-
# 2. We do not support default values for now.
102-
# default=(
103-
# param.default if param.default != inspect.Parameter.empty
104-
# else None
105-
# ),
106-
# 3. We support user-provided descriptions.
107-
description=descriptions.get(name, None),
108-
),
109-
)
110-
for name, param in defaults.items()
111-
# We do not support *args or **kwargs
112-
if param.kind
113-
in (
94+
95+
fields_dict = {}
96+
for name, param in defaults.items():
97+
if param.kind in (
11498
inspect.Parameter.POSITIONAL_OR_KEYWORD,
11599
inspect.Parameter.KEYWORD_ONLY,
116100
inspect.Parameter.POSITIONAL_ONLY,
117-
)
118-
}
119-
parameters = pydantic.create_model(f.__name__, **fields_dict).model_json_schema()
120-
# Postprocessing
121-
# 4. Suppress unnecessary title generation:
122-
# * https://github.com/pydantic/pydantic/issues/1051
123-
# * http://cl/586221780
124-
parameters.pop("title", None)
125-
for name, function_arg in parameters.get("properties", {}).items():
126-
function_arg.pop("title", None)
127-
annotation = defaults[name].annotation
128-
# 5. Nullable fields:
129-
# * https://github.com/pydantic/pydantic/issues/1270
130-
# * https://stackoverflow.com/a/58841311
131-
# * https://github.com/pydantic/pydantic/discussions/4872
132-
if typing.get_origin(annotation) is typing.Union and type(None) in typing.get_args(
133-
annotation
134101
):
135-
function_arg["nullable"] = True
102+
# We do not support default values for now.
103+
# default=(
104+
# param.default if param.default != inspect.Parameter.empty
105+
# else None
106+
# ),
107+
field = pydantic.Field(
108+
# We support user-provided descriptions.
109+
description=descriptions.get(name, None)
110+
)
111+
112+
# 1. We infer the argument type here: use Any rather than None so
113+
# it will not try to auto-infer the type based on the default value.
114+
if param.annotation != inspect.Parameter.empty:
115+
fields_dict[name] = param.annotation, field
116+
else:
117+
fields_dict[name] = Any, field
118+
119+
parameters = _build_schema(f.__name__, fields_dict)
120+
136121
# 6. Annotate required fields.
137-
if required:
122+
if required is not None:
138123
# We use the user-provided "required" fields if specified.
139124
parameters["required"] = required
140125
else:
@@ -152,10 +137,138 @@ def _generate_schema(
152137
)
153138
)
154139
]
155-
schema = dict(name=f.__name__, description=f.__doc__, parameters=parameters)
140+
schema = dict(name=f.__name__, description=f.__doc__)
141+
if parameters["properties"]:
142+
schema["parameters"] = parameters
143+
156144
return schema
157145

158146

147+
def _build_schema(fname, fields_dict):
148+
parameters = pydantic.create_model(fname, **fields_dict).model_json_schema()
149+
defs = parameters.pop("$defs", {})
150+
# flatten the defs
151+
for name, value in defs.items():
152+
unpack_defs(value, defs)
153+
unpack_defs(parameters, defs)
154+
155+
# 5. Nullable fields:
156+
# * https://github.com/pydantic/pydantic/issues/1270
157+
# * https://stackoverflow.com/a/58841311
158+
# * https://github.com/pydantic/pydantic/discussions/4872
159+
convert_to_nullable(parameters)
160+
add_object_type(parameters)
161+
# Postprocessing
162+
# 4. Suppress unnecessary title generation:
163+
# * https://github.com/pydantic/pydantic/issues/1051
164+
# * http://cl/586221780
165+
strip_titles(parameters)
166+
strip_additional_properties(parameters)
167+
return parameters
168+
169+
170+
def unpack_defs(schema, defs):
171+
properties = schema.get("properties", None)
172+
if properties is None:
173+
return
174+
175+
for name, value in properties.items():
176+
ref_key = value.get("$ref", None)
177+
if ref_key is not None:
178+
ref = defs[ref_key.split("defs/")[-1]]
179+
unpack_defs(ref, defs)
180+
properties[name] = ref
181+
continue
182+
183+
anyof = value.get("anyOf", None)
184+
if anyof is not None:
185+
for i, atype in enumerate(anyof):
186+
ref_key = atype.get("$ref", None)
187+
if ref_key is not None:
188+
ref = defs[ref_key.split("defs/")[-1]]
189+
unpack_defs(ref, defs)
190+
anyof[i] = ref
191+
continue
192+
193+
items = value.get("items", None)
194+
if items is not None:
195+
ref_key = items.get("$ref", None)
196+
if ref_key is not None:
197+
ref = defs[ref_key.split("defs/")[-1]]
198+
unpack_defs(ref, defs)
199+
value["items"] = ref
200+
continue
201+
202+
203+
def strip_titles(schema):
204+
title = schema.pop("title", None)
205+
206+
properties = schema.get("properties", None)
207+
if properties is not None:
208+
for name, value in properties.items():
209+
strip_titles(value)
210+
211+
items = schema.get("items", None)
212+
if items is not None:
213+
strip_titles(items)
214+
215+
216+
def strip_additional_properties(schema):
217+
schema.pop("additionalProperties", None)
218+
219+
properties = schema.get("properties", None)
220+
if properties is not None:
221+
for name, value in properties.items():
222+
strip_additional_properties(value)
223+
224+
items = schema.get("items", None)
225+
if items is not None:
226+
strip_additional_properties(items)
227+
228+
229+
def add_object_type(schema):
230+
properties = schema.get("properties", None)
231+
if properties is not None:
232+
schema.pop("required", None)
233+
schema["type"] = "object"
234+
for name, value in properties.items():
235+
add_object_type(value)
236+
237+
items = schema.get("items", None)
238+
if items is not None:
239+
add_object_type(items)
240+
241+
242+
def convert_to_nullable(schema):
243+
anyof = schema.pop("anyOf", None)
244+
if anyof is not None:
245+
if len(anyof) != 2:
246+
raise ValueError(
247+
"Invalid input: Type Unions are not supported, except for `Optional` types. "
248+
"Please provide an `Optional` type or a non-Union type."
249+
)
250+
a, b = anyof
251+
if a == {"type": "null"}:
252+
schema.update(b)
253+
elif b == {"type": "null"}:
254+
schema.update(a)
255+
else:
256+
raise ValueError(
257+
"Invalid input: Type Unions are not supported, except for `Optional` types. "
258+
"Please provide an `Optional` type or a non-Union type."
259+
)
260+
schema["nullable"] = True
261+
262+
properties = schema.get("properties", None)
263+
if properties is not None:
264+
for name, value in properties.items():
265+
convert_to_nullable(value)
266+
267+
items = schema.get("items", None)
268+
if items is not None:
269+
convert_to_nullable(items)
270+
271+
159272
def _rename_schema_fields(schema: dict[str, Any]):
160273
if schema is None:
161274
return schema

google/generativeai/types/content_types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ def _build_schema(fname, fields_dict):
435435
# * https://github.com/pydantic/pydantic/issues/1051
436436
# * http://cl/586221780
437437
strip_titles(parameters)
438+
strip_additional_properties(parameters)
438439
return parameters
439440

440441

@@ -484,6 +485,19 @@ def strip_titles(schema):
484485
strip_titles(items)
485486

486487

488+
def strip_additional_properties(schema):
489+
schema.pop("additionalProperties", None)
490+
491+
properties = schema.get("properties", None)
492+
if properties is not None:
493+
for name, value in properties.items():
494+
strip_additional_properties(value)
495+
496+
items = schema.get("items", None)
497+
if items is not None:
498+
strip_additional_properties(items)
499+
500+
487501
def add_object_type(schema):
488502
properties = schema.get("properties", None)
489503
if properties is not None:

google/generativeai/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
# limitations under the License.
1515
from __future__ import annotations
1616

17-
__version__ = "0.8.4"
17+
__version__ = "0.8.5"

0 commit comments

Comments
 (0)