Python: [BREAKING] Remove deprecated kwargs compatibility paths (#4858)

* [BREAKING] Remove deprecated kwargs compatibility paths

Remove the deprecated kwargs compatibility shims across core agents, clients, tools, middleware, and telemetry.

Keep workflow kwargs behavior intact in this branch and follow up separately in #4850.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix PR CI fallout for kwargs removal

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* updates

* Fix Azure AI CI fallout

Remove the stale _get_current_conversation_id override from the Azure AI client after the OpenAI base helper was deleted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fixed new classes

* Fix Assistants deprecated import gating

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix integration replay regressions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Switch multi-agent hosting samples to Azure chat completions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Simplify Azure multi-agent sample config

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-03-27 22:00:12 +01:00
committed by GitHub
Unverified
parent ca6cdd142e
commit b1b528e4a8
52 changed files with 1136 additions and 971 deletions
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
import inspect
import json
import logging
from typing import Annotated, Any
@@ -11,6 +12,11 @@ from agent_framework import (
Content,
Message,
SupportsChatGetResponse,
SupportsCodeInterpreterTool,
SupportsFileSearchTool,
SupportsImageGenerationTool,
SupportsMCPTool,
SupportsWebSearchTool,
tool,
)
from openai.types.beta.threads import (
@@ -30,6 +36,8 @@ from pydantic import Field
from agent_framework_openai import OpenAIAssistantsClient
pytestmark = pytest.mark.filterwarnings("ignore:OpenAIAssistantsClient is deprecated\\..*:DeprecationWarning")
def create_test_openai_assistants_client(
mock_async_openai: MagicMock,
@@ -104,6 +112,25 @@ def mock_async_openai() -> MagicMock:
return mock_client
def test_openai_assistants_client_is_deprecated(mock_async_openai: MagicMock) -> None:
with pytest.warns(DeprecationWarning, match="OpenAIAssistantsClient is deprecated. Use OpenAIChatClient instead."):
OpenAIAssistantsClient(model="gpt-4", api_key="test-api-key", async_client=mock_async_openai)
def test_openai_assistants_client_init_keeps_var_keyword() -> None:
signature = inspect.signature(OpenAIAssistantsClient.__init__)
assert any(parameter.kind == inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values())
def test_openai_assistants_client_supports_code_interpreter_and_file_search() -> None:
assert isinstance(OpenAIAssistantsClient, SupportsCodeInterpreterTool)
assert not isinstance(OpenAIAssistantsClient, SupportsWebSearchTool)
assert not isinstance(OpenAIAssistantsClient, SupportsImageGenerationTool)
assert not isinstance(OpenAIAssistantsClient, SupportsMCPTool)
assert isinstance(OpenAIAssistantsClient, SupportsFileSearchTool)
def test_init_with_client(mock_async_openai: MagicMock) -> None:
"""Test OpenAIAssistantsClient initialization with existing client."""
client = create_test_openai_assistants_client(
@@ -1,6 +1,7 @@
# Copyright (c) Microsoft. All rights reserved.
import base64
import inspect
import json
import os
from datetime import datetime, timezone
@@ -18,6 +19,11 @@ from agent_framework import (
FunctionTool,
Message,
SupportsChatGetResponse,
SupportsCodeInterpreterTool,
SupportsFileSearchTool,
SupportsImageGenerationTool,
SupportsMCPTool,
SupportsWebSearchTool,
tool,
)
from agent_framework._sessions import (
@@ -48,7 +54,7 @@ from openai.types.responses.response_text_delta_event import ResponseTextDeltaEv
from pydantic import BaseModel
from pytest import param
from agent_framework_openai import OpenAIChatClient
from agent_framework_openai import OpenAIChatClient, OpenAIResponsesClient
from agent_framework_openai._chat_client import OPENAI_LOCAL_SHELL_CALL_ITEM_ID_KEY
from agent_framework_openai._exceptions import OpenAIContentFilterException
@@ -110,6 +116,40 @@ def test_init(openai_unit_test_env: dict[str, str]) -> None:
assert isinstance(openai_responses_client, SupportsChatGetResponse)
def test_init_uses_explicit_parameters() -> None:
signature = inspect.signature(OpenAIChatClient.__init__)
assert "additional_properties" in signature.parameters
assert "compaction_strategy" in signature.parameters
assert "tokenizer" in signature.parameters
assert all(parameter.kind != inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values())
def test_deprecated_responses_client_supports_all_tool_protocols() -> None:
assert isinstance(OpenAIResponsesClient, SupportsCodeInterpreterTool)
assert isinstance(OpenAIResponsesClient, SupportsWebSearchTool)
assert isinstance(OpenAIResponsesClient, SupportsImageGenerationTool)
assert isinstance(OpenAIResponsesClient, SupportsMCPTool)
assert isinstance(OpenAIResponsesClient, SupportsFileSearchTool)
def test_protocol_isinstance_with_responses_client_instance() -> None:
client = object.__new__(OpenAIResponsesClient)
assert isinstance(client, SupportsCodeInterpreterTool)
assert isinstance(client, SupportsWebSearchTool)
def test_deprecated_responses_client_tool_methods_return_dict() -> None:
code_tool = OpenAIResponsesClient.get_code_interpreter_tool()
assert isinstance(code_tool, dict)
assert code_tool.get("type") == "code_interpreter"
web_tool = OpenAIResponsesClient.get_web_search_tool()
assert isinstance(web_tool, dict)
assert web_tool.get("type") == "web_search"
def test_init_prefers_openai_responses_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None:
monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model_id")
@@ -3033,20 +3073,6 @@ async def test_prepare_options_store_parameter_handling() -> None:
assert "previous_response_id" not in options
async def test_conversation_id_precedence_kwargs_over_options() -> None:
"""When both kwargs and options contain conversation_id, kwargs wins."""
client = OpenAIChatClient(model="test-model", api_key="test-key")
messages = [Message(role="user", text="Hello")]
# options has a stale response id, kwargs carries the freshest one
opts = {"conversation_id": "resp_old_123"}
run_opts = await client._prepare_options(messages, opts, conversation_id="resp_new_456") # type: ignore
# Verify kwargs takes precedence and maps to previous_response_id for resp_* IDs
assert run_opts.get("previous_response_id") == "resp_new_456"
assert "conversation" not in run_opts
def _create_mock_responses_text_response(*, response_id: str) -> MagicMock:
mock_response = MagicMock()
mock_response.id = response_id
@@ -465,7 +465,7 @@ async def test_integration_client_agent_existing_session() -> None:
first_response = await first_agent.run(
"My hobby is photography. Remember this.",
session=session,
store=True,
options={"store": True},
)
assert isinstance(first_response, AgentResponse)
@@ -476,7 +476,9 @@ async def test_integration_client_agent_existing_session() -> None:
client=OpenAIChatClient(credential=credential),
instructions="You are a helpful assistant with good memory.",
) as second_agent:
second_response = await second_agent.run("What is my hobby?", session=preserved_session)
second_response = await second_agent.run(
"What is my hobby?", session=preserved_session, options={"store": True}
)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft. All rights reserved.
import inspect
import json
import os
from typing import Any
@@ -11,6 +12,11 @@ from agent_framework import (
Content,
Message,
SupportsChatGetResponse,
SupportsCodeInterpreterTool,
SupportsFileSearchTool,
SupportsImageGenerationTool,
SupportsMCPTool,
SupportsWebSearchTool,
tool,
)
from agent_framework.exceptions import ChatClientException, SettingNotFoundError
@@ -20,7 +26,7 @@ from openai.types.chat.chat_completion_message import ChatCompletionMessage
from pydantic import BaseModel
from pytest import param
from agent_framework_openai import OpenAIChatCompletionClient
from agent_framework_openai import OpenAIChatCompletionClient, RawOpenAIChatCompletionClient
from agent_framework_openai._exceptions import OpenAIContentFilterException
skip_if_openai_integration_tests_disabled = pytest.mark.skipif(
@@ -37,6 +43,41 @@ def test_init(openai_unit_test_env: dict[str, str]) -> None:
assert isinstance(open_ai_chat_completion, SupportsChatGetResponse)
def test_get_response_docstring_surfaces_layered_runtime_docs() -> None:
docstring = inspect.getdoc(OpenAIChatCompletionClient.get_response)
assert docstring is not None
assert "Get a response from a chat client." in docstring
assert "function_invocation_kwargs" in docstring
assert "middleware: Optional per-call chat and function middleware." in docstring
assert "function_middleware: Optional per-call function middleware." not in docstring
def test_get_response_is_defined_on_openai_class() -> None:
signature = inspect.signature(OpenAIChatCompletionClient.get_response)
assert OpenAIChatCompletionClient.get_response.__qualname__ == "OpenAIChatCompletionClient.get_response"
assert "middleware" in signature.parameters
assert all(parameter.kind != inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values())
def test_init_uses_explicit_parameters() -> None:
signature = inspect.signature(RawOpenAIChatCompletionClient.__init__)
assert "additional_properties" in signature.parameters
assert "compaction_strategy" in signature.parameters
assert "tokenizer" in signature.parameters
assert all(parameter.kind != inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values())
def test_supports_web_search_only() -> None:
assert not isinstance(OpenAIChatCompletionClient, SupportsCodeInterpreterTool)
assert isinstance(OpenAIChatCompletionClient, SupportsWebSearchTool)
assert not isinstance(OpenAIChatCompletionClient, SupportsImageGenerationTool)
assert not isinstance(OpenAIChatCompletionClient, SupportsMCPTool)
assert not isinstance(OpenAIChatCompletionClient, SupportsFileSearchTool)
def test_init_prefers_openai_chat_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None:
monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model_id")
@@ -138,7 +138,7 @@ async def test_cmc_structured_output_no_fcc(
openai_chat_completion = OpenAIChatCompletionClient()
await openai_chat_completion.get_response(
messages=chat_history,
response_format=Test,
options={"response_format": Test},
)
mock_create.assert_awaited_once()
@@ -322,7 +322,7 @@ async def test_get_streaming_structured_output_no_fcc(
async for msg in openai_chat_completion.get_response(
stream=True,
messages=chat_history,
response_format=Test,
options={"response_format": Test},
):
assert isinstance(msg, ChatResponseUpdate)
mock_create.assert_awaited_once()
@@ -2,6 +2,7 @@
from __future__ import annotations
import inspect
import os
from unittest.mock import AsyncMock, MagicMock
@@ -15,6 +16,7 @@ from agent_framework_openai import (
OpenAIEmbeddingClient,
OpenAIEmbeddingOptions,
)
from agent_framework_openai._embedding_client import RawOpenAIEmbeddingClient
def _make_openai_response(
@@ -44,6 +46,13 @@ def test_openai_construction_with_explicit_params() -> None:
assert client.model == "text-embedding-3-small"
def test_raw_openai_embedding_client_init_uses_explicit_parameters() -> None:
signature = inspect.signature(RawOpenAIEmbeddingClient.__init__)
assert "additional_properties" in signature.parameters
assert all(parameter.kind != inspect.Parameter.VAR_KEYWORD for parameter in signature.parameters.values())
def test_openai_construction_from_env(openai_unit_test_env: dict[str, str]) -> None:
client = OpenAIEmbeddingClient()
assert client.model == openai_unit_test_env["OPENAI_EMBEDDING_MODEL"]