Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/agent_teams/marketing.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"input_key": "",
"type": "",
"name": "ProxyAgent",
"deployment_name": "gpt-4.1-mini",
"deployment_name": "",
"icon": "",
"system_message": "",
"description": "",
Expand Down
24 changes: 20 additions & 4 deletions data/agent_teams/retail.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"name": "OrderDataAgent",
"deployment_name": "gpt-4.1-mini",
"icon": "",
"system_message": "You have access to internal order, inventory, product, and fulfilment data through a secure index. Use this data to answer questions about products, shipping delays, customer orders, warehouse management, etc. Be mindful of privacy and compliance regulations when handling customer data.",
"description": "An agent that has access to internal order, inventory, product, and fulfilment data. Ask this agent if you have questions about products, shipping delays, customerr orders, warehouse management, etc.",
"system_message": "You have access to internal order, inventory, product, and fulfillment data through a secure index. Use this data to answer questions about products, shipping delays, customer orders, warehouse management, etc. Be mindful of privacy and compliance regulations when handling customer data.",
"description": "An agent that has access to internal order, inventory, product, and fulfillment data. Ask this agent if you have questions about products, shipping delays, customer orders, warehouse management, etc.",
"use_rag": true,
"use_mcp": false,
"use_bing": false,
Expand All @@ -42,7 +42,7 @@
{
"input_key": "",
"type": "",
"name": "AnalysisRecomendationAgent",
"name": "AnalysisRecommendationAgent",
"deployment_name": "o4-mini",
"icon": "",
"system_message": "You are a reasoning agent that can analyze customer data and provide recommendations for improving customer satisfaction and retention. You do not have access to any data sources, but you can reason based on the information provided to you by other agents. Use your reasoning skills to identify patterns, trends, and insights that can help improve customer satisfaction and retention. Provide actionable recommendations based on your analysis. You have access to other agents that can answer questions and provide data about customers, products, orders, inventory, and fulfilment. Use these agents to gather information as needed.",
Expand All @@ -54,6 +54,22 @@
"index_name": "",
"index_foundry_name": "",
"coding_tools": false
},
{
"input_key": "",
"type": "",
"name": "ProxyAgent",
"deployment_name": "",
"icon": "",
"system_message": "",
"description": "",
"use_rag": false,
"use_mcp": false,
"use_bing": false,
"use_reasoning": false,
"index_name": "",
"index_foundry_name": "",
"coding_tools": false
}
],
"protected": false,
Expand All @@ -64,7 +80,7 @@
{
"id": "task-1",
"name": "Satisfaction Plan",
"prompt": "Create a plan to improve Emily Thompson's satisfaction.",
"prompt": "Analyze the satisfaction of Emily Thompson with Contoso. If needed, provide a plan to increase her satisfaction.",
"created": "",
"creator": "",
"logo": ""
Expand Down
2 changes: 1 addition & 1 deletion src/backend/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ APPLICATIONINSIGHTS_CONNECTION_STRING=
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME=gpt-4o
AZURE_COGNITIVE_SERVICES="https://cognitiveservices.azure.com/.default"
AZURE_AI_AGENT_ENDPOINT=
AZURE_BING_CONNECTION_NAME=
# AZURE_BING_CONNECTION_NAME=
REASONING_MODEL_NAME=o3
APP_ENV=dev
MCP_SERVER_ENDPOINT=http://localhost:8080/mcp
Expand Down
16 changes: 9 additions & 7 deletions src/backend/common/config/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from typing import Optional

from azure.ai.projects.aio import AIProjectClient
from azure.cosmos import CosmosClient
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
from dotenv import load_dotenv
from semantic_kernel import Kernel

# Load environment variables from .env file
load_dotenv()
Expand Down Expand Up @@ -52,9 +54,9 @@ def __init__(self):
)
self.AZURE_OPENAI_ENDPOINT = self._get_required("AZURE_OPENAI_ENDPOINT")
self.REASONING_MODEL_NAME = self._get_optional("REASONING_MODEL_NAME", "o3")
self.AZURE_BING_CONNECTION_NAME = self._get_optional(
"AZURE_BING_CONNECTION_NAME"
)
# self.AZURE_BING_CONNECTION_NAME = self._get_optional(
# "AZURE_BING_CONNECTION_NAME"
# )
self.SUPPORTED_MODELS = self._get_optional("SUPPORTED_MODELS")
# Frontend settings
self.FRONTEND_SITE_NAME = self._get_optional(
Expand Down Expand Up @@ -82,7 +84,7 @@ def __init__(self):
self.AZURE_AI_SEARCH_INDEX_NAME = self._get_optional("AZURE_AI_SEARCH_INDEX_NAME")
self.AZURE_AI_SEARCH_ENDPOINT = self._get_optional("AZURE_AI_SEARCH_ENDPOINT")
self.AZURE_AI_SEARCH_API_KEY = self._get_optional("AZURE_AI_SEARCH_API_KEY")
self.BING_CONNECTION_NAME = self._get_optional("BING_CONNECTION_NAME")
# self.BING_CONNECTION_NAME = self._get_optional("BING_CONNECTION_NAME")

test_team_json = self._get_optional("TEST_TEAM_JSON")

Expand Down Expand Up @@ -125,7 +127,7 @@ def get_azure_credentials(self):
async def get_access_token(self) -> str:
"""Get Azure access token for API calls."""
try:
credential = self.get_azure_credentials(self.AZURE_CLIENT_ID)
credential = self.get_azure_credentials()
token = credential.get_token(self.AZURE_COGNITIVE_SERVICES)
return token.token
except Exception as e:
Expand Down Expand Up @@ -190,7 +192,7 @@ def get_cosmos_database_client(self):
try:
if self._cosmos_client is None:
self._cosmos_client = CosmosClient(
self.COSMOSDB_ENDPOINT, credential=get_azure_credential(self.AZURE_CLIENT_ID)
self.COSMOSDB_ENDPOINT, credential=self.get_azure_credential(self.AZURE_CLIENT_ID)
)

if self._cosmos_database is None:
Expand Down Expand Up @@ -227,7 +229,7 @@ def get_ai_project_client(self):
return self._ai_project_client

try:
credential = get_azure_credential(self.AZURE_CLIENT_ID)
credential = self.get_azure_credential(self.AZURE_CLIENT_ID)
if credential is None:
raise RuntimeError(
"Unable to acquire Azure credentials; ensure Managed Identity is configured"
Expand Down
2 changes: 1 addition & 1 deletion src/backend/common/utils/utils_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async def create_RAI_agent() -> FoundryAgentTemplate:
model_deployment_name=model_deployment_name,
enable_code_interpreter=False,
mcp_config=None,
bing_config=None,
#bing_config=None,
search_config=None
)

Expand Down
40 changes: 29 additions & 11 deletions src/backend/v3/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
from fastapi import WebSocket
from semantic_kernel.agents.orchestration.magentic import MagenticOrchestration
from semantic_kernel.connectors.ai.open_ai import (
AzureChatCompletion,
OpenAIChatPromptExecutionSettings,
)

AzureChatCompletion, OpenAIChatPromptExecutionSettings)
from v3.models.messages import WebsocketMessageType

