@@ -18,6 +18,9 @@ def get_response_input_items(response: Response) -> List[ResponseInputItemParam]
1818 consecutive pair when building the ``input`` for the next turn. Filtering
1919 out reasoning items (or re-ordering them) causes a 400 error from the API.
2020
21+ SDK-only fields (e.g. ``parsed`` from ``ParsedResponseOutputText``) are
22+ excluded so the returned dicts conform to ``ResponseInputItemParam``.
23+
2124 Example usage::
2225
2326 from openai.lib import get_response_input_items
@@ -35,17 +38,29 @@ def get_response_input_items(response: Response) -> List[ResponseInputItemParam]
3538 """
3639 items : List [ResponseInputItemParam ] = []
3740 for output_item in response .output :
38- items .append (output_item .model_dump (exclude_unset = True )) # type: ignore[arg-type]
41+ data = output_item .model_dump (
42+ exclude_unset = True ,
43+ exclude = getattr (output_item , "__api_exclude__" , None ),
44+ )
45+ # Strip SDK-only fields from nested content items
46+ # (e.g. ParsedResponseOutputText.parsed is not part of the API schema)
47+ for content_item in data .get ("content" , []):
48+ if isinstance (content_item , dict ):
49+ content_item .pop ("parsed" , None )
50+ items .append (data ) # type: ignore[arg-type]
3951 return items
4052
4153
4254def validate_response_input (items : Sequence [Union [ResponseInputItemParam , object ]]) -> None :
43- """Validate that reasoning+message pairs are not orphaned in an input list.
55+ """Validate that reasoning+message pairs are intact in an input list.
56+
57+ Walks ``items`` and raises ``ValueError`` when it detects a ``reasoning``-type
58+ item that is NOT immediately followed by a ``message``-type item with
59+ role=assistant — the classic broken-pair pattern that causes a 400 from the
60+ API.
4461
45- Walks ``items`` and raises ``ValueError`` when it detects a ``message``-type
46- item (role=assistant) that is NOT immediately preceded by a ``reasoning``-type
47- item, but where a ``reasoning`` item exists elsewhere in the list — the classic
48- orphaning pattern that causes a 400 from the API.
62+ Standalone assistant messages (those not part of a reasoning pair) are allowed
63+ and will not trigger a validation error.
4964
5065 This validator is a standalone opt-in helper. The primary recommendation is
5166 to build the input list with :func:`get_response_input_items` instead of
@@ -59,37 +74,30 @@ def validate_response_input(items: Sequence[Union[ResponseInputItemParam, object
5974
6075 from openai.lib import validate_response_input
6176
62- validate_response_input(conversation) # raises ValueError if orphaned
77+ validate_response_input(conversation) # raises ValueError if broken pair
6378 response = client.responses.create(model="o3", input=conversation)
6479 """
65- has_reasoning = any (_item_type (item ) == "reasoning" for item in items )
66- if not has_reasoning :
67- # No reasoning items at all — nothing to validate.
68- return
69-
7080 for i , item in enumerate (items ):
71- if _item_type (item ) != "message " :
81+ if _item_type (item ) != "reasoning " :
7282 continue
73- role = _item_role (item )
74- if role != "assistant" :
75- continue
76- # This is an assistant message. It must be immediately preceded by a
77- # reasoning item when reasoning items exist in the list.
78- preceded_by_reasoning = i > 0 and _item_type (items [i - 1 ]) == "reasoning"
79- if not preceded_by_reasoning :
80- item_id = _item_id (item )
81- id_hint = f" (id={ item_id !r} )" if item_id else ""
82- raise ValueError (
83- f"Orphaned assistant message{ id_hint } detected: a 'message' item with "
84- f"role='assistant' must be immediately preceded by its paired 'reasoning' "
85- f"item when reasoning items are present in the input. "
86- f"The OpenAI Responses API requires that reasoning and the immediately "
87- f"following assistant message are always passed together as a consecutive "
88- f"pair. Either include the paired reasoning item directly before this "
89- f"message, use 'previous_response_id' to let the API manage context, or "
90- f"build the input list with get_response_input_items() which preserves "
91- f"pairs automatically."
92- )
83+ # Each reasoning item must be immediately followed by an assistant message.
84+ next_idx = i + 1
85+ if next_idx < len (items ):
86+ next_item = items [next_idx ]
87+ if _item_type (next_item ) == "message" and _item_role (next_item ) == "assistant" :
88+ continue
89+ item_id = _item_id (item )
90+ id_hint = f" (id={ item_id !r} )" if item_id else ""
91+ raise ValueError (
92+ f"Orphaned reasoning item{ id_hint } detected: a 'reasoning' item "
93+ f"must be immediately followed by its paired 'message' item with "
94+ f"role='assistant'. The OpenAI Responses API requires that reasoning "
95+ f"and the immediately following assistant message are always passed "
96+ f"together as a consecutive pair. Either include the paired assistant "
97+ f"message directly after this reasoning item, or remove the reasoning "
98+ f"item. Use get_response_input_items() to build input lists that "
99+ f"preserve pairs automatically."
100+ )
93101
94102
95103def _item_type (item : object ) -> str :
0 commit comments