mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-06 04:23:40 +00:00
fix: streaming container_id and consistent Pydantic types in output
- Populate container_id on streaming code_interpreter_results by re-emitting at message_delta when container info arrives - Reconstruct Pydantic OutputCodeInterpreterCall objects from plain dicts in _extract_tool_result_output_items so responses_output has uniform types across streaming and non-streaming paths
This commit is contained in:
@@ -546,6 +546,7 @@ class ModelResponseIterator:
|
||||
self._server_tool_inputs: Dict[str, Any] = {}
|
||||
self.tool_results: List[Dict[str, Any]] = []
|
||||
self._current_server_tool_id: Optional[str] = None
|
||||
self._container_id: Optional[str] = None
|
||||
|
||||
def check_empty_tool_call_args(self) -> bool:
|
||||
"""
|
||||
@@ -726,7 +727,7 @@ class ModelResponseIterator:
|
||||
type="code_interpreter_call",
|
||||
id=call_id,
|
||||
code=code,
|
||||
container_id=None,
|
||||
container_id=self._container_id,
|
||||
status="completed",
|
||||
outputs=log_outputs,
|
||||
)
|
||||
@@ -928,6 +929,17 @@ class ModelResponseIterator:
|
||||
finish_reason, usage, container = self._handle_message_delta(chunk)
|
||||
if container:
|
||||
provider_specific_fields["container"] = container
|
||||
# Store container_id and re-emit code_interpreter_results
|
||||
# so stream_chunk_builder's last-value-wins picks up the
|
||||
# version with container_id populated.
|
||||
container_id = (
|
||||
container.get("id") if isinstance(container, dict) else None
|
||||
)
|
||||
if container_id and self.tool_results:
|
||||
self._container_id = container_id
|
||||
provider_specific_fields["code_interpreter_results"] = (
|
||||
self._build_code_interpreter_results()
|
||||
)
|
||||
elif type_chunk == "message_start":
|
||||
"""
|
||||
Anthropic
|
||||
|
||||
@@ -1738,10 +1738,7 @@ class LiteLLMCompletionResponsesConfig:
|
||||
)
|
||||
)
|
||||
if tool_result_items:
|
||||
result_by_id = {
|
||||
(item.get("id") if isinstance(item, dict) else item.id): item
|
||||
for item in tool_result_items
|
||||
}
|
||||
result_by_id = {item.id: item for item in tool_result_items}
|
||||
replaced_ids = set(result_by_id.keys())
|
||||
responses_output = [
|
||||
(
|
||||
@@ -1778,7 +1775,14 @@ class LiteLLMCompletionResponsesConfig:
|
||||
continue
|
||||
results = psf.get("code_interpreter_results")
|
||||
if results and isinstance(results, list):
|
||||
output_items.extend(results)
|
||||
for item in results:
|
||||
# In the streaming path, items are plain dicts after
|
||||
# model_dump() in stream_chunk_builder. Reconstruct
|
||||
# Pydantic objects so responses_output has a uniform type.
|
||||
if isinstance(item, dict):
|
||||
output_items.append(OutputCodeInterpreterCall(**item))
|
||||
else:
|
||||
output_items.append(item)
|
||||
return output_items
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -58,7 +58,8 @@ def test_extract_tool_result_output_items_from_pydantic_objects():
|
||||
|
||||
|
||||
def test_extract_tool_result_output_items_from_dicts():
|
||||
"""Streaming path: after model_dump(), code_interpreter_results are plain dicts."""
|
||||
"""Streaming path: after model_dump(), code_interpreter_results are plain dicts.
|
||||
_extract_tool_result_output_items reconstructs them as Pydantic objects."""
|
||||
items = [
|
||||
{
|
||||
"type": "code_interpreter_call",
|
||||
@@ -72,7 +73,8 @@ def test_extract_tool_result_output_items_from_dicts():
|
||||
resp = _make_model_response(code_interpreter_results=items)
|
||||
result = LiteLLMCompletionResponsesConfig._extract_tool_result_output_items(resp)
|
||||
assert len(result) == 1
|
||||
assert result[0]["id"] == "srvtoolu_01AAA"
|
||||
assert isinstance(result[0], OutputCodeInterpreterCall)
|
||||
assert result[0].id == "srvtoolu_01AAA"
|
||||
|
||||
|
||||
def test_extract_tool_result_output_items_empty():
|
||||
@@ -258,8 +260,9 @@ def test_end_to_end_streaming_chunks_to_code_interpreter_output():
|
||||
)
|
||||
assert len(tool_result_items) == 1
|
||||
item = tool_result_items[0]
|
||||
# Items are dicts after the model_dump path
|
||||
assert item["type"] == "code_interpreter_call"
|
||||
assert item["id"] == "srvtoolu_01AAA"
|
||||
assert item["code"] == "echo e2e_test"
|
||||
assert item["outputs"][0]["logs"] == "e2e_test\n"
|
||||
# Items are reconstructed as Pydantic OutputCodeInterpreterCall objects
|
||||
assert isinstance(item, OutputCodeInterpreterCall)
|
||||
assert item.type == "code_interpreter_call"
|
||||
assert item.id == "srvtoolu_01AAA"
|
||||
assert item.code == "echo e2e_test"
|
||||
assert item.outputs[0].logs == "e2e_test\n"
|
||||
|
||||
Reference in New Issue
Block a user