logger = logging.getLogger(__name__)
Expand All @@ -35,7 +32,7 @@ def __init__(self):
self.endpoint = config.AZURE_OPENAI_ENDPOINT
self.reasoning_model = config.REASONING_MODEL_NAME
self.standard_model = config.AZURE_OPENAI_DEPLOYMENT_NAME
self.bing_connection_name = config.AZURE_BING_CONNECTION_NAME
#self.bing_connection_name = config.AZURE_BING_CONNECTION_NAME

# Create credential
self.credential = config.get_azure_credentials()
Expand Down Expand Up @@ -89,6 +86,7 @@ def __init__(self):
self.approvals: Dict[str, bool] = {} # m_plan_id -> approval status
self.sockets: Dict[str, WebSocket] = {} # user_id -> WebSocket
self.clarifications: Dict[str, str] = {} # m_plan_id -> clarification response
self.max_rounds: int = 20 # Maximum number of replanning rounds 20 needed to accommodate complex tasks

def get_current_orchestration(self, user_id: str) -> MagenticOrchestration:
"""get existing orchestration instance."""
Expand Down Expand Up @@ -199,16 +197,36 @@ async def send_status_update_async(
)
return

print(f" websocket {message}")
print(f" websocket original message: {message}")
print(f" websocket message type: {type(message)}")

