Python: KernelJsonSchemaBuilder ignores string forward references inside list[...]/dict[...], emitting a bare {"type": "object"}
メンテナーはふだん 2 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 76/100
調査の方向性
semantic_kernel/schema/kernel_json_schema_builder.py から始め、特に build_model_schema と handle_complex_type を確認します。コンテナの args がどのように build に渡されるかを調べます。issue の Holder の例を使って list["Inner"] と list[Inner] の違いを再現し、その後、同等の item スキーマと additionalProperties スキーマを示すカバレッジを追加します。
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
KernelJsonSchemaBuilder silently drops the element schema when a container's element type is written as a string forward reference. list["Inner"] produces {"type": "object"} for the items — no properties, no required — while list[Inner] produces the full schema.
That schema is what gets sent to the model as a function-calling parameter definition, so a plugin using this annotation style hands the model an untyped blob for that argument.
To Reproduce
from semantic_kernel.kernel_pydantic import KernelBaseModel
from semantic_kernel.schema.kernel_json_schema_builder import KernelJsonSchemaBuilder as B
class Inner(KernelBaseModel):
value: int
label: str
class HolderDirect(KernelBaseModel):
items: list[Inner] = []
class HolderFwd(KernelBaseModel):
items: list["Inner"] = []
class HolderTop(KernelBaseModel):
one: "Inner"
| model | items / one schema |
|---|---|
HolderDirect |
{"type": "array", "items": {"type": "object", "properties": {"value": ..., "label": ...}, "required": [...]}} |
HolderFwd |
{"type": "array", "items": {"type": "object"}} |
HolderTop |
full Inner schema |
dict[str, "Inner"] |
additionalProperties: {"type": "object", "properties": {}} |
HolderTop works and HolderFwd doesn't, which is the part that makes this easy to miss — forward references look supported.
Why
HolderFwd.__annotations__["items"] -> list['Inner']
get_type_hints(HolderFwd)["items"] -> list['Inner'] # unchanged
get_args(...) -> ('Inner',) # a str, not a type
HolderFwd.model_fields["items"].annotation -> list['Inner'] # pydantic doesn't resolve it either
get_type_hints evaluates an annotation that is a string. It does not descend into a generic alias that already exists as an object and evaluate strings sitting in its __args__. list["Inner"] goes through list.__class_getitem__, which stores "Inner" verbatim — no ForwardRef wrapper, so there's nothing for get_type_hints to resolve. typing.Optional["Inner"] does wrap the string in a ForwardRef, which is why the top-level and Optional forms work.
handle_complex_type then calls cls.build("Inner", ...), which takes the isinstance(parameter_type, str) branch at the top of build and lands in build_from_type_name. No entry matches "Inner", so it returns the {"type": "object"} fallback:
KernelJsonSchemaBuilder.build("Inner") # -> {'type': 'object'}
Nothing raises, and {"type": "object"} is indistinguishable from a genuinely-unknown type downstream.
Expected behavior
list["Inner"] and list[Inner] produce the same schema.
Resolving str args against the owning model's module globals inside handle_complex_type before recursing would do it — the module globals are already fetched a few lines up in build_model_schema for the get_type_hints call.
Platform
- OS: Linux
- Python: 3.10.12
- Semantic Kernel:
main@ 7d885dd (python)
Additional context
Separate from the recursion work in #14198. That PR is about cycles; this fires on a plain non-recursive list["Inner"]. It's also the reason two of #14198's new tests currently fail — TreeNode and Author/Book reach their cycles through list[...], so the string never resolves to a class and the cycle detection never engages.
- 主要言語
- C#
- スター
- 28.6k
- フォーク
- 4.8k
- 平均マージ
- 13時間 24分
- マージ済み PR(30日)
- 11
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/semantic-kernel のほかの issue
-
python triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
microsoft/semantic-kernel#14491 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
python triage
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
microsoft/semantic-kernel#14490 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
Python: [Python] structured_outputs_transform reuses ChatHistory across calls (prompt pollution)オープンpython triage
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
microsoft/semantic-kernel#14483 · コメント 2 件 ·
メンテナーはふだん 2 日以内に返信
-
.NET python triage
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
microsoft/semantic-kernel#14482 · コメント 3 件 ·
メンテナーはふだん 2 日以内に返信
-
python triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
microsoft/semantic-kernel#14481 ·
メンテナーはふだん 2 日以内に返信
microsoft/semantic-kernel の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
SubtitleEdit/subtitleedit#15462 ·
メンテナーはふだん 1 日以内に返信
-
:watch: Not Triaged
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
comp:instrumentation.aspnetcore
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
open-telemetry/opentelemetry-dotnet-contrib#5427 ·
メンテナーはふだん 1 日以内に返信
-
design-proposal
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
dotnet/aspnetcore#69592 ·
メンテナーはふだん 1 日以内に返信
-
Client Container Registry customer-reported needs-team-attention question Service Attention
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
Azure/azure-sdk-for-net#63470 · コメント 3 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信