@@ -108,3 +108,145 @@ def test_flatten_allof_non_object_members_are_left_as_is() -> None:
108108 # Expect: we cannot sensibly merge non-object members; keep allOf
109109 flattened = flatten_allof (copy .deepcopy (schema ))
110110 assert 'allOf' in flattened
111+
112+
113+ def test_flatten_allof_object_like_without_type () -> None :
114+ """Test that object-like schemas without explicit type are recognized."""
115+ from pydantic_ai ._json_schema import flatten_allof
116+
117+ schema : dict [str , Any ] = {
118+ 'type' : 'object' ,
119+ 'allOf' : [
120+ {
121+ # No type, but has properties - should be recognized as object-like
122+ 'properties' : {'a' : {'type' : 'string' }},
123+ 'required' : ['a' ],
124+ },
125+ {
126+ 'type' : 'object' ,
127+ 'properties' : {'b' : {'type' : 'integer' }},
128+ 'required' : ['b' ],
129+ },
130+ ],
131+ }
132+
133+ flattened = flatten_allof (copy .deepcopy (schema ))
134+ assert 'allOf' not in flattened
135+ assert set (flattened ['required' ]) == {'a' , 'b' }
136+
137+
138+ def test_flatten_allof_with_dict_additional_properties () -> None :
139+ """Test merging when additionalProperties is a dict schema."""
140+ from pydantic_ai ._json_schema import flatten_allof
141+
142+ schema : dict [str , Any ] = {
143+ 'type' : 'object' ,
144+ 'allOf' : [
145+ {
146+ 'type' : 'object' ,
147+ 'properties' : {'a' : {'type' : 'string' }},
148+ 'additionalProperties' : {'type' : 'string' }, # dict schema
149+ },
150+ {
151+ 'type' : 'object' ,
152+ 'properties' : {'b' : {'type' : 'integer' }},
153+ 'additionalProperties' : False ,
154+ },
155+ ],
156+ }
157+
158+ flattened = flatten_allof (copy .deepcopy (schema ))
159+ assert 'allOf' not in flattened
160+ # When any member has dict additionalProperties, result should be True
161+ assert flattened .get ('additionalProperties' ) is True
162+
163+
164+ def test_flatten_allof_with_non_dict_member () -> None :
165+ """Test that allOf with non-dict members is left untouched."""
166+ from pydantic_ai ._json_schema import flatten_allof
167+
168+ schema : dict [str , Any ] = {
169+ 'type' : 'object' ,
170+ 'allOf' : [
171+ {'type' : 'object' , 'properties' : {'a' : {'type' : 'string' }}},
172+ 'not a dict' , # Non-dict member
173+ ],
174+ }
175+
176+ flattened = flatten_allof (copy .deepcopy (schema ))
177+ # Should be left untouched because one member is not a dict
178+ assert 'allOf' in flattened
179+
180+
181+ def test_flatten_allof_no_initial_properties () -> None :
182+ """Test flattening when root schema has no initial properties."""
183+ from pydantic_ai ._json_schema import flatten_allof
184+
185+ schema : dict [str , Any ] = {
186+ 'type' : 'object' ,
187+ 'allOf' : [
188+ {
189+ 'type' : 'object' ,
190+ 'properties' : {'a' : {'type' : 'string' }},
191+ 'required' : ['a' ],
192+ },
193+ ],
194+ }
195+
196+ flattened = flatten_allof (copy .deepcopy (schema ))
197+ assert 'allOf' not in flattened
198+ assert flattened ['properties' ]['a' ]['type' ] == 'string'
199+ assert flattened ['required' ] == ['a' ]
200+
201+
202+ def test_flatten_allof_members_without_properties () -> None :
203+ """Test flattening when some members don't have properties/required/patternProperties."""
204+ from pydantic_ai ._json_schema import flatten_allof
205+
206+ schema : dict [str , Any ] = {
207+ 'type' : 'object' ,
208+ 'allOf' : [
209+ {
210+ 'type' : 'object' ,
211+ 'properties' : {'a' : {'type' : 'string' }},
212+ 'required' : ['a' ],
213+ },
214+ {
215+ 'type' : 'object' ,
216+ # No properties, required, or patternProperties
217+ 'additionalProperties' : False ,
218+ },
219+ {
220+ 'type' : 'object' ,
221+ 'properties' : {'b' : {'type' : 'integer' }},
222+ # No required
223+ },
224+ ],
225+ }
226+
227+ flattened = flatten_allof (copy .deepcopy (schema ))
228+ assert 'allOf' not in flattened
229+ assert set (flattened ['properties' ].keys ()) == {'a' , 'b' }
230+ assert flattened ['required' ] == ['a' ] # Only from first member
231+ assert flattened .get ('additionalProperties' ) is False
232+
233+
234+ def test_flatten_allof_empty_properties_after_merge () -> None :
235+ """Test edge case where properties/required/patternProperties might be empty."""
236+ from pydantic_ai ._json_schema import flatten_allof
237+
238+ schema : dict [str , Any ] = {
239+ 'type' : 'object' ,
240+ 'allOf' : [
241+ {
242+ 'type' : 'object' ,
243+ # No properties, required, or patternProperties
244+ },
245+ ],
246+ }
247+
248+ flattened = flatten_allof (copy .deepcopy (schema ))
249+ assert 'allOf' not in flattened
250+ # Should not have properties/required if they're empty
251+ assert 'properties' not in flattened or not flattened .get ('properties' )
252+ assert 'required' not in flattened or not flattened .get ('required' )
0 commit comments