Skip to content

Commit 55ee693

Browse files
committed
Merge branch 'main' into customize-solution-update
2 parents df69976 + 4d17c26 commit 55ee693

32 files changed

+675
-280
lines changed

.github/workflows/docker-build-and-push.yml

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,13 @@ jobs:
3232
uses: docker/setup-buildx-action@v1
3333

3434
- name: Log in to Azure Container Registry
35-
if: ${{ github.ref_name == 'main' }}
35+
if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'demo' || github.ref_name == 'hotfix') }}
3636
uses: azure/docker-login@v2
3737
with:
3838
login-server: ${{ secrets.ACR_LOGIN_SERVER }}
3939
username: ${{ secrets.ACR_USERNAME }}
4040
password: ${{ secrets.ACR_PASSWORD }}
4141

42-
- name: Log in to Azure Container Registry (Dev/Demo)
43-
if: ${{ github.ref_name == 'dev' || github.ref_name == 'demo' || github.ref_name == 'hotfix' }}
44-
uses: azure/docker-login@v2
45-
with:
46-
login-server: ${{ secrets.ACR_DEV_LOGIN_SERVER }}
47-
username: ${{ secrets.ACR_DEV_USERNAME }}
48-
password: ${{ secrets.ACR_DEV_PASSWORD }}
49-
5042
- name: Set Docker image tag
5143
run: |
5244
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
@@ -57,27 +49,27 @@ jobs:
5749
echo "TAG=demo" >> $GITHUB_ENV
5850
elif [[ "${{ github.ref }}" == "refs/heads/hotfix" ]]; then
5951
echo "TAG=hotfix" >> $GITHUB_ENV
52+
else
53+
echo "TAG=pullrequest-ignore" >> $GITHUB_ENV
6054
fi
61-
- name: Build and push Docker images
62-
if: ${{ github.ref_name == 'main' }}
63-
run: |
64-
cd src/backend
65-
docker build -t ${{ secrets.ACR_LOGIN_SERVER }}/macae-backend:${{ env.TAG }} -f Dockerfile . && \
66-
docker push ${{ secrets.ACR_LOGIN_SERVER }}/macae-backend:${{ env.TAG }} && \
67-
echo "Backend image built and pushed successfully."
68-
cd ../frontend
69-
docker build -t ${{ secrets.ACR_LOGIN_SERVER }}/mac-webapp:${{ env.TAG }} -f Dockerfile . && \
70-
docker push ${{ secrets.ACR_LOGIN_SERVER }}/mac-webapp:${{ env.TAG }} && \
71-
echo "Frontend image built and pushed successfully."
72-
- name: Build and push Docker images (Dev/Demo/hotfix)
73-
if: ${{ github.ref_name == 'dev' || github.ref_name == 'demo' || github.ref_name == 'hotfix' }}
55+
56+
- name: Build and push Docker images optionally
7457
run: |
7558
cd src/backend
76-
docker build -t ${{ secrets.ACR_DEV_LOGIN_SERVER }}/macae-backend:${{ env.TAG }} -f Dockerfile . && \
77-
docker push ${{ secrets.ACR_DEV_LOGIN_SERVER }}/macae-backend:${{ env.TAG }} && \
78-
echo "Dev/Demo/Hotfix Backend image built and pushed successfully."
59+
docker build -t ${{ secrets.ACR_LOGIN_SERVER }}/macaebackend:${{ env.TAG }} -f Dockerfile . && \
60+
if [[ "${{ env.TAG }}" == "latest" || "${{ env.TAG }}" == "dev" || "${{ env.TAG }}" == "demo" || "${{ env.TAG }}" == "hotfix" ]]; then
61+
docker push ${{ secrets.ACR_LOGIN_SERVER }}/macaebackend:${{ env.TAG }} && \
62+
echo "Backend image built and pushed successfully."
63+
else
64+
echo "Skipping Docker push for backend with tag: ${{ env.TAG }}"
65+
fi
7966
cd ../frontend
80-
docker build -t ${{ secrets.ACR_DEV_LOGIN_SERVER }}/mac-webapp:${{ env.TAG }} -f Dockerfile . && \
81-
docker push ${{ secrets.ACR_DEV_LOGIN_SERVER }}/mac-webapp:${{ env.TAG }} && \
82-
echo "Dev/Demo/Hotfix Frontend image built and pushed successfully."
67+
docker build -t ${{ secrets.ACR_LOGIN_SERVER }}/macaefrontend:${{ env.TAG }} -f Dockerfile . && \
68+
if [[ "${{ env.TAG }}" == "latest" || "${{ env.TAG }}" == "dev" || "${{ env.TAG }}" == "demo" || "${{ env.TAG }}" == "hotfix" ]]; then
69+
docker push ${{ secrets.ACR_LOGIN_SERVER }}/macaefrontend:${{ env.TAG }} && \
70+
echo "Frontend image built and pushed successfully."
71+
else
72+
echo "Skipping Docker push for frontend with tag: ${{ env.TAG }}"
73+
fi
74+
8375

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
python -m pip install --upgrade pip
3939
pip install -r src/backend/requirements.txt
4040
pip install pytest-cov
41+
pip install pytest-asyncio
4142
4243
- name: Check if test files exist
4344
id: check_tests

