8000 Fix: Preserve deeply nested schemas (#133) · lgigit200/sdk-python@8ffe24b · GitHub
[go: up one dir, main page]

Skip to content

Commit 8ffe24b

Browse files
authored
Fix: Preserve deeply nested schemas (strands-agents#133)
* Preserve deeply nested schemas * Refactor schema tests to assert entire structure --------- Authored-by: Luke Harris <lkhar@amazon.com>
1 parent a805919 commit 8ffe24b

File tree

2 files changed

+273
-92
lines changed

2 files changed

+273
-92
lines changed

src/strands/tools/tools.py

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,50 +63,54 @@ def validate_tool_use_name(tool: ToolUse) -> None:
6363
raise InvalidToolUseNameException(message)
6464

6565

66+
def _normalize_property(prop_name: str, prop_def: Any) -> Dict[str, Any]:
67+
"""Normalize a single property definition.
68+
69+
Args:
70+
prop_name: The name of the property.
71+
prop_def: The property definition to normalize.
72+
73+
Returns:
74+
The normalized property definition.
75+
"""
76+
if not isinstance(prop_def, dict):
77+
return {"type": "string", "description": f"Property {prop_name}"}
78+
79+
if prop_def.get("type") == "object" and "properties" in prop_def:
80+
return normalize_schema(prop_def) # Recursive call
81+
82+
# Copy existing property, ensuring defaults
83+
normalized_prop = prop_def.copy()
84+
normalized_prop.setdefault("type", "string")
85+
normalized_prop.setdefault("description", f"Property {prop_name}")
86+
return normalized_prop
87+
88+
6689
def normalize_schema(schema: Dict[str, Any]) -> Dict[str, Any]:
6790
"""Normalize a JSON schema to match expectations.
6891
92< 10000 code class="diff-text syntax-highlighted-line addition">+
This function recursively processes nested objects to preserve the complete schema structure.
93+
Uses a copy-then-normalize approach to preserve all original schema properties.
94+
6995
Args:
7096
schema: The schema to normalize.
7197
7298
Returns:
7399
The normalized schema.
74100
"""
75-
normalized = {"type": schema.get("type", "object"), "properties": {}}
76-
77-
# Handle properties
78-
if "properties" in schema:
79-
for prop_name, prop_def in schema["properties"].items():
80-
if isinstance(prop_def, dict):
81-
normalized_prop = {
82-
"type": prop_def.get("type", "string"),
83-
"description": prop_def.get("description", f"Property {prop_name}"),
84-
}
85-
86-
# Handle enum values correctly
87-
if "enum" in prop_def:
88-
normalized_prop["enum"] = prop_def["enum"]
89-
90-
# Handle numeric constraints
91-
if prop_def.get("type") in ["number", "integer"]:
92-
if "minimum" in prop_def:
93-
normalized_prop["minimum"] = prop_def["minimum"]
94-
if "maximum" in prop_def:
95-
normalized_prop["maximum"] = prop_def["maximum"]
96-
97-
normalized["properties"][prop_name] = normalized_prop
98-
else:
99-
# Handle non-dict property definitions (like simple strings)
100-
normalized["properties"][prop_name] = {
101-
"type": "string",
102-
"description": f"Property {prop_name}",
103-
}
104-
105-
# Required fields
106-
if "required" in schema:
107-
normalized["required"] = schema["required"]
108-
else:
109-
normalized["required"] = []
101+
# Start with a complete copy to preserve a 8D0B ll existing properties
102+
normalized = schema.copy()
103+
104+
# Ensure essential structure exists
105+
normalized.setdefault("type", "object")
106+
normalized.setdefault("properties", {})
107+
normalized.setdefault("required", [])
108+
109+
# Process properties recursively
110+
if "properties" in normalized:
111+
properties = normalized["properties"]
112+
for prop_name, prop_def in properties.items():
113+
normalized["properties"][prop_name] = _normalize_property(prop_name, prop_def)
110114

111115
return normalized
112116

0 commit comments

Comments
 (0)
0