mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-01 07:03:02 +00:00
fix(ollama): forward assistant tool call ids in ollama_chat requests (#49278)
* test(ollama): cover assistant tool call ids in ollama_chat requests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(ollama): forward assistant tool call ids in ollama_chat requests Co-authored-by: Kenneth Bingham <w@qrk.us> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * style(ollama): format tool call id regression assertion Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(ollama): keep tool call ID handling type safe Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * style(ollama): format tool-call id helper Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(ollama): preserve typed tool call arguments Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Kenneth Bingham <w@qrk.us>
This commit is contained in:
parent
5898a42f5a
commit
4f7150f832
3 changed files with 110 additions and 10 deletions
|
|
@ -235,6 +235,19 @@ class OllamaChatConfig(BaseConfig):
|
|||
litellm_params["function_name"] = function_name
|
||||
tools: Final = optional_params.pop("tools", None)
|
||||
|
||||
def transform_tool_call(typed_tool: ChatCompletionAssistantToolCall) -> OllamaToolCall:
|
||||
function: Final = OllamaToolCallFunction(
|
||||
name=typed_tool["function"].get("name") or "",
|
||||
arguments=json.loads(typed_tool["function"]["arguments"])
|
||||
if "arguments" in typed_tool["function"]
|
||||
else {},
|
||||
)
|
||||
tool_id: Final = typed_tool.get("id")
|
||||
ollama_tool_call: Final = (
|
||||
OllamaToolCall(function=function) if tool_id is None else OllamaToolCall(id=tool_id, function=function)
|
||||
)
|
||||
return ollama_tool_call
|
||||
|
||||
new_messages: Final = []
|
||||
for m in messages:
|
||||
if isinstance(
|
||||
|
|
@ -248,16 +261,7 @@ class OllamaChatConfig(BaseConfig):
|
|||
for tool in tool_calls:
|
||||
typed_tool = ChatCompletionAssistantToolCall(**tool)
|
||||
if typed_tool["type"] == "function":
|
||||
arguments = {}
|
||||
if "arguments" in typed_tool["function"]:
|
||||
arguments = json.loads(typed_tool["function"]["arguments"])
|
||||
ollama_tool_call = OllamaToolCall(
|
||||
function=OllamaToolCallFunction(
|
||||
name=typed_tool["function"].get("name") or "",
|
||||
arguments=arguments,
|
||||
)
|
||||
)
|
||||
new_tools.append(ollama_tool_call)
|
||||
new_tools.append(transform_tool_call(typed_tool))
|
||||
reasoning_content, parsed_content = extract_reasoning_content(cast(dict, m))
|
||||
content_str = convert_content_list_to_str(cast(AllMessageValues, m))
|
||||
images = extract_images_from_message(cast(AllMessageValues, m))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
from typing_extensions import (
|
||||
NotRequired,
|
||||
ReadOnly,
|
||||
Required,
|
||||
TypedDict,
|
||||
)
|
||||
|
|
@ -12,6 +14,7 @@ class OllamaToolCallFunction(
|
|||
|
||||
|
||||
class OllamaToolCall(TypedDict):
|
||||
id: NotRequired[ReadOnly[str]]
|
||||
function: OllamaToolCallFunction
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -856,6 +856,99 @@ class TestOllamaReasoningContentStreaming:
|
|||
|
||||
|
||||
class TestOllamaToolCallTransformation:
|
||||
@pytest.mark.parametrize("stream", [False, True])
|
||||
def test_transform_request_keeps_parallel_call_ids_paired_with_results(self, stream: bool):
|
||||
config: Final = OllamaChatConfig()
|
||||
messages: Final = cast(
|
||||
list[AllMessageValues],
|
||||
[
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "",
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": "call_first",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_fixture",
|
||||
"arguments": '{"path": "first.txt"}',
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "call_second",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_fixture",
|
||||
"arguments": '{"path": "second.txt"}',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_second",
|
||||
"content": "second result",
|
||||
},
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": "call_first",
|
||||
"content": "first result",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
result: Final = config.transform_request(
|
||||
model="ollama_chat/test-model",
|
||||
messages=messages,
|
||||
optional_params={"stream": stream},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert result["messages"][0]["tool_calls"] == [
|
||||
{
|
||||
"id": "call_first",
|
||||
"function": {"name": "read_fixture", "arguments": {"path": "first.txt"}},
|
||||
},
|
||||
{
|
||||
"id": "call_second",
|
||||
"function": {"name": "read_fixture", "arguments": {"path": "second.txt"}},
|
||||
},
|
||||
]
|
||||
assert [message.get("tool_call_id") for message in result["messages"][1:]] == [
|
||||
"call_second",
|
||||
"call_first",
|
||||
]
|
||||
|
||||
def test_transform_request_does_not_invent_an_id_for_an_unidentified_call(self):
|
||||
config: Final = OllamaChatConfig()
|
||||
messages: Final = cast(
|
||||
list[AllMessageValues],
|
||||
[
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "",
|
||||
"tool_calls": [
|
||||
{
|
||||
"id": None,
|
||||
"type": "function",
|
||||
"function": {"name": "read_fixture", "arguments": "{}"},
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
result: Final = config.transform_request(
|
||||
model="ollama_chat/test-model",
|
||||
messages=messages,
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert result["messages"][0]["tool_calls"] == [{"function": {"name": "read_fixture", "arguments": {}}}]
|
||||
|
||||
def test_transform_request_preserves_tool_calls(self):
|
||||
"""
|
||||
tool_calls on assistant messages must survive transform_request.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue