mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-23 05:34:41 +00:00
Merge aecc81d228 into 82ca10cc2d
This commit is contained in:
commit
ee817f2383
2 changed files with 79 additions and 6 deletions
|
|
@ -166,6 +166,31 @@ def adapt_messages_to_generic_oci_standard_tool_response(role: str, tool_call_id
|
|||
)
|
||||
|
||||
|
||||
def normalize_tool_result_content(content: object) -> str:
|
||||
"""Convert OpenAI text content parts to the string required by OCI."""
|
||||
if isinstance(content, str):
|
||||
return content
|
||||
if not isinstance(content, list):
|
||||
raise OCIError(
|
||||
status_code=400,
|
||||
message="Tool result message `content` must be a string or list of text parts",
|
||||
)
|
||||
|
||||
for content_item in content:
|
||||
if not isinstance(content_item, dict) or content_item.get("type") not in ("text", "input_text"):
|
||||
raise OCIError(
|
||||
status_code=400,
|
||||
message="Tool result content must contain only text parts",
|
||||
)
|
||||
if not isinstance(content_item.get("text"), str):
|
||||
raise OCIError(
|
||||
status_code=400,
|
||||
message="Tool result text content must have a string `text` field",
|
||||
)
|
||||
|
||||
return "\n".join(content_item["text"] for content_item in content)
|
||||
|
||||
|
||||
def adapt_messages_to_generic_oci_standard(
|
||||
messages: list[AllMessageValues],
|
||||
) -> list[OCIMessage]:
|
||||
|
|
@ -196,12 +221,13 @@ def adapt_messages_to_generic_oci_standard(
|
|||
status_code=400,
|
||||
message="Tool result message must have a string `tool_call_id`",
|
||||
)
|
||||
if not isinstance(content, str):
|
||||
raise OCIError(
|
||||
status_code=400,
|
||||
message="Tool result message `content` must be a string",
|
||||
new_messages.append(
|
||||
adapt_messages_to_generic_oci_standard_tool_response(
|
||||
role,
|
||||
tool_call_id,
|
||||
normalize_tool_result_content(content),
|
||||
)
|
||||
new_messages.append(adapt_messages_to_generic_oci_standard_tool_response(role, tool_call_id, content))
|
||||
)
|
||||
|
||||
return new_messages
|
||||
|
||||
|
|
@ -431,6 +457,7 @@ def handle_generic_stream_chunk(dict_chunk: dict) -> ModelResponseStream:
|
|||
StreamingChoices(
|
||||
index=typed_chunk.index,
|
||||
delta=Delta(
|
||||
role="assistant",
|
||||
content=text,
|
||||
tool_calls=tool_calls,
|
||||
provider_specific_fields=None,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
Unit tests for litellm/llms/oci/chat/generic.py — error paths and stream handling.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from typing import Final
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from litellm import ModelResponse
|
||||
from litellm.llms.oci.chat.generic import (
|
||||
|
|
@ -22,6 +23,7 @@ from litellm.llms.oci.chat.transformation import (
|
|||
_model_uses_max_completion_tokens,
|
||||
)
|
||||
from litellm.llms.oci.common_utils import OCIError
|
||||
from litellm.types.llms.oci import OCIMessage, OCITextContentPart
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# adapt_messages_to_generic_oci_standard_content_message — error paths
|
||||
|
|
@ -158,6 +160,49 @@ class TestGenericToolCallErrors:
|
|||
|
||||
|
||||
class TestGenericMessageAdaptation:
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
[
|
||||
("plain result", "plain result"),
|
||||
([], ""),
|
||||
([{"type": "text", "text": "first"}], "first"),
|
||||
([{"type": "input_text", "text": "second"}], "second"),
|
||||
(
|
||||
[{"type": "text", "text": "first"}, {"type": "input_text", "text": "second"}],
|
||||
"first\nsecond",
|
||||
),
|
||||
([{"type": "text", "text": ""}, {"type": "text", "text": "last"}], "\nlast"),
|
||||
],
|
||||
)
|
||||
def test_tool_result_preserves_call_id_and_normalizes_text(self, content: object, expected: str) -> None:
|
||||
result: Final = adapt_messages_to_generic_oci_standard(
|
||||
[{"role": "tool", "tool_call_id": "call_mcp", "content": content}]
|
||||
)
|
||||
|
||||
assert result == [OCIMessage(role="TOOL", content=[OCITextContentPart(text=expected)], toolCallId="call_mcp")]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, error",
|
||||
[
|
||||
(None, "must be a string or list of text parts"),
|
||||
(42, "must be a string or list of text parts"),
|
||||
(["text"], "must contain only text parts"),
|
||||
([{"text": "missing type"}], "must contain only text parts"),
|
||||
(
|
||||
[{"type": "image_url", "image_url": {"url": "https://example.com/image.png"}}],
|
||||
"must contain only text parts",
|
||||
),
|
||||
([{"type": "text"}], "must have a string `text` field"),
|
||||
([{"type": "input_text", "text": 42}], "must have a string `text` field"),
|
||||
([{"type": "text", "text": "valid"}, {"type": "text", "text": None}], "must have a string `text` field"),
|
||||
],
|
||||
)
|
||||
def test_tool_result_rejects_invalid_content(self, content: object, error: str) -> None:
|
||||
with pytest.raises(OCIError, match=error) as exc_info:
|
||||
adapt_messages_to_generic_oci_standard([{"role": "tool", "tool_call_id": "call_mcp", "content": content}])
|
||||
|
||||
assert exc_info.value.status_code == 400
|
||||
|
||||
def test_tool_calls_not_list_raises(self):
|
||||
messages = [
|
||||
{
|
||||
|
|
@ -310,6 +355,7 @@ class TestHandleGenericStreamChunk:
|
|||
},
|
||||
}
|
||||
result = handle_generic_stream_chunk(chunk)
|
||||
assert result.choices[0].delta.role == "assistant"
|
||||
assert result.choices[0].delta.tool_calls is not None
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue