mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 07:09:11 +02:00
Fix nondeterministic required order in transformed tool schemas
Co-authored-by: Bill Easton <6384545+strawgate@users.noreply.github.com>
This commit is contained in:
parent
33ed688a8f
commit
9f5a9f34d8
2 changed files with 29 additions and 2 deletions
|
|
@ -707,7 +707,9 @@ class TransformedTool(Tool):
|
||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": new_props,
|
"properties": new_props,
|
||||||
"required": list(new_required),
|
# Order by property insertion order so the schema is deterministic
|
||||||
|
# across processes (a bare set() order depends on PYTHONHASHSEED).
|
||||||
|
"required": [name for name in new_props if name in new_required],
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -899,7 +901,9 @@ class TransformedTool(Tool):
|
||||||
result = {
|
result = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": merged_props,
|
"properties": merged_props,
|
||||||
"required": list(final_required),
|
# Order by property insertion order so the schema is deterministic
|
||||||
|
# across processes (a bare set() order depends on PYTHONHASHSEED).
|
||||||
|
"required": [name for name in merged_props if name in final_required],
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -553,3 +553,26 @@ class TestInputSchema:
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequiredOrdering:
|
||||||
|
def test_required_follows_property_order(self):
|
||||||
|
"""Transformed `required` should match property order deterministically.
|
||||||
|
|
||||||
|
Regression test for a bug where `required` was built from a set, so its
|
||||||
|
order depended on PYTHONHASHSEED and differed across processes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def base(alpha: int, beta: str, gamma: float, delta: bool, epsilon: int) -> str:
|
||||||
|
return "x"
|
||||||
|
|
||||||
|
transformed = Tool.from_tool(
|
||||||
|
Tool.from_function(base),
|
||||||
|
transform_args={"alpha": ArgTransform(name="a")},
|
||||||
|
)
|
||||||
|
|
||||||
|
properties = list(transformed.parameters["properties"])
|
||||||
|
required = transformed.parameters["required"]
|
||||||
|
|
||||||
|
assert required == [name for name in properties if name in set(required)]
|
||||||
|
assert required == ["a", "beta", "gamma", "delta", "epsilon"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue