diff --git a/ollama/_utils.py b/ollama/_utils.py index 15f1cc0c..ce2aace1 100644 --- a/ollama/_utils.py +++ b/ollama/_utils.py @@ -73,9 +73,14 @@ def convert_function_to_tool(func: Callable) -> Tool: schema['required'].remove(k) types.discard('null') + # Emit a single type as a string and multiple types as a JSON-Schema array. + # A comma-joined string (e.g. 'integer, string') is parsed by the server as one + # invalid type name, silently dropping the constraint. Sorting also makes the + # output deterministic across runs since types is a set. + sorted_types = sorted(types) schema['properties'][k] = { 'description': parsed_docstring[k], - 'type': ', '.join(types), + 'type': sorted_types if len(sorted_types) > 1 else ''.join(sorted_types), } tool = Tool( diff --git a/tests/test_utils.py b/tests/test_utils.py index cb9e0d4f..1c99ee0a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -98,8 +98,10 @@ def all_types( if sys.version_info >= (3, 10): assert tool['function']['parameters']['properties']['z']['type'] == 'array' assert tool['function']['parameters']['properties']['w']['type'] == 'object' - assert {x.strip().strip("'") for x in tool['function']['parameters']['properties']['v']['type'].removeprefix('[').removesuffix(']').split(',')} == {'string', 'integer'} - assert tool['function']['parameters']['properties']['v']['type'] != 'null' + # A multi-type parameter must be a JSON array, not a comma-joined string, so the + # server parses each type instead of one invalid 'integer, string' type name. + assert isinstance(tool['function']['parameters']['properties']['v']['type'], list) + assert tool['function']['parameters']['properties']['v']['type'] == ['integer', 'string'] assert tool['function']['parameters']['required'] == ['x', 'y', 'z', 'w'] else: assert tool['function']['parameters']['properties']['z']['type'] == 'array'