README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Multi-Agent: Custom Automation Engine – Solution Accelerator
1+
# Multi-Agent-Custom-Automation-Engine – Solution Accelerator
22

33
MENU: [**USER STORY**](#user-story) \| [**QUICK DEPLOY**](#quick-deploy) \| [**SUPPORTING DOCUMENTATION**](#supporting-documentation) \|
44

@@ -13,23 +13,23 @@ Problem:
1313
Agentic AI systems are set to transform the way businesses operate, however it can be fairly complex to build an initial MVP to demonstrate this value.
1414

1515
Solution:
16-
The Multi-Agent -Custom Automation Engine Solution Accelerator provides a ready to go application to use as the base of the MVP, or as a reference, allowing you to hit the ground running.
16+
The Multi-Agent-Custom Automation Engine Solution Accelerator provides a ready to go application to use as the base of the MVP, or as a reference, allowing you to hit the ground running.
1717

1818
### Technology Note
1919
This accelerator uses the AutoGen framework from Microsoft Research. This is an open source project that is maintained by [Microsoft Research’s AI Frontiers Lab](https://www.microsoft.com/research/lab/ai-frontiers/). Please see this [blog post](https://devblogs.microsoft.com/autogen/microsofts-agentic-frameworks-autogen-and-semantic-kernel/) for the latest information on using the AutoGen framework in production solutions.
2020

2121
### Use cases / scenarios
2222
The multi-agent approach allows users to utilize multiple AI agents simultaneously for repeatable tasks, ensuring consistency and efficiency.
23-
The agents collaborate with a manager on various assignments for onboarding a new employee , such as HR and tech support AI working together to set up software accounts, configure hardware, schedule onboarding meetings, register employees for benefits, and send welcome emails. Additionally, these agents can handle tasks like procurement and drafting press releases.
23+
The agents collaborate with a manager on various assignments for onboarding a new employee, such as HR and tech support AI working together to set up software accounts, configure hardware, schedule onboarding meetings, register employees for benefits, and send welcome emails. Additionally, these agents can handle tasks like procurement and drafting press releases.
2424

2525
### Business value
26-
Multi-agent systems represent the next wave of Generative AI use cases, offering entirely new opportunities to drive efficiencies in your business. The Multi-Agent -Custom Automation Engine Solution Accelerator demonstrates several key benefits:
26+
Multi-agent systems represent the next wave of Generative AI use cases, offering entirely new opportunities to drive efficiencies in your business. The Multi-Agent-Custom-Automation-Engine Solution Accelerator demonstrates several key benefits:
2727

2828
- **Allows people to focus on what matters:** by doing the heavy lifting involved with coordinating activities across an organization, peoples’ time is freed up to focus on their specializations.
2929
- **Enabling GenAI to scale:** by not needing to build one application after another, organizations are able to reduce the friction of adopting GenAI across their entire organization. One capability can unlock almost unlimited use cases.
3030
- **Applicable to most industries:** these are common challenges that most organizations face, across most industries.
3131

32-
Whilst still an emerging area, investing in agentic use cases, digitatization and developing tools will be key to ensuring you are able to leverage these new technologies and seize the GenAI moment.
32+
Whilst still an emerging area, investing in agentic use cases, digitization and developing tools will be key to ensuring you are able to leverage these new technologies and seize the GenAI moment.
3333

3434
### Technical key features
3535

@@ -177,15 +177,18 @@ To add your newly created backend image:
177177
name: 'FRONTEND_SITE_NAME'
178178
value: 'https://<website Name>.azurewebsites.net'
179179

180+
name: 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY'
181+
value: <Application Insights Instrumentation Key>
182+
180183
- Click 'Save' and deploy your new revision
181184

182185
To add the new container to your website run the following:
183186

184187
```
185-
az webapp config container set --resource-group macae_full_deploy2_rg \
186-
--name macae-frontend-2t62qyozi76bs \
187-
--container-image-name macaeacr2t62qyozi76bs.azurecr.io/frontendmacae:latest \
188-
--container-registry-url https://macaeacr2t62qyozi76bs.azurecr.io
188+
az webapp config container set --resource-group <resource_group_name> \
189+
--name <container_name> \
190+
--container-image-name <e.g. macaeacr2t62qyozi76bs.azurecr.io/frontendmacae:latest> \
191+
--container-registry-url <e.g. https://macaeacr2t62qyozi76bs.azurecr.io>
189192
```
190193

191194

@@ -196,7 +199,7 @@ To add the identity provider, please follow the steps outlined in [Set Up Authen
196199

197200
To debug the solution, you can use the Cosmos and OpenAI services you have manually deployed. To do this, you need to ensure that your Azure identity has the required permissions on the Cosmos and OpenAI services.
198201

199-
- For OpeAI service, you can add yourself to the ‘Cognitive Services OpenAI User’ permission in the Access Control (IAM) pane of the Azure portal.
202+
- For OpenAI service, you can add yourself to the ‘Cognitive Services OpenAI User’ permission in the Access Control (IAM) pane of the Azure portal.
200203
- Cosmos is a little more difficult as it requires permissions be added through script. See these examples for more information:
201204
- [Use data plane role-based access control - Azure Cosmos DB for NoSQL | Microsoft Learn](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/security/how-to-grant-data-plane-role-based-access?tabs=built-in-definition%2Cpython&pivots=azure-interface-cli)
202205
- [az cosmosdb sql role assignment | Microsoft Learn](https://learn.microsoft.com/en-us/cli/azure/cosmosdb/sql/role/assignment?view=azure-cli-latest#az-cosmosdb-sql-role-assignment-create)

deploy/macae-continer-oc.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"_generator": {
77
"name": "bicep",
88
"version": "0.32.4.45862",
9-
"templateHash": "17567587246932458853"
9+
"templateHash": "13282901028774763433"
1010
}
1111
},
1212
"parameters": {
@@ -366,13 +366,18 @@
366366
{
367367
"name": "FRONTEND_SITE_NAME",
368368
"value": "[format('https://{0}.azurewebsites.net', format(variables('uniqueNameFormat'), 'frontend'))]"
369+
},
370+
{
371+
"name": "APPLICATIONINSIGHTS_INSTRUMENTATION_KEY",
372+
"value": "[reference('appInsights').ConnectionString]"
369373
}
370374
]
371375
}
372376
]
373377
}
374378
},
375379
"dependsOn": [
380+
"appInsights",
376381
"cosmos::autogenDb",
377382
"containerAppEnv",
378383
"cosmos",

deploy/macae-continer.bicep

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
279279
name: 'FRONTEND_SITE_NAME'
280280
value: 'https://${format(uniqueNameFormat, 'frontend')}.azurewebsites.net'
281281
}
282+
{
283+
name: 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY'
284+
value: appInsights.properties.ConnectionString
285+
}
282286
]
283287
}
284288
]

