From 5acd185f7ced2c629f5c36387f01c4ceb5fb4c9b Mon Sep 17 00:00:00 2001 From: Tranquil-Flow Date: Sat, 13 Jun 2026 05:09:20 -0700 Subject: [PATCH] fix(moonshot): handle union type arrays in tool schemas --- agent/moonshot_schema.py | 9 +++++- tests/agent/test_moonshot_schema.py | 49 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/agent/moonshot_schema.py b/agent/moonshot_schema.py index f22176f936e..206ccee1653 100644 --- a/agent/moonshot_schema.py +++ b/agent/moonshot_schema.py @@ -135,7 +135,14 @@ def _repair_schema(node: Any, is_schema: bool = True) -> Any: def _fill_missing_type(node: Dict[str, Any]) -> Dict[str, Any]: """Infer a reasonable ``type`` if this schema node has none.""" - if "type" in node and node["type"] not in {None, ""}: + node_type = node.get("type") + if isinstance(node_type, list): + concrete = next( + (t for t in node_type if isinstance(t, str) and t not in {"", "null"}), + "string", + ) + return {**node, "type": concrete} + if "type" in node and node_type not in {None, ""}: return node # Heuristic: presence of ``properties`` → object, ``items`` → array, ``enum`` diff --git a/tests/agent/test_moonshot_schema.py b/tests/agent/test_moonshot_schema.py index 2ce2daa096a..69727f9ab77 100644 --- a/tests/agent/test_moonshot_schema.py +++ b/tests/agent/test_moonshot_schema.py @@ -397,3 +397,52 @@ class TestEnumNullStripping: assert db_type["type"] == "string" assert db_type["enum"] == ["mysql", "postgresql"], \ "null/empty enum values must be stripped after anyOf collapse" + + +class TestUnionTypeList: + """Moonshot sanitizer accepts JSON Schema union type arrays.""" + + def test_union_type_list_normalizes_to_first_concrete_type(self): + params = { + "type": "object", + "properties": { + "limit": { + "type": ["number", "string"], + "description": "Max results", + }, + }, + } + + out = sanitize_moonshot_tool_parameters(params) + + assert out["properties"]["limit"]["type"] == "number" + + def test_union_type_list_skips_null_type(self): + params = { + "type": "object", + "properties": { + "name": {"type": ["null", "string"]}, + }, + } + + out = sanitize_moonshot_tool_parameters(params) + + assert out["properties"]["name"]["type"] == "string" + + def test_union_type_list_with_enum_does_not_crash_or_mutate_input(self): + params = { + "type": "object", + "properties": { + "sort": { + "type": ["string", "null"], + "enum": ["asc", "desc", None, ""], + }, + }, + } + + out = sanitize_moonshot_tool_parameters(params) + + sort = out["properties"]["sort"] + assert sort["type"] == "string" + assert sort["enum"] == ["asc", "desc"] + assert params["properties"]["sort"]["type"] == ["string", "null"]