Skip to content
Closed
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
3 changes: 2 additions & 1 deletion infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ var modelVersion = '2024-08-06'
var aiServicesName = '${prefix}-aiservices'
var deploymentType = 'GlobalStandard'
var gptModelVersion = 'gpt-4o'
var appVersion = 'latest'
var appVersion = 'fnd01'
var resgistryName = 'biabcontainerreg'
var dockerRegistryUrl = 'https://${resgistryName}.azurecr.io'

Expand Down Expand Up @@ -196,6 +196,7 @@ resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = {
locationName: location
}
]
disableLocalAuth: true
capabilities: [ { name: 'EnableServerless' } ]
}

Expand Down
59 changes: 35 additions & 24 deletions src/backend/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,30 +220,41 @@ async def create_azure_ai_agent(
if client is None:
client = self.get_ai_project_client()

# First try to get an existing agent with this name as assistant_id
try:

existing_definition = await client.agents.get_agent(agent_name)
# Create the agent instance directly with project_client and existing definition
agent = AzureAIAgent(
client=client,
definition=existing_definition,
plugins=tools,
)

return agent
except Exception as e:
# The Azure AI Projects SDK throws an exception when the agent doesn't exist
# (not returning None), so we catch it and proceed to create a new agent
if "ResourceNotFound" in str(e) or "404" in str(e):
logging.info(
f"Agent with ID {agent_name} not found. Will create a new one."
)
else:
# Log unexpected errors but still try to create a new agent
logging.warning(
f"Unexpected error while retrieving agent {agent_name}: {str(e)}. Attempting to create new agent."
)
# # ToDo: This is the fixed code but commenting it out as agent clean up is no happening yet
# # and there are multiple versions of agents due to testing
# # First try to get an existing agent with this name as assistant_id
# try:
# agent_id = None
# agent_list = await client.agents.list_agents()
# for agent in agent_list.data:
# if agent.name == agent_name:
# agent_id = agent.id
# break
# # If the agent already exists, we can use it directly
# # Get the existing agent definition
# existing_definition = await client.agents.get_agent(agent_id)
# # Create the agent instance directly with project_client and existing definition
# agent = AzureAIAgent(
# client=client,
# definition=existing_definition,
# plugins=tools,
# )

# client.agents.list_agents()

# return agent
# except Exception as e:
# # The Azure AI Projects SDK throws an exception when the agent doesn't exist
# # (not returning None), so we catch it and proceed to create a new agent
# if "ResourceNotFound" in str(e) or "404" in str(e):
# logging.info(
# f"Agent with ID {agent_name} not found. Will create a new one."
# )
# else:
# # Log unexpected errors but still try to create a new agent
# logging.warning(
# f"Unexpected error while retrieving agent {agent_name}: {str(e)}. Attempting to create new agent."
# )

# Create the agent using the project client with the agent_name as both name and assistantId
agent_definition = await client.agents.create_agent(
Expand Down
112 changes: 91 additions & 21 deletions src/backend/app_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,21 @@
from event_utils import track_event_if_configured
from models.messages_kernel import AgentType
from kernel_agents.agent_factory import AgentFactory
from app_config import config

# # Check if the Application Insights Instrumentation Key is set in the environment variables
# instrumentation_key = os.getenv("APPLICATIONINSIGHTS_INSTRUMENTATION_KEY")
# if instrumentation_key:
# # Configure Application Insights if the Instrumentation Key is found
# configure_azure_monitor(connection_string=instrumentation_key)
# logging.info("Application Insights configured with the provided Instrumentation Key")
# else:
# # Log a warning if the Instrumentation Key is not found
# logging.warning("No Application Insights Instrumentation Key found. Skipping configuration")
instrumentation_key = os.getenv("APPLICATIONINSIGHTS_INSTRUMENTATION_KEY")
if instrumentation_key:
# Configure Application Insights if the Instrumentation Key is found
configure_azure_monitor(connection_string=instrumentation_key)
logging.info(
"Application Insights configured with the provided Instrumentation Key"
)
else:
# Log a warning if the Instrumentation Key is not found
logging.warning(
"No Application Insights Instrumentation Key found. Skipping configuration"
)

# Configure logging
logging.basicConfig(level=logging.INFO)
Expand All @@ -61,9 +66,9 @@
logging.getLogger("azure.identity.aio._internal").setLevel(logging.WARNING)

# # Suppress info logs from OpenTelemetry exporter
# logging.getLogger("azure.monitor.opentelemetry.exporter.export._base").setLevel(
# logging.WARNING
# )
logging.getLogger("azure.monitor.opentelemetry.exporter.export._base").setLevel(
logging.WARNING
)

# Initialize the FastAPI app
app = FastAPI()
Expand Down Expand Up @@ -124,10 +129,17 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
kernel, memory_store = await initialize_runtime_and_context(
input_task.session_id, user_id
)
client = None
try:
client = config.get_ai_project_client()
except Exception as client_exc:
logging.error(f"Error creating AIProjectClient: {client_exc}")

agents = await AgentFactory.create_all_agents(
session_id=input_task.session_id,
user_id=user_id,
memory_store=memory_store,
client=client,
)

group_chat_manager = agents[AgentType.GROUP_CHAT_MANAGER.value]
Expand Down Expand Up @@ -161,7 +173,11 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
"description": input_task.description,
},
)