documentation/LocalDeployment.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
```
2323
- To specify a tenant, use:
2424
```bash
25-
az login --tenant 16b3c013-0000-0000-0000-000000000
25+
az login --tenant <tenant_id>
2626
```
2727

2828
3. **Create a Resource Group:**
@@ -42,29 +42,47 @@
4242
```bash
4343
az ad signed-in-user show --query id -o tsv
4444
```
45-
You will also be prompted for locations for Cosmos and Open AI services. This is to allow separate regions where there may be service quota restrictions
45+
You will also be prompted for locations for Cosmos and Open AI services. This is to allow separate regions where there may be service quota restrictions.
4646
47-
5. **Create a `.env` file:**
47+
- **Additional Notes**:
48+
49+
**Role Assignments in Bicep Deployment:**
50+
51+
The **macae-dev.bicep** deployment includes the assignment of the appropriate roles to AOAI and Cosmos services. If you want to modify an existing implementation—for example, to use resources deployed as part of the simple deployment for local debugging—you will need to add your own credentials to access the Cosmos and AOAI services. You can add these permissions using the following commands:
52+
```bash
53+
az cosmosdb sql role assignment create --resource-group <solution-accelerator-rg> --account-name <cosmos-db-account-name> --role-definition-name "Cosmos DB Built-in Data Contributor" --principal-id <aad-user-object-id> --scope /subscriptions/<subscription-id>/resourceGroups/<solution-accelerator-rg>/providers/Microsoft.DocumentDB/databaseAccounts/<cosmos-db-account-name>
54+
```
55+
56+
```bash
57+
az role assignment create --assignee <aad-user-upn> --role "Cognitive Services OpenAI User" --scope /subscriptions/<subscription-id>/resourceGroups/<solution-accelerator-rg>/providers/Microsoft.CognitiveServices/accounts/<azure-openai-account-name>
58+
```
59+
**Using a Different Database in Cosmos:**
60+
61+
You can set the solution up to use a different database in Cosmos. For example, you can name it something like autogen-dev. To do this:
62+
1. Change the environment variable **COSMOSDB_DATABASE** to the new database name.
63+
2. You will need to create the database in the Cosmos DB account. You can do this from the Data Explorer pane in the portal, click on the drop down labeled “_+ New Container_” and provide all the necessary details.
64+
65+
6. **Create a `.env` file:**
4866
4967
- Navigate to the `src` folder and create a `.env` file based on the provided `.env.sample` file.
5068
51-
6. **Fill in the `.env` file:**
69+
7. **Fill in the `.env` file:**
5270
5371
- Use the output from the deployment or check the Azure Portal under "Deployments" in the resource group.
5472
55-
7. **(Optional) Set up a virtual environment:**
73+
8. **(Optional) Set up a virtual environment:**
5674
5775
- If you are using `venv`, create and activate your virtual environment for both the frontend and backend folders.
5876
59-
8. **Install requirements - frontend:**
77+
9. **Install requirements - frontend:**
6078
6179
- In each of the frontend and backend folders -
6280
Open a terminal in the `src` folder and run:
6381
```bash
6482
pip install -r requirements.txt
6583
```
6684
67-
9. **Run the application:**
85+
10. **Run the application:**
6886
- From the src/backend directory:
6987
```bash
7088
python app.py

