From 14d88068d5cc78a737a76d78748e1fbd2bda2905 Mon Sep 17 00:00:00 2001 From: Unmilan Mukherjee <52813146+Missing-Identity@users.noreply.github.com> Date: Sun, 21 Jun 2026 00:50:07 +0530 Subject: [PATCH 1/2] fix(types): preserve tool call id on Message.ToolCall (#667) --- ollama/_types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ollama/_types.py b/ollama/_types.py index 96529d63..4c175eb8 100644 --- a/ollama/_types.py +++ b/ollama/_types.py @@ -1,3 +1,4 @@ +successfully downloaded text file (SHA: 96529d630ff7a59b36b34bde5fd4ede7725c5ab4) import contextlib import json from base64 import b64decode, b64encode @@ -335,6 +336,9 @@ class ToolCall(SubscriptableBaseModel): Model tool calls. """ + id: Optional[str] = None + 'ID of the tool call, when provided by the model/server.' + class Function(SubscriptableBaseModel): """ Tool call function. From 50966840833dfecfa2dc25e3525ee99ea53ebd0f Mon Sep 17 00:00:00 2001 From: Unmilan Mukherjee <52813146+Missing-Identity@users.noreply.github.com> Date: Sun, 21 Jun 2026 00:50:10 +0530 Subject: [PATCH 2/2] test(types): cover tool call id parsing and default (#667) --- tests/test_type_serialization.py | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/test_type_serialization.py b/tests/test_type_serialization.py index f458cd23..ea60ea10 100644 --- a/tests/test_type_serialization.py +++ b/tests/test_type_serialization.py @@ -1,10 +1,11 @@ +successfully downloaded text file (SHA: f458cd23da2a4e195e4cb28f61e934cfb79a2c46) import tempfile from base64 import b64encode from pathlib import Path import pytest -from ollama._types import CreateRequest, Image +from ollama._types import CreateRequest, Image, Message def test_image_serialization_bytes(): @@ -92,3 +93,36 @@ def test_create_request_serialization_license_list(): request = CreateRequest(model='test-model', license=['MIT', 'Apache-2.0']) serialized = request.model_dump() assert serialized['license'] == ['MIT', 'Apache-2.0'] + + +def test_message_tool_call_id_preserved(): + # Server responses include an 'id' on each tool call. Ensure it is parsed and kept. + message = Message.model_validate( + { + 'role': 'assistant', + 'content': '', + 'tool_calls': [ + { + 'id': 'call_p7o2gz50', + 'function': {'name': 'test_function', 'arguments': {'param1': 'test1', 'param2': 123}}, + } + ], + } + ) + assert message.tool_calls is not None + assert message.tool_calls[0].id == 'call_p7o2gz50' + assert message.tool_calls[0].function.name == 'test_function' + + +def test_message_tool_call_id_defaults_to_none(): + # When the server omits 'id', the field should default to None (backwards compatible). + message = Message.model_validate( + { + 'role': 'assistant', + 'tool_calls': [ + {'function': {'name': 'test_function', 'arguments': {}}}, + ], + } + ) + assert message.tool_calls is not None + assert message.tool_calls[0].id is None