Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,17 @@ def convert_tools(
if parameters is not None:
ollama_properties = {}
for prop_name, prop_schema in parameters["properties"].items():
# Determine property type, checking "type" first, then "anyOf", defaulting to "string"
prop_type = prop_schema.get("type")
if prop_type is None and "anyOf" in prop_schema:
prop_type = next(
(opt.get("type") for opt in prop_schema["anyOf"] if opt.get("type") != "null"),
None, # Default to None if no non-null type found in anyOf
)
prop_type = prop_type or "string"

ollama_properties[prop_name] = OllamaTool.Function.Parameters.Property(
type=prop_schema["type"],
type=prop_type,
description=prop_schema["description"] if "description" in prop_schema else None,
)
result.append(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import logging
from typing import Any, AsyncGenerator, Dict, List, Mapping
from typing import Any, AsyncGenerator, Dict, List, Mapping, Optional

import httpx
import pytest
Expand All @@ -13,11 +13,11 @@
FunctionExecutionResultMessage,
UserMessage,
)
from autogen_core.tools import FunctionTool
from autogen_core.tools import FunctionTool, ToolSchema
from autogen_ext.models.ollama import OllamaChatCompletionClient
from autogen_ext.models.ollama._ollama_client import OLLAMA_VALID_CREATE_KWARGS_KEYS
from autogen_ext.models.ollama._ollama_client import OLLAMA_VALID_CREATE_KWARGS_KEYS, convert_tools
from httpx import Response
from ollama import AsyncClient, ChatResponse, Message
from ollama import AsyncClient, ChatResponse, Message, Tool
from pydantic import BaseModel


Expand Down Expand Up @@ -206,6 +206,46 @@ async def _mock_chat(*args: Any, **kwargs: Any) -> ChatResponse:
assert create_result.usage.completion_tokens == 12


@pytest.mark.asyncio
async def test_convert_tools() -> None:
def add(x: int, y: Optional[int]) -> str:
if y is None:
return str(x)
return str(x + y)

add_tool = FunctionTool(add, description="Add two numbers")

tool_schema_noparam: ToolSchema = {
"name": "manual_tool",
"description": "A tool defined manually",
"parameters": {
"type": "object",
"properties": {
"param_with_type": {"type": "integer", "description": "An integer param"},
"param_without_type": {"description": "A param without explicit type"},
},
"required": ["param_with_type"],
},
}

converted_tools = convert_tools([add_tool, tool_schema_noparam])
assert len(converted_tools) == 2
assert isinstance(converted_tools[0].function, Tool.Function)
assert isinstance(converted_tools[0].function.parameters, Tool.Function.Parameters)
assert converted_tools[0].function.parameters.properties is not None
assert converted_tools[0].function.name == add_tool.name
assert converted_tools[0].function.parameters.properties["y"].type == "integer"

# test it defaults to string
assert isinstance(converted_tools[1].function, Tool.Function)
assert isinstance(converted_tools[1].function.parameters, Tool.Function.Parameters)
assert converted_tools[1].function.parameters.properties is not None
assert converted_tools[1].function.name == "manual_tool"
assert converted_tools[1].function.parameters.properties["param_with_type"].type == "integer"
assert converted_tools[1].function.parameters.properties["param_without_type"].type == "string"
assert converted_tools[1].function.parameters.required == ["param_with_type"]


@pytest.mark.asyncio
async def test_create_stream_tools(monkeypatch: pytest.MonkeyPatch) -> None:
def add(x: int, y: int) -> str:
Expand Down