fix: Refine Ollama content flattening and provider checks

- Stripping whitespace from custom LLM provider and model names when checking for "ollama_chat".
- Enhancing `_flatten_ollama_content` to correctly handle content that is None, a string, a dictionary, or an iterable (like a tuple) of content blocks, not just lists. This aligns with LiteLLM's `OpenAIMessageContent` type being an `Iterable`.

Close #3928

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 845848017
This commit is contained in:
George Weale
2025-12-17 11:25:44 -08:00
committed by Copybara-Service
parent 1add41e160
commit c6f389d4bc
2 changed files with 33 additions and 6 deletions
+22 -6
View File
@@ -628,9 +628,12 @@ def _is_ollama_chat_provider(
model: Optional[str], custom_llm_provider: Optional[str]
) -> bool:
"""Returns True when requests should be normalized for ollama_chat."""
if custom_llm_provider and custom_llm_provider.lower() == "ollama_chat":
if (
custom_llm_provider
and custom_llm_provider.strip().lower() == "ollama_chat"
):
return True
if model and model.lower().startswith("ollama_chat"):
if model and model.strip().lower().startswith("ollama_chat"):
return True
return False
@@ -644,11 +647,24 @@ def _flatten_ollama_content(
join them with newlines, and fall back to a JSON string for non-text content.
If both text and non-text parts are present, only the text parts are kept.
"""
if not isinstance(content, list):
if content is None or isinstance(content, str):
return content
# `OpenAIMessageContent` is typed as `Iterable[...]` in LiteLLM. Some
# providers or LiteLLM versions may hand back tuples or other iterables.
if isinstance(content, dict):
try:
return json.dumps(content)
except TypeError:
return str(content)
try:
blocks = list(content)
except TypeError:
return str(content)
text_parts = []
for block in content:
for block in blocks:
if isinstance(block, dict) and block.get("type") == "text":
text_value = block.get("text")
if text_value:
@@ -658,9 +674,9 @@ def _flatten_ollama_content(
return _NEW_LINE.join(text_parts)
try:
return json.dumps(content)
return json.dumps(blocks)
except TypeError:
return str(content)
return str(blocks)
def _normalize_ollama_chat_messages(
+11
View File
@@ -1549,6 +1549,17 @@ async def test_generate_content_async_custom_provider_flattens_content(
assert "Describe this image." in message_content
def test_flatten_ollama_content_accepts_tuple_blocks():
from google.adk.models.lite_llm import _flatten_ollama_content
content = (
{"type": "text", "text": "first"},
{"type": "text", "text": "second"},
)
flattened = _flatten_ollama_content(content)
assert flattened == "first\nsecond"
@pytest.mark.asyncio
async def test_content_to_message_param_user_message():
content = types.Content(