Repository navigation
Fix hydration of mutually recursive schema types - #6137
wozhenbang2004 wants to merge 4 commits into
Conversation
Generated with OpenAI Codex. Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com>
Generated with OpenAI Codex. Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
This pull request is awaiting maintainer assignment. Linked PRs stay open while maintainers triage the issue; this check remains failing until assignment. Per CONTRIBUTING.md, an external PR must reference an issue that's assigned to its author. To get there:
Once you're assigned and the link is present, this check is re-run automatically. Previously gate-closed PRs also reopen — no further action needed. Maintainers: reopen this PR or remove the |
|
Additional regression coverage for your fix at With these cases added temporarily, Runnable coverage if useful alongside your two-type/client cases: from copy import deepcopy
from typing import Any
import pytest
from pydantic import TypeAdapter
from fastmcp.utilities.json_schema_type import json_schema_to_type
@pytest.mark.parametrize("extra", [False, True], ids=["dataclass", "pydantic"])
@pytest.mark.parametrize("title", [None, "Record"], ids=["untitled", "same-title"])
def test_three_type_cycle_through_array(extra: bool, title: str | None) -> None:
definitions: dict[str, Any] = {
"A": {
"type": "object",
"properties": {
"a": {"type": "string"},
"children": {"type": "array", "items": {"$ref": "#/$defs/B"}},
},
"required": ["a", "children"],
},
"B": {
"type": "object",
"properties": {
"b": {"type": "integer"},
"next": {"$ref": "#/$defs/C"},
},
"required": ["b", "next"],
},
"C": {
"type": "object",
"properties": {
"c": {"type": "boolean"},
"next": {"$ref": "#/$defs/A"},
},
"required": ["c", "next"],
},
}
for definition in definitions.values():
if extra:
definition["additionalProperties"] = True
if title:
definition["title"] = title
schema = {
"type": "object",
"properties": {"node": {"$ref": "#/$defs/A"}},
"required": ["node"],
"$defs": definitions,
}
original = deepcopy(schema)
value = {
"node": {
"a": "first",
"children": [
{"b": 7, "next": {"c": True, "next": {"a": "last", "children": []}}}
],
}
}
generated = json_schema_to_type(schema)
for _ in range(2):
result = TypeAdapter(generated).validate_python(value)
first = result.node
middle = first.children[0]
last = middle.next.next
assert last.a == "last"
assert last.children == []
assert type(last) is type(first)
assert len({type(first), type(middle), type(middle.next)}) == 3
assert TypeAdapter(generated).dump_python(result) == value
assert json_schema_to_type(schema) is generated
assert schema == originalGenerated and executed with OpenAI Codex. No human review before posting. |
|
Thanks for checking this. The three-type cycle through an array is useful additional regression coverage. |
Generated with OpenAI Codex. Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com>
There was a problem hiding this comment.
Automated review by the FastMCP triage reviewer bot.
The identity-bound recursive references fix the reported silent hydration error at the schema-conversion layer. Nested Person/Pet values retain their correct fields and types, and the additional three-type array cycle also preserves distinct classes and serialization. No consequential defect was found in this pass.
Checks
All seven regression cases fail on the base and pass with this revision. Four array-cycle probes and 93 neighboring recursion/default/cache tests also pass.
zzstoatzz
left a comment
There was a problem hiding this comment.
Independent adversarial review passed for this exact revision. Mutually recursive schema identity and complete-graph caching passed independent mixed dataclass/Pydantic probes. Applicable local static checks and the combined recovery tests passed. This is code approval; current CI, contribution gate and repository merge requirements remain separate prerequisites.
There was a problem hiding this comment.
Automated review by the FastMCP triage reviewer bot.
The converter fix preserves distinct recursive model shapes without changing public class names. Independent three-type array cycles also retain class identity and serialize correctly across mixed dataclass/Pydantic graphs. No actionable defect found; this is not a merge-readiness determination.
Checks
At this revision, seven hydration regressions and 15 cache tests pass. The seven regressions fail on the pinned baseline. All 16 independent mixed-model cycle probes pass; the workflow change was inspected but its corpus run was not executed.
|
thanks — the fix and tests landed as #6394 with you as co-author, without the schema-crash workflow commit so that change can be reviewed on its own. closing this in favor of that one. |
* fix: keep additionalProperties on object schemas without a type (#6127) Fixes #6124. Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com> (cherry picked from commit 2a8f333) * Fix hydration of mutually recursive schema types (#6394) Fixes #6135. Supersedes #6137. Co-authored-by: wozhenbang2004 <113896798+wozhenbang2004@users.noreply.github.com> Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 0d7bb12) * Isolate filesystem component construction failures (#6210) Fixes #6209. (cherry picked from commit f911b58) * fix(config): apply tool transforms before tag filters on single servers (#6214) Fixes #6196. Co-authored-by: arjunprabhulal <11761445+arjunprabhulal@users.noreply.github.com> (cherry picked from commit 02c121c) * fix(tools): isolate mutable defaults in transformed tool calls (#6184) Fixes #6183. (cherry picked from commit b25a1c5) * fix(openapi): make resource templates for non-identifier path parameters readable (#6187) Fixes #6150. Co-authored-by: alpaylan <19610315+alpaylan@users.noreply.github.com> (cherry picked from commit 63f5718) * Keep constraints on scalar schema references (#6041) Fixes #6042. (cherry picked from commit e5176c9) * Document that a custom httpx_client_factory owns its timeout (#5923) Fixes #5922. (cherry picked from commit c9f64de) * Stop PingMiddleware erroring when the client has no back-channel (#5901) Fixes #5900. (cherry picked from commit 044a519) * Store sessionless client log levels on the connection (#5899) Fixes #5898. (cherry picked from commit c6e0c4d) * Register templated MCPMixin resources as resource templates (#5895) Fixes #5894. (cherry picked from commit 0c9f5f7) * Send the whole body when a body $ref with siblings cannot be flattened (#5893) Fixes #5892. (cherry picked from commit cad6074) * Pass the transport to the fastmcp-remote proxy so it forwards server-initiated requests (#5885) Fixes #5884. (cherry picked from commit 285dd4c) * fix(cli): forward path, stateless and log-level to SDK MCPServer servers (#5870) Fixes #5869. (cherry picked from commit 6dcec21) * fix(client): preserve a caller-provided OAuth httpx client factory when verify is set (#5849) Fixes #5848. (cherry picked from commit b7c6568) * fix(prompts): resolve postponed annotations when rendering (#5803) Fixes #5801. Co-authored-by: BlueX888 <140241684+BlueX888@users.noreply.github.com> (cherry picked from commit 3bf92a6) * Roll back the tool stamp when a tool registration is rejected (#5798) Fixes #5797. (cherry picked from commit d6566c5) * fix(openapi): hydrate data for wrapped non-object responses with validate_output=False (#5784) Fixes #5781. Co-authored-by: BlueX888 <140241684+BlueX888@users.noreply.github.com> (cherry picked from commit 6451faa) * Carry prompt argument titles through PromptArgument and proxies (#5749) Fixes #5748. (cherry picked from commit 288485c) * Relay the client's sampling result unchanged through proxies (#5747) Fixes #5746. (cherry picked from commit 19c349f) * fix(json-schema): keep x-unsupported-pattern when a format is set (#5731) Fixes #5729. (cherry picked from commit dc9849d) * fix(tasks): let async-generator tools run as background tasks (#5730) Fixes #5728. (cherry picked from commit c66e181) * Honor Code Mode search limits after BM25 ranking (#5715) Fixes #5712. Co-authored-by: BlueX888 <140241684+BlueX888@users.noreply.github.com> (cherry picked from commit ee71391) * Keep the client timeout from capping the HTTP read timeout (#5690) Fixes #5675. (cherry picked from commit bf95d12) * fix(auth): avoid rereading failed authorization forms (#5570) Fixes #5569. Co-authored-by: JordanAfolabiLaw <252951842+JordanAfolabiLaw@users.noreply.github.com> (cherry picked from commit e9f0443) * Fix unbounded Apps dev log retention (#5549) Fixes #5548. (cherry picked from commit 0a9a482) * Bound error-stat cardinality in ErrorHandlingMiddleware (#5537) Fixes #5536. (cherry picked from commit 089ff09) * fix(auth): preserve GitHub sessions across transient verification failures (#4881) Fixes #4854. Co-authored-by: benjohngf <7750978+benjohngf@users.noreply.github.com> (cherry picked from commit 3c6fbf7) * Expect the extended read timeout in the factory timeout test (#6395) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit d8c4edf) * fix(auth): keep revocation ownership separate from user identity (#6404) Fixes #5800. Builds on #5807. Co-authored-by: BlueX888 <140241684+BlueX888@users.noreply.github.com> Co-authored-by: Luck <232011771+67-luck@users.noreply.github.com> (cherry picked from commit cdec3a9) * Authenticate and pin the schema download in the OpenAPI performance test (#6177) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit a66dd71) * Resolve deferred defaults by alias and keep unverified GitHub scopes out of the cache Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit e064736) * Revert "Roll back the tool stamp when a tool registration is rejected (#5798)" This reverts commit 36a1264. * Revert "Keep constraints on scalar schema references (#6041)" This reverts commit 1ffb3e6. * Revert "fix(json-schema): keep x-unsupported-pattern when a format is set (#5731)" This reverts commit 9da9835. --------- Co-authored-by: zgy <101915083+bfs2021@users.noreply.github.com> Co-authored-by: Alperen Keleş <19610315+alpaylan@users.noreply.github.com> Co-authored-by: wozhenbang2004 <113896798+wozhenbang2004@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: ppy <285454460@qq.com> Co-authored-by: ayush <ayushkumarsaha32@gmail.com> Co-authored-by: arjunprabhulal <11761445+arjunprabhulal@users.noreply.github.com> Co-authored-by: Priyanshu Gupta <priyanshug26005@gmail.com> Co-authored-by: Shayan Ali <shayan.ali8799@gmail.com> Co-authored-by: Asem ahmed <94972604+asasemahmed@users.noreply.github.com> Co-authored-by: 哈基米 <140241684+BlueX888@users.noreply.github.com> Co-authored-by: Luck <2115759892@qq.com> Co-authored-by: Winoren <158550716+Winoren@users.noreply.github.com> Co-authored-by: nosmile99 <147114285+nosmile99@users.noreply.github.com> Co-authored-by: Aarnav Noble <98567595+AarnavNoble@users.noreply.github.com> Co-authored-by: 一片一片 <3037678834@qq.com> Co-authored-by: Junpei Zhang <1259636180@qq.com> Co-authored-by: JordanAfolabiLaw <252951842+JordanAfolabiLaw@users.noreply.github.com> Co-authored-by: mika <spacexstarship01@outlook.com> Co-authored-by: sui-ni2 <loxri127@gmail.com> Co-authored-by: benjohngf <7750978+benjohngf@users.noreply.github.com> Co-authored-by: Luck <232011771+67-luck@users.noreply.github.com>
Tools returning mutually recursive
Person.pet/Pet.ownermodels can send correctstructured_contentwhile the client's.datasilently uses the wrong class several levels down. Without schema titles, distinct generated classes share the display nameRoot, and recursive references bind to that shared name.Bind recursive references to each generated class's identity, resolve the complete graph, and only then share it through the class cache. Public class names remain unchanged. For the four-level result in #6135, the final pet retains its
ownerfield:Fixes #6135.
🤖 Generated with OpenAI Codex.
Co-authored-by: Alperen Keleş 19610315+alpaylan@users.noreply.github.com