documentation/azure_app_service_auth_setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
![Add Provider](./images/azure-app-service-auth-setup/AppAuthIdentityProviderAdd.png)
2020

21-
5. Accept the default values and click on `Add` button to go back to the previous page with the identify provider added.
21+
5. Accept the default values and click on `Add` button to go back to the previous page with the idenity provider added.
2222

2323
![Add Provider](./images/azure-app-service-auth-setup/AppAuthIdentityProviderAdded.png)
2424

src/backend/.env.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ COSMOSDB_CONTAINER=memory
55
AZURE_OPENAI_ENDPOINT=
66
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o
77
AZURE_OPENAI_API_VERSION=2024-08-01-preview
8+
APPLICATIONINSIGHTS_INSTRUMENTATION_KEY=
89

910
BACKEND_API_URL='http://localhost:8000'
1011
FRONTEND_SITE_NAME='http://127.0.0.1:3000'

src/backend/agents/agentutils.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import json
22

3-
from autogen_core.components.models import (AssistantMessage,
4-
AzureOpenAIChatCompletionClient)
3+
from autogen_core.components.models import (
4+
AssistantMessage,
5+
AzureOpenAIChatCompletionClient,
6+
)
57
from pydantic import BaseModel
68

79
from context.cosmos_memory import CosmosBufferedChatCompletionContext
8-
from models.messages import InputTask, PlanStatus, Step, StepStatus
10+
from models.messages import Step
911