if client:
try:
client.close()
except Exception as e:
logging.error(f"Error sending to AIProjectClient: {e}")
return {
"status": f"Plan created with ID: {plan.id}",
"session_id": input_task.session_id,
Expand Down Expand Up @@ -249,12 +265,31 @@ async def human_feedback_endpoint(human_feedback: HumanFeedback, request: Reques
kernel, memory_store = await initialize_runtime_and_context(
human_feedback.session_id, user_id
)
agents = await AgentFactory.create_all_agents(
session_id=human_feedback.session_id, user_id=user_id, memory_store=memory_store

client = None
try:
client = config.get_ai_project_client()
except Exception as client_exc:
logging.error(f"Error creating AIProjectClient: {client_exc}")

human_agent = await AgentFactory.create_agent(
agent_type=AgentType.HUMAN,
session_id=human_feedback.session_id,
user_id=user_id,
memory_store=memory_store,
client=client,
)

# Send the feedback to the human agent
human_agent = agents[AgentType.HUMAN.value]
if human_agent is None:
track_event_if_configured(
"AgentNotFound",
{
"status": "Agent not found",
"session_id": human_feedback.session_id,
"step_id": human_feedback.step_id,
},
)
raise HTTPException(status_code=404, detail="Agent not found")

# Use the human agent to handle the feedback
await human_agent.handle_human_feedback(human_feedback=human_feedback)
Expand All @@ -267,7 +302,11 @@ async def human_feedback_endpoint(human_feedback: HumanFeedback, request: Reques
"step_id": human_feedback.step_id,
},
)

if client:
try:
client.close()
except Exception as e:
logging.error(f"Error sending to AIProjectClient: {e}")
return {
"status": "Feedback received",
"session_id": human_feedback.session_id,
Expand Down Expand Up @@ -333,14 +372,30 @@ async def human_clarification_endpoint(
kernel, memory_store = await initialize_runtime_and_context(
human_clarification.session_id, user_id
)
agents = await AgentFactory.create_all_agents(
client = None
try:
client = config.get_ai_project_client()
except Exception as client_exc:
logging.error(f"Error creating AIProjectClient: {client_exc}")

human_agent = await AgentFactory.create_agent(
agent_type=AgentType.HUMAN,
session_id=human_clarification.session_id,
user_id=user_id,
memory_store=memory_store,
client=client,
)

# Send the feedback to the human agent
human_agent = agents[AgentType.HUMAN.value]
if human_agent is None:
track_event_if_configured(
"AgentNotFound",
{
"status": "Agent not found",
"session_id": human_clarification.session_id,
"step_id": human_clarification.step_id,
},
)
raise HTTPException(status_code=404, detail="Agent not found")

# Use the human agent to handle the feedback
await human_agent.handle_human_clarification(
Expand All @@ -354,7 +409,11 @@ async def human_clarification_endpoint(
"session_id": human_clarification.session_id,
},
)

if client:
try:
client.close()
except Exception as e:
logging.error(f"Error sending to AIProjectClient: {e}")
return {
"status": "Clarification received",
"session_id": human_clarification.session_id,
Expand Down Expand Up @@ -427,17 +486,28 @@ async def approve_step_endpoint(
kernel, memory_store = await initialize_runtime_and_context(
human_feedback.session_id, user_id
)
client = None
try:
client = config.get_ai_project_client()
except Exception as client_exc:
logging.error(f"Error creating AIProjectClient: {client_exc}")
agents = await AgentFactory.create_all_agents(
session_id=human_feedback.session_id,
user_id=user_id,
memory_store=memory_store,
client=client,
)

# Send the approval to the group chat manager
group_chat_manager = agents[AgentType.GROUP_CHAT_MANAGER.value]

await group_chat_manager.handle_human_feedback(human_feedback)

if client:
try:
client.close()
except Exception as e:
logging.error(f"Error sending to AIProjectClient: {e}")
# Return a status message
if human_feedback.step_id:
track_event_if_configured(
Expand Down
10 changes: 6 additions & 4 deletions src/backend/event_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

def track_event_if_configured(event_name: str, event_data: dict):
"""Track an event if Application Insights is configured.

This function safely wraps the Azure Monitor track_event function
to handle potential errors with the ProxyLogger.

Args:
event_name: The name of the event to track
event_data: Dictionary of event data/dimensions
Expand All @@ -17,8 +17,10 @@ def track_event_if_configured(event_name: str, event_data: dict):
instrumentation_key = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING")
if instrumentation_key:
track_event(event_name, event_data)
# else:
# logging.warning(f"Skipping track_event for {event_name} as Application Insights is not configured")
else:
logging.warning(
f"Skipping track_event for {event_name} as Application Insights is not configured"
)
except AttributeError as e:
# Handle the 'ProxyLogger' object has no attribute 'resource' error
logging.warning(f"ProxyLogger error in track_event: {e}")
Expand Down
12 changes: 11 additions & 1 deletion src/backend/kernel_agents/agent_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ async def create_agent(

# Build the agent definition (functions schema)
definition = None
client = None

try:
if client is None:
Expand Down Expand Up @@ -239,6 +238,7 @@ async def create_all_agents(
user_id: str,
temperature: float = 0.0,
memory_store: Optional[CosmosMemoryContext] = None,
client: Optional[Any] = None,
) -> Dict[AgentType, BaseAgent]:
"""Create all agent types for a session in a specific order.

Expand All @@ -265,6 +265,13 @@ async def create_all_agents(
planner_agent_type = AgentType.PLANNER
group_chat_manager_type = AgentType.GROUP_CHAT_MANAGER

try:
if client is None:
# Create the AIProjectClient instance using the config
# This is a placeholder; replace with actual client creation logic
client = config.get_ai_project_client()
except Exception as client_exc:
logger.error(f"Error creating AIProjectClient: {client_exc}")
# Initialize cache for this session if it doesn't exist
if session_id not in cls._agent_cache:
cls._agent_cache[session_id] = {}
Expand All @@ -280,6 +287,7 @@ async def create_all_agents(
session_id=session_id,
user_id=user_id,
temperature=temperature,
client=client,
memory_store=memory_store,
)

Expand All @@ -305,6 +313,7 @@ async def create_all_agents(
user_id=user_id,
temperature=temperature,
agent_instances=agent_instances, # Pass agent instances to the planner
client=client,
response_format=ResponseFormatJsonSchemaType(
json_schema=ResponseFormatJsonSchema(
name=PlannerResponsePlan.__name__,
Expand All @@ -324,6 +333,7 @@ async def create_all_agents(
session_id=session_id,
user_id=user_id,
temperature=temperature,
client=client,
agent_instances=agent_instances, # Pass agent instances to the planner
)
agents[group_chat_manager_type] = group_chat_manager
Expand Down
Loading
Loading