Skip to content

Commit 18f650a

Browse files
Fix ChatMessage and Role API changes across packages
After rebasing on upstream/main which merged PR #3647 (Types API Review improvements), fix all packages to use the new API: - ChatMessage: Use keyword args (role=, text=, contents=) instead of positional args - Role: Compare using .value attribute since it's now an enum Packages fixed: - ag-ui: Fixed Role value extraction bugs in _message_adapters.py - anthropic: Fixed ChatMessage and Role comparisons in tests - azure-ai: Fixed Role comparison in _client.py - azure-ai-search: Fixed ChatMessage and Role in source/tests - bedrock: Fixed ChatMessage signatures in tests - chatkit: Fixed ChatMessage and Role in source/tests - copilotstudio: Fixed ChatMessage and Role in tests - declarative: Fixed ChatMessage in _executors_agents.py - mem0: Fixed ChatMessage and Role in source/tests - purview: Fixed ChatMessage in source/tests
1 parent 4cefbc0 commit 18f650a

File tree

15 files changed

+126
-116
lines changed

15 files changed

+126
-116
lines changed

python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ def _update_tool_call_arguments(
268268

269269
def _find_matching_func_call(call_id: str) -> Content | None:
270270
for prev_msg in result:
271-
role_val = prev_msg.role if hasattr(prev_msg.role, "value") else str(prev_msg.role)
271+
role_val = prev_msg.role.value if hasattr(prev_msg.role, "value") else str(prev_msg.role)
272272
if role_val != "assistant":
273273
continue
274274
for content in prev_msg.contents or []:
@@ -286,7 +286,7 @@ def _resolve_approval_call_id(tool_call_id: str, parsed_payload: dict[str, Any]
286286
return str(explicit_call_id)
287287

288288
for prev_msg in result:
289-
role_val = prev_msg.role if hasattr(prev_msg.role, "value") else str(prev_msg.role)
289+
role_val = prev_msg.role.value if hasattr(prev_msg.role, "value") else str(prev_msg.role)
290290
if role_val != "assistant":
291291
continue
292292
direct_call = None
@@ -395,7 +395,7 @@ def _filter_modified_args(
395395
m
396396
for m in result
397397
if not (
398-
(m.role if hasattr(m.role, "value") else str(m.role)) == "tool"
398+
(m.role.value if hasattr(m.role, "value") else str(m.role)) == "tool"
399399
and any(
400400
c.type == "function_result" and c.call_id == approval_call_id
401401
for c in (m.contents or [])

python/packages/anthropic/tests/test_anthropic_client.py

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def test_anthropic_client_service_url(mock_anthropic_client: MagicMock) -> None:
148148
def test_prepare_message_for_anthropic_text(mock_anthropic_client: MagicMock) -> None:
149149
"""Test converting text message to Anthropic format."""
150150
chat_client = create_test_anthropic_client(mock_anthropic_client)
151-
message = ChatMessage("user", ["Hello, world!"])
151+
message = ChatMessage(role="user", text="Hello, world!")
152152

153153
result = chat_client._prepare_message_for_anthropic(message)
154154

@@ -227,8 +227,8 @@ def test_prepare_messages_for_anthropic_with_system(mock_anthropic_client: Magic
227227
"""Test converting messages list with system message."""
228228
chat_client = create_test_anthropic_client(mock_anthropic_client)
229229
messages = [
230-
ChatMessage("system", ["You are a helpful assistant."]),
231-
ChatMessage("user", ["Hello!"]),
230+
ChatMessage(role="system", text="You are a helpful assistant."),
231+
ChatMessage(role="user", text="Hello!"),
232232
]
233233

234234
result = chat_client._prepare_messages_for_anthropic(messages)
@@ -243,8 +243,8 @@ def test_prepare_messages_for_anthropic_without_system(mock_anthropic_client: Ma
243243
"""Test converting messages list without system message."""
244244
chat_client = create_test_anthropic_client(mock_anthropic_client)
245245
messages = [
246-
ChatMessage("user", ["Hello!"]),
247-
ChatMessage("assistant", ["Hi there!"]),
246+
ChatMessage(role="user", text="Hello!"),
247+
ChatMessage(role="assistant", text="Hi there!"),
248248
]
249249

250250
result = chat_client._prepare_messages_for_anthropic(messages)
@@ -372,7 +372,7 @@ async def test_prepare_options_basic(mock_anthropic_client: MagicMock) -> None:
372372
"""Test _prepare_options with basic ChatOptions."""
373373
chat_client = create_test_anthropic_client(mock_anthropic_client)
374374

375-
messages = [ChatMessage("user", ["Hello"])]
375+
messages = [ChatMessage(role="user", text="Hello")]
376376
chat_options = ChatOptions(max_tokens=100, temperature=0.7)
377377

378378
run_options = chat_client._prepare_options(messages, chat_options)
@@ -388,8 +388,8 @@ async def test_prepare_options_with_system_message(mock_anthropic_client: MagicM
388388
chat_client = create_test_anthropic_client(mock_anthropic_client)
389389

390390
messages = [
391-
ChatMessage("system", ["You are helpful."]),
392-
ChatMessage("user", ["Hello"]),
391+
ChatMessage(role="system", text="You are helpful."),
392+
ChatMessage(role="user", text="Hello"),
393393
]
394394
chat_options = ChatOptions()
395395

@@ -403,7 +403,7 @@ async def test_prepare_options_with_tool_choice_auto(mock_anthropic_client: Magi
403403
"""Test _prepare_options with auto tool choice."""
404404
chat_client = create_test_anthropic_client(mock_anthropic_client)
405405

406-
messages = [ChatMessage("user", ["Hello"])]
406+
messages = [ChatMessage(role="user", text="Hello")]
407407
chat_options = ChatOptions(tool_choice="auto")
408408

409409
run_options = chat_client._prepare_options(messages, chat_options)
@@ -415,7 +415,7 @@ async def test_prepare_options_with_tool_choice_required(mock_anthropic_client:
415415
"""Test _prepare_options with required tool choice."""
416416
chat_client = create_test_anthropic_client(mock_anthropic_client)
417417

418-
messages = [ChatMessage("user", ["Hello"])]
418+
messages = [ChatMessage(role="user", text="Hello")]
419419
# For required with specific function, need to pass as dict
420420
chat_options = ChatOptions(tool_choice={"mode": "required", "required_function_name": "get_weather"})
421421

@@ -429,7 +429,7 @@ async def test_prepare_options_with_tool_choice_none(mock_anthropic_client: Magi
429429
"""Test _prepare_options with none tool choice."""
430430
chat_client = create_test_anthropic_client(mock_anthropic_client)
431431

432-
messages = [ChatMessage("user", ["Hello"])]
432+
messages = [ChatMessage(role="user", text="Hello")]
433433
chat_options = ChatOptions(tool_choice="none")
434434

435435
run_options = chat_client._prepare_options(messages, chat_options)
@@ -446,7 +446,7 @@ def get_weather(location: str) -> str:
446446
"""Get weather for a location."""
447447
return f"Weather for {location}"
448448

449-
messages = [ChatMessage("user", ["Hello"])]
449+
messages = [ChatMessage(role="user", text="Hello")]
450450
chat_options = ChatOptions(tools=[get_weather])
451451

452452
run_options = chat_client._prepare_options(messages, chat_options)
@@ -459,7 +459,7 @@ async def test_prepare_options_with_stop_sequences(mock_anthropic_client: MagicM
459459
"""Test _prepare_options with stop sequences."""
460460
chat_client = create_test_anthropic_client(mock_anthropic_client)
461461

462-
messages = [ChatMessage("user", ["Hello"])]
462+
messages = [ChatMessage(role="user", text="Hello")]
463463
chat_options = ChatOptions(stop=["STOP", "END"])
464464

465465
run_options = chat_client._prepare_options(messages, chat_options)
@@ -471,7 +471,7 @@ async def test_prepare_options_with_top_p(mock_anthropic_client: MagicMock) -> N
471471
"""Test _prepare_options with top_p."""
472472
chat_client = create_test_anthropic_client(mock_anthropic_client)
473473

474-
messages = [ChatMessage("user", ["Hello"])]
474+
messages = [ChatMessage(role="user", text="Hello")]
475475
chat_options = ChatOptions(top_p=0.9)
476476

477477
run_options = chat_client._prepare_options(messages, chat_options)
@@ -498,11 +498,11 @@ def test_process_message_basic(mock_anthropic_client: MagicMock) -> None:
498498
assert response.response_id == "msg_123"
499499
assert response.model_id == "claude-3-5-sonnet-20241022"
500500
assert len(response.messages) == 1
501-
assert response.messages[0].role == "assistant"
501+
assert response.messages[0].role.value == "assistant"
502502
assert len(response.messages[0].contents) == 1
503503
assert response.messages[0].contents[0].type == "text"
504504
assert response.messages[0].contents[0].text == "Hello there!"
505-
assert response.finish_reason == "stop"
505+
assert response.finish_reason.value == "stop"
506506
assert response.usage_details is not None
507507
assert response.usage_details["input_token_count"] == 10
508508
assert response.usage_details["output_token_count"] == 5
@@ -532,7 +532,7 @@ def test_process_message_with_tool_use(mock_anthropic_client: MagicMock) -> None
532532
assert response.messages[0].contents[0].type == "function_call"
533533
assert response.messages[0].contents[0].call_id == "call_123"
534534
assert response.messages[0].contents[0].name == "get_weather"
535-
assert response.finish_reason == "tool_calls"
535+
assert response.finish_reason.value == "tool_calls"
536536

537537

538538
def test_parse_usage_from_anthropic_basic(mock_anthropic_client: MagicMock) -> None:
@@ -666,7 +666,7 @@ async def test_inner_get_response(mock_anthropic_client: MagicMock) -> None:
666666

667667
mock_anthropic_client.beta.messages.create.return_value = mock_message
668668

669-
messages = [ChatMessage("user", ["Hi"])]
669+
messages = [ChatMessage(role="user", text="Hi")]
670670
chat_options = ChatOptions(max_tokens=10)
671671

672672
response = await chat_client._inner_get_response( # type: ignore[attr-defined]
@@ -690,7 +690,7 @@ async def mock_stream():
690690

691691
mock_anthropic_client.beta.messages.create.return_value = mock_stream()
692692

693-
messages = [ChatMessage("user", ["Hi"])]
693+
messages = [ChatMessage(role="user", text="Hi")]
694694
chat_options = ChatOptions(max_tokens=10)
695695

696696
chunks: list[ChatResponseUpdate] = []
@@ -721,13 +721,13 @@ async def test_anthropic_client_integration_basic_chat() -> None:
721721
"""Integration test for basic chat completion."""
722722
client = AnthropicClient()
723723

724-
messages = [ChatMessage("user", ["Say 'Hello, World!' and nothing else."])]
724+
messages = [ChatMessage(role="user", text="Say 'Hello, World!' and nothing else.")]
725725

726726
response = await client.get_response(messages=messages, options={"max_tokens": 50})
727727

728728
assert response is not None
729729
assert len(response.messages) > 0
730-
assert response.messages[0].role == "assistant"
730+
assert response.messages[0].role.value == "assistant"
731731
assert len(response.messages[0].text) > 0
732732
assert response.usage_details is not None
733733

@@ -738,7 +738,7 @@ async def test_anthropic_client_integration_streaming_chat() -> None:
738738
"""Integration test for streaming chat completion."""
739739
client = AnthropicClient()
740740

741-
messages = [ChatMessage("user", ["Count from 1 to 5."])]
741+
messages = [ChatMessage(role="user", text="Count from 1 to 5.")]
742742

743743
chunks = []
744744
async for chunk in client.get_response(messages=messages, stream=True, options={"max_tokens": 50}):
@@ -754,7 +754,7 @@ async def test_anthropic_client_integration_function_calling() -> None:
754754
"""Integration test for function calling."""
755755
client = AnthropicClient()
756756

757-
messages = [ChatMessage("user", ["What's the weather in San Francisco?"])]
757+
messages = [ChatMessage(role="user", text="What's the weather in San Francisco?")]
758758
tools = [get_weather]
759759

760760
response = await client.get_response(
@@ -774,7 +774,7 @@ async def test_anthropic_client_integration_hosted_tools() -> None:
774774
"""Integration test for hosted tools."""
775775
client = AnthropicClient()
776776

777-
messages = [ChatMessage("user", ["What tools do you have available?"])]
777+
messages = [ChatMessage(role="user", text="What tools do you have available?")]
778778
tools = [
779779
HostedWebSearchTool(),
780780
HostedCodeInterpreterTool(),
@@ -801,8 +801,8 @@ async def test_anthropic_client_integration_with_system_message() -> None:
801801
client = AnthropicClient()
802802

803803
messages = [
804-
ChatMessage("system", ["You are a pirate. Always respond like a pirate."]),
805-
ChatMessage("user", ["Hello!"]),
804+
ChatMessage(role="system", text="You are a pirate. Always respond like a pirate."),
805+
ChatMessage(role="user", text="Hello!"),
806806
]
807807

808808
response = await client.get_response(messages=messages, options={"max_tokens": 50})
@@ -817,7 +817,7 @@ async def test_anthropic_client_integration_temperature_control() -> None:
817817
"""Integration test with temperature control."""
818818
client = AnthropicClient()
819819

820-
messages = [ChatMessage("user", ["Say hello."])]
820+
messages = [ChatMessage(role="user", text="Say hello.")]
821821

822822
response = await client.get_response(
823823
messages=messages,
@@ -835,11 +835,11 @@ async def test_anthropic_client_integration_ordering() -> None:
835835
client = AnthropicClient()
836836

837837
messages = [
838-
ChatMessage("user", ["Say hello."]),
839-
ChatMessage("user", ["Then say goodbye."]),
840-
ChatMessage("assistant", ["Thank you for chatting!"]),
841-
ChatMessage("assistant", ["Let me know if I can help."]),
842-
ChatMessage("user", ["Just testing things."]),
838+
ChatMessage(role="user", text="Say hello."),
839+
ChatMessage(role="user", text="Then say goodbye."),
840+
ChatMessage(role="assistant", text="Thank you for chatting!"),
841+
ChatMessage(role="assistant", text="Let me know if I can help."),
842+
ChatMessage(role="user", text="Just testing things."),
843843
]
844844

845845
response = await client.get_response(messages=messages)

python/packages/azure-ai-search/agent_framework_azure_ai_search/_search_provider.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,13 @@ async def invoking(
524524
# Convert to list and filter to USER/ASSISTANT messages with text only
525525
messages_list = [messages] if isinstance(messages, ChatMessage) else list(messages)
526526

527+
def get_role_value(role: str) -> str:
528+
return role.value if hasattr(role, "value") else str(role) # type: ignore[union-attr]
529+
527530
filtered_messages = [
528-
msg for msg in messages_list if msg and msg.text and msg.text.strip() and msg.role in ["user", "assistant"]
531+
msg
532+
for msg in messages_list
533+
if msg and msg.text and msg.text.strip() and get_role_value(msg.role) in ["user", "assistant"]
529534
]
530535

531536
if not filtered_messages:
@@ -546,8 +551,8 @@ async def invoking(
546551
return Context()
547552

548553
# Create context messages: first message with prompt, then one message per result part
549-
context_messages = [ChatMessage("user", [self.context_prompt])]
550-
context_messages.extend([ChatMessage("user", [part]) for part in search_result_parts])
554+
context_messages = [ChatMessage(role="user", text=self.context_prompt)]
555+
context_messages.extend([ChatMessage(role="user", text=part) for part in search_result_parts])
551556

552557
return Context(messages=context_messages)
553558

@@ -919,7 +924,7 @@ async def _agentic_search(self, messages: list[ChatMessage]) -> list[str]:
919924
# Medium/low reasoning uses messages with conversation history
920925
kb_messages = [
921926
KnowledgeBaseMessage(
922-
role=msg.role if hasattr(msg.role, "value") else str(msg.role),
927+
role=msg.role.value if hasattr(msg.role, "value") else str(msg.role),
923928
content=[KnowledgeBaseMessageTextContent(text=msg.text)],
924929
)
925930
for msg in messages

python/packages/azure-ai-search/tests/test_search_provider.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def mock_index_client() -> AsyncMock:
3939
def sample_messages() -> list[ChatMessage]:
4040
"""Create sample chat messages for testing."""
4141
return [
42-
ChatMessage("user", ["What is in the documents?"]),
42+
ChatMessage(role="user", text="What is in the documents?"),
4343
]
4444

4545

@@ -318,7 +318,7 @@ async def test_semantic_search_empty_query(self, mock_search_class: MagicMock) -
318318
)
319319

320320
# Empty message
321-
context = await provider.invoking([ChatMessage("user", [""])])
321+
context = await provider.invoking([ChatMessage(role="user", text="")])
322322

323323
assert isinstance(context, Context)
324324
assert len(context.messages) == 0
@@ -520,10 +520,10 @@ async def test_filters_non_user_assistant_messages(self, mock_search_class: Magi
520520

521521
# Mix of message types
522522
messages = [
523-
ChatMessage("system", ["System message"]),
524-
ChatMessage("user", ["User message"]),
525-
ChatMessage("assistant", ["Assistant message"]),
526-
ChatMessage("tool", ["Tool message"]),
523+
ChatMessage(role="system", text="System message"),
524+
ChatMessage(role="user", text="User message"),
525+
ChatMessage(role="assistant", text="Assistant message"),
526+
ChatMessage(role="tool", text="Tool message"),
527527
]
528528

529529
context = await provider.invoking(messages)
@@ -548,9 +548,9 @@ async def test_filters_empty_messages(self, mock_search_class: MagicMock) -> Non
548548

549549
# Messages with empty/whitespace text
550550
messages = [
551-
ChatMessage("user", [""]),
552-
ChatMessage("user", [" "]),
553-
ChatMessage("user", [None]),
551+
ChatMessage(role="user", text=""),
552+
ChatMessage(role="user", text=" "),
553+
ChatMessage(role="user", text=""), # ChatMessage with None text becomes empty string
554554
]
555555

556556
context = await provider.invoking(messages)
@@ -581,7 +581,7 @@ async def test_citations_included_in_semantic_search(self, mock_search_class: Ma
581581
mode="semantic",
582582
)
583583

584-
context = await provider.invoking([ChatMessage("user", ["test query"])])
584+
context = await provider.invoking([ChatMessage(role="user", text="test query")])
585585

586586
# Check that citation is included
587587
assert isinstance(context, Context)

python/packages/azure-ai/agent_framework_azure_ai/_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ def _prepare_messages_for_azure_ai(self, messages: Sequence[ChatMessage]) -> tup
495495

496496
# System/developer messages are turned into instructions, since there is no such message roles in Azure AI.
497497
for message in messages:
498-
if message.role in ["system", "developer"]:
498+
role_value = message.role.value if hasattr(message.role, "value") else message.role
499+
if role_value in ["system", "developer"]:
499500
for text_content in [content for content in message.contents if content.type == "text"]:
500501
instructions_list.append(text_content.text) # type: ignore[arg-type]
501502
else:

python/packages/bedrock/tests/test_bedrock_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ async def test_get_response_invokes_bedrock_runtime() -> None:
4141
)
4242

4343
messages = [
44-
ChatMessage("system", [Content.from_text(text="You are concise.")]),
45-
ChatMessage("user", [Content.from_text(text="hello")]),
44+
ChatMessage(role="system", contents=[Content.from_text(text="You are concise.")]),
45+
ChatMessage(role="user", contents=[Content.from_text(text="hello")]),
4646
]
4747

4848
response = await client.get_response(messages=messages, options={"max_tokens": 32})
@@ -62,7 +62,7 @@ def test_build_request_requires_non_system_messages() -> None:
6262
client=_StubBedrockRuntime(),
6363
)
6464

65-
messages = [ChatMessage("system", [Content.from_text(text="Only system text")])]
65+
messages = [ChatMessage(role="system", contents=[Content.from_text(text="Only system text")])]
6666

6767
with pytest.raises(ServiceInitializationError):
6868
client._prepare_options(messages, {})

python/packages/bedrock/tests/test_bedrock_settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_build_request_includes_tool_config() -> None:
4646
"tools": [tool],
4747
"tool_choice": {"mode": "required", "required_function_name": "get_weather"},
4848
}
49-
messages = [ChatMessage("user", [Content.from_text(text="hi")])]
49+
messages = [ChatMessage(role="user", contents=[Content.from_text(text="hi")])]
5050

5151
request = client._prepare_options(messages, options)
5252

@@ -58,7 +58,7 @@ def test_build_request_serializes_tool_history() -> None:
5858
client = _build_client()
5959
options: ChatOptions = {}
6060
messages = [
61-
ChatMessage("user", [Content.from_text(text="how's weather?")]),
61+
ChatMessage(role="user", contents=[Content.from_text(text="how's weather?")]),
6262
ChatMessage(
6363
role="assistant",
6464
contents=[

0 commit comments

Comments
 (0)