FunctionDeclaration.from_callable drops enum and properties from Optional[...] parameters
メンテナーはふだん 1 日以内に返信
@Venkaiahbabuneelam がすでに取り組んでいます。
2026年10月13日 から。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 67/100
調査の方向性
_automatic_function_calling_util.py の _parse_schema_from_parameter 周辺と、282 行付近の単一メンバー Union の縮約を読みます。Issue 内の Optional とパイプユニオン examples を比較し、tests/types/test_types.py にオプショナルな Literal パラメーターとモデルパラメーターの回帰ケースを追加します。生成されるスキーマが enum または object のプロパティを保持しつつ nullable のままであれば完了です。
索引モデルが issue の本文から書いたものです。
説明
FunctionDeclaration.from_callable keeps only the type of the inner schema when a parameter is Optional[X]. An Optional[Literal["c", "f"]] parameter becomes a nullable string with no enum. An Optional[Address] parameter becomes a bare nullable object with no properties or required. Address | None keeps them, but Literal["c", "f"] | None loses its enum too.
import json
from typing import Literal, Optional
import pydantic
from google import genai
from google.genai import types
client = genai.Client(api_key="not-a-real-key") # no request is sent
class Address(pydantic.BaseModel):
city: str
def unit_plain(unit: Literal["c", "f"]) -> str: ...
def unit_optional(unit: Optional[Literal["c", "f"]] = None) -> str: ...
def addr_optional(addr: Optional[Address] = None) -> str: ...
def addrs_optional(addrs: Optional[list[Address]] = None) -> str: ...
def unit_pipe(unit: Literal["c", "f"] | None = None) -> str: ...
def addr_pipe(addr: Address | None = None) -> str: ...
for f in [unit_plain, unit_optional, addr_optional, addrs_optional, unit_pipe, addr_pipe]:
fd = types.FunctionDeclaration.from_callable(client=client, callable=f)
(name, s), = fd.parameters.properties.items()
print(f"{f.__name__:15}", json.dumps(s.model_dump(exclude_none=True)))
$ python -I genai_fd3.py
unit_plain {"enum": ["c", "f"], "type": "STRING"}
unit_optional {"nullable": true, "type": "STRING"}
addr_optional {"nullable": true, "type": "OBJECT"}
addrs_optional {"items": {"properties": {"city": {"type": "STRING"}}, "required": ["city"], "type": "OBJECT"}, "nullable": true, "type": "ARRAY"}
unit_pipe {"nullable": true, "type": "STRING"}
addr_pipe {"nullable": true, "properties": {"city": {"type": "STRING"}}, "required": ["city"], "type": "OBJECT"}
# google-genai 2.29.0 at 6a6501c (main, 2026-10-11), CPython 3.12.3, Linux x86_64
The single-member collapse in the Union branch of _parse_schema_from_parameter (_automatic_function_calling_util.py:282) copies schema.any_of[0].type and nothing else. Optional[list[...]] survives only because the lines above it copy items by hand. Copying the whole member fixes both:
if len(schema.any_of) == 1: # param: Union[List, None] -> Array
- schema.type = schema.any_of[0].type
- schema.any_of = None
+ schema = schema.any_of[0].model_copy(
+ update={'nullable': schema.nullable}
+ )
$ python -I genai_fd3.py # with the patch
unit_plain {"enum": ["c", "f"], "type": "STRING"}
unit_optional {"enum": ["c", "f"], "nullable": true, "type": "STRING"}
addr_optional {"nullable": true, "properties": {"city": {"type": "STRING"}}, "required": ["city"], "type": "OBJECT"}
addrs_optional {"items": {"properties": {"city": {"type": "STRING"}}, "required": ["city"], "type": "OBJECT"}, "nullable": true, "type": "ARRAY"}
unit_pipe {"enum": ["c", "f"], "nullable": true, "type": "STRING"}
addr_pipe {"nullable": true, "properties": {"city": {"type": "STRING"}}, "required": ["city"], "type": "OBJECT"}
$ python -m pytest -q google/genai/tests/types/test_types.py google/genai/tests/types/test_future.py
95 passed, 6 skipped, 2 warnings # same count before and after the patch
# not run: any request to the live API
This is the default use_json_schema=False path, so it hits direct from_callable callers. A function passed straight into tools=[...] takes use_json_schema=True (_transformers.py:961), where open #3074 and #3093 work. @Venkaiahbabuneelam, CONTRIBUTING.md says outside pull requests are not taken yet, so the diff above is the whole proposal. Would a test for these signatures in tests/types/test_types.py help it land?
- 主要言語
- Python
- スター
- 4k
- フォーク
- 1k
- 平均マージ
- 1日 7時間
- マージ済み PR(30日)
- 82
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
googleapis/python-genai のほかの issue
-
priority: p2 type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
googleapis/python-genai#3122 ·
メンテナーはふだん 1 日以内に返信
-
Curated history keeps half a user turn when the model turn is invalid対応中かも @Venkaiahbabuneelam が 9 日前に担当しました。 オープンpriority: p2 type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
googleapis/python-genai#3051 · コメント 3 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
[Bug]: Unsubscripted typing.List and typing.Dict crash convert_if_exist_pydantic_model in AFC対応中かも @Venkaiahbabuneelam が 9 日前に担当しました。 オープンpriority: p2 type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
googleapis/python-genai#3044 · コメント 1 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
Name collision in google.genai.interactions: triggers.Interaction shadows response model Interaction in static type checkers対応中かも @Venkaiahbabuneelam が 16 日前に担当しました。 オープンpriority: p2 type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
googleapis/python-genai#3013 · コメント 1 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
priority: p2 type: bug
難易度 5/5 1週間以上 初心者へのやさしさ 8/100
googleapis/python-genai#3120 ·
メンテナーはふだん 1 日以内に返信
googleapis/python-genai の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
onyx-dot-app/onyx#16016 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
black --check exits 0 and prints All done when a multi file run is interrupted対応中かも @jiteshgulati が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 2 日以内に返信
-
Non-positive worker counts wait for results without starting workers対応中かも @IlyaKhalafi が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信