# Convert message to proper format for frontend
try:
if hasattr(message, "data") and hasattr(message, "type"):
message = message.data
if hasattr(message, "to_dict"):
# Use the custom to_dict method if available
message_data = message.to_dict()
print(f" websocket used to_dict(): {message_data}")
elif hasattr(message, "data") and hasattr(message, "type"):
# Handle structured messages with data property
message_data = message.data
print(f" websocket used message.data: {message_data}")
elif isinstance(message, dict):
# Already a dictionary
message_data = message
print(f" websocket already dict: {message_data}")
else:
# Convert to string if it's a simple type
message_data = str(message)
print(f" websocket converted to string: {message_data}")
except Exception as e:
print(f"Error loading message data: {e}")
print(f" websocket after {message}")
print(f"Error processing message data: {e}")
message_data = str(message)

print(f" websocket final message_data: {message_data}")

standard_message = {
"type": message_type,
"data": message
"data": message_data
}
connection = self.get_connection(process_id)
if connection:
Expand Down
54 changes: 28 additions & 26 deletions src/backend/v3/magentic_agents/foundry_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
CodeInterpreterToolDefinition)
from semantic_kernel.agents import AzureAIAgent # pylint: disable=E0611
from v3.magentic_agents.common.lifecycle import AzureAgentBase
from v3.magentic_agents.models.agent_models import (BingConfig, MCPConfig,
SearchConfig)
from v3.magentic_agents.models.agent_models import MCPConfig, SearchConfig

# from v3.magentic_agents.models.agent_models import (BingConfig, MCPConfig,
# SearchConfig)

