mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: added ChatClientBase with function calling (#147)
* added ChatClientBase with function calling * streaming update * fixed typing * test setup * small update * src setup * removed src, updated test naming * fixed test command * alolow args * updated test run * added unit test folder to azure * added init and unit test to azure * added other cross tests * restructured * reset test run * fix name * removed always * updated test * extend pytest.xml locations * run surface always * added decorators for FC and marked tests * fixed mypy settings and added tests * fix override import * removed import
This commit is contained in:
committed by
GitHub
Unverified
parent
daf4788868
commit
3449902b03
@@ -1,115 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from collections.abc import AsyncIterable, Sequence
|
||||
from typing import Any, TypeVar
|
||||
from uuid import uuid4
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pytest import fixture
|
||||
|
||||
from agent_framework import Agent, AgentThread, ChatMessage, ChatResponse, ChatResponseUpdate, ChatRole, TextContent
|
||||
|
||||
TThreadType = TypeVar("TThreadType", bound=AgentThread)
|
||||
|
||||
|
||||
# Mock AgentThread implementation for testing
|
||||
class MockAgentThread(AgentThread):
|
||||
async def _create(self) -> str:
|
||||
return str(uuid4())
|
||||
|
||||
async def _delete(self) -> None:
|
||||
pass
|
||||
|
||||
async def _on_new_message(self, new_messages: ChatMessage | Sequence[ChatMessage]) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# Mock Agent implementation for testing
|
||||
class MockAgent(BaseModel):
|
||||
id: str = Field(default_factory=lambda: str(uuid4()))
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
instructions: str | None = None
|
||||
|
||||
async def run(
|
||||
self,
|
||||
messages: ChatMessage | str | list[ChatMessage] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
**kwargs: Any,
|
||||
) -> ChatResponse:
|
||||
return ChatResponse(messages=[ChatMessage(role=ChatRole.ASSISTANT, contents=[TextContent("Response")])])
|
||||
|
||||
async def run_stream(
|
||||
self,
|
||||
messages: str | ChatMessage | list[ChatMessage] | None = None,
|
||||
*,
|
||||
thread: AgentThread | None = None,
|
||||
**kwargs: Any,
|
||||
) -> AsyncIterable[ChatResponseUpdate]:
|
||||
yield ChatResponseUpdate(contents=[TextContent("Response")])
|
||||
|
||||
def get_new_thread(self) -> AgentThread:
|
||||
return MockAgentThread()
|
||||
|
||||
|
||||
@fixture
|
||||
def agent_thread() -> AgentThread:
|
||||
return MockAgentThread()
|
||||
|
||||
|
||||
@fixture
|
||||
def agent() -> Agent:
|
||||
return MockAgent()
|
||||
|
||||
|
||||
def test_agent_thread_type(agent_thread: AgentThread) -> None:
|
||||
assert isinstance(agent_thread, AgentThread)
|
||||
|
||||
|
||||
async def test_agent_thread_id_property(agent_thread: AgentThread) -> None:
|
||||
assert agent_thread.id is None
|
||||
await agent_thread.create()
|
||||
assert isinstance(agent_thread.id, str)
|
||||
|
||||
|
||||
async def test_agent_thread_create(agent_thread: AgentThread) -> None:
|
||||
thread_id = await agent_thread.create()
|
||||
assert thread_id == agent_thread.id
|
||||
assert isinstance(thread_id, str)
|
||||
|
||||
|
||||
async def test_agent_thread_create_already_exists(agent_thread: AgentThread) -> None:
|
||||
thread_id = await agent_thread.create()
|
||||
same_id = await agent_thread.create()
|
||||
assert thread_id == same_id
|
||||
|
||||
|
||||
async def test_agent_thread_delete_already_deleted(agent_thread: AgentThread) -> None:
|
||||
await agent_thread.delete()
|
||||
await agent_thread.delete() # Should not raise error
|
||||
|
||||
|
||||
async def test_agent_thread_on_new_message_creates_thread(agent_thread: AgentThread) -> None:
|
||||
message = ChatMessage(role=ChatRole.USER, contents=[TextContent("Hello")])
|
||||
await agent_thread.on_new_message(message)
|
||||
assert agent_thread.id is not None
|
||||
|
||||
|
||||
def test_agent_type(agent: Agent) -> None:
|
||||
assert isinstance(agent, Agent)
|
||||
|
||||
|
||||
async def test_agent_run(agent: Agent) -> None:
|
||||
response = await agent.run("test")
|
||||
assert response.messages[0].role == ChatRole.ASSISTANT
|
||||
assert response.messages[0].text == "Response"
|
||||
|
||||
|
||||
async def test_agent_run_stream(agent: Agent) -> None:
|
||||
async def collect_updates(updates: AsyncIterable[ChatResponseUpdate]) -> list[ChatResponseUpdate]:
|
||||
return [u async for u in updates]
|
||||
|
||||
updates = await collect_updates(agent.run_stream(messages="test"))
|
||||
assert len(updates) == 1
|
||||
assert updates[0].text == "Response"
|
||||
@@ -1,93 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from collections.abc import AsyncIterable, Sequence
|
||||
from typing import Any
|
||||
|
||||
from pytest import fixture
|
||||
|
||||
from agent_framework import (
|
||||
ChatClient,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
ChatRole,
|
||||
EmbeddingGenerator,
|
||||
GeneratedEmbeddings,
|
||||
TextContent,
|
||||
)
|
||||
|
||||
|
||||
class ImplementedChatClient:
|
||||
"""Simple implementation of a chat client."""
|
||||
|
||||
async def get_response(
|
||||
self,
|
||||
messages: ChatMessage | Sequence[ChatMessage],
|
||||
**kwargs: Any,
|
||||
) -> ChatResponse:
|
||||
# Implement the method
|
||||
|
||||
return ChatResponse(messages=ChatMessage(role="assistant", text="test response"))
|
||||
|
||||
async def get_streaming_response(
|
||||
self,
|
||||
messages: ChatMessage | Sequence[ChatMessage],
|
||||
**kwargs: Any,
|
||||
) -> AsyncIterable[ChatResponseUpdate]:
|
||||
# Implement the method
|
||||
yield ChatResponseUpdate(text=TextContent(text="test streaming response"), role="assistant")
|
||||
yield ChatResponseUpdate(contents=[TextContent(text="another update")], role="assistant")
|
||||
|
||||
|
||||
class ImplementedEmbeddingGenerator:
|
||||
"""Simple implementation of an embedding generator."""
|
||||
|
||||
async def generate(
|
||||
self,
|
||||
input_data: Sequence[str],
|
||||
**kwargs: Any,
|
||||
) -> GeneratedEmbeddings[list[float]]:
|
||||
# Implement the method
|
||||
embeddings = GeneratedEmbeddings[list[float]]()
|
||||
for i, _ in enumerate(input_data):
|
||||
embeddings.append([0.0 * 1, 0.1 * 1, 0.2 * 1, 0.3 * i, 0.4 * i])
|
||||
return embeddings
|
||||
|
||||
|
||||
@fixture
|
||||
def chat_client() -> ImplementedChatClient:
|
||||
return ImplementedChatClient()
|
||||
|
||||
|
||||
@fixture
|
||||
def embedding_generator() -> ImplementedEmbeddingGenerator:
|
||||
gen: EmbeddingGenerator[str, list[float]] = ImplementedEmbeddingGenerator()
|
||||
return gen
|
||||
|
||||
|
||||
def test_chat_client_type(chat_client: ImplementedChatClient):
|
||||
assert isinstance(chat_client, ChatClient)
|
||||
|
||||
|
||||
async def test_chat_client_get_response(chat_client: ImplementedChatClient):
|
||||
response = await chat_client.get_response(ChatMessage(role="user", text="Hello"))
|
||||
assert response.text == "test response"
|
||||
assert response.messages[0].role == ChatRole.ASSISTANT
|
||||
|
||||
|
||||
async def test_chat_client_get_streaming_response(chat_client: ImplementedChatClient):
|
||||
async for update in chat_client.get_streaming_response(ChatMessage(role="user", text="Hello")):
|
||||
assert update.text == "test streaming response" or update.text == "another update"
|
||||
assert update.role == ChatRole.ASSISTANT
|
||||
|
||||
|
||||
def test_embedding_generator_type(embedding_generator: ImplementedEmbeddingGenerator):
|
||||
assert isinstance(embedding_generator, EmbeddingGenerator)
|
||||
|
||||
|
||||
async def test_embedding_generator_generate(embedding_generator: ImplementedEmbeddingGenerator):
|
||||
input_data = ["Hello", "world"]
|
||||
embeddings = await embedding_generator.generate(input_data)
|
||||
assert len(embeddings) == len(input_data)
|
||||
for emb in embeddings:
|
||||
assert len(emb) == 5
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from agent_framework import get_logger
|
||||
from agent_framework.exceptions import AgentFrameworkException
|
||||
|
||||
|
||||
def test_get_logger():
|
||||
"""Test that the logger is created with the correct name."""
|
||||
logger = get_logger()
|
||||
assert logger.name == "agent_framework"
|
||||
|
||||
|
||||
def test_get_logger_custom_name():
|
||||
"""Test that the logger can be created with a custom name."""
|
||||
custom_name = "agent_framework.custom"
|
||||
logger = get_logger(custom_name)
|
||||
assert logger.name == custom_name
|
||||
|
||||
|
||||
def test_get_logger_invalid_name():
|
||||
"""Test that an exception is raised for an invalid logger name."""
|
||||
with pytest.raises(AgentFrameworkException, match="Logger name must start with 'agent_framework'."):
|
||||
get_logger("invalid_name")
|
||||
|
||||
|
||||
def test_log(caplog):
|
||||
"""Test that the logger can log messages and adheres to the expected format."""
|
||||
logger = get_logger()
|
||||
with caplog.at_level("DEBUG"):
|
||||
logger.debug("This is a debug message")
|
||||
assert len(caplog.records) == 1
|
||||
record = caplog.records[0]
|
||||
assert record.levelname == "DEBUG"
|
||||
assert record.message == "This is a debug message"
|
||||
assert record.name == "agent_framework"
|
||||
assert record.pathname.endswith("test_logging.py")
|
||||
@@ -1,43 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from agent_framework import AITool, ai_function
|
||||
|
||||
|
||||
def test_ai_function_decorator():
|
||||
"""Test the ai_function decorator."""
|
||||
|
||||
@ai_function(name="test_tool", description="A test tool")
|
||||
def test_tool(x: int, y: int) -> int:
|
||||
"""A simple function that adds two numbers."""
|
||||
return x + y
|
||||
|
||||
assert isinstance(test_tool, AITool)
|
||||
assert test_tool.name == "test_tool"
|
||||
assert test_tool.description == "A test tool"
|
||||
assert test_tool.model_json_schema() == {
|
||||
"properties": {"x": {"title": "X", "type": "integer"}, "y": {"title": "Y", "type": "integer"}},
|
||||
"required": ["x", "y"],
|
||||
"title": "test_tool_input",
|
||||
"type": "object",
|
||||
}
|
||||
assert test_tool(1, 2) == 3
|
||||
|
||||
|
||||
async def test_ai_function_decorator_with_async():
|
||||
"""Test the ai_function decorator with an async function."""
|
||||
|
||||
@ai_function(name="async_test_tool", description="An async test tool")
|
||||
async def async_test_tool(x: int, y: int) -> int:
|
||||
"""An async function that adds two numbers."""
|
||||
return x + y
|
||||
|
||||
assert isinstance(async_test_tool, AITool)
|
||||
assert async_test_tool.name == "async_test_tool"
|
||||
assert async_test_tool.description == "An async test tool"
|
||||
assert async_test_tool.model_json_schema() == {
|
||||
"properties": {"x": {"title": "X", "type": "integer"}, "y": {"title": "Y", "type": "integer"}},
|
||||
"required": ["x", "y"],
|
||||
"title": "async_test_tool_input",
|
||||
"type": "object",
|
||||
}
|
||||
assert (await async_test_tool(1, 2)) == 3
|
||||
@@ -1,482 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from collections.abc import MutableSequence
|
||||
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from pytest import mark, raises
|
||||
|
||||
from agent_framework import (
|
||||
AIContent,
|
||||
AIContents,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
ChatRole,
|
||||
ChatToolMode,
|
||||
DataContent,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
GeneratedEmbeddings,
|
||||
StructuredResponse,
|
||||
TextContent,
|
||||
TextReasoningContent,
|
||||
UriContent,
|
||||
UsageDetails,
|
||||
)
|
||||
|
||||
# region: TextContent
|
||||
|
||||
|
||||
def test_text_content_positional():
|
||||
"""Test the TextContent class to ensure it initializes correctly and inherits from AIContent."""
|
||||
# Create an instance of TextContent
|
||||
content = TextContent("Hello, world!", raw_representation="Hello, world!", additional_properties={"version": 1})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "text"
|
||||
assert content.text == "Hello, world!"
|
||||
assert content.raw_representation == "Hello, world!"
|
||||
assert content.additional_properties["version"] == 1
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
with raises(ValidationError):
|
||||
content.type = "ai"
|
||||
|
||||
|
||||
def test_text_content_keyword():
|
||||
"""Test the TextContent class to ensure it initializes correctly and inherits from AIContent."""
|
||||
# Create an instance of TextContent
|
||||
content = TextContent(
|
||||
text="Hello, world!", raw_representation="Hello, world!", additional_properties={"version": 1}
|
||||
)
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "text"
|
||||
assert content.text == "Hello, world!"
|
||||
assert content.raw_representation == "Hello, world!"
|
||||
assert content.additional_properties["version"] == 1
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
with raises(ValidationError):
|
||||
content.type = "ai"
|
||||
|
||||
|
||||
# region: DataContent
|
||||
|
||||
|
||||
def test_data_content_bytes():
|
||||
"""Test the DataContent class to ensure it initializes correctly."""
|
||||
# Create an instance of DataContent
|
||||
content = DataContent(data=b"test", media_type="application/octet-stream", additional_properties={"version": 1})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "data"
|
||||
assert content.uri == "data:application/octet-stream;base64,dGVzdA=="
|
||||
assert content.additional_properties["version"] == 1
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
|
||||
|
||||
def test_data_content_uri():
|
||||
"""Test the DataContent class to ensure it initializes correctly with a URI."""
|
||||
# Create an instance of DataContent with a URI
|
||||
content = DataContent(uri="data:application/octet-stream;base64,dGVzdA==", additional_properties={"version": 1})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "data"
|
||||
assert content.uri == "data:application/octet-stream;base64,dGVzdA=="
|
||||
assert content.additional_properties["version"] == 1
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
|
||||
|
||||
def test_data_content_invalid():
|
||||
"""Test the DataContent class to ensure it raises an error for invalid initialization."""
|
||||
# Attempt to create an instance of DataContent with invalid data
|
||||
# not a proper uri
|
||||
with raises(ValidationError):
|
||||
DataContent(uri="invalid_uri")
|
||||
# unknown media type
|
||||
with raises(ValidationError):
|
||||
DataContent(uri="data:application/random;base64,dGVzdA==")
|
||||
# not valid base64 data
|
||||
|
||||
with raises(ValidationError):
|
||||
DataContent(uri="data:application/json;base64,dGVzdA&")
|
||||
|
||||
|
||||
def test_data_content_empty():
|
||||
"""Test the DataContent class to ensure it raises an error for empty data."""
|
||||
# Attempt to create an instance of DataContent with empty data
|
||||
with raises(ValidationError):
|
||||
DataContent(data=b"", media_type="application/octet-stream")
|
||||
|
||||
# Attempt to create an instance of DataContent with empty URI
|
||||
with raises(ValidationError):
|
||||
DataContent(uri="")
|
||||
|
||||
|
||||
# region: UriContent
|
||||
|
||||
|
||||
def test_uri_content():
|
||||
"""Test the UriContent class to ensure it initializes correctly."""
|
||||
content = UriContent(uri="http://example.com", media_type="image/jpg", additional_properties={"version": 1})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "uri"
|
||||
assert content.uri == "http://example.com"
|
||||
assert content.media_type == "image/jpg"
|
||||
assert content.additional_properties["version"] == 1
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
|
||||
|
||||
# region: FunctionCallContent
|
||||
|
||||
|
||||
def test_function_call_content():
|
||||
"""Test the FunctionCallContent class to ensure it initializes correctly."""
|
||||
content = FunctionCallContent(call_id="1", name="example_function", arguments={"param1": "value1"})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "function_call"
|
||||
assert content.name == "example_function"
|
||||
assert content.arguments == {"param1": "value1"}
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
|
||||
|
||||
# region: FunctionResultContent
|
||||
|
||||
|
||||
def test_function_result_content():
|
||||
"""Test the FunctionResultContent class to ensure it initializes correctly."""
|
||||
content = FunctionResultContent(call_id="1", result={"param1": "value1"})
|
||||
|
||||
# Check the type and content
|
||||
assert content.type == "function_result"
|
||||
assert content.result == {"param1": "value1"}
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(content, AIContent)
|
||||
|
||||
|
||||
# region: UsageDetails
|
||||
|
||||
|
||||
def test_usage_details():
|
||||
usage = UsageDetails(input_token_count=5, output_token_count=10, total_token_count=15)
|
||||
assert usage.input_token_count == 5
|
||||
assert usage.output_token_count == 10
|
||||
assert usage.total_token_count == 15
|
||||
assert usage.additional_counts == {}
|
||||
|
||||
|
||||
def test_usage_details_addition():
|
||||
usage1 = UsageDetails(
|
||||
input_token_count=5,
|
||||
output_token_count=10,
|
||||
total_token_count=15,
|
||||
test1=10,
|
||||
test2=20,
|
||||
)
|
||||
usage2 = UsageDetails(
|
||||
input_token_count=3,
|
||||
output_token_count=6,
|
||||
total_token_count=9,
|
||||
test1=10,
|
||||
test3=30,
|
||||
)
|
||||
|
||||
combined_usage = usage1 + usage2
|
||||
assert combined_usage.input_token_count == 8
|
||||
assert combined_usage.output_token_count == 16
|
||||
assert combined_usage.total_token_count == 24
|
||||
assert combined_usage.additional_counts["test1"] == 20
|
||||
assert combined_usage.additional_counts["test2"] == 20
|
||||
assert combined_usage.additional_counts["test3"] == 30
|
||||
|
||||
|
||||
def test_usage_details_fail():
|
||||
with raises(ValidationError):
|
||||
UsageDetails(input_token_count=5, output_token_count=10, total_token_count=15, wrong_type="42.923")
|
||||
|
||||
|
||||
def test_usage_details_additional_counts():
|
||||
usage = UsageDetails(input_token_count=5, output_token_count=10, total_token_count=15, **{"test": 1})
|
||||
assert usage.additional_counts["test"] == 1
|
||||
|
||||
|
||||
# region: AIContent Serialization
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"content_type, args",
|
||||
[
|
||||
(TextContent, {"text": "Hello, world!"}),
|
||||
(DataContent, {"data": b"Hello, world!", "media_type": "text/plain"}),
|
||||
(UriContent, {"uri": "http://example.com", "media_type": "text/html"}),
|
||||
(FunctionCallContent, {"call_id": "1", "name": "example_function", "arguments": {}}),
|
||||
(FunctionResultContent, {"call_id": "1", "result": {}}),
|
||||
],
|
||||
)
|
||||
def test_ai_content_serialization(content_type: type[AIContent], args: dict):
|
||||
content = content_type(**args)
|
||||
serialized = content.model_dump()
|
||||
deserialized = content_type.model_validate(serialized)
|
||||
assert deserialized == content
|
||||
|
||||
class TestModel(BaseModel):
|
||||
content: AIContents
|
||||
|
||||
test_item = TestModel.model_validate({"content": serialized})
|
||||
|
||||
assert isinstance(test_item.content, content_type)
|
||||
|
||||
|
||||
# region: ChatMessage
|
||||
|
||||
|
||||
def test_chat_message_text():
|
||||
"""Test the ChatMessage class to ensure it initializes correctly with text content."""
|
||||
# Create a ChatMessage with a role and text content
|
||||
message = ChatMessage(role="user", text="Hello, how are you?")
|
||||
|
||||
# Check the type and content
|
||||
assert message.role == ChatRole.USER
|
||||
assert len(message.contents) == 1
|
||||
assert isinstance(message.contents[0], TextContent)
|
||||
assert message.contents[0].text == "Hello, how are you?"
|
||||
assert message.text == "Hello, how are you?"
|
||||
|
||||
# Ensure the instance is of type AIContent
|
||||
assert isinstance(message.contents[0], AIContent)
|
||||
|
||||
|
||||
def test_chat_message_contents():
|
||||
"""Test the ChatMessage class to ensure it initializes correctly with contents."""
|
||||
# Create a ChatMessage with a role and multiple contents
|
||||
content1 = TextContent("Hello, how are you?")
|
||||
content2 = TextContent("I'm fine, thank you!")
|
||||
message = ChatMessage(role="user", contents=[content1, content2])
|
||||
|
||||
# Check the type and content
|
||||
assert message.role == ChatRole.USER
|
||||
assert len(message.contents) == 2
|
||||
assert isinstance(message.contents[0], TextContent)
|
||||
assert isinstance(message.contents[1], TextContent)
|
||||
assert message.contents[0].text == "Hello, how are you?"
|
||||
assert message.contents[1].text == "I'm fine, thank you!"
|
||||
assert message.text == "Hello, how are you?\nI'm fine, thank you!"
|
||||
|
||||
|
||||
# region: ChatResponse
|
||||
|
||||
|
||||
def test_chat_response():
|
||||
"""Test the ChatResponse class to ensure it initializes correctly with a message."""
|
||||
# Create a ChatMessage
|
||||
message = ChatMessage(role="assistant", text="I'm doing well, thank you!")
|
||||
|
||||
# Create a ChatResponse with the message
|
||||
response = ChatResponse(messages=message)
|
||||
|
||||
# Check the type and content
|
||||
assert response.messages[0].role == ChatRole.ASSISTANT
|
||||
assert response.messages[0].text == "I'm doing well, thank you!"
|
||||
assert isinstance(response.messages[0], ChatMessage)
|
||||
|
||||
|
||||
# region: StructuredResponse
|
||||
|
||||
|
||||
def test_structured_response():
|
||||
"""Test the StructuredResponse class to ensure it initializes correctly with a value."""
|
||||
|
||||
class ResponseModel(BaseModel):
|
||||
content: str
|
||||
action: str
|
||||
|
||||
# Create a StructuredResponse with a value
|
||||
response = StructuredResponse[ResponseModel](
|
||||
value=ResponseModel(content="Hello, world!", action="test"),
|
||||
text="{'content': 'Hello, world!', 'action': 'test'}",
|
||||
)
|
||||
|
||||
# Check the type and content
|
||||
assert response.value == ResponseModel(content="Hello, world!", action="test")
|
||||
assert isinstance(response, StructuredResponse)
|
||||
|
||||
|
||||
# region: ChatResponseUpdate
|
||||
|
||||
|
||||
def test_chat_response_update():
|
||||
"""Test the ChatResponseUpdate class to ensure it initializes correctly with a message."""
|
||||
# Create a ChatMessage
|
||||
message = TextContent(text="I'm doing well, thank you!")
|
||||
|
||||
# Create a ChatResponseUpdate with the message
|
||||
response_update = ChatResponseUpdate(contents=[message])
|
||||
|
||||
# Check the type and content
|
||||
assert response_update.contents[0].text == "I'm doing well, thank you!"
|
||||
assert isinstance(response_update.contents[0], TextContent)
|
||||
|
||||
|
||||
def test_chat_response_updates_to_chat_response_one():
|
||||
"""Test converting ChatResponseUpdate to ChatResponse."""
|
||||
# Create a ChatMessage
|
||||
message1 = TextContent("I'm doing well, ")
|
||||
message2 = TextContent("thank you!")
|
||||
|
||||
# Create a ChatResponseUpdate with the message
|
||||
response_updates = [
|
||||
ChatResponseUpdate(text=message1, message_id="1"),
|
||||
ChatResponseUpdate(text=message2, message_id="1"),
|
||||
]
|
||||
|
||||
# Convert to ChatResponse
|
||||
chat_response = ChatResponse.from_chat_response_updates(response_updates)
|
||||
|
||||
# Check the type and content
|
||||
assert len(chat_response.messages) == 1
|
||||
assert chat_response.text == "I'm doing well, \nthank you!"
|
||||
assert isinstance(chat_response.messages[0], ChatMessage)
|
||||
assert len(chat_response.messages[0].contents) == 1
|
||||
assert chat_response.messages[0].message_id == "1"
|
||||
|
||||
|
||||
def test_chat_response_updates_to_chat_response_two():
|
||||
"""Test converting ChatResponseUpdate to ChatResponse."""
|
||||
# Create a ChatMessage
|
||||
message1 = TextContent("I'm doing well, ")
|
||||
message2 = TextContent("thank you!")
|
||||
|
||||
# Create a ChatResponseUpdate with the message
|
||||
response_updates = [
|
||||
ChatResponseUpdate(text=message1, message_id="1"),
|
||||
ChatResponseUpdate(text=message2, message_id="2"),
|
||||
]
|
||||
|
||||
# Convert to ChatResponse
|
||||
chat_response = ChatResponse.from_chat_response_updates(response_updates)
|
||||
|
||||
# Check the type and content
|
||||
assert len(chat_response.messages) == 2
|
||||
assert chat_response.text == "I'm doing well, \nthank you!"
|
||||
assert isinstance(chat_response.messages[0], ChatMessage)
|
||||
assert chat_response.messages[0].message_id == "1"
|
||||
assert isinstance(chat_response.messages[1], ChatMessage)
|
||||
assert chat_response.messages[1].message_id == "2"
|
||||
|
||||
|
||||
def test_chat_response_updates_to_chat_response_multiple():
|
||||
"""Test converting ChatResponseUpdate to ChatResponse."""
|
||||
# Create a ChatMessage
|
||||
message1 = TextContent("I'm doing well, ")
|
||||
message2 = TextContent("thank you!")
|
||||
|
||||
# Create a ChatResponseUpdate with the message
|
||||
response_updates = [
|
||||
ChatResponseUpdate(text=message1, message_id="1"),
|
||||
ChatResponseUpdate(contents=[TextReasoningContent(text="Additional context")], message_id="1"),
|
||||
ChatResponseUpdate(text=message2, message_id="1"),
|
||||
]
|
||||
|
||||
# Convert to ChatResponse
|
||||
chat_response = ChatResponse.from_chat_response_updates(response_updates)
|
||||
|
||||
# Check the type and content
|
||||
assert len(chat_response.messages) == 1
|
||||
assert chat_response.text == "I'm doing well, \nthank you!"
|
||||
assert isinstance(chat_response.messages[0], ChatMessage)
|
||||
assert len(chat_response.messages[0].contents) == 3
|
||||
assert chat_response.messages[0].message_id == "1"
|
||||
|
||||
|
||||
def test_chat_response_updates_to_chat_response_multiple_multiple():
|
||||
"""Test converting ChatResponseUpdate to ChatResponse."""
|
||||
# Create a ChatMessage
|
||||
message1 = TextContent("I'm doing well, ")
|
||||
message2 = TextContent("thank you!")
|
||||
|
||||
# Create a ChatResponseUpdate with the message
|
||||
response_updates = [
|
||||
ChatResponseUpdate(text=message1, message_id="1"),
|
||||
ChatResponseUpdate(text=message2, message_id="1"),
|
||||
ChatResponseUpdate(contents=[TextReasoningContent(text="Additional context")], message_id="1"),
|
||||
ChatResponseUpdate(contents=[TextContent(text="More context")], message_id="1"),
|
||||
ChatResponseUpdate(text="Final part", message_id="1"),
|
||||
]
|
||||
|
||||
# Convert to ChatResponse
|
||||
chat_response = ChatResponse.from_chat_response_updates(response_updates)
|
||||
|
||||
# Check the type and content
|
||||
assert len(chat_response.messages) == 1
|
||||
assert chat_response.text == "I'm doing well, \nthank you!\nMore context\nFinal part"
|
||||
assert isinstance(chat_response.messages[0], ChatMessage)
|
||||
assert len(chat_response.messages[0].contents) == 3
|
||||
assert chat_response.messages[0].message_id == "1"
|
||||
|
||||
|
||||
# region: ChatToolMode
|
||||
|
||||
|
||||
def test_chat_tool_mode():
|
||||
"""Test the ChatToolMode class to ensure it initializes correctly."""
|
||||
# Create instances of ChatToolMode
|
||||
auto_mode = ChatToolMode.AUTO
|
||||
required_any = ChatToolMode.REQUIRED_ANY
|
||||
required_mode = ChatToolMode.REQUIRED("example_function")
|
||||
none_mode = ChatToolMode.NONE
|
||||
|
||||
# Check the type and content
|
||||
assert auto_mode.mode == "auto"
|
||||
assert auto_mode.required_function_name is None
|
||||
assert required_any.mode == "required"
|
||||
assert required_any.required_function_name is None
|
||||
assert required_mode.mode == "required"
|
||||
assert required_mode.required_function_name == "example_function"
|
||||
assert none_mode.mode == "none"
|
||||
assert none_mode.required_function_name is None
|
||||
|
||||
# Ensure the instances are of type ChatToolMode
|
||||
assert isinstance(auto_mode, ChatToolMode)
|
||||
assert isinstance(required_any, ChatToolMode)
|
||||
assert isinstance(required_mode, ChatToolMode)
|
||||
assert isinstance(none_mode, ChatToolMode)
|
||||
|
||||
assert ChatToolMode.REQUIRED("example_function") == ChatToolMode.REQUIRED("example_function")
|
||||
|
||||
|
||||
def test_chat_tool_mode_from_dict():
|
||||
"""Test creating ChatToolMode from a dictionary."""
|
||||
mode_dict = {"mode": "required", "required_function_name": "example_function"}
|
||||
mode = ChatToolMode(**mode_dict)
|
||||
|
||||
# Check the type and content
|
||||
assert mode.mode == "required"
|
||||
assert mode.required_function_name == "example_function"
|
||||
|
||||
# Ensure the instance is of type ChatToolMode
|
||||
assert isinstance(mode, ChatToolMode)
|
||||
|
||||
|
||||
def test_generated_embeddings():
|
||||
"""Test the GeneratedEmbeddings class to ensure it initializes correctly."""
|
||||
# Create an instance of GeneratedEmbeddings
|
||||
embeddings = GeneratedEmbeddings(embeddings=[[0.1, 0.2, 0.3]])
|
||||
|
||||
# Check the type and content
|
||||
assert embeddings.embeddings == [[0.1, 0.2, 0.3]]
|
||||
|
||||
# Ensure the instance is of type GeneratedEmbeddings
|
||||
assert isinstance(embeddings, GeneratedEmbeddings)
|
||||
assert issubclass(GeneratedEmbeddings, MutableSequence)
|
||||
@@ -1,8 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
|
||||
from agent_framework import __version__
|
||||
|
||||
|
||||
def test_version():
|
||||
assert __version__ is not None
|
||||
Reference in New Issue
Block a user