From 4f18a08ea7ed5835468542510a21d373c8b03738 Mon Sep 17 00:00:00 2001 From: Zara Thomas Date: Wed, 19 Aug 2026 09:26:15 +0100 Subject: [PATCH] address greptile feedback: expand sanitizer traversal, use object type - Traverse propertyNames, prefixItems, and definitions subschemas (Greptile P1: propertyNames could retain rejected keywords) - Use `object` instead of `Any` for the sanitizer parameter (Greptile P2: reduces untyped boundary) - Combine anyOf/allOf/oneOf/prefixItems branches (ruff SIM114) - Add tests for propertyNames, prefixItems, and definitions traversal Co-authored-by: Cursor --- .../llms/fireworks_ai/chat/transformation.py | 13 +++--- .../chat/test_fireworks_schema_sanitize.py | 45 +++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/litellm/llms/fireworks_ai/chat/transformation.py b/litellm/llms/fireworks_ai/chat/transformation.py index 3cbe8a8d9dc..c4a9c85dbe2 100644 --- a/litellm/llms/fireworks_ai/chat/transformation.py +++ b/litellm/llms/fireworks_ai/chat/transformation.py @@ -468,12 +468,13 @@ class FireworksAIConfig(FireworksAIMixin, OpenAIGPTConfig): _FIREWORKS_TOOL_SCHEMA_STRIP_KEYS: Final = frozenset({"pattern", "title"}) @staticmethod - def _sanitize_tool_schema(schema: Any) -> None: + def _sanitize_tool_schema(schema: object) -> None: """Recursively strip JSON Schema keywords Fireworks rejects from tool parameter schemas, in place. - Walks ``properties``, ``items``, ``anyOf``/``allOf``/``oneOf``, and - ``$defs``. Removes ``pattern`` and ``title`` everywhere, and ``default`` + Walks ``properties``, ``items``, ``anyOf``/``allOf``/``oneOf``, + ``$defs``, ``definitions``, ``prefixItems``, and ``propertyNames``. + Removes ``pattern`` and ``title`` everywhere, and ``default`` only when its value is ``None``. Non-null defaults, enums, and all other keywords are preserved. """ @@ -489,12 +490,14 @@ class FireworksAIConfig(FireworksAIMixin, OpenAIGPTConfig): FireworksAIConfig._sanitize_tool_schema(prop) elif key == "items" and isinstance(schema[key], dict): FireworksAIConfig._sanitize_tool_schema(schema[key]) - elif key == "$defs" and isinstance(schema[key], dict): + elif key in ("$defs", "definitions") and isinstance(schema[key], dict): for defn in schema[key].values(): FireworksAIConfig._sanitize_tool_schema(defn) - elif key in ("anyOf", "allOf", "oneOf") and isinstance(schema[key], list): + elif key in ("anyOf", "allOf", "oneOf", "prefixItems") and isinstance(schema[key], list): for item in schema[key]: FireworksAIConfig._sanitize_tool_schema(item) + elif key == "propertyNames" and isinstance(schema[key], dict): + FireworksAIConfig._sanitize_tool_schema(schema[key]) def _transform_messages_helper( self, messages: list[AllMessageValues], model: str, litellm_params: dict diff --git a/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_schema_sanitize.py b/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_schema_sanitize.py index 13e92c8f2a5..4f55143440e 100644 --- a/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_schema_sanitize.py +++ b/tests/test_litellm/llms/fireworks_ai/chat/test_fireworks_schema_sanitize.py @@ -228,6 +228,51 @@ def test_sanitize_deeply_nested(): assert "pattern" not in deep +def test_sanitize_recurses_into_propertyNames(): + """propertyNames subschema must be traversed (Greptile P1).""" + config = FireworksAIConfig() + schema = { + "type": "object", + "propertyNames": { + "type": "string", + "pattern": "^[a-z]+$", + "title": "Prop Name", + }, + } + config._sanitize_tool_schema(schema) + assert "pattern" not in schema["propertyNames"] + assert "title" not in schema["propertyNames"] + + +def test_sanitize_recurses_into_prefixItems(): + """prefixItems array must be traversed.""" + config = FireworksAIConfig() + schema = { + "type": "array", + "prefixItems": [ + {"type": "string", "pattern": "^[A-Z]+$"}, + {"type": "string", "title": "Second"}, + ], + } + config._sanitize_tool_schema(schema) + assert "pattern" not in schema["prefixItems"][0] + assert "title" not in schema["prefixItems"][1] + + +def test_sanitize_recurses_into_definitions(): + """Legacy draft-04 definitions must be traversed.""" + config = FireworksAIConfig() + schema = { + "type": "object", + "definitions": { + "Foo": {"type": "string", "pattern": "^[a-z]+$", "title": "Foo"}, + }, + } + config._sanitize_tool_schema(schema) + assert "pattern" not in schema["definitions"]["Foo"] + assert "title" not in schema["definitions"]["Foo"] + + # --------------------------------------------------------------------------- # _transform_tools integration tests # ---------------------------------------------------------------------------