A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 14, 05:30 UTC
[CI][Entrypoints]: add filter to generation to filter out invalid tool calls (#22826)
Signed-off-by: Will Eaton <weaton@redhat.com>
Will Eaton committed
Aug 13, 2025 at 23:09 UTC
b6af24fba73cad27254e8826bbd842810cce7ee8
1 file changed
+32
-16
tests/entrypoints/openai/test_openai_schema.py
+32
-16
@@ -54,38 +54,54 @@ def before_generate_case(context: schemathesis.hooks.HookContext, strategy):
54
op = context.operation
55
assert op is not None
56
57
- def no_file_type(case: schemathesis.models.Case):
57
+ def no_invalid_types(case: schemathesis.models.Case):
58
"""
59
- This filter skips test cases for the `POST /tokenize` endpoint where the
60
- HTTP request body uses `"type": "file"` in any message's content.
61
- We expect these cases to fail because that type isn't implemented here
62
- https://github.com/vllm-project/vllm/blob/0b34593017953051b3225b1483ce0f4670e3eb0e/vllm/entrypoints/chat_utils.py#L1038-L1095
59
+ This filter skips test cases with invalid data that schemathesis
60
+ incorrectly generates due to permissive schema configurations.
61
+
62
+ 1. Skips `POST /tokenize` endpoint cases with `"type": "file"` in
63
+ message content, which isn't implemented.
64
+
65
+ 2. Skips tool_calls with `"type": "custom"` which schemathesis
66
+ incorrectly generates instead of the valid `"type": "function"`.
67
68
Example test cases that are skipped:
69
curl -X POST -H 'Content-Type: application/json' \
66
- -d '{"messages": [{"role": "assistant"}, {"content": [{"file": {}, "type": "file"}], "role": "user"}]}' \
70
+ -d '{"messages": [{"content": [{"file": {}, "type": "file"}], "role": "user"}]}' \
71
http://localhost:8000/tokenize
72
73
curl -X POST -H 'Content-Type: application/json' \
70
- -d '{"messages": [{"content": [{"file": {}, "type": "file"}], "role": "user"}]}' \
71
- http://localhost:8000/tokenize
74
+ -d '{"messages": [{"role": "assistant", "tool_calls": [{"custom": {"input": "", "name": ""}, "id": "", "type": "custom"}]}]}' \
75
+ http://localhost:8000/v1/chat/completions
76
""" # noqa: E501
73
- if (op.method.lower() == "post" and op.path == "/tokenize"
74
- and hasattr(case, "body") and isinstance(case.body, dict)
77
+ if (hasattr(case, "body") and isinstance(case.body, dict)
78
and "messages" in case.body
79
and isinstance(case.body["messages"], list)
80
and len(case.body["messages"]) > 0):
81
+
82
for message in case.body["messages"]:
83
if not isinstance(message, dict):
84
continue
81
- content = message.get("content", [])
82
- if not isinstance(content, list) or len(content) == 0:
83
- continue
84
- if any(item.get("type") == "file" for item in content):
85
- return False
85
+
86
+ # Check for invalid file type in tokenize endpoint
87
+ if op.method.lower() == "post" and op.path == "/tokenize":
88
+ content = message.get("content", [])
89
+ if (isinstance(content, list) and len(content) > 0 and any(
90
+ item.get("type") == "file" for item in content)):
91
+ return False
92
+
93
+ # Check for invalid tool_calls with non-function types
94
+ tool_calls = message.get("tool_calls", [])
95
+ if isinstance(tool_calls, list):
96
+ for tool_call in tool_calls:
97
+ if isinstance(tool_call, dict):
98
+ if tool_call.get("type") != "function":
99
+ return False
100
+ if "custom" in tool_call:
101
+ return False
102
return True
103
88
- return strategy.filter(no_file_type)
104
+ return strategy.filter(no_invalid_types)
105
106
107
@schema.parametrize()