Repository navigation
Description
Bug Description
When using the Responses API (e.g., via Azure gpt-5.1-codex-mini through LiteLLM proxy), the response.completed streaming event always returns finish_reason='stop', even when the response contains function_call items in its output. This causes agents and clients that rely on finish_reason='tool_calls' to determine if tools need to be executed to incorrectly conclude the stream ended without any pending tool calls.
Environment
- LiteLLM Version: Versions after 1.80.8-stable.1
- Model: Azure gpt-5.1-codex-mini (any model using Responses API with tool calling)
- Setup: LiteLLM proxy with custom provider (e.g., OpenCode)
Steps to Reproduce
- Configure LiteLLM proxy to route to an Azure OpenAI deployment using the Responses API
- Send a request with tools defined that triggers the model to make a function call
- Observe the streaming events
Expected Behavior
When the model decides to call a tool, the final response.completed event should return finish_reason='tool_calls' to signal the client that tools need to be executed.
Actual Behavior
The response.completed event always returns finish_reason='stop', regardless of whether the response contains function calls.
Server Log Example
23:12:38 - LiteLLM:DEBUG: transformation.py:238 - Raw OpenAI Chunk={
'type': 'response.completed',
'sequence_number': 26,
'response': {
'id': 'resp_...',
'status': 'completed',
'output': [
{
'type': 'function_call',
'id': 'call_abc123',
'name': 'read_file',
'arguments': '{"path": "/tmp/test.py"}',
'status': 'completed'
}
],
...
}
}
Despite the response containing a function_call in output, the transformation returns finish_reason='stop'.
Impact
This breaks tool/function calling workflows for agents like OpenCode when using newer LiteLLM versions (after 1.80.8). The agent:
- Receives the tool call events correctly
- Receives
finish_reason='stop'fromresponse.completed - Concludes the stream ended normally without tools to execute
- Stops waiting for more input, leaving the tool call unexecuted
Users must repeatedly prompt the model to get it to respond, as the agent doesn't recognize it needs to execute the pending tool call.
Root Cause
In litellm/completion_extras/litellm_responses_transformation/transformation.py, the response.completed handler unconditionally returns finish_reason='stop':
elif event_type == "response.completed":
return ModelResponseStream(
choices=[
StreamingChoices(
index=0,
delta=Delta(content=""),
finish_reason="stop", # BUG: Should check for function_call items
)
]
)Suggested Fix
Inspect the response.output field in the response.completed event to determine the correct finish_reason:
- Return
'tool_calls'when output containsfunction_callitems - Return
'stop'otherwise
Activity
[-]response.completed always returns finish_reason='stop' even when response contains tool calls[/-][+][Bug] - response.completed always returns finish_reason='stop' even when response contains tool calls[/+]tkyggit commentedon Feb 5, 2026
It’s great.
I look forward to the release where this code is merged.
I was also having trouble because it wouldn't work at all when going from opencode through litellm. I encountered what seemed to be the same issue with Azure OpenAI and Ollama GPT-OSS.
anuragxxd commentedon Feb 12, 2026
I’m seeing the same problem. Looking forward to getting this merged.
mWozDev commentedon Feb 14, 2026
@krrishdholakia can the associated PR be merged? this issue is also prevalent for multiple users I know as well that have been affected
JosXa commentedon Feb 17, 2026
We just installedv1.81.13(which, from what I can tell, should include #19745) and there was zero improvement:@felixti is that the right release?
Edit: Ah, apparently not. Eagerly waiting for the release here @krrishdholakia :)
fix(completion): unify finish_reason mapping to OpenAI-compatible values
fix(completion): unify finish_reason mapping to OpenAI-compatible values
kavolorn commentedon Sep 1, 2026
Looks like issue still exists. I cannot use DeepSeek V4 (both Flash and Pro) with Ollama.
I'm defining my Ollama model like that:
This response I get:
{ "id": "f62f763b-d2fc-4c1f-ab47-088d268a1ffd", "model": "deepseek-v4-flash:0731", "usage": { "total_tokens": 12963, "prompt_tokens": 12879, "completion_tokens": 84, "prompt_tokens_details": null, "completion_tokens_details": { "text_tokens": null, "audio_tokens": null, "image_tokens": null, "video_tokens": null, "reasoning_tokens": 42, "accepted_prediction_tokens": null, "rejected_prediction_tokens": null } }, "object": "chat.completion", "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "6f890a8f-23b9-4aa4-929c-3d2b2fba5d7f", "type": "function", "function": { "name": "terminal", "arguments": "{\"command\": \"date\"}" } } ], "function_call": null, "reasoning_content": "The user asks for the current datetime. I have system info: Today's Date: 2026-09-01. But I should give the actual current datetime. Let me check viaterminal." }, "finish_reason": "stop" } ], "created": 1788230116, "system_fingerprint": null }Finish reason forces agent to stop turns.