diff --git a/model_tools.py b/model_tools.py index bee80f49bd..2b7767fda3 100644 --- a/model_tools.py +++ b/model_tools.py @@ -418,6 +418,31 @@ def _coerce_value(value: str, expected_type): return _coerce_number(value, integer_only=(expected_type == "integer")) if expected_type == "boolean": return _coerce_boolean(value) + if expected_type == "array": + return _coerce_json(value, list) + if expected_type == "object": + return _coerce_json(value, dict) + return value + + +def _coerce_json(value: str, expected_python_type: type): + """Parse *value* as JSON when the schema expects an array or object. + + Handles model output drift where a complex oneOf/discriminated-union schema + causes the LLM to emit the array/object as a JSON string instead of a native + structure. Returns the original string if parsing fails or yields the wrong + Python type. + """ + try: + parsed = json.loads(value) + except (ValueError, TypeError): + return value + if isinstance(parsed, expected_python_type): + logger.debug( + "coerce_tool_args: coerced string to %s via json.loads", + expected_python_type.__name__, + ) + return parsed return value