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 5, 07:15 UTC
[Frontend] Supports resubmitting output items with missing fields in Responses API (#41355)
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Chauncey committed
May 6, 2026 at 10:21 UTC
c7aa186d67b6f051680831418e957c67f34ba7a2
1 file changed
+60
-10
vllm/entrypoints/openai/responses/protocol.py
+60
-10
@@ -23,7 +23,9 @@ from openai.types.responses import (
23
ResponseOutputItem,
24
ResponseOutputItemAddedEvent,
25
ResponseOutputItemDoneEvent,
26
+ ResponseOutputMessage,
27
ResponsePrompt,
28
+ ResponseReasoningItem,
29
ResponseReasoningTextDeltaEvent,
30
ResponseReasoningTextDoneEvent,
31
ResponseStatus,
@@ -451,18 +453,21 @@ class ResponsesRequest(OpenAIBaseModel):
453
454
@model_validator(mode="before")
455
@classmethod
454
- def function_call_parsing(cls, data):
455
- """Parse function_call dictionaries into ResponseFunctionToolCall objects.
456
- This ensures Pydantic can properly resolve union types in the input field.
457
- Function calls provided as dicts are converted to ResponseFunctionToolCall
458
- objects before validation, while invalid structures are left for Pydantic
459
- to reject with appropriate error messages.
460
- """
456
+ def input_item_parsing(cls, data):
457
+ """Parse input items that are missing required fields or that Pydantic
458
+ cannot disambiguate in a Union of TypedDict / BaseModel types.
459
+
460
+ Specifically handles:
461
+ - function_call -> ResponseFunctionToolCall
462
+ - reasoning -> ResponseReasoningItem (auto-generates id)
463
+ - message(role=assistant) -> ResponseOutputMessage (auto-generates
464
+ id/status and annotations)
465
466
+ Invalid structures are left for Pydantic to reject.
467
+ """
468
input_data = data.get("input")
469
470
# Early return for None, strings, or bytes
465
- # (strings are iterable but shouldn't be processed)
471
if input_data is None or isinstance(input_data, (str, bytes)):
472
return data
473
@@ -476,16 +481,61 @@ class ResponsesRequest(OpenAIBaseModel):
481
482
processed_input = []
483
for item in input_data:
479
- if isinstance(item, dict) and item.get("type") == "function_call":
484
+ if not isinstance(item, dict):
485
+ processed_input.append(item)
486
+ continue
487
+
488
+ item_type = item.get("type")
489
+
490
+ if item_type == "function_call":
491
try:
492
processed_input.append(ResponseFunctionToolCall(**item))
493
except ValidationError:
483
- # Let Pydantic handle validation for malformed function calls
494
logger.debug(
495
"Failed to parse function_call to ResponseFunctionToolCall, "
496
"leaving for Pydantic validation"
497
)
498
processed_input.append(item)
499
+
500
+ elif item_type == "reasoning":
501
+ if "id" not in item:
502
+ item = {**item, "id": f"rs_{random_uuid()}"}
503
+ try:
504
+ processed_input.append(ResponseReasoningItem(**item))
505
+ except ValidationError:
506
+ logger.debug(
507
+ "Failed to parse reasoning to ResponseReasoningItem, "
508
+ "leaving for Pydantic validation"
509
+ )
510
+ processed_input.append(item)
511
+
512
+ elif item_type == "message" and item.get("role") == "assistant":
513
+ item = dict(item)
514
+ if "id" not in item:
515
+ item["id"] = f"msg_{random_uuid()}"
516
+ if "status" not in item:
517
+ item["status"] = "completed"
518
+ # ResponseOutputText requires annotations
519
+ if isinstance(item.get("content"), list):
520
+ new_content = []
521
+ for c in item["content"]:
522
+ if (
523
+ isinstance(c, dict)
524
+ and c.get("type") == "output_text"
525
+ and "annotations" not in c
526
+ ):
527
+ c = {**c, "annotations": []}
528
+ new_content.append(c)
529
+ item["content"] = new_content
530
+ try:
531
+ processed_input.append(ResponseOutputMessage(**item))
532
+ except ValidationError:
533
+ logger.debug(
534
+ "Failed to parse assistant message to ResponseOutputMessage, "
535
+ "leaving for Pydantic validation"
536
+ )
537
+ processed_input.append(item)
538
+
539
else:
540
processed_input.append(item)
541