Repository: BerriAI/litellm

Issue:
[Bug]: openai conversion from responses to completions returns empty chunks
### What happened?

Conversion from responses to completions failing to preserve function name and generating empty chunks.


I'll submit a PR shortly which fixes this.


### Relevant log output

When using the chat completions API with OpenAI configured as a provider and the gpt-5.1-codex model I noticed the following in the logs...

```text
3:53:07 - LiteLLM:DEBUG: transformation.py:735 - Chat provider: Unhandled event type 'ResponsesAPIStreamEvents.OUTPUT_ITEM_ADDED', creating empty chunk
```

Further to this, when using native function calling, the conversion is missing the function name...
```text
        "tool_calls": [
          {
            "id": "call_Pf4aqfmsR9MsusGoby2Uatmi",
            "type": "function",
            "function": {
              "name": "",
              "arguments": "{\"result\”:\”...snip...\”}”
            }
          }
        ]
```

converted to...

```text
data: {"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"fc_03371b909217388b00691e4f189304819a931bb734cede12a8","type":"function_call","status":"in_progress","arguments":"","call_id":"call_Pf4aqfmsR9MsusGoby2Uatmi","name":"attempt_completion"}}
```

### Are you a ML Ops Team?

Yes

### What LiteLLM version are you on ?

v1.79.3

### Twitter / LinkedIn details

https://www.linkedin.com/in/nigelkukard

Discussion:

Fix (patch):
diff --git a/litellm/completion_extras/litellm_responses_transformation/transformation.py b/litellm/completion_extras/litellm_responses_transformation/transformation.py
index 54d32fe34668..588fdd66350d 100644
--- a/litellm/completion_extras/litellm_responses_transformation/transformation.py
+++ b/litellm/completion_extras/litellm_responses_transformation/transformation.py
@@ -30,6 +30,7 @@
     ChatCompletionToolParamFunctionChunk,
     Reasoning,
     ResponsesAPIOptionalRequestParams,
+    ResponsesAPIStreamEvents,
 )
 
 if TYPE_CHECKING:
@@ -652,6 +653,8 @@ def chunk_parser(
 
         # Handle different event types from responses API
         event_type = parsed_chunk.get("type")
+        if isinstance(event_type, ResponsesAPIStreamEvents):
+            event_type = event_type.value
         verbose_logger.debug(f"Chat provider: Processing event type: {event_type}")
 
         if event_type == "response.created":
@@ -671,7 +674,7 @@ def chunk_parser(
                         index=0,
                         type="function",
                         function=ChatCompletionToolCallFunctionChunk(
-                            name=parsed_chunk.get("name", None),
+                            name=output_item.get("name", None),
                             arguments=parsed_chunk.get("arguments", ""),
                         ),
                     ),
@@ -717,7 +720,7 @@ def chunk_parser(
                         index=0,
                         type="function",
                         function=ChatCompletionToolCallFunctionChunk(
-                            name=parsed_chunk.get("name", None),
+                            name=output_item.get("name", None),
                             arguments="",  # responses API sends everything again, we don't
                         ),
                     ),


Test changes:
diff --git a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py
index 1b3bc5a92efa..e9c71ef43c47 100644
--- a/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py
+++ b/tests/test_litellm/completion_extras/litellm_responses_transformation/test_completion_extras_litellm_responses_transformation_transformation.py
@@ -86,6 +86,73 @@ def test_openai_responses_chunk_parser_reasoning_summary():
     assert delta.function_call is None
 
 
+def test_chunk_parser_string_output_text_delta_produces_text():
+    from litellm.completion_extras.litellm_responses_transformation.transformation import (
+        OpenAiResponsesToChatCompletionStreamIterator,
+    )
+
+    iterator = OpenAiResponsesToChatCompletionStreamIterator(
+        streaming_response=None, sync_stream=True
+    )
+
+    chunk = {"type": "response.output_text.delta", "delta": "literal text"}
+
+    result = iterator.chunk_parser(chunk)
+
+    assert result["text"] == "literal text"
+    assert result.get("tool_use") is None
+    assert result.get("finish_reason") == ""
+    assert not result.get("is_finished")
+
+
+def test_chunk_parser_enum_output_text_delta_produces_text():
+    from litellm.completion_extras.litellm_responses_transformation.transformation import (
+        OpenAiResponsesToChatCompletionStreamIterator,
+    )
+    from litellm.types.llms.openai import ResponsesAPIStreamEvents
+
+    iterator = OpenAiResponsesToChatCompletionStreamIterator(
+        streaming_response=None, sync_stream=True
+    )
+
+    chunk = {"type": ResponsesAPIStreamEvents.OUTPUT_TEXT_DELTA, "delta": "enum text"}
+
+    result = iterator.chunk_parser(chunk)
+
+    assert result["text"] == "enum text"
+    assert result.get("tool_use") is None
+    assert result.get("finish_reason") == ""
+    assert not result.get("is_finished")
+
+
+def test_chunk_parser_function_call_added_produces_tool_use():
+    from litellm.completion_extras.litellm_responses_transformation.transformation import (
+        OpenAiResponsesToChatCompletionStreamIterator,
+    )
+    from litellm.types.llms.openai import ResponsesAPIStreamEvents
+
+    iterator = OpenAiResponsesToChatCompletionStreamIterator(
+        streaming_response=None, sync_stream=True
+    )
+
+    chunk = {
+        "type": ResponsesAPIStreamEvents.OUTPUT_ITEM_ADDED,
+        "arguments": '{"key": "value"}',
+        "item": {"type": "function_call", "name": "fn", "call_id": "call-42"},
+    }
+
+    result = iterator.chunk_parser(chunk)
+
+    tool_use = result["tool_use"]
+    assert tool_use is not None
+    assert tool_use["id"] == "call-42"
+    assert tool_use["type"] == "function"
+    assert tool_use["function"]["name"] == "fn"
+    assert tool_use["function"]["arguments"] == '{"key": "value"}'
+    assert result.get("finish_reason") == ""
+    assert not result.get("is_finished")
+
+
 def test_transform_response_with_reasoning_and_output():
     """Test transform_response handles ResponsesAPIResponse with reasoning items and output messages."""
     from unittest.mock import Mock