Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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

未关闭
#14,239 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@ErenAta16 已经在做这个了。

开始于 2026年7月29日。

  • #14241 来自 @ErenAta16 —— 未关闭
  • #14268 来自 @Diwak4r —— 已关闭,未合并
  • #14310 来自 @Om-singhaI —— 未关闭

评估

难度
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 schema。

由索引模型根据 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.7k
派生
4.8k
平均合并
1 天 21 小时
30 天内合并 PR
28

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/semantic-kernel 的其他 Issue

查看 microsoft/semantic-kernel 的全部 Issue

相似的 Issue

更多 C# Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。