Skip to content

Commit 006fefc

Browse files
Merge branch 'main' into dev
2 parents 6207327 + af8f43b commit 006fefc

19 files changed

+581
-286
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Each line is a file pattern followed by one or more owners.
33

44
# These owners will be the default owners for everything in the repo.
5-
* @Avijit-Microsoft @Roopan-Microsoft @Prajwal-Microsoft @marktayl1 @Fr4nc3
5+
* @Avijit-Microsoft @Roopan-Microsoft @Prajwal-Microsoft @marktayl1 @Fr4nc3 @Vinay-Microsoft @aniaroramsft

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
id: generate_rg_name
7474
run: |
7575
echo "Generating a unique resource group name..."
76-
ACCL_NAME="ci-biab" # Account name as specified
76+
ACCL_NAME="macae" # Account name as specified
7777
SHORT_UUID=$(uuidgen | cut -d'-' -f1)
7878
UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}"
7979
echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ Here are some example regions where the services are available: East US, East US
9595

9696
Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage. The majority of the Azure resources used in this infrastructure are on usage-based pricing tiers. However, Azure Container Registry has a fixed cost per registry per day.
9797

98-
Use the [Azure pricing calculator](https://azure.microsoft.com/en-us/pricing/calculator) to calculate the cost of this solution in your subscription.
99-
98+
Use the [Azure pricing calculator](https://azure.microsoft.com/en-us/pricing/calculator) to calculate the cost of this solution in your subscription. [Review a sample pricing sheet for the achitecture](https://azure.com/e/86d0eefbe4dd4a23981c1d3d4f6fe7ed).
10099
| Product | Description | Cost |
101100
|---|---|---|
102101
| [Azure OpenAI Service](https://learn.microsoft.com/azure/ai-services/openai/) | Powers the AI agents for task automation | [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/) |

azure.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
22
name: multi-agent-custom-automation-engine-solution-accelerator
3+
metadata:
4+
-5.04 KB
Loading

infra/main.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ var modelVersion = '2024-08-06'
7070
var aiServicesName = '${abbrs.ai.aiServices}${solutionPrefix}'
7171
var deploymentType = 'GlobalStandard'
7272
var gptModelVersion = 'gpt-4o'
73-
var appVersion = 'fnd01'
73+
var appVersion = 'latest'
7474
var resgistryName = 'biabcontainerreg'
7575
var dockerRegistryUrl = 'https://${resgistryName}.azurecr.io'
7676

infra/main.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"_generator": {
77
"name": "bicep",
88
"version": "0.35.1.17967",
9-
"templateHash": "5028939591915540887"
9+
"templateHash": "6559422175999367984"
1010
}
1111
},
1212
"parameters": {
@@ -341,7 +341,7 @@
341341
"aiServicesName": "[format('{0}{1}', variables('abbrs').ai.aiServices, variables('solutionPrefix'))]",
342342
"deploymentType": "GlobalStandard",
343343
"gptModelVersion": "gpt-4o",
344-
"appVersion": "fnd01",
344+
"appVersion": "latest",
345345
"resgistryName": "biabcontainerreg",
346346
"dockerRegistryUrl": "[format('https://{0}.azurecr.io', variables('resgistryName'))]",
347347
"backendDockerImageURL": "[format('{0}.azurecr.io/macaebackend:{1}', variables('resgistryName'), variables('appVersion'))]",

src/backend/app_config.py

Lines changed: 6 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# app_config.py
2-
import os
32
import logging
4-
from typing import Optional, List
5-
from dotenv import load_dotenv
6-
from azure.identity import DefaultAzureCredential
7-
from azure.cosmos.aio import CosmosClient
3+
import os
4+
from typing import Optional
5+
86
from azure.ai.projects.aio import AIProjectClient
7+
from azure.cosmos.aio import CosmosClient
8+
from azure.identity import DefaultAzureCredential
9+
from dotenv import load_dotenv
910
from semantic_kernel.kernel import Kernel
10-
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent
11-
from semantic_kernel.functions import KernelFunction
1211

1312
# Load environment variables from .env file
1413
load_dotenv()
@@ -188,94 +187,6 @@ def get_ai_project_client(self):
188187
logging.error("Failed to create AIProjectClient: %s", exc)
189188
raise
190189

191-
async def create_azure_ai_agent(
192-
self,
193-
agent_name: str,
194-
instructions: str,
195-
tools: Optional[List[KernelFunction]] = None,
196-
client=None,
197-
response_format=None,
198-
temperature: float = 0.0,
199-
):
200-
"""
201-
Creates a new Azure AI Agent with the specified name and instructions using AIProjectClient.
202-
If an agent with the given name (assistant_id) already exists, it tries to retrieve it first.
203-
204-
Args:
205-
kernel: The Semantic Kernel instance
206-
agent_name: The name of the agent (will be used as assistant_id)
207-
instructions: The system message / instructions for the agent
208-
agent_type: The type of agent (defaults to "assistant")
209-
tools: Optional tool definitions for the agent
210-
tool_resources: Optional tool resources required by the tools
211-
response_format: Optional response format to control structured output
212-
temperature: The temperature setting for the agent (defaults to 0.0)
213-
214-
Returns:
215-
A new AzureAIAgent instance
216-
"""
217-
try:
218-
# Get the AIProjectClient
219-
if client is None:
220-
client = self.get_ai_project_client()
221-
222-
# # ToDo: This is the fixed code but commenting it out as agent clean up is no happening yet
223-
# # and there are multiple versions of agents due to testing
224-
# # First try to get an existing agent with this name as assistant_id
225-
# try:
226-
# agent_id = None
227-
# agent_list = await client.agents.list_agents()
228-
# for agent in agent_list.data:
229-
# if agent.name == agent_name:
230-
# agent_id = agent.id
231-
# break
232-
# # If the agent already exists, we can use it directly
233-
# # Get the existing agent definition
234-
# existing_definition = await client.agents.get_agent(agent_id)
235-
# # Create the agent instance directly with project_client and existing definition
236-
# agent = AzureAIAgent(
237-
# client=client,
238-
# definition=existing_definition,
239-
# plugins=tools,
240-
# )
241-
242-
# client.agents.list_agents()
243-
244-
# return agent
245-
# except Exception as e:
246-
# # The Azure AI Projects SDK throws an exception when the agent doesn't exist
247-
# # (not returning None), so we catch it and proceed to create a new agent
248-
# if "ResourceNotFound" in str(e) or "404" in str(e):
249-
# logging.info(
250-
# f"Agent with ID {agent_name} not found. Will create a new one."
251-
# )
252-
# else:
253-
# # Log unexpected errors but still try to create a new agent
254-
# logging.warning(
255-
# f"Unexpected error while retrieving agent {agent_name}: {str(e)}. Attempting to create new agent."
256-
# )
257-
258-
# Create the agent using the project client with the agent_name as both name and assistantId
259-
agent_definition = await client.agents.create_agent(
260-
model=self.AZURE_OPENAI_DEPLOYMENT_NAME,
261-
name=agent_name,
262-
instructions=instructions,
263-
temperature=temperature,
264-
response_format=response_format,
265-
)
266-
267-
# Create the agent instance directly with project_client and definition
268-
agent = AzureAIAgent(
269-
client=client,
270-
definition=agent_definition,
271-
plugins=tools,
272-
)
273-
274-
return agent
275-
except Exception as exc:
276-
logging.error("Failed to create Azure AI Agent: %s", exc)
277-
raise
278-
279190

280191
# Create a global instance of AppConfig
281192
config = AppConfig()

src/backend/kernel_agents/agent_base.py

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
11
import logging
2-
from typing import Any, List, Mapping, Optional
3-
4-
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent
5-
from semantic_kernel.functions import KernelFunction
6-
2+
from abc import abstractmethod
3+
from typing import (Any, List, Mapping, Optional)
74

85
# Import the new AppConfig instance
96
from app_config import config
107
from context.cosmos_memory_kernel import CosmosMemoryContext
118
from event_utils import track_event_if_configured
12-
from models.messages_kernel import (
13-
ActionRequest,
14-
ActionResponse,
15-
AgentMessage,
16-
Step,
17-
StepStatus,
18-
)
9+
from models.messages_kernel import (ActionRequest, ActionResponse,
10+
AgentMessage, Step, StepStatus)
11+
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent
12+
from semantic_kernel.functions import KernelFunction
1913

2014
# Default formatting instructions used across agents
2115
DEFAULT_FORMATTING_INSTRUCTIONS = "Instructions: returning the output of this function call verbatim to the user in markdown. Then write AGENT SUMMARY: and then include a summary of what you did."
@@ -59,6 +53,7 @@ def __init__(
5953
endpoint=None, # Set as needed
6054
api_version=None, # Set as needed
6155
token=None, # Set as needed
56+
model=config.AZURE_OPENAI_DEPLOYMENT_NAME,
6257
agent_name=agent_name,
6358
system_prompt=system_message,
6459
client=client,
@@ -73,7 +68,7 @@ def __init__(
7368
self._tools = tools
7469
self._system_message = system_message
7570
self._chat_history = [{"role": "system", "content": self._system_message}]
76-
self._agent = None # Will be initialized in async_init
71+
# self._agent = None # Will be initialized in async_init
7772

7873
# Required properties for AgentGroupChat compatibility
7974
self.name = agent_name # This is crucial for AgentGroupChat to identify agents
@@ -91,24 +86,6 @@ def default_system_message(agent_name=None) -> str:
9186
name = agent_name
9287
return f"You are an AI assistant named {name}. Help the user by providing accurate and helpful information."
9388

94-
async def async_init(self):
95-
"""Asynchronously initialize the agent after construction.
96-
97-
This method must be called after creating the agent to complete initialization.
98-
"""
99-
logging.info(f"Initializing agent: {self._agent_name}")
100-
# Create Azure AI Agent or fallback
101-
if not self._agent:
102-
self._agent = await config.create_azure_ai_agent(
103-
agent_name=self._agent_name,
104-
instructions=self._system_message,
105-
tools=self._tools,
106-
)
107-
else:
108-
logging.info(f"Agent {self._agent_name} already initialized.")
109-
# Tools are registered with the kernel via get_tools_from_config
110-
return self
111-
11289
async def handle_action_request(self, action_request: ActionRequest) -> str:
11390
"""Handle an action request from another agent or the system.
11491
@@ -154,7 +131,7 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
154131
# thread = self.client.agents.get_thread(
155132
# thread=step.session_id
156133
# ) # AzureAIAgentThread(thread_id=step.session_id)
157-
async_generator = self._agent.invoke(
134+
async_generator = self.invoke(
158135
messages=f"{str(self._chat_history)}\n\nPlease perform this action",
159136
thread=thread,
160137
)
@@ -258,3 +235,83 @@ def save_state(self) -> Mapping[str, Any]:
258235
def load_state(self, state: Mapping[str, Any]) -> None:
259236
"""Load the state of this agent."""
260237
self._memory_store.load_state(state["memory"])
238+
239+
@classmethod
240+
@abstractmethod
241+
async def create(cls, **kwargs) -> "BaseAgent":
242+
"""Create an instance of the agent."""
243+
pass
244+
245+
@staticmethod
246+
async def _create_azure_ai_agent_definition(
247+
agent_name: str,
248+
instructions: str,
249+
tools: Optional[List[KernelFunction]] = None,
250+
client=None,
251+
response_format=None,
252+
temperature: float = 0.0,
253+
):
254+
"""
255+
Creates a new Azure AI Agent with the specified name and instructions using AIProjectClient.
256+
If an agent with the given name (assistant_id) already exists, it tries to retrieve it first.
257+
258+
Args:
259+
kernel: The Semantic Kernel instance
260+
agent_name: The name of the agent (will be used as assistant_id)
261+
instructions: The system message / instructions for the agent
262+
agent_type: The type of agent (defaults to "assistant")
263+
tools: Optional tool definitions for the agent
264+
tool_resources: Optional tool resources required by the tools
265+
response_format: Optional response format to control structured output
266+
temperature: The temperature setting for the agent (defaults to 0.0)
267+
268+
Returns:
269+
A new AzureAIAgent definition or an existing one if found
270+
"""
271+
try:
272+
# Get the AIProjectClient
273+
if client is None:
274+
client = config.get_ai_project_client()
275+
276+
# # First try to get an existing agent with this name as assistant_id
277+
try:
278+
agent_id = None
279+
agent_list = await client.agents.list_agents()
280+
for agent in agent_list.data:
281+
if agent.name == agent_name:
282+
agent_id = agent.id
283+
break
284+
# If the agent already exists, we can use it directly
285+
# Get the existing agent definition
286+
if agent_id is not None:
287+
logging.info(f"Agent with ID {agent_id} exists.")
288+
289+
existing_definition = await client.agents.get_agent(agent_id)
290+
291+
return existing_definition
292+
except Exception as e:
293+
# The Azure AI Projects SDK throws an exception when the agent doesn't exist
294+
# (not returning None), so we catch it and proceed to create a new agent
295+
if "ResourceNotFound" in str(e) or "404" in str(e):
296+
logging.info(
297+
f"Agent with ID {agent_name} not found. Will create a new one."
298+
)
299+
else:
300+
# Log unexpected errors but still try to create a new agent
301+
logging.warning(
302+
f"Unexpected error while retrieving agent {agent_name}: {str(e)}. Attempting to create new agent."
303+
)
304+
305+
# Create the agent using the project client with the agent_name as both name and assistantId
306+
agent_definition = await client.agents.create_agent(
307+
model=config.AZURE_OPENAI_DEPLOYMENT_NAME,
308+
name=agent_name,
309+
instructions=instructions,
310+
temperature=temperature,
311+
response_format=response_format,
312+
)
313+
314+
return agent_definition
315+
except Exception as exc:
316+
logging.error("Failed to create Azure AI Agent: %s", exc)
317+
raise

0 commit comments

Comments
 (0)