# exception too broad warning
# pylint: disable=w0718
Expand All @@ -22,15 +24,15 @@ def __init__(self, agent_name: str,
model_deployment_name: str,
enable_code_interpreter: bool = False,
mcp_config: MCPConfig | None = None,
bing_config: BingConfig | None = None,
#bing_config: BingConfig | None = None,
search_config: SearchConfig | None = None) -> None:
super().__init__(mcp=mcp_config)
self.agent_name = agent_name
self.agent_description = agent_description
self.agent_instructions = agent_instructions
self.model_deployment_name = model_deployment_name
self.enable_code_interpreter = enable_code_interpreter
self.bing = bing_config
#self.bing = bing_config
self.mcp = mcp_config
self.search = search_config
self._search_connection = None
Expand All @@ -40,19 +42,19 @@ def __init__(self, agent_name: str,
if self.model_deployment_name is any(["o3", "o4-mini"]):
raise ValueError("The current version of Foundry agents do not support reasoning models.")

async def _make_bing_tool(self) -> Optional[BingGroundingTool]:
"""Create Bing search tool for web search."""
if not all([self.client, self.bing.connection_name]):
self.logger.info("Bing tool not enabled")
return None
try:
self._bing_connection = await self.client.connections.get(name=self.bing.connection_name)
bing_tool = BingGroundingTool(connection_id=self._bing_connection.id)
self.logger.info("Bing tool created with connection %s", self._bing_connection.id)
return bing_tool
except Exception as ex:
self.logger.error("Bing tool creation failed: %s", ex)
return None
# async def _make_bing_tool(self) -> Optional[BingGroundingTool]:
# """Create Bing search tool for web search."""
# if not all([self.client, self.bing.connection_name]):
# self.logger.info("Bing tool not enabled")
# return None
# try:
# self._bing_connection = await self.client.connections.get(name=self.bing.connection_name)
# bing_tool = BingGroundingTool(connection_id=self._bing_connection.id)
# self.logger.info("Bing tool created with connection %s", self._bing_connection.id)
# return bing_tool
# except Exception as ex:
# self.logger.error("Bing tool creation failed: %s", ex)
# return None

async def _make_azure_search_tool(self) -> Optional[AzureAISearchTool]:
"""Create Azure AI Search tool for RAG capabilities."""
Expand Down Expand Up @@ -95,13 +97,13 @@ async def _collect_tools_and_resources(self) -> tuple[List, dict]:
self.logger.error("Something went wrong, Azure AI Search tool not configured")

# Add Bing search tool
if self.bing and self.bing.connection_name:
bing_tool = await self._make_bing_tool()
if bing_tool:
tools.extend(bing_tool.definitions)
self.logger.info("Added Bing search tools: %d tools", len(bing_tool.definitions))
else:
self.logger.error("Something went wrong, Bing tool not configured")
# if self.bing and self.bing.connection_name:
# bing_tool = await self._make_bing_tool()
# if bing_tool:
# tools.extend(bing_tool.definitions)
# self.logger.info("Added Bing search tools: %d tools", len(bing_tool.definitions))
# else:
# self.logger.error("Something went wrong, Bing tool not configured")

if self.enable_code_interpreter:
try:
Expand Down Expand Up @@ -145,7 +147,7 @@ async def create_foundry_agent(agent_name:str,
agent_instructions:str,
model_deployment_name:str,
mcp_config:MCPConfig,
bing_config:BingConfig,
#bing_config:BingConfig,
search_config:SearchConfig) -> FoundryAgentTemplate:

"""Factory function to create and open a ResearcherAgent."""
Expand All @@ -155,7 +157,7 @@ async def create_foundry_agent(agent_name:str,
model_deployment_name=model_deployment_name,
enable_code_interpreter=True,
mcp_config=mcp_config,
bing_config=bing_config,
#bing_config=bing_config,
search_config=search_config)
await agent.open()
return agent
Expand Down
12 changes: 7 additions & 5 deletions src/backend/v3/magentic_agents/magentic_agent_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
from types import SimpleNamespace
from typing import List, Union

from common.config.app_config import config
from common.models.messages_kernel import TeamConfiguration
from v3.config.settings import current_user_id
from v3.magentic_agents.foundry_agent import FoundryAgentTemplate
from v3.magentic_agents.models.agent_models import (BingConfig, MCPConfig,
SearchConfig)
from v3.magentic_agents.models.agent_models import MCPConfig, SearchConfig
# from v3.magentic_agents.models.agent_models import (BingConfig, MCPConfig,
# SearchConfig)
from v3.magentic_agents.proxy_agent import ProxyAgent
from v3.magentic_agents.reasoning_agent import ReasoningAgentTemplate
from common.config.app_config import config


class UnsupportedModelError(Exception):
"""Raised when an unsupported model is specified."""
Expand Down Expand Up @@ -87,7 +89,7 @@ async def create_agent_from_config(self, agent_obj: SimpleNamespace) -> Union[Fo
# Only create configs for explicitly requested capabilities
search_config = SearchConfig.from_env() if getattr(agent_obj, 'use_rag', False) else None
mcp_config = MCPConfig.from_env() if getattr(agent_obj, 'use_mcp', False) else None
bing_config = BingConfig.from_env() if getattr(agent_obj, 'use_bing', False) else None
# bing_config = BingConfig.from_env() if getattr(agent_obj, 'use_bing', False) else None

self.logger.info(f"Creating agent '{agent_obj.name}' with model '{deployment_name}' "
f"(Template: {'Reasoning' if use_reasoning else 'Foundry'})")
Expand All @@ -114,7 +116,7 @@ async def create_agent_from_config(self, agent_obj: SimpleNamespace) -> Union[Fo
model_deployment_name=deployment_name,
enable_code_interpreter=getattr(agent_obj, 'coding_tools', False),
mcp_config=mcp_config,
bing_config=bing_config,
#bing_config=bing_config,
search_config=search_config
)

Expand Down
26 changes: 13 additions & 13 deletions src/backend/v3/magentic_agents/models/agent_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,22 @@ def from_env(cls) -> "MCPConfig":
client_id=client_id,
)

@dataclass(slots=True)
class BingConfig:
"""Configuration for connecting to Bing Search."""
connection_name: str = "Bing"
# @dataclass(slots=True)
# class BingConfig:
# """Configuration for connecting to Bing Search."""
# connection_name: str = "Bing"

@classmethod
def from_env(cls) -> "BingConfig":
connection_name = config.BING_CONNECTION_NAME
# @classmethod
# def from_env(cls) -> "BingConfig":
# connection_name = config.BING_CONNECTION_NAME

# Raise exception if required environment variable is missing
if not connection_name:
raise ValueError(f"{cls.__name__} Missing required environment variables")
# # Raise exception if required environment variable is missing
# if not connection_name:
# raise ValueError(f"{cls.__name__} Missing required environment variables")

return cls(
connection_name=connection_name,
)
# return cls(
# connection_name=connection_name,
# )

@dataclass(slots=True)
class SearchConfig:
Expand Down
Loading
Loading