Skip to content

Commit bb5a11f

Browse files
Merge pull request #860 from microsoft/dev-v4
fix: upgraded the agent-framework to latest version
2 parents 946a475 + 649ac4f commit bb5a11f

9 files changed

Lines changed: 315 additions & 240 deletions

File tree

src/backend/pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ requires-python = ">=3.11"
77
dependencies = [
88
"azure-ai-evaluation==1.11.0",
99
"azure-ai-inference==1.0.0b9",
10-
"azure-ai-projects==2.0.0b3",
10+
"azure-ai-projects==2.0.0",
1111
"azure-cosmos==4.9.0",
1212
"azure-identity==1.24.0",
1313
"azure-monitor-events-extension==0.1.0",
@@ -32,8 +32,9 @@ dependencies = [
3232
"mcp==1.26.0",
3333
"werkzeug==3.1.5",
3434
"azure-core==1.38.0",
35-
"agent-framework-azure-ai==1.0.0b260130",
36-
"agent-framework-core==1.0.0b260130",
35+
"agent-framework-azure-ai==1.0.0rc4",
36+
"agent-framework-core==1.0.0rc4",
37+
"agent-framework-orchestrations==1.0.0b260311",
3738
"urllib3==2.6.3",
3839
"protobuf==5.29.6",
3940
"cryptography==46.0.5",

src/backend/uv.lock

Lines changed: 30 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/backend/v4/callbacks/response_handlers.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import re
99
from typing import Any
1010

11-
from agent_framework import ChatMessage
11+
from agent_framework import Message
1212

1313
from v4.config.settings import connection_config
1414
from v4.models.messages import (
@@ -64,22 +64,22 @@ def _extract_tool_calls_from_contents(contents: list[Any]) -> list[AgentToolCall
6464

6565
def agent_response_callback(
6666
agent_id: str,
67-
message: ChatMessage,
67+
message: Message,
6868
user_id: str | None = None,
6969
) -> None:
7070
"""
71-
Final (non-streaming) agent response callback using agent_framework ChatMessage.
71+
Final (non-streaming) agent response callback using agent_framework Message.
7272
"""
7373
agent_name = getattr(message, "author_name", None) or agent_id or "Unknown Agent"
7474
role = getattr(message, "role", "assistant")
7575

76-
# FIX: Properly extract text from ChatMessage
77-
# ChatMessage has a .text property that concatenates all TextContent items
76+
# FIX: Properly extract text from Message
77+
# Message has a .text property that concatenates all TextContent items
7878
text = ""
79-
if isinstance(message, ChatMessage):
79+
if isinstance(message, Message):
8080
text = message.text # Use the property directly
8181
else:
82-
# Fallback for non-ChatMessage objects
82+
# Fallback for non-Message objects
8383
text = str(getattr(message, "text", ""))
8484

8585
text = clean_citations(text or "")
@@ -125,8 +125,8 @@ async def streaming_agent_response_callback(
125125
# If text is None, don't fall back to str(update) as that would show object repr
126126
# Just skip if there's no actual text content
127127
if chunk_text is None:
128-
# Check if update is a ChatMessage
129-
if isinstance(update, ChatMessage):
128+
# Check if update is a Message
129+
if isinstance(update, Message):
130130
chunk_text = update.text or ""
131131
elif hasattr(update, "content"):
132132
chunk_text = str(update.content) if update.content else ""

src/backend/v4/magentic_agents/common/lifecycle.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
from typing import Any, Optional
66

77
from agent_framework import (
8-
ChatAgent,
9-
HostedMCPTool,
8+
Agent,
109
MCPStreamableHTTPTool,
1110
)
1211

@@ -46,8 +45,8 @@ def __init__(
4645
) -> None:
4746
self._stack: AsyncExitStack | None = None
4847
self.mcp_cfg: MCPConfig | None = mcp
49-
self.mcp_tool: HostedMCPTool | None = None
50-
self._agent: ChatAgent | None = None
48+
self.mcp_tool: MCPStreamableHTTPTool | None = None
49+
self._agent: Agent | None = None
5150
self.team_service: TeamService | None = team_service
5251
self.team_config: TeamConfiguration | None = team_config
5352
self.client: Optional[AgentsClient] = None
@@ -155,9 +154,9 @@ def get_chat_client(self) -> AzureAIClient:
155154
"""
156155
if (
157156
self._agent
158-
and self._agent.chat_client
157+
and self._agent.client
159158
):
160-
return self._agent.chat_client # type: ignore
159+
return self._agent.client # type: ignore
161160
chat_client = AzureAIClient(
162161
project_endpoint=self.project_endpoint,
163162
agent_name=self.agent_name,

src/backend/v4/magentic_agents/foundry_agent.py

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
import logging
44
from typing import List, Optional
55

6-
from agent_framework import (ChatAgent, ChatMessage, HostedCodeInterpreterTool,
7-
Role)
6+
from agent_framework import (Agent, Message, ChatOptions)
87
from agent_framework_azure_ai import \
98
AzureAIClient # Provided by agent_framework
109
from azure.ai.projects.models import (
1110
PromptAgentDefinition,
12-
AzureAISearchAgentTool,
11+
AzureAISearchTool,
1312
AzureAISearchToolResource,
1413
AISearchIndexResource,
1514
)
@@ -92,17 +91,13 @@ def _is_azure_search_requested(self) -> bool:
9291
return False
9392

9493
async def _collect_tools(self) -> List:
95-
"""Collect tool definitions for ChatAgent (MCP path only)."""
94+
"""Collect tool definitions for Agent (MCP path only)."""
9695
tools: List = []
9796

98-
# Code Interpreter (only in MCP path per incompatibility note)
97+
# Code Interpreter is now handled server-side via AzureAIClient agent definition.
98+
# HostedCodeInterpreterTool was removed in rc4.
9999
if self.enable_code_interpreter:
100-
try:
101-
code_tool = HostedCodeInterpreterTool()
102-
tools.append(code_tool)
103-
self.logger.info("Added Code Interpreter tool.")
104-
except Exception as ie:
105-
self.logger.error("Code Interpreter tool creation failed: %s", ie)
100+
self.logger.info("Code Interpreter requested — handled server-side by AzureAIClient.")
106101

107102
# MCP Tool (from base class)
108103
if self.mcp_tool:
@@ -121,7 +116,7 @@ async def _create_azure_search_enabled_client(self) -> Optional[AzureAIClient]:
121116
122117
This uses the AIProjectClient.agents.create_version() approach with:
123118
- PromptAgentDefinition for agent configuration
124-
- AzureAISearchAgentTool with AzureAISearchToolResource for search capability
119+
- AzureAISearchTool with AzureAISearchToolResource for search capability
125120
- AISearchIndexResource for index configuration with project_connection_id
126121
127122
Requirements:
@@ -167,7 +162,7 @@ async def _create_azure_search_enabled_client(self) -> Optional[AzureAIClient]:
167162
top_k,
168163
)
169164

170-
# Create agent using create_version with PromptAgentDefinition and AzureAISearchAgentTool
165+
# Create agent using create_version with PromptAgentDefinition and AzureAISearchTool
171166
# This approach matches the Knowledge Mining Solution Accelerator pattern
172167
try:
173168
enhanced_instructions = (
@@ -181,7 +176,7 @@ async def _create_azure_search_enabled_client(self) -> Optional[AzureAIClient]:
181176
model=self.model_deployment_name,
182177
instructions=enhanced_instructions,
183178
tools=[
184-
AzureAISearchAgentTool(
179+
AzureAISearchTool(
185180
azure_ai_search=AzureAISearchToolResource(
186181
indexes=[
187182
AISearchIndexResource(
@@ -253,37 +248,39 @@ async def _after_open(self) -> None:
253248
)
254249

255250
# In Azure Search raw tool path, tools/tool_choice are handled server-side.
256-
self._agent = ChatAgent(
251+
self._agent = Agent(
257252
id=self.get_agent_id(),
258-
chat_client=chat_client,
253+
client=chat_client,
259254
instructions=self.agent_instructions,
260255
name=self.agent_name,
261256
description=self.agent_description,
262-
tool_choice="required", # Force usage
263-
temperature=temp,
264-
model_id=self.model_deployment_name,
265-
default_options={"store": False}, # Client-managed conversation to avoid stale tool call IDs across rounds
257+
default_options=ChatOptions(
258+
store=False,
259+
tool_choice="required",
260+
temperature=temp,
261+
),
266262
)
267263
else:
268264
# MCP path (also used by RAI agent which has no tools)
269265
self.logger.info("Initializing agent in MCP mode.")
270266
tools = await self._collect_tools()
271-
self._agent = ChatAgent(
267+
self._agent = Agent(
272268
id=self.get_agent_id(),
273-
chat_client=self.get_chat_client(),
269+
client=self.get_chat_client(),
274270
instructions=self.agent_instructions,
275271
name=self.agent_name,
276272
description=self.agent_description,
277273
tools=tools if tools else None,
278-
tool_choice="auto" if tools else "none",
279-
temperature=temp,
280-
model_id=self.model_deployment_name,
281-
default_options={"store": False}, # Client-managed conversation to avoid stale tool call IDs across rounds
274+
default_options=ChatOptions(
275+
store=False,
276+
tool_choice="auto" if tools else "none",
277+
temperature=temp,
278+
),
282279
)
283-
self.logger.info("Initialized ChatAgent '%s'", self.agent_name)
280+
self.logger.info("Initialized Agent '%s'", self.agent_name)
284281

285282
except Exception as ex:
286-
self.logger.error("Failed to initialize ChatAgent: %s", ex)
283+
self.logger.error("Failed to initialize Agent: %s", ex)
287284
raise
288285

289286
# Register agent globally
@@ -305,9 +302,9 @@ async def invoke(self, prompt: str):
305302
if not self._agent:
306303
raise RuntimeError("Agent not initialized; call open() first.")
307304

308-
messages = [ChatMessage(role=Role.USER, text=prompt)]
305+
messages = [Message(role="user", text=prompt)]
309306

310-
async for update in self._agent.run_stream(messages):
307+
async for update in self._agent.run(messages, stream=True):
311308
yield update
312309

313310
# -------------------------

0 commit comments

Comments
 (0)