mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
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:
co-authored by
Evan Mattson
parent
a4c9e43afb
commit
0521f5bed8
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user