Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Python: KernelJsonSchemaBuilder ignores string forward references inside list[...]/dict[...], emitting a bare {"type": "object"}

オープン
#14,239 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 2 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
python
領域
api, backend

調査の方向性

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

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/semantic-kernel のほかの issue

microsoft/semantic-kernel の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。