Python: [BREAKING] Simplify API: ChatAgent -> Agent, ChatMessage -> Message (#3747)

* [BREAKING] Rename ChatAgent -> Agent, ChatMessage -> Message, ChatClientProtocol -> SupportsChatGetResponse

Simplify the public API by removing redundant 'Chat' prefix from core types:
- ChatAgent -> Agent
- RawChatAgent -> RawAgent
- ChatMessage -> Message
- ChatClientProtocol -> SupportsChatGetResponse

Also renamed internal WorkflowMessage (was Message in _runner_context) to avoid collision.

No backward compatibility aliases - this is a clean breaking change.

* [BREAKING] Rename Agent chat_client parameter to client

* Fix rebase issues: WorkflowMessage references and broken markdown links

* Fix formatting and lint issues from code quality checks

* Fix import ordering in workflow sample files

* fixed rebase

* Fix test failures: use WorkflowMessage and A2AMessage after ChatMessage→Message rename

- Replace Message(data=..., source_id=...) with WorkflowMessage(...) in workflow tests
- Fix isinstance check in A2A agent to use A2AMessage instead of Message
- Fix import in test_workflow_observability.py (Message→WorkflowMessage)

* Fix lint, fmt, and sample errors after ChatMessage→Message rename

- Auto-fix 70+ ruff lint issues across samples (ChatMessage→Message refs)
- Fix HostedVectorStoreContent→Content.from_hosted_vector_store in file search sample
- Fix _normalize_messages→normalize_messages in custom agent sample
- Fix context.terminate→raise MiddlewareTermination in middleware samples
- Fix with_update_hook→with_transform_hook in override middleware sample
- Add TOptions_co import back to custom_chat_client sample
- Add noqa for FastAPI File() default in chatkit sample
- Fix B023 loop variable capture in weather agent sample

* fix: update Agent constructor calls from chat_client to client in declaration-only tool tests

* fix: add register_cleanup to devui lazy-loading proxy and type stub

* fixed tests and updated new pieces

* fix agui typevar

* fix merge errors

* fix merge conflicts

* fiux merge

* Remove unused links

---------

Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
This commit is contained in:
Eduard van Valkenburg
2026-02-10 23:04:32 +00:00
committed by GitHub
co-authored by Evan Mattson
parent a4c9e43afb
commit 0521f5bed8
418 changed files with 5385 additions and 5389 deletions
@@ -11,7 +11,6 @@ from agent_framework import (
Annotation,
BaseChatClient,
ChatAndFunctionMiddlewareTypes,
ChatMessage,
ChatMiddlewareLayer,
ChatOptions,
ChatResponse,
@@ -24,6 +23,7 @@ from agent_framework import (
HostedCodeInterpreterTool,
HostedMCPTool,
HostedWebSearchTool,
Message,
ResponseStream,
TextSpanRegion,
UsageDetails,
@@ -356,7 +356,7 @@ class AnthropicClient(
def _inner_get_response(
self,
*,
messages: Sequence[ChatMessage],
messages: Sequence[Message],
options: Mapping[str, Any],
stream: bool = False,
**kwargs: Any,
@@ -385,7 +385,7 @@ class AnthropicClient(
def _prepare_options(
self,
messages: Sequence[ChatMessage],
messages: Sequence[Message],
options: Mapping[str, Any],
**kwargs: Any,
) -> dict[str, Any]:
@@ -430,7 +430,7 @@ class AnthropicClient(
run_options["messages"] = self._prepare_messages_for_anthropic(messages)
# system message - first system message is passed as instructions
if messages and isinstance(messages[0], ChatMessage) and messages[0].role == "system":
if messages and isinstance(messages[0], Message) and messages[0].role == "system":
run_options["system"] = messages[0].text
# betas
@@ -516,22 +516,22 @@ class AnthropicClient(
"schema": schema,
}
def _prepare_messages_for_anthropic(self, messages: Sequence[ChatMessage]) -> list[dict[str, Any]]:
def _prepare_messages_for_anthropic(self, messages: Sequence[Message]) -> list[dict[str, Any]]:
"""Prepare a list of ChatMessages for the Anthropic client.
This skips the first message if it is a system message,
as Anthropic expects system instructions as a separate parameter.
"""
# first system message is passed as instructions
if messages and isinstance(messages[0], ChatMessage) and messages[0].role == "system":
if messages and isinstance(messages[0], Message) and messages[0].role == "system":
return [self._prepare_message_for_anthropic(msg) for msg in messages[1:]]
return [self._prepare_message_for_anthropic(msg) for msg in messages]
def _prepare_message_for_anthropic(self, message: ChatMessage) -> dict[str, Any]:
"""Prepare a ChatMessage for the Anthropic client.
def _prepare_message_for_anthropic(self, message: Message) -> dict[str, Any]:
"""Prepare a Message for the Anthropic client.
Args:
message: The ChatMessage to convert.
message: The Message to convert.
Returns:
A dictionary representing the message in Anthropic format.
@@ -693,7 +693,7 @@ class AnthropicClient(
return ChatResponse(
response_id=message.id,
messages=[
ChatMessage(
Message(
role="assistant",
contents=self._parse_contents_from_anthropic(message.content),
raw_representation=message,
@@ -6,14 +6,14 @@ from unittest.mock import MagicMock, patch
import pytest
from agent_framework import (
ChatClientProtocol,
ChatMessage,
ChatOptions,
ChatResponseUpdate,
Content,
HostedCodeInterpreterTool,
HostedMCPTool,
HostedWebSearchTool,
Message,
SupportsChatGetResponse,
tool,
)
from agent_framework.exceptions import ServiceInitializationError
@@ -98,11 +98,11 @@ def test_anthropic_settings_missing_api_key(anthropic_unit_test_env: dict[str, s
def test_anthropic_client_init_with_client(mock_anthropic_client: MagicMock) -> None:
"""Test AnthropicClient initialization with existing anthropic_client."""
chat_client = create_test_anthropic_client(mock_anthropic_client, model_id="claude-3-5-sonnet-20241022")
client = create_test_anthropic_client(mock_anthropic_client, model_id="claude-3-5-sonnet-20241022")
assert chat_client.anthropic_client is mock_anthropic_client
assert chat_client.model_id == "claude-3-5-sonnet-20241022"
assert isinstance(chat_client, ChatClientProtocol)
assert client.anthropic_client is mock_anthropic_client
assert client.model_id == "claude-3-5-sonnet-20241022"
assert isinstance(client, SupportsChatGetResponse)
def test_anthropic_client_init_auto_create_client(anthropic_unit_test_env: dict[str, str]) -> None:
@@ -138,8 +138,8 @@ def test_anthropic_client_init_validation_error() -> None:
def test_anthropic_client_service_url(mock_anthropic_client: MagicMock) -> None:
"""Test service_url method."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
assert chat_client.service_url() == "https://api.anthropic.com"
client = create_test_anthropic_client(mock_anthropic_client)
assert client.service_url() == "https://api.anthropic.com"
# Message Conversion Tests
@@ -147,10 +147,10 @@ def test_anthropic_client_service_url(mock_anthropic_client: MagicMock) -> None:
def test_prepare_message_for_anthropic_text(mock_anthropic_client: MagicMock) -> None:
"""Test converting text message to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
message = ChatMessage(role="user", text="Hello, world!")
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(role="user", text="Hello, world!")
result = chat_client._prepare_message_for_anthropic(message)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "user"
assert len(result["content"]) == 1
@@ -160,8 +160,8 @@ def test_prepare_message_for_anthropic_text(mock_anthropic_client: MagicMock) ->
def test_prepare_message_for_anthropic_function_call(mock_anthropic_client: MagicMock) -> None:
"""Test converting function call message to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
message = ChatMessage(
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="assistant",
contents=[
Content.from_function_call(
@@ -172,7 +172,7 @@ def test_prepare_message_for_anthropic_function_call(mock_anthropic_client: Magi
],
)
result = chat_client._prepare_message_for_anthropic(message)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "assistant"
assert len(result["content"]) == 1
@@ -184,8 +184,8 @@ def test_prepare_message_for_anthropic_function_call(mock_anthropic_client: Magi
def test_prepare_message_for_anthropic_function_result(mock_anthropic_client: MagicMock) -> None:
"""Test converting function result message to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
message = ChatMessage(
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="tool",
contents=[
Content.from_function_result(
@@ -195,7 +195,7 @@ def test_prepare_message_for_anthropic_function_result(mock_anthropic_client: Ma
],
)
result = chat_client._prepare_message_for_anthropic(message)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "user"
assert len(result["content"]) == 1
@@ -209,13 +209,13 @@ def test_prepare_message_for_anthropic_function_result(mock_anthropic_client: Ma
def test_prepare_message_for_anthropic_text_reasoning(mock_anthropic_client: MagicMock) -> None:
"""Test converting text reasoning message to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
message = ChatMessage(
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="assistant",
contents=[Content.from_text_reasoning(text="Let me think about this...")],
)
result = chat_client._prepare_message_for_anthropic(message)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "assistant"
assert len(result["content"]) == 1
@@ -225,13 +225,13 @@ def test_prepare_message_for_anthropic_text_reasoning(mock_anthropic_client: Mag
def test_prepare_messages_for_anthropic_with_system(mock_anthropic_client: MagicMock) -> None:
"""Test converting messages list with system message."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [
ChatMessage(role="system", text="You are a helpful assistant."),
ChatMessage(role="user", text="Hello!"),
Message(role="system", text="You are a helpful assistant."),
Message(role="user", text="Hello!"),
]
result = chat_client._prepare_messages_for_anthropic(messages)
result = client._prepare_messages_for_anthropic(messages)
# System message should be skipped
assert len(result) == 1
@@ -241,13 +241,13 @@ def test_prepare_messages_for_anthropic_with_system(mock_anthropic_client: Magic
def test_prepare_messages_for_anthropic_without_system(mock_anthropic_client: MagicMock) -> None:
"""Test converting messages list without system message."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [
ChatMessage(role="user", text="Hello!"),
ChatMessage(role="assistant", text="Hi there!"),
Message(role="user", text="Hello!"),
Message(role="assistant", text="Hi there!"),
]
result = chat_client._prepare_messages_for_anthropic(messages)
result = client._prepare_messages_for_anthropic(messages)
assert len(result) == 2
assert result[0]["role"] == "user"
@@ -259,7 +259,7 @@ def test_prepare_messages_for_anthropic_without_system(mock_anthropic_client: Ma
def test_prepare_tools_for_anthropic_tool(mock_anthropic_client: MagicMock) -> None:
"""Test converting FunctionTool to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
@tool(approval_mode="never_require")
def get_weather(location: Annotated[str, Field(description="Location to get weather for")]) -> str:
@@ -267,7 +267,7 @@ def test_prepare_tools_for_anthropic_tool(mock_anthropic_client: MagicMock) -> N
return f"Weather for {location}"
chat_options = ChatOptions(tools=[get_weather])
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "tools" in result
@@ -279,10 +279,10 @@ def test_prepare_tools_for_anthropic_tool(mock_anthropic_client: MagicMock) -> N
def test_prepare_tools_for_anthropic_web_search(mock_anthropic_client: MagicMock) -> None:
"""Test converting HostedWebSearchTool to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions(tools=[HostedWebSearchTool()])
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "tools" in result
@@ -293,10 +293,10 @@ def test_prepare_tools_for_anthropic_web_search(mock_anthropic_client: MagicMock
def test_prepare_tools_for_anthropic_code_interpreter(mock_anthropic_client: MagicMock) -> None:
"""Test converting HostedCodeInterpreterTool to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions(tools=[HostedCodeInterpreterTool()])
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "tools" in result
@@ -307,10 +307,10 @@ def test_prepare_tools_for_anthropic_code_interpreter(mock_anthropic_client: Mag
def test_prepare_tools_for_anthropic_mcp_tool(mock_anthropic_client: MagicMock) -> None:
"""Test converting HostedMCPTool to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions(tools=[HostedMCPTool(name="test-mcp", url="https://example.com/mcp")])
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "mcp_servers" in result
@@ -322,7 +322,7 @@ def test_prepare_tools_for_anthropic_mcp_tool(mock_anthropic_client: MagicMock)
def test_prepare_tools_for_anthropic_mcp_with_auth(mock_anthropic_client: MagicMock) -> None:
"""Test converting HostedMCPTool with authorization headers."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions(
tools=[
HostedMCPTool(
@@ -333,7 +333,7 @@ def test_prepare_tools_for_anthropic_mcp_with_auth(mock_anthropic_client: MagicM
]
)
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "mcp_servers" in result
@@ -344,10 +344,10 @@ def test_prepare_tools_for_anthropic_mcp_with_auth(mock_anthropic_client: MagicM
def test_prepare_tools_for_anthropic_dict_tool(mock_anthropic_client: MagicMock) -> None:
"""Test converting dict tool to Anthropic format."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions(tools=[{"type": "custom", "name": "custom_tool", "description": "A custom tool"}])
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is not None
assert "tools" in result
@@ -357,10 +357,10 @@ def test_prepare_tools_for_anthropic_dict_tool(mock_anthropic_client: MagicMock)
def test_prepare_tools_for_anthropic_none(mock_anthropic_client: MagicMock) -> None:
"""Test converting None tools."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
chat_options = ChatOptions()
result = chat_client._prepare_tools_for_anthropic(chat_options)
result = client._prepare_tools_for_anthropic(chat_options)
assert result is None
@@ -370,14 +370,14 @@ def test_prepare_tools_for_anthropic_none(mock_anthropic_client: MagicMock) -> N
async def test_prepare_options_basic(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with basic ChatOptions."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(max_tokens=100, temperature=0.7)
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["model"] == chat_client.model_id
assert run_options["model"] == client.model_id
assert run_options["max_tokens"] == 100
assert run_options["temperature"] == 0.7
assert "messages" in run_options
@@ -385,15 +385,15 @@ async def test_prepare_options_basic(mock_anthropic_client: MagicMock) -> None:
async def test_prepare_options_with_system_message(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with system message."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [
ChatMessage(role="system", text="You are helpful."),
ChatMessage(role="user", text="Hello"),
Message(role="system", text="You are helpful."),
Message(role="user", text="Hello"),
]
chat_options = ChatOptions()
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["system"] == "You are helpful."
assert len(run_options["messages"]) == 1 # System message not in messages list
@@ -401,25 +401,25 @@ async def test_prepare_options_with_system_message(mock_anthropic_client: MagicM
async def test_prepare_options_with_tool_choice_auto(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with auto tool choice."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(tool_choice="auto")
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["tool_choice"]["type"] == "auto"
async def test_prepare_options_with_tool_choice_required(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with required tool choice."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
# For required with specific function, need to pass as dict
chat_options = ChatOptions(tool_choice={"mode": "required", "required_function_name": "get_weather"})
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["tool_choice"]["type"] == "tool"
assert run_options["tool_choice"]["name"] == "get_weather"
@@ -427,29 +427,29 @@ async def test_prepare_options_with_tool_choice_required(mock_anthropic_client:
async def test_prepare_options_with_tool_choice_none(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with none tool choice."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(tool_choice="none")
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["tool_choice"]["type"] == "none"
async def test_prepare_options_with_tools(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with tools."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
@tool(approval_mode="never_require")
def get_weather(location: str) -> str:
"""Get weather for a location."""
return f"Weather for {location}"
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(tools=[get_weather])
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert "tools" in run_options
assert len(run_options["tools"]) == 1
@@ -457,24 +457,24 @@ async def test_prepare_options_with_tools(mock_anthropic_client: MagicMock) -> N
async def test_prepare_options_with_stop_sequences(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with stop sequences."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(stop=["STOP", "END"])
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["stop_sequences"] == ["STOP", "END"]
async def test_prepare_options_with_top_p(mock_anthropic_client: MagicMock) -> None:
"""Test _prepare_options with top_p."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options = ChatOptions(top_p=0.9)
run_options = chat_client._prepare_options(messages, chat_options)
run_options = client._prepare_options(messages, chat_options)
assert run_options["top_p"] == 0.9
@@ -485,9 +485,9 @@ async def test_prepare_options_filters_internal_kwargs(mock_anthropic_client: Ma
Internal kwargs like _function_middleware_pipeline, thread, and middleware
should be filtered out before being passed to the Anthropic API.
"""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
messages = [ChatMessage(role="user", text="Hello")]
messages = [Message(role="user", text="Hello")]
chat_options: ChatOptions = {}
# Simulate internal kwargs that get passed through the middleware pipeline
@@ -499,7 +499,7 @@ async def test_prepare_options_filters_internal_kwargs(mock_anthropic_client: Ma
"middleware": [object()],
}
run_options = chat_client._prepare_options(messages, chat_options, **internal_kwargs)
run_options = client._prepare_options(messages, chat_options, **internal_kwargs)
# Internal kwargs should be filtered out
assert "_function_middleware_pipeline" not in run_options
@@ -514,7 +514,7 @@ async def test_prepare_options_filters_internal_kwargs(mock_anthropic_client: Ma
def test_process_message_basic(mock_anthropic_client: MagicMock) -> None:
"""Test _process_message with basic text response."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
mock_message = MagicMock(spec=BetaMessage)
mock_message.id = "msg_123"
@@ -523,7 +523,7 @@ def test_process_message_basic(mock_anthropic_client: MagicMock) -> None:
mock_message.usage = BetaUsage(input_tokens=10, output_tokens=5)
mock_message.stop_reason = "end_turn"
response = chat_client._process_message(mock_message, {})
response = client._process_message(mock_message, {})
assert response.response_id == "msg_123"
assert response.model_id == "claude-3-5-sonnet-20241022"
@@ -540,7 +540,7 @@ def test_process_message_basic(mock_anthropic_client: MagicMock) -> None:
def test_process_message_with_tool_use(mock_anthropic_client: MagicMock) -> None:
"""Test _process_message with tool use."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
mock_message = MagicMock(spec=BetaMessage)
mock_message.id = "msg_123"
@@ -556,7 +556,7 @@ def test_process_message_with_tool_use(mock_anthropic_client: MagicMock) -> None
mock_message.usage = BetaUsage(input_tokens=10, output_tokens=5)
mock_message.stop_reason = "tool_use"
response = chat_client._process_message(mock_message, {})
response = client._process_message(mock_message, {})
assert len(response.messages[0].contents) == 1
assert response.messages[0].contents[0].type == "function_call"
@@ -567,10 +567,10 @@ def test_process_message_with_tool_use(mock_anthropic_client: MagicMock) -> None
def test_parse_usage_from_anthropic_basic(mock_anthropic_client: MagicMock) -> None:
"""Test _parse_usage_from_anthropic with basic usage."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
usage = BetaUsage(input_tokens=10, output_tokens=5)
result = chat_client._parse_usage_from_anthropic(usage)
result = client._parse_usage_from_anthropic(usage)
assert result is not None
assert result["input_token_count"] == 10
@@ -579,19 +579,19 @@ def test_parse_usage_from_anthropic_basic(mock_anthropic_client: MagicMock) -> N
def test_parse_usage_from_anthropic_none(mock_anthropic_client: MagicMock) -> None:
"""Test _parse_usage_from_anthropic with None usage."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
result = chat_client._parse_usage_from_anthropic(None)
result = client._parse_usage_from_anthropic(None)
assert result is None
def test_parse_contents_from_anthropic_text(mock_anthropic_client: MagicMock) -> None:
"""Test _parse_contents_from_anthropic with text content."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
content = [BetaTextBlock(type="text", text="Hello!")]
result = chat_client._parse_contents_from_anthropic(content)
result = client._parse_contents_from_anthropic(content)
assert len(result) == 1
assert result[0].type == "text"
@@ -600,7 +600,7 @@ def test_parse_contents_from_anthropic_text(mock_anthropic_client: MagicMock) ->
def test_parse_contents_from_anthropic_tool_use(mock_anthropic_client: MagicMock) -> None:
"""Test _parse_contents_from_anthropic with tool use."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
content = [
BetaToolUseBlock(
@@ -610,7 +610,7 @@ def test_parse_contents_from_anthropic_tool_use(mock_anthropic_client: MagicMock
input={"location": "SF"},
)
]
result = chat_client._parse_contents_from_anthropic(content)
result = client._parse_contents_from_anthropic(content)
assert len(result) == 1
assert result[0].type == "function_call"
@@ -625,7 +625,7 @@ def test_parse_contents_from_anthropic_input_json_delta_no_duplicate_name(mock_a
and subsequent input_json_delta events should have name="" to prevent
ag-ui from emitting duplicate ToolCallStartEvents.
"""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
# First, simulate a tool_use event that sets _last_call_id_name
tool_use_content = MagicMock()
@@ -634,7 +634,7 @@ def test_parse_contents_from_anthropic_input_json_delta_no_duplicate_name(mock_a
tool_use_content.name = "get_weather"
tool_use_content.input = {}
result = chat_client._parse_contents_from_anthropic([tool_use_content])
result = client._parse_contents_from_anthropic([tool_use_content])
assert len(result) == 1
assert result[0].type == "function_call"
assert result[0].call_id == "call_123"
@@ -645,7 +645,7 @@ def test_parse_contents_from_anthropic_input_json_delta_no_duplicate_name(mock_a
delta_content_1.type = "input_json_delta"
delta_content_1.partial_json = '{"location":'
result = chat_client._parse_contents_from_anthropic([delta_content_1])
result = client._parse_contents_from_anthropic([delta_content_1])
assert len(result) == 1
assert result[0].type == "function_call"
assert result[0].call_id == "call_123"
@@ -657,7 +657,7 @@ def test_parse_contents_from_anthropic_input_json_delta_no_duplicate_name(mock_a
delta_content_2.type = "input_json_delta"
delta_content_2.partial_json = '"San Francisco"}'
result = chat_client._parse_contents_from_anthropic([delta_content_2])
result = client._parse_contents_from_anthropic([delta_content_2])
assert len(result) == 1
assert result[0].type == "function_call"
assert result[0].call_id == "call_123"
@@ -670,13 +670,13 @@ def test_parse_contents_from_anthropic_input_json_delta_no_duplicate_name(mock_a
def test_process_stream_event_simple(mock_anthropic_client: MagicMock) -> None:
"""Test _process_stream_event with simple mock event."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
# Test with a basic mock event - the actual implementation will handle real events
mock_event = MagicMock()
mock_event.type = "message_stop"
result = chat_client._process_stream_event(mock_event)
result = client._process_stream_event(mock_event)
# message_stop events return None
assert result is None
@@ -684,7 +684,7 @@ def test_process_stream_event_simple(mock_anthropic_client: MagicMock) -> None:
async def test_inner_get_response(mock_anthropic_client: MagicMock) -> None:
"""Test _inner_get_response method."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
# Create a mock message response
mock_message = MagicMock(spec=BetaMessage)
@@ -696,10 +696,10 @@ async def test_inner_get_response(mock_anthropic_client: MagicMock) -> None:
mock_anthropic_client.beta.messages.create.return_value = mock_message
messages = [ChatMessage(role="user", text="Hi")]
messages = [Message(role="user", text="Hi")]
chat_options = ChatOptions(max_tokens=10)
response = await chat_client._inner_get_response( # type: ignore[attr-defined]
response = await client._inner_get_response( # type: ignore[attr-defined]
messages=messages, options=chat_options
)
@@ -710,7 +710,7 @@ async def test_inner_get_response(mock_anthropic_client: MagicMock) -> None:
async def test_inner_get_response_streaming(mock_anthropic_client: MagicMock) -> None:
"""Test _inner_get_response method with streaming."""
chat_client = create_test_anthropic_client(mock_anthropic_client)
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock streaming response
async def mock_stream():
@@ -720,11 +720,11 @@ async def test_inner_get_response_streaming(mock_anthropic_client: MagicMock) ->
mock_anthropic_client.beta.messages.create.return_value = mock_stream()
messages = [ChatMessage(role="user", text="Hi")]
messages = [Message(role="user", text="Hi")]
chat_options = ChatOptions(max_tokens=10)
chunks: list[ChatResponseUpdate] = []
async for chunk in chat_client._inner_get_response( # type: ignore[attr-defined]
async for chunk in client._inner_get_response( # type: ignore[attr-defined]
messages=messages, options=chat_options, stream=True
):
if chunk:
@@ -751,7 +751,7 @@ async def test_anthropic_client_integration_basic_chat() -> None:
"""Integration test for basic chat completion."""
client = AnthropicClient()
messages = [ChatMessage(role="user", text="Say 'Hello, World!' and nothing else.")]
messages = [Message(role="user", text="Say 'Hello, World!' and nothing else.")]
response = await client.get_response(messages=messages, options={"max_tokens": 50})
@@ -768,7 +768,7 @@ async def test_anthropic_client_integration_streaming_chat() -> None:
"""Integration test for streaming chat completion."""
client = AnthropicClient()
messages = [ChatMessage(role="user", text="Count from 1 to 5.")]
messages = [Message(role="user", text="Count from 1 to 5.")]
chunks = []
async for chunk in client.get_response(messages=messages, stream=True, options={"max_tokens": 50}):
@@ -784,7 +784,7 @@ async def test_anthropic_client_integration_function_calling() -> None:
"""Integration test for function calling."""
client = AnthropicClient()
messages = [ChatMessage(role="user", text="What's the weather in San Francisco?")]
messages = [Message(role="user", text="What's the weather in San Francisco?")]
tools = [get_weather]
response = await client.get_response(
@@ -804,7 +804,7 @@ async def test_anthropic_client_integration_hosted_tools() -> None:
"""Integration test for hosted tools."""
client = AnthropicClient()
messages = [ChatMessage(role="user", text="What tools do you have available?")]
messages = [Message(role="user", text="What tools do you have available?")]
tools = [
HostedWebSearchTool(),
HostedCodeInterpreterTool(),
@@ -831,8 +831,8 @@ async def test_anthropic_client_integration_with_system_message() -> None:
client = AnthropicClient()
messages = [
ChatMessage(role="system", text="You are a pirate. Always respond like a pirate."),
ChatMessage(role="user", text="Hello!"),
Message(role="system", text="You are a pirate. Always respond like a pirate."),
Message(role="user", text="Hello!"),
]
response = await client.get_response(messages=messages, options={"max_tokens": 50})
@@ -847,7 +847,7 @@ async def test_anthropic_client_integration_temperature_control() -> None:
"""Integration test with temperature control."""
client = AnthropicClient()
messages = [ChatMessage(role="user", text="Say hello.")]
messages = [Message(role="user", text="Say hello.")]
response = await client.get_response(
messages=messages,
@@ -865,11 +865,11 @@ async def test_anthropic_client_integration_ordering() -> None:
client = AnthropicClient()
messages = [
ChatMessage(role="user", text="Say hello."),
ChatMessage(role="user", text="Then say goodbye."),
ChatMessage(role="assistant", text="Thank you for chatting!"),
ChatMessage(role="assistant", text="Let me know if I can help."),
ChatMessage(role="user", text="Just testing things."),
Message(role="user", text="Say hello."),
Message(role="user", text="Then say goodbye."),
Message(role="assistant", text="Thank you for chatting!"),
Message(role="assistant", text="Let me know if I can help."),
Message(role="user", text="Just testing things."),
]
response = await client.get_response(messages=messages)
@@ -890,7 +890,7 @@ async def test_anthropic_client_integration_images() -> None:
image_bytes = img_file.read()
messages = [
ChatMessage(
Message(
role="user",
contents=[
Content.from_text(text="Describe this image"),