Python: [Breaking] removed pydantic from types and workflows (#917)

* removed pydantic from types

* fix test

* fix test

* fix tests

* fix assistants client

* Remove Pydantic usage from workflow code.

* updated pydantic removal

* updated lock and test fixes

* fix mypy

* updated build system

* updated chat client parsing

* fix broken test

---------

Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
Eduard van Valkenburg
2025-09-29 23:19:58 +02:00
committed by GitHub
Unverified
parent 647db9635a
commit b4ebafa9b1
56 changed files with 3881 additions and 1735 deletions
@@ -20,7 +20,6 @@ from agent_framework import (
ChatOptions,
ChatResponse,
ChatResponseUpdate,
ChatToolMode,
FunctionCallContent,
FunctionResultContent,
HostedCodeInterpreterTool,
@@ -28,6 +27,7 @@ from agent_framework import (
HostedVectorStoreContent,
Role,
TextContent,
ToolMode,
UriContent,
UsageContent,
ai_function,
@@ -622,7 +622,7 @@ def test_openai_assistants_client_prepare_options_basic(mock_async_openai: Magic
# Create basic chat options
chat_options = ChatOptions(
max_tokens=100,
ai_model_id="gpt-4",
model_id="gpt-4",
temperature=0.7,
top_p=0.9,
)
@@ -716,7 +716,7 @@ def test_openai_assistants_client_prepare_options_required_function(mock_async_o
chat_client = create_test_openai_assistants_client(mock_async_openai)
# Create a required function tool choice
tool_choice = ChatToolMode(mode="required", required_function_name="specific_function")
tool_choice = ToolMode(mode="required", required_function_name="specific_function")
chat_options = ChatOptions(
tool_choice=tool_choice,
@@ -1,14 +1,11 @@
# Copyright (c) Microsoft. All rights reserved.
import json
import os
from datetime import datetime
from typing import Annotated
from unittest.mock import MagicMock, patch
import pytest
from openai import BadRequestError
from pydantic import BaseModel
from agent_framework import (
AgentRunResponse,
@@ -691,68 +688,6 @@ def test_function_result_exception_handling(openai_unit_test_env: dict[str, str]
assert openai_messages[0]["tool_call_id"] == "call-123"
def test_prepare_function_call_results_with_basemodel():
"""Test prepare_function_call_results with BaseModel objects."""
class TestModel(BaseModel):
name: str
value: int
raw_representation: str = "should be excluded"
additional_properties: dict = {"should": "be excluded"}
model_instance = TestModel(name="test", value=42)
result = prepare_function_call_results(model_instance)
assert isinstance(result, str)
parsed = json.loads(result)
assert parsed["name"] == "test"
assert parsed["value"] == 42
assert "raw_representation" not in parsed
assert "additional_properties" not in parsed
def test_prepare_function_call_results_with_nested_structures():
"""Test prepare_function_call_results with complex nested structures."""
class NestedModel(BaseModel):
id: int
raw_representation: str = "excluded"
# Test with list of BaseModel objects
models = [NestedModel(id=1), [NestedModel(id=2)]]
result = prepare_function_call_results(models)
assert isinstance(result, str)
parsed = json.loads(result)
assert len(parsed) == 2
assert parsed[0]["id"] == 1
assert isinstance(parsed[1], list)
assert len(parsed[1]) == 1
assert parsed[1][0]["id"] == 2
assert "raw_representation" not in parsed[0]
assert "raw_representation" not in parsed[1][0]
def test_prepare_function_call_results_with_dict_containing_basemodel():
"""Test prepare_function_call_results with dictionary containing BaseModel."""
class TestModel(BaseModel):
value: str
raw_representation: str = "excluded"
# Test with dict containing BaseModel
complex_dict = {"model": TestModel(value="test"), "simple": "value", "number": 42}
result = prepare_function_call_results(complex_dict)
assert isinstance(result, str)
parsed = json.loads(result)
assert parsed["model"]["value"] == "test"
assert "raw_representation" not in parsed["model"]
assert parsed["simple"] == "value"
assert parsed["number"] == 42
def test_prepare_function_call_results_string_passthrough():
"""Test that string values are passed through directly without JSON encoding."""
result = prepare_function_call_results("simple string")
@@ -760,28 +695,6 @@ def test_prepare_function_call_results_string_passthrough():
assert isinstance(result, str)
def test_prepare_function_call_results_with_none_values():
"""Test that None values in BaseModel fields are preserved to avoid validation errors during reloading."""
class Flight(BaseModel):
flight_id: str
departure: datetime | None
arrival: datetime | None
# Test single BaseModel with None values (performance shortcut)
flight_with_nones = Flight(flight_id="123", departure=None, arrival=None)
result = prepare_function_call_results(flight_with_nones)
assert isinstance(result, str)
parsed = json.loads(result)
assert parsed["flight_id"] == "123"
assert parsed["departure"] is None
assert parsed["arrival"] is None
new_flight = Flight.model_validate_json(result)
assert new_flight == flight_with_nones
def test_openai_content_parser_data_content_image(openai_unit_test_env: dict[str, str]) -> None:
"""Test _openai_content_parser converts DataContent with image media type to OpenAI format."""
client = OpenAIChatClient()
@@ -370,7 +370,7 @@ async def test_response_format_parse_path() -> None:
)
assert response.conversation_id == "parsed_response_123"
assert response.ai_model_id == "test-model"
assert response.model_id == "test-model"
async def test_bad_request_error_non_content_filter() -> None:
@@ -783,7 +783,7 @@ def test_create_streaming_response_content_with_mcp_approval_request() -> None:
@pytest.mark.parametrize("enable_otel", [False], indirect=True)
@pytest.mark.parametrize("enable_sensitive_data", [False], indirect=True)
def test_end_to_end_mcp_approval_flow() -> None:
def test_end_to_end_mcp_approval_flow(span_exporter) -> None:
"""End-to-end mocked test:
model issues an mcp_approval_request, user approves, client sends mcp_approval_response.
"""
@@ -937,7 +937,7 @@ def test_streaming_response_basic_structure() -> None:
# Should get a valid ChatResponseUpdate structure
assert isinstance(response, ChatResponseUpdate)
assert response.role == Role.ASSISTANT
assert response.ai_model_id == "test-model"
assert response.model_id == "test-model"
assert isinstance(response.contents, list)
assert response.raw_representation is mock_event