Python: [BREAKING] update to v1.0.0 (#5062)

* updates to final deprecated pieces and versions

* fix mypy

* fix readme links
This commit is contained in:
Eduard van Valkenburg
2026-04-02 17:26:30 +02:00
committed by GitHub
Unverified
parent 5f06b68535
commit 3446eb8d5d
171 changed files with 2580 additions and 2392 deletions
+1 -1
View File
@@ -136,7 +136,7 @@ from agent_framework import BaseChatClient, ChatResponse, Message
class MyClient(BaseChatClient):
async def _inner_get_response(self, *, messages, options, **kwargs) -> ChatResponse:
# Call your LLM here
return ChatResponse(messages=[Message(role="assistant", text="Hi!")])
return ChatResponse(messages=[Message(role="assistant", contents=["Hi!"])])
async def _inner_get_streaming_response(self, *, messages, options, **kwargs):
yield ChatResponseUpdate(...)
+3 -3
View File
@@ -13,11 +13,11 @@ Highlights
## Quick Install
```bash
pip install agent-framework-core --pre
pip install agent-framework-core
# Optional: Add Azure AI Foundry integration
pip install agent-framework-foundry --pre
pip install agent-framework-foundry
# Optional: Add OpenAI integration
pip install agent-framework-openai --pre
pip install agent-framework-openai
```
Supported Platforms:
@@ -102,8 +102,6 @@ from ._middleware import (
)
from ._sessions import (
AgentSession,
BaseContextProvider, # type: ignore[reportDeprecated]
BaseHistoryProvider, # type: ignore[reportDeprecated]
ContextProvider,
HistoryProvider,
InMemoryHistoryProvider,
@@ -280,9 +278,7 @@ __all__ = [
"Annotation",
"BaseAgent",
"BaseChatClient",
"BaseContextProvider",
"BaseEmbeddingClient",
"BaseHistoryProvider",
"Case",
"CharacterEstimatorTokenizer",
"ChatAndFunctionMiddlewareTypes",
@@ -253,7 +253,8 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
else:
# Non-streaming implementation
return ChatResponse(
messages=[Message(role="assistant", text="Hello!")], response_id="custom-response"
messages=[Message(role="assistant", contents=["Hello!"])],
response_id="custom-response",
)
@@ -261,9 +262,9 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]):
client = CustomChatClient()
# Use the client to get responses
response = await client.get_response([Message(role="user", text="Hello, how are you?")])
response = await client.get_response([Message(role="user", contents=["Hello, how are you?"])])
# Or stream responses
async for update in client.get_response([Message(role="user", text="Hello!")], stream=True):
async for update in client.get_response([Message(role="user", contents=["Hello!"])], stream=True):
print(update)
"""
@@ -877,7 +877,7 @@ class ToolResultCompactionStrategy:
insertion_index = starts.get(group_id, 0)
summary_message = Message(
role="assistant",
text=summary_text,
contents=[summary_text],
message_id=summary_id,
additional_properties={
GROUP_ANNOTATION_KEY: summary_annotation,
@@ -1015,10 +1015,10 @@ class SummarizationStrategy:
try:
summary_response: ChatResponse[None] = await self.client.get_response(
[
Message(role="system", text=self.prompt),
Message(role="system", contents=[self.prompt]),
Message(
role="user",
text=_format_messages_for_summary(messages_to_summarize),
contents=[_format_messages_for_summary(messages_to_summarize)],
),
],
stream=False,
@@ -1044,7 +1044,7 @@ class SummarizationStrategy:
summary_message = Message(
role="assistant",
text=summary_text,
contents=[summary_text],
message_id=summary_id,
additional_properties={
GROUP_ANNOTATION_KEY: summary_annotation,
@@ -502,7 +502,7 @@ class ChatMiddleware(ABC):
# Add system prompt to messages
from agent_framework import Message
context.messages.insert(0, Message(role="system", text=self.system_prompt))
context.messages.insert(0, Message(role="system", contents=[self.system_prompt]))
# Continue execution
await call_next()
@@ -40,7 +40,7 @@ class SerializationProtocol(Protocol):
# Message implements SerializationProtocol via SerializationMixin
user_msg = Message(role="user", text="What's the weather like today?")
user_msg = Message(role="user", contents=["What's the weather like today?"])
# Serialize to dictionary - automatic type identification and nested serialization
msg_dict = user_msg.to_dict()
@@ -13,17 +13,11 @@ This module provides the core types for the context provider pipeline:
from __future__ import annotations
import copy
import sys
import uuid
from abc import abstractmethod
from collections.abc import Awaitable, Callable, Mapping, Sequence
from typing import TYPE_CHECKING, Any, ClassVar, TypeGuard, cast
if sys.version_info >= (3, 13):
from warnings import deprecated # type: ignore # pragma: no cover
else:
from typing_extensions import deprecated # type: ignore # pragma: no cover
from ._middleware import ChatContext, ChatMiddleware
from ._types import AgentResponse, ChatResponse, Message, ResponseStream
from .exceptions import ChatClientInvalidResponseException
@@ -698,30 +692,6 @@ class PerServiceCallHistoryPersistingMiddleware(ChatMiddleware):
)
@deprecated(
"BaseContextProvider is deprecated. Use ContextProvider instead.",
category=DeprecationWarning,
)
class BaseContextProvider(ContextProvider):
"""Deprecated alias for :class:`ContextProvider`.
.. deprecated::
BaseContextProvider is deprecated. Use :class:`ContextProvider` instead.
"""
@deprecated(
"BaseHistoryProvider is deprecated. Use HistoryProvider instead.",
category=DeprecationWarning,
)
class BaseHistoryProvider(HistoryProvider):
"""Deprecated alias for :class:`HistoryProvider`.
.. deprecated::
BaseHistoryProvider is deprecated. Use :class:`HistoryProvider` instead.
"""
class AgentSession:
"""A conversation session with an agent.
@@ -1669,7 +1669,6 @@ class Message(SerializationMixin):
role: RoleLiteral | str,
contents: Sequence[Content | str | Mapping[str, Any]] | None = None,
*,
text: str | None = None,
author_name: str | None = None,
message_id: str | None = None,
additional_properties: MutableMapping[str, Any] | None = None,
@@ -1683,21 +1682,14 @@ class Message(SerializationMixin):
to TextContent), or dicts (parsed via Content.from_dict). Defaults to empty list.
Keyword Args:
text: Deprecated. Text content of the message. Use contents instead.
This parameter is kept for backward compatibility with serialization.
author_name: Optional name of the author of the message.
message_id: Optional ID of the chat message.
additional_properties: Optional additional properties associated with the chat message.
Additional properties are used within Agent Framework, they are not sent to services.
raw_representation: Optional raw representation of the chat message.
"""
# Handle contents conversion
parsed_contents = [] if contents is None else _parse_content_list(contents)
# Handle text for backward compatibility (from serialization)
if text is not None:
parsed_contents.append(Content.from_text(text=text))
self.role: str = role
self.contents = parsed_contents
self.author_name = author_name
@@ -21,7 +21,7 @@ def normalize_messages_input(
return []
if isinstance(messages, str):
return [Message(role="user", text=messages)]
return [Message(role="user", contents=[messages])]
if isinstance(messages, Content):
return [Message(role="user", contents=[messages])]
@@ -31,9 +31,7 @@ def normalize_messages_input(
normalized: list[Message] = []
for item in messages:
if isinstance(item, str):
normalized.append(Message(role="user", text=item))
elif isinstance(item, Content):
if isinstance(item, (str, Content)):
normalized.append(Message(role="user", contents=[item]))
elif isinstance(item, Message):
normalized.append(item)
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Microsoft Agent Framework for building AI Agents with Python. Thi
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0rc6"
version = "1.0.0"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -12,7 +12,7 @@ urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=ta
urls.issues = "https://github.com/microsoft/agent-framework/issues"
classifiers = [
"License :: OSI Approved :: MIT License",
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
+3 -3
View File
@@ -105,7 +105,7 @@ class MockChatClient:
self.call_count += 1
if self.responses:
return self.responses.pop(0)
return ChatResponse(messages=Message(role="assistant", text="test response"))
return ChatResponse(messages=Message(role="assistant", contents=["test response"]))
return _get()
@@ -186,7 +186,7 @@ class MockBaseChatClient(
logger.debug(f"Running base chat client inner, with: {messages=}, {options=}, {kwargs=}")
self.call_count += 1
if not self.run_responses:
return ChatResponse(messages=Message(role="assistant", text=f"test response - {messages[-1].text}"))
return ChatResponse(messages=Message(role="assistant", contents=[f"test response - {messages[-1].text}"]))
response = self.run_responses.pop(0)
@@ -194,7 +194,7 @@ class MockBaseChatClient(
return ChatResponse(
messages=Message(
role="assistant",
text="I broke out of the function invocation loop...",
contents=["I broke out of the function invocation loop..."],
),
conversation_id=response.conversation_id,
)
+30 -28
View File
@@ -306,7 +306,7 @@ async def test_chat_client_agent_response_format_dict_from_default_options(
) -> None:
"""AgentResponse.value should parse JSON dicts from default_options response_format."""
json_text = json.dumps({"greeting": "Hello"})
client.responses.append(ChatResponse(messages=Message(role="assistant", text=json_text))) # type: ignore[attr-defined]
client.responses.append(ChatResponse(messages=Message(role="assistant", contents=[json_text]))) # type: ignore[attr-defined]
agent = Agent(
client=client,
@@ -366,13 +366,13 @@ async def test_chat_client_agent_prepare_session_and_messages(
from agent_framework._sessions import InMemoryHistoryProvider
agent = Agent(client=client, context_providers=[InMemoryHistoryProvider()])
message = Message(role="user", text="Hello")
message = Message(role="user", contents=["Hello"])
session = AgentSession()
session.state[InMemoryHistoryProvider.DEFAULT_SOURCE_ID] = {"messages": [message]}
session_context, _ = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=session,
input_messages=[Message(role="user", text="Test")],
input_messages=[Message(role="user", contents=["Test"])],
)
result_messages = session_context.get_messages(include_input=True)
@@ -393,7 +393,7 @@ async def test_prepare_session_does_not_mutate_agent_chat_options(
_, prepared_chat_options = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=session,
input_messages=[Message(role="user", text="Test")],
input_messages=[Message(role="user", contents=["Test"])],
)
assert prepared_chat_options.get("tools") is not None
@@ -444,8 +444,8 @@ async def test_chat_agent_persists_history_per_service_call(
session = AgentSession()
session.state[provider.source_id] = {
"messages": [
Message(role="user", text="Earlier question"),
Message(role="assistant", text="Earlier answer"),
Message(role="user", contents=["Earlier question"]),
Message(role="assistant", contents=["Earlier answer"]),
]
}
chat_client_base.run_responses = [
@@ -462,7 +462,9 @@ async def test_chat_agent_persists_history_per_service_call(
),
response_id="resp_call_1",
),
ChatResponse(messages=Message(role="assistant", text="It is sunny in Seattle."), response_id="resp_call_2"),
ChatResponse(
messages=Message(role="assistant", contents=["It is sunny in Seattle."]), response_id="resp_call_2"
),
]
agent = Agent(
@@ -498,8 +500,8 @@ async def test_chat_agent_persists_history_per_service_call_streaming(
session = AgentSession()
session.state[provider.source_id] = {
"messages": [
Message(role="user", text="Earlier question"),
Message(role="assistant", text="Earlier answer"),
Message(role="user", contents=["Earlier question"]),
Message(role="assistant", contents=["Earlier answer"]),
]
}
chat_client_base.streaming_responses = [
@@ -634,7 +636,7 @@ async def test_per_service_call_persistence_uses_real_service_storage_when_clien
response_id="resp_call_1",
),
ChatResponse(
messages=Message(role="assistant", text="It is sunny in Seattle."),
messages=Message(role="assistant", contents=["It is sunny in Seattle."]),
conversation_id="resp_service_managed",
response_id="resp_call_2",
),
@@ -777,7 +779,7 @@ async def test_chat_agent_without_per_service_call_persistence_preserves_respons
) -> None:
chat_client_base.run_responses = [
ChatResponse(
messages=Message(role="assistant", text="Hello"),
messages=Message(role="assistant", contents=["Hello"]),
response_id="resp_call_1",
)
]
@@ -801,7 +803,7 @@ async def test_per_service_call_persistence_rejects_real_service_conversation_id
session.state[provider.source_id] = {"messages": []}
chat_client_base.run_responses = [
ChatResponse(
messages=Message(role="assistant", text="Hello"),
messages=Message(role="assistant", contents=["Hello"]),
conversation_id="resp_service_managed",
)
]
@@ -1138,7 +1140,7 @@ async def test_chat_agent_context_providers_model_before_run(
client: SupportsChatGetResponse,
) -> None:
"""Test that context providers' before_run is called during agent run."""
mock_provider = MockContextProvider(messages=[Message(role="system", text="Test context instructions")])
mock_provider = MockContextProvider(messages=[Message(role="system", contents=["Test context instructions"])])
agent = Agent(client=client, context_providers=[mock_provider])
await agent.run("Hello")
@@ -1185,7 +1187,7 @@ async def test_chat_agent_context_instructions_in_messages(
client: SupportsChatGetResponse,
) -> None:
"""Test that AI context instructions are included in messages."""
mock_provider = MockContextProvider(messages=[Message(role="system", text="Context-specific instructions")])
mock_provider = MockContextProvider(messages=[Message(role="system", contents=["Context-specific instructions"])])
agent = Agent(
client=client,
instructions="Agent instructions",
@@ -1194,7 +1196,7 @@ async def test_chat_agent_context_instructions_in_messages(
# We need to test the _prepare_session_and_messages method directly
session_context, _ = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=None, input_messages=[Message(role="user", text="Hello")]
session=None, input_messages=[Message(role="user", contents=["Hello"])]
)
messages = session_context.get_messages(include_input=True)
@@ -1219,7 +1221,7 @@ async def test_chat_agent_no_context_instructions(
)
session_context, _ = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=None, input_messages=[Message(role="user", text="Hello")]
session=None, input_messages=[Message(role="user", contents=["Hello"])]
)
messages = session_context.get_messages(include_input=True)
@@ -1233,7 +1235,7 @@ async def test_chat_agent_run_stream_context_providers(
client: SupportsChatGetResponse,
) -> None:
"""Test that context providers work with run method."""
mock_provider = MockContextProvider(messages=[Message(role="system", text="Stream context instructions")])
mock_provider = MockContextProvider(messages=[Message(role="system", contents=["Stream context instructions"])])
agent = Agent(client=client, context_providers=[mock_provider])
# Collect all stream updates and get final response
@@ -1727,7 +1729,7 @@ async def test_agent_tool_without_context_does_not_receive_session(chat_client_b
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
agent = Agent(client=chat_client_base, tools=[echo_session_info])
@@ -1766,7 +1768,7 @@ async def test_agent_tool_receives_explicit_session_via_function_invocation_cont
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
agent = Agent(client=chat_client_base, tools=[capture_session_context])
@@ -1899,8 +1901,8 @@ async def test_chat_agent_compaction_overrides_client_defaults(chat_client_base:
)
await agent.run([
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
])
assert captured_roles == [["user", "assistant"]]
@@ -1924,8 +1926,8 @@ async def test_chat_agent_uses_client_compaction_defaults_when_agent_unset(chat_
agent = Agent(client=chat_client_base)
await agent.run([
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
])
assert captured_roles == [["assistant"]]
@@ -1957,8 +1959,8 @@ async def test_chat_agent_run_level_compaction_and_tokenizer_override_agent_defa
await agent.run(
[
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
],
compaction_strategy=TruncationStrategy(max_n=1, compact_to=1),
tokenizer=_FixedTokenizer(23),
@@ -2352,7 +2354,7 @@ async def test_chat_agent_context_provider_adds_tools_when_agent_has_none(
# Run the agent and verify context tools are added
_, options = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=None, input_messages=[Message(role="user", text="Hello")]
session=None, input_messages=[Message(role="user", contents=["Hello"])]
)
# The context tools should now be in the options
@@ -2381,7 +2383,7 @@ async def test_chat_agent_context_provider_adds_instructions_when_agent_has_none
# Run the agent and verify context instructions are available
_, options = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=None, input_messages=[Message(role="user", text="Hello")]
session=None, input_messages=[Message(role="user", contents=["Hello"])]
)
# The context instructions should now be in the options
@@ -2408,7 +2410,7 @@ async def test_chat_agent_context_provider_adds_middleware_when_agent_has_none(
session_context, _ = await agent._prepare_session_and_messages( # type: ignore[reportPrivateUsage]
session=None,
input_messages=[Message(role="user", text="Hello")],
input_messages=[Message(role="user", contents=["Hello"])],
)
assert session_context.middleware["middleware-context"] == [context_chat_middleware]
@@ -40,7 +40,7 @@ class TestAsToolKwargsPropagation:
# Setup mock response
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="Response from sub-agent")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from sub-agent"])]),
]
# Create sub-agent with middleware
@@ -82,7 +82,7 @@ class TestAsToolKwargsPropagation:
# Setup mock response
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="Response from sub-agent")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from sub-agent"])]),
]
sub_agent = Agent(
@@ -133,8 +133,8 @@ class TestAsToolKwargsPropagation:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Response from agent_c")]),
ChatResponse(messages=[Message(role="assistant", text="Response from agent_b")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from agent_c"])]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from agent_b"])]),
]
# Create agent C (bottom level)
@@ -219,7 +219,7 @@ class TestAsToolKwargsPropagation:
"""Test that as_tool works correctly when no extra kwargs are provided."""
# Setup mock response
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="Response from agent")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from agent"])]),
]
sub_agent = Agent(
@@ -248,7 +248,7 @@ class TestAsToolKwargsPropagation:
# Setup mock response
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="Response with options")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response with options"])]),
]
sub_agent = Agent(
@@ -295,8 +295,8 @@ class TestAsToolKwargsPropagation:
# Setup mock responses for both calls
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="First response")]),
ChatResponse(messages=[Message(role="assistant", text="Second response")]),
ChatResponse(messages=[Message(role="assistant", contents=["First response"])]),
ChatResponse(messages=[Message(role="assistant", contents=["Second response"])]),
]
sub_agent = Agent(
@@ -342,7 +342,7 @@ class TestAsToolKwargsPropagation:
# Setup mock response
client.responses = [
ChatResponse(messages=[Message(role="assistant", text="Response from sub-agent")]),
ChatResponse(messages=[Message(role="assistant", contents=["Response from sub-agent"])]),
]
sub_agent = Agent(
+21 -21
View File
@@ -31,13 +31,13 @@ def test_chat_client_type(client: SupportsChatGetResponse):
async def test_chat_client_get_response(client: SupportsChatGetResponse):
response = await client.get_response([Message(role="user", text="Hello")])
response = await client.get_response([Message(role="user", contents=["Hello"])])
assert response.text == "test response"
assert response.messages[0].role == "assistant"
async def test_chat_client_get_response_streaming(client: SupportsChatGetResponse):
async for update in client.get_response([Message(role="user", text="Hello")], stream=True):
async for update in client.get_response([Message(role="user", contents=["Hello"])], stream=True):
assert update.text == "test streaming response " or update.text == "another update"
assert update.role == "assistant"
@@ -62,7 +62,7 @@ async def test_base_client_get_response_uses_explicit_client_kwargs(chat_client_
async def fake_inner_get_response(**kwargs):
assert kwargs["trace_id"] == "trace-123"
assert "function_invocation_kwargs" not in kwargs
return ChatResponse(messages=[Message(role="assistant", text="ok")])
return ChatResponse(messages=[Message(role="assistant", contents=["ok"])])
with patch.object(
chat_client_base,
@@ -70,7 +70,7 @@ async def test_base_client_get_response_uses_explicit_client_kwargs(chat_client_
side_effect=fake_inner_get_response,
) as mock_inner_get_response:
await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
function_invocation_kwargs={"tool_request_id": "tool-123"},
client_kwargs={"trace_id": "trace-123"},
)
@@ -78,13 +78,13 @@ async def test_base_client_get_response_uses_explicit_client_kwargs(chat_client_
async def test_base_client_get_response(chat_client_base: SupportsChatGetResponse):
response = await chat_client_base.get_response([Message(role="user", text="Hello")])
response = await chat_client_base.get_response([Message(role="user", contents=["Hello"])])
assert response.messages[0].role == "assistant"
assert response.messages[0].text == "test response - Hello"
async def test_base_client_get_response_streaming(chat_client_base: SupportsChatGetResponse):
async for update in chat_client_base.get_response([Message(role="user", text="Hello")], stream=True):
async for update in chat_client_base.get_response([Message(role="user", contents=["Hello"])], stream=True):
assert update.text == "update - Hello" or update.text == "another update"
@@ -107,8 +107,8 @@ async def test_base_client_applies_compaction_before_non_streaming_inner_call(
chat_client_base._get_non_streaming_response = _capture # type: ignore[attr-defined,method-assign]
await chat_client_base.get_response([
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
])
assert captured_roles == [["assistant"]]
@@ -133,8 +133,8 @@ async def test_base_client_applies_compaction_before_streaming_inner_call(
chat_client_base._get_streaming_response = _capture # type: ignore[attr-defined,method-assign]
async for _ in chat_client_base.get_response(
[
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
],
stream=True,
):
@@ -161,8 +161,8 @@ async def test_base_client_per_call_compaction_override_applies_before_inner_cal
chat_client_base._get_non_streaming_response = _capture # type: ignore[attr-defined,method-assign]
await chat_client_base.get_response(
[
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
],
compaction_strategy=TruncationStrategy(max_n=1, compact_to=1),
)
@@ -191,8 +191,8 @@ async def test_base_client_per_call_tokenizer_override_annotates_messages(
chat_client_base._get_non_streaming_response = _capture # type: ignore[attr-defined,method-assign]
await chat_client_base.get_response(
[
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
],
compaction_strategy=SlidingWindowStrategy(keep_last_groups=2),
tokenizer=_FixedTokenizer(17),
@@ -222,8 +222,8 @@ async def test_base_client_per_call_tokenizer_override_without_strategy_annotate
chat_client_base._get_non_streaming_response = _capture # type: ignore[attr-defined,method-assign]
await chat_client_base.get_response(
[
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
],
tokenizer=_FixedTokenizer(17),
)
@@ -252,8 +252,8 @@ async def test_base_client_default_tokenizer_without_strategy_annotates_messages
chat_client_base._get_non_streaming_response = _capture # type: ignore[attr-defined,method-assign]
await chat_client_base.get_response([
Message(role="user", text="Hello"),
Message(role="assistant", text="Previous response"),
Message(role="user", contents=["Hello"]),
Message(role="assistant", contents=["Previous response"]),
])
assert captured_token_counts == [[19, 19]]
@@ -276,7 +276,7 @@ async def test_chat_client_instructions_handling(chat_client_base: SupportsChatG
instructions = "You are a helpful assistant."
async def fake_inner_get_response(**kwargs):
return ChatResponse(messages=[Message(role="assistant", text="ok")])
return ChatResponse(messages=[Message(role="assistant", contents=["ok"])])
with patch.object(
chat_client_base,
@@ -284,7 +284,7 @@ async def test_chat_client_instructions_handling(chat_client_base: SupportsChatG
side_effect=fake_inner_get_response,
) as mock_inner_get_response:
await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"instructions": instructions}
[Message(role="user", contents=["hello"])], options={"instructions": instructions}
)
mock_inner_get_response.assert_called_once()
_, kwargs = mock_inner_get_response.call_args
@@ -296,7 +296,7 @@ async def test_chat_client_instructions_handling(chat_client_base: SupportsChatG
from agent_framework._types import prepend_instructions_to_messages
appended_messages = prepend_instructions_to_messages(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
instructions,
)
assert len(appended_messages) == 2
@@ -105,10 +105,10 @@ def _group_unknown_value(message: Message, key: str) -> Any:
def test_group_annotations_keep_tool_call_and_tool_result_atomic() -> None:
messages = [
Message(role="user", text="hello"),
Message(role="user", contents=["hello"]),
_assistant_function_call("c1"),
_tool_result("c1", "ok"),
Message(role="assistant", text="final"),
Message(role="assistant", contents=["final"]),
]
annotate_message_groups(messages)
@@ -136,11 +136,11 @@ def test_group_annotations_include_reasoning_in_tool_call_group() -> None:
def test_group_annotations_handle_same_message_reasoning_and_function_calls() -> None:
messages = [
Message(role="user", text="hello"),
Message(role="user", contents=["hello"]),
_assistant_reasoning_and_function_calls("c1", "c2"),
_tool_result("c1", "ok1"),
_tool_result("c2", "ok2"),
Message(role="assistant", text="final"),
Message(role="assistant", contents=["final"]),
]
annotate_message_groups(messages)
@@ -155,8 +155,8 @@ def test_group_annotations_handle_same_message_reasoning_and_function_calls() ->
def test_annotate_message_groups_with_tokenizer_adds_token_counts() -> None:
messages = [
Message(role="user", text="hello"),
Message(role="assistant", text="world"),
Message(role="user", contents=["hello"]),
Message(role="assistant", contents=["world"]),
]
annotate_message_groups(
@@ -187,9 +187,9 @@ def test_extend_compaction_messages_preserves_existing_annotations_and_tokens()
def test_append_compaction_message_annotates_new_message() -> None:
messages = [Message(role="user", text="hello")]
messages = [Message(role="user", contents=["hello"])]
annotate_message_groups(messages)
append_compaction_message(messages, Message(role="assistant", text="world"))
append_compaction_message(messages, Message(role="assistant", contents=["world"]))
assert len(messages) == 2
assert isinstance(_group_id(messages[1]), str)
@@ -197,11 +197,11 @@ def test_append_compaction_message_annotates_new_message() -> None:
async def test_truncation_strategy_keeps_system_anchor() -> None:
messages = [
Message(role="system", text="you are helpful"),
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="system", contents=["you are helpful"]),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
]
strategy = TruncationStrategy(max_n=3, compact_to=3, preserve_system=True)
annotate_message_groups(messages)
@@ -217,9 +217,9 @@ async def test_truncation_strategy_keeps_system_anchor() -> None:
async def test_truncation_strategy_compacts_when_token_limit_exceeded() -> None:
tokenizer = CharacterEstimatorTokenizer()
messages = [
Message(role="system", text="you are helpful"),
Message(role="user", text="u1 " * 200),
Message(role="assistant", text="a1 " * 200),
Message(role="system", contents=["you are helpful"]),
Message(role="user", contents=["u1 " * 200]),
Message(role="assistant", contents=["a1 " * 200]),
]
strategy = TruncationStrategy(
max_n=80,
@@ -248,12 +248,12 @@ def test_truncation_strategy_validates_token_targets() -> None:
async def test_selective_tool_call_strategy_excludes_older_tool_groups() -> None:
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
_assistant_function_call("call-2"),
_tool_result("call-2", "r2"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=1)
annotate_message_groups(messages)
@@ -269,10 +269,10 @@ async def test_selective_tool_call_strategy_excludes_older_tool_groups() -> None
async def test_selective_tool_call_strategy_with_zero_removes_assistant_tool_pair() -> None:
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=0)
annotate_message_groups(messages)
@@ -304,7 +304,7 @@ class _FakeSummarizer:
options: dict[str, Any] | None = None,
**kwargs: Any,
) -> ChatResponse:
return ChatResponse(messages=[Message(role="assistant", text="summarized context")])
return ChatResponse(messages=[Message(role="assistant", contents=["summarized context"])])
class _FailingSummarizer:
@@ -328,17 +328,17 @@ class _EmptySummarizer:
options: dict[str, Any] | None = None,
**kwargs: Any,
) -> ChatResponse:
return ChatResponse(messages=[Message(role="assistant", text=" ")])
return ChatResponse(messages=[Message(role="assistant", contents=[" "])])
async def test_summarization_strategy_adds_bidirectional_trace_links() -> None:
messages = [
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", text="u3"),
Message(role="assistant", text="a3"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
Message(role="user", contents=["u3"]),
Message(role="assistant", contents=["a3"]),
]
strategy = SummarizationStrategy(client=_FakeSummarizer(), target_count=2, threshold=0)
annotate_message_groups(messages)
@@ -366,12 +366,12 @@ async def test_summarization_strategy_returns_false_when_summary_generation_fail
caplog: Any,
) -> None:
messages = [
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", text="u3"),
Message(role="assistant", text="a3"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
Message(role="user", contents=["u3"]),
Message(role="assistant", contents=["a3"]),
]
strategy = SummarizationStrategy(client=_FailingSummarizer(), target_count=2, threshold=0)
annotate_message_groups(messages)
@@ -388,12 +388,12 @@ async def test_summarization_strategy_returns_false_when_summary_is_empty(
caplog: Any,
) -> None:
messages = [
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", text="u3"),
Message(role="assistant", text="a3"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
Message(role="user", contents=["u3"]),
Message(role="assistant", contents=["a3"]),
]
strategy = SummarizationStrategy(client=_EmptySummarizer(), target_count=2, threshold=0)
annotate_message_groups(messages)
@@ -408,9 +408,9 @@ async def test_summarization_strategy_returns_false_when_summary_is_empty(
async def test_token_budget_composed_strategy_meets_budget_or_falls_back() -> None:
messages = [
Message(role="system", text="system"),
Message(role="user", text="user " * 200),
Message(role="assistant", text="assistant " * 200),
Message(role="system", contents=["system"]),
Message(role="user", contents=["user " * 200]),
Message(role="assistant", contents=["assistant " * 200]),
]
strategy = TokenBudgetComposedStrategy(
token_budget=20,
@@ -445,9 +445,9 @@ class _ExcludeOldestNonSystem:
async def test_apply_compaction_projects_included_messages_only() -> None:
messages = [
Message(role="system", text="sys"),
Message(role="user", text="hello"),
Message(role="assistant", text="world"),
Message(role="system", contents=["sys"]),
Message(role="user", contents=["hello"]),
Message(role="assistant", contents=["world"]),
]
projected = await apply_compaction(messages, strategy=_ExcludeOldestNonSystem())
@@ -462,12 +462,12 @@ async def test_apply_compaction_projects_included_messages_only() -> None:
async def test_tool_result_compaction_collapses_old_groups_into_summary() -> None:
"""Old tool-call groups are collapsed into summary messages, newest kept."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
_assistant_function_call("call-2"),
_tool_result("call-2", "r2"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=1)
annotate_message_groups(messages)
@@ -486,12 +486,12 @@ async def test_tool_result_compaction_collapses_old_groups_into_summary() -> Non
async def test_tool_result_compaction_zero_collapses_all() -> None:
"""With keep=0, all tool-call groups are collapsed into summaries."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
_assistant_function_call("call-2"),
_tool_result("call-2", "r2"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=0)
annotate_message_groups(messages)
@@ -508,7 +508,7 @@ async def test_tool_result_compaction_zero_collapses_all() -> None:
async def test_tool_result_compaction_no_change_when_within_limit() -> None:
"""No compaction when tool groups count does not exceed keep limit."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
]
@@ -532,7 +532,7 @@ def test_tool_result_compaction_rejects_negative() -> None:
async def test_tool_result_compaction_preserves_tool_results_in_summary() -> None:
"""Summary text should include the tool results from the collapsed group."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
Message(
role="assistant",
contents=[
@@ -542,7 +542,7 @@ async def test_tool_result_compaction_preserves_tool_results_in_summary() -> Non
),
_tool_result("c1", "sunny"),
_tool_result("c2", "found 3 docs"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=0)
annotate_message_groups(messages)
@@ -559,10 +559,10 @@ async def test_tool_result_compaction_preserves_tool_results_in_summary() -> Non
async def test_tool_result_compaction_bidirectional_tracing() -> None:
"""Summary and originals should link to each other like SummarizationStrategy does."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("call-1"),
_tool_result("call-1", "r1"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=0)
annotate_message_groups(messages)
@@ -594,10 +594,10 @@ async def test_tool_result_compaction_bidirectional_tracing() -> None:
async def test_tool_result_compaction_summary_has_full_annotations() -> None:
"""Summary messages inserted by ToolResultCompactionStrategy must have all compaction annotations."""
messages = [
Message(role="user", text="u"),
Message(role="user", contents=["u"]),
_assistant_function_call("c1"),
_tool_result("c1", "r1"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=0)
annotate_message_groups(messages)
@@ -617,12 +617,12 @@ async def test_tool_result_compaction_summary_has_full_annotations() -> None:
async def test_summarization_strategy_summary_has_full_annotations() -> None:
"""Summary messages inserted by SummarizationStrategy must have all compaction annotations."""
messages = [
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", text="u3"),
Message(role="assistant", text="a3"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
Message(role="user", contents=["u3"]),
Message(role="assistant", contents=["a3"]),
]
strategy = SummarizationStrategy(client=_FakeSummarizer(), target_count=2, threshold=0)
annotate_message_groups(messages)
@@ -647,14 +647,14 @@ async def test_tool_result_compaction_multiple_groups_combined() -> None:
separate summary, group 3 stays verbatim.
"""
messages = [
Message(role="user", text="Compare weather in London, Paris, and Tokyo"),
Message(role="user", contents=["Compare weather in London, Paris, and Tokyo"]),
# Group 1: get_weather for London
Message(
role="assistant",
contents=[Content.from_function_call(call_id="c1", name="get_weather", arguments='{"city":"London"}')],
),
_tool_result("c1", '{"temp":12,"condition":"cloudy","wind":"NW 15km/h"}'),
Message(role="assistant", text="London is cloudy at 12°C."),
Message(role="assistant", contents=["London is cloudy at 12°C."]),
# Group 2: get_weather for Paris + search_hotels
Message(
role="assistant",
@@ -665,14 +665,14 @@ async def test_tool_result_compaction_multiple_groups_combined() -> None:
),
_tool_result("c2", '{"temp":18,"condition":"sunny"}'),
_tool_result("c3", "Grand Hotel (€120), Le Petit (€85)"),
Message(role="assistant", text="Paris is sunny at 18°C. Found 2 hotels."),
Message(role="assistant", contents=["Paris is sunny at 18°C. Found 2 hotels."]),
# Group 3: get_weather for Tokyo (most recent — should be kept)
Message(
role="assistant",
contents=[Content.from_function_call(call_id="c4", name="get_weather", arguments='{"city":"Tokyo"}')],
),
_tool_result("c4", '{"temp":22,"condition":"rainy"}'),
Message(role="assistant", text="Tokyo is rainy at 22°C."),
Message(role="assistant", contents=["Tokyo is rainy at 22°C."]),
]
strategy = ToolResultCompactionStrategy(keep_last_tool_call_groups=1)
annotate_message_groups(messages)
@@ -758,13 +758,13 @@ async def test_compaction_provider_compacts_existing_context_messages() -> None:
context = _MockSessionContext()
context.context_messages["history"] = [
Message(role="system", text="sys"),
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", text="u3"),
Message(role="assistant", text="a3"),
Message(role="system", contents=["sys"]),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
Message(role="user", contents=["u3"]),
Message(role="assistant", contents=["a3"]),
]
await provider.before_run(agent=None, session=None, context=context, state={})
@@ -796,13 +796,13 @@ async def test_compaction_provider_preserves_messages_from_multiple_sources() ->
context = _MockSessionContext()
context.context_messages["history"] = [
Message(role="system", text="sys"),
Message(role="user", text="old_user"),
Message(role="assistant", text="old_assistant"),
Message(role="system", contents=["sys"]),
Message(role="user", contents=["old_user"]),
Message(role="assistant", contents=["old_assistant"]),
]
context.context_messages["rag"] = [
Message(role="user", text="recent_rag_context"),
Message(role="assistant", text="recent_rag_answer"),
Message(role="user", contents=["recent_rag_context"]),
Message(role="assistant", contents=["recent_rag_answer"]),
]
await provider.before_run(agent=None, session=None, context=context, state={})
@@ -829,11 +829,11 @@ async def test_compaction_provider_after_run_compacts_stored_history() -> None:
session = _MockSession()
session.state["in_memory_history"] = {
"messages": [
Message(role="user", text="old question"),
Message(role="assistant", text="old answer"),
Message(role="user", contents=["old question"]),
Message(role="assistant", contents=["old answer"]),
_assistant_function_call("c1"),
_tool_result("c1", "result"),
Message(role="assistant", text="final answer"),
Message(role="assistant", contents=["final answer"]),
]
}
@@ -873,11 +873,11 @@ async def test_compaction_provider_both_strategies() -> None:
# before_run: compact loaded context
context = _MockSessionContext()
context.context_messages["history"] = [
Message(role="system", text="sys"),
Message(role="user", text="u1"),
Message(role="assistant", text="a1"),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="system", contents=["sys"]),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"]),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
]
await provider.before_run(agent=None, session=None, context=context, state={})
assert len(context.get_messages()) == 3
@@ -886,10 +886,10 @@ async def test_compaction_provider_both_strategies() -> None:
session = _MockSession()
session.state["history"] = {
"messages": [
Message(role="user", text="q"),
Message(role="user", contents=["q"]),
_assistant_function_call("c1"),
_tool_result("c1", "ok"),
Message(role="assistant", text="done"),
Message(role="assistant", contents=["done"]),
]
}
await provider.after_run(agent=None, session=session, context=_MockSessionContext(), state={})
@@ -904,8 +904,8 @@ async def test_compaction_provider_none_strategies_are_noop() -> None:
context = _MockSessionContext()
context.context_messages["history"] = [
Message(role="user", text="hello"),
Message(role="assistant", text="hi"),
Message(role="user", contents=["hello"]),
Message(role="assistant", contents=["hi"]),
]
await provider.before_run(agent=None, session=None, context=context, state={})
@@ -924,10 +924,10 @@ async def test_in_memory_history_provider_skip_excluded() -> None:
provider = _InMemoryHistoryProvider(skip_excluded=True)
state: dict[str, Any] = {
"messages": [
Message(role="user", text="u1"),
Message(role="assistant", text="a1", additional_properties={EXCLUDED_KEY: True}),
Message(role="user", text="u2"),
Message(role="assistant", text="a2"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"], additional_properties={EXCLUDED_KEY: True}),
Message(role="user", contents=["u2"]),
Message(role="assistant", contents=["a2"]),
]
}
@@ -944,9 +944,9 @@ async def test_in_memory_history_provider_default_loads_all() -> None:
provider = _InMemoryHistoryProvider()
state: dict[str, Any] = {
"messages": [
Message(role="user", text="u1"),
Message(role="assistant", text="a1", additional_properties={EXCLUDED_KEY: True}),
Message(role="user", text="u2"),
Message(role="user", contents=["u1"]),
Message(role="assistant", contents=["a1"], additional_properties={EXCLUDED_KEY: True}),
Message(role="user", contents=["u2"]),
]
}
@@ -55,10 +55,10 @@ async def test_base_client_with_function_calling(chat_client_base: SupportsChatG
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [ai_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [ai_func]}
)
assert exec_counter == 1
assert len(response.messages) == 3
@@ -93,7 +93,7 @@ async def test_base_client_with_function_calling_string_input(chat_client_base:
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response("hello", options={"tool_choice": "auto", "tools": [ai_func]})
@@ -132,10 +132,10 @@ async def test_base_client_with_function_calling_resets(chat_client_base: Suppor
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [ai_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [ai_func]}
)
assert exec_counter == 2
assert len(response.messages) == 5
@@ -193,11 +193,11 @@ async def test_function_loop_applies_compaction_projection_each_model_call(chat_
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [ai_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [ai_func]}
)
assert len(captured_roles) >= 2
@@ -256,11 +256,11 @@ async def test_function_loop_token_budget_strategy_caps_tokens_each_iteration(
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello " * 160)],
[Message(role="user", contents=["hello " * 160])],
options={"tool_choice": "auto", "tools": [ai_func]},
)
@@ -349,13 +349,13 @@ async def test_base_client_executes_function_calls_across_multiple_response_mess
conversation_id="conv_after_first_call",
),
ChatResponse(
messages=Message(role="assistant", text="done"),
messages=Message(role="assistant", contents=["done"]),
conversation_id="conv_after_second_call",
),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [ai_func], "conversation_id": "conv_initial"},
)
@@ -392,7 +392,7 @@ async def test_function_invocation_inside_aiohttp_server(chat_client_base: Suppo
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
agent = Agent(client=chat_client_base, tools=[ai_func])
@@ -449,7 +449,7 @@ async def test_function_invocation_in_threaded_aiohttp_app(chat_client_base: Sup
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
agent = Agent(client=chat_client_base, tools=[ai_func])
@@ -569,7 +569,7 @@ async def test_function_invocation_scenarios(
# Single function call content
func_call = Content.from_function_call(call_id="1", name=function_name, arguments='{"arg1": "value1"}')
completion = Message(role="assistant", text="done")
completion = Message(role="assistant", contents=["done"])
chat_client_base.run_responses = [ChatResponse(messages=Message(role="assistant", contents=[func_call]))] + (
[] if approval_required else [ChatResponse(messages=completion)]
@@ -618,12 +618,12 @@ async def test_function_invocation_scenarios(
options["conversation_id"] = conversation_id
if not streaming:
response = await chat_client_base.get_response([Message(role="user", text="hello")], options=options)
response = await chat_client_base.get_response([Message(role="user", contents=["hello"])], options=options)
messages = response.messages
else:
updates = []
async for update in chat_client_base.get_response(
[Message(role="user", text="hello")], options=options, stream=True
[Message(role="user", contents=["hello"])], options=options, stream=True
):
updates.append(update)
messages = updates
@@ -729,7 +729,7 @@ async def test_rejected_approval(chat_client_base: SupportsChatGetResponse):
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Get the response with approval requests
@@ -850,7 +850,7 @@ async def test_persisted_approval_messages_replay_correctly(chat_client_base: Su
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Get approval request
@@ -860,7 +860,7 @@ async def test_persisted_approval_messages_replay_correctly(chat_client_base: Su
# Store messages (like a thread would)
persisted_messages = [
Message(role="user", text="hello"),
Message(role="user", contents=["hello"]),
*response1.messages,
]
@@ -899,7 +899,7 @@ async def test_no_duplicate_function_calls_after_approval_processing(chat_client
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response1 = await chat_client_base.get_response(
@@ -943,7 +943,7 @@ async def test_rejection_result_uses_function_call_id(chat_client_base: Supports
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response1 = await chat_client_base.get_response(
@@ -1000,14 +1000,14 @@ async def test_max_iterations_limit(chat_client_base: SupportsChatGetResponse):
)
),
# Failsafe response when tool_choice is set to "none"
ChatResponse(messages=Message(role="assistant", text="giving up on tools")),
ChatResponse(messages=Message(role="assistant", contents=["giving up on tools"])),
]
# Set max_iterations to 1 in additional_properties
chat_client_base.function_invocation_configuration["max_iterations"] = 1
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [ai_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [ai_func]}
)
# With max_iterations=1, we should:
@@ -1061,7 +1061,7 @@ async def test_max_iterations_no_orphaned_function_calls(chat_client_base: Suppo
chat_client_base.function_invocation_configuration["max_iterations"] = 2
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [ai_func]},
)
@@ -1111,13 +1111,13 @@ async def test_max_iterations_makes_final_toolchoice_none_call(chat_client_base:
)
),
# This response should be reached via failsafe (tool_choice="none")
ChatResponse(messages=Message(role="assistant", text="Final answer after giving up on tools.")),
ChatResponse(messages=Message(role="assistant", contents=["Final answer after giving up on tools."])),
]
chat_client_base.function_invocation_configuration["max_iterations"] = 1
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [ai_func]},
)
@@ -1170,13 +1170,13 @@ async def test_max_iterations_preserves_all_fcc_messages(chat_client_base: Suppo
],
)
),
ChatResponse(messages=Message(role="assistant", text="Done")),
ChatResponse(messages=Message(role="assistant", contents=["Done"])),
]
chat_client_base.function_invocation_configuration["max_iterations"] = 2
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [ai_func]},
)
@@ -1301,14 +1301,14 @@ async def test_max_function_calls_limits_parallel_invocations(chat_client_base:
)
),
# Final response after tool_choice="none" is forced
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Allow many iterations but cap total function calls at 5
chat_client_base.function_invocation_configuration["max_function_calls"] = 5
response = await chat_client_base.get_response(
[Message(role="user", text="search")], options={"tool_choice": "auto", "tools": [search_func]}
[Message(role="user", contents=["search"])], options={"tool_choice": "auto", "tools": [search_func]}
)
# First iteration executes 3 calls (total=3, under limit).
@@ -1355,13 +1355,13 @@ async def test_max_function_calls_single_calls_per_iteration(chat_client_base: S
)
),
# After limit is reached
ChatResponse(messages=Message(role="assistant", text="all done")),
ChatResponse(messages=Message(role="assistant", contents=["all done"])),
]
chat_client_base.function_invocation_configuration["max_function_calls"] = 2
response = await chat_client_base.get_response(
[Message(role="user", text="look up keys")], options={"tool_choice": "auto", "tools": [lookup_func]}
[Message(role="user", contents=["look up keys"])], options={"tool_choice": "auto", "tools": [lookup_func]}
)
# 2 single calls executed, then limit reached, tool_choice="none" forced
@@ -1390,13 +1390,13 @@ async def test_max_function_calls_none_means_unlimited(chat_client_base: Support
)
)
for i in range(5)
] + [ChatResponse(messages=Message(role="assistant", text="finished"))]
] + [ChatResponse(messages=Message(role="assistant", contents=["finished"]))]
# Explicitly set to None (default) — should not limit
chat_client_base.function_invocation_configuration["max_function_calls"] = None
response = await chat_client_base.get_response(
[Message(role="user", text="do things")], options={"tool_choice": "auto", "tools": [do_thing_func]}
[Message(role="user", contents=["do things"])], options={"tool_choice": "auto", "tools": [do_thing_func]}
)
assert exec_counter == 5
@@ -1414,14 +1414,14 @@ async def test_function_invocation_config_enabled_false(chat_client_base: Suppor
return f"Processed {arg1}"
chat_client_base.run_responses = [
ChatResponse(messages=Message(role="assistant", text="response without function calling")),
ChatResponse(messages=Message(role="assistant", contents=["response without function calling"])),
]
# Disable function invocation
chat_client_base.function_invocation_configuration["enabled"] = False
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [ai_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [ai_func]}
)
# Function should not be executed - when enabled=False, the loop doesn't run
@@ -1447,12 +1447,12 @@ async def test_function_invocation_config_enabled_false_preserves_invocation_kwa
chat_client_base.chat_middleware = [capture_middleware]
chat_client_base.run_responses = [
ChatResponse(messages=Message(role="assistant", text="response without function calling")),
ChatResponse(messages=Message(role="assistant", contents=["response without function calling"])),
]
chat_client_base.function_invocation_configuration["enabled"] = False
await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [ai_func]},
function_invocation_kwargs={"tool_request_id": "tool-123"},
)
@@ -1502,14 +1502,14 @@ async def test_function_invocation_config_max_consecutive_errors(chat_client_bas
],
)
),
ChatResponse(messages=Message(role="assistant", text="final response")),
ChatResponse(messages=Message(role="assistant", contents=["final response"])),
]
# Set max_consecutive_errors to 2
chat_client_base.function_invocation_configuration["max_consecutive_errors_per_request"] = 2
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [error_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [error_func]}
)
# Should stop after 2 consecutive errors and force a non-tool response
@@ -1552,7 +1552,7 @@ async def test_function_invocation_stop_clears_conversation_id_non_stream(chat_c
session_stub = type("SessionStub", (), {"service_session_id": "resp_seed"})()
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
options={"tool_choice": "auto", "tools": [error_func]},
client_kwargs={"session": session_stub},
)
@@ -1579,14 +1579,14 @@ async def test_function_invocation_config_terminate_on_unknown_calls_false(chat_
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set terminate_on_unknown_calls to False (default)
chat_client_base.function_invocation_configuration["terminate_on_unknown_calls"] = False
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [known_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [known_func]}
)
# Should have a result message indicating the tool wasn't found
@@ -1624,7 +1624,7 @@ async def test_function_invocation_config_terminate_on_unknown_calls_true(chat_c
# Should raise an exception when encountering an unknown function
with pytest.raises(KeyError, match='Error: Requested function "unknown_function" not found'):
await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [known_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [known_func]}
)
assert exec_counter == 0
@@ -1656,7 +1656,7 @@ async def test_function_invocation_config_additional_tools(chat_client_base: Sup
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Add hidden_func to additional_tools
@@ -1664,7 +1664,7 @@ async def test_function_invocation_config_additional_tools(chat_client_base: Sup
# Only pass visible_func in the tools parameter
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [visible_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [visible_func]}
)
# Additional tools are treated as declaration_only, so not executed
@@ -1697,14 +1697,14 @@ async def test_function_invocation_config_include_detailed_errors_false(chat_cli
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to False (default)
chat_client_base.function_invocation_configuration["include_detailed_errors"] = False
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [error_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [error_func]}
)
# Should have a generic error message
@@ -1733,14 +1733,14 @@ async def test_function_invocation_config_include_detailed_errors_true(chat_clie
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to True
chat_client_base.function_invocation_configuration["include_detailed_errors"] = True
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [error_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [error_func]}
)
# Should have detailed error message
@@ -1832,14 +1832,14 @@ async def test_argument_validation_error_with_detailed_errors(chat_client_base:
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to True
chat_client_base.function_invocation_configuration["include_detailed_errors"] = True
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [typed_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [typed_func]}
)
# Should have detailed validation error
@@ -1868,14 +1868,14 @@ async def test_argument_validation_error_without_detailed_errors(chat_client_bas
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to False (default)
chat_client_base.function_invocation_configuration["include_detailed_errors"] = False
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [typed_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [typed_func]}
)
# Should have generic validation error
@@ -1906,7 +1906,7 @@ async def test_hosted_tool_approval_response(chat_client_base: SupportsChatGetRe
)
chat_client_base.run_responses = [
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Send the approval response
@@ -1947,13 +1947,13 @@ async def test_hosted_mcp_approval_response_passthrough(chat_client_base: Suppor
# The second call (after approval) should return a final response
chat_client_base.run_responses = [
ChatResponse(messages=Message(role="assistant", text="Here are the docs results.")),
ChatResponse(messages=Message(role="assistant", contents=["Here are the docs results."])),
]
# Build message list mimicking handle_approvals_without_session:
# [original query, assistant with approval_request, user with approval_response]
messages = [
Message(role="user", text="Search docs for azure storage"),
Message(role="user", contents=["Search docs for azure storage"]),
Message(role="assistant", contents=[mcp_approval_request]),
Message(role="user", contents=[mcp_approval_response]),
]
@@ -2034,7 +2034,7 @@ async def test_mixed_local_and_hosted_approval_flow(chat_client_base: SupportsCh
chat_client_base.run_responses = [
ChatResponse(messages=Message(role="assistant", contents=[local_fc])),
# After local approval + hosted approval, the final response
ChatResponse(messages=Message(role="assistant", text="Done with both tools.")),
ChatResponse(messages=Message(role="assistant", contents=["Done with both tools."])),
]
# User approves the local function call
@@ -2045,7 +2045,7 @@ async def test_mixed_local_and_hosted_approval_flow(chat_client_base: SupportsCh
mcp_approval_response = mcp_approval_request.to_function_approval_response(approved=True)
messages = [
Message(role="user", text="Search docs and run local"),
Message(role="user", contents=["Search docs and run local"]),
Message(role="assistant", contents=[local_fc, mcp_approval_request]),
Message(role="user", contents=[local_approval_response]),
Message(role="user", contents=[mcp_approval_response]),
@@ -2080,12 +2080,12 @@ async def test_unapproved_tool_execution_raises_exception(chat_client_base: Supp
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Get approval request
response1 = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [test_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [test_func]}
)
approval_req = [c for c in response1.messages[0].contents if c.type == "function_approval_request"][0]
@@ -2137,7 +2137,7 @@ async def test_approved_function_call_with_error_without_detailed_errors(chat_cl
contents=[Content.from_function_call(call_id="1", name="error_func", arguments='{"arg1": "value1"}')],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to False (default)
@@ -2145,7 +2145,7 @@ async def test_approved_function_call_with_error_without_detailed_errors(chat_cl
# Get approval request
response1 = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [error_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [error_func]}
)
approval_req = [c for c in response1.messages[0].contents if c.type == "function_approval_request"][0]
@@ -2202,7 +2202,7 @@ async def test_approved_function_call_with_error_with_detailed_errors(chat_clien
contents=[Content.from_function_call(call_id="1", name="error_func", arguments='{"arg1": "value1"}')],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to True
@@ -2210,7 +2210,7 @@ async def test_approved_function_call_with_error_with_detailed_errors(chat_clien
# Get approval request
response1 = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [error_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [error_func]}
)
approval_req = [c for c in response1.messages[0].contents if c.type == "function_approval_request"][0]
@@ -2267,7 +2267,7 @@ async def test_approved_function_call_with_validation_error(chat_client_base: Su
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Set include_detailed_errors to True to see validation details
@@ -2275,7 +2275,7 @@ async def test_approved_function_call_with_validation_error(chat_client_base: Su
# Get approval request
response1 = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [typed_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [typed_func]}
)
approval_req = [c for c in response1.messages[0].contents if c.type == "function_approval_request"][0]
@@ -2328,12 +2328,12 @@ async def test_approved_function_call_successful_execution(chat_client_base: Sup
contents=[Content.from_function_call(call_id="1", name="success_func", arguments='{"arg1": "value1"}')],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Get approval request
response1 = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [success_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [success_func]}
)
approval_req = [c for c in response1.messages[0].contents if c.type == "function_approval_request"][0]
@@ -2391,7 +2391,7 @@ async def test_declaration_only_tool(chat_client_base: SupportsChatGetResponse):
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
@@ -2447,11 +2447,11 @@ async def test_multiple_function_calls_parallel_execution(chat_client_base: Supp
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [func1, func2]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [func1, func2]}
)
# Both functions should have been executed
@@ -2485,12 +2485,12 @@ async def test_callable_function_converted_to_tool(chat_client_base: SupportsCha
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
# Pass plain function (will be auto-converted)
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [plain_function]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [plain_function]}
)
# Function should be executed
@@ -2518,13 +2518,13 @@ async def test_conversation_id_handling(chat_client_base: SupportsChatGetRespons
conversation_id="conv_123", # Simulate service-side thread
),
ChatResponse(
messages=Message(role="assistant", text="done"),
messages=Message(role="assistant", contents=["done"]),
conversation_id="conv_123",
),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [test_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [test_func]}
)
# Should have executed the function
@@ -2549,11 +2549,11 @@ async def test_function_result_appended_to_existing_assistant_message(chat_clien
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [test_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [test_func]}
)
# Should have messages with both function call and function result
@@ -2596,11 +2596,11 @@ async def test_error_recovery_resets_counter(chat_client_base: SupportsChatGetRe
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [sometimes_fails]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [sometimes_fails]}
)
# Should have both an error and a success
@@ -2912,7 +2912,7 @@ async def test_streaming_function_invocation_config_terminate_on_unknown_calls_t
# Should raise an exception when encountering an unknown function
with pytest.raises(KeyError, match='Error: Requested function "unknown_function" not found'):
async for _ in chat_client_base.get_response(
[Message(role="user", text="hello")], options={"tool_choice": "auto", "tools": [known_func]}
[Message(role="user", contents=["hello"])], options={"tool_choice": "auto", "tools": [known_func]}
):
pass
@@ -3248,7 +3248,7 @@ async def test_terminate_loop_single_function_call(chat_client_base: SupportsCha
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
@@ -3314,7 +3314,7 @@ async def test_terminate_loop_multiple_function_calls_one_terminates(chat_client
],
)
),
ChatResponse(messages=Message(role="assistant", text="done")),
ChatResponse(messages=Message(role="assistant", contents=["done"])),
]
response = await chat_client_base.get_response(
@@ -3444,7 +3444,7 @@ async def test_conversation_id_updated_in_options_between_tool_iterations():
async def _get() -> ChatResponse:
self.call_count += 1
if not self.run_responses:
return ChatResponse(messages=Message(role="assistant", text="done"))
return ChatResponse(messages=Message(role="assistant", contents=["done"]))
return self.run_responses.pop(0)
return _get()
@@ -3491,7 +3491,7 @@ async def test_conversation_id_updated_in_options_between_tool_iterations():
conversation_id="conv_after_first_call",
),
ChatResponse(
messages=Message(role="assistant", text="done"),
messages=Message(role="assistant", contents=["done"]),
conversation_id="conv_after_second_call",
),
]
@@ -3706,7 +3706,7 @@ async def test_user_input_request_propagates_through_as_tool(chat_client_base: S
]
response = await chat_client_base.get_response(
[Message(role="user", text="delegate this")],
[Message(role="user", contents=["delegate this"])],
options={"tool_choice": "auto", "tools": [delegate_tool]},
)
@@ -3755,7 +3755,7 @@ async def test_user_input_request_multiple_contents_propagate(chat_client_base:
]
response = await chat_client_base.get_response(
[Message(role="user", text="do something")],
[Message(role="user", contents=["do something"])],
options={"tool_choice": "auto", "tools": [multi_request]},
)
@@ -3792,11 +3792,11 @@ async def test_user_input_request_empty_contents_returns_fallback(chat_client_ba
],
)
),
ChatResponse(messages=Message(role="assistant", text="handled")),
ChatResponse(messages=Message(role="assistant", contents=["handled"])),
]
response = await chat_client_base.get_response(
[Message(role="user", text="do something")],
[Message(role="user", contents=["do something"])],
options={"tool_choice": "auto", "tools": [empty_request]},
)
@@ -38,7 +38,7 @@ class TestAgentContext:
def test_init_with_defaults(self, mock_agent: SupportsAgentRun) -> None:
"""Test AgentContext initialization with default values."""
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
assert context.agent is mock_agent
@@ -48,7 +48,7 @@ class TestAgentContext:
def test_init_with_custom_values(self, mock_agent: SupportsAgentRun) -> None:
"""Test AgentContext initialization with custom values."""
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
metadata = {"key": "value"}
context = AgentContext(agent=mock_agent, messages=messages, stream=True, metadata=metadata)
@@ -61,7 +61,7 @@ class TestAgentContext:
"""Test AgentContext initialization with session parameter."""
from agent_framework import AgentSession
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
session = AgentSession()
context = AgentContext(agent=mock_agent, messages=messages, session=session)
@@ -100,7 +100,7 @@ class TestChatContext:
def test_init_with_defaults(self, mock_chat_client: Any) -> None:
"""Test ChatContext initialization with default values."""
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
@@ -113,7 +113,7 @@ class TestChatContext:
def test_init_with_custom_values(self, mock_chat_client: Any) -> None:
"""Test ChatContext initialization with custom values."""
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {"temperature": 0.5}
metadata = {"key": "value"}
@@ -167,10 +167,10 @@ class TestAgentMiddlewarePipeline:
async def test_execute_no_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution with no middleware."""
pipeline = AgentMiddlewarePipeline()
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
expected_response = AgentResponse(messages=[Message(role="assistant", text="response")])
expected_response = AgentResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: AgentContext) -> AgentResponse:
return expected_response
@@ -193,10 +193,10 @@ class TestAgentMiddlewarePipeline:
middleware = OrderTrackingMiddleware("test")
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
expected_response = AgentResponse(messages=[Message(role="assistant", text="response")])
expected_response = AgentResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: AgentContext) -> AgentResponse:
execution_order.append("handler")
@@ -209,7 +209,7 @@ class TestAgentMiddlewarePipeline:
async def test_execute_stream_no_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline streaming execution with no middleware."""
pipeline = AgentMiddlewarePipeline()
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
async def final_handler(ctx: AgentContext) -> ResponseStream[AgentResponseUpdate, AgentResponse]:
@@ -244,7 +244,7 @@ class TestAgentMiddlewarePipeline:
middleware = StreamOrderTrackingMiddleware("test")
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
async def final_handler(ctx: AgentContext) -> ResponseStream[AgentResponseUpdate, AgentResponse]:
@@ -270,14 +270,14 @@ class TestAgentMiddlewarePipeline:
"""Test pipeline execution with termination before next()."""
middleware = self.PreNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentContext) -> AgentResponse:
# Handler should not be executed when terminated before next()
execution_order.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
response = await pipeline.execute(context, final_handler)
assert response is None
@@ -288,13 +288,13 @@ class TestAgentMiddlewarePipeline:
"""Test pipeline execution with termination after next()."""
middleware = self.PostNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentContext) -> AgentResponse:
execution_order.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
response = await pipeline.execute(context, final_handler)
assert response is not None
@@ -306,7 +306,7 @@ class TestAgentMiddlewarePipeline:
"""Test pipeline streaming execution with termination before next()."""
middleware = self.PreNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
execution_order: list[str] = []
@@ -334,7 +334,7 @@ class TestAgentMiddlewarePipeline:
"""Test pipeline streaming execution with termination after next()."""
middleware = self.PostNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
execution_order: list[str] = []
@@ -371,11 +371,11 @@ class TestAgentMiddlewarePipeline:
middleware = SessionCapturingMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
session = AgentSession()
context = AgentContext(agent=mock_agent, messages=messages, session=session)
expected_response = AgentResponse(messages=[Message(role="assistant", text="response")])
expected_response = AgentResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: AgentContext) -> AgentResponse:
return expected_response
@@ -396,10 +396,10 @@ class TestAgentMiddlewarePipeline:
middleware = SessionCapturingMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, session=None)
expected_response = AgentResponse(messages=[Message(role="assistant", text="response")])
expected_response = AgentResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: AgentContext) -> AgentResponse:
return expected_response
@@ -563,11 +563,11 @@ class TestChatMiddlewarePipeline:
async def test_execute_no_middleware(self, mock_chat_client: Any) -> None:
"""Test pipeline execution with no middleware."""
pipeline = ChatMiddlewarePipeline()
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
expected_response = ChatResponse(messages=[Message(role="assistant", text="response")])
expected_response = ChatResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: ChatContext) -> ChatResponse:
return expected_response
@@ -590,11 +590,11 @@ class TestChatMiddlewarePipeline:
middleware = OrderTrackingChatMiddleware("test")
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
expected_response = ChatResponse(messages=[Message(role="assistant", text="response")])
expected_response = ChatResponse(messages=[Message(role="assistant", contents=["response"])])
async def final_handler(ctx: ChatContext) -> ChatResponse:
execution_order.append("handler")
@@ -607,7 +607,7 @@ class TestChatMiddlewarePipeline:
async def test_execute_stream_no_middleware(self, mock_chat_client: Any) -> None:
"""Test pipeline streaming execution with no middleware."""
pipeline = ChatMiddlewarePipeline()
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
@@ -642,7 +642,7 @@ class TestChatMiddlewarePipeline:
middleware = StreamOrderTrackingChatMiddleware("test")
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
@@ -669,7 +669,7 @@ class TestChatMiddlewarePipeline:
"""Test pipeline execution with termination before next()."""
middleware = self.PreNextTerminateChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
execution_order: list[str] = []
@@ -677,7 +677,7 @@ class TestChatMiddlewarePipeline:
async def final_handler(ctx: ChatContext) -> ChatResponse:
# Handler should not be executed when terminated before next()
execution_order.append("handler")
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
response = await pipeline.execute(context, final_handler)
assert response is None
@@ -688,14 +688,14 @@ class TestChatMiddlewarePipeline:
"""Test pipeline execution with termination after next()."""
middleware = self.PostNextTerminateChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
execution_order: list[str] = []
async def final_handler(ctx: ChatContext) -> ChatResponse:
execution_order.append("handler")
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
response = await pipeline.execute(context, final_handler)
assert response is not None
@@ -707,7 +707,7 @@ class TestChatMiddlewarePipeline:
"""Test pipeline streaming execution with termination before next()."""
middleware = self.PreNextTerminateChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
execution_order: list[str] = []
@@ -732,7 +732,7 @@ class TestChatMiddlewarePipeline:
"""Test pipeline streaming execution with termination after next()."""
middleware = self.PostNextTerminateChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
execution_order: list[str] = []
@@ -774,12 +774,12 @@ class TestClassBasedMiddleware:
middleware = MetadataAgentMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
metadata_updates.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -835,12 +835,12 @@ class TestFunctionBasedMiddleware:
execution_order.append("function_after")
pipeline = AgentMiddlewarePipeline(test_agent_middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
execution_order.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -894,12 +894,12 @@ class TestMixedMiddleware:
execution_order.append("function_after")
pipeline = AgentMiddlewarePipeline(ClassMiddleware(), function_middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
execution_order.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -956,13 +956,13 @@ class TestMixedMiddleware:
execution_order.append("function_after")
pipeline = ChatMiddlewarePipeline(ClassChatMiddleware(), function_chat_middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
async def final_handler(ctx: ChatContext) -> ChatResponse:
execution_order.append("handler")
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -997,12 +997,12 @@ class TestMultipleMiddlewareOrdering:
middleware = [FirstMiddleware(), SecondMiddleware(), ThirdMiddleware()]
pipeline = AgentMiddlewarePipeline(*middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
execution_order.append("handler")
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -1081,13 +1081,13 @@ class TestMultipleMiddlewareOrdering:
middleware = [FirstChatMiddleware(), SecondChatMiddleware(), ThirdChatMiddleware()]
pipeline = ChatMiddlewarePipeline(*middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
async def final_handler(ctx: ChatContext) -> ChatResponse:
execution_order.append("handler")
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
@@ -1133,13 +1133,13 @@ class TestContextContentValidation:
middleware = ContextValidationMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
# Verify metadata was set by middleware
assert ctx.metadata.get("validated") is True
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
assert result is not None
@@ -1212,14 +1212,14 @@ class TestContextContentValidation:
middleware = ChatContextValidationMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {"temperature": 0.5}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
async def final_handler(ctx: ChatContext) -> ChatResponse:
# Verify metadata was set by middleware
assert ctx.metadata.get("validated") is True
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
result = await pipeline.execute(context, final_handler)
assert result is not None
@@ -1239,14 +1239,14 @@ class TestStreamingScenarios:
middleware = StreamingFlagMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
# Test non-streaming
context = AgentContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentContext) -> AgentResponse:
streaming_flags.append(ctx.stream)
return AgentResponse(messages=[Message(role="assistant", text="response")])
return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
await pipeline.execute(context, final_handler)
@@ -1280,7 +1280,7 @@ class TestStreamingScenarios:
middleware = StreamProcessingMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
async def final_stream_handler(ctx: AgentContext) -> ResponseStream[AgentResponseUpdate, AgentResponse]:
@@ -1320,7 +1320,7 @@ class TestStreamingScenarios:
middleware = ChatStreamingFlagMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
# Test non-streaming
@@ -1328,7 +1328,7 @@ class TestStreamingScenarios:
async def final_handler(ctx: ChatContext) -> ChatResponse:
streaming_flags.append(ctx.stream)
return ChatResponse(messages=[Message(role="assistant", text="response")])
return ChatResponse(messages=[Message(role="assistant", contents=["response"])])
await pipeline.execute(context, final_handler)
@@ -1362,7 +1362,7 @@ class TestStreamingScenarios:
middleware = ChatStreamProcessingMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
@@ -1442,7 +1442,7 @@ class TestMiddlewareExecutionControl:
middleware = NoNextMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
handler_called = False
@@ -1450,7 +1450,7 @@ class TestMiddlewareExecutionControl:
async def final_handler(ctx: AgentContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentResponse(messages=[Message(role="assistant", text="should not execute")])
return AgentResponse(messages=[Message(role="assistant", contents=["should not execute"])])
result = await pipeline.execute(context, final_handler)
@@ -1469,7 +1469,7 @@ class TestMiddlewareExecutionControl:
middleware = NoNextStreamingMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
handler_called = False
@@ -1539,7 +1539,7 @@ class TestMiddlewareExecutionControl:
await call_next()
pipeline = AgentMiddlewarePipeline(FirstMiddleware(), SecondMiddleware())
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
handler_called = False
@@ -1547,7 +1547,7 @@ class TestMiddlewareExecutionControl:
async def final_handler(ctx: AgentContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentResponse(messages=[Message(role="assistant", text="should not execute")])
return AgentResponse(messages=[Message(role="assistant", contents=["should not execute"])])
result = await pipeline.execute(context, final_handler)
@@ -1566,7 +1566,7 @@ class TestMiddlewareExecutionControl:
middleware = NoNextChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
@@ -1575,7 +1575,7 @@ class TestMiddlewareExecutionControl:
async def final_handler(ctx: ChatContext) -> ChatResponse:
nonlocal handler_called
handler_called = True
return ChatResponse(messages=[Message(role="assistant", text="should not execute")])
return ChatResponse(messages=[Message(role="assistant", contents=["should not execute"])])
result = await pipeline.execute(context, final_handler)
@@ -1594,7 +1594,7 @@ class TestMiddlewareExecutionControl:
middleware = NoNextStreamingChatMiddleware()
pipeline = ChatMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options, stream=True)
@@ -1639,7 +1639,7 @@ class TestMiddlewareExecutionControl:
await call_next()
pipeline = ChatMiddlewarePipeline(FirstChatMiddleware(), SecondChatMiddleware())
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
chat_options: dict[str, Any] = {}
context = ChatContext(client=mock_chat_client, messages=messages, options=chat_options)
@@ -1648,7 +1648,7 @@ class TestMiddlewareExecutionControl:
async def final_handler(ctx: ChatContext) -> ChatResponse:
nonlocal handler_called
handler_called = True
return ChatResponse(messages=[Message(role="assistant", text="should not execute")])
return ChatResponse(messages=[Message(role="assistant", contents=["should not execute"])])
result = await pipeline.execute(context, final_handler)
@@ -39,7 +39,7 @@ class TestResultOverrideMiddleware:
async def test_agent_middleware_response_override_non_streaming(self, mock_agent: SupportsAgentRun) -> None:
"""Test that agent middleware can override response for non-streaming execution."""
override_response = AgentResponse(messages=[Message(role="assistant", text="overridden response")])
override_response = AgentResponse(messages=[Message(role="assistant", contents=["overridden response"])])
class ResponseOverrideMiddleware(AgentMiddleware):
async def process(self, context: AgentContext, call_next: Callable[[], Awaitable[None]]) -> None:
@@ -49,7 +49,7 @@ class TestResultOverrideMiddleware:
middleware = ResponseOverrideMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages)
handler_called = False
@@ -57,7 +57,7 @@ class TestResultOverrideMiddleware:
async def final_handler(ctx: AgentContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentResponse(messages=[Message(role="assistant", text="original response")])
return AgentResponse(messages=[Message(role="assistant", contents=["original response"])])
result = await pipeline.execute(context, final_handler)
@@ -83,7 +83,7 @@ class TestResultOverrideMiddleware:
middleware = StreamResponseOverrideMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=True)
async def final_handler(ctx: AgentContext) -> ResponseStream[AgentResponseUpdate, AgentResponse]:
@@ -146,7 +146,7 @@ class TestResultOverrideMiddleware:
# Then conditionally override based on content
if any("special" in msg.text for msg in context.messages if msg.text):
context.result = AgentResponse(
messages=[Message(role="assistant", text="Special response from middleware!")]
messages=[Message(role="assistant", contents=["Special response from middleware!"])]
)
# Create Agent with override middleware
@@ -154,14 +154,14 @@ class TestResultOverrideMiddleware:
agent = Agent(client=mock_chat_client, middleware=[middleware])
# Test override case
override_messages = [Message(role="user", text="Give me a special response")]
override_messages = [Message(role="user", contents=["Give me a special response"])]
override_response = await agent.run(override_messages)
assert override_response.messages[0].text == "Special response from middleware!"
# Verify chat client was called since middleware called next()
assert mock_chat_client.call_count == 1
# Test normal case
normal_messages = [Message(role="user", text="Normal request")]
normal_messages = [Message(role="user", contents=["Normal request"])]
normal_response = await agent.run(normal_messages)
assert normal_response.messages[0].text == "test response"
# Verify chat client was called for normal case
@@ -190,7 +190,7 @@ class TestResultOverrideMiddleware:
agent = Agent(client=mock_chat_client, middleware=[middleware])
# Test streaming override case
override_messages = [Message(role="user", text="Give me a custom stream")]
override_messages = [Message(role="user", contents=["Give me a custom stream"])]
override_updates: list[AgentResponseUpdate] = []
async for update in agent.run(override_messages, stream=True):
override_updates.append(update)
@@ -201,7 +201,7 @@ class TestResultOverrideMiddleware:
assert override_updates[2].text == " response!"
# Test normal streaming case
normal_messages = [Message(role="user", text="Normal streaming request")]
normal_messages = [Message(role="user", contents=["Normal streaming request"])]
normal_updates: list[AgentResponseUpdate] = []
async for update in agent.run(normal_messages, stream=True):
normal_updates.append(update)
@@ -228,10 +228,10 @@ class TestResultOverrideMiddleware:
async def final_handler(ctx: AgentContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentResponse(messages=[Message(role="assistant", text="executed response")])
return AgentResponse(messages=[Message(role="assistant", contents=["executed response"])])
# Test case where next() is NOT called
no_execute_messages = [Message(role="user", text="Don't run this")]
no_execute_messages = [Message(role="user", contents=["Don't run this"])]
no_execute_context = AgentContext(agent=mock_agent, messages=no_execute_messages, stream=False)
no_execute_result = await pipeline.execute(no_execute_context, final_handler)
@@ -243,7 +243,7 @@ class TestResultOverrideMiddleware:
handler_called = False
# Test case where next() IS called
execute_messages = [Message(role="user", text="Please execute this")]
execute_messages = [Message(role="user", contents=["Please execute this"])]
execute_context = AgentContext(agent=mock_agent, messages=execute_messages, stream=False)
execute_result = await pipeline.execute(execute_context, final_handler)
@@ -321,11 +321,11 @@ class TestResultObservability:
middleware = ObservabilityMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=False)
async def final_handler(ctx: AgentContext) -> AgentResponse:
return AgentResponse(messages=[Message(role="assistant", text="executed response")])
return AgentResponse(messages=[Message(role="assistant", contents=["executed response"])])
result = await pipeline.execute(context, final_handler)
@@ -384,16 +384,16 @@ class TestResultObservability:
if "modify" in context.result.messages[0].text:
# Override after observing
context.result = AgentResponse(
messages=[Message(role="assistant", text="modified after execution")]
messages=[Message(role="assistant", contents=["modified after execution"])]
)
middleware = PostExecutionOverrideMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
messages = [Message(role="user", text="test")]
messages = [Message(role="user", contents=["test"])]
context = AgentContext(agent=mock_agent, messages=messages, stream=False)
async def final_handler(ctx: AgentContext) -> AgentResponse:
return AgentResponse(messages=[Message(role="assistant", text="response to modify")])
return AgentResponse(messages=[Message(role="assistant", contents=["response to modify"])])
result = await pipeline.execute(context, final_handler)
@@ -56,7 +56,7 @@ class TestChatAgentClassBasedMiddleware:
agent = Agent(client=client, middleware=[middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -105,7 +105,7 @@ class TestChatAgentClassBasedMiddleware:
middleware = TrackingFunctionMiddleware("function_middleware")
agent = Agent(client=chat_client_base, middleware=[middleware])
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
assert response is not None
@@ -135,8 +135,8 @@ class TestChatAgentFunctionBasedMiddleware:
# Execute the agent with multiple messages
messages = [
Message(role="user", text="message1"),
Message(role="user", text="message2"), # This should not be processed due to termination
Message(role="user", contents=["message1"]),
Message(role="user", contents=["message2"]), # This should not be processed due to termination
]
response = await agent.run(messages)
@@ -163,8 +163,8 @@ class TestChatAgentFunctionBasedMiddleware:
# Execute the agent with multiple messages
messages = [
Message(role="user", text="message1"),
Message(role="user", text="message2"),
Message(role="user", contents=["message1"]),
Message(role="user", contents=["message2"]),
]
response = await agent.run(messages)
@@ -229,7 +229,7 @@ class TestChatAgentFunctionBasedMiddleware:
agent = Agent(client=client, middleware=[tracking_agent_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -266,7 +266,7 @@ class TestChatAgentFunctionBasedMiddleware:
execution_order.append("function_function_after")
agent = Agent(client=chat_client_base, middleware=[tracking_function_middleware])
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
assert response is not None
@@ -303,7 +303,7 @@ class TestChatAgentStreamingMiddleware:
]
# Execute streaming
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
updates: list[AgentResponseUpdate] = []
async for update in agent.run(messages, stream=True):
updates.append(update)
@@ -333,7 +333,7 @@ class TestChatAgentStreamingMiddleware:
# Create Agent with middleware
middleware = FlagTrackingMiddleware()
agent = Agent(client=client, middleware=[middleware])
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
# Test non-streaming execution
response = await agent.run(messages)
@@ -372,7 +372,7 @@ class TestChatAgentMultipleMiddlewareOrdering:
agent = Agent(client=client, middleware=[middleware1, middleware2, middleware3])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -424,7 +424,7 @@ class TestChatAgentMultipleMiddlewareOrdering:
function_function_middleware,
],
)
await agent.run([Message(role="user", text="test")])
await agent.run([Message(role="user", contents=["test"])])
async def test_mixed_middleware_types_with_supported_client(self, chat_client_base: "MockBaseChatClient") -> None:
"""Test mixed class and function-based middleware with a full chat client."""
@@ -457,7 +457,7 @@ class TestChatAgentMultipleMiddlewareOrdering:
],
)
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
assert response is not None
@@ -488,7 +488,7 @@ class TestChatAgentMultipleMiddlewareOrdering:
MiddlewareException,
match="Context providers may only add chat or function middleware",
):
await agent.run([Message(role="user", text="test message")])
await agent.run([Message(role="user", contents=["test message"])])
# region Tool Functions for Testing
@@ -547,7 +547,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.run_responses = [function_call_response, final_response]
@@ -560,7 +560,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
# Execute the agent
messages = [Message(role="user", text="Get weather for Seattle")]
messages = [Message(role="user", contents=["Get weather for Seattle"])]
response = await agent.run(messages)
# Verify response
@@ -609,7 +609,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.run_responses = [function_call_response, final_response]
@@ -621,7 +621,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
# Execute the agent
messages = [Message(role="user", text="Get weather for San Francisco")]
messages = [Message(role="user", contents=["Get weather for San Francisco"])]
response = await agent.run(messages)
# Verify response
@@ -683,7 +683,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.run_responses = [function_call_response, final_response]
@@ -695,7 +695,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
# Execute the agent
messages = [Message(role="user", text="Get weather for New York")]
messages = [Message(role="user", contents=["Get weather for New York"])]
response = await agent.run(messages)
# Verify response
@@ -795,7 +795,7 @@ class TestChatAgentFunctionMiddlewareWithTools:
agent = Agent(client=chat_client_base, middleware=[kwargs_middleware], tools=[sample_tool_function])
# Execute the agent with custom parameters passed as kwargs
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages, options={"additional_function_arguments": {"custom_param": "test_value"}})
# Verify response
@@ -841,14 +841,14 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Done!")]),
ChatResponse(messages=[Message(role="assistant", contents=["Done!"])]),
]
agent = Agent(client=chat_client_base, middleware=[capture_middleware], tools=[sample_tool_function])
session_metadata = {"tenant": "acme-corp", "region": "us-west"}
await agent.run(
[Message(role="user", text="Get weather")],
[Message(role="user", contents=["Get weather"])],
function_invocation_kwargs={
"user_id": "user-456",
"session_metadata": session_metadata,
@@ -885,13 +885,13 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Done!")]),
ChatResponse(messages=[Message(role="assistant", contents=["Done!"])]),
]
agent = Agent(client=chat_client_base, middleware=[capture_middleware], tools=[sample_tool_function])
await agent.run(
[Message(role="user", text="Get weather")],
[Message(role="user", contents=["Get weather"])],
function_invocation_kwargs={
"user_id": "from-kwargs",
"tenant_id": "from-kwargs",
@@ -940,13 +940,13 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Done!")]),
ChatResponse(messages=[Message(role="assistant", contents=["Done!"])]),
]
agent = Agent(client=chat_client_base, middleware=[capture_middleware], tools=[sample_tool_function])
await agent.run(
[Message(role="user", text="Get weather for both cities")],
[Message(role="user", contents=["Get weather for both cities"])],
function_invocation_kwargs={
"user_id": "user-456",
"request_id": "req-001",
@@ -984,12 +984,12 @@ class TestChatAgentFunctionMiddlewareWithTools:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Done!")]),
ChatResponse(messages=[Message(role="assistant", contents=["Done!"])]),
]
agent = Agent(client=chat_client_base, middleware=[capture_middleware], tools=[sample_tool_function])
await agent.run([Message(role="user", text="Get weather")])
await agent.run([Message(role="user", contents=["Get weather"])])
# No runtime kwargs should be present
assert "user_id" not in captured_kwargs
@@ -1355,7 +1355,7 @@ class TestRunLevelMiddleware:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.run_responses = [function_call_response, final_response]
# Create agent with agent-level middleware
@@ -1446,7 +1446,7 @@ class TestMiddlewareDecoratorLogic:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.responses = [function_call_response, final_response]
# Should work without errors
@@ -1456,7 +1456,7 @@ class TestMiddlewareDecoratorLogic:
tools=[custom_tool_wrapped],
)
response = await agent.run([Message(role="user", text="test")])
response = await agent.run([Message(role="user", contents=["test"])])
assert response is not None
assert "decorator_type_match_agent" in execution_order
@@ -1477,7 +1477,7 @@ class TestMiddlewareDecoratorLogic:
await call_next()
agent = Agent(client=client, middleware=[mismatched_middleware])
await agent.run([Message(role="user", text="test")])
await agent.run([Message(role="user", contents=["test"])])
async def test_only_decorator_specified(self, chat_client_base: "MockBaseChatClient") -> None:
"""Only decorator specified - rely on decorator."""
@@ -1517,7 +1517,7 @@ class TestMiddlewareDecoratorLogic:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.responses = [function_call_response, final_response]
# Should work - relies on decorator
@@ -1527,7 +1527,7 @@ class TestMiddlewareDecoratorLogic:
tools=[custom_tool_wrapped],
)
response = await agent.run([Message(role="user", text="test")])
response = await agent.run([Message(role="user", contents=["test"])])
assert response is not None
assert "decorator_only_agent" in execution_order
@@ -1573,7 +1573,7 @@ class TestMiddlewareDecoratorLogic:
)
]
)
final_response = ChatResponse(messages=[Message(role="assistant", text="Final response")])
final_response = ChatResponse(messages=[Message(role="assistant", contents=["Final response"])])
chat_client_base.responses = [function_call_response, final_response]
# Should work - relies on type annotations
@@ -1581,7 +1581,7 @@ class TestMiddlewareDecoratorLogic:
client=chat_client_base, middleware=[type_only_agent, type_only_function], tools=[custom_tool_wrapped]
)
response = await agent.run([Message(role="user", text="test")])
response = await agent.run([Message(role="user", contents=["test"])])
assert response is not None
assert "type_only_agent" in execution_order
@@ -1596,7 +1596,7 @@ class TestMiddlewareDecoratorLogic:
# Should raise MiddlewareException
with pytest.raises(MiddlewareException, match="Cannot determine middleware type"):
agent = Agent(client=client, middleware=[no_info_middleware])
await agent.run([Message(role="user", text="test")])
await agent.run([Message(role="user", contents=["test"])])
async def test_insufficient_parameters_error(self, client: Any) -> None:
"""Test that middleware with insufficient parameters raises an error."""
@@ -1610,7 +1610,7 @@ class TestMiddlewareDecoratorLogic:
pass
agent = Agent(client=client, middleware=[insufficient_params_middleware])
await agent.run([Message(role="user", text="test")])
await agent.run([Message(role="user", contents=["test"])])
async def test_decorator_markers_preserved(self) -> None:
"""Test that decorator markers are properly set on functions."""
@@ -1682,7 +1682,7 @@ class TestChatAgentSessionBehavior:
session = agent.create_session()
# First run
first_messages = [Message(role="user", text="first message")]
first_messages = [Message(role="user", contents=["first message"])]
first_response = await agent.run(first_messages, session=session)
# Verify first response
@@ -1690,7 +1690,7 @@ class TestChatAgentSessionBehavior:
assert len(first_response.messages) > 0
# Second run - use the same thread
second_messages = [Message(role="user", text="second message")]
second_messages = [Message(role="user", contents=["second message"])]
second_response = await agent.run(second_messages, session=session)
# Verify second response
@@ -1762,7 +1762,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -1789,7 +1789,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[tracking_chat_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -1813,7 +1813,7 @@ class TestChatAgentChatMiddleware:
if msg.role == "system":
continue
original_text = msg.text or ""
context.messages[idx] = Message(role=msg.role, text=f"MODIFIED: {original_text}")
context.messages[idx] = Message(role=msg.role, contents=[f"MODIFIED: {original_text}"])
break
await call_next()
@@ -1822,7 +1822,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[message_modifier_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify that the message was modified (MockBaseChatClient echoes back the input)
@@ -1836,7 +1836,7 @@ class TestChatAgentChatMiddleware:
async def response_override_middleware(context: ChatContext, call_next: Callable[[], Awaitable[None]]) -> None:
# Override the response without calling next()
context.result = ChatResponse(
messages=[Message(role="assistant", text="MiddlewareTypes overridden response")],
messages=[Message(role="assistant", contents=["MiddlewareTypes overridden response"])],
response_id="middleware-response-123",
)
context.terminate = True
@@ -1846,7 +1846,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[response_override_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify that the response was overridden
@@ -1876,7 +1876,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[first_middleware, second_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -1914,7 +1914,7 @@ class TestChatAgentChatMiddleware:
]
# Execute streaming
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
updates: list[AgentResponseUpdate] = []
async for update in agent.run(messages, stream=True):
updates.append(update)
@@ -1937,7 +1937,9 @@ class TestChatAgentChatMiddleware:
async def process(self, context: ChatContext, call_next: Callable[[], Awaitable[None]]) -> None:
execution_order.append("middleware_before")
# Set a custom response since we're terminating
context.result = ChatResponse(messages=[Message(role="assistant", text="Terminated by middleware")])
context.result = ChatResponse(
messages=[Message(role="assistant", contents=["Terminated by middleware"])]
)
raise MiddlewareTermination
# We call next() but since terminate=True, execution should stop
await call_next()
@@ -1948,7 +1950,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[PreTerminationChatMiddleware()])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response was from middleware
@@ -1973,7 +1975,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[PostTerminationChatMiddleware()])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response is from actual execution
@@ -2012,7 +2014,7 @@ class TestChatAgentChatMiddleware:
middleware=[chat_middleware, function_middleware, agent_middleware],
tools=[sample_tool_function],
)
await agent.run([Message(role="user", text="test")])
await agent.run([Message(role="user", contents=["test"])])
assert execution_order == [
"agent_middleware_before",
@@ -2041,7 +2043,7 @@ class TestChatAgentChatMiddleware:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Final response")]),
ChatResponse(messages=[Message(role="assistant", contents=["Final response"])]),
]
async def tracking_agent_middleware(
@@ -2076,7 +2078,7 @@ class TestChatAgentChatMiddleware:
tools=[sample_tool_function],
)
response = await agent.run([Message(role="user", text="test")])
response = await agent.run([Message(role="user", contents=["test"])])
assert response is not None
assert client.call_count == 2
@@ -2168,7 +2170,7 @@ class TestChatAgentChatMiddleware:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Final response")]),
ChatResponse(messages=[Message(role="assistant", contents=["Final response"])]),
]
agent = Agent(
@@ -2179,7 +2181,7 @@ class TestChatAgentChatMiddleware:
)
response = await agent.run(
[Message(role="user", text="Get weather for Seattle")],
[Message(role="user", contents=["Get weather for Seattle"])],
middleware=[run_chat_middleware, run_function_middleware],
)
@@ -2230,7 +2232,7 @@ class TestChatAgentChatMiddleware:
agent = Agent(client=client, middleware=[kwargs_middleware])
# Execute the agent with runtime options
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(
messages,
options={"temperature": 0.7, "max_tokens": 100, "custom_param": "test_value"},
@@ -2288,7 +2290,7 @@ class TestChatAgentChatMiddleware:
# yield AgentResponseUpdate()
# return _stream()
# return AgentResponse(messages=[Message(role="assistant", text="response")])
# return AgentResponse(messages=[Message(role="assistant", contents=["response"])])
# def get_new_thread(self, **kwargs):
# return None
@@ -43,7 +43,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [LoggingChatMiddleware()]
# Execute chat client directly
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(messages)
# Verify response
@@ -68,7 +68,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [logging_chat_middleware]
# Execute chat client directly
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(messages)
# Verify response
@@ -87,14 +87,14 @@ class TestChatMiddleware:
# Modify the first message by adding a prefix
if context.messages and len(context.messages) > 0:
original_text = context.messages[0].text or ""
context.messages[0] = Message(role=context.messages[0].role, text=f"MODIFIED: {original_text}")
context.messages[0] = Message(role=context.messages[0].role, contents=[f"MODIFIED: {original_text}"])
await call_next()
# Add middleware to chat client
chat_client_base.chat_middleware = [message_modifier_middleware]
# Execute chat client
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(messages)
# Verify that the message was modified (MockChatClient echoes back the input)
@@ -110,7 +110,7 @@ class TestChatMiddleware:
async def response_override_middleware(context: ChatContext, call_next: Callable[[], Awaitable[None]]) -> None:
# Override the response without calling next()
context.result = ChatResponse(
messages=[Message(role="assistant", text="MiddlewareTypes overridden response")],
messages=[Message(role="assistant", contents=["MiddlewareTypes overridden response"])],
response_id="middleware-response-123",
)
context.terminate = True
@@ -119,7 +119,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [response_override_middleware]
# Execute chat client
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(messages)
# Verify that the response was overridden
@@ -148,7 +148,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [first_middleware, second_middleware]
# Execute chat client
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(messages)
# Verify response
@@ -179,7 +179,7 @@ class TestChatMiddleware:
agent = Agent(client=client, middleware=[agent_level_chat_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -213,7 +213,7 @@ class TestChatMiddleware:
agent = Agent(client=chat_client_base, middleware=[first_middleware, second_middleware])
# Execute the agent
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await agent.run(messages)
# Verify response
@@ -252,7 +252,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [streaming_middleware]
# Execute streaming response
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
updates: list[object] = []
async for update in chat_client_base.get_response(messages, stream=True):
updates.append(update)
@@ -274,7 +274,7 @@ class TestChatMiddleware:
await call_next()
# First call with run-level middleware
messages = [Message(role="user", text="first message")]
messages = [Message(role="user", contents=["first message"])]
response1 = await chat_client_base.get_response(
messages,
client_kwargs={"middleware": [counting_middleware]},
@@ -283,13 +283,13 @@ class TestChatMiddleware:
assert execution_count["count"] == 1
# Second call WITHOUT run-level middleware - should not execute the middleware
messages = [Message(role="user", text="second message")]
messages = [Message(role="user", contents=["second message"])]
response2 = await chat_client_base.get_response(messages)
assert response2 is not None
assert execution_count["count"] == 1 # Should still be 1, not 2
# Third call with run-level middleware again - should execute
messages = [Message(role="user", text="third message")]
messages = [Message(role="user", contents=["third message"])]
response3 = await chat_client_base.get_response(
messages,
client_kwargs={"middleware": [counting_middleware]},
@@ -310,7 +310,7 @@ class TestChatMiddleware:
async def fake_inner_get_response(**kwargs: Any) -> ChatResponse:
assert "middleware" not in kwargs
return ChatResponse(messages=[Message(role="assistant", text="ok")])
return ChatResponse(messages=[Message(role="assistant", contents=["ok"])])
with patch.object(
chat_client_base,
@@ -318,7 +318,7 @@ class TestChatMiddleware:
side_effect=fake_inner_get_response,
) as mock_inner_get_response:
response = await chat_client_base.get_response(
[Message(role="user", text="hello")],
[Message(role="user", contents=["hello"])],
client_kwargs={"middleware": [inspecting_middleware], "trace_id": "trace-123"},
)
@@ -350,7 +350,7 @@ class TestChatMiddleware:
chat_client_base.chat_middleware = [kwargs_middleware]
# Execute chat client with runtime options
messages = [Message(role="user", text="test message")]
messages = [Message(role="user", contents=["test message"])]
response = await chat_client_base.get_response(
messages,
options={"temperature": 0.7, "max_tokens": 100, "custom_param": "test_value"},
@@ -493,12 +493,12 @@ class TestChatMiddleware:
]
)
final_response = ChatResponse(
messages=[Message(role="assistant", text="Based on the weather data, it's sunny!")]
messages=[Message(role="assistant", contents=["Based on the weather data, it's sunny!"])]
)
client.run_responses = [function_call_response, final_response]
# Execute the chat client directly with tools - this should trigger function invocation and middleware
messages = [Message(role="user", text="What's the weather in San Francisco?")]
messages = [Message(role="user", contents=["What's the weather in San Francisco?"])]
response = await client.get_response(messages, options={"tools": [sample_tool_wrapped]})
# Verify response
@@ -557,7 +557,7 @@ class TestChatMiddleware:
client.run_responses = [function_call_response]
# Execute the chat client directly with run-level middleware and tools
messages = [Message(role="user", text="What's the weather in New York?")]
messages = [Message(role="user", contents=["What's the weather in New York?"])]
response = await client.get_response(
messages,
options={"tools": [sample_tool_wrapped]},
@@ -627,11 +627,11 @@ class TestChatMiddleware:
)
]
),
ChatResponse(messages=[Message(role="assistant", text="Based on the weather data, it's sunny!")]),
ChatResponse(messages=[Message(role="assistant", contents=["Based on the weather data, it's sunny!"])]),
]
response = await client.get_response(
[Message(role="user", text="What's the weather in Seattle?")],
[Message(role="user", contents=["What's the weather in Seattle?"])],
options={"tools": [sample_tool_wrapped]},
client_kwargs={"middleware": [run_level_chat_middleware, run_level_function_middleware]},
)
@@ -710,7 +710,7 @@ class TestChatMiddleware:
updates: list[ChatResponseUpdate] = []
async for update in client.get_response(
[Message(role="user", text="What's the weather in Seattle?")],
[Message(role="user", contents=["What's the weather in Seattle?"])],
options={"tools": [sample_tool_wrapped]},
client_kwargs={"middleware": [run_level_chat_middleware, run_level_function_middleware]},
stream=True,
@@ -203,7 +203,7 @@ async def test_chat_client_observability(mock_chat_client, span_exporter: InMemo
"""Test that when diagnostics are enabled, telemetry is applied."""
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await client.get_response(messages=messages, options={"model": "Test"})
assert response is not None
@@ -227,7 +227,7 @@ async def test_chat_client_observability_accepts_model_option(
"""Test that telemetry also captures the modern model option."""
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await client.get_response(messages=messages, options={"model": "Test"})
assert response is not None
@@ -243,7 +243,7 @@ async def test_chat_client_streaming_observability(
):
"""Test streaming telemetry through the chat telemetry mixin."""
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
# Collect all yielded updates
updates = []
@@ -274,7 +274,7 @@ async def test_chat_client_observability_with_instructions(
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
options = {"model": "Test", "instructions": "You are a helpful assistant."}
span_exporter.clear()
response = await client.get_response(messages=messages, options=options)
@@ -303,7 +303,7 @@ async def test_chat_client_streaming_observability_with_instructions(
import json
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
options = {"model": "Test", "instructions": "You are a helpful assistant."}
span_exporter.clear()
@@ -332,7 +332,7 @@ async def test_chat_client_observability_without_instructions(
"""Test that system_instructions attribute is not set when instructions are not provided."""
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
options = {"model": "Test"} # No instructions
span_exporter.clear()
response = await client.get_response(messages=messages, options=options)
@@ -353,7 +353,7 @@ async def test_chat_client_observability_with_empty_instructions(
"""Test that system_instructions attribute is not set when instructions is an empty string."""
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
options = {"model": "Test", "instructions": ""} # Empty string
span_exporter.clear()
response = await client.get_response(messages=messages, options=options)
@@ -376,7 +376,7 @@ async def test_chat_client_observability_with_list_instructions(
client = mock_chat_client()
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
options = {"model": "Test", "instructions": ["Instruction 1", "Instruction 2"]}
span_exporter.clear()
response = await client.get_response(messages=messages, options=options)
@@ -397,7 +397,7 @@ async def test_chat_client_observability_with_list_instructions(
async def test_chat_client_without_model_observability(mock_chat_client, span_exporter: InMemorySpanExporter):
"""Test telemetry shouldn't fail when the model is not provided for unknown reason."""
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
response = await client.get_response(messages=messages)
@@ -414,7 +414,7 @@ async def test_chat_client_without_model_observability(mock_chat_client, span_ex
async def test_chat_client_streaming_without_model_observability(mock_chat_client, span_exporter: InMemorySpanExporter):
"""Test streaming telemetry shouldn't fail when the model is not provided for unknown reason."""
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
# Collect all yielded updates
updates = []
@@ -1549,7 +1549,7 @@ async def test_chat_client_observability_exception(mock_chat_client, span_export
raise ValueError("Test error")
client = FailingChatClient()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
with pytest.raises(ValueError, match="Test error"):
@@ -1579,7 +1579,7 @@ async def test_chat_client_streaming_observability_exception(mock_chat_client, s
return ResponseStream(_stream(), finalizer=ChatResponse.from_updates)
client = FailingStreamingChatClient()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
with pytest.raises(ValueError, match="Streaming error"):
@@ -2079,13 +2079,13 @@ async def test_capture_messages_with_finish_reason(mock_chat_client, span_export
class ClientWithFinishReason(mock_chat_client):
async def _inner_get_response(self, *, messages, options, **kwargs):
return ChatResponse(
messages=[Message(role="assistant", text="Done")],
messages=[Message(role="assistant", contents=["Done"])],
usage_details=UsageDetails(input_token_count=5, output_token_count=10),
finish_reason="stop",
)
client = ClientWithFinishReason()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
response = await client.get_response(messages=messages, options={"model": "Test"})
@@ -2175,7 +2175,7 @@ async def test_agent_streaming_exception(span_exporter: InMemorySpanExporter, en
async def test_chat_client_when_disabled(mock_chat_client, span_exporter: InMemorySpanExporter):
"""Test that no spans are created when instrumentation is disabled."""
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
response = await client.get_response(messages=messages, options={"model": "Test"})
@@ -2190,7 +2190,7 @@ async def test_chat_client_when_disabled(mock_chat_client, span_exporter: InMemo
async def test_chat_client_streaming_when_disabled(mock_chat_client, span_exporter: InMemorySpanExporter):
"""Test streaming creates no spans when instrumentation is disabled."""
client = mock_chat_client()
messages = [Message(role="user", text="Test")]
messages = [Message(role="user", contents=["Test"])]
span_exporter.clear()
updates = []
@@ -2540,7 +2540,7 @@ async def test_layer_ordering_span_sequence_with_function_calling(span_exporter:
],
)
return ChatResponse(
messages=[Message(role="assistant", text="The weather in Seattle is sunny!")],
messages=[Message(role="assistant", contents=["The weather in Seattle is sunny!"])],
)
return _get()
@@ -2549,7 +2549,7 @@ async def test_layer_ordering_span_sequence_with_function_calling(span_exporter:
span_exporter.clear()
response = await client.get_response(
messages=[Message(role="user", text="What's the weather in Seattle?")],
messages=[Message(role="user", contents=["What's the weather in Seattle?"])],
options={"tools": [get_weather], "tool_choice": "auto"},
)
@@ -2598,7 +2598,7 @@ async def test_agent_and_chat_spans_do_not_duplicate_response_telemetry(
def _finalize(updates: Sequence[ChatResponseUpdate]) -> ChatResponse:
return ChatResponse(
messages=[Message(role="assistant", text="Nested response")],
messages=[Message(role="assistant", contents=["Nested response"])],
response_id="nested_resp_123",
usage_details=UsageDetails(input_token_count=11, output_token_count=22),
finish_reason="stop",
@@ -2608,7 +2608,7 @@ async def test_agent_and_chat_spans_do_not_duplicate_response_telemetry(
async def _get() -> ChatResponse:
return ChatResponse(
messages=[Message(role="assistant", text="Nested response")],
messages=[Message(role="assistant", contents=["Nested response"])],
response_id="nested_resp_123",
usage_details=UsageDetails(input_token_count=11, output_token_count=22),
finish_reason="stop",
@@ -2666,12 +2666,12 @@ async def test_capture_messages_preserves_non_ascii_characters(mock_chat_client,
class ClientWithJapanese(mock_chat_client):
async def _inner_get_response(self, *, messages, options, **kwargs):
return ChatResponse(
messages=[Message(role="assistant", text=japanese_text)],
messages=[Message(role="assistant", contents=[japanese_text])],
usage_details=UsageDetails(input_token_count=5, output_token_count=10),
)
client = ClientWithJapanese()
messages = [Message(role="user", text=japanese_text)]
messages = [Message(role="user", contents=[japanese_text])]
span_exporter.clear()
response = await client.get_response(messages=messages, options={"model": "Test"})
@@ -2715,7 +2715,7 @@ async def test_system_instructions_preserves_non_ascii_characters(span_exporter:
_capture_messages(
span=span,
provider_name="test_provider",
messages=[Message(role="user", text="Test")],
messages=[Message(role="user", contents=["Test"])],
system_instructions=chinese_text,
)
@@ -2840,7 +2840,7 @@ async def test_agent_instructions_from_default_options(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel", "instructions": "Default system instructions."}
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await agent.run(messages)
@@ -2866,7 +2866,7 @@ async def test_agent_instructions_from_options_override(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel"} # No default instructions
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await agent.run(messages, options={"instructions": "Override instructions."})
@@ -2891,7 +2891,7 @@ async def test_agent_instructions_merged_from_default_and_options(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel", "instructions": "Default instructions."}
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await agent.run(messages, options={"instructions": "Additional instructions."})
@@ -2918,7 +2918,7 @@ async def test_agent_streaming_instructions_from_default_options(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel", "instructions": "Default streaming instructions."}
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
updates = []
stream = agent.run(messages, stream=True)
@@ -2947,7 +2947,7 @@ async def test_agent_streaming_instructions_merged_from_default_and_options(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel", "instructions": "Default instructions."}
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
updates = []
stream = agent.run(messages, stream=True, options={"instructions": "Stream override."})
@@ -2975,7 +2975,7 @@ async def test_agent_no_instructions_in_default_or_options(
agent = mock_chat_agent()
agent.default_options = {"model": "TestModel"} # No instructions
messages = [Message(role="user", text="Test message")]
messages = [Message(role="user", contents=["Test message"])]
span_exporter.clear()
response = await agent.run(messages)
@@ -3204,7 +3204,7 @@ async def test_agent_invoke_span_aggregates_usage_across_tool_calls(span_exporte
usage_details=UsageDetails(input_token_count=2239, output_token_count=192),
),
ChatResponse(
messages=Message(role="assistant", text="The weather in Seattle is sunny."),
messages=Message(role="assistant", contents=["The weather in Seattle is sunny."]),
usage_details=UsageDetails(input_token_count=2569, output_token_count=99),
),
]
@@ -3248,7 +3248,7 @@ async def test_agent_invoke_span_usage_single_call(span_exporter: InMemorySpanEx
client = MockBaseChatClient()
client.run_responses = [
ChatResponse(
messages=Message(role="assistant", text="Hello!"),
messages=Message(role="assistant", contents=["Hello!"]),
usage_details=UsageDetails(input_token_count=100, output_token_count=50),
),
]
@@ -3291,7 +3291,7 @@ async def test_agent_invoke_span_aggregates_usage_on_max_iterations_exhaustion(s
),
# Exhaustion path: consumed by tool_choice="none" final call (mock ignores usage)
ChatResponse(
messages=Message(role="assistant", text="placeholder"),
messages=Message(role="assistant", contents=["placeholder"]),
usage_details=UsageDetails(input_token_count=300, output_token_count=60),
),
]
@@ -8,8 +8,6 @@ import pytest
from agent_framework import (
AgentContext,
AgentSession,
BaseContextProvider,
BaseHistoryProvider,
ChatContext,
ContextProvider,
HistoryProvider,
@@ -237,23 +235,6 @@ class TestContextProvider:
await provider.after_run(agent=None, session=session, context=ctx, state={}) # type: ignore[arg-type]
# ---------------------------------------------------------------------------
# Deprecated provider alias tests
# ---------------------------------------------------------------------------
class TestDeprecatedProviderAliases:
def test_base_context_provider_warns_and_is_compatible(self) -> None:
with pytest.warns(DeprecationWarning, match="BaseContextProvider is deprecated. Use ContextProvider instead."):
provider = BaseContextProvider(source_id="test")
assert isinstance(provider, ContextProvider)
def test_base_provider_aliases_preserve_subtyping(self) -> None:
assert issubclass(BaseContextProvider, ContextProvider)
assert issubclass(BaseHistoryProvider, HistoryProvider)
# ---------------------------------------------------------------------------
# HistoryProvider tests
# ---------------------------------------------------------------------------
+13 -13
View File
@@ -699,7 +699,7 @@ def test_ai_content_serialization(args: dict):
def test_chat_message_text():
"""Test the Message class to ensure it initializes correctly with text content."""
# Create a Message with a role and text content
message = Message(role="user", text="Hello, how are you?")
message = Message(role="user", contents=["Hello, how are you?"])
# Check the type and content
assert message.role == "user"
@@ -730,7 +730,7 @@ def test_chat_message_contents():
def test_chat_message_with_chatrole_instance():
m = Message(role="user", text="hi")
m = Message(role="user", contents=["hi"])
assert m.role == "user"
assert m.text == "hi"
@@ -741,7 +741,7 @@ def test_chat_message_with_chatrole_instance():
def test_chat_response():
"""Test the ChatResponse class to ensure it initializes correctly with a message."""
# Create a Message
message = Message(role="assistant", text="I'm doing well, thank you!")
message = Message(role="assistant", contents=["I'm doing well, thank you!"])
# Create a ChatResponse with the message
response = ChatResponse(messages=message)
@@ -756,7 +756,7 @@ def test_chat_response():
def test_chat_response_accepts_model_alias() -> None:
"""Test ChatResponse accepts model and exposes it through model alias."""
response = ChatResponse(messages=Message(role="assistant", text="Hello"), model="claude-test")
response = ChatResponse(messages=Message(role="assistant", contents=["Hello"]), model="claude-test")
assert response.model == "claude-test"
assert response.model == "claude-test"
@@ -769,7 +769,7 @@ class OutputModel(BaseModel):
def test_chat_response_with_format():
"""Test the ChatResponse class to ensure it initializes correctly with a message."""
# Create a Message
message = Message(role="assistant", text='{"response": "Hello"}')
message = Message(role="assistant", contents=['{"response": "Hello"}'])
# Create a ChatResponse with the message
response = ChatResponse(messages=message, response_format=OutputModel)
@@ -786,7 +786,7 @@ def test_chat_response_with_format():
def test_chat_response_with_format_init():
"""Test the ChatResponse class to ensure it initializes correctly with a message."""
# Create a Message
message = Message(role="assistant", text='{"response": "Hello"}')
message = Message(role="assistant", contents=['{"response": "Hello"}'])
# Create a ChatResponse with the message
response = ChatResponse(messages=message, response_format=OutputModel)
@@ -802,7 +802,7 @@ def test_chat_response_with_format_init():
def test_chat_response_with_mapping_response_format() -> None:
"""ChatResponse.value should parse JSON when response_format is a mapping."""
message = Message(role="assistant", text='{"response": "Hello"}')
message = Message(role="assistant", contents=['{"response": "Hello"}'])
response = ChatResponse(
messages=message,
response_format={"type": "object", "properties": {"response": {"type": "string"}}},
@@ -821,7 +821,7 @@ def test_chat_response_value_raises_on_invalid_schema():
name: str = Field(min_length=10)
score: int = Field(gt=0, le=100)
message = Message(role="assistant", text='{"id": 1, "name": "test", "score": -5}')
message = Message(role="assistant", contents=['{"id": 1, "name": "test", "score": -5}'])
response = ChatResponse(messages=message, response_format=StrictSchema)
with raises(ValidationError) as exc_info:
@@ -842,7 +842,7 @@ def test_agent_response_value_raises_on_invalid_schema():
name: str = Field(min_length=10)
score: int = Field(gt=0, le=100)
message = Message(role="assistant", text='{"id": 1, "name": "test", "score": -5}')
message = Message(role="assistant", contents=['{"id": 1, "name": "test", "score": -5}'])
response = AgentResponse(messages=message, response_format=StrictSchema)
with raises(ValidationError) as exc_info:
@@ -1185,7 +1185,7 @@ def test_chat_options_and_tool_choice_required_specific_function() -> None:
@fixture
def chat_message() -> Message:
return Message(role="user", text="Hello")
return Message(role="user", contents=["Hello"])
@fixture
@@ -1302,7 +1302,7 @@ def test_agent_run_response_created_at() -> None:
# Test with a properly formatted UTC timestamp
utc_timestamp = "2024-12-01T00:31:30.000000Z"
response = AgentResponse(
messages=[Message(role="assistant", text="Hello")],
messages=[Message(role="assistant", contents=["Hello"])],
created_at=utc_timestamp,
)
assert response.created_at == utc_timestamp
@@ -1312,7 +1312,7 @@ def test_agent_run_response_created_at() -> None:
now_utc = datetime.now(tz=timezone.utc)
formatted_utc = now_utc.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
response_with_now = AgentResponse(
messages=[Message(role="assistant", text="Hello")],
messages=[Message(role="assistant", contents=["Hello"])],
created_at=formatted_utc,
)
assert response_with_now.created_at == formatted_utc
@@ -1466,7 +1466,7 @@ def test_chat_tool_mode_eq_with_string():
@fixture
def agent_run_response_async() -> AgentResponse:
return AgentResponse(messages=[Message(role="user", text="Hello")])
return AgentResponse(messages=[Message(role="user", contents=["Hello"])])
async def test_agent_run_response_from_async_generator():
@@ -158,8 +158,8 @@ async def test_agent_executor_checkpoint_stores_and_restores_state() -> None:
# Add some initial messages to the session state to verify session state persistence
initial_messages = [
Message(role="user", text="Initial message 1"),
Message(role="assistant", text="Initial response 1"),
Message(role="user", contents=["Initial message 1"]),
Message(role="assistant", contents=["Initial response 1"]),
]
initial_session.state["history"] = {"messages": initial_messages}
@@ -256,9 +256,9 @@ async def test_agent_executor_save_and_restore_state_directly() -> None:
# Add messages to session state
session_messages = [
Message(role="user", text="Message in session 1"),
Message(role="assistant", text="Session response 1"),
Message(role="user", text="Message in session 2"),
Message(role="user", contents=["Message in session 1"]),
Message(role="assistant", contents=["Session response 1"]),
Message(role="user", contents=["Message in session 2"]),
]
session.state["history"] = {"messages": session_messages}
@@ -266,8 +266,8 @@ async def test_agent_executor_save_and_restore_state_directly() -> None:
# Add messages to executor cache
cache_messages = [
Message(role="user", text="Cached user message"),
Message(role="assistant", text="Cached assistant response"),
Message(role="user", contents=["Cached user message"]),
Message(role="assistant", contents=["Cached assistant response"]),
]
executor._cache = list(cache_messages) # type: ignore[reportPrivateUsage]
@@ -562,7 +562,7 @@ async def test_checkpoint_restore_works_without_context_mode_in_state() -> None:
# Simulate a checkpoint state without context_mode (as saved by the new code)
state: dict[str, Any] = {
"cache": [Message(role="user", text="cached msg")],
"cache": [Message(role="user", contents=["cached msg"])],
"full_conversation": [],
"agent_session": AgentSession().to_dict(),
"pending_agent_requests": {},
@@ -8,7 +8,7 @@ from agent_framework._workflows._events import WorkflowEvent
def test_workflow_event_with_agent_response_data_type() -> None:
"""Verify WorkflowEvent[AgentResponse].data is typed as AgentResponse."""
response = AgentResponse(messages=[Message(role="assistant", text="Hello")])
response = AgentResponse(messages=[Message(role="assistant", contents=["Hello"])])
event: WorkflowEvent[AgentResponse] = WorkflowEvent.emit(executor_id="test", data=response)
# This assignment should pass type checking without a cast
@@ -29,7 +29,7 @@ def test_workflow_event_with_agent_response_update_data_type() -> None:
def test_workflow_event_repr() -> None:
"""Verify WorkflowEvent.__repr__ uses consistent format."""
response = AgentResponse(messages=[Message(role="assistant", text="Hello")])
response = AgentResponse(messages=[Message(role="assistant", contents=["Hello"])])
event: WorkflowEvent[AgentResponse] = WorkflowEvent.emit(executor_id="test", data=response)
repr_str = repr(event)
@@ -540,7 +540,7 @@ async def test_executor_invoked_event_data_not_mutated_by_handler():
async def mutator(messages: list[Message], ctx: WorkflowContext[list[Message]]) -> None:
# The handler mutates the input list by appending new messages
original_len = len(messages)
messages.append(Message(role="assistant", text="Added by executor"))
messages.append(Message(role="assistant", contents=["Added by executor"]))
await ctx.send_message(messages)
# Verify mutation happened
assert len(messages) == original_len + 1
@@ -548,7 +548,7 @@ async def test_executor_invoked_event_data_not_mutated_by_handler():
workflow = WorkflowBuilder(start_executor=mutator).build()
# Run with a single user message
input_messages = [Message(role="user", text="hello")]
input_messages = [Message(role="user", contents=["hello"])]
events = await workflow.run(input_messages)
# Find the invoked event for the Mutator executor
@@ -322,7 +322,7 @@ class _RoundTripCoordinator(Executor):
assert response.full_conversation is not None
await ctx.send_message(
AgentExecutorRequest(
messages=list(response.full_conversation) + [Message(role="user", text="apply feedback")],
messages=list(response.full_conversation) + [Message(role="user", contents=["apply feedback"])],
should_respond=True,
),
target_id=self._target_agent_id,
@@ -418,7 +418,7 @@ class _FullHistoryReplayCoordinator(Executor):
ctx: WorkflowContext[AgentExecutorRequest, Any],
) -> None:
full_conv = list(response.full_conversation or response.agent_response.messages)
full_conv.append(Message(role="user", text="follow-up"))
full_conv.append(Message(role="user", contents=["follow-up"]))
# Simulate a prior run: the target executor has a stored previous_response_id.
self._target_exec._session.service_session_id = "resp_PREVIOUS_RUN" # pyright: ignore[reportPrivateUsage]
await ctx.send_message(
@@ -344,7 +344,7 @@ class TestWorkflowAgent:
workflow = WorkflowBuilder(start_executor=yielding_executor).build()
# Run directly - should return output event (type='output') in result
direct_result = await workflow.run([Message(role="user", text="hello")])
direct_result = await workflow.run([Message(role="user", contents=["hello"])])
direct_outputs = direct_result.get_outputs()
assert len(direct_outputs) == 1
assert direct_outputs[0] == "processed: hello"
@@ -479,8 +479,8 @@ class TestWorkflowAgent:
async def list_yielding_executor(messages: list[Message], ctx: WorkflowContext[Never, list[Message]]) -> None:
# Yield a list of Messages (as SequentialBuilder does)
msg_list = [
Message(role="user", text="first message"),
Message(role="assistant", text="second message"),
Message(role="user", contents=["first message"]),
Message(role="assistant", contents=["second message"]),
Message(
role="assistant",
contents=[Content.from_text(text="third"), Content.from_text(text="fourth")],
@@ -65,7 +65,7 @@ class DummyAgent(BaseAgent):
if isinstance(m, Message):
norm.append(m)
elif isinstance(m, str):
norm.append(Message(role="user", text=m))
norm.append(Message(role="user", contents=[m]))
return AgentResponse(messages=norm)
async def _run_stream_impl(self) -> AsyncIterator[AgentResponseUpdate]:
@@ -469,10 +469,10 @@ async def test_magentic_kwargs_flow_to_agents() -> None:
self.task_ledger = None
async def plan(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Plan: Test task", author_name="manager")
return Message(role="assistant", contents=["Plan: Test task"], author_name="manager")
async def replan(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Replan: Test task", author_name="manager")
return Message(role="assistant", contents=["Replan: Test task"], author_name="manager")
async def create_progress_ledger(self, magentic_context: MagenticContext) -> MagenticProgressLedger:
# Return completed on first call
@@ -485,7 +485,7 @@ async def test_magentic_kwargs_flow_to_agents() -> None:
)
async def prepare_final_answer(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Final answer", author_name="manager")
return Message(role="assistant", contents=["Final answer"], author_name="manager")
agent = _KwargsCapturingAgent(name="agent1")
manager = _MockManager()
@@ -520,10 +520,10 @@ async def test_magentic_kwargs_stored_in_state() -> None:
self.task_ledger = None
async def plan(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Plan", author_name="manager")
return Message(role="assistant", contents=["Plan"], author_name="manager")
async def replan(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Replan", author_name="manager")
return Message(role="assistant", contents=["Replan"], author_name="manager")
async def create_progress_ledger(self, magentic_context: MagenticContext) -> MagenticProgressLedger:
return MagenticProgressLedger(
@@ -535,7 +535,7 @@ async def test_magentic_kwargs_stored_in_state() -> None:
)
async def prepare_final_answer(self, magentic_context: MagenticContext) -> Message:
return Message(role="assistant", text="Final", author_name="manager")
return Message(role="assistant", contents=["Final"], author_name="manager")
agent = _KwargsCapturingAgent(name="agent1")
manager = _MockManager()