@@ -590,6 +590,13 @@ def _convert_response_to_chat_message(responses: Response | ParsedResponse) -> C
590590 extra = output .to_dict ()
591591 # we dont need the summary in the extra
592592 extra .pop ("summary" )
593+ if output .content :
594+ logger .warning (
595+ "OpenAI returned a non-empty 'content' field on a reasoning item ({_id}). "
596+ "The content is preserved in ReasoningContent.extra['content'] but is NOT "
597+ "reflected in ReasoningContent.reasoning_text." ,
598+ _id = output .id ,
599+ )
593600 reasoning_text = "\n " .join ([summary .text for summary in summaries if summaries ])
594601 reasoning = ReasoningContent (reasoning_text = reasoning_text , extra = extra )
595602
@@ -675,6 +682,15 @@ def _convert_response_chunk_to_streaming_chunk( # noqa: PLR0911
675682 # event falls through to the generic default and reasoning=None, so encrypted_content
676683 # is never available for multi-turn conversations.
677684 if chunk .item .type == "reasoning" :
685+ if chunk .item .content :
686+ logger .warning (
687+ "OpenAI returned a non-empty 'content' field on a reasoning item ({_id}). "
688+ "This field is currently undocumented and was never observed in practice. "
689+ "The content is preserved in ReasoningContent.extra['content'] but is NOT "
690+ "reflected in ReasoningContent.reasoning_text. Please report this at "
691+ "https://github.com/deepset-ai/haystack/issues so we can update the mapping." ,
692+ _id = chunk .item .id ,
693+ )
678694 reasoning = ReasoningContent (reasoning_text = "" , extra = chunk .item .to_dict ())
679695 return StreamingChunk (
680696 content = "" ,
@@ -927,7 +943,15 @@ def convert_part(part: Any) -> dict[str, str | None]:
927943 if reasonings :
928944 formatted_reasonings = []
929945 for reasoning in reasonings :
930- reasoning_item = {"summary" : [], ** (reasoning .extra )}
946+ # Streaming events (e.g. response.reasoning_summary_text.delta) store event-level
947+ # fields like item_id, output_index, summary_index, event_id, sequence_number into
948+ # reasoning.extra. Those are not valid reasoning input item fields and the API
949+ # rejects them with "Unknown parameter" when sent back in subsequent turns.
950+ # Valid fields per ResponseReasoningItem schema: id, type, summary (handled separately),
951+ # content, encrypted_content, status.
952+ _valid_reasoning_fields = {"id" , "type" , "encrypted_content" , "status" , "content" }
953+ filtered_extra = {k : v for k , v in reasoning .extra .items () if k in _valid_reasoning_fields }
954+ reasoning_item = {"summary" : [], ** filtered_extra }
931955 if reasoning .reasoning_text :
932956 reasoning_item ["summary" ] = [{"text" : reasoning .reasoning_text , "type" : "summary_text" }]
933957 formatted_reasonings .append (reasoning_item )
0 commit comments