diff --git a/backend/app/agent/agent_model.py b/backend/app/agent/agent_model.py index 1b1fe860b..e80d00a09 100644 --- a/backend/app/agent/agent_model.py +++ b/backend/app/agent/agent_model.py @@ -28,6 +28,42 @@ from app.utils.event_loop_utils import _schedule_async_task +def _sanitize_tool_schema(obj): + """Recursively fix tool JSON schemas for strict providers (e.g. Groq).""" + if isinstance(obj, list): + for item in obj: + _sanitize_tool_schema(item) + return + if not isinstance(obj, dict): + return + # force additionalProperties to false on objects + if obj.get("type") == "object": + obj["additionalProperties"] = False + # collapse integer/number overlap in anyOf/oneOf + for union_key in ("anyOf", "oneOf"): + union = obj.get(union_key) + if isinstance(union, list): + types_in_union = [ + item.get("type") + for item in union + if isinstance(item, dict) and "type" in item + ] + if "integer" in types_in_union and "number" in types_in_union: + obj[union_key] = [ + item + for item in union + if not ( + isinstance(item, dict) + and item.get("type") == "integer" + ) + ] + # Recurse + for key, value in list(obj.items()): + if key == "additionalProperties" and value is not False: + continue + _sanitize_tool_schema(value) + + def agent_model( agent_name: str, system_message: str | BaseMessage, @@ -145,6 +181,15 @@ def agent_model( **init_params, ) + # Fix tool schemas for strict providers (e.g. Groq) that require + # additionalProperties: false and reject integer/number overlap. + if tools: + for tool in tools: + if isinstance(tool, FunctionTool) and hasattr( + tool, "openai_tool_schema" + ): + _sanitize_tool_schema(tool.openai_tool_schema) + return ListenChatAgent( options.project_id, agent_name,