1012
common_agent_system_message = "If you do not have the information for the arguments of the function you need to call, do not call the function. Instead, respond back to the user requesting further information. You must not hallucinate or invent any of the information used as arguments in the function. For example, if you need to call a function that requires a delivery address, you must not generate 123 Example St. You must skip calling functions and return a clarification message along the lines of: Sorry, I'm missing some information I need to help you with that. Could you please provide the delivery address so I can do that for you?"
1113

@@ -27,7 +29,7 @@ class FSMStateAndTransition(BaseModel):
2729
identifiedTargetState: str
2830
identifiedTargetTransition: str
2931

30-
cosmos = CosmosBufferedChatCompletionContext(session_id or "",user_id)
32+
cosmos = CosmosBufferedChatCompletionContext(session_id or "", user_id)
3133
combined_LLM_messages = [
3234
AssistantMessage(content=step.action, source="GroupChatManager")
3335
]

src/backend/agents/base_agent.py

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,26 @@
33

44
from autogen_core.base import AgentId, MessageContext
55
from autogen_core.components import RoutedAgent, message_handler
6-
from autogen_core.components.models import (AssistantMessage,
7-
AzureOpenAIChatCompletionClient,
8-
LLMMessage, SystemMessage,
9-
UserMessage)
6+
from autogen_core.components.models import (
7+
AssistantMessage,
8+
AzureOpenAIChatCompletionClient,
9+
LLMMessage,
10+
SystemMessage,
11+
UserMessage,
12+
)
1013
from autogen_core.components.tool_agent import tool_agent_caller_loop
1114
from autogen_core.components.tools import Tool
1215

1316
from context.cosmos_memory import CosmosBufferedChatCompletionContext
14-
from models.messages import (ActionRequest, ActionResponse,
15-
AgentMessage, Step, StepStatus)
17+
from models.messages import (
18+
ActionRequest,
19+
ActionResponse,
20+
AgentMessage,
21+
Step,
22+
StepStatus,
23+
)
24+
from event_utils import track_event_if_configured
25+
1626

1727
class BaseAgent(RoutedAgent):
1828
def __init__(
@@ -94,15 +104,54 @@ async def handle_action_request(
94104
step_id=message.step_id,
95105
)
96106
)
107+
108+
track_event_if_configured(
109+
"Base agent - Added into the cosmos",
110+
{
111+
"session_id": message.session_id,
112+
"user_id": self._user_id,
113+
"plan_id": message.plan_id,
114+
"content": f"{result}",
115+
"source": self._agent_name,
116+
"step_id": message.step_id,
117+
},
118+
)
119+
97120
except Exception as e:
98-
print(f"Error during LLM call: {e}")
121+
logging.exception(f"Error during LLM call: {e}")
122+
track_event_if_configured(
123+
"Base agent - Error during llm call, captured into the cosmos",
124+
{
125+
"session_id": message.session_id,
126+
"user_id": self._user_id,
127+
"plan_id": message.plan_id,
128+
"content": f"{e}",
129+
"source": self._agent_name,
130+
"step_id": message.step_id,
131+
},
132+
)
133+
99134
return
100135
print(f"Task completed: {result}")
101136

102137
step.status = StepStatus.completed
103138
step.agent_reply = result
104139
await self._model_context.update_step(step)
105140

141+
track_event_if_configured(
142+
"Base agent - Updated step and updated into the cosmos",
143+
{
144+
"status": StepStatus.completed,
145+
"session_id": message.session_id,
146+
"agent_reply": f"{result}",
147+
"user_id": self._user_id,
148+
"plan_id": message.plan_id,
149+
"content": f"{result}",
150+
"source": self._agent_name,
151+
"step_id": message.step_id,
152+
},
153+
)
154+
106155
action_response = ActionResponse(
107156
step_id=step.id,
108157
plan_id=step.plan_id,

0 commit comments

Comments
 (0)