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
52 changes: 48 additions & 4 deletions src/backend/app_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import uuid
from typing import Dict, List, Optional
import uvicorn
import locale

# Semantic Kernel imports
from app_config import config
Expand Down Expand Up @@ -85,6 +87,25 @@
async def input_task_endpoint(input_task: InputTask, request: Request):
"""
Receive the initial input task from the user.

---
parameters:
- name: body
in: body
required: true
schema:
type: object
properties:
session_id:
type: string
description: Session ID for the task
description:
type: string
description: Description of the task to be performed
user_locale:
type: string
description: User's locale preference (e.g., 'en_US', 'en_GB', 'de_DE')
default: 'en_GB'
"""
# Fix 1: Properly await the async rai_success function
if not await rai_success(input_task.description):
Expand Down Expand Up @@ -115,6 +136,9 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
if not input_task.session_id:
input_task.session_id = str(uuid.uuid4())

# Extract user locale from request headers or input task
user_locale = request.headers.get("X-User-Locale", input_task.user_locale or "en_GB")

try:
# Create all agents instead of just the planner agent
# This ensures other agents are created first and the planner has access to them
Expand All @@ -132,6 +156,7 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
user_id=user_id,
memory_store=memory_store,
client=client,
user_locale=user_locale,
)

group_chat_manager = agents[AgentType.GROUP_CHAT_MANAGER.value]
Expand Down Expand Up @@ -229,6 +254,10 @@ async def human_feedback_endpoint(human_feedback: HumanFeedback, request: Reques
user_id:
type: string
description: The user ID providing the feedback
user_locale:
type: string
description: User's locale preference (e.g., 'en_US', 'en_GB', 'de_DE')
default: 'en_GB'
responses:
200:
description: Feedback received successfully
Expand Down Expand Up @@ -256,6 +285,9 @@ async def human_feedback_endpoint(human_feedback: HumanFeedback, request: Reques
human_feedback.session_id, user_id
)

# Extract user locale from request headers or feedback object
user_locale = request.headers.get("X-User-Locale", human_feedback.user_locale or "en_GB")

client = None
try:
client = config.get_ai_project_client()
Expand All @@ -268,6 +300,7 @@ async def human_feedback_endpoint(human_feedback: HumanFeedback, request: Reques
user_id=user_id,
memory_store=memory_store,
client=client,
user_locale=user_locale,
)

if human_agent is None:
Expand Down Expand Up @@ -476,6 +509,10 @@ async def approve_step_endpoint(
kernel, memory_store = await initialize_runtime_and_context(
human_feedback.session_id, user_id
)

# Extract user locale from request headers or feedback object
user_locale = request.headers.get("X-User-Locale", human_feedback.user_locale or "en_GB")

client = None
try:
client = config.get_ai_project_client()
Expand All @@ -486,6 +523,7 @@ async def approve_step_endpoint(
user_id=user_id,
memory_store=memory_store,
client=client,
user_locale=user_locale,
)

# Send the approval to the group chat manager
Expand Down Expand Up @@ -640,6 +678,16 @@ async def get_plans(
plan_with_steps.update_step_counts()
list_of_plans_with_steps.append(plan_with_steps)

# Print local system preference date format, selected language, and language code

# Get system locale settings
system_locale = locale.getdefaultlocale()
language_code = system_locale[0] if system_locale else "unknown"

# Add "local_system_language_selecetd" to each plan
for plan in list_of_plans_with_steps:
plan.user_locale = language_code.replace("_", "-")

return list_of_plans_with_steps


Expand Down Expand Up @@ -969,9 +1017,5 @@ async def get_agent_tools():
"""
return []


# Run the app
if __name__ == "__main__":
import uvicorn

uvicorn.run("app_kernel:app", host="127.0.0.1", port=8000, reload=True)
5 changes: 3 additions & 2 deletions src/backend/kernel_agents/agent_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ def default_system_message(agent_name=None) -> str:
name = agent_name
return f"You are an AI assistant named {name}. Help the user by providing accurate and helpful information."

async def handle_action_request(self, action_request: ActionRequest) -> str:
async def handle_action_request(self, action_request: ActionRequest, **kwargs) -> str:
"""Handle an action request from another agent or the system.

Args:
action_request_json: The action request as a JSON string
action_request: The action request object
**kwargs: Additional keyword arguments (e.g., user_locale)

Returns:
A JSON string containing the action response
Expand Down
44 changes: 43 additions & 1 deletion src/backend/kernel_agents/agent_factory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Factory for creating agents in the Multi-Agent Custom Automation Engine."""
"""Factory for creating agents in Multi-Agent Custom Automation Engine."""

import inspect
import logging
Expand All @@ -21,6 +21,13 @@
from kernel_agents.product_agent import ProductAgent
from kernel_agents.tech_support_agent import TechSupportAgent
from models.messages_kernel import AgentType, PlannerResponsePlan
# Import all tool classes to generate agent_tools_list
from kernel_tools.hr_tools import HrTools
from kernel_tools.marketing_tools import MarketingTools
from kernel_tools.product_tools import ProductTools
from kernel_tools.procurement_tools import ProcurementTools
from kernel_tools.tech_support_tools import TechSupportTools
from kernel_tools.generic_tools import GenericTools
# pylint:disable=E0611
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent

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

Expand Down Expand Up @@ -279,13 +287,18 @@ async def create_all_agents(
agents[planner_agent_type] = planner_agent

# Phase 3: Create group chat manager with all agents including the planner
# Generate the agent tools list for the GroupChatManager
agent_tools_list = cls._generate_agent_tools_list()

group_chat_manager = await cls.create_agent(
agent_type=AgentType.GROUP_CHAT_MANAGER,
session_id=session_id,
user_id=user_id,
temperature=temperature,
client=client,
agent_instances=agent_instances, # Pass agent instances to the planner
agent_tools_list=agent_tools_list,
user_locale=user_locale,
)
agents[group_chat_manager_type] = group_chat_manager

Expand Down Expand Up @@ -327,3 +340,32 @@ def clear_cache(cls, session_id: Optional[str] = None) -> None:
cls._agent_cache.clear()
cls._azure_ai_agent_cache.clear()
logger.info("Cleared all agent caches")

@classmethod
def _generate_agent_tools_list(cls) -> list[str]:
"""Generate a list of all available tool names across all agents.

Returns:
List of tool names that can be used by agents
"""
tool_classes = [
HrTools,
MarketingTools,
ProductTools,
ProcurementTools,
TechSupportTools,
GenericTools,
]

all_tools = []
for tool_class in tool_classes:
# Get all methods from the tool class
for name in dir(tool_class):
# Skip private methods and special methods
if not name.startswith("_") and name != "generate_tools_json_doc":
# Check if it's a callable method
method = getattr(tool_class, name)
if callable(method):
all_tools.append(f"{tool_class.__name__}.{name}")

return all_tools
5 changes: 3 additions & 2 deletions src/backend/kernel_agents/generic_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,16 @@ def plugins(self):
return GenericTools.get_all_kernel_functions()

# Explicitly inherit handle_action_request from the parent class
async def handle_action_request(self, action_request_json: str) -> str:
async def handle_action_request(self, action_request_json: str, **kwargs) -> str:
"""Handle an action request from another agent or the system.

This method is inherited from BaseAgent but explicitly included here for clarity.

Args:
action_request_json: The action request as a JSON string
**kwargs: Additional keyword arguments (e.g., user_locale)

Returns:
A JSON string containing the action response
"""
return await super().handle_action_request(action_request_json)
return await super().handle_action_request(action_request_json, **kwargs)
Loading
Loading