@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 3ee202ea1e
Fork 0

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

[GPT-OSS] Add support for arrays at tool message content (#25593)

Signed-off-by: Luis Tomas Bolivar <ltomasbo@redhat.com>

Luis Tomas Bolivar committed Oct 10, 2025 at 11:00 UTC 3ee202ea1e0f8a1b5a4f51d2746af97a1ad10139
2 files changed +139
tests/entrypoints/openai/test_serving_chat.py
+132
@@ -207,6 +207,138 @@ async def test_gpt_oss_multi_turn_chat(gptoss_client: OpenAI, with_tool_parser:
207 )
208
209
210 +@pytest.mark.asyncio
211 +async def test_gpt_oss_tool_message_array_content(gptoss_client: OpenAI,
212 + with_tool_parser: bool):
213 + """Test that tool messages support both string and array content formats."""
214 + if not with_tool_parser:
215 + pytest.skip("skip non-tool for array content tests")
216 +
217 + tools = [{
218 + "type": "function",
219 + "function": {
220 + "name": "get_weather",
221 + "description": "Get the current weather in a given location",
222 + "parameters": {
223 + "type": "object",
224 + "properties": {
225 + "city": {
226 + "type": "string"
227 + },
228 + "state": {
229 + "type": "string"
230 + },
231 + },
232 + "required": ["city", "state"],
233 + },
234 + },
235 + }]
236 +
237 + # Test 1: Tool message with string content
238 + messages_string = [{
239 + "role": "user",
240 + "content": "What's the weather in Paris?"
241 + }, {
242 + "role":
243 + "assistant",
244 + "tool_calls": [{
245 + "id": "call_123",
246 + "type": "function",
247 + "function": {
248 + "name": "get_weather",
249 + "arguments": '{"city": "Paris", "state": "TX"}'
250 + }
251 + }]
252 + }, {
253 + "role": "tool",
254 + "content": "The weather in Paris, TX is sunny, 22°C"
255 + }]
256 +
257 + response_string = await gptoss_client.chat.completions.create(
258 + model=GPT_OSS_MODEL_NAME,
259 + messages=messages_string,
260 + tools=tools,
261 + temperature=0.0,
262 + )
263 +
264 + assert response_string is not None
265 + assert response_string.choices[0].message is not None
266 +
267 + # Test 2: Tool message with array content
268 + messages_array = [{
269 + "role": "user",
270 + "content": "What's the weather in Dallas?"
271 + }, {
272 + "role":
273 + "assistant",
274 + "tool_calls": [{
275 + "id": "call_456",
276 + "type": "function",
277 + "function": {
278 + "name": "get_weather",
279 + "arguments": '{"city": "Dallas", "state": "TX"}'
280 + }
281 + }]
282 + }, {
283 + "role":
284 + "tool",
285 + "content": [{
286 + "type": "text",
287 + "text": "f2e897a7-2705-4337-8193-2a8f57b81618"
288 + }]
289 + }]
290 +
291 + response_array = await gptoss_client.chat.completions.create(
292 + model=GPT_OSS_MODEL_NAME,
293 + messages=messages_array,
294 + tools=tools,
295 + temperature=0.0,
296 + )
297 +
298 + assert response_array is not None
299 + assert response_array.choices[0].message is not None
300 +
301 + # Test 3: Tool message with multiple array content items
302 + messages_multi_array = [{
303 + "role": "user",
304 + "content": "Search for information"
305 + }, {
306 + "role":
307 + "assistant",
308 + "tool_calls": [{
309 + "id": "call_789",
310 + "type": "function",
311 + "function": {
312 + "name": "get_weather",
313 + "arguments": '{"city": "Austin", "state": "TX"}'
314 + }
315 + }]
316 + }, {
317 + "role":
318 + "tool",
319 + "content": [{
320 + "type": "text",
321 + "text": "Weather data: "
322 + }, {
323 + "type": "text",
324 + "text": "Austin, TX - Partly cloudy, 25°C"
325 + }, {
326 + "type": "text",
327 + "text": " with 60% humidity"
328 + }]
329 + }]
330 +
331 + response_multi_array = await gptoss_client.chat.completions.create(
332 + model=GPT_OSS_MODEL_NAME,
333 + messages=messages_multi_array,
334 + tools=tools,
335 + temperature=0.0,
336 + )
337 +
338 + assert response_multi_array is not None
339 + assert response_multi_array.choices[0].message is not None
340 +
341 +
342 MODEL_NAME = "openai-community/gpt2"
343 MODEL_NAME_SHORT = "gpt2"
344 CHAT_TEMPLATE = "Dummy chat template for testing {}"
vllm/entrypoints/harmony_utils.py
+7
@@ -256,6 +256,13 @@ def parse_chat_input(chat_msg) -> list[Message]:
256 if role == "tool":
257 name = chat_msg.get("name", "")
258 content = chat_msg.get("content", "") or ""
259 + if isinstance(content, list):
260 + # Handle array format for tool message content
261 + # by concatenating all text parts.
262 + content = "".join(
263 + item.get("text", "") for item in content
264 + if isinstance(item, dict) and item.get("type") == "text")
265 +
266 msg = Message.from_author_and_content(
267 Author.new(Role.TOOL, f"functions.{name}"), content
268 ).with_channel("commentary")