fix: address Greptile review comments for message transformation

- Handle Pydantic BaseModel messages by calling model_dump() instead of
  silently dropping them (matches Groq's pattern)
- Document that is_async parameter is accepted for interface compatibility
  but not used (Snowflake doesn't need async image URL operations)
- Add warning log when tool_call_id is not found in prior assistant messages,
  making the failure mode explicit rather than silent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
stevejaker 2026-03-10 13:34:33 -06:00
parent 229aa70201
commit c55192d74c

View file

@ -6,7 +6,9 @@ import json
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
import httpx
from pydantic import BaseModel
import litellm
from litellm.types.llms.openai import AllMessageValues
from litellm.types.utils import ChatCompletionMessageToolCall, Function, ModelResponse
@ -164,9 +166,13 @@ class SnowflakeConfig(SnowflakeBaseConfig, OpenAIGPTConfig):
1. Assistant messages with tool_calls -> content_list with tool_use blocks
2. Tool messages (role: "tool") -> User messages with content_list containing tool_results
Snowflake uses a format similar to Anthropic/Bedrock where:
Snowflake uses a format where:
- tool_use blocks are in assistant message content_list
- tool_results are in user message content_list (not role: "tool")
Note: is_async parameter is accepted for interface compatibility but not used.
Snowflake transformation is synchronous and doesn't require async operations
like image URL downloads that the parent class handles.
"""
# Build a map of tool_call_id -> tool_call for looking up function names
tool_calls_map: Dict[str, Dict[str, Any]] = {}
@ -180,7 +186,10 @@ class SnowflakeConfig(SnowflakeBaseConfig, OpenAIGPTConfig):
pending_tool_messages: List[Dict[str, Any]] = []
for message in messages:
if not isinstance(message, dict):
# Handle Pydantic models by converting to dict
if isinstance(message, BaseModel):
message = message.model_dump()
elif not isinstance(message, dict):
continue
role = message.get("role", "")
@ -300,9 +309,16 @@ class SnowflakeConfig(SnowflakeBaseConfig, OpenAIGPTConfig):
for tool_msg in tool_messages:
tool_call_id = tool_msg.get("tool_call_id", "")
tool_call = tool_calls_map.get(tool_call_id, {})
function = tool_call.get("function", {})
function_name = function.get("name", "")
tool_call = tool_calls_map.get(tool_call_id)
if tool_call is None:
litellm.utils.verbose_logger.warning(
f"Snowflake: tool_call_id '{tool_call_id}' not found in prior "
"assistant messages; function name will be empty."
)
function_name = ""
else:
function = tool_call.get("function", {})
function_name = function.get("name", "")
# Get content - could be string, list, or None
content = tool_msg.get("content")